2017-01-13 02:32:17 -05:00
|
|
|
#ifndef OSRM_CONTRACTOR_GRAPH_CONTRACTOR_HPP
|
|
|
|
#define OSRM_CONTRACTOR_GRAPH_CONTRACTOR_HPP
|
2016-01-07 13:19:55 -05:00
|
|
|
|
2017-01-13 02:32:17 -05:00
|
|
|
#include "contractor/contractor_dijkstra.hpp"
|
|
|
|
#include "contractor/contractor_graph.hpp"
|
2016-05-27 15:05:04 -04:00
|
|
|
#include "contractor/query_edge.hpp"
|
2016-01-07 13:19:55 -05:00
|
|
|
#include "util/deallocating_vector.hpp"
|
|
|
|
#include "util/integer_range.hpp"
|
2016-12-06 15:30:46 -05:00
|
|
|
#include "util/log.hpp"
|
2016-05-27 15:05:04 -04:00
|
|
|
#include "util/percent.hpp"
|
2016-01-07 13:19:55 -05:00
|
|
|
#include "util/timing_util.hpp"
|
|
|
|
#include "util/typedefs.hpp"
|
2016-05-27 15:05:04 -04:00
|
|
|
#include "util/xor_fast_hash.hpp"
|
2016-01-07 13:19:55 -05:00
|
|
|
|
|
|
|
#include <boost/assert.hpp>
|
|
|
|
|
|
|
|
#include <tbb/enumerable_thread_specific.h>
|
|
|
|
#include <tbb/parallel_for.h>
|
|
|
|
#include <tbb/parallel_sort.h>
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <limits>
|
|
|
|
#include <memory>
|
|
|
|
#include <vector>
|
|
|
|
|
2017-07-10 06:17:17 -04:00
|
|
|
#if USE_STXXL_LIBRARY
|
|
|
|
#include <stxxl/vector>
|
|
|
|
#endif
|
|
|
|
|
2016-01-07 13:19:55 -05:00
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace contractor
|
|
|
|
{
|
|
|
|
|
|
|
|
class GraphContractor
|
|
|
|
{
|
|
|
|
private:
|
2017-07-10 06:17:17 -04:00
|
|
|
#if USE_STXXL_LIBRARY
|
|
|
|
template <typename T> using ExternalVector = stxxl::vector<T>;
|
|
|
|
#else
|
|
|
|
template <typename T> using ExternalVector = std::vector<T>;
|
|
|
|
#endif
|
|
|
|
|
2016-01-07 13:19:55 -05:00
|
|
|
struct ContractorThreadData
|
|
|
|
{
|
2017-01-13 02:32:17 -05:00
|
|
|
ContractorDijkstra dijkstra;
|
2016-01-07 13:19:55 -05:00
|
|
|
std::vector<ContractorEdge> inserted_edges;
|
|
|
|
std::vector<NodeID> neighbours;
|
2017-01-13 02:32:17 -05:00
|
|
|
explicit ContractorThreadData(NodeID nodes) : dijkstra(nodes) {}
|
2016-01-07 13:19:55 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
using NodeDepth = int;
|
|
|
|
|
|
|
|
struct ContractionStats
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct RemainingNodeData
|
|
|
|
{
|
|
|
|
RemainingNodeData() : id(0), is_independent(false) {}
|
|
|
|
NodeID id : 31;
|
|
|
|
bool is_independent : 1;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ThreadDataContainer
|
|
|
|
{
|
|
|
|
explicit ThreadDataContainer(int number_of_nodes) : number_of_nodes(number_of_nodes) {}
|
|
|
|
|
2016-04-28 18:05:54 -04:00
|
|
|
inline ContractorThreadData *GetThreadData()
|
2016-01-07 13:19:55 -05:00
|
|
|
{
|
|
|
|
bool exists = false;
|
|
|
|
auto &ref = data.local(exists);
|
|
|
|
if (!exists)
|
|
|
|
{
|
2017-01-13 02:32:17 -05:00
|
|
|
// ref = std::make_shared<ContractorThreadData>(number_of_nodes);
|
|
|
|
ref = std::make_shared<ContractorThreadData>(4000);
|
2016-01-07 13:19:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return ref.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
int number_of_nodes;
|
|
|
|
using EnumerableThreadData =
|
|
|
|
tbb::enumerable_thread_specific<std::shared_ptr<ContractorThreadData>>;
|
|
|
|
EnumerableThreadData data;
|
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
2017-01-13 02:32:17 -05:00
|
|
|
GraphContractor(int nodes, std::vector<ContractorEdge> input_edge_list);
|
2016-01-07 13:19:55 -05:00
|
|
|
|
|
|
|
GraphContractor(int nodes,
|
2017-01-13 02:32:17 -05:00
|
|
|
std::vector<ContractorEdge> edges,
|
2017-06-15 10:52:14 -04:00
|
|
|
std::vector<float> node_levels_,
|
|
|
|
std::vector<EdgeWeight> node_weights_);
|
2016-01-07 13:19:55 -05:00
|
|
|
|
2017-01-05 04:21:01 -05:00
|
|
|
/* Flush all data from the contraction to disc and reorder stuff for better locality */
|
|
|
|
void FlushDataAndRebuildContractorGraph(ThreadDataContainer &thread_data_list,
|
|
|
|
std::vector<RemainingNodeData> &remaining_nodes,
|
2017-01-13 02:32:17 -05:00
|
|
|
std::vector<float> &node_priorities);
|
2016-01-07 13:19:55 -05:00
|
|
|
|
2017-01-13 02:32:17 -05:00
|
|
|
void Run(double core_factor = 1.0);
|
2016-01-07 13:19:55 -05:00
|
|
|
|
2017-06-15 10:52:14 -04:00
|
|
|
std::vector<bool> GetCoreMarker();
|
2016-01-07 13:19:55 -05:00
|
|
|
|
2017-06-15 10:52:14 -04:00
|
|
|
std::vector<float> GetNodeLevels();
|
2016-01-07 13:19:55 -05:00
|
|
|
|
2017-06-15 10:52:14 -04:00
|
|
|
template <class Edge> inline util::DeallocatingVector<Edge> GetEdges()
|
2016-01-07 13:19:55 -05:00
|
|
|
{
|
2017-06-15 10:52:14 -04:00
|
|
|
util::DeallocatingVector<Edge> edges;
|
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
util::UnbufferedLog log;
|
|
|
|
log << "Getting edges of minimized graph ";
|
|
|
|
util::Percent p(log, contractor_graph->GetNumberOfNodes());
|
2016-01-07 13:19:55 -05:00
|
|
|
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
|
|
|
|
if (contractor_graph->GetNumberOfNodes())
|
|
|
|
{
|
|
|
|
Edge new_edge;
|
|
|
|
for (const auto node : util::irange(0u, number_of_nodes))
|
|
|
|
{
|
2016-04-28 18:46:59 -04:00
|
|
|
p.PrintStatus(node);
|
2016-01-07 13:19:55 -05:00
|
|
|
for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
|
|
|
|
{
|
|
|
|
const NodeID target = contractor_graph->GetTarget(edge);
|
|
|
|
const ContractorGraph::EdgeData &data = contractor_graph->GetEdgeData(edge);
|
|
|
|
if (!orig_node_id_from_new_node_id_map.empty())
|
|
|
|
{
|
|
|
|
new_edge.source = orig_node_id_from_new_node_id_map[node];
|
|
|
|
new_edge.target = orig_node_id_from_new_node_id_map[target];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
new_edge.source = node;
|
|
|
|
new_edge.target = target;
|
|
|
|
}
|
|
|
|
BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.source, "Source id invalid");
|
|
|
|
BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.target, "Target id invalid");
|
2016-05-12 12:50:10 -04:00
|
|
|
new_edge.data.weight = data.weight;
|
2017-01-19 16:52:09 -05:00
|
|
|
new_edge.data.duration = data.duration;
|
2016-01-07 13:19:55 -05:00
|
|
|
new_edge.data.shortcut = data.shortcut;
|
|
|
|
if (!data.is_original_via_node_ID && !orig_node_id_from_new_node_id_map.empty())
|
|
|
|
{
|
|
|
|
// tranlate the _node id_ of the shortcutted node
|
2017-03-10 04:57:07 -05:00
|
|
|
new_edge.data.turn_id = orig_node_id_from_new_node_id_map[data.id];
|
2016-01-07 13:19:55 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-10 04:57:07 -05:00
|
|
|
new_edge.data.turn_id = data.id;
|
2016-01-07 13:19:55 -05:00
|
|
|
}
|
2017-03-10 04:57:07 -05:00
|
|
|
BOOST_ASSERT_MSG(new_edge.data.turn_id != INT_MAX, // 2^31
|
2016-01-07 13:19:55 -05:00
|
|
|
"edge id invalid");
|
|
|
|
new_edge.data.forward = data.forward;
|
|
|
|
new_edge.data.backward = data.backward;
|
|
|
|
edges.push_back(new_edge);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
contractor_graph.reset();
|
|
|
|
orig_node_id_from_new_node_id_map.clear();
|
|
|
|
orig_node_id_from_new_node_id_map.shrink_to_fit();
|
|
|
|
|
|
|
|
BOOST_ASSERT(0 == orig_node_id_from_new_node_id_map.capacity());
|
|
|
|
|
|
|
|
edges.append(external_edge_list.begin(), external_edge_list.end());
|
|
|
|
external_edge_list.clear();
|
2017-06-15 10:52:14 -04:00
|
|
|
|
|
|
|
// sort and remove duplicates
|
|
|
|
tbb::parallel_sort(edges.begin(), edges.end());
|
|
|
|
auto new_end = std::unique(edges.begin(), edges.end());
|
|
|
|
edges.resize(new_end - edges.begin());
|
|
|
|
|
|
|
|
return edges;
|
2016-01-07 13:19:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2017-01-13 02:32:17 -05:00
|
|
|
float EvaluateNodePriority(ContractorThreadData *const data,
|
|
|
|
const NodeDepth node_depth,
|
|
|
|
const NodeID node);
|
2016-01-07 13:19:55 -05:00
|
|
|
|
|
|
|
template <bool RUNSIMULATION>
|
2017-01-13 02:32:17 -05:00
|
|
|
bool
|
2016-01-07 13:19:55 -05:00
|
|
|
ContractNode(ContractorThreadData *data, const NodeID node, ContractionStats *stats = nullptr)
|
|
|
|
{
|
2017-01-13 02:32:17 -05:00
|
|
|
auto &dijkstra = data->dijkstra;
|
2016-01-07 13:19:55 -05:00
|
|
|
std::size_t inserted_edges_size = data->inserted_edges.size();
|
|
|
|
std::vector<ContractorEdge> &inserted_edges = data->inserted_edges;
|
2017-01-11 10:19:49 -05:00
|
|
|
constexpr bool SHORTCUT_ARC = true;
|
|
|
|
constexpr bool FORWARD_DIRECTION_ENABLED = true;
|
|
|
|
constexpr bool FORWARD_DIRECTION_DISABLED = false;
|
|
|
|
constexpr bool REVERSE_DIRECTION_ENABLED = true;
|
|
|
|
constexpr bool REVERSE_DIRECTION_DISABLED = false;
|
2016-01-07 13:19:55 -05:00
|
|
|
|
|
|
|
for (auto in_edge : contractor_graph->GetAdjacentEdgeRange(node))
|
|
|
|
{
|
|
|
|
const ContractorEdgeData &in_data = contractor_graph->GetEdgeData(in_edge);
|
|
|
|
const NodeID source = contractor_graph->GetTarget(in_edge);
|
|
|
|
if (source == node)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (RUNSIMULATION)
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(stats != nullptr);
|
|
|
|
++stats->edges_deleted_count;
|
|
|
|
stats->original_edges_deleted_count += in_data.originalEdges;
|
|
|
|
}
|
|
|
|
if (!in_data.backward)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-13 02:32:17 -05:00
|
|
|
dijkstra.Clear();
|
|
|
|
dijkstra.Insert(source, 0, ContractorHeapData{});
|
2016-05-12 12:50:10 -04:00
|
|
|
EdgeWeight max_weight = 0;
|
2016-01-07 13:19:55 -05:00
|
|
|
unsigned number_of_targets = 0;
|
|
|
|
|
|
|
|
for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
|
|
|
|
{
|
|
|
|
const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge);
|
|
|
|
if (!out_data.forward)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const NodeID target = contractor_graph->GetTarget(out_edge);
|
|
|
|
if (node == target)
|
2017-01-11 10:24:16 -05:00
|
|
|
{
|
2016-01-07 13:19:55 -05:00
|
|
|
continue;
|
2017-01-11 10:24:16 -05:00
|
|
|
}
|
2016-01-07 13:19:55 -05:00
|
|
|
|
2016-05-12 12:50:10 -04:00
|
|
|
const EdgeWeight path_weight = in_data.weight + out_data.weight;
|
2016-01-07 13:19:55 -05:00
|
|
|
if (target == source)
|
|
|
|
{
|
2016-05-12 12:50:10 -04:00
|
|
|
if (path_weight < node_weights[node])
|
2016-01-07 13:19:55 -05:00
|
|
|
{
|
|
|
|
if (RUNSIMULATION)
|
|
|
|
{
|
|
|
|
// make sure to prune better, but keep inserting this loop if it should
|
|
|
|
// still be the best
|
|
|
|
// CAREFUL: This only works due to the independent node-setting. This
|
|
|
|
// guarantees that source is not connected to another node that is
|
|
|
|
// contracted
|
2016-05-12 12:50:10 -04:00
|
|
|
node_weights[source] = path_weight + 1;
|
2016-01-07 13:19:55 -05:00
|
|
|
BOOST_ASSERT(stats != nullptr);
|
|
|
|
stats->edges_added_count += 2;
|
|
|
|
stats->original_edges_added_count +=
|
|
|
|
2 * (out_data.originalEdges + in_data.originalEdges);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// CAREFUL: This only works due to the independent node-setting. This
|
|
|
|
// guarantees that source is not connected to another node that is
|
|
|
|
// contracted
|
2016-05-12 12:50:10 -04:00
|
|
|
node_weights[source] = path_weight; // make sure to prune better
|
2016-05-27 15:05:04 -04:00
|
|
|
inserted_edges.emplace_back(source,
|
|
|
|
target,
|
2016-05-12 12:50:10 -04:00
|
|
|
path_weight,
|
2017-01-19 16:52:09 -05:00
|
|
|
in_data.duration + out_data.duration,
|
2016-05-27 15:05:04 -04:00
|
|
|
out_data.originalEdges +
|
|
|
|
in_data.originalEdges,
|
|
|
|
node,
|
|
|
|
SHORTCUT_ARC,
|
|
|
|
FORWARD_DIRECTION_ENABLED,
|
|
|
|
REVERSE_DIRECTION_DISABLED);
|
|
|
|
|
|
|
|
inserted_edges.emplace_back(target,
|
|
|
|
source,
|
2016-05-12 12:50:10 -04:00
|
|
|
path_weight,
|
2017-01-19 16:52:09 -05:00
|
|
|
in_data.duration + out_data.duration,
|
2016-05-27 15:05:04 -04:00
|
|
|
out_data.originalEdges +
|
|
|
|
in_data.originalEdges,
|
|
|
|
node,
|
|
|
|
SHORTCUT_ARC,
|
|
|
|
FORWARD_DIRECTION_DISABLED,
|
|
|
|
REVERSE_DIRECTION_ENABLED);
|
2016-01-07 13:19:55 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2016-05-12 12:50:10 -04:00
|
|
|
max_weight = std::max(max_weight, path_weight);
|
2017-01-13 02:32:17 -05:00
|
|
|
if (!dijkstra.WasInserted(target))
|
2016-01-07 13:19:55 -05:00
|
|
|
{
|
2017-01-13 02:32:17 -05:00
|
|
|
dijkstra.Insert(target, INVALID_EDGE_WEIGHT, ContractorHeapData{0, true});
|
2016-01-07 13:19:55 -05:00
|
|
|
++number_of_targets;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RUNSIMULATION)
|
|
|
|
{
|
|
|
|
const int constexpr SIMULATION_SEARCH_SPACE_SIZE = 1000;
|
2017-01-13 02:32:17 -05:00
|
|
|
dijkstra.Run(number_of_targets,
|
|
|
|
SIMULATION_SEARCH_SPACE_SIZE,
|
|
|
|
max_weight,
|
|
|
|
node,
|
|
|
|
*contractor_graph);
|
2016-01-07 13:19:55 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const int constexpr FULL_SEARCH_SPACE_SIZE = 2000;
|
2017-01-13 02:32:17 -05:00
|
|
|
dijkstra.Run(
|
|
|
|
number_of_targets, FULL_SEARCH_SPACE_SIZE, max_weight, node, *contractor_graph);
|
2016-01-07 13:19:55 -05:00
|
|
|
}
|
|
|
|
for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
|
|
|
|
{
|
|
|
|
const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge);
|
|
|
|
if (!out_data.forward)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const NodeID target = contractor_graph->GetTarget(out_edge);
|
|
|
|
if (target == node)
|
|
|
|
continue;
|
2017-01-19 16:52:09 -05:00
|
|
|
|
2016-05-12 12:50:10 -04:00
|
|
|
const EdgeWeight path_weight = in_data.weight + out_data.weight;
|
|
|
|
const EdgeWeight weight = dijkstra.GetKey(target);
|
2016-05-12 12:50:10 -04:00
|
|
|
if (path_weight < weight)
|
2016-01-07 13:19:55 -05:00
|
|
|
{
|
|
|
|
if (RUNSIMULATION)
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(stats != nullptr);
|
|
|
|
stats->edges_added_count += 2;
|
|
|
|
stats->original_edges_added_count +=
|
|
|
|
2 * (out_data.originalEdges + in_data.originalEdges);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-05-27 15:05:04 -04:00
|
|
|
inserted_edges.emplace_back(source,
|
|
|
|
target,
|
2016-05-12 12:50:10 -04:00
|
|
|
path_weight,
|
2017-01-19 16:52:09 -05:00
|
|
|
in_data.duration + out_data.duration,
|
2016-01-07 13:19:55 -05:00
|
|
|
out_data.originalEdges + in_data.originalEdges,
|
2016-05-27 15:05:04 -04:00
|
|
|
node,
|
|
|
|
SHORTCUT_ARC,
|
|
|
|
FORWARD_DIRECTION_ENABLED,
|
2016-01-07 13:19:55 -05:00
|
|
|
REVERSE_DIRECTION_DISABLED);
|
|
|
|
|
2016-05-27 15:05:04 -04:00
|
|
|
inserted_edges.emplace_back(target,
|
|
|
|
source,
|
2016-05-12 12:50:10 -04:00
|
|
|
path_weight,
|
2017-01-19 16:52:09 -05:00
|
|
|
in_data.duration + out_data.duration,
|
2016-01-07 13:19:55 -05:00
|
|
|
out_data.originalEdges + in_data.originalEdges,
|
2016-05-27 15:05:04 -04:00
|
|
|
node,
|
|
|
|
SHORTCUT_ARC,
|
|
|
|
FORWARD_DIRECTION_DISABLED,
|
2016-01-07 13:19:55 -05:00
|
|
|
REVERSE_DIRECTION_ENABLED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Check For One-Way Streets to decide on the creation of self-loops
|
|
|
|
|
|
|
|
if (!RUNSIMULATION)
|
|
|
|
{
|
|
|
|
std::size_t iend = inserted_edges.size();
|
|
|
|
for (std::size_t i = inserted_edges_size; i < iend; ++i)
|
|
|
|
{
|
|
|
|
bool found = false;
|
|
|
|
for (std::size_t other = i + 1; other < iend; ++other)
|
|
|
|
{
|
|
|
|
if (inserted_edges[other].source != inserted_edges[i].source)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (inserted_edges[other].target != inserted_edges[i].target)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2016-05-12 12:50:10 -04:00
|
|
|
if (inserted_edges[other].data.weight != inserted_edges[i].data.weight)
|
2016-01-07 13:19:55 -05:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (inserted_edges[other].data.shortcut != inserted_edges[i].data.shortcut)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
inserted_edges[other].data.forward |= inserted_edges[i].data.forward;
|
|
|
|
inserted_edges[other].data.backward |= inserted_edges[i].data.backward;
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!found)
|
|
|
|
{
|
|
|
|
inserted_edges[inserted_edges_size++] = inserted_edges[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
inserted_edges.resize(inserted_edges_size);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-01-13 02:32:17 -05:00
|
|
|
void DeleteIncomingEdges(ContractorThreadData *data, const NodeID node);
|
2016-01-07 13:19:55 -05:00
|
|
|
|
2017-01-13 02:32:17 -05:00
|
|
|
bool UpdateNodeNeighbours(std::vector<float> &priorities,
|
|
|
|
std::vector<NodeDepth> &node_depth,
|
|
|
|
ContractorThreadData *const data,
|
|
|
|
const NodeID node);
|
2016-01-07 13:19:55 -05:00
|
|
|
|
2017-01-13 02:32:17 -05:00
|
|
|
bool IsNodeIndependent(const std::vector<float> &priorities,
|
|
|
|
ContractorThreadData *const data,
|
|
|
|
NodeID node) const;
|
2016-01-07 13:19:55 -05:00
|
|
|
|
|
|
|
// This bias function takes up 22 assembly instructions in total on X86
|
2017-01-13 02:32:17 -05:00
|
|
|
bool Bias(const NodeID a, const NodeID b) const;
|
2016-01-07 13:19:55 -05:00
|
|
|
|
|
|
|
std::shared_ptr<ContractorGraph> contractor_graph;
|
2017-07-10 06:17:17 -04:00
|
|
|
ExternalVector<QueryEdge> external_edge_list;
|
2016-01-07 13:19:55 -05:00
|
|
|
std::vector<NodeID> orig_node_id_from_new_node_id_map;
|
|
|
|
std::vector<float> node_levels;
|
|
|
|
|
|
|
|
// A list of weights for every node in the graph.
|
|
|
|
// The weight represents the cost for a u-turn on the segment in the base-graph in addition to
|
|
|
|
// its traversal.
|
|
|
|
// During contraction, self-loops are checked against this node weight to ensure that necessary
|
|
|
|
// self-loops are added.
|
|
|
|
std::vector<EdgeWeight> node_weights;
|
|
|
|
std::vector<bool> is_core_node;
|
2016-01-21 13:17:02 -05:00
|
|
|
util::XORFastHash<> fast_hash;
|
2016-01-07 13:19:55 -05:00
|
|
|
};
|
|
|
|
|
2017-01-13 02:32:17 -05:00
|
|
|
} // namespace contractor
|
|
|
|
} // namespace osrm
|
|
|
|
|
|
|
|
#endif // OSRM_CONTRACTOR_GRAPH_CONTRACTOR_HPP
|