202 lines
7.9 KiB
C++
202 lines
7.9 KiB
C++
#ifndef ALTERNATIVE_PATH_ROUTING_HPP
|
|
#define ALTERNATIVE_PATH_ROUTING_HPP
|
|
|
|
#include "engine/datafacade/datafacade_base.hpp"
|
|
#include "engine/routing_algorithms/routing_base.hpp"
|
|
#include "engine/search_engine_data.hpp"
|
|
#include "util/integer_range.hpp"
|
|
|
|
#include <boost/assert.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
|
|
#include <vector>
|
|
|
|
namespace osrm
|
|
{
|
|
namespace engine
|
|
{
|
|
namespace routing_algorithms
|
|
{
|
|
|
|
const double constexpr VIAPATH_ALPHA = 0.10;
|
|
const double constexpr VIAPATH_EPSILON = 0.15; // alternative at most 15% longer
|
|
const double constexpr VIAPATH_GAMMA = 0.75; // alternative shares at most 75% with the shortest.
|
|
|
|
class AlternativeRouting final : private BasicRoutingInterface
|
|
{
|
|
using super = BasicRoutingInterface;
|
|
using QueryHeap = SearchEngineData::QueryHeap;
|
|
using SearchSpaceEdge = std::pair<NodeID, NodeID>;
|
|
|
|
struct RankedCandidateNode
|
|
{
|
|
RankedCandidateNode(const NodeID node, const int length, const int sharing)
|
|
: node(node), length(length), sharing(sharing)
|
|
{
|
|
}
|
|
|
|
NodeID node;
|
|
int length;
|
|
int sharing;
|
|
|
|
bool operator<(const RankedCandidateNode &other) const
|
|
{
|
|
return (2 * length + sharing) < (2 * other.length + other.sharing);
|
|
}
|
|
};
|
|
SearchEngineData &engine_working_data;
|
|
|
|
public:
|
|
AlternativeRouting(SearchEngineData &engine_working_data)
|
|
: engine_working_data(engine_working_data)
|
|
{
|
|
}
|
|
|
|
virtual ~AlternativeRouting() {}
|
|
|
|
void operator()(const std::shared_ptr<const datafacade::BaseDataFacade> facade,
|
|
const PhantomNodes &phantom_node_pair,
|
|
InternalRouteResult &raw_route_data);
|
|
|
|
private:
|
|
// unpack alternate <s,..,v,..,t> by exploring search spaces from v
|
|
void RetrievePackedAlternatePath(const QueryHeap &forward_heap1,
|
|
const QueryHeap &reverse_heap1,
|
|
const QueryHeap &forward_heap2,
|
|
const QueryHeap &reverse_heap2,
|
|
const NodeID s_v_middle,
|
|
const NodeID v_t_middle,
|
|
std::vector<NodeID> &packed_path) const;
|
|
|
|
// TODO: reorder parameters
|
|
// compute and unpack <s,..,v> and <v,..,t> by exploring search spaces
|
|
// from v and intersecting against queues. only half-searches have to be
|
|
// done at this stage
|
|
void
|
|
ComputeLengthAndSharingOfViaPath(const std::shared_ptr<const datafacade::BaseDataFacade> facade,
|
|
const NodeID via_node,
|
|
int *real_length_of_via_path,
|
|
int *sharing_of_via_path,
|
|
const std::vector<NodeID> &packed_shortest_path,
|
|
const EdgeWeight min_edge_offset);
|
|
|
|
// todo: reorder parameters
|
|
template <bool is_forward_directed>
|
|
void AlternativeRoutingStep(const std::shared_ptr<const datafacade::BaseDataFacade> facade,
|
|
QueryHeap &heap1,
|
|
QueryHeap &heap2,
|
|
NodeID *middle_node,
|
|
int *upper_bound_to_shortest_path_weight,
|
|
std::vector<NodeID> &search_space_intersection,
|
|
std::vector<SearchSpaceEdge> &search_space,
|
|
const EdgeWeight min_edge_offset) const
|
|
{
|
|
QueryHeap &forward_heap = (is_forward_directed ? heap1 : heap2);
|
|
QueryHeap &reverse_heap = (is_forward_directed ? heap2 : heap1);
|
|
|
|
const NodeID node = forward_heap.DeleteMin();
|
|
const int weight = forward_heap.GetKey(node);
|
|
// const NodeID parentnode = forward_heap.GetData(node).parent;
|
|
// util::Log() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled
|
|
// edge ("
|
|
// << parentnode << "," << node << "), dist: " << weight;
|
|
|
|
const int scaled_weight =
|
|
static_cast<int>((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))
|
|
{
|
|
forward_heap.DeleteAll();
|
|
return;
|
|
}
|
|
|
|
search_space.emplace_back(forward_heap.GetData(node).parent, node);
|
|
|
|
if (reverse_heap.WasInserted(node))
|
|
{
|
|
search_space_intersection.emplace_back(node);
|
|
const int new_weight = reverse_heap.GetKey(node) + weight;
|
|
if (new_weight < *upper_bound_to_shortest_path_weight)
|
|
{
|
|
if (new_weight >= 0)
|
|
{
|
|
*middle_node = node;
|
|
*upper_bound_to_shortest_path_weight = new_weight;
|
|
// util::Log() << "accepted middle_node " << *middle_node
|
|
// << " at
|
|
// weight " << new_weight;
|
|
// } else {
|
|
// util::Log() << "discarded middle_node " << *middle_node
|
|
// << "
|
|
// at weight " << new_weight;
|
|
}
|
|
else
|
|
{
|
|
// check whether there is a loop present at the node
|
|
const auto loop_weight = super::GetLoopWeight(facade, node);
|
|
const int new_weight_with_loop = new_weight + loop_weight;
|
|
if (loop_weight != INVALID_EDGE_WEIGHT &&
|
|
new_weight_with_loop <= *upper_bound_to_shortest_path_weight)
|
|
{
|
|
*middle_node = node;
|
|
*upper_bound_to_shortest_path_weight = loop_weight;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto edge : facade->GetAdjacentEdgeRange(node))
|
|
{
|
|
const EdgeData &data = facade->GetEdgeData(edge);
|
|
const bool edge_is_forward_directed =
|
|
(is_forward_directed ? data.forward : data.backward);
|
|
if (edge_is_forward_directed)
|
|
{
|
|
const NodeID to = facade->GetTarget(edge);
|
|
const int edge_weight = data.weight;
|
|
|
|
BOOST_ASSERT(edge_weight > 0);
|
|
const int to_weight = weight + edge_weight;
|
|
|
|
// New Node discovered -> Add to Heap + Node Info Storage
|
|
if (!forward_heap.WasInserted(to))
|
|
{
|
|
forward_heap.Insert(to, to_weight, node);
|
|
}
|
|
// Found a shorter Path -> Update weight
|
|
else if (to_weight < forward_heap.GetKey(to))
|
|
{
|
|
// new parent
|
|
forward_heap.GetData(to).parent = node;
|
|
// decreased weight
|
|
forward_heap.DecreaseKey(to, to_weight);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// conduct T-Test
|
|
bool ViaNodeCandidatePassesTTest(const std::shared_ptr<const datafacade::BaseDataFacade> facade,
|
|
QueryHeap &existing_forward_heap,
|
|
QueryHeap &existing_reverse_heap,
|
|
QueryHeap &new_forward_heap,
|
|
QueryHeap &new_reverse_heap,
|
|
const RankedCandidateNode &candidate,
|
|
const int length_of_shortest_path,
|
|
int *length_of_via_path,
|
|
NodeID *s_v_middle,
|
|
NodeID *v_t_middle,
|
|
const EdgeWeight min_edge_offset) const;
|
|
};
|
|
|
|
} // namespace routing_algorithms
|
|
} // namespace engine
|
|
} // namespace osrm
|
|
|
|
#endif /* ALTERNATIVE_PATH_ROUTING_HPP */
|