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