Add support for annotations=distances in MLD
This commit brings feature parity with CH for the `table` pluging.
This commit is contained in:
parent
1a1293608d
commit
2a15e6dec8
@ -1,4 +1,4 @@
|
|||||||
@matrix @testbot @ch
|
@matrix @testbot
|
||||||
Feature: Basic Distance Matrix
|
Feature: Basic Distance Matrix
|
||||||
# note that results of travel distance are in metres
|
# note that results of travel distance are in metres
|
||||||
|
|
||||||
@ -21,6 +21,7 @@ Feature: Basic Distance Matrix
|
|||||||
| a | 0 | 100+-1 |
|
| a | 0 | 100+-1 |
|
||||||
| b | 100+-1 | 0 |
|
| b | 100+-1 | 0 |
|
||||||
|
|
||||||
|
@ch
|
||||||
Scenario: Testbot - Travel distance matrix of minimal network with toll exclude
|
Scenario: Testbot - Travel distance matrix of minimal network with toll exclude
|
||||||
Given the query options
|
Given the query options
|
||||||
| exclude | toll |
|
| exclude | toll |
|
||||||
@ -45,6 +46,7 @@ Feature: Basic Distance Matrix
|
|||||||
| c | | | 0 | 100+-1 |
|
| c | | | 0 | 100+-1 |
|
||||||
| d | | | 100+-1 | 0 |
|
| d | | | 100+-1 | 0 |
|
||||||
|
|
||||||
|
@ch
|
||||||
Scenario: Testbot - Travel distance matrix of minimal network with motorway exclude
|
Scenario: Testbot - Travel distance matrix of minimal network with motorway exclude
|
||||||
Given the query options
|
Given the query options
|
||||||
| exclude | motorway |
|
| exclude | motorway |
|
||||||
@ -66,8 +68,8 @@ Feature: Basic Distance Matrix
|
|||||||
| | a | b | c | d |
|
| | a | b | c | d |
|
||||||
| a | 0 | 300+-2 | 100+-2 | 200+-2 |
|
| a | 0 | 300+-2 | 100+-2 | 200+-2 |
|
||||||
|
|
||||||
|
@ch
|
||||||
Scenario: Testbot - Travel distance matrix of minimal network disconnected motorway exclude
|
Scenario: Testbot - Travel distance matrix of minimal network disconnected motorway exclude
|
||||||
Given the query options
|
Given the query options
|
||||||
| exclude | motorway |
|
| exclude | motorway |
|
||||||
And the extract extra arguments "--small-component-size 4"
|
And the extract extra arguments "--small-component-size 4"
|
||||||
@ -88,7 +90,7 @@ Feature: Basic Distance Matrix
|
|||||||
| | a | b | e |
|
| | a | b | e |
|
||||||
| a | 0 | 50+-1 | |
|
| a | 0 | 50+-1 | |
|
||||||
|
|
||||||
|
@ch
|
||||||
Scenario: Testbot - Travel distance matrix of minimal network with motorway and toll excludes
|
Scenario: Testbot - Travel distance matrix of minimal network with motorway and toll excludes
|
||||||
Given the query options
|
Given the query options
|
||||||
| exclude | motorway,toll |
|
| exclude | motorway,toll |
|
||||||
@ -212,6 +214,13 @@ Feature: Basic Distance Matrix
|
|||||||
| be |
|
| be |
|
||||||
| cf |
|
| cf |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | distance |
|
||||||
|
| e | a | 200m +- 1 |
|
||||||
|
| e | b | 100m +- 1 |
|
||||||
|
| f | a | 300m +- 1 |
|
||||||
|
| f | b | 200m +- 1 |
|
||||||
|
|
||||||
When I request a travel distance matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b | e | f |
|
| | a | b | e | f |
|
||||||
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
|
||||||
@ -255,7 +264,6 @@ Feature: Basic Distance Matrix
|
|||||||
| e | 200+-1 | 100+-1 | 0 | 100+-1 |
|
| e | 200+-1 | 100+-1 | 0 | 100+-1 |
|
||||||
| f | 300+-1 | 200+-1 | 100+-1 | 0 |
|
| f | 300+-1 | 200+-1 | 100+-1 | 0 |
|
||||||
|
|
||||||
|
|
||||||
Scenario: Testbot - Travel distance 3x2 matrix
|
Scenario: Testbot - Travel distance 3x2 matrix
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
@ -445,10 +453,21 @@ Feature: Basic Distance Matrix
|
|||||||
| 7 | 300+-5 | 200+-5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 | 0 | 1100+-5 |
|
| 7 | 300+-5 | 200+-5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 | 0 | 1100+-5 |
|
||||||
| 8 | 400+-5 | 300+-5 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 | 100+-5 | 0 |
|
| 8 | 400+-5 | 300+-5 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 | 100+-5 | 0 |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | 1 |
|
||||||
|
| 1 | 0 |
|
||||||
|
| 2 | 100+-5 |
|
||||||
|
| 3 | 900+-5 |
|
||||||
|
| 4 | 1000+-5 |
|
||||||
|
| 5 | 600+-5 |
|
||||||
|
| 6 | 700+-5 |
|
||||||
|
| 7 | 300+-5 |
|
||||||
|
| 8 | 400+-5 |
|
||||||
|
|
||||||
Scenario: Testbot - Travel distance matrix with ties
|
Scenario: Testbot - Travel distance matrix with ties
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a b
|
a b
|
||||||
|
|
||||||
c d
|
c d
|
||||||
"""
|
"""
|
||||||
@ -466,21 +485,26 @@ Feature: Basic Distance Matrix
|
|||||||
|
|
||||||
When I route I should get
|
When I route I should get
|
||||||
| from | to | route | distance |
|
| from | to | route | distance |
|
||||||
| a | b | ab,ab | 300m +- 1 |
|
| a | b | ab,ab | 450m |
|
||||||
| a | c | ac,ac | 200m |
|
| a | c | ac,ac | 200m |
|
||||||
| a | d | ab,bd,bd | 500m +- 1 |
|
| a | d | ac,dc,dc | 500m +- 1 |
|
||||||
|
|
||||||
When I request a travel distance matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b | c | d |
|
| | a | b | c | d |
|
||||||
| a | 0 | 300+-2 | 200+-2 | 500+-2 |
|
| a | 0 | 450+-2 | 200+-2 | 500+-2 |
|
||||||
|
|
||||||
When I request a travel distance matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a |
|
| | a |
|
||||||
| a | 0 |
|
| a | 0 |
|
||||||
| b | 300+-2 |
|
| b | 450+-2 |
|
||||||
| c | 200+-2 |
|
| c | 200+-2 |
|
||||||
| d | 500+-2 |
|
| d | 500+-2 |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | c |
|
||||||
|
| a | 0 | 200+-2 |
|
||||||
|
| c | 200+-2 | 0 |
|
||||||
|
|
||||||
|
|
||||||
# Check rounding errors
|
# Check rounding errors
|
||||||
Scenario: Testbot - Long distances in tables
|
Scenario: Testbot - Long distances in tables
|
||||||
@ -492,8 +516,58 @@ Feature: Basic Distance Matrix
|
|||||||
|
|
||||||
And the ways
|
And the ways
|
||||||
| nodes |
|
| nodes |
|
||||||
| abcd |
|
| abcd |
|
||||||
|
|
||||||
When I request a travel distance matrix I should get
|
When I request a travel distance matrix I should get
|
||||||
| | a | b | c | d |
|
| | a | b | c | d |
|
||||||
| a | 0 | 1000+-3 | 2000+-3 | 3000+-3 |
|
| a | 0 | 1000+-3 | 2000+-3 | 3000+-3 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Testbot - OneToMany vs ManyToOne
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
c
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| ab | yes |
|
||||||
|
| ac | |
|
||||||
|
| bc | |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | b |
|
||||||
|
| b | 240.4 | 0 |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a |
|
||||||
|
| a | 0 |
|
||||||
|
| b | 240.4 |
|
||||||
|
|
||||||
|
Scenario: Testbot - Varying distances between nodes
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b c d
|
||||||
|
|
||||||
|
e
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
f
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| feabcd | yes |
|
||||||
|
| ec | |
|
||||||
|
| fd | |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | b | c | d | e | f |
|
||||||
|
| a | 0 | 100+-1 | 300+-1 | 650+-1 | 1930+-1 | 1533+-1 |
|
||||||
|
| b | 760+-1 | 0 | 200+-1 | 550+-1 | 1830+-1 | 1433+-1 |
|
||||||
|
| c | 560+-2 | 660+-2 | 0 | 350+-1 | 1630+-1 | 1233+-1 |
|
||||||
|
| d | 1480+-2 | 1580+-1 | 1780+-1 | 0 | 1280+-1 | 883+-1 |
|
||||||
|
| e | 200+-2 | 300+-2 | 500+-1 | 710+-1 | 0 | 1593+-1 |
|
||||||
|
| f | 597+-1 | 696+-1 | 896+-1 | 1108+-1 | 400+-3 | 0 |
|
||||||
|
@ -488,3 +488,25 @@ Feature: Basic Duration Matrix
|
|||||||
| b | 1 |
|
| b | 1 |
|
||||||
| c | 15 |
|
| c | 15 |
|
||||||
| d | 10 |
|
| d | 10 |
|
||||||
|
|
||||||
|
Scenario: Testbot - OneToMany vs ManyToOne
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
c
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | oneway |
|
||||||
|
| ab | yes |
|
||||||
|
| ac | |
|
||||||
|
| bc | |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b |
|
||||||
|
| b | 24.1 | 0 |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a |
|
||||||
|
| a | 0 |
|
||||||
|
| b | 24.1 |
|
||||||
|
@ -106,6 +106,40 @@ Feature: Multi level routing
|
|||||||
| l | 144.7 | 60 |
|
| l | 144.7 | 60 |
|
||||||
| o | 124.7 | 0 |
|
| o | 124.7 | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | f | l | o |
|
||||||
|
| a | 0+-2 | 2287+-2 | 1443+-2 | 1243+-2 |
|
||||||
|
| f | 2284+-2 | 0+-2 | 1241+-2 | 1443+-2 |
|
||||||
|
| l | 1443+-2 | 1244+-2 | 0+-2 | 600+-2 |
|
||||||
|
| o | 1243+-2 | 1444+-2 | 600+-2 | 0+-2 |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | f | l | o |
|
||||||
|
| a | 0 | 2287.2+-2 | 1443+-2 | 1243+-2 |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a |
|
||||||
|
| a | 0 |
|
||||||
|
| f | 2284.5+-2 |
|
||||||
|
| l | 1443.1 |
|
||||||
|
| o | 1243 |
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | f | l | o |
|
||||||
|
| a | 0 | 2287+-2 | 1443+-2 | 1243+-2 |
|
||||||
|
| o | 1243 | 1444+-2 | 600+-2 | 0+-2 |
|
||||||
|
|
||||||
|
|
||||||
|
When I request a travel distance matrix I should get
|
||||||
|
| | a | o |
|
||||||
|
| a | 0+-2 | 1243+-2 |
|
||||||
|
| f | 2284+-2 | 1443+-2 |
|
||||||
|
| l | 1443+-2 | 600+-2 |
|
||||||
|
| o | 1243+-2 | 0+-2 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Scenario: Testbot - Multi level routing: horizontal road
|
Scenario: Testbot - Multi level routing: horizontal road
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
|
@ -54,7 +54,7 @@ Feature: Traffic - speeds
|
|||||||
| a | d | ad,ad | 27 km/h | 1275.7,0 | 1 |
|
| a | d | ad,ad | 27 km/h | 1275.7,0 | 1 |
|
||||||
| d | c | dc,dc | 36 km/h | 956.8,0 | 0 |
|
| d | c | dc,dc | 36 km/h | 956.8,0 | 0 |
|
||||||
| g | b | fb,fb | 36 km/h | 164.7,0 | 0 |
|
| g | b | fb,fb | 36 km/h | 164.7,0 | 0 |
|
||||||
| a | g | ad,df,fb,fb | 30 km/h | 1275.7,487.5,304.7,0 | 1:0:0 |
|
| a | g | ad,df,fb,fb | 30 km/h | 1295.7,487.5,304.7,0 | 1:0:0 |
|
||||||
|
|
||||||
|
|
||||||
Scenario: Weighting based on speed file weights, ETA based on file durations
|
Scenario: Weighting based on speed file weights, ETA based on file durations
|
||||||
|
@ -15,24 +15,25 @@ namespace engine
|
|||||||
{
|
{
|
||||||
namespace routing_algorithms
|
namespace routing_algorithms
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct NodeBucket
|
struct NodeBucket
|
||||||
{
|
{
|
||||||
NodeID middle_node;
|
NodeID middle_node;
|
||||||
NodeID parent_node;
|
NodeID parent_node;
|
||||||
|
bool from_clique_arc;
|
||||||
unsigned column_index; // a column in the weight/duration matrix
|
unsigned column_index; // a column in the weight/duration matrix
|
||||||
EdgeWeight weight;
|
EdgeWeight weight;
|
||||||
EdgeDuration duration;
|
EdgeDuration duration;
|
||||||
|
|
||||||
NodeBucket(NodeID middle_node,
|
NodeBucket(NodeID middle_node,
|
||||||
NodeID parent_node,
|
NodeID parent_node,
|
||||||
|
bool from_clique_arc,
|
||||||
unsigned column_index,
|
unsigned column_index,
|
||||||
EdgeWeight weight,
|
EdgeWeight weight,
|
||||||
EdgeDuration duration)
|
EdgeDuration duration)
|
||||||
: middle_node(middle_node), parent_node(parent_node), column_index(column_index),
|
: middle_node(middle_node), parent_node(parent_node), from_clique_arc(from_clique_arc),
|
||||||
weight(weight), duration(duration)
|
column_index(column_index), weight(weight), duration(duration)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ inline bool checkParentCellRestriction(CellID, const PhantomNodes &) { return tr
|
|||||||
|
|
||||||
// Restricted search (Args is LevelID, CellID):
|
// Restricted search (Args is LevelID, CellID):
|
||||||
// * use the fixed level for queries
|
// * use the fixed level for queries
|
||||||
// * check if the node cell is the same as the specified parent onr
|
// * check if the node cell is the same as the specified parent
|
||||||
template <typename MultiLevelPartition>
|
template <typename MultiLevelPartition>
|
||||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &, NodeID, LevelID level, CellID)
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &, NodeID, LevelID level, CellID)
|
||||||
{
|
{
|
||||||
@ -65,6 +65,61 @@ inline bool checkParentCellRestriction(CellID cell, LevelID, CellID parent)
|
|||||||
{
|
{
|
||||||
return cell == parent;
|
return cell == parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unrestricted search with a single phantom node (Args is const PhantomNode &):
|
||||||
|
// * use partition.GetQueryLevel to find the node query level
|
||||||
|
// * allow to traverse all cells
|
||||||
|
template <typename MultiLevelPartition>
|
||||||
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||||
|
const NodeID node,
|
||||||
|
const PhantomNode &phantom_node)
|
||||||
|
{
|
||||||
|
auto highest_diffrent_level = [&partition, node](const SegmentID &phantom_node) {
|
||||||
|
if (phantom_node.enabled)
|
||||||
|
return partition.GetHighestDifferentLevel(phantom_node.id, node);
|
||||||
|
return INVALID_LEVEL_ID;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto node_level = std::min(highest_diffrent_level(phantom_node.forward_segment_id),
|
||||||
|
highest_diffrent_level(phantom_node.reverse_segment_id));
|
||||||
|
|
||||||
|
return node_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unrestricted search with a single phantom node and a vector of phantom nodes:
|
||||||
|
// * use partition.GetQueryLevel to find the node query level
|
||||||
|
// * allow to traverse all cells
|
||||||
|
template <typename MultiLevelPartition>
|
||||||
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||||
|
NodeID node,
|
||||||
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
|
const std::size_t phantom_index,
|
||||||
|
const std::vector<std::size_t> &phantom_indices)
|
||||||
|
{
|
||||||
|
auto min_level = [&partition, node](const PhantomNode &phantom_node) {
|
||||||
|
|
||||||
|
const auto &forward_segment = phantom_node.forward_segment_id;
|
||||||
|
const auto forward_level =
|
||||||
|
forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id)
|
||||||
|
: INVALID_LEVEL_ID;
|
||||||
|
|
||||||
|
const auto &reverse_segment = phantom_node.reverse_segment_id;
|
||||||
|
const auto reverse_level =
|
||||||
|
reverse_segment.enabled ? partition.GetHighestDifferentLevel(node, reverse_segment.id)
|
||||||
|
: INVALID_LEVEL_ID;
|
||||||
|
|
||||||
|
return std::min(forward_level, reverse_level);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get minimum level over all phantoms of the highest different level with respect to node
|
||||||
|
// This is equivalent to min_{∀ source, target} partition.GetQueryLevel(source, node, target)
|
||||||
|
auto result = min_level(phantom_nodes[phantom_index]);
|
||||||
|
for (const auto &index : phantom_indices)
|
||||||
|
{
|
||||||
|
result = std::min(result, min_level(phantom_nodes[index]));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Heaps only record for each node its predecessor ("parent") on the shortest path.
|
// Heaps only record for each node its predecessor ("parent") on the shortest path.
|
||||||
@ -74,6 +129,46 @@ inline bool checkParentCellRestriction(CellID cell, LevelID, CellID parent)
|
|||||||
using PackedEdge = std::tuple</*from*/ NodeID, /*to*/ NodeID, /*from_clique_arc*/ bool>;
|
using PackedEdge = std::tuple</*from*/ NodeID, /*to*/ NodeID, /*from_clique_arc*/ bool>;
|
||||||
using PackedPath = std::vector<PackedEdge>;
|
using PackedPath = std::vector<PackedEdge>;
|
||||||
|
|
||||||
|
template <bool DIRECTION, typename OutIter>
|
||||||
|
inline void retrievePackedPathFromSingleManyToManyHeap(
|
||||||
|
const SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap, const NodeID middle, OutIter out)
|
||||||
|
{
|
||||||
|
|
||||||
|
NodeID current = middle;
|
||||||
|
NodeID parent = heap.GetData(current).parent;
|
||||||
|
|
||||||
|
while (current != parent)
|
||||||
|
{
|
||||||
|
const auto &data = heap.GetData(current);
|
||||||
|
|
||||||
|
if (DIRECTION == FORWARD_DIRECTION)
|
||||||
|
{
|
||||||
|
*out = std::make_tuple(parent, current, data.from_clique_arc);
|
||||||
|
++out;
|
||||||
|
}
|
||||||
|
else if (DIRECTION == REVERSE_DIRECTION)
|
||||||
|
{
|
||||||
|
*out = std::make_tuple(current, parent, data.from_clique_arc);
|
||||||
|
++out;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = parent;
|
||||||
|
parent = heap.GetData(parent).parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool DIRECTION>
|
||||||
|
inline PackedPath retrievePackedPathFromSingleManyToManyHeap(
|
||||||
|
const SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap, const NodeID middle)
|
||||||
|
{
|
||||||
|
|
||||||
|
PackedPath packed_path;
|
||||||
|
retrievePackedPathFromSingleManyToManyHeap<DIRECTION>(
|
||||||
|
heap, middle, std::back_inserter(packed_path));
|
||||||
|
|
||||||
|
return packed_path;
|
||||||
|
}
|
||||||
|
|
||||||
template <bool DIRECTION, typename OutIter>
|
template <bool DIRECTION, typename OutIter>
|
||||||
inline void retrievePackedPathFromSingleHeap(const SearchEngineData<Algorithm>::QueryHeap &heap,
|
inline void retrievePackedPathFromSingleHeap(const SearchEngineData<Algorithm>::QueryHeap &heap,
|
||||||
const NodeID middle,
|
const NodeID middle,
|
||||||
@ -351,6 +446,21 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
// Get packed path as edges {from node ID, to node ID, from_clique_arc}
|
// Get packed path as edges {from node ID, to node ID, from_clique_arc}
|
||||||
auto packed_path = retrievePackedPathFromHeap(forward_heap, reverse_heap, middle);
|
auto packed_path = retrievePackedPathFromHeap(forward_heap, reverse_heap, middle);
|
||||||
|
|
||||||
|
// if (!packed_path.empty())
|
||||||
|
// {
|
||||||
|
// std::cout << "packed_path: ";
|
||||||
|
// for (auto edge : packed_path)
|
||||||
|
// {
|
||||||
|
// std::cout << std::get<0>(edge) << ",";
|
||||||
|
// }
|
||||||
|
// std::cout << std::get<1>(packed_path.back());
|
||||||
|
// std::cout << std::endl;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// std::cout << "no packed_path!" << std::endl;
|
||||||
|
// }
|
||||||
|
|
||||||
// Beware the edge case when start, middle, end are all the same.
|
// Beware the edge case when start, middle, end are all the same.
|
||||||
// In this case we return a single node, no edges. We also don't unpack.
|
// In this case we return a single node, no edges. We also don't unpack.
|
||||||
const NodeID source_node = !packed_path.empty() ? std::get<0>(packed_path.front()) : middle;
|
const NodeID source_node = !packed_path.empty() ? std::get<0>(packed_path.front()) : middle;
|
||||||
@ -410,7 +520,96 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
unpacked_edges.insert(unpacked_edges.end(), subpath_edges.begin(), subpath_edges.end());
|
unpacked_edges.insert(unpacked_edges.end(), subpath_edges.begin(), subpath_edges.end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// std::cout << "unpacked_nodes: ";
|
||||||
|
// for (auto node : unpacked_nodes)
|
||||||
|
// {
|
||||||
|
// std::cout << node << ", ";
|
||||||
|
// }
|
||||||
|
// std::cout << std::endl;
|
||||||
|
return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges));
|
||||||
|
}
|
||||||
|
|
||||||
|
// With (s, middle, t) we trace back the paths middle -> s and middle -> t.
|
||||||
|
// This gives us a packed path (node ids) from the base graph around s and t,
|
||||||
|
// and overlay node ids otherwise. We then have to unpack the overlay clique
|
||||||
|
// edges by recursively descending unpacking the path down to the base graph.
|
||||||
|
|
||||||
|
using UnpackedNodes = std::vector<NodeID>;
|
||||||
|
using UnpackedEdges = std::vector<EdgeID>;
|
||||||
|
using UnpackedPath = std::tuple<EdgeWeight, UnpackedNodes, UnpackedEdges>;
|
||||||
|
|
||||||
|
template <typename Algorithm, typename... Args>
|
||||||
|
UnpackedPath
|
||||||
|
unpackPathAndCalculateDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
|
const DataFacade<Algorithm> &facade,
|
||||||
|
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||||
|
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||||
|
const bool force_loop_forward,
|
||||||
|
const bool force_loop_reverse,
|
||||||
|
EdgeWeight weight_upper_bound,
|
||||||
|
PackedPath packed_path,
|
||||||
|
NodeID middle,
|
||||||
|
Args... args)
|
||||||
|
{
|
||||||
|
EdgeWeight weight = weight_upper_bound;
|
||||||
|
const auto &partition = facade.GetMultiLevelPartition();
|
||||||
|
const NodeID source_node = !packed_path.empty() ? std::get<0>(packed_path.front()) : middle;
|
||||||
|
|
||||||
|
// Unpack path
|
||||||
|
std::vector<NodeID> unpacked_nodes;
|
||||||
|
std::vector<EdgeID> unpacked_edges;
|
||||||
|
unpacked_nodes.reserve(packed_path.size());
|
||||||
|
unpacked_edges.reserve(packed_path.size());
|
||||||
|
|
||||||
|
unpacked_nodes.push_back(source_node);
|
||||||
|
|
||||||
|
for (auto const &packed_edge : packed_path)
|
||||||
|
{
|
||||||
|
NodeID source, target;
|
||||||
|
bool overlay_edge;
|
||||||
|
std::tie(source, target, overlay_edge) = packed_edge;
|
||||||
|
if (!overlay_edge)
|
||||||
|
{ // a base graph edge
|
||||||
|
unpacked_nodes.push_back(target);
|
||||||
|
unpacked_edges.push_back(facade.FindEdge(source, target));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // an overlay graph edge
|
||||||
|
LevelID level = getNodeQueryLevel(partition, source, args...);
|
||||||
|
CellID parent_cell_id = partition.GetCell(level, source);
|
||||||
|
BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target));
|
||||||
|
|
||||||
|
LevelID sublevel = level - 1;
|
||||||
|
|
||||||
|
// Here heaps can be reused, let's go deeper!
|
||||||
|
forward_heap.Clear();
|
||||||
|
reverse_heap.Clear();
|
||||||
|
forward_heap.Insert(source, 0, {source});
|
||||||
|
reverse_heap.Insert(target, 0, {target});
|
||||||
|
|
||||||
|
// TODO: when structured bindings will be allowed change to
|
||||||
|
// auto [subpath_weight, subpath_source, subpath_target, subpath] = ...
|
||||||
|
EdgeWeight subpath_weight;
|
||||||
|
std::vector<NodeID> subpath_nodes;
|
||||||
|
std::vector<EdgeID> subpath_edges;
|
||||||
|
std::tie(subpath_weight, subpath_nodes, subpath_edges) = search(engine_working_data,
|
||||||
|
facade,
|
||||||
|
forward_heap,
|
||||||
|
reverse_heap,
|
||||||
|
force_loop_forward,
|
||||||
|
force_loop_reverse,
|
||||||
|
weight_upper_bound,
|
||||||
|
sublevel,
|
||||||
|
parent_cell_id);
|
||||||
|
BOOST_ASSERT(!subpath_edges.empty());
|
||||||
|
BOOST_ASSERT(subpath_nodes.size() > 1);
|
||||||
|
BOOST_ASSERT(subpath_nodes.front() == source);
|
||||||
|
BOOST_ASSERT(subpath_nodes.back() == target);
|
||||||
|
unpacked_nodes.insert(
|
||||||
|
unpacked_nodes.end(), std::next(subpath_nodes.begin()), subpath_nodes.end());
|
||||||
|
unpacked_edges.insert(unpacked_edges.end(), subpath_edges.begin(), subpath_edges.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges));
|
return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,12 +226,14 @@ class QueryHeap
|
|||||||
Data &GetData(NodeID node)
|
Data &GetData(NodeID node)
|
||||||
{
|
{
|
||||||
const auto index = node_index.peek_index(node);
|
const auto index = node_index.peek_index(node);
|
||||||
|
BOOST_ASSERT((int)index >= 0 && (int)index < (int)inserted_nodes.size());
|
||||||
return inserted_nodes[index].data;
|
return inserted_nodes[index].data;
|
||||||
}
|
}
|
||||||
|
|
||||||
Data const &GetData(NodeID node) const
|
Data const &GetData(NodeID node) const
|
||||||
{
|
{
|
||||||
const auto index = node_index.peek_index(node);
|
const auto index = node_index.peek_index(node);
|
||||||
|
BOOST_ASSERT((int)index >= 0 && (int)index < (int)inserted_nodes.size());
|
||||||
return inserted_nodes[index].data;
|
return inserted_nodes[index].data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
-- Secondary road: 18km/h = 18000m/3600s = 100m/20s
|
-- Secondary road: 18km/h = 18000m/3600s = 100m/20s
|
||||||
-- Tertiary road: 12km/h = 12000m/3600s = 100m/30s
|
-- Tertiary road: 12km/h = 12000m/3600s = 100m/30s
|
||||||
|
|
||||||
api_version = 3
|
api_version = 4
|
||||||
|
|
||||||
function setup()
|
function setup()
|
||||||
return {
|
return {
|
||||||
@ -14,7 +14,7 @@ function setup()
|
|||||||
max_speed_for_map_matching = 30/3.6, --km -> m/s
|
max_speed_for_map_matching = 30/3.6, --km -> m/s
|
||||||
weight_name = 'duration',
|
weight_name = 'duration',
|
||||||
process_call_tagless_node = false,
|
process_call_tagless_node = false,
|
||||||
uturn_penalty = 20,
|
u_turn_penalty = 20,
|
||||||
traffic_light_penalty = 7, -- seconds
|
traffic_light_penalty = 7, -- seconds
|
||||||
use_turn_restrictions = true
|
use_turn_restrictions = true
|
||||||
},
|
},
|
||||||
@ -128,13 +128,15 @@ function process_way (profile, way, result)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function process_turn (profile, turn)
|
function process_turn (profile, turn)
|
||||||
if turn.direction_modifier == direction_modifier.uturn then
|
if turn.is_u_turn then
|
||||||
turn.duration = profile.properties.uturn_penalty
|
turn.duration = turn.duration + profile.properties.u_turn_penalty
|
||||||
turn.weight = profile.properties.uturn_penalty
|
turn.weight = turn.weight + profile.properties.u_turn_penalty
|
||||||
end
|
end
|
||||||
if turn.has_traffic_light then
|
if turn.has_traffic_light then
|
||||||
turn.duration = turn.duration + profile.properties.traffic_light_penalty
|
turn.duration = turn.duration + profile.properties.traffic_light_penalty
|
||||||
end
|
end
|
||||||
|
|
||||||
|
io.write("after penalty turn.duration: ", turn.duration, "turn.weight: ", turn.weight, "\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -85,14 +85,6 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
|||||||
bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance;
|
bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance;
|
||||||
bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
|
bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
|
||||||
|
|
||||||
if (request_distance && !algorithms.SupportsDistanceAnnotationType())
|
|
||||||
{
|
|
||||||
return Error("NotImplemented",
|
|
||||||
"The distance annotations calculation is not implemented for the chosen "
|
|
||||||
"search algorithm.",
|
|
||||||
result);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto result_tables_pair = algorithms.ManyToManySearch(
|
auto result_tables_pair = algorithms.ManyToManySearch(
|
||||||
snapped_phantoms, params.sources, params.destinations, request_distance, request_duration);
|
snapped_phantoms, params.sources, params.destinations, request_distance, request_duration);
|
||||||
|
|
||||||
|
@ -74,6 +74,15 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &e
|
|||||||
auto &reverse_heap = *engine_working_data.reverse_heap_1;
|
auto &reverse_heap = *engine_working_data.reverse_heap_1;
|
||||||
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
|
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
|
||||||
|
|
||||||
|
std::cout << "source_phantom.forward_segment_id.id: "
|
||||||
|
<< phantom_nodes.source_phantom.forward_segment_id.id
|
||||||
|
<< " source_phantom.reverse_segment_id.id: "
|
||||||
|
<< phantom_nodes.source_phantom.reverse_segment_id.id << std::endl;
|
||||||
|
std::cout << "target_phantom.forward_segment_id.id: "
|
||||||
|
<< phantom_nodes.target_phantom.forward_segment_id.id
|
||||||
|
<< " target_phantom.reverse_segment_id.id: "
|
||||||
|
<< phantom_nodes.target_phantom.reverse_segment_id.id << std::endl;
|
||||||
|
|
||||||
// TODO: when structured bindings will be allowed change to
|
// TODO: when structured bindings will be allowed change to
|
||||||
// auto [weight, source_node, target_node, unpacked_edges] = ...
|
// auto [weight, source_node, target_node, unpacked_edges] = ...
|
||||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||||
|
@ -148,10 +148,11 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
const auto target_weight = query_heap.GetKey(node);
|
const auto target_weight = query_heap.GetKey(node);
|
||||||
const auto target_duration = query_heap.GetData(node).duration;
|
const auto target_duration = query_heap.GetData(node).duration;
|
||||||
const auto parent = query_heap.GetData(node).parent;
|
const auto parent = query_heap.GetData(node).parent;
|
||||||
|
const bool INVALID_CLIQUE_ARC_TYPE = false;
|
||||||
|
|
||||||
// Store settled nodes in search space bucket
|
// Store settled nodes in search space bucket
|
||||||
search_space_with_buckets.emplace_back(
|
search_space_with_buckets.emplace_back(
|
||||||
node, parent, column_index, target_weight, target_duration);
|
node, parent, INVALID_CLIQUE_ARC_TYPE, column_index, target_weight, target_duration);
|
||||||
|
|
||||||
relaxOutgoingEdges<REVERSE_DIRECTION>(
|
relaxOutgoingEdges<REVERSE_DIRECTION>(
|
||||||
facade, node, target_weight, target_duration, query_heap, phantom_node);
|
facade, node, target_weight, target_duration, query_heap, phantom_node);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include "engine/routing_algorithms/many_to_many.hpp"
|
#include "engine/routing_algorithms/many_to_many.hpp"
|
||||||
#include "engine/routing_algorithms/routing_base.hpp"
|
#include "engine/routing_algorithms/routing_base_mld.hpp"
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
#include <boost/range/iterator_range_core.hpp>
|
#include <boost/range/iterator_range_core.hpp>
|
||||||
@ -19,22 +19,8 @@ namespace routing_algorithms
|
|||||||
namespace mld
|
namespace mld
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename MultiLevelPartition>
|
using PackedEdge = std::tuple</*from*/ NodeID, /*to*/ NodeID, /*from_clique_arc*/ bool>;
|
||||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
using PackedPath = std::vector<PackedEdge>;
|
||||||
const NodeID node,
|
|
||||||
const PhantomNode &phantom_node)
|
|
||||||
{
|
|
||||||
auto highest_diffrent_level = [&partition, node](const SegmentID &phantom_node) {
|
|
||||||
if (phantom_node.enabled)
|
|
||||||
return partition.GetHighestDifferentLevel(phantom_node.id, node);
|
|
||||||
return INVALID_LEVEL_ID;
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto node_level = std::min(highest_diffrent_level(phantom_node.forward_segment_id),
|
|
||||||
highest_diffrent_level(phantom_node.reverse_segment_id));
|
|
||||||
|
|
||||||
return node_level;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename MultiLevelPartition>
|
template <typename MultiLevelPartition>
|
||||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||||
@ -50,38 +36,6 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
|||||||
return node_level;
|
return node_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename MultiLevelPartition>
|
|
||||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
|
||||||
NodeID node,
|
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
|
||||||
const std::size_t phantom_index,
|
|
||||||
const std::vector<std::size_t> &phantom_indices)
|
|
||||||
{
|
|
||||||
auto min_level = [&partition, node](const PhantomNode &phantom_node) {
|
|
||||||
|
|
||||||
const auto &forward_segment = phantom_node.forward_segment_id;
|
|
||||||
const auto forward_level =
|
|
||||||
forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id)
|
|
||||||
: INVALID_LEVEL_ID;
|
|
||||||
|
|
||||||
const auto &reverse_segment = phantom_node.reverse_segment_id;
|
|
||||||
const auto reverse_level =
|
|
||||||
reverse_segment.enabled ? partition.GetHighestDifferentLevel(node, reverse_segment.id)
|
|
||||||
: INVALID_LEVEL_ID;
|
|
||||||
|
|
||||||
return std::min(forward_level, reverse_level);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get minimum level over all phantoms of the highest different level with respect to node
|
|
||||||
// This is equivalent to min_{∀ source, target} partition.GetQueryLevel(source, node, target)
|
|
||||||
auto result = min_level(phantom_nodes[phantom_index]);
|
|
||||||
for (const auto &index : phantom_indices)
|
|
||||||
{
|
|
||||||
result = std::min(result, min_level(phantom_nodes[index]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool DIRECTION, typename... Args>
|
template <bool DIRECTION, typename... Args>
|
||||||
void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
||||||
const NodeID node,
|
const NodeID node,
|
||||||
@ -125,8 +79,10 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
|||||||
{
|
{
|
||||||
query_heap.Insert(to, to_weight, {node, true, to_duration});
|
query_heap.Insert(to, to_weight, {node, true, to_duration});
|
||||||
}
|
}
|
||||||
else if (std::tie(to_weight, to_duration) <
|
else if (std::tie(to_weight, to_duration, node) <
|
||||||
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
|
std::tie(query_heap.GetKey(to),
|
||||||
|
query_heap.GetData(to).duration,
|
||||||
|
query_heap.GetData(to).parent))
|
||||||
{
|
{
|
||||||
query_heap.GetData(to) = {node, true, to_duration};
|
query_heap.GetData(to) = {node, true, to_duration};
|
||||||
query_heap.DecreaseKey(to, to_weight);
|
query_heap.DecreaseKey(to, to_weight);
|
||||||
@ -155,8 +111,10 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
|||||||
{
|
{
|
||||||
query_heap.Insert(to, to_weight, {node, true, to_duration});
|
query_heap.Insert(to, to_weight, {node, true, to_duration});
|
||||||
}
|
}
|
||||||
else if (std::tie(to_weight, to_duration) <
|
else if (std::tie(to_weight, to_duration, node) <
|
||||||
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
|
std::tie(query_heap.GetKey(to),
|
||||||
|
query_heap.GetData(to).duration,
|
||||||
|
query_heap.GetData(to).parent))
|
||||||
{
|
{
|
||||||
query_heap.GetData(to) = {node, true, to_duration};
|
query_heap.GetData(to) = {node, true, to_duration};
|
||||||
query_heap.DecreaseKey(to, to_weight);
|
query_heap.DecreaseKey(to, to_weight);
|
||||||
@ -198,8 +156,10 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
|
|||||||
query_heap.Insert(to, to_weight, {node, false, to_duration});
|
query_heap.Insert(to, to_weight, {node, false, to_duration});
|
||||||
}
|
}
|
||||||
// Found a shorter Path -> Update weight and set new parent
|
// Found a shorter Path -> Update weight and set new parent
|
||||||
else if (std::tie(to_weight, to_duration) <
|
else if (std::tie(to_weight, to_duration, node) <
|
||||||
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
|
std::tie(query_heap.GetKey(to),
|
||||||
|
query_heap.GetData(to).duration,
|
||||||
|
query_heap.GetData(to).parent))
|
||||||
{
|
{
|
||||||
query_heap.GetData(to) = {node, false, to_duration};
|
query_heap.GetData(to) = {node, false, to_duration};
|
||||||
query_heap.DecreaseKey(to, to_weight);
|
query_heap.DecreaseKey(to, to_weight);
|
||||||
@ -217,11 +177,13 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
const DataFacade<Algorithm> &facade,
|
const DataFacade<Algorithm> &facade,
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
std::size_t phantom_index,
|
std::size_t phantom_index,
|
||||||
const std::vector<std::size_t> &phantom_indices)
|
const std::vector<std::size_t> &phantom_indices,
|
||||||
|
const bool calculate_distance)
|
||||||
{
|
{
|
||||||
std::vector<EdgeWeight> weights(phantom_indices.size(), INVALID_EDGE_WEIGHT);
|
std::vector<EdgeWeight> weights(phantom_indices.size(), INVALID_EDGE_WEIGHT);
|
||||||
std::vector<EdgeDuration> durations(phantom_indices.size(), MAXIMAL_EDGE_DURATION);
|
std::vector<EdgeDuration> durations(phantom_indices.size(), MAXIMAL_EDGE_DURATION);
|
||||||
std::vector<EdgeDistance> distances(phantom_indices.size(), INVALID_EDGE_DISTANCE);
|
std::vector<EdgeDistance> distances_table;
|
||||||
|
std::vector<NodeID> middle_nodes_table(phantom_indices.size(), SPECIAL_NODEID);
|
||||||
|
|
||||||
// Collect destination (source) nodes into a map
|
// Collect destination (source) nodes into a map
|
||||||
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration>>
|
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration>>
|
||||||
@ -289,6 +251,7 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
{
|
{
|
||||||
weights[index] = path_weight;
|
weights[index] = path_weight;
|
||||||
durations[index] = path_duration;
|
durations[index] = path_duration;
|
||||||
|
middle_nodes_table[index] = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove node from destinations list
|
// Remove node from destinations list
|
||||||
@ -306,12 +269,15 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
// Update single node paths
|
// Update single node paths
|
||||||
update_values(node, initial_weight, initial_duration);
|
update_values(node, initial_weight, initial_duration);
|
||||||
|
|
||||||
|
query_heap.Insert(node, initial_weight, {node, initial_duration});
|
||||||
|
|
||||||
// Place adjacent nodes into heap
|
// Place adjacent nodes into heap
|
||||||
for (auto edge : facade.GetAdjacentEdgeRange(node))
|
for (auto edge : facade.GetAdjacentEdgeRange(node))
|
||||||
{
|
{
|
||||||
const auto &data = facade.GetEdgeData(edge);
|
const auto &data = facade.GetEdgeData(edge);
|
||||||
if ((DIRECTION == FORWARD_DIRECTION) ? facade.IsForwardEdge(edge)
|
if ((DIRECTION == FORWARD_DIRECTION ? facade.IsForwardEdge(edge)
|
||||||
: facade.IsBackwardEdge(edge))
|
: facade.IsBackwardEdge(edge)) &&
|
||||||
|
!query_heap.WasInserted(facade.GetTarget(edge)))
|
||||||
{
|
{
|
||||||
const auto turn_id = data.turn_id;
|
const auto turn_id = data.turn_id;
|
||||||
const auto node_id = DIRECTION == FORWARD_DIRECTION ? node : facade.GetTarget(edge);
|
const auto node_id = DIRECTION == FORWARD_DIRECTION ? node : facade.GetTarget(edge);
|
||||||
@ -330,28 +296,35 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
|
|
||||||
if (DIRECTION == FORWARD_DIRECTION)
|
if (DIRECTION == FORWARD_DIRECTION)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (phantom_node.IsValidForwardSource())
|
if (phantom_node.IsValidForwardSource())
|
||||||
|
{
|
||||||
insert_node(phantom_node.forward_segment_id.id,
|
insert_node(phantom_node.forward_segment_id.id,
|
||||||
-phantom_node.GetForwardWeightPlusOffset(),
|
-phantom_node.GetForwardWeightPlusOffset(),
|
||||||
-phantom_node.GetForwardDuration());
|
-phantom_node.GetForwardDuration());
|
||||||
|
}
|
||||||
|
|
||||||
if (phantom_node.IsValidReverseSource())
|
if (phantom_node.IsValidReverseSource())
|
||||||
|
{
|
||||||
insert_node(phantom_node.reverse_segment_id.id,
|
insert_node(phantom_node.reverse_segment_id.id,
|
||||||
-phantom_node.GetReverseWeightPlusOffset(),
|
-phantom_node.GetReverseWeightPlusOffset(),
|
||||||
-phantom_node.GetReverseDuration());
|
-phantom_node.GetReverseDuration());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (DIRECTION == REVERSE_DIRECTION)
|
else if (DIRECTION == REVERSE_DIRECTION)
|
||||||
{
|
{
|
||||||
if (phantom_node.IsValidForwardTarget())
|
if (phantom_node.IsValidForwardTarget())
|
||||||
|
{
|
||||||
insert_node(phantom_node.forward_segment_id.id,
|
insert_node(phantom_node.forward_segment_id.id,
|
||||||
phantom_node.GetForwardWeightPlusOffset(),
|
phantom_node.GetForwardWeightPlusOffset(),
|
||||||
phantom_node.GetForwardDuration());
|
phantom_node.GetForwardDuration());
|
||||||
|
}
|
||||||
|
|
||||||
if (phantom_node.IsValidReverseTarget())
|
if (phantom_node.IsValidReverseTarget())
|
||||||
|
{
|
||||||
insert_node(phantom_node.reverse_segment_id.id,
|
insert_node(phantom_node.reverse_segment_id.id,
|
||||||
phantom_node.GetReverseWeightPlusOffset(),
|
phantom_node.GetReverseWeightPlusOffset(),
|
||||||
phantom_node.GetReverseDuration());
|
phantom_node.GetReverseDuration());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,7 +349,127 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
phantom_indices);
|
phantom_indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_pair(durations, distances);
|
if (calculate_distance)
|
||||||
|
{
|
||||||
|
// Initialize unpacking heaps
|
||||||
|
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||||
|
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
|
||||||
|
|
||||||
|
distances_table.resize(phantom_indices.size(), INVALID_EDGE_DISTANCE);
|
||||||
|
|
||||||
|
for (unsigned location = 0; location < phantom_indices.size(); ++location)
|
||||||
|
{
|
||||||
|
// Get the "middle" node that is the last node of a path
|
||||||
|
const NodeID middle_node_id = middle_nodes_table[location];
|
||||||
|
if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the packed path from the heap
|
||||||
|
PackedPath packed_path = mld::retrievePackedPathFromSingleManyToManyHeap<DIRECTION>(
|
||||||
|
query_heap, middle_node_id);
|
||||||
|
|
||||||
|
// ... and reverse it to have packed edges in the correct order,
|
||||||
|
if (DIRECTION == FORWARD_DIRECTION)
|
||||||
|
{
|
||||||
|
std::reverse(packed_path.begin(), packed_path.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... unpack path
|
||||||
|
auto &forward_heap = *engine_working_data.forward_heap_1;
|
||||||
|
auto &reverse_heap = *engine_working_data.reverse_heap_1;
|
||||||
|
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||||
|
std::vector<NodeID> unpacked_nodes;
|
||||||
|
std::vector<EdgeID> unpacked_edges;
|
||||||
|
|
||||||
|
std::tie(weight, unpacked_nodes, unpacked_edges) =
|
||||||
|
unpackPathAndCalculateDistance(engine_working_data,
|
||||||
|
facade,
|
||||||
|
forward_heap,
|
||||||
|
reverse_heap,
|
||||||
|
DO_NOT_FORCE_LOOPS,
|
||||||
|
DO_NOT_FORCE_LOOPS,
|
||||||
|
INVALID_EDGE_WEIGHT,
|
||||||
|
packed_path,
|
||||||
|
middle_node_id,
|
||||||
|
phantom_nodes,
|
||||||
|
phantom_index,
|
||||||
|
phantom_indices);
|
||||||
|
|
||||||
|
// Accumulate the path length without the last node
|
||||||
|
auto annotation = 0.0;
|
||||||
|
|
||||||
|
BOOST_ASSERT(!unpacked_nodes.empty());
|
||||||
|
for (auto node = unpacked_nodes.begin(), last_node = std::prev(unpacked_nodes.end());
|
||||||
|
node != last_node;
|
||||||
|
++node)
|
||||||
|
{
|
||||||
|
annotation += computeEdgeDistance(facade, *node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... and add negative source and positive target offsets
|
||||||
|
// ⚠ for REVERSE_DIRECTION original source and target phantom nodes are swapped
|
||||||
|
// Get source and target phantom nodes
|
||||||
|
// * 1-to-N: source is a single index, target is the corresponding from the indices list
|
||||||
|
// * N-to-1: source is the corresponding from the indices list, target is a single index
|
||||||
|
auto source_phantom_index = phantom_index;
|
||||||
|
auto target_phantom_index = phantom_indices[location];
|
||||||
|
if (DIRECTION == REVERSE_DIRECTION)
|
||||||
|
{
|
||||||
|
std::swap(source_phantom_index, target_phantom_index);
|
||||||
|
}
|
||||||
|
const auto &source_phantom = phantom_nodes[source_phantom_index];
|
||||||
|
const auto &target_phantom = phantom_nodes[target_phantom_index];
|
||||||
|
const NodeID source_node = unpacked_nodes.front();
|
||||||
|
const NodeID target_node = unpacked_nodes.back();
|
||||||
|
|
||||||
|
EdgeDistance source_offset = 0., target_offset = 0.;
|
||||||
|
if (source_phantom.IsValidForwardSource() &&
|
||||||
|
source_phantom.forward_segment_id.id == source_node)
|
||||||
|
{
|
||||||
|
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||||
|
// to 3
|
||||||
|
// -->s <-- subtract offset to start at source
|
||||||
|
// ......... <-- want this distance as result
|
||||||
|
// entry 0---1---2---3--- <-- 3 is exit node
|
||||||
|
source_offset = source_phantom.GetForwardDistance();
|
||||||
|
}
|
||||||
|
else if (source_phantom.IsValidReverseSource() &&
|
||||||
|
source_phantom.reverse_segment_id.id == source_node)
|
||||||
|
{
|
||||||
|
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||||
|
// s<------- <-- subtract offset to start at source
|
||||||
|
// ... <-- want this distance
|
||||||
|
// entry 0---1---2---3 <-- 3 is exit node
|
||||||
|
source_offset = source_phantom.GetReverseDistance();
|
||||||
|
}
|
||||||
|
if (target_phantom.IsValidForwardTarget() &&
|
||||||
|
target_phantom.forward_segment_id.id == target_node)
|
||||||
|
{
|
||||||
|
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||||
|
// to 3
|
||||||
|
// ++>t <-- add offset to get to target
|
||||||
|
// ................ <-- want this distance as result
|
||||||
|
// entry 0---1---2---3--- <-- 3 is exit node
|
||||||
|
target_offset = target_phantom.GetForwardDistance();
|
||||||
|
}
|
||||||
|
else if (target_phantom.IsValidReverseTarget() &&
|
||||||
|
target_phantom.reverse_segment_id.id == target_node)
|
||||||
|
{
|
||||||
|
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||||
|
// to 3
|
||||||
|
// <++t <-- add offset to get from target
|
||||||
|
// ................ <-- want this distance as result
|
||||||
|
// entry 0---1---2---3--- <-- 3 is exit node
|
||||||
|
target_offset = target_phantom.GetReverseDistance();
|
||||||
|
}
|
||||||
|
|
||||||
|
distances_table[location] = -source_offset + annotation + target_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair(durations, distances_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -391,6 +484,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
const std::vector<NodeBucket> &search_space_with_buckets,
|
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||||
std::vector<EdgeWeight> &weights_table,
|
std::vector<EdgeWeight> &weights_table,
|
||||||
std::vector<EdgeDuration> &durations_table,
|
std::vector<EdgeDuration> &durations_table,
|
||||||
|
std::vector<NodeID> &middle_nodes_table,
|
||||||
const PhantomNode &phantom_node)
|
const PhantomNode &phantom_node)
|
||||||
{
|
{
|
||||||
const auto node = query_heap.DeleteMin();
|
const auto node = query_heap.DeleteMin();
|
||||||
@ -427,6 +521,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
{
|
{
|
||||||
current_weight = new_weight;
|
current_weight = new_weight;
|
||||||
current_duration = new_duration;
|
current_duration = new_duration;
|
||||||
|
middle_nodes_table[location] = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,10 +540,11 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
const auto target_weight = query_heap.GetKey(node);
|
const auto target_weight = query_heap.GetKey(node);
|
||||||
const auto target_duration = query_heap.GetData(node).duration;
|
const auto target_duration = query_heap.GetData(node).duration;
|
||||||
const auto parent = query_heap.GetData(node).parent;
|
const auto parent = query_heap.GetData(node).parent;
|
||||||
|
const auto from_clique_arc = query_heap.GetData(node).from_clique_arc;
|
||||||
|
|
||||||
// Store settled nodes in search space bucket
|
// Store settled nodes in search space bucket
|
||||||
search_space_with_buckets.emplace_back(
|
search_space_with_buckets.emplace_back(
|
||||||
node, parent, column_idx, target_weight, target_duration);
|
node, parent, from_clique_arc, column_idx, target_weight, target_duration);
|
||||||
|
|
||||||
const auto &partition = facade.GetMultiLevelPartition();
|
const auto &partition = facade.GetMultiLevelPartition();
|
||||||
const auto maximal_level = partition.GetNumberOfLevels() - 1;
|
const auto maximal_level = partition.GetNumberOfLevels() - 1;
|
||||||
@ -457,13 +553,226 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
|||||||
facade, node, target_weight, target_duration, query_heap, phantom_node, maximal_level);
|
facade, node, target_weight, target_duration, query_heap, phantom_node, maximal_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <bool DIRECTION>
|
||||||
|
void retrievePackedPathFromSearchSpace(NodeID middle_node_id,
|
||||||
|
const unsigned column_idx,
|
||||||
|
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||||
|
PackedPath &path)
|
||||||
|
{
|
||||||
|
auto bucket_list = std::equal_range(search_space_with_buckets.begin(),
|
||||||
|
search_space_with_buckets.end(),
|
||||||
|
middle_node_id,
|
||||||
|
NodeBucket::ColumnCompare(column_idx));
|
||||||
|
|
||||||
|
BOOST_ASSERT_MSG(std::distance(bucket_list.first, bucket_list.second) == 1,
|
||||||
|
"The pointers are not pointing to the same element.");
|
||||||
|
|
||||||
|
NodeID current_node_id = middle_node_id;
|
||||||
|
|
||||||
|
while (bucket_list.first->parent_node != current_node_id &&
|
||||||
|
bucket_list.first != search_space_with_buckets.end())
|
||||||
|
{
|
||||||
|
const auto parent_node_id = bucket_list.first->parent_node;
|
||||||
|
|
||||||
|
const auto from = DIRECTION == FORWARD_DIRECTION ? current_node_id : parent_node_id;
|
||||||
|
const auto to = DIRECTION == FORWARD_DIRECTION ? parent_node_id : current_node_id;
|
||||||
|
path.emplace_back(std::make_tuple(from, to, bucket_list.first->from_clique_arc));
|
||||||
|
|
||||||
|
current_node_id = parent_node_id;
|
||||||
|
bucket_list = std::equal_range(search_space_with_buckets.begin(),
|
||||||
|
search_space_with_buckets.end(),
|
||||||
|
current_node_id,
|
||||||
|
NodeBucket::ColumnCompare(column_idx));
|
||||||
|
|
||||||
|
BOOST_ASSERT_MSG(std::distance(bucket_list.first, bucket_list.second) == 1,
|
||||||
|
"The pointers are not pointing to the same element.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool DIRECTION>
|
||||||
|
void calculateDistances(typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||||
|
const DataFacade<mld::Algorithm> &facade,
|
||||||
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
|
const std::vector<std::size_t> &target_indices,
|
||||||
|
const unsigned row_idx,
|
||||||
|
const std::size_t source_index,
|
||||||
|
const unsigned number_of_sources,
|
||||||
|
const unsigned number_of_targets,
|
||||||
|
const std::vector<NodeBucket> &search_space_with_buckets,
|
||||||
|
std::vector<EdgeDistance> &distances_table,
|
||||||
|
const std::vector<NodeID> &middle_nodes_table,
|
||||||
|
SearchEngineData<mld::Algorithm> &engine_working_data)
|
||||||
|
{
|
||||||
|
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(),
|
||||||
|
facade.GetMaxBorderNodeID() + 1);
|
||||||
|
|
||||||
|
for (unsigned column_idx = 0; column_idx < number_of_targets; ++column_idx)
|
||||||
|
{
|
||||||
|
// Step 1: Get source and target phantom nodes that were used in the bucketed search
|
||||||
|
auto source_phantom_index = source_index;
|
||||||
|
auto target_phantom_index = target_indices[column_idx];
|
||||||
|
const auto &source_phantom = phantom_nodes[source_phantom_index];
|
||||||
|
const auto &target_phantom = phantom_nodes[target_phantom_index];
|
||||||
|
|
||||||
|
const auto location = DIRECTION == FORWARD_DIRECTION
|
||||||
|
? row_idx * number_of_targets + column_idx
|
||||||
|
: row_idx + column_idx * number_of_sources;
|
||||||
|
|
||||||
|
if (source_phantom_index == target_phantom_index)
|
||||||
|
{
|
||||||
|
distances_table[location] = 0.0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeID middle_node_id = middle_nodes_table[location];
|
||||||
|
|
||||||
|
if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways
|
||||||
|
{
|
||||||
|
distances_table[location] = INVALID_EDGE_DISTANCE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Find path from source to middle node
|
||||||
|
PackedPath packed_path =
|
||||||
|
mld::retrievePackedPathFromSingleManyToManyHeap<DIRECTION>(query_heap, middle_node_id);
|
||||||
|
|
||||||
|
if (DIRECTION == FORWARD_DIRECTION)
|
||||||
|
{
|
||||||
|
std::reverse(packed_path.begin(), packed_path.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &forward_heap = *engine_working_data.forward_heap_1;
|
||||||
|
auto &reverse_heap = *engine_working_data.reverse_heap_1;
|
||||||
|
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||||
|
std::vector<NodeID> unpacked_nodes_from_source;
|
||||||
|
std::vector<EdgeID> unpacked_edges;
|
||||||
|
std::tie(weight, unpacked_nodes_from_source, unpacked_edges) =
|
||||||
|
unpackPathAndCalculateDistance(engine_working_data,
|
||||||
|
facade,
|
||||||
|
forward_heap,
|
||||||
|
reverse_heap,
|
||||||
|
DO_NOT_FORCE_LOOPS,
|
||||||
|
DO_NOT_FORCE_LOOPS,
|
||||||
|
INVALID_EDGE_WEIGHT,
|
||||||
|
packed_path,
|
||||||
|
middle_node_id,
|
||||||
|
source_phantom);
|
||||||
|
|
||||||
|
// Step 3: Find path from middle to target node
|
||||||
|
packed_path.clear();
|
||||||
|
retrievePackedPathFromSearchSpace<DIRECTION>(
|
||||||
|
middle_node_id, column_idx, search_space_with_buckets, packed_path);
|
||||||
|
|
||||||
|
if (DIRECTION == REVERSE_DIRECTION)
|
||||||
|
{
|
||||||
|
std::reverse(packed_path.begin(), packed_path.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<NodeID> unpacked_nodes_to_target;
|
||||||
|
std::tie(weight, unpacked_nodes_to_target, unpacked_edges) =
|
||||||
|
unpackPathAndCalculateDistance(engine_working_data,
|
||||||
|
facade,
|
||||||
|
forward_heap,
|
||||||
|
reverse_heap,
|
||||||
|
DO_NOT_FORCE_LOOPS,
|
||||||
|
DO_NOT_FORCE_LOOPS,
|
||||||
|
INVALID_EDGE_WEIGHT,
|
||||||
|
packed_path,
|
||||||
|
middle_node_id,
|
||||||
|
target_phantom);
|
||||||
|
|
||||||
|
if (DIRECTION == REVERSE_DIRECTION)
|
||||||
|
{
|
||||||
|
std::swap(unpacked_nodes_to_target, unpacked_nodes_from_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Compute annotation value along the path nodes without the target node
|
||||||
|
auto annotation = 0.0;
|
||||||
|
|
||||||
|
for (auto node = unpacked_nodes_from_source.begin(),
|
||||||
|
last_node = std::prev(unpacked_nodes_from_source.end());
|
||||||
|
node != last_node;
|
||||||
|
++node)
|
||||||
|
{
|
||||||
|
annotation += computeEdgeDistance(facade, *node);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto node = unpacked_nodes_to_target.begin(),
|
||||||
|
last_node = std::prev(unpacked_nodes_to_target.end());
|
||||||
|
node != last_node;
|
||||||
|
++node)
|
||||||
|
{
|
||||||
|
annotation += computeEdgeDistance(facade, *node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5: Get phantom node offsets and compute the annotation value
|
||||||
|
EdgeDistance source_offset = 0., target_offset = 0.;
|
||||||
|
{
|
||||||
|
// ⚠ for REVERSE_DIRECTION original source and target phantom nodes are swapped
|
||||||
|
if (DIRECTION == REVERSE_DIRECTION)
|
||||||
|
{
|
||||||
|
std::swap(source_phantom_index, target_phantom_index);
|
||||||
|
}
|
||||||
|
const auto &source_phantom = phantom_nodes[source_phantom_index];
|
||||||
|
const auto &target_phantom = phantom_nodes[target_phantom_index];
|
||||||
|
|
||||||
|
NodeID source_node = unpacked_nodes_from_source.front();
|
||||||
|
NodeID target_node = unpacked_nodes_to_target.back();
|
||||||
|
|
||||||
|
if (source_phantom.IsValidForwardSource() &&
|
||||||
|
source_phantom.forward_segment_id.id == source_node)
|
||||||
|
{
|
||||||
|
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||||
|
// to 3
|
||||||
|
// -->s <-- subtract offset to start at source
|
||||||
|
// ......... <-- want this distance as result
|
||||||
|
// entry 0---1---2---3--- <-- 3 is exit node
|
||||||
|
source_offset = source_phantom.GetForwardDistance();
|
||||||
|
}
|
||||||
|
else if (source_phantom.IsValidReverseSource() &&
|
||||||
|
source_phantom.reverse_segment_id.id == source_node)
|
||||||
|
{
|
||||||
|
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
|
||||||
|
// s<------- <-- subtract offset to start at source
|
||||||
|
// ... <-- want this distance
|
||||||
|
// entry 0---1---2---3 <-- 3 is exit node
|
||||||
|
source_offset = source_phantom.GetReverseDistance();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_phantom.IsValidForwardTarget() &&
|
||||||
|
target_phantom.forward_segment_id.id == target_node)
|
||||||
|
{
|
||||||
|
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||||
|
// to 3
|
||||||
|
// ++>t <-- add offset to get to target
|
||||||
|
// ................ <-- want this distance as result
|
||||||
|
// entry 0---1---2---3--- <-- 3 is exit node
|
||||||
|
target_offset = target_phantom.GetForwardDistance();
|
||||||
|
}
|
||||||
|
else if (target_phantom.IsValidReverseTarget() &&
|
||||||
|
target_phantom.reverse_segment_id.id == target_node)
|
||||||
|
{
|
||||||
|
// ............ <-- calculateEGBAnnotation returns distance from 0
|
||||||
|
// to 3
|
||||||
|
// <++t <-- add offset to get from target
|
||||||
|
// ................ <-- want this distance as result
|
||||||
|
// entry 0---1---2---3--- <-- 3 is exit node
|
||||||
|
target_offset = target_phantom.GetReverseDistance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
distances_table[location] = -source_offset + annotation + target_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <bool DIRECTION>
|
template <bool DIRECTION>
|
||||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||||
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||||
const DataFacade<Algorithm> &facade,
|
const DataFacade<Algorithm> &facade,
|
||||||
const std::vector<PhantomNode> &phantom_nodes,
|
const std::vector<PhantomNode> &phantom_nodes,
|
||||||
const std::vector<std::size_t> &source_indices,
|
const std::vector<std::size_t> &source_indices,
|
||||||
const std::vector<std::size_t> &target_indices)
|
const std::vector<std::size_t> &target_indices,
|
||||||
|
const bool calculate_distance)
|
||||||
{
|
{
|
||||||
const auto number_of_sources = source_indices.size();
|
const auto number_of_sources = source_indices.size();
|
||||||
const auto number_of_targets = target_indices.size();
|
const auto number_of_targets = target_indices.size();
|
||||||
@ -471,7 +780,8 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
|
|
||||||
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
|
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
|
||||||
std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
|
std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
|
||||||
std::vector<EdgeDistance> distances_table(number_of_entries, MAXIMAL_EDGE_DURATION);
|
std::vector<EdgeDistance> distances_table;
|
||||||
|
std::vector<NodeID> middle_nodes_table(number_of_entries, SPECIAL_NODEID);
|
||||||
|
|
||||||
std::vector<NodeBucket> search_space_with_buckets;
|
std::vector<NodeBucket> search_space_with_buckets;
|
||||||
|
|
||||||
@ -479,22 +789,22 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
for (std::uint32_t column_idx = 0; column_idx < target_indices.size(); ++column_idx)
|
for (std::uint32_t column_idx = 0; column_idx < target_indices.size(); ++column_idx)
|
||||||
{
|
{
|
||||||
const auto index = target_indices[column_idx];
|
const auto index = target_indices[column_idx];
|
||||||
const auto &phantom = phantom_nodes[index];
|
const auto &target_phantom = phantom_nodes[index];
|
||||||
|
|
||||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||||
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
|
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
|
||||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||||
|
|
||||||
if (DIRECTION == FORWARD_DIRECTION)
|
if (DIRECTION == FORWARD_DIRECTION)
|
||||||
insertTargetInHeap(query_heap, phantom);
|
insertTargetInHeap(query_heap, target_phantom);
|
||||||
else
|
else
|
||||||
insertSourceInHeap(query_heap, phantom);
|
insertSourceInHeap(query_heap, target_phantom);
|
||||||
|
|
||||||
// explore search space
|
// explore search space
|
||||||
while (!query_heap.Empty())
|
while (!query_heap.Empty())
|
||||||
{
|
{
|
||||||
backwardRoutingStep<DIRECTION>(
|
backwardRoutingStep<DIRECTION>(
|
||||||
facade, column_idx, query_heap, search_space_with_buckets, phantom);
|
facade, column_idx, query_heap, search_space_with_buckets, target_phantom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,18 +814,19 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
// Find shortest paths from sources to all accessible nodes
|
// Find shortest paths from sources to all accessible nodes
|
||||||
for (std::uint32_t row_idx = 0; row_idx < source_indices.size(); ++row_idx)
|
for (std::uint32_t row_idx = 0; row_idx < source_indices.size(); ++row_idx)
|
||||||
{
|
{
|
||||||
const auto index = source_indices[row_idx];
|
const auto source_index = source_indices[row_idx];
|
||||||
const auto &phantom = phantom_nodes[index];
|
const auto &source_phantom = phantom_nodes[source_index];
|
||||||
|
|
||||||
// Clear heap and insert source nodes
|
// Clear heap and insert source nodes
|
||||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||||
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
|
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
|
||||||
|
|
||||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||||
|
|
||||||
if (DIRECTION == FORWARD_DIRECTION)
|
if (DIRECTION == FORWARD_DIRECTION)
|
||||||
insertSourceInHeap(query_heap, phantom);
|
insertSourceInHeap(query_heap, source_phantom);
|
||||||
else
|
else
|
||||||
insertTargetInHeap(query_heap, phantom);
|
insertTargetInHeap(query_heap, source_phantom);
|
||||||
|
|
||||||
// Explore search space
|
// Explore search space
|
||||||
while (!query_heap.Empty())
|
while (!query_heap.Empty())
|
||||||
@ -528,7 +839,25 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
|||||||
search_space_with_buckets,
|
search_space_with_buckets,
|
||||||
weights_table,
|
weights_table,
|
||||||
durations_table,
|
durations_table,
|
||||||
phantom);
|
middle_nodes_table,
|
||||||
|
source_phantom);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (calculate_distance)
|
||||||
|
{
|
||||||
|
distances_table.resize(number_of_entries, INVALID_EDGE_DISTANCE);
|
||||||
|
calculateDistances<DIRECTION>(query_heap,
|
||||||
|
facade,
|
||||||
|
phantom_nodes,
|
||||||
|
target_indices, // source_indices
|
||||||
|
row_idx,
|
||||||
|
source_index,
|
||||||
|
number_of_sources,
|
||||||
|
number_of_targets,
|
||||||
|
search_space_with_buckets,
|
||||||
|
distances_table,
|
||||||
|
middle_nodes_table,
|
||||||
|
engine_working_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,31 +888,45 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
|||||||
const bool calculate_distance,
|
const bool calculate_distance,
|
||||||
const bool calculate_duration)
|
const bool calculate_duration)
|
||||||
{
|
{
|
||||||
(void)calculate_distance; // flag stub to use for calculating distances in matrix in mld in the
|
|
||||||
// future
|
|
||||||
(void)calculate_duration; // flag stub to use for calculating distances in matrix in mld in the
|
(void)calculate_duration; // flag stub to use for calculating distances in matrix in mld in the
|
||||||
// future
|
// future
|
||||||
|
|
||||||
if (source_indices.size() == 1)
|
if (source_indices.size() == 1)
|
||||||
{ // TODO: check if target_indices.size() == 1 and do a bi-directional search
|
{ // TODO: check if target_indices.size() == 1 and do a bi-directional search
|
||||||
return mld::oneToManySearch<FORWARD_DIRECTION>(
|
return mld::oneToManySearch<FORWARD_DIRECTION>(engine_working_data,
|
||||||
engine_working_data, facade, phantom_nodes, source_indices.front(), target_indices);
|
facade,
|
||||||
|
phantom_nodes,
|
||||||
|
source_indices.front(),
|
||||||
|
target_indices,
|
||||||
|
calculate_distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target_indices.size() == 1)
|
if (target_indices.size() == 1)
|
||||||
{
|
{
|
||||||
return mld::oneToManySearch<REVERSE_DIRECTION>(
|
return mld::oneToManySearch<REVERSE_DIRECTION>(engine_working_data,
|
||||||
engine_working_data, facade, phantom_nodes, target_indices.front(), source_indices);
|
facade,
|
||||||
|
phantom_nodes,
|
||||||
|
target_indices.front(),
|
||||||
|
source_indices,
|
||||||
|
calculate_distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target_indices.size() < source_indices.size())
|
if (target_indices.size() < source_indices.size())
|
||||||
{
|
{
|
||||||
return mld::manyToManySearch<REVERSE_DIRECTION>(
|
return mld::manyToManySearch<REVERSE_DIRECTION>(engine_working_data,
|
||||||
engine_working_data, facade, phantom_nodes, target_indices, source_indices);
|
facade,
|
||||||
|
phantom_nodes,
|
||||||
|
target_indices,
|
||||||
|
source_indices,
|
||||||
|
calculate_distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mld::manyToManySearch<FORWARD_DIRECTION>(
|
return mld::manyToManySearch<FORWARD_DIRECTION>(engine_working_data,
|
||||||
engine_working_data, facade, phantom_nodes, source_indices, target_indices);
|
facade,
|
||||||
|
phantom_nodes,
|
||||||
|
source_indices,
|
||||||
|
target_indices,
|
||||||
|
calculate_distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
|
@ -225,8 +225,7 @@ tables.forEach(function(annotation) {
|
|||||||
annotations: [annotation.slice(0,-1)]
|
annotations: [annotation.slice(0,-1)]
|
||||||
};
|
};
|
||||||
osrm.table(options, function(err, response) {
|
osrm.table(options, function(err, response) {
|
||||||
if (annotation === 'durations') assert.equal(response[annotation].length, 2);
|
assert.equal(response[annotation].length, 2);
|
||||||
else assert.error(response, 'NotImplemented');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user