diff --git a/CMakeLists.txt b/CMakeLists.txt index 98270e753..6c9361772 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,6 +115,7 @@ configure_file( ) file(GLOB UtilGlob src/util/*.cpp src/util/*/*.cpp) file(GLOB ExtractorGlob src/extractor/*.cpp src/extractor/*/*.cpp) +file(GLOB PartitionerGlob src/partition/*.cpp) file(GLOB ContractorGlob src/contractor/*.cpp) file(GLOB StorageGlob src/storage/*.cpp) file(GLOB ServerGlob src/server/*.cpp src/server/**/*.cpp) @@ -122,6 +123,7 @@ file(GLOB EngineGlob src/engine/*.cpp src/engine/**/*.cpp) add_library(UTIL OBJECT ${UtilGlob}) add_library(EXTRACTOR OBJECT ${ExtractorGlob}) +add_library(PARTITIONER OBJECT ${PartitionerGlob}) add_library(CONTRACTOR OBJECT ${ContractorGlob}) add_library(STORAGE OBJECT ${StorageGlob}) add_library(ENGINE OBJECT ${EngineGlob}) @@ -130,11 +132,13 @@ add_library(SERVER OBJECT ${ServerGlob}) set_target_properties(UTIL PROPERTIES LINKER_LANGUAGE CXX) add_executable(osrm-extract src/tools/extract.cpp) +add_executable(osrm-partition src/tools/partition.cpp) add_executable(osrm-contract src/tools/contract.cpp) add_executable(osrm-routed src/tools/routed.cpp $ $) add_executable(osrm-datastore src/tools/store.cpp $) add_library(osrm src/osrm/osrm.cpp $ $ $) add_library(osrm_extract $ $) +add_library(osrm_partition $ $) add_library(osrm_contract $ $) add_library(osrm_store $ $) @@ -563,6 +567,7 @@ set(BOOST_ENGINE_LIBRARIES # Binaries target_link_libraries(osrm-datastore osrm_store ${Boost_PROGRAM_OPTIONS_LIBRARY}) target_link_libraries(osrm-extract osrm_extract ${Boost_PROGRAM_OPTIONS_LIBRARY}) +target_link_libraries(osrm-partition osrm_partition ${Boost_PROGRAM_OPTIONS_LIBRARY}) target_link_libraries(osrm-contract osrm_contract ${Boost_PROGRAM_OPTIONS_LIBRARY}) target_link_libraries(osrm-routed osrm ${Boost_PROGRAM_OPTIONS_LIBRARY} ${OPTIONAL_SOCKET_LIBS} ${ZLIB_LIBRARY}) @@ -578,6 +583,13 @@ set(EXTRACTOR_LIBRARIES ${TBB_LIBRARIES} ${ZLIB_LIBRARY} ${MAYBE_COVERAGE_LIBRARIES}) +set(PARTITIONER_LIBRARIES + ${BOOST_ENGINE_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + ${TBB_LIBRARIES} + ${MAYBE_RT_LIBRARY} + ${MAYBE_COVERAGE_LIBRARIES} + ${ZLIB_LIBRARY}) set(CONTRACTOR_LIBRARIES ${BOOST_BASE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} @@ -609,6 +621,7 @@ set(UTIL_LIBRARIES target_link_libraries(osrm ${ENGINE_LIBRARIES}) target_link_libraries(osrm_contract ${CONTRACTOR_LIBRARIES}) target_link_libraries(osrm_extract ${EXTRACTOR_LIBRARIES}) +target_link_libraries(osrm_partition ${PARTITIONER_LIBRARIES}) target_link_libraries(osrm_store ${STORAGE_LIBRARIES}) # BUILD_COMPONENTS @@ -641,6 +654,7 @@ endif() # (i.e., from /usr/local/bin/) the linker can find library dependencies. For # more info see http://www.cmake.org/Wiki/CMake_RPATH_handling set_property(TARGET osrm-extract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) +set_property(TARGET osrm-partition PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) set_property(TARGET osrm-contract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) set_property(TARGET osrm-datastore PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) set_property(TARGET osrm-routed PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) diff --git a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp index c1f12dacd..c176346b5 100644 --- a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp +++ b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp @@ -59,7 +59,6 @@ class ContiguousInternalMemoryDataFacade : public BaseDataFacade using GraphNode = QueryGraph::NodeArrayEntry; using GraphEdge = QueryGraph::EdgeArrayEntry; using IndexBlock = util::RangeTable<16, true>::BlockT; - using InputEdge = QueryGraph::InputEdge; using RTreeLeaf = super::RTreeLeaf; using SharedRTree = util::StaticRTree::vector, true>; diff --git a/include/partition/bisection_graph.hpp b/include/partition/bisection_graph.hpp new file mode 100644 index 000000000..562195bac --- /dev/null +++ b/include/partition/bisection_graph.hpp @@ -0,0 +1,99 @@ +#ifndef OSRM_BISECTION_GRAPH_HPP_ +#define OSRM_BISECTION_GRAPH_HPP_ + +#include "util/coordinate.hpp" +#include "util/static_graph.hpp" +#include "util/typedefs.hpp" + +#include "extractor/edge_based_edge.hpp" + +#include +#include + +namespace osrm +{ +namespace partition +{ + +// Required for usage in static graph +struct BisectionNode +{ + std::size_t first_edge; + util::Coordinate cordinate; +}; + +// The edge is used within a partition +struct BisectionEdge +{ + NodeID target; + std::int32_t data; // will be one, but we have the space... +}; + +// workaround of how static graph assumes edges to be formatted :( +using BisectionGraph = util::FlexibleStaticGraph; + +template std::vector groupBySource(std::vector edges) +{ + std::sort(edges.begin(), edges.end(), [](const auto &lhs, const auto &rhs) { + return std::tie(lhs.source, lhs.target) < std::tie(rhs.source, rhs.target); + }); + + return edges; +} + +template +std::vector computeNodes(const std::vector coordinates, + const std::vector &edges) +{ + std::vector result; + result.reserve(coordinates.size() + 1); + + // stateful transform, counting node ids and moving the edge itr forward + const auto coordinate_to_bisection_node = + [ edge_itr = edges.begin(), node_id = 0u, &edges ]( + const util::Coordinate coordinate) mutable->BisectionNode + { + const auto edges_of_node = edge_itr; + + // count all edges with this source + while (edge_itr != edges.end() && edge_itr->source == node_id) + ++edge_itr; + + // go to the next node + ++node_id; + + return {static_cast(std::distance(edges.begin(), edges_of_node)), coordinate}; + }; + + std::transform(coordinates.begin(), + coordinates.end(), + std::back_inserter(result), + coordinate_to_bisection_node); + + // sentinel element + result.push_back( + {edges.size(), util::Coordinate(util::FloatLongitude{0.0}, util::FloatLatitude{0.0})}); + + return result; +} + +template +std::vector adaptToBisectionEdge(std::vector edges) +{ + std::vector result; + + result.reserve(edges.size()); + std::transform(edges.begin(), + edges.end(), + std::back_inserter(result), + [](const auto &edge) -> BisectionEdge { + return {edge.target, 1}; + }); + + return result; +} + +} // namespace partition +} // namespace osrm + +#endif // OSRM_BISECTION_GRAPH_HPP_ diff --git a/include/partition/graph_view.hpp b/include/partition/graph_view.hpp new file mode 100644 index 000000000..ec3a78d88 --- /dev/null +++ b/include/partition/graph_view.hpp @@ -0,0 +1,76 @@ +#ifndef OSRM_PARTITION_GRAPHVIEW_HPP_ +#define OSRM_PARTITION_GRAPHVIEW_HPP_ + +#include "partition/bisection_graph.hpp" +#include "partition/recursive_bisection_state.hpp" + +#include +#include + +namespace osrm +{ +namespace partition +{ + +struct HasSamePartitionID +{ + HasSamePartitionID(const RecursiveBisectionState::BisectionID bisection_id, + const BisectionGraph &bisection_graph, + const RecursiveBisectionState &recursive_bisection_state); + + bool operator()(const EdgeID eid) const; + + private: + const RecursiveBisectionState::BisectionID bisection_id; + const BisectionGraph &bisection_graph; + const RecursiveBisectionState &recursive_bisection_state; +}; + +// a wrapper around the EdgeIDs returned by the static graph to make them iterable +class EdgeIDIterator + : public boost::iterator_facade +{ + public: + EdgeIDIterator() : position(SPECIAL_EDGEID) {} + explicit EdgeIDIterator(EdgeID position_) : position(position_) {} + + private: + friend class boost::iterator_core_access; + + void increment() { position++; } + bool equal(const EdgeIDIterator &other) const { return position == other.position; } + const EdgeID &dereference() const { return position; } + + EdgeID position; +}; + +class GraphView +{ + public: + using EdgeIterator = boost::filter_iterator; + + GraphView(const BisectionGraph &graph, + const RecursiveBisectionState &bisection_state, + const RecursiveBisectionState::IDIterator begin, + const RecursiveBisectionState::IDIterator end); + + std::size_t NumberOfNodes() const; + + RecursiveBisectionState::IDIterator Begin() const; + RecursiveBisectionState::IDIterator End() const; + + EdgeIterator EdgeBegin(const NodeID nid) const; + EdgeIterator EdgeEnd(const NodeID nid) const; + + private: + const BisectionGraph &bisection_graph; + const RecursiveBisectionState &bisection_state; + + const RecursiveBisectionState::IDIterator begin; + const RecursiveBisectionState::IDIterator end; +}; + +} // namespace partition +} // namespace osrm + +#endif // OSRM_PARTITION_GRAPHVIEW_HPP_ diff --git a/include/partition/inertial_flow.hpp b/include/partition/inertial_flow.hpp new file mode 100644 index 000000000..e569c9b52 --- /dev/null +++ b/include/partition/inertial_flow.hpp @@ -0,0 +1,25 @@ +#ifndef OSRM_PARTITION_INERTIAL_FLOW_HPP_ +#define OSRM_PARTITION_INERTIAL_FLOW_HPP_ + +#include "partition/graph_view.hpp" +#include + +namespace osrm +{ +namespace partition +{ + +class InertialFlow +{ + public: + InertialFlow(const GraphView &view); + + std::vector ComputePartition(const double balance, const double source_sink_rate); + private: + const GraphView &view; +}; + +} // namespace partition +} // namespace osrm + +#endif // OSRM_PARTITION_INERTIAL_FLOW_HPP_ diff --git a/include/partition/partition_config.hpp b/include/partition/partition_config.hpp new file mode 100644 index 000000000..a3c3f5930 --- /dev/null +++ b/include/partition/partition_config.hpp @@ -0,0 +1,47 @@ +#ifndef PARTITIONER_CONFIG_HPP +#define PARTITIONER_CONFIG_HPP + +#include + +#include +#include + +namespace osrm +{ +namespace partition +{ + +struct PartitionConfig +{ + PartitionConfig() noexcept : requested_num_threads(0) {} + + void UseDefaults() + { + std::string basepath = base_path.string(); + + const std::string ext = ".osrm"; + const auto pos = basepath.find(ext); + if (pos != std::string::npos) + { + basepath.replace(pos, ext.size(), ""); + } + else + { + // unknown extension + } + + edge_based_graph_path = basepath + ".osrm.ebg"; + partition_path = basepath + ".osrm.partition"; + } + + // might be changed to the node based graph at some point + boost::filesystem::path base_path; + boost::filesystem::path edge_based_graph_path; + boost::filesystem::path partition_path; + + unsigned requested_num_threads; +}; +} +} + +#endif // PARTITIONER_CONFIG_HPP diff --git a/include/partition/partitioner.hpp b/include/partition/partitioner.hpp new file mode 100644 index 000000000..ed7d91ffd --- /dev/null +++ b/include/partition/partitioner.hpp @@ -0,0 +1,21 @@ +#ifndef OSRM_PARTITION_PARTITIONER_HPP_ +#define OSRM_PARTITION_PARTITIONER_HPP_ + +#include "partition/partition_config.hpp" + +namespace osrm +{ +namespace partition +{ + +// tool access to the recursive partitioner +class Partitioner +{ + public: + int Run(const PartitionConfig &config); +}; + +} // namespace partition +} // namespace osrm + +#endif // OSRM_PARTITION_PARTITIONER_HPP_ diff --git a/include/partition/recursive_bisection.hpp b/include/partition/recursive_bisection.hpp new file mode 100644 index 000000000..56c0f1b32 --- /dev/null +++ b/include/partition/recursive_bisection.hpp @@ -0,0 +1,30 @@ +#ifndef OSRM_PARTITION_RECURSIVE_BISECTION_HPP_ +#define OSRM_PARTITION_RECURSIVE_BISECTION_HPP_ + +#include "partition/bisection_graph.hpp" +#include "partition/recursive_bisection_state.hpp" + +#include + +namespace osrm +{ +namespace partition +{ + +class RecursiveBisection +{ + public: + RecursiveBisection(std::size_t maximum_cell_size, + double balance, + double boundary_factor, + const BisectionGraph &bisection_graph); + + private: + const BisectionGraph &bisection_graph; + RecursiveBisectionState internal_state; +}; + +} // namespace partition +} // namespace osrm + +#endif // OSRM_PARTITION_RECURSIVE_BISECTION_HPP_ diff --git a/include/partition/recursive_bisection_state.hpp b/include/partition/recursive_bisection_state.hpp new file mode 100644 index 000000000..18b6191a0 --- /dev/null +++ b/include/partition/recursive_bisection_state.hpp @@ -0,0 +1,74 @@ +#ifndef OSRM_PARTITION_RECURSIVE_BISECTION_STATE_HPP_ +#define OSRM_PARTITION_RECURSIVE_BISECTION_STATE_HPP_ + +#include +#include + +#include "partition/bisection_graph.hpp" +#include "util/typedefs.hpp" + +namespace osrm +{ +namespace partition +{ + +// The recursive state describes the relation between our global graph and the recursive state in a +// recursive bisection. +//  +// We describe the state with the use of two arrays: +//  +// The id-arrays keeps nodes in order, based on their partitioning. Initially, it contains all nodes +// in sorted order: +//  +// ids: [0,1,2,3,4,5,6,7,8,9] +//  +// When partitioned (for this example we use even : odd), the arrays is re-ordered to group all +// elements within a single cell of the partition: +//  +// ids: [0,2,4,6,8,1,3,5,7,9] +// +// This can be performed recursively by interpreting the arrays [0,2,4,6,8] and [1,3,5,7,9] as new +// input. +// +// The partitioning array describes all results of the partitioning in form of `left` or `right`. +// It is a sequence of bits for every id that describes if it is moved to the `front` or `back` +// during the split of the ID array. In the example, we would get the result +//  +// bisection-ids: [0,1,0,1,0,1,0,1,0,1] +//  +// Further partitioning [0,2,4,6,8] into [0,4,8], [2,6] and [1,3,5,7,9] into [1,3,9] and [5,7] +// the result would be: +//  +// bisection-ids: [00,10,01,10,00,11,01,11,00,10] + +class RecursiveBisectionState +{ + public: + // the ID in the partition arr + using BisectionID = std::uint32_t; + using IDIterator = std::vector::const_iterator; + + RecursiveBisectionState(const BisectionGraph &bisection_graph); + ~RecursiveBisectionState(); + + BisectionID GetBisectionID(const NodeID nid) const; + + // returns the center of the bisection + IDIterator ApplyBisection(const IDIterator begin, + const IDIterator end, + const std::vector &partition); + + const IDIterator Begin() const; + const IDIterator End() const; + + private: + const BisectionGraph &bisection_graph; + + std::vector id_array; + std::vector bisection_ids; +}; + +} // namespace partition +} // namespace osrm + +#endif // OSRM_PARTITION_RECURSIVE_BISECTION_STATE_HPP_ diff --git a/include/util/static_graph.hpp b/include/util/static_graph.hpp index 0e13dbc4c..f2faf78f3 100644 --- a/include/util/static_graph.hpp +++ b/include/util/static_graph.hpp @@ -18,54 +18,64 @@ namespace osrm namespace util { -template class StaticGraph +namespace static_graph_details +{ + +using NodeIterator = NodeID; +using EdgeIterator = NodeID; + +struct NodeArrayEntry +{ + // index of the first edge + EdgeIterator first_edge; +}; + +template struct EdgeArrayEntry +{ + NodeID target; + EdgeDataT data; +}; + +template class SortableEdgeWithData { public: - using NodeIterator = NodeID; - using EdgeIterator = NodeID; - using EdgeData = EdgeDataT; + NodeIterator source; + NodeIterator target; + EdgeDataT data; + + template + SortableEdgeWithData(NodeIterator source, NodeIterator target, Ts &&... data) + : source(source), target(target), data(std::forward(data)...) + { + } + bool operator<(const SortableEdgeWithData &right) const + { + if (source != right.source) + { + return source < right.source; + } + return target < right.target; + } +}; + +} // namespace static_graph_details + +template class FlexibleStaticGraph +{ + public: + using NodeIterator = static_graph_details::NodeIterator; + using EdgeIterator = static_graph_details::EdgeIterator; + using EdgeData = decltype(EdgeT::data); using EdgeRange = range; - - class InputEdge - { - public: - NodeIterator source; - NodeIterator target; - EdgeDataT data; - - template - InputEdge(NodeIterator source, NodeIterator target, Ts &&... data) - : source(source), target(target), data(std::forward(data)...) - { - } - bool operator<(const InputEdge &right) const - { - if (source != right.source) - { - return source < right.source; - } - return target < right.target; - } - }; - - struct NodeArrayEntry - { - // index of the first edge - EdgeIterator first_edge; - }; - - struct EdgeArrayEntry - { - NodeID target; - EdgeDataT data; - }; + using NodeArrayEntry = NodeT; + using EdgeArrayEntry = EdgeT; EdgeRange GetAdjacentEdgeRange(const NodeID node) const { return irange(BeginEdges(node), EndEdges(node)); } - template StaticGraph(const int nodes, const ContainerT &graph) + template FlexibleStaticGraph(const int nodes, const ContainerT &graph) { BOOST_ASSERT(std::is_sorted(const_cast(graph).begin(), const_cast(graph).end())); @@ -99,8 +109,8 @@ template class StaticGraph } } - StaticGraph(typename ShM::vector &nodes, - typename ShM::vector &edges) + FlexibleStaticGraph(typename ShM::vector &nodes, + typename ShM::vector &edges) { number_of_nodes = static_cast(nodes.size() - 1); number_of_edges = static_cast(edges.size()); @@ -121,9 +131,9 @@ template class StaticGraph return NodeIterator(edge_array[e].target); } - EdgeDataT &GetEdgeData(const EdgeIterator e) { return edge_array[e].data; } + auto &GetEdgeData(const EdgeIterator e) { return edge_array[e].data; } - const EdgeDataT &GetEdgeData(const EdgeIterator e) const { return edge_array[e].data; } + const auto &GetEdgeData(const EdgeIterator e) const { return edge_array[e].data; } EdgeIterator BeginEdges(const NodeIterator n) const { @@ -200,13 +210,21 @@ template class StaticGraph return current_iterator; } + const NodeArrayEntry& GetNode(const NodeID nid) const { return node_array[nid]; } + const EdgeArrayEntry& GetEdge(const EdgeID eid) const { return edge_array[eid]; } + private: NodeIterator number_of_nodes; EdgeIterator number_of_edges; - typename ShM::vector node_array; - typename ShM::vector edge_array; + typename ShM::vector node_array; + typename ShM::vector edge_array; }; + +template +using StaticGraph = FlexibleStaticGraph, + UseSharedMemory>; } } diff --git a/src/partition/graph_view.cpp b/src/partition/graph_view.cpp new file mode 100644 index 000000000..6221be3d0 --- /dev/null +++ b/src/partition/graph_view.cpp @@ -0,0 +1,65 @@ +#include "partition/graph_view.hpp" +#include + +namespace osrm +{ +namespace partition +{ + +HasSamePartitionID::HasSamePartitionID(const RecursiveBisectionState::BisectionID bisection_id_, + const BisectionGraph &bisection_graph_, + const RecursiveBisectionState &recursive_bisection_state_) + : bisection_id(bisection_id_), bisection_graph(bisection_graph_), + recursive_bisection_state(recursive_bisection_state_) +{ +} + +bool HasSamePartitionID::operator()(const EdgeID eid) const +{ + return recursive_bisection_state.GetBisectionID(bisection_graph.GetTarget(eid)) == bisection_id; +} + +GraphView::GraphView(const BisectionGraph &bisection_graph_, + const RecursiveBisectionState &bisection_state_, + const RecursiveBisectionState::IDIterator begin_, + const RecursiveBisectionState::IDIterator end_) + : bisection_graph(bisection_graph_), bisection_state(bisection_state_), begin(begin_), end(end_) +{ + // print graph + std::cout << "Graph\n"; + for( auto itr = begin_; itr != end_; ++itr ) + { + std::cout << "Node: " << *itr << std::endl; + for( auto eitr = EdgeBegin(*itr); eitr != EdgeEnd(*itr); ++eitr ) + { + std::cout << "\t" << *eitr << " -> " << bisection_graph.GetTarget(*eitr) << std::endl; + } + } +} + +RecursiveBisectionState::IDIterator GraphView::Begin() const { return begin; } + +RecursiveBisectionState::IDIterator GraphView::End() const { return end; } + +std::size_t GraphView::NumberOfNodes() const { return std::distance(begin, end); } + +GraphView::EdgeIterator GraphView::EdgeBegin(const NodeID nid) const +{ + return boost::make_filter_iterator( + HasSamePartitionID(bisection_state.GetBisectionID(nid), + bisection_graph, + bisection_state), + EdgeIDIterator(bisection_graph.BeginEdges(nid)), + EdgeIDIterator(bisection_graph.EndEdges(nid))); +} + +GraphView::EdgeIterator GraphView::EdgeEnd(const NodeID nid) const +{ + return boost::make_filter_iterator( + HasSamePartitionID(bisection_state.GetBisectionID(nid), bisection_graph, bisection_state), + EdgeIDIterator(bisection_graph.EndEdges(nid)), + EdgeIDIterator(bisection_graph.EndEdges(nid))); +} + +} // namespace partition +} // namespace osrm diff --git a/src/partition/inertial_flow.cpp b/src/partition/inertial_flow.cpp new file mode 100644 index 000000000..3cc018689 --- /dev/null +++ b/src/partition/inertial_flow.cpp @@ -0,0 +1,22 @@ +#include "partition/inertial_flow.hpp" + +namespace osrm +{ +namespace partition +{ + +InertialFlow::InertialFlow(const GraphView &view_) : view(view_) {} + +std::vector InertialFlow::ComputePartition(const double balance, const double source_sink_rate) +{ + std::vector partition(view.NumberOfNodes()); + std::size_t i = 0; + for( auto itr = partition.begin(); itr != partition.end(); ++itr ) + { + *itr = (i++ % 2) != 0; + } + return partition; +} + +} // namespace partition +} // namespace osrm diff --git a/src/partition/partitioner.cpp b/src/partition/partitioner.cpp new file mode 100644 index 000000000..c1f32da42 --- /dev/null +++ b/src/partition/partitioner.cpp @@ -0,0 +1,78 @@ +#include "partition/partitioner.hpp" +#include "partition/bisection_graph.hpp" + +#include "partition/recursive_bisection.hpp" + +// TODO remove after testing +#include "util/coordinate.hpp" + +namespace osrm +{ +namespace partition +{ + +int Partitioner::Run(const PartitionConfig &config) +{ + struct TestEdge + { + NodeID source; + NodeID target; + }; + + std::vector input_edges; + + // 0 - 1 - 2 - 3 + // | \ | | + // 4 - 5 - 6 - 7 + + input_edges.push_back({0, 1}); + input_edges.push_back({0, 4}); + input_edges.push_back({0, 5}); + + input_edges.push_back({1, 0}); + input_edges.push_back({1, 2}); + + input_edges.push_back({2, 1}); + input_edges.push_back({2, 3}); + input_edges.push_back({2, 6}); + + input_edges.push_back({3, 2}); + input_edges.push_back({3, 7}); + + input_edges.push_back({4, 0}); + input_edges.push_back({4, 5}); + + input_edges.push_back({5, 0}); + input_edges.push_back({5, 4}); + input_edges.push_back({5, 6}); + + input_edges.push_back({6, 2}); + input_edges.push_back({6, 5}); + input_edges.push_back({6, 7}); + + input_edges.push_back({7, 3}); + input_edges.push_back({7, 6}); + + input_edges = groupBySource(std::move(input_edges)); + + std::vector coordinates; + + for (std::size_t i = 0; i < 8; ++i) + { + coordinates.push_back( + {util::FloatLongitude{(i % 4) / 4.0}, util::FloatLatitude{(double)(i / 4)}}); + } + + // do the partitioning + std::vector nodes = computeNodes(coordinates, input_edges); + std::vector edges = adaptToBisectionEdge(input_edges); + + BisectionGraph graph(nodes, edges); + + RecursiveBisection recursive_bisection(1024, 1.1, 0.25, graph); + + return 0; +} + +} // namespace partition +} // namespace osrm diff --git a/src/partition/recursive_bisection.cpp b/src/partition/recursive_bisection.cpp new file mode 100644 index 000000000..bb5294ef4 --- /dev/null +++ b/src/partition/recursive_bisection.cpp @@ -0,0 +1,38 @@ +#include "partition/recursive_bisection.hpp" +#include "partition/inertial_flow.hpp" + +#include "partition/graph_view.hpp" +#include "partition/recursive_bisection_state.hpp" + +namespace osrm +{ +namespace partition +{ + +RecursiveBisection::RecursiveBisection(std::size_t maximum_cell_size, + double balance, + double boundary_factor, + const BisectionGraph &bisection_graph_) + : bisection_graph(bisection_graph_), internal_state(bisection_graph_) +{ + GraphView view(bisection_graph, internal_state, internal_state.Begin(), internal_state.End()); + InertialFlow flow(view); + const auto partition = flow.ComputePartition(balance, boundary_factor); + const auto center = internal_state.ApplyBisection(view.Begin(), view.End(), partition); + { + auto state = internal_state; + } + + GraphView recursive_view_lhs(bisection_graph, internal_state, view.Begin(), center); + InertialFlow flow_lhs(recursive_view_lhs); + const auto partition_lhs = flow_lhs.ComputePartition(balance,boundary_factor); + internal_state.ApplyBisection(recursive_view_lhs.Begin(),recursive_view_lhs.End(),partition_lhs); + + GraphView recursive_view_rhs(bisection_graph, internal_state, center, view.End()); + InertialFlow flow_rhs(recursive_view_rhs); + const auto partition_rhs = flow_rhs.ComputePartition(balance,boundary_factor); + internal_state.ApplyBisection(recursive_view_rhs.Begin(),recursive_view_rhs.End(),partition_rhs); +} + +} // namespace partition +} // namespace osrm diff --git a/src/partition/recursive_bisection_state.cpp b/src/partition/recursive_bisection_state.cpp new file mode 100644 index 000000000..8ee1afc87 --- /dev/null +++ b/src/partition/recursive_bisection_state.cpp @@ -0,0 +1,69 @@ +#include "partition/recursive_bisection_state.hpp" + +#include + +//TODO remove +#include +#include + +namespace osrm +{ +namespace partition +{ + +RecursiveBisectionState::RecursiveBisectionState(const BisectionGraph &bisection_graph_) + : bisection_graph(bisection_graph_) +{ + id_array.resize(bisection_graph.GetNumberOfNodes()); + std::iota(id_array.begin(), id_array.end(), 0); + bisection_ids.resize(bisection_graph.GetNumberOfNodes(), 0); +} + +RecursiveBisectionState::~RecursiveBisectionState() +{ + std::cout << "Internal Result\n"; + std::cout << "IDArray:"; + for( auto id : id_array ) + std::cout << " " << id; + std::cout << std::endl; + + std::cout << "BisectionIDs:"; + for( auto id : bisection_ids) + std::cout << " " << (std::bitset<4>(id)); + + std::cout << std::endl; +} + +const RecursiveBisectionState::IDIterator RecursiveBisectionState::Begin() const +{ + return id_array.begin(); +} + +const RecursiveBisectionState::IDIterator RecursiveBisectionState::End() const +{ + return id_array.end(); +} + +RecursiveBisectionState::BisectionID RecursiveBisectionState::GetBisectionID(const NodeID nid) const +{ + return bisection_ids[nid]; +} + +RecursiveBisectionState::IDIterator RecursiveBisectionState::ApplyBisection( + const IDIterator begin, const IDIterator end, const std::vector &partition) +{ + // augment the partition ids + for (auto itr = begin; itr != end; ++itr) + { + bisection_ids[*itr] <<= 1; + bisection_ids[*itr] |= partition[std::distance(begin, itr)]; + } + + // keep items with `0` as partition id to the left, move other to the right + return std::stable_partition(id_array.begin() + std::distance(id_array.cbegin(), begin), + id_array.begin() + std::distance(id_array.cbegin(), end), + [this](const auto nid) { return 0 == (bisection_ids[nid] & 1); }); +} + +} // namespace partition +} // namespace osrm diff --git a/src/tools/components.cpp b/src/tools/components.cpp index 9e805face..9965aee65 100644 --- a/src/tools/components.cpp +++ b/src/tools/components.cpp @@ -42,7 +42,7 @@ struct TarjanEdgeData }; using TarjanGraph = util::StaticGraph; -using TarjanEdge = TarjanGraph::InputEdge; +using TarjanEdge = util::static_graph_details::SortableEdgeWithData; std::size_t loadGraph(const std::string &path, std::vector &coordinate_list, diff --git a/src/tools/partition.cpp b/src/tools/partition.cpp new file mode 100644 index 000000000..6bff9206a --- /dev/null +++ b/src/tools/partition.cpp @@ -0,0 +1,145 @@ +#include "partition/partitioner.hpp" +#include "partition/partition_config.hpp" + +#include "util/log.hpp" +#include "util/version.hpp" + +#include + +#include +#include + +#include + +using namespace osrm; + +enum class return_code : unsigned +{ + ok, + fail, + exit +}; + +return_code parseArguments(int argc, char *argv[], partition::PartitionConfig &partition_config) +{ + // declare a group of options that will be allowed only on command line + boost::program_options::options_description generic_options("Options"); + generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message"); + + // declare a group of options that will be allowed both on command line + boost::program_options::options_description config_options("Configuration"); + config_options.add_options()( + "threads,t", + boost::program_options::value(&partition_config.requested_num_threads) + ->default_value(tbb::task_scheduler_init::default_num_threads()), + "Number of threads to use"); + + // hidden options, will be allowed on command line, but will not be + // shown to the user + boost::program_options::options_description hidden_options("Hidden options"); + hidden_options.add_options()( + "input,i", + boost::program_options::value(&partition_config.base_path), + "Input file in .osrm format"); + + // positional option + boost::program_options::positional_options_description positional_options; + positional_options.add("input", 1); + + // combine above options for parsing + boost::program_options::options_description cmdline_options; + cmdline_options.add(generic_options).add(config_options).add(hidden_options); + + const auto *executable = argv[0]; + boost::program_options::options_description visible_options( + boost::filesystem::path(executable).filename().string() + " [options]"); + visible_options.add(generic_options).add(config_options); + + // parse command line options + boost::program_options::variables_map option_variables; + try + { + boost::program_options::store(boost::program_options::command_line_parser(argc, argv) + .options(cmdline_options) + .positional(positional_options) + .run(), + option_variables); + } + catch (const boost::program_options::error &e) + { + util::Log(logERROR) << e.what(); + return return_code::fail; + } + + if (option_variables.count("version")) + { + std::cout << OSRM_VERSION << std::endl; + return return_code::exit; + } + + if (option_variables.count("help")) + { + std::cout << visible_options; + return return_code::exit; + } + + boost::program_options::notify(option_variables); + + if (!option_variables.count("input")) + { + std::cout << visible_options; + return return_code::exit; + } + + return return_code::ok; +} + +int main(int argc, char *argv[]) try +{ + util::LogPolicy::GetInstance().Unmute(); + partition::PartitionConfig partition_config; + + const auto result = parseArguments(argc, argv, partition_config); + + if (return_code::fail == result) + { + return EXIT_FAILURE; + } + + if (return_code::exit == result) + { + return EXIT_SUCCESS; + } + + // set the default in/output names + partition_config.UseDefaults(); + + if (1 > partition_config.requested_num_threads) + { + util::Log(logERROR) << "Number of threads must be 1 or larger"; + return EXIT_FAILURE; + } + + if (!boost::filesystem::is_regular_file(partition_config.base_path)) + { + util::Log(logERROR) << "Input file " << partition_config.base_path.string() + << " not found!"; + return EXIT_FAILURE; + } + + auto exitcode = partition::Partitioner().Run(partition_config); + return exitcode; +} +catch (const std::bad_alloc &e) +{ + util::Log(logERROR) << "[exception] " << e.what(); + util::Log(logERROR) << "Please provide more memory or consider using a larger swapfile"; + return EXIT_FAILURE; +} +#ifdef _WIN32 +catch (const std::exception &e) +{ + util::Log(logERROR) << "[exception] " << e.what() << std::endl; + return EXIT_FAILURE; +} +#endif diff --git a/unit_tests/util/static_graph.cpp b/unit_tests/util/static_graph.cpp index 05fe60df7..506ffd18c 100644 --- a/unit_tests/util/static_graph.cpp +++ b/unit_tests/util/static_graph.cpp @@ -21,7 +21,7 @@ struct TestData typedef StaticGraph TestStaticGraph; typedef TestStaticGraph::NodeArrayEntry TestNodeArrayEntry; typedef TestStaticGraph::EdgeArrayEntry TestEdgeArrayEntry; -typedef TestStaticGraph::InputEdge TestInputEdge; +typedef static_graph_details::SortableEdgeWithData TestInputEdge; constexpr unsigned TEST_NUM_NODES = 100; constexpr unsigned TEST_NUM_EDGES = 500;