Skip to content

Commit e033e0b

Browse files
authored
Fix table result when source and destination on same one-way segment (#5828)
Fixes #5788 Table queries where source and destination are phantom nodes on the same one-way segment can fail to find valid routes. This is due to a bug in the MLD table generation for the special case where the query can be simplified to a one-to-many search. If the destination is before the source on the one-way segment, it will fail to find a route. We fix this case by not marking the node as visited at the start, so that valid paths to this node can be found later in the search. We also remove redundant initialization for the source node as the same actions are performed by a search step.
1 parent c24f917 commit e033e0b

File tree

3 files changed

+152
-72
lines changed

3 files changed

+152
-72
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- CHANGED: default car weight was reduced to 2000 kg. [#5371](https://github.com/Project-OSRM/osrm-backend/pull/5371)
1515
- CHANGED: default car height was reduced to 2 meters. [#5389](https://github.com/Project-OSRM/osrm-backend/pull/5389)
1616
- FIXED: treat `bicycle=use_sidepath` as no access on the tagged way. [#5622](https://github.com/Project-OSRM/osrm-backend/pull/5622)
17+
- FIXED: fix table result when source and destination on same one-way segment. [#5828](https://github.com/Project-OSRM/osrm-backend/pull/5828)
1718
- FIXED: fix occasional segfault when swapping data with osrm-datastore and using `exclude=` [#5844](https://github.com/Project-OSRM/osrm-backend/pull/5844)
1819
- Misc:
1920
- CHANGED: Reduce memory usage for raster source handling. [#5572](https://github.com/Project-OSRM/osrm-backend/pull/5572)
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
@routing @testbot @oneway
2+
Feature: Handle multiple phantom nodes in one-way segment
3+
4+
# Check we handle routes where source and destination are
5+
# phantom nodes on the same one-way segment.
6+
# See: https://github.com/Project-OSRM/osrm-backend/issues/5788
7+
8+
Background:
9+
Given the profile "testbot"
10+
11+
Scenario: One-way segment with adjacent phantom nodes
12+
Given the node map
13+
"""
14+
d c
15+
16+
a12b
17+
"""
18+
19+
And the ways
20+
| nodes | oneway |
21+
| ab | yes |
22+
| bc | no |
23+
| cd | no |
24+
| da | no |
25+
26+
When I route I should get
27+
| from | to | route | time | distance |
28+
| 1 | 2 | ab,ab | 5s +-0.1 | 50m ~1% |
29+
| 1 | c | ab,bc,bc | 30s +-0.1 | 300m ~1% |
30+
| 2 | 1 | ab,bc,cd,da,ab | 65s +-0.1 | 650m ~1% |
31+
| 2 | c | ab,bc,bc | 25s +-0.1 | 250m ~1% |
32+
| c | 1 | cd,da,ab | 40s +-0.1 | 400m ~1% |
33+
| c | 2 | cd,da,ab | 45s +-0.1 | 450m ~1% |
34+
35+
When I request a travel time matrix I should get
36+
| | 1 | 2 | c |
37+
| 1 | 0 | 5 +-0.1 | 30 +-0.1 |
38+
| 2 | 65 +-0.1 | 0 | 25 +-0.1 |
39+
| c | 40 +-0.1 | 45 +-0.1 | 0 |
40+
41+
When I request a travel time matrix I should get
42+
| | 1 | 2 | c |
43+
| 1 | 0 | 5 +-0.1 | 30 +-0.1 |
44+
45+
When I request a travel time matrix I should get
46+
| | 1 | 2 | c |
47+
| 2 | 65 +-0.1 | 0 | 25 +-0.1 |
48+
49+
When I request a travel time matrix I should get
50+
| | 1 |
51+
| 1 | 0 |
52+
| 2 | 65 +-0.1 |
53+
| c | 40 +-0.1 |
54+
55+
When I request a travel time matrix I should get
56+
| | 2 |
57+
| 1 | 5 +-0.1 |
58+
| 2 | 0 |
59+
| c | 45 +-0.1 |
60+
61+
When I request a travel distance matrix I should get
62+
| | 1 | 2 | c |
63+
| 1 | 0 | 50 ~1% | 300 ~1% |
64+
| 2 | 650 ~1% | 0 | 250 ~1% |
65+
| c | 400 ~1% | 450 ~1% | 0 |
66+
67+
When I request a travel distance matrix I should get
68+
| | 1 | 2 | c |
69+
| 1 | 0 | 50 ~1% | 300 ~1% |
70+
71+
When I request a travel distance matrix I should get
72+
| | 1 | 2 | c |
73+
| 2 | 650 ~1% | 0 | 250 ~1% |
74+
75+
When I request a travel distance matrix I should get
76+
| | 1 |
77+
| 1 | 0 |
78+
| 2 | 650 ~1% |
79+
| c | 400 ~1% |
80+
81+
When I request a travel distance matrix I should get
82+
| | 2 |
83+
| 1 | 50 ~1% |
84+
| 2 | 0 |
85+
| c | 450 ~1% |

src/engine/routing_algorithms/many_to_many_mld.cpp

Lines changed: 66 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,59 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
3636
return node_level;
3737
}
3838

39+
template <bool DIRECTION>
40+
void relaxBorderEdges(const DataFacade<mld::Algorithm> &facade,
41+
const NodeID node,
42+
const EdgeWeight weight,
43+
const EdgeDuration duration,
44+
const EdgeDistance distance,
45+
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
46+
LevelID level)
47+
{
48+
for (const auto edge : facade.GetBorderEdgeRange(level, node))
49+
{
50+
const auto &data = facade.GetEdgeData(edge);
51+
if ((DIRECTION == FORWARD_DIRECTION) ? facade.IsForwardEdge(edge)
52+
: facade.IsBackwardEdge(edge))
53+
{
54+
const NodeID to = facade.GetTarget(edge);
55+
if (facade.ExcludeNode(to))
56+
{
57+
continue;
58+
}
59+
60+
const auto turn_id = data.turn_id;
61+
const auto node_id = DIRECTION == FORWARD_DIRECTION ? node : facade.GetTarget(edge);
62+
const auto node_weight = facade.GetNodeWeight(node_id);
63+
const auto node_duration = facade.GetNodeDuration(node_id);
64+
const auto node_distance = facade.GetNodeDistance(node_id);
65+
const auto turn_weight = node_weight + facade.GetWeightPenaltyForEdgeID(turn_id);
66+
const auto turn_duration = node_duration + facade.GetDurationPenaltyForEdgeID(turn_id);
67+
68+
BOOST_ASSERT_MSG(node_weight + turn_weight > 0, "edge weight is invalid");
69+
const auto to_weight = weight + turn_weight;
70+
const auto to_duration = duration + turn_duration;
71+
const auto to_distance = distance + node_distance;
72+
73+
// New Node discovered -> Add to Heap + Node Info Storage
74+
if (!query_heap.WasInserted(to))
75+
{
76+
query_heap.Insert(to, to_weight, {node, false, to_duration, to_distance});
77+
}
78+
// Found a shorter Path -> Update weight and set new parent
79+
else if (std::tie(to_weight, to_duration, to_distance, node) <
80+
std::tie(query_heap.GetKey(to),
81+
query_heap.GetData(to).duration,
82+
query_heap.GetData(to).distance,
83+
query_heap.GetData(to).parent))
84+
{
85+
query_heap.GetData(to) = {node, false, to_duration, to_distance};
86+
query_heap.DecreaseKey(to, to_weight);
87+
}
88+
}
89+
}
90+
}
91+
3992
template <bool DIRECTION, typename... Args>
4093
void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
4194
const NodeID node,
@@ -140,48 +193,7 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
140193
}
141194
}
142195

143-
for (const auto edge : facade.GetBorderEdgeRange(level, node))
144-
{
145-
const auto &data = facade.GetEdgeData(edge);
146-
if ((DIRECTION == FORWARD_DIRECTION) ? facade.IsForwardEdge(edge)
147-
: facade.IsBackwardEdge(edge))
148-
{
149-
const NodeID to = facade.GetTarget(edge);
150-
if (facade.ExcludeNode(to))
151-
{
152-
continue;
153-
}
154-
155-
const auto turn_id = data.turn_id;
156-
const auto node_id = DIRECTION == FORWARD_DIRECTION ? node : facade.GetTarget(edge);
157-
const auto node_weight = facade.GetNodeWeight(node_id);
158-
const auto node_duration = facade.GetNodeDuration(node_id);
159-
const auto node_distance = facade.GetNodeDistance(node_id);
160-
const auto turn_weight = node_weight + facade.GetWeightPenaltyForEdgeID(turn_id);
161-
const auto turn_duration = node_duration + facade.GetDurationPenaltyForEdgeID(turn_id);
162-
163-
BOOST_ASSERT_MSG(node_weight + turn_weight > 0, "edge weight is invalid");
164-
const auto to_weight = weight + turn_weight;
165-
const auto to_duration = duration + turn_duration;
166-
const auto to_distance = distance + node_distance;
167-
168-
// New Node discovered -> Add to Heap + Node Info Storage
169-
if (!query_heap.WasInserted(to))
170-
{
171-
query_heap.Insert(to, to_weight, {node, false, to_duration, to_distance});
172-
}
173-
// Found a shorter Path -> Update weight and set new parent
174-
else if (std::tie(to_weight, to_duration, to_distance, node) <
175-
std::tie(query_heap.GetKey(to),
176-
query_heap.GetData(to).duration,
177-
query_heap.GetData(to).distance,
178-
query_heap.GetData(to).parent))
179-
{
180-
query_heap.GetData(to) = {node, false, to_duration, to_distance};
181-
query_heap.DecreaseKey(to, to_weight);
182-
}
183-
}
184-
}
196+
relaxBorderEdges<DIRECTION>(facade, node, weight, duration, distance, query_heap, level);
185197
}
186198

187199
//
@@ -297,37 +309,19 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
297309
EdgeWeight initial_weight,
298310
EdgeDuration initial_duration,
299311
EdgeDistance initial_distance) {
300-
301-
// Update single node paths
302-
update_values(node, initial_weight, initial_duration, initial_distance);
303-
304-
query_heap.Insert(node, initial_weight, {node, initial_duration, initial_distance});
305-
306-
// Place adjacent nodes into heap
307-
for (auto edge : facade.GetAdjacentEdgeRange(node))
312+
if (target_nodes_index.count(node))
308313
{
309-
const auto &data = facade.GetEdgeData(edge);
310-
const auto to = facade.GetTarget(edge);
311-
312-
if (facade.ExcludeNode(to))
313-
{
314-
continue;
315-
}
316-
317-
if ((DIRECTION == FORWARD_DIRECTION ? facade.IsForwardEdge(edge)
318-
: facade.IsBackwardEdge(edge)) &&
319-
!query_heap.WasInserted(to))
320-
{
321-
const auto turn_id = data.turn_id;
322-
const auto node_id = DIRECTION == FORWARD_DIRECTION ? node : to;
323-
const auto edge_weight = initial_weight + facade.GetNodeWeight(node_id) +
324-
facade.GetWeightPenaltyForEdgeID(turn_id);
325-
const auto edge_duration = initial_duration + facade.GetNodeDuration(node_id) +
326-
facade.GetDurationPenaltyForEdgeID(turn_id);
327-
const auto edge_distance = initial_distance + facade.GetNodeDistance(node_id);
328-
329-
query_heap.Insert(to, edge_weight, {node, edge_duration, edge_distance});
330-
}
314+
// Source and target on the same edge node. If target is not reachable directly via
315+
// the node (e.g destination is before source on oneway segment) we want to allow
316+
// node to be visited later in the search along a reachable path.
317+
// Therefore, we manually run first step of search without marking node as visited.
318+
update_values(node, initial_weight, initial_duration, initial_distance);
319+
relaxBorderEdges<DIRECTION>(
320+
facade, node, initial_weight, initial_duration, initial_distance, query_heap, 0);
321+
}
322+
else
323+
{
324+
query_heap.Insert(node, initial_weight, {node, initial_duration, initial_distance});
331325
}
332326
};
333327

0 commit comments

Comments
 (0)