osrm-backend/include/engine/trip/trip_brute_force.hpp
Michael Bell 5d468f2897
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.
2022-10-28 15:16:12 +01:00

101 lines
3.4 KiB
C++

#ifndef TRIP_BRUTE_FORCE_HPP
#define TRIP_BRUTE_FORCE_HPP
#include "util/dist_table_wrapper.hpp"
#include "util/log.hpp"
#include "util/typedefs.hpp"
#include "osrm/json_container.hpp"
#include <algorithm>
#include <cstdlib>
#include <iterator>
#include <limits>
#include <numeric>
#include <string>
#include <vector>
namespace osrm
{
namespace engine
{
namespace trip
{
// computes the distance of a given permutation
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)
{
EdgeDuration route_dist = {0};
std::size_t current_index = 0;
while (current_index < location_order.size() && (route_dist < min_route_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_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_DURATION;
}
else
{
route_dist += edge_weight;
}
// 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_DURATION,
"invalid route found");
++current_index;
}
return route_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<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;
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");
BOOST_ASSERT_MSG(*(std::max_element(std::begin(node_order), std::end(node_order))) <
number_of_locations,
"invalid node id");
do
{
const auto new_distance =
ReturnDistance(dist_table, node_order, min_route_dist, number_of_locations);
// we can use `<` instead of `<=` here, since all distances are `!=` INVALID_EDGE_WEIGHT
// In case we really sum up to invalid edge weight for all permutations, keeping the very
// first one is fine too.
if (new_distance < min_route_dist)
{
min_route_dist = new_distance;
route = node_order;
}
} while (std::next_permutation(std::begin(node_order), std::end(node_order)));
return route;
}
} // namespace trip
} // namespace engine
} // namespace osrm
#endif // TRIP_BRUTE_FORCE_HPP