diff --git a/algorithms/tiny_components.hpp b/algorithms/tiny_components.hpp index 71336bf45..44256e2ab 100644 --- a/algorithms/tiny_components.hpp +++ b/algorithms/tiny_components.hpp @@ -30,7 +30,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../typedefs.h" #include "../data_structures/deallocating_vector.hpp" -#include "../data_structures/dynamic_graph.hpp" #include "../data_structures/import_edge.hpp" #include "../data_structures/query_node.hpp" #include "../data_structures/percent.hpp" @@ -46,17 +45,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include #include -#if defined(__APPLE__) || defined (_WIN32) -#include -#include -#else -#include -#include -#endif #include @@ -66,9 +57,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +template class TarjanSCC { - private: + struct TarjanStackFrame + { + explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {} + NodeID v; + NodeID parent; + }; + struct TarjanNode { TarjanNode() : index(SPECIAL_NODEID), low_link(SPECIAL_NODEID), on_stack(false) {} @@ -77,45 +75,28 @@ class TarjanSCC bool on_stack; }; - struct TarjanEdgeData - { - TarjanEdgeData() : distance(INVALID_EDGE_WEIGHT), name_id(INVALID_NAMEID) {} - TarjanEdgeData(int distance, unsigned name_id) : distance(distance), name_id(name_id) {} - int distance; - unsigned name_id; - }; - - struct TarjanStackFrame - { - explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {} - NodeID v; - NodeID parent; - }; - - using TarjanDynamicGraph = DynamicGraph; - using TarjanEdge = TarjanDynamicGraph::InputEdge; using RestrictionSource = std::pair; using RestrictionTarget = std::pair; using EmanatingRestrictionsVector = std::vector; using RestrictionMap = std::unordered_map; - std::vector m_coordinate_list; std::vector m_restriction_bucket_list; - std::shared_ptr m_node_based_graph; + std::vector components_index; + std::vector component_size_vector; + std::shared_ptr m_node_based_graph; std::unordered_set barrier_node_list; - std::unordered_set traffic_light_list; - unsigned m_restriction_counter; + unsigned size_one_counter; RestrictionMap m_restriction_map; public: - TarjanSCC(int number_of_nodes, - std::vector &input_edges, + TarjanSCC(std::shared_ptr graph, std::vector &bn, - std::vector &tl, - std::vector &irs, - std::vector &nI) - : m_coordinate_list(nI), m_restriction_counter(irs.size()) + std::vector &irs) + : components_index(graph->GetNumberOfNodes(), SPECIAL_NODEID), + m_node_based_graph(graph), + size_one_counter(0) { + TIMER_START(SCC_LOAD); for (const TurnRestriction &restriction : irs) { @@ -149,91 +130,19 @@ class TarjanSCC } barrier_node_list.insert(bn.begin(), bn.end()); - traffic_light_list.insert(tl.begin(), tl.end()); - DeallocatingVector edge_list; - for (const NodeBasedEdge &input_edge : input_edges) - { - if (input_edge.source == input_edge.target) - { - continue; - } - - if (input_edge.forward) - { - edge_list.emplace_back(input_edge.source, - input_edge.target, - (std::max)((int)input_edge.weight, 1), - input_edge.name_id); - } - if (input_edge.backward) - { - edge_list.emplace_back(input_edge.target, - input_edge.source, - (std::max)((int)input_edge.weight, 1), - input_edge.name_id); - } - } - input_edges.clear(); - input_edges.shrink_to_fit(); - BOOST_ASSERT_MSG(0 == input_edges.size() && 0 == input_edges.capacity(), - "input edge vector not properly deallocated"); - - tbb::parallel_sort(edge_list.begin(), edge_list.end()); - m_node_based_graph = std::make_shared(number_of_nodes, edge_list); TIMER_STOP(SCC_LOAD); SimpleLogger().Write() << "Loading data into SCC took " << TIMER_MSEC(SCC_LOAD)/1000. << "s"; } - ~TarjanSCC() { m_node_based_graph.reset(); } - void Run() { - TIMER_START(SCC_RUN_SETUP); - // remove files from previous run if exist - DeleteFileIfExists("component.dbf"); - DeleteFileIfExists("component.shx"); - DeleteFileIfExists("component.shp"); - - Percent p(m_node_based_graph->GetNumberOfNodes()); - - OGRRegisterAll(); - - const char *pszDriverName = "ESRI Shapefile"; - OGRSFDriver *poDriver = - OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(pszDriverName); - if (nullptr == poDriver) - { - throw OSRMException("ESRI Shapefile driver not available"); - } - OGRDataSource *poDS = poDriver->CreateDataSource("component.shp", nullptr); - - if (nullptr == poDS) - { - throw OSRMException("Creation of output file failed"); - } - - OGRSpatialReference *poSRS = new OGRSpatialReference(); - poSRS->importFromEPSG(4326); - - OGRLayer *poLayer = poDS->CreateLayer("component", poSRS, wkbLineString, nullptr); - - if (nullptr == poLayer) - { - throw OSRMException("Layer creation failed."); - } - TIMER_STOP(SCC_RUN_SETUP); - SimpleLogger().Write() << "shapefile setup took " << TIMER_MSEC(SCC_RUN_SETUP)/1000. << "s"; - TIMER_START(SCC_RUN); // The following is a hack to distinguish between stuff that happens // before the recursive call and stuff that happens after std::stack recursion_stack; // true = stuff before, false = stuff after call std::stack tarjan_stack; - std::vector components_index(m_node_based_graph->GetNumberOfNodes(), - SPECIAL_NODEID); - std::vector component_size_vector; std::vector tarjan_node_list(m_node_based_graph->GetNumberOfNodes()); unsigned component_index = 0, size_of_current_component = 0; int index = 0; @@ -274,8 +183,7 @@ class TarjanSCC // Traverse outgoing edges for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(v)) { - const TarjanDynamicGraph::NodeIterator vprime = - m_node_based_graph->GetTarget(current_edge); + const auto vprime = m_node_based_graph->GetTarget(current_edge); if (SPECIAL_NODEID == tarjan_node_list[vprime].index) { recursion_stack.emplace(TarjanStackFrame(vprime, v)); @@ -327,86 +235,23 @@ class TarjanSCC TIMER_STOP(SCC_RUN); SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN)/1000. << "s"; - SimpleLogger().Write() << "identified: " << component_size_vector.size() - << " many components, marking small components"; + SimpleLogger().Write() << "identified: " << component_size_vector.size() << " many components"; - TIMER_START(SCC_OUTPUT); - const unsigned size_one_counter = std::count_if(component_size_vector.begin(), - component_size_vector.end(), - [](unsigned value) - { + size_one_counter = std::count_if(component_size_vector.begin(), + component_size_vector.end(), + [](unsigned value) + { return 1 == value; }); SimpleLogger().Write() << "identified " << size_one_counter << " SCCs of size 1"; - uint64_t total_network_distance = 0; - p.reinit(m_node_based_graph->GetNumberOfNodes()); - // const NodeID last_u_node = m_node_based_graph->GetNumberOfNodes(); - for (const NodeID source : osrm::irange(0u, last_node)) - { - p.printIncrement(); - for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(source)) - { - const TarjanDynamicGraph::NodeIterator target = - m_node_based_graph->GetTarget(current_edge); + } - if (source < target || - m_node_based_graph->EndEdges(target) == - m_node_based_graph->FindEdge(target, source)) - { - total_network_distance += - 100 * FixedPointCoordinate::ApproximateEuclideanDistance( - m_coordinate_list[source].lat, - m_coordinate_list[source].lon, - m_coordinate_list[target].lat, - m_coordinate_list[target].lon); - - BOOST_ASSERT(current_edge != SPECIAL_EDGEID); - BOOST_ASSERT(source != SPECIAL_NODEID); - BOOST_ASSERT(target != SPECIAL_NODEID); - - const unsigned size_of_containing_component = - std::min(component_size_vector[components_index[source]], - component_size_vector[components_index[target]]); - - // edges that end on bollard nodes may actually be in two distinct components - if (size_of_containing_component < 10) - { - OGRLineString lineString; - lineString.addPoint(m_coordinate_list[source].lon / COORDINATE_PRECISION, - m_coordinate_list[source].lat / COORDINATE_PRECISION); - lineString.addPoint(m_coordinate_list[target].lon / COORDINATE_PRECISION, - m_coordinate_list[target].lat / COORDINATE_PRECISION); - - OGRFeature *poFeature = OGRFeature::CreateFeature(poLayer->GetLayerDefn()); - - poFeature->SetGeometry(&lineString); - if (OGRERR_NONE != poLayer->CreateFeature(poFeature)) - { - throw OSRMException("Failed to create feature in shapefile."); - } - OGRFeature::DestroyFeature(poFeature); - } - } - } - } - OGRDataSource::DestroyDataSource(poDS); - component_size_vector.clear(); - component_size_vector.shrink_to_fit(); - BOOST_ASSERT_MSG(0 == component_size_vector.size() && 0 == component_size_vector.capacity(), - "component_size_vector not properly deallocated"); - - components_index.clear(); - components_index.shrink_to_fit(); - BOOST_ASSERT_MSG(0 == components_index.size() && 0 == components_index.capacity(), - "components_index not properly deallocated"); - TIMER_STOP(SCC_OUTPUT); - SimpleLogger().Write() << "generating output took: " << TIMER_MSEC(SCC_OUTPUT)/1000. << "s"; - - SimpleLogger().Write() << "total network distance: " - << (uint64_t)total_network_distance / 100 / 1000. << " km"; + unsigned get_component_size(const NodeID node) const + { + return component_size_vector[components_index[node]]; } private: @@ -446,14 +291,6 @@ class TarjanSCC } return false; } - - void DeleteFileIfExists(const std::string &file_name) const - { - if (boost::filesystem::exists(file_name)) - { - boost::filesystem::remove(file_name); - } - } }; #endif /* TINY_COMPONENTS_HPP */ diff --git a/tools/components.cpp b/tools/components.cpp index e80eb8d57..2dda96016 100644 --- a/tools/components.cpp +++ b/tools/components.cpp @@ -27,11 +27,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../typedefs.h" #include "../algorithms/tiny_components.hpp" +#include "../data_structures/dynamic_graph.hpp" #include "../Util/GraphLoader.h" +#include "../Util/make_unique.hpp" #include "../Util/OSRMException.h" #include "../Util/simple_logger.hpp" #include "../Util/FingerPrint.h" +#include + +#if defined(__APPLE__) || defined (_WIN32) +#include +#include +#else +#include +#include +#endif + #include #include #include @@ -39,8 +51,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. std::vector coordinate_list; std::vector restrictions_vector; -std::vector bollard_ID_list; -std::vector trafficlight_ID_list; +std::vector bollard_node_list; +std::vector traffic_lights_list; + +struct TarjanEdgeData +{ + TarjanEdgeData() : distance(INVALID_EDGE_WEIGHT), name_id(INVALID_NAMEID) {} + TarjanEdgeData(int distance, unsigned name_id) : distance(distance), name_id(name_id) {} + int distance; + unsigned name_id; +}; + +using TarjanDynamicGraph = DynamicGraph; +using TarjanEdge = TarjanDynamicGraph::InputEdge; + +void DeleteFileIfExists(const std::string &file_name) +{ + if (boost::filesystem::exists(file_name)) + { + boost::filesystem::remove(file_name); + } +} int main(int argc, char *argv[]) { @@ -94,32 +125,158 @@ int main(int argc, char *argv[]) std::vector edge_list; const NodeID number_of_nodes = readBinaryOSRMGraphFromStream(input_stream, edge_list, - bollard_ID_list, - trafficlight_ID_list, + bollard_node_list, + traffic_lights_list, &coordinate_list, restrictions_vector); input_stream.close(); + BOOST_ASSERT_MSG(restrictions_vector.size() == usable_restrictions, "size of restrictions_vector changed"); SimpleLogger().Write() << restrictions_vector.size() << " restrictions, " - << bollard_ID_list.size() << " bollard nodes, " - << trafficlight_ID_list.size() << " traffic lights"; + << bollard_node_list.size() << " bollard nodes, " + << traffic_lights_list.size() << " traffic lights"; - // Building an edge-expanded graph from node-based input an turn - // restrictions - SimpleLogger().Write() << "Starting SCC graph traversal"; - std::shared_ptr tarjan = std::make_shared(number_of_nodes, - edge_list, - bollard_ID_list, - trafficlight_ID_list, - restrictions_vector, - coordinate_list); + traffic_lights_list.clear(); + traffic_lights_list.shrink_to_fit(); + + // Building an node-based graph + DeallocatingVector graph_edge_list; + for (const NodeBasedEdge &input_edge : edge_list) + { + if (input_edge.source == input_edge.target) + { + continue; + } + + if (input_edge.forward) + { + graph_edge_list.emplace_back(input_edge.source, + input_edge.target, + (std::max)((int)input_edge.weight, 1), + input_edge.name_id); + } + if (input_edge.backward) + { + graph_edge_list.emplace_back(input_edge.target, + input_edge.source, + (std::max)((int)input_edge.weight, 1), + input_edge.name_id); + } + } + edge_list.clear(); + edge_list.shrink_to_fit(); + BOOST_ASSERT_MSG(0 == edge_list.size() && 0 == edge_list.capacity(), + "input edge vector not properly deallocated"); + + tbb::parallel_sort(graph_edge_list.begin(), graph_edge_list.end()); + auto graph = std::make_shared(number_of_nodes, graph_edge_list); edge_list.clear(); edge_list.shrink_to_fit(); + SimpleLogger().Write() << "Starting SCC graph traversal"; + auto tarjan = osrm::make_unique>(graph, + bollard_node_list, + restrictions_vector); tarjan->Run(); + + // output + TIMER_START(SCC_RUN_SETUP); + + // remove files from previous run if exist + DeleteFileIfExists("component.dbf"); + DeleteFileIfExists("component.shx"); + DeleteFileIfExists("component.shp"); + + Percent p(number_of_nodes); + + OGRRegisterAll(); + + const char *pszDriverName = "ESRI Shapefile"; + OGRSFDriver *poDriver = + OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(pszDriverName); + if (nullptr == poDriver) + { + throw OSRMException("ESRI Shapefile driver not available"); + } + OGRDataSource *poDS = poDriver->CreateDataSource("component.shp", nullptr); + + if (nullptr == poDS) + { + throw OSRMException("Creation of output file failed"); + } + + OGRSpatialReference *poSRS = new OGRSpatialReference(); + poSRS->importFromEPSG(4326); + + OGRLayer *poLayer = poDS->CreateLayer("component", poSRS, wkbLineString, nullptr); + + if (nullptr == poLayer) + { + throw OSRMException("Layer creation failed."); + } + TIMER_STOP(SCC_RUN_SETUP); + SimpleLogger().Write() << "shapefile setup took " << TIMER_MSEC(SCC_RUN_SETUP)/1000. << "s"; + + uint64_t total_network_distance = 0; + p.reinit(number_of_nodes); + // const NodeID last_u_node = m_node_based_graph->GetNumberOfNodes(); + TIMER_START(SCC_OUTPUT); + for (const NodeID source : osrm::irange(0u, number_of_nodes)) + { + p.printIncrement(); + for (const auto current_edge : graph->GetAdjacentEdgeRange(source)) + { + const TarjanDynamicGraph::NodeIterator target = graph->GetTarget(current_edge); + + if (source < target || graph->EndEdges(target) == graph->FindEdge(target, source)) + { + total_network_distance += + 100 * FixedPointCoordinate::ApproximateEuclideanDistance( + coordinate_list[source].lat, + coordinate_list[source].lon, + coordinate_list[target].lat, + coordinate_list[target].lon); + + BOOST_ASSERT(current_edge != SPECIAL_EDGEID); + BOOST_ASSERT(source != SPECIAL_NODEID); + BOOST_ASSERT(target != SPECIAL_NODEID); + + const unsigned size_of_containing_component = + std::min(tarjan->get_component_size(source), + tarjan->get_component_size(target)); + + // edges that end on bollard nodes may actually be in two distinct components + if (size_of_containing_component < 1000) + { + OGRLineString lineString; + lineString.addPoint(coordinate_list[source].lon / COORDINATE_PRECISION, + coordinate_list[source].lat / COORDINATE_PRECISION); + lineString.addPoint(coordinate_list[target].lon / COORDINATE_PRECISION, + coordinate_list[target].lat / COORDINATE_PRECISION); + + OGRFeature *poFeature = OGRFeature::CreateFeature(poLayer->GetLayerDefn()); + + poFeature->SetGeometry(&lineString); + if (OGRERR_NONE != poLayer->CreateFeature(poFeature)) + { + throw OSRMException("Failed to create feature in shapefile."); + } + OGRFeature::DestroyFeature(poFeature); + } + } + } + } + OGRSpatialReference::DestroySpatialReference(poSRS); + OGRDataSource::DestroyDataSource(poDS); + TIMER_STOP(SCC_OUTPUT); + SimpleLogger().Write() << "generating output took: " << TIMER_MSEC(SCC_OUTPUT)/1000. << "s"; + + SimpleLogger().Write() << "total network distance: " + << (uint64_t)total_network_distance / 100 / 1000. << " km"; + SimpleLogger().Write() << "finished component analysis"; } catch (const std::exception &e)