Matrix plugin with MLD overlay

This commit is contained in:
Michael Krasnyk 2017-06-28 00:48:18 +02:00 committed by Patrick Niklaus
parent b910ab9bcb
commit 517cb5f094
7 changed files with 327 additions and 51 deletions

View File

@ -1,3 +1,9 @@
# 5.9.0
- Changes from 5.8
- Algorithm:
- Multi-Level Dijkstra:
- Plugins supported: `table`
# 5.8.0
- Changes from 5.7
- API:

View File

@ -41,12 +41,6 @@ bool needsLoopForward(const PhantomNode &source_phantom, const PhantomNode &targ
bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &target_phantom);
void insertSourceInHeap(SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node);
void insertTargetInHeap(SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node);
template <typename Heap>
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes)
{
@ -81,6 +75,40 @@ void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNod
}
}
template <typename ManyToManyQueryHeap>
void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
{
if (phantom_node.IsValidForwardSource())
{
heap.Insert(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()});
}
if (phantom_node.IsValidReverseSource())
{
heap.Insert(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()});
}
}
template <typename ManyToManyQueryHeap>
void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
{
if (phantom_node.IsValidForwardTarget())
{
heap.Insert(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id, phantom_node.GetForwardDuration()});
}
if (phantom_node.IsValidReverseTarget())
{
heap.Insert(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id, phantom_node.GetReverseDuration()});
}
}
template <typename FacadeT>
void annotatePath(const FacadeT &facade,
const PhantomNodes &phantom_node_pair,

View File

@ -78,6 +78,20 @@ struct MultiLayerDijkstraHeapData
MultiLayerDijkstraHeapData(NodeID p, bool from) : parent(p), from_clique_arc(from) {}
};
struct ManyToManyMultiLayerDijkstraHeapData : MultiLayerDijkstraHeapData
{
LevelID level;
EdgeWeight duration;
ManyToManyMultiLayerDijkstraHeapData(NodeID p, EdgeWeight duration)
: MultiLayerDijkstraHeapData(p), level(0), duration(duration)
{
}
ManyToManyMultiLayerDijkstraHeapData(NodeID p, bool from, LevelID level, EdgeWeight duration)
: MultiLayerDijkstraHeapData(p, from), level(level), duration(duration)
{
}
};
template <> struct SearchEngineData<routing_algorithms::mld::Algorithm>
{
using QueryHeap = util::QueryHeap<NodeID,
@ -86,12 +100,23 @@ template <> struct SearchEngineData<routing_algorithms::mld::Algorithm>
MultiLayerDijkstraHeapData,
util::UnorderedMapStorage<NodeID, int>>;
using ManyToManyQueryHeap = util::QueryHeap<NodeID,
NodeID,
EdgeWeight,
ManyToManyMultiLayerDijkstraHeapData,
util::UnorderedMapStorage<NodeID, int>>;
using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
using ManyToManyHeapPtr = boost::thread_specific_ptr<ManyToManyQueryHeap>;
static SearchEngineHeapPtr forward_heap_1;
static SearchEngineHeapPtr reverse_heap_1;
static ManyToManyHeapPtr many_to_many_heap;
void InitializeOrClearFirstThreadLocalStorage(unsigned number_of_nodes);
void InitializeOrClearManyToManyThreadLocalStorage(unsigned number_of_nodes);
};
}
}

View File

@ -15,11 +15,6 @@ namespace engine
namespace routing_algorithms
{
namespace ch
{
using ManyToManyQueryHeap = SearchEngineData<Algorithm>::ManyToManyQueryHeap;
namespace
{
struct NodeBucket
@ -32,16 +27,19 @@ struct NodeBucket
{
}
};
}
// FIXME This should be replaced by an std::unordered_multimap, though this needs benchmarking
using SearchSpaceWithBuckets = std::unordered_map<NodeID, std::vector<NodeBucket>>;
namespace ch
{
template <bool DIRECTION>
void relaxOutgoingEdges(const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
const NodeID node,
const EdgeWeight weight,
const EdgeWeight duration,
ManyToManyQueryHeap &query_heap)
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap)
{
for (auto edge : facade.GetAdjacentEdgeRange(node))
{
@ -75,7 +73,7 @@ void relaxOutgoingEdges(const datafacade::ContiguousInternalMemoryDataFacade<Alg
void forwardRoutingStep(const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
const unsigned row_idx,
const unsigned number_of_targets,
ManyToManyQueryHeap &query_heap,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
const SearchSpaceWithBuckets &search_space_with_buckets,
std::vector<EdgeWeight> &weights_table,
std::vector<EdgeWeight> &durations_table)
@ -131,7 +129,7 @@ void forwardRoutingStep(const datafacade::ContiguousInternalMemoryDataFacade<Alg
void backwardRoutingStep(const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
const unsigned column_idx,
ManyToManyQueryHeap &query_heap,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
SearchSpaceWithBuckets &search_space_with_buckets)
{
const NodeID node = query_heap.DeleteMin();
@ -148,7 +146,6 @@ void backwardRoutingStep(const datafacade::ContiguousInternalMemoryDataFacade<Al
relaxOutgoingEdges<REVERSE_DIRECTION>(facade, node, target_weight, target_duration, query_heap);
}
}
std::vector<EdgeWeight>
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
@ -247,6 +244,168 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
// TODO: generalize with CH version
namespace mld
{
template <bool DIRECTION>
void relaxOutgoingEdges(const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
const NodeID node,
const EdgeWeight weight,
const EdgeWeight duration,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap)
{
const auto &partition = facade.GetMultiLevelPartition();
const auto &cells = facade.GetCellStorage();
const auto &node_data = query_heap.GetData(node);
const auto level =
std::max(node_data.level, partition.GetHighestDifferentLevel(node_data.parent, node));
if (level >= 1 && !node_data.from_clique_arc)
{
const auto &cell = cells.GetCell(level, partition.GetCell(level, node));
if (DIRECTION == FORWARD_DIRECTION)
{
// Shortcuts in forward direction
auto destination = cell.GetDestinationNodes().begin();
auto shortcut_durations = cell.GetOutDuration(node);
for (auto shortcut_weight : cell.GetOutWeight(node))
{
BOOST_ASSERT(destination != cell.GetDestinationNodes().end());
BOOST_ASSERT(!shortcut_durations.empty());
const NodeID to = *destination;
if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to)
{
const auto to_weight = weight + shortcut_weight;
const auto to_duration = duration + shortcut_durations.front();
if (!query_heap.WasInserted(to))
{
query_heap.Insert(to, to_weight, {node, true, level, to_duration});
}
else if (to_weight < query_heap.GetKey(to))
{
query_heap.GetData(to) = {node, true, level, to_duration};
query_heap.DecreaseKey(to, to_weight);
}
}
++destination;
shortcut_durations.advance_begin(1);
}
BOOST_ASSERT(shortcut_durations.empty());
}
else
{
// Shortcuts in backward direction
auto source = cell.GetSourceNodes().begin();
auto shortcut_durations = cell.GetInDuration(node);
for (auto shortcut_weight : cell.GetInWeight(node))
{
BOOST_ASSERT(source != cell.GetSourceNodes().end());
BOOST_ASSERT(!shortcut_durations.empty());
const NodeID to = *source;
if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to)
{
const auto to_weight = weight + shortcut_weight;
const auto to_duration = duration + shortcut_durations.front();
if (!query_heap.WasInserted(to))
{
query_heap.Insert(to, to_weight, {node, true, level, to_duration});
}
else if (to_weight < query_heap.GetKey(to))
{
query_heap.GetData(to) = {node, true, level, to_duration};
query_heap.DecreaseKey(to, to_weight);
}
}
++source;
shortcut_durations.advance_begin(1);
}
BOOST_ASSERT(shortcut_durations.empty());
}
}
for (const auto edge : facade.GetBorderEdgeRange(level, node))
{
const auto &data = facade.GetEdgeData(edge);
if (DIRECTION == FORWARD_DIRECTION ? data.forward : data.backward)
{
const NodeID to = facade.GetTarget(edge);
const EdgeWeight edge_weight = data.weight;
const EdgeWeight edge_duration = data.duration;
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
const EdgeWeight to_weight = weight + edge_weight;
const EdgeWeight to_duration = duration + edge_duration;
// New Node discovered -> Add to Heap + Node Info Storage
if (!query_heap.WasInserted(to))
{
query_heap.Insert(to, to_weight, {node, false, level, to_duration});
}
// Found a shorter Path -> Update weight
else if (to_weight < query_heap.GetKey(to))
{
// new parent
query_heap.GetData(to) = {node, false, level, to_duration};
query_heap.DecreaseKey(to, to_weight);
}
}
}
}
void forwardRoutingStep(const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
const unsigned row_idx,
const unsigned number_of_targets,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
const SearchSpaceWithBuckets &search_space_with_buckets,
std::vector<EdgeWeight> &weights_table,
std::vector<EdgeWeight> &durations_table)
{
const NodeID node = query_heap.DeleteMin();
const EdgeWeight source_weight = query_heap.GetKey(node);
const EdgeWeight source_duration = query_heap.GetData(node).duration;
// check if each encountered node has an entry
const auto bucket_iterator = search_space_with_buckets.find(node);
// iterate bucket if there exists one
if (bucket_iterator != search_space_with_buckets.end())
{
const std::vector<NodeBucket> &bucket_list = bucket_iterator->second;
for (const NodeBucket &current_bucket : bucket_list)
{
// get target id from bucket entry
const unsigned column_idx = current_bucket.target_id;
const EdgeWeight target_weight = current_bucket.weight;
const EdgeWeight target_duration = current_bucket.duration;
auto &current_weight = weights_table[row_idx * number_of_targets + column_idx];
auto &current_duration = durations_table[row_idx * number_of_targets + column_idx];
// check if new weight is better
const EdgeWeight new_weight = source_weight + target_weight;
if (new_weight >= 0 && new_weight < current_weight)
{
current_weight = new_weight;
current_duration = source_duration + target_duration;
}
}
}
relaxOutgoingEdges<FORWARD_DIRECTION>(facade, node, source_weight, source_duration, query_heap);
}
void backwardRoutingStep(const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
const unsigned column_idx,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
SearchSpaceWithBuckets &search_space_with_buckets)
{
const NodeID node = query_heap.DeleteMin();
const EdgeWeight target_weight = query_heap.GetKey(node);
const EdgeWeight target_duration = query_heap.GetData(node).duration;
// store settled nodes in search space bucket
search_space_with_buckets[node].emplace_back(column_idx, target_weight, target_duration);
relaxOutgoingEdges<REVERSE_DIRECTION>(facade, node, target_weight, target_duration, query_heap);
}
std::vector<EdgeWeight>
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
@ -263,6 +422,79 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
std::vector<EdgeWeight> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(facade.GetNumberOfNodes());
auto &query_heap = *(engine_working_data.many_to_many_heap);
SearchSpaceWithBuckets search_space_with_buckets;
unsigned column_idx = 0;
const auto search_target_phantom = [&](const PhantomNode &phantom) {
// clear heap and insert target nodes
query_heap.Clear();
insertTargetInHeap(query_heap, phantom);
// explore search space
while (!query_heap.Empty())
{
backwardRoutingStep(facade, column_idx, query_heap, search_space_with_buckets);
}
++column_idx;
};
// for each source do forward search
unsigned row_idx = 0;
const auto search_source_phantom = [&](const PhantomNode &phantom) {
// clear heap and insert source nodes
query_heap.Clear();
insertSourceInHeap(query_heap, phantom);
// explore search space
while (!query_heap.Empty())
{
forwardRoutingStep(facade,
row_idx,
number_of_targets,
query_heap,
search_space_with_buckets,
weights_table,
durations_table);
}
++row_idx;
};
if (target_indices.empty())
{
for (const auto &phantom : phantom_nodes)
{
search_target_phantom(phantom);
}
}
else
{
for (const auto index : target_indices)
{
const auto &phantom = phantom_nodes[index];
search_target_phantom(phantom);
}
}
if (source_indices.empty())
{
for (const auto &phantom : phantom_nodes)
{
search_source_phantom(phantom);
}
}
else
{
for (const auto index : source_indices)
{
const auto &phantom = phantom_nodes[index];
search_source_phantom(phantom);
}
}
return durations_table;
}

View File

@ -23,40 +23,6 @@ bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &ta
target_phantom.GetReverseWeightPlusOffset();
}
void insertSourceInHeap(SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node)
{
if (phantom_node.IsValidForwardSource())
{
heap.Insert(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()});
}
if (phantom_node.IsValidReverseSource())
{
heap.Insert(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()});
}
}
void insertTargetInHeap(SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node)
{
if (phantom_node.IsValidForwardTarget())
{
heap.Insert(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id, phantom_node.GetForwardDuration()});
}
if (phantom_node.IsValidReverseTarget())
{
heap.Insert(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id, phantom_node.GetReverseDuration()});
}
}
} // namespace routing_algorithms
} // namespace engine
} // namespace osrm

View File

@ -94,6 +94,7 @@ void SearchEngineData<CH>::InitializeOrClearManyToManyThreadLocalStorage(unsigne
using MLD = routing_algorithms::mld::Algorithm;
SearchEngineData<MLD>::SearchEngineHeapPtr SearchEngineData<MLD>::forward_heap_1;
SearchEngineData<MLD>::SearchEngineHeapPtr SearchEngineData<MLD>::reverse_heap_1;
SearchEngineData<MLD>::ManyToManyHeapPtr SearchEngineData<MLD>::many_to_many_heap;
void SearchEngineData<MLD>::InitializeOrClearFirstThreadLocalStorage(unsigned number_of_nodes)
{
@ -116,5 +117,16 @@ void SearchEngineData<MLD>::InitializeOrClearFirstThreadLocalStorage(unsigned nu
}
}
void SearchEngineData<MLD>::InitializeOrClearManyToManyThreadLocalStorage(unsigned number_of_nodes)
{
if (many_to_many_heap.get())
{
many_to_many_heap->Clear();
}
else
{
many_to_many_heap.reset(new ManyToManyQueryHeap(number_of_nodes));
}
}
}
}

View File

@ -25,6 +25,7 @@ auto makeGraph(const MultiLevelPartition &mlp, const std::vector<MockEdge> &mock
struct EdgeData
{
EdgeWeight weight;
EdgeDuration duration;
bool forward;
bool backward;
};
@ -34,8 +35,8 @@ auto makeGraph(const MultiLevelPartition &mlp, const std::vector<MockEdge> &mock
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, true, false});
edges.push_back(Edge{m.target, m.start, m.weight, false, true});
edges.push_back(Edge{m.start, m.target, m.weight, 2 * m.weight, true, false});
edges.push_back(Edge{m.target, m.start, m.weight, 2 * m.weight, false, true});
}
std::sort(edges.begin(), edges.end());
return partition::MultiLevelGraph<EdgeData, osrm::storage::Ownership::Container>(
@ -253,6 +254,12 @@ BOOST_AUTO_TEST_CASE(four_levels_test)
CHECK_EQUAL_RANGE(cell_2_1.GetInWeight(9), 0, INVALID_EDGE_WEIGHT);
CHECK_EQUAL_RANGE(cell_2_1.GetInWeight(12), INVALID_EDGE_WEIGHT, 10);
CHECK_EQUAL_RANGE(cell_2_1.GetOutDuration(9), 6, 0, INVALID_EDGE_WEIGHT);
CHECK_EQUAL_RANGE(cell_2_1.GetOutDuration(13), INVALID_EDGE_WEIGHT, INVALID_EDGE_WEIGHT, 20);
CHECK_EQUAL_RANGE(cell_2_1.GetInDuration(8), 6, INVALID_EDGE_WEIGHT);
CHECK_EQUAL_RANGE(cell_2_1.GetInDuration(9), 0, INVALID_EDGE_WEIGHT);
CHECK_EQUAL_RANGE(cell_2_1.GetInDuration(12), INVALID_EDGE_WEIGHT, 20);
CellStorage storage_rec(mlp, graph);
customizer.Customize(graph, storage_rec);