diff --git a/include/customizer/cell_customizer.hpp b/include/customizer/cell_customizer.hpp index df5499579..80e483357 100644 --- a/include/customizer/cell_customizer.hpp +++ b/include/customizer/cell_customizer.hpp @@ -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 #include @@ -116,7 +117,8 @@ class CellCustomizer void Customize(const GraphT &graph, const partitioner::CellStorage &cells, const std::vector &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); + } } }); } diff --git a/include/customizer/cell_update_record.hpp b/include/customizer/cell_update_record.hpp new file mode 100644 index 000000000..002eca2df --- /dev/null +++ b/include/customizer/cell_update_record.hpp @@ -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 +#include +#include + +namespace osrm +{ +namespace customizer +{ +namespace detail +{ + +class CellUpdateRecordImpl +{ +//using CellIDSet = std::unordered_set +using CellIDSet = tbb::concurrent_unordered_set; +using MultiLevelCellIDSet = std::vector; +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(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 < 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]; diff --git a/include/updater/updater.hpp b/include/updater/updater.hpp index 565b293cb..7ea632158 100644 --- a/include/updater/updater.hpp +++ b/include/updater/updater.hpp @@ -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 #include @@ -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; +using NodeSetPtr = std::shared_ptr; +using NodeSetViewerPtr = std::shared_ptr; + class Updater { public: @@ -20,19 +25,22 @@ class Updater EdgeID LoadAndUpdateEdgeExpandedGraph(std::vector &edge_based_edge_list, std::vector &node_weights, - std::uint32_t &connectivity_checksum) const; + std::uint32_t &connectivity_checksum, + NodeSetPtr node_updated) const; EdgeID LoadAndUpdateEdgeExpandedGraph( std::vector &edge_based_edge_list, std::vector &node_weights, std::vector &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 &edge_based_edge_list, std::vector &node_weights, std::vector &node_durations, // TODO: remove when optional std::vector &node_distances, // TODO: remove when optional - std::uint32_t &connectivity_checksum) const; + std::uint32_t &connectivity_checksum, + NodeSetPtr node_updated) const; private: UpdaterConfig config; diff --git a/include/updater/updater_config.hpp b/include/updater/updater_config.hpp index 64306a609..ecf009618 100644 --- a/include/updater/updater_config.hpp +++ b/include/updater/updater_config.hpp @@ -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 segment_speed_lookup_paths; std::vector turn_penalty_lookup_paths; std::string tz_file_path; + bool incremental; }; } } diff --git a/src/contractor/contractor.cpp b/src/contractor/contractor.cpp index 266367080..f226e1db3 100644 --- a/src/contractor/contractor.cpp +++ b/src/contractor/contractor.cpp @@ -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) diff --git a/src/customize/customizer.cpp b/src/customize/customizer.cpp index d7e2af90d..6fade3d28 100644 --- a/src/customize/customizer.cpp +++ b/src/customize/customizer.cpp @@ -77,13 +77,14 @@ auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config, std::vector &node_weights, std::vector &node_durations, std::vector &node_distances, - std::uint32_t &connectivity_checksum) + std::uint32_t &connectivity_checksum, + updater::NodeSetPtr node_updated) { updater::Updater updater(config.updater_config); std::vector 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 customizeFilteredMetrics(const partitioner::MultiLevelEdgeBasedGraph &graph, +bool customizeFilteredMetrics(const partitioner::MultiLevelEdgeBasedGraph &graph, const partitioner::CellStorage &storage, const CellCustomizer &customizer, - const std::vector> &node_filters) + const std::vector> &node_filters, + const CellUpdateRecord &cell_update_record, + std::vector& metrics, + bool incremental) { - std::vector 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 node_durations; // TODO: remove when durations are optional std::vector 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() : 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 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> 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"; diff --git a/src/tools/customize.cpp b/src/tools/customize.cpp index 97217aa95..36ed061af 100644 --- a/src/tools/customize.cpp +++ b/src/tools/customize.cpp @@ -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(&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 diff --git a/src/updater/updater.cpp b/src/updater/updater.cpp index f4dc902a3..71602847f 100644 --- a/src/updater/updater.cpp +++ b/src/updater/updater.cpp @@ -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 updateSegmentData(const UpdaterConfig &config, const extractor::ProfileProperties &profile_properties, const SegmentLookupTable &segment_speed_lookup, extractor::SegmentDataContainer &segment_data, std::vector &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 &turn_weight_penalties, std::vector &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 &turn_weight_penalties, EdgeID Updater::LoadAndUpdateEdgeExpandedGraph(std::vector &edge_based_edge_list, std::vector &node_weights, - std::uint32_t &connectivity_checksum) const + std::uint32_t &connectivity_checksum, + NodeSetPtr node_updated) const { std::vector 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 &edge_based_edge_list, std::vector &node_weights, std::vector &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 &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 &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 &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 diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt index 86a5297e5..580fcd82f 100644 --- a/unit_tests/CMakeLists.txt +++ b/unit_tests/CMakeLists.txt @@ -16,6 +16,7 @@ file(GLOB PartitionTestsSources file(GLOB CustomizerTestsSources customizer_tests.cpp + cell_update_record.cpp customizer/*.cpp) file(GLOB UpdaterTestsSources diff --git a/unit_tests/customizer/cell_customization.cpp b/unit_tests/customizer/cell_customization.cpp index d5a3f9eb8..e54b0c1e7 100644 --- a/unit_tests/customizer/cell_customization.cpp +++ b/unit_tests/customizer/cell_customization.cpp @@ -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 l1{{0, 0, 1, 1}}; + MultiLevelPartition mlp{{l1}, {2}}; + + BOOST_REQUIRE_EQUAL(mlp.GetNumberOfLevels(), 2); + + std::vector edges = {{0, 1, 1}, {0, 2, 1}, {2, 3, 1}, {3, 1, 1}, {3, 2, 1}}; + + auto graph = makeGraph(mlp, edges); + std::vector 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); diff --git a/unit_tests/customizer/cell_update_record.cpp b/unit_tests/customizer/cell_update_record.cpp new file mode 100644 index 000000000..a186b6533 --- /dev/null +++ b/unit_tests/customizer/cell_update_record.cpp @@ -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 + +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 &mock_edges) +{ + struct EdgeData + { + EdgeWeight weight; + EdgeDuration duration; + EdgeDistance distance; + bool forward; + bool backward; + }; + using Edge = static_graph_details::SortableEdgeWithData; + std::vector edges; + std::size_t max_id = 0; + for (const auto &m : mock_edges) + { + max_id = std::max(max_id, std::max(m.start, m.target)); + edges.push_back(Edge{m.start, + m.target, + m.weight, + 2 * m.weight, + static_cast(1.0), + true, + false}); + edges.push_back(Edge{m.target, + m.start, + m.weight, + 2 * m.weight, + static_cast(1.0), + false, + true}); + } + std::sort(edges.begin(), edges.end()); + return partitioner::MultiLevelGraph( + 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 l1{{0, 0, 1, 1, 1, 1}}; + std::vector l2{{0, 0, 0, 0, 0, 0}}; + MultiLevelPartition mlp{{l1, l2}, {2, 1}}; + + BOOST_REQUIRE_EQUAL(mlp.GetNumberOfLevels(), 3); + + std::vector 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 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 l1{{0, 0, 1, 1, 1, 1}}; + std::vector 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(); + 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 l1{{0, 0, 1, 1, 1, 1}}; + std::vector 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 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 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 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(); + 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() + diff --git a/unit_tests/updater/concurrent_node_set.cpp b/unit_tests/updater/concurrent_node_set.cpp new file mode 100644 index 000000000..2c9c83c3f --- /dev/null +++ b/unit_tests/updater/concurrent_node_set.cpp @@ -0,0 +1,24 @@ +#include "updater/updater.hpp" +#include "util/typedefs.hpp" + +#include +#include + +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(); + 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()