#ifndef OSRM_CONTRACTOR_CONTRACT_EXCLUDABLE_GRAPH_HPP #define OSRM_CONTRACTOR_CONTRACT_EXCLUDABLE_GRAPH_HPP #include "contractor/contracted_edge_container.hpp" #include "contractor/contractor_graph.hpp" #include "contractor/graph_contractor.hpp" #include "contractor/graph_contractor_adaptors.hpp" #include "contractor/query_graph.hpp" namespace osrm { namespace contractor { using GraphFilterAndCore = std::tuple>, std::vector>>; inline auto contractExcludableGraph(ContractorGraph contractor_graph_, std::vector node_weights, const std::vector> &filters, const float core_factor = 1.0) { auto num_nodes = contractor_graph_.GetNumberOfNodes(); ContractedEdgeContainer edge_container; ContractorGraph shared_core_graph; std::vector is_shared_core; { ContractorGraph contractor_graph = std::move(contractor_graph_); std::vector always_allowed(num_nodes, true); for (const auto &filter : filters) { for (const auto node : util::irange(0, num_nodes)) { always_allowed[node] = always_allowed[node] && filter[node]; } } // By not contracting all contractable nodes we avoid creating // a very dense core. This increases the overall graph sizes a little bit // but increases the final CH quality and contraction speed. constexpr float BASE_CORE = 0.9; is_shared_core = contractGraph(contractor_graph, std::move(always_allowed), node_weights, std::min(BASE_CORE, core_factor)); // Add all non-core edges to container { auto non_core_edges = toEdges(contractor_graph); auto new_end = std::remove_if(non_core_edges.begin(), non_core_edges.end(), [&](const auto &edge) { return is_shared_core[edge.source] && is_shared_core[edge.target]; }); non_core_edges.resize(new_end - non_core_edges.begin()); edge_container.Insert(std::move(non_core_edges)); } // Extract core graph for further contraction shared_core_graph = contractor_graph.Filter( [&is_shared_core](const NodeID node) { return is_shared_core[node]; }); } std::vector> cores; for (const auto &filter : filters) { auto filtered_core_graph = shared_core_graph.Filter([&filter](const NodeID node) { return filter[node]; }); auto core = contractGraph( filtered_core_graph, is_shared_core, is_shared_core, node_weights, core_factor); if (core_factor == 1.0) { core.clear(); } cores.push_back(std::move(core)); edge_container.Merge(toEdges(std::move(filtered_core_graph))); } return GraphFilterAndCore{QueryGraph{num_nodes, std::move(edge_container.edges)}, edge_container.MakeEdgeFilters(), std::move(cores)}; } } } #endif