Cache the node priorities between runs
This speeds up processings on the same dataset significantly by creating a .level file that saves the level in which a node was contracted. It removes the need for expensive recomputation of priorities and such. Use with care! Running `osrm-extract` again will invalidate .level files.
This commit is contained in:
parent
8f3482561b
commit
63ba6018f3
@ -158,6 +158,15 @@ class Contractor
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
template <class ContainerT> Contractor(int nodes, ContainerT &input_edge_list)
|
template <class ContainerT> Contractor(int nodes, ContainerT &input_edge_list)
|
||||||
|
: Contractor(nodes, input_edge_list, {}, {})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ContainerT>
|
||||||
|
Contractor(int nodes,
|
||||||
|
ContainerT &input_edge_list,
|
||||||
|
std::vector<float> &&node_levels_)
|
||||||
|
: node_levels(std::move(node_levels_))
|
||||||
{
|
{
|
||||||
std::vector<ContractorEdge> edges;
|
std::vector<ContractorEdge> edges;
|
||||||
edges.reserve(input_edge_list.size() * 2);
|
edges.reserve(input_edge_list.size() * 2);
|
||||||
@ -305,14 +314,14 @@ class Contractor
|
|||||||
ThreadDataContainer thread_data_list(number_of_nodes);
|
ThreadDataContainer thread_data_list(number_of_nodes);
|
||||||
|
|
||||||
NodeID number_of_contracted_nodes = 0;
|
NodeID number_of_contracted_nodes = 0;
|
||||||
std::vector<RemainingNodeData> remaining_nodes(number_of_nodes);
|
std::vector<NodePriorityData> node_data;
|
||||||
std::vector<float> node_priorities(number_of_nodes);
|
std::vector<float> node_priorities;
|
||||||
std::vector<NodePriorityData> node_data(number_of_nodes);
|
|
||||||
is_core_node.resize(number_of_nodes, false);
|
is_core_node.resize(number_of_nodes, false);
|
||||||
|
|
||||||
|
std::vector<RemainingNodeData> remaining_nodes(number_of_nodes);
|
||||||
// initialize priorities in parallel
|
// initialize priorities in parallel
|
||||||
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, InitGrainSize),
|
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, InitGrainSize),
|
||||||
[&remaining_nodes](const tbb::blocked_range<int> &range)
|
[this, &remaining_nodes](const tbb::blocked_range<int> &range)
|
||||||
{
|
{
|
||||||
for (int x = range.begin(), end = range.end(); x != end; ++x)
|
for (int x = range.begin(), end = range.end(); x != end; ++x)
|
||||||
{
|
{
|
||||||
@ -320,6 +329,19 @@ class Contractor
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bool use_cached_node_priorities = !node_levels.empty();
|
||||||
|
if (use_cached_node_priorities)
|
||||||
|
{
|
||||||
|
std::cout << "using cached node priorities ..." << std::flush;
|
||||||
|
node_priorities.swap(node_levels);
|
||||||
|
std::cout << "ok" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node_data.resize(number_of_nodes);
|
||||||
|
node_priorities.resize(number_of_nodes);
|
||||||
|
node_levels.resize(number_of_nodes);
|
||||||
|
|
||||||
std::cout << "initializing elimination PQ ..." << std::flush;
|
std::cout << "initializing elimination PQ ..." << std::flush;
|
||||||
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
|
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
|
||||||
[this, &node_priorities, &node_data, &thread_data_list](
|
[this, &node_priorities, &node_data, &thread_data_list](
|
||||||
@ -332,9 +354,13 @@ class Contractor
|
|||||||
this->EvaluateNodePriority(data, &node_data[x], x);
|
this->EvaluateNodePriority(data, &node_data[x], x);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
std::cout << "ok" << std::endl
|
std::cout << "ok" << std::endl;
|
||||||
<< "preprocessing " << number_of_nodes << " nodes ..." << std::flush;
|
}
|
||||||
|
BOOST_ASSERT(node_priorities.size() == number_of_nodes);
|
||||||
|
|
||||||
|
std::cout << "preprocessing " << number_of_nodes << " nodes ..." << std::flush;
|
||||||
|
|
||||||
|
unsigned current_level = 0;
|
||||||
bool flushed_contractor = false;
|
bool flushed_contractor = false;
|
||||||
while (number_of_nodes > 2 &&
|
while (number_of_nodes > 2 &&
|
||||||
number_of_contracted_nodes < static_cast<NodeID>(number_of_nodes * core_factor))
|
number_of_contracted_nodes < static_cast<NodeID>(number_of_nodes * core_factor))
|
||||||
@ -359,29 +385,32 @@ class Contractor
|
|||||||
// remaining graph
|
// remaining graph
|
||||||
std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, UINT_MAX);
|
std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, UINT_MAX);
|
||||||
|
|
||||||
// build forward and backward renumbering map and remap ids in remaining_nodes and
|
|
||||||
// Priorities.
|
|
||||||
for (const auto new_node_id : osrm::irange<std::size_t>(0, remaining_nodes.size()))
|
for (const auto new_node_id : osrm::irange<std::size_t>(0, remaining_nodes.size()))
|
||||||
{
|
{
|
||||||
|
auto& node = remaining_nodes[new_node_id];
|
||||||
|
BOOST_ASSERT(node_priorities.size() > node.id);
|
||||||
|
new_node_priority[new_node_id] = node_priorities[node.id];
|
||||||
|
}
|
||||||
|
|
||||||
|
// build forward and backward renumbering map and remap ids in remaining_nodes
|
||||||
|
for (const auto new_node_id : osrm::irange<std::size_t>(0, remaining_nodes.size()))
|
||||||
|
{
|
||||||
|
auto& node = remaining_nodes[new_node_id];
|
||||||
// create renumbering maps in both directions
|
// create renumbering maps in both directions
|
||||||
orig_node_id_from_new_node_id_map[new_node_id] =
|
orig_node_id_from_new_node_id_map[new_node_id] = node.id;
|
||||||
remaining_nodes[new_node_id].id;
|
new_node_id_from_orig_id_map[node.id] = new_node_id;
|
||||||
new_node_id_from_orig_id_map[remaining_nodes[new_node_id].id] = new_node_id;
|
node.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;
|
|
||||||
}
|
}
|
||||||
// walk over all nodes
|
// walk over all nodes
|
||||||
for (const auto i :
|
for (const auto source :
|
||||||
osrm::irange<std::size_t>(0, contractor_graph->GetNumberOfNodes()))
|
osrm::irange<NodeID>(0, contractor_graph->GetNumberOfNodes()))
|
||||||
{
|
{
|
||||||
const NodeID source = i;
|
|
||||||
for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(source))
|
for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(source))
|
||||||
{
|
{
|
||||||
ContractorGraph::EdgeData &data =
|
ContractorGraph::EdgeData &data =
|
||||||
contractor_graph->GetEdgeData(current_edge);
|
contractor_graph->GetEdgeData(current_edge);
|
||||||
const NodeID target = contractor_graph->GetTarget(current_edge);
|
const NodeID target = contractor_graph->GetTarget(current_edge);
|
||||||
if (SPECIAL_NODEID == new_node_id_from_orig_id_map[i])
|
if (SPECIAL_NODEID == new_node_id_from_orig_id_map[source])
|
||||||
{
|
{
|
||||||
external_edge_list.push_back({source, target, data});
|
external_edge_list.push_back({source, target, data});
|
||||||
}
|
}
|
||||||
@ -428,14 +457,13 @@ class Contractor
|
|||||||
thread_data_list.number_of_nodes = contractor_graph->GetNumberOfNodes();
|
thread_data_list.number_of_nodes = contractor_graph->GetNumberOfNodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
const int last = (int)remaining_nodes.size();
|
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, remaining_nodes.size(), IndependentGrainSize),
|
||||||
tbb::parallel_for(tbb::blocked_range<int>(0, last, IndependentGrainSize),
|
|
||||||
[this, &node_priorities, &remaining_nodes, &thread_data_list](
|
[this, &node_priorities, &remaining_nodes, &thread_data_list](
|
||||||
const tbb::blocked_range<int> &range)
|
const tbb::blocked_range<std::size_t> &range)
|
||||||
{
|
{
|
||||||
ContractorThreadData *data = thread_data_list.getThreadData();
|
ContractorThreadData *data = thread_data_list.getThreadData();
|
||||||
// determine independent node set
|
// determine independent node set
|
||||||
for (int i = range.begin(), end = range.end(); i != end; ++i)
|
for (auto i = range.begin(), end = range.end(); i != end; ++i)
|
||||||
{
|
{
|
||||||
const NodeID node = remaining_nodes[i].id;
|
const NodeID node = remaining_nodes[i].id;
|
||||||
remaining_nodes[i].is_independent =
|
remaining_nodes[i].is_independent =
|
||||||
@ -443,17 +471,45 @@ class Contractor
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const auto first = stable_partition(remaining_nodes.begin(), remaining_nodes.end(),
|
// sort all remaining nodes to the beginning of the sequence
|
||||||
|
const auto begin_independent_nodes = stable_partition(remaining_nodes.begin(), remaining_nodes.end(),
|
||||||
[](RemainingNodeData node_data)
|
[](RemainingNodeData node_data)
|
||||||
{
|
{
|
||||||
return !node_data.is_independent;
|
return !node_data.is_independent;
|
||||||
});
|
});
|
||||||
const int first_independent_node = static_cast<int>(first - remaining_nodes.begin());
|
auto begin_independent_nodes_idx = std::distance(remaining_nodes.begin(), begin_independent_nodes);
|
||||||
|
auto end_independent_nodes_idx = remaining_nodes.size();
|
||||||
|
|
||||||
|
if (!use_cached_node_priorities)
|
||||||
|
{
|
||||||
|
// write out contraction level
|
||||||
|
tbb::parallel_for(
|
||||||
|
tbb::blocked_range<std::size_t>(begin_independent_nodes_idx, end_independent_nodes_idx, ContractGrainSize),
|
||||||
|
[this, remaining_nodes, flushed_contractor, current_level](const tbb::blocked_range<std::size_t> &range)
|
||||||
|
{
|
||||||
|
if (flushed_contractor)
|
||||||
|
{
|
||||||
|
for (int position = range.begin(), end = range.end(); position != end; ++position)
|
||||||
|
{
|
||||||
|
const NodeID x = remaining_nodes[position].id;
|
||||||
|
node_levels[orig_node_id_from_new_node_id_map[x]] = current_level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int position = range.begin(), end = range.end(); position != end; ++position)
|
||||||
|
{
|
||||||
|
const NodeID x = remaining_nodes[position].id;
|
||||||
|
node_levels[x] = current_level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// contract independent nodes
|
// contract independent nodes
|
||||||
tbb::parallel_for(
|
tbb::parallel_for(
|
||||||
tbb::blocked_range<int>(first_independent_node, last, ContractGrainSize),
|
tbb::blocked_range<std::size_t>(begin_independent_nodes_idx, end_independent_nodes_idx, ContractGrainSize),
|
||||||
[this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int> &range)
|
[this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<std::size_t> &range)
|
||||||
{
|
{
|
||||||
ContractorThreadData *data = thread_data_list.getThreadData();
|
ContractorThreadData *data = thread_data_list.getThreadData();
|
||||||
for (int position = range.begin(), end = range.end(); position != end; ++position)
|
for (int position = range.begin(), end = range.end(); position != end; ++position)
|
||||||
@ -462,17 +518,9 @@ class Contractor
|
|||||||
this->ContractNode<false>(data, x);
|
this->ContractNode<false>(data, x);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// make sure we really sort each block
|
|
||||||
tbb::parallel_for(
|
tbb::parallel_for(
|
||||||
thread_data_list.data.range(),
|
tbb::blocked_range<int>(begin_independent_nodes_idx, end_independent_nodes_idx, DeleteGrainSize),
|
||||||
[&](const ThreadDataContainer::EnumerableThreadData::range_type &range)
|
|
||||||
{
|
|
||||||
for (auto &data : range)
|
|
||||||
tbb::parallel_sort(data->inserted_edges.begin(),
|
|
||||||
data->inserted_edges.end());
|
|
||||||
});
|
|
||||||
tbb::parallel_for(
|
|
||||||
tbb::blocked_range<int>(first_independent_node, last, DeleteGrainSize),
|
|
||||||
[this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int> &range)
|
[this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int> &range)
|
||||||
{
|
{
|
||||||
ContractorThreadData *data = thread_data_list.getThreadData();
|
ContractorThreadData *data = thread_data_list.getThreadData();
|
||||||
@ -483,6 +531,16 @@ class Contractor
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// make sure we really sort each block
|
||||||
|
tbb::parallel_for(
|
||||||
|
thread_data_list.data.range(),
|
||||||
|
[&](const ThreadDataContainer::EnumerableThreadData::range_type &range)
|
||||||
|
{
|
||||||
|
for (auto &data : range)
|
||||||
|
tbb::parallel_sort(data->inserted_edges.begin(),
|
||||||
|
data->inserted_edges.end());
|
||||||
|
});
|
||||||
|
|
||||||
// insert new edges
|
// insert new edges
|
||||||
for (auto &data : thread_data_list.data)
|
for (auto &data : thread_data_list.data)
|
||||||
{
|
{
|
||||||
@ -508,9 +566,11 @@ class Contractor
|
|||||||
data->inserted_edges.clear();
|
data->inserted_edges.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!use_cached_node_priorities)
|
||||||
|
{
|
||||||
tbb::parallel_for(
|
tbb::parallel_for(
|
||||||
tbb::blocked_range<int>(first_independent_node, last, NeighboursGrainSize),
|
tbb::blocked_range<int>(begin_independent_nodes_idx, end_independent_nodes_idx, NeighboursGrainSize),
|
||||||
[this, &remaining_nodes, &node_priorities, &node_data, &thread_data_list](
|
[this, &node_priorities, &remaining_nodes, &node_data, &thread_data_list](
|
||||||
const tbb::blocked_range<int> &range)
|
const tbb::blocked_range<int> &range)
|
||||||
{
|
{
|
||||||
ContractorThreadData *data = thread_data_list.getThreadData();
|
ContractorThreadData *data = thread_data_list.getThreadData();
|
||||||
@ -520,11 +580,11 @@ class Contractor
|
|||||||
this->UpdateNodeNeighbours(node_priorities, node_data, data, x);
|
this->UpdateNodeNeighbours(node_priorities, node_data, data, x);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// remove contracted nodes from the pool
|
// remove contracted nodes from the pool
|
||||||
number_of_contracted_nodes += last - first_independent_node;
|
number_of_contracted_nodes += end_independent_nodes_idx - begin_independent_nodes_idx;
|
||||||
remaining_nodes.resize(first_independent_node);
|
remaining_nodes.resize(begin_independent_nodes_idx);
|
||||||
remaining_nodes.shrink_to_fit();
|
|
||||||
// unsigned maxdegree = 0;
|
// unsigned maxdegree = 0;
|
||||||
// unsigned avgdegree = 0;
|
// unsigned avgdegree = 0;
|
||||||
// unsigned mindegree = UINT_MAX;
|
// unsigned mindegree = UINT_MAX;
|
||||||
@ -551,24 +611,36 @@ class Contractor
|
|||||||
// quad: " << quaddegree;
|
// quad: " << quaddegree;
|
||||||
|
|
||||||
p.printStatus(number_of_contracted_nodes);
|
p.printStatus(number_of_contracted_nodes);
|
||||||
|
++current_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remaining_nodes.size() > 2)
|
if (remaining_nodes.size() > 2)
|
||||||
{
|
{
|
||||||
if (orig_node_id_from_new_node_id_map.empty())
|
if (orig_node_id_from_new_node_id_map.size() > 0)
|
||||||
{
|
{
|
||||||
for (const auto &node : remaining_nodes)
|
tbb::parallel_for(
|
||||||
|
tbb::blocked_range<int>(0, remaining_nodes.size(), InitGrainSize),
|
||||||
|
[this, &remaining_nodes](const tbb::blocked_range<int> &range)
|
||||||
{
|
{
|
||||||
is_core_node[node.id] = true;
|
for (int x = range.begin(), end = range.end(); x != end; ++x)
|
||||||
|
{
|
||||||
|
const auto orig_id = remaining_nodes[x].id;
|
||||||
|
is_core_node[orig_node_id_from_new_node_id_map[orig_id]] = true;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (const auto &node : remaining_nodes)
|
tbb::parallel_for(
|
||||||
|
tbb::blocked_range<int>(0, remaining_nodes.size(), InitGrainSize),
|
||||||
|
[this, &remaining_nodes](const tbb::blocked_range<int> &range)
|
||||||
{
|
{
|
||||||
auto orig_id = orig_node_id_from_new_node_id_map[node.id];
|
for (int x = range.begin(), end = range.end(); x != end; ++x)
|
||||||
|
{
|
||||||
|
const auto orig_id = remaining_nodes[x].id;
|
||||||
is_core_node[orig_id] = true;
|
is_core_node[orig_id] = true;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -589,6 +661,11 @@ class Contractor
|
|||||||
out_is_core_node.swap(is_core_node);
|
out_is_core_node.swap(is_core_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void GetNodeLevels(std::vector<float> &out_node_levels)
|
||||||
|
{
|
||||||
|
out_node_levels.swap(node_levels);
|
||||||
|
}
|
||||||
|
|
||||||
template <class Edge> inline void GetEdges(DeallocatingVector<Edge> &edges)
|
template <class Edge> inline void GetEdges(DeallocatingVector<Edge> &edges)
|
||||||
{
|
{
|
||||||
Percent p(contractor_graph->GetNumberOfNodes());
|
Percent p(contractor_graph->GetNumberOfNodes());
|
||||||
@ -998,6 +1075,7 @@ class Contractor
|
|||||||
std::shared_ptr<ContractorGraph> contractor_graph;
|
std::shared_ptr<ContractorGraph> contractor_graph;
|
||||||
stxxl::vector<QueryEdge> external_edge_list;
|
stxxl::vector<QueryEdge> external_edge_list;
|
||||||
std::vector<NodeID> orig_node_id_from_new_node_id_map;
|
std::vector<NodeID> orig_node_id_from_new_node_id_map;
|
||||||
|
std::vector<float> node_levels;
|
||||||
std::vector<bool> is_core_node;
|
std::vector<bool> is_core_node;
|
||||||
XORFastHash fast_hash;
|
XORFastHash fast_hash;
|
||||||
};
|
};
|
||||||
|
@ -48,16 +48,20 @@ ContractorOptions::ParseArguments(int argc, char *argv[], ContractorConfig &cont
|
|||||||
// declare a group of options that will be allowed both on command line and in config file
|
// declare a group of options that will be allowed both on command line and in config file
|
||||||
boost::program_options::options_description config_options("Configuration");
|
boost::program_options::options_description config_options("Configuration");
|
||||||
config_options.add_options()(
|
config_options.add_options()(
|
||||||
"profile,p", boost::program_options::value<boost::filesystem::path>(&contractor_config.profile_path)
|
"profile,p",
|
||||||
|
boost::program_options::value<boost::filesystem::path>(&contractor_config.profile_path)
|
||||||
->default_value("profile.lua"),
|
->default_value("profile.lua"),
|
||||||
"Path to LUA routing profile")(
|
"Path to LUA routing profile")(
|
||||||
"threads,t", boost::program_options::value<unsigned int>(&contractor_config.requested_num_threads)
|
"threads,t",
|
||||||
|
boost::program_options::value<unsigned int>(&contractor_config.requested_num_threads)
|
||||||
->default_value(tbb::task_scheduler_init::default_num_threads()),
|
->default_value(tbb::task_scheduler_init::default_num_threads()),
|
||||||
"Number of threads to use")(
|
"Number of threads to use")(
|
||||||
"core,k", boost::program_options::value<double>(&contractor_config.core_factor)
|
"core,k",
|
||||||
->default_value(1.0),"Percentage of the graph (in vertices) to contract [0.1]");
|
boost::program_options::value<double>(&contractor_config.core_factor)->default_value(1.0),
|
||||||
|
"Percentage of the graph (in vertices) to contract [0.1]")(
|
||||||
|
"level-cache,o",
|
||||||
|
boost::program_options::value<bool>(&contractor_config.use_cached_priority)->default_value(false),
|
||||||
|
"Use .level file to retain the contaction level for each node from the last run.");
|
||||||
|
|
||||||
// hidden options, will be allowed both on command line and in config file, but will not be
|
// hidden options, will be allowed both on command line and in config file, but will not be
|
||||||
// shown to the user
|
// shown to the user
|
||||||
@ -122,6 +126,7 @@ ContractorOptions::ParseArguments(int argc, char *argv[], ContractorConfig &cont
|
|||||||
|
|
||||||
void ContractorOptions::GenerateOutputFilesNames(ContractorConfig &contractor_config)
|
void ContractorOptions::GenerateOutputFilesNames(ContractorConfig &contractor_config)
|
||||||
{
|
{
|
||||||
|
contractor_config.level_output_path = contractor_config.osrm_input_path.string() + ".level";
|
||||||
contractor_config.core_output_path = contractor_config.osrm_input_path.string() + ".core";
|
contractor_config.core_output_path = contractor_config.osrm_input_path.string() + ".core";
|
||||||
contractor_config.graph_output_path = contractor_config.osrm_input_path.string() + ".hsgr";
|
contractor_config.graph_output_path = contractor_config.osrm_input_path.string() + ".hsgr";
|
||||||
contractor_config.edge_based_graph_path = contractor_config.osrm_input_path.string() + ".ebg";
|
contractor_config.edge_based_graph_path = contractor_config.osrm_input_path.string() + ".ebg";
|
||||||
|
@ -47,10 +47,13 @@ struct ContractorConfig
|
|||||||
boost::filesystem::path osrm_input_path;
|
boost::filesystem::path osrm_input_path;
|
||||||
boost::filesystem::path profile_path;
|
boost::filesystem::path profile_path;
|
||||||
|
|
||||||
|
std::string level_output_path;
|
||||||
std::string core_output_path;
|
std::string core_output_path;
|
||||||
std::string graph_output_path;
|
std::string graph_output_path;
|
||||||
std::string edge_based_graph_path;
|
std::string edge_based_graph_path;
|
||||||
|
|
||||||
|
bool use_cached_priority;
|
||||||
|
|
||||||
unsigned requested_num_threads;
|
unsigned requested_num_threads;
|
||||||
|
|
||||||
//A percentage of vertices that will be contracted for the hierarchy.
|
//A percentage of vertices that will be contracted for the hierarchy.
|
||||||
|
@ -26,8 +26,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "processing_chain.hpp"
|
#include "processing_chain.hpp"
|
||||||
|
|
||||||
#include "contractor.hpp"
|
#include "contractor.hpp"
|
||||||
|
|
||||||
#include "../data_structures/deallocating_vector.hpp"
|
#include "../data_structures/deallocating_vector.hpp"
|
||||||
|
|
||||||
#include "../algorithms/crc32_processor.hpp"
|
#include "../algorithms/crc32_processor.hpp"
|
||||||
@ -78,8 +78,13 @@ int Prepare::Run()
|
|||||||
|
|
||||||
TIMER_START(contraction);
|
TIMER_START(contraction);
|
||||||
std::vector<bool> is_core_node;
|
std::vector<bool> is_core_node;
|
||||||
|
std::vector<float> node_levels;
|
||||||
|
if (config.use_cached_priority)
|
||||||
|
{
|
||||||
|
ReadNodeLevels(node_levels);
|
||||||
|
}
|
||||||
DeallocatingVector<QueryEdge> contracted_edge_list;
|
DeallocatingVector<QueryEdge> contracted_edge_list;
|
||||||
ContractGraph(max_edge_id, edge_based_edge_list, contracted_edge_list, is_core_node);
|
ContractGraph(max_edge_id, edge_based_edge_list, contracted_edge_list, is_core_node, node_levels);
|
||||||
TIMER_STOP(contraction);
|
TIMER_STOP(contraction);
|
||||||
|
|
||||||
SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
|
SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
|
||||||
@ -87,6 +92,10 @@ int Prepare::Run()
|
|||||||
std::size_t number_of_used_edges =
|
std::size_t number_of_used_edges =
|
||||||
WriteContractedGraph(max_edge_id, contracted_edge_list);
|
WriteContractedGraph(max_edge_id, contracted_edge_list);
|
||||||
WriteCoreNodeMarker(std::move(is_core_node));
|
WriteCoreNodeMarker(std::move(is_core_node));
|
||||||
|
if (!config.use_cached_priority)
|
||||||
|
{
|
||||||
|
WriteNodeLevels(std::move(node_levels));
|
||||||
|
}
|
||||||
|
|
||||||
TIMER_STOP(preparing);
|
TIMER_STOP(preparing);
|
||||||
|
|
||||||
@ -131,11 +140,35 @@ std::size_t Prepare::LoadEdgeExpandedGraph(
|
|||||||
return max_edge_id;
|
return max_edge_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Prepare::ReadNodeLevels(std::vector<float> &node_levels) const
|
||||||
|
{
|
||||||
|
boost::filesystem::ifstream order_input_stream(config.level_output_path,
|
||||||
|
std::ios::binary);
|
||||||
|
|
||||||
|
unsigned level_size;
|
||||||
|
order_input_stream.read((char *)&level_size, sizeof(unsigned));
|
||||||
|
node_levels.resize(level_size);
|
||||||
|
order_input_stream.read((char *)node_levels.data(),
|
||||||
|
sizeof(float) * node_levels.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Prepare::WriteNodeLevels(std::vector<float> &&in_node_levels) const
|
||||||
|
{
|
||||||
|
std::vector<float> node_levels(std::move(in_node_levels));
|
||||||
|
|
||||||
|
boost::filesystem::ofstream order_output_stream(config.level_output_path,
|
||||||
|
std::ios::binary);
|
||||||
|
|
||||||
|
unsigned level_size = node_levels.size();
|
||||||
|
order_output_stream.write((char *)&level_size, sizeof(unsigned));
|
||||||
|
order_output_stream.write((char *)node_levels.data(),
|
||||||
|
sizeof(float) * node_levels.size());
|
||||||
|
}
|
||||||
|
|
||||||
void Prepare::WriteCoreNodeMarker(std::vector<bool> &&in_is_core_node) const
|
void Prepare::WriteCoreNodeMarker(std::vector<bool> &&in_is_core_node) const
|
||||||
{
|
{
|
||||||
std::vector<bool> is_core_node(in_is_core_node);
|
std::vector<bool> is_core_node(std::move(in_is_core_node));
|
||||||
std::vector<char> unpacked_bool_flags(is_core_node.size());
|
std::vector<char> unpacked_bool_flags(std::move(is_core_node.size()));
|
||||||
for (auto i = 0u; i < is_core_node.size(); ++i)
|
for (auto i = 0u; i < is_core_node.size(); ++i)
|
||||||
{
|
{
|
||||||
unpacked_bool_flags[i] = is_core_node[i] ? 1 : 0;
|
unpacked_bool_flags[i] = is_core_node[i] ? 1 : 0;
|
||||||
@ -270,12 +303,17 @@ std::size_t Prepare::WriteContractedGraph(unsigned max_node_id,
|
|||||||
void Prepare::ContractGraph(const unsigned max_edge_id,
|
void Prepare::ContractGraph(const unsigned max_edge_id,
|
||||||
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||||
DeallocatingVector<QueryEdge> &contracted_edge_list,
|
DeallocatingVector<QueryEdge> &contracted_edge_list,
|
||||||
std::vector<bool> &is_core_node)
|
std::vector<bool> &is_core_node,
|
||||||
|
std::vector<float> &inout_node_levels) const
|
||||||
{
|
{
|
||||||
Contractor contractor(max_edge_id + 1, edge_based_edge_list);
|
std::vector<float> node_levels;
|
||||||
|
node_levels.swap(inout_node_levels);
|
||||||
|
|
||||||
|
Contractor contractor(max_edge_id + 1, edge_based_edge_list, std::move(node_levels));
|
||||||
contractor.Run(config.core_factor);
|
contractor.Run(config.core_factor);
|
||||||
contractor.GetEdges(contracted_edge_list);
|
contractor.GetEdges(contracted_edge_list);
|
||||||
contractor.GetCoreMarker(is_core_node);
|
contractor.GetCoreMarker(is_core_node);
|
||||||
|
contractor.GetNodeLevels(inout_node_levels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,8 +60,11 @@ class Prepare
|
|||||||
void ContractGraph(const unsigned max_edge_id,
|
void ContractGraph(const unsigned max_edge_id,
|
||||||
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||||
DeallocatingVector<QueryEdge> &contracted_edge_list,
|
DeallocatingVector<QueryEdge> &contracted_edge_list,
|
||||||
std::vector<bool> &is_core_node);
|
std::vector<bool> &is_core_node,
|
||||||
|
std::vector<float> &node_levels) const;
|
||||||
void WriteCoreNodeMarker(std::vector<bool> &&is_core_node) const;
|
void WriteCoreNodeMarker(std::vector<bool> &&is_core_node) const;
|
||||||
|
void WriteNodeLevels(std::vector<float> &&node_levels) const;
|
||||||
|
void ReadNodeLevels(std::vector<float> &contraction_order) const;
|
||||||
std::size_t WriteContractedGraph(unsigned number_of_edge_based_nodes,
|
std::size_t WriteContractedGraph(unsigned number_of_edge_based_nodes,
|
||||||
const DeallocatingVector<QueryEdge> &contracted_edge_list);
|
const DeallocatingVector<QueryEdge> &contracted_edge_list);
|
||||||
void FindComponents(unsigned max_edge_id,
|
void FindComponents(unsigned max_edge_id,
|
||||||
|
Loading…
Reference in New Issue
Block a user