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:
@@ -90,7 +90,8 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
std::vector<api::TableAPI::TableCellRef> estimated_pairs;
|
||||
|
||||
// Scan table for null results - if any exist, replace with distance estimates
|
||||
if (params.fallback_speed != INVALID_FALLBACK_SPEED || params.scale_factor != 1)
|
||||
if (params.fallback_speed != from_alias<double>(INVALID_FALLBACK_SPEED) ||
|
||||
params.scale_factor != 1)
|
||||
{
|
||||
for (std::size_t row = 0; row < num_sources; row++)
|
||||
{
|
||||
@@ -98,7 +99,8 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
{
|
||||
const auto &table_index = row * num_destinations + column;
|
||||
BOOST_ASSERT(table_index < result_tables_pair.first.size());
|
||||
if (params.fallback_speed != INVALID_FALLBACK_SPEED && params.fallback_speed > 0 &&
|
||||
if (params.fallback_speed != from_alias<double>(INVALID_FALLBACK_SPEED) &&
|
||||
params.fallback_speed > 0 &&
|
||||
result_tables_pair.first[table_index] == MAXIMAL_EDGE_DURATION)
|
||||
{
|
||||
const auto &source =
|
||||
@@ -118,29 +120,32 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
candidatesSnappedLocation(destination));
|
||||
|
||||
result_tables_pair.first[table_index] =
|
||||
distance_estimate / (double)params.fallback_speed;
|
||||
to_alias<EdgeDuration>(distance_estimate / params.fallback_speed);
|
||||
if (!result_tables_pair.second.empty())
|
||||
{
|
||||
result_tables_pair.second[table_index] = distance_estimate;
|
||||
result_tables_pair.second[table_index] =
|
||||
to_alias<EdgeDistance>(distance_estimate);
|
||||
}
|
||||
|
||||
estimated_pairs.emplace_back(row, column);
|
||||
}
|
||||
if (params.scale_factor > 0 && params.scale_factor != 1 &&
|
||||
result_tables_pair.first[table_index] != MAXIMAL_EDGE_DURATION &&
|
||||
result_tables_pair.first[table_index] != 0)
|
||||
result_tables_pair.first[table_index] != EdgeDuration{0})
|
||||
{
|
||||
EdgeDuration diff =
|
||||
MAXIMAL_EDGE_DURATION / result_tables_pair.first[table_index];
|
||||
|
||||
if (params.scale_factor >= diff)
|
||||
if (params.scale_factor >= from_alias<double>(diff))
|
||||
{
|
||||
result_tables_pair.first[table_index] = MAXIMAL_EDGE_DURATION - 1;
|
||||
result_tables_pair.first[table_index] =
|
||||
MAXIMAL_EDGE_DURATION - EdgeDuration{1};
|
||||
}
|
||||
else
|
||||
{
|
||||
result_tables_pair.first[table_index] = std::lround(
|
||||
result_tables_pair.first[table_index] * params.scale_factor);
|
||||
result_tables_pair.first[table_index] = to_alias<EdgeDuration>(
|
||||
std::lround(from_alias<double>(result_tables_pair.first[table_index]) *
|
||||
params.scale_factor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-16
@@ -497,17 +497,17 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
||||
auto name = facade.GetNameForID(name_id);
|
||||
|
||||
// If this is a valid forward edge, go ahead and add it to the tile
|
||||
if (forward_duration != 0 && edge.forward_segment_id.enabled)
|
||||
if (forward_duration != SegmentDuration{0} && edge.forward_segment_id.enabled)
|
||||
{
|
||||
// Calculate the speed for this line
|
||||
std::uint32_t speed_kmh_idx =
|
||||
static_cast<std::uint32_t>(round(length / forward_duration * 10 * 3.6));
|
||||
std::uint32_t speed_kmh_idx = static_cast<std::uint32_t>(
|
||||
round(length / from_alias<double>(forward_duration) * 10 * 3.6));
|
||||
|
||||
// Rate values are in meters per weight-unit - and similar to speeds, we
|
||||
// present 1 decimal place of precision (these values are added as
|
||||
// double/10) lower down
|
||||
std::uint32_t forward_rate =
|
||||
static_cast<std::uint32_t>(round(length / forward_weight * 10.));
|
||||
std::uint32_t forward_rate = static_cast<std::uint32_t>(
|
||||
round(length / from_alias<double>(forward_weight) * 10.));
|
||||
|
||||
auto tile_line = coordinatesToTileLine(a, b, tile_bbox);
|
||||
if (!tile_line.empty())
|
||||
@@ -519,8 +519,8 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
||||
fbuilder.set_is_small(component_id.is_tiny);
|
||||
fbuilder.set_datasource(
|
||||
facade.GetDatasourceName(forward_datasource_idx).to_string());
|
||||
fbuilder.set_weight(forward_weight / 10.0);
|
||||
fbuilder.set_duration(forward_duration / 10.0);
|
||||
fbuilder.set_weight(from_alias<double>(forward_weight) / 10.0);
|
||||
fbuilder.set_duration(from_alias<double>(forward_duration) / 10.0);
|
||||
fbuilder.set_name(name);
|
||||
fbuilder.set_rate(forward_rate / 10.0);
|
||||
fbuilder.set_is_startpoint(is_startpoint);
|
||||
@@ -531,17 +531,17 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
||||
|
||||
// Repeat the above for the coordinates reversed and using the `reverse`
|
||||
// properties
|
||||
if (reverse_duration != 0 && edge.reverse_segment_id.enabled)
|
||||
if (reverse_duration != SegmentDuration{0} && edge.reverse_segment_id.enabled)
|
||||
{
|
||||
// Calculate the speed for this line
|
||||
std::uint32_t speed_kmh_idx =
|
||||
static_cast<std::uint32_t>(round(length / reverse_duration * 10 * 3.6));
|
||||
std::uint32_t speed_kmh_idx = static_cast<std::uint32_t>(
|
||||
round(length / from_alias<double>(reverse_duration) * 10 * 3.6));
|
||||
|
||||
// Rate values are in meters per weight-unit - and similar to speeds, we
|
||||
// present 1 decimal place of precision (these values are added as
|
||||
// double/10) lower down
|
||||
std::uint32_t reverse_rate =
|
||||
static_cast<std::uint32_t>(round(length / reverse_weight * 10.));
|
||||
std::uint32_t reverse_rate = static_cast<std::uint32_t>(
|
||||
round(length / from_alias<double>(reverse_weight) * 10.));
|
||||
|
||||
auto tile_line = coordinatesToTileLine(b, a, tile_bbox);
|
||||
if (!tile_line.empty())
|
||||
@@ -553,8 +553,8 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
||||
fbuilder.set_is_small(component_id.is_tiny);
|
||||
fbuilder.set_datasource(
|
||||
facade.GetDatasourceName(reverse_datasource_idx).to_string());
|
||||
fbuilder.set_weight(reverse_weight / 10.0);
|
||||
fbuilder.set_duration(reverse_duration / 10.0);
|
||||
fbuilder.set_weight(from_alias<double>(reverse_weight) / 10.0);
|
||||
fbuilder.set_duration(from_alias<double>(reverse_duration) / 10.0);
|
||||
fbuilder.set_name(name);
|
||||
fbuilder.set_rate(reverse_rate / 10.0);
|
||||
fbuilder.set_is_startpoint(is_startpoint);
|
||||
@@ -582,8 +582,8 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
||||
|
||||
fbuilder.set_bearing_in(turn_data.in_angle);
|
||||
fbuilder.set_turn_angle(turn_data.turn_angle);
|
||||
fbuilder.set_cost(turn_data.duration / 10.0);
|
||||
fbuilder.set_weight(turn_data.weight / 10.0);
|
||||
fbuilder.set_cost(from_alias<double>(turn_data.duration) / 10.0);
|
||||
fbuilder.set_weight(from_alias<double>(turn_data.weight) / 10.0);
|
||||
fbuilder.set_turn(turn_data.turn_instruction);
|
||||
|
||||
fbuilder.commit();
|
||||
|
||||
+12
-12
@@ -20,9 +20,9 @@ namespace engine
|
||||
namespace plugins
|
||||
{
|
||||
|
||||
bool IsStronglyConnectedComponent(const util::DistTableWrapper<EdgeWeight> &result_table)
|
||||
bool IsStronglyConnectedComponent(const util::DistTableWrapper<EdgeDuration> &result_table)
|
||||
{
|
||||
return std::find(std::begin(result_table), std::end(result_table), INVALID_EDGE_WEIGHT) ==
|
||||
return std::find(std::begin(result_table), std::end(result_table), INVALID_EDGE_DURATION) ==
|
||||
std::end(result_table);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ TripPlugin::ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
|
||||
|
||||
void ManipulateTableForFSE(const std::size_t source_id,
|
||||
const std::size_t destination_id,
|
||||
util::DistTableWrapper<EdgeWeight> &result_table)
|
||||
util::DistTableWrapper<EdgeDuration> &result_table)
|
||||
{
|
||||
// ****************** Change Table *************************
|
||||
// The following code manipulates the table and produces the new table for
|
||||
@@ -94,7 +94,7 @@ void ManipulateTableForFSE(const std::size_t source_id,
|
||||
{
|
||||
if (i == source_id)
|
||||
continue;
|
||||
result_table.SetValue(i, source_id, INVALID_EDGE_WEIGHT);
|
||||
result_table.SetValue(i, source_id, INVALID_EDGE_DURATION);
|
||||
}
|
||||
|
||||
// change parameters.destination row
|
||||
@@ -104,22 +104,22 @@ void ManipulateTableForFSE(const std::size_t source_id,
|
||||
{
|
||||
if (i == destination_id)
|
||||
continue;
|
||||
result_table.SetValue(destination_id, i, INVALID_EDGE_WEIGHT);
|
||||
result_table.SetValue(destination_id, i, INVALID_EDGE_DURATION);
|
||||
}
|
||||
|
||||
// set destination->source to zero so roundtrip treats source and
|
||||
// destination as one location
|
||||
result_table.SetValue(destination_id, source_id, 0);
|
||||
result_table.SetValue(destination_id, source_id, {0});
|
||||
|
||||
// set source->destination as very high number so algorithm is forced
|
||||
// to find another path to get to destination
|
||||
result_table.SetValue(source_id, destination_id, INVALID_EDGE_WEIGHT);
|
||||
result_table.SetValue(source_id, destination_id, INVALID_EDGE_DURATION);
|
||||
|
||||
//********* End of changes to table *************************************
|
||||
}
|
||||
|
||||
void ManipulateTableForNonRoundtripFS(const std::size_t source_id,
|
||||
util::DistTableWrapper<EdgeWeight> &result_table)
|
||||
util::DistTableWrapper<EdgeDuration> &result_table)
|
||||
{
|
||||
// We can use the round-trip calculation to simulate non-round-trip fixed start
|
||||
// by making all paths to the source location zero. Effectively finding an 'optimal'
|
||||
@@ -127,12 +127,12 @@ void ManipulateTableForNonRoundtripFS(const std::size_t source_id,
|
||||
// source.
|
||||
for (const auto i : util::irange<size_t>(0, result_table.GetNumberOfNodes()))
|
||||
{
|
||||
result_table.SetValue(i, source_id, 0);
|
||||
result_table.SetValue(i, source_id, {0});
|
||||
}
|
||||
}
|
||||
|
||||
void ManipulateTableForNonRoundtripFE(const std::size_t destination_id,
|
||||
util::DistTableWrapper<EdgeWeight> &result_table)
|
||||
util::DistTableWrapper<EdgeDuration> &result_table)
|
||||
{
|
||||
// We can use the round-trip calculation to simulate non-round-trip fixed end
|
||||
// by making all paths from the destination to other locations zero.
|
||||
@@ -140,7 +140,7 @@ void ManipulateTableForNonRoundtripFE(const std::size_t destination_id,
|
||||
// from the destination to any source.
|
||||
for (const auto i : util::irange<size_t>(0, result_table.GetNumberOfNodes()))
|
||||
{
|
||||
result_table.SetValue(destination_id, i, 0);
|
||||
result_table.SetValue(destination_id, i, {0});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ Status TripPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
BOOST_ASSERT(snapped_phantoms.size() == number_of_locations);
|
||||
|
||||
// compute the duration table of all phantom nodes
|
||||
auto result_duration_table = util::DistTableWrapper<EdgeWeight>(
|
||||
auto result_duration_table = util::DistTableWrapper<EdgeDuration>(
|
||||
algorithms.ManyToManySearch(snapped_phantoms, {}, {}, /*requestDistance*/ false).first,
|
||||
number_of_locations);
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ struct RankedCandidateNode
|
||||
|
||||
bool operator<(const RankedCandidateNode &other) const
|
||||
{
|
||||
return (2 * weight + sharing) < (2 * other.weight + other.sharing);
|
||||
return (EdgeWeight{2} * weight + sharing) < (EdgeWeight{2} * other.weight + other.sharing);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -66,8 +66,8 @@ void alternativeRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
// toHeapNode is the same
|
||||
const auto heapNode = forward_heap.DeleteMinGetHeapNode();
|
||||
|
||||
const auto scaled_weight =
|
||||
static_cast<EdgeWeight>((heapNode.weight + min_edge_offset) / (1. + VIAPATH_EPSILON));
|
||||
const auto scaled_weight = to_alias<EdgeWeight>(
|
||||
from_alias<double>(heapNode.weight + min_edge_offset) / (1. + VIAPATH_EPSILON));
|
||||
if ((INVALID_EDGE_WEIGHT != *upper_bound_to_shortest_path_weight) &&
|
||||
(scaled_weight > *upper_bound_to_shortest_path_weight))
|
||||
{
|
||||
@@ -84,7 +84,7 @@ void alternativeRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const EdgeWeight new_weight = reverseHeapNode->weight + heapNode.weight;
|
||||
if (new_weight < *upper_bound_to_shortest_path_weight)
|
||||
{
|
||||
if (new_weight >= 0)
|
||||
if (new_weight >= EdgeWeight{0})
|
||||
{
|
||||
*middle_node = heapNode.node;
|
||||
*upper_bound_to_shortest_path_weight = new_weight;
|
||||
@@ -92,7 +92,8 @@ void alternativeRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
else
|
||||
{
|
||||
// check whether there is a loop present at the node
|
||||
const auto loop_weight = std::get<0>(getLoopWeight<false>(facade, heapNode.node));
|
||||
const auto loop_weight =
|
||||
std::get<0>(getLoopMetric<EdgeWeight>(facade, heapNode.node));
|
||||
const EdgeWeight new_weight_with_loop = new_weight + loop_weight;
|
||||
if (loop_weight != INVALID_EDGE_WEIGHT &&
|
||||
new_weight_with_loop <= *upper_bound_to_shortest_path_weight)
|
||||
@@ -112,7 +113,7 @@ void alternativeRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const NodeID to = facade.GetTarget(edge);
|
||||
const EdgeWeight edge_weight = data.weight;
|
||||
|
||||
BOOST_ASSERT(edge_weight > 0);
|
||||
BOOST_ASSERT(edge_weight > EdgeWeight{0});
|
||||
const EdgeWeight to_weight = heapNode.weight + edge_weight;
|
||||
|
||||
const auto toHeapNode = forward_heap.GetHeapNodeIfWasInserted(to);
|
||||
@@ -180,7 +181,7 @@ void computeWeightAndSharingOfViaPath(SearchEngineData<Algorithm> &engine_workin
|
||||
|
||||
NodeID s_v_middle = SPECIAL_NODEID;
|
||||
EdgeWeight upper_bound_s_v_path_weight = INVALID_EDGE_WEIGHT;
|
||||
new_reverse_heap.Insert(via_node, 0, via_node);
|
||||
new_reverse_heap.Insert(via_node, {0}, via_node);
|
||||
// compute path <s,..,v> by reusing forward search from s
|
||||
while (!new_reverse_heap.Empty())
|
||||
{
|
||||
@@ -196,7 +197,7 @@ void computeWeightAndSharingOfViaPath(SearchEngineData<Algorithm> &engine_workin
|
||||
// compute path <v,..,t> by reusing backward search from node t
|
||||
NodeID v_t_middle = SPECIAL_NODEID;
|
||||
EdgeWeight upper_bound_of_v_t_path_weight = INVALID_EDGE_WEIGHT;
|
||||
new_forward_heap.Insert(via_node, 0, via_node);
|
||||
new_forward_heap.Insert(via_node, {0}, via_node);
|
||||
while (!new_forward_heap.Empty())
|
||||
{
|
||||
routingStep<FORWARD_DIRECTION>(facade,
|
||||
@@ -342,7 +343,7 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
||||
*s_v_middle = SPECIAL_NODEID;
|
||||
EdgeWeight upper_bound_s_v_path_weight = INVALID_EDGE_WEIGHT;
|
||||
// compute path <s,..,v> by reusing forward search from s
|
||||
new_reverse_heap.Insert(candidate.node, 0, candidate.node);
|
||||
new_reverse_heap.Insert(candidate.node, {0}, candidate.node);
|
||||
while (new_reverse_heap.Size() > 0)
|
||||
{
|
||||
routingStep<REVERSE_DIRECTION>(facade,
|
||||
@@ -363,7 +364,7 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
||||
// compute path <v,..,t> by reusing backward search from t
|
||||
*v_t_middle = SPECIAL_NODEID;
|
||||
EdgeWeight upper_bound_of_v_t_path_weight = INVALID_EDGE_WEIGHT;
|
||||
new_forward_heap.Insert(candidate.node, 0, candidate.node);
|
||||
new_forward_heap.Insert(candidate.node, {0}, candidate.node);
|
||||
while (new_forward_heap.Size() > 0)
|
||||
{
|
||||
routingStep<FORWARD_DIRECTION>(facade,
|
||||
@@ -400,8 +401,9 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const EdgeWeight T_threshold = static_cast<EdgeWeight>(VIAPATH_ALPHA * weight_of_shortest_path);
|
||||
EdgeWeight unpacked_until_weight = 0;
|
||||
const EdgeWeight T_threshold =
|
||||
to_alias<EdgeWeight>(VIAPATH_ALPHA * from_alias<double>(weight_of_shortest_path));
|
||||
EdgeWeight unpacked_until_weight = {0};
|
||||
|
||||
std::stack<SearchSpaceEdge> unpack_stack;
|
||||
// Traverse path s-->v
|
||||
@@ -463,7 +465,7 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
||||
}
|
||||
|
||||
EdgeWeight t_test_path_weight = unpacked_until_weight;
|
||||
unpacked_until_weight = 0;
|
||||
unpacked_until_weight = {0};
|
||||
// Traverse path s-->v
|
||||
BOOST_ASSERT(!packed_v_t_path.empty());
|
||||
for (unsigned i = 0, packed_path_length = static_cast<unsigned>(packed_v_t_path.size() - 1);
|
||||
@@ -532,8 +534,8 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
||||
EdgeWeight upper_bound = INVALID_EDGE_WEIGHT;
|
||||
NodeID middle = SPECIAL_NODEID;
|
||||
|
||||
forward_heap3.Insert(s_P, 0, s_P);
|
||||
reverse_heap3.Insert(t_P, 0, t_P);
|
||||
forward_heap3.Insert(s_P, {0}, s_P);
|
||||
reverse_heap3.Insert(t_P, {0}, t_P);
|
||||
// exploration from s and t until deletemin/(1+epsilon) > _lengt_oO_sShortest_path
|
||||
while ((forward_heap3.Size() + reverse_heap3.Size()) > 0)
|
||||
{
|
||||
@@ -580,10 +582,11 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
||||
|
||||
insertNodesInHeaps(forward_heap1, reverse_heap1, endpoint_candidates);
|
||||
// get offset to account for offsets on phantom nodes on compressed edges
|
||||
EdgeWeight min_edge_offset = forward_heap1.Empty() ? 0 : std::min(0, forward_heap1.MinKey());
|
||||
BOOST_ASSERT(min_edge_offset <= 0);
|
||||
EdgeWeight min_edge_offset =
|
||||
forward_heap1.Empty() ? EdgeWeight{0} : std::min<EdgeWeight>({0}, forward_heap1.MinKey());
|
||||
BOOST_ASSERT(min_edge_offset <= EdgeWeight{0});
|
||||
// we only every insert negative offsets for nodes in the forward heap
|
||||
BOOST_ASSERT(reverse_heap1.Empty() || reverse_heap1.MinKey() >= 0);
|
||||
BOOST_ASSERT(reverse_heap1.Empty() || reverse_heap1.MinKey() >= EdgeWeight{0});
|
||||
|
||||
// search from s and t till new_min/(1+epsilon) > weight_of_shortest_path
|
||||
while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
|
||||
@@ -701,22 +704,27 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
||||
if (node == middle_node)
|
||||
continue;
|
||||
const auto fwd_iterator = approximated_forward_sharing.find(node);
|
||||
const EdgeWeight fwd_sharing =
|
||||
(fwd_iterator != approximated_forward_sharing.end()) ? fwd_iterator->second : 0;
|
||||
const EdgeWeight fwd_sharing = (fwd_iterator != approximated_forward_sharing.end())
|
||||
? fwd_iterator->second
|
||||
: EdgeWeight{0};
|
||||
const auto rev_iterator = approximated_reverse_sharing.find(node);
|
||||
const EdgeWeight rev_sharing =
|
||||
(rev_iterator != approximated_reverse_sharing.end()) ? rev_iterator->second : 0;
|
||||
const EdgeWeight rev_sharing = (rev_iterator != approximated_reverse_sharing.end())
|
||||
? rev_iterator->second
|
||||
: EdgeWeight{0};
|
||||
|
||||
const EdgeWeight approximated_sharing = fwd_sharing + rev_sharing;
|
||||
const EdgeWeight approximated_weight =
|
||||
forward_heap1.GetKey(node) + reverse_heap1.GetKey(node);
|
||||
const bool weight_passes =
|
||||
(approximated_weight < upper_bound_to_shortest_path_weight * (1 + VIAPATH_EPSILON));
|
||||
(from_alias<double>(approximated_weight) <
|
||||
from_alias<double>(upper_bound_to_shortest_path_weight) * (1 + VIAPATH_EPSILON));
|
||||
const bool sharing_passes =
|
||||
(approximated_sharing <= upper_bound_to_shortest_path_weight * VIAPATH_GAMMA);
|
||||
(from_alias<double>(approximated_sharing) <=
|
||||
from_alias<double>(upper_bound_to_shortest_path_weight) * VIAPATH_GAMMA);
|
||||
const bool stretch_passes =
|
||||
(approximated_weight - approximated_sharing) <
|
||||
((1. + VIAPATH_EPSILON) * (upper_bound_to_shortest_path_weight - approximated_sharing));
|
||||
from_alias<double>(approximated_weight - approximated_sharing) <
|
||||
((1. + VIAPATH_EPSILON) *
|
||||
from_alias<double>(upper_bound_to_shortest_path_weight - approximated_sharing));
|
||||
|
||||
if (weight_passes && sharing_passes && stretch_passes)
|
||||
{
|
||||
@@ -737,7 +745,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
||||
// prioritizing via nodes for deep inspection
|
||||
for (const NodeID node : preselected_node_list)
|
||||
{
|
||||
EdgeWeight weight_of_via_path = 0, sharing_of_via_path = 0;
|
||||
EdgeWeight weight_of_via_path = {0}, sharing_of_via_path = {0};
|
||||
computeWeightAndSharingOfViaPath(engine_working_data,
|
||||
facade,
|
||||
node,
|
||||
@@ -745,10 +753,11 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
||||
&sharing_of_via_path,
|
||||
packed_shortest_path,
|
||||
min_edge_offset);
|
||||
const EdgeWeight maximum_allowed_sharing =
|
||||
static_cast<EdgeWeight>(upper_bound_to_shortest_path_weight * VIAPATH_GAMMA);
|
||||
const EdgeWeight maximum_allowed_sharing = to_alias<EdgeWeight>(
|
||||
from_alias<double>(upper_bound_to_shortest_path_weight) * VIAPATH_GAMMA);
|
||||
if (sharing_of_via_path <= maximum_allowed_sharing &&
|
||||
weight_of_via_path <= upper_bound_to_shortest_path_weight * (1 + VIAPATH_EPSILON))
|
||||
from_alias<double>(weight_of_via_path) <=
|
||||
from_alias<double>(upper_bound_to_shortest_path_weight) * (1 + VIAPATH_EPSILON))
|
||||
{
|
||||
ranked_candidates_list.emplace_back(node, weight_of_via_path, sharing_of_via_path);
|
||||
}
|
||||
|
||||
@@ -85,9 +85,9 @@ struct WeightedViaNodeUnpackedPath
|
||||
// Scale the maximum allowed weight increase based on its magnitude:
|
||||
// - Shortest path 10 minutes, alternative 13 minutes => Factor of 0.30 ok
|
||||
// - Shortest path 10 hours, alternative 13 hours => Factor of 0.30 unreasonable
|
||||
double getLongerByFactorBasedOnDuration(const EdgeWeight duration)
|
||||
double getLongerByFactorBasedOnDuration(const EdgeDuration duration)
|
||||
{
|
||||
BOOST_ASSERT(duration != INVALID_EDGE_WEIGHT);
|
||||
BOOST_ASSERT(duration != INVALID_EDGE_DURATION);
|
||||
|
||||
// We only have generic weights here and no durations without unpacking.
|
||||
// We also have restricted way penalties which are huge and will screw scaling here.
|
||||
@@ -118,19 +118,20 @@ double getLongerByFactorBasedOnDuration(const EdgeWeight duration)
|
||||
const constexpr auto c = 2.45437877e+09;
|
||||
const constexpr auto d = -2.07944571e+03;
|
||||
|
||||
if (duration < EdgeWeight(5 * 60))
|
||||
if (duration < EdgeDuration{5 * 60})
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
else if (duration > EdgeWeight(10 * 60 * 60))
|
||||
else if (duration > EdgeDuration{10 * 60 * 60})
|
||||
{
|
||||
return 0.20;
|
||||
}
|
||||
|
||||
// Bigger than 10 minutes but smaller than 10 hours
|
||||
BOOST_ASSERT(duration >= 5 * 60 && duration <= 10 * 60 * 60);
|
||||
BOOST_ASSERT(duration >= EdgeDuration{5 * 60} && duration <= EdgeDuration{10 * 60 * 60});
|
||||
|
||||
return a + b / (duration - d) + c / std::pow(duration - d, 3);
|
||||
return a + b / (from_alias<double>(duration) - d) +
|
||||
c / std::pow(from_alias<double>(duration) - d, 3);
|
||||
}
|
||||
|
||||
Parameters parametersFromRequest(const PhantomEndpointCandidates &endpoint_candidates)
|
||||
@@ -223,10 +224,11 @@ RandIt filterViaCandidatesByStretch(RandIt first,
|
||||
// Assumes weight roughly corresponds to duration-ish. If this is not the case e.g.
|
||||
// because users are setting weight to be distance in the profiles, then we might
|
||||
// either generate more candidates than we have to or not enough. But is okay.
|
||||
const auto stretch_weight_limit = (1. + parameters.kAtMostLongerBy) * weight;
|
||||
const auto stretch_weight_limit =
|
||||
(1. + parameters.kAtMostLongerBy) * from_alias<double>(weight);
|
||||
|
||||
const auto over_weight_limit = [=](const auto via) {
|
||||
return via.weight > stretch_weight_limit;
|
||||
return from_alias<double>(via.weight) > stretch_weight_limit;
|
||||
};
|
||||
|
||||
return std::remove_if(first, last, over_weight_limit);
|
||||
@@ -444,7 +446,8 @@ RandIt filterPackedPathsByLocalOptimality(const WeightedViaNodePackedPath &path,
|
||||
const auto detour_length = forward_heap.GetKey(via) - forward_heap.GetKey(a) +
|
||||
reverse_heap.GetKey(via) - reverse_heap.GetKey(b);
|
||||
|
||||
return plateaux_length < parameters.kAtLeastOptimalAroundViaBy * detour_length;
|
||||
return from_alias<double>(plateaux_length) <
|
||||
parameters.kAtLeastOptimalAroundViaBy * from_alias<double>(detour_length);
|
||||
};
|
||||
|
||||
return std::remove_if(first, last, is_not_locally_optimal);
|
||||
@@ -482,8 +485,8 @@ RandIt filterUnpackedPathsBySharing(RandIt first,
|
||||
return false;
|
||||
}
|
||||
|
||||
EdgeWeight total_duration = 0;
|
||||
const auto add_if_seen = [&](const EdgeWeight duration, const NodeID node) {
|
||||
EdgeDuration total_duration = {0};
|
||||
const auto add_if_seen = [&](const EdgeDuration duration, const NodeID node) {
|
||||
auto node_duration = facade.GetNodeDuration(node);
|
||||
total_duration += node_duration;
|
||||
if (nodes.count(node) > 0)
|
||||
@@ -496,7 +499,7 @@ RandIt filterUnpackedPathsBySharing(RandIt first,
|
||||
const auto shared_duration = std::accumulate(
|
||||
begin(unpacked.nodes), end(unpacked.nodes), EdgeDuration{0}, add_if_seen);
|
||||
|
||||
unpacked.sharing = shared_duration / static_cast<double>(total_duration);
|
||||
unpacked.sharing = from_alias<double>(shared_duration) / from_alias<double>(total_duration);
|
||||
BOOST_ASSERT(unpacked.sharing >= 0.);
|
||||
BOOST_ASSERT(unpacked.sharing <= 1.);
|
||||
|
||||
@@ -531,10 +534,11 @@ RandIt filterAnnotatedRoutesByStretch(RandIt first,
|
||||
BOOST_ASSERT(shortest_route.is_valid());
|
||||
|
||||
const auto shortest_route_duration = shortest_route.duration();
|
||||
const auto stretch_duration_limit = (1. + parameters.kAtMostLongerBy) * shortest_route_duration;
|
||||
const auto stretch_duration_limit =
|
||||
(1. + parameters.kAtMostLongerBy) * from_alias<double>(shortest_route_duration);
|
||||
|
||||
const auto over_duration_limit = [=](const auto &route) {
|
||||
return route.duration() > stretch_duration_limit;
|
||||
return from_alias<double>(route.duration()) > stretch_duration_limit;
|
||||
};
|
||||
|
||||
return std::remove_if(first, last, over_duration_limit);
|
||||
@@ -610,8 +614,8 @@ void unpackPackedPaths(InputIt first,
|
||||
// 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});
|
||||
|
||||
BOOST_ASSERT(!facade.ExcludeNode(source));
|
||||
BOOST_ASSERT(!facade.ExcludeNode(target));
|
||||
@@ -694,7 +698,8 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
||||
while (forward_heap.Size() + reverse_heap.Size() > 0)
|
||||
{
|
||||
if (shortest_path_weight != INVALID_EDGE_WEIGHT)
|
||||
overlap_weight = shortest_path_weight * parameters.kSearchSpaceOverlapFactor;
|
||||
overlap_weight = to_alias<EdgeWeight>(from_alias<double>(shortest_path_weight) *
|
||||
parameters.kSearchSpaceOverlapFactor);
|
||||
|
||||
// Termination criteria - when we have a shortest path this will guarantee for our overlap.
|
||||
const bool keep_going = forward_heap_min + reverse_heap_min < overlap_weight;
|
||||
@@ -820,8 +825,10 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
||||
NodeID shortest_path_via = shortest_path_via_it->node;
|
||||
EdgeWeight shortest_path_weight = shortest_path_via_it->weight;
|
||||
|
||||
const double duration_estimation = shortest_path_weight / facade.GetWeightMultiplier();
|
||||
parameters.kAtMostLongerBy = getLongerByFactorBasedOnDuration(duration_estimation);
|
||||
const double duration_estimation =
|
||||
from_alias<double>(shortest_path_weight) / facade.GetWeightMultiplier();
|
||||
parameters.kAtMostLongerBy =
|
||||
getLongerByFactorBasedOnDuration(to_alias<EdgeDuration>(duration_estimation));
|
||||
|
||||
// Filters via candidate nodes with heuristics
|
||||
|
||||
|
||||
@@ -24,16 +24,16 @@ inline bool addLoopWeight(const DataFacade<ch::Algorithm> &facade,
|
||||
EdgeDuration &duration,
|
||||
EdgeDistance &distance)
|
||||
{ // Special case for CH when contractor creates a loop edge node->node
|
||||
BOOST_ASSERT(weight < 0);
|
||||
BOOST_ASSERT(weight < EdgeWeight{0});
|
||||
|
||||
const auto loop_weight = ch::getLoopWeight<false>(facade, node);
|
||||
const auto loop_weight = ch::getLoopMetric<EdgeWeight>(facade, node);
|
||||
if (std::get<0>(loop_weight) != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
const auto new_weight_with_loop = weight + std::get<0>(loop_weight);
|
||||
if (new_weight_with_loop >= 0)
|
||||
if (new_weight_with_loop >= EdgeWeight{0})
|
||||
{
|
||||
weight = new_weight_with_loop;
|
||||
auto result = ch::getLoopWeight<true>(facade, node);
|
||||
auto result = ch::getLoopMetric<EdgeDuration>(facade, node);
|
||||
duration += std::get<0>(result);
|
||||
distance += std::get<1>(result);
|
||||
return true;
|
||||
@@ -67,9 +67,9 @@ void relaxOutgoingEdges(
|
||||
const auto edge_duration = data.duration;
|
||||
const auto edge_distance = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
BOOST_ASSERT_MSG(edge_weight > EdgeWeight{0}, "edge_weight invalid");
|
||||
const auto to_weight = heapNode.weight + edge_weight;
|
||||
const auto to_duration = heapNode.data.duration + edge_duration;
|
||||
const auto to_duration = heapNode.data.duration + to_alias<EdgeDuration>(edge_duration);
|
||||
const auto to_distance = heapNode.data.distance + edge_distance;
|
||||
|
||||
const auto toHeapNode = query_heap.GetHeapNodeIfWasInserted(to);
|
||||
@@ -120,7 +120,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
|
||||
auto ¤t_weight = weights_table[row_index * number_of_targets + column_index];
|
||||
|
||||
EdgeDistance nulldistance = 0;
|
||||
EdgeDistance nulldistance = {0};
|
||||
|
||||
auto ¤t_duration = durations_table[row_index * number_of_targets + column_index];
|
||||
auto ¤t_distance =
|
||||
@@ -132,7 +132,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
auto new_duration = heapNode.data.duration + target_duration;
|
||||
auto new_distance = heapNode.data.distance + target_distance;
|
||||
|
||||
if (new_weight < 0)
|
||||
if (new_weight < EdgeWeight{0})
|
||||
{
|
||||
if (addLoopWeight(facade, heapNode.node, new_weight, new_duration, new_distance))
|
||||
{
|
||||
|
||||
@@ -62,10 +62,13 @@ void relaxBorderEdges(const DataFacade<mld::Algorithm> &facade,
|
||||
const auto node_weight = facade.GetNodeWeight(node_id);
|
||||
const auto node_duration = facade.GetNodeDuration(node_id);
|
||||
const auto node_distance = facade.GetNodeDistance(node_id);
|
||||
const auto turn_weight = node_weight + facade.GetWeightPenaltyForEdgeID(turn_id);
|
||||
const auto turn_duration = node_duration + facade.GetDurationPenaltyForEdgeID(turn_id);
|
||||
const auto turn_weight =
|
||||
node_weight + alias_cast<EdgeWeight>(facade.GetWeightPenaltyForEdgeID(turn_id));
|
||||
const auto turn_duration =
|
||||
node_duration +
|
||||
alias_cast<EdgeDuration>(facade.GetDurationPenaltyForEdgeID(turn_id));
|
||||
|
||||
BOOST_ASSERT_MSG(node_weight + turn_weight > 0, "edge weight is invalid");
|
||||
BOOST_ASSERT_MSG(node_weight + turn_weight > EdgeWeight{0}, "edge weight is invalid");
|
||||
const auto to_weight = weight + turn_weight;
|
||||
const auto to_duration = duration + turn_duration;
|
||||
const auto to_distance = distance + node_distance;
|
||||
@@ -259,17 +262,17 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.forward_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance())});
|
||||
EdgeWeight{0} - phantom_node.GetForwardWeightPlusOffset(),
|
||||
EdgeDuration{0} - phantom_node.GetForwardDuration(),
|
||||
EdgeDistance{0} - phantom_node.GetForwardDistance())});
|
||||
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
-phantom_node.GetReverseDuration(),
|
||||
-phantom_node.GetReverseDistance())});
|
||||
EdgeWeight{0} - phantom_node.GetReverseWeightPlusOffset(),
|
||||
EdgeDuration{0} - phantom_node.GetReverseDuration(),
|
||||
EdgeDistance{0} - phantom_node.GetReverseDistance())});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,12 +295,12 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
std::tie(index, target_weight, target_duration, target_distance) = it->second;
|
||||
|
||||
const auto path_weight = weight + target_weight;
|
||||
if (path_weight >= 0)
|
||||
if (path_weight >= EdgeWeight{0})
|
||||
{
|
||||
const auto path_duration = duration + target_duration;
|
||||
const auto path_distance = distance + target_distance;
|
||||
|
||||
EdgeDistance nulldistance = 0;
|
||||
EdgeDistance nulldistance = {0};
|
||||
auto ¤t_distance =
|
||||
distances_table.empty() ? nulldistance : distances_table[index];
|
||||
|
||||
@@ -350,17 +353,17 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
{
|
||||
insert_node(phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance());
|
||||
EdgeWeight{0} - phantom_node.GetForwardWeightPlusOffset(),
|
||||
EdgeDuration{0} - phantom_node.GetForwardDuration(),
|
||||
EdgeDistance{0} - phantom_node.GetForwardDistance());
|
||||
}
|
||||
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
{
|
||||
insert_node(phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
-phantom_node.GetReverseDuration(),
|
||||
-phantom_node.GetReverseDistance());
|
||||
EdgeWeight{0} - phantom_node.GetReverseWeightPlusOffset(),
|
||||
EdgeDuration{0} - phantom_node.GetReverseDuration(),
|
||||
EdgeDistance{0} - phantom_node.GetReverseDistance());
|
||||
}
|
||||
}
|
||||
else if (DIRECTION == REVERSE_DIRECTION)
|
||||
@@ -444,7 +447,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
auto ¤t_weight = weights_table[location];
|
||||
auto ¤t_duration = durations_table[location];
|
||||
|
||||
EdgeDistance nulldistance = 0;
|
||||
EdgeDistance nulldistance = {0};
|
||||
auto ¤t_distance = distances_table.empty() ? nulldistance : distances_table[location];
|
||||
|
||||
// Check if new weight is better
|
||||
@@ -452,8 +455,9 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
auto new_duration = heapNode.data.duration + target_duration;
|
||||
auto new_distance = heapNode.data.distance + target_distance;
|
||||
|
||||
if (new_weight >= 0 && std::tie(new_weight, new_duration, new_distance) <
|
||||
std::tie(current_weight, current_duration, current_distance))
|
||||
if (new_weight >= EdgeWeight{0} &&
|
||||
std::tie(new_weight, new_duration, new_distance) <
|
||||
std::tie(current_weight, current_duration, current_distance))
|
||||
{
|
||||
current_weight = new_weight;
|
||||
current_duration = new_duration;
|
||||
|
||||
@@ -217,8 +217,8 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const auto haversine_distance = util::coordinate_calculation::greatCircleDistance(
|
||||
prev_coordinate, current_coordinate);
|
||||
// assumes minumum of 4 m/s
|
||||
const EdgeWeight weight_upper_bound =
|
||||
((haversine_distance + max_distance_delta) / 4.) * facade.GetWeightMultiplier();
|
||||
const EdgeWeight weight_upper_bound = to_alias<EdgeWeight>(
|
||||
((haversine_distance + max_distance_delta) / 4.) * facade.GetWeightMultiplier());
|
||||
|
||||
// compute d_t for this timestamp and the next one
|
||||
for (const auto s : util::irange<std::size_t>(0UL, prev_viterbi.size()))
|
||||
|
||||
@@ -109,10 +109,10 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
|
||||
weight = weight_upper_bound;
|
||||
|
||||
// get offset to account for offsets on phantom nodes on compressed edges
|
||||
const auto min_edge_offset = std::min(0, forward_heap.MinKey());
|
||||
BOOST_ASSERT(min_edge_offset <= 0);
|
||||
const auto min_edge_offset = std::min<EdgeWeight>({0}, forward_heap.MinKey());
|
||||
BOOST_ASSERT(min_edge_offset <= EdgeWeight{0});
|
||||
// we only every insert negative offsets for nodes in the forward heap
|
||||
BOOST_ASSERT(reverse_heap.MinKey() >= 0);
|
||||
BOOST_ASSERT(reverse_heap.MinKey() >= EdgeWeight{0});
|
||||
|
||||
// run two-Target Dijkstra routing step.
|
||||
while (0 < (forward_heap.Size() + reverse_heap.Size()))
|
||||
|
||||
@@ -182,8 +182,8 @@ std::vector<TurnData> generateTurns(const datafacade &facade,
|
||||
all_turn_data.push_back(TurnData{coord_via,
|
||||
angle_in,
|
||||
turn_angle,
|
||||
turn_weight,
|
||||
turn_duration,
|
||||
alias_cast<EdgeWeight>(turn_weight),
|
||||
alias_cast<EdgeDuration>(turn_duration),
|
||||
turn_instruction});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user