Feature/profile customize cell (#62)
* feat: Add unit test for two level customization issues: #49 * feat: Add class for statistic set and related unit test issue: #49 * Initial commit of cell_update_record with unit tests. * feat: Initial commit of cell_update_record with unit tests. issue: #49 * Refactor code. * Refactor code. issue: #49 * Integrate logic with customization issue: #49 * fix: adjust comments issue: #49 * feat: add flag of incremental, will load previous metrix table if set to true issues: #49 * fix: compilation in docker. issues: #49 * fix: fix crash issue and add protection code issues: #49 * Fix: Update code based on pull request's comments issue: #49 * fix: Remove util/concurrent_set, directly define set in updater.hpp issue: #49 * fix: Passing shared_ptr by reference.
This commit is contained in:
parent
7677b8513b
commit
85a8cc645f
@ -4,6 +4,7 @@
|
||||
#include "partitioner/cell_storage.hpp"
|
||||
#include "partitioner/multi_level_partition.hpp"
|
||||
#include "util/query_heap.hpp"
|
||||
#include "customizer/cell_update_record.hpp"
|
||||
|
||||
#include <tbb/enumerable_thread_specific.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
@ -116,7 +117,8 @@ class CellCustomizer
|
||||
void Customize(const GraphT &graph,
|
||||
const partitioner::CellStorage &cells,
|
||||
const std::vector<bool> &allowed_nodes,
|
||||
CellMetric &metric) const
|
||||
CellMetric &metric,
|
||||
const CellUpdateRecord &cell_update_record) const
|
||||
{
|
||||
Heap heap_exemplar(graph.GetNumberOfNodes());
|
||||
HeapPtr heaps(heap_exemplar);
|
||||
@ -128,8 +130,11 @@ class CellCustomizer
|
||||
auto &heap = heaps.local();
|
||||
for (auto id = range.begin(), end = range.end(); id != end; ++id)
|
||||
{
|
||||
Customize(
|
||||
if (cell_update_record.Check(level, id))
|
||||
{
|
||||
Customize(
|
||||
graph, heap, cells, allowed_nodes, metric, level, id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
131
include/customizer/cell_update_record.hpp
Normal file
131
include/customizer/cell_update_record.hpp
Normal file
@ -0,0 +1,131 @@
|
||||
#ifndef OSRM_CELLS_UPDATED_RECORD_HPP
|
||||
#define OSRM_CELLS_UPDATED_RECORD_HPP
|
||||
|
||||
#include "util/log.hpp"
|
||||
#include "updater/updater.hpp"
|
||||
#include "partitioner/multi_level_partition.hpp"
|
||||
|
||||
#include "tbb/concurrent_unordered_set.h"
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <iomanip>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace customizer
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
class CellUpdateRecordImpl
|
||||
{
|
||||
//using CellIDSet = std::unordered_set<CellID>
|
||||
using CellIDSet = tbb::concurrent_unordered_set<CellID>;
|
||||
using MultiLevelCellIDSet = std::vector<CellIDSet>;
|
||||
public:
|
||||
CellUpdateRecordImpl(const partitioner::MultiLevelPartition& mlp, bool incremental)
|
||||
: partition(mlp),
|
||||
isIncremental(incremental)
|
||||
{
|
||||
MultiLevelCellIDSet tmp(partition.GetNumberOfLevels() - 1, CellIDSet());
|
||||
cellsets = std::move(tmp);
|
||||
}
|
||||
|
||||
void Collect(updater::NodeSetViewerPtr node_updated)
|
||||
{
|
||||
if (!isIncremental || !node_updated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& n : *node_updated)
|
||||
{
|
||||
for (std::size_t level = 1; level < partition.GetNumberOfLevels(); ++level)
|
||||
{
|
||||
cellsets[level-1].insert(partition.GetCell(level, n));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Check(LevelID l, CellID c) const
|
||||
{
|
||||
// always return true for none-incremental mode
|
||||
if (!isIncremental)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (l < 1 || (l - 1) >= static_cast<LevelID>(cellsets.size()))
|
||||
{
|
||||
util::Log(logERROR) << "Incorrect level be passed to"
|
||||
<< typeid(*this).name() << "::" << __func__;
|
||||
return false;
|
||||
}
|
||||
return (cellsets[l-1].find(c) != cellsets[l-1].end());
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for (size_t i = 0; i < cellsets.size(); ++i)
|
||||
{
|
||||
cellsets[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
std::string Statistic() const
|
||||
{
|
||||
if (!isIncremental)
|
||||
{
|
||||
return "Nothing has been recorded in cell_update_record.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream ss;
|
||||
|
||||
int sumOfUpdates = 0;
|
||||
ss << "Cell Update Status(count for levels): (";
|
||||
for (size_t i = 0; i < cellsets.size(); ++i)
|
||||
{
|
||||
ss << cellsets[i].size();
|
||||
sumOfUpdates += cellsets[i].size();
|
||||
if (i != cellsets.size() - 1)
|
||||
{
|
||||
ss << ",";
|
||||
}
|
||||
}
|
||||
ss << ") ";
|
||||
|
||||
ss << "of (";
|
||||
int sumOfCells = 0;
|
||||
for (LevelID level = 1; level < partition.GetNumberOfLevels(); ++level)
|
||||
{
|
||||
ss << partition.GetNumberOfCells(level);
|
||||
sumOfCells += partition.GetNumberOfCells(level);
|
||||
if (level != (partition.GetNumberOfLevels() - 1))
|
||||
{
|
||||
ss << ",";
|
||||
}
|
||||
}
|
||||
ss << ") be updated.";
|
||||
|
||||
float percentage = (float)(sumOfUpdates * 100) / sumOfCells;
|
||||
ss <<std::setprecision(4) << " About " << percentage << "% in total.\n";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
MultiLevelCellIDSet cellsets;
|
||||
const partitioner::MultiLevelPartition &partition;
|
||||
bool isIncremental;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using CellUpdateRecord = detail::CellUpdateRecordImpl;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -94,6 +94,10 @@ template <storage::Ownership Ownership> class MultiLevelPartitionImpl final
|
||||
// returns the index of the cell the vertex is contained at level l
|
||||
CellID GetCell(LevelID l, NodeID node) const
|
||||
{
|
||||
// GetCell could be called with original node id from OSM data,
|
||||
// which might not has related cellid
|
||||
if (node > partition.size() || l > GetNumberOfLevels())
|
||||
return INVALID_CELL_ID;
|
||||
auto p = partition[node];
|
||||
auto lidx = LevelIDToIndex(l);
|
||||
auto masked = p & level_data->lidx_to_mask[lidx];
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
#define OSRM_UPDATER_UPDATER_HPP
|
||||
|
||||
#include "updater/updater_config.hpp"
|
||||
|
||||
#include "extractor/edge_based_edge.hpp"
|
||||
#include "tbb/concurrent_unordered_set.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
@ -12,6 +12,11 @@ namespace osrm
|
||||
{
|
||||
namespace updater
|
||||
{
|
||||
// https://www.threadingbuildingblocks.org/docs/help/reference/containers_overview/concurrent_unordered_set_cls.html
|
||||
using NodeSet = tbb::concurrent_unordered_set<NodeID>;
|
||||
using NodeSetPtr = std::shared_ptr<NodeSet>;
|
||||
using NodeSetViewerPtr = std::shared_ptr<const NodeSet>;
|
||||
|
||||
class Updater
|
||||
{
|
||||
public:
|
||||
@ -20,19 +25,22 @@ class Updater
|
||||
EdgeID
|
||||
LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||
std::vector<EdgeWeight> &node_weights,
|
||||
std::uint32_t &connectivity_checksum) const;
|
||||
std::uint32_t &connectivity_checksum,
|
||||
NodeSetPtr node_updated) const;
|
||||
|
||||
EdgeID LoadAndUpdateEdgeExpandedGraph(
|
||||
std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||
std::vector<EdgeWeight> &node_weights,
|
||||
std::vector<EdgeDuration> &node_durations, // TODO: remove when optional
|
||||
std::uint32_t &connectivity_checksum) const;
|
||||
std::uint32_t &connectivity_checksum,
|
||||
NodeSetPtr node_updated) const;
|
||||
EdgeID LoadAndUpdateEdgeExpandedGraph(
|
||||
std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||
std::vector<EdgeWeight> &node_weights,
|
||||
std::vector<EdgeDuration> &node_durations, // TODO: remove when optional
|
||||
std::vector<EdgeDistance> &node_distances, // TODO: remove when optional
|
||||
std::uint32_t &connectivity_checksum) const;
|
||||
std::uint32_t &connectivity_checksum,
|
||||
NodeSetPtr node_updated) const;
|
||||
|
||||
private:
|
||||
UpdaterConfig config;
|
||||
|
||||
@ -57,7 +57,8 @@ struct UpdaterConfig final : storage::IOConfig
|
||||
".osrm.enw"},
|
||||
{},
|
||||
{".osrm.datasource_names"}),
|
||||
valid_now(0)
|
||||
valid_now(0),
|
||||
incremental(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -72,6 +73,7 @@ struct UpdaterConfig final : storage::IOConfig
|
||||
std::vector<std::string> segment_speed_lookup_paths;
|
||||
std::vector<std::string> turn_penalty_lookup_paths;
|
||||
std::string tz_file_path;
|
||||
bool incremental;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,8 +72,10 @@ int Contractor::Run()
|
||||
|
||||
updater::Updater updater(config.updater_config);
|
||||
std::uint32_t connectivity_checksum = 0;
|
||||
// For contractor, no need to collect updated node set
|
||||
updater::NodeSetPtr node_updated = nullptr;
|
||||
EdgeID number_of_edge_based_nodes = updater.LoadAndUpdateEdgeExpandedGraph(
|
||||
edge_based_edge_list, node_weights, connectivity_checksum);
|
||||
edge_based_edge_list, node_weights, connectivity_checksum, node_updated);
|
||||
|
||||
// Convert node weights for oneway streets to INVALID_EDGE_WEIGHT
|
||||
for (auto &weight : node_weights)
|
||||
|
||||
@ -77,13 +77,14 @@ auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config,
|
||||
std::vector<EdgeWeight> &node_weights,
|
||||
std::vector<EdgeDuration> &node_durations,
|
||||
std::vector<EdgeDistance> &node_distances,
|
||||
std::uint32_t &connectivity_checksum)
|
||||
std::uint32_t &connectivity_checksum,
|
||||
updater::NodeSetPtr node_updated)
|
||||
{
|
||||
updater::Updater updater(config.updater_config);
|
||||
|
||||
std::vector<extractor::EdgeBasedEdge> edge_based_edge_list;
|
||||
EdgeID num_nodes = updater.LoadAndUpdateEdgeExpandedGraph(
|
||||
edge_based_edge_list, node_weights, node_durations, connectivity_checksum);
|
||||
edge_based_edge_list, node_weights, node_durations, connectivity_checksum, node_updated);
|
||||
|
||||
extractor::files::readEdgeBasedNodeDistances(config.GetPath(".osrm.enw"), node_distances);
|
||||
|
||||
@ -98,22 +99,39 @@ auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config,
|
||||
return edge_based_graph;
|
||||
}
|
||||
|
||||
std::vector<CellMetric> customizeFilteredMetrics(const partitioner::MultiLevelEdgeBasedGraph &graph,
|
||||
bool customizeFilteredMetrics(const partitioner::MultiLevelEdgeBasedGraph &graph,
|
||||
const partitioner::CellStorage &storage,
|
||||
const CellCustomizer &customizer,
|
||||
const std::vector<std::vector<bool>> &node_filters)
|
||||
const std::vector<std::vector<bool>> &node_filters,
|
||||
const CellUpdateRecord &cell_update_record,
|
||||
std::vector<CellMetric>& metrics,
|
||||
bool incremental)
|
||||
{
|
||||
std::vector<CellMetric> metrics;
|
||||
|
||||
for (auto filter : node_filters)
|
||||
if (metrics.size() != node_filters.size())
|
||||
{
|
||||
auto metric = storage.MakeMetric();
|
||||
customizer.Customize(graph, storage, filter, metric);
|
||||
metrics.push_back(std::move(metric));
|
||||
util::Log(logERROR) << "Under incremental mod, metrics array is compatible with nodefilter array.";
|
||||
util::Log(logERROR) << "metrics.size() = " << metrics.size() << " node_filters.size() = " << node_filters.size()<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return metrics;
|
||||
for (size_t i = 0; i < metrics.size(); ++i)
|
||||
{
|
||||
if (incremental)
|
||||
{
|
||||
customizer.Customize(graph, storage, node_filters[i], metrics[i], cell_update_record);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto metric = storage.MakeMetric();
|
||||
customizer.Customize(graph, storage, node_filters[i], metric, cell_update_record);
|
||||
metrics[i] = std::move(metric);
|
||||
//metrics.push_back(std::move(metric));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int Customizer::Run(const CustomizationConfig &config)
|
||||
@ -130,12 +148,25 @@ int Customizer::Run(const CustomizationConfig &config)
|
||||
std::vector<EdgeDuration> node_durations; // TODO: remove when durations are optional
|
||||
std::vector<EdgeDistance> node_distances; // TODO: remove when distances are optional
|
||||
std::uint32_t connectivity_checksum = 0;
|
||||
|
||||
updater::NodeSetPtr node_updated = config.updater_config.incremental ? std::make_shared<updater::NodeSet>() : nullptr;
|
||||
auto graph = LoadAndUpdateEdgeExpandedGraph(
|
||||
config, mlp, node_weights, node_durations, node_distances, connectivity_checksum);
|
||||
config, mlp, node_weights, node_durations, node_distances, connectivity_checksum, node_updated);
|
||||
BOOST_ASSERT(graph.GetNumberOfNodes() == node_weights.size());
|
||||
std::for_each(node_weights.begin(), node_weights.end(), [](auto &w) { w &= 0x7fffffff; });
|
||||
util::Log() << "Loaded edge based graph: " << graph.GetNumberOfEdges() << " edges, "
|
||||
<< graph.GetNumberOfNodes() << " nodes";
|
||||
|
||||
if (config.updater_config.incremental && node_updated)
|
||||
{
|
||||
double percentage = 0;
|
||||
if (0 != graph.GetNumberOfNodes())
|
||||
{
|
||||
percentage = (double)(node_updated->size() * 100) / graph.GetNumberOfNodes();
|
||||
}
|
||||
util::Log() << "Collect " << node_updated->size() << " updated nodes, "
|
||||
<< "about " << percentage << "% of total nodes in graph.";
|
||||
}
|
||||
|
||||
partitioner::CellStorage storage;
|
||||
partitioner::files::readCells(config.GetPath(".osrm.cells"), storage);
|
||||
@ -149,9 +180,50 @@ int Customizer::Run(const CustomizationConfig &config)
|
||||
|
||||
util::Log() << "Loading partition data took " << TIMER_SEC(loading_data) << " seconds";
|
||||
|
||||
std::vector<CellMetric> metrics;
|
||||
for (auto mask : properties.excludable_classes)
|
||||
{
|
||||
if (mask != extractor::INAVLID_CLASS_DATA)
|
||||
{
|
||||
metrics.push_back(CellMetric());
|
||||
}
|
||||
}
|
||||
|
||||
if (config.updater_config.incremental)
|
||||
{
|
||||
TIMER_START(reading_mld_data);
|
||||
if (boost::filesystem::exists(config.GetPath(".osrm.cell_metrics")))
|
||||
{
|
||||
std::unordered_map<std::string, std::vector<CellMetric>> previous_metric_exclude_classes = {
|
||||
{properties.GetWeightName(), std::move(metrics)},
|
||||
};
|
||||
customizer::files::readCellMetrics(config.GetPath(".osrm.cell_metrics"), previous_metric_exclude_classes);
|
||||
metrics = std::move(previous_metric_exclude_classes[properties.GetWeightName()]);
|
||||
}
|
||||
else
|
||||
{
|
||||
util::Log() << "Incremental mode must have valid cell_metrics.";
|
||||
return -1;
|
||||
}
|
||||
TIMER_STOP(reading_mld_data);
|
||||
util::Log() << "MLD customization reading took " << TIMER_SEC(reading_mld_data) << " seconds";
|
||||
}
|
||||
|
||||
TIMER_START(cell_customize);
|
||||
CellUpdateRecord cell_update_record(mlp, config.updater_config.incremental);
|
||||
{
|
||||
updater::NodeSetViewerPtr node_updated_viewer = std::move(node_updated);
|
||||
cell_update_record.Collect(node_updated_viewer);
|
||||
}
|
||||
util::Log() << cell_update_record.Statistic();
|
||||
|
||||
auto filter = util::excludeFlagsToNodeFilter(graph.GetNumberOfNodes(), node_data, properties);
|
||||
auto metrics = customizeFilteredMetrics(graph, storage, CellCustomizer{mlp}, filter);
|
||||
auto metrics_succeed = customizeFilteredMetrics(graph, storage, CellCustomizer{mlp}, filter, cell_update_record, metrics, config.updater_config.incremental);
|
||||
if (!metrics_succeed)
|
||||
{
|
||||
util::Log() << "Critical error in metrics table generation!" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
TIMER_STOP(cell_customize);
|
||||
util::Log() << "Cells customization took " << TIMER_SEC(cell_customize) << " seconds";
|
||||
|
||||
|
||||
@ -70,7 +70,11 @@ return_code parseArguments(int argc,
|
||||
&customization_config.updater_config.tz_file_path)
|
||||
->default_value(""),
|
||||
"Required for conditional turn restriction parsing, provide a geojson file containing "
|
||||
"time zone boundaries");
|
||||
"time zone boundaries")(
|
||||
"incremental",
|
||||
boost::program_options::value<bool>(&customization_config.updater_config.incremental)->default_value(false),
|
||||
"Setting incremental to true means reuse matrix table be calculated before and only customize cells with incremental traffic."
|
||||
);
|
||||
|
||||
// hidden options, will be allowed on command line, but will not be
|
||||
// shown to the user
|
||||
|
||||
@ -145,13 +145,22 @@ void checkWeightsConsistency(
|
||||
|
||||
static const constexpr std::size_t LUA_SOURCE = 0;
|
||||
|
||||
void recordsUpdatedNodes(NodeSetPtr& node_updated, const NodeID n)
|
||||
{
|
||||
if (node_updated)
|
||||
{
|
||||
node_updated->insert(n);
|
||||
}
|
||||
}
|
||||
|
||||
tbb::concurrent_vector<GeometryID>
|
||||
updateSegmentData(const UpdaterConfig &config,
|
||||
const extractor::ProfileProperties &profile_properties,
|
||||
const SegmentLookupTable &segment_speed_lookup,
|
||||
extractor::SegmentDataContainer &segment_data,
|
||||
std::vector<util::Coordinate> &coordinates,
|
||||
extractor::PackedOSMIDs &osm_node_ids)
|
||||
extractor::PackedOSMIDs &osm_node_ids,
|
||||
NodeSetPtr node_updated)
|
||||
{
|
||||
// vector to count used speeds for logging
|
||||
// size offset by one since index 0 is used for speeds not from external file
|
||||
@ -255,6 +264,9 @@ updateSegmentData(const UpdaterConfig &config,
|
||||
fwd_durations_range[segment_offset] = new_duration;
|
||||
fwd_datasources_range[segment_offset] = value->source;
|
||||
counters[value->source] += 1;
|
||||
|
||||
recordsUpdatedNodes(node_updated, nodes_range[segment_offset]);
|
||||
recordsUpdatedNodes(node_updated, nodes_range[segment_offset + 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -295,6 +307,9 @@ updateSegmentData(const UpdaterConfig &config,
|
||||
rev_durations_range[segment_offset] = new_duration;
|
||||
rev_datasources_range[segment_offset] = value->source;
|
||||
counters[value->source] += 1;
|
||||
|
||||
recordsUpdatedNodes(node_updated, nodes_range[segment_offset]);
|
||||
recordsUpdatedNodes(node_updated, nodes_range[segment_offset + 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -428,7 +443,8 @@ updateTurnPenalties(const UpdaterConfig &config,
|
||||
const TurnLookupTable &turn_penalty_lookup,
|
||||
std::vector<TurnPenalty> &turn_weight_penalties,
|
||||
std::vector<TurnPenalty> &turn_duration_penalties,
|
||||
extractor::PackedOSMIDs osm_node_ids)
|
||||
extractor::PackedOSMIDs osm_node_ids,
|
||||
NodeSetPtr node_updated)
|
||||
{
|
||||
const auto weight_multiplier = profile_properties.GetWeightMultiplier();
|
||||
|
||||
@ -466,6 +482,8 @@ updateTurnPenalties(const UpdaterConfig &config,
|
||||
turn_duration_penalties[edge_index] = turn_duration_penalty;
|
||||
turn_weight_penalties[edge_index] = turn_weight_penalty;
|
||||
updated_turns.push_back(edge_index);
|
||||
|
||||
recordsUpdatedNodes(node_updated, internal_turn.via_id);
|
||||
}
|
||||
|
||||
if (turn_weight_penalty < 0)
|
||||
@ -528,18 +546,20 @@ updateConditionalTurns(std::vector<TurnPenalty> &turn_weight_penalties,
|
||||
EdgeID
|
||||
Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||
std::vector<EdgeWeight> &node_weights,
|
||||
std::uint32_t &connectivity_checksum) const
|
||||
std::uint32_t &connectivity_checksum,
|
||||
NodeSetPtr node_updated) const
|
||||
{
|
||||
std::vector<EdgeDuration> node_durations(node_weights.size());
|
||||
return LoadAndUpdateEdgeExpandedGraph(
|
||||
edge_based_edge_list, node_weights, node_durations, connectivity_checksum);
|
||||
edge_based_edge_list, node_weights, node_durations, connectivity_checksum, node_updated);
|
||||
}
|
||||
|
||||
EdgeID
|
||||
Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||
std::vector<EdgeWeight> &node_weights,
|
||||
std::vector<EdgeDuration> &node_durations,
|
||||
std::uint32_t &connectivity_checksum) const
|
||||
std::uint32_t &connectivity_checksum,
|
||||
NodeSetPtr node_updated) const
|
||||
{
|
||||
TIMER_START(load_edges);
|
||||
|
||||
@ -616,7 +636,8 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
segment_speed_lookup,
|
||||
segment_data,
|
||||
coordinates,
|
||||
osm_node_ids);
|
||||
osm_node_ids,
|
||||
node_updated);
|
||||
// Now save out the updated compressed geometries
|
||||
extractor::files::writeSegmentData(config.GetPath(".osrm.geometry"), segment_data);
|
||||
TIMER_STOP(segment);
|
||||
@ -631,7 +652,8 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
turn_penalty_lookup,
|
||||
turn_weight_penalties,
|
||||
turn_duration_penalties,
|
||||
osm_node_ids);
|
||||
osm_node_ids,
|
||||
node_updated);
|
||||
const auto offset = updated_segments.size();
|
||||
updated_segments.resize(offset + updated_turn_penalties.size());
|
||||
// we need to re-compute all edges that have updated turn penalties.
|
||||
@ -645,6 +667,7 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
});
|
||||
}
|
||||
|
||||
// @Telenav, after the modification of #49, conditional_turns related cell will also need to be adjusted
|
||||
if (update_conditional_turns)
|
||||
{
|
||||
// initialize instance of class that handles time zone resolution
|
||||
|
||||
@ -16,6 +16,7 @@ file(GLOB PartitionTestsSources
|
||||
|
||||
file(GLOB CustomizerTestsSources
|
||||
customizer_tests.cpp
|
||||
cell_update_record.cpp
|
||||
customizer/*.cpp)
|
||||
|
||||
file(GLOB UpdaterTestsSources
|
||||
|
||||
@ -119,6 +119,66 @@ BOOST_AUTO_TEST_CASE(two_level_test)
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetInWeight(3), 1, 0);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(two_level_test2)
|
||||
{
|
||||
// 0 --- 1
|
||||
// | |
|
||||
// 2 --- 3
|
||||
// node: 0 1 2 3
|
||||
std::vector<CellID> l1{{0, 0, 1, 1}};
|
||||
MultiLevelPartition mlp{{l1}, {2}};
|
||||
|
||||
BOOST_REQUIRE_EQUAL(mlp.GetNumberOfLevels(), 2);
|
||||
|
||||
std::vector<MockEdge> edges = {{0, 1, 1}, {0, 2, 1}, {2, 3, 1}, {3, 1, 1}, {3, 2, 1}};
|
||||
|
||||
auto graph = makeGraph(mlp, edges);
|
||||
std::vector<bool> node_filter(graph.GetNumberOfNodes(), true);
|
||||
|
||||
CellStorage storage(mlp, graph);
|
||||
auto metric = storage.MakeMetric();
|
||||
CellCustomizer customizer(mlp);
|
||||
CellCustomizer::Heap heap(graph.GetNumberOfNodes());
|
||||
|
||||
auto cell_1_0 = storage.GetCell(metric, 1, 0);
|
||||
auto cell_1_1 = storage.GetCell(metric, 1, 1);
|
||||
|
||||
REQUIRE_SIZE_RANGE(cell_1_0.GetSourceNodes(), 1);
|
||||
REQUIRE_SIZE_RANGE(cell_1_0.GetDestinationNodes(), 1);
|
||||
REQUIRE_SIZE_RANGE(cell_1_1.GetSourceNodes(), 2);
|
||||
REQUIRE_SIZE_RANGE(cell_1_1.GetDestinationNodes(), 2);
|
||||
|
||||
CHECK_EQUAL_RANGE(cell_1_0.GetSourceNodes(), 0);
|
||||
CHECK_EQUAL_RANGE(cell_1_0.GetDestinationNodes(), 1);
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetSourceNodes(), 2, 3);
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetDestinationNodes(), 2, 3);
|
||||
|
||||
REQUIRE_SIZE_RANGE(cell_1_0.GetOutWeight(0), 1);
|
||||
REQUIRE_SIZE_RANGE(cell_1_0.GetOutWeight(1), 0);
|
||||
REQUIRE_SIZE_RANGE(cell_1_0.GetInWeight(1), 1);
|
||||
REQUIRE_SIZE_RANGE(cell_1_0.GetInWeight(0), 0);
|
||||
REQUIRE_SIZE_RANGE(cell_1_1.GetOutWeight(2), 2);
|
||||
REQUIRE_SIZE_RANGE(cell_1_1.GetInWeight(3), 2);
|
||||
|
||||
customizer.Customize(graph, heap, storage, node_filter, metric, 1, 0);
|
||||
customizer.Customize(graph, heap, storage, node_filter, metric, 1, 1);
|
||||
|
||||
// cell 0
|
||||
// check row source -> destination
|
||||
CHECK_EQUAL_RANGE(cell_1_0.GetOutWeight(0), 1);
|
||||
// check column destination -> source
|
||||
CHECK_EQUAL_RANGE(cell_1_0.GetInWeight(1), 1);
|
||||
|
||||
// cell 1
|
||||
// check row source -> destination
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetOutWeight(2), 0, 1);
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetOutWeight(3), 1, 0);
|
||||
// check column destination -> source
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetInWeight(2), 0, 1);
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetInWeight(3), 1, 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(four_levels_test)
|
||||
{
|
||||
// node: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
@ -283,7 +343,8 @@ BOOST_AUTO_TEST_CASE(four_levels_test)
|
||||
|
||||
CellStorage storage_rec(mlp, graph);
|
||||
auto metric_rec = storage_rec.MakeMetric();
|
||||
customizer.Customize(graph, storage_rec, node_filter, metric_rec);
|
||||
CellUpdateRecord cell_update_record(mlp, false);
|
||||
customizer.Customize(graph, storage_rec, node_filter, metric_rec, cell_update_record);
|
||||
|
||||
CHECK_EQUAL_COLLECTIONS(cell_2_1.GetOutWeight(9),
|
||||
storage_rec.GetCell(metric_rec, 2, 1).GetOutWeight(9));
|
||||
@ -324,7 +385,8 @@ BOOST_AUTO_TEST_CASE(exclude_test)
|
||||
CellCustomizer customizer(mlp);
|
||||
CellStorage storage(mlp, graph);
|
||||
auto metric = storage.MakeMetric();
|
||||
customizer.Customize(graph, storage, node_filter, metric);
|
||||
CellUpdateRecord cell_update_record(mlp, false);
|
||||
customizer.Customize(graph, storage, node_filter, metric, cell_update_record);
|
||||
|
||||
auto cell_1_0 = storage.GetCell(metric, 1, 0);
|
||||
auto cell_1_1 = storage.GetCell(metric, 1, 1);
|
||||
|
||||
195
unit_tests/customizer/cell_update_record.cpp
Normal file
195
unit_tests/customizer/cell_update_record.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
#include "common/range_tools.hpp"
|
||||
|
||||
#include "customizer/cell_update_record.hpp"
|
||||
#include "customizer/cell_customizer.hpp"
|
||||
#include "partitioner/multi_level_graph.hpp"
|
||||
#include "partitioner/multi_level_partition.hpp"
|
||||
#include "util/static_graph.hpp"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
using namespace osrm;
|
||||
using namespace osrm::customizer;
|
||||
using namespace osrm::partitioner;
|
||||
using namespace osrm::util;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct MockEdge
|
||||
{
|
||||
NodeID start;
|
||||
NodeID target;
|
||||
EdgeWeight weight;
|
||||
};
|
||||
|
||||
auto makeGraph(const MultiLevelPartition &mlp, const std::vector<MockEdge> &mock_edges)
|
||||
{
|
||||
struct EdgeData
|
||||
{
|
||||
EdgeWeight weight;
|
||||
EdgeDuration duration;
|
||||
EdgeDistance distance;
|
||||
bool forward;
|
||||
bool backward;
|
||||
};
|
||||
using Edge = static_graph_details::SortableEdgeWithData<EdgeData>;
|
||||
std::vector<Edge> edges;
|
||||
std::size_t max_id = 0;
|
||||
for (const auto &m : mock_edges)
|
||||
{
|
||||
max_id = std::max<std::size_t>(max_id, std::max(m.start, m.target));
|
||||
edges.push_back(Edge{m.start,
|
||||
m.target,
|
||||
m.weight,
|
||||
2 * m.weight,
|
||||
static_cast<EdgeDistance>(1.0),
|
||||
true,
|
||||
false});
|
||||
edges.push_back(Edge{m.target,
|
||||
m.start,
|
||||
m.weight,
|
||||
2 * m.weight,
|
||||
static_cast<EdgeDistance>(1.0),
|
||||
false,
|
||||
true});
|
||||
}
|
||||
std::sort(edges.begin(), edges.end());
|
||||
return partitioner::MultiLevelGraph<EdgeData, osrm::storage::Ownership::Container>(
|
||||
mlp, max_id + 1, edges);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(cell_update_record_test)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cell_update_record_basic_test)
|
||||
{
|
||||
// 0 --- 1 --- 4
|
||||
// | | |
|
||||
// 2 --- 3 --- 5
|
||||
// node: 0 1 2 3 4 5
|
||||
std::vector<CellID> l1{{0, 0, 1, 1, 1, 1}};
|
||||
std::vector<CellID> l2{{0, 0, 0, 0, 0, 0}};
|
||||
MultiLevelPartition mlp{{l1, l2}, {2, 1}};
|
||||
|
||||
BOOST_REQUIRE_EQUAL(mlp.GetNumberOfLevels(), 3);
|
||||
|
||||
std::vector<MockEdge> edges = {{0, 1, 1}, {0, 2, 1}, {2, 3, 1}, {3, 1, 1},
|
||||
{2, 4, 1}, {3, 5, 1}, {5, 3, 1}, {4, 5, 1}};
|
||||
|
||||
auto graph = makeGraph(mlp, edges);
|
||||
std::vector<bool> node_filter(true, graph.GetNumberOfNodes());
|
||||
|
||||
CellStorage storage_rec(mlp, graph);
|
||||
auto metric_rec = storage_rec.MakeMetric();
|
||||
|
||||
auto cell_1_0 = storage_rec.GetCell(metric_rec, 1, 0);
|
||||
auto cell_1_1 = storage_rec.GetCell(metric_rec, 1, 1);
|
||||
//auto cell_2_0 = storage_rec.GetCell(metric_rec, 2, 0);
|
||||
|
||||
// level 1
|
||||
CHECK_EQUAL_RANGE(cell_1_0.GetSourceNodes(), 0);
|
||||
CHECK_EQUAL_RANGE(cell_1_0.GetDestinationNodes(), 1);
|
||||
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetSourceNodes(), 2, 3);
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetDestinationNodes(), 3);
|
||||
|
||||
CellCustomizer customizer(mlp);
|
||||
CellUpdateRecord cell_update_record(mlp, false);
|
||||
customizer.Customize(graph, storage_rec, node_filter, metric_rec, cell_update_record);
|
||||
|
||||
// verify customization result
|
||||
CHECK_EQUAL_RANGE(cell_1_0.GetOutWeight(0), 1);
|
||||
CHECK_EQUAL_RANGE(cell_1_0.GetInWeight(1), 1);
|
||||
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetOutWeight(2), 1);
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetOutWeight(3), 0);
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetInWeight(3), 1, 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cell_update_record_test_check)
|
||||
{
|
||||
// 0 --- 1 --- 4
|
||||
// | | |
|
||||
// 2 --- 3 --- 5
|
||||
// node: 0 1 2 3 4 5
|
||||
std::vector<CellID> l1{{0, 0, 1, 1, 1, 1}};
|
||||
std::vector<CellID> l2{{0, 0, 0, 0, 0, 0}};
|
||||
MultiLevelPartition mlp{{l1, l2}, {2, 1}};
|
||||
|
||||
BOOST_REQUIRE_EQUAL(mlp.GetNumberOfLevels(), 3);
|
||||
|
||||
updater::NodeSetPtr ss = std::make_shared<updater::NodeSet>();
|
||||
ss->insert(2);
|
||||
ss->insert(3);
|
||||
CellUpdateRecord cr(mlp, true);
|
||||
cr.Collect(ss);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(cr.Check(1, 0), false);
|
||||
BOOST_REQUIRE_EQUAL(cr.Check(1, 1), true);
|
||||
BOOST_REQUIRE_EQUAL(cr.Check(2, 0), true);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cell_update_record_with_cost_update)
|
||||
{
|
||||
// 0 --- 1 --- 4
|
||||
// | | |
|
||||
// 2 --- 3 --- 5
|
||||
// node: 0 1 2 3 4 5
|
||||
std::vector<CellID> l1{{0, 0, 1, 1, 1, 1}};
|
||||
std::vector<CellID> l2{{0, 0, 0, 0, 0, 0}};
|
||||
MultiLevelPartition mlp{{l1, l2}, {2, 1}};
|
||||
|
||||
BOOST_REQUIRE_EQUAL(mlp.GetNumberOfLevels(), 3);
|
||||
|
||||
// update cost {2, 3, 2}
|
||||
// A better way to test is updating cost in the graph after initial customization
|
||||
std::vector<MockEdge> edges = {{0, 1, 1}, {0, 2, 1}, {2, 3, 1}, {3, 1, 1},
|
||||
{2, 4, 1}, {3, 5, 1}, {5, 3, 1}, {4, 5, 1}};
|
||||
|
||||
auto graph = makeGraph(mlp, edges);
|
||||
std::vector<bool> node_filter(true, graph.GetNumberOfNodes());
|
||||
CellStorage storage_rec(mlp, graph);
|
||||
auto metric_rec = storage_rec.MakeMetric();
|
||||
auto cell_1_0 = storage_rec.GetCell(metric_rec, 1, 0);
|
||||
auto cell_1_1 = storage_rec.GetCell(metric_rec, 1, 1);
|
||||
|
||||
CellCustomizer customizer(mlp);
|
||||
CellUpdateRecord cr(mlp, false);
|
||||
customizer.Customize(graph, storage_rec, node_filter, metric_rec, cr);
|
||||
|
||||
// verify customization result
|
||||
CHECK_EQUAL_RANGE(cell_1_0.GetOutWeight(0), 1);
|
||||
CHECK_EQUAL_RANGE(cell_1_0.GetInWeight(1), 1);
|
||||
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetOutWeight(2), 1);
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetOutWeight(3), 0);
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetInWeight(3), 1, 0);
|
||||
|
||||
// Init graph 2
|
||||
// update cost {2, 3, 2}
|
||||
// A better way to test is updating cost in the graph after initial customization
|
||||
std::vector<MockEdge> edges2 = {{0, 1, 1}, {0, 2, 1}, {2, 3, 2}, {3, 1, 1},
|
||||
{2, 4, 1}, {3, 5, 1}, {5, 3, 1}, {4, 5, 1}};
|
||||
auto graph2 = makeGraph(mlp, edges2);
|
||||
|
||||
updater::NodeSetPtr ss = std::make_shared<updater::NodeSet>();
|
||||
ss->insert(2);
|
||||
ss->insert(3);
|
||||
updater::NodeSetViewerPtr sViewer = std::move(ss);
|
||||
CellUpdateRecord cr2(mlp, true);
|
||||
cr2.Collect(sViewer);
|
||||
customizer.Customize(graph2, storage_rec, node_filter, metric_rec, cr2);
|
||||
// verify customization result
|
||||
CHECK_EQUAL_RANGE(cell_1_0.GetOutWeight(0), 1);
|
||||
CHECK_EQUAL_RANGE(cell_1_0.GetInWeight(1), 1);
|
||||
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetOutWeight(2), 2);
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetOutWeight(3), 0);
|
||||
CHECK_EQUAL_RANGE(cell_1_1.GetInWeight(3), 2, 0);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(cr2.Statistic(), "Cell Update Status(count for levels): (1,1) of (2,1) be updated. About 66.67% in total.\n");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
24
unit_tests/updater/concurrent_node_set.cpp
Normal file
24
unit_tests/updater/concurrent_node_set.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "updater/updater.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <set>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(concurrent_node_set_test)
|
||||
|
||||
using namespace osrm;
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(node_set_enable_test)
|
||||
{
|
||||
updater::NodeSetPtr ns = std::make_shared<updater::NodeSet>();
|
||||
ns->insert(1);
|
||||
ns->insert(2);
|
||||
ns->insert(3);
|
||||
|
||||
updater::NodeSetViewerPtr nsv = std::move(ns);
|
||||
BOOST_CHECK(ns == nullptr);
|
||||
BOOST_CHECK(nsv->size() == 3);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
Loading…
Reference in New Issue
Block a user