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:
@@ -23,12 +23,12 @@ namespace trip
|
||||
{
|
||||
|
||||
// computes the distance of a given permutation
|
||||
inline EdgeWeight ReturnDistance(const util::DistTableWrapper<EdgeWeight> &dist_table,
|
||||
const std::vector<NodeID> &location_order,
|
||||
const EdgeWeight min_route_dist,
|
||||
const std::size_t number_of_locations)
|
||||
inline EdgeDuration ReturnDistance(const util::DistTableWrapper<EdgeDuration> &dist_table,
|
||||
const std::vector<NodeID> &location_order,
|
||||
const EdgeDuration min_route_dist,
|
||||
const std::size_t number_of_locations)
|
||||
{
|
||||
EdgeWeight route_dist = 0;
|
||||
EdgeDuration route_dist = {0};
|
||||
std::size_t current_index = 0;
|
||||
while (current_index < location_order.size() && (route_dist < min_route_dist))
|
||||
{
|
||||
@@ -36,12 +36,13 @@ inline EdgeWeight ReturnDistance(const util::DistTableWrapper<EdgeWeight> &dist_
|
||||
std::size_t next_index = (current_index + 1) % number_of_locations;
|
||||
auto edge_weight = dist_table(location_order[current_index], location_order[next_index]);
|
||||
|
||||
// If the edge_weight is very large (INVALID_EDGE_WEIGHT) then the algorithm will not choose
|
||||
// this edge in final minimal path. So instead of computing all the permutations after this
|
||||
// large edge, discard this edge right here and don't consider the path after this edge.
|
||||
if (edge_weight == INVALID_EDGE_WEIGHT)
|
||||
// If the edge_weight is very large (INVALID_EDGE_DURATION) then the algorithm will not
|
||||
// choose this edge in final minimal path. So instead of computing all the permutations
|
||||
// after this large edge, discard this edge right here and don't consider the path after
|
||||
// this edge.
|
||||
if (edge_weight == INVALID_EDGE_DURATION)
|
||||
{
|
||||
return INVALID_EDGE_WEIGHT;
|
||||
return INVALID_EDGE_DURATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -50,7 +51,7 @@ inline EdgeWeight ReturnDistance(const util::DistTableWrapper<EdgeWeight> &dist_
|
||||
|
||||
// This boost assert should not be reached if TFSE table
|
||||
BOOST_ASSERT_MSG(dist_table(location_order[current_index], location_order[next_index]) !=
|
||||
INVALID_EDGE_WEIGHT,
|
||||
INVALID_EDGE_DURATION,
|
||||
"invalid route found");
|
||||
++current_index;
|
||||
}
|
||||
@@ -60,14 +61,14 @@ inline EdgeWeight ReturnDistance(const util::DistTableWrapper<EdgeWeight> &dist_
|
||||
|
||||
// computes the route by computing all permutations and selecting the shortest
|
||||
inline std::vector<NodeID> BruteForceTrip(const std::size_t number_of_locations,
|
||||
const util::DistTableWrapper<EdgeWeight> &dist_table)
|
||||
const util::DistTableWrapper<EdgeDuration> &dist_table)
|
||||
{
|
||||
// set initial order in which nodes are visited to 0, 1, 2, 3, ...
|
||||
std::vector<NodeID> node_order(number_of_locations);
|
||||
std::iota(std::begin(node_order), std::end(node_order), 0);
|
||||
std::vector<NodeID> route = node_order;
|
||||
|
||||
EdgeWeight min_route_dist = INVALID_EDGE_WEIGHT;
|
||||
EdgeDuration min_route_dist = INVALID_EDGE_DURATION;
|
||||
|
||||
// check length of all possible permutation of the component ids
|
||||
BOOST_ASSERT_MSG(node_order.size() > 0, "no order permutation given");
|
||||
|
||||
@@ -23,15 +23,15 @@ namespace trip
|
||||
// given a route and a new location, find the best place of insertion and
|
||||
// check the distance of roundtrip when the new location is additionally visited
|
||||
using NodeIDIter = std::vector<NodeID>::iterator;
|
||||
inline std::pair<EdgeWeight, NodeIDIter>
|
||||
inline std::pair<EdgeDuration, NodeIDIter>
|
||||
GetShortestRoundTrip(const NodeID new_loc,
|
||||
const util::DistTableWrapper<EdgeWeight> &dist_table,
|
||||
const util::DistTableWrapper<EdgeDuration> &dist_table,
|
||||
const std::size_t number_of_locations,
|
||||
std::vector<NodeID> &route)
|
||||
{
|
||||
(void)number_of_locations; // unused
|
||||
|
||||
auto min_trip_distance = INVALID_EDGE_WEIGHT;
|
||||
auto min_trip_distance = INVALID_EDGE_DURATION;
|
||||
NodeIDIter next_insert_point_candidate;
|
||||
|
||||
// for all nodes in the current trip find the best insertion resulting in the shortest path
|
||||
@@ -48,10 +48,11 @@ GetShortestRoundTrip(const NodeID new_loc,
|
||||
|
||||
const auto dist_from = dist_table(*from_node, new_loc);
|
||||
const auto dist_to = dist_table(new_loc, *to_node);
|
||||
// If the edge_weight is very large (INVALID_EDGE_WEIGHT) then the algorithm will not choose
|
||||
// this edge in final minimal path. So instead of computing all the permutations after this
|
||||
// large edge, discard this edge right here and don't consider the path after this edge.
|
||||
if (dist_from == INVALID_EDGE_WEIGHT || dist_to == INVALID_EDGE_WEIGHT)
|
||||
// If the edge_weight is very large (INVALID_EDGE_DURATION) then the algorithm will not
|
||||
// choose this edge in final minimal path. So instead of computing all the permutations
|
||||
// after this large edge, discard this edge right here and don't consider the path after
|
||||
// this edge.
|
||||
if (dist_from == INVALID_EDGE_DURATION || dist_to == INVALID_EDGE_DURATION)
|
||||
continue;
|
||||
|
||||
const auto trip_dist = dist_from + dist_to - dist_table(*from_node, *to_node);
|
||||
@@ -71,14 +72,14 @@ GetShortestRoundTrip(const NodeID new_loc,
|
||||
next_insert_point_candidate = to_node;
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT_MSG(min_trip_distance != INVALID_EDGE_WEIGHT, "trip has invalid edge weight");
|
||||
BOOST_ASSERT_MSG(min_trip_distance != INVALID_EDGE_DURATION, "trip has invalid edge weight");
|
||||
|
||||
return std::make_pair(min_trip_distance, next_insert_point_candidate);
|
||||
}
|
||||
|
||||
// given two initial start nodes, find a roundtrip route using the farthest insertion algorithm
|
||||
inline std::vector<NodeID> FindRoute(const std::size_t &number_of_locations,
|
||||
const util::DistTableWrapper<EdgeWeight> &dist_table,
|
||||
const util::DistTableWrapper<EdgeDuration> &dist_table,
|
||||
const NodeID &start1,
|
||||
const NodeID &start2)
|
||||
{
|
||||
@@ -99,7 +100,7 @@ inline std::vector<NodeID> FindRoute(const std::size_t &number_of_locations,
|
||||
// two nodes are already in the initial start trip, so we need to add all other nodes
|
||||
for (std::size_t added_nodes = 2; added_nodes < number_of_locations; ++added_nodes)
|
||||
{
|
||||
auto farthest_distance = std::numeric_limits<int>::min();
|
||||
auto farthest_distance = EdgeDuration{std::numeric_limits<EdgeDuration::value_type>::min()};
|
||||
auto next_node = -1;
|
||||
NodeIDIter next_insert_point;
|
||||
|
||||
@@ -112,7 +113,7 @@ inline std::vector<NodeID> FindRoute(const std::size_t &number_of_locations,
|
||||
const auto insert_candidate =
|
||||
GetShortestRoundTrip(id, dist_table, number_of_locations, route);
|
||||
|
||||
BOOST_ASSERT_MSG(insert_candidate.first != INVALID_EDGE_WEIGHT,
|
||||
BOOST_ASSERT_MSG(insert_candidate.first != INVALID_EDGE_DURATION,
|
||||
"shortest round trip is invalid");
|
||||
|
||||
// add the location to the current trip such that it results in the shortest total
|
||||
@@ -137,7 +138,7 @@ inline std::vector<NodeID> FindRoute(const std::size_t &number_of_locations,
|
||||
|
||||
inline std::vector<NodeID>
|
||||
FarthestInsertionTrip(const std::size_t number_of_locations,
|
||||
const util::DistTableWrapper<EdgeWeight> &dist_table)
|
||||
const util::DistTableWrapper<EdgeDuration> &dist_table)
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// START FARTHEST INSERTION HERE
|
||||
|
||||
Reference in New Issue
Block a user