diff --git a/Algorithms/StronglyConnectedComponents.h b/Algorithms/StronglyConnectedComponents.h index f2376727e..95137dac0 100644 --- a/Algorithms/StronglyConnectedComponents.h +++ b/Algorithms/StronglyConnectedComponents.h @@ -35,11 +35,13 @@ Strongly connected components using Tarjan's Algorithm #include "../Util/SimpleLogger.h" +#include #include #include #include #include #include +#include #ifdef __APPLE__ #include @@ -48,7 +50,7 @@ Strongly connected components using Tarjan's Algorithm #include #include #endif -#include + #include #include @@ -64,7 +66,6 @@ private: struct TarjanEdgeData { int distance; - unsigned edgeBasedNodeID; unsigned nameID:31; bool shortcut:1; short type; @@ -77,26 +78,28 @@ private: }; struct TarjanStackFrame { - explicit TarjanStackFrame(NodeID _v, NodeID p) : v(_v), parent(p) {} + explicit TarjanStackFrame( + NodeID v, + NodeID parent + ) : v(v), parent(parent) { } NodeID v; NodeID parent; }; - typedef DynamicGraph TarjanDynamicGraph; - typedef TarjanDynamicGraph::InputEdge TarjanEdge; - typedef std::pair RestrictionSource; - typedef std::pair RestrictionTarget; - typedef std::vector EmanatingRestrictionsVector; + typedef DynamicGraph TarjanDynamicGraph; + typedef TarjanDynamicGraph::InputEdge TarjanEdge; + typedef std::pair RestrictionSource; + typedef std::pair restriction_target; + typedef std::vector EmanatingRestrictionsVector; typedef boost::unordered_map RestrictionMap; - std::vector inputNodeInfoList; - unsigned numberOfTurnRestrictions; - boost::shared_ptr _nodeBasedGraph; - boost::unordered_map _barrierNodes; - boost::unordered_map _trafficLights; - - std::vector _restrictionBucketVector; - RestrictionMap _restrictionMap; + std::vector m_coordinate_list; + std::vector m_restriction_bucket_list; + boost::shared_ptr m_node_based_graph; + boost::unordered_set m_barrier_node_list; + boost::unordered_set m_traffic_light_list; + unsigned m_restriction_counter; + RestrictionMap m_restriction_map; struct EdgeBasedNode { bool operator<(const EdgeBasedNode & other) const { @@ -116,93 +119,99 @@ private: bool ignoreInGrid:1; }; - DeallocatingVector edgeBasedNodes; public: TarjanSCC( - int nodes, - std::vector & inputEdges, + int number_of_nodes, + std::vector & input_edges, std::vector & bn, std::vector & tl, std::vector & irs, std::vector & nI ) : - inputNodeInfoList(nI), - numberOfTurnRestrictions(irs.size()) + m_coordinate_list(nI), + m_restriction_counter(irs.size()) { BOOST_FOREACH(const TurnRestriction & restriction, irs) { std::pair restrictionSource = std::make_pair( restriction.fromNode, restriction.viaNode ); unsigned index; - RestrictionMap::iterator restrIter = _restrictionMap.find(restrictionSource); - if(restrIter == _restrictionMap.end()) { - index = _restrictionBucketVector.size(); - _restrictionBucketVector.resize(index+1); - _restrictionMap[restrictionSource] = index; + RestrictionMap::iterator restriction_iterator = m_restriction_map.find(restrictionSource); + if(restriction_iterator == m_restriction_map.end()) { + index = m_restriction_bucket_list.size(); + m_restriction_bucket_list.resize(index+1); + m_restriction_map[restrictionSource] = index; } else { - index = restrIter->second; + index = restriction_iterator->second; //Map already contains an is_only_*-restriction - if(_restrictionBucketVector.at(index).begin()->second) + if(m_restriction_bucket_list.at(index).begin()->second) { continue; - else if(restriction.flags.isOnly){ + } else if(restriction.flags.isOnly) { //We are going to insert an is_only_*-restriction. There can be only one. - _restrictionBucketVector.at(index).clear(); + m_restriction_bucket_list.at(index).clear(); } } - _restrictionBucketVector.at(index).push_back( + m_restriction_bucket_list.at(index).push_back( std::make_pair(restriction.toNode, restriction.flags.isOnly) ); } - BOOST_FOREACH(NodeID id, bn) { - _barrierNodes[id] = true; - } - BOOST_FOREACH(NodeID id, tl) { - _trafficLights[id] = true; - } - - DeallocatingVector< TarjanEdge > edges; - for ( std::vector< NodeBasedEdge >::const_iterator i = inputEdges.begin(); i != inputEdges.end(); ++i ) { + m_barrier_node_list.insert(bn.begin(), bn.end()); + m_traffic_light_list.insert(tl.begin(), tl.end()); + DeallocatingVector< TarjanEdge > edge_list; + BOOST_FOREACH(const NodeBasedEdge & input_edge, input_edges) { TarjanEdge edge; - if(!i->isForward()) { - edge.source = i->target(); - edge.target = i->source(); - edge.data.backward = i->isForward(); - edge.data.forward = i->isBackward(); + if(!input_edge.isForward()) { + edge.source = input_edge.target(); + edge.target = input_edge.source(); + edge.data.backward = input_edge.isForward(); + edge.data.forward = input_edge.isBackward(); } else { - edge.source = i->source(); - edge.target = i->target(); - edge.data.forward = i->isForward(); - edge.data.backward = i->isBackward(); + edge.source = input_edge.source(); + edge.target = input_edge.target(); + edge.data.forward = input_edge.isForward(); + edge.data.backward = input_edge.isBackward(); } - if(edge.source == edge.target) + if(edge.source == edge.target) { continue; + } - edge.data.distance = (std::max)((int)i->weight(), 1 ); - assert( edge.data.distance > 0 ); + edge.data.distance = (std::max)((int)input_edge.weight(), 1 ); + BOOST_ASSERT( edge.data.distance > 0 ); edge.data.shortcut = false; - edge.data.roundabout = i->isRoundabout(); - edge.data.ignoreInGrid = i->ignoreInGrid(); - edge.data.nameID = i->name(); - edge.data.type = i->type(); - edge.data.isAccessRestricted = i->isAccessRestricted(); - edge.data.edgeBasedNodeID = edges.size(); + edge.data.roundabout = input_edge.isRoundabout(); + edge.data.ignoreInGrid = input_edge.ignoreInGrid(); + edge.data.nameID = input_edge.name(); + edge.data.type = input_edge.type(); + edge.data.isAccessRestricted = input_edge.isAccessRestricted(); edge.data.reversedEdge = false; - edges.push_back( edge ); + edge_list.push_back( edge ); if( edge.data.backward ) { std::swap( edge.source, edge.target ); - edge.data.forward = i->isBackward(); - edge.data.backward = i->isForward(); - edge.data.edgeBasedNodeID = edges.size(); + edge.data.forward = input_edge.isBackward(); + edge.data.backward = input_edge.isForward(); edge.data.reversedEdge = true; - edges.push_back( edge ); + edge_list.push_back( edge ); } } - std::vector().swap(inputEdges); - std::sort( edges.begin(), edges.end() ); - _nodeBasedGraph = boost::make_shared( nodes, edges ); + std::vector().swap(input_edges); + BOOST_ASSERT_MSG( + 0 == input_edges.size() && 0 == input_edges.capacity(), + "input edge vector not properly deallocated" + ); + + std::sort( edge_list.begin(), edge_list.end() ); + + m_node_based_graph = boost::make_shared( + number_of_nodes, + edge_list + ); + } + + ~TarjanSCC() { + m_node_based_graph.reset(); } void Run() { @@ -211,162 +220,203 @@ public: DeleteFileIfExists("component.shx"); DeleteFileIfExists("component.shp"); - Percent p(_nodeBasedGraph->GetNumberOfNodes()); - - const char *pszDriverName = "ESRI Shapefile"; - OGRSFDriver *poDriver; + Percent p(m_node_based_graph->GetNumberOfNodes()); OGRRegisterAll(); - poDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName( - pszDriverName ); - if( poDriver == NULL ) - { - printf( "%s driver not available.\n", pszDriverName ); - exit( 1 ); + const char *pszDriverName = "ESRI Shapefile"; + OGRSFDriver * poDriver = OGRSFDriverRegistrar::GetRegistrar()-> + GetDriverByName( pszDriverName ); + if( NULL == poDriver ) { + throw OSRMException("ESRI Shapefile driver not available"); } - OGRDataSource *poDS; + OGRDataSource * poDS = poDriver->CreateDataSource( + "component.shp", + NULL + ); - poDS = poDriver->CreateDataSource( "component.shp", NULL ); - if( poDS == NULL ) { - printf( "Creation of output file failed.\n" ); - exit( 1 ); + if( NULL == poDS ) { + throw OSRMException("Creation of output file failed"); } - OGRLayer *poLayer; + OGRLayer * poLayer = poDS->CreateLayer( + "component", + NULL, + wkbLineString, + NULL + ); - poLayer = poDS->CreateLayer( "component", NULL, wkbLineString, NULL ); - if( poLayer == NULL ) { - printf( "Layer creation failed.\n" ); - exit( 1 ); + if( NULL == poLayer ) { + throw OSRMException("Layer creation failed."); } - - //The following is a hack to distinguish between stuff that happens before the recursive call and stuff that happens after - std::stack > recursionStack; //true = stuff before, false = stuff after call - std::stack tarjanStack; - std::vector componentsIndex(_nodeBasedGraph->GetNumberOfNodes(), UINT_MAX); - std::vector vectorOfComponentSizes; - std::vector tarjanNodes(_nodeBasedGraph->GetNumberOfNodes()); - unsigned currentComponent = 0, sizeOfCurrentComponent = 0; + //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(), + UINT_MAX + ); + 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; - for(NodeID node = 0, endNodes = _nodeBasedGraph->GetNumberOfNodes(); node < endNodes; ++node) { - if(UINT_MAX == componentsIndex[node]) { - recursionStack.push(std::make_pair(true, TarjanStackFrame(node,node)) ); + for( + NodeID node = 0, last_node = m_node_based_graph->GetNumberOfNodes(); + node < last_node; + ++node + ) { + if(UINT_MAX == components_index[node]) { + recursion_stack.push( + std::make_pair(true, TarjanStackFrame(node,node)) + ); } - while(!recursionStack.empty()) { - bool beforeRecursion = recursionStack.top().first; - TarjanStackFrame currentFrame = recursionStack.top().second; + while(!recursion_stack.empty()) { + bool before_recursion = recursion_stack.top().first; + TarjanStackFrame currentFrame = recursion_stack.top().second; NodeID v = currentFrame.v; -// SimpleLogger().Write() << "popping node " << v << (beforeRecursion ? " before " : " after ") << "recursion"; - recursionStack.pop(); + recursion_stack.pop(); - if(beforeRecursion) { + if(before_recursion) { //Mark frame to handle tail of recursion - recursionStack.push(std::make_pair(false, currentFrame)); + recursion_stack.push(std::make_pair(false, currentFrame)); //Mark essential information for SCC - tarjanNodes[v].index = index; - tarjanNodes[v].lowlink = index; - tarjanStack.push(v); - tarjanNodes[v].onStack = true; + tarjan_node_list[v].index = index; + tarjan_node_list[v].lowlink = index; + tarjan_stack.push(v); + tarjan_node_list[v].onStack = true; ++index; -// SimpleLogger().Write() << "pushing " << v << " onto tarjan stack, idx[" << v << "]=" << tarjanNodes[v].index << ", lowlink["<< v << "]=" << tarjanNodes[v].lowlink; //Traverse outgoing edges - for(TarjanDynamicGraph::EdgeIterator e2 = _nodeBasedGraph->BeginEdges(v); e2 < _nodeBasedGraph->EndEdges(v); ++e2) { - TarjanDynamicGraph::NodeIterator vprime = _nodeBasedGraph->GetTarget(e2); -// SimpleLogger().Write() << "traversing edge (" << v << "," << vprime << ")"; - if(UINT_MAX == tarjanNodes[vprime].index) { - - recursionStack.push(std::make_pair(true,TarjanStackFrame(vprime, v))); + for( + TarjanDynamicGraph::EdgeIterator e2 = m_node_based_graph->BeginEdges(v); + e2 < m_node_based_graph->EndEdges(v); + ++e2 + ) { + const TarjanDynamicGraph::NodeIterator vprime = + m_node_based_graph->GetTarget(e2); + if(UINT_MAX == tarjan_node_list[vprime].index) { + recursion_stack.push( + std::make_pair( + true, + TarjanStackFrame(vprime, v) + ) + ); } else { -// SimpleLogger().Write() << "Node " << vprime << " is already explored"; - if(tarjanNodes[vprime].onStack) { - unsigned newLowlink = std::min(tarjanNodes[v].lowlink, tarjanNodes[vprime].index); -// SimpleLogger().Write() << "Setting lowlink[" << v << "] from " << tarjanNodes[v].lowlink << " to " << newLowlink; - tarjanNodes[v].lowlink = newLowlink; -// } else { -// SimpleLogger().Write() << "But node " << vprime << " is not on stack"; + if( + tarjan_node_list[vprime].onStack && + tarjan_node_list[vprime].index < tarjan_node_list[v].lowlink + ) { + tarjan_node_list[v].lowlink = tarjan_node_list[vprime].index; } } } } else { - -// SimpleLogger().Write() << "we are at the end of recursion and checking node " << v; - { // setting lowlink in its own scope so it does not pollute namespace - // NodeID parent = (UINT_MAX == tarjanNodes[v].parent ? v : tarjanNodes[v].parent ); -// SimpleLogger().Write() << "parent=" << currentFrame.parent; -// SimpleLogger().Write() << "tarjanNodes[" << v << "].lowlink=" << tarjanNodes[v].lowlink << ", tarjanNodes[" << currentFrame.parent << "].lowlink=" << tarjanNodes[currentFrame.parent].lowlink; - //Note the index shift by 1 compared to the recursive version - tarjanNodes[currentFrame.parent].lowlink = std::min(tarjanNodes[currentFrame.parent].lowlink, tarjanNodes[v].lowlink); -// SimpleLogger().Write() << "Setting tarjanNodes[" << currentFrame.parent <<"].lowlink=" << tarjanNodes[currentFrame.parent].lowlink; - } -// SimpleLogger().Write() << "tarjanNodes[" << v << "].lowlink=" << tarjanNodes[v].lowlink << ", tarjanNodes[" << v << "].index=" << tarjanNodes[v].index; - + tarjan_node_list[currentFrame.parent].lowlink = + std::min( + tarjan_node_list[currentFrame.parent].lowlink, + tarjan_node_list[v].lowlink + ); //after recursion, lets do cycle checking //Check if we found a cycle. This is the bottom part of the recursion - if(tarjanNodes[v].lowlink == tarjanNodes[v].index) { + if(tarjan_node_list[v].lowlink == tarjan_node_list[v].index) { NodeID vprime; do { -// SimpleLogger().Write() << "identified component " << currentComponent << ": " << tarjanStack.top(); - vprime = tarjanStack.top(); tarjanStack.pop(); - tarjanNodes[vprime].onStack = false; - componentsIndex[vprime] = currentComponent; - ++sizeOfCurrentComponent; + vprime = tarjan_stack.top(); tarjan_stack.pop(); + tarjan_node_list[vprime].onStack = false; + components_index[vprime] = component_index; + ++size_of_current_component; } while( v != vprime); - vectorOfComponentSizes.push_back(sizeOfCurrentComponent); - if(sizeOfCurrentComponent > 1000) - SimpleLogger().Write() << "large component [" << currentComponent << "]=" << sizeOfCurrentComponent; - ++currentComponent; - sizeOfCurrentComponent = 0; + + component_size_vector.push_back(size_of_current_component); + + if(size_of_current_component > 1000) { + SimpleLogger().Write() << + "large component [" << component_index << "]=" << + size_of_current_component; + } + + ++component_index; + size_of_current_component = 0; } } } } - SimpleLogger().Write() << "identified: " << vectorOfComponentSizes.size() << " many components, marking small components"; + SimpleLogger().Write() << + "identified: " << component_size_vector.size() << + " many components, marking small components"; - int singleCounter = 0; - for(unsigned i = 0; i < vectorOfComponentSizes.size(); ++i){ - if(1 == vectorOfComponentSizes[i]) - ++singleCounter; + unsigned size_one_counter = 0; + for(unsigned i = 0, end = component_size_vector.size(); i < end; ++i){ + if(1 == component_size_vector[i]) { + ++size_one_counter; + } } - SimpleLogger().Write() << "identified " << singleCounter << " SCCs of size 1"; + + SimpleLogger().Write() << + "identified " << size_one_counter << " SCCs of size 1"; + uint64_t total_network_distance = 0; - p.reinit(_nodeBasedGraph->GetNumberOfNodes()); - for(TarjanDynamicGraph::NodeIterator u = 0; u < _nodeBasedGraph->GetNumberOfNodes(); ++u ) { + p.reinit(m_node_based_graph->GetNumberOfNodes()); + for( + TarjanDynamicGraph::NodeIterator u = 0, last_u_node = m_node_based_graph->GetNumberOfNodes(); + u < last_u_node; + ++u + ) { p.printIncrement(); - for(TarjanDynamicGraph::EdgeIterator e1 = _nodeBasedGraph->BeginEdges(u); e1 < _nodeBasedGraph->EndEdges(u); ++e1) { - if(_nodeBasedGraph->GetEdgeData(e1).reversedEdge) { + for( + TarjanDynamicGraph::EdgeIterator e1 = m_node_based_graph->BeginEdges(u), last_edge = m_node_based_graph->EndEdges(u); + e1 < last_edge; + ++e1 + ) { + if(!m_node_based_graph->GetEdgeData(e1).reversedEdge) { continue; } - TarjanDynamicGraph::NodeIterator v = _nodeBasedGraph->GetTarget(e1); + const TarjanDynamicGraph::NodeIterator v = m_node_based_graph->GetTarget(e1); total_network_distance += 100*ApproximateDistance( - inputNodeInfoList[u].lat, - inputNodeInfoList[u].lon, - inputNodeInfoList[v].lat, - inputNodeInfoList[v].lon + m_coordinate_list[u].lat, + m_coordinate_list[u].lon, + m_coordinate_list[v].lat, + m_coordinate_list[v].lon ); - if(_nodeBasedGraph->GetEdgeData(e1).type != SHRT_MAX) { - assert(e1 != UINT_MAX); - assert(u != UINT_MAX); - assert(v != UINT_MAX); + if( SHRT_MAX != m_node_based_graph->GetEdgeData(e1).type ) { + BOOST_ASSERT(e1 != UINT_MAX); + BOOST_ASSERT(u != UINT_MAX); + BOOST_ASSERT(v != UINT_MAX); + + const unsigned size_of_containing_component = + std::min( + component_size_vector[components_index[u]], + component_size_vector[components_index[v]] + ); //edges that end on bollard nodes may actually be in two distinct components - if(std::min(vectorOfComponentSizes[componentsIndex[u]], vectorOfComponentSizes[componentsIndex[v]]) < 10) { - - //INFO("(" << inputNodeInfoList[u].lat/COORDINATE_PRECISION << ";" << inputNodeInfoList[u].lon/COORDINATE_PRECISION << ") -> (" << inputNodeInfoList[v].lat/COORDINATE_PRECISION << ";" << inputNodeInfoList[v].lon/COORDINATE_PRECISION << ")"); + if(size_of_containing_component < 10) { OGRLineString lineString; - lineString.addPoint(inputNodeInfoList[u].lon/COORDINATE_PRECISION, inputNodeInfoList[u].lat/COORDINATE_PRECISION); - lineString.addPoint(inputNodeInfoList[v].lon/COORDINATE_PRECISION, inputNodeInfoList[v].lat/COORDINATE_PRECISION); - OGRFeature *poFeature; - poFeature = OGRFeature::CreateFeature( poLayer->GetLayerDefn() ); + lineString.addPoint( + m_coordinate_list[u].lon/COORDINATE_PRECISION, + m_coordinate_list[u].lat/COORDINATE_PRECISION + ); + lineString.addPoint( + m_coordinate_list[v].lon/COORDINATE_PRECISION, + m_coordinate_list[v].lat/COORDINATE_PRECISION + ); + + OGRFeature * poFeature = OGRFeature::CreateFeature( + poLayer->GetLayerDefn() + ); + poFeature->SetGeometry( &lineString ); - if( poLayer->CreateFeature( poFeature ) != OGRERR_NONE ) { + if( OGRERR_NONE != poLayer->CreateFeature(poFeature) ) { throw OSRMException( "Failed to create feature in shapefile." ); @@ -377,39 +427,66 @@ public: } } OGRDataSource::DestroyDataSource( poDS ); - std::vector().swap(vectorOfComponentSizes); - std::vector().swap(componentsIndex); - SimpleLogger().Write() << "total network distance: " << (uint64_t)total_network_distance/100/1000. << " km"; + std::vector().swap(component_size_vector); + BOOST_ASSERT_MSG( + 0 == component_size_vector.size() && + 0 == component_size_vector.capacity(), + "component_size_vector not properly deallocated" + ); + + std::vector().swap(components_index); + BOOST_ASSERT_MSG( + 0 == components_index.size() && 0 == components_index.capacity(), + "icomponents_index not properly deallocated" + ); + + SimpleLogger().Write() + << "total network distance: " << + (uint64_t)total_network_distance/100/1000. << + " km"; } + private: unsigned CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const { - std::pair < NodeID, NodeID > restrictionSource = std::make_pair(u, v); - RestrictionMap::const_iterator restrIter = _restrictionMap.find(restrictionSource); - if (restrIter != _restrictionMap.end()) { - unsigned index = restrIter->second; - BOOST_FOREACH(RestrictionSource restrictionTarget, _restrictionBucketVector.at(index)) { - if(restrictionTarget.second) { - return restrictionTarget.first; + std::pair < NodeID, NodeID > restriction_source = std::make_pair(u, v); + RestrictionMap::const_iterator restriction_iterator = m_restriction_map.find(restriction_source); + if (restriction_iterator != m_restriction_map.end()) { + const unsigned index = restriction_iterator->second; + BOOST_FOREACH( + const RestrictionSource & restriction_target, + m_restriction_bucket_list.at(index) + ) { + if(restriction_target.second) { + return restriction_target.first; } } } return UINT_MAX; } - bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const { + + bool CheckIfTurnIsRestricted( + const NodeID u, + const NodeID v, + const NodeID w + ) const { //only add an edge if turn is not a U-turn except it is the end of dead-end street. - std::pair < NodeID, NodeID > restrictionSource = std::make_pair(u, v); - RestrictionMap::const_iterator restrIter = _restrictionMap.find(restrictionSource); - if (restrIter != _restrictionMap.end()) { - unsigned index = restrIter->second; - BOOST_FOREACH(RestrictionTarget restrictionTarget, _restrictionBucketVector.at(index)) { - if(w == restrictionTarget.first) + std::pair < NodeID, NodeID > restriction_source = std::make_pair(u, v); + RestrictionMap::const_iterator restriction_iterator = m_restriction_map.find(restriction_source); + if (restriction_iterator != m_restriction_map.end()) { + const unsigned index = restriction_iterator->second; + BOOST_FOREACH( + const restriction_target & restriction_target, + m_restriction_bucket_list.at(index) + ) { + if(w == restriction_target.first) { return true; + } } } return false; } - void DeleteFileIfExists(const std::string file_name) const { + void DeleteFileIfExists(const std::string & file_name) const { if (boost::filesystem::exists(file_name) ) { boost::filesystem::remove(file_name); }