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:
Xun(Perry) Liu 2019-10-11 02:38:11 -07:00 committed by Jay
parent 7677b8513b
commit 85a8cc645f
13 changed files with 564 additions and 31 deletions

View File

@ -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);
}
}
});
}

View 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

View File

@ -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];

View File

@ -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;

View File

@ -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;
};
}
}

View File

@ -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)

View File

@ -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";

View File

@ -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

View File

@ -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

View File

@ -16,6 +16,7 @@ file(GLOB PartitionTestsSources
file(GLOB CustomizerTestsSources
customizer_tests.cpp
cell_update_record.cpp
customizer/*.cpp)
file(GLOB UpdaterTestsSources

View File

@ -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);

View 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()

View 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()