Initial version of core ch
This improves preprocessing times in favour of worse query performance. Core size can be set over the --core parameater, default is the old behaviour to fully contract the graph.
This commit is contained in:
parent
94f44e1d5d
commit
b526cadebd
@ -284,7 +284,7 @@ class Contractor
|
|||||||
|
|
||||||
~Contractor() {}
|
~Contractor() {}
|
||||||
|
|
||||||
void Run()
|
void Run( double core_factor = 1.0 )
|
||||||
{
|
{
|
||||||
// for the preperation we can use a big grain size, which is much faster (probably cache)
|
// for the preperation we can use a big grain size, which is much faster (probably cache)
|
||||||
constexpr size_t InitGrainSize = 100000;
|
constexpr size_t InitGrainSize = 100000;
|
||||||
@ -333,9 +333,9 @@ class Contractor
|
|||||||
<< std::flush;
|
<< std::flush;
|
||||||
|
|
||||||
bool flushed_contractor = false;
|
bool flushed_contractor = false;
|
||||||
while (number_of_nodes > 2 && number_of_contracted_nodes < number_of_nodes)
|
while (number_of_nodes > 2 && number_of_contracted_nodes < static_cast<NodeID>(number_of_nodes * core_factor) )
|
||||||
{
|
{
|
||||||
if (!flushed_contractor && (number_of_contracted_nodes > (number_of_nodes * 0.65)))
|
if (!flushed_contractor && (number_of_contracted_nodes > static_cast<NodeID>(number_of_nodes * 0.65 * core_factor)))
|
||||||
{
|
{
|
||||||
DeallocatingVector<ContractorEdge> new_edge_set; // this one is not explicitely
|
DeallocatingVector<ContractorEdge> new_edge_set; // this one is not explicitely
|
||||||
// cleared since it goes out of
|
// cleared since it goes out of
|
||||||
@ -524,7 +524,7 @@ class Contractor
|
|||||||
// unsigned quaddegree = 0;
|
// unsigned quaddegree = 0;
|
||||||
//
|
//
|
||||||
// for(unsigned i = 0; i < remaining_nodes.size(); ++i) {
|
// for(unsigned i = 0; i < remaining_nodes.size(); ++i) {
|
||||||
// unsigned degree = contractor_graph->EndEdges(remaining_nodes[i].first)
|
// unsigned degree = contractor_graph->EndEdges(remaining_nodes[i].id)
|
||||||
// -
|
// -
|
||||||
// contractor_graph->BeginEdges(remaining_nodes[i].first);
|
// contractor_graph->BeginEdges(remaining_nodes[i].first);
|
||||||
// if(degree > maxdegree)
|
// if(degree > maxdegree)
|
||||||
@ -546,6 +546,8 @@ class Contractor
|
|||||||
p.printStatus(number_of_contracted_nodes);
|
p.printStatus(number_of_contracted_nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SimpleLogger().Write() << "[core] " << remaining_nodes.size() << " nodes " << contractor_graph->GetNumberOfEdges() << " edges." << std::endl;
|
||||||
|
|
||||||
thread_data_list.data.clear();
|
thread_data_list.data.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,11 @@ ContractorOptions::ParseArguments(int argc, char *argv[], ContractorConfig &cont
|
|||||||
"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)
|
||||||
|
->default_value(1.0),"Percentage of the graph (in vertices) to contract [0.1]");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -56,6 +56,12 @@ struct ContractorConfig
|
|||||||
std::string rtree_leafs_output_path;
|
std::string rtree_leafs_output_path;
|
||||||
|
|
||||||
unsigned requested_num_threads;
|
unsigned requested_num_threads;
|
||||||
|
|
||||||
|
//A percentage of vertices that will be contracted for the hierarchy.
|
||||||
|
//Offers a trade-off between preprocessing and query time.
|
||||||
|
//The remaining vertices form the core of the hierarchy
|
||||||
|
//(e.g. 0.8 contracts 80 percent of the hierarchy, leaving a core of 20%)
|
||||||
|
double core_factor;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ContractorOptions
|
struct ContractorOptions
|
||||||
|
@ -414,7 +414,7 @@ void Prepare::ContractGraph(const unsigned max_edge_id,
|
|||||||
DeallocatingVector<QueryEdge>& contracted_edge_list)
|
DeallocatingVector<QueryEdge>& contracted_edge_list)
|
||||||
{
|
{
|
||||||
Contractor contractor(max_edge_id + 1, edge_based_edge_list);
|
Contractor contractor(max_edge_id + 1, edge_based_edge_list);
|
||||||
contractor.Run();
|
contractor.Run(config.core_factor);
|
||||||
contractor.GetEdges(contracted_edge_list);
|
contractor.GetEdges(contracted_edge_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,6 +189,11 @@ class BinaryHeap
|
|||||||
return inserted_nodes[heap[1].index].node;
|
return inserted_nodes[heap[1].index].node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Weight MinKey() const {
|
||||||
|
BOOST_ASSERT(heap.size() > 1);
|
||||||
|
return heap[1].weight;
|
||||||
|
}
|
||||||
|
|
||||||
NodeID DeleteMin()
|
NodeID DeleteMin()
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(heap.size() > 1);
|
BOOST_ASSERT(heap.size() > 1);
|
||||||
|
@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "../routing_algorithms/many_to_many.hpp"
|
#include "../routing_algorithms/many_to_many.hpp"
|
||||||
#include "../routing_algorithms/map_matching.hpp"
|
#include "../routing_algorithms/map_matching.hpp"
|
||||||
#include "../routing_algorithms/shortest_path.hpp"
|
#include "../routing_algorithms/shortest_path.hpp"
|
||||||
|
#include "../routing_algorithms/direct_shortest_path.hpp"
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
@ -44,6 +45,7 @@ template <class DataFacadeT> class SearchEngine
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
ShortestPathRouting<DataFacadeT> shortest_path;
|
ShortestPathRouting<DataFacadeT> shortest_path;
|
||||||
|
DirectShortestPathRouting<DataFacadeT> direct_shortest_path;
|
||||||
AlternativeRouting<DataFacadeT> alternative_path;
|
AlternativeRouting<DataFacadeT> alternative_path;
|
||||||
ManyToManyRouting<DataFacadeT> distance_table;
|
ManyToManyRouting<DataFacadeT> distance_table;
|
||||||
MapMatching<DataFacadeT> map_matching;
|
MapMatching<DataFacadeT> map_matching;
|
||||||
@ -51,6 +53,7 @@ template <class DataFacadeT> class SearchEngine
|
|||||||
explicit SearchEngine(DataFacadeT *facade)
|
explicit SearchEngine(DataFacadeT *facade)
|
||||||
: facade(facade),
|
: facade(facade),
|
||||||
shortest_path(facade, engine_working_data),
|
shortest_path(facade, engine_working_data),
|
||||||
|
direct_shortest_path(facade, engine_working_data),
|
||||||
alternative_path(facade, engine_working_data),
|
alternative_path(facade, engine_working_data),
|
||||||
distance_table(facade, engine_working_data),
|
distance_table(facade, engine_working_data),
|
||||||
map_matching(facade, engine_working_data)
|
map_matching(facade, engine_working_data)
|
||||||
|
@ -16,7 +16,8 @@ Feature: osrm-prepare command line options: help
|
|||||||
And stdout should contain "--restrictions"
|
And stdout should contain "--restrictions"
|
||||||
And stdout should contain "--profile"
|
And stdout should contain "--profile"
|
||||||
And stdout should contain "--threads"
|
And stdout should contain "--threads"
|
||||||
And stdout should contain 15 lines
|
And stdout should contain "--core"
|
||||||
|
And stdout should contain 17 lines
|
||||||
And it should exit with code 1
|
And it should exit with code 1
|
||||||
|
|
||||||
Scenario: osrm-prepare - Help, short
|
Scenario: osrm-prepare - Help, short
|
||||||
@ -31,7 +32,8 @@ Feature: osrm-prepare command line options: help
|
|||||||
And stdout should contain "--restrictions"
|
And stdout should contain "--restrictions"
|
||||||
And stdout should contain "--profile"
|
And stdout should contain "--profile"
|
||||||
And stdout should contain "--threads"
|
And stdout should contain "--threads"
|
||||||
And stdout should contain 15 lines
|
And stdout should contain "--core"
|
||||||
|
And stdout should contain 17 lines
|
||||||
And it should exit with code 0
|
And it should exit with code 0
|
||||||
|
|
||||||
Scenario: osrm-prepare - Help, long
|
Scenario: osrm-prepare - Help, long
|
||||||
@ -46,5 +48,6 @@ Feature: osrm-prepare command line options: help
|
|||||||
And stdout should contain "--restrictions"
|
And stdout should contain "--restrictions"
|
||||||
And stdout should contain "--profile"
|
And stdout should contain "--profile"
|
||||||
And stdout should contain "--threads"
|
And stdout should contain "--threads"
|
||||||
And stdout should contain 15 lines
|
And stdout should contain "--core"
|
||||||
|
And stdout should contain 17 lines
|
||||||
And it should exit with code 0
|
And it should exit with code 0
|
||||||
|
@ -39,6 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "../util/json_renderer.hpp"
|
#include "../util/json_renderer.hpp"
|
||||||
#include "../util/make_unique.hpp"
|
#include "../util/make_unique.hpp"
|
||||||
#include "../util/simple_logger.hpp"
|
#include "../util/simple_logger.hpp"
|
||||||
|
#include "../util/timing_util.hpp"
|
||||||
|
|
||||||
#include <osrm/json_container.hpp>
|
#include <osrm/json_container.hpp>
|
||||||
|
|
||||||
@ -153,10 +154,18 @@ template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
|
|||||||
};
|
};
|
||||||
osrm::for_each_pair(phantom_node_pair_list, build_phantom_pairs);
|
osrm::for_each_pair(phantom_node_pair_list, build_phantom_pairs);
|
||||||
|
|
||||||
if (route_parameters.alternate_route && 1 == raw_route.segment_end_coordinates.size())
|
if (1 == raw_route.segment_end_coordinates.size())
|
||||||
{
|
{
|
||||||
search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
|
if (route_parameters.alternate_route)
|
||||||
raw_route);
|
{
|
||||||
|
search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
|
||||||
|
raw_route);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
search_engine_ptr->direct_shortest_path(raw_route.segment_end_coordinates,
|
||||||
|
route_parameters.uturns, raw_route);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
165
routing_algorithms/direct_shortest_path.hpp
Normal file
165
routing_algorithms/direct_shortest_path.hpp
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2015, Project OSRM contributors
|
||||||
|
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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DIRECT_SHORTEST_PATH_HPP
|
||||||
|
#define DIRECT_SHORTEST_PATH_HPP
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
|
#include "routing_base.hpp"
|
||||||
|
#include "../data_structures/search_engine_data.hpp"
|
||||||
|
#include "../util/integer_range.hpp"
|
||||||
|
#include "../util/timing_util.hpp"
|
||||||
|
#include "../typedefs.h"
|
||||||
|
|
||||||
|
/// This is a striped down version of the general shortest path algorithm.
|
||||||
|
/// The general algorithm always computes two queries for each leg. This is only
|
||||||
|
/// necessary in case of vias, where the directions of the start node is constrainted
|
||||||
|
/// by the previous route.
|
||||||
|
/// This variation is only an optimazation for graphs with slow queries, for example
|
||||||
|
/// not fully contracted graphs.
|
||||||
|
template <class DataFacadeT>
|
||||||
|
class DirectShortestPathRouting final
|
||||||
|
: public BasicRoutingInterface<DataFacadeT, DirectShortestPathRouting<DataFacadeT>>
|
||||||
|
{
|
||||||
|
using super = BasicRoutingInterface<DataFacadeT, DirectShortestPathRouting<DataFacadeT>>;
|
||||||
|
using QueryHeap = SearchEngineData::QueryHeap;
|
||||||
|
SearchEngineData &engine_working_data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DirectShortestPathRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
|
||||||
|
: super(facade), engine_working_data(engine_working_data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~DirectShortestPathRouting() {}
|
||||||
|
|
||||||
|
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
|
||||||
|
const std::vector<bool> &uturn_indicators,
|
||||||
|
InternalRouteResult &raw_route_data) const
|
||||||
|
{
|
||||||
|
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||||
|
super::facade->GetNumberOfNodes());
|
||||||
|
|
||||||
|
QueryHeap &forward_heap = *(engine_working_data.forward_heap_1);
|
||||||
|
QueryHeap &reverse_heap = *(engine_working_data.reverse_heap_1);
|
||||||
|
|
||||||
|
// Get distance to next pair of target nodes.
|
||||||
|
BOOST_ASSERT_MSG(1 == phantom_nodes_vector.size(),
|
||||||
|
"Direct Shortest Path Query only accepts a single source and target pair. Multiple ones have been specified.");
|
||||||
|
|
||||||
|
const auto& phantom_node_pair = phantom_nodes_vector.front();
|
||||||
|
|
||||||
|
forward_heap.Clear();
|
||||||
|
reverse_heap.Clear();
|
||||||
|
int distance = INVALID_EDGE_WEIGHT;
|
||||||
|
NodeID middle = SPECIAL_NODEID;
|
||||||
|
|
||||||
|
const EdgeWeight min_edge_offset =
|
||||||
|
std::min(-phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
|
||||||
|
-phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
|
||||||
|
|
||||||
|
// insert new starting nodes into forward heap, adjusted by previous distances.
|
||||||
|
if (phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID)
|
||||||
|
{
|
||||||
|
forward_heap.Insert(
|
||||||
|
phantom_node_pair.source_phantom.forward_node_id,
|
||||||
|
-phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
|
||||||
|
phantom_node_pair.source_phantom.forward_node_id);
|
||||||
|
}
|
||||||
|
if ( phantom_node_pair.source_phantom.reverse_node_id != SPECIAL_NODEID)
|
||||||
|
{
|
||||||
|
forward_heap.Insert(
|
||||||
|
phantom_node_pair.source_phantom.reverse_node_id,
|
||||||
|
-phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
|
||||||
|
phantom_node_pair.source_phantom.reverse_node_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert new backward nodes into backward heap, unadjusted.
|
||||||
|
if (phantom_node_pair.target_phantom.forward_node_id != SPECIAL_NODEID)
|
||||||
|
{
|
||||||
|
reverse_heap.Insert(phantom_node_pair.target_phantom.forward_node_id,
|
||||||
|
phantom_node_pair.target_phantom.GetForwardWeightPlusOffset(),
|
||||||
|
phantom_node_pair.target_phantom.forward_node_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phantom_node_pair.target_phantom.reverse_node_id != SPECIAL_NODEID)
|
||||||
|
{
|
||||||
|
reverse_heap.Insert(phantom_node_pair.target_phantom.reverse_node_id,
|
||||||
|
phantom_node_pair.target_phantom.GetReverseWeightPlusOffset(),
|
||||||
|
phantom_node_pair.target_phantom.reverse_node_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// run two-Target Dijkstra routing step.
|
||||||
|
while (0 < (forward_heap.Size() + reverse_heap.Size()) )
|
||||||
|
{
|
||||||
|
if (!forward_heap.Empty())
|
||||||
|
{
|
||||||
|
super::RoutingStep(forward_heap, reverse_heap, &middle, &distance,
|
||||||
|
min_edge_offset, true);
|
||||||
|
}
|
||||||
|
if (!reverse_heap.Empty())
|
||||||
|
{
|
||||||
|
super::RoutingStep(reverse_heap, forward_heap, &middle, &distance,
|
||||||
|
min_edge_offset, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No path found for both target nodes?
|
||||||
|
if ((INVALID_EDGE_WEIGHT == distance))
|
||||||
|
{
|
||||||
|
raw_route_data.shortest_path_length = INVALID_EDGE_WEIGHT;
|
||||||
|
raw_route_data.alternative_path_length = INVALID_EDGE_WEIGHT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Was a paths over one of the forward/reverse nodes not found?
|
||||||
|
BOOST_ASSERT_MSG((SPECIAL_NODEID == middle || INVALID_EDGE_WEIGHT != distance),
|
||||||
|
"no path found");
|
||||||
|
|
||||||
|
// Unpack paths if they exist
|
||||||
|
std::vector<NodeID> packed_leg;
|
||||||
|
if (INVALID_EDGE_WEIGHT != distance)
|
||||||
|
{
|
||||||
|
super::RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
|
||||||
|
|
||||||
|
BOOST_ASSERT_MSG(!packed_leg.empty(), "packed path empty");
|
||||||
|
|
||||||
|
raw_route_data.unpacked_path_segments.resize(1);
|
||||||
|
raw_route_data.source_traversed_in_reverse.push_back(
|
||||||
|
(packed_leg.front() != phantom_node_pair.source_phantom.forward_node_id));
|
||||||
|
raw_route_data.target_traversed_in_reverse.push_back(
|
||||||
|
(packed_leg.back() != phantom_node_pair.target_phantom.forward_node_id));
|
||||||
|
|
||||||
|
super::UnpackPath(packed_leg, phantom_node_pair, raw_route_data.unpacked_path_segments.front());
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_route_data.shortest_path_length = distance;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DIRECT_SHORTEST_PATH_HPP */
|
@ -165,6 +165,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(decrease_key_test, T, storage_types, RandomData
|
|||||||
{
|
{
|
||||||
heap.DecreaseKey(id, weights[id]);
|
heap.DecreaseKey(id, weights[id]);
|
||||||
BOOST_CHECK_EQUAL(heap.Min(), min_id);
|
BOOST_CHECK_EQUAL(heap.Min(), min_id);
|
||||||
|
BOOST_CHECK_EQUAL(heap.MinKey(), min_weight);
|
||||||
weights[id]--;
|
weights[id]--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,6 +173,7 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(decrease_key_test, T, storage_types, RandomData
|
|||||||
weights[id] -= 2;
|
weights[id] -= 2;
|
||||||
heap.DecreaseKey(id, weights[id]);
|
heap.DecreaseKey(id, weights[id]);
|
||||||
BOOST_CHECK_EQUAL(heap.Min(), id);
|
BOOST_CHECK_EQUAL(heap.Min(), id);
|
||||||
|
BOOST_CHECK_EQUAL(heap.MinKey(), weights[id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user