Chris@16: // (C) Copyright 2009 Eric Bose-Wolf Chris@16: // Chris@16: // Use, modification and distribution are subject to the Chris@16: // Boost Software License, Version 1.0 (See accompanying file Chris@16: // LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_GRAPH_TRANSITIVE_REDUCTION_HPP Chris@16: #define BOOST_GRAPH_TRANSITIVE_REDUCTION_HPP Chris@16: Chris@16: #include Chris@16: #include //std::find Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@16: // also I didn't got all of the concepts thin. Am I suppose to check Chris@16: // for all concepts, which are needed for functions I call? (As if I Chris@16: // wouldn't do that, the users would see the functions called by Chris@16: // complaining about missings concepts, which would be clearly an error Chris@16: // message revealing internal implementation and should therefore be avoided?) Chris@16: Chris@16: // the pseudocode which I followed implementing this algorithmn was taken Chris@16: // from the german book Algorithmische Graphentheorie by Volker Turau Chris@16: // it is proposed to be of O(n + nm_red ) where n is the number Chris@16: // of vertices and m_red is the number of edges in the transitive Chris@16: // reduction, but I think my implementation spoiled this up at some point Chris@16: // indicated below. Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: template < Chris@16: typename Graph, typename GraphTR, typename G_to_TR_VertexMap, Chris@16: typename VertexIndexMap Chris@16: > Chris@16: BOOST_CONCEPT_REQUIRES( Chris@16: ((VertexListGraphConcept< Graph >)) Chris@16: ((IncidenceGraphConcept< Graph >)) Chris@16: ((MutableGraphConcept< GraphTR >)) Chris@16: ((ReadablePropertyMapConcept< VertexIndexMap, Chris@16: typename graph_traits::vertex_descriptor >)) Chris@16: ((Integer< typename Chris@16: property_traits< VertexIndexMap >::value_type >)) Chris@16: ((LvaluePropertyMapConcept< G_to_TR_VertexMap, Chris@16: typename graph_traits::vertex_descriptor >)), Chris@16: (void)) Chris@16: transitive_reduction(const Graph& g, GraphTR& tr, Chris@16: G_to_TR_VertexMap g_to_tr_map, Chris@16: VertexIndexMap g_index_map ) Chris@16: { Chris@16: typedef typename graph_traits::vertex_descriptor Vertex; Chris@16: typedef typename graph_traits::vertex_iterator VertexIterator; Chris@16: typedef typename std::vector::size_type size_type; Chris@16: Chris@16: std::vector topo_order; Chris@16: topological_sort(g, std::back_inserter(topo_order)); Chris@16: Chris@16: std::vector topo_number_storage(num_vertices(g)); Chris@16: Chris@16: iterator_property_map topo_number( &topo_number_storage[0], g_index_map ); Chris@16: Chris@16: { Chris@16: typename std::vector::reverse_iterator it = topo_order.rbegin(); Chris@16: size_type n = 0; Chris@16: for(; it != topo_order.rend(); ++it,++n ) { Chris@16: topo_number[ *it ] = n; Chris@16: } Chris@16: } Chris@16: Chris@16: std::vector< std::vector< bool > > edge_in_closure(num_vertices(g), Chris@16: std::vector( num_vertices(g), false)); Chris@16: { Chris@16: typename std::vector::reverse_iterator it = topo_order.rbegin(); Chris@16: for( ; it != topo_order.rend(); ++it ) { Chris@16: g_to_tr_map[*it] = add_vertex(tr); Chris@16: } Chris@16: } Chris@16: Chris@16: typename std::vector::iterator Chris@16: it = topo_order.begin(), Chris@16: end = topo_order.end(); Chris@16: for( ; it != end; ++it ) { Chris@16: size_type i = topo_number[ *it ]; Chris@16: edge_in_closure[i][i] = true; Chris@16: std::vector neighbors; Chris@16: Chris@16: //I have to collect the successors of *it and traverse them in Chris@16: //ascending topological order. I didn't know a better way, how to Chris@16: //do that. So what I'm doint is, collection the successors of *it here Chris@16: { Chris@16: typename Graph::out_edge_iterator oi,oi_end; Chris@16: for( boost::tie(oi, oi_end) = out_edges( *it, g ); oi != oi_end; ++oi ) { Chris@16: neighbors.push_back( target( *oi, g ) ); Chris@16: } Chris@16: } Chris@16: Chris@16: { Chris@16: //and run through all vertices in topological order Chris@16: typename std::vector::reverse_iterator Chris@16: rit = topo_order.rbegin(), Chris@16: rend = topo_order.rend(); Chris@16: for(; rit != rend; ++rit ) { Chris@16: //looking if they are successors of *it Chris@16: if( std::find( neighbors.begin(), neighbors.end(), *rit) != neighbors.end() ) { Chris@16: size_type j = topo_number[ *rit ]; Chris@16: if( not edge_in_closure[i][j] ) { Chris@16: for(size_type k = j; k < num_vertices(g); ++k) { Chris@16: if( not edge_in_closure[i][k] ) { Chris@16: //here we need edge_in_closure to be in topological order, Chris@16: edge_in_closure[i][k] = edge_in_closure[j][k]; Chris@16: } Chris@16: } Chris@16: //therefore we only access edge_in_closure only through Chris@16: //topo_number property_map Chris@16: add_edge(g_to_tr_map[*it], g_to_tr_map[*rit], tr); Chris@16: } //if ( not edge_in_ Chris@16: } //if (find ( Chris@16: } //for( typename vector::reverse_iterator Chris@16: } // { Chris@16: Chris@16: } //for( typename vector::iterator Chris@16: Chris@16: } //void transitive_reduction Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #endif Chris@16: