Skip to content

Commit

Permalink
MLD plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
oxidase committed Mar 10, 2017
1 parent fcdb3b2 commit 96c64ee
Show file tree
Hide file tree
Showing 8 changed files with 415 additions and 49 deletions.
2 changes: 1 addition & 1 deletion include/engine/algorithm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ template <> struct HasManyToManySearch<algorithm::MLD> final : std::false_type
template <> struct HasShortestPathSearch<algorithm::MLD> final : std::false_type
{
};
template <> struct HasDirectShortestPathSearch<algorithm::MLD> final : std::false_type
template <> struct HasDirectShortestPathSearch<algorithm::MLD> final : std::true_type
{
};
template <> struct HasMapMatching<algorithm::MLD> final : std::false_type
Expand Down
7 changes: 0 additions & 7 deletions include/engine/routing_algorithms.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,6 @@ RoutingAlgorithms<algorithm::MLD>::ShortestPathSearch(const std::vector<PhantomN
throw util::exception("ShortestPathSearch is not implemented");
}

template <>
InternalRouteResult inline RoutingAlgorithms<algorithm::MLD>::DirectShortestPathSearch(
const PhantomNodes &) const
{
throw util::exception("DirectShortestPathSearch is not implemented");
}

template <>
inline std::vector<EdgeWeight>
RoutingAlgorithms<algorithm::MLD>::ManyToManySearch(const std::vector<PhantomNode> &,
Expand Down
14 changes: 5 additions & 9 deletions include/engine/routing_algorithms/direct_shortest_path.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,11 @@ namespace routing_algorithms
/// by the previous route.
/// This variation is only an optimazation for graphs with slow queries, for example
/// not fully contracted graphs.
InternalRouteResult directShortestPathSearch(
SearchEngineData &engine_working_data,
const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CH> &facade,
const PhantomNodes &phantom_nodes);

InternalRouteResult directShortestPathSearch(
SearchEngineData &engine_working_data,
const datafacade::ContiguousInternalMemoryDataFacade<algorithm::CoreCH> &facade,
const PhantomNodes &phantom_nodes);
template <typename AlgorithmT>
InternalRouteResult
directShortestPathSearch(SearchEngineData &engine_working_data,
const datafacade::ContiguousInternalMemoryDataFacade<AlgorithmT> &facade,
const PhantomNodes &phantom_nodes);

} // namespace routing_algorithms
} // namespace engine
Expand Down
17 changes: 0 additions & 17 deletions include/engine/routing_algorithms/routing_base_ch.hpp
Original file line number Diff line number Diff line change
@@ -1,32 +1,15 @@
#ifndef OSRM_ENGINE_ROUTING_BASE_CH_HPP
#define OSRM_ENGINE_ROUTING_BASE_CH_HPP

#include "extractor/guidance/turn_instruction.hpp"

#include "engine/algorithm.hpp"
#include "engine/datafacade/contiguous_internalmem_datafacade.hpp"
#include "engine/internal_route_result.hpp"
#include "engine/routing_algorithms/routing_base.hpp"
#include "engine/search_engine_data.hpp"

#include "util/coordinate_calculation.hpp"
#include "util/guidance/turn_bearing.hpp"
#include "util/typedefs.hpp"

#include <boost/assert.hpp>

#include <cstddef>
#include <cstdint>

#include <algorithm>
#include <functional>
#include <iterator>
#include <memory>
#include <numeric>
#include <stack>
#include <utility>
#include <vector>

namespace osrm
{
namespace engine
Expand Down
276 changes: 276 additions & 0 deletions include/engine/routing_algorithms/routing_base_mld.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
#ifndef OSRM_ENGINE_ROUTING_BASE_MLD_HPP
#define OSRM_ENGINE_ROUTING_BASE_MLD_HPP

#include "engine/algorithm.hpp"
#include "engine/datafacade/contiguous_internalmem_datafacade.hpp"
#include "engine/routing_algorithms/routing_base.hpp"
#include "engine/search_engine_data.hpp"

#include "util/typedefs.hpp"

#include <boost/assert.hpp>

namespace osrm
{
namespace engine
{
namespace routing_algorithms
{
namespace mld
{

template <bool DIRECTION>
void routingStep(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::MLD> &facade,
const partition::MultiLevelPartitionView &partition,
const partition::CellStorageView &cells,
SearchEngineData::MultiLayerDijkstraHeap &forward_heap,
SearchEngineData::MultiLayerDijkstraHeap &reverse_heap,
const std::pair<LevelID, CellID> &parent_cell,
NodeID &middle_node,
EdgeWeight &path_upper_bound,
EdgeWeight &forward_upper_bound,
EdgeWeight &reverse_upper_bound)
{
const auto node = forward_heap.DeleteMin();
const auto weight = forward_heap.GetKey(node);

auto update_upper_bounds = [&](NodeID to, EdgeWeight forward_weight, EdgeWeight edge_weight) {
if (reverse_heap.WasInserted(to) && reverse_heap.WasRemoved(to))
{
auto reverse_weight = reverse_heap.GetKey(to);
auto path_weight = forward_weight + edge_weight + reverse_weight;
BOOST_ASSERT(path_weight >= 0);
if (path_weight < path_upper_bound)
{
middle_node = to;
path_upper_bound = path_weight;
forward_upper_bound = forward_weight + edge_weight;
reverse_upper_bound = reverse_weight + edge_weight;
}
}
};

// Edge case: single node path
update_upper_bounds(node, weight, 0);

const auto &node_data = forward_heap.GetData(node);
const auto is_boundary = node_data.IsBoundary() || node_data.parent == node;
const auto level = node_data.level;

if (is_boundary && level >= 1)
{
if (DIRECTION == FORWARD_DIRECTION)
{
// Shortcuts in forward direction
const auto &cell = cells.GetCell(level, partition.GetCell(level, node));
auto destination = cell.GetDestinationNodes().begin();
for (auto shortcut_weight : cell.GetOutWeight(node))
{
BOOST_ASSERT(destination != cell.GetDestinationNodes().end());
const NodeID to = *destination;
if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to)
{
const EdgeWeight to_weight = weight + shortcut_weight;
if (!forward_heap.WasInserted(to))
{
forward_heap.Insert(to, to_weight, {node, level});
update_upper_bounds(to, weight, shortcut_weight);
}
else if (to_weight < forward_heap.GetKey(to))
{
forward_heap.GetData(to) = {node, level};
forward_heap.DecreaseKey(to, to_weight);
update_upper_bounds(to, weight, shortcut_weight);
}
}
++destination;
}
}
else
{
// Shortcuts in backward direction
const auto &cell = cells.GetCell(level, partition.GetCell(level, node));
auto source = cell.GetSourceNodes().begin();
for (auto shortcut_weight : cell.GetInWeight(node))
{
BOOST_ASSERT(source != cell.GetSourceNodes().end());
const NodeID to = *source;
if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to)
{
const EdgeWeight to_weight = weight + shortcut_weight;
if (!forward_heap.WasInserted(to))
{
forward_heap.Insert(to, to_weight, {node, level});
update_upper_bounds(to, weight, shortcut_weight);
}
else if (to_weight < forward_heap.GetKey(to))
{
forward_heap.GetData(to) = {node, level};
forward_heap.DecreaseKey(to, to_weight);
update_upper_bounds(to, weight, shortcut_weight);
}
}
++source;
}
}
}

// Boundary edges
for (const auto edge : facade.GetAdjacentEdgeRange(node))
{
const auto &edge_data = facade.GetEdgeData(edge);
if (DIRECTION == FORWARD_DIRECTION ? edge_data.forward : edge_data.backward)
{
const NodeID to = facade.GetTarget(edge);
const auto to_level =
std::min(parent_cell.first, partition.GetHighestDifferentLevel(node, to));

if ( // Routing is unrestricted or restricted to the highest level cell
(parent_cell.second == INVALID_CELL_ID ||
parent_cell.second == partition.GetCell(parent_cell.first + 1, to)) &&
// "Never-go-down" at border edges
to_level >= level)
{
BOOST_ASSERT_MSG(edge_data.weight > 0, "edge_weight invalid");
const EdgeWeight to_weight = weight + edge_data.weight;

if (!forward_heap.WasInserted(to))
{
forward_heap.Insert(to, to_weight, {node, to_level, edge});
update_upper_bounds(to, weight, edge_data.weight);
}
else if (to_weight < forward_heap.GetKey(to))
{
forward_heap.GetData(to) = {node, to_level, edge};
forward_heap.DecreaseKey(to, to_weight);
update_upper_bounds(to, weight, edge_data.weight);
}
}
}
}
}

auto search(const datafacade::ContiguousInternalMemoryDataFacade<algorithm::MLD> &facade,
const partition::MultiLevelPartitionView &partition,
const partition::CellStorageView &cells,
SearchEngineData::MultiLayerDijkstraHeap &forward_heap,
SearchEngineData::MultiLayerDijkstraHeap &reverse_heap,
const std::pair<LevelID, CellID> &parent_cell)
{
// run two-Target Dijkstra routing step.
NodeID middle = SPECIAL_NODEID;
EdgeWeight weight = INVALID_EDGE_WEIGHT;
EdgeWeight forward_search_radius = INVALID_EDGE_WEIGHT;
EdgeWeight reverse_search_radius = INVALID_EDGE_WEIGHT;
bool progress;
do
{
progress = false;
if (!forward_heap.Empty() && (forward_heap.MinKey() < forward_search_radius))
{
progress = true;
routingStep<FORWARD_DIRECTION>(facade,
partition,
cells,
forward_heap,
reverse_heap,
parent_cell,
middle,
weight,
forward_search_radius,
reverse_search_radius);
}
if (!reverse_heap.Empty() && (reverse_heap.MinKey() < reverse_search_radius))
{
progress = true;
routingStep<REVERSE_DIRECTION>(facade,
partition,
cells,
reverse_heap,
forward_heap,
parent_cell,
middle,
weight,
reverse_search_radius,
forward_search_radius);
}
} while (progress);

// No path found for both target nodes?
if (weight == INVALID_EDGE_WEIGHT || SPECIAL_NODEID == middle)
{
return std::make_tuple(
INVALID_EDGE_WEIGHT, SPECIAL_NODEID, SPECIAL_NODEID, std::vector<EdgeID>());
}

// Get packed path as edges {level, from node ID, to node ID, edge ID}
std::vector<std::tuple<LevelID, NodeID, NodeID, EdgeID>> packed_path;
NodeID current_node = middle, parent_node = forward_heap.GetData(middle).parent;
while (parent_node != current_node)
{
const auto &data = forward_heap.GetData(current_node);
packed_path.push_back({data.level, parent_node, current_node, data.edge_id});
current_node = parent_node;
parent_node = forward_heap.GetData(parent_node).parent;
}
std::reverse(std::begin(packed_path), std::end(packed_path));
const NodeID source_node = current_node;

current_node = middle, parent_node = reverse_heap.GetData(middle).parent;
while (parent_node != current_node)
{
const auto &data = reverse_heap.GetData(current_node);
packed_path.push_back({data.level, current_node, parent_node, data.edge_id});
current_node = parent_node;
parent_node = reverse_heap.GetData(parent_node).parent;
}
const NodeID target_node = current_node;

// Unpack path
std::vector<EdgeID> unpacked_path;
unpacked_path.reserve(packed_path.size());
for (auto &packed_edge : packed_path)
{
LevelID level;
NodeID source, target;
EdgeID edge_id;
std::tie(level, source, target, edge_id) = packed_edge;
if (edge_id != SPECIAL_EDGEID)
{ // a base graph edge
unpacked_path.push_back(edge_id);
}
else
{ // an overlay graph edge
LevelID sublevel = level - 1;
CellID parent_cell_id = partition.GetCell(level, source);
BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target));

// Here heaps can be reused, let's go deeper!
forward_heap.Clear();
reverse_heap.Clear();
forward_heap.Insert(source, 0, {source, sublevel});
reverse_heap.Insert(target, 0, {target, sublevel});

// TODO: when structured bindings will be allowed change to
// auto [subpath_weight, subpath_source, subpath_target, subpath] = ...
EdgeWeight subpath_weight;
NodeID subpath_source, subpath_target;
std::vector<EdgeID> subpath;
std::tie(subpath_weight, subpath_source, subpath_target, subpath) = search(
facade, partition, cells, forward_heap, reverse_heap, {sublevel, parent_cell_id});
BOOST_ASSERT(!subpath.empty());
BOOST_ASSERT(subpath_source == source);
BOOST_ASSERT(subpath_target == target);
unpacked_path.insert(unpacked_path.end(), subpath.begin(), subpath.end());
}
}

return std::make_tuple(weight, source_node, target_node, std::move(unpacked_path));
}

} // namespace mld
} // namespace routing_algorithms
} // namespace engine
} // namespace osrm

#endif // OSRM_ENGINE_ROUTING_BASE_MLD_HPP
Loading

0 comments on commit 96c64ee

Please sign in to comment.