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.
101 lines
3.4 KiB
C++
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
|