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:
MoKob 2015-07-13 21:09:19 +02:00 committed by Patrick Niklaus
parent 94f44e1d5d
commit b526cadebd
10 changed files with 211 additions and 12 deletions

View File

@ -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();
} }

View File

@ -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

View File

@ -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

View File

@ -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);
} }

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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,12 +154,20 @@ 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())
{
if (route_parameters.alternate_route)
{ {
search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(), search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
raw_route); raw_route);
} }
else else
{
search_engine_ptr->direct_shortest_path(raw_route.segment_end_coordinates,
route_parameters.uturns, raw_route);
}
}
else
{ {
search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, search_engine_ptr->shortest_path(raw_route.segment_end_coordinates,
route_parameters.uturns, raw_route); route_parameters.uturns, raw_route);

View 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 */

View File

@ -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]);
} }
} }