osrm-backend/Contractor/Contractor.h

975 lines
39 KiB
C
Raw Normal View History

2010-07-09 05:05:40 -04:00
/*
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
2010-07-09 05:05:40 -04:00
2014-05-09 08:21:33 -04:00
#ifndef CONTRACTOR_H
#define CONTRACTOR_H
2012-05-25 05:41:52 -04:00
#include "../DataStructures/BinaryHeap.h"
#include "../DataStructures/DeallocatingVector.h"
#include "../DataStructures/DynamicGraph.h"
2010-10-01 06:30:46 -04:00
#include "../DataStructures/Percent.h"
#include "../DataStructures/QueryEdge.h"
2014-08-05 11:19:09 -04:00
#include "../DataStructures/Range.h"
2012-05-25 05:41:52 -04:00
#include "../DataStructures/XORFastHash.h"
#include "../DataStructures/XORFastHashStorage.h"
#include "../Util/SimpleLogger.h"
#include "../Util/StringUtil.h"
2014-05-20 17:57:48 -04:00
#include "../Util/TimingUtil.h"
#include "../typedefs.h"
2013-06-24 16:05:27 -04:00
#include <boost/assert.hpp>
#include <stxxl/vector>
2014-05-20 17:57:48 -04:00
#include <tbb/enumerable_thread_specific.h>
#include <tbb/parallel_for.h>
#include <tbb/parallel_sort.h>
2014-05-20 17:57:48 -04:00
2013-06-24 16:05:27 -04:00
#include <algorithm>
#include <limits>
#include <vector>
2014-05-08 17:07:16 -04:00
class Contractor
{
private:
struct ContractorEdgeData
{
ContractorEdgeData()
: distance(0), id(0), originalEdges(0), shortcut(0), forward(0), backward(0),
2014-05-09 08:21:33 -04:00
is_original_via_node_ID(false)
2014-05-08 17:07:16 -04:00
{
}
2014-07-14 11:35:02 -04:00
ContractorEdgeData(unsigned distance,
unsigned original_edges,
unsigned id,
bool shortcut,
bool forward,
bool backward)
: distance(distance), id(id),
originalEdges(std::min((unsigned)1 << 28, original_edges)), shortcut(shortcut),
forward(forward), backward(backward), is_original_via_node_ID(false)
2014-05-08 17:07:16 -04:00
{
}
unsigned distance;
unsigned id;
2014-05-08 17:07:16 -04:00
unsigned originalEdges : 28;
bool shortcut : 1;
bool forward : 1;
bool backward : 1;
2014-05-09 08:21:33 -04:00
bool is_original_via_node_ID : 1;
} data;
2014-05-09 08:21:33 -04:00
struct ContractorHeapData
2014-05-08 17:07:16 -04:00
{
short hop;
bool target;
2014-05-09 08:21:33 -04:00
ContractorHeapData() : hop(0), target(false) {}
ContractorHeapData(short h, bool t) : hop(h), target(t) {}
};
2014-05-09 08:21:33 -04:00
typedef DynamicGraph<ContractorEdgeData> ContractorGraph;
// typedef BinaryHeap< NodeID, NodeID, int, ContractorHeapData, ArrayStorage<NodeID, NodeID>
// > ContractorHeap;
typedef BinaryHeap<NodeID, NodeID, int, ContractorHeapData, XORFastHashStorage<NodeID, NodeID>>
ContractorHeap;
typedef ContractorGraph::InputEdge ContractorEdge;
2014-05-09 08:21:33 -04:00
struct ContractorThreadData
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
ContractorHeap heap;
std::vector<ContractorEdge> inserted_edges;
2014-05-08 17:07:16 -04:00
std::vector<NodeID> neighbours;
2014-05-09 08:21:33 -04:00
ContractorThreadData(NodeID nodes) : heap(nodes) {}
};
2014-05-09 08:21:33 -04:00
struct NodePriorityData
2014-05-08 17:07:16 -04:00
{
int depth;
2014-05-09 08:21:33 -04:00
NodePriorityData() : depth(0) {}
};
2014-05-09 08:21:33 -04:00
struct ContractionStats
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
int edges_deleted_count;
int edges_added_count;
int original_edges_deleted_count;
int original_edges_added_count;
ContractionStats()
: edges_deleted_count(0), edges_added_count(0), original_edges_deleted_count(0),
original_edges_added_count(0)
2014-05-08 17:07:16 -04:00
{
}
};
2014-05-09 08:21:33 -04:00
struct RemainingNodeData
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
RemainingNodeData() : id(0), is_independent(false) {}
2014-05-08 17:07:16 -04:00
NodeID id : 31;
2014-05-09 08:21:33 -04:00
bool is_independent : 1;
};
2010-07-09 05:05:40 -04:00
2014-05-20 17:57:48 -04:00
struct ThreadDataContainer
{
ThreadDataContainer(int number_of_nodes) : number_of_nodes(number_of_nodes) {}
inline ContractorThreadData* getThreadData()
{
bool exists = false;
auto& ref = data.local(exists);
if (!exists)
{
ref = std::make_shared<ContractorThreadData>(number_of_nodes);
}
return ref.get();
}
int number_of_nodes;
typedef tbb::enumerable_thread_specific<std::shared_ptr<ContractorThreadData>> EnumerableThreadData;
EnumerableThreadData data;
};
2014-05-08 17:07:16 -04:00
public:
2014-05-09 08:21:33 -04:00
template <class ContainerT> Contractor(int nodes, ContainerT &input_edge_list)
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
std::vector<ContractorEdge> edges;
edges.reserve(input_edge_list.size() * 2);
const auto dend = input_edge_list.dend();
for (auto diter = input_edge_list.dbegin(); diter != dend; ++diter)
2014-05-08 17:07:16 -04:00
{
BOOST_ASSERT_MSG(static_cast<unsigned int>(std::max(diter->weight, 1)) > 0, "edge distance < 1");
2012-04-25 08:21:03 -04:00
#ifndef NDEBUG
if (static_cast<unsigned int>(std::max(diter->weight, 1)) > 24 * 60 * 60 * 10)
2014-05-08 17:07:16 -04:00
{
SimpleLogger().Write(logWARNING) << "Edge weight large -> "
<< static_cast<unsigned int>(std::max(diter->weight, 1));
}
2011-03-15 11:19:20 -04:00
#endif
edges.emplace_back(diter->source, diter->target,
static_cast<unsigned int>(std::max(diter->weight, 1)),
1,
diter->edge_id,
false,
diter->forward ? true : false,
diter->backward ? true : false);
edges.emplace_back(diter->target, diter->source,
static_cast<unsigned int>(std::max(diter->weight, 1)),
1,
diter->edge_id,
false,
diter->backward ? true : false,
diter->forward ? true : false);
}
// clear input vector
2014-05-09 08:21:33 -04:00
input_edge_list.clear();
edges.shrink_to_fit();
tbb::parallel_sort(edges.begin(), edges.end());
NodeID edge = 0;
2014-05-08 17:07:16 -04:00
for (NodeID i = 0; i < edges.size();)
{
const NodeID source = edges[i].source;
const NodeID target = edges[i].target;
const NodeID id = edges[i].data.id;
2014-05-08 17:07:16 -04:00
// remove eigenloops
if (source == target)
{
++i;
continue;
}
2014-05-09 08:21:33 -04:00
ContractorEdge forward_edge;
ContractorEdge reverse_edge;
forward_edge.source = reverse_edge.source = source;
forward_edge.target = reverse_edge.target = target;
forward_edge.data.forward = reverse_edge.data.backward = true;
forward_edge.data.backward = reverse_edge.data.forward = false;
forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
forward_edge.data.id = reverse_edge.data.id = id;
forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1;
forward_edge.data.distance = reverse_edge.data.distance =
2014-05-08 17:07:16 -04:00
std::numeric_limits<int>::max();
// remove parallel edges
while (i < edges.size() && edges[i].source == source && edges[i].target == target)
{
if (edges[i].data.forward)
{
2014-05-09 08:21:33 -04:00
forward_edge.data.distance =
std::min(edges[i].data.distance, forward_edge.data.distance);
2013-01-27 08:16:32 -05:00
}
2014-05-08 17:07:16 -04:00
if (edges[i].data.backward)
{
2014-05-09 08:21:33 -04:00
reverse_edge.data.distance =
std::min(edges[i].data.distance, reverse_edge.data.distance);
2013-01-27 08:16:32 -05:00
}
++i;
}
2014-05-08 17:07:16 -04:00
// merge edges (s,t) and (t,s) into bidirectional edge
2014-05-09 08:21:33 -04:00
if (forward_edge.data.distance == reverse_edge.data.distance)
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
if ((int)forward_edge.data.distance != std::numeric_limits<int>::max())
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
forward_edge.data.backward = true;
edges[edge++] = forward_edge;
}
2014-05-08 17:07:16 -04:00
}
else
{ // insert seperate edges
2014-05-09 08:21:33 -04:00
if (((int)forward_edge.data.distance) != std::numeric_limits<int>::max())
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
edges[edge++] = forward_edge;
}
2014-05-09 08:21:33 -04:00
if ((int)reverse_edge.data.distance != std::numeric_limits<int>::max())
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
edges[edge++] = reverse_edge;
}
}
}
2014-05-08 17:07:16 -04:00
std::cout << "merged " << edges.size() - edge << " edges out of " << edges.size()
<< std::endl;
edges.resize(edge);
2014-05-09 08:21:33 -04:00
contractor_graph = std::make_shared<ContractorGraph>(nodes, edges);
edges.clear();
2014-05-09 08:21:33 -04:00
edges.shrink_to_fit();
2014-05-08 17:07:16 -04:00
BOOST_ASSERT(0 == edges.capacity());
// unsigned maxdegree = 0;
// NodeID highestNode = 0;
//
2014-05-09 08:21:33 -04:00
// for(unsigned i = 0; i < contractor_graph->GetNumberOfNodes(); ++i) {
// unsigned degree = contractor_graph->EndEdges(i) -
// contractor_graph->BeginEdges(i);
// if(degree > maxdegree) {
// maxdegree = degree;
// highestNode = i;
// }
// }
//
2014-05-08 17:07:16 -04:00
// SimpleLogger().Write() << "edges at node with id " << highestNode << " has degree
// " << maxdegree;
2014-05-09 08:21:33 -04:00
// for(unsigned i = contractor_graph->BeginEdges(highestNode); i <
// contractor_graph->EndEdges(highestNode); ++i) {
// SimpleLogger().Write() << " ->(" << highestNode << "," <<
// contractor_graph->GetTarget(i)
// << "); via: " << contractor_graph->GetEdgeData(i).via;
// }
2012-03-07 02:49:10 -05:00
std::cout << "contractor finished initalization" << std::endl;
}
~Contractor() { }
2014-05-08 17:07:16 -04:00
void Run()
{
2014-05-20 17:57:48 -04:00
// for the preperation we can use a big grain size, which is much faster (probably cache)
constexpr size_t InitGrainSize = 100000;
constexpr size_t PQGrainSize = 100000;
// auto_partitioner will automatically increase the blocksize if we have
// a lot of data. It is *important* for the last loop iterations
// (which have a very small dataset) that it is devisible.
constexpr size_t IndependentGrainSize = 1;
constexpr size_t ContractGrainSize = 1;
constexpr size_t NeighboursGrainSize = 1;
constexpr size_t DeleteGrainSize = 1;
2014-05-09 08:21:33 -04:00
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
Percent p(number_of_nodes);
2014-05-20 17:57:48 -04:00
ThreadDataContainer thread_data_list(number_of_nodes);
2014-05-09 08:21:33 -04:00
NodeID number_of_contracted_nodes = 0;
std::vector<RemainingNodeData> remaining_nodes(number_of_nodes);
std::vector<float> node_priorities(number_of_nodes);
std::vector<NodePriorityData> node_data(number_of_nodes);
2014-05-20 17:57:48 -04:00
// initialize priorities in parallel
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, InitGrainSize),
[&remaining_nodes](const tbb::blocked_range<int>& range)
{
for (int x = range.begin(); x != range.end(); ++x)
{
remaining_nodes[x].id = x;
}
}
);
2010-07-09 05:05:40 -04:00
std::cout << "initializing elimination PQ ..." << std::flush;
2014-05-20 17:57:48 -04:00
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
[this, &node_priorities, &node_data, &thread_data_list](const tbb::blocked_range<int>& range)
2014-05-08 17:07:16 -04:00
{
2014-05-20 17:57:48 -04:00
ContractorThreadData *data = thread_data_list.getThreadData();
for (int x = range.begin(); x != range.end(); ++x)
{
node_priorities[x] = this->EvaluateNodePriority(data, &node_data[x], x);
}
}
2014-05-20 17:57:48 -04:00
);
2014-05-09 08:21:33 -04:00
std::cout << "ok" << std::endl << "preprocessing " << number_of_nodes << " nodes ..."
2014-05-08 17:07:16 -04:00
<< std::flush;
2014-05-09 08:21:33 -04:00
bool flushed_contractor = false;
while (number_of_nodes > 2 && number_of_contracted_nodes < number_of_nodes)
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
if (!flushed_contractor && (number_of_contracted_nodes > (number_of_nodes * 0.65)))
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
DeallocatingVector<ContractorEdge> new_edge_set; // this one is not explicitely
// cleared since it goes out of
// scope anywa
std::cout << " [flush " << number_of_contracted_nodes << " nodes] " << std::flush;
// Delete old heap data to free memory that we need for the coming operations
2014-05-20 17:57:48 -04:00
thread_data_list.data.clear();
2014-05-08 17:07:16 -04:00
// Create new priority array
2014-05-09 08:21:33 -04:00
std::vector<float> new_node_priority(remaining_nodes.size());
2014-05-08 17:07:16 -04:00
// this map gives the old IDs from the new ones, necessary to get a consistent graph
// at the end of contraction
2014-05-09 08:21:33 -04:00
orig_node_id_to_new_id_map.resize(remaining_nodes.size());
2014-05-08 17:07:16 -04:00
// this map gives the new IDs from the old ones, necessary to remap targets from the
// remaining graph
2014-05-09 08:21:33 -04:00
std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, UINT_MAX);
2014-05-09 08:21:33 -04:00
// build forward and backward renumbering map and remap ids in remaining_nodes and
2014-05-08 17:07:16 -04:00
// Priorities.
2014-08-05 11:19:09 -04:00
for (const auto new_node_id : osrm::irange<std::size_t>(0, remaining_nodes.size()))
2014-05-08 17:07:16 -04:00
{
// create renumbering maps in both directions
2014-05-09 08:21:33 -04:00
orig_node_id_to_new_id_map[new_node_id] = remaining_nodes[new_node_id].id;
new_node_id_from_orig_id_map[remaining_nodes[new_node_id].id] = new_node_id;
new_node_priority[new_node_id] =
node_priorities[remaining_nodes[new_node_id].id];
remaining_nodes[new_node_id].id = new_node_id;
}
2014-05-08 17:07:16 -04:00
// walk over all nodes
2014-08-05 11:19:09 -04:00
for (const auto i : osrm::irange<std::size_t>(0, contractor_graph->GetNumberOfNodes()))
2014-05-08 17:07:16 -04:00
{
2014-05-28 12:19:27 -04:00
const NodeID source = i;
for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(source))
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
ContractorGraph::EdgeData &data =
contractor_graph->GetEdgeData(current_edge);
const NodeID target = contractor_graph->GetTarget(current_edge);
if (SPECIAL_NODEID == new_node_id_from_orig_id_map[i])
2014-05-08 17:07:16 -04:00
{
external_edge_list.push_back({source, target, data});
2014-05-08 17:07:16 -04:00
}
else
{
// node is not yet contracted.
// add (renumbered) outgoing edges to new DynamicGraph.
ContractorEdge new_edge = {
new_node_id_from_orig_id_map[source],
new_node_id_from_orig_id_map[target],
data
};
2014-05-09 08:21:33 -04:00
new_edge.data.is_original_via_node_ID = true;
2014-05-28 12:19:27 -04:00
BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[source],
"new source id not resolveable");
2014-05-09 08:21:33 -04:00
BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[target],
2014-05-08 17:07:16 -04:00
"new target id not resolveable");
2014-05-09 08:21:33 -04:00
new_edge_set.push_back(new_edge);
}
}
}
2014-05-08 17:07:16 -04:00
// Delete map from old NodeIDs to new ones.
2014-05-09 08:21:33 -04:00
new_node_id_from_orig_id_map.clear();
new_node_id_from_orig_id_map.shrink_to_fit();
2014-05-08 17:07:16 -04:00
// Replace old priorities array by new one
2014-05-09 08:21:33 -04:00
node_priorities.swap(new_node_priority);
// Delete old node_priorities vector
new_node_priority.clear();
new_node_priority.shrink_to_fit();
2014-05-08 17:07:16 -04:00
// old Graph is removed
2014-05-09 08:21:33 -04:00
contractor_graph.reset();
2012-05-08 13:46:01 -04:00
2014-05-08 17:07:16 -04:00
// create new graph
2014-05-09 08:21:33 -04:00
std::sort(new_edge_set.begin(), new_edge_set.end());
contractor_graph =
std::make_shared<ContractorGraph>(remaining_nodes.size(), new_edge_set);
2014-05-09 08:21:33 -04:00
new_edge_set.clear();
flushed_contractor = true;
2014-05-08 17:07:16 -04:00
// INFO: MAKE SURE THIS IS THE LAST OPERATION OF THE FLUSH!
// reinitialize heaps and ThreadData objects with appropriate size
2014-05-20 17:57:48 -04:00
thread_data_list.number_of_nodes = contractor_graph->GetNumberOfNodes();
}
2014-05-09 08:21:33 -04:00
const int last = (int)remaining_nodes.size();
2014-05-20 17:57:48 -04:00
tbb::parallel_for(tbb::blocked_range<int>(0, last, IndependentGrainSize),
[this, &node_priorities, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
2014-05-08 17:07:16 -04:00
{
2014-05-20 17:57:48 -04:00
ContractorThreadData *data = thread_data_list.getThreadData();
// determine independent node set
for (int i = range.begin(); i != range.end(); ++i)
{
const NodeID node = remaining_nodes[i].id;
remaining_nodes[i].is_independent =
this->IsNodeIndependent(node_priorities, data, node);
}
}
2014-05-20 17:57:48 -04:00
);
2014-05-09 08:21:33 -04:00
const auto first = stable_partition(remaining_nodes.begin(),
remaining_nodes.end(),
[](RemainingNodeData node_data)
{ return !node_data.is_independent; });
2014-06-18 04:43:26 -04:00
const int first_independent_node = static_cast<int>(first - remaining_nodes.begin());
2014-05-20 17:57:48 -04:00
// contract independent nodes
tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, ContractGrainSize),
[this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
2014-05-08 17:07:16 -04:00
{
2014-05-20 17:57:48 -04:00
ContractorThreadData *data = thread_data_list.getThreadData();
for (int position = range.begin(); position != range.end(); ++position)
{
2014-05-21 15:48:53 -04:00
const NodeID x = remaining_nodes[position].id;
2014-05-20 17:57:48 -04:00
this->ContractNode<false>(data, x);
}
}
2014-05-20 17:57:48 -04:00
);
// make sure we really sort each block
tbb::parallel_for(thread_data_list.data.range(),
[&](const ThreadDataContainer::EnumerableThreadData::range_type& range)
2014-05-08 17:07:16 -04:00
{
2014-05-20 17:57:48 -04:00
for (auto& data : range)
std::sort(data->inserted_edges.begin(),
data->inserted_edges.end());
}
2014-05-20 17:57:48 -04:00
);
tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, DeleteGrainSize),
[this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
{
ContractorThreadData *data = thread_data_list.getThreadData();
for (int position = range.begin(); position != range.end(); ++position)
{
2014-05-21 15:48:53 -04:00
const NodeID x = remaining_nodes[position].id;
2014-05-20 17:57:48 -04:00
this->DeleteIncomingEdges(data, x);
}
}
);
2014-05-09 08:21:33 -04:00
// insert new edges
2014-05-20 17:57:48 -04:00
for (auto& data : thread_data_list.data)
2014-05-09 08:21:33 -04:00
{
2014-05-20 17:57:48 -04:00
for (const ContractorEdge &edge : data->inserted_edges)
2014-05-09 08:21:33 -04:00
{
2014-05-21 15:48:53 -04:00
const EdgeID current_edge_ID = contractor_graph->FindEdge(edge.source, edge.target);
2014-05-09 08:21:33 -04:00
if (current_edge_ID < contractor_graph->EndEdges(edge.source))
{
ContractorGraph::EdgeData &current_data =
contractor_graph->GetEdgeData(current_edge_ID);
if (current_data.shortcut && edge.data.forward == current_data.forward &&
edge.data.backward == current_data.backward &&
edge.data.distance < current_data.distance)
2014-05-08 17:07:16 -04:00
{
// found a duplicate edge with smaller weight, update it.
2014-05-09 08:21:33 -04:00
current_data = edge.data;
continue;
}
}
2014-05-09 08:21:33 -04:00
contractor_graph->InsertEdge(edge.source, edge.target, edge.data);
}
2014-05-20 17:57:48 -04:00
data->inserted_edges.clear();
}
2014-05-20 17:57:48 -04:00
tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, NeighboursGrainSize),
[this, &remaining_nodes, &node_priorities, &node_data, &thread_data_list](const tbb::blocked_range<int>& range)
2014-05-08 17:07:16 -04:00
{
2014-05-20 17:57:48 -04:00
ContractorThreadData *data = thread_data_list.getThreadData();
for (int position = range.begin(); position != range.end(); ++position)
{
NodeID x = remaining_nodes[position].id;
this->UpdateNodeNeighbours(node_priorities, node_data, data, x);
}
}
2014-05-20 17:57:48 -04:00
);
2014-05-08 17:07:16 -04:00
// remove contracted nodes from the pool
2014-05-09 08:21:33 -04:00
number_of_contracted_nodes += last - first_independent_node;
remaining_nodes.resize(first_independent_node);
remaining_nodes.shrink_to_fit();
// unsigned maxdegree = 0;
// unsigned avgdegree = 0;
// unsigned mindegree = UINT_MAX;
// unsigned quaddegree = 0;
//
2014-05-09 08:21:33 -04:00
// for(unsigned i = 0; i < remaining_nodes.size(); ++i) {
// unsigned degree = contractor_graph->EndEdges(remaining_nodes[i].first)
// -
// contractor_graph->BeginEdges(remaining_nodes[i].first);
// if(degree > maxdegree)
// maxdegree = degree;
// if(degree < mindegree)
// mindegree = degree;
//
// avgdegree += degree;
// quaddegree += (degree*degree);
// }
//
2014-05-09 08:21:33 -04:00
// avgdegree /= std::max((unsigned)1,(unsigned)remaining_nodes.size() );
// quaddegree /= std::max((unsigned)1,(unsigned)remaining_nodes.size() );
//
2014-05-09 08:21:33 -04:00
// SimpleLogger().Write() << "rest: " << remaining_nodes.size() << ", max: "
2014-05-08 17:07:16 -04:00
// << maxdegree << ", min: " << mindegree << ", avg: " << avgdegree << ",
// quad: " << quaddegree;
2012-03-07 02:49:10 -05:00
2014-05-09 08:21:33 -04:00
p.printStatus(number_of_contracted_nodes);
}
2014-05-20 17:57:48 -04:00
thread_data_list.data.clear();
}
2014-05-08 17:07:16 -04:00
template <class Edge> inline void GetEdges(DeallocatingVector<Edge> &edges)
{
2014-05-09 08:21:33 -04:00
Percent p(contractor_graph->GetNumberOfNodes());
SimpleLogger().Write() << "Getting edges of minimized graph";
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
2014-05-09 08:21:33 -04:00
if (contractor_graph->GetNumberOfNodes())
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
Edge new_edge;
2014-08-05 11:19:09 -04:00
for (const auto node : osrm::irange(0u, number_of_nodes))
2014-05-08 17:07:16 -04:00
{
p.printStatus(node);
for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
const NodeID target = contractor_graph->GetTarget(edge);
const ContractorGraph::EdgeData &data = contractor_graph->GetEdgeData(edge);
if (!orig_node_id_to_new_id_map.empty())
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
new_edge.source = orig_node_id_to_new_id_map[node];
new_edge.target = orig_node_id_to_new_id_map[target];
2014-05-08 17:07:16 -04:00
}
else
{
2014-05-09 08:21:33 -04:00
new_edge.source = node;
new_edge.target = target;
2013-06-25 13:27:03 -04:00
}
2014-05-09 08:21:33 -04:00
BOOST_ASSERT_MSG(UINT_MAX != new_edge.source, "Source id invalid");
BOOST_ASSERT_MSG(UINT_MAX != new_edge.target, "Target id invalid");
new_edge.data.distance = data.distance;
new_edge.data.shortcut = data.shortcut;
if (!data.is_original_via_node_ID && !orig_node_id_to_new_id_map.empty())
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
new_edge.data.id = orig_node_id_to_new_id_map[data.id];
2014-05-08 17:07:16 -04:00
}
else
{
2014-05-09 08:21:33 -04:00
new_edge.data.id = data.id;
2013-06-25 13:27:03 -04:00
}
2014-05-09 08:21:33 -04:00
BOOST_ASSERT_MSG(new_edge.data.id != INT_MAX, // 2^31
2014-05-08 17:07:16 -04:00
"edge id invalid");
2014-05-09 08:21:33 -04:00
new_edge.data.forward = data.forward;
new_edge.data.backward = data.backward;
edges.push_back(new_edge);
}
}
}
2014-05-09 08:21:33 -04:00
contractor_graph.reset();
orig_node_id_to_new_id_map.clear();
orig_node_id_to_new_id_map.shrink_to_fit();
2014-05-09 08:21:33 -04:00
BOOST_ASSERT(0 == orig_node_id_to_new_id_map.capacity());
2013-11-29 10:27:26 -05:00
edges.append(external_edge_list.begin(), external_edge_list.end());
external_edge_list.clear();
}
2014-05-08 17:07:16 -04:00
private:
2014-05-09 08:21:33 -04:00
inline void Dijkstra(const int max_distance,
const unsigned number_of_targets,
const int maxNodes,
ContractorThreadData *const data,
const NodeID middleNode)
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
ContractorHeap &heap = data->heap;
int nodes = 0;
2014-05-09 08:21:33 -04:00
unsigned number_of_targets_found = 0;
while (!heap.Empty())
2014-05-08 17:07:16 -04:00
{
const NodeID node = heap.DeleteMin();
2014-05-08 17:07:16 -04:00
const int distance = heap.GetKey(node);
2014-05-09 08:21:33 -04:00
const short current_hop = heap.GetData(node).hop + 1;
2014-05-08 17:07:16 -04:00
if (++nodes > maxNodes)
2014-05-09 08:21:33 -04:00
{
return;
2014-05-09 08:21:33 -04:00
}
if (distance > max_distance)
{
return;
2014-05-09 08:21:33 -04:00
}
// Destination settled?
2014-05-08 17:07:16 -04:00
if (heap.GetData(node).target)
{
2014-05-09 08:21:33 -04:00
++number_of_targets_found;
if (number_of_targets_found >= number_of_targets)
2014-05-08 17:07:16 -04:00
{
return;
2013-06-24 16:05:27 -04:00
}
}
2014-05-08 17:07:16 -04:00
// iterate over all edges of node
for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
const ContractorEdgeData &data = contractor_graph->GetEdgeData(edge);
2014-05-08 17:07:16 -04:00
if (!data.forward)
{
continue;
2013-06-25 13:27:03 -04:00
}
2014-05-09 08:21:33 -04:00
const NodeID to = contractor_graph->GetTarget(edge);
2014-05-08 17:07:16 -04:00
if (middleNode == to)
{
continue;
2013-06-25 13:27:03 -04:00
}
2014-05-09 08:21:33 -04:00
const int to_distance = distance + data.distance;
2014-05-08 17:07:16 -04:00
// New Node discovered -> Add to Heap + Node Info Storage
if (!heap.WasInserted(to))
{
2014-05-09 08:21:33 -04:00
heap.Insert(to, to_distance, ContractorHeapData(current_hop, false));
2013-06-24 16:05:27 -04:00
}
2014-05-08 17:07:16 -04:00
// Found a shorter Path -> Update distance
2014-05-09 08:21:33 -04:00
else if (to_distance < heap.GetKey(to))
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
heap.DecreaseKey(to, to_distance);
heap.GetData(to).hop = current_hop;
}
}
}
}
2014-05-09 08:21:33 -04:00
inline float EvaluateNodePriority(ContractorThreadData *const data,
NodePriorityData *const node_data,
const NodeID node)
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
ContractionStats stats;
2014-05-08 17:07:16 -04:00
// perform simulated contraction
2014-05-09 08:21:33 -04:00
ContractNode<true>(data, node, &stats);
// Result will contain the priority
2012-05-25 05:41:52 -04:00
float result;
2014-05-09 08:21:33 -04:00
if (0 == (stats.edges_deleted_count * stats.original_edges_deleted_count))
{
2014-06-18 04:43:26 -04:00
result = 1.f * node_data->depth;
2014-05-09 08:21:33 -04:00
}
2012-03-07 02:49:10 -05:00
else
2014-05-09 08:21:33 -04:00
{
2014-06-18 04:43:26 -04:00
result = 2.f * (((float)stats.edges_added_count) / stats.edges_deleted_count) +
4.f * (((float)stats.original_edges_added_count) /
stats.original_edges_deleted_count) +
1.f * node_data->depth;
2014-05-09 08:21:33 -04:00
}
BOOST_ASSERT(result >= 0);
2012-03-07 02:49:10 -05:00
return result;
}
2014-05-09 08:21:33 -04:00
template <bool RUNSIMULATION>
inline bool
ContractNode(ContractorThreadData *data, const NodeID node, ContractionStats *stats = nullptr)
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
ContractorHeap &heap = data->heap;
int inserted_edges_size = data->inserted_edges.size();
std::vector<ContractorEdge> &inserted_edges = data->inserted_edges;
for (auto in_edge : contractor_graph->GetAdjacentEdgeRange(node))
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
const ContractorEdgeData &in_data = contractor_graph->GetEdgeData(in_edge);
const NodeID source = contractor_graph->GetTarget(in_edge);
if (RUNSIMULATION)
2014-05-08 17:07:16 -04:00
{
BOOST_ASSERT(stats != nullptr);
2014-05-09 08:21:33 -04:00
++stats->edges_deleted_count;
stats->original_edges_deleted_count += in_data.originalEdges;
}
2014-05-09 08:21:33 -04:00
if (!in_data.backward)
{
continue;
2014-05-09 08:21:33 -04:00
}
heap.Clear();
2014-05-09 08:21:33 -04:00
heap.Insert(source, 0, ContractorHeapData());
int max_distance = 0;
unsigned number_of_targets = 0;
for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge);
if (!out_data.forward)
2014-05-08 17:07:16 -04:00
{
continue;
2013-06-25 13:27:03 -04:00
}
2014-05-09 08:21:33 -04:00
const NodeID target = contractor_graph->GetTarget(out_edge);
const int path_distance = in_data.distance + out_data.distance;
max_distance = std::max(max_distance, path_distance);
2014-05-08 17:07:16 -04:00
if (!heap.WasInserted(target))
{
2014-05-09 08:21:33 -04:00
heap.Insert(target, INT_MAX, ContractorHeapData(0, true));
++number_of_targets;
}
}
2014-05-09 08:21:33 -04:00
if (RUNSIMULATION)
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
Dijkstra(max_distance, number_of_targets, 1000, data, node);
2014-05-08 17:07:16 -04:00
}
else
{
2014-05-09 08:21:33 -04:00
Dijkstra(max_distance, number_of_targets, 2000, data, node);
2013-06-25 13:27:03 -04:00
}
for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge);
if (!out_data.forward)
2014-05-08 17:07:16 -04:00
{
continue;
2013-06-25 13:27:03 -04:00
}
2014-05-09 08:21:33 -04:00
const NodeID target = contractor_graph->GetTarget(out_edge);
const int path_distance = in_data.distance + out_data.distance;
2014-05-08 17:07:16 -04:00
const int distance = heap.GetKey(target);
2014-05-09 08:21:33 -04:00
if (path_distance < distance)
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
if (RUNSIMULATION)
2014-05-08 17:07:16 -04:00
{
BOOST_ASSERT(stats != nullptr);
2014-05-09 08:21:33 -04:00
stats->edges_added_count += 2;
stats->original_edges_added_count +=
2 * (out_data.originalEdges + in_data.originalEdges);
2014-05-08 17:07:16 -04:00
}
else
{
inserted_edges.emplace_back(source, target, path_distance,
out_data.originalEdges + in_data.originalEdges,
node,
true,
true,
false);
inserted_edges.emplace_back(target, source, path_distance,
out_data.originalEdges + in_data.originalEdges,
node,
true,
false,
true);
}
}
}
}
2014-05-09 08:21:33 -04:00
if (!RUNSIMULATION)
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
int iend = inserted_edges.size();
for (int i = inserted_edges_size; i < iend; ++i)
2014-05-08 17:07:16 -04:00
{
bool found = false;
2014-05-08 17:07:16 -04:00
for (int other = i + 1; other < iend; ++other)
{
2014-05-09 08:21:33 -04:00
if (inserted_edges[other].source != inserted_edges[i].source)
{
continue;
2014-05-09 08:21:33 -04:00
}
if (inserted_edges[other].target != inserted_edges[i].target)
{
continue;
2014-05-09 08:21:33 -04:00
}
if (inserted_edges[other].data.distance != inserted_edges[i].data.distance)
{
continue;
2014-05-09 08:21:33 -04:00
}
if (inserted_edges[other].data.shortcut != inserted_edges[i].data.shortcut)
{
continue;
2014-05-09 08:21:33 -04:00
}
inserted_edges[other].data.forward |= inserted_edges[i].data.forward;
inserted_edges[other].data.backward |= inserted_edges[i].data.backward;
found = true;
break;
}
2014-05-09 08:21:33 -04:00
if (!found)
{
inserted_edges[inserted_edges_size++] = inserted_edges[i];
2013-06-25 13:27:03 -04:00
}
}
2014-05-09 08:21:33 -04:00
inserted_edges.resize(inserted_edges_size);
}
return true;
}
2014-05-09 08:21:33 -04:00
inline void DeleteIncomingEdges(ContractorThreadData *data, const NodeID node)
2014-05-08 17:07:16 -04:00
{
std::vector<NodeID> &neighbours = data->neighbours;
neighbours.clear();
2014-05-08 17:07:16 -04:00
// find all neighbours
for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
const NodeID u = contractor_graph->GetTarget(e);
2014-05-08 17:07:16 -04:00
if (u != node)
2014-05-09 08:21:33 -04:00
{
2014-05-08 17:07:16 -04:00
neighbours.push_back(u);
2014-05-09 08:21:33 -04:00
}
}
2014-05-08 17:07:16 -04:00
// eliminate duplicate entries ( forward + backward edges )
std::sort(neighbours.begin(), neighbours.end());
neighbours.resize(std::unique(neighbours.begin(), neighbours.end()) - neighbours.begin());
2014-08-05 11:19:09 -04:00
for (const auto i : osrm::irange<std::size_t>(0, neighbours.size()))
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
contractor_graph->DeleteEdgesTo(neighbours[i], node);
}
}
2014-05-09 08:21:33 -04:00
inline bool UpdateNodeNeighbours(std::vector<float> &priorities,
std::vector<NodePriorityData> &node_data,
ContractorThreadData *const data,
const NodeID node)
2014-05-08 17:07:16 -04:00
{
std::vector<NodeID> &neighbours = data->neighbours;
neighbours.clear();
2014-05-08 17:07:16 -04:00
// find all neighbours
for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
const NodeID u = contractor_graph->GetTarget(e);
2014-05-08 17:07:16 -04:00
if (u == node)
2014-05-09 08:21:33 -04:00
{
continue;
2014-05-09 08:21:33 -04:00
}
2014-05-08 17:07:16 -04:00
neighbours.push_back(u);
2014-05-09 08:21:33 -04:00
node_data[u].depth = (std::max)(node_data[node].depth + 1, node_data[u].depth);
}
2014-05-08 17:07:16 -04:00
// eliminate duplicate entries ( forward + backward edges )
std::sort(neighbours.begin(), neighbours.end());
neighbours.resize(std::unique(neighbours.begin(), neighbours.end()) - neighbours.begin());
2014-05-09 08:21:33 -04:00
// re-evaluate priorities of neighboring nodes
for (const NodeID u : neighbours)
{
priorities[u] = EvaluateNodePriority(data, &(node_data)[u], u);
}
return true;
}
2014-05-09 08:21:33 -04:00
inline bool IsNodeIndependent(
const std::vector<float> &priorities,
2014-05-09 08:21:33 -04:00
ContractorThreadData *const data,
2014-05-08 17:07:16 -04:00
NodeID node) const
{
2014-05-09 08:21:33 -04:00
const float priority = priorities[node];
2014-05-08 17:07:16 -04:00
std::vector<NodeID> &neighbours = data->neighbours;
neighbours.clear();
for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
const NodeID target = contractor_graph->GetTarget(e);
2014-05-08 17:07:16 -04:00
if (node == target)
2014-05-09 08:21:33 -04:00
{
continue;
2014-05-09 08:21:33 -04:00
}
const float target_priority = priorities[target];
BOOST_ASSERT(target_priority >= 0);
2014-05-08 17:07:16 -04:00
// found a neighbour with lower priority?
2014-05-09 08:21:33 -04:00
if (priority > target_priority)
{
return false;
2014-05-09 08:21:33 -04:00
}
2014-05-08 17:07:16 -04:00
// tie breaking
2014-05-09 08:21:33 -04:00
if (std::abs(priority - target_priority) < std::numeric_limits<float>::epsilon() &&
2014-05-08 17:07:16 -04:00
bias(node, target))
{
return false;
}
2014-05-08 17:07:16 -04:00
neighbours.push_back(target);
}
2014-05-08 17:07:16 -04:00
std::sort(neighbours.begin(), neighbours.end());
neighbours.resize(std::unique(neighbours.begin(), neighbours.end()) - neighbours.begin());
2014-05-08 17:07:16 -04:00
// examine all neighbours that are at most 2 hops away
2014-05-09 08:21:33 -04:00
for (const NodeID u : neighbours)
2014-05-08 17:07:16 -04:00
{
for (auto e : contractor_graph->GetAdjacentEdgeRange(u))
2014-05-08 17:07:16 -04:00
{
2014-05-09 08:21:33 -04:00
const NodeID target = contractor_graph->GetTarget(e);
2014-05-08 17:07:16 -04:00
if (node == target)
2014-05-09 08:21:33 -04:00
{
continue;
2014-05-09 08:21:33 -04:00
}
const float target_priority = priorities[target];
BOOST_ASSERT(target_priority >= 0);
2014-05-09 08:21:33 -04:00
// found a neighbour with lower priority?
if (priority > target_priority)
{
return false;
2014-05-09 08:21:33 -04:00
}
// tie breaking
if (std::abs(priority - target_priority) < std::numeric_limits<float>::epsilon() &&
bias(node, target))
{
return false;
}
}
}
return true;
}
2014-05-09 08:21:33 -04:00
// This bias function takes up 22 assembly instructions in total on X86
2014-05-08 17:07:16 -04:00
inline bool bias(const NodeID a, const NodeID b) const
{
2014-07-24 05:23:33 -04:00
const unsigned short hasha = fast_hash(a);
const unsigned short hashb = fast_hash(b);
2014-05-08 17:07:16 -04:00
// The compiler optimizes that to conditional register flags but without branching
// statements!
if (hasha != hashb)
2014-05-09 08:21:33 -04:00
{
2012-05-25 05:41:52 -04:00
return hasha < hashb;
2014-05-09 08:21:33 -04:00
}
2012-05-25 05:41:52 -04:00
return a < b;
}
2014-05-09 08:21:33 -04:00
std::shared_ptr<ContractorGraph> contractor_graph;
std::vector<ContractorGraph::InputEdge> contracted_edge_list;
stxxl::vector<QueryEdge> external_edge_list;
2014-05-09 08:21:33 -04:00
std::vector<NodeID> orig_node_id_to_new_id_map;
XORFastHash fast_hash;
2010-07-09 05:05:40 -04:00
};
2014-05-09 08:21:33 -04:00
#endif // CONTRACTOR_H