diff --git a/include/partition/edge_based_graph_reader.hpp b/include/partition/edge_based_graph_reader.hpp new file mode 100644 index 000000000..7c4fb0649 --- /dev/null +++ b/include/partition/edge_based_graph_reader.hpp @@ -0,0 +1,203 @@ +#ifndef OSRM_EDGE_BASED_GRAPH_READER_HPP +#define OSRM_EDGE_BASED_GRAPH_READER_HPP + +#include "storage/io.hpp" +#include "util/coordinate.hpp" +#include "util/dynamic_graph.hpp" +#include "util/typedefs.hpp" + +#include + +#include +#include +#include +#include + +namespace osrm +{ +namespace partition +{ + +struct EdgeBasedGraphEdgeData +{ + NodeID edge_id : 31; + // Artificial edge used to fixup partitioning, see #3205. + // These artificial edges have invalid weight / duration. + std::uint32_t is_boundary_arc : 1; + EdgeWeight weight; + EdgeWeight duration : 30; + std::uint32_t forward : 1; + std::uint32_t backward : 1; +}; + +struct EdgeBasedGraph : util::DynamicGraph +{ + using Base = util::DynamicGraph; + using Base::Base; +}; + +struct EdgeBasedGraphEdge : EdgeBasedGraph::InputEdge +{ + using Base = EdgeBasedGraph::InputEdge; + using Base::Base; +}; + +struct EdgeBasedGraphReader +{ + EdgeBasedGraphReader(storage::io::FileReader &reader) + { + // Reads: | Fingerprint | #e | max_eid | edges | + // - uint64: number of edges + // - EdgeID: max edge id + // - extractor::EdgeBasedEdge edges + // + // Gets written in Extractor::WriteEdgeBasedGraph + + const auto num_edges = reader.ReadElementCount64(); + const auto max_edge_id = reader.ReadOne(); + + num_nodes = max_edge_id + 1; + + edges.resize(num_edges); + reader.ReadInto(edges); + } + + // FIXME: wrapped in unique_ptr since dynamic_graph is not move-able + + std::unique_ptr BuildEdgeBasedGraph() + { + // FIXME: The following is a rough adaption from: + // - adaptToContractorInput + // - GraphContractor::GraphContractor + // and should really be abstracted over. + + auto directed = SplitBidirectionalEdges(edges); + auto tidied = PrepareEdgesForUsageInGraph(directed); + + return std::make_unique(num_nodes, tidied); + } + + private: + // Bidirectional (s,t) to (s,t) and (t,s) + static std::vector + SplitBidirectionalEdges(std::vector edges) + { + std::vector directed; + directed.reserve(edges.size() * 2); + + for (const auto &edge : edges) + { + directed.emplace_back(edge.source, + edge.target, + edge.edge_id, + std::max(edge.weight, 1), + edge.duration, + edge.forward, + edge.backward); + + directed.emplace_back(edge.target, + edge.source, + edge.edge_id, + std::max(edge.weight, 1), + edge.duration, + edge.backward, + edge.forward); + } + + std::swap(directed, edges); + + return directed; + } + + static std::vector + PrepareEdgesForUsageInGraph(std::vector edges) + { + std::sort(begin(edges), end(edges)); + + std::vector graph_edges; + graph_edges.reserve(edges.size()); + + for (NodeID i = 0; i < edges.size();) + { + const NodeID source = edges[i].source; + const NodeID target = edges[i].target; + + // remove eigenloops + if (source == target) + { + ++i; + continue; + } + + EdgeBasedGraphEdge forward_edge; + EdgeBasedGraphEdge reverse_edge; + forward_edge.source = reverse_edge.source = source; + forward_edge.target = reverse_edge.target = target; + forward_edge.data.edge_id = reverse_edge.data.edge_id = edges[i].edge_id; + forward_edge.data.is_boundary_arc = reverse_edge.data.is_boundary_arc = false; + forward_edge.data.weight = reverse_edge.data.weight = INVALID_EDGE_WEIGHT; + forward_edge.data.duration = reverse_edge.data.duration = MAXIMAL_EDGE_DURATION; + forward_edge.data.forward = reverse_edge.data.backward = true; + forward_edge.data.backward = reverse_edge.data.forward = false; + + + // remove parallel edges + while (i < edges.size() && edges[i].source == source && edges[i].target == target) + { + if (edges[i].forward) + { + forward_edge.data.weight = std::min(edges[i].weight, forward_edge.data.weight); + forward_edge.data.duration = + std::min(edges[i].duration, forward_edge.data.duration); + } + if (edges[i].backward) + { + reverse_edge.data.weight = std::min(edges[i].weight, reverse_edge.data.weight); + reverse_edge.data.duration = + std::min(edges[i].duration, reverse_edge.data.duration); + } + ++i; + } + // merge edges (s,t) and (t,s) into bidirectional edge + if (forward_edge.data.weight == reverse_edge.data.weight) + { + if ((int)forward_edge.data.weight != INVALID_EDGE_WEIGHT) + { + forward_edge.data.backward = true; + graph_edges.push_back(forward_edge); + } + } + else + { // insert seperate edges + if (((int)forward_edge.data.weight) != INVALID_EDGE_WEIGHT) + { + graph_edges.push_back(forward_edge); + } + if ((int)reverse_edge.data.weight != INVALID_EDGE_WEIGHT) + { + graph_edges.push_back(reverse_edge); + } + } + } + + return graph_edges; + } + + std::vector edges; + std::size_t num_nodes; +}; + +inline std::unique_ptr LoadEdgeBasedGraph(const std::string &path) +{ + const auto fingerprint = storage::io::FileReader::VerifyFingerprint; + storage::io::FileReader reader(path, fingerprint); + + EdgeBasedGraphReader builder{reader}; + + return builder.BuildEdgeBasedGraph(); +} + +} // ns partition +} // ns osrm + +#endif diff --git a/include/util/dynamic_graph.hpp b/include/util/dynamic_graph.hpp index 8312292ca..ab588c620 100644 --- a/include/util/dynamic_graph.hpp +++ b/include/util/dynamic_graph.hpp @@ -105,8 +105,6 @@ template class DynamicGraph } } - ~DynamicGraph() {} - unsigned GetNumberOfNodes() const { return number_of_nodes; } unsigned GetNumberOfEdges() const { return number_of_edges; } diff --git a/include/util/static_graph_traits.hpp b/include/util/graph_traits.hpp similarity index 83% rename from include/util/static_graph_traits.hpp rename to include/util/graph_traits.hpp index ea256bf24..419e6e276 100644 --- a/include/util/static_graph_traits.hpp +++ b/include/util/graph_traits.hpp @@ -1,5 +1,5 @@ -#ifndef STATIC_GRAPH_TRAITS_HPP -#define STATIC_GRAPH_TRAITS_HPP +#ifndef OSRM_GRAPH_TRAITS_HPP +#define OSRM_GRAPH_TRAITS_HPP #include @@ -31,14 +31,14 @@ struct HasTargetMember().target) > 0)) { }; -// Static Graph requires edges to have a .target and .data member attribute +// Our graphs require edges to have a .target and .data member attribute template struct HasDataAndTargetMember : std::integral_constant::value && HasTargetMember::value> { }; -// Static Graph requires nodes to have a .first_edge member attribute +// Our graphs require nodes to have a .first_edge member attribute template struct HasFirstEdgeMember : std::false_type { }; diff --git a/include/util/static_graph.hpp b/include/util/static_graph.hpp index 42d531741..8dee24a23 100644 --- a/include/util/static_graph.hpp +++ b/include/util/static_graph.hpp @@ -1,10 +1,10 @@ #ifndef STATIC_GRAPH_HPP #define STATIC_GRAPH_HPP +#include "util/graph_traits.hpp" #include "util/integer_range.hpp" #include "util/percent.hpp" #include "util/shared_memory_vector_wrapper.hpp" -#include "util/static_graph_traits.hpp" #include "util/typedefs.hpp" #include diff --git a/src/partition/partitioner.cpp b/src/partition/partitioner.cpp index eae60f877..4223defd6 100644 --- a/src/partition/partitioner.cpp +++ b/src/partition/partitioner.cpp @@ -2,12 +2,14 @@ #include "partition/annotated_partition.hpp" #include "partition/bisection_graph.hpp" #include "partition/compressed_node_based_graph_reader.hpp" +#include "partition/edge_based_graph_reader.hpp" #include "partition/node_based_graph_to_edge_based_graph_mapping_reader.hpp" #include "partition/recursive_bisection.hpp" #include "util/coordinate.hpp" #include "util/geojson_debug_logger.hpp" #include "util/geojson_debug_policies.hpp" +#include "util/integer_range.hpp" #include "util/json_container.hpp" #include "util/log.hpp" @@ -136,9 +138,30 @@ int Partitioner::Run(const PartitionConfig &config) recursive_bisection.BisectionIDs()); auto mapping = LoadNodeBasedGraphToEdgeBasedGraphMapping(config.nbg_ebg_mapping_path.string()); - util::Log() << "Loaded node based graph to edge based graph mapping"; + auto edge_based_graph = LoadEdgeBasedGraph(config.edge_based_graph_path.string()); + util::Log() << "Loaded edge based graph for mapping partition ids: " + << edge_based_graph->GetNumberOfEdges() << " edges, " + << edge_based_graph->GetNumberOfNodes() << " nodes"; + + for (const auto node_id : util::irange(0u, edge_based_graph->GetNumberOfNodes())) + { + const auto node_based_nodes = mapping.Lookup(node_id); + + const auto u = node_based_nodes.u; + const auto v = node_based_nodes.v; + + auto partition_id = [](auto) { + return 0; /*dummy*/ + }; + + if (partition_id(u) != partition_id(v)) + { + // TODO: resolve border nodes u, v + } + } + return 0; }