Make edge metrics strongly typed (#6421)
This change takes the existing typedefs for weight, duration and distance, and makes them proper types, using the existing Alias functionality. Primarily this is to prevent bugs where the metrics are switched, but it also adds additional documentation. For example, it now makes it clear (despite the naming of variables) that most of the trip algorithm is running on the duration metric. I've not made any changes to the casts performed between metrics and numeric types, they now just more explicit.
This commit is contained in:
@@ -43,14 +43,14 @@ void insertSourceInForwardHeap(Heap &forward_heap, const PhantomNode &source)
|
||||
if (source.IsValidForwardSource())
|
||||
{
|
||||
forward_heap.Insert(source.forward_segment_id.id,
|
||||
-source.GetForwardWeightPlusOffset(),
|
||||
EdgeWeight{0} - source.GetForwardWeightPlusOffset(),
|
||||
source.forward_segment_id.id);
|
||||
}
|
||||
|
||||
if (source.IsValidReverseSource())
|
||||
{
|
||||
forward_heap.Insert(source.reverse_segment_id.id,
|
||||
-source.GetReverseWeightPlusOffset(),
|
||||
EdgeWeight{0} - source.GetReverseWeightPlusOffset(),
|
||||
source.reverse_segment_id.id);
|
||||
}
|
||||
}
|
||||
@@ -127,18 +127,18 @@ void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNodeCandidates &
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
{
|
||||
heap.Insert(phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
EdgeWeight{0} - phantom_node.GetForwardWeightPlusOffset(),
|
||||
{phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance()});
|
||||
EdgeDuration{0} - phantom_node.GetForwardDuration(),
|
||||
EdgeDistance{0} - phantom_node.GetForwardDistance()});
|
||||
}
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
{
|
||||
heap.Insert(phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
EdgeWeight{0} - phantom_node.GetReverseWeightPlusOffset(),
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseDuration(),
|
||||
-phantom_node.GetReverseDistance()});
|
||||
EdgeDuration{0} - phantom_node.GetReverseDuration(),
|
||||
EdgeDistance{0} - phantom_node.GetReverseDistance()});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,25 +251,24 @@ void annotatePath(const FacadeT &facade,
|
||||
BOOST_ASSERT(start_index < end_index);
|
||||
for (std::size_t segment_idx = start_index; segment_idx < end_index; ++segment_idx)
|
||||
{
|
||||
unpacked_path.push_back(
|
||||
PathData{node_id,
|
||||
id_vector[segment_idx + 1],
|
||||
static_cast<EdgeWeight>(weight_vector[segment_idx]),
|
||||
0,
|
||||
static_cast<EdgeDuration>(duration_vector[segment_idx]),
|
||||
0,
|
||||
datasource_vector[segment_idx],
|
||||
boost::none});
|
||||
unpacked_path.push_back(PathData{node_id,
|
||||
id_vector[segment_idx + 1],
|
||||
alias_cast<EdgeWeight>(weight_vector[segment_idx]),
|
||||
{0},
|
||||
alias_cast<EdgeDuration>(duration_vector[segment_idx]),
|
||||
{0},
|
||||
datasource_vector[segment_idx],
|
||||
boost::none});
|
||||
}
|
||||
BOOST_ASSERT(!unpacked_path.empty());
|
||||
|
||||
const auto turn_duration = facade.GetDurationPenaltyForEdgeID(turn_id);
|
||||
const auto turn_weight = facade.GetWeightPenaltyForEdgeID(turn_id);
|
||||
|
||||
unpacked_path.back().duration_until_turn += turn_duration;
|
||||
unpacked_path.back().duration_of_turn = turn_duration;
|
||||
unpacked_path.back().weight_until_turn += turn_weight;
|
||||
unpacked_path.back().weight_of_turn = turn_weight;
|
||||
unpacked_path.back().duration_until_turn += alias_cast<EdgeDuration>(turn_duration);
|
||||
unpacked_path.back().duration_of_turn = alias_cast<EdgeDuration>(turn_duration);
|
||||
unpacked_path.back().weight_until_turn += alias_cast<EdgeWeight>(turn_weight);
|
||||
unpacked_path.back().weight_of_turn = alias_cast<EdgeWeight>(turn_weight);
|
||||
unpacked_path.back().turn_edge = turn_id;
|
||||
}
|
||||
|
||||
@@ -311,10 +310,10 @@ void annotatePath(const FacadeT &facade,
|
||||
unpacked_path.push_back(
|
||||
PathData{target_node_id,
|
||||
id_vector[start_index < end_index ? segment_idx + 1 : segment_idx - 1],
|
||||
static_cast<EdgeWeight>(weight_vector[segment_idx]),
|
||||
0,
|
||||
static_cast<EdgeDuration>(duration_vector[segment_idx]),
|
||||
0,
|
||||
alias_cast<EdgeWeight>(weight_vector[segment_idx]),
|
||||
{0},
|
||||
alias_cast<EdgeDuration>(duration_vector[segment_idx]),
|
||||
{0},
|
||||
datasource_vector[segment_idx],
|
||||
boost::none});
|
||||
}
|
||||
@@ -341,9 +340,9 @@ void annotatePath(const FacadeT &facade,
|
||||
// node to the first turn would be the same as from end to end of a segment,
|
||||
// which is obviously incorrect and not ideal...
|
||||
unpacked_path.front().weight_until_turn =
|
||||
std::max(unpacked_path.front().weight_until_turn - source_weight, 0);
|
||||
std::max(unpacked_path.front().weight_until_turn - source_weight, {0});
|
||||
unpacked_path.front().duration_until_turn =
|
||||
std::max(unpacked_path.front().duration_until_turn - source_duration, 0);
|
||||
std::max(unpacked_path.front().duration_until_turn - source_duration, {0});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,7 +409,7 @@ template <typename FacadeT> EdgeDistance computeEdgeDistance(const FacadeT &faca
|
||||
{
|
||||
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
||||
|
||||
EdgeDistance total_distance = 0.0;
|
||||
EdgeDistance total_distance = {0};
|
||||
|
||||
auto geometry_range = facade.GetUncompressedForwardGeometry(geometry_index.id);
|
||||
for (auto current = geometry_range.begin(); current < geometry_range.end() - 1; ++current)
|
||||
|
||||
@@ -34,7 +34,7 @@ bool stallAtNode(const DataFacade<Algorithm> &facade,
|
||||
{
|
||||
const NodeID to = facade.GetTarget(edge);
|
||||
const EdgeWeight edge_weight = data.weight;
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
BOOST_ASSERT_MSG(edge_weight > EdgeWeight{0}, "edge_weight invalid");
|
||||
const auto toHeapNode = query_heap.GetHeapNodeIfWasInserted(to);
|
||||
if (toHeapNode)
|
||||
{
|
||||
@@ -61,7 +61,7 @@ void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
|
||||
const NodeID to = facade.GetTarget(edge);
|
||||
const EdgeWeight edge_weight = data.weight;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
BOOST_ASSERT_MSG(edge_weight > EdgeWeight{0}, "edge_weight invalid");
|
||||
const EdgeWeight to_weight = heapNode.weight + edge_weight;
|
||||
|
||||
const auto toHeapNode = heap.GetHeapNodeIfWasInserted(to);
|
||||
@@ -135,7 +135,7 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
||||
force_loop(force_loop_reverse_nodes, heapNode) ||
|
||||
// in this case we are looking at a bi-directional way where the source
|
||||
// and target phantom are on the same edge based node
|
||||
new_weight < 0)
|
||||
new_weight < EdgeWeight{0})
|
||||
{
|
||||
// check whether there is a loop present at the node
|
||||
for (const auto edge : facade.GetAdjacentEdgeRange(heapNode.node))
|
||||
@@ -148,7 +148,7 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
||||
{
|
||||
const EdgeWeight edge_weight = data.weight;
|
||||
const EdgeWeight loop_weight = new_weight + edge_weight;
|
||||
if (loop_weight >= 0 && loop_weight < upper_bound)
|
||||
if (loop_weight >= EdgeWeight{0} && loop_weight < upper_bound)
|
||||
{
|
||||
middle_node_id = heapNode.node;
|
||||
upper_bound = loop_weight;
|
||||
@@ -159,7 +159,7 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(new_weight >= 0);
|
||||
BOOST_ASSERT(new_weight >= EdgeWeight{0});
|
||||
|
||||
middle_node_id = heapNode.node;
|
||||
upper_bound = new_weight;
|
||||
@@ -169,7 +169,7 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
||||
|
||||
// make sure we don't terminate too early if we initialize the weight
|
||||
// for the nodes in the forward heap with the forward/reverse offset
|
||||
BOOST_ASSERT(min_edge_offset <= 0);
|
||||
BOOST_ASSERT(min_edge_offset <= EdgeWeight{0});
|
||||
if (heapNode.weight + min_edge_offset > upper_bound)
|
||||
{
|
||||
forward_heap.DeleteAll();
|
||||
@@ -185,31 +185,6 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
||||
relaxOutgoingEdges<DIRECTION>(facade, heapNode, forward_heap);
|
||||
}
|
||||
|
||||
template <bool UseDuration>
|
||||
std::tuple<EdgeWeight, EdgeDistance> getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node)
|
||||
{
|
||||
EdgeWeight loop_weight = UseDuration ? MAXIMAL_EDGE_DURATION : INVALID_EDGE_WEIGHT;
|
||||
EdgeDistance loop_distance = MAXIMAL_EDGE_DISTANCE;
|
||||
for (auto edge : facade.GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const auto &data = facade.GetEdgeData(edge);
|
||||
if (data.forward)
|
||||
{
|
||||
const NodeID to = facade.GetTarget(edge);
|
||||
if (to == node)
|
||||
{
|
||||
const auto value = UseDuration ? data.duration : data.weight;
|
||||
if (value < loop_weight)
|
||||
{
|
||||
loop_weight = value;
|
||||
loop_distance = data.distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::make_tuple(loop_weight, loop_distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a sequence of connected `NodeID`s in the CH graph, performs a depth-first unpacking of
|
||||
* the shortcut
|
||||
@@ -301,7 +276,7 @@ EdgeDistance calculateEBGNodeAnnotations(const DataFacade<Algorithm> &facade,
|
||||
// Make sure we have at least something to unpack
|
||||
if (packed_path_begin == packed_path_end ||
|
||||
std::distance(packed_path_begin, packed_path_end) <= 1)
|
||||
return 0;
|
||||
return {0};
|
||||
|
||||
std::stack<std::tuple<NodeID, NodeID, bool>> recursion_stack;
|
||||
std::stack<EdgeDistance> distance_stack;
|
||||
@@ -383,7 +358,7 @@ EdgeDistance calculateEBGNodeAnnotations(const DataFacade<Algorithm> &facade,
|
||||
}
|
||||
}
|
||||
|
||||
EdgeDistance total_distance = 0;
|
||||
EdgeDistance total_distance = {0};
|
||||
while (!distance_stack.empty())
|
||||
{
|
||||
total_distance += distance_stack.top();
|
||||
@@ -505,8 +480,48 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
int duration_upper_bound = INVALID_EDGE_WEIGHT);
|
||||
EdgeWeight duration_upper_bound = INVALID_EDGE_WEIGHT);
|
||||
|
||||
template <typename EdgeMetric>
|
||||
std::tuple<EdgeMetric, EdgeDistance> getLoopMetric(const DataFacade<Algorithm> &facade, NodeID node)
|
||||
{
|
||||
EdgeMetric loop_metric;
|
||||
if constexpr (std::is_same<EdgeMetric, EdgeDuration>::value)
|
||||
{
|
||||
loop_metric = INVALID_EDGE_DURATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
loop_metric = INVALID_EDGE_WEIGHT;
|
||||
}
|
||||
EdgeDistance loop_distance = MAXIMAL_EDGE_DISTANCE;
|
||||
for (auto edge : facade.GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const auto &data = facade.GetEdgeData(edge);
|
||||
if (data.forward)
|
||||
{
|
||||
const NodeID to = facade.GetTarget(edge);
|
||||
if (to == node)
|
||||
{
|
||||
EdgeMetric value;
|
||||
if constexpr (std::is_same<EdgeMetric, EdgeDuration>::value)
|
||||
{
|
||||
value = to_alias<EdgeDuration>(data.duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = data.weight;
|
||||
}
|
||||
if (value < loop_metric)
|
||||
{
|
||||
loop_metric = value;
|
||||
loop_distance = data.distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::make_tuple(loop_metric, loop_distance);
|
||||
}
|
||||
} // namespace ch
|
||||
} // namespace routing_algorithms
|
||||
} // namespace engine
|
||||
|
||||
@@ -363,7 +363,8 @@ void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
|
||||
|
||||
// TODO: BOOST_ASSERT(edge_data.weight == node_weight + turn_penalty);
|
||||
|
||||
const EdgeWeight to_weight = heapNode.weight + node_weight + turn_penalty;
|
||||
const EdgeWeight to_weight =
|
||||
heapNode.weight + node_weight + alias_cast<EdgeWeight>(turn_penalty);
|
||||
|
||||
const auto toHeapNode = forward_heap.GetHeapNodeIfWasInserted(to);
|
||||
if (!toHeapNode)
|
||||
@@ -410,7 +411,7 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
||||
// MLD uses loops forcing only to prune single node paths in forward and/or
|
||||
// backward direction (there is no need to force loops in MLD but in CH)
|
||||
if (!force_loop(force_loop_forward_nodes, heapNode) &&
|
||||
!force_loop(force_loop_reverse_nodes, heapNode) && (path_weight >= 0) &&
|
||||
!force_loop(force_loop_reverse_nodes, heapNode) && (path_weight >= EdgeWeight{0}) &&
|
||||
(path_weight < path_upper_bound))
|
||||
{
|
||||
middle_node = heapNode.node;
|
||||
@@ -529,8 +530,8 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
// 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});
|
||||
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] = ...
|
||||
|
||||
@@ -292,7 +292,7 @@ shortestPathWithWaypointUTurns(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const std::vector<PhantomNodeCandidates> &waypoint_candidates)
|
||||
{
|
||||
|
||||
EdgeWeight total_weight = 0;
|
||||
EdgeWeight total_weight = {0};
|
||||
std::vector<NodeID> total_packed_path;
|
||||
std::vector<std::size_t> packed_leg_begin;
|
||||
|
||||
@@ -467,8 +467,8 @@ struct route_state
|
||||
route_state(const PhantomNodeCandidates &init_candidates)
|
||||
: current_leg(0), previous_leg_path_offset(0)
|
||||
{
|
||||
last.total_weight_to_forward.resize(init_candidates.size(), 0);
|
||||
last.total_weight_to_reverse.resize(init_candidates.size(), 0);
|
||||
last.total_weight_to_forward.resize(init_candidates.size(), {0});
|
||||
last.total_weight_to_reverse.resize(init_candidates.size(), {0});
|
||||
// Initialize routability from source validity.
|
||||
std::transform(
|
||||
init_candidates.begin(),
|
||||
|
||||
@@ -23,7 +23,7 @@ struct TurnData final
|
||||
const int in_angle;
|
||||
const int turn_angle;
|
||||
const EdgeWeight weight;
|
||||
const EdgeWeight duration;
|
||||
const EdgeDuration duration;
|
||||
const guidance::TurnInstruction turn_instruction;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user