osrm-backend/include/customizer/cell_customizer.hpp

160 lines
5.6 KiB
C++
Raw Normal View History

2017-02-20 08:20:22 -05:00
#ifndef OSRM_CELLS_CUSTOMIZER_HPP
#define OSRM_CELLS_CUSTOMIZER_HPP
#include "partition/cell_storage.hpp"
#include "partition/multi_level_partition.hpp"
#include "util/binary_heap.hpp"
#include <boost/thread/tss.hpp>
#include <unordered_set>
namespace osrm
{
namespace customizer
2017-02-20 08:20:22 -05:00
{
class CellCustomizer
{
public:
CellCustomizer(const partition::MultiLevelPartition &partition) : partition(partition) {}
template <typename GraphT>
void Customize(const GraphT &graph, partition::CellStorage &cells, LevelID level, CellID id)
2017-02-20 08:20:22 -05:00
{
auto cell = cells.GetCell(level, id);
auto destinations = cell.GetDestinationNodes();
// for each source do forward search
for (auto source : cell.GetSourceNodes())
{
std::unordered_set<NodeID> destinations_set(destinations.begin(), destinations.end());
Heap heap(graph.GetNumberOfNodes());
2017-04-04 07:04:30 -04:00
heap.Insert(source, 0, {false});
2017-02-20 08:20:22 -05:00
// explore search space
while (!heap.Empty() && !destinations_set.empty())
{
const NodeID node = heap.DeleteMin();
const EdgeWeight weight = heap.GetKey(node);
if (level == 1)
2017-03-28 02:29:17 -04:00
RelaxNode<true>(graph, cells, heap, level, node, weight);
2017-02-20 08:20:22 -05:00
else
2017-03-28 02:29:17 -04:00
RelaxNode<false>(graph, cells, heap, level, node, weight);
2017-02-20 08:20:22 -05:00
destinations_set.erase(node);
}
// fill a map of destination nodes to placeholder pointers
auto destination_iter = destinations.begin();
for (auto &weight : cell.GetOutWeight(source))
{
BOOST_ASSERT(destination_iter != destinations.end());
const auto destination = *destination_iter++;
weight =
heap.WasInserted(destination) ? heap.GetKey(destination) : INVALID_EDGE_WEIGHT;
}
}
}
template <typename GraphT> void Customize(const GraphT &graph, partition::CellStorage &cells)
{
for (std::size_t level = 1; level < partition.GetNumberOfLevels(); ++level)
{
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, partition.GetNumberOfCells(level)),
[&](const tbb::blocked_range<std::size_t> &range) {
for (auto id = range.begin(), end = range.end(); id != end; ++id)
{
Customize(graph, cells, level, id);
}
});
}
}
private:
struct HeapData
{
2017-04-04 07:04:30 -04:00
bool from_clique;
2017-02-20 08:20:22 -05:00
};
using Heap = util::
BinaryHeap<NodeID, NodeID, EdgeWeight, HeapData, util::UnorderedMapStorage<NodeID, int>>;
using HeapPtr = boost::thread_specific_ptr<Heap>;
template <bool first_level, typename GraphT>
void RelaxNode(const GraphT &graph,
const partition::CellStorage &cells,
Heap &heap,
LevelID level,
2017-02-20 08:20:22 -05:00
NodeID node,
EdgeWeight weight) const
{
2017-04-04 07:04:30 -04:00
BOOST_ASSERT(heap.WasInserted(node));
2017-02-20 08:20:22 -05:00
if (!first_level)
{
2017-04-04 07:04:30 -04:00
// if we reaches this node from a clique arc we don't need to scan
// the clique arcs again because of the triangle inequality
//
// d(parent, node) + d(node, v) >= d(parent, v)
//
// And if there is a path (parent, node, v) there must also be a
// clique arc (parent, v) with d(parent, v).
if (!heap.GetData(node).from_clique)
2017-02-20 08:20:22 -05:00
{
2017-04-04 07:04:30 -04:00
// Relax sub-cell nodes
auto subcell_id = partition.GetCell(level - 1, node);
auto subcell = cells.GetCell(level - 1, subcell_id);
auto subcell_destination = subcell.GetDestinationNodes().begin();
for (auto subcell_weight : subcell.GetOutWeight(node))
2017-02-20 08:20:22 -05:00
{
2017-04-04 07:04:30 -04:00
if (subcell_weight != INVALID_EDGE_WEIGHT)
2017-02-20 08:20:22 -05:00
{
2017-04-04 07:04:30 -04:00
const NodeID to = *subcell_destination;
const EdgeWeight to_weight = subcell_weight + weight;
if (!heap.WasInserted(to))
{
heap.Insert(to, to_weight, {true});
}
else if (to_weight < heap.GetKey(to))
{
heap.DecreaseKey(to, to_weight);
heap.GetData(to).from_clique = true;
}
2017-02-20 08:20:22 -05:00
}
2017-04-04 07:04:30 -04:00
++subcell_destination;
}
2017-02-20 08:20:22 -05:00
}
}
// Relax base graph edges if a sub-cell border edge
for (auto edge : graph.GetInternalEdgeRange(level, node))
2017-02-20 08:20:22 -05:00
{
const NodeID to = graph.GetTarget(edge);
const auto &data = graph.GetEdgeData(edge);
2017-03-20 12:00:44 -04:00
if (data.forward &&
(first_level ||
2017-02-20 08:20:22 -05:00
partition.GetCell(level - 1, node) != partition.GetCell(level - 1, to)))
{
const EdgeWeight to_weight = data.weight + weight;
if (!heap.WasInserted(to))
{
2017-04-04 07:04:30 -04:00
heap.Insert(to, to_weight, {false});
2017-02-20 08:20:22 -05:00
}
else if (to_weight < heap.GetKey(to))
{
heap.DecreaseKey(to, to_weight);
2017-04-04 07:04:30 -04:00
heap.GetData(to).from_clique = false;
2017-02-20 08:20:22 -05:00
}
}
}
}
const partition::MultiLevelPartition &partition;
};
}
}
#endif // OSRM_CELLS_CUSTOMIZER_HPP