?????????? ????????? - ??????????????? - /home/agenciai/public_html/cd38d8/graph.tar
???????
floyd_warshall_shortest.hpp 0000644 00000020476 15125521275 0012240 0 ustar 00 // Copyright 2002 Rensselaer Polytechnic Institute // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Lauren Foutz // Scott Hill /* This file implements the functions template <class VertexListGraph, class DistanceMatrix, class P, class T, class R> bool floyd_warshall_initialized_all_pairs_shortest_paths( const VertexListGraph& g, DistanceMatrix& d, const bgl_named_params<P, T, R>& params) AND template <class VertexAndEdgeListGraph, class DistanceMatrix, class P, class T, class R> bool floyd_warshall_all_pairs_shortest_paths( const VertexAndEdgeListGraph& g, DistanceMatrix& d, const bgl_named_params<P, T, R>& params) */ #ifndef BOOST_GRAPH_FLOYD_WARSHALL_HPP #define BOOST_GRAPH_FLOYD_WARSHALL_HPP #include <boost/property_map/property_map.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/relax.hpp> #include <boost/concept/assert.hpp> namespace boost { namespace detail { template < typename T, typename BinaryPredicate > T min_with_compare(const T& x, const T& y, const BinaryPredicate& compare) { if (compare(x, y)) return x; else return y; } template < typename VertexListGraph, typename DistanceMatrix, typename BinaryPredicate, typename BinaryFunction, typename Infinity, typename Zero > bool floyd_warshall_dispatch(const VertexListGraph& g, DistanceMatrix& d, const BinaryPredicate& compare, const BinaryFunction& combine, const Infinity& inf, const Zero& zero) { typename graph_traits< VertexListGraph >::vertex_iterator i, lasti, j, lastj, k, lastk; for (boost::tie(k, lastk) = vertices(g); k != lastk; k++) for (boost::tie(i, lasti) = vertices(g); i != lasti; i++) if (d[*i][*k] != inf) for (boost::tie(j, lastj) = vertices(g); j != lastj; j++) if (d[*k][*j] != inf) d[*i][*j] = detail::min_with_compare(d[*i][*j], combine(d[*i][*k], d[*k][*j]), compare); for (boost::tie(i, lasti) = vertices(g); i != lasti; i++) if (compare(d[*i][*i], zero)) return false; return true; } } template < typename VertexListGraph, typename DistanceMatrix, typename BinaryPredicate, typename BinaryFunction, typename Infinity, typename Zero > bool floyd_warshall_initialized_all_pairs_shortest_paths( const VertexListGraph& g, DistanceMatrix& d, const BinaryPredicate& compare, const BinaryFunction& combine, const Infinity& inf, const Zero& zero) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< VertexListGraph >)); return detail::floyd_warshall_dispatch(g, d, compare, combine, inf, zero); } template < typename VertexAndEdgeListGraph, typename DistanceMatrix, typename WeightMap, typename BinaryPredicate, typename BinaryFunction, typename Infinity, typename Zero > bool floyd_warshall_all_pairs_shortest_paths(const VertexAndEdgeListGraph& g, DistanceMatrix& d, const WeightMap& w, const BinaryPredicate& compare, const BinaryFunction& combine, const Infinity& inf, const Zero& zero) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< VertexAndEdgeListGraph >)); BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< VertexAndEdgeListGraph >)); BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< VertexAndEdgeListGraph >)); typename graph_traits< VertexAndEdgeListGraph >::vertex_iterator firstv, lastv, firstv2, lastv2; typename graph_traits< VertexAndEdgeListGraph >::edge_iterator first, last; for (boost::tie(firstv, lastv) = vertices(g); firstv != lastv; firstv++) for (boost::tie(firstv2, lastv2) = vertices(g); firstv2 != lastv2; firstv2++) d[*firstv][*firstv2] = inf; for (boost::tie(firstv, lastv) = vertices(g); firstv != lastv; firstv++) d[*firstv][*firstv] = zero; for (boost::tie(first, last) = edges(g); first != last; first++) { if (d[source(*first, g)][target(*first, g)] != inf) { d[source(*first, g)][target(*first, g)] = detail::min_with_compare(get(w, *first), d[source(*first, g)][target(*first, g)], compare); } else d[source(*first, g)][target(*first, g)] = get(w, *first); } bool is_undirected = is_same< typename graph_traits< VertexAndEdgeListGraph >::directed_category, undirected_tag >::value; if (is_undirected) { for (boost::tie(first, last) = edges(g); first != last; first++) { if (d[target(*first, g)][source(*first, g)] != inf) d[target(*first, g)][source(*first, g)] = detail::min_with_compare(get(w, *first), d[target(*first, g)][source(*first, g)], compare); else d[target(*first, g)][source(*first, g)] = get(w, *first); } } return detail::floyd_warshall_dispatch(g, d, compare, combine, inf, zero); } namespace detail { template < class VertexListGraph, class DistanceMatrix, class WeightMap, class P, class T, class R > bool floyd_warshall_init_dispatch(const VertexListGraph& g, DistanceMatrix& d, WeightMap /*w*/, const bgl_named_params< P, T, R >& params) { typedef typename property_traits< WeightMap >::value_type WM; WM inf = choose_param(get_param(params, distance_inf_t()), std::numeric_limits< WM >::max BOOST_PREVENT_MACRO_SUBSTITUTION()); return floyd_warshall_initialized_all_pairs_shortest_paths(g, d, choose_param( get_param(params, distance_compare_t()), std::less< WM >()), choose_param(get_param(params, distance_combine_t()), closed_plus< WM >(inf)), inf, choose_param(get_param(params, distance_zero_t()), WM())); } template < class VertexAndEdgeListGraph, class DistanceMatrix, class WeightMap, class P, class T, class R > bool floyd_warshall_noninit_dispatch(const VertexAndEdgeListGraph& g, DistanceMatrix& d, WeightMap w, const bgl_named_params< P, T, R >& params) { typedef typename property_traits< WeightMap >::value_type WM; WM inf = choose_param(get_param(params, distance_inf_t()), std::numeric_limits< WM >::max BOOST_PREVENT_MACRO_SUBSTITUTION()); return floyd_warshall_all_pairs_shortest_paths(g, d, w, choose_param( get_param(params, distance_compare_t()), std::less< WM >()), choose_param(get_param(params, distance_combine_t()), closed_plus< WM >(inf)), inf, choose_param(get_param(params, distance_zero_t()), WM())); } } // namespace detail template < class VertexListGraph, class DistanceMatrix, class P, class T, class R > bool floyd_warshall_initialized_all_pairs_shortest_paths( const VertexListGraph& g, DistanceMatrix& d, const bgl_named_params< P, T, R >& params) { return detail::floyd_warshall_init_dispatch(g, d, choose_const_pmap(get_param(params, edge_weight), g, edge_weight), params); } template < class VertexListGraph, class DistanceMatrix > bool floyd_warshall_initialized_all_pairs_shortest_paths( const VertexListGraph& g, DistanceMatrix& d) { bgl_named_params< int, int > params(0); return detail::floyd_warshall_init_dispatch( g, d, get(edge_weight, g), params); } template < class VertexAndEdgeListGraph, class DistanceMatrix, class P, class T, class R > bool floyd_warshall_all_pairs_shortest_paths(const VertexAndEdgeListGraph& g, DistanceMatrix& d, const bgl_named_params< P, T, R >& params) { return detail::floyd_warshall_noninit_dispatch(g, d, choose_const_pmap(get_param(params, edge_weight), g, edge_weight), params); } template < class VertexAndEdgeListGraph, class DistanceMatrix > bool floyd_warshall_all_pairs_shortest_paths( const VertexAndEdgeListGraph& g, DistanceMatrix& d) { bgl_named_params< int, int > params(0); return detail::floyd_warshall_noninit_dispatch( g, d, get(edge_weight, g), params); } } // namespace boost #endif king_ordering.hpp 0000644 00000027233 15125521275 0010112 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Copyright 2004, 2005 Trustees of Indiana University // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, // Doug Gregor, D. Kevin McGrath // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //=======================================================================// #ifndef BOOST_GRAPH_KING_HPP #define BOOST_GRAPH_KING_HPP #include <boost/config.hpp> #include <boost/graph/detail/sparse_ordering.hpp> #include <boost/graph/graph_utility.hpp> /* King Algorithm for matrix reordering */ namespace boost { namespace detail { template < typename OutputIterator, typename Buffer, typename Compare, typename PseudoDegreeMap, typename VecMap, typename VertexIndexMap > class bfs_king_visitor : public default_bfs_visitor { public: bfs_king_visitor(OutputIterator* iter, Buffer* b, Compare compare, PseudoDegreeMap deg, std::vector< int > loc, VecMap color, VertexIndexMap vertices) : permutation(iter) , Qptr(b) , degree(deg) , comp(compare) , Qlocation(loc) , colors(color) , vertex_map(vertices) { } template < typename Vertex, typename Graph > void finish_vertex(Vertex, Graph& g) { typename graph_traits< Graph >::out_edge_iterator ei, ei_end; Vertex v, w; typedef typename std::deque< Vertex >::reverse_iterator reverse_iterator; reverse_iterator rend = Qptr->rend() - index_begin; reverse_iterator rbegin = Qptr->rbegin(); // heap the vertices already there std::make_heap(rbegin, rend, boost::bind< bool >(comp, _2, _1)); unsigned i = 0; for (i = index_begin; i != Qptr->size(); ++i) { colors[get(vertex_map, (*Qptr)[i])] = 1; Qlocation[get(vertex_map, (*Qptr)[i])] = i; } i = 0; for (; rbegin != rend; rend--) { percolate_down< Vertex >(i); w = (*Qptr)[index_begin + i]; for (boost::tie(ei, ei_end) = out_edges(w, g); ei != ei_end; ++ei) { v = target(*ei, g); put(degree, v, get(degree, v) - 1); if (colors[get(vertex_map, v)] == 1) { percolate_up< Vertex >(get(vertex_map, v), i); } } colors[get(vertex_map, w)] = 0; i++; } } template < typename Vertex, typename Graph > void examine_vertex(Vertex u, const Graph&) { *(*permutation)++ = u; index_begin = Qptr->size(); } protected: // this function replaces pop_heap, and tracks state information template < typename Vertex > void percolate_down(int offset) { int heap_last = index_begin + offset; int heap_first = Qptr->size() - 1; // pop_heap functionality: // swap first, last std::swap((*Qptr)[heap_last], (*Qptr)[heap_first]); // swap in the location queue std::swap(Qlocation[heap_first], Qlocation[heap_last]); // set drifter, children int drifter = heap_first; int drifter_heap = Qptr->size() - drifter; int right_child_heap = drifter_heap * 2 + 1; int right_child = Qptr->size() - right_child_heap; int left_child_heap = drifter_heap * 2; int left_child = Qptr->size() - left_child_heap; // check that we are staying in the heap bool valid = (right_child < heap_last) ? false : true; // pick smallest child of drifter, and keep in mind there might only // be left child int smallest_child = (valid && get(degree, (*Qptr)[left_child]) > get(degree, (*Qptr)[right_child])) ? right_child : left_child; while (valid && smallest_child < heap_last && comp((*Qptr)[drifter], (*Qptr)[smallest_child])) { // if smallest child smaller than drifter, swap them std::swap((*Qptr)[smallest_child], (*Qptr)[drifter]); std::swap(Qlocation[drifter], Qlocation[smallest_child]); // update the values, run again, as necessary drifter = smallest_child; drifter_heap = Qptr->size() - drifter; right_child_heap = drifter_heap * 2 + 1; right_child = Qptr->size() - right_child_heap; left_child_heap = drifter_heap * 2; left_child = Qptr->size() - left_child_heap; valid = (right_child < heap_last) ? false : true; smallest_child = (valid && get(degree, (*Qptr)[left_child]) > get(degree, (*Qptr)[right_child])) ? right_child : left_child; } } // this is like percolate down, but we always compare against the // parent, as there is only a single choice template < typename Vertex > void percolate_up(int vertex, int offset) { int child_location = Qlocation[vertex]; int heap_child_location = Qptr->size() - child_location; int heap_parent_location = (int)(heap_child_location / 2); unsigned parent_location = Qptr->size() - heap_parent_location; bool valid = (heap_parent_location != 0 && child_location > index_begin + offset && parent_location < Qptr->size()); while (valid && comp((*Qptr)[child_location], (*Qptr)[parent_location])) { // swap in the heap std::swap((*Qptr)[child_location], (*Qptr)[parent_location]); // swap in the location queue std::swap( Qlocation[child_location], Qlocation[parent_location]); child_location = parent_location; heap_child_location = heap_parent_location; heap_parent_location = (int)(heap_child_location / 2); parent_location = Qptr->size() - heap_parent_location; valid = (heap_parent_location != 0 && child_location > index_begin + offset); } } OutputIterator* permutation; int index_begin; Buffer* Qptr; PseudoDegreeMap degree; Compare comp; std::vector< int > Qlocation; VecMap colors; VertexIndexMap vertex_map; }; } // namespace detail template < class Graph, class OutputIterator, class ColorMap, class DegreeMap, typename VertexIndexMap > OutputIterator king_ordering(const Graph& g, std::deque< typename graph_traits< Graph >::vertex_descriptor > vertex_queue, OutputIterator permutation, ColorMap color, DegreeMap degree, VertexIndexMap index_map) { typedef typename property_traits< DegreeMap >::value_type ds_type; typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef iterator_property_map< typename std::vector< ds_type >::iterator, VertexIndexMap, ds_type, ds_type& > PseudoDegreeMap; typedef indirect_cmp< PseudoDegreeMap, std::less< ds_type > > Compare; typedef typename boost::sparse::sparse_ordering_queue< Vertex > queue; typedef typename detail::bfs_king_visitor< OutputIterator, queue, Compare, PseudoDegreeMap, std::vector< int >, VertexIndexMap > Visitor; typedef typename graph_traits< Graph >::vertices_size_type vertices_size_type; std::vector< ds_type > pseudo_degree_vec(num_vertices(g)); PseudoDegreeMap pseudo_degree(pseudo_degree_vec.begin(), index_map); typename graph_traits< Graph >::vertex_iterator ui, ui_end; queue Q; // Copy degree to pseudo_degree // initialize the color map for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { put(pseudo_degree, *ui, get(degree, *ui)); put(color, *ui, Color::white()); } Compare comp(pseudo_degree); std::vector< int > colors(num_vertices(g)); for (vertices_size_type i = 0; i < num_vertices(g); i++) colors[i] = 0; std::vector< int > loc(num_vertices(g)); // create the visitor Visitor vis(&permutation, &Q, comp, pseudo_degree, loc, colors, index_map); while (!vertex_queue.empty()) { Vertex s = vertex_queue.front(); vertex_queue.pop_front(); // call BFS with visitor breadth_first_visit(g, s, Q, vis, color); } return permutation; } // This is the case where only a single starting vertex is supplied. template < class Graph, class OutputIterator, class ColorMap, class DegreeMap, typename VertexIndexMap > OutputIterator king_ordering(const Graph& g, typename graph_traits< Graph >::vertex_descriptor s, OutputIterator permutation, ColorMap color, DegreeMap degree, VertexIndexMap index_map) { std::deque< typename graph_traits< Graph >::vertex_descriptor > vertex_queue; vertex_queue.push_front(s); return king_ordering( g, vertex_queue, permutation, color, degree, index_map); } template < class Graph, class OutputIterator, class ColorMap, class DegreeMap, class VertexIndexMap > OutputIterator king_ordering(const Graph& G, OutputIterator permutation, ColorMap color, DegreeMap degree, VertexIndexMap index_map) { if (has_no_vertices(G)) return permutation; typedef typename boost::graph_traits< Graph >::vertex_descriptor Vertex; typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; std::deque< Vertex > vertex_queue; // Mark everything white BGL_FORALL_VERTICES_T(v, G, Graph) put(color, v, Color::white()); // Find one vertex from each connected component BGL_FORALL_VERTICES_T(v, G, Graph) { if (get(color, v) == Color::white()) { depth_first_visit(G, v, dfs_visitor<>(), color); vertex_queue.push_back(v); } } // Find starting nodes for all vertices // TBD: How to do this with a directed graph? for (typename std::deque< Vertex >::iterator i = vertex_queue.begin(); i != vertex_queue.end(); ++i) *i = find_starting_node(G, *i, color, degree); return king_ordering( G, vertex_queue, permutation, color, degree, index_map); } template < typename Graph, typename OutputIterator, typename VertexIndexMap > OutputIterator king_ordering( const Graph& G, OutputIterator permutation, VertexIndexMap index_map) { if (has_no_vertices(G)) return permutation; std::vector< default_color_type > colors(num_vertices(G)); return king_ordering(G, permutation, make_iterator_property_map(&colors[0], index_map, colors[0]), make_out_degree_map(G), index_map); } template < typename Graph, typename OutputIterator > inline OutputIterator king_ordering(const Graph& G, OutputIterator permutation) { return king_ordering(G, permutation, get(vertex_index, G)); } } // namespace boost #endif // BOOST_GRAPH_KING_HPP random_spanning_tree.hpp 0000644 00000013217 15125521275 0011462 0 ustar 00 // Copyright 2010 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Jeremiah Willcock // Andrew Lumsdaine #ifndef BOOST_GRAPH_RANDOM_SPANNING_TREE_HPP #define BOOST_GRAPH_RANDOM_SPANNING_TREE_HPP #include <vector> #include <boost/assert.hpp> #include <boost/graph/loop_erased_random_walk.hpp> #include <boost/graph/random.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/property_map/property_map.hpp> #include <boost/config.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/named_function_params.hpp> namespace boost { namespace detail { // Use Wilson's algorithm (based on loop-free random walks) to generate a // random spanning tree. The distribution of edges used is controlled by // the next_edge() function, so this version allows either weighted or // unweighted selection of trees. // Algorithm is from http://en.wikipedia.org/wiki/Uniform_spanning_tree template < typename Graph, typename PredMap, typename ColorMap, typename NextEdge > void random_spanning_tree_internal(const Graph& g, typename graph_traits< Graph >::vertex_descriptor s, PredMap pred, ColorMap color, NextEdge next_edge) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; BOOST_ASSERT(num_vertices(g) >= 1); // g must also be undirected (or symmetric) and connected typedef color_traits< typename property_traits< ColorMap >::value_type > color_gen; BGL_FORALL_VERTICES_T(v, g, Graph) put(color, v, color_gen::white()); std::vector< vertex_descriptor > path; put(color, s, color_gen::black()); put(pred, s, graph_traits< Graph >::null_vertex()); BGL_FORALL_VERTICES_T(v, g, Graph) { if (get(color, v) != color_gen::white()) continue; loop_erased_random_walk(g, v, next_edge, color, path); for (typename std::vector< vertex_descriptor >::const_reverse_iterator i = path.rbegin(); boost::next(i) != (typename std::vector< vertex_descriptor >::const_reverse_iterator)path.rend(); ++i) { typename std::vector< vertex_descriptor >::const_reverse_iterator j = i; ++j; BOOST_ASSERT(get(color, *j) == color_gen::gray()); put(color, *j, color_gen::black()); put(pred, *j, *i); } } } } // Compute a uniformly-distributed spanning tree on a graph. Use Wilson's // algorithm: // @inproceedings{wilson96generating, // author = {Wilson, David Bruce}, // title = {Generating random spanning trees more quickly than the cover // time}, booktitle = {STOC '96: Proceedings of the twenty-eighth annual ACM // symposium on Theory of computing}, year = {1996}, isbn = {0-89791-785-5}, // pages = {296--303}, // location = {Philadelphia, Pennsylvania, United States}, // doi = {http://doi.acm.org/10.1145/237814.237880}, // publisher = {ACM}, // address = {New York, NY, USA}, // } // template < typename Graph, typename Gen, typename PredMap, typename ColorMap > void random_spanning_tree(const Graph& g, Gen& gen, typename graph_traits< Graph >::vertex_descriptor root, PredMap pred, static_property_map< double >, ColorMap color) { unweighted_random_out_edge_gen< Graph, Gen > random_oe(gen); detail::random_spanning_tree_internal(g, root, pred, color, random_oe); } // Compute a weight-distributed spanning tree on a graph. template < typename Graph, typename Gen, typename PredMap, typename WeightMap, typename ColorMap > void random_spanning_tree(const Graph& g, Gen& gen, typename graph_traits< Graph >::vertex_descriptor root, PredMap pred, WeightMap weight, ColorMap color) { weighted_random_out_edge_gen< Graph, WeightMap, Gen > random_oe( weight, gen); detail::random_spanning_tree_internal(g, root, pred, color, random_oe); } template < typename Graph, typename Gen, typename P, typename T, typename R > void random_spanning_tree( const Graph& g, Gen& gen, const bgl_named_params< P, T, R >& params) { using namespace boost::graph::keywords; typedef bgl_named_params< P, T, R > params_type; BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params) typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; vertex_descriptor default_vertex = *vertices(g).first; vertex_descriptor start_vertex = arg_pack[_root_vertex | default_vertex]; typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::predecessor_map >::type pred_map = arg_pack[_predecessor_map]; static_property_map< double > default_weight_map(1.); typename boost::parameter::value_type< arg_pack_type, boost::graph::keywords::tag::weight_map, static_property_map< double > >::type e_w_map = arg_pack[_weight_map | default_weight_map]; typename boost::detail::map_maker< Graph, arg_pack_type, boost::graph::keywords::tag::color_map, boost::default_color_type >::map_type c_map = boost::detail::make_color_map_from_arg_pack(g, arg_pack); random_spanning_tree(g, gen, start_vertex, pred_map, e_w_map, c_map); } } #include <boost/graph/iteration_macros_undef.hpp> #endif // BOOST_GRAPH_RANDOM_SPANNING_TREE_HPP bellman_ford_shortest_paths.hpp 0000644 00000020045 15125521275 0013041 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // /* This file implements the function template <class EdgeListGraph, class Size, class P, class T, class R> bool bellman_ford_shortest_paths(EdgeListGraph& g, Size N, const bgl_named_params<P, T, R>& params) */ #ifndef BOOST_GRAPH_BELLMAN_FORD_SHORTEST_PATHS_HPP #define BOOST_GRAPH_BELLMAN_FORD_SHORTEST_PATHS_HPP #include <boost/config.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/relax.hpp> #include <boost/graph/visitors.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/concept/assert.hpp> namespace boost { template < class Visitor, class Graph > struct BellmanFordVisitorConcept { void constraints() { BOOST_CONCEPT_ASSERT((CopyConstructibleConcept< Visitor >)); vis.examine_edge(e, g); vis.edge_relaxed(e, g); vis.edge_not_relaxed(e, g); vis.edge_minimized(e, g); vis.edge_not_minimized(e, g); } Visitor vis; Graph g; typename graph_traits< Graph >::edge_descriptor e; }; template < class Visitors = null_visitor > class bellman_visitor { public: bellman_visitor() {} bellman_visitor(Visitors vis) : m_vis(vis) {} template < class Edge, class Graph > void examine_edge(Edge u, Graph& g) { invoke_visitors(m_vis, u, g, on_examine_edge()); } template < class Edge, class Graph > void edge_relaxed(Edge u, Graph& g) { invoke_visitors(m_vis, u, g, on_edge_relaxed()); } template < class Edge, class Graph > void edge_not_relaxed(Edge u, Graph& g) { invoke_visitors(m_vis, u, g, on_edge_not_relaxed()); } template < class Edge, class Graph > void edge_minimized(Edge u, Graph& g) { invoke_visitors(m_vis, u, g, on_edge_minimized()); } template < class Edge, class Graph > void edge_not_minimized(Edge u, Graph& g) { invoke_visitors(m_vis, u, g, on_edge_not_minimized()); } protected: Visitors m_vis; }; template < class Visitors > bellman_visitor< Visitors > make_bellman_visitor(Visitors vis) { return bellman_visitor< Visitors >(vis); } typedef bellman_visitor<> default_bellman_visitor; template < class EdgeListGraph, class Size, class WeightMap, class PredecessorMap, class DistanceMap, class BinaryFunction, class BinaryPredicate, class BellmanFordVisitor > bool bellman_ford_shortest_paths(EdgeListGraph& g, Size N, WeightMap weight, PredecessorMap pred, DistanceMap distance, BinaryFunction combine, BinaryPredicate compare, BellmanFordVisitor v) { BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< EdgeListGraph >)); typedef graph_traits< EdgeListGraph > GTraits; typedef typename GTraits::edge_descriptor Edge; typedef typename GTraits::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< DistanceMap, Vertex >)); BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< WeightMap, Edge >)); typename GTraits::edge_iterator i, end; for (Size k = 0; k < N; ++k) { bool at_least_one_edge_relaxed = false; for (boost::tie(i, end) = edges(g); i != end; ++i) { v.examine_edge(*i, g); if (relax(*i, g, weight, pred, distance, combine, compare)) { at_least_one_edge_relaxed = true; v.edge_relaxed(*i, g); } else v.edge_not_relaxed(*i, g); } if (!at_least_one_edge_relaxed) break; } for (boost::tie(i, end) = edges(g); i != end; ++i) if (compare(combine(get(distance, source(*i, g)), get(weight, *i)), get(distance, target(*i, g)))) { v.edge_not_minimized(*i, g); return false; } else v.edge_minimized(*i, g); return true; } namespace detail { template < typename VertexAndEdgeListGraph, typename Size, typename WeightMap, typename PredecessorMap, typename DistanceMap, typename P, typename T, typename R > bool bellman_dispatch2(VertexAndEdgeListGraph& g, typename graph_traits< VertexAndEdgeListGraph >::vertex_descriptor s, Size N, WeightMap weight, PredecessorMap pred, DistanceMap distance, const bgl_named_params< P, T, R >& params) { typedef typename property_traits< DistanceMap >::value_type D; bellman_visitor<> null_vis; typedef typename property_traits< WeightMap >::value_type weight_type; typename graph_traits< VertexAndEdgeListGraph >::vertex_iterator v, v_end; for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) { put(distance, *v, (std::numeric_limits< weight_type >::max)()); put(pred, *v, *v); } put(distance, s, weight_type(0)); return bellman_ford_shortest_paths(g, N, weight, pred, distance, choose_param( get_param(params, distance_combine_t()), closed_plus< D >()), choose_param( get_param(params, distance_compare_t()), std::less< D >()), choose_param(get_param(params, graph_visitor), null_vis)); } template < typename VertexAndEdgeListGraph, typename Size, typename WeightMap, typename PredecessorMap, typename DistanceMap, typename P, typename T, typename R > bool bellman_dispatch2(VertexAndEdgeListGraph& g, param_not_found, Size N, WeightMap weight, PredecessorMap pred, DistanceMap distance, const bgl_named_params< P, T, R >& params) { typedef typename property_traits< DistanceMap >::value_type D; bellman_visitor<> null_vis; return bellman_ford_shortest_paths(g, N, weight, pred, distance, choose_param( get_param(params, distance_combine_t()), closed_plus< D >()), choose_param( get_param(params, distance_compare_t()), std::less< D >()), choose_param(get_param(params, graph_visitor), null_vis)); } template < class EdgeListGraph, class Size, class WeightMap, class DistanceMap, class P, class T, class R > bool bellman_dispatch(EdgeListGraph& g, Size N, WeightMap weight, DistanceMap distance, const bgl_named_params< P, T, R >& params) { dummy_property_map dummy_pred; return detail::bellman_dispatch2(g, get_param(params, root_vertex_t()), N, weight, choose_param(get_param(params, vertex_predecessor), dummy_pred), distance, params); } } // namespace detail template < class EdgeListGraph, class Size, class P, class T, class R > bool bellman_ford_shortest_paths( EdgeListGraph& g, Size N, const bgl_named_params< P, T, R >& params) { return detail::bellman_dispatch(g, N, choose_const_pmap(get_param(params, edge_weight), g, edge_weight), choose_pmap(get_param(params, vertex_distance), g, vertex_distance), params); } template < class EdgeListGraph, class Size > bool bellman_ford_shortest_paths(EdgeListGraph& g, Size N) { bgl_named_params< int, int > params(0); return bellman_ford_shortest_paths(g, N, params); } template < class VertexAndEdgeListGraph, class P, class T, class R > bool bellman_ford_shortest_paths( VertexAndEdgeListGraph& g, const bgl_named_params< P, T, R >& params) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< VertexAndEdgeListGraph >)); return detail::bellman_dispatch(g, num_vertices(g), choose_const_pmap(get_param(params, edge_weight), g, edge_weight), choose_pmap(get_param(params, vertex_distance), g, vertex_distance), params); } } // namespace boost #endif // BOOST_GRAPH_BELLMAN_FORD_SHORTEST_PATHS_HPP relax.hpp 0000644 00000010460 15125521275 0006376 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_RELAX_HPP #define BOOST_GRAPH_RELAX_HPP #include <functional> #include <boost/limits.hpp> // for numeric limits #include <boost/graph/graph_traits.hpp> #include <boost/property_map/property_map.hpp> namespace boost { // The following version of the plus functor prevents // problems due to overflow at positive infinity. template < class T > struct closed_plus { const T inf; closed_plus() : inf((std::numeric_limits< T >::max)()) {} closed_plus(T inf) : inf(inf) {} T operator()(const T& a, const T& b) const { using namespace std; if (a == inf) return inf; if (b == inf) return inf; return a + b; } }; template < class Graph, class WeightMap, class PredecessorMap, class DistanceMap, class BinaryFunction, class BinaryPredicate > bool relax(typename graph_traits< Graph >::edge_descriptor e, const Graph& g, const WeightMap& w, PredecessorMap& p, DistanceMap& d, const BinaryFunction& combine, const BinaryPredicate& compare) { typedef typename graph_traits< Graph >::directed_category DirCat; bool is_undirected = is_same< DirCat, undirected_tag >::value; typedef typename graph_traits< Graph >::vertex_descriptor Vertex; Vertex u = source(e, g), v = target(e, g); typedef typename property_traits< DistanceMap >::value_type D; typedef typename property_traits< WeightMap >::value_type W; const D d_u = get(d, u); const D d_v = get(d, v); const W& w_e = get(w, e); // The seemingly redundant comparisons after the distance puts are to // ensure that extra floating-point precision in x87 registers does not // lead to relax() returning true when the distance did not actually // change. if (compare(combine(d_u, w_e), d_v)) { put(d, v, combine(d_u, w_e)); if (compare(get(d, v), d_v)) { put(p, v, u); return true; } else { return false; } } else if (is_undirected && compare(combine(d_v, w_e), d_u)) { put(d, u, combine(d_v, w_e)); if (compare(get(d, u), d_u)) { put(p, u, v); return true; } else { return false; } } else return false; } template < class Graph, class WeightMap, class PredecessorMap, class DistanceMap, class BinaryFunction, class BinaryPredicate > bool relax_target(typename graph_traits< Graph >::edge_descriptor e, const Graph& g, const WeightMap& w, PredecessorMap& p, DistanceMap& d, const BinaryFunction& combine, const BinaryPredicate& compare) { typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename property_traits< DistanceMap >::value_type D; typedef typename property_traits< WeightMap >::value_type W; const Vertex u = source(e, g); const Vertex v = target(e, g); const D d_u = get(d, u); const D d_v = get(d, v); const W& w_e = get(w, e); // The seemingly redundant comparisons after the distance puts are to // ensure that extra floating-point precision in x87 registers does not // lead to relax() returning true when the distance did not actually // change. if (compare(combine(d_u, w_e), d_v)) { put(d, v, combine(d_u, w_e)); if (compare(get(d, v), d_v)) { put(p, v, u); return true; } } return false; } template < class Graph, class WeightMap, class PredecessorMap, class DistanceMap > bool relax(typename graph_traits< Graph >::edge_descriptor e, const Graph& g, WeightMap w, PredecessorMap p, DistanceMap d) { typedef typename property_traits< DistanceMap >::value_type D; typedef closed_plus< D > Combine; typedef std::less< D > Compare; return relax(e, g, w, p, d, Combine(), Compare()); } } // namespace boost #endif /* BOOST_GRAPH_RELAX_HPP */ is_kuratowski_subgraph.hpp 0000644 00000024024 15125521275 0012055 0 ustar 00 //======================================================================= // Copyright 2007 Aaron Windsor // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef __IS_KURATOWSKI_SUBGRAPH_HPP__ #define __IS_KURATOWSKI_SUBGRAPH_HPP__ #include <boost/config.hpp> #include <boost/tuple/tuple.hpp> //for tie #include <boost/property_map/property_map.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/isomorphism.hpp> #include <boost/graph/adjacency_list.hpp> #include <algorithm> #include <vector> #include <set> namespace boost { namespace detail { template < typename Graph > Graph make_K_5() { typename graph_traits< Graph >::vertex_iterator vi, vi_end, inner_vi; Graph K_5(5); for (boost::tie(vi, vi_end) = vertices(K_5); vi != vi_end; ++vi) for (inner_vi = next(vi); inner_vi != vi_end; ++inner_vi) add_edge(*vi, *inner_vi, K_5); return K_5; } template < typename Graph > Graph make_K_3_3() { typename graph_traits< Graph >::vertex_iterator vi, vi_end, bipartition_start, inner_vi; Graph K_3_3(6); bipartition_start = next(next(next(vertices(K_3_3).first))); for (boost::tie(vi, vi_end) = vertices(K_3_3); vi != bipartition_start; ++vi) for (inner_vi = bipartition_start; inner_vi != vi_end; ++inner_vi) add_edge(*vi, *inner_vi, K_3_3); return K_3_3; } template < typename AdjacencyList, typename Vertex > void contract_edge(AdjacencyList& neighbors, Vertex u, Vertex v) { // Remove u from v's neighbor list neighbors[v].erase( std::remove(neighbors[v].begin(), neighbors[v].end(), u), neighbors[v].end()); // Replace any references to u with references to v typedef typename AdjacencyList::value_type::iterator adjacency_iterator_t; adjacency_iterator_t u_neighbor_end = neighbors[u].end(); for (adjacency_iterator_t u_neighbor_itr = neighbors[u].begin(); u_neighbor_itr != u_neighbor_end; ++u_neighbor_itr) { Vertex u_neighbor(*u_neighbor_itr); std::replace(neighbors[u_neighbor].begin(), neighbors[u_neighbor].end(), u, v); } // Remove v from u's neighbor list neighbors[u].erase( std::remove(neighbors[u].begin(), neighbors[u].end(), v), neighbors[u].end()); // Add everything in u's neighbor list to v's neighbor list std::copy(neighbors[u].begin(), neighbors[u].end(), std::back_inserter(neighbors[v])); // Clear u's neighbor list neighbors[u].clear(); } enum target_graph_t { tg_k_3_3, tg_k_5 }; } // namespace detail template < typename Graph, typename ForwardIterator, typename VertexIndexMap > bool is_kuratowski_subgraph(const Graph& g, ForwardIterator begin, ForwardIterator end, VertexIndexMap vm) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; typedef typename graph_traits< Graph >::edge_descriptor edge_t; typedef typename graph_traits< Graph >::edges_size_type e_size_t; typedef typename graph_traits< Graph >::vertices_size_type v_size_t; typedef typename std::vector< vertex_t > v_list_t; typedef typename v_list_t::iterator v_list_iterator_t; typedef iterator_property_map< typename std::vector< v_list_t >::iterator, VertexIndexMap > vertex_to_v_list_map_t; typedef adjacency_list< vecS, vecS, undirectedS > small_graph_t; detail::target_graph_t target_graph = detail::tg_k_3_3; // unless we decide otherwise later static small_graph_t K_5(detail::make_K_5< small_graph_t >()); static small_graph_t K_3_3(detail::make_K_3_3< small_graph_t >()); v_size_t n_vertices(num_vertices(g)); v_size_t max_num_edges(3 * n_vertices - 5); std::vector< v_list_t > neighbors_vector(n_vertices); vertex_to_v_list_map_t neighbors(neighbors_vector.begin(), vm); e_size_t count = 0; for (ForwardIterator itr = begin; itr != end; ++itr) { if (count++ > max_num_edges) return false; edge_t e(*itr); vertex_t u(source(e, g)); vertex_t v(target(e, g)); neighbors[u].push_back(v); neighbors[v].push_back(u); } for (v_size_t max_size = 2; max_size < 5; ++max_size) { vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { vertex_t v(*vi); // a hack to make sure we don't contract the middle edge of a path // of four degree-3 vertices if (max_size == 4 && neighbors[v].size() == 3) { if (neighbors[neighbors[v][0]].size() + neighbors[neighbors[v][1]].size() + neighbors[neighbors[v][2]].size() < 11 // so, it has two degree-3 neighbors ) continue; } while (neighbors[v].size() > 0 && neighbors[v].size() < max_size) { // Find one of v's neighbors u such that v and u // have no neighbors in common. We'll look for such a // neighbor with a naive cubic-time algorithm since the // max size of any of the neighbor sets we'll consider // merging is 3 bool neighbor_sets_intersect = false; vertex_t min_u = graph_traits< Graph >::null_vertex(); vertex_t u; v_list_iterator_t v_neighbor_end = neighbors[v].end(); for (v_list_iterator_t v_neighbor_itr = neighbors[v].begin(); v_neighbor_itr != v_neighbor_end; ++v_neighbor_itr) { neighbor_sets_intersect = false; u = *v_neighbor_itr; v_list_iterator_t u_neighbor_end = neighbors[u].end(); for (v_list_iterator_t u_neighbor_itr = neighbors[u].begin(); u_neighbor_itr != u_neighbor_end && !neighbor_sets_intersect; ++u_neighbor_itr) { for (v_list_iterator_t inner_v_neighbor_itr = neighbors[v].begin(); inner_v_neighbor_itr != v_neighbor_end; ++inner_v_neighbor_itr) { if (*u_neighbor_itr == *inner_v_neighbor_itr) { neighbor_sets_intersect = true; break; } } } if (!neighbor_sets_intersect && (min_u == graph_traits< Graph >::null_vertex() || neighbors[u].size() < neighbors[min_u].size())) { min_u = u; } } if (min_u == graph_traits< Graph >::null_vertex()) // Exited the loop without finding an appropriate neighbor // of v, so v must be a lost cause. Move on to other // vertices. break; else u = min_u; detail::contract_edge(neighbors, u, v); } // end iteration over v's neighbors } // end iteration through vertices v if (max_size == 3) { // check to see whether we should go on to find a K_5 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) if (neighbors[*vi].size() == 4) { target_graph = detail::tg_k_5; break; } if (target_graph == detail::tg_k_3_3) break; } } // end iteration through max degree 2,3, and 4 // Now, there should only be 5 or 6 vertices with any neighbors. Find them. v_list_t main_vertices; vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { if (!neighbors[*vi].empty()) main_vertices.push_back(*vi); } // create a graph isomorphic to the contracted graph to test // against K_5 and K_3_3 small_graph_t contracted_graph(main_vertices.size()); std::map< vertex_t, typename graph_traits< small_graph_t >::vertex_descriptor > contracted_vertex_map; typename v_list_t::iterator itr, itr_end; itr_end = main_vertices.end(); typename graph_traits< small_graph_t >::vertex_iterator si = vertices(contracted_graph).first; for (itr = main_vertices.begin(); itr != itr_end; ++itr, ++si) { contracted_vertex_map[*itr] = *si; } typename v_list_t::iterator jtr, jtr_end; for (itr = main_vertices.begin(); itr != itr_end; ++itr) { jtr_end = neighbors[*itr].end(); for (jtr = neighbors[*itr].begin(); jtr != jtr_end; ++jtr) { if (get(vm, *itr) < get(vm, *jtr)) { add_edge(contracted_vertex_map[*itr], contracted_vertex_map[*jtr], contracted_graph); } } } if (target_graph == detail::tg_k_5) { return boost::isomorphism(K_5, contracted_graph); } else // target_graph == tg_k_3_3 { return boost::isomorphism(K_3_3, contracted_graph); } } template < typename Graph, typename ForwardIterator > bool is_kuratowski_subgraph( const Graph& g, ForwardIterator begin, ForwardIterator end) { return is_kuratowski_subgraph(g, begin, end, get(vertex_index, g)); } } #endif //__IS_KURATOWSKI_SUBGRAPH_HPP__ leda_graph.hpp 0000644 00000070165 15125521275 0007361 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Copyright 2004 The Trustees of Indiana University. // Copyright 2007 University of Karlsruhe // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Douglas Gregor, // Jens Mueller // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_LEDA_HPP #define BOOST_GRAPH_LEDA_HPP #include <boost/config.hpp> #include <boost/iterator/iterator_facade.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <LEDA/graph/graph.h> #include <LEDA/graph/node_array.h> #include <LEDA/graph/node_map.h> // The functions and classes in this file allows the user to // treat a LEDA GRAPH object as a boost graph "as is". No // wrapper is needed for the GRAPH object. // Warning: this implementation relies on partial specialization // for the graph_traits class (so it won't compile with Visual C++) // Warning: this implementation is in alpha and has not been tested namespace boost { struct leda_graph_traversal_category : public virtual bidirectional_graph_tag, public virtual adjacency_graph_tag, public virtual vertex_list_graph_tag { }; template < class vtype, class etype > struct graph_traits< leda::GRAPH< vtype, etype > > { typedef leda::node vertex_descriptor; typedef leda::edge edge_descriptor; class adjacency_iterator : public iterator_facade< adjacency_iterator, leda::node, bidirectional_traversal_tag, leda::node, const leda::node* > { public: adjacency_iterator( leda::node node = 0, const leda::GRAPH< vtype, etype >* g = 0) : base(node), g(g) { } private: leda::node dereference() const { return leda::target(base); } bool equal(const adjacency_iterator& other) const { return base == other.base; } void increment() { base = g->adj_succ(base); } void decrement() { base = g->adj_pred(base); } leda::edge base; const leda::GRAPH< vtype, etype >* g; friend class iterator_core_access; }; class out_edge_iterator : public iterator_facade< out_edge_iterator, leda::edge, bidirectional_traversal_tag, const leda::edge&, const leda::edge* > { public: out_edge_iterator( leda::node node = 0, const leda::GRAPH< vtype, etype >* g = 0) : base(node), g(g) { } private: const leda::edge& dereference() const { return base; } bool equal(const out_edge_iterator& other) const { return base == other.base; } void increment() { base = g->adj_succ(base); } void decrement() { base = g->adj_pred(base); } leda::edge base; const leda::GRAPH< vtype, etype >* g; friend class iterator_core_access; }; class in_edge_iterator : public iterator_facade< in_edge_iterator, leda::edge, bidirectional_traversal_tag, const leda::edge&, const leda::edge* > { public: in_edge_iterator( leda::node node = 0, const leda::GRAPH< vtype, etype >* g = 0) : base(node), g(g) { } private: const leda::edge& dereference() const { return base; } bool equal(const in_edge_iterator& other) const { return base == other.base; } void increment() { base = g->in_succ(base); } void decrement() { base = g->in_pred(base); } leda::edge base; const leda::GRAPH< vtype, etype >* g; friend class iterator_core_access; }; class vertex_iterator : public iterator_facade< vertex_iterator, leda::node, bidirectional_traversal_tag, const leda::node&, const leda::node* > { public: vertex_iterator( leda::node node = 0, const leda::GRAPH< vtype, etype >* g = 0) : base(node), g(g) { } private: const leda::node& dereference() const { return base; } bool equal(const vertex_iterator& other) const { return base == other.base; } void increment() { base = g->succ_node(base); } void decrement() { base = g->pred_node(base); } leda::node base; const leda::GRAPH< vtype, etype >* g; friend class iterator_core_access; }; class edge_iterator : public iterator_facade< edge_iterator, leda::edge, bidirectional_traversal_tag, const leda::edge&, const leda::edge* > { public: edge_iterator( leda::edge edge = 0, const leda::GRAPH< vtype, etype >* g = 0) : base(edge), g(g) { } private: const leda::edge& dereference() const { return base; } bool equal(const edge_iterator& other) const { return base == other.base; } void increment() { base = g->succ_edge(base); } void decrement() { base = g->pred_edge(base); } leda::node base; const leda::GRAPH< vtype, etype >* g; friend class iterator_core_access; }; typedef directed_tag directed_category; typedef allow_parallel_edge_tag edge_parallel_category; // not sure here typedef leda_graph_traversal_category traversal_category; typedef int vertices_size_type; typedef int edges_size_type; typedef int degree_size_type; }; template <> struct graph_traits< leda::graph > { typedef leda::node vertex_descriptor; typedef leda::edge edge_descriptor; class adjacency_iterator : public iterator_facade< adjacency_iterator, leda::node, bidirectional_traversal_tag, leda::node, const leda::node* > { public: adjacency_iterator(leda::edge edge = 0, const leda::graph* g = 0) : base(edge), g(g) { } private: leda::node dereference() const { return leda::target(base); } bool equal(const adjacency_iterator& other) const { return base == other.base; } void increment() { base = g->adj_succ(base); } void decrement() { base = g->adj_pred(base); } leda::edge base; const leda::graph* g; friend class iterator_core_access; }; class out_edge_iterator : public iterator_facade< out_edge_iterator, leda::edge, bidirectional_traversal_tag, const leda::edge&, const leda::edge* > { public: out_edge_iterator(leda::edge edge = 0, const leda::graph* g = 0) : base(edge), g(g) { } private: const leda::edge& dereference() const { return base; } bool equal(const out_edge_iterator& other) const { return base == other.base; } void increment() { base = g->adj_succ(base); } void decrement() { base = g->adj_pred(base); } leda::edge base; const leda::graph* g; friend class iterator_core_access; }; class in_edge_iterator : public iterator_facade< in_edge_iterator, leda::edge, bidirectional_traversal_tag, const leda::edge&, const leda::edge* > { public: in_edge_iterator(leda::edge edge = 0, const leda::graph* g = 0) : base(edge), g(g) { } private: const leda::edge& dereference() const { return base; } bool equal(const in_edge_iterator& other) const { return base == other.base; } void increment() { base = g->in_succ(base); } void decrement() { base = g->in_pred(base); } leda::edge base; const leda::graph* g; friend class iterator_core_access; }; class vertex_iterator : public iterator_facade< vertex_iterator, leda::node, bidirectional_traversal_tag, const leda::node&, const leda::node* > { public: vertex_iterator(leda::node node = 0, const leda::graph* g = 0) : base(node), g(g) { } private: const leda::node& dereference() const { return base; } bool equal(const vertex_iterator& other) const { return base == other.base; } void increment() { base = g->succ_node(base); } void decrement() { base = g->pred_node(base); } leda::node base; const leda::graph* g; friend class iterator_core_access; }; class edge_iterator : public iterator_facade< edge_iterator, leda::edge, bidirectional_traversal_tag, const leda::edge&, const leda::edge* > { public: edge_iterator(leda::edge edge = 0, const leda::graph* g = 0) : base(edge), g(g) { } private: const leda::edge& dereference() const { return base; } bool equal(const edge_iterator& other) const { return base == other.base; } void increment() { base = g->succ_edge(base); } void decrement() { base = g->pred_edge(base); } leda::edge base; const leda::graph* g; friend class iterator_core_access; }; typedef directed_tag directed_category; typedef allow_parallel_edge_tag edge_parallel_category; // not sure here typedef leda_graph_traversal_category traversal_category; typedef int vertices_size_type; typedef int edges_size_type; typedef int degree_size_type; }; } // namespace boost namespace boost { //=========================================================================== // functions for GRAPH<vtype,etype> template < class vtype, class etype > typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor source( typename graph_traits< leda::GRAPH< vtype, etype > >::edge_descriptor e, const leda::GRAPH< vtype, etype >& g) { return source(e); } template < class vtype, class etype > typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor target( typename graph_traits< leda::GRAPH< vtype, etype > >::edge_descriptor e, const leda::GRAPH< vtype, etype >& g) { return target(e); } template < class vtype, class etype > inline std::pair< typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_iterator, typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_iterator > vertices(const leda::GRAPH< vtype, etype >& g) { typedef typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_iterator Iter; return std::make_pair(Iter(g.first_node(), &g), Iter(0, &g)); } template < class vtype, class etype > inline std::pair< typename graph_traits< leda::GRAPH< vtype, etype > >::edge_iterator, typename graph_traits< leda::GRAPH< vtype, etype > >::edge_iterator > edges(const leda::GRAPH< vtype, etype >& g) { typedef typename graph_traits< leda::GRAPH< vtype, etype > >::edge_iterator Iter; return std::make_pair(Iter(g.first_edge(), &g), Iter(0, &g)); } template < class vtype, class etype > inline std::pair< typename graph_traits< leda::GRAPH< vtype, etype > >::out_edge_iterator, typename graph_traits< leda::GRAPH< vtype, etype > >::out_edge_iterator > out_edges( typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor u, const leda::GRAPH< vtype, etype >& g) { typedef typename graph_traits< leda::GRAPH< vtype, etype > >::out_edge_iterator Iter; return std::make_pair(Iter(g.first_adj_edge(u, 0), &g), Iter(0, &g)); } template < class vtype, class etype > inline std::pair< typename graph_traits< leda::GRAPH< vtype, etype > >::in_edge_iterator, typename graph_traits< leda::GRAPH< vtype, etype > >::in_edge_iterator > in_edges( typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor u, const leda::GRAPH< vtype, etype >& g) { typedef typename graph_traits< leda::GRAPH< vtype, etype > >::in_edge_iterator Iter; return std::make_pair(Iter(g.first_adj_edge(u, 1), &g), Iter(0, &g)); } template < class vtype, class etype > inline std::pair< typename graph_traits< leda::GRAPH< vtype, etype > >::adjacency_iterator, typename graph_traits< leda::GRAPH< vtype, etype > >::adjacency_iterator > adjacent_vertices( typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor u, const leda::GRAPH< vtype, etype >& g) { typedef typename graph_traits< leda::GRAPH< vtype, etype > >::adjacency_iterator Iter; return std::make_pair(Iter(g.first_adj_edge(u, 0), &g), Iter(0, &g)); } template < class vtype, class etype > typename graph_traits< leda::GRAPH< vtype, etype > >::vertices_size_type num_vertices(const leda::GRAPH< vtype, etype >& g) { return g.number_of_nodes(); } template < class vtype, class etype > typename graph_traits< leda::GRAPH< vtype, etype > >::edges_size_type num_edges( const leda::GRAPH< vtype, etype >& g) { return g.number_of_edges(); } template < class vtype, class etype > typename graph_traits< leda::GRAPH< vtype, etype > >::degree_size_type out_degree( typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor u, const leda::GRAPH< vtype, etype >& g) { return g.outdeg(u); } template < class vtype, class etype > typename graph_traits< leda::GRAPH< vtype, etype > >::degree_size_type in_degree( typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor u, const leda::GRAPH< vtype, etype >& g) { return g.indeg(u); } template < class vtype, class etype > typename graph_traits< leda::GRAPH< vtype, etype > >::degree_size_type degree( typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor u, const leda::GRAPH< vtype, etype >& g) { return g.outdeg(u) + g.indeg(u); } template < class vtype, class etype > typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor add_vertex(leda::GRAPH< vtype, etype >& g) { return g.new_node(); } template < class vtype, class etype > typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor add_vertex(const vtype& vp, leda::GRAPH< vtype, etype >& g) { return g.new_node(vp); } template < class vtype, class etype > void clear_vertex( typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor u, leda::GRAPH< vtype, etype >& g) { typename graph_traits< leda::GRAPH< vtype, etype > >::out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ei++) remove_edge(*ei); typename graph_traits< leda::GRAPH< vtype, etype > >::in_edge_iterator iei, iei_end; for (boost::tie(iei, iei_end) = in_edges(u, g); iei != iei_end; iei++) remove_edge(*iei); } template < class vtype, class etype > void remove_vertex( typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor u, leda::GRAPH< vtype, etype >& g) { g.del_node(u); } template < class vtype, class etype > std::pair< typename graph_traits< leda::GRAPH< vtype, etype > >::edge_descriptor, bool > add_edge( typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor u, typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor v, leda::GRAPH< vtype, etype >& g) { return std::make_pair(g.new_edge(u, v), true); } template < class vtype, class etype > std::pair< typename graph_traits< leda::GRAPH< vtype, etype > >::edge_descriptor, bool > add_edge( typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor u, typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor v, const etype& et, leda::GRAPH< vtype, etype >& g) { return std::make_pair(g.new_edge(u, v, et), true); } template < class vtype, class etype > void remove_edge( typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor u, typename graph_traits< leda::GRAPH< vtype, etype > >::vertex_descriptor v, leda::GRAPH< vtype, etype >& g) { typename graph_traits< leda::GRAPH< vtype, etype > >::out_edge_iterator i, iend; for (boost::tie(i, iend) = out_edges(u, g); i != iend; ++i) if (target(*i, g) == v) g.del_edge(*i); } template < class vtype, class etype > void remove_edge( typename graph_traits< leda::GRAPH< vtype, etype > >::edge_descriptor e, leda::GRAPH< vtype, etype >& g) { g.del_edge(e); } //=========================================================================== // functions for graph (non-templated version) graph_traits< leda::graph >::vertex_descriptor source( graph_traits< leda::graph >::edge_descriptor e, const leda::graph& g) { return source(e); } graph_traits< leda::graph >::vertex_descriptor target( graph_traits< leda::graph >::edge_descriptor e, const leda::graph& g) { return target(e); } inline std::pair< graph_traits< leda::graph >::vertex_iterator, graph_traits< leda::graph >::vertex_iterator > vertices(const leda::graph& g) { typedef graph_traits< leda::graph >::vertex_iterator Iter; return std::make_pair(Iter(g.first_node(), &g), Iter(0, &g)); } inline std::pair< graph_traits< leda::graph >::edge_iterator, graph_traits< leda::graph >::edge_iterator > edges(const leda::graph& g) { typedef graph_traits< leda::graph >::edge_iterator Iter; return std::make_pair(Iter(g.first_edge(), &g), Iter(0, &g)); } inline std::pair< graph_traits< leda::graph >::out_edge_iterator, graph_traits< leda::graph >::out_edge_iterator > out_edges( graph_traits< leda::graph >::vertex_descriptor u, const leda::graph& g) { typedef graph_traits< leda::graph >::out_edge_iterator Iter; return std::make_pair(Iter(g.first_adj_edge(u), &g), Iter(0, &g)); } inline std::pair< graph_traits< leda::graph >::in_edge_iterator, graph_traits< leda::graph >::in_edge_iterator > in_edges(graph_traits< leda::graph >::vertex_descriptor u, const leda::graph& g) { typedef graph_traits< leda::graph >::in_edge_iterator Iter; return std::make_pair(Iter(g.first_in_edge(u), &g), Iter(0, &g)); } inline std::pair< graph_traits< leda::graph >::adjacency_iterator, graph_traits< leda::graph >::adjacency_iterator > adjacent_vertices( graph_traits< leda::graph >::vertex_descriptor u, const leda::graph& g) { typedef graph_traits< leda::graph >::adjacency_iterator Iter; return std::make_pair(Iter(g.first_adj_edge(u), &g), Iter(0, &g)); } graph_traits< leda::graph >::vertices_size_type num_vertices( const leda::graph& g) { return g.number_of_nodes(); } graph_traits< leda::graph >::edges_size_type num_edges(const leda::graph& g) { return g.number_of_edges(); } graph_traits< leda::graph >::degree_size_type out_degree( graph_traits< leda::graph >::vertex_descriptor u, const leda::graph& g) { return g.outdeg(u); } graph_traits< leda::graph >::degree_size_type in_degree( graph_traits< leda::graph >::vertex_descriptor u, const leda::graph& g) { return g.indeg(u); } graph_traits< leda::graph >::degree_size_type degree( graph_traits< leda::graph >::vertex_descriptor u, const leda::graph& g) { return g.outdeg(u) + g.indeg(u); } graph_traits< leda::graph >::vertex_descriptor add_vertex(leda::graph& g) { return g.new_node(); } void remove_edge(graph_traits< leda::graph >::vertex_descriptor u, graph_traits< leda::graph >::vertex_descriptor v, leda::graph& g) { graph_traits< leda::graph >::out_edge_iterator i, iend; for (boost::tie(i, iend) = out_edges(u, g); i != iend; ++i) if (target(*i, g) == v) g.del_edge(*i); } void remove_edge(graph_traits< leda::graph >::edge_descriptor e, leda::graph& g) { g.del_edge(e); } void clear_vertex( graph_traits< leda::graph >::vertex_descriptor u, leda::graph& g) { graph_traits< leda::graph >::out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ei++) remove_edge(*ei, g); graph_traits< leda::graph >::in_edge_iterator iei, iei_end; for (boost::tie(iei, iei_end) = in_edges(u, g); iei != iei_end; iei++) remove_edge(*iei, g); } void remove_vertex( graph_traits< leda::graph >::vertex_descriptor u, leda::graph& g) { g.del_node(u); } std::pair< graph_traits< leda::graph >::edge_descriptor, bool > add_edge( graph_traits< leda::graph >::vertex_descriptor u, graph_traits< leda::graph >::vertex_descriptor v, leda::graph& g) { return std::make_pair(g.new_edge(u, v), true); } //=========================================================================== // property maps for GRAPH<vtype,etype> class leda_graph_id_map : public put_get_helper< int, leda_graph_id_map > { public: typedef readable_property_map_tag category; typedef int value_type; typedef int reference; typedef leda::node key_type; leda_graph_id_map() {} template < class T > long operator[](T x) const { return x->id(); } }; template < class vtype, class etype > inline leda_graph_id_map get( vertex_index_t, const leda::GRAPH< vtype, etype >& g) { return leda_graph_id_map(); } template < class vtype, class etype > inline leda_graph_id_map get(edge_index_t, const leda::GRAPH< vtype, etype >& g) { return leda_graph_id_map(); } template < class Tag > struct leda_property_map { }; template <> struct leda_property_map< vertex_index_t > { template < class vtype, class etype > struct bind_ { typedef leda_graph_id_map type; typedef leda_graph_id_map const_type; }; }; template <> struct leda_property_map< edge_index_t > { template < class vtype, class etype > struct bind_ { typedef leda_graph_id_map type; typedef leda_graph_id_map const_type; }; }; template < class Data, class DataRef, class GraphPtr > class leda_graph_data_map : public put_get_helper< DataRef, leda_graph_data_map< Data, DataRef, GraphPtr > > { public: typedef Data value_type; typedef DataRef reference; typedef void key_type; typedef lvalue_property_map_tag category; leda_graph_data_map(GraphPtr g) : m_g(g) {} template < class NodeOrEdge > DataRef operator[](NodeOrEdge x) const { return (*m_g)[x]; } protected: GraphPtr m_g; }; template <> struct leda_property_map< vertex_all_t > { template < class vtype, class etype > struct bind_ { typedef leda_graph_data_map< vtype, vtype&, leda::GRAPH< vtype, etype >* > type; typedef leda_graph_data_map< vtype, const vtype&, const leda::GRAPH< vtype, etype >* > const_type; }; }; template < class vtype, class etype > inline typename property_map< leda::GRAPH< vtype, etype >, vertex_all_t >::type get(vertex_all_t, leda::GRAPH< vtype, etype >& g) { typedef typename property_map< leda::GRAPH< vtype, etype >, vertex_all_t >::type pmap_type; return pmap_type(&g); } template < class vtype, class etype > inline typename property_map< leda::GRAPH< vtype, etype >, vertex_all_t >::const_type get(vertex_all_t, const leda::GRAPH< vtype, etype >& g) { typedef typename property_map< leda::GRAPH< vtype, etype >, vertex_all_t >::const_type pmap_type; return pmap_type(&g); } template <> struct leda_property_map< edge_all_t > { template < class vtype, class etype > struct bind_ { typedef leda_graph_data_map< etype, etype&, leda::GRAPH< vtype, etype >* > type; typedef leda_graph_data_map< etype, const etype&, const leda::GRAPH< vtype, etype >* > const_type; }; }; template < class vtype, class etype > inline typename property_map< leda::GRAPH< vtype, etype >, edge_all_t >::type get(edge_all_t, leda::GRAPH< vtype, etype >& g) { typedef typename property_map< leda::GRAPH< vtype, etype >, edge_all_t >::type pmap_type; return pmap_type(&g); } template < class vtype, class etype > inline typename property_map< leda::GRAPH< vtype, etype >, edge_all_t >::const_type get(edge_all_t, const leda::GRAPH< vtype, etype >& g) { typedef typename property_map< leda::GRAPH< vtype, etype >, edge_all_t >::const_type pmap_type; return pmap_type(&g); } // property map interface to the LEDA node_array class template < class E, class ERef, class NodeMapPtr > class leda_node_property_map : public put_get_helper< ERef, leda_node_property_map< E, ERef, NodeMapPtr > > { public: typedef E value_type; typedef ERef reference; typedef leda::node key_type; typedef lvalue_property_map_tag category; leda_node_property_map(NodeMapPtr a) : m_array(a) {} ERef operator[](leda::node n) const { return (*m_array)[n]; } protected: NodeMapPtr m_array; }; template < class E > leda_node_property_map< E, const E&, const leda::node_array< E >* > make_leda_node_property_map(const leda::node_array< E >& a) { typedef leda_node_property_map< E, const E&, const leda::node_array< E >* > pmap_type; return pmap_type(&a); } template < class E > leda_node_property_map< E, E&, leda::node_array< E >* > make_leda_node_property_map(leda::node_array< E >& a) { typedef leda_node_property_map< E, E&, leda::node_array< E >* > pmap_type; return pmap_type(&a); } template < class E > leda_node_property_map< E, const E&, const leda::node_map< E >* > make_leda_node_property_map(const leda::node_map< E >& a) { typedef leda_node_property_map< E, const E&, const leda::node_map< E >* > pmap_type; return pmap_type(&a); } template < class E > leda_node_property_map< E, E&, leda::node_map< E >* > make_leda_node_property_map(leda::node_map< E >& a) { typedef leda_node_property_map< E, E&, leda::node_map< E >* > pmap_type; return pmap_type(&a); } // g++ 'enumeral_type' in template unification not implemented workaround template < class vtype, class etype, class Tag > struct property_map< leda::GRAPH< vtype, etype >, Tag > { typedef typename leda_property_map< Tag >::template bind_< vtype, etype > map_gen; typedef typename map_gen::type type; typedef typename map_gen::const_type const_type; }; template < class vtype, class etype, class PropertyTag, class Key > inline typename boost::property_traits< typename boost::property_map< leda::GRAPH< vtype, etype >, PropertyTag >::const_type >::value_type get(PropertyTag p, const leda::GRAPH< vtype, etype >& g, const Key& key) { return get(get(p, g), key); } template < class vtype, class etype, class PropertyTag, class Key, class Value > inline void put(PropertyTag p, leda::GRAPH< vtype, etype >& g, const Key& key, const Value& value) { typedef typename property_map< leda::GRAPH< vtype, etype >, PropertyTag >::type Map; Map pmap = get(p, g); put(pmap, key, value); } // property map interface to the LEDA edge_array class template < class E, class ERef, class EdgeMapPtr > class leda_edge_property_map : public put_get_helper< ERef, leda_edge_property_map< E, ERef, EdgeMapPtr > > { public: typedef E value_type; typedef ERef reference; typedef leda::edge key_type; typedef lvalue_property_map_tag category; leda_edge_property_map(EdgeMapPtr a) : m_array(a) {} ERef operator[](leda::edge n) const { return (*m_array)[n]; } protected: EdgeMapPtr m_array; }; template < class E > leda_edge_property_map< E, const E&, const leda::edge_array< E >* > make_leda_node_property_map(const leda::node_array< E >& a) { typedef leda_edge_property_map< E, const E&, const leda::node_array< E >* > pmap_type; return pmap_type(&a); } template < class E > leda_edge_property_map< E, E&, leda::edge_array< E >* > make_leda_edge_property_map(leda::edge_array< E >& a) { typedef leda_edge_property_map< E, E&, leda::edge_array< E >* > pmap_type; return pmap_type(&a); } template < class E > leda_edge_property_map< E, const E&, const leda::edge_map< E >* > make_leda_edge_property_map(const leda::edge_map< E >& a) { typedef leda_edge_property_map< E, const E&, const leda::edge_map< E >* > pmap_type; return pmap_type(&a); } template < class E > leda_edge_property_map< E, E&, leda::edge_map< E >* > make_leda_edge_property_map(leda::edge_map< E >& a) { typedef leda_edge_property_map< E, E&, leda::edge_map< E >* > pmap_type; return pmap_type(&a); } } // namespace boost #endif // BOOST_GRAPH_LEDA_HPP adjacency_iterator.hpp 0000644 00000005570 15125521275 0011123 0 ustar 00 //======================================================================= // Copyright 2002 Indiana University. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_ADJACENCY_ITERATOR_HPP #define BOOST_ADJACENCY_ITERATOR_HPP #include <boost/detail/iterator.hpp> #include <boost/iterator/iterator_adaptor.hpp> #include <boost/graph/graph_traits.hpp> namespace boost { template < class Graph, class Vertex, class OutEdgeIter, class Difference > struct adjacency_iterator : iterator_adaptor< adjacency_iterator< Graph, Vertex, OutEdgeIter, Difference >, OutEdgeIter, Vertex, use_default, Vertex, Difference > { typedef iterator_adaptor< adjacency_iterator< Graph, Vertex, OutEdgeIter, Difference >, OutEdgeIter, Vertex, use_default, Vertex, Difference > super_t; inline adjacency_iterator() {} inline adjacency_iterator(OutEdgeIter const& i, const Graph* g) : super_t(i), m_g(g) { } inline Vertex dereference() const { return target(*this->base(), *m_g); } const Graph* m_g; }; template < class Graph, class Vertex = typename graph_traits< Graph >::vertex_descriptor, class OutEdgeIter = typename graph_traits< Graph >::out_edge_iterator > class adjacency_iterator_generator { typedef typename boost::detail::iterator_traits< OutEdgeIter >::difference_type difference_type; public: typedef adjacency_iterator< Graph, Vertex, OutEdgeIter, difference_type > type; }; template < class Graph, class Vertex, class InEdgeIter, class Difference > struct inv_adjacency_iterator : iterator_adaptor< inv_adjacency_iterator< Graph, Vertex, InEdgeIter, Difference >, InEdgeIter, Vertex, use_default, Vertex, Difference > { typedef iterator_adaptor< inv_adjacency_iterator< Graph, Vertex, InEdgeIter, Difference >, InEdgeIter, Vertex, use_default, Vertex, Difference > super_t; inline inv_adjacency_iterator() {} inline inv_adjacency_iterator(InEdgeIter const& i, const Graph* g) : super_t(i), m_g(g) { } inline Vertex dereference() const { return source(*this->base(), *m_g); } const Graph* m_g; }; template < class Graph, class Vertex = typename graph_traits< Graph >::vertex_descriptor, class InEdgeIter = typename graph_traits< Graph >::in_edge_iterator > class inv_adjacency_iterator_generator { typedef typename boost::detail::iterator_traits< InEdgeIter >::difference_type difference_type; public: typedef inv_adjacency_iterator< Graph, Vertex, InEdgeIter, difference_type > type; }; } // namespace boost #endif // BOOST_DETAIL_ADJACENCY_ITERATOR_HPP push_relabel_max_flow.hpp 0000644 00000103661 15125521275 0011632 0 ustar 00 //======================================================================= // Copyright 2000 University of Notre Dame. // Authors: Jeremy G. Siek, Andrew Lumsdaine, Lie-Quan Lee // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_PUSH_RELABEL_MAX_FLOW_HPP #define BOOST_PUSH_RELABEL_MAX_FLOW_HPP #include <boost/config.hpp> #include <boost/assert.hpp> #include <vector> #include <list> #include <iosfwd> #include <algorithm> // for std::min and std::max #include <boost/pending/queue.hpp> #include <boost/limits.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/named_function_params.hpp> namespace boost { namespace detail { // This implementation is based on Goldberg's // "On Implementing Push-Relabel Method for the Maximum Flow Problem" // by B.V. Cherkassky and A.V. Goldberg, IPCO '95, pp. 157--171 // and on the h_prf.c and hi_pr.c code written by the above authors. // This implements the highest-label version of the push-relabel method // with the global relabeling and gap relabeling heuristics. // The terms "rank", "distance", "height" are synonyms in // Goldberg's implementation, paper and in the CLR. A "layer" is a // group of vertices with the same distance. The vertices in each // layer are categorized as active or inactive. An active vertex // has positive excess flow and its distance is less than n (it is // not blocked). template < class Vertex > struct preflow_layer { std::list< Vertex > active_vertices; std::list< Vertex > inactive_vertices; }; template < class Graph, class EdgeCapacityMap, // integer value type class ResidualCapacityEdgeMap, class ReverseEdgeMap, class VertexIndexMap, // vertex_descriptor -> integer class FlowValue > class push_relabel { public: typedef graph_traits< Graph > Traits; typedef typename Traits::vertex_descriptor vertex_descriptor; typedef typename Traits::edge_descriptor edge_descriptor; typedef typename Traits::vertex_iterator vertex_iterator; typedef typename Traits::out_edge_iterator out_edge_iterator; typedef typename Traits::vertices_size_type vertices_size_type; typedef typename Traits::edges_size_type edges_size_type; typedef preflow_layer< vertex_descriptor > Layer; typedef std::vector< Layer > LayerArray; typedef typename LayerArray::iterator layer_iterator; typedef typename LayerArray::size_type distance_size_type; typedef color_traits< default_color_type > ColorTraits; //======================================================================= // Some helper predicates inline bool is_admissible(vertex_descriptor u, vertex_descriptor v) { return get(distance, u) == get(distance, v) + 1; } inline bool is_residual_edge(edge_descriptor a) { return 0 < get(residual_capacity, a); } inline bool is_saturated(edge_descriptor a) { return get(residual_capacity, a) == 0; } //======================================================================= // Layer List Management Functions typedef typename std::list< vertex_descriptor >::iterator list_iterator; void add_to_active_list(vertex_descriptor u, Layer& layer) { BOOST_USING_STD_MIN(); BOOST_USING_STD_MAX(); layer.active_vertices.push_front(u); max_active = max BOOST_PREVENT_MACRO_SUBSTITUTION( get(distance, u), max_active); min_active = min BOOST_PREVENT_MACRO_SUBSTITUTION( get(distance, u), min_active); layer_list_ptr[u] = layer.active_vertices.begin(); } void remove_from_active_list(vertex_descriptor u) { layers[get(distance, u)].active_vertices.erase(layer_list_ptr[u]); } void add_to_inactive_list(vertex_descriptor u, Layer& layer) { layer.inactive_vertices.push_front(u); layer_list_ptr[u] = layer.inactive_vertices.begin(); } void remove_from_inactive_list(vertex_descriptor u) { layers[get(distance, u)].inactive_vertices.erase(layer_list_ptr[u]); } //======================================================================= // initialization push_relabel(Graph& g_, EdgeCapacityMap cap, ResidualCapacityEdgeMap res, ReverseEdgeMap rev, vertex_descriptor src_, vertex_descriptor sink_, VertexIndexMap idx) : g(g_) , n(num_vertices(g_)) , capacity(cap) , src(src_) , sink(sink_) , index(idx) , excess_flow_data(num_vertices(g_)) , excess_flow(excess_flow_data.begin(), idx) , current_data(num_vertices(g_), out_edges(*vertices(g_).first, g_)) , current(current_data.begin(), idx) , distance_data(num_vertices(g_)) , distance(distance_data.begin(), idx) , color_data(num_vertices(g_)) , color(color_data.begin(), idx) , reverse_edge(rev) , residual_capacity(res) , layers(num_vertices(g_)) , layer_list_ptr_data( num_vertices(g_), layers.front().inactive_vertices.end()) , layer_list_ptr(layer_list_ptr_data.begin(), idx) , push_count(0) , update_count(0) , relabel_count(0) , gap_count(0) , gap_node_count(0) , work_since_last_update(0) { vertex_iterator u_iter, u_end; // Don't count the reverse edges edges_size_type m = num_edges(g) / 2; nm = alpha() * n + m; // Initialize flow to zero which means initializing // the residual capacity to equal the capacity. out_edge_iterator ei, e_end; for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) for (boost::tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei) { put(residual_capacity, *ei, get(capacity, *ei)); } for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) { vertex_descriptor u = *u_iter; put(excess_flow, u, 0); current[u] = out_edges(u, g); } bool overflow_detected = false; FlowValue test_excess = 0; out_edge_iterator a_iter, a_end; for (boost::tie(a_iter, a_end) = out_edges(src, g); a_iter != a_end; ++a_iter) if (target(*a_iter, g) != src) test_excess += get(residual_capacity, *a_iter); if (test_excess > (std::numeric_limits< FlowValue >::max)()) overflow_detected = true; if (overflow_detected) put(excess_flow, src, (std::numeric_limits< FlowValue >::max)()); else { put(excess_flow, src, 0); for (boost::tie(a_iter, a_end) = out_edges(src, g); a_iter != a_end; ++a_iter) { edge_descriptor a = *a_iter; vertex_descriptor tgt = target(a, g); if (tgt != src) { ++push_count; FlowValue delta = get(residual_capacity, a); put(residual_capacity, a, get(residual_capacity, a) - delta); edge_descriptor rev = get(reverse_edge, a); put(residual_capacity, rev, get(residual_capacity, rev) + delta); put(excess_flow, tgt, get(excess_flow, tgt) + delta); } } } max_distance = num_vertices(g) - 1; max_active = 0; min_active = n; for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) { vertex_descriptor u = *u_iter; if (u == sink) { put(distance, u, 0); continue; } else if (u == src && !overflow_detected) put(distance, u, n); else put(distance, u, 1); if (get(excess_flow, u) > 0) add_to_active_list(u, layers[1]); else if (get(distance, u) < n) add_to_inactive_list(u, layers[1]); } } // push_relabel constructor //======================================================================= // This is a breadth-first search over the residual graph // (well, actually the reverse of the residual graph). // Would be cool to have a graph view adaptor for hiding certain // edges, like the saturated (non-residual) edges in this case. // Goldberg's implementation abused "distance" for the coloring. void global_distance_update() { BOOST_USING_STD_MAX(); ++update_count; vertex_iterator u_iter, u_end; for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) { put(color, *u_iter, ColorTraits::white()); put(distance, *u_iter, n); } put(color, sink, ColorTraits::gray()); put(distance, sink, 0); for (distance_size_type l = 0; l <= max_distance; ++l) { layers[l].active_vertices.clear(); layers[l].inactive_vertices.clear(); } max_distance = max_active = 0; min_active = n; Q.push(sink); while (!Q.empty()) { vertex_descriptor u = Q.top(); Q.pop(); distance_size_type d_v = get(distance, u) + 1; out_edge_iterator ai, a_end; for (boost::tie(ai, a_end) = out_edges(u, g); ai != a_end; ++ai) { edge_descriptor a = *ai; vertex_descriptor v = target(a, g); if (get(color, v) == ColorTraits::white() && is_residual_edge(get(reverse_edge, a))) { put(distance, v, d_v); put(color, v, ColorTraits::gray()); current[v] = out_edges(v, g); max_distance = max BOOST_PREVENT_MACRO_SUBSTITUTION( d_v, max_distance); if (get(excess_flow, v) > 0) add_to_active_list(v, layers[d_v]); else add_to_inactive_list(v, layers[d_v]); Q.push(v); } } } } // global_distance_update() //======================================================================= // This function is called "push" in Goldberg's h_prf implementation, // but it is called "discharge" in the paper and in hi_pr.c. void discharge(vertex_descriptor u) { BOOST_ASSERT(get(excess_flow, u) > 0); while (1) { out_edge_iterator ai, ai_end; for (boost::tie(ai, ai_end) = current[u]; ai != ai_end; ++ai) { edge_descriptor a = *ai; if (is_residual_edge(a)) { vertex_descriptor v = target(a, g); if (is_admissible(u, v)) { ++push_count; if (v != sink && get(excess_flow, v) == 0) { remove_from_inactive_list(v); add_to_active_list(v, layers[get(distance, v)]); } push_flow(a); if (get(excess_flow, u) == 0) break; } } } // for out_edges of i starting from current Layer& layer = layers[get(distance, u)]; distance_size_type du = get(distance, u); if (ai == ai_end) { // i must be relabeled relabel_distance(u); if (layer.active_vertices.empty() && layer.inactive_vertices.empty()) gap(du); if (get(distance, u) == n) break; } else { // i is no longer active current[u].first = ai; add_to_inactive_list(u, layer); break; } } // while (1) } // discharge() //======================================================================= // This corresponds to the "push" update operation of the paper, // not the "push" function in Goldberg's h_prf.c implementation. // The idea is to push the excess flow from from vertex u to v. void push_flow(edge_descriptor u_v) { vertex_descriptor u = source(u_v, g), v = target(u_v, g); BOOST_USING_STD_MIN(); FlowValue flow_delta = min BOOST_PREVENT_MACRO_SUBSTITUTION( get(excess_flow, u), get(residual_capacity, u_v)); put(residual_capacity, u_v, get(residual_capacity, u_v) - flow_delta); edge_descriptor rev = get(reverse_edge, u_v); put(residual_capacity, rev, get(residual_capacity, rev) + flow_delta); put(excess_flow, u, get(excess_flow, u) - flow_delta); put(excess_flow, v, get(excess_flow, v) + flow_delta); } // push_flow() //======================================================================= // The main purpose of this routine is to set distance[v] // to the smallest value allowed by the valid labeling constraints, // which are: // distance[t] = 0 // distance[u] <= distance[v] + 1 for every residual edge (u,v) // distance_size_type relabel_distance(vertex_descriptor u) { BOOST_USING_STD_MAX(); ++relabel_count; work_since_last_update += beta(); distance_size_type min_distance = num_vertices(g); put(distance, u, min_distance); // Examine the residual out-edges of vertex i, choosing the // edge whose target vertex has the minimal distance. out_edge_iterator ai, a_end, min_edge_iter; for (boost::tie(ai, a_end) = out_edges(u, g); ai != a_end; ++ai) { ++work_since_last_update; edge_descriptor a = *ai; vertex_descriptor v = target(a, g); if (is_residual_edge(a) && get(distance, v) < min_distance) { min_distance = get(distance, v); min_edge_iter = ai; } } ++min_distance; if (min_distance < n) { put(distance, u, min_distance); // this is the main action current[u].first = min_edge_iter; max_distance = max BOOST_PREVENT_MACRO_SUBSTITUTION( min_distance, max_distance); } return min_distance; } // relabel_distance() //======================================================================= // cleanup beyond the gap void gap(distance_size_type empty_distance) { ++gap_count; distance_size_type r; // distance of layer before the current layer r = empty_distance - 1; // Set the distance for the vertices beyond the gap to "infinity". for (layer_iterator l = layers.begin() + empty_distance + 1; l < layers.begin() + max_distance; ++l) { list_iterator i; for (i = l->inactive_vertices.begin(); i != l->inactive_vertices.end(); ++i) { put(distance, *i, n); ++gap_node_count; } l->inactive_vertices.clear(); } max_distance = r; max_active = r; } //======================================================================= // This is the core part of the algorithm, "phase one". FlowValue maximum_preflow() { work_since_last_update = 0; while (max_active >= min_active) { // "main" loop Layer& layer = layers[max_active]; list_iterator u_iter = layer.active_vertices.begin(); if (u_iter == layer.active_vertices.end()) --max_active; else { vertex_descriptor u = *u_iter; remove_from_active_list(u); discharge(u); if (work_since_last_update * global_update_frequency() > nm) { global_distance_update(); work_since_last_update = 0; } } } // while (max_active >= min_active) return get(excess_flow, sink); } // maximum_preflow() //======================================================================= // remove excess flow, the "second phase" // This does a DFS on the reverse flow graph of nodes with excess flow. // If a cycle is found, cancel it. // Return the nodes with excess flow in topological order. // // Unlike the prefl_to_flow() implementation, we use // "color" instead of "distance" for the DFS labels // "parent" instead of nl_prev for the DFS tree // "topo_next" instead of nl_next for the topological ordering void convert_preflow_to_flow() { vertex_iterator u_iter, u_end; out_edge_iterator ai, a_end; vertex_descriptor r, restart, u; std::vector< vertex_descriptor > parent(n); std::vector< vertex_descriptor > topo_next(n); vertex_descriptor tos(parent[0]), bos(parent[0]); // bogus initialization, just to avoid warning bool bos_null = true; // handle self-loops for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) for (boost::tie(ai, a_end) = out_edges(*u_iter, g); ai != a_end; ++ai) if (target(*ai, g) == *u_iter) put(residual_capacity, *ai, get(capacity, *ai)); // initialize for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) { u = *u_iter; put(color, u, ColorTraits::white()); parent[get(index, u)] = u; current[u] = out_edges(u, g); } // eliminate flow cycles and topologically order the vertices for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) { u = *u_iter; if (get(color, u) == ColorTraits::white() && get(excess_flow, u) > 0 && u != src && u != sink) { r = u; put(color, r, ColorTraits::gray()); while (1) { for (; current[u].first != current[u].second; ++current[u].first) { edge_descriptor a = *current[u].first; if (get(capacity, a) == 0 && is_residual_edge(a)) { vertex_descriptor v = target(a, g); if (get(color, v) == ColorTraits::white()) { put(color, v, ColorTraits::gray()); parent[get(index, v)] = u; u = v; break; } else if (get(color, v) == ColorTraits::gray()) { // find minimum flow on the cycle FlowValue delta = get(residual_capacity, a); while (1) { BOOST_USING_STD_MIN(); delta = min BOOST_PREVENT_MACRO_SUBSTITUTION( delta, get(residual_capacity, *current[v].first)); if (v == u) break; else v = target(*current[v].first, g); } // remove delta flow units v = u; while (1) { a = *current[v].first; put(residual_capacity, a, get(residual_capacity, a) - delta); edge_descriptor rev = get(reverse_edge, a); put(residual_capacity, rev, get(residual_capacity, rev) + delta); v = target(a, g); if (v == u) break; } // back-out of DFS to the first saturated // edge restart = u; for (v = target(*current[u].first, g); v != u; v = target(a, g)) { a = *current[v].first; if (get(color, v) == ColorTraits::white() || is_saturated(a)) { put(color, target(*current[v].first, g), ColorTraits::white()); if (get(color, v) != ColorTraits::white()) restart = v; } } if (restart != u) { u = restart; ++current[u].first; break; } } // else if (color[v] == ColorTraits::gray()) } // if (get(capacity, a) == 0 ... } // for out_edges(u, g) (though "u" changes during // loop) if (current[u].first == current[u].second) { // scan of i is complete put(color, u, ColorTraits::black()); if (u != src) { if (bos_null) { bos = u; bos_null = false; tos = u; } else { topo_next[get(index, u)] = tos; tos = u; } } if (u != r) { u = parent[get(index, u)]; ++current[u].first; } else break; } } // while (1) } // if (color[u] == white && excess_flow[u] > 0 & ...) } // for all vertices in g // return excess flows // note that the sink is not on the stack if (!bos_null) { for (u = tos; u != bos; u = topo_next[get(index, u)]) { boost::tie(ai, a_end) = out_edges(u, g); while (get(excess_flow, u) > 0 && ai != a_end) { if (get(capacity, *ai) == 0 && is_residual_edge(*ai)) push_flow(*ai); ++ai; } } // do the bottom u = bos; boost::tie(ai, a_end) = out_edges(u, g); while (get(excess_flow, u) > 0 && ai != a_end) { if (get(capacity, *ai) == 0 && is_residual_edge(*ai)) push_flow(*ai); ++ai; } } } // convert_preflow_to_flow() //======================================================================= inline bool is_flow() { vertex_iterator u_iter, u_end; out_edge_iterator ai, a_end; // check edge flow values for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) { for (boost::tie(ai, a_end) = out_edges(*u_iter, g); ai != a_end; ++ai) { edge_descriptor a = *ai; if (get(capacity, a) > 0) if ((get(residual_capacity, a) + get( residual_capacity, get(reverse_edge, a)) != get(capacity, a) + get(capacity, get(reverse_edge, a))) || (get(residual_capacity, a) < 0) || (get(residual_capacity, get(reverse_edge, a)) < 0)) return false; } } // check conservation FlowValue sum; for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) { vertex_descriptor u = *u_iter; if (u != src && u != sink) { if (get(excess_flow, u) != 0) return false; sum = 0; for (boost::tie(ai, a_end) = out_edges(u, g); ai != a_end; ++ai) if (get(capacity, *ai) > 0) sum -= get(capacity, *ai) - get(residual_capacity, *ai); else sum += get(residual_capacity, *ai); if (get(excess_flow, u) != sum) return false; } } return true; } // is_flow() bool is_optimal() { // check if mincut is saturated... global_distance_update(); return get(distance, src) >= n; } void print_statistics(std::ostream& os) const { os << "pushes: " << push_count << std::endl << "relabels: " << relabel_count << std::endl << "updates: " << update_count << std::endl << "gaps: " << gap_count << std::endl << "gap nodes: " << gap_node_count << std::endl << std::endl; } void print_flow_values(std::ostream& os) const { os << "flow values" << std::endl; vertex_iterator u_iter, u_end; out_edge_iterator ei, e_end; for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) for (boost::tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei) if (get(capacity, *ei) > 0) os << *u_iter << " " << target(*ei, g) << " " << (get(capacity, *ei) - get(residual_capacity, *ei)) << std::endl; os << std::endl; } //======================================================================= Graph& g; vertices_size_type n; vertices_size_type nm; EdgeCapacityMap capacity; vertex_descriptor src; vertex_descriptor sink; VertexIndexMap index; // will need to use random_access_property_map with these std::vector< FlowValue > excess_flow_data; iterator_property_map< typename std::vector< FlowValue >::iterator, VertexIndexMap > excess_flow; std::vector< std::pair< out_edge_iterator, out_edge_iterator > > current_data; iterator_property_map< typename std::vector< std::pair< out_edge_iterator, out_edge_iterator > >::iterator, VertexIndexMap > current; std::vector< distance_size_type > distance_data; iterator_property_map< typename std::vector< distance_size_type >::iterator, VertexIndexMap > distance; std::vector< default_color_type > color_data; iterator_property_map< std::vector< default_color_type >::iterator, VertexIndexMap > color; // Edge Property Maps that must be interior to the graph ReverseEdgeMap reverse_edge; ResidualCapacityEdgeMap residual_capacity; LayerArray layers; std::vector< list_iterator > layer_list_ptr_data; iterator_property_map< typename std::vector< list_iterator >::iterator, VertexIndexMap > layer_list_ptr; distance_size_type max_distance; // maximal distance distance_size_type max_active; // maximal distance with active node distance_size_type min_active; // minimal distance with active node boost::queue< vertex_descriptor > Q; // Statistics counters long push_count; long update_count; long relabel_count; long gap_count; long gap_node_count; inline double global_update_frequency() { return 0.5; } inline vertices_size_type alpha() { return 6; } inline long beta() { return 12; } long work_since_last_update; }; } // namespace detail template < class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap, class ReverseEdgeMap, class VertexIndexMap > typename property_traits< CapacityEdgeMap >::value_type push_relabel_max_flow( Graph& g, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink, CapacityEdgeMap cap, ResidualCapacityEdgeMap res, ReverseEdgeMap rev, VertexIndexMap index_map) { typedef typename property_traits< CapacityEdgeMap >::value_type FlowValue; detail::push_relabel< Graph, CapacityEdgeMap, ResidualCapacityEdgeMap, ReverseEdgeMap, VertexIndexMap, FlowValue > algo(g, cap, res, rev, src, sink, index_map); FlowValue flow = algo.maximum_preflow(); algo.convert_preflow_to_flow(); BOOST_ASSERT(algo.is_flow()); BOOST_ASSERT(algo.is_optimal()); return flow; } // push_relabel_max_flow() template < class Graph, class P, class T, class R > typename detail::edge_capacity_value< Graph, P, T, R >::type push_relabel_max_flow(Graph& g, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink, const bgl_named_params< P, T, R >& params) { return push_relabel_max_flow(g, src, sink, choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity), choose_pmap(get_param(params, edge_residual_capacity), g, edge_residual_capacity), choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse), choose_const_pmap(get_param(params, vertex_index), g, vertex_index)); } template < class Graph > typename property_traits< typename property_map< Graph, edge_capacity_t >::const_type >::value_type push_relabel_max_flow(Graph& g, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink) { bgl_named_params< int, buffer_param_t > params(0); // bogus empty param return push_relabel_max_flow(g, src, sink, params); } } // namespace boost #endif // BOOST_PUSH_RELABEL_MAX_FLOW_HPP directed_graph.hpp 0000644 00000057226 15125521275 0010242 0 ustar 00 // (C) Copyright 2007-2009 Andrew Sutton // // 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_DIRECTED_GRAPH_HPP #define BOOST_GRAPH_DIRECTED_GRAPH_HPP #include <boost/graph/adjacency_list.hpp> #include <boost/graph/properties.hpp> #include <boost/pending/property.hpp> #include <boost/property_map/transform_value_property_map.hpp> #include <boost/type_traits.hpp> #include <boost/mpl/if.hpp> namespace boost { struct directed_graph_tag { }; /** * The directed_graph class template is a simplified version of the BGL * adjacency list. This class is provided for ease of use, but may not * perform as well as custom-defined adjacency list classes. Instances of * this template model the BidirectionalGraph, VertexIndexGraph, and * EdgeIndexGraph concepts. The graph is also fully mutable, supporting * both insertions and removals of vertices and edges. * * @note Special care must be taken when removing vertices or edges since * those operations can invalidate the numbering of vertices. */ template < typename VertexProp = no_property, typename EdgeProp = no_property, typename GraphProp = no_property > class directed_graph { public: typedef GraphProp graph_property_type; typedef VertexProp vertex_property_type; typedef EdgeProp edge_property_type; typedef typename lookup_one_property< GraphProp, graph_bundle_t >::type graph_bundled; typedef typename lookup_one_property< VertexProp, vertex_bundle_t >::type vertex_bundled; typedef typename lookup_one_property< EdgeProp, edge_bundle_t >::type edge_bundled; public: // Embed indices into the vertex type. typedef property< vertex_index_t, unsigned, vertex_property_type > internal_vertex_property; typedef property< edge_index_t, unsigned, edge_property_type > internal_edge_property; public: typedef adjacency_list< listS, listS, bidirectionalS, internal_vertex_property, internal_edge_property, GraphProp, listS > graph_type; private: // storage selectors typedef typename graph_type::vertex_list_selector vertex_list_selector; typedef typename graph_type::edge_list_selector edge_list_selector; typedef typename graph_type::out_edge_list_selector out_edge_list_selector; typedef typename graph_type::directed_selector directed_selector; public: // more commonly used graph types typedef typename graph_type::stored_vertex stored_vertex; typedef typename graph_type::vertices_size_type vertices_size_type; typedef typename graph_type::edges_size_type edges_size_type; typedef typename graph_type::degree_size_type degree_size_type; typedef typename graph_type::vertex_descriptor vertex_descriptor; typedef typename graph_type::edge_descriptor edge_descriptor; // iterator types typedef typename graph_type::vertex_iterator vertex_iterator; typedef typename graph_type::edge_iterator edge_iterator; typedef typename graph_type::out_edge_iterator out_edge_iterator; typedef typename graph_type::in_edge_iterator in_edge_iterator; typedef typename graph_type::adjacency_iterator adjacency_iterator; // miscellaneous types typedef directed_graph_tag graph_tag; typedef typename graph_type::directed_category directed_category; typedef typename graph_type::edge_parallel_category edge_parallel_category; typedef typename graph_type::traversal_category traversal_category; typedef std::size_t vertex_index_type; typedef std::size_t edge_index_type; directed_graph(GraphProp const& p = GraphProp()) : m_graph(p) , m_num_vertices(0) , m_num_edges(0) , m_max_vertex_index(0) , m_max_edge_index(0) { } directed_graph(directed_graph const& x) : m_graph(x.m_graph) , m_num_vertices(x.m_num_vertices) , m_num_edges(x.m_num_edges) , m_max_vertex_index(x.m_max_vertex_index) , m_max_edge_index(x.m_max_edge_index) { } directed_graph(vertices_size_type n, GraphProp const& p = GraphProp()) : m_graph(n, p) , m_num_vertices(n) , m_num_edges(0) , m_max_vertex_index(n) , m_max_edge_index(0) { renumber_vertex_indices(); } template < typename EdgeIterator > directed_graph(EdgeIterator f, EdgeIterator l, vertices_size_type n, edges_size_type m = 0, GraphProp const& p = GraphProp()) : m_graph(f, l, n, m, p) , m_num_vertices(n) , m_num_edges(0) , m_max_vertex_index(n) , m_max_edge_index(0) { // Unfortunately, we have to renumber the entire graph. renumber_indices(); // Can't always guarantee that the number of edges is actually // m if distance(f, l) != m (or is undefined). m_num_edges = m_max_edge_index = boost::num_edges(m_graph); } directed_graph& operator=(directed_graph const& g) { if (&g != this) { m_graph = g.m_graph; m_num_vertices = g.m_num_vertices; m_num_edges = g.m_num_edges; m_max_vertex_index = g.m_max_vertex_index; m_max_edge_index = g.m_max_edge_index; } return *this; } // The impl_() methods are not part of the public interface. graph_type& impl() { return m_graph; } graph_type const& impl() const { return m_graph; } // The following methods are not part of the public interface vertices_size_type num_vertices() const { return m_num_vertices; } private: // This helper function manages the attribution of vertex indices. vertex_descriptor make_index(vertex_descriptor v) { boost::put(vertex_index, m_graph, v, m_max_vertex_index); m_num_vertices++; m_max_vertex_index++; return v; } public: vertex_descriptor add_vertex() { return make_index(boost::add_vertex(m_graph)); } vertex_descriptor add_vertex(vertex_property_type const& p) { return make_index( boost::add_vertex(internal_vertex_property(0u, p), m_graph)); } void clear_vertex(vertex_descriptor v) { m_num_edges -= boost::degree(v, m_graph); boost::clear_vertex(v, m_graph); } void remove_vertex(vertex_descriptor v) { boost::remove_vertex(v, m_graph); --m_num_vertices; } edges_size_type num_edges() const { return m_num_edges; } private: // A helper function for managing edge index attributes. std::pair< edge_descriptor, bool > const& make_index( std::pair< edge_descriptor, bool > const& x) { if (x.second) { boost::put(edge_index, m_graph, x.first, m_max_edge_index); ++m_num_edges; ++m_max_edge_index; } return x; } public: std::pair< edge_descriptor, bool > add_edge( vertex_descriptor u, vertex_descriptor v) { return make_index(boost::add_edge(u, v, m_graph)); } std::pair< edge_descriptor, bool > add_edge( vertex_descriptor u, vertex_descriptor v, edge_property_type const& p) { return make_index( boost::add_edge(u, v, internal_edge_property(0u, p), m_graph)); } void remove_edge(vertex_descriptor u, vertex_descriptor v) { // find all edges, (u, v) std::vector< edge_descriptor > edges; out_edge_iterator i, i_end; for (boost::tie(i, i_end) = boost::out_edges(u, m_graph); i != i_end; ++i) { if (boost::target(*i, m_graph) == v) { edges.push_back(*i); } } // remove all edges, (u, v) typename std::vector< edge_descriptor >::iterator j = edges.begin(), j_end = edges.end(); for (; j != j_end; ++j) { remove_edge(*j); } } void remove_edge(edge_iterator i) { remove_edge(*i); } void remove_edge(edge_descriptor e) { boost::remove_edge(e, m_graph); --m_num_edges; } vertex_index_type max_vertex_index() const { return m_max_vertex_index; } void renumber_vertex_indices() { vertex_iterator i, end; boost::tie(i, end) = vertices(m_graph); m_max_vertex_index = renumber_vertex_indices(i, end, 0); } void remove_vertex_and_renumber_indices(vertex_iterator i) { vertex_iterator j = next(i), end = vertices(m_graph).second; vertex_index_type n = get(vertex_index, m_graph, *i); // remove the offending vertex and renumber everything after remove_vertex(*i); m_max_vertex_index = renumber_vertex_indices(j, end, n); } edge_index_type max_edge_index() const { return m_max_edge_index; } void renumber_edge_indices() { edge_iterator i, end; boost::tie(i, end) = edges(m_graph); m_max_edge_index = renumber_edge_indices(i, end, 0); } void remove_edge_and_renumber_indices(edge_iterator i) { edge_iterator j = next(i), end = edges(m_graph).second; edge_index_type n = get(edge_index, m_graph, *i); // remove the offending edge and renumber everything after remove_edge(*i); m_max_edge_index = renumber_edge_indices(j, end, n); } void renumber_indices() { renumber_vertex_indices(); renumber_edge_indices(); } // bundled property support #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES vertex_bundled& operator[](vertex_descriptor v) { return m_graph[v]; } vertex_bundled const& operator[](vertex_descriptor v) const { return m_graph[v]; } edge_bundled& operator[](edge_descriptor e) { return m_graph[e]; } edge_bundled const& operator[](edge_descriptor e) const { return m_graph[e]; } graph_bundled& operator[](graph_bundle_t) { return get_property(*this); } graph_bundled const& operator[](graph_bundle_t) const { return get_property(*this); } #endif // Graph concepts static vertex_descriptor null_vertex() { return graph_type::null_vertex(); } void clear() { m_graph.clear(); m_num_vertices = m_max_vertex_index = 0; m_num_edges = m_max_edge_index = 0; } void swap(directed_graph& g) { m_graph.swap(g.m_graph); std::swap(m_num_vertices, g.m_num_vertices); std::swap(m_max_vertex_index, g.m_max_vertex_index); std::swap(m_num_edges, g.m_num_edges); std::swap(m_max_edge_index, g.m_max_edge_index); } private: vertices_size_type renumber_vertex_indices( vertex_iterator i, vertex_iterator end, vertices_size_type n) { typedef typename property_map< graph_type, vertex_index_t >::type IndexMap; IndexMap indices = get(vertex_index, m_graph); for (; i != end; ++i) { indices[*i] = n++; } return n; } vertices_size_type renumber_edge_indices( edge_iterator i, edge_iterator end, vertices_size_type n) { typedef typename property_map< graph_type, edge_index_t >::type IndexMap; IndexMap indices = get(edge_index, m_graph); for (; i != end; ++i) { indices[*i] = n++; } return n; } graph_type m_graph; vertices_size_type m_num_vertices; edges_size_type m_num_edges; vertex_index_type m_max_vertex_index; edge_index_type m_max_edge_index; }; #define DIRECTED_GRAPH_PARAMS typename VP, typename EP, typename GP #define DIRECTED_GRAPH directed_graph< VP, EP, GP > // IncidenceGraph concepts template < DIRECTED_GRAPH_PARAMS > inline typename DIRECTED_GRAPH::vertex_descriptor source( typename DIRECTED_GRAPH::edge_descriptor e, DIRECTED_GRAPH const& g) { return source(e, g.impl()); } template < DIRECTED_GRAPH_PARAMS > inline typename DIRECTED_GRAPH::vertex_descriptor target( typename DIRECTED_GRAPH::edge_descriptor e, DIRECTED_GRAPH const& g) { return target(e, g.impl()); } template < DIRECTED_GRAPH_PARAMS > inline typename DIRECTED_GRAPH::degree_size_type out_degree( typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH const& g) { return out_degree(v, g.impl()); } template < DIRECTED_GRAPH_PARAMS > inline std::pair< typename DIRECTED_GRAPH::out_edge_iterator, typename DIRECTED_GRAPH::out_edge_iterator > out_edges(typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH const& g) { return out_edges(v, g.impl()); } // BidirectionalGraph concepts template < DIRECTED_GRAPH_PARAMS > inline typename DIRECTED_GRAPH::degree_size_type in_degree( typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH const& g) { return in_degree(v, g.impl()); } template < DIRECTED_GRAPH_PARAMS > inline std::pair< typename DIRECTED_GRAPH::in_edge_iterator, typename DIRECTED_GRAPH::in_edge_iterator > in_edges(typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH const& g) { return in_edges(v, g.impl()); } template < DIRECTED_GRAPH_PARAMS > inline typename DIRECTED_GRAPH::degree_size_type degree( typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH const& g) { return degree(v, g.impl()); } // AdjacencyGraph concepts template < DIRECTED_GRAPH_PARAMS > inline std::pair< typename DIRECTED_GRAPH::adjacency_iterator, typename DIRECTED_GRAPH::adjacency_iterator > adjacent_vertices( typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH const& g) { return adjacent_vertices(v, g.impl()); } template < DIRECTED_GRAPH_PARAMS > typename DIRECTED_GRAPH::vertex_descriptor vertex( typename DIRECTED_GRAPH::vertices_size_type n, DIRECTED_GRAPH const& g) { return vertex(n, g.impl()); } template < DIRECTED_GRAPH_PARAMS > std::pair< typename DIRECTED_GRAPH::edge_descriptor, bool > edge( typename DIRECTED_GRAPH::vertex_descriptor u, typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH const& g) { return edge(u, v, g.impl()); } // VertexListGraph concepts template < DIRECTED_GRAPH_PARAMS > inline typename DIRECTED_GRAPH::vertices_size_type num_vertices( DIRECTED_GRAPH const& g) { return g.num_vertices(); } template < DIRECTED_GRAPH_PARAMS > inline std::pair< typename DIRECTED_GRAPH::vertex_iterator, typename DIRECTED_GRAPH::vertex_iterator > vertices(DIRECTED_GRAPH const& g) { return vertices(g.impl()); } // EdgeListGraph concepts template < DIRECTED_GRAPH_PARAMS > inline typename DIRECTED_GRAPH::edges_size_type num_edges( DIRECTED_GRAPH const& g) { return g.num_edges(); } template < DIRECTED_GRAPH_PARAMS > inline std::pair< typename DIRECTED_GRAPH::edge_iterator, typename DIRECTED_GRAPH::edge_iterator > edges(DIRECTED_GRAPH const& g) { return edges(g.impl()); } // MutableGraph concepts template < DIRECTED_GRAPH_PARAMS > inline typename DIRECTED_GRAPH::vertex_descriptor add_vertex(DIRECTED_GRAPH& g) { return g.add_vertex(); } template < DIRECTED_GRAPH_PARAMS > inline typename DIRECTED_GRAPH::vertex_descriptor add_vertex( typename DIRECTED_GRAPH::vertex_property_type const& p, DIRECTED_GRAPH& g) { return g.add_vertex(p); } template < DIRECTED_GRAPH_PARAMS > inline void clear_vertex( typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH& g) { return g.clear_vertex(v); } template < DIRECTED_GRAPH_PARAMS > inline void remove_vertex( typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH& g) { return g.remove_vertex(v); } template < DIRECTED_GRAPH_PARAMS > inline std::pair< typename DIRECTED_GRAPH::edge_descriptor, bool > add_edge( typename DIRECTED_GRAPH::vertex_descriptor u, typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH& g) { return g.add_edge(u, v); } template < DIRECTED_GRAPH_PARAMS > inline std::pair< typename DIRECTED_GRAPH::edge_descriptor, bool > add_edge( typename DIRECTED_GRAPH::vertex_descriptor u, typename DIRECTED_GRAPH::vertex_descriptor v, typename DIRECTED_GRAPH::edge_property_type const& p, DIRECTED_GRAPH& g) { return g.add_edge(u, v, p); } template < DIRECTED_GRAPH_PARAMS > inline void remove_edge(typename DIRECTED_GRAPH::vertex_descriptor u, typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH& g) { return g.remove_edge(u, v); } template < DIRECTED_GRAPH_PARAMS > inline void remove_edge( typename DIRECTED_GRAPH::edge_descriptor e, DIRECTED_GRAPH& g) { return g.remove_edge(e); } template < DIRECTED_GRAPH_PARAMS > inline void remove_edge( typename DIRECTED_GRAPH::edge_iterator i, DIRECTED_GRAPH& g) { return g.remove_edge(i); } template < DIRECTED_GRAPH_PARAMS, class Predicate > inline void remove_edge_if(Predicate pred, DIRECTED_GRAPH& g) { return remove_edge_if(pred, g.impl()); } template < DIRECTED_GRAPH_PARAMS, class Predicate > inline void remove_out_edge_if(typename DIRECTED_GRAPH::vertex_descriptor v, Predicate pred, DIRECTED_GRAPH& g) { return remove_out_edge_if(v, pred, g.impl()); } template < DIRECTED_GRAPH_PARAMS, class Predicate > inline void remove_in_edge_if(typename DIRECTED_GRAPH::vertex_descriptor v, Predicate pred, DIRECTED_GRAPH& g) { return remove_in_edge_if(v, pred, g.impl()); } template < DIRECTED_GRAPH_PARAMS, typename Property > struct property_map< DIRECTED_GRAPH, Property > : property_map< typename DIRECTED_GRAPH::graph_type, Property > { }; template < DIRECTED_GRAPH_PARAMS > struct property_map< DIRECTED_GRAPH, vertex_all_t > { typedef transform_value_property_map< detail::remove_first_property, typename property_map< typename DIRECTED_GRAPH::graph_type, vertex_all_t >::const_type > const_type; typedef transform_value_property_map< detail::remove_first_property, typename property_map< typename DIRECTED_GRAPH::graph_type, vertex_all_t >::type > type; }; template < DIRECTED_GRAPH_PARAMS > struct property_map< DIRECTED_GRAPH, edge_all_t > { typedef transform_value_property_map< detail::remove_first_property, typename property_map< typename DIRECTED_GRAPH::graph_type, edge_all_t >::const_type > const_type; typedef transform_value_property_map< detail::remove_first_property, typename property_map< typename DIRECTED_GRAPH::graph_type, edge_all_t >::type > type; }; // PropertyGraph concepts template < DIRECTED_GRAPH_PARAMS, typename Property > inline typename property_map< DIRECTED_GRAPH, Property >::type get( Property p, DIRECTED_GRAPH& g) { return get(p, g.impl()); } template < DIRECTED_GRAPH_PARAMS, typename Property > inline typename property_map< DIRECTED_GRAPH, Property >::const_type get( Property p, DIRECTED_GRAPH const& g) { return get(p, g.impl()); } template < DIRECTED_GRAPH_PARAMS > inline typename property_map< DIRECTED_GRAPH, vertex_all_t >::type get( vertex_all_t, DIRECTED_GRAPH& g) { return typename property_map< DIRECTED_GRAPH, vertex_all_t >::type( detail::remove_first_property(), get(vertex_all, g.impl())); } template < DIRECTED_GRAPH_PARAMS > inline typename property_map< DIRECTED_GRAPH, vertex_all_t >::const_type get( vertex_all_t, DIRECTED_GRAPH const& g) { return typename property_map< DIRECTED_GRAPH, vertex_all_t >::const_type( detail::remove_first_property(), get(vertex_all, g.impl())); } template < DIRECTED_GRAPH_PARAMS > inline typename property_map< DIRECTED_GRAPH, edge_all_t >::type get( edge_all_t, DIRECTED_GRAPH& g) { return typename property_map< DIRECTED_GRAPH, edge_all_t >::type( detail::remove_first_property(), get(edge_all, g.impl())); } template < DIRECTED_GRAPH_PARAMS > inline typename property_map< DIRECTED_GRAPH, edge_all_t >::const_type get( edge_all_t, DIRECTED_GRAPH const& g) { return typename property_map< DIRECTED_GRAPH, edge_all_t >::const_type( detail::remove_first_property(), get(edge_all, g.impl())); } template < DIRECTED_GRAPH_PARAMS, typename Property, typename Key > inline typename property_traits< typename property_map< typename DIRECTED_GRAPH::graph_type, Property >::const_type >::value_type get(Property p, DIRECTED_GRAPH const& g, Key const& k) { return get(p, g.impl(), k); } template < DIRECTED_GRAPH_PARAMS, typename Key > inline typename property_traits< typename property_map< typename DIRECTED_GRAPH::graph_type, vertex_all_t >::const_type >::value_type get(vertex_all_t, DIRECTED_GRAPH const& g, Key const& k) { return get(vertex_all, g.impl(), k).m_base; } template < DIRECTED_GRAPH_PARAMS, typename Key > inline typename property_traits< typename property_map< typename DIRECTED_GRAPH::graph_type, edge_all_t >::const_type >::value_type get(edge_all_t, DIRECTED_GRAPH const& g, Key const& k) { return get(edge_all, g.impl(), k).m_base; } template < DIRECTED_GRAPH_PARAMS, typename Property, typename Key, typename Value > inline void put(Property p, DIRECTED_GRAPH& g, Key const& k, Value const& v) { put(p, g.impl(), k, v); } template < DIRECTED_GRAPH_PARAMS, typename Key, typename Value > inline void put(vertex_all_t, DIRECTED_GRAPH& g, Key const& k, Value const& v) { put(vertex_all, g.impl(), k, typename DIRECTED_GRAPH::internal_vertex_property( get(vertex_index, g.impl(), k), v)); } template < DIRECTED_GRAPH_PARAMS, typename Key, typename Value > inline void put(edge_all_t, DIRECTED_GRAPH& g, Key const& k, Value const& v) { put(edge_all, g.impl(), k, typename DIRECTED_GRAPH::internal_vertex_property( get(edge_index, g.impl(), k), v)); } template < DIRECTED_GRAPH_PARAMS, class Property > typename graph_property< DIRECTED_GRAPH, Property >::type& get_property( DIRECTED_GRAPH& g, Property p) { return get_property(g.impl(), p); } template < DIRECTED_GRAPH_PARAMS, class Property > typename graph_property< DIRECTED_GRAPH, Property >::type const& get_property( DIRECTED_GRAPH const& g, Property p) { return get_property(g.impl(), p); } template < DIRECTED_GRAPH_PARAMS, class Property, class Value > void set_property(DIRECTED_GRAPH& g, Property p, Value v) { return set_property(g.impl(), p, v); } // Vertex index management template < DIRECTED_GRAPH_PARAMS > inline typename DIRECTED_GRAPH::vertex_index_type get_vertex_index( typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH const& g) { return get(vertex_index, g, v); } template < DIRECTED_GRAPH_PARAMS > typename DIRECTED_GRAPH::vertex_index_type max_vertex_index( DIRECTED_GRAPH const& g) { return g.max_vertex_index(); } template < DIRECTED_GRAPH_PARAMS > inline void renumber_vertex_indices(DIRECTED_GRAPH& g) { g.renumber_vertex_indices(); } template < DIRECTED_GRAPH_PARAMS > inline void remove_vertex_and_renumber_indices( typename DIRECTED_GRAPH::vertex_iterator i, DIRECTED_GRAPH& g) { g.remove_vertex_and_renumber_indices(i); } // Edge index management template < DIRECTED_GRAPH_PARAMS > inline typename DIRECTED_GRAPH::edge_index_type get_edge_index( typename DIRECTED_GRAPH::edge_descriptor v, DIRECTED_GRAPH const& g) { return get(edge_index, g, v); } template < DIRECTED_GRAPH_PARAMS > typename DIRECTED_GRAPH::edge_index_type max_edge_index(DIRECTED_GRAPH const& g) { return g.max_edge_index(); } template < DIRECTED_GRAPH_PARAMS > inline void renumber_edge_indices(DIRECTED_GRAPH& g) { g.renumber_edge_indices(); } template < DIRECTED_GRAPH_PARAMS > inline void remove_edge_and_renumber_indices( typename DIRECTED_GRAPH::edge_iterator i, DIRECTED_GRAPH& g) { g.remove_edge_and_renumber_indices(i); } // Index management template < DIRECTED_GRAPH_PARAMS > inline void renumber_indices(DIRECTED_GRAPH& g) { g.renumber_indices(); } // Mutability Traits template < DIRECTED_GRAPH_PARAMS > struct graph_mutability_traits< DIRECTED_GRAPH > { typedef mutable_property_graph_tag category; }; #undef DIRECTED_GRAPH_PARAMS #undef DIRECTED_GRAPH } /* namespace boost */ #endif bipartite.hpp 0000644 00000032316 15125521275 0007252 0 ustar 00 /** * * Copyright (c) 2010 Matthias Walter (xammy@xammy.homelinux.net) * * Authors: Matthias Walter * * Distributed under the Boost Software License, Version 1.0. (See * accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * */ #ifndef BOOST_GRAPH_BIPARTITE_HPP #define BOOST_GRAPH_BIPARTITE_HPP #include <utility> #include <vector> #include <exception> #include <boost/graph/properties.hpp> #include <boost/graph/adjacency_list.hpp> #include <boost/graph/depth_first_search.hpp> #include <boost/graph/one_bit_color_map.hpp> #include <boost/bind.hpp> namespace boost { namespace detail { /** * The bipartite_visitor_error is thrown if an edge cannot be colored. * The witnesses are the edges incident vertices. */ template < typename Vertex > struct BOOST_SYMBOL_VISIBLE bipartite_visitor_error : std::exception { std::pair< Vertex, Vertex > witnesses; bipartite_visitor_error(Vertex a, Vertex b) : witnesses(a, b) {} const char* what() const throw() { return "Graph is not bipartite."; } }; /** * Functor which colors edges to be non-monochromatic. */ template < typename PartitionMap > struct bipartition_colorize { typedef on_tree_edge event_filter; bipartition_colorize(PartitionMap partition_map) : partition_map_(partition_map) { } template < typename Edge, typename Graph > void operator()(Edge e, const Graph& g) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t; typedef color_traits< typename property_traits< PartitionMap >::value_type > color_traits; vertex_descriptor_t source_vertex = source(e, g); vertex_descriptor_t target_vertex = target(e, g); if (get(partition_map_, source_vertex) == color_traits::white()) put(partition_map_, target_vertex, color_traits::black()); else put(partition_map_, target_vertex, color_traits::white()); } private: PartitionMap partition_map_; }; /** * Creates a bipartition_colorize functor which colors edges * to be non-monochromatic. * * @param partition_map Color map for the bipartition * @return The functor. */ template < typename PartitionMap > inline bipartition_colorize< PartitionMap > colorize_bipartition( PartitionMap partition_map) { return bipartition_colorize< PartitionMap >(partition_map); } /** * Functor which tests an edge to be monochromatic. */ template < typename PartitionMap > struct bipartition_check { typedef on_back_edge event_filter; bipartition_check(PartitionMap partition_map) : partition_map_(partition_map) { } template < typename Edge, typename Graph > void operator()(Edge e, const Graph& g) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t; vertex_descriptor_t source_vertex = source(e, g); vertex_descriptor_t target_vertex = target(e, g); if (get(partition_map_, source_vertex) == get(partition_map_, target_vertex)) throw bipartite_visitor_error< vertex_descriptor_t >( source_vertex, target_vertex); } private: PartitionMap partition_map_; }; /** * Creates a bipartition_check functor which raises an error if a * monochromatic edge is found. * * @param partition_map The map for a bipartition. * @return The functor. */ template < typename PartitionMap > inline bipartition_check< PartitionMap > check_bipartition( PartitionMap partition_map) { return bipartition_check< PartitionMap >(partition_map); } /** * Find the beginning of a common suffix of two sequences * * @param sequence1 Pair of bidirectional iterators defining the first * sequence. * @param sequence2 Pair of bidirectional iterators defining the second * sequence. * @return Pair of iterators pointing to the beginning of the common suffix. */ template < typename BiDirectionalIterator1, typename BiDirectionalIterator2 > inline std::pair< BiDirectionalIterator1, BiDirectionalIterator2 > reverse_mismatch( std::pair< BiDirectionalIterator1, BiDirectionalIterator1 > sequence1, std::pair< BiDirectionalIterator2, BiDirectionalIterator2 > sequence2) { if (sequence1.first == sequence1.second || sequence2.first == sequence2.second) return std::make_pair(sequence1.first, sequence2.first); BiDirectionalIterator1 iter1 = sequence1.second; BiDirectionalIterator2 iter2 = sequence2.second; while (true) { --iter1; --iter2; if (*iter1 != *iter2) { ++iter1; ++iter2; break; } if (iter1 == sequence1.first) break; if (iter2 == sequence2.first) break; } return std::make_pair(iter1, iter2); } } /** * Checks a given graph for bipartiteness and fills the given color map with * white and black according to the bipartition. If the graph is not * bipartite, the contents of the color map are undefined. Runs in linear * time in the size of the graph, if access to the property maps is in * constant time. * * @param graph The given graph. * @param index_map An index map associating vertices with an index. * @param partition_map A color map to fill with the bipartition. * @return true if and only if the given graph is bipartite. */ template < typename Graph, typename IndexMap, typename PartitionMap > bool is_bipartite( const Graph& graph, const IndexMap index_map, PartitionMap partition_map) { /// General types and variables typedef typename property_traits< PartitionMap >::value_type partition_color_t; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t; /// Declare dfs visitor // detail::empty_recorder recorder; // typedef detail::bipartite_visitor <PartitionMap, // detail::empty_recorder> dfs_visitor_t; dfs_visitor_t dfs_visitor // (partition_map, recorder); /// Call dfs try { depth_first_search(graph, vertex_index_map(index_map).visitor(make_dfs_visitor( std::make_pair(detail::colorize_bipartition(partition_map), std::make_pair(detail::check_bipartition(partition_map), put_property(partition_map, color_traits< partition_color_t >::white(), on_start_vertex())))))); } catch (const detail::bipartite_visitor_error< vertex_descriptor_t >&) { return false; } return true; } /** * Checks a given graph for bipartiteness. * * @param graph The given graph. * @param index_map An index map associating vertices with an index. * @return true if and only if the given graph is bipartite. */ template < typename Graph, typename IndexMap > bool is_bipartite(const Graph& graph, const IndexMap index_map) { typedef one_bit_color_map< IndexMap > partition_map_t; partition_map_t partition_map(num_vertices(graph), index_map); return is_bipartite(graph, index_map, partition_map); } /** * Checks a given graph for bipartiteness. The graph must * have an internal vertex_index property. Runs in linear time in the * size of the graph, if access to the property maps is in constant time. * * @param graph The given graph. * @return true if and only if the given graph is bipartite. */ template < typename Graph > bool is_bipartite(const Graph& graph) { return is_bipartite(graph, get(vertex_index, graph)); } /** * Checks a given graph for bipartiteness and fills a given color map with * white and black according to the bipartition. If the graph is not * bipartite, a sequence of vertices, producing an odd-cycle, is written to * the output iterator. The final iterator value is returned. Runs in linear * time in the size of the graph, if access to the property maps is in * constant time. * * @param graph The given graph. * @param index_map An index map associating vertices with an index. * @param partition_map A color map to fill with the bipartition. * @param result An iterator to write the odd-cycle vertices to. * @return The final iterator value after writing. */ template < typename Graph, typename IndexMap, typename PartitionMap, typename OutputIterator > OutputIterator find_odd_cycle(const Graph& graph, const IndexMap index_map, PartitionMap partition_map, OutputIterator result) { /// General types and variables typedef typename property_traits< PartitionMap >::value_type partition_color_t; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; vertex_iterator_t vertex_iter, vertex_end; /// Declare predecessor map typedef std::vector< vertex_descriptor_t > predecessors_t; typedef iterator_property_map< typename predecessors_t::iterator, IndexMap, vertex_descriptor_t, vertex_descriptor_t& > predecessor_map_t; predecessors_t predecessors( num_vertices(graph), graph_traits< Graph >::null_vertex()); predecessor_map_t predecessor_map(predecessors.begin(), index_map); /// Initialize predecessor map for (boost::tie(vertex_iter, vertex_end) = vertices(graph); vertex_iter != vertex_end; ++vertex_iter) { put(predecessor_map, *vertex_iter, *vertex_iter); } /// Call dfs try { depth_first_search(graph, vertex_index_map(index_map).visitor(make_dfs_visitor( std::make_pair(detail::colorize_bipartition(partition_map), std::make_pair(detail::check_bipartition(partition_map), std::make_pair( put_property(partition_map, color_traits< partition_color_t >::white(), on_start_vertex()), record_predecessors( predecessor_map, on_tree_edge()))))))); } catch (const detail::bipartite_visitor_error< vertex_descriptor_t >& error) { typedef std::vector< vertex_descriptor_t > path_t; path_t path1, path2; vertex_descriptor_t next, current; /// First path next = error.witnesses.first; do { current = next; path1.push_back(current); next = predecessor_map[current]; } while (current != next); /// Second path next = error.witnesses.second; do { current = next; path2.push_back(current); next = predecessor_map[current]; } while (current != next); /// Find beginning of common suffix std::pair< typename path_t::iterator, typename path_t::iterator > mismatch = detail::reverse_mismatch( std::make_pair(path1.begin(), path1.end()), std::make_pair(path2.begin(), path2.end())); /// Copy the odd-length cycle result = std::copy(path1.begin(), mismatch.first + 1, result); return std::reverse_copy(path2.begin(), mismatch.second, result); } return result; } /** * Checks a given graph for bipartiteness. If the graph is not bipartite, a * sequence of vertices, producing an odd-cycle, is written to the output * iterator. The final iterator value is returned. Runs in linear time in the * size of the graph, if access to the property maps is in constant time. * * @param graph The given graph. * @param index_map An index map associating vertices with an index. * @param result An iterator to write the odd-cycle vertices to. * @return The final iterator value after writing. */ template < typename Graph, typename IndexMap, typename OutputIterator > OutputIterator find_odd_cycle( const Graph& graph, const IndexMap index_map, OutputIterator result) { typedef one_bit_color_map< IndexMap > partition_map_t; partition_map_t partition_map(num_vertices(graph), index_map); return find_odd_cycle(graph, index_map, partition_map, result); } /** * Checks a given graph for bipartiteness. If the graph is not bipartite, a * sequence of vertices, producing an odd-cycle, is written to the output * iterator. The final iterator value is returned. The graph must have an * internal vertex_index property. Runs in linear time in the size of the * graph, if access to the property maps is in constant time. * * @param graph The given graph. * @param result An iterator to write the odd-cycle vertices to. * @return The final iterator value after writing. */ template < typename Graph, typename OutputIterator > OutputIterator find_odd_cycle(const Graph& graph, OutputIterator result) { return find_odd_cycle(graph, get(vertex_index, graph), result); } } #endif /// BOOST_GRAPH_BIPARTITE_HPP stoer_wagner_min_cut.hpp 0000644 00000030177 15125521275 0011507 0 ustar 00 // Copyright Daniel Trebbien 2010. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or the copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GRAPH_STOER_WAGNER_MIN_CUT_HPP #define BOOST_GRAPH_STOER_WAGNER_MIN_CUT_HPP 1 #include <boost/assert.hpp> #include <set> #include <vector> #include <boost/concept_check.hpp> #include <boost/concept/assert.hpp> #include <boost/graph/adjacency_list.hpp> #include <boost/graph/buffer_concepts.hpp> #include <boost/graph/exception.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/maximum_adjacency_search.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/graph/one_bit_color_map.hpp> #include <boost/graph/detail/d_ary_heap.hpp> #include <boost/property_map/property_map.hpp> #include <boost/tuple/tuple.hpp> #include <boost/utility/result_of.hpp> #include <boost/graph/iteration_macros.hpp> namespace boost { namespace detail { template < typename ParityMap, typename WeightMap, typename IndexMap > class mas_min_cut_visitor : public boost::default_mas_visitor { typedef one_bit_color_map< IndexMap > InternalParityMap; typedef typename boost::property_traits< WeightMap >::value_type weight_type; public: template < typename Graph > mas_min_cut_visitor(const Graph& g, ParityMap parity, weight_type& cutweight, const WeightMap& weight_map, IndexMap index_map) : m_bestParity(parity) , m_parity(make_one_bit_color_map(num_vertices(g), index_map)) , m_bestWeight(cutweight) , m_cutweight(0) , m_visited(0) , m_weightMap(weight_map) { // set here since the init list sets the reference m_bestWeight = (std::numeric_limits< weight_type >::max)(); } template < typename Vertex, typename Graph > void initialize_vertex(Vertex u, const Graph& g) { typedef typename boost::property_traits< ParityMap >::value_type parity_type; typedef typename boost::property_traits< InternalParityMap >::value_type internal_parity_type; put(m_parity, u, internal_parity_type(0)); put(m_bestParity, u, parity_type(0)); } template < typename Edge, typename Graph > void examine_edge(Edge e, const Graph& g) { weight_type w = get(m_weightMap, e); // if the target of e is already marked then decrease cutweight // otherwise, increase it if (get(m_parity, boost::target(e, g))) { m_cutweight -= w; } else { m_cutweight += w; } } template < typename Vertex, typename Graph > void finish_vertex(Vertex u, const Graph& g) { typedef typename boost::property_traits< InternalParityMap >::value_type internal_parity_type; ++m_visited; put(m_parity, u, internal_parity_type(1)); if (m_cutweight < m_bestWeight && m_visited < num_vertices(g)) { m_bestWeight = m_cutweight; BGL_FORALL_VERTICES_T(i, g, Graph) { put(m_bestParity, i, get(m_parity, i)); } } } inline void clear() { m_bestWeight = (std::numeric_limits< weight_type >::max)(); m_visited = 0; m_cutweight = 0; } private: ParityMap m_bestParity; InternalParityMap m_parity; weight_type& m_bestWeight; weight_type m_cutweight; unsigned m_visited; const WeightMap& m_weightMap; }; /** * \brief Computes a min-cut of the input graph * * Computes a min-cut of the input graph using the Stoer-Wagner algorithm. * * \pre \p g is a connected, undirected graph * \pre <code>pq.empty()</code> * \param[in] g the input graph * \param[in] weights a readable property map from each edge to its weight * (a non-negative value) \param[out] parities a writable property map from * each vertex to a bool type object for distinguishing the two vertex sets * of the min-cut \param[out] assignments a read/write property map from * each vertex to a \c vertex_descriptor object. This map serves as work * space, and no particular meaning should be derived from property values * after completion of the algorithm. * \param[out] pq a keyed, updatable max-priority queue * \returns the cut weight of the min-cut * \see * http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.114.6687&rep=rep1&type=pdf * \see * http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.31.614&rep=rep1&type=pdf * * \author Daniel Trebbien * \date 2010-09-11 */ template < class UndirectedGraph, class WeightMap, class ParityMap, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue, class IndexMap > typename boost::property_traits< WeightMap >::value_type stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq, IndexMap index_map) { typedef typename boost::graph_traits< UndirectedGraph >::vertex_descriptor vertex_descriptor; typedef typename boost::property_traits< WeightMap >::value_type weight_type; typename graph_traits< UndirectedGraph >::vertex_iterator u_iter, u_end; weight_type bestW = (std::numeric_limits< weight_type >::max)(); weight_type bestThisTime = (std::numeric_limits< weight_type >::max)(); vertex_descriptor bestStart = boost::graph_traits< UndirectedGraph >::null_vertex(); detail::mas_min_cut_visitor< ParityMap, WeightMap, IndexMap > vis( g, parities, bestThisTime, weights, index_map); // for each node in the graph, for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) { // run the MAS and find the min cut vis.clear(); boost::maximum_adjacency_search(g, boost::weight_map(weights) .visitor(vis) .root_vertex(*u_iter) .vertex_assignment_map(assignments) .max_priority_queue(pq)); if (bestThisTime < bestW) { bestW = bestThisTime; bestStart = *u_iter; } } // Run one more time, starting from the best start location, to // ensure the visitor has the best values. vis.clear(); boost::maximum_adjacency_search(g, boost::vertex_assignment_map(assignments) .weight_map(weights) .visitor(vis) .root_vertex(bestStart) .max_priority_queue(pq)); return bestW; } } // end `namespace detail` within `namespace boost` template < class UndirectedGraph, class WeightMap, class ParityMap, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue, class IndexMap > typename boost::property_traits< WeightMap >::value_type stoer_wagner_min_cut( const UndirectedGraph& g, WeightMap weights, ParityMap parities, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq, IndexMap index_map) { BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept< UndirectedGraph >)); BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept< UndirectedGraph >)); typedef typename boost::graph_traits< UndirectedGraph >::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits< UndirectedGraph >::vertices_size_type vertices_size_type; typedef typename boost::graph_traits< UndirectedGraph >::edge_descriptor edge_descriptor; BOOST_CONCEPT_ASSERT((boost::Convertible< typename boost::graph_traits< UndirectedGraph >::directed_category, boost::undirected_tag >)); BOOST_CONCEPT_ASSERT( (boost::ReadablePropertyMapConcept< WeightMap, edge_descriptor >)); // typedef typename boost::property_traits<WeightMap>::value_type // weight_type; BOOST_CONCEPT_ASSERT( (boost::WritablePropertyMapConcept< ParityMap, vertex_descriptor >)); // typedef typename boost::property_traits<ParityMap>::value_type // parity_type; BOOST_CONCEPT_ASSERT( (boost::ReadWritePropertyMapConcept< VertexAssignmentMap, vertex_descriptor >)); BOOST_CONCEPT_ASSERT((boost::Convertible< vertex_descriptor, typename boost::property_traits< VertexAssignmentMap >::value_type >)); BOOST_CONCEPT_ASSERT( (boost::KeyedUpdatableQueueConcept< KeyedUpdatablePriorityQueue >)); vertices_size_type n = num_vertices(g); if (n < 2) throw boost::bad_graph( "the input graph must have at least two vertices."); else if (!pq.empty()) throw std::invalid_argument( "the max-priority queue must be empty initially."); return detail::stoer_wagner_min_cut( g, weights, parities, assignments, pq, index_map); } namespace graph { namespace detail { template < class UndirectedGraph, class WeightMap > struct stoer_wagner_min_cut_impl { typedef typename boost::property_traits< WeightMap >::value_type result_type; template < typename ArgPack > result_type operator()(const UndirectedGraph& g, WeightMap weights, const ArgPack& arg_pack) const { using namespace boost::graph::keywords; typedef typename boost::graph_traits< UndirectedGraph >::vertex_descriptor vertex_descriptor; typedef typename boost::property_traits< WeightMap >::value_type weight_type; typedef boost::detail::make_priority_queue_from_arg_pack_gen< boost::graph::keywords::tag::max_priority_queue, weight_type, vertex_descriptor, std::greater< weight_type > > gen_type; gen_type gen( choose_param(get_param(arg_pack, boost::distance_zero_t()), weight_type(0))); typename boost::result_of< gen_type( const UndirectedGraph&, const ArgPack&) >::type pq = gen(g, arg_pack); boost::dummy_property_map dummy_prop; return boost::stoer_wagner_min_cut(g, weights, arg_pack[_parity_map | dummy_prop], boost::detail::make_property_map_from_arg_pack_gen< tag::vertex_assignment_map, vertex_descriptor >( vertex_descriptor())(g, arg_pack), pq, boost::detail::override_const_property( arg_pack, _vertex_index_map, g, vertex_index)); } }; } BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(stoer_wagner_min_cut, 2, 4) } // Named parameter interface BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(stoer_wagner_min_cut, 2) namespace graph { // version without IndexMap kept for backwards compatibility // (but requires vertex_index_t to be defined in the graph) // Place after the macro to avoid compilation errors template < class UndirectedGraph, class WeightMap, class ParityMap, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue > typename boost::property_traits< WeightMap >::value_type stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq) { return stoer_wagner_min_cut( g, weights, parities, assignments, pq, get(vertex_index, g)); } } // end `namespace graph` } // end `namespace boost` #include <boost/graph/iteration_macros_undef.hpp> #endif // !BOOST_GRAPH_STOER_WAGNER_MIN_CUT_HPP overloading.hpp 0000644 00000003060 15125521275 0007572 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine // // This file contains helps that enable concept-based overloading // within the Boost Graph Library. // #ifndef BOOST_GRAPH_OVERLOADING_HPP #define BOOST_GRAPH_OVERLOADING_HPP #include <boost/type_traits/is_base_and_derived.hpp> #include <boost/utility/enable_if.hpp> namespace boost { namespace graph { namespace detail { struct no_parameter { }; } } } // end namespace boost::graph::detail #ifndef BOOST_NO_SFINAE #define BOOST_GRAPH_ENABLE_IF_MODELS(Graph, Tag, Type) \ typename enable_if_c< \ (is_base_and_derived< Tag, \ typename graph_traits< Graph >::traversal_category >::value), \ Type >::type #define BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, Tag) \ , \ BOOST_GRAPH_ENABLE_IF_MODELS( \ Graph, Tag, ::boost::graph::detail::no_parameter) \ = ::boost::graph::detail::no_parameter() #else #define BOOST_GRAPH_ENABLE_IF_MODELS(Graph, Tag, Type) Type #define BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, Tag) #endif // no SFINAE support #endif // BOOST_GRAPH_OVERLOADING_HPP exterior_property.hpp 0000644 00000010301 15125521275 0011062 0 ustar 00 // (C) Copyright 2007-2009 Andrew Sutton // // 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_EXTERIOR_PROPERTY_HPP #define BOOST_GRAPH_EXTERIOR_PROPERTY_HPP #include <vector> #include <boost/graph/property_maps/container_property_map.hpp> #include <boost/graph/property_maps/matrix_property_map.hpp> namespace boost { namespace detail { // The vector matrix provides a little abstraction over vector // types that makes matrices easier to work with. template < typename Value > struct vector_matrix { typedef std::vector< Value > container_type; typedef std::vector< container_type > matrix_type; typedef container_type value_type; typedef container_type& reference; typedef const container_type const_reference; typedef container_type* pointer; typedef typename matrix_type::size_type size_type; // Instantiate the matrix over n elements (creates an n by n matrix). // The graph has to be passed in order to ensure the index maps // are constructed correctly when returning indexible elements. inline vector_matrix(size_type n) : m_matrix(n, container_type(n)) {} inline reference operator[](size_type n) { return m_matrix[n]; } inline const_reference operator[](size_type n) const { return m_matrix[n]; } matrix_type m_matrix; }; } /* namespace detail */ /** * The exterior_property metafunction defines an appropriate set of types for * creating an exterior property. An exterior property is comprised of a both * a container and a property map that acts as its abstraction. An extension * of this metafunction will select an appropriate "matrix" property that * records values for pairs of vertices. * * @todo This does not currently support the ability to define exterior * properties for graph types that do not model the IndexGraph concepts. A * solution should not be especially difficult, but will require an extension * of type traits to affect the type selection. */ template < typename Graph, typename Key, typename Value > struct exterior_property { typedef Key key_type; typedef Value value_type; typedef std::vector< Value > container_type; typedef container_property_map< Graph, Key, container_type > map_type; typedef detail::vector_matrix< Value > matrix_type; typedef matrix_property_map< Graph, Key, matrix_type > matrix_map_type; private: exterior_property() {} exterior_property(const exterior_property&) {} }; /** * Define a the container and property map types requried to create an exterior * vertex property for the given value type. The Graph parameter is required to * model the VertexIndexGraph concept. */ template < typename Graph, typename Value > struct exterior_vertex_property { typedef exterior_property< Graph, typename graph_traits< Graph >::vertex_descriptor, Value > property_type; typedef typename property_type::key_type key_type; typedef typename property_type::value_type value_type; typedef typename property_type::container_type container_type; typedef typename property_type::map_type map_type; typedef typename property_type::matrix_type matrix_type; typedef typename property_type::matrix_map_type matrix_map_type; }; /** * Define a the container and property map types requried to create an exterior * edge property for the given value type. The Graph parameter is required to * model the EdgeIndexGraph concept. */ template < typename Graph, typename Value > struct exterior_edge_property { typedef exterior_property< Graph, typename graph_traits< Graph >::edge_descriptor, Value > property_type; typedef typename property_type::key_type key_type; typedef typename property_type::value_type value_type; typedef typename property_type::container_type container_type; typedef typename property_type::map_type map_type; typedef typename property_type::matrix_type matrix_type; typedef typename property_type::matrix_map_type matrix_map_type; }; } /* namespace boost */ #endif transitive_closure.hpp 0000644 00000033601 15125521275 0011211 0 ustar 00 // Copyright (C) 2001 Vladimir Prus <ghost@cs.msu.su> // Copyright (C) 2001 Jeremy Siek <jsiek@cs.indiana.edu> // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // NOTE: this final is generated by libs/graph/doc/transitive_closure.w #ifndef BOOST_GRAPH_TRANSITIVE_CLOSURE_HPP #define BOOST_GRAPH_TRANSITIVE_CLOSURE_HPP #include <vector> #include <algorithm> // for std::min and std::max #include <functional> #include <boost/config.hpp> #include <boost/bind.hpp> #include <boost/graph/strong_components.hpp> #include <boost/graph/topological_sort.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/graph/adjacency_list.hpp> #include <boost/concept/assert.hpp> namespace boost { namespace detail { inline void union_successor_sets(const std::vector< std::size_t >& s1, const std::vector< std::size_t >& s2, std::vector< std::size_t >& s3) { BOOST_USING_STD_MIN(); for (std::size_t k = 0; k < s1.size(); ++k) s3[k] = min BOOST_PREVENT_MACRO_SUBSTITUTION(s1[k], s2[k]); } } // namespace detail namespace detail { template < typename TheContainer, typename ST = std::size_t, typename VT = typename TheContainer::value_type > struct subscript_t { typedef ST argument_type; typedef VT& result_type; subscript_t(TheContainer& c) : container(&c) {} VT& operator()(const ST& i) const { return (*container)[i]; } protected: TheContainer* container; }; template < typename TheContainer > subscript_t< TheContainer > subscript(TheContainer& c) { return subscript_t< TheContainer >(c); } } // namespace detail template < typename Graph, typename GraphTC, typename G_to_TC_VertexMap, typename VertexIndexMap > void transitive_closure(const Graph& g, GraphTC& tc, G_to_TC_VertexMap g_to_tc_map, VertexIndexMap index_map) { if (num_vertices(g) == 0) return; typedef typename graph_traits< Graph >::vertex_descriptor vertex; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator; typedef typename property_traits< VertexIndexMap >::value_type size_type; typedef typename graph_traits< Graph >::adjacency_iterator adjacency_iterator; BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); BOOST_CONCEPT_ASSERT((AdjacencyGraphConcept< Graph >)); BOOST_CONCEPT_ASSERT((VertexMutableGraphConcept< GraphTC >)); BOOST_CONCEPT_ASSERT((EdgeMutableGraphConcept< GraphTC >)); BOOST_CONCEPT_ASSERT( (ReadablePropertyMapConcept< VertexIndexMap, vertex >)); typedef size_type cg_vertex; std::vector< cg_vertex > component_number_vec(num_vertices(g)); iterator_property_map< cg_vertex*, VertexIndexMap, cg_vertex, cg_vertex& > component_number(&component_number_vec[0], index_map); int num_scc = strong_components(g, component_number, vertex_index_map(index_map)); std::vector< std::vector< vertex > > components; build_component_lists(g, num_scc, component_number, components); typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS > CG_t; CG_t CG(num_scc); for (cg_vertex s = 0; s < components.size(); ++s) { std::vector< cg_vertex > adj; for (size_type i = 0; i < components[s].size(); ++i) { vertex u = components[s][i]; adjacency_iterator v, v_end; for (boost::tie(v, v_end) = adjacent_vertices(u, g); v != v_end; ++v) { cg_vertex t = component_number[*v]; if (s != t) // Avoid loops in the condensation graph adj.push_back(t); } } std::sort(adj.begin(), adj.end()); typename std::vector< cg_vertex >::iterator di = std::unique(adj.begin(), adj.end()); if (di != adj.end()) adj.erase(di, adj.end()); for (typename std::vector< cg_vertex >::const_iterator i = adj.begin(); i != adj.end(); ++i) { add_edge(s, *i, CG); } } std::vector< cg_vertex > topo_order; std::vector< cg_vertex > topo_number(num_vertices(CG)); topological_sort(CG, std::back_inserter(topo_order), vertex_index_map(identity_property_map())); std::reverse(topo_order.begin(), topo_order.end()); size_type n = 0; for (typename std::vector< cg_vertex >::iterator iter = topo_order.begin(); iter != topo_order.end(); ++iter) topo_number[*iter] = n++; std::vector< std::vector< cg_vertex > > CG_vec(num_vertices(CG)); for (size_type i = 0; i < num_vertices(CG); ++i) { typedef typename boost::graph_traits< CG_t >::adjacency_iterator cg_adj_iter; std::pair< cg_adj_iter, cg_adj_iter > pr = adjacent_vertices(i, CG); CG_vec[i].assign(pr.first, pr.second); std::sort(CG_vec[i].begin(), CG_vec[i].end(), boost::bind(std::less< cg_vertex >(), boost::bind(detail::subscript(topo_number), _1), boost::bind(detail::subscript(topo_number), _2))); } std::vector< std::vector< cg_vertex > > chains; { std::vector< cg_vertex > in_a_chain(CG_vec.size()); for (typename std::vector< cg_vertex >::iterator i = topo_order.begin(); i != topo_order.end(); ++i) { cg_vertex v = *i; if (!in_a_chain[v]) { chains.resize(chains.size() + 1); std::vector< cg_vertex >& chain = chains.back(); for (;;) { chain.push_back(v); in_a_chain[v] = true; typename std::vector< cg_vertex >::const_iterator next = std::find_if(CG_vec[v].begin(), CG_vec[v].end(), std::not1(detail::subscript(in_a_chain))); if (next != CG_vec[v].end()) v = *next; else break; // end of chain, dead-end } } } } std::vector< size_type > chain_number(CG_vec.size()); std::vector< size_type > pos_in_chain(CG_vec.size()); for (size_type i = 0; i < chains.size(); ++i) for (size_type j = 0; j < chains[i].size(); ++j) { cg_vertex v = chains[i][j]; chain_number[v] = i; pos_in_chain[v] = j; } cg_vertex inf = (std::numeric_limits< cg_vertex >::max)(); std::vector< std::vector< cg_vertex > > successors( CG_vec.size(), std::vector< cg_vertex >(chains.size(), inf)); for (typename std::vector< cg_vertex >::reverse_iterator i = topo_order.rbegin(); i != topo_order.rend(); ++i) { cg_vertex u = *i; typename std::vector< cg_vertex >::const_iterator adj, adj_last; for (adj = CG_vec[u].begin(), adj_last = CG_vec[u].end(); adj != adj_last; ++adj) { cg_vertex v = *adj; if (topo_number[v] < successors[u][chain_number[v]]) { // Succ(u) = Succ(u) U Succ(v) detail::union_successor_sets( successors[u], successors[v], successors[u]); // Succ(u) = Succ(u) U {v} successors[u][chain_number[v]] = topo_number[v]; } } } for (size_type i = 0; i < CG_vec.size(); ++i) CG_vec[i].clear(); for (size_type i = 0; i < CG_vec.size(); ++i) for (size_type j = 0; j < chains.size(); ++j) { size_type topo_num = successors[i][j]; if (topo_num < inf) { cg_vertex v = topo_order[topo_num]; for (size_type k = pos_in_chain[v]; k < chains[j].size(); ++k) CG_vec[i].push_back(chains[j][k]); } } // Add vertices to the transitive closure graph { vertex_iterator i, i_end; for (boost::tie(i, i_end) = vertices(g); i != i_end; ++i) g_to_tc_map[*i] = add_vertex(tc); } // Add edges between all the vertices in two adjacent SCCs typename std::vector< std::vector< cg_vertex > >::const_iterator si, si_end; for (si = CG_vec.begin(), si_end = CG_vec.end(); si != si_end; ++si) { cg_vertex s = si - CG_vec.begin(); typename std::vector< cg_vertex >::const_iterator i, i_end; for (i = CG_vec[s].begin(), i_end = CG_vec[s].end(); i != i_end; ++i) { cg_vertex t = *i; for (size_type k = 0; k < components[s].size(); ++k) for (size_type l = 0; l < components[t].size(); ++l) add_edge(g_to_tc_map[components[s][k]], g_to_tc_map[components[t][l]], tc); } } // Add edges connecting all vertices in a SCC for (size_type i = 0; i < components.size(); ++i) if (components[i].size() > 1) for (size_type k = 0; k < components[i].size(); ++k) for (size_type l = 0; l < components[i].size(); ++l) { vertex u = components[i][k], v = components[i][l]; add_edge(g_to_tc_map[u], g_to_tc_map[v], tc); } // Find loopbacks in the original graph. // Need to add it to transitive closure. { vertex_iterator i, i_end; for (boost::tie(i, i_end) = vertices(g); i != i_end; ++i) { adjacency_iterator ab, ae; for (boost::tie(ab, ae) = adjacent_vertices(*i, g); ab != ae; ++ab) { if (*ab == *i) if (components[component_number[*i]].size() == 1) add_edge(g_to_tc_map[*i], g_to_tc_map[*i], tc); } } } } template < typename Graph, typename GraphTC > void transitive_closure(const Graph& g, GraphTC& tc) { if (num_vertices(g) == 0) return; typedef typename property_map< Graph, vertex_index_t >::const_type VertexIndexMap; VertexIndexMap index_map = get(vertex_index, g); typedef typename graph_traits< GraphTC >::vertex_descriptor tc_vertex; std::vector< tc_vertex > to_tc_vec(num_vertices(g)); iterator_property_map< tc_vertex*, VertexIndexMap, tc_vertex, tc_vertex& > g_to_tc_map(&to_tc_vec[0], index_map); transitive_closure(g, tc, g_to_tc_map, index_map); } namespace detail { template < typename Graph, typename GraphTC, typename G_to_TC_VertexMap, typename VertexIndexMap > void transitive_closure_dispatch(const Graph& g, GraphTC& tc, G_to_TC_VertexMap g_to_tc_map, VertexIndexMap index_map) { typedef typename graph_traits< GraphTC >::vertex_descriptor tc_vertex; typename std::vector< tc_vertex >::size_type n = is_default_param(g_to_tc_map) ? num_vertices(g) : 1; std::vector< tc_vertex > to_tc_vec(n); transitive_closure(g, tc, choose_param(g_to_tc_map, make_iterator_property_map( to_tc_vec.begin(), index_map, to_tc_vec[0])), index_map); } } // namespace detail template < typename Graph, typename GraphTC, typename P, typename T, typename R > void transitive_closure( const Graph& g, GraphTC& tc, const bgl_named_params< P, T, R >& params) { if (num_vertices(g) == 0) return; detail::transitive_closure_dispatch(g, tc, get_param(params, orig_to_copy_t()), choose_const_pmap(get_param(params, vertex_index), g, vertex_index)); } template < typename G > void warshall_transitive_closure(G& g) { typedef typename graph_traits< G >::vertex_iterator vertex_iterator; BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< G >)); BOOST_CONCEPT_ASSERT((EdgeMutableGraphConcept< G >)); // Matrix form: // for k // for i // if A[i,k] // for j // A[i,j] = A[i,j] | A[k,j] vertex_iterator ki, ke, ii, ie, ji, je; for (boost::tie(ki, ke) = vertices(g); ki != ke; ++ki) for (boost::tie(ii, ie) = vertices(g); ii != ie; ++ii) if (edge(*ii, *ki, g).second) for (boost::tie(ji, je) = vertices(g); ji != je; ++ji) if (!edge(*ii, *ji, g).second && edge(*ki, *ji, g).second) { add_edge(*ii, *ji, g); } } template < typename G > void warren_transitive_closure(G& g) { using namespace boost; typedef typename graph_traits< G >::vertex_iterator vertex_iterator; BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< G >)); BOOST_CONCEPT_ASSERT((EdgeMutableGraphConcept< G >)); // Make sure second loop will work if (num_vertices(g) == 0) return; // for i = 2 to n // for k = 1 to i - 1 // if A[i,k] // for j = 1 to n // A[i,j] = A[i,j] | A[k,j] vertex_iterator ic, ie, jc, je, kc, ke; for (boost::tie(ic, ie) = vertices(g), ++ic; ic != ie; ++ic) for (boost::tie(kc, ke) = vertices(g); *kc != *ic; ++kc) if (edge(*ic, *kc, g).second) for (boost::tie(jc, je) = vertices(g); jc != je; ++jc) if (!edge(*ic, *jc, g).second && edge(*kc, *jc, g).second) { add_edge(*ic, *jc, g); } // for i = 1 to n - 1 // for k = i + 1 to n // if A[i,k] // for j = 1 to n // A[i,j] = A[i,j] | A[k,j] for (boost::tie(ic, ie) = vertices(g), --ie; ic != ie; ++ic) for (kc = ic, ke = ie, ++kc; kc != ke; ++kc) if (edge(*ic, *kc, g).second) for (boost::tie(jc, je) = vertices(g); jc != je; ++jc) if (!edge(*ic, *jc, g).second && edge(*kc, *jc, g).second) { add_edge(*ic, *jc, g); } } } // namespace boost #endif // BOOST_GRAPH_TRANSITIVE_CLOSURE_HPP metis.hpp 0000644 00000025346 15125521275 0006415 0 ustar 00 // Copyright 2005 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_METIS_HPP #define BOOST_GRAPH_METIS_HPP #ifdef BOOST_GRAPH_METIS_NO_INLINE #define BOOST_GRAPH_METIS_INLINE_KEYWORD #else #define BOOST_GRAPH_METIS_INLINE_KEYWORD inline #endif #include <string> #include <iostream> #include <iterator> #include <utility> #include <sstream> #include <exception> #include <vector> #include <algorithm> namespace boost { namespace graph { class BOOST_SYMBOL_VISIBLE metis_exception : public std::exception { }; class BOOST_SYMBOL_VISIBLE metis_input_exception : public metis_exception { }; class metis_reader { public: typedef std::size_t vertices_size_type; typedef std::size_t edges_size_type; typedef double vertex_weight_type; typedef double edge_weight_type; class edge_iterator { public: typedef std::input_iterator_tag iterator_category; typedef std::pair< vertices_size_type, vertices_size_type > value_type; typedef const value_type& reference; typedef const value_type* pointer; typedef std::ptrdiff_t difference_type; private: class postincrement_proxy { postincrement_proxy(const value_type& value) : value(value) {} public: reference operator*() const { return value; } private: value_type value; friend class edge_iterator; }; public: edge_iterator& operator++(); postincrement_proxy operator++(int); reference operator*() const { return self->edge; } pointer operator->() const { return &self->edge; } // Default copy constructor and assignment operator are okay private: edge_iterator(metis_reader* self); void advance(bool skip_initial_read); metis_reader* self; friend class metis_reader; friend bool operator==(edge_iterator, edge_iterator); friend bool operator!=(edge_iterator, edge_iterator); }; friend class edge_iterator; class edge_weight_iterator { public: typedef std::input_iterator_tag iterator_category; typedef edge_weight_type value_type; typedef const value_type& reference; typedef const value_type* pointer; // Default copy constructor and assignment operator are okay reference operator*() const { return self->edge_weight; } pointer operator->() const { return &self->edge_weight; } edge_weight_iterator& operator++() { return *this; } edge_weight_iterator operator++(int) { return *this; } private: edge_weight_iterator(metis_reader* self) : self(self) {} metis_reader* self; friend class metis_reader; }; metis_reader(std::istream& in) : in(in), edge_weight(1.0) { start(); } edge_iterator begin(); edge_iterator end(); edge_weight_iterator weight_begin(); vertices_size_type num_vertices() const { return n_vertices; } edges_size_type num_edges() const { return n_edges; } std::size_t num_vertex_weights() const { return n_vertex_weights; } vertex_weight_type vertex_weight(vertices_size_type v, std::size_t n) { return vertex_weights[v * num_vertex_weights() + n]; } bool has_edge_weights() const { return edge_weights; } private: void start(); // Configuration information std::istream& in; // Information about the current METIS file vertices_size_type n_vertices; edges_size_type n_edges; std::size_t n_vertex_weights; bool edge_weights; // Information about the current edge/vertex std::istringstream line_in; std::pair< vertices_size_type, vertices_size_type > edge; std::vector< vertex_weight_type > vertex_weights; edge_weight_type edge_weight; friend bool operator==(edge_iterator, edge_iterator); friend bool operator!=(edge_iterator, edge_iterator); }; class metis_distribution { public: typedef int process_id_type; typedef std::size_t size_type; typedef std::vector< process_id_type >::iterator iterator; metis_distribution(std::istream& in, process_id_type my_id); size_type block_size(process_id_type id, size_type) const; process_id_type operator()(size_type n) const { return vertices[n]; } size_type local(size_type n) const; size_type global(size_type n) const { return global(my_id, n); } size_type global(process_id_type id, size_type n) const; iterator begin() { return vertices.begin(); } iterator end() { return vertices.end(); } private: process_id_type my_id; std::vector< process_id_type > vertices; }; #if !defined(BOOST_GRAPH_METIS_NO_INLINE) || defined(BOOST_GRAPH_METIS_SOURCE) BOOST_GRAPH_METIS_INLINE_KEYWORD bool operator==( metis_reader::edge_iterator x, metis_reader::edge_iterator y) { return (x.self == y.self || (x.self && x.self->edge.first == x.self->num_vertices()) || (y.self && y.self->edge.first == y.self->num_vertices())); } BOOST_GRAPH_METIS_INLINE_KEYWORD bool operator!=( metis_reader::edge_iterator x, metis_reader::edge_iterator y) { return !(x == y); } BOOST_GRAPH_METIS_INLINE_KEYWORD metis_reader::edge_iterator::edge_iterator(metis_reader* self) : self(self) { if (self) advance(true); } BOOST_GRAPH_METIS_INLINE_KEYWORD metis_reader::edge_iterator& metis_reader::edge_iterator::operator++() { advance(false); return *this; } BOOST_GRAPH_METIS_INLINE_KEYWORD void metis_reader::edge_iterator::advance(bool skip_initial_read) { do { if (!skip_initial_read) { // Try to read the next edge if (self->line_in >> std::ws >> self->edge.second) { --self->edge.second; if (self->has_edge_weights()) { if (!(self->line_in >> self->edge_weight)) boost::throw_exception(metis_input_exception()); } return; } // Check if we're done ++self->edge.first; if (self->edge.first == self->num_vertices()) return; } // Find the next line std::string line; while (getline(self->in, line) && !line.empty() && line[0] == '%') { /* Keep reading lines in the loop header... */ } if (!self->in) boost::throw_exception(metis_input_exception()); self->line_in.str(line); self->line_in.clear(); // Read the next line std::size_t weights_left = self->n_vertex_weights; vertex_weight_type weight; while (weights_left > 0) { if (self->line_in >> weight) self->vertex_weights.push_back(weight); else boost::throw_exception(metis_input_exception()); --weights_left; } // Successive iterations will pick up edges for this vertex. skip_initial_read = false; } while (true); } BOOST_GRAPH_METIS_INLINE_KEYWORD metis_reader::edge_iterator::postincrement_proxy metis_reader::edge_iterator::operator++(int) { postincrement_proxy result(**this); ++(*this); return result; } BOOST_GRAPH_METIS_INLINE_KEYWORD metis_reader::edge_iterator metis_reader::begin() { if (edge.first != 0) start(); return edge_iterator(this); } BOOST_GRAPH_METIS_INLINE_KEYWORD metis_reader::edge_iterator metis_reader::end() { return edge_iterator(0); } BOOST_GRAPH_METIS_INLINE_KEYWORD metis_reader::edge_weight_iterator metis_reader::weight_begin() { return edge_weight_iterator(this); } BOOST_GRAPH_METIS_INLINE_KEYWORD void metis_reader::start() { in.seekg(0, std::ios::beg); std::string line; while (getline(in, line) && !line.empty() && line[0] == '%') { /* Keep getting lines in loop header. */ } if (!in || line.empty()) boost::throw_exception(metis_input_exception()); // Determine number of vertices and edges in the graph line_in.str(line); if (!(line_in >> n_vertices >> n_edges)) boost::throw_exception(metis_input_exception()); // Determine whether vertex or edge weights are included in the graph int fmt = 0; line_in >> fmt; n_vertex_weights = fmt / 10; edge_weights = (fmt % 10 == 1); // Determine how many (if any!) vertex weights are included if (n_vertex_weights) line_in >> n_vertex_weights; // Setup the iteration data structures edge_weight = 1.0; edge.first = 0; edge.second = 0; vertex_weights.reserve(n_vertex_weights * num_vertices()); } metis_distribution::metis_distribution( std::istream& in, process_id_type my_id) : my_id(my_id) , vertices(std::istream_iterator< process_id_type >(in), std::istream_iterator< process_id_type >()) { } metis_distribution::size_type metis_distribution::block_size( process_id_type id, size_type) const { return std::count(vertices.begin(), vertices.end(), id); } metis_distribution::size_type metis_distribution::local(size_type n) const { return std::count(vertices.begin(), vertices.begin() + n, vertices[n]); } metis_distribution::size_type metis_distribution::global( process_id_type id, size_type n) const { std::vector< process_id_type >::const_iterator i = vertices.begin(); while (*i != id) ++i; while (n > 0) { do { ++i; } while (*i != id); --n; } return i - vertices.begin(); } #endif } } // end namespace boost::graph #endif // BOOST_GRAPH_METIS_HPP use_mpi.hpp 0000644 00000000665 15125521275 0006732 0 ustar 00 // Copyright (C) 2004-2009 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Nick Edmonds // Andrew Lumsdaine #ifndef BOOST_GRAPH_USE_MPI_HPP #define BOOST_GRAPH_USE_MPI_HPP #define BOOST_GRAPH_USE_MPI #endif // BOOST_GRAPH_USE_MPI_HPP fruchterman_reingold.hpp 0000644 00000041665 15125521275 0011477 0 ustar 00 // Copyright 2004, 2005 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_FRUCHTERMAN_REINGOLD_FORCE_DIRECTED_LAYOUT_HPP #define BOOST_GRAPH_FRUCHTERMAN_REINGOLD_FORCE_DIRECTED_LAYOUT_HPP #include <boost/config/no_tr1/cmath.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/graph/topology.hpp> // For topology concepts #include <boost/graph/detail/mpi_include.hpp> #include <vector> #include <list> #include <algorithm> // for std::min and std::max #include <numeric> // for std::accumulate #include <cmath> // for std::sqrt and std::fabs #include <functional> namespace boost { struct square_distance_attractive_force { template < typename Graph, typename T > T operator()(typename graph_traits< Graph >::edge_descriptor, T k, T d, const Graph&) const { return d * d / k; } }; struct square_distance_repulsive_force { template < typename Graph, typename T > T operator()(typename graph_traits< Graph >::vertex_descriptor, typename graph_traits< Graph >::vertex_descriptor, T k, T d, const Graph&) const { return k * k / d; } }; template < typename T > struct linear_cooling { typedef T result_type; linear_cooling(std::size_t iterations) : temp(T(iterations) / T(10)), step(0.1) { } linear_cooling(std::size_t iterations, T temp) : temp(temp), step(temp / T(iterations)) { } T operator()() { T old_temp = temp; temp -= step; if (temp < T(0)) temp = T(0); return old_temp; } private: T temp; T step; }; struct all_force_pairs { template < typename Graph, typename ApplyForce > void operator()(const Graph& g, ApplyForce apply_force) { typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator; vertex_iterator v, end; for (boost::tie(v, end) = vertices(g); v != end; ++v) { vertex_iterator u = v; for (++u; u != end; ++u) { apply_force(*u, *v); apply_force(*v, *u); } } } }; template < typename Topology, typename PositionMap > struct grid_force_pairs { typedef typename property_traits< PositionMap >::value_type Point; BOOST_STATIC_ASSERT(Point::dimensions == 2); typedef typename Topology::point_difference_type point_difference_type; template < typename Graph > explicit grid_force_pairs( const Topology& topology, PositionMap position, const Graph& g) : topology(topology), position(position) { two_k = 2. * this->topology.volume(this->topology.extent()) / std::sqrt((double)num_vertices(g)); } template < typename Graph, typename ApplyForce > void operator()(const Graph& g, ApplyForce apply_force) { typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; typedef std::list< vertex_descriptor > bucket_t; typedef std::vector< bucket_t > buckets_t; std::size_t columns = std::size_t(topology.extent()[0] / two_k + 1.); std::size_t rows = std::size_t(topology.extent()[1] / two_k + 1.); buckets_t buckets(rows * columns); vertex_iterator v, v_end; for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) { std::size_t column = std::size_t( (get(position, *v)[0] + topology.extent()[0] / 2) / two_k); std::size_t row = std::size_t( (get(position, *v)[1] + topology.extent()[1] / 2) / two_k); if (column >= columns) column = columns - 1; if (row >= rows) row = rows - 1; buckets[row * columns + column].push_back(*v); } for (std::size_t row = 0; row < rows; ++row) for (std::size_t column = 0; column < columns; ++column) { bucket_t& bucket = buckets[row * columns + column]; typedef typename bucket_t::iterator bucket_iterator; for (bucket_iterator u = bucket.begin(); u != bucket.end(); ++u) { // Repulse vertices in this bucket bucket_iterator v = u; for (++v; v != bucket.end(); ++v) { apply_force(*u, *v); apply_force(*v, *u); } std::size_t adj_start_row = row == 0 ? 0 : row - 1; std::size_t adj_end_row = row == rows - 1 ? row : row + 1; std::size_t adj_start_column = column == 0 ? 0 : column - 1; std::size_t adj_end_column = column == columns - 1 ? column : column + 1; for (std::size_t other_row = adj_start_row; other_row <= adj_end_row; ++other_row) for (std::size_t other_column = adj_start_column; other_column <= adj_end_column; ++other_column) if (other_row != row || other_column != column) { // Repulse vertices in this bucket bucket_t& other_bucket = buckets[other_row * columns + other_column]; for (v = other_bucket.begin(); v != other_bucket.end(); ++v) { double dist = topology.distance( get(position, *u), get(position, *v)); if (dist < two_k) apply_force(*u, *v); } } } } } private: const Topology& topology; PositionMap position; double two_k; }; template < typename PositionMap, typename Topology, typename Graph > inline grid_force_pairs< Topology, PositionMap > make_grid_force_pairs( const Topology& topology, const PositionMap& position, const Graph& g) { return grid_force_pairs< Topology, PositionMap >(topology, position, g); } template < typename Graph, typename PositionMap, typename Topology > void scale_graph(const Graph& g, PositionMap position, const Topology& topology, typename Topology::point_type upper_left, typename Topology::point_type lower_right) { if (num_vertices(g) == 0) return; typedef typename Topology::point_type Point; typedef typename Topology::point_difference_type point_difference_type; // Find min/max ranges Point min_point = get(position, *vertices(g).first), max_point = min_point; BGL_FORALL_VERTICES_T(v, g, Graph) { min_point = topology.pointwise_min(min_point, get(position, v)); max_point = topology.pointwise_max(max_point, get(position, v)); } Point old_origin = topology.move_position_toward(min_point, 0.5, max_point); Point new_origin = topology.move_position_toward(upper_left, 0.5, lower_right); point_difference_type old_size = topology.difference(max_point, min_point); point_difference_type new_size = topology.difference(lower_right, upper_left); // Scale to bounding box provided BGL_FORALL_VERTICES_T(v, g, Graph) { point_difference_type relative_loc = topology.difference(get(position, v), old_origin); relative_loc = (relative_loc / old_size) * new_size; put(position, v, topology.adjust(new_origin, relative_loc)); } } namespace detail { template < typename Topology, typename PropMap, typename Vertex > void maybe_jitter_point(const Topology& topology, const PropMap& pm, Vertex v, const typename Topology::point_type& p2) { double too_close = topology.norm(topology.extent()) / 10000.; if (topology.distance(get(pm, v), p2) < too_close) { put(pm, v, topology.move_position_toward( get(pm, v), 1. / 200, topology.random_point())); } } template < typename Topology, typename PositionMap, typename DisplacementMap, typename RepulsiveForce, typename Graph > struct fr_apply_force { typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; typedef typename Topology::point_type Point; typedef typename Topology::point_difference_type PointDiff; fr_apply_force(const Topology& topology, const PositionMap& position, const DisplacementMap& displacement, RepulsiveForce repulsive_force, double k, const Graph& g) : topology(topology) , position(position) , displacement(displacement) , repulsive_force(repulsive_force) , k(k) , g(g) { } void operator()(vertex_descriptor u, vertex_descriptor v) { if (u != v) { // When the vertices land on top of each other, move the // first vertex away from the boundaries. maybe_jitter_point(topology, position, u, get(position, v)); double dist = topology.distance(get(position, u), get(position, v)); typename Topology::point_difference_type dispv = get(displacement, v); if (dist == 0.) { for (std::size_t i = 0; i < Point::dimensions; ++i) { dispv[i] += 0.01; } } else { double fr = repulsive_force(u, v, k, dist, g); dispv += (fr / dist) * topology.difference( get(position, v), get(position, u)); } put(displacement, v, dispv); } } private: const Topology& topology; PositionMap position; DisplacementMap displacement; RepulsiveForce repulsive_force; double k; const Graph& g; }; } // end namespace detail template < typename Topology, typename Graph, typename PositionMap, typename AttractiveForce, typename RepulsiveForce, typename ForcePairs, typename Cooling, typename DisplacementMap > void fruchterman_reingold_force_directed_layout(const Graph& g, PositionMap position, const Topology& topology, AttractiveForce attractive_force, RepulsiveForce repulsive_force, ForcePairs force_pairs, Cooling cool, DisplacementMap displacement) { typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; typedef typename graph_traits< Graph >::edge_iterator edge_iterator; double volume = topology.volume(topology.extent()); // assume positions are initialized randomly double k = pow(volume / num_vertices(g), 1. / (double)(Topology::point_difference_type::dimensions)); detail::fr_apply_force< Topology, PositionMap, DisplacementMap, RepulsiveForce, Graph > apply_force(topology, position, displacement, repulsive_force, k, g); do { // Calculate repulsive forces vertex_iterator v, v_end; for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) put(displacement, *v, typename Topology::point_difference_type()); force_pairs(g, apply_force); // Calculate attractive forces edge_iterator e, e_end; for (boost::tie(e, e_end) = edges(g); e != e_end; ++e) { vertex_descriptor v = source(*e, g); vertex_descriptor u = target(*e, g); // When the vertices land on top of each other, move the // first vertex away from the boundaries. ::boost::detail::maybe_jitter_point( topology, position, u, get(position, v)); typename Topology::point_difference_type delta = topology.difference(get(position, v), get(position, u)); double dist = topology.distance(get(position, u), get(position, v)); double fa = attractive_force(*e, k, dist, g); put(displacement, v, get(displacement, v) - (fa / dist) * delta); put(displacement, u, get(displacement, u) + (fa / dist) * delta); } if (double temp = cool()) { // Update positions BGL_FORALL_VERTICES_T(v, g, Graph) { BOOST_USING_STD_MIN(); BOOST_USING_STD_MAX(); double disp_size = topology.norm(get(displacement, v)); put(position, v, topology.adjust(get(position, v), get(displacement, v) * (min BOOST_PREVENT_MACRO_SUBSTITUTION( disp_size, temp) / disp_size))); put(position, v, topology.bound(get(position, v))); } } else { break; } } while (true); } namespace detail { template < typename DisplacementMap > struct fr_force_directed_layout { template < typename Topology, typename Graph, typename PositionMap, typename AttractiveForce, typename RepulsiveForce, typename ForcePairs, typename Cooling, typename Param, typename Tag, typename Rest > static void run(const Graph& g, PositionMap position, const Topology& topology, AttractiveForce attractive_force, RepulsiveForce repulsive_force, ForcePairs force_pairs, Cooling cool, DisplacementMap displacement, const bgl_named_params< Param, Tag, Rest >&) { fruchterman_reingold_force_directed_layout(g, position, topology, attractive_force, repulsive_force, force_pairs, cool, displacement); } }; template <> struct fr_force_directed_layout< param_not_found > { template < typename Topology, typename Graph, typename PositionMap, typename AttractiveForce, typename RepulsiveForce, typename ForcePairs, typename Cooling, typename Param, typename Tag, typename Rest > static void run(const Graph& g, PositionMap position, const Topology& topology, AttractiveForce attractive_force, RepulsiveForce repulsive_force, ForcePairs force_pairs, Cooling cool, param_not_found, const bgl_named_params< Param, Tag, Rest >& params) { typedef typename Topology::point_difference_type PointDiff; std::vector< PointDiff > displacements(num_vertices(g)); fruchterman_reingold_force_directed_layout(g, position, topology, attractive_force, repulsive_force, force_pairs, cool, make_iterator_property_map(displacements.begin(), choose_const_pmap( get_param(params, vertex_index), g, vertex_index), PointDiff())); } }; } // end namespace detail template < typename Topology, typename Graph, typename PositionMap, typename Param, typename Tag, typename Rest > void fruchterman_reingold_force_directed_layout(const Graph& g, PositionMap position, const Topology& topology, const bgl_named_params< Param, Tag, Rest >& params) { typedef typename get_param_type< vertex_displacement_t, bgl_named_params< Param, Tag, Rest > >::type D; detail::fr_force_directed_layout< D >::run(g, position, topology, choose_param(get_param(params, attractive_force_t()), square_distance_attractive_force()), choose_param(get_param(params, repulsive_force_t()), square_distance_repulsive_force()), choose_param(get_param(params, force_pairs_t()), make_grid_force_pairs(topology, position, g)), choose_param( get_param(params, cooling_t()), linear_cooling< double >(100)), get_param(params, vertex_displacement_t()), params); } template < typename Topology, typename Graph, typename PositionMap > void fruchterman_reingold_force_directed_layout( const Graph& g, PositionMap position, const Topology& topology) { fruchterman_reingold_force_directed_layout(g, position, topology, attractive_force(square_distance_attractive_force())); } } // end namespace boost #include BOOST_GRAPH_MPI_INCLUDE(< boost / graph / distributed / fruchterman_reingold.hpp >) #endif // BOOST_GRAPH_FRUCHTERMAN_REINGOLD_FORCE_DIRECTED_LAYOUT_HPP circle_layout.hpp 0000644 00000003604 15125521275 0010123 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_CIRCLE_LAYOUT_HPP #define BOOST_GRAPH_CIRCLE_LAYOUT_HPP #include <boost/config/no_tr1/cmath.hpp> #include <boost/math/constants/constants.hpp> #include <utility> #include <boost/graph/graph_traits.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/graph/topology.hpp> #include <boost/static_assert.hpp> namespace boost { /** * \brief Layout the graph with the vertices at the points of a regular * n-polygon. * * The distance from the center of the polygon to each point is * determined by the @p radius parameter. The @p position parameter * must be an Lvalue Property Map whose value type is a class type * containing @c x and @c y members that will be set to the @c x and * @c y coordinates. */ template < typename VertexListGraph, typename PositionMap, typename Radius > void circle_graph_layout( const VertexListGraph& g, PositionMap position, Radius radius) { BOOST_STATIC_ASSERT( property_traits< PositionMap >::value_type::dimensions >= 2); const double pi = boost::math::constants::pi< double >(); #ifndef BOOST_NO_STDC_NAMESPACE using std::cos; using std::sin; #endif // BOOST_NO_STDC_NAMESPACE typedef typename graph_traits< VertexListGraph >::vertices_size_type vertices_size_type; vertices_size_type n = num_vertices(g); vertices_size_type i = 0; double two_pi_over_n = 2. * pi / n; BGL_FORALL_VERTICES_T(v, g, VertexListGraph) { position[v][0] = radius * cos(i * two_pi_over_n); position[v][1] = radius * sin(i * two_pi_over_n); ++i; } } } // end namespace boost #endif // BOOST_GRAPH_CIRCLE_LAYOUT_HPP undirected_graph.hpp 0000644 00000061274 15125521275 0010603 0 ustar 00 // (C) Copyright 2007-2009 Andrew Sutton // // 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_UNDIRECTED_GRAPH_HPP #define BOOST_GRAPH_UNDIRECTED_GRAPH_HPP #include <boost/graph/adjacency_list.hpp> #include <boost/graph/properties.hpp> #include <boost/pending/property.hpp> #include <boost/property_map/transform_value_property_map.hpp> #include <boost/type_traits.hpp> #include <boost/mpl/if.hpp> namespace boost { struct undirected_graph_tag { }; /** * The undirected_graph class template is a simplified version of the BGL * adjacency list. This class is provided for ease of use, but may not * perform as well as custom-defined adjacency list classes. Instances of * this template model the VertexIndexGraph, and EdgeIndexGraph concepts. The * graph is also fully mutable, supporting both insertions and removals of * vertices and edges. * * @note Special care must be taken when removing vertices or edges since * those operations can invalidate the numbering of vertices. */ template < typename VertexProp = no_property, typename EdgeProp = no_property, typename GraphProp = no_property > class undirected_graph { public: typedef GraphProp graph_property_type; typedef VertexProp vertex_property_type; typedef EdgeProp edge_property_type; typedef typename lookup_one_property< GraphProp, graph_bundle_t >::type graph_bundled; typedef typename lookup_one_property< VertexProp, vertex_bundle_t >::type vertex_bundled; typedef typename lookup_one_property< EdgeProp, edge_bundle_t >::type edge_bundled; public: // Embed indices into the vertex type. typedef property< vertex_index_t, unsigned, vertex_property_type > internal_vertex_property; typedef property< edge_index_t, unsigned, edge_property_type > internal_edge_property; public: typedef adjacency_list< listS, listS, undirectedS, internal_vertex_property, internal_edge_property, GraphProp, listS > graph_type; private: // storage selectors typedef typename graph_type::vertex_list_selector vertex_list_selector; typedef typename graph_type::edge_list_selector edge_list_selector; typedef typename graph_type::out_edge_list_selector out_edge_list_selector; typedef typename graph_type::directed_selector directed_selector; public: // more commonly used graph types typedef typename graph_type::stored_vertex stored_vertex; typedef typename graph_type::vertices_size_type vertices_size_type; typedef typename graph_type::edges_size_type edges_size_type; typedef typename graph_type::degree_size_type degree_size_type; typedef typename graph_type::vertex_descriptor vertex_descriptor; typedef typename graph_type::edge_descriptor edge_descriptor; // iterator types typedef typename graph_type::vertex_iterator vertex_iterator; typedef typename graph_type::edge_iterator edge_iterator; typedef typename graph_type::out_edge_iterator out_edge_iterator; typedef typename graph_type::in_edge_iterator in_edge_iterator; typedef typename graph_type::adjacency_iterator adjacency_iterator; // miscellaneous types typedef undirected_graph_tag graph_tag; typedef typename graph_type::directed_category directed_category; typedef typename graph_type::edge_parallel_category edge_parallel_category; typedef typename graph_type::traversal_category traversal_category; typedef std::size_t vertex_index_type; typedef std::size_t edge_index_type; inline undirected_graph(GraphProp const& p = GraphProp()) : m_graph(p) , m_num_vertices(0) , m_num_edges(0) , m_max_vertex_index(0) , m_max_edge_index(0) { } inline undirected_graph(undirected_graph const& x) : m_graph(x.m_graph) , m_num_vertices(x.m_num_vertices) , m_num_edges(x.m_num_edges) , m_max_vertex_index(x.m_max_vertex_index) , m_max_edge_index(x.m_max_edge_index) { } inline undirected_graph( vertices_size_type n, GraphProp const& p = GraphProp()) : m_graph(n, p) , m_num_vertices(n) , m_num_edges(0) , m_max_vertex_index(n) , m_max_edge_index(0) { renumber_vertex_indices(); } template < typename EdgeIterator > inline undirected_graph(EdgeIterator f, EdgeIterator l, vertices_size_type n, edges_size_type m = 0, GraphProp const& p = GraphProp()) : m_graph(f, l, n, m, p) , m_num_vertices(n) , m_num_edges(0) , m_max_vertex_index(n) , m_max_edge_index(0) { // Unfortunately, we have to renumber to ensure correct indexing. renumber_indices(); // Can't always guarantee that the number of edges is actually // m if distance(f, l) != m (or is undefined). m_num_edges = m_max_edge_index = boost::num_edges(m_graph); } undirected_graph& operator=(undirected_graph const& g) { if (&g != this) { m_graph = g.m_graph; m_num_vertices = g.m_num_vertices; m_num_edges = g.m_num_edges; m_max_vertex_index = g.m_max_vertex_index; } return *this; } // The impl_() methods are not part of the public interface. graph_type& impl() { return m_graph; } graph_type const& impl() const { return m_graph; } // The following methods are not part of the public interface vertices_size_type num_vertices() const { return m_num_vertices; } private: // This helper function manages the attribution of vertex indices. vertex_descriptor make_index(vertex_descriptor v) { boost::put(vertex_index, m_graph, v, m_max_vertex_index); m_num_vertices++; m_max_vertex_index++; return v; } public: vertex_descriptor add_vertex() { return make_index(boost::add_vertex(m_graph)); } vertex_descriptor add_vertex(vertex_property_type const& p) { return make_index( boost::add_vertex(internal_vertex_property(0u, p), m_graph)); } void clear_vertex(vertex_descriptor v) { std::pair< out_edge_iterator, out_edge_iterator > p = boost::out_edges(v, m_graph); m_num_edges -= std::distance(p.first, p.second); boost::clear_vertex(v, m_graph); } void remove_vertex(vertex_descriptor v) { boost::remove_vertex(v, m_graph); --m_num_vertices; } edges_size_type num_edges() const { return m_num_edges; } private: // A helper fucntion for managing edge index attributes. std::pair< edge_descriptor, bool > const& make_index( std::pair< edge_descriptor, bool > const& x) { if (x.second) { boost::put(edge_index, m_graph, x.first, m_max_edge_index); ++m_num_edges; ++m_max_edge_index; } return x; } public: std::pair< edge_descriptor, bool > add_edge( vertex_descriptor u, vertex_descriptor v) { return make_index(boost::add_edge(u, v, m_graph)); } std::pair< edge_descriptor, bool > add_edge( vertex_descriptor u, vertex_descriptor v, edge_property_type const& p) { return make_index( boost::add_edge(u, v, internal_edge_property(0u, p), m_graph)); } void remove_edge(vertex_descriptor u, vertex_descriptor v) { // find all edges, (u, v) std::vector< edge_descriptor > edges; out_edge_iterator i, i_end; for (boost::tie(i, i_end) = boost::out_edges(u, m_graph); i != i_end; ++i) { if (boost::target(*i, m_graph) == v) { edges.push_back(*i); } } // remove all edges, (u, v) typename std::vector< edge_descriptor >::iterator j = edges.begin(), j_end = edges.end(); for (; j != j_end; ++j) { remove_edge(*j); } } void remove_edge(edge_iterator i) { remove_edge(*i); } void remove_edge(edge_descriptor e) { boost::remove_edge(e, m_graph); --m_num_edges; } vertex_index_type max_vertex_index() const { return m_max_vertex_index; } void renumber_vertex_indices() { vertex_iterator i, i_end; boost::tie(i, i_end) = vertices(m_graph); m_max_vertex_index = renumber_vertex_indices(i, i_end, 0); } void remove_vertex_and_renumber_indices(vertex_iterator i) { vertex_iterator j = next(i), end = vertices(m_graph).second; vertex_index_type n = get(vertex_index, m_graph, *i); // remove the offending vertex and renumber everything after remove_vertex(*i); m_max_vertex_index = renumber_vertex_indices(j, end, n); } edge_index_type max_edge_index() const { return m_max_edge_index; } void renumber_edge_indices() { edge_iterator i, end; boost::tie(i, end) = edges(m_graph); m_max_edge_index = renumber_edge_indices(i, end, 0); } void remove_edge_and_renumber_indices(edge_iterator i) { edge_iterator j = next(i), end = edges(m_graph.second); edge_index_type n = get(edge_index, m_graph, *i); // remove the edge and renumber everything after it remove_edge(*i); m_max_edge_index = renumber_edge_indices(j, end, n); } void renumber_indices() { renumber_vertex_indices(); renumber_edge_indices(); } // bundled property support #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES vertex_bundled& operator[](vertex_descriptor v) { return m_graph[v]; } vertex_bundled const& operator[](vertex_descriptor v) const { return m_graph[v]; } edge_bundled& operator[](edge_descriptor e) { return m_graph[e]; } edge_bundled const& operator[](edge_descriptor e) const { return m_graph[e]; } graph_bundled& operator[](graph_bundle_t) { return get_property(*this); } graph_bundled const& operator[](graph_bundle_t) const { return get_property(*this); } #endif // Graph concepts static vertex_descriptor null_vertex() { return graph_type::null_vertex(); } void clear() { m_graph.clear(); m_num_vertices = m_max_vertex_index = 0; m_num_edges = m_max_edge_index = 0; } void swap(undirected_graph& g) { m_graph.swap(g.m_graph); std::swap(m_num_vertices, g.m_num_vertices); std::swap(m_max_vertex_index, g.m_max_vertex_index); std::swap(m_num_edges, g.m_num_edges); std::swap(m_max_edge_index, g.m_max_edge_index); } private: vertices_size_type renumber_vertex_indices( vertex_iterator i, vertex_iterator end, vertices_size_type n) { typedef typename property_map< graph_type, vertex_index_t >::type IndexMap; IndexMap indices = get(vertex_index, m_graph); for (; i != end; ++i) { indices[*i] = n++; } return n; } edges_size_type renumber_edge_indices( edge_iterator i, edge_iterator end, edges_size_type n) { typedef typename property_map< graph_type, edge_index_t >::type IndexMap; IndexMap indices = get(edge_index, m_graph); for (; i != end; ++i) { indices[*i] = n++; } return n; } graph_type m_graph; vertices_size_type m_num_vertices; edges_size_type m_num_edges; vertex_index_type m_max_vertex_index; edge_index_type m_max_edge_index; }; #define UNDIRECTED_GRAPH_PARAMS typename VP, typename EP, typename GP #define UNDIRECTED_GRAPH undirected_graph< VP, EP, GP > // IncidenceGraph concepts template < UNDIRECTED_GRAPH_PARAMS > inline typename UNDIRECTED_GRAPH::vertex_descriptor source( typename UNDIRECTED_GRAPH::edge_descriptor e, UNDIRECTED_GRAPH const& g) { return source(e, g.impl()); } template < UNDIRECTED_GRAPH_PARAMS > inline typename UNDIRECTED_GRAPH::vertex_descriptor target( typename UNDIRECTED_GRAPH::edge_descriptor e, UNDIRECTED_GRAPH const& g) { return target(e, g.impl()); } template < UNDIRECTED_GRAPH_PARAMS > inline typename UNDIRECTED_GRAPH::degree_size_type out_degree( typename UNDIRECTED_GRAPH::vertex_descriptor v, UNDIRECTED_GRAPH const& g) { return out_degree(v, g.impl()); } template < UNDIRECTED_GRAPH_PARAMS > inline std::pair< typename UNDIRECTED_GRAPH::out_edge_iterator, typename UNDIRECTED_GRAPH::out_edge_iterator > out_edges( typename UNDIRECTED_GRAPH::vertex_descriptor v, UNDIRECTED_GRAPH const& g) { return out_edges(v, g.impl()); } // BidirectionalGraph concepts template < UNDIRECTED_GRAPH_PARAMS > inline typename UNDIRECTED_GRAPH::degree_size_type in_degree( typename UNDIRECTED_GRAPH::vertex_descriptor v, UNDIRECTED_GRAPH const& g) { return in_degree(v, g.impl()); } template < UNDIRECTED_GRAPH_PARAMS > inline std::pair< typename UNDIRECTED_GRAPH::in_edge_iterator, typename UNDIRECTED_GRAPH::in_edge_iterator > in_edges( typename UNDIRECTED_GRAPH::vertex_descriptor v, UNDIRECTED_GRAPH const& g) { return in_edges(v, g.impl()); } template < UNDIRECTED_GRAPH_PARAMS > inline std::pair< typename UNDIRECTED_GRAPH::out_edge_iterator, typename UNDIRECTED_GRAPH::out_edge_iterator > incident_edges( typename UNDIRECTED_GRAPH::vertex_descriptor v, UNDIRECTED_GRAPH const& g) { return out_edges(v, g.impl()); } template < UNDIRECTED_GRAPH_PARAMS > inline typename UNDIRECTED_GRAPH::degree_size_type degree( typename UNDIRECTED_GRAPH::vertex_descriptor v, UNDIRECTED_GRAPH const& g) { return degree(v, g.impl()); } // AdjacencyGraph concepts template < UNDIRECTED_GRAPH_PARAMS > inline std::pair< typename UNDIRECTED_GRAPH::adjacency_iterator, typename UNDIRECTED_GRAPH::adjacency_iterator > adjacent_vertices( typename UNDIRECTED_GRAPH::vertex_descriptor v, UNDIRECTED_GRAPH const& g) { return adjacent_vertices(v, g.impl()); } template < UNDIRECTED_GRAPH_PARAMS > typename UNDIRECTED_GRAPH::vertex_descriptor vertex( typename UNDIRECTED_GRAPH::vertices_size_type n, UNDIRECTED_GRAPH const& g) { return vertex(n, g.impl()); } template < UNDIRECTED_GRAPH_PARAMS > std::pair< typename UNDIRECTED_GRAPH::edge_descriptor, bool > edge( typename UNDIRECTED_GRAPH::vertex_descriptor u, typename UNDIRECTED_GRAPH::vertex_descriptor v, UNDIRECTED_GRAPH const& g) { return edge(u, v, g.impl()); } // VertexListGraph concepts template < UNDIRECTED_GRAPH_PARAMS > inline typename UNDIRECTED_GRAPH::vertices_size_type num_vertices( UNDIRECTED_GRAPH const& g) { return g.num_vertices(); } template < UNDIRECTED_GRAPH_PARAMS > inline std::pair< typename UNDIRECTED_GRAPH::vertex_iterator, typename UNDIRECTED_GRAPH::vertex_iterator > vertices(UNDIRECTED_GRAPH const& g) { return vertices(g.impl()); } // EdgeListGraph concepts template < UNDIRECTED_GRAPH_PARAMS > inline typename UNDIRECTED_GRAPH::edges_size_type num_edges( UNDIRECTED_GRAPH const& g) { return g.num_edges(); } template < UNDIRECTED_GRAPH_PARAMS > inline std::pair< typename UNDIRECTED_GRAPH::edge_iterator, typename UNDIRECTED_GRAPH::edge_iterator > edges(UNDIRECTED_GRAPH const& g) { return edges(g.impl()); } // MutableGraph concepts template < UNDIRECTED_GRAPH_PARAMS > inline typename UNDIRECTED_GRAPH::vertex_descriptor add_vertex( UNDIRECTED_GRAPH& g) { return g.add_vertex(); } template < UNDIRECTED_GRAPH_PARAMS > inline typename UNDIRECTED_GRAPH::vertex_descriptor add_vertex( typename UNDIRECTED_GRAPH::vertex_property_type const& p, UNDIRECTED_GRAPH& g) { return g.add_vertex(p); } template < UNDIRECTED_GRAPH_PARAMS > inline void clear_vertex( typename UNDIRECTED_GRAPH::vertex_descriptor v, UNDIRECTED_GRAPH& g) { return g.clear_vertex(v); } template < UNDIRECTED_GRAPH_PARAMS > inline void remove_vertex( typename UNDIRECTED_GRAPH::vertex_descriptor v, UNDIRECTED_GRAPH& g) { return g.remove_vertex(v); } template < UNDIRECTED_GRAPH_PARAMS > inline std::pair< typename UNDIRECTED_GRAPH::edge_descriptor, bool > add_edge( typename UNDIRECTED_GRAPH::vertex_descriptor u, typename UNDIRECTED_GRAPH::vertex_descriptor v, UNDIRECTED_GRAPH& g) { return g.add_edge(u, v); } template < UNDIRECTED_GRAPH_PARAMS > inline std::pair< typename UNDIRECTED_GRAPH::edge_descriptor, bool > add_edge( typename UNDIRECTED_GRAPH::vertex_descriptor u, typename UNDIRECTED_GRAPH::vertex_descriptor v, typename UNDIRECTED_GRAPH::edge_property_type const& p, UNDIRECTED_GRAPH& g) { return g.add_edge(u, v, p); } template < UNDIRECTED_GRAPH_PARAMS > inline void remove_edge(typename UNDIRECTED_GRAPH::vertex_descriptor u, typename UNDIRECTED_GRAPH::vertex_descriptor v, UNDIRECTED_GRAPH& g) { return g.remove_edge(u, v); } template < UNDIRECTED_GRAPH_PARAMS > inline void remove_edge( typename UNDIRECTED_GRAPH::edge_descriptor e, UNDIRECTED_GRAPH& g) { return g.remove_edge(e); } template < UNDIRECTED_GRAPH_PARAMS > inline void remove_edge( typename UNDIRECTED_GRAPH::edge_iterator i, UNDIRECTED_GRAPH& g) { return g.remove_edge(i); } template < UNDIRECTED_GRAPH_PARAMS, class Predicate > inline void remove_edge_if(Predicate pred, UNDIRECTED_GRAPH& g) { return remove_edge_if(pred, g.impl()); } template < UNDIRECTED_GRAPH_PARAMS, class Predicate > inline void remove_incident_edge_if( typename UNDIRECTED_GRAPH::vertex_descriptor v, Predicate pred, UNDIRECTED_GRAPH& g) { return remove_out_edge_if(v, pred, g.impl()); } template < UNDIRECTED_GRAPH_PARAMS, class Predicate > inline void remove_out_edge_if(typename UNDIRECTED_GRAPH::vertex_descriptor v, Predicate pred, UNDIRECTED_GRAPH& g) { return remove_out_edge_if(v, pred, g.impl()); } template < UNDIRECTED_GRAPH_PARAMS, class Predicate > inline void remove_in_edge_if(typename UNDIRECTED_GRAPH::vertex_descriptor v, Predicate pred, UNDIRECTED_GRAPH& g) { return remove_in_edge_if(v, pred, g.impl()); } template < UNDIRECTED_GRAPH_PARAMS, typename Property > struct property_map< UNDIRECTED_GRAPH, Property > : property_map< typename UNDIRECTED_GRAPH::graph_type, Property > { }; template < UNDIRECTED_GRAPH_PARAMS > struct property_map< UNDIRECTED_GRAPH, vertex_all_t > { typedef transform_value_property_map< detail::remove_first_property, typename property_map< typename UNDIRECTED_GRAPH::graph_type, vertex_all_t >::const_type > const_type; typedef transform_value_property_map< detail::remove_first_property, typename property_map< typename UNDIRECTED_GRAPH::graph_type, vertex_all_t >::type > type; }; template < UNDIRECTED_GRAPH_PARAMS > struct property_map< UNDIRECTED_GRAPH, edge_all_t > { typedef transform_value_property_map< detail::remove_first_property, typename property_map< typename UNDIRECTED_GRAPH::graph_type, edge_all_t >::const_type > const_type; typedef transform_value_property_map< detail::remove_first_property, typename property_map< typename UNDIRECTED_GRAPH::graph_type, edge_all_t >::type > type; }; // PropertyGraph concepts template < UNDIRECTED_GRAPH_PARAMS, typename Property > inline typename property_map< UNDIRECTED_GRAPH, Property >::type get( Property p, UNDIRECTED_GRAPH& g) { return get(p, g.impl()); } template < UNDIRECTED_GRAPH_PARAMS, typename Property > inline typename property_map< UNDIRECTED_GRAPH, Property >::const_type get( Property p, UNDIRECTED_GRAPH const& g) { return get(p, g.impl()); } template < UNDIRECTED_GRAPH_PARAMS > inline typename property_map< UNDIRECTED_GRAPH, vertex_all_t >::type get( vertex_all_t, UNDIRECTED_GRAPH& g) { return typename property_map< UNDIRECTED_GRAPH, vertex_all_t >::type( detail::remove_first_property(), get(vertex_all, g.impl())); } template < UNDIRECTED_GRAPH_PARAMS > inline typename property_map< UNDIRECTED_GRAPH, vertex_all_t >::const_type get( vertex_all_t, UNDIRECTED_GRAPH const& g) { return typename property_map< UNDIRECTED_GRAPH, vertex_all_t >::const_type( detail::remove_first_property(), get(vertex_all, g.impl())); } template < UNDIRECTED_GRAPH_PARAMS > inline typename property_map< UNDIRECTED_GRAPH, edge_all_t >::type get( edge_all_t, UNDIRECTED_GRAPH& g) { return typename property_map< UNDIRECTED_GRAPH, edge_all_t >::type( detail::remove_first_property(), get(edge_all, g.impl())); } template < UNDIRECTED_GRAPH_PARAMS > inline typename property_map< UNDIRECTED_GRAPH, edge_all_t >::const_type get( edge_all_t, UNDIRECTED_GRAPH const& g) { return typename property_map< UNDIRECTED_GRAPH, edge_all_t >::const_type( detail::remove_first_property(), get(edge_all, g.impl())); } template < UNDIRECTED_GRAPH_PARAMS, typename Property, typename Key > inline typename property_traits< typename property_map< typename UNDIRECTED_GRAPH::graph_type, Property >::const_type >::value_type get(Property p, UNDIRECTED_GRAPH const& g, Key const& k) { return get(p, g.impl(), k); } template < UNDIRECTED_GRAPH_PARAMS, typename Key > inline typename property_traits< typename property_map< typename UNDIRECTED_GRAPH::graph_type, vertex_all_t >::const_type >::value_type get(vertex_all_t, UNDIRECTED_GRAPH const& g, Key const& k) { return get(vertex_all, g.impl(), k).m_base; } template < UNDIRECTED_GRAPH_PARAMS, typename Key > inline typename property_traits< typename property_map< typename UNDIRECTED_GRAPH::graph_type, edge_all_t >::const_type >::value_type get(edge_all_t, UNDIRECTED_GRAPH const& g, Key const& k) { return get(edge_all, g.impl(), k).m_base; } template < UNDIRECTED_GRAPH_PARAMS, typename Property, typename Key, typename Value > inline void put(Property p, UNDIRECTED_GRAPH& g, Key const& k, Value const& v) { put(p, g.impl(), k, v); } template < UNDIRECTED_GRAPH_PARAMS, typename Key, typename Value > inline void put(vertex_all_t, UNDIRECTED_GRAPH& g, Key const& k, Value const& v) { put(vertex_all, g.impl(), k, typename UNDIRECTED_GRAPH::internal_vertex_property( get(vertex_index, g.impl(), k), v)); } template < UNDIRECTED_GRAPH_PARAMS, typename Key, typename Value > inline void put(edge_all_t, UNDIRECTED_GRAPH& g, Key const& k, Value const& v) { put(edge_all, g.impl(), k, typename UNDIRECTED_GRAPH::internal_vertex_property( get(edge_index, g.impl(), k), v)); } template < UNDIRECTED_GRAPH_PARAMS, class Property > inline typename graph_property< UNDIRECTED_GRAPH, Property >::type& get_property(UNDIRECTED_GRAPH& g, Property p) { return get_property(g.impl(), p); } template < UNDIRECTED_GRAPH_PARAMS, class Property > inline typename graph_property< UNDIRECTED_GRAPH, Property >::type const& get_property(UNDIRECTED_GRAPH const& g, Property p) { return get_property(g.impl(), p); } template < UNDIRECTED_GRAPH_PARAMS, class Property, class Value > inline void set_property(UNDIRECTED_GRAPH& g, Property p, Value v) { return set_property(g.impl(), p, v); } // Indexed Vertex graph template < UNDIRECTED_GRAPH_PARAMS > inline typename UNDIRECTED_GRAPH::vertex_index_type get_vertex_index( typename UNDIRECTED_GRAPH::vertex_descriptor v, UNDIRECTED_GRAPH const& g) { return get(vertex_index, g, v); } template < UNDIRECTED_GRAPH_PARAMS > typename UNDIRECTED_GRAPH::vertex_index_type max_vertex_index( UNDIRECTED_GRAPH const& g) { return g.max_vertex_index(); } template < UNDIRECTED_GRAPH_PARAMS > inline void renumber_vertex_indices(UNDIRECTED_GRAPH& g) { g.renumber_vertex_indices(); } template < UNDIRECTED_GRAPH_PARAMS > inline void remove_vertex_and_renumber_indices( typename UNDIRECTED_GRAPH::vertex_iterator i, UNDIRECTED_GRAPH& g) { g.remove_vertex_and_renumber_indices(i); } // Edge index management template < UNDIRECTED_GRAPH_PARAMS > inline typename UNDIRECTED_GRAPH::edge_index_type get_edge_index( typename UNDIRECTED_GRAPH::edge_descriptor v, UNDIRECTED_GRAPH const& g) { return get(edge_index, g, v); } template < UNDIRECTED_GRAPH_PARAMS > typename UNDIRECTED_GRAPH::edge_index_type max_edge_index( UNDIRECTED_GRAPH const& g) { return g.max_edge_index(); } template < UNDIRECTED_GRAPH_PARAMS > inline void renumber_edge_indices(UNDIRECTED_GRAPH& g) { g.renumber_edge_indices(); } template < UNDIRECTED_GRAPH_PARAMS > inline void remove_edge_and_renumber_indices( typename UNDIRECTED_GRAPH::edge_iterator i, UNDIRECTED_GRAPH& g) { g.remove_edge_and_renumber_indices(i); } // Index management template < UNDIRECTED_GRAPH_PARAMS > inline void renumber_indices(UNDIRECTED_GRAPH& g) { g.renumber_indices(); } // Mutability Traits template < UNDIRECTED_GRAPH_PARAMS > struct graph_mutability_traits< UNDIRECTED_GRAPH > { typedef mutable_property_graph_tag category; }; #undef UNDIRECTED_GRAPH_PARAMS #undef UNDIRECTED_GRAPH } /* namespace boost */ #endif edge_list.hpp 0000644 00000023334 15125521275 0007226 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_EDGE_LIST_HPP #define BOOST_GRAPH_EDGE_LIST_HPP #include <iterator> #include <boost/config.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/bool.hpp> #include <boost/range/irange.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> namespace boost { // // The edge_list class is an EdgeListGraph module that is constructed // from a pair of iterators whose value type is a pair of vertex // descriptors. // // For example: // // typedef std::pair<int,int> E; // list<E> elist; // ... // typedef edge_list<list<E>::iterator> Graph; // Graph g(elist.begin(), elist.end()); // // If the iterators are random access, then Graph::edge_descriptor // is of Integral type, otherwise it is a struct, though it is // convertible to an Integral type. // struct edge_list_tag { }; // The implementation class for edge_list. template < class G, class EdgeIter, class T, class D > class edge_list_impl { public: typedef D edge_id; typedef T Vpair; typedef typename Vpair::first_type V; typedef V vertex_descriptor; typedef edge_list_tag graph_tag; typedef void edge_property_type; struct edge_descriptor { edge_descriptor() {} edge_descriptor(EdgeIter p, edge_id id) : _ptr(p), _id(id) {} operator edge_id() { return _id; } EdgeIter _ptr; edge_id _id; }; typedef edge_descriptor E; struct edge_iterator { typedef edge_iterator self; typedef E value_type; typedef E& reference; typedef E* pointer; typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; edge_iterator() {} edge_iterator(EdgeIter iter) : _iter(iter), _i(0) {} E operator*() { return E(_iter, _i); } self& operator++() { ++_iter; ++_i; return *this; } self operator++(int) { self t = *this; ++(*this); return t; } bool operator==(const self& x) { return _iter == x._iter; } bool operator!=(const self& x) { return _iter != x._iter; } EdgeIter _iter; edge_id _i; }; typedef void out_edge_iterator; typedef void in_edge_iterator; typedef void adjacency_iterator; typedef void vertex_iterator; }; template < class G, class EI, class T, class D > std::pair< typename edge_list_impl< G, EI, T, D >::edge_iterator, typename edge_list_impl< G, EI, T, D >::edge_iterator > edges(const edge_list_impl< G, EI, T, D >& g_) { const G& g = static_cast< const G& >(g_); typedef typename edge_list_impl< G, EI, T, D >::edge_iterator edge_iterator; return std::make_pair(edge_iterator(g._first), edge_iterator(g._last)); } template < class G, class EI, class T, class D > typename edge_list_impl< G, EI, T, D >::vertex_descriptor source( typename edge_list_impl< G, EI, T, D >::edge_descriptor e, const edge_list_impl< G, EI, T, D >&) { return (*e._ptr).first; } template < class G, class EI, class T, class D > typename edge_list_impl< G, EI, T, D >::vertex_descriptor target( typename edge_list_impl< G, EI, T, D >::edge_descriptor e, const edge_list_impl< G, EI, T, D >&) { return (*e._ptr).second; } template < class D, class E > class el_edge_property_map : public put_get_helper< D, el_edge_property_map< D, E > > { public: typedef E key_type; typedef D value_type; typedef D reference; typedef readable_property_map_tag category; value_type operator[](key_type e) const { return e._i; } }; struct edge_list_edge_property_selector { template < class Graph, class Property, class Tag > struct bind_ { typedef el_edge_property_map< typename Graph::edge_id, typename Graph::edge_descriptor > type; typedef type const_type; }; }; template <> struct edge_property_selector< edge_list_tag > { typedef edge_list_edge_property_selector type; }; template < class G, class EI, class T, class D > typename property_map< edge_list_impl< G, EI, T, D >, edge_index_t >::type get( edge_index_t, const edge_list_impl< G, EI, T, D >&) { typedef typename property_map< edge_list_impl< G, EI, T, D >, edge_index_t >::type EdgeIndexMap; return EdgeIndexMap(); } template < class G, class EI, class T, class D > inline D get(edge_index_t, const edge_list_impl< G, EI, T, D >&, typename edge_list_impl< G, EI, T, D >::edge_descriptor e) { return e._i; } // A specialized implementation for when the iterators are random access. struct edge_list_ra_tag { }; template < class G, class EdgeIter, class T, class D > class edge_list_impl_ra { public: typedef D edge_id; typedef T Vpair; typedef typename Vpair::first_type V; typedef edge_list_ra_tag graph_tag; typedef void edge_property_type; typedef edge_id edge_descriptor; typedef V vertex_descriptor; typedef typename boost::integer_range< edge_id >::iterator edge_iterator; typedef void out_edge_iterator; typedef void in_edge_iterator; typedef void adjacency_iterator; typedef void vertex_iterator; }; template < class G, class EI, class T, class D > std::pair< typename edge_list_impl_ra< G, EI, T, D >::edge_iterator, typename edge_list_impl_ra< G, EI, T, D >::edge_iterator > edges(const edge_list_impl_ra< G, EI, T, D >& g_) { const G& g = static_cast< const G& >(g_); typedef typename edge_list_impl_ra< G, EI, T, D >::edge_iterator edge_iterator; return std::make_pair(edge_iterator(0), edge_iterator(g._last - g._first)); } template < class G, class EI, class T, class D > typename edge_list_impl_ra< G, EI, T, D >::vertex_descriptor source( typename edge_list_impl_ra< G, EI, T, D >::edge_descriptor e, const edge_list_impl_ra< G, EI, T, D >& g_) { const G& g = static_cast< const G& >(g_); return g._first[e].first; } template < class G, class EI, class T, class D > typename edge_list_impl_ra< G, EI, T, D >::vertex_descriptor target( typename edge_list_impl_ra< G, EI, T, D >::edge_descriptor e, const edge_list_impl_ra< G, EI, T, D >& g_) { const G& g = static_cast< const G& >(g_); return g._first[e].second; } template < class E > class el_ra_edge_property_map : public put_get_helper< E, el_ra_edge_property_map< E > > { public: typedef E key_type; typedef E value_type; typedef E reference; typedef readable_property_map_tag category; value_type operator[](key_type e) const { return e; } }; struct edge_list_ra_edge_property_selector { template < class Graph, class Property, class Tag > struct bind_ { typedef el_ra_edge_property_map< typename Graph::edge_descriptor > type; typedef type const_type; }; }; template <> struct edge_property_selector< edge_list_ra_tag > { typedef edge_list_ra_edge_property_selector type; }; template < class G, class EI, class T, class D > inline typename property_map< edge_list_impl_ra< G, EI, T, D >, edge_index_t >::type get(edge_index_t, const edge_list_impl_ra< G, EI, T, D >&) { typedef typename property_map< edge_list_impl_ra< G, EI, T, D >, edge_index_t >::type EdgeIndexMap; return EdgeIndexMap(); } template < class G, class EI, class T, class D > inline D get(edge_index_t, const edge_list_impl_ra< G, EI, T, D >&, typename edge_list_impl_ra< G, EI, T, D >::edge_descriptor e) { return e; } // Some helper classes for determining if the iterators are random access template < class Cat > struct is_random { enum { RET = false }; typedef mpl::false_ type; }; template <> struct is_random< std::random_access_iterator_tag > { enum { RET = true }; typedef mpl::true_ type; }; // The edge_list class conditionally inherits from one of the // above two classes. template < class EdgeIter, #if !defined BOOST_NO_STD_ITERATOR_TRAITS class T = typename std::iterator_traits< EdgeIter >::value_type, class D = typename std::iterator_traits< EdgeIter >::difference_type, class Cat = typename std::iterator_traits< EdgeIter >::iterator_category > #else class T, class D, class Cat > #endif class edge_list : public mpl::if_< typename is_random< Cat >::type, edge_list_impl_ra< edge_list< EdgeIter, T, D, Cat >, EdgeIter, T, D >, edge_list_impl< edge_list< EdgeIter, T, D, Cat >, EdgeIter, T, D > >::type { public: typedef directed_tag directed_category; typedef allow_parallel_edge_tag edge_parallel_category; typedef edge_list_graph_tag traversal_category; typedef std::size_t edges_size_type; typedef std::size_t vertices_size_type; typedef std::size_t degree_size_type; edge_list(EdgeIter first, EdgeIter last) : _first(first), _last(last) { m_num_edges = std::distance(first, last); } edge_list(EdgeIter first, EdgeIter last, edges_size_type E) : _first(first), _last(last), m_num_edges(E) { } EdgeIter _first, _last; edges_size_type m_num_edges; }; template < class EdgeIter, class T, class D, class Cat > std::size_t num_edges(const edge_list< EdgeIter, T, D, Cat >& el) { return el.m_num_edges; } #ifndef BOOST_NO_STD_ITERATOR_TRAITS template < class EdgeIter > inline edge_list< EdgeIter > make_edge_list(EdgeIter first, EdgeIter last) { return edge_list< EdgeIter >(first, last); } #endif } /* namespace boost */ #endif /* BOOST_GRAPH_EDGE_LIST_HPP */ properties.hpp 0000644 00000030201 15125521275 0007452 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_PROPERTIES_HPP #define BOOST_GRAPH_PROPERTIES_HPP #include <boost/config.hpp> #include <boost/assert.hpp> #include <boost/pending/property.hpp> #include <boost/detail/workaround.hpp> // Include the property map library and extensions in the BGL. #include <boost/property_map/property_map.hpp> #include <boost/graph/property_maps/constant_property_map.hpp> #include <boost/graph/property_maps/null_property_map.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/type_traits.hpp> #include <boost/limits.hpp> #include <boost/mpl/and.hpp> #include <boost/mpl/not.hpp> #include <boost/mpl/if.hpp> namespace boost { enum default_color_type { white_color, gray_color, green_color, red_color, black_color }; template < class ColorValue > struct color_traits { static default_color_type white() { return white_color; } static default_color_type gray() { return gray_color; } static default_color_type green() { return green_color; } static default_color_type red() { return red_color; } static default_color_type black() { return black_color; } }; // These functions are now obsolete, replaced by color_traits. inline default_color_type white(default_color_type) { return white_color; } inline default_color_type gray(default_color_type) { return gray_color; } inline default_color_type green(default_color_type) { return green_color; } inline default_color_type red(default_color_type) { return red_color; } inline default_color_type black(default_color_type) { return black_color; } struct graph_property_tag { }; struct vertex_property_tag { }; struct edge_property_tag { }; // See examples/edge_property.cpp for how to use this. #define BOOST_INSTALL_PROPERTY(KIND, NAME) \ template <> struct property_kind< KIND##_##NAME##_t > \ { \ typedef KIND##_property_tag type; \ } #define BOOST_DEF_PROPERTY(KIND, NAME) \ enum KIND##_##NAME##_t { KIND##_##NAME }; \ BOOST_INSTALL_PROPERTY(KIND, NAME) // These three are defined in boost/pending/property.hpp BOOST_INSTALL_PROPERTY(vertex, all); BOOST_INSTALL_PROPERTY(edge, all); BOOST_INSTALL_PROPERTY(graph, all); BOOST_DEF_PROPERTY(vertex, index); BOOST_DEF_PROPERTY(vertex, index1); BOOST_DEF_PROPERTY(vertex, index2); BOOST_DEF_PROPERTY(vertex, root); BOOST_DEF_PROPERTY(edge, index); BOOST_DEF_PROPERTY(edge, name); BOOST_DEF_PROPERTY(edge, weight); BOOST_DEF_PROPERTY(edge, weight2); BOOST_DEF_PROPERTY(edge, color); BOOST_DEF_PROPERTY(vertex, name); BOOST_DEF_PROPERTY(graph, name); BOOST_DEF_PROPERTY(vertex, distance); BOOST_DEF_PROPERTY(vertex, distance2); BOOST_DEF_PROPERTY(vertex, color); BOOST_DEF_PROPERTY(vertex, degree); BOOST_DEF_PROPERTY(vertex, in_degree); BOOST_DEF_PROPERTY(vertex, out_degree); BOOST_DEF_PROPERTY(vertex, current_degree); BOOST_DEF_PROPERTY(vertex, priority); BOOST_DEF_PROPERTY(vertex, discover_time); BOOST_DEF_PROPERTY(vertex, finish_time); BOOST_DEF_PROPERTY(vertex, predecessor); BOOST_DEF_PROPERTY(vertex, rank); BOOST_DEF_PROPERTY(vertex, centrality); BOOST_DEF_PROPERTY(vertex, lowpoint); BOOST_DEF_PROPERTY(vertex, potential); BOOST_DEF_PROPERTY(vertex, update); BOOST_DEF_PROPERTY(vertex, underlying); BOOST_DEF_PROPERTY(edge, reverse); BOOST_DEF_PROPERTY(edge, capacity); BOOST_DEF_PROPERTY(edge, flow); BOOST_DEF_PROPERTY(edge, residual_capacity); BOOST_DEF_PROPERTY(edge, centrality); BOOST_DEF_PROPERTY(edge, discover_time); BOOST_DEF_PROPERTY(edge, update); BOOST_DEF_PROPERTY(edge, finished); BOOST_DEF_PROPERTY(edge, underlying); BOOST_DEF_PROPERTY(graph, visitor); // These tags are used for property bundles // These three are defined in boost/pending/property.hpp BOOST_INSTALL_PROPERTY(graph, bundle); BOOST_INSTALL_PROPERTY(vertex, bundle); BOOST_INSTALL_PROPERTY(edge, bundle); // These tags are used to denote the owners and local descriptors // for the vertices and edges of a distributed graph. BOOST_DEF_PROPERTY(vertex, global); BOOST_DEF_PROPERTY(vertex, owner); BOOST_DEF_PROPERTY(vertex, local); BOOST_DEF_PROPERTY(edge, global); BOOST_DEF_PROPERTY(edge, owner); BOOST_DEF_PROPERTY(edge, local); BOOST_DEF_PROPERTY(vertex, local_index); BOOST_DEF_PROPERTY(edge, local_index); #undef BOOST_DEF_PROPERTY namespace detail { template < typename G, typename Tag > struct property_kind_from_graph : property_kind< Tag > { }; #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES template < typename G, typename R, typename T > struct property_kind_from_graph< G, R T::* > { typedef typename boost::mpl::if_< boost::is_base_of< T, typename vertex_bundle_type< G >::type >, vertex_property_tag, typename boost::mpl::if_< boost::is_base_of< T, typename edge_bundle_type< G >::type >, edge_property_tag, typename boost::mpl::if_< boost::is_base_of< T, typename graph_bundle_type< G >::type >, graph_property_tag, void >::type >::type >::type type; }; #endif struct dummy_edge_property_selector { template < class Graph, class Property, class Tag > struct bind_ { typedef identity_property_map type; typedef identity_property_map const_type; }; }; struct dummy_vertex_property_selector { template < class Graph, class Property, class Tag > struct bind_ { typedef identity_property_map type; typedef identity_property_map const_type; }; }; } // namespace detail // Graph classes can either partially specialize property_map // or they can specialize these two selector classes. template < class GraphTag > struct edge_property_selector { typedef detail::dummy_edge_property_selector type; }; template < class GraphTag > struct vertex_property_selector { typedef detail::dummy_vertex_property_selector type; }; namespace detail { template < typename A > struct return_void { typedef void type; }; template < typename Graph, typename Enable = void > struct graph_tag_or_void { typedef void type; }; template < typename Graph > struct graph_tag_or_void< Graph, typename return_void< typename Graph::graph_tag >::type > { typedef typename Graph::graph_tag type; }; template < class Graph, class PropertyTag > struct edge_property_map : edge_property_selector< typename graph_tag_or_void< Graph >::type >:: type::template bind_< Graph, typename edge_property_type< Graph >::type, PropertyTag > { }; template < class Graph, class PropertyTag > struct vertex_property_map : vertex_property_selector< typename graph_tag_or_void< Graph >::type >:: type::template bind_< Graph, typename vertex_property_type< Graph >::type, PropertyTag > { }; } // namespace detail template < class Graph, class Property, class Enable = void > struct property_map : mpl::if_< is_same< typename detail::property_kind_from_graph< Graph, Property >::type, edge_property_tag >, detail::edge_property_map< Graph, Property >, detail::vertex_property_map< Graph, Property > >::type { }; // shortcut for accessing the value type of the property map template < class Graph, class Property > class property_map_value { typedef typename property_map< Graph, Property >::const_type PMap; public: typedef typename property_traits< PMap >::value_type type; }; template < class Graph, class Property > class graph_property { public: typedef typename property_value< typename boost::graph_property_type< Graph >::type, Property >::type type; }; template < typename Graph > struct vertex_property : vertex_property_type< Graph > { }; template < typename Graph > struct edge_property : edge_property_type< Graph > { }; template < typename Graph > class degree_property_map : public put_get_helper< typename graph_traits< Graph >::degree_size_type, degree_property_map< Graph > > { public: typedef typename graph_traits< Graph >::vertex_descriptor key_type; typedef typename graph_traits< Graph >::degree_size_type value_type; typedef value_type reference; typedef readable_property_map_tag category; degree_property_map(const Graph& g) : m_g(g) {} value_type operator[](const key_type& v) const { return degree(v, m_g); } private: const Graph& m_g; }; template < typename Graph > inline degree_property_map< Graph > make_degree_map(const Graph& g) { return degree_property_map< Graph >(g); } //======================================================================== // Iterator Property Map Generating Functions contributed by // Kevin Vanhorn. (see also the property map generating functions // in boost/property_map/property_map.hpp) #if !defined(BOOST_NO_STD_ITERATOR_TRAITS) // A helper function for creating a vertex property map out of a // random access iterator and the internal vertex index map from a // graph. template < class PropertyGraph, class RandomAccessIterator > inline iterator_property_map< RandomAccessIterator, typename property_map< PropertyGraph, vertex_index_t >::type, typename std::iterator_traits< RandomAccessIterator >::value_type, typename std::iterator_traits< RandomAccessIterator >::reference > make_iterator_vertex_map(RandomAccessIterator iter, const PropertyGraph& g) { return make_iterator_property_map(iter, get(vertex_index, g)); } // Use this next function when vertex_descriptor is known to be an // integer type, with values ranging from 0 to num_vertices(g). // template < class RandomAccessIterator > inline iterator_property_map< RandomAccessIterator, identity_property_map, typename std::iterator_traits< RandomAccessIterator >::value_type, typename std::iterator_traits< RandomAccessIterator >::reference > make_iterator_vertex_map(RandomAccessIterator iter) { return make_iterator_property_map(iter, identity_property_map()); } #endif template < class PropertyGraph, class RandomAccessContainer > inline iterator_property_map< typename RandomAccessContainer::iterator, typename property_map< PropertyGraph, vertex_index_t >::type, typename RandomAccessContainer::value_type, typename RandomAccessContainer::reference > make_container_vertex_map(RandomAccessContainer& c, const PropertyGraph& g) { BOOST_ASSERT(c.size() >= num_vertices(g)); return make_iterator_vertex_map(c.begin(), g); } template < class RandomAccessContainer > inline iterator_property_map< typename RandomAccessContainer::iterator, identity_property_map, typename RandomAccessContainer::value_type, typename RandomAccessContainer::reference > make_container_vertex_map(RandomAccessContainer& c) { return make_iterator_vertex_map(c.begin()); } // NOTE: These functions are declared, but never defined since they need to // be overloaded by graph implementations. However, we need them to be // declared for the functions below. template < typename Graph, typename Tag > typename graph_property< Graph, graph_bundle_t >::type& get_property( Graph& g, Tag); template < typename Graph, typename Tag > typename graph_property< Graph, graph_bundle_t >::type const& get_property( Graph const& g, Tag); #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES // NOTE: This operation is a simple adaptor over the overloaded get_property // operations. template < typename Graph > inline typename graph_property< Graph, graph_bundle_t >::type& get_property( Graph& g) { return get_property(g, graph_bundle); } template < typename Graph > inline typename graph_property< Graph, graph_bundle_t >::type const& get_property(const Graph& g) { return get_property(g, graph_bundle); } #endif } // namespace boost #endif /* BOOST_GRAPH_PROPERTIES_HPP */ planar_canonical_ordering.hpp 0000644 00000016043 15125521275 0012443 0 ustar 00 //======================================================================= // Copyright (c) Aaron Windsor 2007 // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef __PLANAR_CANONICAL_ORDERING_HPP__ #define __PLANAR_CANONICAL_ORDERING_HPP__ #include <vector> #include <list> #include <boost/config.hpp> #include <boost/next_prior.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/property_map/property_map.hpp> namespace boost { namespace detail { enum planar_canonical_ordering_state { PCO_PROCESSED, PCO_UNPROCESSED, PCO_ONE_NEIGHBOR_PROCESSED, PCO_READY_TO_BE_PROCESSED }; } template < typename Graph, typename PlanarEmbedding, typename OutputIterator, typename VertexIndexMap > void planar_canonical_ordering(const Graph& g, PlanarEmbedding embedding, OutputIterator ordering, VertexIndexMap vm) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::edge_descriptor edge_t; typedef typename graph_traits< Graph >::adjacency_iterator adjacency_iterator_t; typedef typename property_traits< PlanarEmbedding >::value_type embedding_value_t; typedef typename embedding_value_t::const_iterator embedding_iterator_t; typedef iterator_property_map< typename std::vector< vertex_t >::iterator, VertexIndexMap > vertex_to_vertex_map_t; typedef iterator_property_map< typename std::vector< std::size_t >::iterator, VertexIndexMap > vertex_to_size_t_map_t; std::vector< vertex_t > processed_neighbor_vector(num_vertices(g)); vertex_to_vertex_map_t processed_neighbor( processed_neighbor_vector.begin(), vm); std::vector< std::size_t > status_vector( num_vertices(g), detail::PCO_UNPROCESSED); vertex_to_size_t_map_t status(status_vector.begin(), vm); std::list< vertex_t > ready_to_be_processed; vertex_t first_vertex = *vertices(g).first; vertex_t second_vertex = first_vertex; adjacency_iterator_t ai, ai_end; for (boost::tie(ai, ai_end) = adjacent_vertices(first_vertex, g); ai != ai_end; ++ai) { if (*ai == first_vertex) continue; second_vertex = *ai; break; } ready_to_be_processed.push_back(first_vertex); status[first_vertex] = detail::PCO_READY_TO_BE_PROCESSED; ready_to_be_processed.push_back(second_vertex); status[second_vertex] = detail::PCO_READY_TO_BE_PROCESSED; while (!ready_to_be_processed.empty()) { vertex_t u = ready_to_be_processed.front(); ready_to_be_processed.pop_front(); if (status[u] != detail::PCO_READY_TO_BE_PROCESSED && u != second_vertex) continue; embedding_iterator_t ei, ei_start, ei_end; embedding_iterator_t next_edge_itr, prior_edge_itr; ei_start = embedding[u].begin(); ei_end = embedding[u].end(); prior_edge_itr = prior(ei_end); while (source(*prior_edge_itr, g) == target(*prior_edge_itr, g)) prior_edge_itr = prior(prior_edge_itr); for (ei = ei_start; ei != ei_end; ++ei) { edge_t e(*ei); // e = (u,v) next_edge_itr = boost::next(ei) == ei_end ? ei_start : boost::next(ei); vertex_t v = source(e, g) == u ? target(e, g) : source(e, g); vertex_t prior_vertex = source(*prior_edge_itr, g) == u ? target(*prior_edge_itr, g) : source(*prior_edge_itr, g); vertex_t next_vertex = source(*next_edge_itr, g) == u ? target(*next_edge_itr, g) : source(*next_edge_itr, g); // Need prior_vertex, u, v, and next_vertex to all be // distinct. This is possible, since the input graph is // triangulated. It'll be true all the time in a simple // graph, but loops and parallel edges cause some complications. if (prior_vertex == v || prior_vertex == u) { prior_edge_itr = ei; continue; } // Skip any self-loops if (u == v) continue; // Move next_edge_itr (and next_vertex) forwards // past any loops or parallel edges while (next_vertex == v || next_vertex == u) { next_edge_itr = boost::next(next_edge_itr) == ei_end ? ei_start : boost::next(next_edge_itr); next_vertex = source(*next_edge_itr, g) == u ? target(*next_edge_itr, g) : source(*next_edge_itr, g); } if (status[v] == detail::PCO_UNPROCESSED) { status[v] = detail::PCO_ONE_NEIGHBOR_PROCESSED; processed_neighbor[v] = u; } else if (status[v] == detail::PCO_ONE_NEIGHBOR_PROCESSED) { vertex_t x = processed_neighbor[v]; // are edges (v,u) and (v,x) adjacent in the planar // embedding? if so, set status[v] = 1. otherwise, set // status[v] = 2. if ((next_vertex == x && !(first_vertex == u && second_vertex == x)) || (prior_vertex == x && !(first_vertex == x && second_vertex == u))) { status[v] = detail::PCO_READY_TO_BE_PROCESSED; } else { status[v] = detail::PCO_READY_TO_BE_PROCESSED + 1; } } else if (status[v] > detail::PCO_ONE_NEIGHBOR_PROCESSED) { // check the two edges before and after (v,u) in the planar // embedding, and update status[v] accordingly bool processed_before = false; if (status[prior_vertex] == detail::PCO_PROCESSED) processed_before = true; bool processed_after = false; if (status[next_vertex] == detail::PCO_PROCESSED) processed_after = true; if (!processed_before && !processed_after) ++status[v]; else if (processed_before && processed_after) --status[v]; } if (status[v] == detail::PCO_READY_TO_BE_PROCESSED) ready_to_be_processed.push_back(v); prior_edge_itr = ei; } status[u] = detail::PCO_PROCESSED; *ordering = u; ++ordering; } } template < typename Graph, typename PlanarEmbedding, typename OutputIterator > void planar_canonical_ordering( const Graph& g, PlanarEmbedding embedding, OutputIterator ordering) { planar_canonical_ordering(g, embedding, ordering, get(vertex_index, g)); } } // namespace boost #endif //__PLANAR_CANONICAL_ORDERING_HPP__ closeness_centrality.hpp 0000644 00000013651 15125521275 0011524 0 ustar 00 // (C) Copyright 2007-2009 Andrew Sutton // // 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_CLOSENESS_CENTRALITY_HPP #define BOOST_GRAPH_CLOSENESS_CENTRALITY_HPP #include <boost/graph/detail/geodesic.hpp> #include <boost/graph/exterior_property.hpp> #include <boost/concept/assert.hpp> namespace boost { template < typename Graph, typename DistanceType, typename ResultType, typename Reciprocal = detail::reciprocal< ResultType > > struct closeness_measure : public geodesic_measure< Graph, DistanceType, ResultType > { typedef geodesic_measure< Graph, DistanceType, ResultType > base_type; typedef typename base_type::distance_type distance_type; typedef typename base_type::result_type result_type; result_type operator()(distance_type d, const Graph&) { BOOST_CONCEPT_ASSERT((NumericValueConcept< DistanceType >)); BOOST_CONCEPT_ASSERT((NumericValueConcept< ResultType >)); BOOST_CONCEPT_ASSERT((AdaptableUnaryFunctionConcept< Reciprocal, ResultType, ResultType >)); return (d == base_type::infinite_distance()) ? base_type::zero_result() : rec(result_type(d)); } Reciprocal rec; }; template < typename Graph, typename DistanceMap > inline closeness_measure< Graph, typename property_traits< DistanceMap >::value_type, double, detail::reciprocal< double > > measure_closeness(const Graph&, DistanceMap) { typedef typename property_traits< DistanceMap >::value_type Distance; return closeness_measure< Graph, Distance, double, detail::reciprocal< double > >(); } template < typename T, typename Graph, typename DistanceMap > inline closeness_measure< Graph, typename property_traits< DistanceMap >::value_type, T, detail::reciprocal< T > > measure_closeness(const Graph&, DistanceMap) { typedef typename property_traits< DistanceMap >::value_type Distance; return closeness_measure< Graph, Distance, T, detail::reciprocal< T > >(); } template < typename T, typename Graph, typename DistanceMap, typename Reciprocal > inline closeness_measure< Graph, typename property_traits< DistanceMap >::value_type, T, Reciprocal > measure_closeness(const Graph&, DistanceMap) { typedef typename property_traits< DistanceMap >::value_type Distance; return closeness_measure< Graph, Distance, T, Reciprocal >(); } template < typename Graph, typename DistanceMap, typename Measure, typename Combinator > inline typename Measure::result_type closeness_centrality( const Graph& g, DistanceMap dist, Measure measure, Combinator combine) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< DistanceMap, Vertex >)); typedef typename property_traits< DistanceMap >::value_type Distance; BOOST_CONCEPT_ASSERT((NumericValueConcept< Distance >)); BOOST_CONCEPT_ASSERT((DistanceMeasureConcept< Measure, Graph >)); Distance n = detail::combine_distances(g, dist, combine, Distance(0)); return measure(n, g); } template < typename Graph, typename DistanceMap, typename Measure > inline typename Measure::result_type closeness_centrality( const Graph& g, DistanceMap dist, Measure measure) { BOOST_CONCEPT_ASSERT((GraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< DistanceMap, Vertex >)); typedef typename property_traits< DistanceMap >::value_type Distance; return closeness_centrality(g, dist, measure, std::plus< Distance >()); } template < typename Graph, typename DistanceMap > inline double closeness_centrality(const Graph& g, DistanceMap dist) { return closeness_centrality(g, dist, measure_closeness(g, dist)); } template < typename T, typename Graph, typename DistanceMap > inline T closeness_centrality(const Graph& g, DistanceMap dist) { return closeness_centrality(g, dist, measure_closeness< T >(g, dist)); } template < typename Graph, typename DistanceMatrixMap, typename CentralityMap, typename Measure > inline void all_closeness_centralities( const Graph& g, DistanceMatrixMap dist, CentralityMap cent, Measure measure) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT( (ReadablePropertyMapConcept< DistanceMatrixMap, Vertex >)); typedef typename property_traits< DistanceMatrixMap >::value_type DistanceMap; BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< DistanceMap, Vertex >)); BOOST_CONCEPT_ASSERT((WritablePropertyMapConcept< CentralityMap, Vertex >)); typedef typename property_traits< CentralityMap >::value_type Centrality; typename graph_traits< Graph >::vertex_iterator i, end; for (boost::tie(i, end) = vertices(g); i != end; ++i) { DistanceMap dm = get(dist, *i); Centrality c = closeness_centrality(g, dm, measure); put(cent, *i, c); } } template < typename Graph, typename DistanceMatrixMap, typename CentralityMap > inline void all_closeness_centralities( const Graph& g, DistanceMatrixMap dist, CentralityMap cent) { BOOST_CONCEPT_ASSERT((GraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT( (ReadablePropertyMapConcept< DistanceMatrixMap, Vertex >)); typedef typename property_traits< DistanceMatrixMap >::value_type DistanceMap; BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< DistanceMap, Vertex >)); typedef typename property_traits< CentralityMap >::value_type Result; all_closeness_centralities( g, dist, cent, measure_closeness< Result >(g, DistanceMap())); } } /* namespace boost */ #endif dag_shortest_paths.hpp 0000644 00000013660 15125521275 0011155 0 ustar 00 //======================================================================= // Copyright 2002 Indiana University. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_DAG_SHORTEST_PATHS_HPP #define BOOST_GRAPH_DAG_SHORTEST_PATHS_HPP #include <boost/graph/topological_sort.hpp> #include <boost/graph/dijkstra_shortest_paths.hpp> // single-source shortest paths for a Directed Acyclic Graph (DAG) namespace boost { // Initalize distances and call depth first search template < class VertexListGraph, class DijkstraVisitor, class DistanceMap, class WeightMap, class ColorMap, class PredecessorMap, class Compare, class Combine, class DistInf, class DistZero > inline void dag_shortest_paths(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, DistanceMap distance, WeightMap weight, ColorMap color, PredecessorMap pred, DijkstraVisitor vis, Compare compare, Combine combine, DistInf inf, DistZero zero) { typedef typename graph_traits< VertexListGraph >::vertex_descriptor Vertex; std::vector< Vertex > rev_topo_order; rev_topo_order.reserve(num_vertices(g)); // Call 'depth_first_visit', not 'topological_sort', because we don't // want to traverse the entire graph, only vertices reachable from 's', // and 'topological_sort' will traverse everything. The logic below // is the same as for 'topological_sort', only we call 'depth_first_visit' // and 'topological_sort' calls 'depth_first_search'. topo_sort_visitor< std::back_insert_iterator< std::vector< Vertex > > > topo_visitor(std::back_inserter(rev_topo_order)); depth_first_visit(g, s, topo_visitor, color); typename graph_traits< VertexListGraph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { put(distance, *ui, inf); put(pred, *ui, *ui); } put(distance, s, zero); vis.discover_vertex(s, g); typename std::vector< Vertex >::reverse_iterator i; for (i = rev_topo_order.rbegin(); i != rev_topo_order.rend(); ++i) { Vertex u = *i; vis.examine_vertex(u, g); typename graph_traits< VertexListGraph >::out_edge_iterator e, e_end; for (boost::tie(e, e_end) = out_edges(u, g); e != e_end; ++e) { vis.discover_vertex(target(*e, g), g); bool decreased = relax(*e, g, weight, pred, distance, combine, compare); if (decreased) vis.edge_relaxed(*e, g); else vis.edge_not_relaxed(*e, g); } vis.finish_vertex(u, g); } } namespace detail { // Defaults are the same as Dijkstra's algorithm // Handle Distance Compare, Combine, Inf and Zero defaults template < class VertexListGraph, class DijkstraVisitor, class DistanceMap, class WeightMap, class ColorMap, class IndexMap, class Params > inline void dag_sp_dispatch2(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, DistanceMap distance, WeightMap weight, ColorMap color, IndexMap /*id*/, DijkstraVisitor vis, const Params& params) { typedef typename property_traits< DistanceMap >::value_type D; dummy_property_map p_map; D inf = choose_param(get_param(params, distance_inf_t()), (std::numeric_limits< D >::max)()); dag_shortest_paths(g, s, distance, weight, color, choose_param(get_param(params, vertex_predecessor), p_map), vis, choose_param( get_param(params, distance_compare_t()), std::less< D >()), choose_param( get_param(params, distance_combine_t()), closed_plus< D >(inf)), inf, choose_param(get_param(params, distance_zero_t()), D())); } // Handle DistanceMap and ColorMap defaults template < class VertexListGraph, class DijkstraVisitor, class DistanceMap, class WeightMap, class ColorMap, class IndexMap, class Params > inline void dag_sp_dispatch1(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, DistanceMap distance, WeightMap weight, ColorMap color, IndexMap id, DijkstraVisitor vis, const Params& params) { typedef typename property_traits< WeightMap >::value_type T; typename std::vector< T >::size_type n; n = is_default_param(distance) ? num_vertices(g) : 1; std::vector< T > distance_map(n); n = is_default_param(color) ? num_vertices(g) : 1; std::vector< default_color_type > color_map(n); dag_sp_dispatch2(g, s, choose_param(distance, make_iterator_property_map( distance_map.begin(), id, distance_map[0])), weight, choose_param(color, make_iterator_property_map( color_map.begin(), id, color_map[0])), id, vis, params); } } // namespace detail template < class VertexListGraph, class Param, class Tag, class Rest > inline void dag_shortest_paths(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, const bgl_named_params< Param, Tag, Rest >& params) { // assert that the graph is directed... null_visitor null_vis; detail::dag_sp_dispatch1(g, s, get_param(params, vertex_distance), choose_const_pmap(get_param(params, edge_weight), g, edge_weight), get_param(params, vertex_color), choose_const_pmap(get_param(params, vertex_index), g, vertex_index), choose_param( get_param(params, graph_visitor), make_dijkstra_visitor(null_vis)), params); } } // namespace boost #endif // BOOST_GRAPH_DAG_SHORTEST_PATHS_HPP graph_mutability_traits.hpp 0000644 00000011603 15125521275 0012215 0 ustar 00 // Copyright (C) 2009 Andrew Sutton // // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GRAPH_MUTABILITY_TRAITS_HPP #define BOOST_GRAPH_MUTABILITY_TRAITS_HPP #include <boost/config.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/and.hpp> #include <boost/mpl/bool.hpp> #include <boost/type_traits/is_same.hpp> namespace boost { // The mutabiltiy categories classify graphs by their mutating operations // on the edge and vertex sets. This is a substantially more refined // categorization than the MutableGraph and MutablePropertyGraph denote. // Currently, this framework is only used in the graph tests to help // dispatch test to the correct places. However, there are probably some // constructive or destructive algorithms (i.e., graph generators) that // may use these to describe requirements on graph inputs. struct add_vertex_tag { }; struct add_vertex_property_tag : virtual add_vertex_tag { }; struct add_edge_tag { }; struct add_edge_property_tag : virtual add_edge_tag { }; struct remove_vertex_tag { }; struct remove_edge_tag { }; struct mutable_vertex_graph_tag : virtual add_vertex_tag, virtual remove_vertex_tag { }; struct mutable_vertex_property_graph_tag : virtual add_vertex_property_tag, virtual remove_vertex_tag { }; struct mutable_edge_graph_tag : virtual add_edge_tag, virtual remove_edge_tag { }; struct mutable_edge_property_graph_tag : virtual add_edge_property_tag, virtual remove_edge_tag { }; struct mutable_graph_tag : virtual mutable_vertex_graph_tag, virtual mutable_edge_graph_tag { }; struct mutable_property_graph_tag : virtual mutable_vertex_property_graph_tag, virtual mutable_edge_property_graph_tag { }; // Some graphs just don't like to be torn down. Note this only restricts // teardown to the set of vertices, not the vertex set. // TODO: Find a better name for this tag. struct add_only_property_graph_tag : virtual add_vertex_property_tag, virtual mutable_edge_property_graph_tag { }; /** * The graph_mutability_traits provide methods for determining the * interfaces supported by graph classes for adding and removing vertices * and edges. */ template < typename Graph > struct graph_mutability_traits { typedef typename Graph::mutability_category category; }; template < typename Graph > struct graph_has_add_vertex : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, add_vertex_tag >::value > { }; template < typename Graph > struct graph_has_add_vertex_with_property : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, add_vertex_property_tag >::value > { }; template < typename Graph > struct graph_has_remove_vertex : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, remove_vertex_tag >::value > { }; template < typename Graph > struct graph_has_add_edge : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, add_edge_tag >::value > { }; template < typename Graph > struct graph_has_add_edge_with_property : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, add_edge_property_tag >::value > { }; template < typename Graph > struct graph_has_remove_edge : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, remove_edge_tag >::value > { }; template < typename Graph > struct is_mutable_vertex_graph : mpl::and_< graph_has_add_vertex< Graph >, graph_has_remove_vertex< Graph > > { }; template < typename Graph > struct is_mutable_vertex_property_graph : mpl::and_< graph_has_add_vertex_with_property< Graph >, graph_has_remove_vertex< Graph > > { }; template < typename Graph > struct is_mutable_edge_graph : mpl::and_< graph_has_add_edge< Graph >, graph_has_remove_edge< Graph > > { }; template < typename Graph > struct is_mutable_edge_property_graph : mpl::and_< graph_has_add_edge_with_property< Graph >, graph_has_remove_edge< Graph > > { }; template < typename Graph > struct is_mutable_graph : mpl::and_< is_mutable_vertex_graph< Graph >, is_mutable_edge_graph< Graph > > { }; template < typename Graph > struct is_mutable_property_graph : mpl::and_< is_mutable_vertex_property_graph< Graph >, is_mutable_edge_property_graph< Graph > > { }; template < typename Graph > struct is_add_only_property_graph : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, add_only_property_graph_tag >::value > { }; /** @name Mutability Traits Specializations */ //@{ //@} } // namespace boost #endif gursoy_atun_layout.hpp 0000644 00000031700 15125521275 0011237 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Jeremiah Willcock // Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_GURSOY_ATUN_LAYOUT_HPP #define BOOST_GRAPH_GURSOY_ATUN_LAYOUT_HPP // Gürsoy-Atun graph layout, based on: // "Neighbourhood Preserving Load Balancing: A Self-Organizing Approach" // in 6th International Euro-Par Conference Munich, Germany, August 29 – // September 1, 2000 Proceedings, pp 234-241 // https://doi.org/10.1007/3-540-44520-X_32 #include <boost/config/no_tr1/cmath.hpp> #include <boost/throw_exception.hpp> #include <boost/assert.hpp> #include <vector> #include <exception> #include <algorithm> #include <boost/graph/visitors.hpp> #include <boost/graph/properties.hpp> #include <boost/random/uniform_01.hpp> #include <boost/random/linear_congruential.hpp> #include <boost/shared_ptr.hpp> #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/dijkstra_shortest_paths.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/graph/topology.hpp> namespace boost { namespace detail { struct over_distance_limit : public std::exception { }; template < typename PositionMap, typename NodeDistanceMap, typename Topology, typename Graph > struct update_position_visitor { typedef typename Topology::point_type Point; PositionMap position_map; NodeDistanceMap node_distance; const Topology& space; Point input_vector; double distance_limit; double learning_constant; double falloff_ratio; typedef boost::on_examine_vertex event_filter; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; update_position_visitor(PositionMap position_map, NodeDistanceMap node_distance, const Topology& space, const Point& input_vector, double distance_limit, double learning_constant, double falloff_ratio) : position_map(position_map) , node_distance(node_distance) , space(space) , input_vector(input_vector) , distance_limit(distance_limit) , learning_constant(learning_constant) , falloff_ratio(falloff_ratio) { } void operator()(vertex_descriptor v, const Graph&) const { #ifndef BOOST_NO_STDC_NAMESPACE using std::pow; #endif if (get(node_distance, v) > distance_limit) BOOST_THROW_EXCEPTION(over_distance_limit()); Point old_position = get(position_map, v); double distance = get(node_distance, v); double fraction = learning_constant * pow(falloff_ratio, distance * distance); put(position_map, v, space.move_position_toward( old_position, fraction, input_vector)); } }; template < typename EdgeWeightMap > struct gursoy_shortest { template < typename Graph, typename NodeDistanceMap, typename UpdatePosition > static inline void run(const Graph& g, typename graph_traits< Graph >::vertex_descriptor s, NodeDistanceMap node_distance, UpdatePosition& update_position, EdgeWeightMap weight) { boost::dijkstra_shortest_paths(g, s, weight_map(weight).visitor(boost::make_dijkstra_visitor( std::make_pair(boost::record_distances( node_distance, boost::on_edge_relaxed()), update_position)))); } }; template <> struct gursoy_shortest< dummy_property_map > { template < typename Graph, typename NodeDistanceMap, typename UpdatePosition > static inline void run(const Graph& g, typename graph_traits< Graph >::vertex_descriptor s, NodeDistanceMap node_distance, UpdatePosition& update_position, dummy_property_map) { boost::breadth_first_search(g, s, visitor(boost::make_bfs_visitor( std::make_pair(boost::record_distances( node_distance, boost::on_tree_edge()), update_position)))); } }; } // namespace detail template < typename VertexListAndIncidenceGraph, typename Topology, typename PositionMap, typename Diameter, typename VertexIndexMap, typename EdgeWeightMap > void gursoy_atun_step(const VertexListAndIncidenceGraph& graph, const Topology& space, PositionMap position, Diameter diameter, double learning_constant, VertexIndexMap vertex_index_map, EdgeWeightMap weight) { #ifndef BOOST_NO_STDC_NAMESPACE using std::exp; using std::pow; #endif typedef typename graph_traits< VertexListAndIncidenceGraph >::vertex_iterator vertex_iterator; typedef typename graph_traits< VertexListAndIncidenceGraph >::vertex_descriptor vertex_descriptor; typedef typename Topology::point_type point_type; vertex_iterator i, iend; std::vector< double > distance_from_input_vector(num_vertices(graph)); typedef boost::iterator_property_map< std::vector< double >::iterator, VertexIndexMap, double, double& > DistanceFromInputMap; DistanceFromInputMap distance_from_input( distance_from_input_vector.begin(), vertex_index_map); std::vector< double > node_distance_map_vector(num_vertices(graph)); typedef boost::iterator_property_map< std::vector< double >::iterator, VertexIndexMap, double, double& > NodeDistanceMap; NodeDistanceMap node_distance( node_distance_map_vector.begin(), vertex_index_map); point_type input_vector = space.random_point(); vertex_descriptor min_distance_loc = graph_traits< VertexListAndIncidenceGraph >::null_vertex(); double min_distance = 0.0; bool min_distance_unset = true; for (boost::tie(i, iend) = vertices(graph); i != iend; ++i) { double this_distance = space.distance(get(position, *i), input_vector); put(distance_from_input, *i, this_distance); if (min_distance_unset || this_distance < min_distance) { min_distance = this_distance; min_distance_loc = *i; } min_distance_unset = false; } BOOST_ASSERT(!min_distance_unset); // Graph must have at least one vertex boost::detail::update_position_visitor< PositionMap, NodeDistanceMap, Topology, VertexListAndIncidenceGraph > update_position(position, node_distance, space, input_vector, diameter, learning_constant, exp(-1. / (2 * diameter * diameter))); std::fill( node_distance_map_vector.begin(), node_distance_map_vector.end(), 0); try { typedef detail::gursoy_shortest< EdgeWeightMap > shortest; shortest::run( graph, min_distance_loc, node_distance, update_position, weight); } catch (const detail::over_distance_limit&) { /* Thrown to break out of BFS or Dijkstra early */ } } template < typename VertexListAndIncidenceGraph, typename Topology, typename PositionMap, typename VertexIndexMap, typename EdgeWeightMap > void gursoy_atun_refine(const VertexListAndIncidenceGraph& graph, const Topology& space, PositionMap position, int nsteps, double diameter_initial, double diameter_final, double learning_constant_initial, double learning_constant_final, VertexIndexMap vertex_index_map, EdgeWeightMap weight) { #ifndef BOOST_NO_STDC_NAMESPACE using std::exp; using std::pow; #endif typedef typename graph_traits< VertexListAndIncidenceGraph >::vertex_iterator vertex_iterator; vertex_iterator i, iend; double diameter_ratio = (double)diameter_final / diameter_initial; double learning_constant_ratio = learning_constant_final / learning_constant_initial; std::vector< double > distance_from_input_vector(num_vertices(graph)); typedef boost::iterator_property_map< std::vector< double >::iterator, VertexIndexMap, double, double& > DistanceFromInputMap; DistanceFromInputMap distance_from_input( distance_from_input_vector.begin(), vertex_index_map); std::vector< int > node_distance_map_vector(num_vertices(graph)); typedef boost::iterator_property_map< std::vector< int >::iterator, VertexIndexMap, double, double& > NodeDistanceMap; NodeDistanceMap node_distance( node_distance_map_vector.begin(), vertex_index_map); for (int round = 0; round < nsteps; ++round) { double part_done = (double)round / (nsteps - 1); // fprintf(stderr, "%2d%% done\n", int(rint(part_done * 100.))); int diameter = (int)(diameter_initial * pow(diameter_ratio, part_done)); double learning_constant = learning_constant_initial * pow(learning_constant_ratio, part_done); gursoy_atun_step(graph, space, position, diameter, learning_constant, vertex_index_map, weight); } } template < typename VertexListAndIncidenceGraph, typename Topology, typename PositionMap, typename VertexIndexMap, typename EdgeWeightMap > void gursoy_atun_layout(const VertexListAndIncidenceGraph& graph, const Topology& space, PositionMap position, int nsteps, double diameter_initial, double diameter_final, double learning_constant_initial, double learning_constant_final, VertexIndexMap vertex_index_map, EdgeWeightMap weight) { typedef typename graph_traits< VertexListAndIncidenceGraph >::vertex_iterator vertex_iterator; vertex_iterator i, iend; for (boost::tie(i, iend) = vertices(graph); i != iend; ++i) { put(position, *i, space.random_point()); } gursoy_atun_refine(graph, space, position, nsteps, diameter_initial, diameter_final, learning_constant_initial, learning_constant_final, vertex_index_map, weight); } template < typename VertexListAndIncidenceGraph, typename Topology, typename PositionMap, typename VertexIndexMap > void gursoy_atun_layout(const VertexListAndIncidenceGraph& graph, const Topology& space, PositionMap position, int nsteps, double diameter_initial, double diameter_final, double learning_constant_initial, double learning_constant_final, VertexIndexMap vertex_index_map) { gursoy_atun_layout(graph, space, position, nsteps, diameter_initial, diameter_final, learning_constant_initial, learning_constant_final, vertex_index_map, dummy_property_map()); } template < typename VertexListAndIncidenceGraph, typename Topology, typename PositionMap > void gursoy_atun_layout(const VertexListAndIncidenceGraph& graph, const Topology& space, PositionMap position, int nsteps, double diameter_initial, double diameter_final = 1.0, double learning_constant_initial = 0.8, double learning_constant_final = 0.2) { gursoy_atun_layout(graph, space, position, nsteps, diameter_initial, diameter_final, learning_constant_initial, learning_constant_final, get(vertex_index, graph)); } template < typename VertexListAndIncidenceGraph, typename Topology, typename PositionMap > void gursoy_atun_layout(const VertexListAndIncidenceGraph& graph, const Topology& space, PositionMap position, int nsteps) { #ifndef BOOST_NO_STDC_NAMESPACE using std::sqrt; #endif gursoy_atun_layout( graph, space, position, nsteps, sqrt((double)num_vertices(graph))); } template < typename VertexListAndIncidenceGraph, typename Topology, typename PositionMap > void gursoy_atun_layout(const VertexListAndIncidenceGraph& graph, const Topology& space, PositionMap position) { gursoy_atun_layout(graph, space, position, num_vertices(graph)); } template < typename VertexListAndIncidenceGraph, typename Topology, typename PositionMap, typename P, typename T, typename R > void gursoy_atun_layout(const VertexListAndIncidenceGraph& graph, const Topology& space, PositionMap position, const bgl_named_params< P, T, R >& params) { #ifndef BOOST_NO_STDC_NAMESPACE using std::sqrt; #endif std::pair< double, double > diam(sqrt(double(num_vertices(graph))), 1.0); std::pair< double, double > learn(0.8, 0.2); gursoy_atun_layout(graph, space, position, choose_param(get_param(params, iterations_t()), num_vertices(graph)), choose_param(get_param(params, diameter_range_t()), diam).first, choose_param(get_param(params, diameter_range_t()), diam).second, choose_param(get_param(params, learning_constant_range_t()), learn) .first, choose_param(get_param(params, learning_constant_range_t()), learn) .second, choose_const_pmap(get_param(params, vertex_index), graph, vertex_index), choose_param(get_param(params, edge_weight), dummy_property_map())); } } // namespace boost #endif // BOOST_GRAPH_GURSOY_ATUN_LAYOUT_HPP astar_search.hpp 0000644 00000064160 15125521275 0007730 0 ustar 00 // //======================================================================= // Copyright (c) 2004 Kristopher Beevers // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_ASTAR_SEARCH_HPP #define BOOST_GRAPH_ASTAR_SEARCH_HPP #include <functional> #include <vector> #include <boost/limits.hpp> #include <boost/throw_exception.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/graph/relax.hpp> #include <boost/graph/exception.hpp> #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/graph/detail/d_ary_heap.hpp> #include <boost/graph/property_maps/constant_property_map.hpp> #include <boost/property_map/property_map.hpp> #include <boost/property_map/vector_property_map.hpp> #include <boost/property_map/function_property_map.hpp> #include <boost/concept/assert.hpp> namespace boost { template < class Heuristic, class Graph > struct AStarHeuristicConcept { void constraints() { BOOST_CONCEPT_ASSERT((CopyConstructibleConcept< Heuristic >)); h(u); } Heuristic h; typename graph_traits< Graph >::vertex_descriptor u; }; template < class Graph, class CostType > class astar_heuristic { public: typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef Vertex argument_type; typedef CostType result_type; astar_heuristic() {} CostType operator()(Vertex u) { return static_cast< CostType >(0); } }; template < class Visitor, class Graph > struct AStarVisitorConcept { void constraints() { BOOST_CONCEPT_ASSERT((CopyConstructibleConcept< Visitor >)); vis.initialize_vertex(u, g); vis.discover_vertex(u, g); vis.examine_vertex(u, g); vis.examine_edge(e, g); vis.edge_relaxed(e, g); vis.edge_not_relaxed(e, g); vis.black_target(e, g); vis.finish_vertex(u, g); } Visitor vis; Graph g; typename graph_traits< Graph >::vertex_descriptor u; typename graph_traits< Graph >::edge_descriptor e; }; template < class Visitors = null_visitor > class astar_visitor : public bfs_visitor< Visitors > { public: astar_visitor() {} astar_visitor(Visitors vis) : bfs_visitor< Visitors >(vis) {} template < class Edge, class Graph > void edge_relaxed(Edge e, const Graph& g) { invoke_visitors(this->m_vis, e, g, on_edge_relaxed()); } template < class Edge, class Graph > void edge_not_relaxed(Edge e, const Graph& g) { invoke_visitors(this->m_vis, e, g, on_edge_not_relaxed()); } private: template < class Edge, class Graph > void tree_edge(Edge e, const Graph& g) { } template < class Edge, class Graph > void non_tree_edge(Edge e, const Graph& g) { } }; template < class Visitors > astar_visitor< Visitors > make_astar_visitor(Visitors vis) { return astar_visitor< Visitors >(vis); } typedef astar_visitor<> default_astar_visitor; namespace detail { template < class AStarHeuristic, class UniformCostVisitor, class UpdatableQueue, class PredecessorMap, class CostMap, class DistanceMap, class WeightMap, class ColorMap, class BinaryFunction, class BinaryPredicate > struct astar_bfs_visitor { typedef typename property_traits< CostMap >::value_type C; typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; typedef typename property_traits< DistanceMap >::value_type distance_type; astar_bfs_visitor(AStarHeuristic h, UniformCostVisitor vis, UpdatableQueue& Q, PredecessorMap p, CostMap c, DistanceMap d, WeightMap w, ColorMap col, BinaryFunction combine, BinaryPredicate compare, C zero) : m_h(h) , m_vis(vis) , m_Q(Q) , m_predecessor(p) , m_cost(c) , m_distance(d) , m_weight(w) , m_color(col) , m_combine(combine) , m_compare(compare) , m_zero(zero) { } template < class Vertex, class Graph > void initialize_vertex(Vertex u, const Graph& g) { m_vis.initialize_vertex(u, g); } template < class Vertex, class Graph > void discover_vertex(Vertex u, const Graph& g) { m_vis.discover_vertex(u, g); } template < class Vertex, class Graph > void examine_vertex(Vertex u, const Graph& g) { m_vis.examine_vertex(u, g); } template < class Vertex, class Graph > void finish_vertex(Vertex u, const Graph& g) { m_vis.finish_vertex(u, g); } template < class Edge, class Graph > void examine_edge(Edge e, const Graph& g) { if (m_compare(get(m_weight, e), m_zero)) BOOST_THROW_EXCEPTION(negative_edge()); m_vis.examine_edge(e, g); } template < class Edge, class Graph > void non_tree_edge(Edge, const Graph&) { } template < class Edge, class Graph > void tree_edge(Edge e, const Graph& g) { using boost::get; bool m_decreased = relax(e, g, m_weight, m_predecessor, m_distance, m_combine, m_compare); if (m_decreased) { m_vis.edge_relaxed(e, g); put(m_cost, target(e, g), m_combine( get(m_distance, target(e, g)), m_h(target(e, g)))); } else m_vis.edge_not_relaxed(e, g); } template < class Edge, class Graph > void gray_target(Edge e, const Graph& g) { using boost::get; bool m_decreased = relax(e, g, m_weight, m_predecessor, m_distance, m_combine, m_compare); if (m_decreased) { put(m_cost, target(e, g), m_combine( get(m_distance, target(e, g)), m_h(target(e, g)))); m_Q.update(target(e, g)); m_vis.edge_relaxed(e, g); } else m_vis.edge_not_relaxed(e, g); } template < class Edge, class Graph > void black_target(Edge e, const Graph& g) { using boost::get; bool m_decreased = relax(e, g, m_weight, m_predecessor, m_distance, m_combine, m_compare); if (m_decreased) { m_vis.edge_relaxed(e, g); put(m_cost, target(e, g), m_combine( get(m_distance, target(e, g)), m_h(target(e, g)))); m_Q.push(target(e, g)); put(m_color, target(e, g), Color::gray()); m_vis.black_target(e, g); } else m_vis.edge_not_relaxed(e, g); } AStarHeuristic m_h; UniformCostVisitor m_vis; UpdatableQueue& m_Q; PredecessorMap m_predecessor; CostMap m_cost; DistanceMap m_distance; WeightMap m_weight; ColorMap m_color; BinaryFunction m_combine; BinaryPredicate m_compare; C m_zero; }; } // namespace detail template < typename VertexListGraph, typename AStarHeuristic, typename AStarVisitor, typename PredecessorMap, typename CostMap, typename DistanceMap, typename WeightMap, typename ColorMap, typename VertexIndexMap, typename CompareFunction, typename CombineFunction, typename CostInf, typename CostZero > inline void astar_search_no_init(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, AStarHeuristic h, AStarVisitor vis, PredecessorMap predecessor, CostMap cost, DistanceMap distance, WeightMap weight, ColorMap color, VertexIndexMap index_map, CompareFunction compare, CombineFunction combine, CostInf /*inf*/, CostZero zero) { typedef typename graph_traits< VertexListGraph >::vertex_descriptor Vertex; typedef boost::vector_property_map< std::size_t, VertexIndexMap > IndexInHeapMap; IndexInHeapMap index_in_heap(index_map); typedef d_ary_heap_indirect< Vertex, 4, IndexInHeapMap, CostMap, CompareFunction > MutableQueue; MutableQueue Q(cost, index_in_heap, compare); detail::astar_bfs_visitor< AStarHeuristic, AStarVisitor, MutableQueue, PredecessorMap, CostMap, DistanceMap, WeightMap, ColorMap, CombineFunction, CompareFunction > bfs_vis(h, vis, Q, predecessor, cost, distance, weight, color, combine, compare, zero); breadth_first_visit(g, s, Q, bfs_vis, color); } namespace graph_detail { template < typename A, typename B > struct select1st { typedef std::pair< A, B > argument_type; typedef A result_type; A operator()(const std::pair< A, B >& p) const { return p.first; } }; } template < typename VertexListGraph, typename AStarHeuristic, typename AStarVisitor, typename PredecessorMap, typename CostMap, typename DistanceMap, typename WeightMap, typename CompareFunction, typename CombineFunction, typename CostInf, typename CostZero > inline void astar_search_no_init_tree(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, AStarHeuristic h, AStarVisitor vis, PredecessorMap predecessor, CostMap cost, DistanceMap distance, WeightMap weight, CompareFunction compare, CombineFunction combine, CostInf /*inf*/, CostZero zero) { typedef typename graph_traits< VertexListGraph >::vertex_descriptor Vertex; typedef typename property_traits< DistanceMap >::value_type Distance; typedef d_ary_heap_indirect< std::pair< Distance, Vertex >, 4, null_property_map< std::pair< Distance, Vertex >, std::size_t >, function_property_map< graph_detail::select1st< Distance, Vertex >, std::pair< Distance, Vertex > >, CompareFunction > MutableQueue; MutableQueue Q(make_function_property_map< std::pair< Distance, Vertex > >( graph_detail::select1st< Distance, Vertex >()), null_property_map< std::pair< Distance, Vertex >, std::size_t >(), compare); vis.discover_vertex(s, g); Q.push(std::make_pair(get(cost, s), s)); while (!Q.empty()) { Vertex v; Distance v_rank; boost::tie(v_rank, v) = Q.top(); Q.pop(); vis.examine_vertex(v, g); BGL_FORALL_OUTEDGES_T(v, e, g, VertexListGraph) { Vertex w = target(e, g); vis.examine_edge(e, g); Distance e_weight = get(weight, e); if (compare(e_weight, zero)) BOOST_THROW_EXCEPTION(negative_edge()); bool decreased = relax(e, g, weight, predecessor, distance, combine, compare); combine(get(distance, v), e_weight); if (decreased) { vis.edge_relaxed(e, g); Distance w_rank = combine(get(distance, w), h(w)); put(cost, w, w_rank); vis.discover_vertex(w, g); Q.push(std::make_pair(w_rank, w)); } else { vis.edge_not_relaxed(e, g); } } vis.finish_vertex(v, g); } } // Non-named parameter interface template < typename VertexListGraph, typename AStarHeuristic, typename AStarVisitor, typename PredecessorMap, typename CostMap, typename DistanceMap, typename WeightMap, typename VertexIndexMap, typename ColorMap, typename CompareFunction, typename CombineFunction, typename CostInf, typename CostZero > inline void astar_search(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, AStarHeuristic h, AStarVisitor vis, PredecessorMap predecessor, CostMap cost, DistanceMap distance, WeightMap weight, VertexIndexMap index_map, ColorMap color, CompareFunction compare, CombineFunction combine, CostInf inf, CostZero zero) { typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; typename graph_traits< VertexListGraph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { put(color, *ui, Color::white()); put(distance, *ui, inf); put(cost, *ui, inf); put(predecessor, *ui, *ui); vis.initialize_vertex(*ui, g); } put(distance, s, zero); put(cost, s, h(s)); astar_search_no_init(g, s, h, vis, predecessor, cost, distance, weight, color, index_map, compare, combine, inf, zero); } // Non-named parameter interface template < typename VertexListGraph, typename AStarHeuristic, typename AStarVisitor, typename PredecessorMap, typename CostMap, typename DistanceMap, typename WeightMap, typename CompareFunction, typename CombineFunction, typename CostInf, typename CostZero > inline void astar_search_tree(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, AStarHeuristic h, AStarVisitor vis, PredecessorMap predecessor, CostMap cost, DistanceMap distance, WeightMap weight, CompareFunction compare, CombineFunction combine, CostInf inf, CostZero zero) { typename graph_traits< VertexListGraph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { put(distance, *ui, inf); put(cost, *ui, inf); put(predecessor, *ui, *ui); vis.initialize_vertex(*ui, g); } put(distance, s, zero); put(cost, s, h(s)); astar_search_no_init_tree(g, s, h, vis, predecessor, cost, distance, weight, compare, combine, inf, zero); } // Named parameter interfaces template < typename VertexListGraph, typename AStarHeuristic, typename P, typename T, typename R > void astar_search(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, AStarHeuristic h, const bgl_named_params< P, T, R >& params) { using namespace boost::graph::keywords; typedef bgl_named_params< P, T, R > params_type; BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params) // Distance type is the value type of the distance map if there is one, // otherwise the value type of the weight map. typedef typename boost::detail::override_const_property_result< arg_pack_type, boost::graph::keywords::tag::weight_map, edge_weight_t, VertexListGraph >::type weight_map_type; typedef typename boost::property_traits< weight_map_type >::value_type D; const D inf = arg_pack[_distance_inf || detail::get_max< D >()]; const D zero_actual = D(); const D zero_d = arg_pack[_distance_zero | zero_actual]; null_visitor null_vis; astar_visitor< null_visitor > default_visitor(null_vis); typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::visitor, dummy_property_map& >::type vis = arg_pack[_visitor | default_visitor]; dummy_property_map dummy_prop; typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::predecessor_map, dummy_property_map& >::type pred_map = arg_pack[_predecessor_map | dummy_prop]; boost::detail::make_property_map_from_arg_pack_gen< boost::graph::keywords::tag::rank_map, D > rank_map_gen(zero_actual); typename boost::detail::map_maker< VertexListGraph, arg_pack_type, boost::graph::keywords::tag::rank_map, D >::map_type r_map = rank_map_gen(g, arg_pack); boost::detail::make_property_map_from_arg_pack_gen< boost::graph::keywords::tag::distance_map, D > dist_map_gen(zero_actual); typename boost::detail::map_maker< VertexListGraph, arg_pack_type, boost::graph::keywords::tag::distance_map, D >::map_type dist_map = dist_map_gen(g, arg_pack); weight_map_type w_map = detail::override_const_property( arg_pack, _weight_map, g, edge_weight); typename boost::detail::override_const_property_result< arg_pack_type, boost::graph::keywords::tag::vertex_index_map, vertex_index_t, VertexListGraph >::type v_i_map = detail::override_const_property( arg_pack, _vertex_index_map, g, vertex_index); typename boost::detail::map_maker< VertexListGraph, arg_pack_type, boost::graph::keywords::tag::color_map, boost::default_color_type >::map_type c_map = boost::detail::make_color_map_from_arg_pack(g, arg_pack); std::less< D > default_compare; typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::distance_compare, std::less< D >& >::type dist_comp = arg_pack[_distance_compare | default_compare]; closed_plus< D > default_combine(inf); typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::distance_combine, closed_plus< D >& >::type dist_comb = arg_pack[_distance_combine | default_combine]; astar_search(g, s, h, vis, pred_map, r_map, dist_map, w_map, v_i_map, c_map, dist_comp, dist_comb, inf, zero_d); } template < typename VertexListGraph, typename AStarHeuristic, typename P, typename T, typename R > void astar_search_tree(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, AStarHeuristic h, const bgl_named_params< P, T, R >& params) { using namespace boost::graph::keywords; typedef bgl_named_params< P, T, R > params_type; BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params) // Distance type is the value type of the distance map if there is one, // otherwise the value type of the weight map. typedef typename boost::detail::override_const_property_result< arg_pack_type, boost::graph::keywords::tag::weight_map, edge_weight_t, VertexListGraph >::type weight_map_type; typedef typename boost::property_traits< weight_map_type >::value_type D; const D inf = arg_pack[_distance_inf || detail::get_max< D >()]; const D zero_actual = D(); const D zero_d = arg_pack[_distance_zero | zero_actual]; null_visitor null_vis; astar_visitor< null_visitor > default_visitor(null_vis); typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::visitor, dummy_property_map& >::type vis = arg_pack[_visitor | default_visitor]; dummy_property_map dummy_prop; typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::predecessor_map, dummy_property_map& >::type pred_map = arg_pack[_predecessor_map | dummy_prop]; boost::detail::make_property_map_from_arg_pack_gen< boost::graph::keywords::tag::rank_map, D > rank_map_gen(zero_actual); typename boost::detail::map_maker< VertexListGraph, arg_pack_type, boost::graph::keywords::tag::rank_map, D >::map_type r_map = rank_map_gen(g, arg_pack); boost::detail::make_property_map_from_arg_pack_gen< boost::graph::keywords::tag::distance_map, D > dist_map_gen(zero_actual); typename boost::detail::map_maker< VertexListGraph, arg_pack_type, boost::graph::keywords::tag::distance_map, D >::map_type dist_map = dist_map_gen(g, arg_pack); weight_map_type w_map = detail::override_const_property( arg_pack, _weight_map, g, edge_weight); std::less< D > default_compare; typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::distance_compare, std::less< D >& >::type dist_comp = arg_pack[_distance_compare | default_compare]; closed_plus< D > default_combine(inf); typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::distance_combine, closed_plus< D >& >::type dist_comb = arg_pack[_distance_combine | default_combine]; astar_search_tree(g, s, h, vis, pred_map, r_map, dist_map, w_map, dist_comp, dist_comb, inf, zero_d); } template < typename VertexListGraph, typename AStarHeuristic, typename P, typename T, typename R > void astar_search_no_init(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, AStarHeuristic h, const bgl_named_params< P, T, R >& params) { using namespace boost::graph::keywords; typedef bgl_named_params< P, T, R > params_type; BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params) typedef typename boost::detail::override_const_property_result< arg_pack_type, boost::graph::keywords::tag::weight_map, edge_weight_t, VertexListGraph >::type weight_map_type; typedef typename boost::property_traits< weight_map_type >::value_type D; const D inf = arg_pack[_distance_inf || detail::get_max< D >()]; const D zero_actual = D(); const D zero_d = arg_pack[_distance_zero | zero_actual]; null_visitor null_vis; astar_visitor< null_visitor > default_visitor(null_vis); typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::visitor, dummy_property_map& >::type vis = arg_pack[_visitor | default_visitor]; dummy_property_map dummy_prop; typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::predecessor_map, dummy_property_map& >::type pred_map = arg_pack[_predecessor_map | dummy_prop]; boost::detail::make_property_map_from_arg_pack_gen< boost::graph::keywords::tag::rank_map, D > rank_map_gen(zero_actual); typename boost::detail::map_maker< VertexListGraph, arg_pack_type, boost::graph::keywords::tag::rank_map, D >::map_type r_map = rank_map_gen(g, arg_pack); boost::detail::make_property_map_from_arg_pack_gen< boost::graph::keywords::tag::distance_map, D > dist_map_gen(zero_actual); typename boost::detail::map_maker< VertexListGraph, arg_pack_type, boost::graph::keywords::tag::distance_map, D >::map_type dist_map = dist_map_gen(g, arg_pack); weight_map_type w_map = detail::override_const_property( arg_pack, _weight_map, g, edge_weight); typename boost::detail::map_maker< VertexListGraph, arg_pack_type, boost::graph::keywords::tag::color_map, boost::default_color_type >::map_type c_map = boost::detail::make_color_map_from_arg_pack(g, arg_pack); typename boost::detail::override_const_property_result< arg_pack_type, boost::graph::keywords::tag::vertex_index_map, vertex_index_t, VertexListGraph >::type v_i_map = detail::override_const_property( arg_pack, _vertex_index_map, g, vertex_index); std::less< D > default_compare; typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::distance_compare, std::less< D >& >::type dist_comp = arg_pack[_distance_compare | default_compare]; closed_plus< D > default_combine(inf); typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::distance_combine, closed_plus< D >& >::type dist_comb = arg_pack[_distance_combine | default_combine]; astar_search_no_init(g, s, h, vis, pred_map, r_map, dist_map, w_map, c_map, v_i_map, dist_comp, dist_comb, inf, zero_d); } template < typename VertexListGraph, typename AStarHeuristic, typename P, typename T, typename R > void astar_search_no_init_tree(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, AStarHeuristic h, const bgl_named_params< P, T, R >& params) { using namespace boost::graph::keywords; typedef bgl_named_params< P, T, R > params_type; BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params) typedef typename boost::detail::override_const_property_result< arg_pack_type, boost::graph::keywords::tag::weight_map, edge_weight_t, VertexListGraph >::type weight_map_type; typedef typename boost::property_traits< weight_map_type >::value_type D; const D inf = arg_pack[_distance_inf || detail::get_max< D >()]; const D zero_actual = D(); const D zero_d = arg_pack[_distance_zero | zero_actual]; null_visitor null_vis; astar_visitor< null_visitor > default_visitor(null_vis); typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::visitor, dummy_property_map& >::type vis = arg_pack[_visitor | default_visitor]; dummy_property_map dummy_prop; typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::predecessor_map, dummy_property_map& >::type pred_map = arg_pack[_predecessor_map | dummy_prop]; boost::detail::make_property_map_from_arg_pack_gen< boost::graph::keywords::tag::rank_map, D > rank_map_gen(zero_actual); typename boost::detail::map_maker< VertexListGraph, arg_pack_type, boost::graph::keywords::tag::rank_map, D >::map_type r_map = rank_map_gen(g, arg_pack); boost::detail::make_property_map_from_arg_pack_gen< boost::graph::keywords::tag::distance_map, D > dist_map_gen(zero_actual); typename boost::detail::map_maker< VertexListGraph, arg_pack_type, boost::graph::keywords::tag::distance_map, D >::map_type dist_map = dist_map_gen(g, arg_pack); weight_map_type w_map = detail::override_const_property( arg_pack, _weight_map, g, edge_weight); std::less< D > default_compare; typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::distance_compare, std::less< D >& >::type dist_comp = arg_pack[_distance_compare | default_compare]; closed_plus< D > default_combine(inf); typename boost::parameter::binding< arg_pack_type, boost::graph::keywords::tag::distance_combine, closed_plus< D >& >::type dist_comb = arg_pack[_distance_combine | default_combine]; astar_search_no_init_tree(g, s, h, vis, pred_map, r_map, dist_map, w_map, dist_comp, dist_comb, inf, zero_d); } } // namespace boost #endif // BOOST_GRAPH_ASTAR_SEARCH_HPP bc_clustering.hpp 0000644 00000013461 15125521275 0010112 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_BETWEENNESS_CENTRALITY_CLUSTERING_HPP #define BOOST_GRAPH_BETWEENNESS_CENTRALITY_CLUSTERING_HPP #include <boost/graph/betweenness_centrality.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_utility.hpp> #include <boost/pending/indirect_cmp.hpp> #include <algorithm> #include <vector> #include <boost/property_map/property_map.hpp> namespace boost { /** Threshold termination function for the betweenness centrality * clustering algorithm. */ template < typename T > struct bc_clustering_threshold { typedef T centrality_type; /// Terminate clustering when maximum absolute edge centrality is /// below the given threshold. explicit bc_clustering_threshold(T threshold) : threshold(threshold), dividend(1.0) { } /** * Terminate clustering when the maximum edge centrality is below * the given threshold. * * @param threshold the threshold value * * @param g the graph on which the threshold will be calculated * * @param normalize when true, the threshold is compared against the * normalized edge centrality based on the input graph; otherwise, * the threshold is compared against the absolute edge centrality. */ template < typename Graph > bc_clustering_threshold(T threshold, const Graph& g, bool normalize = true) : threshold(threshold), dividend(1.0) { if (normalize) { typename graph_traits< Graph >::vertices_size_type n = num_vertices(g); dividend = T((n - 1) * (n - 2)) / T(2); } } /** Returns true when the given maximum edge centrality (potentially * normalized) falls below the threshold. */ template < typename Graph, typename Edge > bool operator()(T max_centrality, Edge, const Graph&) { return (max_centrality / dividend) < threshold; } protected: T threshold; T dividend; }; /** Graph clustering based on edge betweenness centrality. * * This algorithm implements graph clustering based on edge * betweenness centrality. It is an iterative algorithm, where in each * step it compute the edge betweenness centrality (via @ref * brandes_betweenness_centrality) and removes the edge with the * maximum betweenness centrality. The @p done function object * determines when the algorithm terminates (the edge found when the * algorithm terminates will not be removed). * * @param g The graph on which clustering will be performed. The type * of this parameter (@c MutableGraph) must be a model of the * VertexListGraph, IncidenceGraph, EdgeListGraph, and Mutable Graph * concepts. * * @param done The function object that indicates termination of the * algorithm. It must be a ternary function object thats accepts the * maximum centrality, the descriptor of the edge that will be * removed, and the graph @p g. * * @param edge_centrality (UTIL/OUT) The property map that will store * the betweenness centrality for each edge. When the algorithm * terminates, it will contain the edge centralities for the * graph. The type of this property map must model the * ReadWritePropertyMap concept. Defaults to an @c * iterator_property_map whose value type is * @c Done::centrality_type and using @c get(edge_index, g) for the * index map. * * @param vertex_index (IN) The property map that maps vertices to * indices in the range @c [0, num_vertices(g)). This type of this * property map must model the ReadablePropertyMap concept and its * value type must be an integral type. Defaults to * @c get(vertex_index, g). */ template < typename MutableGraph, typename Done, typename EdgeCentralityMap, typename VertexIndexMap > void betweenness_centrality_clustering(MutableGraph& g, Done done, EdgeCentralityMap edge_centrality, VertexIndexMap vertex_index) { typedef typename property_traits< EdgeCentralityMap >::value_type centrality_type; typedef typename graph_traits< MutableGraph >::edge_iterator edge_iterator; typedef typename graph_traits< MutableGraph >::edge_descriptor edge_descriptor; if (has_no_edges(g)) return; // Function object that compares the centrality of edges indirect_cmp< EdgeCentralityMap, std::less< centrality_type > > cmp( edge_centrality); bool is_done; do { brandes_betweenness_centrality(g, edge_centrality_map(edge_centrality) .vertex_index_map(vertex_index)); std::pair< edge_iterator, edge_iterator > edges_iters = edges(g); edge_descriptor e = *max_element(edges_iters.first, edges_iters.second, cmp); is_done = done(get(edge_centrality, e), e, g); if (!is_done) remove_edge(e, g); } while (!is_done && !has_no_edges(g)); } /** * \overload */ template < typename MutableGraph, typename Done, typename EdgeCentralityMap > void betweenness_centrality_clustering( MutableGraph& g, Done done, EdgeCentralityMap edge_centrality) { betweenness_centrality_clustering( g, done, edge_centrality, get(vertex_index, g)); } /** * \overload */ template < typename MutableGraph, typename Done > void betweenness_centrality_clustering(MutableGraph& g, Done done) { typedef typename Done::centrality_type centrality_type; std::vector< centrality_type > edge_centrality(num_edges(g)); betweenness_centrality_clustering(g, done, make_iterator_property_map(edge_centrality.begin(), get(edge_index, g)), get(vertex_index, g)); } } // end namespace boost #endif // BOOST_GRAPH_BETWEENNESS_CENTRALITY_CLUSTERING_HPP page_rank.hpp 0000644 00000014034 15125521275 0007213 0 ustar 00 // Copyright 2004-5 The Trustees of Indiana University. // Copyright 2002 Brad King and Douglas Gregor // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_PAGE_RANK_HPP #define BOOST_GRAPH_PAGE_RANK_HPP #include <boost/property_map/property_map.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/graph/overloading.hpp> #include <boost/graph/detail/mpi_include.hpp> #include <vector> namespace boost { namespace graph { struct n_iterations { explicit n_iterations(std::size_t n) : n(n) {} template < typename RankMap, typename Graph > bool operator()(const RankMap&, const Graph&) { return n-- == 0; } private: std::size_t n; }; namespace detail { template < typename Graph, typename RankMap, typename RankMap2 > void page_rank_step(const Graph& g, RankMap from_rank, RankMap2 to_rank, typename property_traits< RankMap >::value_type damping, incidence_graph_tag) { typedef typename property_traits< RankMap >::value_type rank_type; // Set new rank maps BGL_FORALL_VERTICES_T(v, g, Graph) put(to_rank, v, rank_type(1 - damping)); BGL_FORALL_VERTICES_T(u, g, Graph) { rank_type u_rank_out = damping * get(from_rank, u) / out_degree(u, g); BGL_FORALL_ADJ_T(u, v, g, Graph) put(to_rank, v, get(to_rank, v) + u_rank_out); } } template < typename Graph, typename RankMap, typename RankMap2 > void page_rank_step(const Graph& g, RankMap from_rank, RankMap2 to_rank, typename property_traits< RankMap >::value_type damping, bidirectional_graph_tag) { typedef typename property_traits< RankMap >::value_type damping_type; BGL_FORALL_VERTICES_T(v, g, Graph) { typename property_traits< RankMap >::value_type rank(0); BGL_FORALL_INEDGES_T(v, e, g, Graph) rank += get(from_rank, source(e, g)) / out_degree(source(e, g), g); put(to_rank, v, (damping_type(1) - damping) + damping * rank); } } } // end namespace detail template < typename Graph, typename RankMap, typename Done, typename RankMap2 > void page_rank(const Graph& g, RankMap rank_map, Done done, typename property_traits< RankMap >::value_type damping, typename graph_traits< Graph >::vertices_size_type n, RankMap2 rank_map2 BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { typedef typename property_traits< RankMap >::value_type rank_type; rank_type initial_rank = rank_type(rank_type(1) / n); BGL_FORALL_VERTICES_T(v, g, Graph) put(rank_map, v, initial_rank); bool to_map_2 = true; while ((to_map_2 && !done(rank_map, g)) || (!to_map_2 && !done(rank_map2, g))) { typedef typename graph_traits< Graph >::traversal_category category; if (to_map_2) { detail::page_rank_step( g, rank_map, rank_map2, damping, category()); } else { detail::page_rank_step( g, rank_map2, rank_map, damping, category()); } to_map_2 = !to_map_2; } if (!to_map_2) { BGL_FORALL_VERTICES_T(v, g, Graph) put(rank_map, v, get(rank_map2, v)); } } template < typename Graph, typename RankMap, typename Done > void page_rank(const Graph& g, RankMap rank_map, Done done, typename property_traits< RankMap >::value_type damping, typename graph_traits< Graph >::vertices_size_type n) { typedef typename property_traits< RankMap >::value_type rank_type; std::vector< rank_type > ranks2(num_vertices(g)); page_rank(g, rank_map, done, damping, n, make_iterator_property_map(ranks2.begin(), get(vertex_index, g))); } template < typename Graph, typename RankMap, typename Done > inline void page_rank(const Graph& g, RankMap rank_map, Done done, typename property_traits< RankMap >::value_type damping = 0.85) { page_rank(g, rank_map, done, damping, num_vertices(g)); } template < typename Graph, typename RankMap > inline void page_rank(const Graph& g, RankMap rank_map) { page_rank(g, rank_map, n_iterations(20)); } // TBD: this could be _much_ more efficient, using a queue to store // the vertices that should be reprocessed and keeping track of which // vertices are in the queue with a property map. Baah, this only // applies when we have a bidirectional graph. template < typename MutableGraph > void remove_dangling_links( MutableGraph& g BOOST_GRAPH_ENABLE_IF_MODELS_PARM( MutableGraph, vertex_list_graph_tag)) { typename graph_traits< MutableGraph >::vertices_size_type old_n; do { old_n = num_vertices(g); typename graph_traits< MutableGraph >::vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; /* in loop */) { typename graph_traits< MutableGraph >::vertex_descriptor v = *vi++; if (out_degree(v, g) == 0) { clear_vertex(v, g); remove_vertex(v, g); } } } while (num_vertices(g) < old_n); } } } // end namespace boost::graph #include BOOST_GRAPH_MPI_INCLUDE(< boost / graph / distributed / page_rank.hpp >) #endif // BOOST_GRAPH_PAGE_RANK_HPP connected_components.hpp 0000644 00000010056 15125521275 0011473 0 ustar 00 // //======================================================================= // Copyright 1997-2001 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_CONNECTED_COMPONENTS_HPP #define BOOST_GRAPH_CONNECTED_COMPONENTS_HPP #include <boost/config.hpp> #include <boost/graph/depth_first_search.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/overloading.hpp> #include <boost/graph/detail/mpi_include.hpp> #include <boost/static_assert.hpp> #include <boost/concept/assert.hpp> namespace boost { namespace detail { // This visitor is used both in the connected_components algorithm // and in the kosaraju strong components algorithm during the // second DFS traversal. template < class ComponentsMap > class components_recorder : public dfs_visitor<> { typedef typename property_traits< ComponentsMap >::value_type comp_type; public: components_recorder(ComponentsMap c, comp_type& c_count) : m_component(c), m_count(c_count) { } template < class Vertex, class Graph > void start_vertex(Vertex, Graph&) { if (m_count == (std::numeric_limits< comp_type >::max)()) m_count = 0; // start counting components at zero else ++m_count; } template < class Vertex, class Graph > void discover_vertex(Vertex u, Graph&) { put(m_component, u, m_count); } protected: ComponentsMap m_component; comp_type& m_count; }; } // namespace detail // This function computes the connected components of an undirected // graph using a single application of depth first search. template < class Graph, class ComponentMap, class P, class T, class R > inline typename property_traits< ComponentMap >::value_type connected_components(const Graph& g, ComponentMap c, const bgl_named_params< P, T, R >& params BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { if (num_vertices(g) == 0) return 0; typedef typename graph_traits< Graph >::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT((WritablePropertyMapConcept< ComponentMap, Vertex >)); typedef typename boost::graph_traits< Graph >::directed_category directed; BOOST_STATIC_ASSERT((boost::is_same< directed, undirected_tag >::value)); typedef typename property_traits< ComponentMap >::value_type comp_type; // c_count initialized to "nil" (with nil represented by (max)()) comp_type c_count((std::numeric_limits< comp_type >::max)()); detail::components_recorder< ComponentMap > vis(c, c_count); depth_first_search(g, params.visitor(vis)); return c_count + 1; } template < class Graph, class ComponentMap > inline typename property_traits< ComponentMap >::value_type connected_components(const Graph& g, ComponentMap c BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { if (num_vertices(g) == 0) return 0; typedef typename graph_traits< Graph >::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT((WritablePropertyMapConcept< ComponentMap, Vertex >)); // typedef typename boost::graph_traits<Graph>::directed_category directed; // BOOST_STATIC_ASSERT((boost::is_same<directed, undirected_tag>::value)); typedef typename property_traits< ComponentMap >::value_type comp_type; // c_count initialized to "nil" (with nil represented by (max)()) comp_type c_count((std::numeric_limits< comp_type >::max)()); detail::components_recorder< ComponentMap > vis(c, c_count); depth_first_search(g, visitor(vis)); return c_count + 1; } } // namespace boost #include BOOST_GRAPH_MPI_INCLUDE(< boost / graph / distributed / connected_components.hpp >) #endif // BOOST_GRAPH_CONNECTED_COMPONENTS_HPP stanford_graph.hpp 0000644 00000047236 15125521275 0010277 0 ustar 00 //======================================================================= // Copyright 1997-2001 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_SGB_GRAPH_HPP #define BOOST_GRAPH_SGB_GRAPH_HPP #include <boost/config.hpp> #include <boost/operators.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> // Thanks to Andreas Scherer for numerous suggestions and fixes! // This file adapts a Stanford GraphBase (SGB) Graph pointer into a // VertexListGraph. Note that a graph adaptor class is not needed, // SGB's Graph* is used as is. The VertexListGraph concept is fulfilled by // defining the appropriate non-member functions for Graph*. // // The PROTOTYPES change file extensions to SGB must be applied so // that the SGB functions have real prototypes which are necessary for // the C++ compiler. To apply the PROTOTYPES extensions, before you do // "make tests install" for SGB do "ln -s PROTOTYPES/* ." to the SGB // root directory (or just copy all the files from the PROTOTYPES // directory to the SGB root directory). // extern "C" { // We include all global definitions for the general stuff // of The Stanford GraphBase and its various graph generator // functions by reading all SGB headerfiles as in section 2 of // the "test_sample" program. #include <gb_graph.h> /* SGB data structures */ #include <gb_io.h> /* SGB input/output routines */ #include <gb_flip.h> /* random number generator */ #include <gb_dijk.h> /* routines for shortest paths */ #include <gb_basic.h> /* the basic graph operations */ #undef empty /* avoid name clash with C++ standard library */ inline Graph* empty(long n) /* and provide workaround */ { return board(n, 0L, 0L, 0L, 2L, 0L, 0L); } #include <gb_books.h> /* graphs based on literature */ #include <gb_econ.h> /* graphs based on economic data */ #include <gb_games.h> /* graphs based on football scores */ #undef ap /* avoid name clash with BGL parameter */ // ap ==> Vertex::u.I #include <gb_gates.h> /* graphs based on logic circuits */ #undef val /* avoid name clash with g++ headerfile stl_tempbuf.h */ // val ==> Vertex::x.I #include <gb_lisa.h> /* graphs based on Mona Lisa */ #include <gb_miles.h> /* graphs based on mileage data */ #include <gb_plane.h> /* planar graphs */ #include <gb_raman.h> /* Ramanujan graphs */ #include <gb_rand.h> /* random graphs */ #include <gb_roget.h> /* graphs based on Roget's Thesaurus */ #include <gb_save.h> /* we save results in ASCII format */ #include <gb_words.h> /* five-letter-word graphs */ #undef weight /* avoid name clash with BGL parameter */ // weight ==> Vertex::u.I } namespace boost { class sgb_edge; } class sgb_out_edge_iterator; class sgb_adj_iterator; class sgb_vertex_iterator; namespace boost { typedef Graph* sgb_graph_ptr; typedef const Graph* sgb_const_graph_ptr; struct sgb_traversal_tag : public virtual vertex_list_graph_tag, public virtual incidence_graph_tag, public virtual adjacency_graph_tag { }; template <> struct graph_traits< sgb_graph_ptr > { typedef Vertex* vertex_descriptor; typedef boost::sgb_edge edge_descriptor; typedef sgb_out_edge_iterator out_edge_iterator; typedef void in_edge_iterator; typedef sgb_adj_iterator adjacency_iterator; typedef sgb_vertex_iterator vertex_iterator; typedef void edge_iterator; typedef long vertices_size_type; typedef long edge_size_type; typedef long degree_size_type; typedef directed_tag directed_category; typedef sgb_traversal_tag traversal_category; typedef allow_parallel_edge_tag edge_parallel_category; /** Return a null descriptor */ static vertex_descriptor null_vertex() { return NULL; } }; template <> struct graph_traits< sgb_const_graph_ptr > { typedef Vertex* vertex_descriptor; typedef boost::sgb_edge edge_descriptor; typedef sgb_out_edge_iterator out_edge_iterator; typedef void in_edge_iterator; typedef sgb_adj_iterator adjacency_iterator; typedef sgb_vertex_iterator vertex_iterator; typedef void edge_iterator; typedef long vertices_size_type; typedef long edge_size_type; typedef long degree_size_type; typedef directed_tag directed_category; typedef sgb_traversal_tag traversal_category; typedef allow_parallel_edge_tag edge_parallel_category; /** Return a null descriptor */ static vertex_descriptor null_vertex() { return NULL; } }; } namespace boost { struct edge_length_t { typedef edge_property_tag kind; }; // We could just use Arc* as the edge descriptor type, but // we want to add the source(e,g) function which requires // that we carry along a pointer to the source vertex. class sgb_edge { typedef sgb_edge self; public: sgb_edge() : _arc(0), _src(0) {} sgb_edge(Arc* a, Vertex* s) : _arc(a), _src(s) {} friend Vertex* source(self e, sgb_const_graph_ptr) { return e._src; } friend Vertex* target(self e, sgb_const_graph_ptr) { return e._arc->tip; } friend bool operator==(const self& a, const self& b) { return a._arc == b._arc; } friend bool operator!=(const self& a, const self& b) { return a._arc != b._arc; } #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template < class Ref > friend class sgb_edge_length_map; template < class Tag, class Ref > friend class sgb_edge_util_map; friend long get(edge_length_t, const sgb_graph_ptr&, const sgb_edge& key); friend long get( edge_length_t, const sgb_const_graph_ptr&, const sgb_edge& key); friend void put( edge_length_t, sgb_graph_ptr&, const sgb_edge& key, long value); protected: #endif Arc* _arc; Vertex* _src; }; } // namespace boost class sgb_out_edge_iterator : public boost::forward_iterator_helper< sgb_out_edge_iterator, boost::sgb_edge, std::ptrdiff_t, boost::sgb_edge*, boost::sgb_edge > { typedef sgb_out_edge_iterator self; public: sgb_out_edge_iterator() : _src(0), _arc(0) {} sgb_out_edge_iterator(Vertex* s, Arc* d) : _src(s), _arc(d) {} boost::sgb_edge operator*() { return boost::sgb_edge(_arc, _src); } self& operator++() { _arc = _arc->next; return *this; } friend bool operator==(const self& x, const self& y) { return x._arc == y._arc; } protected: Vertex* _src; Arc* _arc; }; class sgb_adj_iterator : public boost::forward_iterator_helper< sgb_adj_iterator, Vertex*, std::ptrdiff_t, Vertex**, Vertex* > { typedef sgb_adj_iterator self; public: sgb_adj_iterator() : _arc(0) {} sgb_adj_iterator(Arc* d) : _arc(d) {} Vertex* operator*() { return _arc->tip; } self& operator++() { _arc = _arc->next; return *this; } friend bool operator==(const self& x, const self& y) { return x._arc == y._arc; } protected: Arc* _arc; }; // The reason we have this instead of just using Vertex* is that we // want to use Vertex* as the vertex_descriptor instead of just // Vertex, which avoids problems with boost passing vertex descriptors // by value and how that interacts with the sgb_vertex_id_map. class sgb_vertex_iterator : public boost::forward_iterator_helper< sgb_vertex_iterator, Vertex*, std::ptrdiff_t, Vertex**, Vertex* > { typedef sgb_vertex_iterator self; public: sgb_vertex_iterator() : _v(0) {} sgb_vertex_iterator(Vertex* v) : _v(v) {} Vertex* operator*() { return _v; } self& operator++() { ++_v; return *this; } friend bool operator==(const self& x, const self& y) { return x._v == y._v; } protected: Vertex* _v; }; namespace boost { inline std::pair< sgb_vertex_iterator, sgb_vertex_iterator > vertices( sgb_const_graph_ptr g) { return std::make_pair(sgb_vertex_iterator(g->vertices), sgb_vertex_iterator(g->vertices + g->n)); } inline std::pair< sgb_out_edge_iterator, sgb_out_edge_iterator > out_edges( Vertex* u, sgb_const_graph_ptr) { return std::make_pair( sgb_out_edge_iterator(u, u->arcs), sgb_out_edge_iterator(u, 0)); } inline boost::graph_traits< sgb_graph_ptr >::degree_size_type out_degree( Vertex* u, sgb_const_graph_ptr g) { boost::graph_traits< sgb_graph_ptr >::out_edge_iterator i, i_end; boost::tie(i, i_end) = out_edges(u, g); return std::distance(i, i_end); } // in_edges? inline std::pair< sgb_adj_iterator, sgb_adj_iterator > adjacent_vertices( Vertex* u, sgb_const_graph_ptr) { return std::make_pair(sgb_adj_iterator(u->arcs), sgb_adj_iterator(0)); } inline long num_vertices(sgb_const_graph_ptr g) { return g->n; } inline long num_edges(sgb_const_graph_ptr g) { return g->m; } inline Vertex* vertex(long v, sgb_const_graph_ptr g) { return g->vertices + v; } // Various Property Maps // Vertex ID class sgb_vertex_id_map : public boost::put_get_helper< long, sgb_vertex_id_map > { public: typedef boost::readable_property_map_tag category; typedef long value_type; typedef long reference; typedef Vertex* key_type; sgb_vertex_id_map() : _g(0) {} sgb_vertex_id_map(sgb_graph_ptr g) : _g(g) {} long operator[](Vertex* v) const { return v - _g->vertices; } protected: sgb_graph_ptr _g; }; inline sgb_vertex_id_map get(vertex_index_t, sgb_graph_ptr g) { return sgb_vertex_id_map(g); } // Vertex Name class sgb_vertex_name_map : public boost::put_get_helper< char*, sgb_vertex_name_map > { public: typedef boost::readable_property_map_tag category; typedef char* value_type; typedef char* reference; typedef Vertex* key_type; char* operator[](Vertex* v) const { return v->name; } }; inline sgb_vertex_name_map get(vertex_name_t, sgb_graph_ptr) { return sgb_vertex_name_map(); } // Vertex Property Tags #define SGB_PROPERTY_TAG(KIND, TAG) \ template < class T > struct TAG##_property \ { \ typedef KIND##_property_tag kind; \ typedef T type; \ }; SGB_PROPERTY_TAG(vertex, u) SGB_PROPERTY_TAG(vertex, v) SGB_PROPERTY_TAG(vertex, w) SGB_PROPERTY_TAG(vertex, x) SGB_PROPERTY_TAG(vertex, y) SGB_PROPERTY_TAG(vertex, z) // Edge Property Tags SGB_PROPERTY_TAG(edge, a) SGB_PROPERTY_TAG(edge, b) // Various Utility Maps // helpers inline Vertex*& get_util(util& u, Vertex*) { return u.V; } inline Arc*& get_util(util& u, Arc*) { return u.A; } inline sgb_graph_ptr& get_util(util& u, sgb_graph_ptr) { return u.G; } inline char*& get_util(util& u, char*) { return u.S; } inline long& get_util(util& u, long) { return u.I; } #define SGB_GET_UTIL_FIELD(KIND, X) \ template < class T > inline T& get_util_field(KIND* k, X##_property< T >) \ { \ return get_util(k->X, T()); \ } SGB_GET_UTIL_FIELD(Vertex, u) SGB_GET_UTIL_FIELD(Vertex, v) SGB_GET_UTIL_FIELD(Vertex, w) SGB_GET_UTIL_FIELD(Vertex, x) SGB_GET_UTIL_FIELD(Vertex, y) SGB_GET_UTIL_FIELD(Vertex, z) SGB_GET_UTIL_FIELD(Arc, a) SGB_GET_UTIL_FIELD(Arc, b) // Vertex Utility Map template < class Tag, class Ref > class sgb_vertex_util_map : public boost::put_get_helper< Ref, sgb_vertex_util_map< Tag, Ref > > { Tag tag; public: explicit sgb_vertex_util_map(Tag tag = Tag()) : tag(tag) {} typedef boost::lvalue_property_map_tag category; typedef typename Tag::type value_type; typedef Vertex* key_type; typedef Ref reference; reference operator[](Vertex* v) const { return get_util_field(v, tag); } }; // Edge Utility Map template < class Tag, class Ref > class sgb_edge_util_map : public boost::put_get_helper< Ref, sgb_edge_util_map< Tag, Ref > > { Tag tag; public: explicit sgb_edge_util_map(Tag tag = Tag()) : tag(tag) {} typedef boost::lvalue_property_map_tag category; typedef typename Tag::type value_type; typedef Vertex* key_type; typedef Ref reference; reference operator[](const sgb_edge& e) const { return get_util_field(e._arc, tag); } }; template < class Tag > inline sgb_vertex_util_map< Tag, const typename Tag::type& > get_property_map( Tag, const sgb_graph_ptr& g, vertex_property_tag) { return sgb_vertex_util_map< Tag, const typename Tag::type& >(); } template < class Tag > inline sgb_vertex_util_map< Tag, typename Tag::type& > get_property_map( Tag, sgb_graph_ptr& g, vertex_property_tag) { return sgb_vertex_util_map< Tag, typename Tag::type& >(); } template < class Tag > inline sgb_edge_util_map< Tag, const typename Tag::type& > get_property_map( Tag, const sgb_graph_ptr& g, edge_property_tag) { return sgb_edge_util_map< Tag, const typename Tag::type& >(); } template < class Tag > inline sgb_edge_util_map< Tag, typename Tag::type& > get_property_map( Tag, sgb_graph_ptr& g, edge_property_tag) { return sgb_edge_util_map< Tag, typename Tag::type& >(); } // Edge Length Access template < class Ref > class sgb_edge_length_map : public boost::put_get_helper< Ref, sgb_edge_length_map< Ref > > { public: typedef boost::lvalue_property_map_tag category; typedef long value_type; typedef sgb_edge key_type; typedef Ref reference; reference operator[](const sgb_edge& e) const { return e._arc->len; } }; inline sgb_edge_length_map< const long& > get( edge_length_t, const sgb_graph_ptr&) { return sgb_edge_length_map< const long& >(); } inline sgb_edge_length_map< const long& > get( edge_length_t, const sgb_const_graph_ptr&) { return sgb_edge_length_map< const long& >(); } inline sgb_edge_length_map< long& > get(edge_length_t, sgb_graph_ptr&) { return sgb_edge_length_map< long& >(); } inline long get(edge_length_t, const sgb_graph_ptr&, const sgb_edge& key) { return key._arc->len; } inline long get(edge_length_t, const sgb_const_graph_ptr&, const sgb_edge& key) { return key._arc->len; } inline void put(edge_length_t, sgb_graph_ptr&, const sgb_edge& key, long value) { key._arc->len = value; } // Property Map Traits Classes template <> struct property_map< sgb_graph_ptr, edge_length_t > { typedef sgb_edge_length_map< long& > type; typedef sgb_edge_length_map< const long& > const_type; }; template <> struct property_map< sgb_graph_ptr, vertex_index_t > { typedef sgb_vertex_id_map type; typedef sgb_vertex_id_map const_type; }; template <> struct property_map< sgb_graph_ptr, vertex_name_t > { typedef sgb_vertex_name_map type; typedef sgb_vertex_name_map const_type; }; template <> struct property_map< sgb_const_graph_ptr, edge_length_t > { typedef sgb_edge_length_map< const long& > const_type; }; template <> struct property_map< sgb_const_graph_ptr, vertex_index_t > { typedef sgb_vertex_id_map const_type; }; template <> struct property_map< sgb_const_graph_ptr, vertex_name_t > { typedef sgb_vertex_name_map const_type; }; namespace detail { template < class Kind, class PropertyTag > struct sgb_choose_property_map { }; template < class PropertyTag > struct sgb_choose_property_map< vertex_property_tag, PropertyTag > { typedef typename PropertyTag::type value_type; typedef sgb_vertex_util_map< PropertyTag, value_type& > type; typedef sgb_vertex_util_map< PropertyTag, const value_type& > const_type; }; template < class PropertyTag > struct sgb_choose_property_map< edge_property_tag, PropertyTag > { typedef typename PropertyTag::type value_type; typedef sgb_edge_util_map< PropertyTag, value_type& > type; typedef sgb_edge_util_map< PropertyTag, const value_type& > const_type; }; } // namespace detail template < class PropertyTag > struct property_map< sgb_graph_ptr, PropertyTag > { typedef typename property_kind< PropertyTag >::type Kind; typedef detail::sgb_choose_property_map< Kind, PropertyTag > Choice; typedef typename Choice::type type; typedef typename Choice::const_type const_type; }; template < class PropertyTag > struct property_map< sgb_const_graph_ptr, PropertyTag > { typedef typename property_kind< PropertyTag >::type Kind; typedef detail::sgb_choose_property_map< Kind, PropertyTag > Choice; typedef typename Choice::const_type const_type; }; #define SGB_UTIL_ACCESSOR(KIND, X) \ template < class T > \ inline sgb_##KIND##_util_map< X##_property< T >, T& > get( \ X##_property< T >, sgb_graph_ptr&) \ { \ return sgb_##KIND##_util_map< X##_property< T >, T& >(); \ } \ template < class T > \ inline sgb_##KIND##_util_map< X##_property< T >, const T& > get( \ X##_property< T >, const sgb_graph_ptr&) \ { \ return sgb_##KIND##_util_map< X##_property< T >, const T& >(); \ } \ template < class T > \ inline sgb_##KIND##_util_map< X##_property< T >, const T& > get( \ X##_property< T >, const sgb_const_graph_ptr&) \ { \ return sgb_##KIND##_util_map< X##_property< T >, const T& >(); \ } \ template < class T, class Key > \ inline typename sgb_##KIND##_util_map< X##_property< T >, \ const T& >::value_type \ get(X##_property< T >, const sgb_graph_ptr&, const Key& key) \ { \ return sgb_##KIND##_util_map< X##_property< T >, const T& >()[key]; \ } \ template < class T, class Key > \ inline typename sgb_##KIND##_util_map< X##_property< T >, \ const T& >::value_type \ get(X##_property< T >, const sgb_const_graph_ptr&, const Key& key) \ { \ return sgb_##KIND##_util_map< X##_property< T >, const T& >()[key]; \ } \ template < class T, class Key, class Value > \ inline void put( \ X##_property< T >, sgb_graph_ptr&, const Key& key, const Value& value) \ { \ sgb_##KIND##_util_map< X##_property< T >, T& >()[key] = value; \ } SGB_UTIL_ACCESSOR(vertex, u) SGB_UTIL_ACCESSOR(vertex, v) SGB_UTIL_ACCESSOR(vertex, w) SGB_UTIL_ACCESSOR(vertex, x) SGB_UTIL_ACCESSOR(vertex, y) SGB_UTIL_ACCESSOR(vertex, z) SGB_UTIL_ACCESSOR(edge, a) SGB_UTIL_ACCESSOR(edge, b) } // namespace boost #endif // BOOST_GRAPH_SGB_GRAPH_HPP adjacency_list.hpp 0000644 00000032574 15125521275 0010251 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Copyright 2010 Thomas Claveirole // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Thomas Claveirole // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_ADJACENCY_LIST_HPP #define BOOST_GRAPH_ADJACENCY_LIST_HPP #include <boost/config.hpp> #include <vector> #include <list> #include <set> #include <boost/unordered_set.hpp> #include <boost/scoped_ptr.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_mutability_traits.hpp> #include <boost/graph/graph_selectors.hpp> #include <boost/property_map/property_map.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/and.hpp> #include <boost/mpl/not.hpp> #include <boost/mpl/bool.hpp> #include <boost/graph/detail/edge.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/detail/workaround.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/named_graph.hpp> namespace boost { //=========================================================================== // Selectors for the VertexList and EdgeList template parameters of // adjacency_list, and the container_gen traits class which is used // to map the selectors to the container type used to implement the // graph. struct vecS { }; struct listS { }; struct setS { }; struct mapS { }; struct multisetS { }; struct multimapS { }; struct hash_setS { }; struct hash_mapS { }; struct hash_multisetS { }; struct hash_multimapS { }; template < class Selector, class ValueType > struct container_gen { }; template < class ValueType > struct container_gen< listS, ValueType > { typedef std::list< ValueType > type; }; template < class ValueType > struct container_gen< vecS, ValueType > { typedef std::vector< ValueType > type; }; template < class ValueType > struct container_gen< mapS, ValueType > { typedef std::set< ValueType > type; }; template < class ValueType > struct container_gen< setS, ValueType > { typedef std::set< ValueType > type; }; template < class ValueType > struct container_gen< multisetS, ValueType > { typedef std::multiset< ValueType > type; }; template < class ValueType > struct container_gen< multimapS, ValueType > { typedef std::multiset< ValueType > type; }; template < class ValueType > struct container_gen< hash_setS, ValueType > { typedef boost::unordered_set< ValueType > type; }; template < class ValueType > struct container_gen< hash_mapS, ValueType > { typedef boost::unordered_set< ValueType > type; }; template < class ValueType > struct container_gen< hash_multisetS, ValueType > { typedef boost::unordered_multiset< ValueType > type; }; template < class ValueType > struct container_gen< hash_multimapS, ValueType > { typedef boost::unordered_multiset< ValueType > type; }; template < class StorageSelector > struct parallel_edge_traits { }; template <> struct parallel_edge_traits< vecS > { typedef allow_parallel_edge_tag type; }; template <> struct parallel_edge_traits< listS > { typedef allow_parallel_edge_tag type; }; template <> struct parallel_edge_traits< setS > { typedef disallow_parallel_edge_tag type; }; template <> struct parallel_edge_traits< multisetS > { typedef allow_parallel_edge_tag type; }; template <> struct parallel_edge_traits< hash_setS > { typedef disallow_parallel_edge_tag type; }; // mapS is obsolete, replaced with setS template <> struct parallel_edge_traits< mapS > { typedef disallow_parallel_edge_tag type; }; template <> struct parallel_edge_traits< hash_mapS > { typedef disallow_parallel_edge_tag type; }; template <> struct parallel_edge_traits< hash_multisetS > { typedef allow_parallel_edge_tag type; }; template <> struct parallel_edge_traits< hash_multimapS > { typedef allow_parallel_edge_tag type; }; namespace detail { template < class Directed > struct is_random_access { enum { value = false }; typedef mpl::false_ type; }; template <> struct is_random_access< vecS > { enum { value = true }; typedef mpl::true_ type; }; } // namespace detail template < typename Selector > struct is_distributed_selector : mpl::false_ { }; //=========================================================================== // The adjacency_list_traits class, which provides a way to access // some of the associated types of an adjacency_list type without // having to first create the adjacency_list type. This is useful // when trying to create interior vertex or edge properties who's // value type is a vertex or edge descriptor. template < class OutEdgeListS = vecS, class VertexListS = vecS, class DirectedS = directedS, class EdgeListS = listS > struct adjacency_list_traits { typedef typename detail::is_random_access< VertexListS >::type is_rand_access; typedef typename DirectedS::is_bidir_t is_bidir; typedef typename DirectedS::is_directed_t is_directed; typedef typename mpl::if_< is_bidir, bidirectional_tag, typename mpl::if_< is_directed, directed_tag, undirected_tag >::type >::type directed_category; typedef typename parallel_edge_traits< OutEdgeListS >::type edge_parallel_category; typedef std::size_t vertices_size_type; typedef void* vertex_ptr; typedef typename mpl::if_< is_rand_access, vertices_size_type, vertex_ptr >::type vertex_descriptor; typedef detail::edge_desc_impl< directed_category, vertex_descriptor > edge_descriptor; private: // Logic to figure out the edges_size_type struct dummy { }; typedef typename container_gen< EdgeListS, dummy >::type EdgeContainer; typedef typename DirectedS::is_bidir_t BidirectionalT; typedef typename DirectedS::is_directed_t DirectedT; typedef typename mpl::and_< DirectedT, typename mpl::not_< BidirectionalT >::type >::type on_edge_storage; public: typedef typename mpl::if_< on_edge_storage, std::size_t, typename EdgeContainer::size_type >::type edges_size_type; }; } // namespace boost #include <boost/graph/detail/adjacency_list.hpp> namespace boost { //=========================================================================== // The adjacency_list class. // template < class OutEdgeListS = vecS, // a Sequence or an AssociativeContainer class VertexListS = vecS, // a Sequence or a RandomAccessContainer class DirectedS = directedS, class VertexProperty = no_property, class EdgeProperty = no_property, class GraphProperty = no_property, class EdgeListS = listS > class adjacency_list : public detail::adj_list_gen< adjacency_list< OutEdgeListS, VertexListS, DirectedS, VertexProperty, EdgeProperty, GraphProperty, EdgeListS >, VertexListS, OutEdgeListS, DirectedS, VertexProperty, EdgeProperty, GraphProperty, EdgeListS >::type, // Support for named vertices public graph::maybe_named_graph< adjacency_list< OutEdgeListS, VertexListS, DirectedS, VertexProperty, EdgeProperty, GraphProperty, EdgeListS >, typename adjacency_list_traits< OutEdgeListS, VertexListS, DirectedS, EdgeListS >::vertex_descriptor, VertexProperty > { public: typedef GraphProperty graph_property_type; typedef typename lookup_one_property< GraphProperty, graph_bundle_t >::type graph_bundled; typedef VertexProperty vertex_property_type; typedef typename lookup_one_property< VertexProperty, vertex_bundle_t >::type vertex_bundled; typedef EdgeProperty edge_property_type; typedef typename lookup_one_property< EdgeProperty, edge_bundle_t >::type edge_bundled; private: typedef adjacency_list self; typedef typename detail::adj_list_gen< self, VertexListS, OutEdgeListS, DirectedS, vertex_property_type, edge_property_type, GraphProperty, EdgeListS >::type Base; public: typedef typename Base::stored_vertex stored_vertex; typedef typename Base::vertices_size_type vertices_size_type; typedef typename Base::edges_size_type edges_size_type; typedef typename Base::degree_size_type degree_size_type; typedef typename Base::vertex_descriptor vertex_descriptor; typedef typename Base::edge_descriptor edge_descriptor; typedef OutEdgeListS out_edge_list_selector; typedef VertexListS vertex_list_selector; typedef DirectedS directed_selector; typedef EdgeListS edge_list_selector; adjacency_list(const GraphProperty& p = GraphProperty()) : m_property(new graph_property_type(p)) { } adjacency_list(const adjacency_list& x) : Base(x), m_property(new graph_property_type(*x.m_property)) { } adjacency_list& operator=(const adjacency_list& x) { // TBD: probably should give the strong guarantee if (&x != this) { Base::operator=(x); // Copy/swap the ptr since we can't just assign it... property_ptr p(new graph_property_type(*x.m_property)); m_property.swap(p); } return *this; } // Required by Mutable Graph adjacency_list(vertices_size_type num_vertices, const GraphProperty& p = GraphProperty()) : Base(num_vertices), m_property(new graph_property_type(p)) { } // Required by Iterator Constructible Graph template < class EdgeIterator > adjacency_list(EdgeIterator first, EdgeIterator last, vertices_size_type n, edges_size_type = 0, const GraphProperty& p = GraphProperty()) : Base(n, first, last), m_property(new graph_property_type(p)) { } template < class EdgeIterator, class EdgePropertyIterator > adjacency_list(EdgeIterator first, EdgeIterator last, EdgePropertyIterator ep_iter, vertices_size_type n, edges_size_type = 0, const GraphProperty& p = GraphProperty()) : Base(n, first, last, ep_iter), m_property(new graph_property_type(p)) { } void swap(adjacency_list& x) { // Is there a more efficient way to do this? adjacency_list tmp(x); x = *this; *this = tmp; } void clear() { this->clearing_graph(); Base::clear(); } #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES // Directly access a vertex or edge bundle vertex_bundled& operator[](vertex_descriptor v) { return get(vertex_bundle, *this)[v]; } const vertex_bundled& operator[](vertex_descriptor v) const { return get(vertex_bundle, *this)[v]; } edge_bundled& operator[](edge_descriptor e) { return get(edge_bundle, *this)[e]; } const edge_bundled& operator[](edge_descriptor e) const { return get(edge_bundle, *this)[e]; } graph_bundled& operator[](graph_bundle_t) { return get_property(*this); } graph_bundled const& operator[](graph_bundle_t) const { return get_property(*this); } #endif // protected: (would be protected if friends were more portable) typedef scoped_ptr< graph_property_type > property_ptr; property_ptr m_property; }; #define ADJLIST_PARAMS \ typename OEL, typename VL, typename D, typename VP, typename EP, \ typename GP, typename EL #define ADJLIST adjacency_list< OEL, VL, D, VP, EP, GP, EL > template < ADJLIST_PARAMS, typename Tag, typename Value > inline void set_property(ADJLIST& g, Tag tag, Value const& value) { get_property_value(*g.m_property, tag) = value; } template < ADJLIST_PARAMS, typename Tag > inline typename graph_property< ADJLIST, Tag >::type& get_property( ADJLIST& g, Tag tag) { return get_property_value(*g.m_property, tag); } template < ADJLIST_PARAMS, typename Tag > inline typename graph_property< ADJLIST, Tag >::type const& get_property( ADJLIST const& g, Tag tag) { return get_property_value(*g.m_property, tag); } // dwa 09/25/00 - needed to be more explicit so reverse_graph would work. template < class Directed, class Vertex, class OutEdgeListS, class VertexListS, class DirectedS, class VertexProperty, class EdgeProperty, class GraphProperty, class EdgeListS > inline Vertex source(const detail::edge_base< Directed, Vertex >& e, const adjacency_list< OutEdgeListS, VertexListS, DirectedS, VertexProperty, EdgeProperty, GraphProperty, EdgeListS >&) { return e.m_source; } template < class Directed, class Vertex, class OutEdgeListS, class VertexListS, class DirectedS, class VertexProperty, class EdgeProperty, class GraphProperty, class EdgeListS > inline Vertex target(const detail::edge_base< Directed, Vertex >& e, const adjacency_list< OutEdgeListS, VertexListS, DirectedS, VertexProperty, EdgeProperty, GraphProperty, EdgeListS >&) { return e.m_target; } // Mutability Traits template < ADJLIST_PARAMS > struct graph_mutability_traits< ADJLIST > { typedef mutable_property_graph_tag category; }; // Can't remove vertices from adjacency lists with VL==vecS template < typename OEL, typename D, typename VP, typename EP, typename GP, typename EL > struct graph_mutability_traits< adjacency_list< OEL, vecS, D, VP, EP, GP, EL > > { typedef add_only_property_graph_tag category; }; #undef ADJLIST_PARAMS #undef ADJLIST } // namespace boost #endif // BOOST_GRAPH_ADJACENCY_LIST_HPP graphml.hpp 0000644 00000032224 15125521275 0006717 0 ustar 00 // Copyright (C) 2006 Tiago de Paula Peixoto <tiago@forked.de> // Copyright (C) 2004 The Trustees of Indiana University. // // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Authors: Douglas Gregor // Andrew Lumsdaine // Tiago de Paula Peixoto #ifndef BOOST_GRAPH_GRAPHML_HPP #define BOOST_GRAPH_GRAPHML_HPP #include <boost/config.hpp> #include <boost/lexical_cast.hpp> #include <boost/any.hpp> #include <boost/type_traits/is_convertible.hpp> #include <boost/graph/dll_import_export.hpp> #include <boost/graph/graphviz.hpp> // for exceptions #include <typeinfo> #include <boost/mpl/bool.hpp> #include <boost/mpl/vector.hpp> #include <boost/mpl/find.hpp> #include <boost/mpl/for_each.hpp> #include <boost/property_tree/detail/xml_parser_utils.hpp> #include <boost/throw_exception.hpp> #include <exception> #include <sstream> namespace boost { ///////////////////////////////////////////////////////////////////////////// // Graph reader exceptions ///////////////////////////////////////////////////////////////////////////// struct BOOST_SYMBOL_VISIBLE parse_error : public graph_exception { parse_error(const std::string& err) { error = err; statement = "parse error: " + error; } virtual ~parse_error() throw() {} virtual const char* what() const throw() { return statement.c_str(); } std::string statement; std::string error; }; class mutate_graph { public: virtual ~mutate_graph() {} virtual bool is_directed() const = 0; virtual boost::any do_add_vertex() = 0; virtual std::pair< boost::any, bool > do_add_edge( boost::any source, boost::any target) = 0; virtual void set_graph_property(const std::string& name, const std::string& value, const std::string& value_type) = 0; virtual void set_vertex_property(const std::string& name, boost::any vertex, const std::string& value, const std::string& value_type) = 0; virtual void set_edge_property(const std::string& name, boost::any edge, const std::string& value, const std::string& value_type) = 0; }; template < typename MutableGraph > class mutate_graph_impl : public mutate_graph { typedef typename graph_traits< MutableGraph >::vertex_descriptor vertex_descriptor; typedef typename graph_traits< MutableGraph >::edge_descriptor edge_descriptor; public: mutate_graph_impl(MutableGraph& g, dynamic_properties& dp) : m_g(g), m_dp(dp) { } bool is_directed() const { return is_convertible< typename graph_traits< MutableGraph >::directed_category, directed_tag >::value; } virtual any do_add_vertex() { return any(add_vertex(m_g)); } virtual std::pair< any, bool > do_add_edge(any source, any target) { std::pair< edge_descriptor, bool > retval = add_edge(any_cast< vertex_descriptor >(source), any_cast< vertex_descriptor >(target), m_g); return std::make_pair(any(retval.first), retval.second); } virtual void set_graph_property(const std::string& name, const std::string& value, const std::string& value_type) { bool type_found = false; try { mpl::for_each< value_types >( put_property< MutableGraph*, value_types >(name, m_dp, &m_g, value, value_type, m_type_names, type_found)); } catch (const bad_lexical_cast&) { BOOST_THROW_EXCEPTION(parse_error("invalid value \"" + value + "\" for key " + name + " of type " + value_type)); } if (!type_found) { BOOST_THROW_EXCEPTION(parse_error( "unrecognized type \"" + value_type + "\" for key " + name)); } } virtual void set_vertex_property(const std::string& name, any vertex, const std::string& value, const std::string& value_type) { bool type_found = false; try { mpl::for_each< value_types >( put_property< vertex_descriptor, value_types >(name, m_dp, any_cast< vertex_descriptor >(vertex), value, value_type, m_type_names, type_found)); } catch (const bad_lexical_cast&) { BOOST_THROW_EXCEPTION(parse_error("invalid value \"" + value + "\" for key " + name + " of type " + value_type)); } if (!type_found) { BOOST_THROW_EXCEPTION(parse_error( "unrecognized type \"" + value_type + "\" for key " + name)); } } virtual void set_edge_property(const std::string& name, any edge, const std::string& value, const std::string& value_type) { bool type_found = false; try { mpl::for_each< value_types >( put_property< edge_descriptor, value_types >(name, m_dp, any_cast< edge_descriptor >(edge), value, value_type, m_type_names, type_found)); } catch (const bad_lexical_cast&) { BOOST_THROW_EXCEPTION(parse_error("invalid value \"" + value + "\" for key " + name + " of type " + value_type)); } if (!type_found) { BOOST_THROW_EXCEPTION(parse_error( "unrecognized type \"" + value_type + "\" for key " + name)); } } template < typename Key, typename ValueVector > class put_property { public: put_property(const std::string& name, dynamic_properties& dp, const Key& key, const std::string& value, const std::string& value_type, const char** type_names, bool& type_found) : m_name(name) , m_dp(dp) , m_key(key) , m_value(value) , m_value_type(value_type) , m_type_names(type_names) , m_type_found(type_found) { } template < class Value > void operator()(Value) { if (m_value_type == m_type_names[mpl::find< ValueVector, Value >::type::pos::value]) { put(m_name, m_dp, m_key, lexical_cast< Value >(m_value)); m_type_found = true; } } private: const std::string& m_name; dynamic_properties& m_dp; const Key& m_key; const std::string& m_value; const std::string& m_value_type; const char** m_type_names; bool& m_type_found; }; protected: MutableGraph& m_g; dynamic_properties& m_dp; typedef mpl::vector< bool, int, long, float, double, std::string > value_types; static const char* m_type_names[]; }; template < typename MutableGraph > const char* mutate_graph_impl< MutableGraph >::m_type_names[] = { "boolean", "int", "long", "float", "double", "string" }; void BOOST_GRAPH_DECL read_graphml( std::istream& in, mutate_graph& g, size_t desired_idx); template < typename MutableGraph > void read_graphml(std::istream& in, MutableGraph& g, dynamic_properties& dp, size_t desired_idx = 0) { mutate_graph_impl< MutableGraph > mg(g, dp); read_graphml(in, mg, desired_idx); } template < typename Types > class get_type_name { public: get_type_name(const std::type_info& type, const char** type_names, std::string& type_name) : m_type(type), m_type_names(type_names), m_type_name(type_name) { } template < typename Type > void operator()(Type) { if (typeid(Type) == m_type) m_type_name = m_type_names[mpl::find< Types, Type >::type::pos::value]; } private: const std::type_info& m_type; const char** m_type_names; std::string& m_type_name; }; template < typename Graph, typename VertexIndexMap > void write_graphml(std::ostream& out, const Graph& g, VertexIndexMap vertex_index, const dynamic_properties& dp, bool ordered_vertices = false) { typedef typename graph_traits< Graph >::directed_category directed_category; typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; using boost::property_tree::xml_parser::encode_char_entities; BOOST_STATIC_CONSTANT(bool, graph_is_directed = (is_convertible< directed_category*, directed_tag* >::value)); out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" << "<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\" " "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " "xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns " "http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">\n"; typedef mpl::vector< bool, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long, float, double, long double, std::string > value_types; const char* type_names[] = { "boolean", "int", "int", "int", "int", "long", "long", "long", "long", "float", "double", "double", "string" }; std::map< std::string, std::string > graph_key_ids; std::map< std::string, std::string > vertex_key_ids; std::map< std::string, std::string > edge_key_ids; int key_count = 0; // Output keys for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i) { std::string key_id = "key" + lexical_cast< std::string >(key_count++); if (i->second->key() == typeid(Graph*)) graph_key_ids[i->first] = key_id; else if (i->second->key() == typeid(vertex_descriptor)) vertex_key_ids[i->first] = key_id; else if (i->second->key() == typeid(edge_descriptor)) edge_key_ids[i->first] = key_id; else continue; std::string type_name = "string"; mpl::for_each< value_types >(get_type_name< value_types >( i->second->value(), type_names, type_name)); out << " <key id=\"" << encode_char_entities(key_id) << "\" for=\"" << (i->second->key() == typeid(Graph*) ? "graph" : (i->second->key() == typeid(vertex_descriptor) ? "node" : "edge")) << "\"" << " attr.name=\"" << i->first << "\"" << " attr.type=\"" << type_name << "\"" << " />\n"; } out << " <graph id=\"G\" edgedefault=\"" << (graph_is_directed ? "directed" : "undirected") << "\"" << " parse.nodeids=\"" << (ordered_vertices ? "canonical" : "free") << "\"" << " parse.edgeids=\"canonical\" parse.order=\"nodesfirst\">\n"; // Output graph data for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i) { if (i->second->key() == typeid(Graph*)) { // The const_cast here is just to get typeid correct for property // map key; the graph should not be mutated using it. out << " <data key=\"" << graph_key_ids[i->first] << "\">" << encode_char_entities( i->second->get_string(const_cast< Graph* >(&g))) << "</data>\n"; } } typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator; vertex_iterator v, v_end; for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) { out << " <node id=\"n" << get(vertex_index, *v) << "\">\n"; // Output data for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i) { if (i->second->key() == typeid(vertex_descriptor)) { out << " <data key=\"" << vertex_key_ids[i->first] << "\">" << encode_char_entities(i->second->get_string(*v)) << "</data>\n"; } } out << " </node>\n"; } typedef typename graph_traits< Graph >::edge_iterator edge_iterator; edge_iterator e, e_end; typename graph_traits< Graph >::edges_size_type edge_count = 0; for (boost::tie(e, e_end) = edges(g); e != e_end; ++e) { out << " <edge id=\"e" << edge_count++ << "\" source=\"n" << get(vertex_index, source(*e, g)) << "\" target=\"n" << get(vertex_index, target(*e, g)) << "\">\n"; // Output data for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i) { if (i->second->key() == typeid(edge_descriptor)) { out << " <data key=\"" << edge_key_ids[i->first] << "\">" << encode_char_entities(i->second->get_string(*e)) << "</data>\n"; } } out << " </edge>\n"; } out << " </graph>\n" << "</graphml>\n"; } template < typename Graph > void write_graphml(std::ostream& out, const Graph& g, const dynamic_properties& dp, bool ordered_vertices = false) { write_graphml(out, g, get(vertex_index, g), dp, ordered_vertices); } } // boost namespace #endif // BOOST_GRAPH_GRAPHML_HPP labeled_graph.hpp 0000644 00000074302 15125521275 0010041 0 ustar 00 // Copyright (C) 2009 Andrew Sutton // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GRAPH_LABELED_GRAPH_HPP #define BOOST_GRAPH_LABELED_GRAPH_HPP #include <boost/config.hpp> #include <vector> #include <map> #include <boost/static_assert.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/bool.hpp> #include <boost/unordered_map.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/type_traits/is_unsigned.hpp> #include <boost/pending/container_traits.hpp> #include <boost/graph/graph_traits.hpp> // This file implements a utility for creating mappings from arbitrary // identifiers to the vertices of a graph. namespace boost { // A type selector that denotes the use of some default value. struct defaultS { }; /** @internal */ namespace graph_detail { /** Returns true if the selector is the default selector. */ template < typename Selector > struct is_default : mpl::bool_< is_same< Selector, defaultS >::value > { }; /** * Choose the default map instance. If Label is an unsigned integral type * the we can use a vector to store the information. */ template < typename Label, typename Vertex > struct choose_default_map { typedef typename mpl::if_< is_unsigned< Label >, std::vector< Vertex >, std::map< Label, Vertex > // TODO: Should use unordered_map? >::type type; }; /** * @name Generate Label Map * These type generators are responsible for instantiating an associative * container for the the labeled graph. Note that the Selector must be * select a pair associative container or a vecS, which is only valid if * Label is an integral type. */ //@{ template < typename Selector, typename Label, typename Vertex > struct generate_label_map { }; template < typename Label, typename Vertex > struct generate_label_map< vecS, Label, Vertex > { typedef std::vector< Vertex > type; }; template < typename Label, typename Vertex > struct generate_label_map< mapS, Label, Vertex > { typedef std::map< Label, Vertex > type; }; template < typename Label, typename Vertex > struct generate_label_map< multimapS, Label, Vertex > { typedef std::multimap< Label, Vertex > type; }; template < typename Label, typename Vertex > struct generate_label_map< hash_mapS, Label, Vertex > { typedef boost::unordered_map< Label, Vertex > type; }; template < typename Label, typename Vertex > struct generate_label_map< hash_multimapS, Label, Vertex > { typedef boost::unordered_multimap< Label, Vertex > type; }; template < typename Selector, typename Label, typename Vertex > struct choose_custom_map { typedef typename generate_label_map< Selector, Label, Vertex >::type type; }; //@} /** * Choose and instantiate an "associative" container. Note that this can * also choose vector. */ template < typename Selector, typename Label, typename Vertex > struct choose_map { typedef typename mpl::eval_if< is_default< Selector >, choose_default_map< Label, Vertex >, choose_custom_map< Selector, Label, Vertex > >::type type; }; /** @name Insert Labeled Vertex */ //@{ // Tag dispatch on random access containers (i.e., vectors). This function // basically requires a) that Container is vector<Label> and that Label // is an unsigned integral value. Note that this will resize the vector // to accommodate indices. template < typename Container, typename Graph, typename Label, typename Prop > std::pair< typename graph_traits< Graph >::vertex_descriptor, bool > insert_labeled_vertex(Container& c, Graph& g, Label const& l, Prop const& p, random_access_container_tag) { typedef typename graph_traits< Graph >::vertex_descriptor Vertex; // If the label is out of bounds, resize the vector to accommodate. // Resize by 2x the index so we don't cause quadratic insertions over // time. if (l >= c.size()) { c.resize((l + 1) * 2); } Vertex v = add_vertex(p, g); c[l] = v; return std::make_pair(c[l], true); } // Tag dispatch on multi associative containers (i.e. multimaps). template < typename Container, typename Graph, typename Label, typename Prop > std::pair< typename graph_traits< Graph >::vertex_descriptor, bool > insert_labeled_vertex(Container& c, Graph& g, Label const& l, Prop const& p, multiple_associative_container_tag const&) { // Note that insertion always succeeds so we can add the vertex first // and then the mapping to the label. typedef typename graph_traits< Graph >::vertex_descriptor Vertex; Vertex v = add_vertex(p, g); c.insert(std::make_pair(l, v)); return std::make_pair(v, true); } // Tag dispatch on unique associative containers (i.e. maps). template < typename Container, typename Graph, typename Label, typename Prop > std::pair< typename graph_traits< Graph >::vertex_descriptor, bool > insert_labeled_vertex(Container& c, Graph& g, Label const& l, Prop const& p, unique_associative_container_tag) { // Here, we actually have to try the insertion first, and only add // the vertex if we get a new element. typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename Container::iterator Iterator; std::pair< Iterator, bool > x = c.insert(std::make_pair(l, Vertex())); if (x.second) { x.first->second = add_vertex(g); put(boost::vertex_all, g, x.first->second, p); } return std::make_pair(x.first->second, x.second); } // Dispatcher template < typename Container, typename Graph, typename Label, typename Prop > std::pair< typename graph_traits< Graph >::vertex_descriptor, bool > insert_labeled_vertex(Container& c, Graph& g, Label const& l, Prop const& p) { return insert_labeled_vertex(c, g, l, p, container_category(c)); } //@} /** @name Find Labeled Vertex */ //@{ // Tag dispatch for sequential maps (i.e., vectors). template < typename Container, typename Graph, typename Label > typename graph_traits< Graph >::vertex_descriptor find_labeled_vertex( Container const& c, Graph const&, Label const& l, random_access_container_tag) { return l < c.size() ? c[l] : graph_traits< Graph >::null_vertex(); } // Tag dispatch for pair associative maps (more or less). template < typename Container, typename Graph, typename Label > typename graph_traits< Graph >::vertex_descriptor find_labeled_vertex( Container const& c, Graph const&, Label const& l, associative_container_tag) { typename Container::const_iterator i = c.find(l); return i != c.end() ? i->second : graph_traits< Graph >::null_vertex(); } // Dispatcher template < typename Container, typename Graph, typename Label > typename graph_traits< Graph >::vertex_descriptor find_labeled_vertex( Container const& c, Graph const& g, Label const& l) { return find_labeled_vertex(c, g, l, container_category(c)); } //@} /** @name Put Vertex Label */ //@{ // Tag dispatch on vectors. template < typename Container, typename Label, typename Graph, typename Vertex > bool put_vertex_label(Container& c, Graph const&, Label const& l, Vertex v, random_access_container_tag) { // If the element is already occupied, then we probably don't want to // overwrite it. if (c[l] == graph_traits< Graph >::null_vertex()) return false; c[l] = v; return true; } // Attempt the insertion and return its result. template < typename Container, typename Label, typename Graph, typename Vertex > bool put_vertex_label(Container& c, Graph const&, Label const& l, Vertex v, unique_associative_container_tag) { return c.insert(std::make_pair(l, v)).second; } // Insert the pair and return true. template < typename Container, typename Label, typename Graph, typename Vertex > bool put_vertex_label(Container& c, Graph const&, Label const& l, Vertex v, multiple_associative_container_tag) { c.insert(std::make_pair(l, v)); return true; } // Dispatcher template < typename Container, typename Label, typename Graph, typename Vertex > bool put_vertex_label( Container& c, Graph const& g, Label const& l, Vertex v) { return put_vertex_label(c, g, l, v, container_category(c)); } //@} } // namespace detail struct labeled_graph_class_tag { }; /** @internal * This class is responsible for the deduction and declaration of type names * for the labeled_graph class template. */ template < typename Graph, typename Label, typename Selector > struct labeled_graph_types { typedef Graph graph_type; // Label and maps typedef Label label_type; typedef typename graph_detail::choose_map< Selector, Label, typename graph_traits< Graph >::vertex_descriptor >::type map_type; }; /** * The labeled_graph class is a graph adaptor that maintains a mapping between * vertex labels and vertex descriptors. * * @todo This class is somewhat redundant for adjacency_list<*, vecS> if * the intended label is an unsigned int (and perhaps some other cases), but * it does avoid some weird ambiguities (i.e. adding a vertex with a label that * does not match its target index). * * @todo This needs to be reconciled with the named_graph, but since there is * no documentation or examples, its not going to happen. */ template < typename Graph, typename Label, typename Selector = defaultS > class labeled_graph : protected labeled_graph_types< Graph, Label, Selector > { typedef labeled_graph_types< Graph, Label, Selector > Base; public: typedef labeled_graph_class_tag graph_tag; typedef typename Base::graph_type graph_type; typedef typename graph_traits< graph_type >::vertex_descriptor vertex_descriptor; typedef typename graph_traits< graph_type >::edge_descriptor edge_descriptor; typedef typename graph_traits< graph_type >::directed_category directed_category; typedef typename graph_traits< graph_type >::edge_parallel_category edge_parallel_category; typedef typename graph_traits< graph_type >::traversal_category traversal_category; typedef typename graph_traits< graph_type >::out_edge_iterator out_edge_iterator; typedef typename graph_traits< graph_type >::in_edge_iterator in_edge_iterator; typedef typename graph_traits< graph_type >::adjacency_iterator adjacency_iterator; typedef typename graph_traits< graph_type >::degree_size_type degree_size_type; typedef typename graph_traits< graph_type >::vertex_iterator vertex_iterator; typedef typename graph_traits< graph_type >::vertices_size_type vertices_size_type; typedef typename graph_traits< graph_type >::edge_iterator edge_iterator; typedef typename graph_traits< graph_type >::edges_size_type edges_size_type; typedef typename graph_type::graph_property_type graph_property_type; typedef typename graph_type::graph_bundled graph_bundled; typedef typename graph_type::vertex_property_type vertex_property_type; typedef typename graph_type::vertex_bundled vertex_bundled; typedef typename graph_type::edge_property_type edge_property_type; typedef typename graph_type::edge_bundled edge_bundled; typedef typename Base::label_type label_type; typedef typename Base::map_type map_type; public: labeled_graph(graph_property_type const& gp = graph_property_type()) : _graph(gp), _map() { } labeled_graph(labeled_graph const& x) : _graph(x._graph), _map(x._map) {} // This constructor can only be used if map_type supports positional // range insertion (i.e. its a vector). This is the only case where we can // try to guess the intended labels for graph. labeled_graph(vertices_size_type n, graph_property_type const& gp = graph_property_type()) : _graph(n, gp), _map() { std::pair< vertex_iterator, vertex_iterator > rng = vertices(_graph); _map.insert(_map.end(), rng.first, rng.second); } // Construct a graph over n vertices, each of which receives a label from // the range [l, l + n). Note that the graph is not directly constructed // over the n vertices, but added sequentially. This constructor is // necessarily slower than the underlying counterpart. template < typename LabelIter > labeled_graph(vertices_size_type n, LabelIter l, graph_property_type const& gp = graph_property_type()) : _graph(gp) { while (n-- > 0) add_vertex(*l++); } // Construct the graph over n vertices each of which has a label in the // range [l, l + n) and a property in the range [p, p + n). template < typename LabelIter, typename PropIter > labeled_graph(vertices_size_type n, LabelIter l, PropIter p, graph_property_type const& gp = graph_property_type()) : _graph(gp) { while (n-- > 0) add_vertex(*l++, *p++); } labeled_graph& operator=(labeled_graph const& x) { _graph = x._graph; _map = x._map; return *this; } /** @name Graph Accessors */ //@{ graph_type& graph() { return _graph; } graph_type const& graph() const { return _graph; } //@} /** * Create a new label for the given vertex, returning false, if the label * cannot be created. */ bool label_vertex(vertex_descriptor v, Label const& l) { return graph_detail::put_vertex_label(_map, _graph, l, v); } /** @name Add Vertex * Add a vertex to the graph, returning the descriptor. If the vertices * are uniquely labeled and the label already exists within the graph, * then no vertex is added, and the returned descriptor refers to the * existing vertex. A vertex property can be given as a parameter, if * needed. */ //@{ vertex_descriptor add_vertex(Label const& l) { return graph_detail::insert_labeled_vertex( _map, _graph, l, vertex_property_type()) .first; } vertex_descriptor add_vertex(Label const& l, vertex_property_type const& p) { return graph_detail::insert_labeled_vertex(_map, _graph, l, p).first; } //@} /** @name Insert Vertex * Insert a vertex into the graph, returning a pair containing the * descriptor of a vertex and a boolean value that describes whether or not * a new vertex was inserted. If vertices are not uniquely labeled, then * insertion will always succeed. */ //@{ std::pair< vertex_descriptor, bool > insert_vertex(Label const& l) { return graph_detail::insert_labeled_vertex( _map, _graph, l, vertex_property_type()); } std::pair< vertex_descriptor, bool > insert_vertex( Label const& l, vertex_property_type const& p) { return graph_detail::insert_labeled_vertex(_map, _graph, l, p); } //@} /** Remove the vertex with the given label. */ void remove_vertex(Label const& l) { return boost::remove_vertex(vertex(l), _graph); } /** Return a descriptor for the given label. */ vertex_descriptor vertex(Label const& l) const { return graph_detail::find_labeled_vertex(_map, _graph, l); } #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES /** @name Bundled Properties */ //@{ // Lookup the requested vertex and return the bundle. vertex_bundled& operator[](Label const& l) { return _graph[vertex(l)]; } vertex_bundled const& operator[](Label const& l) const { return _graph[vertex(l)]; } // Delegate edge lookup to the underlying graph. edge_bundled& operator[](edge_descriptor e) { return _graph[e]; } edge_bundled const& operator[](edge_descriptor e) const { return _graph[e]; } //@} #endif /** Return a null descriptor */ static vertex_descriptor null_vertex() { return graph_traits< graph_type >::null_vertex(); } private: graph_type _graph; map_type _map; }; /** * The partial specialization over graph pointers allows the construction * of temporary labeled graph objects. In this case, the labels are destructed * when the wrapper goes out of scope. */ template < typename Graph, typename Label, typename Selector > class labeled_graph< Graph*, Label, Selector > : protected labeled_graph_types< Graph, Label, Selector > { typedef labeled_graph_types< Graph, Label, Selector > Base; public: typedef labeled_graph_class_tag graph_tag; typedef typename Base::graph_type graph_type; typedef typename graph_traits< graph_type >::vertex_descriptor vertex_descriptor; typedef typename graph_traits< graph_type >::edge_descriptor edge_descriptor; typedef typename graph_traits< graph_type >::directed_category directed_category; typedef typename graph_traits< graph_type >::edge_parallel_category edge_parallel_category; typedef typename graph_traits< graph_type >::traversal_category traversal_category; typedef typename graph_traits< graph_type >::out_edge_iterator out_edge_iterator; typedef typename graph_traits< graph_type >::in_edge_iterator in_edge_iterator; typedef typename graph_traits< graph_type >::adjacency_iterator adjacency_iterator; typedef typename graph_traits< graph_type >::degree_size_type degree_size_type; typedef typename graph_traits< graph_type >::vertex_iterator vertex_iterator; typedef typename graph_traits< graph_type >::vertices_size_type vertices_size_type; typedef typename graph_traits< graph_type >::edge_iterator edge_iterator; typedef typename graph_traits< graph_type >::edges_size_type edges_size_type; typedef typename graph_type::vertex_property_type vertex_property_type; typedef typename graph_type::edge_property_type edge_property_type; typedef typename graph_type::graph_property_type graph_property_type; typedef typename graph_type::vertex_bundled vertex_bundled; typedef typename graph_type::edge_bundled edge_bundled; typedef typename Base::label_type label_type; typedef typename Base::map_type map_type; labeled_graph(graph_type* g) : _graph(g) {} /** @name Graph Access */ //@{ graph_type& graph() { return *_graph; } graph_type const& graph() const { return *_graph; } //@} /** * Create a new label for the given vertex, returning false, if the label * cannot be created. */ bool label_vertex(vertex_descriptor v, Label const& l) { return graph_detail::put_vertex_label(_map, *_graph, l, v); } /** @name Add Vertex */ //@{ vertex_descriptor add_vertex(Label const& l) { return graph_detail::insert_labeled_vertex( _map, *_graph, l, vertex_property_type()) .first; } vertex_descriptor add_vertex(Label const& l, vertex_property_type const& p) { return graph_detail::insert_labeled_vertex(_map, *_graph, l, p).first; } std::pair< vertex_descriptor, bool > insert_vertex(Label const& l) { return graph_detail::insert_labeled_vertex( _map, *_graph, l, vertex_property_type()); } //@} /** Try to insert a vertex with the given label. */ std::pair< vertex_descriptor, bool > insert_vertex( Label const& l, vertex_property_type const& p) { return graph_detail::insert_labeled_vertex(_map, *_graph, l, p); } /** Remove the vertex with the given label. */ void remove_vertex(Label const& l) { return boost::remove_vertex(vertex(l), *_graph); } /** Return a descriptor for the given label. */ vertex_descriptor vertex(Label const& l) const { return graph_detail::find_labeled_vertex(_map, *_graph, l); } #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES /** @name Bundled Properties */ //@{ // Lookup the requested vertex and return the bundle. vertex_bundled& operator[](Label const& l) { return (*_graph)[vertex(l)]; } vertex_bundled const& operator[](Label const& l) const { return (*_graph)[vertex(l)]; } // Delegate edge lookup to the underlying graph. edge_bundled& operator[](edge_descriptor e) { return (*_graph)[e]; } edge_bundled const& operator[](edge_descriptor e) const { return (*_graph)[e]; } //@} #endif static vertex_descriptor null_vertex() { return graph_traits< graph_type >::null_vertex(); } private: graph_type* _graph; map_type _map; }; #define LABELED_GRAPH_PARAMS typename G, typename L, typename S #define LABELED_GRAPH labeled_graph< G, L, S > /** @name Labeled Graph */ //@{ template < LABELED_GRAPH_PARAMS > inline bool label_vertex(typename LABELED_GRAPH::vertex_descriptor v, typename LABELED_GRAPH::label_type const l, LABELED_GRAPH& g) { return g.label_vertex(v, l); } template < LABELED_GRAPH_PARAMS > inline typename LABELED_GRAPH::vertex_descriptor vertex_by_label( typename LABELED_GRAPH::label_type const l, LABELED_GRAPH& g) { return g.vertex(l); } //@} /** @name Graph */ //@{ template < LABELED_GRAPH_PARAMS > inline std::pair< typename LABELED_GRAPH::edge_descriptor, bool > edge( typename LABELED_GRAPH::vertex_descriptor const& u, typename LABELED_GRAPH::vertex_descriptor const& v, LABELED_GRAPH const& g) { return edge(u, v, g.graph()); } // Labeled Extensions template < LABELED_GRAPH_PARAMS > inline std::pair< typename LABELED_GRAPH::edge_descriptor, bool > edge_by_label( typename LABELED_GRAPH::label_type const& u, typename LABELED_GRAPH::label_type const& v, LABELED_GRAPH const& g) { return edge(g.vertex(u), g.vertex(v), g); } //@} /** @name Incidence Graph */ //@{ template < LABELED_GRAPH_PARAMS > inline std::pair< typename LABELED_GRAPH::out_edge_iterator, typename LABELED_GRAPH::out_edge_iterator > out_edges(typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH const& g) { return out_edges(v, g.graph()); } template < LABELED_GRAPH_PARAMS > inline typename LABELED_GRAPH::degree_size_type out_degree( typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH const& g) { return out_degree(v, g.graph()); } template < LABELED_GRAPH_PARAMS > inline typename LABELED_GRAPH::vertex_descriptor source( typename LABELED_GRAPH::edge_descriptor e, LABELED_GRAPH const& g) { return source(e, g.graph()); } template < LABELED_GRAPH_PARAMS > inline typename LABELED_GRAPH::vertex_descriptor target( typename LABELED_GRAPH::edge_descriptor e, LABELED_GRAPH const& g) { return target(e, g.graph()); } //@} /** @name Bidirectional Graph */ //@{ template < LABELED_GRAPH_PARAMS > inline std::pair< typename LABELED_GRAPH::in_edge_iterator, typename LABELED_GRAPH::in_edge_iterator > in_edges(typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH const& g) { return in_edges(v, g.graph()); } template < LABELED_GRAPH_PARAMS > inline typename LABELED_GRAPH::degree_size_type in_degree( typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH const& g) { return in_degree(v, g.graph()); } template < LABELED_GRAPH_PARAMS > inline typename LABELED_GRAPH::degree_size_type degree( typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH const& g) { return degree(v, g.graph()); } //@} /** @name Adjacency Graph */ //@{ template < LABELED_GRAPH_PARAMS > inline std::pair< typename LABELED_GRAPH::adjacency_iterator, typename LABELED_GRAPH::adjacency_iterator > adjacenct_vertices( typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH const& g) { return adjacent_vertices(v, g.graph()); } //@} /** @name VertexListGraph */ //@{ template < LABELED_GRAPH_PARAMS > inline std::pair< typename LABELED_GRAPH::vertex_iterator, typename LABELED_GRAPH::vertex_iterator > vertices(LABELED_GRAPH const& g) { return vertices(g.graph()); } template < LABELED_GRAPH_PARAMS > inline typename LABELED_GRAPH::vertices_size_type num_vertices( LABELED_GRAPH const& g) { return num_vertices(g.graph()); } //@} /** @name EdgeListGraph */ //@{ template < LABELED_GRAPH_PARAMS > inline std::pair< typename LABELED_GRAPH::edge_iterator, typename LABELED_GRAPH::edge_iterator > edges(LABELED_GRAPH const& g) { return edges(g.graph()); } template < LABELED_GRAPH_PARAMS > inline typename LABELED_GRAPH::edges_size_type num_edges(LABELED_GRAPH const& g) { return num_edges(g.graph()); } //@} /** @internal @name Property Lookup */ //@{ namespace graph_detail { struct labeled_graph_vertex_property_selector { template < class LabeledGraph, class Property, class Tag > struct bind_ { typedef typename LabeledGraph::graph_type Graph; typedef property_map< Graph, Tag > PropertyMap; typedef typename PropertyMap::type type; typedef typename PropertyMap::const_type const_type; }; }; struct labeled_graph_edge_property_selector { template < class LabeledGraph, class Property, class Tag > struct bind_ { typedef typename LabeledGraph::graph_type Graph; typedef property_map< Graph, Tag > PropertyMap; typedef typename PropertyMap::type type; typedef typename PropertyMap::const_type const_type; }; }; } template <> struct vertex_property_selector< labeled_graph_class_tag > { typedef graph_detail::labeled_graph_vertex_property_selector type; }; template <> struct edge_property_selector< labeled_graph_class_tag > { typedef graph_detail::labeled_graph_edge_property_selector type; }; //@} /** @name Property Graph */ //@{ template < LABELED_GRAPH_PARAMS, typename Prop > inline typename property_map< LABELED_GRAPH, Prop >::type get( Prop p, LABELED_GRAPH& g) { return get(p, g.graph()); } template < LABELED_GRAPH_PARAMS, typename Prop > inline typename property_map< LABELED_GRAPH, Prop >::const_type get( Prop p, LABELED_GRAPH const& g) { return get(p, g.graph()); } template < LABELED_GRAPH_PARAMS, typename Prop, typename Key > inline typename property_traits< typename property_map< typename LABELED_GRAPH::graph_type, Prop >::const_type >::value_type get(Prop p, LABELED_GRAPH const& g, const Key& k) { return get(p, g.graph(), k); } template < LABELED_GRAPH_PARAMS, typename Prop, typename Key, typename Value > inline void put(Prop p, LABELED_GRAPH& g, Key const& k, Value const& v) { put(p, g.graph(), k, v); } //@} /** @name Mutable Graph */ //@{ template < LABELED_GRAPH_PARAMS > inline std::pair< typename LABELED_GRAPH::edge_descriptor, bool > add_edge( typename LABELED_GRAPH::vertex_descriptor const& u, typename LABELED_GRAPH::vertex_descriptor const& v, LABELED_GRAPH& g) { return add_edge(u, v, g.graph()); } template < LABELED_GRAPH_PARAMS > inline std::pair< typename LABELED_GRAPH::edge_descriptor, bool > add_edge( typename LABELED_GRAPH::vertex_descriptor const& u, typename LABELED_GRAPH::vertex_descriptor const& v, typename LABELED_GRAPH::edge_property_type const& p, LABELED_GRAPH& g) { return add_edge(u, v, p, g.graph()); } template < LABELED_GRAPH_PARAMS > inline void clear_vertex( typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH& g) { return clear_vertex(v, g.graph()); } template < LABELED_GRAPH_PARAMS > inline void remove_edge( typename LABELED_GRAPH::edge_descriptor e, LABELED_GRAPH& g) { return remove_edge(e, g.graph()); } template < LABELED_GRAPH_PARAMS > inline void remove_edge(typename LABELED_GRAPH::vertex_descriptor u, typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH& g) { return remove_edge(u, v, g.graph()); } // Labeled extensions template < LABELED_GRAPH_PARAMS > inline std::pair< typename LABELED_GRAPH::edge_descriptor, bool > add_edge_by_label(typename LABELED_GRAPH::label_type const& u, typename LABELED_GRAPH::label_type const& v, LABELED_GRAPH& g) { return add_edge(g.vertex(u), g.vertex(v), g); } template < LABELED_GRAPH_PARAMS > inline std::pair< typename LABELED_GRAPH::edge_descriptor, bool > add_edge_by_label(typename LABELED_GRAPH::label_type const& u, typename LABELED_GRAPH::label_type const& v, typename LABELED_GRAPH::edge_property_type const& p, LABELED_GRAPH& g) { return add_edge(g.vertex(u), g.vertex(v), p, g); } template < LABELED_GRAPH_PARAMS > inline void clear_vertex_by_label( typename LABELED_GRAPH::label_type const& l, LABELED_GRAPH& g) { clear_vertex(g.vertex(l), g.graph()); } template < LABELED_GRAPH_PARAMS > inline void remove_edge_by_label(typename LABELED_GRAPH::label_type const& u, typename LABELED_GRAPH::label_type const& v, LABELED_GRAPH& g) { remove_edge(g.vertex(u), g.vertex(v), g.graph()); } //@} /** @name Labeled Mutable Graph * The labeled mutable graph hides the add_ and remove_ vertex functions from * the mutable graph concept. Note that the remove_vertex is hidden because * removing the vertex without its key could leave a dangling reference in * the map. */ //@{ template < LABELED_GRAPH_PARAMS > inline typename LABELED_GRAPH::vertex_descriptor add_vertex( typename LABELED_GRAPH::label_type const& l, LABELED_GRAPH& g) { return g.add_vertex(l); } // MutableLabeledPropertyGraph::add_vertex(l, vp, g) template < LABELED_GRAPH_PARAMS > inline typename LABELED_GRAPH::vertex_descriptor add_vertex( typename LABELED_GRAPH::label_type const& l, typename LABELED_GRAPH::vertex_property_type const& p, LABELED_GRAPH& g) { return g.add_vertex(l, p); } template < LABELED_GRAPH_PARAMS > inline void remove_vertex( typename LABELED_GRAPH::label_type const& l, LABELED_GRAPH& g) { g.remove_vertex(l); } //@} #undef LABELED_GRAPH_PARAMS #undef LABELED_GRAPH } // namespace boost // Pull the labeled graph traits #include <boost/graph/detail/labeled_graph_traits.hpp> #endif // BOOST_GRAPH_LABELED_GRAPH_HPP johnson_all_pairs_shortest.hpp 0000644 00000016736 15125521275 0012736 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= /* This file implements the function template <class VertexAndEdgeListGraph, class DistanceMatrix, class P, class T, class R> bool johnson_all_pairs_shortest_paths (VertexAndEdgeListGraph& g, DistanceMatrix& D, const bgl_named_params<P, T, R>& params) */ #ifndef BOOST_GRAPH_JOHNSON_HPP #define BOOST_GRAPH_JOHNSON_HPP #include <boost/graph/graph_traits.hpp> #include <boost/property_map/property_map.hpp> #include <boost/property_map/shared_array_property_map.hpp> #include <boost/graph/bellman_ford_shortest_paths.hpp> #include <boost/graph/dijkstra_shortest_paths.hpp> #include <boost/graph/adjacency_list.hpp> #include <boost/type_traits/same_traits.hpp> #include <boost/concept/assert.hpp> namespace boost { template < class VertexAndEdgeListGraph, class DistanceMatrix, class VertexID, class Weight, typename BinaryPredicate, typename BinaryFunction, typename Infinity, class DistanceZero > bool johnson_all_pairs_shortest_paths(VertexAndEdgeListGraph& g1, DistanceMatrix& D, VertexID id1, Weight w1, const BinaryPredicate& compare, const BinaryFunction& combine, const Infinity& inf, DistanceZero zero) { typedef graph_traits< VertexAndEdgeListGraph > Traits1; typedef typename property_traits< Weight >::value_type DT; BOOST_CONCEPT_ASSERT((BasicMatrixConcept< DistanceMatrix, typename Traits1::vertices_size_type, DT >)); typedef typename Traits1::directed_category DirCat; bool is_undirected = is_same< DirCat, undirected_tag >::value; typedef adjacency_list< vecS, vecS, directedS, property< vertex_distance_t, DT >, property< edge_weight_t, DT, property< edge_weight2_t, DT > > > Graph2; typedef graph_traits< Graph2 > Traits2; Graph2 g2(num_vertices(g1) + 1); typename property_map< Graph2, edge_weight_t >::type w = get(edge_weight, g2); typename property_map< Graph2, edge_weight2_t >::type w_hat = get(edge_weight2, g2); typename property_map< Graph2, vertex_distance_t >::type d = get(vertex_distance, g2); typedef typename property_map< Graph2, vertex_index_t >::type VertexID2; VertexID2 id2 = get(vertex_index, g2); // Construct g2 where V[g2] = V[g1] U {s} // and E[g2] = E[g1] U {(s,v)| v in V[g1]} std::vector< typename Traits1::vertex_descriptor > verts1( num_vertices(g1) + 1); typename Traits2::vertex_descriptor s = *vertices(g2).first; { typename Traits1::vertex_iterator v, v_end; int i = 1; for (boost::tie(v, v_end) = vertices(g1); v != v_end; ++v, ++i) { typename Traits2::edge_descriptor e; bool z; boost::tie(e, z) = add_edge(s, get(id1, *v) + 1, g2); put(w, e, zero); verts1[i] = *v; } typename Traits1::edge_iterator e, e_end; for (boost::tie(e, e_end) = edges(g1); e != e_end; ++e) { typename Traits2::edge_descriptor e2; bool z; boost::tie(e2, z) = add_edge( get(id1, source(*e, g1)) + 1, get(id1, target(*e, g1)) + 1, g2); put(w, e2, get(w1, *e)); if (is_undirected) { boost::tie(e2, z) = add_edge(get(id1, target(*e, g1)) + 1, get(id1, source(*e, g1)) + 1, g2); put(w, e2, get(w1, *e)); } } } typename Traits2::vertex_iterator v, v_end, u, u_end; typename Traits2::edge_iterator e, e_end; shared_array_property_map< DT, VertexID2 > h(num_vertices(g2), id2); for (boost::tie(v, v_end) = vertices(g2); v != v_end; ++v) put(d, *v, inf); put(d, s, zero); // Using the non-named parameter versions of bellman_ford and // dijkstra for portability reasons. dummy_property_map pred; bellman_visitor<> bvis; if (bellman_ford_shortest_paths( g2, num_vertices(g2), w, pred, d, combine, compare, bvis)) { for (boost::tie(v, v_end) = vertices(g2); v != v_end; ++v) put(h, *v, get(d, *v)); // Reweight the edges to remove negatives for (boost::tie(e, e_end) = edges(g2); e != e_end; ++e) { typename Traits2::vertex_descriptor a = source(*e, g2), b = target(*e, g2); put(w_hat, *e, combine((get(h, a) - get(h, b)), get(w, *e))); } for (boost::tie(u, u_end) = vertices(g2); u != u_end; ++u) { dijkstra_visitor<> dvis; dijkstra_shortest_paths( g2, *u, pred, d, w_hat, id2, compare, combine, inf, zero, dvis); for (boost::tie(v, v_end) = vertices(g2); v != v_end; ++v) { if (*u != s && *v != s) { D[get(id2, *u) - 1][get(id2, *v) - 1] = combine((get(h, *v) - get(h, *u)), get(d, *v)); } } } return true; } else return false; } template < class VertexAndEdgeListGraph, class DistanceMatrix, class VertexID, class Weight, class DistanceZero > bool johnson_all_pairs_shortest_paths(VertexAndEdgeListGraph& g1, DistanceMatrix& D, VertexID id1, Weight w1, DistanceZero zero) { typedef typename property_traits< Weight >::value_type WT; return johnson_all_pairs_shortest_paths(g1, D, id1, w1, std::less< WT >(), closed_plus< WT >(), (std::numeric_limits< WT >::max)(), zero); } namespace detail { template < class VertexAndEdgeListGraph, class DistanceMatrix, class P, class T, class R, class Weight, class VertexID > bool johnson_dispatch(VertexAndEdgeListGraph& g, DistanceMatrix& D, const bgl_named_params< P, T, R >& params, Weight w, VertexID id) { typedef typename property_traits< Weight >::value_type WT; return johnson_all_pairs_shortest_paths(g, D, id, w, choose_param( get_param(params, distance_compare_t()), std::less< WT >()), choose_param( get_param(params, distance_combine_t()), closed_plus< WT >()), choose_param(get_param(params, distance_inf_t()), std::numeric_limits< WT >::max BOOST_PREVENT_MACRO_SUBSTITUTION()), choose_param(get_param(params, distance_zero_t()), WT())); } } // namespace detail template < class VertexAndEdgeListGraph, class DistanceMatrix, class P, class T, class R > bool johnson_all_pairs_shortest_paths(VertexAndEdgeListGraph& g, DistanceMatrix& D, const bgl_named_params< P, T, R >& params) { return detail::johnson_dispatch(g, D, params, choose_const_pmap(get_param(params, edge_weight), g, edge_weight), choose_const_pmap(get_param(params, vertex_index), g, vertex_index)); } template < class VertexAndEdgeListGraph, class DistanceMatrix > bool johnson_all_pairs_shortest_paths( VertexAndEdgeListGraph& g, DistanceMatrix& D) { bgl_named_params< int, int > params(1); return detail::johnson_dispatch( g, D, params, get(edge_weight, g), get(vertex_index, g)); } } // namespace boost #endif // BOOST_GRAPH_JOHNSON_HPP edge_coloring.hpp 0000644 00000015231 15125521275 0010064 0 ustar 00 //======================================================================= // Copyright 2013 Maciej Piechotka // Authors: Maciej Piechotka // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_EDGE_COLORING_HPP #define BOOST_GRAPH_EDGE_COLORING_HPP #include <boost/graph/graph_traits.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/graph/properties.hpp> #include <algorithm> #include <limits> #include <vector> /* This algorithm is to find coloring of an edges Reference: Misra, J., & Gries, D. (1992). A constructive proof of Vizing's theorem. In Information Processing Letters. */ namespace boost { namespace detail { template < typename Graph, typename ColorMap > bool is_free(const Graph& g, ColorMap color, typename boost::graph_traits< Graph >::vertex_descriptor u, typename boost::property_traits< ColorMap >::value_type free_color) { typedef typename boost::property_traits< ColorMap >::value_type color_t; if (free_color == (std::numeric_limits< color_t >::max)()) return false; BGL_FORALL_OUTEDGES_T(u, e, g, Graph) { if (get(color, e) == free_color) { return false; } } return true; } template < typename Graph, typename ColorMap > std::vector< typename boost::graph_traits< Graph >::vertex_descriptor > maximal_fan(const Graph& g, ColorMap color, typename boost::graph_traits< Graph >::vertex_descriptor x, typename boost::graph_traits< Graph >::vertex_descriptor y) { typedef typename boost::graph_traits< Graph >::vertex_descriptor vertex_t; std::vector< vertex_t > fan; fan.push_back(y); bool extended; do { extended = false; BGL_FORALL_OUTEDGES_T(x, e, g, Graph) { vertex_t v = target(e, g); if (is_free(g, color, fan.back(), get(color, e)) && std::find(fan.begin(), fan.end(), v) == fan.end()) { fan.push_back(v); extended = true; } } } while (extended); return fan; } template < typename Graph, typename ColorMap > typename boost::property_traits< ColorMap >::value_type find_free_color( const Graph& g, ColorMap color, typename boost::graph_traits< Graph >::vertex_descriptor u) { typename boost::property_traits< ColorMap >::value_type c = 0; while (!is_free(g, color, u, c)) c++; return c; } template < typename Graph, typename ColorMap > void invert_cd_path(const Graph& g, ColorMap color, typename boost::graph_traits< Graph >::vertex_descriptor x, typename boost::graph_traits< Graph >::edge_descriptor eold, typename boost::property_traits< ColorMap >::value_type c, typename boost::property_traits< ColorMap >::value_type d) { put(color, eold, d); BGL_FORALL_OUTEDGES_T(x, e, g, Graph) { if (get(color, e) == d && e != eold) { invert_cd_path(g, color, target(e, g), e, d, c); return; } } } template < typename Graph, typename ColorMap > void invert_cd_path(const Graph& g, ColorMap color, typename boost::graph_traits< Graph >::vertex_descriptor x, typename boost::property_traits< ColorMap >::value_type c, typename boost::property_traits< ColorMap >::value_type d) { BGL_FORALL_OUTEDGES_T(x, e, g, Graph) { if (get(color, e) == d) { invert_cd_path(g, color, target(e, g), e, d, c); return; } } } template < typename Graph, typename ColorMap, typename ForwardIterator > void rotate_fan(const Graph& g, ColorMap color, typename boost::graph_traits< Graph >::vertex_descriptor x, ForwardIterator begin, ForwardIterator end) { typedef typename boost::graph_traits< Graph >::edge_descriptor edge_t; if (begin == end) { return; } edge_t previous = edge(x, *begin, g).first; for (begin++; begin != end; begin++) { edge_t current = edge(x, *begin, g).first; put(color, previous, get(color, current)); previous = current; } } template < typename Graph, typename ColorMap > class find_free_in_fan { public: find_free_in_fan(const Graph& graph, const ColorMap color, typename boost::property_traits< ColorMap >::value_type d) : graph(graph), color(color), d(d) { } bool operator()( const typename boost::graph_traits< Graph >::vertex_descriptor u) const { return is_free(graph, color, u, d); } private: const Graph& graph; const ColorMap color; const typename boost::property_traits< ColorMap >::value_type d; }; } template < typename Graph, typename ColorMap > typename boost::property_traits< ColorMap >::value_type color_edge( const Graph& g, ColorMap color, typename boost::graph_traits< Graph >::edge_descriptor e) { typedef typename boost::graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename boost::property_traits< ColorMap >::value_type color_t; typedef typename std::vector< vertex_t >::iterator fan_iterator; using namespace detail; vertex_t x = source(e, g), y = target(e, g); std::vector< vertex_t > fan = maximal_fan(g, color, x, y); color_t c = find_free_color(g, color, x); color_t d = find_free_color(g, color, fan.back()); invert_cd_path(g, color, x, c, d); fan_iterator w = std::find_if(fan.begin(), fan.end(), find_free_in_fan< Graph, ColorMap >(g, color, d)); rotate_fan(g, color, x, fan.begin(), w + 1); put(color, edge(x, *w, g).first, d); return (std::max)(c, d); } template < typename Graph, typename ColorMap > typename boost::property_traits< ColorMap >::value_type edge_coloring( const Graph& g, ColorMap color) { typedef typename boost::property_traits< ColorMap >::value_type color_t; BGL_FORALL_EDGES_T(e, g, Graph) { put(color, e, (std::numeric_limits< color_t >::max)()); } color_t colors = 0; BGL_FORALL_EDGES_T(e, g, Graph) { colors = (std::max)(colors, color_edge(g, color, e) + 1); } return colors; } } #endif wavefront.hpp 0000644 00000007534 15125521275 0007306 0 ustar 00 // //======================================================================= // Copyright 2002 Marc Wintermantel (wintermantel@even-ag.ch) // ETH Zurich, Center of Structure Technologies // (https://web.archive.org/web/20050307090307/http://www.structures.ethz.ch/) // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_WAVEFRONT_HPP #define BOOST_GRAPH_WAVEFRONT_HPP #include <boost/config.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/detail/numeric_traits.hpp> #include <boost/graph/bandwidth.hpp> #include <boost/config/no_tr1/cmath.hpp> #include <vector> #include <algorithm> // for std::min and std::max namespace boost { template < typename Graph, typename VertexIndexMap > typename graph_traits< Graph >::vertices_size_type ith_wavefront( typename graph_traits< Graph >::vertex_descriptor i, const Graph& g, VertexIndexMap index) { typename graph_traits< Graph >::vertex_descriptor v, w; typename graph_traits< Graph >::vertices_size_type b = 1; typename graph_traits< Graph >::out_edge_iterator edge_it2, edge_it2_end; typename graph_traits< Graph >::vertices_size_type index_i = index[i]; std::vector< bool > rows_active(num_vertices(g), false); rows_active[index_i] = true; typename graph_traits< Graph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { v = *ui; if (index[v] <= index_i) { for (boost::tie(edge_it2, edge_it2_end) = out_edges(v, g); edge_it2 != edge_it2_end; ++edge_it2) { w = target(*edge_it2, g); if ((index[w] >= index_i) && (!rows_active[index[w]])) { b++; rows_active[index[w]] = true; } } } } return b; } template < typename Graph > typename graph_traits< Graph >::vertices_size_type ith_wavefront( typename graph_traits< Graph >::vertex_descriptor i, const Graph& g) { return ith_wavefront(i, g, get(vertex_index, g)); } template < typename Graph, typename VertexIndexMap > typename graph_traits< Graph >::vertices_size_type max_wavefront( const Graph& g, VertexIndexMap index) { BOOST_USING_STD_MAX(); typename graph_traits< Graph >::vertices_size_type b = 0; typename graph_traits< Graph >::vertex_iterator i, end; for (boost::tie(i, end) = vertices(g); i != end; ++i) b = max BOOST_PREVENT_MACRO_SUBSTITUTION( b, ith_wavefront(*i, g, index)); return b; } template < typename Graph > typename graph_traits< Graph >::vertices_size_type max_wavefront(const Graph& g) { return max_wavefront(g, get(vertex_index, g)); } template < typename Graph, typename VertexIndexMap > double aver_wavefront(const Graph& g, VertexIndexMap index) { double b = 0; typename graph_traits< Graph >::vertex_iterator i, end; for (boost::tie(i, end) = vertices(g); i != end; ++i) b += ith_wavefront(*i, g, index); b /= num_vertices(g); return b; } template < typename Graph > double aver_wavefront(const Graph& g) { return aver_wavefront(g, get(vertex_index, g)); } template < typename Graph, typename VertexIndexMap > double rms_wavefront(const Graph& g, VertexIndexMap index) { double b = 0; typename graph_traits< Graph >::vertex_iterator i, end; for (boost::tie(i, end) = vertices(g); i != end; ++i) b += std::pow(double(ith_wavefront(*i, g, index)), 2.0); b /= num_vertices(g); return std::sqrt(b); } template < typename Graph > double rms_wavefront(const Graph& g) { return rms_wavefront(g, get(vertex_index, g)); } } // namespace boost #endif // BOOST_GRAPH_WAVEFRONT_HPP copy.hpp 0000644 00000051351 15125521275 0006241 0 ustar 00 // //======================================================================= // Copyright 1997-2001 University of Notre Dame. // Authors: Jeremy G. Siek, Lie-Quan Lee, Andrew Lumsdaine // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // /* This file implements the following functions: template <typename VertexListGraph, typename MutableGraph> void copy_graph(const VertexListGraph& g_in, MutableGraph& g_out) template <typename VertexListGraph, typename MutableGraph, class P, class T, class R> void copy_graph(const VertexListGraph& g_in, MutableGraph& g_out, const bgl_named_params<P, T, R>& params) template <typename IncidenceGraph, typename MutableGraph> typename graph_traits<MutableGraph>::vertex_descriptor copy_component(IncidenceGraph& g_in, typename graph_traits<IncidenceGraph>::vertex_descriptor src, MutableGraph& g_out) template <typename IncidenceGraph, typename MutableGraph, typename P, typename T, typename R> typename graph_traits<MutableGraph>::vertex_descriptor copy_component(IncidenceGraph& g_in, typename graph_traits<IncidenceGraph>::vertex_descriptor src, MutableGraph& g_out, const bgl_named_params<P, T, R>& params) */ #ifndef BOOST_GRAPH_COPY_HPP #define BOOST_GRAPH_COPY_HPP #include <boost/config.hpp> #include <vector> #include <boost/graph/graph_traits.hpp> #include <boost/graph/reverse_graph.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/graph/breadth_first_search.hpp> #include <boost/type_traits/conversion_traits.hpp> namespace boost { namespace detail { // Hack to make transpose_graph work with the same interface as before template < typename Graph, typename Desc > struct remove_reverse_edge_descriptor { typedef Desc type; static Desc convert(const Desc& d, const Graph&) { return d; } }; template < typename Graph, typename Desc > struct remove_reverse_edge_descriptor< Graph, reverse_graph_edge_descriptor< Desc > > { typedef Desc type; static Desc convert( const reverse_graph_edge_descriptor< Desc >& d, const Graph& g) { return get(edge_underlying, g, d); } }; // Add a reverse_graph_edge_descriptor wrapper if the Graph is a // reverse_graph but the edge descriptor is from the original graph (this // case comes from the fact that transpose_graph uses reverse_graph // internally but doesn't expose the different edge descriptor type to the // user). template < typename Desc, typename Graph > struct add_reverse_edge_descriptor { typedef Desc type; static Desc convert(const Desc& d) { return d; } }; template < typename Desc, typename G, typename GR > struct add_reverse_edge_descriptor< Desc, boost::reverse_graph< G, GR > > { typedef reverse_graph_edge_descriptor< Desc > type; static reverse_graph_edge_descriptor< Desc > convert(const Desc& d) { return reverse_graph_edge_descriptor< Desc >(d); } }; template < typename Desc, typename G, typename GR > struct add_reverse_edge_descriptor< reverse_graph_edge_descriptor< Desc >, boost::reverse_graph< G, GR > > { typedef reverse_graph_edge_descriptor< Desc > type; static reverse_graph_edge_descriptor< Desc > convert( const reverse_graph_edge_descriptor< Desc >& d) { return d; } }; // Default edge and vertex property copiers template < typename Graph1, typename Graph2 > struct edge_copier { edge_copier(const Graph1& g1, Graph2& g2) : edge_all_map1(get(edge_all, g1)), edge_all_map2(get(edge_all, g2)) { } template < typename Edge1, typename Edge2 > void operator()(const Edge1& e1, Edge2& e2) const { put(edge_all_map2, e2, get(edge_all_map1, add_reverse_edge_descriptor< Edge1, Graph1 >::convert(e1))); } typename property_map< Graph1, edge_all_t >::const_type edge_all_map1; mutable typename property_map< Graph2, edge_all_t >::type edge_all_map2; }; template < typename Graph1, typename Graph2 > inline edge_copier< Graph1, Graph2 > make_edge_copier( const Graph1& g1, Graph2& g2) { return edge_copier< Graph1, Graph2 >(g1, g2); } template < typename Graph1, typename Graph2 > struct vertex_copier { vertex_copier(const Graph1& g1, Graph2& g2) : vertex_all_map1(get(vertex_all, g1)) , vertex_all_map2(get(vertex_all, g2)) { } template < typename Vertex1, typename Vertex2 > void operator()(const Vertex1& v1, Vertex2& v2) const { put(vertex_all_map2, v2, get(vertex_all_map1, v1)); } typename property_map< Graph1, vertex_all_t >::const_type vertex_all_map1; mutable typename property_map< Graph2, vertex_all_t >::type vertex_all_map2; }; template < typename Graph1, typename Graph2 > inline vertex_copier< Graph1, Graph2 > make_vertex_copier( const Graph1& g1, Graph2& g2) { return vertex_copier< Graph1, Graph2 >(g1, g2); } // Copy all the vertices and edges of graph g_in into graph g_out. // The copy_vertex and copy_edge function objects control how vertex // and edge properties are copied. template < int Version > struct copy_graph_impl { }; template <> struct copy_graph_impl< 0 > { template < typename Graph, typename MutableGraph, typename CopyVertex, typename CopyEdge, typename IndexMap, typename Orig2CopyVertexIndexMap > static void apply(const Graph& g_in, MutableGraph& g_out, CopyVertex copy_vertex, CopyEdge copy_edge, Orig2CopyVertexIndexMap orig2copy, IndexMap) { typedef remove_reverse_edge_descriptor< Graph, typename graph_traits< Graph >::edge_descriptor > cvt; typename graph_traits< Graph >::vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) { typename graph_traits< MutableGraph >::vertex_descriptor new_v = add_vertex(g_out); put(orig2copy, *vi, new_v); copy_vertex(*vi, new_v); } typename graph_traits< Graph >::edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = edges(g_in); ei != ei_end; ++ei) { typename graph_traits< MutableGraph >::edge_descriptor new_e; bool inserted; boost::tie(new_e, inserted) = add_edge(get(orig2copy, source(*ei, g_in)), get(orig2copy, target(*ei, g_in)), g_out); copy_edge(cvt::convert(*ei, g_in), new_e); } } }; // for directed graphs template <> struct copy_graph_impl< 1 > { template < typename Graph, typename MutableGraph, typename CopyVertex, typename CopyEdge, typename IndexMap, typename Orig2CopyVertexIndexMap > static void apply(const Graph& g_in, MutableGraph& g_out, CopyVertex copy_vertex, CopyEdge copy_edge, Orig2CopyVertexIndexMap orig2copy, IndexMap) { typedef remove_reverse_edge_descriptor< Graph, typename graph_traits< Graph >::edge_descriptor > cvt; typename graph_traits< Graph >::vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) { typename graph_traits< MutableGraph >::vertex_descriptor new_v = add_vertex(g_out); put(orig2copy, *vi, new_v); copy_vertex(*vi, new_v); } for (boost::tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) { typename graph_traits< Graph >::out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(*vi, g_in); ei != ei_end; ++ei) { typename graph_traits< MutableGraph >::edge_descriptor new_e; bool inserted; boost::tie(new_e, inserted) = add_edge(get(orig2copy, source(*ei, g_in)), get(orig2copy, target(*ei, g_in)), g_out); copy_edge(cvt::convert(*ei, g_in), new_e); } } } }; // for undirected graphs template <> struct copy_graph_impl< 2 > { template < typename Graph, typename MutableGraph, typename CopyVertex, typename CopyEdge, typename IndexMap, typename Orig2CopyVertexIndexMap > static void apply(const Graph& g_in, MutableGraph& g_out, CopyVertex copy_vertex, CopyEdge copy_edge, Orig2CopyVertexIndexMap orig2copy, IndexMap index_map) { typedef remove_reverse_edge_descriptor< Graph, typename graph_traits< Graph >::edge_descriptor > cvt; typedef color_traits< default_color_type > Color; std::vector< default_color_type > color( num_vertices(g_in), Color::white()); typename graph_traits< Graph >::vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) { typename graph_traits< MutableGraph >::vertex_descriptor new_v = add_vertex(g_out); put(orig2copy, *vi, new_v); copy_vertex(*vi, new_v); } for (boost::tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) { typename graph_traits< Graph >::out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(*vi, g_in); ei != ei_end; ++ei) { typename graph_traits< MutableGraph >::edge_descriptor new_e; bool inserted; if (color[get(index_map, target(*ei, g_in))] == Color::white()) { boost::tie(new_e, inserted) = add_edge(get(orig2copy, source(*ei, g_in)), get(orig2copy, target(*ei, g_in)), g_out); copy_edge(cvt::convert(*ei, g_in), new_e); } } color[get(index_map, *vi)] = Color::black(); } } }; template < class Graph > struct choose_graph_copy { typedef typename graph_traits< Graph >::traversal_category Trv; typedef typename graph_traits< Graph >::directed_category Dr; enum { algo = (is_convertible< Trv, vertex_list_graph_tag >::value && is_convertible< Trv, edge_list_graph_tag >::value) ? 0 : is_convertible< Dr, directed_tag >::value ? 1 : 2 }; typedef copy_graph_impl< algo > type; }; //------------------------------------------------------------------------- struct choose_copier_parameter { template < class P, class G1, class G2 > struct bind_ { typedef const P& result_type; static result_type apply(const P& p, const G1&, G2&) { return p; } }; }; struct choose_default_edge_copier { template < class P, class G1, class G2 > struct bind_ { typedef edge_copier< G1, G2 > result_type; static result_type apply(const P&, const G1& g1, G2& g2) { return result_type(g1, g2); } }; }; template < class Param > struct choose_edge_copy { typedef choose_copier_parameter type; }; template <> struct choose_edge_copy< param_not_found > { typedef choose_default_edge_copier type; }; template < class Param, class G1, class G2 > struct choose_edge_copier_helper { typedef typename choose_edge_copy< Param >::type Selector; typedef typename Selector::template bind_< Param, G1, G2 > Bind; typedef Bind type; typedef typename Bind::result_type result_type; }; template < typename Param, typename G1, typename G2 > typename detail::choose_edge_copier_helper< Param, G1, G2 >::result_type choose_edge_copier(const Param& params, const G1& g_in, G2& g_out) { typedef typename detail::choose_edge_copier_helper< Param, G1, G2 >::type Choice; return Choice::apply(params, g_in, g_out); } struct choose_default_vertex_copier { template < class P, class G1, class G2 > struct bind_ { typedef vertex_copier< G1, G2 > result_type; static result_type apply(const P&, const G1& g1, G2& g2) { return result_type(g1, g2); } }; }; template < class Param > struct choose_vertex_copy { typedef choose_copier_parameter type; }; template <> struct choose_vertex_copy< param_not_found > { typedef choose_default_vertex_copier type; }; template < class Param, class G1, class G2 > struct choose_vertex_copier_helper { typedef typename choose_vertex_copy< Param >::type Selector; typedef typename Selector::template bind_< Param, G1, G2 > Bind; typedef Bind type; typedef typename Bind::result_type result_type; }; template < typename Param, typename G1, typename G2 > typename detail::choose_vertex_copier_helper< Param, G1, G2 >::result_type choose_vertex_copier(const Param& params, const G1& g_in, G2& g_out) { typedef typename detail::choose_vertex_copier_helper< Param, G1, G2 >::type Choice; return Choice::apply(params, g_in, g_out); } } // namespace detail template < typename VertexListGraph, typename MutableGraph > void copy_graph(const VertexListGraph& g_in, MutableGraph& g_out) { if (num_vertices(g_in) == 0) return; typedef typename graph_traits< MutableGraph >::vertex_descriptor vertex_t; std::vector< vertex_t > orig2copy(num_vertices(g_in)); typedef typename detail::choose_graph_copy< VertexListGraph >::type copy_impl; copy_impl::apply(g_in, g_out, detail::make_vertex_copier(g_in, g_out), detail::make_edge_copier(g_in, g_out), make_iterator_property_map( orig2copy.begin(), get(vertex_index, g_in), orig2copy[0]), get(vertex_index, g_in)); } template < typename VertexListGraph, typename MutableGraph, class P, class T, class R > void copy_graph(const VertexListGraph& g_in, MutableGraph& g_out, const bgl_named_params< P, T, R >& params) { typename std::vector< T >::size_type n; n = is_default_param(get_param(params, orig_to_copy_t())) ? num_vertices(g_in) : 1; if (n == 0) return; std::vector< BOOST_DEDUCED_TYPENAME graph_traits< MutableGraph >::vertex_descriptor > orig2copy(n); typedef typename detail::choose_graph_copy< VertexListGraph >::type copy_impl; copy_impl::apply(g_in, g_out, detail::choose_vertex_copier( get_param(params, vertex_copy_t()), g_in, g_out), detail::choose_edge_copier( get_param(params, edge_copy_t()), g_in, g_out), choose_param(get_param(params, orig_to_copy_t()), make_iterator_property_map(orig2copy.begin(), choose_const_pmap( get_param(params, vertex_index), g_in, vertex_index), orig2copy[0])), choose_const_pmap(get_param(params, vertex_index), g_in, vertex_index)); } namespace detail { template < class NewGraph, class Copy2OrigIndexMap, class CopyVertex, class CopyEdge > struct graph_copy_visitor : public bfs_visitor<> { graph_copy_visitor( NewGraph& graph, Copy2OrigIndexMap c, CopyVertex cv, CopyEdge ce) : g_out(graph), orig2copy(c), copy_vertex(cv), copy_edge(ce) { } template < class Vertex > typename graph_traits< NewGraph >::vertex_descriptor copy_one_vertex( Vertex u) const { typename graph_traits< NewGraph >::vertex_descriptor new_u = add_vertex(g_out); put(orig2copy, u, new_u); copy_vertex(u, new_u); return new_u; } template < class Edge, class Graph > void tree_edge(Edge e, const Graph& g_in) const { // For a tree edge, the target vertex has not been copied yet. typename graph_traits< NewGraph >::edge_descriptor new_e; bool inserted; boost::tie(new_e, inserted) = add_edge(get(orig2copy, source(e, g_in)), this->copy_one_vertex(target(e, g_in)), g_out); copy_edge(e, new_e); } template < class Edge, class Graph > void non_tree_edge(Edge e, const Graph& g_in) const { // For a non-tree edge, the target vertex has already been copied. typename graph_traits< NewGraph >::edge_descriptor new_e; bool inserted; boost::tie(new_e, inserted) = add_edge(get(orig2copy, source(e, g_in)), get(orig2copy, target(e, g_in)), g_out); copy_edge(e, new_e); } private: NewGraph& g_out; Copy2OrigIndexMap orig2copy; CopyVertex copy_vertex; CopyEdge copy_edge; }; template < typename Graph, typename MutableGraph, typename CopyVertex, typename CopyEdge, typename Orig2CopyVertexIndexMap, typename Params > typename graph_traits< MutableGraph >::vertex_descriptor copy_component_impl(const Graph& g_in, typename graph_traits< Graph >::vertex_descriptor src, MutableGraph& g_out, CopyVertex copy_vertex, CopyEdge copy_edge, Orig2CopyVertexIndexMap orig2copy, const Params& params) { graph_copy_visitor< MutableGraph, Orig2CopyVertexIndexMap, CopyVertex, CopyEdge > vis(g_out, orig2copy, copy_vertex, copy_edge); typename graph_traits< MutableGraph >::vertex_descriptor src_copy = vis.copy_one_vertex(src); breadth_first_search(g_in, src, params.visitor(vis)); return src_copy; } } // namespace detail // Copy all the vertices and edges of graph g_in that are reachable // from the source vertex into graph g_out. Return the vertex // in g_out that matches the source vertex of g_in. template < typename IncidenceGraph, typename MutableGraph, typename P, typename T, typename R > typename graph_traits< MutableGraph >::vertex_descriptor copy_component( IncidenceGraph& g_in, typename graph_traits< IncidenceGraph >::vertex_descriptor src, MutableGraph& g_out, const bgl_named_params< P, T, R >& params) { typename std::vector< T >::size_type n; n = is_default_param(get_param(params, orig_to_copy_t())) ? num_vertices(g_in) : 1; std::vector< typename graph_traits< IncidenceGraph >::vertex_descriptor > orig2copy(n); return detail::copy_component_impl(g_in, src, g_out, detail::choose_vertex_copier( get_param(params, vertex_copy_t()), g_in, g_out), detail::choose_edge_copier( get_param(params, edge_copy_t()), g_in, g_out), choose_param(get_param(params, orig_to_copy_t()), make_iterator_property_map(orig2copy.begin(), choose_pmap( get_param(params, vertex_index), g_in, vertex_index), orig2copy[0])), params); } template < typename IncidenceGraph, typename MutableGraph > typename graph_traits< MutableGraph >::vertex_descriptor copy_component( IncidenceGraph& g_in, typename graph_traits< IncidenceGraph >::vertex_descriptor src, MutableGraph& g_out) { std::vector< typename graph_traits< IncidenceGraph >::vertex_descriptor > orig2copy(num_vertices(g_in)); return detail::copy_component_impl(g_in, src, g_out, make_vertex_copier(g_in, g_out), make_edge_copier(g_in, g_out), make_iterator_property_map( orig2copy.begin(), get(vertex_index, g_in), orig2copy[0]), bgl_named_params< char, char >('x') // dummy param object ); } } // namespace boost #endif // BOOST_GRAPH_COPY_HPP graph_archetypes.hpp 0000644 00000025400 15125521275 0010613 0 ustar 00 //======================================================================= // Copyright 2002 Indiana University. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_ARCHETYPES_HPP #define BOOST_GRAPH_ARCHETYPES_HPP #include <boost/property_map/property_map.hpp> #include <boost/concept_archetype.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> namespace boost { // should use a different namespace for this namespace detail { struct null_graph_archetype : public null_archetype<> { struct traversal_category { }; }; } //=========================================================================== template < typename Vertex, typename Directed, typename ParallelCategory, typename Base = detail::null_graph_archetype > struct incidence_graph_archetype : public Base { typedef typename Base::traversal_category base_trav_cat; struct traversal_category : public incidence_graph_tag, public base_trav_cat { }; #if 0 typedef immutable_graph_tag mutability_category; #endif typedef Vertex vertex_descriptor; typedef unsigned int degree_size_type; typedef unsigned int vertices_size_type; typedef unsigned int edges_size_type; struct edge_descriptor { edge_descriptor() {} edge_descriptor(const detail::dummy_constructor&) {} bool operator==(const edge_descriptor&) const { return false; } bool operator!=(const edge_descriptor&) const { return false; } }; typedef input_iterator_archetype< edge_descriptor > out_edge_iterator; typedef Directed directed_category; typedef ParallelCategory edge_parallel_category; typedef void adjacency_iterator; typedef void in_edge_iterator; typedef void vertex_iterator; typedef void edge_iterator; static vertex_descriptor null_vertex() { return vertex_descriptor(); } }; template < typename V, typename D, typename P, typename B > V source( const typename incidence_graph_archetype< V, D, P, B >::edge_descriptor&, const incidence_graph_archetype< V, D, P, B >&) { return V(static_object< detail::dummy_constructor >::get()); } template < typename V, typename D, typename P, typename B > V target( const typename incidence_graph_archetype< V, D, P, B >::edge_descriptor&, const incidence_graph_archetype< V, D, P, B >&) { return V(static_object< detail::dummy_constructor >::get()); } template < typename V, typename D, typename P, typename B > std::pair< typename incidence_graph_archetype< V, D, P, B >::out_edge_iterator, typename incidence_graph_archetype< V, D, P, B >::out_edge_iterator > out_edges(const V&, const incidence_graph_archetype< V, D, P, B >&) { typedef typename incidence_graph_archetype< V, D, P, B >::out_edge_iterator Iter; return std::make_pair(Iter(), Iter()); } template < typename V, typename D, typename P, typename B > typename incidence_graph_archetype< V, D, P, B >::degree_size_type out_degree( const V&, const incidence_graph_archetype< V, D, P, B >&) { return 0; } //=========================================================================== template < typename Vertex, typename Directed, typename ParallelCategory, typename Base = detail::null_graph_archetype > struct adjacency_graph_archetype : public Base { typedef typename Base::traversal_category base_trav_cat; struct traversal_category : public adjacency_graph_tag, public base_trav_cat { }; typedef Vertex vertex_descriptor; typedef unsigned int degree_size_type; typedef unsigned int vertices_size_type; typedef unsigned int edges_size_type; typedef void edge_descriptor; typedef input_iterator_archetype< Vertex > adjacency_iterator; typedef Directed directed_category; typedef ParallelCategory edge_parallel_category; typedef void in_edge_iterator; typedef void out_edge_iterator; typedef void vertex_iterator; typedef void edge_iterator; static vertex_descriptor null_vertex() { return vertex_descriptor(); } }; template < typename V, typename D, typename P, typename B > std::pair< typename adjacency_graph_archetype< V, D, P, B >::adjacency_iterator, typename adjacency_graph_archetype< V, D, P, B >::adjacency_iterator > adjacent_vertices(const V&, const adjacency_graph_archetype< V, D, P, B >&) { typedef typename adjacency_graph_archetype< V, D, P, B >::adjacency_iterator Iter; return std::make_pair(Iter(), Iter()); } template < typename V, typename D, typename P, typename B > typename adjacency_graph_archetype< V, D, P, B >::degree_size_type out_degree( const V&, const adjacency_graph_archetype< V, D, P, B >&) { return 0; } //=========================================================================== template < typename Vertex, typename Directed, typename ParallelCategory, typename Base = detail::null_graph_archetype > struct vertex_list_graph_archetype : public Base { typedef incidence_graph_archetype< Vertex, Directed, ParallelCategory > Incidence; typedef adjacency_graph_archetype< Vertex, Directed, ParallelCategory > Adjacency; typedef typename Base::traversal_category base_trav_cat; struct traversal_category : public vertex_list_graph_tag, public base_trav_cat { }; #if 0 typedef immutable_graph_tag mutability_category; #endif typedef Vertex vertex_descriptor; typedef unsigned int degree_size_type; typedef typename Incidence::edge_descriptor edge_descriptor; typedef typename Incidence::out_edge_iterator out_edge_iterator; typedef typename Adjacency::adjacency_iterator adjacency_iterator; typedef input_iterator_archetype< Vertex > vertex_iterator; typedef unsigned int vertices_size_type; typedef unsigned int edges_size_type; typedef Directed directed_category; typedef ParallelCategory edge_parallel_category; typedef void in_edge_iterator; typedef void edge_iterator; static vertex_descriptor null_vertex() { return vertex_descriptor(); } }; template < typename V, typename D, typename P, typename B > std::pair< typename vertex_list_graph_archetype< V, D, P, B >::vertex_iterator, typename vertex_list_graph_archetype< V, D, P, B >::vertex_iterator > vertices(const vertex_list_graph_archetype< V, D, P, B >&) { typedef typename vertex_list_graph_archetype< V, D, P, B >::vertex_iterator Iter; return std::make_pair(Iter(), Iter()); } template < typename V, typename D, typename P, typename B > typename vertex_list_graph_archetype< V, D, P, B >::vertices_size_type num_vertices(const vertex_list_graph_archetype< V, D, P, B >&) { return 0; } // ambiguously inherited from incidence graph and adjacency graph template < typename V, typename D, typename P, typename B > typename vertex_list_graph_archetype< V, D, P, B >::degree_size_type out_degree( const V&, const vertex_list_graph_archetype< V, D, P, B >&) { return 0; } //=========================================================================== struct property_graph_archetype_tag { }; template < typename GraphArchetype, typename Property, typename ValueArch > struct property_graph_archetype : public GraphArchetype { typedef property_graph_archetype_tag graph_tag; typedef ValueArch vertex_property_type; typedef ValueArch edge_property_type; }; struct choose_edge_property_map_archetype { template < typename Graph, typename Property, typename Tag > struct bind_ { typedef mutable_lvalue_property_map_archetype< typename Graph::edge_descriptor, Property > type; typedef lvalue_property_map_archetype< typename Graph::edge_descriptor, Property > const_type; }; }; template <> struct edge_property_selector< property_graph_archetype_tag > { typedef choose_edge_property_map_archetype type; }; struct choose_vertex_property_map_archetype { template < typename Graph, typename Property, typename Tag > struct bind_ { typedef mutable_lvalue_property_map_archetype< typename Graph::vertex_descriptor, Property > type; typedef lvalue_property_map_archetype< typename Graph::vertex_descriptor, Property > const_type; }; }; template <> struct vertex_property_selector< property_graph_archetype_tag > { typedef choose_vertex_property_map_archetype type; }; template < typename G, typename P, typename V > typename property_map< property_graph_archetype< G, P, V >, P >::type get( P, property_graph_archetype< G, P, V >&) { typename property_map< property_graph_archetype< G, P, V >, P >::type pmap; return pmap; } template < typename G, typename P, typename V > typename property_map< property_graph_archetype< G, P, V >, P >::const_type get( P, const property_graph_archetype< G, P, V >&) { typename property_map< property_graph_archetype< G, P, V >, P >::const_type pmap; return pmap; } template < typename G, typename P, typename K, typename V > typename property_traits< typename property_map< property_graph_archetype< G, P, V >, P >::const_type >::value_type get(P p, const property_graph_archetype< G, P, V >& g, K k) { return get(get(p, g), k); } template < typename G, typename P, typename V, typename Key > void put( P p, property_graph_archetype< G, P, V >& g, const Key& key, const V& value) { typedef typename boost::property_map< property_graph_archetype< G, P, V >, P >::type Map; Map pmap = get(p, g); put(pmap, key, value); } struct color_value_archetype { color_value_archetype() {} color_value_archetype(detail::dummy_constructor) {} bool operator==(const color_value_archetype&) const { return true; } bool operator!=(const color_value_archetype&) const { return true; } }; template <> struct color_traits< color_value_archetype > { static color_value_archetype white() { return color_value_archetype( static_object< detail::dummy_constructor >::get()); } static color_value_archetype gray() { return color_value_archetype( static_object< detail::dummy_constructor >::get()); } static color_value_archetype black() { return color_value_archetype( static_object< detail::dummy_constructor >::get()); } }; template < typename T > class buffer_archetype { public: void push(const T&) {} void pop() {} T& top() { return static_object< T >::get(); } const T& top() const { return static_object< T >::get(); } bool empty() const { return true; } }; } // namespace boost #endif // BOOST_GRAPH_ARCHETYPES_HPP make_biconnected_planar.hpp 0000644 00000006671 15125521275 0012103 0 ustar 00 //======================================================================= // Copyright 2007 Aaron Windsor // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef __MAKE_BICONNECTED_PLANAR_HPP__ #define __MAKE_BICONNECTED_PLANAR_HPP__ #include <boost/config.hpp> #include <boost/tuple/tuple.hpp> //for tie #include <boost/graph/biconnected_components.hpp> #include <boost/property_map/property_map.hpp> #include <vector> #include <iterator> #include <algorithm> #include <boost/graph/planar_detail/add_edge_visitors.hpp> namespace boost { template < typename Graph, typename PlanarEmbedding, typename EdgeIndexMap, typename AddEdgeVisitor > void make_biconnected_planar( Graph& g, PlanarEmbedding embedding, EdgeIndexMap em, AddEdgeVisitor& vis) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::edge_descriptor edge_t; typedef typename graph_traits< Graph >::edges_size_type edge_size_t; typedef typename property_traits< PlanarEmbedding >::value_type embedding_value_t; typedef typename embedding_value_t::const_iterator embedding_iterator_t; typedef iterator_property_map< std::vector< std::size_t >::iterator, EdgeIndexMap > component_map_t; edge_size_t n_edges(num_edges(g)); std::vector< vertex_t > articulation_points; std::vector< edge_size_t > component_vector(n_edges); component_map_t component_map(component_vector.begin(), em); biconnected_components( g, component_map, std::back_inserter(articulation_points)); typename std::vector< vertex_t >::iterator ap, ap_end; ap_end = articulation_points.end(); for (ap = articulation_points.begin(); ap != ap_end; ++ap) { vertex_t v(*ap); embedding_iterator_t pi = embedding[v].begin(); embedding_iterator_t pi_end = embedding[v].end(); edge_size_t previous_component(n_edges + 1); vertex_t previous_vertex = graph_traits< Graph >::null_vertex(); for (; pi != pi_end; ++pi) { edge_t e(*pi); vertex_t e_source(source(e, g)); vertex_t e_target(target(e, g)); // Skip self-loops and parallel edges if (e_source == e_target || previous_vertex == e_target) continue; vertex_t current_vertex = e_source == v ? e_target : e_source; edge_size_t current_component = component_map[e]; if (previous_vertex != graph_traits< Graph >::null_vertex() && current_component != previous_component) { vis.visit_vertex_pair(current_vertex, previous_vertex, g); } previous_vertex = current_vertex; previous_component = current_component; } } } template < typename Graph, typename PlanarEmbedding, typename EdgeIndexMap > inline void make_biconnected_planar( Graph& g, PlanarEmbedding embedding, EdgeIndexMap em) { default_add_edge_visitor vis; make_biconnected_planar(g, embedding, em, vis); } template < typename Graph, typename PlanarEmbedding > inline void make_biconnected_planar(Graph& g, PlanarEmbedding embedding) { make_biconnected_planar(g, embedding, get(edge_index, g)); } } // namespace boost #endif //__MAKE_BICONNECTED_PLANAR_HPP__ visitors.hpp 0000644 00000026066 15125521275 0007156 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // // Revision History: // 01 April 2001: Modified to use new <boost/limits.hpp> header. (JMaddock) // #ifndef BOOST_GRAPH_GRAPH_SEARCH_VISITORS_HPP #define BOOST_GRAPH_GRAPH_SEARCH_VISITORS_HPP #include <iosfwd> #include <boost/config.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/mpl/bool.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/limits.hpp> namespace boost { // This is a bit more convenient than std::numeric_limits because // you don't have to explicitly provide type T. template < class T > inline T numeric_limits_max(T) { return (std::numeric_limits< T >::max)(); } //======================================================================== // Event Tags namespace detail { // For partial specialization workaround enum event_visitor_enum { on_no_event_num, on_initialize_vertex_num, on_start_vertex_num, on_discover_vertex_num, on_finish_vertex_num, on_examine_vertex_num, on_examine_edge_num, on_tree_edge_num, on_non_tree_edge_num, on_gray_target_num, on_black_target_num, on_forward_or_cross_edge_num, on_back_edge_num, on_finish_edge_num, on_edge_relaxed_num, on_edge_not_relaxed_num, on_edge_minimized_num, on_edge_not_minimized_num }; template < typename Event, typename Visitor > struct functor_to_visitor : Visitor { typedef Event event_filter; functor_to_visitor(const Visitor& visitor) : Visitor(visitor) {} }; } // namespace detail struct on_no_event { enum { num = detail::on_no_event_num }; }; struct on_initialize_vertex { enum { num = detail::on_initialize_vertex_num }; }; struct on_start_vertex { enum { num = detail::on_start_vertex_num }; }; struct on_discover_vertex { enum { num = detail::on_discover_vertex_num }; }; struct on_examine_vertex { enum { num = detail::on_examine_vertex_num }; }; struct on_finish_vertex { enum { num = detail::on_finish_vertex_num }; }; struct on_examine_edge { enum { num = detail::on_examine_edge_num }; }; struct on_tree_edge { enum { num = detail::on_tree_edge_num }; }; struct on_non_tree_edge { enum { num = detail::on_non_tree_edge_num }; }; struct on_gray_target { enum { num = detail::on_gray_target_num }; }; struct on_black_target { enum { num = detail::on_black_target_num }; }; struct on_forward_or_cross_edge { enum { num = detail::on_forward_or_cross_edge_num }; }; struct on_back_edge { enum { num = detail::on_back_edge_num }; }; struct on_finish_edge { enum { num = detail::on_finish_edge_num }; }; struct on_edge_relaxed { enum { num = detail::on_edge_relaxed_num }; }; struct on_edge_not_relaxed { enum { num = detail::on_edge_not_relaxed_num }; }; struct on_edge_minimized { enum { num = detail::on_edge_minimized_num }; }; struct on_edge_not_minimized { enum { num = detail::on_edge_not_minimized_num }; }; //======================================================================== // base_visitor and null_visitor // needed for MSVC workaround template < class Visitor > struct base_visitor { typedef on_no_event event_filter; template < class T, class Graph > void operator()(T, Graph&) {} }; struct null_visitor : public base_visitor< null_visitor > { typedef on_no_event event_filter; template < class T, class Graph > void operator()(T, Graph&) {} }; //======================================================================== // The invoke_visitors() function namespace detail { template < class Visitor, class T, class Graph > inline void invoke_dispatch(Visitor& v, T x, Graph& g, mpl::true_) { v(x, g); } template < class Visitor, class T, class Graph > inline void invoke_dispatch(Visitor&, T, Graph&, mpl::false_) { } } // namespace detail template < class Visitor, class Rest, class T, class Graph, class Tag > inline void invoke_visitors( std::pair< Visitor, Rest >& vlist, T x, Graph& g, Tag tag) { typedef typename Visitor::event_filter Category; typedef typename is_same< Category, Tag >::type IsSameTag; detail::invoke_dispatch(vlist.first, x, g, IsSameTag()); invoke_visitors(vlist.second, x, g, tag); } template < class Visitor, class T, class Graph, class Tag > inline void invoke_visitors(Visitor& v, T x, Graph& g, Tag) { typedef typename Visitor::event_filter Category; typedef typename is_same< Category, Tag >::type IsSameTag; detail::invoke_dispatch(v, x, g, IsSameTag()); } //======================================================================== // predecessor_recorder template < class PredecessorMap, class Tag > struct predecessor_recorder : public base_visitor< predecessor_recorder< PredecessorMap, Tag > > { typedef Tag event_filter; predecessor_recorder(PredecessorMap pa) : m_predecessor(pa) {} template < class Edge, class Graph > void operator()(Edge e, const Graph& g) { put(m_predecessor, target(e, g), source(e, g)); } PredecessorMap m_predecessor; }; template < class PredecessorMap, class Tag > predecessor_recorder< PredecessorMap, Tag > record_predecessors( PredecessorMap pa, Tag) { return predecessor_recorder< PredecessorMap, Tag >(pa); } //======================================================================== // edge_predecessor_recorder template < class PredEdgeMap, class Tag > struct edge_predecessor_recorder : public base_visitor< edge_predecessor_recorder< PredEdgeMap, Tag > > { typedef Tag event_filter; edge_predecessor_recorder(PredEdgeMap pa) : m_predecessor(pa) {} template < class Edge, class Graph > void operator()(Edge e, const Graph& g) { put(m_predecessor, target(e, g), e); } PredEdgeMap m_predecessor; }; template < class PredEdgeMap, class Tag > edge_predecessor_recorder< PredEdgeMap, Tag > record_edge_predecessors( PredEdgeMap pa, Tag) { return edge_predecessor_recorder< PredEdgeMap, Tag >(pa); } //======================================================================== // distance_recorder template < class DistanceMap, class Tag > struct distance_recorder : public base_visitor< distance_recorder< DistanceMap, Tag > > { typedef Tag event_filter; distance_recorder(DistanceMap pa) : m_distance(pa) {} template < class Edge, class Graph > void operator()(Edge e, const Graph& g) { typename graph_traits< Graph >::vertex_descriptor u = source(e, g), v = target(e, g); put(m_distance, v, get(m_distance, u) + 1); } DistanceMap m_distance; }; template < class DistanceMap, class Tag > distance_recorder< DistanceMap, Tag > record_distances(DistanceMap pa, Tag) { return distance_recorder< DistanceMap, Tag >(pa); } //======================================================================== // time_stamper template < class TimeMap, class TimeT, class Tag > struct time_stamper : public base_visitor< time_stamper< TimeMap, TimeT, Tag > > { typedef Tag event_filter; time_stamper(TimeMap pa, TimeT& t) : m_time_pa(pa), m_time(t) {} template < class Vertex, class Graph > void operator()(Vertex u, const Graph&) { put(m_time_pa, u, ++m_time); } TimeMap m_time_pa; TimeT& m_time; }; template < class TimeMap, class TimeT, class Tag > time_stamper< TimeMap, TimeT, Tag > stamp_times( TimeMap pa, TimeT& time_counter, Tag) { return time_stamper< TimeMap, TimeT, Tag >(pa, time_counter); } //======================================================================== // property_writer template < class PA, class OutputIterator, class Tag > struct property_writer : public base_visitor< property_writer< PA, OutputIterator, Tag > > { typedef Tag event_filter; property_writer(PA pa, OutputIterator out) : m_pa(pa), m_out(out) {} template < class T, class Graph > void operator()(T x, Graph&) { *m_out++ = get(m_pa, x); } PA m_pa; OutputIterator m_out; }; template < class PA, class OutputIterator, class Tag > property_writer< PA, OutputIterator, Tag > write_property( PA pa, OutputIterator out, Tag) { return property_writer< PA, OutputIterator, Tag >(pa, out); } //======================================================================== // property_put /** * Functor which just sets a given value to a vertex or edge in a property map. */ template < typename PropertyMap, typename EventTag > struct property_put { typedef EventTag event_filter; property_put(PropertyMap property_map, typename property_traits< PropertyMap >::value_type value) : property_map_(property_map), value_(value) { } template < typename VertexOrEdge, typename Graph > void operator()(VertexOrEdge v, const Graph&) { put(property_map_, v, value_); } private: PropertyMap property_map_; typename property_traits< PropertyMap >::value_type value_; }; /** * Creates a property_put functor which just sets a given value to a vertex or * edge. * * @param property_map Given writeable property map * @param value Fixed value of the map * @param tag Event Filter * @return The functor. */ template < typename PropertyMap, typename EventTag > inline property_put< PropertyMap, EventTag > put_property( PropertyMap property_map, typename property_traits< PropertyMap >::value_type value, EventTag) { return property_put< PropertyMap, EventTag >(property_map, value); } #define BOOST_GRAPH_EVENT_STUB(Event, Kind) \ typedef ::boost::Event Event##_type; \ template < typename Visitor > \ Kind##_visitor< std::pair< \ detail::functor_to_visitor< Event##_type, Visitor >, Visitors > > \ do_##Event(Visitor visitor) \ { \ typedef std::pair< \ detail::functor_to_visitor< Event##_type, Visitor >, Visitors > \ visitor_list; \ typedef Kind##_visitor< visitor_list > result_type; \ return result_type(visitor_list(visitor, m_vis)); \ } } /* namespace boost */ #endif filtered_graph.hpp 0000644 00000047202 15125521275 0010246 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_FILTERED_GRAPH_HPP #define BOOST_FILTERED_GRAPH_HPP #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/adjacency_iterator.hpp> #include <boost/graph/detail/set_adaptor.hpp> #include <boost/iterator/filter_iterator.hpp> namespace boost { //========================================================================= // Some predicate classes. struct keep_all { template < typename T > bool operator()(const T&) const { return true; } }; // Keep residual edges (used in maximum-flow algorithms). template < typename ResidualCapacityEdgeMap > struct is_residual_edge { is_residual_edge() {} is_residual_edge(ResidualCapacityEdgeMap rcap) : m_rcap(rcap) {} template < typename Edge > bool operator()(const Edge& e) const { return 0 < get(m_rcap, e); } ResidualCapacityEdgeMap m_rcap; }; template < typename Set > struct is_in_subset { is_in_subset() : m_s(0) {} is_in_subset(const Set& s) : m_s(&s) {} template < typename Elt > bool operator()(const Elt& x) const { return set_contains(*m_s, x); } const Set* m_s; }; template < typename Set > struct is_not_in_subset { is_not_in_subset() : m_s(0) {} is_not_in_subset(const Set& s) : m_s(&s) {} template < typename Elt > bool operator()(const Elt& x) const { return !set_contains(*m_s, x); } const Set* m_s; }; namespace detail { template < typename EdgePredicate, typename VertexPredicate, typename Graph > struct out_edge_predicate { out_edge_predicate() {} out_edge_predicate(EdgePredicate ep, VertexPredicate vp, const Graph& g) : m_edge_pred(ep), m_vertex_pred(vp), m_g(&g) { } template < typename Edge > bool operator()(const Edge& e) const { return m_edge_pred(e) && m_vertex_pred(target(e, *m_g)); } EdgePredicate m_edge_pred; VertexPredicate m_vertex_pred; const Graph* m_g; }; template < typename EdgePredicate, typename VertexPredicate, typename Graph > struct in_edge_predicate { in_edge_predicate() {} in_edge_predicate(EdgePredicate ep, VertexPredicate vp, const Graph& g) : m_edge_pred(ep), m_vertex_pred(vp), m_g(&g) { } template < typename Edge > bool operator()(const Edge& e) const { return m_edge_pred(e) && m_vertex_pred(source(e, *m_g)); } EdgePredicate m_edge_pred; VertexPredicate m_vertex_pred; const Graph* m_g; }; template < typename EdgePredicate, typename VertexPredicate, typename Graph > struct edge_predicate { edge_predicate() {} edge_predicate(EdgePredicate ep, VertexPredicate vp, const Graph& g) : m_edge_pred(ep), m_vertex_pred(vp), m_g(&g) { } template < typename Edge > bool operator()(const Edge& e) const { return m_edge_pred(e) && m_vertex_pred(source(e, *m_g)) && m_vertex_pred(target(e, *m_g)); } EdgePredicate m_edge_pred; VertexPredicate m_vertex_pred; const Graph* m_g; }; } // namespace detail //=========================================================================== // Filtered Graph struct filtered_graph_tag { }; // This base class is a stupid hack to change overload resolution // rules for the source and target functions so that they are a // worse match than the source and target functions defined for // pairs in graph_traits.hpp. I feel dirty. -JGS template < class G > struct filtered_graph_base { typedef graph_traits< G > Traits; typedef typename Traits::vertex_descriptor vertex_descriptor; typedef typename Traits::edge_descriptor edge_descriptor; filtered_graph_base(const G& g) : m_g(g) {} // protected: const G& m_g; }; template < typename Graph, typename EdgePredicate, typename VertexPredicate = keep_all > class filtered_graph : public filtered_graph_base< Graph > { typedef filtered_graph_base< Graph > Base; typedef graph_traits< Graph > Traits; typedef filtered_graph self; public: typedef Graph graph_type; typedef detail::out_edge_predicate< EdgePredicate, VertexPredicate, self > OutEdgePred; typedef detail::in_edge_predicate< EdgePredicate, VertexPredicate, self > InEdgePred; typedef detail::edge_predicate< EdgePredicate, VertexPredicate, self > EdgePred; // Constructors filtered_graph(const Graph& g, EdgePredicate ep) : Base(g), m_edge_pred(ep) { } filtered_graph(const Graph& g, EdgePredicate ep, VertexPredicate vp) : Base(g), m_edge_pred(ep), m_vertex_pred(vp) { } // Graph requirements typedef typename Traits::vertex_descriptor vertex_descriptor; typedef typename Traits::edge_descriptor edge_descriptor; typedef typename Traits::directed_category directed_category; typedef typename Traits::edge_parallel_category edge_parallel_category; typedef typename Traits::traversal_category traversal_category; // IncidenceGraph requirements typedef filter_iterator< OutEdgePred, typename Traits::out_edge_iterator > out_edge_iterator; typedef typename Traits::degree_size_type degree_size_type; // AdjacencyGraph requirements typedef typename adjacency_iterator_generator< self, vertex_descriptor, out_edge_iterator >::type adjacency_iterator; // BidirectionalGraph requirements typedef filter_iterator< InEdgePred, typename Traits::in_edge_iterator > in_edge_iterator; // VertexListGraph requirements typedef filter_iterator< VertexPredicate, typename Traits::vertex_iterator > vertex_iterator; typedef typename Traits::vertices_size_type vertices_size_type; // EdgeListGraph requirements typedef filter_iterator< EdgePred, typename Traits::edge_iterator > edge_iterator; typedef typename Traits::edges_size_type edges_size_type; typedef filtered_graph_tag graph_tag; // Bundled properties support template < typename Descriptor > typename graph::detail::bundled_result< Graph, Descriptor >::type& operator[](Descriptor x) { return const_cast< Graph& >(this->m_g)[x]; } template < typename Descriptor > typename graph::detail::bundled_result< Graph, Descriptor >::type const& operator[](Descriptor x) const { return this->m_g[x]; } static vertex_descriptor null_vertex() { return Traits::null_vertex(); } // private: EdgePredicate m_edge_pred; VertexPredicate m_vertex_pred; }; // Do not instantiate these unless needed template < typename Graph, typename EdgePredicate, typename VertexPredicate > struct vertex_property_type< filtered_graph< Graph, EdgePredicate, VertexPredicate > > : vertex_property_type< Graph > { }; template < typename Graph, typename EdgePredicate, typename VertexPredicate > struct edge_property_type< filtered_graph< Graph, EdgePredicate, VertexPredicate > > : edge_property_type< Graph > { }; template < typename Graph, typename EdgePredicate, typename VertexPredicate > struct graph_property_type< filtered_graph< Graph, EdgePredicate, VertexPredicate > > : graph_property_type< Graph > { }; template < typename Graph, typename EdgePredicate, typename VertexPredicate > struct vertex_bundle_type< filtered_graph< Graph, EdgePredicate, VertexPredicate > > : vertex_bundle_type< Graph > { }; template < typename Graph, typename EdgePredicate, typename VertexPredicate > struct edge_bundle_type< filtered_graph< Graph, EdgePredicate, VertexPredicate > > : edge_bundle_type< Graph > { }; template < typename Graph, typename EdgePredicate, typename VertexPredicate > struct graph_bundle_type< filtered_graph< Graph, EdgePredicate, VertexPredicate > > : graph_bundle_type< Graph > { }; //=========================================================================== // Non-member functions for the Filtered Edge Graph // Helper functions template < typename Graph, typename EdgePredicate > inline filtered_graph< Graph, EdgePredicate > make_filtered_graph( Graph& g, EdgePredicate ep) { return filtered_graph< Graph, EdgePredicate >(g, ep); } template < typename Graph, typename EdgePredicate, typename VertexPredicate > inline filtered_graph< Graph, EdgePredicate, VertexPredicate > make_filtered_graph(Graph& g, EdgePredicate ep, VertexPredicate vp) { return filtered_graph< Graph, EdgePredicate, VertexPredicate >(g, ep, vp); } template < typename Graph, typename EdgePredicate > inline filtered_graph< const Graph, EdgePredicate > make_filtered_graph( const Graph& g, EdgePredicate ep) { return filtered_graph< const Graph, EdgePredicate >(g, ep); } template < typename Graph, typename EdgePredicate, typename VertexPredicate > inline filtered_graph< const Graph, EdgePredicate, VertexPredicate > make_filtered_graph(const Graph& g, EdgePredicate ep, VertexPredicate vp) { return filtered_graph< const Graph, EdgePredicate, VertexPredicate >( g, ep, vp); } template < typename G, typename EP, typename VP > std::pair< typename filtered_graph< G, EP, VP >::vertex_iterator, typename filtered_graph< G, EP, VP >::vertex_iterator > vertices(const filtered_graph< G, EP, VP >& g) { typedef filtered_graph< G, EP, VP > Graph; typename graph_traits< G >::vertex_iterator f, l; boost::tie(f, l) = vertices(g.m_g); typedef typename Graph::vertex_iterator iter; return std::make_pair( iter(g.m_vertex_pred, f, l), iter(g.m_vertex_pred, l, l)); } template < typename G, typename EP, typename VP > std::pair< typename filtered_graph< G, EP, VP >::edge_iterator, typename filtered_graph< G, EP, VP >::edge_iterator > edges(const filtered_graph< G, EP, VP >& g) { typedef filtered_graph< G, EP, VP > Graph; typename Graph::EdgePred pred(g.m_edge_pred, g.m_vertex_pred, g); typename graph_traits< G >::edge_iterator f, l; boost::tie(f, l) = edges(g.m_g); typedef typename Graph::edge_iterator iter; return std::make_pair(iter(pred, f, l), iter(pred, l, l)); } // An alternative for num_vertices() and num_edges() would be to // count the number in the filtered graph. This is problematic // because of the interaction with the vertex indices... they would // no longer go from 0 to num_vertices(), which would cause trouble // for algorithms allocating property storage in an array. We could // try to create a mapping to new recalibrated indices, but I don't // see an efficient way to do this. // // However, the current solution is still unsatisfactory because // the following semantic constraints no longer hold: // boost::tie(vi, viend) = vertices(g); // assert(std::distance(vi, viend) == num_vertices(g)); template < typename G, typename EP, typename VP > typename filtered_graph< G, EP, VP >::vertices_size_type num_vertices( const filtered_graph< G, EP, VP >& g) { return num_vertices(g.m_g); } template < typename G, typename EP, typename VP > typename filtered_graph< G, EP, VP >::edges_size_type num_edges( const filtered_graph< G, EP, VP >& g) { return num_edges(g.m_g); } template < typename G > typename filtered_graph_base< G >::vertex_descriptor source( typename filtered_graph_base< G >::edge_descriptor e, const filtered_graph_base< G >& g) { return source(e, g.m_g); } template < typename G > typename filtered_graph_base< G >::vertex_descriptor target( typename filtered_graph_base< G >::edge_descriptor e, const filtered_graph_base< G >& g) { return target(e, g.m_g); } template < typename G, typename EP, typename VP > std::pair< typename filtered_graph< G, EP, VP >::out_edge_iterator, typename filtered_graph< G, EP, VP >::out_edge_iterator > out_edges(typename filtered_graph< G, EP, VP >::vertex_descriptor u, const filtered_graph< G, EP, VP >& g) { typedef filtered_graph< G, EP, VP > Graph; typename Graph::OutEdgePred pred(g.m_edge_pred, g.m_vertex_pred, g); typedef typename Graph::out_edge_iterator iter; typename graph_traits< G >::out_edge_iterator f, l; boost::tie(f, l) = out_edges(u, g.m_g); return std::make_pair(iter(pred, f, l), iter(pred, l, l)); } template < typename G, typename EP, typename VP > typename filtered_graph< G, EP, VP >::degree_size_type out_degree( typename filtered_graph< G, EP, VP >::vertex_descriptor u, const filtered_graph< G, EP, VP >& g) { typename filtered_graph< G, EP, VP >::degree_size_type n = 0; typename filtered_graph< G, EP, VP >::out_edge_iterator f, l; for (boost::tie(f, l) = out_edges(u, g); f != l; ++f) ++n; return n; } template < typename G, typename EP, typename VP > std::pair< typename filtered_graph< G, EP, VP >::adjacency_iterator, typename filtered_graph< G, EP, VP >::adjacency_iterator > adjacent_vertices(typename filtered_graph< G, EP, VP >::vertex_descriptor u, const filtered_graph< G, EP, VP >& g) { typedef filtered_graph< G, EP, VP > Graph; typedef typename Graph::adjacency_iterator adjacency_iterator; typename Graph::out_edge_iterator f, l; boost::tie(f, l) = out_edges(u, g); return std::make_pair(adjacency_iterator(f, const_cast< Graph* >(&g)), adjacency_iterator(l, const_cast< Graph* >(&g))); } template < typename G, typename EP, typename VP > std::pair< typename filtered_graph< G, EP, VP >::in_edge_iterator, typename filtered_graph< G, EP, VP >::in_edge_iterator > in_edges(typename filtered_graph< G, EP, VP >::vertex_descriptor u, const filtered_graph< G, EP, VP >& g) { typedef filtered_graph< G, EP, VP > Graph; typename Graph::InEdgePred pred(g.m_edge_pred, g.m_vertex_pred, g); typedef typename Graph::in_edge_iterator iter; typename graph_traits< G >::in_edge_iterator f, l; boost::tie(f, l) = in_edges(u, g.m_g); return std::make_pair(iter(pred, f, l), iter(pred, l, l)); } template < typename G, typename EP, typename VP > typename filtered_graph< G, EP, VP >::degree_size_type in_degree( typename filtered_graph< G, EP, VP >::vertex_descriptor u, const filtered_graph< G, EP, VP >& g) { typename filtered_graph< G, EP, VP >::degree_size_type n = 0; typename filtered_graph< G, EP, VP >::in_edge_iterator f, l; for (boost::tie(f, l) = in_edges(u, g); f != l; ++f) ++n; return n; } template < typename G, typename EP, typename VP > typename enable_if< typename is_directed_graph< G >::type, typename filtered_graph< G, EP, VP >::degree_size_type >::type degree(typename filtered_graph< G, EP, VP >::vertex_descriptor u, const filtered_graph< G, EP, VP >& g) { return out_degree(u, g) + in_degree(u, g); } template < typename G, typename EP, typename VP > typename disable_if< typename is_directed_graph< G >::type, typename filtered_graph< G, EP, VP >::degree_size_type >::type degree(typename filtered_graph< G, EP, VP >::vertex_descriptor u, const filtered_graph< G, EP, VP >& g) { return out_degree(u, g); } template < typename G, typename EP, typename VP > std::pair< typename filtered_graph< G, EP, VP >::edge_descriptor, bool > edge( typename filtered_graph< G, EP, VP >::vertex_descriptor u, typename filtered_graph< G, EP, VP >::vertex_descriptor v, const filtered_graph< G, EP, VP >& g) { typename graph_traits< G >::edge_descriptor e; bool exists; boost::tie(e, exists) = edge(u, v, g.m_g); return std::make_pair(e, exists && g.m_edge_pred(e)); } template < typename G, typename EP, typename VP > std::pair< typename filtered_graph< G, EP, VP >::out_edge_iterator, typename filtered_graph< G, EP, VP >::out_edge_iterator > edge_range(typename filtered_graph< G, EP, VP >::vertex_descriptor u, typename filtered_graph< G, EP, VP >::vertex_descriptor v, const filtered_graph< G, EP, VP >& g) { typedef filtered_graph< G, EP, VP > Graph; typename Graph::OutEdgePred pred(g.m_edge_pred, g.m_vertex_pred, g); typedef typename Graph::out_edge_iterator iter; typename graph_traits< G >::out_edge_iterator f, l; boost::tie(f, l) = edge_range(u, v, g.m_g); return std::make_pair(iter(pred, f, l), iter(pred, l, l)); } //=========================================================================== // Property map template < typename G, typename EP, typename VP, typename Property > struct property_map< filtered_graph< G, EP, VP >, Property > : property_map< G, Property > { }; template < typename G, typename EP, typename VP, typename Property > typename property_map< G, Property >::type get( Property p, filtered_graph< G, EP, VP >& g) { return get(p, const_cast< G& >(g.m_g)); } template < typename G, typename EP, typename VP, typename Property > typename property_map< G, Property >::const_type get( Property p, const filtered_graph< G, EP, VP >& g) { return get(p, (const G&)g.m_g); } template < typename G, typename EP, typename VP, typename Property, typename Key > typename property_map_value< G, Property >::type get( Property p, const filtered_graph< G, EP, VP >& g, const Key& k) { return get(p, (const G&)g.m_g, k); } template < typename G, typename EP, typename VP, typename Property, typename Key, typename Value > void put(Property p, const filtered_graph< G, EP, VP >& g, const Key& k, const Value& val) { put(p, const_cast< G& >(g.m_g), k, val); } //=========================================================================== // Some filtered subgraph specializations template < typename Graph, typename Set > struct vertex_subset_filter { typedef filtered_graph< Graph, keep_all, is_in_subset< Set > > type; }; template < typename Graph, typename Set > inline typename vertex_subset_filter< Graph, Set >::type make_vertex_subset_filter(Graph& g, const Set& s) { typedef typename vertex_subset_filter< Graph, Set >::type Filter; is_in_subset< Set > p(s); return Filter(g, keep_all(), p); } // This is misspelled, but present for backwards compatibility; new code // should use the version below that has the correct spelling. template < typename Graph, typename Set > struct vertex_subset_compliment_filter { typedef filtered_graph< Graph, keep_all, is_not_in_subset< Set > > type; }; template < typename Graph, typename Set > inline typename vertex_subset_compliment_filter< Graph, Set >::type make_vertex_subset_compliment_filter(Graph& g, const Set& s) { typedef typename vertex_subset_compliment_filter< Graph, Set >::type Filter; is_not_in_subset< Set > p(s); return Filter(g, keep_all(), p); } template < typename Graph, typename Set > struct vertex_subset_complement_filter { typedef filtered_graph< Graph, keep_all, is_not_in_subset< Set > > type; }; template < typename Graph, typename Set > inline typename vertex_subset_complement_filter< Graph, Set >::type make_vertex_subset_complement_filter(Graph& g, const Set& s) { typedef typename vertex_subset_complement_filter< Graph, Set >::type Filter; is_not_in_subset< Set > p(s); return Filter(g, keep_all(), p); } // Filter that uses a property map whose value_type is a boolean template < typename PropertyMap > struct property_map_filter { property_map_filter() {} property_map_filter(const PropertyMap& property_map) : m_property_map(property_map) { } template < typename Key > bool operator()(const Key& key) const { return (get(m_property_map, key)); } private: PropertyMap m_property_map; }; } // namespace boost #endif // BOOST_FILTERED_GRAPH_HPP transpose_graph.hpp 0000644 00000002256 15125521275 0010466 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_TRANSPOSE_HPP #define BOOST_GRAPH_TRANSPOSE_HPP #include <boost/config.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/reverse_graph.hpp> #include <boost/graph/copy.hpp> namespace boost { template < class VertexListGraph, class MutableGraph > void transpose_graph(const VertexListGraph& G, MutableGraph& G_T) { reverse_graph< VertexListGraph > R(G); copy_graph(R, G_T); } template < class VertexListGraph, class MutableGraph, class P, class T, class R > void transpose_graph(const VertexListGraph& G, MutableGraph& G_T, const bgl_named_params< P, T, R >& params) { reverse_graph< VertexListGraph > Rev(G); copy_graph(Rev, G_T, params); } } // namespace boost #endif // BOOST_GRAPH_TRANSPOSE_HPP compressed_sparse_row_graph.hpp 0000644 00000210377 15125521275 0013065 0 ustar 00 // Copyright 2005-2009 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Jeremiah Willcock // Douglas Gregor // Andrew Lumsdaine // Compressed sparse row graph type #ifndef BOOST_GRAPH_COMPRESSED_SPARSE_ROW_GRAPH_HPP #define BOOST_GRAPH_COMPRESSED_SPARSE_ROW_GRAPH_HPP #include <vector> #include <utility> #include <algorithm> #include <climits> #include <boost/assert.hpp> #include <iterator> #if 0 #include <iostream> // For some debugging code below #endif #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/filtered_graph.hpp> // For keep_all #include <boost/graph/detail/indexed_properties.hpp> #include <boost/graph/detail/compressed_sparse_row_struct.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/iterator/counting_iterator.hpp> #include <boost/iterator/reverse_iterator.hpp> #include <boost/iterator/zip_iterator.hpp> #include <boost/iterator/transform_iterator.hpp> #include <boost/tuple/tuple.hpp> #include <boost/property_map/property_map.hpp> #include <boost/integer.hpp> #include <boost/iterator/iterator_facade.hpp> #include <boost/mpl/if.hpp> #include <boost/utility/enable_if.hpp> #include <boost/graph/graph_selectors.hpp> #include <boost/graph/detail/is_distributed_selector.hpp> #include <boost/graph/properties.hpp> #include <boost/static_assert.hpp> #include <boost/functional/hash.hpp> #include <boost/next_prior.hpp> #include <boost/property_map/transform_value_property_map.hpp> #include <boost/mpl/print.hpp> namespace boost { // A tag type indicating that the graph in question is a compressed // sparse row graph. This is an internal detail of the BGL. struct csr_graph_tag; // A type (edges_are_sorted_t) and a value (edges_are_sorted) used to indicate // that the edge list passed into the CSR graph is already sorted by source // vertex. enum edges_are_sorted_t { edges_are_sorted }; // A type (edges_are_sorted_global_t) and a value (edges_are_sorted_global) // used to indicate that the edge list passed into the CSR graph is already // sorted by source vertex. enum edges_are_sorted_global_t { edges_are_sorted_global }; // A type (edges_are_unsorted_t) and a value (edges_are_unsorted) used to // indicate that the edge list passed into the CSR graph is not sorted by // source vertex. This version caches the edge information in memory, and thus // requires only a single pass over the input data. enum edges_are_unsorted_t { edges_are_unsorted }; // A type (edges_are_unsorted_multi_pass_t) and a value // (edges_are_unsorted_multi_pass) used to indicate that the edge list passed // into the CSR graph is not sorted by source vertex. This version uses less // memory but requires multi-pass capability on the iterators. enum edges_are_unsorted_multi_pass_t { edges_are_unsorted_multi_pass }; // A type (edges_are_unsorted_multi_pass_global_t) and a value // (edges_are_unsorted_multi_pass_global) used to indicate that the edge list // passed into the CSR graph is not sorted by source vertex. This version uses // less memory but requires multi-pass capability on the iterators. The // global mapping and filtering is done here because it is often faster and it // greatly simplifies handling of edge properties. enum edges_are_unsorted_multi_pass_global_t { edges_are_unsorted_multi_pass_global }; // A type (construct_inplace_from_sources_and_targets_t) and a value // (construct_inplace_from_sources_and_targets) used to indicate that mutable // vectors of sources and targets (and possibly edge properties) are being used // to construct the CSR graph. These vectors are sorted in-place and then the // targets and properties are swapped into the graph data structure. enum construct_inplace_from_sources_and_targets_t { construct_inplace_from_sources_and_targets }; // A type (construct_inplace_from_sources_and_targets_global_t) and a value // (construct_inplace_from_sources_and_targets_global) used to indicate that // mutable vectors of sources and targets (and possibly edge properties) are // being used to construct the CSR graph. These vectors are sorted in-place // and then the targets and properties are swapped into the graph data // structure. It is assumed that global indices (for distributed CSR) are // used, and a map is required to convert those to local indices. This // constructor is intended for internal use by the various CSR graphs // (sequential and distributed). enum construct_inplace_from_sources_and_targets_global_t { construct_inplace_from_sources_and_targets_global }; // A type (edges_are_unsorted_global_t) and a value (edges_are_unsorted_global) // used to indicate that the edge list passed into the CSR graph is not sorted // by source vertex. The data is also stored using global vertex indices, and // must be filtered to choose only local vertices. This constructor caches the // edge information in memory, and thus requires only a single pass over the // input data. This constructor is intended for internal use by the // distributed CSR constructors. enum edges_are_unsorted_global_t { edges_are_unsorted_global }; /**************************************************************************** * Local helper macros to reduce typing and clutter later on. * ****************************************************************************/ #define BOOST_CSR_GRAPH_TEMPLATE_PARMS \ typename Directed, typename VertexProperty, typename EdgeProperty, \ typename GraphProperty, typename Vertex, typename EdgeIndex #define BOOST_CSR_GRAPH_TYPE \ compressed_sparse_row_graph< Directed, VertexProperty, EdgeProperty, \ GraphProperty, Vertex, EdgeIndex > #define BOOST_DIR_CSR_GRAPH_TEMPLATE_PARMS \ typename VertexProperty, typename EdgeProperty, typename GraphProperty, \ typename Vertex, typename EdgeIndex #define BOOST_DIR_CSR_GRAPH_TYPE \ compressed_sparse_row_graph< directedS, VertexProperty, EdgeProperty, \ GraphProperty, Vertex, EdgeIndex > #define BOOST_BIDIR_CSR_GRAPH_TEMPLATE_PARMS \ typename VertexProperty, typename EdgeProperty, typename GraphProperty, \ typename Vertex, typename EdgeIndex #define BOOST_BIDIR_CSR_GRAPH_TYPE \ compressed_sparse_row_graph< bidirectionalS, VertexProperty, EdgeProperty, \ GraphProperty, Vertex, EdgeIndex > namespace detail { template < typename T > struct default_construct_iterator : public boost::iterator_facade< default_construct_iterator< T >, T, boost::random_access_traversal_tag, const T& > { typedef boost::iterator_facade< default_construct_iterator< T >, T, std::random_access_iterator_tag, const T& > base_type; T saved_value; const T& dereference() const { return saved_value; } bool equal(default_construct_iterator /*i*/) const { return true; } void increment() {} void decrement() {} void advance(typename base_type::difference_type) {} typename base_type::difference_type distance_to( default_construct_iterator) const { return 0; } }; template < typename Less > struct compare_first { Less less; compare_first(Less less = Less()) : less(less) {} template < typename Tuple > bool operator()(const Tuple& a, const Tuple& b) const { return less(a.template get< 0 >(), b.template get< 0 >()); } }; template < int N, typename Result > struct my_tuple_get_class { typedef const Result& result_type; template < typename Tuple > result_type operator()(const Tuple& t) const { return t.template get< N >(); } }; } /** Compressed sparse row graph. * * Vertex and EdgeIndex should be unsigned integral types and should * specialize numeric_limits. */ template < typename Directed = directedS, typename VertexProperty = no_property, typename EdgeProperty = no_property, typename GraphProperty = no_property, typename Vertex = std::size_t, typename EdgeIndex = Vertex > class compressed_sparse_row_graph; // Not defined template < typename VertexProperty, typename EdgeProperty, typename GraphProperty, typename Vertex, typename EdgeIndex > class compressed_sparse_row_graph< directedS, VertexProperty, EdgeProperty, GraphProperty, Vertex, EdgeIndex > : public detail::indexed_vertex_properties< BOOST_DIR_CSR_GRAPH_TYPE, VertexProperty, Vertex, typed_identity_property_map< Vertex > > { public: typedef detail::indexed_vertex_properties< compressed_sparse_row_graph, VertexProperty, Vertex, typed_identity_property_map< Vertex > > inherited_vertex_properties; // Some tests to prevent use of "void" is a property type (as was done in // some test cases): BOOST_STATIC_ASSERT((!is_same< VertexProperty, void >::value)); BOOST_STATIC_ASSERT((!is_same< EdgeProperty, void >::value)); BOOST_STATIC_ASSERT((!is_same< GraphProperty, void >::value)); public: // For Property Graph typedef GraphProperty graph_property_type; typedef typename lookup_one_property< GraphProperty, graph_bundle_t >::type graph_bundled; typedef detail::compressed_sparse_row_structure< EdgeProperty, Vertex, EdgeIndex > forward_type; public: /* At this time, the compressed sparse row graph can only be used to * create directed and bidirectional graphs. In the future, * undirected CSR graphs will also be supported. */ // BOOST_STATIC_ASSERT((is_same<Directed, directedS>::value)); // Concept requirements: // For Graph typedef Vertex vertex_descriptor; typedef detail::csr_edge_descriptor< Vertex, EdgeIndex > edge_descriptor; typedef directed_tag directed_category; typedef allow_parallel_edge_tag edge_parallel_category; class traversal_category : public incidence_graph_tag, public adjacency_graph_tag, public vertex_list_graph_tag, public edge_list_graph_tag { }; static vertex_descriptor null_vertex() { return vertex_descriptor(-1); } // For VertexListGraph typedef counting_iterator< Vertex > vertex_iterator; typedef Vertex vertices_size_type; // For EdgeListGraph typedef EdgeIndex edges_size_type; // For IncidenceGraph typedef detail::csr_out_edge_iterator< compressed_sparse_row_graph > out_edge_iterator; typedef EdgeIndex degree_size_type; // For AdjacencyGraph typedef typename std::vector< Vertex >::const_iterator adjacency_iterator; // For EdgeListGraph typedef detail::csr_edge_iterator< compressed_sparse_row_graph > edge_iterator; // For BidirectionalGraph (not implemented) typedef void in_edge_iterator; // For internal use typedef csr_graph_tag graph_tag; typedef typename forward_type::inherited_edge_properties::edge_bundled edge_bundled; typedef typename forward_type::inherited_edge_properties::edge_push_back_type edge_push_back_type; typedef typename forward_type::inherited_edge_properties::edge_property_type edge_property_type; // Constructors // Default constructor: an empty graph. compressed_sparse_row_graph() : m_property() {} // With numverts vertices compressed_sparse_row_graph(vertices_size_type numverts) : inherited_vertex_properties(numverts), m_forward(numverts) { } // From number of vertices and unsorted list of edges template < typename MultiPassInputIterator > compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, vertices_size_type numverts, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numverts), m_property(prop) { m_forward.assign_unsorted_multi_pass_edges(edge_begin, edge_end, numverts, typed_identity_property_map< vertices_size_type >(), keep_all()); } // From number of vertices and unsorted list of edges, plus edge properties template < typename MultiPassInputIterator, typename EdgePropertyIterator > compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numverts), m_forward(), m_property(prop) { m_forward.assign_unsorted_multi_pass_edges(edge_begin, edge_end, ep_iter, numverts, typed_identity_property_map< vertices_size_type >(), keep_all()); } // From number of vertices and unsorted list of edges, with filter and // global-to-local map template < typename MultiPassInputIterator, typename GlobalToLocal, typename SourcePred > compressed_sparse_row_graph(edges_are_unsorted_multi_pass_global_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, vertices_size_type numlocalverts, const GlobalToLocal& global_to_local, const SourcePred& source_pred, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numlocalverts), m_forward(), m_property(prop) { m_forward.assign_unsorted_multi_pass_edges( edge_begin, edge_end, numlocalverts, global_to_local, source_pred); } // From number of vertices and unsorted list of edges, plus edge // properties, with filter and global-to-local map template < typename MultiPassInputIterator, typename EdgePropertyIterator, typename GlobalToLocal, typename SourcePred > compressed_sparse_row_graph(edges_are_unsorted_multi_pass_global_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numlocalverts, const GlobalToLocal& global_to_local, const SourcePred& source_pred, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numlocalverts), m_forward(), m_property(prop) { m_forward.assign_unsorted_multi_pass_edges(edge_begin, edge_end, ep_iter, numlocalverts, global_to_local, source_pred); } // From number of vertices and sorted list of edges (new interface) template < typename InputIterator > compressed_sparse_row_graph(edges_are_sorted_t, InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, edges_size_type numedges = 0, const GraphProperty& prop = GraphProperty()) : m_property(prop) { m_forward.assign_from_sorted_edges(edge_begin, edge_end, typed_identity_property_map< vertices_size_type >(), keep_all(), numverts, numedges); inherited_vertex_properties::resize(numverts); } // From number of vertices and sorted list of edges (new interface) template < typename InputIterator, typename EdgePropertyIterator > compressed_sparse_row_graph(edges_are_sorted_t, InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, edges_size_type numedges = 0, const GraphProperty& prop = GraphProperty()) : m_property(prop) { m_forward.assign_from_sorted_edges(edge_begin, edge_end, ep_iter, typed_identity_property_map< vertices_size_type >(), keep_all(), numverts, numedges); inherited_vertex_properties::resize(numverts); } // From number of vertices and sorted list of edges, filtered and global // (new interface) template < typename InputIterator, typename GlobalToLocal, typename SourcePred > compressed_sparse_row_graph(edges_are_sorted_global_t, InputIterator edge_begin, InputIterator edge_end, const GlobalToLocal& global_to_local, const SourcePred& source_pred, vertices_size_type numverts, const GraphProperty& prop = GraphProperty()) : m_property(prop) { m_forward.assign_from_sorted_edges( edge_begin, edge_end, global_to_local, source_pred, numverts, 0); inherited_vertex_properties::resize(numverts); } // From number of vertices and sorted list of edges (new interface) template < typename InputIterator, typename EdgePropertyIterator, typename GlobalToLocal, typename SourcePred > compressed_sparse_row_graph(edges_are_sorted_global_t, InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, const GlobalToLocal& global_to_local, const SourcePred& source_pred, vertices_size_type numverts, const GraphProperty& prop = GraphProperty()) : m_property(prop) { m_forward.assign_from_sorted_edges(edge_begin, edge_end, ep_iter, global_to_local, source_pred, numverts, 0); inherited_vertex_properties::resize(numverts); } // From number of vertices and mutable vectors of sources and targets; // vectors are returned with unspecified contents but are guaranteed not to // share storage with the constructed graph. compressed_sparse_row_graph(construct_inplace_from_sources_and_targets_t, std::vector< vertex_descriptor >& sources, std::vector< vertex_descriptor >& targets, vertices_size_type numverts, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numverts), m_property(prop) { m_forward.assign_sources_and_targets_global(sources, targets, numverts, boost::typed_identity_property_map< vertices_size_type >()); } // From number of vertices and mutable vectors of sources and targets, // expressed with global vertex indices; vectors are returned with // unspecified contents but are guaranteed not to share storage with the // constructed graph. This constructor should only be used by the // distributed CSR graph. template < typename GlobalToLocal > compressed_sparse_row_graph( construct_inplace_from_sources_and_targets_global_t, std::vector< vertex_descriptor >& sources, std::vector< vertex_descriptor >& targets, vertices_size_type numlocalverts, GlobalToLocal global_to_local, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numlocalverts), m_property(prop) { m_forward.assign_sources_and_targets_global( sources, targets, numlocalverts, global_to_local); } // From number of vertices and mutable vectors of sources, targets, and // edge properties; vectors are returned with unspecified contents but are // guaranteed not to share storage with the constructed graph. compressed_sparse_row_graph(construct_inplace_from_sources_and_targets_t, std::vector< vertex_descriptor >& sources, std::vector< vertex_descriptor >& targets, std::vector< typename forward_type::inherited_edge_properties::edge_bundled >& edge_props, vertices_size_type numverts, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numverts), m_property(prop) { m_forward.assign_sources_and_targets_global(sources, targets, edge_props, numverts, boost::typed_identity_property_map< vertices_size_type >()); } // From number of vertices and mutable vectors of sources and targets and // edge properties, expressed with global vertex indices; vectors are // returned with unspecified contents but are guaranteed not to share // storage with the constructed graph. This constructor should only be // used by the distributed CSR graph. template < typename GlobalToLocal > compressed_sparse_row_graph( construct_inplace_from_sources_and_targets_global_t, std::vector< vertex_descriptor >& sources, std::vector< vertex_descriptor >& targets, std::vector< typename forward_type::inherited_edge_properties::edge_bundled >& edge_props, vertices_size_type numlocalverts, GlobalToLocal global_to_local, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numlocalverts), m_property(prop) { m_forward.assign_sources_and_targets_global( sources, targets, edge_props, numlocalverts, global_to_local); } // From number of vertices and single-pass range of unsorted edges. Data // is cached in coordinate form before creating the actual graph. template < typename InputIterator > compressed_sparse_row_graph(edges_are_unsorted_t, InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numverts), m_property(prop) { std::vector< vertex_descriptor > sources, targets; boost::graph::detail::split_into_separate_coords( edge_begin, edge_end, sources, targets); m_forward.assign_sources_and_targets_global(sources, targets, numverts, boost::typed_identity_property_map< vertices_size_type >()); } // From number of vertices and single-pass range of unsorted edges and // single-pass range of edge properties. Data is cached in coordinate form // before creating the actual graph. template < typename InputIterator, typename EdgePropertyIterator > compressed_sparse_row_graph(edges_are_unsorted_t, InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numverts), m_property(prop) { std::vector< vertex_descriptor > sources, targets; boost::graph::detail::split_into_separate_coords( edge_begin, edge_end, sources, targets); size_t numedges = sources.size(); std::vector< typename forward_type::inherited_edge_properties::edge_bundled > edge_props(numedges); for (size_t i = 0; i < numedges; ++i) { edge_props[i] = *ep_iter++; } m_forward.assign_sources_and_targets_global(sources, targets, edge_props, numverts, boost::typed_identity_property_map< vertices_size_type >()); } // From number of vertices and single-pass range of unsorted edges. Data // is cached in coordinate form before creating the actual graph. Edges // are filtered and transformed for use in a distributed graph. template < typename InputIterator, typename GlobalToLocal, typename SourcePred > compressed_sparse_row_graph(edges_are_unsorted_global_t, InputIterator edge_begin, InputIterator edge_end, vertices_size_type numlocalverts, GlobalToLocal global_to_local, const SourcePred& source_pred, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numlocalverts), m_property(prop) { std::vector< vertex_descriptor > sources, targets; boost::graph::detail::split_into_separate_coords_filtered( edge_begin, edge_end, sources, targets, source_pred); m_forward.assign_sources_and_targets_global( sources, targets, numlocalverts, global_to_local); } // From number of vertices and single-pass range of unsorted edges and // single-pass range of edge properties. Data is cached in coordinate form // before creating the actual graph. Edges are filtered and transformed // for use in a distributed graph. template < typename InputIterator, typename EdgePropertyIterator, typename GlobalToLocal, typename SourcePred > compressed_sparse_row_graph(edges_are_unsorted_global_t, InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numlocalverts, GlobalToLocal global_to_local, const SourcePred& source_pred, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numlocalverts), m_property(prop) { std::vector< vertex_descriptor > sources, targets; std::vector< edge_bundled > edge_props; boost::graph::detail::split_into_separate_coords_filtered(edge_begin, edge_end, ep_iter, sources, targets, edge_props, source_pred); m_forward.assign_sources_and_targets_global( sources, targets, edge_props, numlocalverts, global_to_local); } // Requires IncidenceGraph and a vertex index map template < typename Graph, typename VertexIndexMap > compressed_sparse_row_graph(const Graph& g, const VertexIndexMap& vi, vertices_size_type numverts, edges_size_type numedges) : m_property() { assign(g, vi, numverts, numedges); inherited_vertex_properties::resize(numverts); } // Requires VertexListGraph and EdgeListGraph template < typename Graph, typename VertexIndexMap > compressed_sparse_row_graph(const Graph& g, const VertexIndexMap& vi) : m_property() { typename graph_traits< Graph >::edges_size_type numedges = num_edges(g); if (is_same< typename graph_traits< Graph >::directed_category, undirectedS >::value) { numedges *= 2; // Double each edge (actual doubling done by // out_edges function) } vertices_size_type numverts = num_vertices(g); assign(g, vi, numverts, numedges); inherited_vertex_properties::resize(numverts); } // Requires vertex index map plus requirements of previous constructor template < typename Graph > explicit compressed_sparse_row_graph(const Graph& g) : m_property() { typename graph_traits< Graph >::edges_size_type numedges = num_edges(g); if (is_same< typename graph_traits< Graph >::directed_category, undirectedS >::value) { numedges *= 2; // Double each edge (actual doubling done by // out_edges function) } assign(g, get(vertex_index, g), num_vertices(g), numedges); } // From any graph (slow and uses a lot of memory) // Requires IncidenceGraph and a vertex index map // Internal helper function // Note that numedges must be doubled for undirected source graphs template < typename Graph, typename VertexIndexMap > void assign(const Graph& g, const VertexIndexMap& vi, vertices_size_type numverts, edges_size_type numedges) { m_forward.assign(g, vi, numverts, numedges); inherited_vertex_properties::resize(numverts); } // Requires the above, plus VertexListGraph and EdgeListGraph template < typename Graph, typename VertexIndexMap > void assign(const Graph& g, const VertexIndexMap& vi) { typename graph_traits< Graph >::edges_size_type numedges = num_edges(g); if (is_same< typename graph_traits< Graph >::directed_category, undirectedS >::value) { numedges *= 2; // Double each edge (actual doubling done by // out_edges function) } vertices_size_type numverts = num_vertices(g); m_forward.assign(g, vi, numverts, numedges); inherited_vertex_properties::resize(numverts); } // Requires the above, plus a vertex_index map. template < typename Graph > void assign(const Graph& g) { typename graph_traits< Graph >::edges_size_type numedges = num_edges(g); if (is_same< typename graph_traits< Graph >::directed_category, undirectedS >::value) { numedges *= 2; // Double each edge (actual doubling done by // out_edges function) } vertices_size_type numverts = num_vertices(g); m_forward.assign(g, get(vertex_index, g), numverts, numedges); inherited_vertex_properties::resize(numverts); } // Add edges from a sorted (smallest sources first) range of pairs and edge // properties template < typename BidirectionalIteratorOrig, typename EPIterOrig, typename GlobalToLocal > void add_edges_sorted_internal(BidirectionalIteratorOrig first_sorted, BidirectionalIteratorOrig last_sorted, EPIterOrig ep_iter_sorted, const GlobalToLocal& global_to_local) { m_forward.add_edges_sorted_internal( first_sorted, last_sorted, ep_iter_sorted, global_to_local); } template < typename BidirectionalIteratorOrig, typename EPIterOrig > void add_edges_sorted_internal(BidirectionalIteratorOrig first_sorted, BidirectionalIteratorOrig last_sorted, EPIterOrig ep_iter_sorted) { m_forward.add_edges_sorted_internal(first_sorted, last_sorted, ep_iter_sorted, typed_identity_property_map< vertices_size_type >()); } // Add edges from a sorted (smallest sources first) range of pairs template < typename BidirectionalIteratorOrig > void add_edges_sorted_internal(BidirectionalIteratorOrig first_sorted, BidirectionalIteratorOrig last_sorted) { m_forward.add_edges_sorted_internal(first_sorted, last_sorted, detail::default_construct_iterator< edge_bundled >()); } template < typename BidirectionalIteratorOrig, typename GlobalToLocal > void add_edges_sorted_internal_global( BidirectionalIteratorOrig first_sorted, BidirectionalIteratorOrig last_sorted, const GlobalToLocal& global_to_local) { m_forward.add_edges_sorted_internal(first_sorted, last_sorted, detail::default_construct_iterator< edge_bundled >(), global_to_local); } template < typename BidirectionalIteratorOrig, typename EPIterOrig, typename GlobalToLocal > void add_edges_sorted_internal_global( BidirectionalIteratorOrig first_sorted, BidirectionalIteratorOrig last_sorted, EPIterOrig ep_iter_sorted, const GlobalToLocal& global_to_local) { m_forward.add_edges_sorted_internal( first_sorted, last_sorted, ep_iter_sorted, global_to_local); } // Add edges from a range of (source, target) pairs that are unsorted template < typename InputIterator, typename GlobalToLocal > inline void add_edges_internal(InputIterator first, InputIterator last, const GlobalToLocal& global_to_local) { typedef compressed_sparse_row_graph Graph; typedef typename boost::graph_traits< Graph >::vertex_descriptor vertex_t; typedef std::vector< std::pair< vertex_t, vertex_t > > edge_vector_t; edge_vector_t new_edges(first, last); if (new_edges.empty()) return; std::sort(new_edges.begin(), new_edges.end()); this->add_edges_sorted_internal_global( new_edges.begin(), new_edges.end(), global_to_local); } template < typename InputIterator > inline void add_edges_internal(InputIterator first, InputIterator last) { this->add_edges_internal( first, last, typed_identity_property_map< vertices_size_type >()); } // Add edges from a range of (source, target) pairs and edge properties that // are unsorted template < typename InputIterator, typename EPIterator, typename GlobalToLocal > inline void add_edges_internal(InputIterator first, InputIterator last, EPIterator ep_iter, EPIterator ep_iter_end, const GlobalToLocal& global_to_local) { typedef compressed_sparse_row_graph Graph; typedef typename boost::graph_traits< Graph >::vertex_descriptor vertex_t; typedef std::pair< vertex_t, vertex_t > vertex_pair; typedef std::vector< boost::tuple< vertex_pair, edge_bundled > > edge_vector_t; edge_vector_t new_edges( boost::make_zip_iterator(boost::make_tuple(first, ep_iter)), boost::make_zip_iterator(boost::make_tuple(last, ep_iter_end))); if (new_edges.empty()) return; std::sort(new_edges.begin(), new_edges.end(), boost::detail::compare_first< std::less< vertex_pair > >()); m_forward.add_edges_sorted_internal( boost::make_transform_iterator(new_edges.begin(), boost::detail::my_tuple_get_class< 0, vertex_pair >()), boost::make_transform_iterator(new_edges.end(), boost::detail::my_tuple_get_class< 0, vertex_pair >()), boost::make_transform_iterator(new_edges.begin(), boost::detail::my_tuple_get_class< 1, edge_bundled >()), global_to_local); } // Add edges from a range of (source, target) pairs and edge properties that // are unsorted template < typename InputIterator, typename EPIterator > inline void add_edges_internal(InputIterator first, InputIterator last, EPIterator ep_iter, EPIterator ep_iter_end) { this->add_edges_internal(first, last, ep_iter, ep_iter_end, typed_identity_property_map< vertices_size_type >()); } using inherited_vertex_properties::operator[]; // Directly access a edge or edge bundle edge_push_back_type& operator[](const edge_descriptor& v) { return m_forward.m_edge_properties[get(edge_index, *this, v)]; } const edge_push_back_type& operator[](const edge_descriptor& v) const { return m_forward.m_edge_properties[get(edge_index, *this, v)]; } // Directly access a graph bundle graph_bundled& operator[](graph_bundle_t) { return get_property(*this); } const graph_bundled& operator[](graph_bundle_t) const { return get_property(*this); } // private: non-portable, requires friend templates inherited_vertex_properties& vertex_properties() { return *this; } const inherited_vertex_properties& vertex_properties() const { return *this; } typename forward_type::inherited_edge_properties& edge_properties() { return m_forward; } const typename forward_type::inherited_edge_properties& edge_properties() const { return m_forward; } forward_type m_forward; GraphProperty m_property; }; template < typename VertexProperty, typename EdgeProperty, typename GraphProperty, typename Vertex, typename EdgeIndex > class compressed_sparse_row_graph< bidirectionalS, VertexProperty, EdgeProperty, GraphProperty, Vertex, EdgeIndex > : public detail::indexed_vertex_properties< BOOST_BIDIR_CSR_GRAPH_TYPE, VertexProperty, Vertex, typed_identity_property_map< Vertex > > { public: typedef detail::indexed_vertex_properties< compressed_sparse_row_graph, VertexProperty, Vertex, typed_identity_property_map< Vertex > > inherited_vertex_properties; public: // For Property Graph typedef GraphProperty graph_property_type; typedef typename lookup_one_property< GraphProperty, graph_bundle_t >::type graph_bundled; // typedef GraphProperty graph_property_type; typedef detail::compressed_sparse_row_structure< EdgeProperty, Vertex, EdgeIndex > forward_type; typedef EdgeIndex /* typename boost::mpl::if_c<boost::is_same<EdgeProperty, boost::no_property>, boost::no_property, EdgeIndex> */ backward_edge_property; typedef detail::compressed_sparse_row_structure< backward_edge_property, Vertex, EdgeIndex > backward_type; public: // Concept requirements: // For Graph typedef Vertex vertex_descriptor; typedef detail::csr_edge_descriptor< Vertex, EdgeIndex > edge_descriptor; typedef bidirectional_tag directed_category; typedef allow_parallel_edge_tag edge_parallel_category; class traversal_category : public bidirectional_graph_tag, public adjacency_graph_tag, public vertex_list_graph_tag, public edge_list_graph_tag { }; static vertex_descriptor null_vertex() { return vertex_descriptor(-1); } // For VertexListGraph typedef counting_iterator< Vertex > vertex_iterator; typedef Vertex vertices_size_type; // For EdgeListGraph typedef EdgeIndex edges_size_type; // For IncidenceGraph typedef detail::csr_out_edge_iterator< compressed_sparse_row_graph > out_edge_iterator; typedef EdgeIndex degree_size_type; // For AdjacencyGraph typedef typename std::vector< Vertex >::const_iterator adjacency_iterator; // For EdgeListGraph typedef detail::csr_edge_iterator< compressed_sparse_row_graph > edge_iterator; // For BidirectionalGraph (not implemented) typedef detail::csr_in_edge_iterator< compressed_sparse_row_graph > in_edge_iterator; // For internal use typedef csr_graph_tag graph_tag; typedef typename forward_type::inherited_edge_properties::edge_bundled edge_bundled; typedef typename forward_type::inherited_edge_properties::edge_push_back_type edge_push_back_type; typedef typename forward_type::inherited_edge_properties::edge_property_type edge_property_type; // Constructors // Default constructor: an empty graph. compressed_sparse_row_graph() : m_property() {} // With numverts vertices compressed_sparse_row_graph(vertices_size_type numverts) : inherited_vertex_properties(numverts) , m_forward(numverts) , m_backward(numverts) { } private: void set_up_backward_property_links() { std::pair< edge_iterator, edge_iterator > e = edges(*this); m_backward.assign_unsorted_multi_pass_edges( detail::transpose_edges(detail::make_edge_to_index_pair_iter( *this, get(vertex_index, *this), e.first)), detail::transpose_edges(detail::make_edge_to_index_pair_iter( *this, get(vertex_index, *this), e.second)), boost::counting_iterator< EdgeIndex >(0), m_forward.m_rowstart.size() - 1, typed_identity_property_map< Vertex >(), keep_all()); } public: // From number of vertices and unsorted list of edges template < typename MultiPassInputIterator > compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, vertices_size_type numverts, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numverts), m_property(prop) { m_forward.assign_unsorted_multi_pass_edges(edge_begin, edge_end, numverts, typed_identity_property_map< Vertex >(), keep_all()); set_up_backward_property_links(); } // From number of vertices and unsorted list of edges, plus edge properties template < typename MultiPassInputIterator, typename EdgePropertyIterator > compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numverts), m_forward(), m_property(prop) { m_forward.assign_unsorted_multi_pass_edges(edge_begin, edge_end, ep_iter, numverts, typed_identity_property_map< Vertex >(), keep_all()); set_up_backward_property_links(); } // From number of vertices and unsorted list of edges, with filter and // global-to-local map template < typename MultiPassInputIterator, typename GlobalToLocal, typename SourcePred > compressed_sparse_row_graph(edges_are_unsorted_multi_pass_global_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, vertices_size_type numlocalverts, const GlobalToLocal& global_to_local, const SourcePred& source_pred, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numlocalverts), m_forward(), m_property(prop) { m_forward.assign_unsorted_multi_pass_edges( edge_begin, edge_end, numlocalverts, global_to_local, source_pred); set_up_backward_property_links(); } // From number of vertices and unsorted list of edges, plus edge // properties, with filter and global-to-local map template < typename MultiPassInputIterator, typename EdgePropertyIterator, typename GlobalToLocal, typename SourcePred > compressed_sparse_row_graph(edges_are_unsorted_multi_pass_global_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numlocalverts, const GlobalToLocal& global_to_local, const SourcePred& source_pred, const GraphProperty& prop = GraphProperty()) : inherited_vertex_properties(numlocalverts), m_forward(), m_property(prop) { m_forward.assign_unsorted_multi_pass_edges(edge_begin, edge_end, ep_iter, numlocalverts, global_to_local, source_pred); set_up_backward_property_links(); } // Requires IncidenceGraph and a vertex index map template < typename Graph, typename VertexIndexMap > compressed_sparse_row_graph(const Graph& g, const VertexIndexMap& vi, vertices_size_type numverts, edges_size_type numedges) : m_property() { assign(g, vi, numverts, numedges); inherited_vertex_properties::resize(numverts); } // Requires VertexListGraph and EdgeListGraph template < typename Graph, typename VertexIndexMap > compressed_sparse_row_graph(const Graph& g, const VertexIndexMap& vi) : m_property() { typename graph_traits< Graph >::edges_size_type numedges = num_edges(g); if (is_same< typename graph_traits< Graph >::directed_category, undirectedS >::value) { numedges *= 2; // Double each edge (actual doubling done by // out_edges function) } vertices_size_type numverts = num_vertices(g); assign(g, vi, numverts, numedges); inherited_vertex_properties::resize(numverts); } // Requires vertex index map plus requirements of previous constructor template < typename Graph > explicit compressed_sparse_row_graph(const Graph& g) : m_property() { typename graph_traits< Graph >::edges_size_type numedges = num_edges(g); if (is_same< typename graph_traits< Graph >::directed_category, undirectedS >::value) { numedges *= 2; // Double each edge (actual doubling done by // out_edges function) } assign(g, get(vertex_index, g), num_vertices(g), numedges); } // From any graph (slow and uses a lot of memory) // Requires IncidenceGraph and a vertex index map // Internal helper function // Note that numedges must be doubled for undirected source graphs template < typename Graph, typename VertexIndexMap > void assign(const Graph& g, const VertexIndexMap& vi, vertices_size_type numverts, edges_size_type numedges) { m_forward.assign(g, vi, numverts, numedges); inherited_vertex_properties::resize(numverts); set_up_backward_property_links(); } // Requires the above, plus VertexListGraph and EdgeListGraph template < typename Graph, typename VertexIndexMap > void assign(const Graph& g, const VertexIndexMap& vi) { typename graph_traits< Graph >::edges_size_type numedges = num_edges(g); if (is_same< typename graph_traits< Graph >::directed_category, undirectedS >::value) { numedges *= 2; // Double each edge (actual doubling done by // out_edges function) } vertices_size_type numverts = num_vertices(g); m_forward.assign(g, vi, numverts, numedges); inherited_vertex_properties::resize(numverts); set_up_backward_property_links(); } // Requires the above, plus a vertex_index map. template < typename Graph > void assign(const Graph& g) { typename graph_traits< Graph >::edges_size_type numedges = num_edges(g); if (is_same< typename graph_traits< Graph >::directed_category, undirectedS >::value) { numedges *= 2; // Double each edge (actual doubling done by // out_edges function) } vertices_size_type numverts = num_vertices(g); m_forward.assign(g, get(vertex_index, g), numverts, numedges); inherited_vertex_properties::resize(numverts); set_up_backward_property_links(); } using inherited_vertex_properties::operator[]; // Directly access a edge or edge bundle edge_push_back_type& operator[](const edge_descriptor& v) { return m_forward.m_edge_properties[get(edge_index, *this, v)]; } const edge_push_back_type& operator[](const edge_descriptor& v) const { return m_forward.m_edge_properties[get(edge_index, *this, v)]; } // private: non-portable, requires friend templates inherited_vertex_properties& vertex_properties() { return *this; } const inherited_vertex_properties& vertex_properties() const { return *this; } typename forward_type::inherited_edge_properties& edge_properties() { return m_forward; } const typename forward_type::inherited_edge_properties& edge_properties() const { return m_forward; } forward_type m_forward; backward_type m_backward; GraphProperty m_property; }; // Construction functions template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline Vertex add_vertex(BOOST_CSR_GRAPH_TYPE& g) { add_vertex(g, typename BOOST_CSR_GRAPH_TYPE::vertex_bundled()); } template < BOOST_DIR_CSR_GRAPH_TEMPLATE_PARMS > inline Vertex add_vertex(BOOST_DIR_CSR_GRAPH_TYPE& g, typename BOOST_DIR_CSR_GRAPH_TYPE::vertex_bundled const& p) { Vertex old_num_verts_plus_one = g.m_forward.m_rowstart.size(); g.m_forward.m_rowstart.push_back(g.m_forward.m_rowstart.back()); g.vertex_properties().push_back(p); return old_num_verts_plus_one - 1; } template < BOOST_BIDIR_CSR_GRAPH_TEMPLATE_PARMS > inline Vertex add_vertex(BOOST_BIDIR_CSR_GRAPH_TYPE& g, typename BOOST_BIDIR_CSR_GRAPH_TYPE::vertex_bundled const& p) { Vertex old_num_verts_plus_one = g.m_forward.m_rowstart.size(); g.m_forward.m_rowstart.push_back(g.m_forward.m_rowstart.back()); g.m_backward.m_rowstart.push_back(g.m_backward.m_rowstart.back()); g.vertex_properties().push_back(p); return old_num_verts_plus_one - 1; } template < BOOST_DIR_CSR_GRAPH_TEMPLATE_PARMS > inline Vertex add_vertices( typename BOOST_DIR_CSR_GRAPH_TYPE::vertices_size_type count, BOOST_DIR_CSR_GRAPH_TYPE& g) { Vertex old_num_verts_plus_one = g.m_forward.m_rowstart.size(); EdgeIndex numedges = g.m_forward.m_rowstart.back(); g.m_forward.m_rowstart.resize(old_num_verts_plus_one + count, numedges); g.vertex_properties().resize(num_vertices(g)); return old_num_verts_plus_one - 1; } // Add edges from a sorted (smallest sources first) range of pairs and edge // properties template < BOOST_DIR_CSR_GRAPH_TEMPLATE_PARMS, typename BidirectionalIteratorOrig, typename EPIterOrig > void add_edges_sorted(BidirectionalIteratorOrig first_sorted, BidirectionalIteratorOrig last_sorted, EPIterOrig ep_iter_sorted, BOOST_DIR_CSR_GRAPH_TYPE& g) { g.add_edges_sorted_internal(first_sorted, last_sorted, ep_iter_sorted); } // Add edges from a sorted (smallest sources first) range of pairs template < BOOST_DIR_CSR_GRAPH_TEMPLATE_PARMS, typename BidirectionalIteratorOrig > void add_edges_sorted(BidirectionalIteratorOrig first_sorted, BidirectionalIteratorOrig last_sorted, BOOST_DIR_CSR_GRAPH_TYPE& g) { g.add_edges_sorted_internal(first_sorted, last_sorted); } template < BOOST_DIR_CSR_GRAPH_TEMPLATE_PARMS, typename BidirectionalIteratorOrig, typename EPIterOrig, typename GlobalToLocal > void add_edges_sorted_global(BidirectionalIteratorOrig first_sorted, BidirectionalIteratorOrig last_sorted, EPIterOrig ep_iter_sorted, const GlobalToLocal& global_to_local, BOOST_DIR_CSR_GRAPH_TYPE& g) { g.add_edges_sorted_internal_global( first_sorted, last_sorted, ep_iter_sorted, global_to_local); } // Add edges from a sorted (smallest sources first) range of pairs template < BOOST_DIR_CSR_GRAPH_TEMPLATE_PARMS, typename BidirectionalIteratorOrig, typename GlobalToLocal > void add_edges_sorted_global(BidirectionalIteratorOrig first_sorted, BidirectionalIteratorOrig last_sorted, const GlobalToLocal& global_to_local, BOOST_DIR_CSR_GRAPH_TYPE& g) { g.add_edges_sorted_internal_global( first_sorted, last_sorted, global_to_local); } // Add edges from a range of (source, target) pairs that are unsorted template < BOOST_DIR_CSR_GRAPH_TEMPLATE_PARMS, typename InputIterator, typename GlobalToLocal > inline void add_edges_global(InputIterator first, InputIterator last, const GlobalToLocal& global_to_local, BOOST_DIR_CSR_GRAPH_TYPE& g) { g.add_edges_internal(first, last, global_to_local); } // Add edges from a range of (source, target) pairs that are unsorted template < BOOST_DIR_CSR_GRAPH_TEMPLATE_PARMS, typename InputIterator > inline void add_edges( InputIterator first, InputIterator last, BOOST_DIR_CSR_GRAPH_TYPE& g) { g.add_edges_internal(first, last); } // Add edges from a range of (source, target) pairs and edge properties that // are unsorted template < BOOST_DIR_CSR_GRAPH_TEMPLATE_PARMS, typename InputIterator, typename EPIterator > inline void add_edges(InputIterator first, InputIterator last, EPIterator ep_iter, EPIterator ep_iter_end, BOOST_DIR_CSR_GRAPH_TYPE& g) { g.add_edges_internal(first, last, ep_iter, ep_iter_end); } template < BOOST_DIR_CSR_GRAPH_TEMPLATE_PARMS, typename InputIterator, typename EPIterator, typename GlobalToLocal > inline void add_edges_global(InputIterator first, InputIterator last, EPIterator ep_iter, EPIterator ep_iter_end, const GlobalToLocal& global_to_local, BOOST_DIR_CSR_GRAPH_TYPE& g) { g.add_edges_internal(first, last, ep_iter, ep_iter_end, global_to_local); } // From VertexListGraph template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline Vertex num_vertices(const BOOST_CSR_GRAPH_TYPE& g) { return g.m_forward.m_rowstart.size() - 1; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > std::pair< counting_iterator< Vertex >, counting_iterator< Vertex > > inline vertices(const BOOST_CSR_GRAPH_TYPE& g) { return std::make_pair(counting_iterator< Vertex >(0), counting_iterator< Vertex >(num_vertices(g))); } // From IncidenceGraph template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline Vertex source(typename BOOST_CSR_GRAPH_TYPE::edge_descriptor e, const BOOST_CSR_GRAPH_TYPE&) { return e.src; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline Vertex target(typename BOOST_CSR_GRAPH_TYPE::edge_descriptor e, const BOOST_CSR_GRAPH_TYPE& g) { return g.m_forward.m_column[e.idx]; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline std::pair< typename BOOST_CSR_GRAPH_TYPE::out_edge_iterator, typename BOOST_CSR_GRAPH_TYPE::out_edge_iterator > out_edges(Vertex v, const BOOST_CSR_GRAPH_TYPE& g) { typedef typename BOOST_CSR_GRAPH_TYPE::edge_descriptor ed; typedef typename BOOST_CSR_GRAPH_TYPE::out_edge_iterator it; EdgeIndex v_row_start = g.m_forward.m_rowstart[v]; EdgeIndex next_row_start = g.m_forward.m_rowstart[v + 1]; return std::make_pair(it(ed(v, v_row_start)), it(ed(v, next_row_start))); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline EdgeIndex out_degree(Vertex v, const BOOST_CSR_GRAPH_TYPE& g) { EdgeIndex v_row_start = g.m_forward.m_rowstart[v]; EdgeIndex next_row_start = g.m_forward.m_rowstart[v + 1]; return next_row_start - v_row_start; } template < BOOST_BIDIR_CSR_GRAPH_TEMPLATE_PARMS > inline std::pair< typename BOOST_BIDIR_CSR_GRAPH_TYPE::in_edge_iterator, typename BOOST_BIDIR_CSR_GRAPH_TYPE::in_edge_iterator > in_edges(Vertex v, const BOOST_BIDIR_CSR_GRAPH_TYPE& g) { typedef typename BOOST_BIDIR_CSR_GRAPH_TYPE::in_edge_iterator it; EdgeIndex v_row_start = g.m_backward.m_rowstart[v]; EdgeIndex next_row_start = g.m_backward.m_rowstart[v + 1]; return std::make_pair(it(g, v_row_start), it(g, next_row_start)); } template < BOOST_BIDIR_CSR_GRAPH_TEMPLATE_PARMS > inline EdgeIndex in_degree(Vertex v, const BOOST_BIDIR_CSR_GRAPH_TYPE& g) { EdgeIndex v_row_start = g.m_backward.m_rowstart[v]; EdgeIndex next_row_start = g.m_backward.m_rowstart[v + 1]; return next_row_start - v_row_start; } // From AdjacencyGraph template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline std::pair< typename BOOST_CSR_GRAPH_TYPE::adjacency_iterator, typename BOOST_CSR_GRAPH_TYPE::adjacency_iterator > adjacent_vertices(Vertex v, const BOOST_CSR_GRAPH_TYPE& g) { EdgeIndex v_row_start = g.m_forward.m_rowstart[v]; EdgeIndex next_row_start = g.m_forward.m_rowstart[v + 1]; return std::make_pair(g.m_forward.m_column.begin() + v_row_start, g.m_forward.m_column.begin() + next_row_start); } // Extra, common functions template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline typename graph_traits< BOOST_CSR_GRAPH_TYPE >::vertex_descriptor vertex( typename graph_traits< BOOST_CSR_GRAPH_TYPE >::vertex_descriptor i, const BOOST_CSR_GRAPH_TYPE&) { return i; } // edge() can be provided in linear time for the new interface template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline std::pair< typename BOOST_CSR_GRAPH_TYPE::edge_descriptor, bool > edge( Vertex i, Vertex j, const BOOST_CSR_GRAPH_TYPE& g) { typedef typename BOOST_CSR_GRAPH_TYPE::out_edge_iterator out_edge_iter; std::pair< out_edge_iter, out_edge_iter > range = out_edges(i, g); for (; range.first != range.second; ++range.first) { if (target(*range.first, g) == j) return std::make_pair(*range.first, true); } return std::make_pair( typename BOOST_CSR_GRAPH_TYPE::edge_descriptor(), false); } // Find an edge given its index in the graph template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline typename BOOST_CSR_GRAPH_TYPE::edge_descriptor edge_from_index( EdgeIndex idx, const BOOST_CSR_GRAPH_TYPE& g) { typedef typename std::vector< EdgeIndex >::const_iterator row_start_iter; BOOST_ASSERT(idx < num_edges(g)); row_start_iter src_plus_1 = std::upper_bound( g.m_forward.m_rowstart.begin(), g.m_forward.m_rowstart.end(), idx); // Get last source whose rowstart is at most idx // upper_bound returns this position plus 1 Vertex src = (src_plus_1 - g.m_forward.m_rowstart.begin()) - 1; return typename BOOST_CSR_GRAPH_TYPE::edge_descriptor(src, idx); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline EdgeIndex num_edges(const BOOST_CSR_GRAPH_TYPE& g) { return g.m_forward.m_column.size(); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > std::pair< typename BOOST_CSR_GRAPH_TYPE::edge_iterator, typename BOOST_CSR_GRAPH_TYPE::edge_iterator > edges(const BOOST_CSR_GRAPH_TYPE& g) { typedef typename BOOST_CSR_GRAPH_TYPE::edge_iterator ei; typedef typename BOOST_CSR_GRAPH_TYPE::edge_descriptor edgedesc; if (g.m_forward.m_rowstart.size() == 1 || g.m_forward.m_column.empty()) { return std::make_pair(ei(), ei()); } else { // Find the first vertex that has outgoing edges Vertex src = 0; while (g.m_forward.m_rowstart[src + 1] == 0) ++src; return std::make_pair( ei(g, edgedesc(src, 0), g.m_forward.m_rowstart[src + 1]), ei(g, edgedesc(num_vertices(g), g.m_forward.m_column.size()), 0)); } } // For Property Graph // Graph properties template < BOOST_CSR_GRAPH_TEMPLATE_PARMS, class Tag, class Value > inline void set_property(BOOST_CSR_GRAPH_TYPE& g, Tag tag, const Value& value) { get_property_value(g.m_property, tag) = value; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS, class Tag > inline typename graph_property< BOOST_CSR_GRAPH_TYPE, Tag >::type& get_property( BOOST_CSR_GRAPH_TYPE& g, Tag tag) { return get_property_value(g.m_property, tag); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS, class Tag > inline const typename graph_property< BOOST_CSR_GRAPH_TYPE, Tag >::type& get_property(const BOOST_CSR_GRAPH_TYPE& g, Tag tag) { return get_property_value(g.m_property, tag); } template < typename G, typename Tag, typename Kind > struct csr_property_map_helper { }; // Kind == void for invalid property tags, so we can use that to SFINAE out template < BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename Tag > struct csr_property_map_helper< BOOST_CSR_GRAPH_TYPE, Tag, vertex_property_tag > { typedef vertex_all_t all_tag; typedef typename property_traits< typename property_map< BOOST_CSR_GRAPH_TYPE, vertex_all_t >::type >::key_type key_type; typedef VertexProperty plist_type; typedef typename property_map< BOOST_CSR_GRAPH_TYPE, vertex_all_t >::type all_type; typedef typename property_map< BOOST_CSR_GRAPH_TYPE, vertex_all_t >::const_type all_const_type; typedef transform_value_property_map< detail::lookup_one_property_f< plist_type, Tag >, all_type > type; typedef transform_value_property_map< detail::lookup_one_property_f< const plist_type, Tag >, all_const_type > const_type; }; template < BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename Tag > struct csr_property_map_helper< BOOST_CSR_GRAPH_TYPE, Tag, edge_property_tag > { typedef edge_all_t all_tag; typedef typename property_traits< typename property_map< BOOST_CSR_GRAPH_TYPE, edge_all_t >::type >::key_type key_type; typedef EdgeProperty plist_type; typedef typename property_map< BOOST_CSR_GRAPH_TYPE, edge_all_t >::type all_type; typedef typename property_map< BOOST_CSR_GRAPH_TYPE, edge_all_t >::const_type all_const_type; typedef transform_value_property_map< detail::lookup_one_property_f< plist_type, Tag >, all_type > type; typedef transform_value_property_map< detail::lookup_one_property_f< const plist_type, Tag >, all_const_type > const_type; }; template < BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename Tag > struct csr_property_map_helper< BOOST_CSR_GRAPH_TYPE, Tag, graph_property_tag > { typedef graph_all_t all_tag; typedef BOOST_CSR_GRAPH_TYPE* key_type; typedef GraphProperty plist_type; typedef typename property_map< BOOST_CSR_GRAPH_TYPE, graph_all_t >::type all_type; typedef typename property_map< BOOST_CSR_GRAPH_TYPE, graph_all_t >::const_type all_const_type; typedef transform_value_property_map< detail::lookup_one_property_f< plist_type, Tag >, all_type > type; typedef transform_value_property_map< detail::lookup_one_property_f< const plist_type, Tag >, all_const_type > const_type; }; // disable_if isn't truly necessary but required to avoid ambiguity with // specializations below template < BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename Tag > struct property_map< BOOST_CSR_GRAPH_TYPE, Tag, typename disable_if< detail::is_distributed_selector< Vertex > >::type > : csr_property_map_helper< BOOST_CSR_GRAPH_TYPE, Tag, typename detail::property_kind_from_graph< BOOST_CSR_GRAPH_TYPE, Tag >::type > { }; template < BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename Tag > typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::type get( Tag tag, BOOST_CSR_GRAPH_TYPE& g) { return typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::type(tag, get(typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::all_tag(), g)); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename Tag > typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::const_type get( Tag tag, const BOOST_CSR_GRAPH_TYPE& g) { return typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::const_type(tag, get(typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::all_tag(), g)); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename Tag > typename property_traits< typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::type >::reference get(Tag tag, BOOST_CSR_GRAPH_TYPE& g, typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::key_type k) { typedef typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::all_tag all_tag; typedef typename property_map< BOOST_CSR_GRAPH_TYPE, all_tag >::type outer_pm; return lookup_one_property< typename property_traits< outer_pm >::value_type, Tag >::lookup(get(all_tag(), g, k), tag); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename Tag > typename property_traits< typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::const_type >::reference get(Tag tag, const BOOST_CSR_GRAPH_TYPE& g, typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::key_type k) { typedef typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::all_tag all_tag; typedef typename property_map< BOOST_CSR_GRAPH_TYPE, all_tag >::const_type outer_pm; return lookup_one_property< const typename property_traits< outer_pm >::value_type, Tag >::lookup(get(all_tag(), g, k), tag); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename Tag > void put(Tag tag, BOOST_CSR_GRAPH_TYPE& g, typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::key_type k, typename lookup_one_property< typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::plist_type, Tag >::type val) { typedef typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::all_tag all_tag; lookup_one_property< typename property_map< BOOST_CSR_GRAPH_TYPE, Tag >::plist_type, Tag >::lookup(get(all_tag(), g, k), tag) = val; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > struct property_map< BOOST_CSR_GRAPH_TYPE, vertex_index_t, typename disable_if< detail::is_distributed_selector< Vertex > >::type > { typedef typed_identity_property_map< Vertex > type; typedef type const_type; }; template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > struct property_map< BOOST_CSR_GRAPH_TYPE, edge_index_t, typename disable_if< detail::is_distributed_selector< Vertex > >::type > { typedef detail::csr_edge_index_map< Vertex, EdgeIndex > type; typedef type const_type; }; template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > struct property_map< BOOST_CSR_GRAPH_TYPE, vertex_all_t, typename disable_if< detail::is_distributed_selector< Vertex > >::type > { typedef typename BOOST_CSR_GRAPH_TYPE::inherited_vertex_properties:: vertex_map_type type; typedef typename BOOST_CSR_GRAPH_TYPE::inherited_vertex_properties:: const_vertex_map_type const_type; }; template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > struct property_map< BOOST_CSR_GRAPH_TYPE, edge_all_t, typename disable_if< detail::is_distributed_selector< Vertex > >::type > { typedef typename BOOST_CSR_GRAPH_TYPE::forward_type:: inherited_edge_properties::edge_map_type type; typedef typename BOOST_CSR_GRAPH_TYPE::forward_type:: inherited_edge_properties::const_edge_map_type const_type; }; template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > struct property_map< BOOST_CSR_GRAPH_TYPE, graph_all_t, typename disable_if< detail::is_distributed_selector< Vertex > >::type > { typedef boost::ref_property_map< BOOST_CSR_GRAPH_TYPE*, typename BOOST_CSR_GRAPH_TYPE::graph_property_type > type; typedef boost::ref_property_map< BOOST_CSR_GRAPH_TYPE*, const typename BOOST_CSR_GRAPH_TYPE::graph_property_type > const_type; }; template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline typed_identity_property_map< Vertex > get( vertex_index_t, const BOOST_CSR_GRAPH_TYPE&) { return typed_identity_property_map< Vertex >(); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline Vertex get(vertex_index_t, const BOOST_CSR_GRAPH_TYPE&, Vertex v) { return v; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline typed_identity_property_map< Vertex > get( vertex_index_t, BOOST_CSR_GRAPH_TYPE&) { return typed_identity_property_map< Vertex >(); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline Vertex get(vertex_index_t, BOOST_CSR_GRAPH_TYPE&, Vertex v) { return v; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline typename property_map< BOOST_CSR_GRAPH_TYPE, edge_index_t >::const_type get(edge_index_t, const BOOST_CSR_GRAPH_TYPE&) { typedef typename property_map< BOOST_CSR_GRAPH_TYPE, edge_index_t >::const_type result_type; return result_type(); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline EdgeIndex get(edge_index_t, const BOOST_CSR_GRAPH_TYPE&, typename BOOST_CSR_GRAPH_TYPE::edge_descriptor e) { return e.idx; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline typename property_map< BOOST_CSR_GRAPH_TYPE, edge_index_t >::const_type get(edge_index_t, BOOST_CSR_GRAPH_TYPE&) { typedef typename property_map< BOOST_CSR_GRAPH_TYPE, edge_index_t >::const_type result_type; return result_type(); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline EdgeIndex get(edge_index_t, BOOST_CSR_GRAPH_TYPE&, typename BOOST_CSR_GRAPH_TYPE::edge_descriptor e) { return e.idx; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline typename property_map< BOOST_CSR_GRAPH_TYPE, vertex_all_t >::type get( vertex_all_t, BOOST_CSR_GRAPH_TYPE& g) { return g.get_vertex_bundle(get(vertex_index, g)); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline typename property_map< BOOST_CSR_GRAPH_TYPE, vertex_all_t >::const_type get(vertex_all_t, const BOOST_CSR_GRAPH_TYPE& g) { return g.get_vertex_bundle(get(vertex_index, g)); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline VertexProperty& get(vertex_all_t, BOOST_CSR_GRAPH_TYPE& g, Vertex v) { return get(vertex_all, g)[v]; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline const VertexProperty& get( vertex_all_t, const BOOST_CSR_GRAPH_TYPE& g, Vertex v) { return get(vertex_all, g)[v]; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline void put( vertex_all_t, BOOST_CSR_GRAPH_TYPE& g, Vertex v, const VertexProperty& val) { put(get(vertex_all, g), v, val); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline typename property_map< BOOST_CSR_GRAPH_TYPE, edge_all_t >::type get( edge_all_t, BOOST_CSR_GRAPH_TYPE& g) { return g.m_forward.get_edge_bundle(get(edge_index, g)); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline typename property_map< BOOST_CSR_GRAPH_TYPE, edge_all_t >::const_type get(edge_all_t, const BOOST_CSR_GRAPH_TYPE& g) { return g.m_forward.get_edge_bundle(get(edge_index, g)); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline EdgeProperty& get(edge_all_t, BOOST_CSR_GRAPH_TYPE& g, const typename BOOST_CSR_GRAPH_TYPE::edge_descriptor& e) { return get(edge_all, g)[e]; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline const EdgeProperty& get(edge_all_t, const BOOST_CSR_GRAPH_TYPE& g, const typename BOOST_CSR_GRAPH_TYPE::edge_descriptor& e) { return get(edge_all, g)[e]; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline void put(edge_all_t, BOOST_CSR_GRAPH_TYPE& g, const typename BOOST_CSR_GRAPH_TYPE::edge_descriptor& e, const EdgeProperty& val) { put(get(edge_all, g), e, val); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline typename property_map< BOOST_CSR_GRAPH_TYPE, graph_all_t >::type get( graph_all_t, BOOST_CSR_GRAPH_TYPE& g) { return typename property_map< BOOST_CSR_GRAPH_TYPE, graph_all_t >::type( g.m_property); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline typename property_map< BOOST_CSR_GRAPH_TYPE, graph_all_t >::const_type get(graph_all_t, const BOOST_CSR_GRAPH_TYPE& g) { return typename property_map< BOOST_CSR_GRAPH_TYPE, graph_all_t >::const_type( g.m_property); } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline GraphProperty& get( graph_all_t, BOOST_CSR_GRAPH_TYPE& g, BOOST_CSR_GRAPH_TYPE*) { return g.m_property; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline const GraphProperty& get( graph_all_t, const BOOST_CSR_GRAPH_TYPE& g, BOOST_CSR_GRAPH_TYPE*) { return g.m_property; } template < BOOST_CSR_GRAPH_TEMPLATE_PARMS > inline void put(graph_all_t, BOOST_CSR_GRAPH_TYPE& g, BOOST_CSR_GRAPH_TYPE*, const GraphProperty& val) { g.m_property = val; } #undef BOOST_CSR_GRAPH_TYPE #undef BOOST_CSR_GRAPH_TEMPLATE_PARMS #undef BOOST_DIR_CSR_GRAPH_TYPE #undef BOOST_DIR_CSR_GRAPH_TEMPLATE_PARMS #undef BOOST_BIDIR_CSR_GRAPH_TYPE #undef BOOST_BIDIR_CSR_GRAPH_TEMPLATE_PARMS } // end namespace boost #endif // BOOST_GRAPH_COMPRESSED_SPARSE_ROW_GRAPH_HPP property_iter_range.hpp 0000644 00000010371 15125521275 0011347 0 ustar 00 // (C) Copyright Francois Faure, iMAGIS-GRAVIR / UJF, 2001. // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Revision History: // 03 May 2001 Jeremy Siek // Generalized the property map iterator and moved that // part to boost/property_map.hpp. Also modified to // differentiate between const/mutable graphs and // added a workaround to avoid partial specialization. // 02 May 2001 Francois Faure // Initial version. #ifndef BOOST_GRAPH_PROPERTY_ITER_RANGE_HPP #define BOOST_GRAPH_PROPERTY_ITER_RANGE_HPP #include <boost/property_map/property_map_iterator.hpp> #include <boost/graph/properties.hpp> #include <boost/mpl/if.hpp> #include <boost/type_traits/same_traits.hpp> namespace boost { //====================================================================== // graph property iterator range template < class Graph, class PropertyTag > class graph_property_iter_range { typedef typename property_map< Graph, PropertyTag >::type map_type; typedef typename property_map< Graph, PropertyTag >::const_type const_map_type; typedef typename property_kind< PropertyTag >::type Kind; typedef typename mpl::if_c< is_same< Kind, vertex_property_tag >::value, typename graph_traits< Graph >::vertex_iterator, typename graph_traits< Graph >::edge_iterator >::type iter; public: typedef typename property_map_iterator_generator< map_type, iter >::type iterator; typedef typename property_map_iterator_generator< const_map_type, iter >::type const_iterator; typedef std::pair< iterator, iterator > type; typedef std::pair< const_iterator, const_iterator > const_type; }; namespace detail { template < class Graph, class Tag > typename graph_property_iter_range< Graph, Tag >::type get_property_iter_range_kind( Graph& graph, const Tag& tag, const vertex_property_tag&) { typedef typename graph_property_iter_range< Graph, Tag >::iterator iter; return std::make_pair(iter(vertices(graph).first, get(tag, graph)), iter(vertices(graph).second, get(tag, graph))); } template < class Graph, class Tag > typename graph_property_iter_range< Graph, Tag >::const_type get_property_iter_range_kind( const Graph& graph, const Tag& tag, const vertex_property_tag&) { typedef typename graph_property_iter_range< Graph, Tag >::const_iterator iter; return std::make_pair(iter(vertices(graph).first, get(tag, graph)), iter(vertices(graph).second, get(tag, graph))); } template < class Graph, class Tag > typename graph_property_iter_range< Graph, Tag >::type get_property_iter_range_kind( Graph& graph, const Tag& tag, const edge_property_tag&) { typedef typename graph_property_iter_range< Graph, Tag >::iterator iter; return std::make_pair(iter(edges(graph).first, get(tag, graph)), iter(edges(graph).second, get(tag, graph))); } template < class Graph, class Tag > typename graph_property_iter_range< Graph, Tag >::const_type get_property_iter_range_kind( const Graph& graph, const Tag& tag, const edge_property_tag&) { typedef typename graph_property_iter_range< Graph, Tag >::const_iterator iter; return std::make_pair(iter(edges(graph).first, get(tag, graph)), iter(edges(graph).second, get(tag, graph))); } } // namespace detail //====================================================================== // get an iterator range of properties template < class Graph, class Tag > typename graph_property_iter_range< Graph, Tag >::type get_property_iter_range( Graph& graph, const Tag& tag) { typedef typename property_kind< Tag >::type Kind; return detail::get_property_iter_range_kind(graph, tag, Kind()); } template < class Graph, class Tag > typename graph_property_iter_range< Graph, Tag >::const_type get_property_iter_range(const Graph& graph, const Tag& tag) { typedef typename property_kind< Tag >::type Kind; return detail::get_property_iter_range_kind(graph, tag, Kind()); } } // namespace boost #endif // BOOST_GRAPH_PROPERTY_ITER_RANGE_HPP bandwidth.hpp 0000644 00000005640 15125521275 0007233 0 ustar 00 // Copyright (c) Jeremy Siek 2001, Marc Wintermantel 2002 // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GRAPH_BANDWIDTH_HPP #define BOOST_GRAPH_BANDWIDTH_HPP #include <algorithm> // for std::min and std::max #include <boost/config.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/detail/numeric_traits.hpp> namespace boost { template < typename Graph, typename VertexIndexMap > typename graph_traits< Graph >::vertices_size_type ith_bandwidth( typename graph_traits< Graph >::vertex_descriptor i, const Graph& g, VertexIndexMap index) { BOOST_USING_STD_MAX(); using std::abs; typedef typename graph_traits< Graph >::vertices_size_type vertices_size_type; vertices_size_type b = 0; typename graph_traits< Graph >::out_edge_iterator e, end; for (boost::tie(e, end) = out_edges(i, g); e != end; ++e) { int f_i = get(index, i); int f_j = get(index, target(*e, g)); b = max BOOST_PREVENT_MACRO_SUBSTITUTION( b, vertices_size_type(abs(f_i - f_j))); } return b; } template < typename Graph > typename graph_traits< Graph >::vertices_size_type ith_bandwidth( typename graph_traits< Graph >::vertex_descriptor i, const Graph& g) { return ith_bandwidth(i, g, get(vertex_index, g)); } template < typename Graph, typename VertexIndexMap > typename graph_traits< Graph >::vertices_size_type bandwidth( const Graph& g, VertexIndexMap index) { BOOST_USING_STD_MAX(); using std::abs; typedef typename graph_traits< Graph >::vertices_size_type vertices_size_type; vertices_size_type b = 0; typename graph_traits< Graph >::edge_iterator i, end; for (boost::tie(i, end) = edges(g); i != end; ++i) { int f_i = get(index, source(*i, g)); int f_j = get(index, target(*i, g)); b = max BOOST_PREVENT_MACRO_SUBSTITUTION( b, vertices_size_type(abs(f_i - f_j))); } return b; } template < typename Graph > typename graph_traits< Graph >::vertices_size_type bandwidth(const Graph& g) { return bandwidth(g, get(vertex_index, g)); } template < typename Graph, typename VertexIndexMap > typename graph_traits< Graph >::vertices_size_type edgesum( const Graph& g, VertexIndexMap index_map) { typedef typename graph_traits< Graph >::vertices_size_type size_type; typedef typename detail::numeric_traits< size_type >::difference_type diff_t; size_type sum = 0; typename graph_traits< Graph >::edge_iterator i, end; for (boost::tie(i, end) = edges(g); i != end; ++i) { diff_t f_u = get(index_map, source(*i, g)); diff_t f_v = get(index_map, target(*i, g)); using namespace std; // to call abs() unqualified sum += abs(f_u - f_v); } return sum; } } // namespace boost #endif // BOOST_GRAPH_BANDWIDTH_HPP r_c_shortest_paths.hpp 0000644 00000073721 15125521275 0011171 0 ustar 00 // r_c_shortest_paths.hpp header file // Copyright Michael Drexl 2005, 2006. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://boost.org/LICENSE_1_0.txt) #ifndef BOOST_GRAPH_R_C_SHORTEST_PATHS_HPP #define BOOST_GRAPH_R_C_SHORTEST_PATHS_HPP #include <map> #include <queue> #include <vector> #include <list> #include <boost/make_shared.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/property_map/property_map.hpp> namespace boost { // r_c_shortest_paths_label struct template < class Graph, class Resource_Container > struct r_c_shortest_paths_label : public boost::enable_shared_from_this< r_c_shortest_paths_label< Graph, Resource_Container > > { r_c_shortest_paths_label(const unsigned long n, const Resource_Container& rc = Resource_Container(), const boost::shared_ptr< r_c_shortest_paths_label< Graph, Resource_Container > > pl = boost::shared_ptr< r_c_shortest_paths_label< Graph, Resource_Container > >(), const typename graph_traits< Graph >::edge_descriptor& ed = graph_traits< Graph >::edge_descriptor(), const typename graph_traits< Graph >::vertex_descriptor& vd = graph_traits< Graph >::vertex_descriptor()) : num(n) , cumulated_resource_consumption(rc) , p_pred_label(pl) , pred_edge(ed) , resident_vertex(vd) , b_is_dominated(false) , b_is_processed(false) { } r_c_shortest_paths_label& operator=(const r_c_shortest_paths_label& other) { if (this == &other) return *this; this->~r_c_shortest_paths_label(); new (this) r_c_shortest_paths_label(other); return *this; } const unsigned long num; Resource_Container cumulated_resource_consumption; const boost::shared_ptr< r_c_shortest_paths_label< Graph, Resource_Container > > p_pred_label; const typename graph_traits< Graph >::edge_descriptor pred_edge; const typename graph_traits< Graph >::vertex_descriptor resident_vertex; bool b_is_dominated; bool b_is_processed; }; // r_c_shortest_paths_label template < class Graph, class Resource_Container > inline bool operator==( const r_c_shortest_paths_label< Graph, Resource_Container >& l1, const r_c_shortest_paths_label< Graph, Resource_Container >& l2) { return l1.cumulated_resource_consumption == l2.cumulated_resource_consumption; } template < class Graph, class Resource_Container > inline bool operator!=( const r_c_shortest_paths_label< Graph, Resource_Container >& l1, const r_c_shortest_paths_label< Graph, Resource_Container >& l2) { return !(l1 == l2); } template < class Graph, class Resource_Container > inline bool operator<( const r_c_shortest_paths_label< Graph, Resource_Container >& l1, const r_c_shortest_paths_label< Graph, Resource_Container >& l2) { return l1.cumulated_resource_consumption < l2.cumulated_resource_consumption; } template < class Graph, class Resource_Container > inline bool operator>( const r_c_shortest_paths_label< Graph, Resource_Container >& l1, const r_c_shortest_paths_label< Graph, Resource_Container >& l2) { return l2.cumulated_resource_consumption < l1.cumulated_resource_consumption; } template < class Graph, class Resource_Container > inline bool operator<=( const r_c_shortest_paths_label< Graph, Resource_Container >& l1, const r_c_shortest_paths_label< Graph, Resource_Container >& l2) { return l1 < l2 || l1 == l2; } template < class Graph, class Resource_Container > inline bool operator>=( const r_c_shortest_paths_label< Graph, Resource_Container >& l1, const r_c_shortest_paths_label< Graph, Resource_Container >& l2) { return l2 < l1 || l1 == l2; } template < typename Graph, typename Resource_Container > inline bool operator<( const boost::shared_ptr< r_c_shortest_paths_label< Graph, Resource_Container > >& t, const boost::shared_ptr< r_c_shortest_paths_label< Graph, Resource_Container > >& u) { return *t < *u; } template < typename Graph, typename Resource_Container > inline bool operator<=( const boost::shared_ptr< r_c_shortest_paths_label< Graph, Resource_Container > >& t, const boost::shared_ptr< r_c_shortest_paths_label< Graph, Resource_Container > >& u) { return *t <= *u; } template < typename Graph, typename Resource_Container > inline bool operator>( const boost::shared_ptr< r_c_shortest_paths_label< Graph, Resource_Container > >& t, const boost::shared_ptr< r_c_shortest_paths_label< Graph, Resource_Container > >& u) { return *t > *u; } template < typename Graph, typename Resource_Container > inline bool operator>=( const boost::shared_ptr< r_c_shortest_paths_label< Graph, Resource_Container > >& t, const boost::shared_ptr< r_c_shortest_paths_label< Graph, Resource_Container > >& u) { return *t >= *u; } namespace detail { // r_c_shortest_paths_dispatch function (body/implementation) template < class Graph, class VertexIndexMap, class EdgeIndexMap, class Resource_Container, class Resource_Extension_Function, class Dominance_Function, class Label_Allocator, class Visitor > void r_c_shortest_paths_dispatch(const Graph& g, const VertexIndexMap& vertex_index_map, const EdgeIndexMap& /*edge_index_map*/, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, // each inner vector corresponds to a pareto-optimal path std::vector< std::vector< typename graph_traits< Graph >::edge_descriptor > >& pareto_optimal_solutions, std::vector< Resource_Container >& pareto_optimal_resource_containers, bool b_all_pareto_optimal_solutions, // to initialize the first label/resource container // and to carry the type information const Resource_Container& rc, Resource_Extension_Function& ref, Dominance_Function& dominance, // to specify the memory management strategy for the labels Label_Allocator /*la*/, Visitor vis) { pareto_optimal_resource_containers.clear(); pareto_optimal_solutions.clear(); size_t i_label_num = 0; #if defined(BOOST_NO_CXX11_ALLOCATOR) typedef typename Label_Allocator::template rebind< r_c_shortest_paths_label< Graph, Resource_Container > >::other LAlloc; #else typedef typename std::allocator_traits< Label_Allocator >:: template rebind_alloc< r_c_shortest_paths_label< Graph, Resource_Container > > LAlloc; typedef std::allocator_traits< LAlloc > LTraits; #endif LAlloc l_alloc; typedef boost::shared_ptr< r_c_shortest_paths_label< Graph, Resource_Container > > Splabel; std::priority_queue< Splabel, std::vector< Splabel >, std::greater< Splabel > > unprocessed_labels; bool b_feasible = true; Splabel splabel_first_label = boost::allocate_shared< r_c_shortest_paths_label< Graph, Resource_Container > >(l_alloc, i_label_num++, rc, boost::shared_ptr< r_c_shortest_paths_label< Graph, Resource_Container > >(), typename graph_traits< Graph >::edge_descriptor(), s); unprocessed_labels.push(splabel_first_label); std::vector< std::list< Splabel > > vec_vertex_labels_data( num_vertices(g)); iterator_property_map< typename std::vector< std::list< Splabel > >::iterator, VertexIndexMap > vec_vertex_labels(vec_vertex_labels_data.begin(), vertex_index_map); vec_vertex_labels[s].push_back(splabel_first_label); typedef std::vector< typename std::list< Splabel >::iterator > vec_last_valid_positions_for_dominance_data_type; vec_last_valid_positions_for_dominance_data_type vec_last_valid_positions_for_dominance_data(num_vertices(g)); iterator_property_map< typename vec_last_valid_positions_for_dominance_data_type::iterator, VertexIndexMap > vec_last_valid_positions_for_dominance( vec_last_valid_positions_for_dominance_data.begin(), vertex_index_map); BGL_FORALL_VERTICES_T(v, g, Graph) { put(vec_last_valid_positions_for_dominance, v, vec_vertex_labels[v].begin()); } std::vector< size_t > vec_last_valid_index_for_dominance_data( num_vertices(g), 0); iterator_property_map< std::vector< size_t >::iterator, VertexIndexMap > vec_last_valid_index_for_dominance( vec_last_valid_index_for_dominance_data.begin(), vertex_index_map); std::vector< bool > b_vec_vertex_already_checked_for_dominance_data( num_vertices(g), false); iterator_property_map< std::vector< bool >::iterator, VertexIndexMap > b_vec_vertex_already_checked_for_dominance( b_vec_vertex_already_checked_for_dominance_data.begin(), vertex_index_map); while (!unprocessed_labels.empty() && vis.on_enter_loop(unprocessed_labels, g)) { Splabel cur_label = unprocessed_labels.top(); unprocessed_labels.pop(); vis.on_label_popped(*cur_label, g); // an Splabel object in unprocessed_labels and the respective // Splabel object in the respective list<Splabel> of // vec_vertex_labels share their embedded r_c_shortest_paths_label // object to avoid memory leaks, dominated r_c_shortest_paths_label // objects are marked and deleted when popped from // unprocessed_labels, as they can no longer be deleted at the end // of the function; only the Splabel object in unprocessed_labels // still references the r_c_shortest_paths_label object this is also // for efficiency, because the else branch is executed only if there // is a chance that extending the label leads to new undominated // labels, which in turn is possible only if the label to be // extended is undominated if (!cur_label->b_is_dominated) { typename boost::graph_traits< Graph >::vertex_descriptor i_cur_resident_vertex = cur_label->resident_vertex; std::list< Splabel >& list_labels_cur_vertex = get(vec_vertex_labels, i_cur_resident_vertex); if (list_labels_cur_vertex.size() >= 2 && vec_last_valid_index_for_dominance[i_cur_resident_vertex] < list_labels_cur_vertex.size()) { typename std::list< Splabel >::iterator outer_iter = list_labels_cur_vertex.begin(); bool b_outer_iter_at_or_beyond_last_valid_pos_for_dominance = false; while (outer_iter != list_labels_cur_vertex.end()) { Splabel cur_outer_splabel = *outer_iter; typename std::list< Splabel >::iterator inner_iter = outer_iter; if (!b_outer_iter_at_or_beyond_last_valid_pos_for_dominance && outer_iter == get(vec_last_valid_positions_for_dominance, i_cur_resident_vertex)) b_outer_iter_at_or_beyond_last_valid_pos_for_dominance = true; if (!get(b_vec_vertex_already_checked_for_dominance, i_cur_resident_vertex) || b_outer_iter_at_or_beyond_last_valid_pos_for_dominance) { ++inner_iter; } else { inner_iter = get(vec_last_valid_positions_for_dominance, i_cur_resident_vertex); ++inner_iter; } bool b_outer_iter_erased = false; while (inner_iter != list_labels_cur_vertex.end()) { Splabel cur_inner_splabel = *inner_iter; if (dominance(cur_outer_splabel ->cumulated_resource_consumption, cur_inner_splabel ->cumulated_resource_consumption)) { typename std::list< Splabel >::iterator buf = inner_iter; ++inner_iter; list_labels_cur_vertex.erase(buf); if (cur_inner_splabel->b_is_processed) { cur_inner_splabel.reset(); } else cur_inner_splabel->b_is_dominated = true; continue; } else ++inner_iter; if (dominance(cur_inner_splabel ->cumulated_resource_consumption, cur_outer_splabel ->cumulated_resource_consumption)) { typename std::list< Splabel >::iterator buf = outer_iter; ++outer_iter; list_labels_cur_vertex.erase(buf); b_outer_iter_erased = true; if (cur_outer_splabel->b_is_processed) { cur_outer_splabel.reset(); } else cur_outer_splabel->b_is_dominated = true; break; } } if (!b_outer_iter_erased) ++outer_iter; } if (list_labels_cur_vertex.size() > 1) put(vec_last_valid_positions_for_dominance, i_cur_resident_vertex, (--(list_labels_cur_vertex.end()))); else put(vec_last_valid_positions_for_dominance, i_cur_resident_vertex, list_labels_cur_vertex.begin()); put(b_vec_vertex_already_checked_for_dominance, i_cur_resident_vertex, true); put(vec_last_valid_index_for_dominance, i_cur_resident_vertex, list_labels_cur_vertex.size() - 1); } } if (!b_all_pareto_optimal_solutions && cur_label->resident_vertex == t) { // the devil don't sleep if (cur_label->b_is_dominated) { cur_label.reset(); } while (unprocessed_labels.size()) { Splabel l = unprocessed_labels.top(); unprocessed_labels.pop(); // delete only dominated labels, because nondominated labels // are deleted at the end of the function if (l->b_is_dominated) { l.reset(); } } break; } if (!cur_label->b_is_dominated) { cur_label->b_is_processed = true; vis.on_label_not_dominated(*cur_label, g); typename graph_traits< Graph >::vertex_descriptor cur_vertex = cur_label->resident_vertex; typename graph_traits< Graph >::out_edge_iterator oei, oei_end; for (boost::tie(oei, oei_end) = out_edges(cur_vertex, g); oei != oei_end; ++oei) { b_feasible = true; Splabel new_label = boost::allocate_shared< r_c_shortest_paths_label< Graph, Resource_Container > >( l_alloc, i_label_num++, cur_label->cumulated_resource_consumption, cur_label, *oei, target(*oei, g)); b_feasible = ref(g, new_label->cumulated_resource_consumption, new_label->p_pred_label->cumulated_resource_consumption, new_label->pred_edge); if (!b_feasible) { vis.on_label_not_feasible(*new_label, g); new_label.reset(); } else { vis.on_label_feasible(*new_label, g); vec_vertex_labels[new_label->resident_vertex].push_back( new_label); unprocessed_labels.push(new_label); } } } else { vis.on_label_dominated(*cur_label, g); cur_label.reset(); } } std::list< Splabel > dsplabels = get(vec_vertex_labels, t); typename std::list< Splabel >::const_iterator csi = dsplabels.begin(); typename std::list< Splabel >::const_iterator csi_end = dsplabels.end(); // if d could be reached from o if (!dsplabels.empty()) { for (; csi != csi_end; ++csi) { std::vector< typename graph_traits< Graph >::edge_descriptor > cur_pareto_optimal_path; boost::shared_ptr< r_c_shortest_paths_label< Graph, Resource_Container > > p_cur_label = *csi; pareto_optimal_resource_containers.push_back( p_cur_label->cumulated_resource_consumption); while (p_cur_label->num != 0) { cur_pareto_optimal_path.push_back(p_cur_label->pred_edge); p_cur_label = p_cur_label->p_pred_label; // assertion b_is_valid beyond this point is not correct if // the domination function requires resource levels to be // strictly greater than existing values // // Example // Customers // id min_arrival max_departure // 2 0 974 // 3 0 972 // 4 0 964 // 5 678 801 // // Path A: 2-3-4-5 (times: 0-16-49-84-678) // Path B: 3-2-4-5 (times: 0-18-51-62-678) // The partial path 3-2-4 dominates the other partial path // 2-3-4, though the path 3-2-4-5 does not strictly dominate // the path 2-3-4-5 } pareto_optimal_solutions.push_back(cur_pareto_optimal_path); if (!b_all_pareto_optimal_solutions) break; } } BGL_FORALL_VERTICES_T(i, g, Graph) { std::list< Splabel >& list_labels_cur_vertex = vec_vertex_labels[i]; typename std::list< Splabel >::iterator si = list_labels_cur_vertex.begin(); const typename std::list< Splabel >::iterator si_end = list_labels_cur_vertex.end(); for (; si != si_end; ++si) { (*si).reset(); } } } // r_c_shortest_paths_dispatch } // detail // default_r_c_shortest_paths_visitor struct struct default_r_c_shortest_paths_visitor { template < class Label, class Graph > void on_label_popped(const Label&, const Graph&) { } template < class Label, class Graph > void on_label_feasible(const Label&, const Graph&) { } template < class Label, class Graph > void on_label_not_feasible(const Label&, const Graph&) { } template < class Label, class Graph > void on_label_dominated(const Label&, const Graph&) { } template < class Label, class Graph > void on_label_not_dominated(const Label&, const Graph&) { } template < class Queue, class Graph > bool on_enter_loop(const Queue& queue, const Graph& graph) { return true; } }; // default_r_c_shortest_paths_visitor // default_r_c_shortest_paths_allocator typedef std::allocator< int > default_r_c_shortest_paths_allocator; // default_r_c_shortest_paths_allocator // r_c_shortest_paths functions (handle/interface) // first overload: // - return all pareto-optimal solutions // - specify Label_Allocator and Visitor arguments template < class Graph, class VertexIndexMap, class EdgeIndexMap, class Resource_Container, class Resource_Extension_Function, class Dominance_Function, class Label_Allocator, class Visitor > void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, const EdgeIndexMap& edge_index_map, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, // each inner vector corresponds to a pareto-optimal path std::vector< std::vector< typename graph_traits< Graph >::edge_descriptor > >& pareto_optimal_solutions, std::vector< Resource_Container >& pareto_optimal_resource_containers, // to initialize the first label/resource container // and to carry the type information const Resource_Container& rc, const Resource_Extension_Function& ref, const Dominance_Function& dominance, // to specify the memory management strategy for the labels Label_Allocator la, Visitor vis) { r_c_shortest_paths_dispatch(g, vertex_index_map, edge_index_map, s, t, pareto_optimal_solutions, pareto_optimal_resource_containers, true, rc, ref, dominance, la, vis); } // second overload: // - return only one pareto-optimal solution // - specify Label_Allocator and Visitor arguments template < class Graph, class VertexIndexMap, class EdgeIndexMap, class Resource_Container, class Resource_Extension_Function, class Dominance_Function, class Label_Allocator, class Visitor > void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, const EdgeIndexMap& edge_index_map, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, std::vector< typename graph_traits< Graph >::edge_descriptor >& pareto_optimal_solution, Resource_Container& pareto_optimal_resource_container, // to initialize the first label/resource container // and to carry the type information const Resource_Container& rc, const Resource_Extension_Function& ref, const Dominance_Function& dominance, // to specify the memory management strategy for the labels Label_Allocator la, Visitor vis) { // each inner vector corresponds to a pareto-optimal path std::vector< std::vector< typename graph_traits< Graph >::edge_descriptor > > pareto_optimal_solutions; std::vector< Resource_Container > pareto_optimal_resource_containers; r_c_shortest_paths_dispatch(g, vertex_index_map, edge_index_map, s, t, pareto_optimal_solutions, pareto_optimal_resource_containers, false, rc, ref, dominance, la, vis); if (!pareto_optimal_solutions.empty()) { pareto_optimal_solution = pareto_optimal_solutions[0]; pareto_optimal_resource_container = pareto_optimal_resource_containers[0]; } } // third overload: // - return all pareto-optimal solutions // - use default Label_Allocator and Visitor template < class Graph, class VertexIndexMap, class EdgeIndexMap, class Resource_Container, class Resource_Extension_Function, class Dominance_Function > void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, const EdgeIndexMap& edge_index_map, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, // each inner vector corresponds to a pareto-optimal path std::vector< std::vector< typename graph_traits< Graph >::edge_descriptor > >& pareto_optimal_solutions, std::vector< Resource_Container >& pareto_optimal_resource_containers, // to initialize the first label/resource container // and to carry the type information const Resource_Container& rc, const Resource_Extension_Function& ref, const Dominance_Function& dominance) { r_c_shortest_paths_dispatch(g, vertex_index_map, edge_index_map, s, t, pareto_optimal_solutions, pareto_optimal_resource_containers, true, rc, ref, dominance, default_r_c_shortest_paths_allocator(), default_r_c_shortest_paths_visitor()); } // fourth overload: // - return only one pareto-optimal solution // - use default Label_Allocator and Visitor template < class Graph, class VertexIndexMap, class EdgeIndexMap, class Resource_Container, class Resource_Extension_Function, class Dominance_Function > void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, const EdgeIndexMap& edge_index_map, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, std::vector< typename graph_traits< Graph >::edge_descriptor >& pareto_optimal_solution, Resource_Container& pareto_optimal_resource_container, // to initialize the first label/resource container // and to carry the type information const Resource_Container& rc, const Resource_Extension_Function& ref, const Dominance_Function& dominance) { // each inner vector corresponds to a pareto-optimal path std::vector< std::vector< typename graph_traits< Graph >::edge_descriptor > > pareto_optimal_solutions; std::vector< Resource_Container > pareto_optimal_resource_containers; r_c_shortest_paths_dispatch(g, vertex_index_map, edge_index_map, s, t, pareto_optimal_solutions, pareto_optimal_resource_containers, false, rc, ref, dominance, default_r_c_shortest_paths_allocator(), default_r_c_shortest_paths_visitor()); if (!pareto_optimal_solutions.empty()) { pareto_optimal_solution = pareto_optimal_solutions[0]; pareto_optimal_resource_container = pareto_optimal_resource_containers[0]; } } // r_c_shortest_paths // check_r_c_path function template < class Graph, class Resource_Container, class Resource_Extension_Function > void check_r_c_path(const Graph& g, const std::vector< typename graph_traits< Graph >::edge_descriptor >& ed_vec_path, const Resource_Container& initial_resource_levels, // if true, computed accumulated final resource levels must // be equal to desired_final_resource_levels // if false, computed accumulated final resource levels must // be less than or equal to desired_final_resource_levels bool b_result_must_be_equal_to_desired_final_resource_levels, const Resource_Container& desired_final_resource_levels, Resource_Container& actual_final_resource_levels, const Resource_Extension_Function& ref, bool& b_is_a_path_at_all, bool& b_feasible, bool& b_correctly_extended, typename graph_traits< Graph >::edge_descriptor& ed_last_extended_arc) { size_t i_size_ed_vec_path = ed_vec_path.size(); std::vector< typename graph_traits< Graph >::edge_descriptor > buf_path; if (i_size_ed_vec_path == 0) b_feasible = true; else { if (i_size_ed_vec_path == 1 || target(ed_vec_path[0], g) == source(ed_vec_path[1], g)) buf_path = ed_vec_path; else for (size_t i = i_size_ed_vec_path; i > 0; --i) buf_path.push_back(ed_vec_path[i - 1]); for (size_t i = 0; i < i_size_ed_vec_path - 1; ++i) { if (target(buf_path[i], g) != source(buf_path[i + 1], g)) { b_is_a_path_at_all = false; b_feasible = false; b_correctly_extended = false; return; } } } b_is_a_path_at_all = true; b_feasible = true; b_correctly_extended = false; Resource_Container current_resource_levels = initial_resource_levels; actual_final_resource_levels = current_resource_levels; for (size_t i = 0; i < i_size_ed_vec_path; ++i) { ed_last_extended_arc = buf_path[i]; b_feasible = ref(g, actual_final_resource_levels, current_resource_levels, buf_path[i]); current_resource_levels = actual_final_resource_levels; if (!b_feasible) return; } if (b_result_must_be_equal_to_desired_final_resource_levels) b_correctly_extended = actual_final_resource_levels == desired_final_resource_levels ? true : false; else { if (actual_final_resource_levels < desired_final_resource_levels || actual_final_resource_levels == desired_final_resource_levels) b_correctly_extended = true; } } // check_path } // namespace #endif // BOOST_GRAPH_R_C_SHORTEST_PATHS_HPP make_maximal_planar.hpp 0000644 00000016632 15125521275 0011254 0 ustar 00 //======================================================================= // Copyright 2007 Aaron Windsor // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef __MAKE_MAXIMAL_PLANAR_HPP__ #define __MAKE_MAXIMAL_PLANAR_HPP__ #include <boost/config.hpp> #include <boost/tuple/tuple.hpp> //for tie #include <boost/graph/biconnected_components.hpp> #include <boost/property_map/property_map.hpp> #include <vector> #include <iterator> #include <algorithm> #include <boost/graph/planar_face_traversal.hpp> #include <boost/graph/planar_detail/add_edge_visitors.hpp> namespace boost { template < typename Graph, typename VertexIndexMap, typename AddEdgeVisitor > struct triangulation_visitor : public planar_face_traversal_visitor { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::edge_descriptor edge_t; typedef typename graph_traits< Graph >::vertices_size_type v_size_t; typedef typename graph_traits< Graph >::degree_size_type degree_size_t; typedef typename graph_traits< Graph >::edge_iterator edge_iterator_t; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; typedef typename graph_traits< Graph >::adjacency_iterator adjacency_iterator_t; typedef typename std::vector< vertex_t > vertex_vector_t; typedef typename std::vector< v_size_t > v_size_vector_t; typedef typename std::vector< degree_size_t > degree_size_vector_t; typedef iterator_property_map< typename v_size_vector_t::iterator, VertexIndexMap > vertex_to_v_size_map_t; typedef iterator_property_map< typename degree_size_vector_t::iterator, VertexIndexMap > vertex_to_degree_size_map_t; typedef typename vertex_vector_t::iterator face_iterator; triangulation_visitor(Graph& arg_g, VertexIndexMap arg_vm, AddEdgeVisitor arg_add_edge_visitor) : g(arg_g) , vm(arg_vm) , add_edge_visitor(arg_add_edge_visitor) , timestamp(0) , marked_vector(num_vertices(g), timestamp) , degree_vector(num_vertices(g), 0) , marked(marked_vector.begin(), vm) , degree(degree_vector.begin(), vm) { vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) put(degree, *vi, out_degree(*vi, g)); } template < typename Vertex > void next_vertex(Vertex v) { // Self-loops will appear as consecutive vertices in the list of // vertices on a face. We want to skip these. if (!vertices_on_face.empty() && (vertices_on_face.back() == v || vertices_on_face.front() == v)) return; vertices_on_face.push_back(v); } void end_face() { ++timestamp; if (vertices_on_face.size() <= 3) { // At most three vertices on this face - don't need to triangulate vertices_on_face.clear(); return; } // Find vertex on face of minimum degree degree_size_t min_degree = num_vertices(g); typename vertex_vector_t::iterator min_degree_vertex_itr; face_iterator fi_end = vertices_on_face.end(); for (face_iterator fi = vertices_on_face.begin(); fi != fi_end; ++fi) { degree_size_t deg = get(degree, *fi); if (deg < min_degree) { min_degree_vertex_itr = fi; min_degree = deg; } } // To simplify some of the manipulations, we'll re-arrange // vertices_on_face so that it still contains the same // (counter-clockwise) order of the vertices on this face, but now the // min_degree_vertex is the first element in vertices_on_face. vertex_vector_t temp_vector; std::copy(min_degree_vertex_itr, vertices_on_face.end(), std::back_inserter(temp_vector)); std::copy(vertices_on_face.begin(), min_degree_vertex_itr, std::back_inserter(temp_vector)); vertices_on_face.swap(temp_vector); // Mark all of the min degree vertex's neighbors adjacency_iterator_t ai, ai_end; for (boost::tie(ai, ai_end) = adjacent_vertices(vertices_on_face.front(), g); ai != ai_end; ++ai) { put(marked, *ai, timestamp); } typename vertex_vector_t::iterator marked_neighbor = vertices_on_face.end(); // The iterator manipulations on the next two lines are safe because // vertices_on_face.size() > 3 (from the first test in this function) fi_end = prior(vertices_on_face.end()); for (face_iterator fi = boost::next(boost::next(vertices_on_face.begin())); fi != fi_end; ++fi) { if (get(marked, *fi) == timestamp) { marked_neighbor = fi; break; } } if (marked_neighbor == vertices_on_face.end()) { add_edge_range(vertices_on_face[0], boost::next(boost::next(vertices_on_face.begin())), prior(vertices_on_face.end())); } else { add_edge_range(vertices_on_face[1], boost::next(marked_neighbor), vertices_on_face.end()); add_edge_range(*boost::next(marked_neighbor), boost::next(boost::next(vertices_on_face.begin())), marked_neighbor); } // reset for the next face vertices_on_face.clear(); } private: void add_edge_range(vertex_t anchor, face_iterator fi, face_iterator fi_end) { for (; fi != fi_end; ++fi) { vertex_t v(*fi); add_edge_visitor.visit_vertex_pair(anchor, v, g); put(degree, anchor, get(degree, anchor) + 1); put(degree, v, get(degree, v) + 1); } } Graph& g; VertexIndexMap vm; AddEdgeVisitor add_edge_visitor; v_size_t timestamp; vertex_vector_t vertices_on_face; v_size_vector_t marked_vector; degree_size_vector_t degree_vector; vertex_to_v_size_map_t marked; vertex_to_degree_size_map_t degree; }; template < typename Graph, typename PlanarEmbedding, typename VertexIndexMap, typename EdgeIndexMap, typename AddEdgeVisitor > void make_maximal_planar(Graph& g, PlanarEmbedding embedding, VertexIndexMap vm, EdgeIndexMap em, AddEdgeVisitor& vis) { triangulation_visitor< Graph, VertexIndexMap, AddEdgeVisitor > visitor( g, vm, vis); planar_face_traversal(g, embedding, visitor, em); } template < typename Graph, typename PlanarEmbedding, typename VertexIndexMap, typename EdgeIndexMap > void make_maximal_planar( Graph& g, PlanarEmbedding embedding, VertexIndexMap vm, EdgeIndexMap em) { default_add_edge_visitor vis; make_maximal_planar(g, embedding, vm, em, vis); } template < typename Graph, typename PlanarEmbedding, typename VertexIndexMap > void make_maximal_planar(Graph& g, PlanarEmbedding embedding, VertexIndexMap vm) { make_maximal_planar(g, embedding, vm, get(edge_index, g)); } template < typename Graph, typename PlanarEmbedding > void make_maximal_planar(Graph& g, PlanarEmbedding embedding) { make_maximal_planar(g, embedding, get(vertex_index, g)); } } // namespace boost #endif //__MAKE_MAXIMAL_PLANAR_HPP__ rmat_graph_generator.hpp 0000644 00000045543 15125521275 0011467 0 ustar 00 // Copyright 2004, 2005 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Nick Edmonds // Andrew Lumsdaine #ifndef BOOST_GRAPH_RMAT_GENERATOR_HPP #define BOOST_GRAPH_RMAT_GENERATOR_HPP #include <math.h> #include <iterator> #include <utility> #include <vector> #include <queue> #include <map> #include <boost/shared_ptr.hpp> #include <boost/assert.hpp> #include <boost/random/uniform_int.hpp> #include <boost/random/uniform_01.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/detail/mpi_include.hpp> #include <boost/type_traits/is_base_and_derived.hpp> #include <boost/type_traits/is_same.hpp> // #include <boost/test/floating_point_comparison.hpp> using boost::shared_ptr; using boost::uniform_01; // Returns floor(log_2(n)), and -1 when n is 0 template < typename IntegerType > inline int int_log2(IntegerType n) { int l = 0; while (n > 0) { ++l; n >>= 1; } return l - 1; } struct keep_all_edges { template < typename T > bool operator()(const T&, const T&) { return true; } }; template < typename Distribution, typename ProcessId > struct keep_local_edges { keep_local_edges(const Distribution& distrib, const ProcessId& id) : distrib(distrib), id(id) { } template < typename T > bool operator()(const T& x, const T& y) { return distrib(x) == id || distrib(y) == id; } private: const Distribution& distrib; const ProcessId& id; }; template < typename RandomGenerator, typename T > void generate_permutation_vector( RandomGenerator& gen, std::vector< T >& vertexPermutation, T n) { using boost::uniform_int; vertexPermutation.resize(n); // Generate permutation map of vertex numbers uniform_int< T > rand_vertex(0, n - 1); for (T i = 0; i < n; ++i) vertexPermutation[i] = i; // Can't use std::random_shuffle unless we create another (synchronized) // PRNG for (T i = 0; i < n; ++i) std::swap(vertexPermutation[i], vertexPermutation[rand_vertex(gen)]); } template < typename RandomGenerator, typename T > std::pair< T, T > generate_edge( shared_ptr< uniform_01< RandomGenerator > > prob, T n, unsigned int SCALE, double a, double b, double c, double d) { T u = 0, v = 0; T step = n / 2; for (unsigned int j = 0; j < SCALE; ++j) { double p = (*prob)(); if (p < a) ; else if (p >= a && p < a + b) v += step; else if (p >= a + b && p < a + b + c) u += step; else { // p > a + b + c && p < a + b + c + d u += step; v += step; } step /= 2; // 0.2 and 0.9 are hardcoded in the reference SSCA implementation. // The maximum change in any given value should be less than 10% a *= 0.9 + 0.2 * (*prob)(); b *= 0.9 + 0.2 * (*prob)(); c *= 0.9 + 0.2 * (*prob)(); d *= 0.9 + 0.2 * (*prob)(); double S = a + b + c + d; a /= S; b /= S; c /= S; // d /= S; // Ensure all values add up to 1, regardless of floating point errors d = 1. - a - b - c; } return std::make_pair(u, v); } namespace boost { /* Chakrabarti's R-MAT scale free generator. For all flavors of the R-MAT iterator a+b+c+d must equal 1 and for the unique_rmat_iterator 'm' << 'n^2'. If 'm' is too close to 'n^2' the generator may be unable to generate sufficient unique edges To get a true scale free distribution {a, b, c, d : a > b, a > c, a > d} */ template < typename RandomGenerator, typename Graph > class rmat_iterator { typedef typename graph_traits< Graph >::directed_category directed_category; typedef typename graph_traits< Graph >::vertices_size_type vertices_size_type; typedef typename graph_traits< Graph >::edges_size_type edges_size_type; public: typedef std::input_iterator_tag iterator_category; typedef std::pair< vertices_size_type, vertices_size_type > value_type; typedef const value_type& reference; typedef const value_type* pointer; typedef std::ptrdiff_t difference_type; // Not used // No argument constructor, set to terminating condition rmat_iterator() : gen(), edge(0) {} // Initialize for edge generation rmat_iterator(RandomGenerator& gen, vertices_size_type n, edges_size_type m, double a, double b, double c, double d, bool permute_vertices = true) : gen() , n(n) , a(a) , b(b) , c(c) , d(d) , edge(m) , permute_vertices(permute_vertices) , SCALE(int_log2(n)) { this->gen.reset(new uniform_01< RandomGenerator >(gen)); // BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + // d, 1., 1.e-5)); if (permute_vertices) generate_permutation_vector(gen, vertexPermutation, n); // TODO: Generate the entire adjacency matrix then "Clip and flip" if // undirected graph // Generate the first edge vertices_size_type u, v; boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d); if (permute_vertices) current = std::make_pair(vertexPermutation[u], vertexPermutation[v]); else current = std::make_pair(u, v); --edge; } reference operator*() const { return current; } pointer operator->() const { return ¤t; } rmat_iterator& operator++() { vertices_size_type u, v; boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d); if (permute_vertices) current = std::make_pair(vertexPermutation[u], vertexPermutation[v]); else current = std::make_pair(u, v); --edge; return *this; } rmat_iterator operator++(int) { rmat_iterator temp(*this); ++(*this); return temp; } bool operator==(const rmat_iterator& other) const { return edge == other.edge; } bool operator!=(const rmat_iterator& other) const { return !(*this == other); } private: // Parameters shared_ptr< uniform_01< RandomGenerator > > gen; vertices_size_type n; double a, b, c, d; int edge; bool permute_vertices; int SCALE; // Internal data structures std::vector< vertices_size_type > vertexPermutation; value_type current; }; // Sorted version for CSR template < typename T > struct sort_pair { bool operator()(const std::pair< T, T >& x, const std::pair< T, T >& y) { if (x.first == y.first) return x.second > y.second; else return x.first > y.first; } }; template < typename RandomGenerator, typename Graph, typename EdgePredicate = keep_all_edges > class sorted_rmat_iterator { typedef typename graph_traits< Graph >::directed_category directed_category; typedef typename graph_traits< Graph >::vertices_size_type vertices_size_type; typedef typename graph_traits< Graph >::edges_size_type edges_size_type; public: typedef std::input_iterator_tag iterator_category; typedef std::pair< vertices_size_type, vertices_size_type > value_type; typedef const value_type& reference; typedef const value_type* pointer; typedef std::ptrdiff_t difference_type; // Not used // No argument constructor, set to terminating condition sorted_rmat_iterator() : gen(), values(sort_pair< vertices_size_type >()), done(true) { } // Initialize for edge generation sorted_rmat_iterator(RandomGenerator& gen, vertices_size_type n, edges_size_type m, double a, double b, double c, double d, bool permute_vertices = true, EdgePredicate ep = keep_all_edges()) : gen() , permute_vertices(permute_vertices) , values(sort_pair< vertices_size_type >()) , done(false) { // BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + // d, 1., 1.e-5)); this->gen.reset(new uniform_01< RandomGenerator >(gen)); std::vector< vertices_size_type > vertexPermutation; if (permute_vertices) generate_permutation_vector(gen, vertexPermutation, n); // TODO: "Clip and flip" if undirected graph int SCALE = int_log2(n); for (edges_size_type i = 0; i < m; ++i) { vertices_size_type u, v; boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d); if (permute_vertices) { if (ep(vertexPermutation[u], vertexPermutation[v])) values.push(std::make_pair( vertexPermutation[u], vertexPermutation[v])); } else { if (ep(u, v)) values.push(std::make_pair(u, v)); } } current = values.top(); values.pop(); } reference operator*() const { return current; } pointer operator->() const { return ¤t; } sorted_rmat_iterator& operator++() { if (!values.empty()) { current = values.top(); values.pop(); } else done = true; return *this; } sorted_rmat_iterator operator++(int) { sorted_rmat_iterator temp(*this); ++(*this); return temp; } bool operator==(const sorted_rmat_iterator& other) const { return values.empty() && other.values.empty() && done && other.done; } bool operator!=(const sorted_rmat_iterator& other) const { return !(*this == other); } private: // Parameters shared_ptr< uniform_01< RandomGenerator > > gen; bool permute_vertices; // Internal data structures std::priority_queue< value_type, std::vector< value_type >, sort_pair< vertices_size_type > > values; value_type current; bool done; }; // This version is slow but guarantees unique edges template < typename RandomGenerator, typename Graph, typename EdgePredicate = keep_all_edges > class unique_rmat_iterator { typedef typename graph_traits< Graph >::directed_category directed_category; typedef typename graph_traits< Graph >::vertices_size_type vertices_size_type; typedef typename graph_traits< Graph >::edges_size_type edges_size_type; public: typedef std::input_iterator_tag iterator_category; typedef std::pair< vertices_size_type, vertices_size_type > value_type; typedef const value_type& reference; typedef const value_type* pointer; typedef std::ptrdiff_t difference_type; // Not used // No argument constructor, set to terminating condition unique_rmat_iterator() : gen(), done(true) {} // Initialize for edge generation unique_rmat_iterator(RandomGenerator& gen, vertices_size_type n, edges_size_type m, double a, double b, double c, double d, bool permute_vertices = true, EdgePredicate ep = keep_all_edges()) : gen(), done(false) { // BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + // d, 1., 1.e-5)); this->gen.reset(new uniform_01< RandomGenerator >(gen)); std::vector< vertices_size_type > vertexPermutation; if (permute_vertices) generate_permutation_vector(gen, vertexPermutation, n); int SCALE = int_log2(n); std::map< value_type, bool > edge_map; edges_size_type edges = 0; do { vertices_size_type u, v; boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d); // Lowest vertex number always comes first // (this means we don't have to worry about i->j and j->i being in // the edge list) if (u > v && is_same< directed_category, undirected_tag >::value) std::swap(u, v); if (edge_map.find(std::make_pair(u, v)) == edge_map.end()) { edge_map[std::make_pair(u, v)] = true; if (permute_vertices) { if (ep(vertexPermutation[u], vertexPermutation[v])) values.push_back(std::make_pair( vertexPermutation[u], vertexPermutation[v])); } else { if (ep(u, v)) values.push_back(std::make_pair(u, v)); } edges++; } } while (edges < m); // NGE - Asking for more than n^2 edges will result in an infinite loop // here // Asking for a value too close to n^2 edges may as well current = values.back(); values.pop_back(); } reference operator*() const { return current; } pointer operator->() const { return ¤t; } unique_rmat_iterator& operator++() { if (!values.empty()) { current = values.back(); values.pop_back(); } else done = true; return *this; } unique_rmat_iterator operator++(int) { unique_rmat_iterator temp(*this); ++(*this); return temp; } bool operator==(const unique_rmat_iterator& other) const { return values.empty() && other.values.empty() && done && other.done; } bool operator!=(const unique_rmat_iterator& other) const { return !(*this == other); } private: // Parameters shared_ptr< uniform_01< RandomGenerator > > gen; // Internal data structures std::vector< value_type > values; value_type current; bool done; }; // This version is slow but guarantees unique edges template < typename RandomGenerator, typename Graph, typename EdgePredicate = keep_all_edges > class sorted_unique_rmat_iterator { typedef typename graph_traits< Graph >::directed_category directed_category; typedef typename graph_traits< Graph >::vertices_size_type vertices_size_type; typedef typename graph_traits< Graph >::edges_size_type edges_size_type; public: typedef std::input_iterator_tag iterator_category; typedef std::pair< vertices_size_type, vertices_size_type > value_type; typedef const value_type& reference; typedef const value_type* pointer; typedef std::ptrdiff_t difference_type; // Not used // No argument constructor, set to terminating condition sorted_unique_rmat_iterator() : gen(), values(sort_pair< vertices_size_type >()), done(true) { } // Initialize for edge generation sorted_unique_rmat_iterator(RandomGenerator& gen, vertices_size_type n, edges_size_type m, double a, double b, double c, double d, bool bidirectional = false, bool permute_vertices = true, EdgePredicate ep = keep_all_edges()) : gen() , bidirectional(bidirectional) , values(sort_pair< vertices_size_type >()) , done(false) { // BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + // d, 1., 1.e-5)); this->gen.reset(new uniform_01< RandomGenerator >(gen)); std::vector< vertices_size_type > vertexPermutation; if (permute_vertices) generate_permutation_vector(gen, vertexPermutation, n); int SCALE = int_log2(n); std::map< value_type, bool > edge_map; edges_size_type edges = 0; do { vertices_size_type u, v; boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d); if (bidirectional) { if (edge_map.find(std::make_pair(u, v)) == edge_map.end()) { edge_map[std::make_pair(u, v)] = true; edge_map[std::make_pair(v, u)] = true; if (ep(u, v)) { if (permute_vertices) { values.push(std::make_pair( vertexPermutation[u], vertexPermutation[v])); values.push(std::make_pair( vertexPermutation[v], vertexPermutation[u])); } else { values.push(std::make_pair(u, v)); values.push(std::make_pair(v, u)); } } ++edges; } } else { // Lowest vertex number always comes first // (this means we don't have to worry about i->j and j->i being // in the edge list) if (u > v && is_same< directed_category, undirected_tag >::value) std::swap(u, v); if (edge_map.find(std::make_pair(u, v)) == edge_map.end()) { edge_map[std::make_pair(u, v)] = true; if (permute_vertices) { if (ep(vertexPermutation[u], vertexPermutation[v])) values.push(std::make_pair( vertexPermutation[u], vertexPermutation[v])); } else { if (ep(u, v)) values.push(std::make_pair(u, v)); } ++edges; } } } while (edges < m); // NGE - Asking for more than n^2 edges will result in an infinite loop // here // Asking for a value too close to n^2 edges may as well current = values.top(); values.pop(); } reference operator*() const { return current; } pointer operator->() const { return ¤t; } sorted_unique_rmat_iterator& operator++() { if (!values.empty()) { current = values.top(); values.pop(); } else done = true; return *this; } sorted_unique_rmat_iterator operator++(int) { sorted_unique_rmat_iterator temp(*this); ++(*this); return temp; } bool operator==(const sorted_unique_rmat_iterator& other) const { return values.empty() && other.values.empty() && done && other.done; } bool operator!=(const sorted_unique_rmat_iterator& other) const { return !(*this == other); } private: // Parameters shared_ptr< uniform_01< RandomGenerator > > gen; bool bidirectional; // Internal data structures std::priority_queue< value_type, std::vector< value_type >, sort_pair< vertices_size_type > > values; value_type current; bool done; }; } // end namespace boost #include BOOST_GRAPH_MPI_INCLUDE(< boost / graph / distributed / rmat_graph_generator.hpp >) #endif // BOOST_GRAPH_RMAT_GENERATOR_HPP vf2_sub_graph_iso.hpp 0000644 00000136711 15125521275 0010674 0 ustar 00 //======================================================================= // Copyright (C) 2012 Flavio De Lorenzi (fdlorenzi@gmail.com) // Copyright (C) 2013 Jakob Lykke Andersen, University of Southern Denmark // (jlandersen@imada.sdu.dk) // // The algorithm implemented here is derived from original ideas by // Pasquale Foggia and colaborators. For further information see // e.g. Cordella et al. 2001, 2004. // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // Revision History: // 8 April 2013: Fixed a typo in vf2_print_callback. (Flavio De Lorenzi) #ifndef BOOST_VF2_SUB_GRAPH_ISO_HPP #define BOOST_VF2_SUB_GRAPH_ISO_HPP #include <iostream> #include <iomanip> #include <iterator> #include <vector> #include <utility> #include <boost/assert.hpp> #include <boost/concept/assert.hpp> #include <boost/concept_check.hpp> #include <boost/graph/graph_utility.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/mcgregor_common_subgraphs.hpp> // for always_equivalent #include <boost/graph/named_function_params.hpp> #include <boost/type_traits/has_less.hpp> #include <boost/mpl/int.hpp> #include <boost/range/algorithm/sort.hpp> #include <boost/tuple/tuple.hpp> #include <boost/utility/enable_if.hpp> #ifndef BOOST_GRAPH_ITERATION_MACROS_HPP #define BOOST_ISO_INCLUDED_ITER_MACROS // local macro, see bottom of file #include <boost/graph/iteration_macros.hpp> #endif namespace boost { // Default print_callback template < typename Graph1, typename Graph2 > struct vf2_print_callback { vf2_print_callback(const Graph1& graph1, const Graph2& graph2) : graph1_(graph1), graph2_(graph2) { } template < typename CorrespondenceMap1To2, typename CorrespondenceMap2To1 > bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1) const { // Print (sub)graph isomorphism map BGL_FORALL_VERTICES_T(v, graph1_, Graph1) std::cout << '(' << get(vertex_index_t(), graph1_, v) << ", " << get(vertex_index_t(), graph2_, get(f, v)) << ") "; std::cout << std::endl; return true; } private: const Graph1& graph1_; const Graph2& graph2_; }; namespace detail { // State associated with a single graph (graph_this) template < typename GraphThis, typename GraphOther, typename IndexMapThis, typename IndexMapOther > class base_state { typedef typename graph_traits< GraphThis >::vertex_descriptor vertex_this_type; typedef typename graph_traits< GraphOther >::vertex_descriptor vertex_other_type; typedef typename graph_traits< GraphThis >::vertices_size_type size_type; const GraphThis& graph_this_; const GraphOther& graph_other_; IndexMapThis index_map_this_; IndexMapOther index_map_other_; std::vector< vertex_other_type > core_vec_; typedef iterator_property_map< typename std::vector< vertex_other_type >::iterator, IndexMapThis, vertex_other_type, vertex_other_type& > core_map_type; core_map_type core_; std::vector< size_type > in_vec_, out_vec_; typedef iterator_property_map< typename std::vector< size_type >::iterator, IndexMapThis, size_type, size_type& > in_out_map_type; in_out_map_type in_, out_; size_type term_in_count_, term_out_count_, term_both_count_, core_count_; // Forbidden base_state(const base_state&); base_state& operator=(const base_state&); public: base_state(const GraphThis& graph_this, const GraphOther& graph_other, IndexMapThis index_map_this, IndexMapOther index_map_other) : graph_this_(graph_this) , graph_other_(graph_other) , index_map_this_(index_map_this) , index_map_other_(index_map_other) , core_vec_(num_vertices(graph_this_), graph_traits< GraphOther >::null_vertex()) , core_(core_vec_.begin(), index_map_this_) , in_vec_(num_vertices(graph_this_), 0) , out_vec_(num_vertices(graph_this_), 0) , in_(in_vec_.begin(), index_map_this_) , out_(out_vec_.begin(), index_map_this_) , term_in_count_(0) , term_out_count_(0) , term_both_count_(0) , core_count_(0) { } // Adds a vertex pair to the state of graph graph_this void push( const vertex_this_type& v_this, const vertex_other_type& v_other) { ++core_count_; put(core_, v_this, v_other); if (!get(in_, v_this)) { put(in_, v_this, core_count_); ++term_in_count_; if (get(out_, v_this)) ++term_both_count_; } if (!get(out_, v_this)) { put(out_, v_this, core_count_); ++term_out_count_; if (get(in_, v_this)) ++term_both_count_; } BGL_FORALL_INEDGES_T(v_this, e, graph_this_, GraphThis) { vertex_this_type w = source(e, graph_this_); if (!get(in_, w)) { put(in_, w, core_count_); ++term_in_count_; if (get(out_, w)) ++term_both_count_; } } BGL_FORALL_OUTEDGES_T(v_this, e, graph_this_, GraphThis) { vertex_this_type w = target(e, graph_this_); if (!get(out_, w)) { put(out_, w, core_count_); ++term_out_count_; if (get(in_, w)) ++term_both_count_; } } } // Removes vertex pair from state of graph_this void pop(const vertex_this_type& v_this, const vertex_other_type&) { if (!core_count_) return; if (get(in_, v_this) == core_count_) { put(in_, v_this, 0); --term_in_count_; if (get(out_, v_this)) --term_both_count_; } BGL_FORALL_INEDGES_T(v_this, e, graph_this_, GraphThis) { vertex_this_type w = source(e, graph_this_); if (get(in_, w) == core_count_) { put(in_, w, 0); --term_in_count_; if (get(out_, w)) --term_both_count_; } } if (get(out_, v_this) == core_count_) { put(out_, v_this, 0); --term_out_count_; if (get(in_, v_this)) --term_both_count_; } BGL_FORALL_OUTEDGES_T(v_this, e, graph_this_, GraphThis) { vertex_this_type w = target(e, graph_this_); if (get(out_, w) == core_count_) { put(out_, w, 0); --term_out_count_; if (get(in_, w)) --term_both_count_; } } put(core_, v_this, graph_traits< GraphOther >::null_vertex()); --core_count_; } // Returns true if the in-terminal set is not empty bool term_in() const { return core_count_ < term_in_count_; } // Returns true if vertex belongs to the in-terminal set bool term_in(const vertex_this_type& v) const { return (get(in_, v) > 0) && (get(core_, v) == graph_traits< GraphOther >::null_vertex()); } // Returns true if the out-terminal set is not empty bool term_out() const { return core_count_ < term_out_count_; } // Returns true if vertex belongs to the out-terminal set bool term_out(const vertex_this_type& v) const { return (get(out_, v) > 0) && (get(core_, v) == graph_traits< GraphOther >::null_vertex()); } // Returns true of both (in- and out-terminal) sets are not empty bool term_both() const { return core_count_ < term_both_count_; } // Returns true if vertex belongs to both (in- and out-terminal) sets bool term_both(const vertex_this_type& v) const { return (get(in_, v) > 0) && (get(out_, v) > 0) && (get(core_, v) == graph_traits< GraphOther >::null_vertex()); } // Returns true if vertex belongs to the core map, i.e. it is in the // present mapping bool in_core(const vertex_this_type& v) const { return get(core_, v) != graph_traits< GraphOther >::null_vertex(); } // Returns the number of vertices in the mapping size_type count() const { return core_count_; } // Returns the image (in graph_other) of vertex v (in graph_this) vertex_other_type core(const vertex_this_type& v) const { return get(core_, v); } // Returns the mapping core_map_type get_map() const { return core_; } // Returns the "time" (or depth) when vertex was added to the // in-terminal set size_type in_depth(const vertex_this_type& v) const { return get(in_, v); } // Returns the "time" (or depth) when vertex was added to the // out-terminal set size_type out_depth(const vertex_this_type& v) const { return get(out_, v); } // Returns the terminal set counts boost::tuple< size_type, size_type, size_type > term_set() const { return boost::make_tuple( term_in_count_, term_out_count_, term_both_count_); } }; // Function object that checks whether a valid edge // exists. For multi-graphs matched edges are excluded template < typename Graph, typename Enable = void > struct equivalent_edge_exists { typedef typename boost::graph_traits< Graph >::edge_descriptor edge_type; BOOST_CONCEPT_ASSERT((LessThanComparable< edge_type >)); template < typename EdgePredicate > bool operator()(typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, EdgePredicate is_valid_edge, const Graph& g) { BGL_FORALL_OUTEDGES_T(s, e, g, Graph) { if ((target(e, g) == t) && is_valid_edge(e) && (matched_edges_.find(e) == matched_edges_.end())) { matched_edges_.insert(e); return true; } } return false; } private: std::set< edge_type > matched_edges_; }; template < typename Graph > struct equivalent_edge_exists< Graph, typename boost::disable_if< is_multigraph< Graph > >::type > { template < typename EdgePredicate > bool operator()(typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, EdgePredicate is_valid_edge, const Graph& g) { typename graph_traits< Graph >::edge_descriptor e; bool found; boost::tie(e, found) = edge(s, t, g); if (!found) return false; else if (is_valid_edge(e)) return true; return false; } }; // Generates a predicate for edge e1 given a binary predicate and a // fixed edge e2 template < typename Graph1, typename Graph2, typename EdgeEquivalencePredicate > struct edge1_predicate { edge1_predicate(EdgeEquivalencePredicate edge_comp, typename graph_traits< Graph2 >::edge_descriptor e2) : edge_comp_(edge_comp), e2_(e2) { } bool operator()(typename graph_traits< Graph1 >::edge_descriptor e1) { return edge_comp_(e1, e2_); } EdgeEquivalencePredicate edge_comp_; typename graph_traits< Graph2 >::edge_descriptor e2_; }; // Generates a predicate for edge e2 given given a binary predicate and a // fixed edge e1 template < typename Graph1, typename Graph2, typename EdgeEquivalencePredicate > struct edge2_predicate { edge2_predicate(EdgeEquivalencePredicate edge_comp, typename graph_traits< Graph1 >::edge_descriptor e1) : edge_comp_(edge_comp), e1_(e1) { } bool operator()(typename graph_traits< Graph2 >::edge_descriptor e2) { return edge_comp_(e1_, e2); } EdgeEquivalencePredicate edge_comp_; typename graph_traits< Graph1 >::edge_descriptor e1_; }; enum problem_selector { subgraph_mono, subgraph_iso, isomorphism }; // The actual state associated with both graphs template < typename Graph1, typename Graph2, typename IndexMap1, typename IndexMap2, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate, typename SubGraphIsoMapCallback, problem_selector problem_selection > class state { typedef typename graph_traits< Graph1 >::vertex_descriptor vertex1_type; typedef typename graph_traits< Graph2 >::vertex_descriptor vertex2_type; typedef typename graph_traits< Graph1 >::edge_descriptor edge1_type; typedef typename graph_traits< Graph2 >::edge_descriptor edge2_type; typedef typename graph_traits< Graph1 >::vertices_size_type graph1_size_type; typedef typename graph_traits< Graph2 >::vertices_size_type graph2_size_type; const Graph1& graph1_; const Graph2& graph2_; IndexMap1 index_map1_; EdgeEquivalencePredicate edge_comp_; VertexEquivalencePredicate vertex_comp_; base_state< Graph1, Graph2, IndexMap1, IndexMap2 > state1_; base_state< Graph2, Graph1, IndexMap2, IndexMap1 > state2_; // Three helper functions used in Feasibility and Valid functions to // test terminal set counts when testing for: // - graph sub-graph monomorphism, or inline bool comp_term_sets(graph1_size_type a, graph2_size_type b, boost::mpl::int_< subgraph_mono >) const { return a <= b; } // - graph sub-graph isomorphism, or inline bool comp_term_sets(graph1_size_type a, graph2_size_type b, boost::mpl::int_< subgraph_iso >) const { return a <= b; } // - graph isomorphism inline bool comp_term_sets(graph1_size_type a, graph2_size_type b, boost::mpl::int_< isomorphism >) const { return a == b; } // Forbidden state(const state&); state& operator=(const state&); public: state(const Graph1& graph1, const Graph2& graph2, IndexMap1 index_map1, IndexMap2 index_map2, EdgeEquivalencePredicate edge_comp, VertexEquivalencePredicate vertex_comp) : graph1_(graph1) , graph2_(graph2) , index_map1_(index_map1) , edge_comp_(edge_comp) , vertex_comp_(vertex_comp) , state1_(graph1, graph2, index_map1, index_map2) , state2_(graph2, graph1, index_map2, index_map1) { } // Add vertex pair to the state void push(const vertex1_type& v, const vertex2_type& w) { state1_.push(v, w); state2_.push(w, v); } // Remove vertex pair from state void pop(const vertex1_type& v, const vertex2_type&) { vertex2_type w = state1_.core(v); state1_.pop(v, w); state2_.pop(w, v); } // Checks the feasibility of a new vertex pair bool feasible(const vertex1_type& v_new, const vertex2_type& w_new) { if (!vertex_comp_(v_new, w_new)) return false; // graph1 graph1_size_type term_in1_count = 0, term_out1_count = 0, rest1_count = 0; { equivalent_edge_exists< Graph2 > edge2_exists; BGL_FORALL_INEDGES_T(v_new, e1, graph1_, Graph1) { vertex1_type v = source(e1, graph1_); if (state1_.in_core(v) || (v == v_new)) { vertex2_type w = w_new; if (v != v_new) w = state1_.core(v); if (!edge2_exists(w, w_new, edge2_predicate< Graph1, Graph2, EdgeEquivalencePredicate >(edge_comp_, e1), graph2_)) return false; } else { if (0 < state1_.in_depth(v)) ++term_in1_count; if (0 < state1_.out_depth(v)) ++term_out1_count; if ((state1_.in_depth(v) == 0) && (state1_.out_depth(v) == 0)) ++rest1_count; } } } { equivalent_edge_exists< Graph2 > edge2_exists; BGL_FORALL_OUTEDGES_T(v_new, e1, graph1_, Graph1) { vertex1_type v = target(e1, graph1_); if (state1_.in_core(v) || (v == v_new)) { vertex2_type w = w_new; if (v != v_new) w = state1_.core(v); if (!edge2_exists(w_new, w, edge2_predicate< Graph1, Graph2, EdgeEquivalencePredicate >(edge_comp_, e1), graph2_)) return false; } else { if (0 < state1_.in_depth(v)) ++term_in1_count; if (0 < state1_.out_depth(v)) ++term_out1_count; if ((state1_.in_depth(v) == 0) && (state1_.out_depth(v) == 0)) ++rest1_count; } } } // graph2 graph2_size_type term_out2_count = 0, term_in2_count = 0, rest2_count = 0; { equivalent_edge_exists< Graph1 > edge1_exists; BGL_FORALL_INEDGES_T(w_new, e2, graph2_, Graph2) { vertex2_type w = source(e2, graph2_); if (state2_.in_core(w) || (w == w_new)) { if (problem_selection != subgraph_mono) { vertex1_type v = v_new; if (w != w_new) v = state2_.core(w); if (!edge1_exists(v, v_new, edge1_predicate< Graph1, Graph2, EdgeEquivalencePredicate >( edge_comp_, e2), graph1_)) return false; } } else { if (0 < state2_.in_depth(w)) ++term_in2_count; if (0 < state2_.out_depth(w)) ++term_out2_count; if ((state2_.in_depth(w) == 0) && (state2_.out_depth(w) == 0)) ++rest2_count; } } } { equivalent_edge_exists< Graph1 > edge1_exists; BGL_FORALL_OUTEDGES_T(w_new, e2, graph2_, Graph2) { vertex2_type w = target(e2, graph2_); if (state2_.in_core(w) || (w == w_new)) { if (problem_selection != subgraph_mono) { vertex1_type v = v_new; if (w != w_new) v = state2_.core(w); if (!edge1_exists(v_new, v, edge1_predicate< Graph1, Graph2, EdgeEquivalencePredicate >( edge_comp_, e2), graph1_)) return false; } } else { if (0 < state2_.in_depth(w)) ++term_in2_count; if (0 < state2_.out_depth(w)) ++term_out2_count; if ((state2_.in_depth(w) == 0) && (state2_.out_depth(w) == 0)) ++rest2_count; } } } if (problem_selection != subgraph_mono) { // subgraph_iso and isomorphism return comp_term_sets(term_in1_count, term_in2_count, boost::mpl::int_< problem_selection >()) && comp_term_sets(term_out1_count, term_out2_count, boost::mpl::int_< problem_selection >()) && comp_term_sets(rest1_count, rest2_count, boost::mpl::int_< problem_selection >()); } else { // subgraph_mono return comp_term_sets(term_in1_count, term_in2_count, boost::mpl::int_< problem_selection >()) && comp_term_sets(term_out1_count, term_out2_count, boost::mpl::int_< problem_selection >()) && comp_term_sets( term_in1_count + term_out1_count + rest1_count, term_in2_count + term_out2_count + rest2_count, boost::mpl::int_< problem_selection >()); } } // Returns true if vertex v in graph1 is a possible candidate to // be added to the current state bool possible_candidate1(const vertex1_type& v) const { if (state1_.term_both() && state2_.term_both()) return state1_.term_both(v); else if (state1_.term_out() && state2_.term_out()) return state1_.term_out(v); else if (state1_.term_in() && state2_.term_in()) return state1_.term_in(v); else return !state1_.in_core(v); } // Returns true if vertex w in graph2 is a possible candidate to // be added to the current state bool possible_candidate2(const vertex2_type& w) const { if (state1_.term_both() && state2_.term_both()) return state2_.term_both(w); else if (state1_.term_out() && state2_.term_out()) return state2_.term_out(w); else if (state1_.term_in() && state2_.term_in()) return state2_.term_in(w); else return !state2_.in_core(w); } // Returns true if a mapping was found bool success() const { return state1_.count() == num_vertices(graph1_); } // Returns true if a state is valid bool valid() const { boost::tuple< graph1_size_type, graph1_size_type, graph1_size_type > term1; boost::tuple< graph2_size_type, graph2_size_type, graph2_size_type > term2; term1 = state1_.term_set(); term2 = state2_.term_set(); return comp_term_sets(boost::get< 0 >(term1), boost::get< 0 >(term2), boost::mpl::int_< problem_selection >()) && comp_term_sets(boost::get< 1 >(term1), boost::get< 1 >(term2), boost::mpl::int_< problem_selection >()) && comp_term_sets(boost::get< 2 >(term1), boost::get< 2 >(term2), boost::mpl::int_< problem_selection >()); } // Calls the user_callback with a graph (sub)graph mapping bool call_back(SubGraphIsoMapCallback user_callback) const { return user_callback(state1_.get_map(), state2_.get_map()); } }; // Data structure to keep info used for back tracking during // matching process template < typename Graph1, typename Graph2, typename VertexOrder1 > struct vf2_match_continuation { typename VertexOrder1::const_iterator graph1_verts_iter; typename graph_traits< Graph2 >::vertex_iterator graph2_verts_iter; }; // Non-recursive method that explores state space using a depth-first // search strategy. At each depth possible pairs candidate are compute // and tested for feasibility to extend the mapping. If a complete // mapping is found, the mapping is output to user_callback in the form // of a correspondence map (graph1 to graph2). Returning false from the // user_callback will terminate the search. Function match will return // true if the entire search space was explored. template < typename Graph1, typename Graph2, typename IndexMap1, typename IndexMap2, typename VertexOrder1, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate, typename SubGraphIsoMapCallback, problem_selector problem_selection > bool match(const Graph1& graph1, const Graph2& graph2, SubGraphIsoMapCallback user_callback, const VertexOrder1& vertex_order1, state< Graph1, Graph2, IndexMap1, IndexMap2, EdgeEquivalencePredicate, VertexEquivalencePredicate, SubGraphIsoMapCallback, problem_selection >& s) { typename VertexOrder1::const_iterator graph1_verts_iter; typedef typename graph_traits< Graph2 >::vertex_iterator vertex2_iterator_type; vertex2_iterator_type graph2_verts_iter, graph2_verts_iter_end; typedef vf2_match_continuation< Graph1, Graph2, VertexOrder1 > match_continuation_type; std::vector< match_continuation_type > k; bool found_match = false; recur: if (s.success()) { if (!s.call_back(user_callback)) return true; found_match = true; goto back_track; } if (!s.valid()) goto back_track; graph1_verts_iter = vertex_order1.begin(); while (graph1_verts_iter != vertex_order1.end() && !s.possible_candidate1(*graph1_verts_iter)) { ++graph1_verts_iter; } boost::tie(graph2_verts_iter, graph2_verts_iter_end) = vertices(graph2); while (graph2_verts_iter != graph2_verts_iter_end) { if (s.possible_candidate2(*graph2_verts_iter)) { if (s.feasible(*graph1_verts_iter, *graph2_verts_iter)) { match_continuation_type kk; kk.graph1_verts_iter = graph1_verts_iter; kk.graph2_verts_iter = graph2_verts_iter; k.push_back(kk); s.push(*graph1_verts_iter, *graph2_verts_iter); goto recur; } } graph2_loop: ++graph2_verts_iter; } back_track: if (k.empty()) return found_match; const match_continuation_type kk = k.back(); graph1_verts_iter = kk.graph1_verts_iter; graph2_verts_iter = kk.graph2_verts_iter; k.pop_back(); s.pop(*graph1_verts_iter, *graph2_verts_iter); goto graph2_loop; } // Used to sort nodes by in/out degrees template < typename Graph > struct vertex_in_out_degree_cmp { typedef typename graph_traits< Graph >::vertex_descriptor vertex_type; vertex_in_out_degree_cmp(const Graph& graph) : graph_(graph) {} bool operator()(const vertex_type& v, const vertex_type& w) const { // lexicographical comparison return std::make_pair(in_degree(v, graph_), out_degree(v, graph_)) < std::make_pair(in_degree(w, graph_), out_degree(w, graph_)); } const Graph& graph_; }; // Used to sort nodes by multiplicity of in/out degrees template < typename Graph, typename FrequencyMap > struct vertex_frequency_degree_cmp { typedef typename graph_traits< Graph >::vertex_descriptor vertex_type; vertex_frequency_degree_cmp(const Graph& graph, FrequencyMap freq) : graph_(graph), freq_(freq) { } bool operator()(const vertex_type& v, const vertex_type& w) const { // lexicographical comparison return std::make_pair( freq_[v], in_degree(v, graph_) + out_degree(v, graph_)) < std::make_pair( freq_[w], in_degree(w, graph_) + out_degree(w, graph_)); } const Graph& graph_; FrequencyMap freq_; }; // Sorts vertices of a graph by multiplicity of in/out degrees template < typename Graph, typename IndexMap, typename VertexOrder > void sort_vertices( const Graph& graph, IndexMap index_map, VertexOrder& order) { typedef typename graph_traits< Graph >::vertices_size_type size_type; boost::range::sort(order, vertex_in_out_degree_cmp< Graph >(graph)); std::vector< size_type > freq_vec(num_vertices(graph), 0); typedef iterator_property_map< typename std::vector< size_type >::iterator, IndexMap, size_type, size_type& > frequency_map_type; frequency_map_type freq = make_iterator_property_map(freq_vec.begin(), index_map); typedef typename VertexOrder::iterator order_iterator; for (order_iterator order_iter = order.begin(); order_iter != order.end();) { size_type count = 0; for (order_iterator count_iter = order_iter; (count_iter != order.end()) && (in_degree(*order_iter, graph) == in_degree(*count_iter, graph)) && (out_degree(*order_iter, graph) == out_degree(*count_iter, graph)); ++count_iter) ++count; for (size_type i = 0; i < count; ++i) { freq[*order_iter] = count; ++order_iter; } } boost::range::sort(order, vertex_frequency_degree_cmp< Graph, frequency_map_type >( graph, freq)); } // Enumerates all graph sub-graph mono-/iso-morphism mappings between graphs // graph_small and graph_large. Continues until user_callback returns true // or the search space has been fully explored. template < problem_selector problem_selection, typename GraphSmall, typename GraphLarge, typename IndexMapSmall, typename IndexMapLarge, typename VertexOrderSmall, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate, typename SubGraphIsoMapCallback > bool vf2_subgraph_morphism(const GraphSmall& graph_small, const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback, IndexMapSmall index_map_small, IndexMapLarge index_map_large, const VertexOrderSmall& vertex_order_small, EdgeEquivalencePredicate edge_comp, VertexEquivalencePredicate vertex_comp) { // Graph requirements BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< GraphSmall >)); BOOST_CONCEPT_ASSERT((VertexListGraphConcept< GraphSmall >)); BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< GraphSmall >)); BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< GraphSmall >)); BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< GraphLarge >)); BOOST_CONCEPT_ASSERT((VertexListGraphConcept< GraphLarge >)); BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< GraphLarge >)); BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< GraphLarge >)); typedef typename graph_traits< GraphSmall >::vertex_descriptor vertex_small_type; typedef typename graph_traits< GraphLarge >::vertex_descriptor vertex_large_type; typedef typename graph_traits< GraphSmall >::vertices_size_type size_type_small; typedef typename graph_traits< GraphLarge >::vertices_size_type size_type_large; // Property map requirements BOOST_CONCEPT_ASSERT( (ReadablePropertyMapConcept< IndexMapSmall, vertex_small_type >)); typedef typename property_traits< IndexMapSmall >::value_type IndexMapSmallValue; BOOST_STATIC_ASSERT( (is_convertible< IndexMapSmallValue, size_type_small >::value)); BOOST_CONCEPT_ASSERT( (ReadablePropertyMapConcept< IndexMapLarge, vertex_large_type >)); typedef typename property_traits< IndexMapLarge >::value_type IndexMapLargeValue; BOOST_STATIC_ASSERT( (is_convertible< IndexMapLargeValue, size_type_large >::value)); // Edge & vertex requirements typedef typename graph_traits< GraphSmall >::edge_descriptor edge_small_type; typedef typename graph_traits< GraphLarge >::edge_descriptor edge_large_type; BOOST_CONCEPT_ASSERT((BinaryPredicateConcept< EdgeEquivalencePredicate, edge_small_type, edge_large_type >)); BOOST_CONCEPT_ASSERT( (BinaryPredicateConcept< VertexEquivalencePredicate, vertex_small_type, vertex_large_type >)); // Vertex order requirements BOOST_CONCEPT_ASSERT((ContainerConcept< VertexOrderSmall >)); typedef typename VertexOrderSmall::value_type order_value_type; BOOST_STATIC_ASSERT( (is_same< vertex_small_type, order_value_type >::value)); BOOST_ASSERT(num_vertices(graph_small) == vertex_order_small.size()); if (num_vertices(graph_small) > num_vertices(graph_large)) return false; typename graph_traits< GraphSmall >::edges_size_type num_edges_small = num_edges(graph_small); typename graph_traits< GraphLarge >::edges_size_type num_edges_large = num_edges(graph_large); // Double the number of edges for undirected graphs: each edge counts as // in-edge and out-edge if (is_undirected(graph_small)) num_edges_small *= 2; if (is_undirected(graph_large)) num_edges_large *= 2; if (num_edges_small > num_edges_large) return false; detail::state< GraphSmall, GraphLarge, IndexMapSmall, IndexMapLarge, EdgeEquivalencePredicate, VertexEquivalencePredicate, SubGraphIsoMapCallback, problem_selection > s(graph_small, graph_large, index_map_small, index_map_large, edge_comp, vertex_comp); return detail::match( graph_small, graph_large, user_callback, vertex_order_small, s); } } // namespace detail // Returns vertex order (vertices sorted by multiplicity of in/out degrees) template < typename Graph > std::vector< typename graph_traits< Graph >::vertex_descriptor > vertex_order_by_mult(const Graph& graph) { std::vector< typename graph_traits< Graph >::vertex_descriptor > vertex_order; std::copy(vertices(graph).first, vertices(graph).second, std::back_inserter(vertex_order)); detail::sort_vertices(graph, get(vertex_index, graph), vertex_order); return vertex_order; } // Enumerates all graph sub-graph monomorphism mappings between graphs // graph_small and graph_large. Continues until user_callback returns true or // the search space has been fully explored. template < typename GraphSmall, typename GraphLarge, typename IndexMapSmall, typename IndexMapLarge, typename VertexOrderSmall, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate, typename SubGraphIsoMapCallback > bool vf2_subgraph_mono(const GraphSmall& graph_small, const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback, IndexMapSmall index_map_small, IndexMapLarge index_map_large, const VertexOrderSmall& vertex_order_small, EdgeEquivalencePredicate edge_comp, VertexEquivalencePredicate vertex_comp) { return detail::vf2_subgraph_morphism< detail::subgraph_mono >(graph_small, graph_large, user_callback, index_map_small, index_map_large, vertex_order_small, edge_comp, vertex_comp); } // All default interface for vf2_subgraph_iso template < typename GraphSmall, typename GraphLarge, typename SubGraphIsoMapCallback > bool vf2_subgraph_mono(const GraphSmall& graph_small, const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback) { return vf2_subgraph_mono(graph_small, graph_large, user_callback, get(vertex_index, graph_small), get(vertex_index, graph_large), vertex_order_by_mult(graph_small), always_equivalent(), always_equivalent()); } // Named parameter interface of vf2_subgraph_iso template < typename GraphSmall, typename GraphLarge, typename VertexOrderSmall, typename SubGraphIsoMapCallback, typename Param, typename Tag, typename Rest > bool vf2_subgraph_mono(const GraphSmall& graph_small, const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback, const VertexOrderSmall& vertex_order_small, const bgl_named_params< Param, Tag, Rest >& params) { return vf2_subgraph_mono(graph_small, graph_large, user_callback, choose_const_pmap( get_param(params, vertex_index1), graph_small, vertex_index), choose_const_pmap( get_param(params, vertex_index2), graph_large, vertex_index), vertex_order_small, choose_param( get_param(params, edges_equivalent_t()), always_equivalent()), choose_param( get_param(params, vertices_equivalent_t()), always_equivalent())); } // Enumerates all graph sub-graph isomorphism mappings between graphs // graph_small and graph_large. Continues until user_callback returns true or // the search space has been fully explored. template < typename GraphSmall, typename GraphLarge, typename IndexMapSmall, typename IndexMapLarge, typename VertexOrderSmall, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate, typename SubGraphIsoMapCallback > bool vf2_subgraph_iso(const GraphSmall& graph_small, const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback, IndexMapSmall index_map_small, IndexMapLarge index_map_large, const VertexOrderSmall& vertex_order_small, EdgeEquivalencePredicate edge_comp, VertexEquivalencePredicate vertex_comp) { return detail::vf2_subgraph_morphism< detail::subgraph_iso >(graph_small, graph_large, user_callback, index_map_small, index_map_large, vertex_order_small, edge_comp, vertex_comp); } // All default interface for vf2_subgraph_iso template < typename GraphSmall, typename GraphLarge, typename SubGraphIsoMapCallback > bool vf2_subgraph_iso(const GraphSmall& graph_small, const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback) { return vf2_subgraph_iso(graph_small, graph_large, user_callback, get(vertex_index, graph_small), get(vertex_index, graph_large), vertex_order_by_mult(graph_small), always_equivalent(), always_equivalent()); } // Named parameter interface of vf2_subgraph_iso template < typename GraphSmall, typename GraphLarge, typename VertexOrderSmall, typename SubGraphIsoMapCallback, typename Param, typename Tag, typename Rest > bool vf2_subgraph_iso(const GraphSmall& graph_small, const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback, const VertexOrderSmall& vertex_order_small, const bgl_named_params< Param, Tag, Rest >& params) { return vf2_subgraph_iso(graph_small, graph_large, user_callback, choose_const_pmap( get_param(params, vertex_index1), graph_small, vertex_index), choose_const_pmap( get_param(params, vertex_index2), graph_large, vertex_index), vertex_order_small, choose_param( get_param(params, edges_equivalent_t()), always_equivalent()), choose_param( get_param(params, vertices_equivalent_t()), always_equivalent())); } // Enumerates all isomorphism mappings between graphs graph1_ and graph2_. // Continues until user_callback returns true or the search space has been // fully explored. template < typename Graph1, typename Graph2, typename IndexMap1, typename IndexMap2, typename VertexOrder1, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate, typename GraphIsoMapCallback > bool vf2_graph_iso(const Graph1& graph1, const Graph2& graph2, GraphIsoMapCallback user_callback, IndexMap1 index_map1, IndexMap2 index_map2, const VertexOrder1& vertex_order1, EdgeEquivalencePredicate edge_comp, VertexEquivalencePredicate vertex_comp) { // Graph requirements BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph1 >)); BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph1 >)); BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph1 >)); BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< Graph1 >)); BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph2 >)); BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph2 >)); BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph2 >)); BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< Graph2 >)); typedef typename graph_traits< Graph1 >::vertex_descriptor vertex1_type; typedef typename graph_traits< Graph2 >::vertex_descriptor vertex2_type; typedef typename graph_traits< Graph1 >::vertices_size_type size_type1; typedef typename graph_traits< Graph2 >::vertices_size_type size_type2; // Property map requirements BOOST_CONCEPT_ASSERT( (ReadablePropertyMapConcept< IndexMap1, vertex1_type >)); typedef typename property_traits< IndexMap1 >::value_type IndexMap1Value; BOOST_STATIC_ASSERT((is_convertible< IndexMap1Value, size_type1 >::value)); BOOST_CONCEPT_ASSERT( (ReadablePropertyMapConcept< IndexMap2, vertex2_type >)); typedef typename property_traits< IndexMap2 >::value_type IndexMap2Value; BOOST_STATIC_ASSERT((is_convertible< IndexMap2Value, size_type2 >::value)); // Edge & vertex requirements typedef typename graph_traits< Graph1 >::edge_descriptor edge1_type; typedef typename graph_traits< Graph2 >::edge_descriptor edge2_type; BOOST_CONCEPT_ASSERT((BinaryPredicateConcept< EdgeEquivalencePredicate, edge1_type, edge2_type >)); BOOST_CONCEPT_ASSERT((BinaryPredicateConcept< VertexEquivalencePredicate, vertex1_type, vertex2_type >)); // Vertex order requirements BOOST_CONCEPT_ASSERT((ContainerConcept< VertexOrder1 >)); typedef typename VertexOrder1::value_type order_value_type; BOOST_STATIC_ASSERT((is_same< vertex1_type, order_value_type >::value)); BOOST_ASSERT(num_vertices(graph1) == vertex_order1.size()); if (num_vertices(graph1) != num_vertices(graph2)) return false; typename graph_traits< Graph1 >::edges_size_type num_edges1 = num_edges(graph1); typename graph_traits< Graph2 >::edges_size_type num_edges2 = num_edges(graph2); // Double the number of edges for undirected graphs: each edge counts as // in-edge and out-edge if (is_undirected(graph1)) num_edges1 *= 2; if (is_undirected(graph2)) num_edges2 *= 2; if (num_edges1 != num_edges2) return false; detail::state< Graph1, Graph2, IndexMap1, IndexMap2, EdgeEquivalencePredicate, VertexEquivalencePredicate, GraphIsoMapCallback, detail::isomorphism > s(graph1, graph2, index_map1, index_map2, edge_comp, vertex_comp); return detail::match(graph1, graph2, user_callback, vertex_order1, s); } // All default interface for vf2_graph_iso template < typename Graph1, typename Graph2, typename GraphIsoMapCallback > bool vf2_graph_iso(const Graph1& graph1, const Graph2& graph2, GraphIsoMapCallback user_callback) { return vf2_graph_iso(graph1, graph2, user_callback, get(vertex_index, graph1), get(vertex_index, graph2), vertex_order_by_mult(graph1), always_equivalent(), always_equivalent()); } // Named parameter interface of vf2_graph_iso template < typename Graph1, typename Graph2, typename VertexOrder1, typename GraphIsoMapCallback, typename Param, typename Tag, typename Rest > bool vf2_graph_iso(const Graph1& graph1, const Graph2& graph2, GraphIsoMapCallback user_callback, const VertexOrder1& vertex_order1, const bgl_named_params< Param, Tag, Rest >& params) { return vf2_graph_iso(graph1, graph2, user_callback, choose_const_pmap( get_param(params, vertex_index1), graph1, vertex_index), choose_const_pmap( get_param(params, vertex_index2), graph2, vertex_index), vertex_order1, choose_param( get_param(params, edges_equivalent_t()), always_equivalent()), choose_param( get_param(params, vertices_equivalent_t()), always_equivalent())); } // Verifies a graph (sub)graph isomorphism map template < typename Graph1, typename Graph2, typename CorresponenceMap1To2, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate > inline bool verify_vf2_subgraph_iso(const Graph1& graph1, const Graph2& graph2, const CorresponenceMap1To2 f, EdgeEquivalencePredicate edge_comp, VertexEquivalencePredicate vertex_comp) { BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph1 >)); BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< Graph2 >)); detail::equivalent_edge_exists< Graph2 > edge2_exists; BGL_FORALL_EDGES_T(e1, graph1, Graph1) { typename graph_traits< Graph1 >::vertex_descriptor s1, t1; typename graph_traits< Graph2 >::vertex_descriptor s2, t2; s1 = source(e1, graph1); t1 = target(e1, graph1); s2 = get(f, s1); t2 = get(f, t1); if (!vertex_comp(s1, s2) || !vertex_comp(t1, t2)) return false; typename graph_traits< Graph2 >::edge_descriptor e2; if (!edge2_exists(s2, t2, detail::edge2_predicate< Graph1, Graph2, EdgeEquivalencePredicate >(edge_comp, e1), graph2)) return false; } return true; } // Variant of verify_subgraph_iso with all default parameters template < typename Graph1, typename Graph2, typename CorresponenceMap1To2 > inline bool verify_vf2_subgraph_iso( const Graph1& graph1, const Graph2& graph2, const CorresponenceMap1To2 f) { return verify_vf2_subgraph_iso( graph1, graph2, f, always_equivalent(), always_equivalent()); } } // namespace boost #ifdef BOOST_ISO_INCLUDED_ITER_MACROS #undef BOOST_ISO_INCLUDED_ITER_MACROS #include <boost/graph/iteration_macros_undef.hpp> #endif #endif // BOOST_VF2_SUB_GRAPH_ISO_HPP bron_kerbosch_all_cliques.hpp 0000644 00000026730 15125521275 0012467 0 ustar 00 // (C) Copyright 2007-2009 Andrew Sutton // // 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_CLIQUE_HPP #define BOOST_GRAPH_CLIQUE_HPP #include <vector> #include <deque> #include <boost/config.hpp> #include <boost/concept/assert.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/lookup_edge.hpp> #include <boost/concept/detail/concept_def.hpp> namespace boost { namespace concepts { BOOST_concept(CliqueVisitor, (Visitor)(Clique)(Graph)) { BOOST_CONCEPT_USAGE(CliqueVisitor) { vis.clique(k, g); } private: Visitor vis; Graph g; Clique k; }; } /* namespace concepts */ using concepts::CliqueVisitorConcept; } /* namespace boost */ #include <boost/concept/detail/concept_undef.hpp> namespace boost { // The algorithm implemented in this paper is based on the so-called // Algorithm 457, published as: // // @article{362367, // author = {Coen Bron and Joep Kerbosch}, // title = {Algorithm 457: finding all cliques of an undirected graph}, // journal = {Communications of the ACM}, // volume = {16}, // number = {9}, // year = {1973}, // issn = {0001-0782}, // pages = {575--577}, // doi = {http://doi.acm.org/10.1145/362342.362367}, // publisher = {ACM Press}, // address = {New York, NY, USA}, // } // // Sort of. This implementation is adapted from the 1st version of the // algorithm and does not implement the candidate selection optimization // described as published - it could, it just doesn't yet. // // The algorithm is given as proportional to (3.14)^(n/3) power. This is // not the same as O(...), but based on time measures and approximation. // // Unfortunately, this implementation may be less efficient on non- // AdjacencyMatrix modeled graphs due to the non-constant implementation // of the edge(u,v,g) functions. // // TODO: It might be worthwhile to provide functionality for passing // a connectivity matrix to improve the efficiency of those lookups // when needed. This could simply be passed as a BooleanMatrix // s.t. edge(u,v,B) returns true or false. This could easily be // abstracted for adjacency matricies. // // The following paper is interesting for a number of reasons. First, // it lists a number of other such algorithms and second, it describes // a new algorithm (that does not appear to require the edge(u,v,g) // function and appears fairly efficient. It is probably worth investigating. // // @article{DBLP:journals/tcs/TomitaTT06, // author = {Etsuji Tomita and Akira Tanaka and Haruhisa Takahashi}, // title = {The worst-case time complexity for generating all maximal // cliques and computational experiments}, journal = {Theor. Comput. // Sci.}, volume = {363}, number = {1}, year = {2006}, pages = {28-42} // ee = {https://doi.org/10.1016/j.tcs.2006.06.015} // } /** * The default clique_visitor supplies an empty visitation function. */ struct clique_visitor { template < typename VertexSet, typename Graph > void clique(const VertexSet&, Graph&) { } }; /** * The max_clique_visitor records the size of the maximum clique (but not the * clique itself). */ struct max_clique_visitor { max_clique_visitor(std::size_t& max) : maximum(max) {} template < typename Clique, typename Graph > inline void clique(const Clique& p, const Graph& g) { BOOST_USING_STD_MAX(); maximum = max BOOST_PREVENT_MACRO_SUBSTITUTION(maximum, p.size()); } std::size_t& maximum; }; inline max_clique_visitor find_max_clique(std::size_t& max) { return max_clique_visitor(max); } namespace detail { template < typename Graph > inline bool is_connected_to_clique(const Graph& g, typename graph_traits< Graph >::vertex_descriptor u, typename graph_traits< Graph >::vertex_descriptor v, typename graph_traits< Graph >::undirected_category) { return lookup_edge(u, v, g).second; } template < typename Graph > inline bool is_connected_to_clique(const Graph& g, typename graph_traits< Graph >::vertex_descriptor u, typename graph_traits< Graph >::vertex_descriptor v, typename graph_traits< Graph >::directed_category) { // Note that this could alternate between using an || to determine // full connectivity. I believe that this should produce strongly // connected components. Note that using && instead of || will // change the results to a fully connected subgraph (i.e., symmetric // edges between all vertices s.t., if a->b, then b->a. return lookup_edge(u, v, g).second && lookup_edge(v, u, g).second; } template < typename Graph, typename Container > inline void filter_unconnected_vertices(const Graph& g, typename graph_traits< Graph >::vertex_descriptor v, const Container& in, Container& out) { BOOST_CONCEPT_ASSERT((GraphConcept< Graph >)); typename graph_traits< Graph >::directed_category cat; typename Container::const_iterator i, end = in.end(); for (i = in.begin(); i != end; ++i) { if (is_connected_to_clique(g, v, *i, cat)) { out.push_back(*i); } } } template < typename Graph, typename Clique, // compsub type typename Container, // candidates/not type typename Visitor > void extend_clique(const Graph& g, Clique& clique, Container& cands, Container& nots, Visitor vis, std::size_t min) { BOOST_CONCEPT_ASSERT((GraphConcept< Graph >)); BOOST_CONCEPT_ASSERT((CliqueVisitorConcept< Visitor, Clique, Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; // Is there vertex in nots that is connected to all vertices // in the candidate set? If so, no clique can ever be found. // This could be broken out into a separate function. { typename Container::iterator ni, nend = nots.end(); typename Container::iterator ci, cend = cands.end(); for (ni = nots.begin(); ni != nend; ++ni) { for (ci = cands.begin(); ci != cend; ++ci) { // if we don't find an edge, then we're okay. if (!lookup_edge(*ni, *ci, g).second) break; } // if we iterated all the way to the end, then *ni // is connected to all *ci if (ci == cend) break; } // if we broke early, we found *ni connected to all *ci if (ni != nend) return; } // TODO: the original algorithm 457 describes an alternative // (albeit really complicated) mechanism for selecting candidates. // The given optimizaiton seeks to bring about the above // condition sooner (i.e., there is a vertex in the not set // that is connected to all candidates). unfortunately, the // method they give for doing this is fairly unclear. // basically, for every vertex in not, we should know how many // vertices it is disconnected from in the candidate set. if // we fix some vertex in the not set, then we want to keep // choosing vertices that are not connected to that fixed vertex. // apparently, by selecting fix point with the minimum number // of disconnections (i.e., the maximum number of connections // within the candidate set), then the previous condition wil // be reached sooner. // there's some other stuff about using the number of disconnects // as a counter, but i'm jot really sure i followed it. // TODO: If we min-sized cliques to visit, then theoretically, we // should be able to stop recursing if the clique falls below that // size - maybe? // otherwise, iterate over candidates and and test // for maxmimal cliquiness. typename Container::iterator i, j; for (i = cands.begin(); i != cands.end();) { Vertex candidate = *i; // add the candidate to the clique (keeping the iterator!) // typename Clique::iterator ci = clique.insert(clique.end(), // candidate); clique.push_back(candidate); // remove it from the candidate set i = cands.erase(i); // build new candidate and not sets by removing all vertices // that are not connected to the current candidate vertex. // these actually invert the operation, adding them to the new // sets if the vertices are connected. its semantically the same. Container new_cands, new_nots; filter_unconnected_vertices(g, candidate, cands, new_cands); filter_unconnected_vertices(g, candidate, nots, new_nots); if (new_cands.empty() && new_nots.empty()) { // our current clique is maximal since there's nothing // that's connected that we haven't already visited. If // the clique is below our radar, then we won't visit it. if (clique.size() >= min) { vis.clique(clique, g); } } else { // recurse to explore the new candidates extend_clique(g, clique, new_cands, new_nots, vis, min); } // we're done with this vertex, so we need to move it // to the nots, and remove the candidate from the clique. nots.push_back(candidate); clique.pop_back(); } } } /* namespace detail */ template < typename Graph, typename Visitor > inline void bron_kerbosch_all_cliques( const Graph& g, Visitor vis, std::size_t min) { BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >)); BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); BOOST_CONCEPT_ASSERT( (AdjacencyMatrixConcept< Graph >)); // Structural requirement only typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::vertex_iterator VertexIterator; typedef std::vector< Vertex > VertexSet; typedef std::deque< Vertex > Clique; BOOST_CONCEPT_ASSERT((CliqueVisitorConcept< Visitor, Clique, Graph >)); // NOTE: We're using a deque to implement the clique, because it provides // constant inserts and removals at the end and also a constant size. VertexIterator i, end; boost::tie(i, end) = vertices(g); VertexSet cands(i, end); // start with all vertices as candidates VertexSet nots; // start with no vertices visited Clique clique; // the first clique is an empty vertex set detail::extend_clique(g, clique, cands, nots, vis, min); } // NOTE: By default the minimum number of vertices per clique is set at 2 // because singleton cliques aren't really very interesting. template < typename Graph, typename Visitor > inline void bron_kerbosch_all_cliques(const Graph& g, Visitor vis) { bron_kerbosch_all_cliques(g, vis, 2); } template < typename Graph > inline std::size_t bron_kerbosch_clique_number(const Graph& g) { std::size_t ret = 0; bron_kerbosch_all_cliques(g, find_max_clique(ret)); return ret; } } /* namespace boost */ #endif vector_as_graph.hpp 0000644 00000024352 15125521275 0010436 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Copyright 2006 The Trustees of Indiana University. // Copyright (C) 2001 Vladimir Prus <ghost@cs.msu.su> // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Douglas Gregor // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // The mutating functions (add_edge, etc.) were added by Vladimir Prus. #ifndef BOOST_VECTOR_AS_GRAPH_HPP #define BOOST_VECTOR_AS_GRAPH_HPP #include <cassert> #include <utility> #include <vector> #include <cstddef> #include <iterator> #include <boost/iterator/counting_iterator.hpp> #include <boost/range/irange.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/properties.hpp> #include <algorithm> /* This module implements the VertexListGraph concept using a std::vector as the "back-bone" of the graph (the vector *is* the graph object). The edge-lists type of the graph is templated, so the user can choose any STL container, so long as the value_type of the container is convertible to the size_type of the vector. For now any graph properties must be stored seperately. This module requires the C++ compiler to support partial specialization for the graph_traits class, so this is not portable to VC++. */ namespace boost { namespace detail { template < class EdgeList > struct val_out_edge_ret; template < class EdgeList > struct val_out_edge_iter; template < class EdgeList > struct val_edge; } } namespace boost { struct vector_as_graph_traversal_tag : public vertex_list_graph_tag, public adjacency_graph_tag, public incidence_graph_tag { }; template < class EdgeList > struct graph_traits< std::vector< EdgeList > > { typedef typename EdgeList::value_type V; typedef V vertex_descriptor; typedef typename detail::val_edge< EdgeList >::type edge_descriptor; typedef typename EdgeList::const_iterator adjacency_iterator; typedef typename detail::val_out_edge_iter< EdgeList >::type out_edge_iterator; typedef void in_edge_iterator; typedef void edge_iterator; typedef counting_iterator< V > vertex_iterator; typedef directed_tag directed_category; typedef allow_parallel_edge_tag edge_parallel_category; typedef vector_as_graph_traversal_tag traversal_category; typedef typename std::vector< EdgeList >::size_type vertices_size_type; typedef void edges_size_type; typedef typename EdgeList::size_type degree_size_type; static V null_vertex() { return V(-1); } }; template < class EdgeList > struct edge_property_type< std::vector< EdgeList > > { typedef void type; }; template < class EdgeList > struct vertex_property_type< std::vector< EdgeList > > { typedef void type; }; template < class EdgeList > struct graph_property_type< std::vector< EdgeList > > { typedef void type; }; } namespace boost { namespace detail { // "val" is short for Vector Adjacency List template < class EdgeList > struct val_edge { typedef typename EdgeList::value_type V; typedef std::pair< V, V > type; }; // need rewrite this using boost::iterator_adaptor template < class V, class Iter > class val_out_edge_iterator { typedef val_out_edge_iterator self; typedef std::pair< V, V > Edge; public: typedef std::input_iterator_tag iterator_category; typedef std::pair< V, V > value_type; typedef std::ptrdiff_t difference_type; typedef std::pair< V, V >* pointer; typedef const std::pair< V, V > reference; val_out_edge_iterator() {} val_out_edge_iterator(V s, Iter i) : _source(s), _iter(i) {} Edge operator*() const { return Edge(_source, *_iter); } self& operator++() { ++_iter; return *this; } self operator++(int) { self t = *this; ++_iter; return t; } bool operator==(const self& x) const { return _iter == x._iter; } bool operator!=(const self& x) const { return _iter != x._iter; } protected: V _source; Iter _iter; }; template < class EdgeList > struct val_out_edge_iter { typedef typename EdgeList::value_type V; typedef typename EdgeList::const_iterator Iter; typedef val_out_edge_iterator< V, Iter > type; }; template < class EdgeList > struct val_out_edge_ret { typedef typename val_out_edge_iter< EdgeList >::type IncIter; typedef std::pair< IncIter, IncIter > type; }; } // namesapce detail template < class EdgeList, class Alloc > typename detail::val_out_edge_ret< EdgeList >::type out_edges( typename EdgeList::value_type v, const std::vector< EdgeList, Alloc >& g) { typedef typename detail::val_out_edge_iter< EdgeList >::type Iter; typedef typename detail::val_out_edge_ret< EdgeList >::type return_type; return return_type(Iter(v, g[v].begin()), Iter(v, g[v].end())); } template < class EdgeList, class Alloc > typename EdgeList::size_type out_degree( typename EdgeList::value_type v, const std::vector< EdgeList, Alloc >& g) { return g[v].size(); } template < class EdgeList, class Alloc > std::pair< typename EdgeList::const_iterator, typename EdgeList::const_iterator > adjacent_vertices( typename EdgeList::value_type v, const std::vector< EdgeList, Alloc >& g) { return std::make_pair(g[v].begin(), g[v].end()); } // source() and target() already provided for pairs in graph_traits.hpp template < class EdgeList, class Alloc > std::pair< boost::counting_iterator< typename EdgeList::value_type >, boost::counting_iterator< typename EdgeList::value_type > > vertices(const std::vector< EdgeList, Alloc >& v) { typedef boost::counting_iterator< typename EdgeList::value_type > Iter; return std::make_pair(Iter(0), Iter(v.size())); } template < class EdgeList, class Alloc > typename std::vector< EdgeList, Alloc >::size_type num_vertices( const std::vector< EdgeList, Alloc >& v) { return v.size(); } template < class EdgeList, class Allocator > typename std::pair< typename detail::val_edge< EdgeList >::type, bool > add_edge(typename EdgeList::value_type u, typename EdgeList::value_type v, std::vector< EdgeList, Allocator >& g) { typedef typename detail::val_edge< EdgeList >::type edge_type; g[u].insert(g[u].end(), v); return std::make_pair(edge_type(u, v), true); } template < class EdgeList, class Allocator > typename std::pair< typename detail::val_edge< EdgeList >::type, bool > edge( typename EdgeList::value_type u, typename EdgeList::value_type v, std::vector< EdgeList, Allocator >& g) { typedef typename detail::val_edge< EdgeList >::type edge_type; typename EdgeList::iterator i = g[u].begin(), end = g[u].end(); for (; i != end; ++i) if (*i == v) return std::make_pair(edge_type(u, v), true); return std::make_pair(edge_type(), false); } template < class EdgeList, class Allocator > void remove_edge(typename EdgeList::value_type u, typename EdgeList::value_type v, std::vector< EdgeList, Allocator >& g) { typename EdgeList::iterator i = std::remove(g[u].begin(), g[u].end(), v); if (i != g[u].end()) g[u].erase(i, g[u].end()); } template < class EdgeList, class Allocator > void remove_edge(typename detail::val_edge< EdgeList >::type e, std::vector< EdgeList, Allocator >& g) { typename EdgeList::value_type u, v; u = e.first; v = e.second; // FIXME: edge type does not fully specify the edge to be deleted typename EdgeList::iterator i = std::remove(g[u].begin(), g[u].end(), v); if (i != g[u].end()) g[u].erase(i, g[u].end()); } template < class EdgeList, class Allocator, class Predicate > void remove_edge_if(Predicate p, std::vector< EdgeList, Allocator >& g) { for (std::size_t u = 0; u < g.size(); ++u) { // Oops! gcc gets internal compiler error on compose_....... typedef typename EdgeList::iterator iterator; iterator b = g[u].begin(), e = g[u].end(); if (!g[u].empty()) { for (; b != e;) { if (p(std::make_pair(u, *b))) { --e; if (b == e) break; else iter_swap(b, e); } else { ++b; } } } if (e != g[u].end()) g[u].erase(e, g[u].end()); } } template < class EdgeList, class Allocator > typename EdgeList::value_type add_vertex(std::vector< EdgeList, Allocator >& g) { g.resize(g.size() + 1); return g.size() - 1; } template < class EdgeList, class Allocator > void clear_vertex( typename EdgeList::value_type u, std::vector< EdgeList, Allocator >& g) { g[u].clear(); for (std::size_t i = 0; i < g.size(); ++i) remove_edge(i, u, g); } template < class EdgeList, class Allocator > void remove_vertex( typename EdgeList::value_type u, std::vector< EdgeList, Allocator >& g) { typedef typename EdgeList::iterator iterator; clear_vertex(u, g); g.erase(g.begin() + u); for (std::size_t i = 0; i < g.size(); ++i) for (iterator it = g[i].begin(); it != g[i].end(); ++it) // after clear_vertex *it is never equal to u if (*it > u) --*it; } template < typename EdgeList, typename Allocator > struct property_map< std::vector< EdgeList, Allocator >, vertex_index_t > { typedef identity_property_map type; typedef type const_type; }; template < typename EdgeList, typename Allocator > identity_property_map get( vertex_index_t, const std::vector< EdgeList, Allocator >&) { return identity_property_map(); } template < typename EdgeList, typename Allocator > identity_property_map get(vertex_index_t, std::vector< EdgeList, Allocator >&) { return identity_property_map(); } } // namespace boost #endif // BOOST_VECTOR_AS_GRAPH_HPP iteration_macros.hpp 0000644 00000026613 15125521275 0010634 0 ustar 00 //======================================================================= // Copyright 2001 Indiana University // Author: Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_ITERATION_MACROS_HPP #define BOOST_GRAPH_ITERATION_MACROS_HPP #include <utility> #define BGL_CAT(x, y) x##y #define BGL_RANGE(linenum) BGL_CAT(bgl_range_, linenum) #define BGL_FIRST(linenum) (BGL_RANGE(linenum).first) #define BGL_LAST(linenum) (BGL_RANGE(linenum).second) /* BGL_FORALL_VERTICES_T(v, g, graph_t) // This is on line 9 expands to the following, but all on the same line for (typename boost::graph_traits<graph_t>::vertex_iterator bgl_first_9 = vertices(g).first, bgl_last_9 = vertices(g).second; bgl_first_9 != bgl_last_9; bgl_first_9 = bgl_last_9) for (typename boost::graph_traits<graph_t>::vertex_descriptor v; bgl_first_9 != bgl_last_9 ? (v = *bgl_first_9, true) : false; ++bgl_first_9) The purpose of having two for-loops is just to provide a place to declare both the iterator and value variables. There is really only one loop. The stopping condition gets executed two more times than it usually would be, oh well. The reason for the bgl_first_9 = bgl_last_9 in the outer for-loop is in case the user puts a break statement in the inner for-loop. The other macros work in a similar fashion. Use the _T versions when the graph type is a template parameter or dependent on a template parameter. Otherwise use the non _T versions. ----------------------- 6/9/09 THK The above contains two calls to the vertices function. I modified these macros to expand to for (std::pair<typename boost::graph_traits<graph_t>::vertex_iterator, typename boost::graph_traits<graph_t>::vertex_iterator> bgl_range_9 = vertices(g); bgl_range_9.first != bgl_range_9.second; bgl_range_9.first = bgl_range_9.second) for (typename boost::graph_traits<graph_t>::vertex_descriptor v; bgl_range_9.first != bgl_range_9.second ? (v = *bgl_range_9.first, true) : false; ++bgl_range_9.first) */ #define BGL_FORALL_VERTICES_T(VNAME, GNAME, GraphType) \ for (std::pair< \ typename boost::graph_traits< GraphType >::vertex_iterator, \ typename boost::graph_traits< GraphType >::vertex_iterator > \ BGL_RANGE(__LINE__) \ = vertices(GNAME); \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__); \ BGL_FIRST(__LINE__) = BGL_LAST(__LINE__)) \ for (typename boost::graph_traits< GraphType >::vertex_descriptor \ VNAME; \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__) \ ? (VNAME = *BGL_FIRST(__LINE__), true) \ : false; \ ++BGL_FIRST(__LINE__)) #define BGL_FORALL_VERTICES(VNAME, GNAME, GraphType) \ for (std::pair< boost::graph_traits< GraphType >::vertex_iterator, \ boost::graph_traits< GraphType >::vertex_iterator > \ BGL_RANGE(__LINE__) \ = vertices(GNAME); \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__); \ BGL_FIRST(__LINE__) = BGL_LAST(__LINE__)) \ for (boost::graph_traits< GraphType >::vertex_descriptor VNAME; \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__) \ ? (VNAME = *BGL_FIRST(__LINE__), true) \ : false; \ ++BGL_FIRST(__LINE__)) #define BGL_FORALL_EDGES_T(ENAME, GNAME, GraphType) \ for (std::pair< typename boost::graph_traits< GraphType >::edge_iterator, \ typename boost::graph_traits< GraphType >::edge_iterator > \ BGL_RANGE(__LINE__) \ = edges(GNAME); \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__); \ BGL_FIRST(__LINE__) = BGL_LAST(__LINE__)) \ for (typename boost::graph_traits< GraphType >::edge_descriptor ENAME; \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__) \ ? (ENAME = *BGL_FIRST(__LINE__), true) \ : false; \ ++BGL_FIRST(__LINE__)) #define BGL_FORALL_EDGES(ENAME, GNAME, GraphType) \ for (std::pair< boost::graph_traits< GraphType >::edge_iterator, \ boost::graph_traits< GraphType >::edge_iterator > \ BGL_RANGE(__LINE__) \ = edges(GNAME); \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__); \ BGL_FIRST(__LINE__) = BGL_LAST(__LINE__)) \ for (boost::graph_traits< GraphType >::edge_descriptor ENAME; \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__) \ ? (ENAME = *BGL_FIRST(__LINE__), true) \ : false; \ ++BGL_FIRST(__LINE__)) #define BGL_FORALL_ADJ_T(UNAME, VNAME, GNAME, GraphType) \ for (std::pair< \ typename boost::graph_traits< GraphType >::adjacency_iterator, \ typename boost::graph_traits< GraphType >::adjacency_iterator > \ BGL_RANGE(__LINE__) \ = adjacent_vertices(UNAME, GNAME); \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__); \ BGL_FIRST(__LINE__) = BGL_LAST(__LINE__)) \ for (typename boost::graph_traits< GraphType >::vertex_descriptor \ VNAME; \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__) \ ? (VNAME = *BGL_FIRST(__LINE__), true) \ : false; \ ++BGL_FIRST(__LINE__)) #define BGL_FORALL_ADJ(UNAME, VNAME, GNAME, GraphType) \ for (std::pair< boost::graph_traits< GraphType >::adjacency_iterator, \ boost::graph_traits< GraphType >::adjacency_iterator > \ BGL_RANGE(__LINE__) \ = adjacent_vertices(UNAME, GNAME); \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__); \ BGL_FIRST(__LINE__) = BGL_LAST(__LINE__)) \ for (boost::graph_traits< GraphType >::vertex_descriptor VNAME; \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__) \ ? (VNAME = *BGL_FIRST(__LINE__), true) \ : false; \ ++BGL_FIRST(__LINE__)) #define BGL_FORALL_OUTEDGES_T(UNAME, ENAME, GNAME, GraphType) \ for (std::pair< \ typename boost::graph_traits< GraphType >::out_edge_iterator, \ typename boost::graph_traits< GraphType >::out_edge_iterator > \ BGL_RANGE(__LINE__) \ = out_edges(UNAME, GNAME); \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__); \ BGL_FIRST(__LINE__) = BGL_LAST(__LINE__)) \ for (typename boost::graph_traits< GraphType >::edge_descriptor ENAME; \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__) \ ? (ENAME = *BGL_FIRST(__LINE__), true) \ : false; \ ++BGL_FIRST(__LINE__)) #define BGL_FORALL_OUTEDGES(UNAME, ENAME, GNAME, GraphType) \ for (std::pair< boost::graph_traits< GraphType >::out_edge_iterator, \ boost::graph_traits< GraphType >::out_edge_iterator > \ BGL_RANGE(__LINE__) \ = out_edges(UNAME, GNAME); \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__); \ BGL_FIRST(__LINE__) = BGL_LAST(__LINE__)) \ for (boost::graph_traits< GraphType >::edge_descriptor ENAME; \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__) \ ? (ENAME = *BGL_FIRST(__LINE__), true) \ : false; \ ++BGL_FIRST(__LINE__)) #define BGL_FORALL_INEDGES_T(UNAME, ENAME, GNAME, GraphType) \ for (std::pair< \ typename boost::graph_traits< GraphType >::in_edge_iterator, \ typename boost::graph_traits< GraphType >::in_edge_iterator > \ BGL_RANGE(__LINE__) \ = in_edges(UNAME, GNAME); \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__); \ BGL_FIRST(__LINE__) = BGL_LAST(__LINE__)) \ for (typename boost::graph_traits< GraphType >::edge_descriptor ENAME; \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__) \ ? (ENAME = *BGL_FIRST(__LINE__), true) \ : false; \ ++BGL_FIRST(__LINE__)) #define BGL_FORALL_INEDGES(UNAME, ENAME, GNAME, GraphType) \ for (std::pair< boost::graph_traits< GraphType >::in_edge_iterator, \ boost::graph_traits< GraphType >::in_edge_iterator > \ BGL_RANGE(__LINE__) \ = in_edges(UNAME, GNAME); \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__); \ BGL_FIRST(__LINE__) = BGL_LAST(__LINE__)) \ for (boost::graph_traits< GraphType >::edge_descriptor ENAME; \ BGL_FIRST(__LINE__) != BGL_LAST(__LINE__) \ ? (ENAME = *BGL_FIRST(__LINE__), true) \ : false; \ ++BGL_FIRST(__LINE__)) #endif // BOOST_GRAPH_ITERATION_MACROS_HPP ssca_graph_generator.hpp 0000644 00000014644 15125521275 0011453 0 ustar 00 // Copyright 2004, 2005 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Nick Edmonds // Andrew Lumsdaine #ifndef BOOST_GRAPH_SSCA_GENERATOR_HPP #define BOOST_GRAPH_SSCA_GENERATOR_HPP #include <iterator> #include <utility> #include <vector> #include <queue> #include <boost/config.hpp> #include <boost/random/uniform_int.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/type_traits/is_base_and_derived.hpp> #include <boost/type_traits/is_same.hpp> enum Direction { FORWARD = 1, BACKWARD = 2, BOTH = FORWARD | BACKWARD }; namespace boost { // This generator generates graphs according to the method specified // in SSCA 1.1. Current versions of SSCA use R-MAT graphs template < typename RandomGenerator, typename Graph > class ssca_iterator { typedef typename graph_traits< Graph >::directed_category directed_category; typedef typename graph_traits< Graph >::vertices_size_type vertices_size_type; public: typedef std::input_iterator_tag iterator_category; typedef std::pair< vertices_size_type, vertices_size_type > value_type; typedef const value_type& reference; typedef const value_type* pointer; typedef void difference_type; // No argument constructor, set to terminating condition ssca_iterator() : gen(), verticesRemaining(0) {} // Initialize for edge generation ssca_iterator(RandomGenerator& gen, vertices_size_type totVertices, vertices_size_type maxCliqueSize, double probUnidirectional, int maxParallelEdges, double probIntercliqueEdges) : gen(&gen) , totVertices(totVertices) , maxCliqueSize(maxCliqueSize) , probUnidirectional(probUnidirectional) , maxParallelEdges(maxParallelEdges) , probIntercliqueEdges(probIntercliqueEdges) , currentClique(0) , verticesRemaining(totVertices) { cliqueNum = std::vector< int >(totVertices, -1); current = std::make_pair(0, 0); } reference operator*() const { return current; } pointer operator->() const { return ¤t; } ssca_iterator& operator++() { BOOST_USING_STD_MIN(); while (values.empty() && verticesRemaining > 0) { // If there are no values left, generate a new clique uniform_int< vertices_size_type > clique_size(1, maxCliqueSize); uniform_int< vertices_size_type > rand_vertex(0, totVertices - 1); uniform_int< int > num_parallel_edges(1, maxParallelEdges); uniform_int< short > direction(0, 1); uniform_01< RandomGenerator > prob(*gen); std::vector< vertices_size_type > cliqueVertices; cliqueVertices.clear(); vertices_size_type size = min BOOST_PREVENT_MACRO_SUBSTITUTION( clique_size(*gen), verticesRemaining); while (cliqueVertices.size() < size) { vertices_size_type v = rand_vertex(*gen); if (cliqueNum[v] == -1) { cliqueNum[v] = currentClique; cliqueVertices.push_back(v); verticesRemaining--; } } // Nick: This is inefficient when only a few vertices remain... // I should probably just select the remaining vertices // in order when only a certain fraction remain. typename std::vector< vertices_size_type >::iterator first, second; for (first = cliqueVertices.begin(); first != cliqueVertices.end(); ++first) for (second = first + 1; second != cliqueVertices.end(); ++second) { Direction d; int edges; d = prob() < probUnidirectional ? (direction(*gen) == 0 ? FORWARD : BACKWARD) : BOTH; if (d & FORWARD) { edges = num_parallel_edges(*gen); for (int i = 0; i < edges; ++i) values.push(std::make_pair(*first, *second)); } if (d & BACKWARD) { edges = num_parallel_edges(*gen); for (int i = 0; i < edges; ++i) values.push(std::make_pair(*second, *first)); } } if (verticesRemaining == 0) { // Generate interclique edges for (vertices_size_type i = 0; i < totVertices; ++i) { double p = probIntercliqueEdges; for (vertices_size_type d = 2; d < totVertices / 2; d *= 2, p /= 2) { vertices_size_type j = (i + d) % totVertices; if (cliqueNum[j] != cliqueNum[i] && prob() < p) { int edges = num_parallel_edges(*gen); for (int i = 0; i < edges; ++i) values.push(std::make_pair(i, j)); } } } } currentClique++; } if (!values.empty()) { // If we're not done return a value current = values.front(); values.pop(); } return *this; } ssca_iterator operator++(int) { ssca_iterator temp(*this); ++(*this); return temp; } bool operator==(const ssca_iterator& other) const { return verticesRemaining == other.verticesRemaining && values.empty() && other.values.empty(); } bool operator!=(const ssca_iterator& other) const { return !(*this == other); } private: // Parameters RandomGenerator* gen; vertices_size_type totVertices; vertices_size_type maxCliqueSize; double probUnidirectional; int maxParallelEdges; double probIntercliqueEdges; // Internal data structures std::vector< int > cliqueNum; std::queue< value_type > values; int currentClique; vertices_size_type verticesRemaining; value_type current; }; } // end namespace boost #endif // BOOST_GRAPH_SSCA_GENERATOR_HPP planar_face_traversal.hpp 0000644 00000013604 15125521275 0011604 0 ustar 00 //======================================================================= // Copyright (c) Aaron Windsor 2007 // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef __PLANAR_FACE_TRAVERSAL_HPP__ #define __PLANAR_FACE_TRAVERSAL_HPP__ #include <vector> #include <set> #include <map> #include <boost/next_prior.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> namespace boost { struct planar_face_traversal_visitor { void begin_traversal() {} void begin_face() {} template < typename Edge > void next_edge(Edge) {} template < typename Vertex > void next_vertex(Vertex) {} void end_face() {} void end_traversal() {} }; template < typename Graph, typename PlanarEmbedding, typename Visitor, typename EdgeIndexMap > void planar_face_traversal(const Graph& g, PlanarEmbedding embedding, Visitor& visitor, EdgeIndexMap em) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::edge_descriptor edge_t; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; typedef typename graph_traits< Graph >::edge_iterator edge_iterator_t; typedef typename property_traits< PlanarEmbedding >::value_type embedding_value_t; typedef typename embedding_value_t::const_iterator embedding_iterator_t; typedef typename std::vector< std::set< vertex_t > > distinguished_edge_storage_t; typedef typename std::vector< std::map< vertex_t, edge_t > > distinguished_edge_to_edge_storage_t; typedef typename boost::iterator_property_map< typename distinguished_edge_storage_t::iterator, EdgeIndexMap > distinguished_edge_map_t; typedef typename boost::iterator_property_map< typename distinguished_edge_to_edge_storage_t::iterator, EdgeIndexMap > distinguished_edge_to_edge_map_t; distinguished_edge_storage_t visited_vector(num_edges(g)); distinguished_edge_to_edge_storage_t next_edge_vector(num_edges(g)); distinguished_edge_map_t visited(visited_vector.begin(), em); distinguished_edge_to_edge_map_t next_edge(next_edge_vector.begin(), em); vertex_iterator_t vi, vi_end; typename std::vector< edge_t >::iterator ei, ei_end; edge_iterator_t fi, fi_end; embedding_iterator_t pi, pi_begin, pi_end; visitor.begin_traversal(); // Initialize the next_edge property map. This map is initialized from the // PlanarEmbedding so that get(next_edge, e)[v] is the edge that comes // after e in the clockwise embedding around vertex v. for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { vertex_t v(*vi); pi_begin = embedding[v].begin(); pi_end = embedding[v].end(); for (pi = pi_begin; pi != pi_end; ++pi) { edge_t e(*pi); std::map< vertex_t, edge_t > m = get(next_edge, e); m[v] = boost::next(pi) == pi_end ? *pi_begin : *boost::next(pi); put(next_edge, e, m); } } // Take a copy of the edges in the graph here, since we want to accomodate // face traversals that add edges to the graph (for triangulation, in // particular) and don't want to use invalidated edge iterators. // Also, while iterating over all edges in the graph, we single out // any self-loops, which need some special treatment in the face traversal. std::vector< edge_t > self_loops; std::vector< edge_t > edges_cache; std::vector< vertex_t > vertices_in_edge; for (boost::tie(fi, fi_end) = edges(g); fi != fi_end; ++fi) { edge_t e(*fi); edges_cache.push_back(e); if (source(e, g) == target(e, g)) self_loops.push_back(e); } // Iterate over all edges in the graph ei_end = edges_cache.end(); for (ei = edges_cache.begin(); ei != ei_end; ++ei) { edge_t e(*ei); vertices_in_edge.clear(); vertices_in_edge.push_back(source(e, g)); vertices_in_edge.push_back(target(e, g)); typename std::vector< vertex_t >::iterator vi, vi_end; vi_end = vertices_in_edge.end(); // Iterate over both vertices in the current edge for (vi = vertices_in_edge.begin(); vi != vi_end; ++vi) { vertex_t v(*vi); std::set< vertex_t > e_visited = get(visited, e); typename std::set< vertex_t >::iterator e_visited_found = e_visited.find(v); if (e_visited_found == e_visited.end()) visitor.begin_face(); while (e_visited.find(v) == e_visited.end()) { visitor.next_vertex(v); visitor.next_edge(e); e_visited.insert(v); put(visited, e, e_visited); v = source(e, g) == v ? target(e, g) : source(e, g); e = get(next_edge, e)[v]; e_visited = get(visited, e); } if (e_visited_found == e_visited.end()) visitor.end_face(); } } // Iterate over all self-loops, visiting them once separately // (they've already been visited once, this visitation is for // the "inside" of the self-loop) ei_end = self_loops.end(); for (ei = self_loops.begin(); ei != ei_end; ++ei) { visitor.begin_face(); visitor.next_edge(*ei); visitor.next_vertex(source(*ei, g)); visitor.end_face(); } visitor.end_traversal(); } template < typename Graph, typename PlanarEmbedding, typename Visitor > inline void planar_face_traversal( const Graph& g, PlanarEmbedding embedding, Visitor& visitor) { planar_face_traversal(g, embedding, visitor, get(edge_index, g)); } } // namespace boost #endif //__PLANAR_FACE_TRAVERSAL_HPP__ small_world_generator.hpp 0000644 00000007126 15125521275 0011655 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_SMALL_WORLD_GENERATOR_HPP #define BOOST_GRAPH_SMALL_WORLD_GENERATOR_HPP #include <iterator> #include <utility> #include <boost/random/uniform_01.hpp> #include <boost/random/uniform_int.hpp> namespace boost { // Assumes undirected template < typename RandomGenerator, typename Graph > class small_world_iterator { typedef typename graph_traits< Graph >::vertices_size_type vertices_size_type; public: typedef std::input_iterator_tag iterator_category; typedef std::pair< vertices_size_type, vertices_size_type > value_type; typedef const value_type& reference; typedef const value_type* pointer; typedef void difference_type; small_world_iterator() : gen(0) {} small_world_iterator(RandomGenerator& gen, vertices_size_type n, vertices_size_type k, double prob = 0.0, bool allow_self_loops = false) : gen(&gen) , n(n) , k(k) , prob(prob) , source(0) , target(allow_self_loops ? 0 : 1) , allow_self_loops(allow_self_loops) , current(0, allow_self_loops ? 0 : 1) { } reference operator*() const { return current; } pointer operator->() const { return ¤t; } small_world_iterator& operator++() { target = (target + 1) % n; if (target == (source + k / 2 + 1) % n) { ++source; if (allow_self_loops) target = source; else target = (source + 1) % n; } current.first = source; uniform_01< RandomGenerator, double > rand01(*gen); uniform_int< vertices_size_type > rand_vertex_gen(0, n - 1); double x = rand01(); *gen = rand01.base(); // GRRRR if (x < prob) { vertices_size_type lower = (source + n - k / 2) % n; vertices_size_type upper = (source + k / 2) % n; do { current.second = rand_vertex_gen(*gen); } while ((current.second >= lower && current.second <= upper) || (upper < lower && (current.second >= lower || current.second <= upper))); } else { current.second = target; } return *this; } small_world_iterator operator++(int) { small_world_iterator temp(*this); ++(*this); return temp; } bool operator==(const small_world_iterator& other) const { if (!gen && other.gen) return other == *this; else if (gen && !other.gen) return source == n; else if (!gen && !other.gen) return true; return source == other.source && target == other.target; } bool operator!=(const small_world_iterator& other) const { return !(*this == other); } private: void next() { uniform_int< vertices_size_type > rand_vertex(0, n - 1); current.first = rand_vertex(*gen); do { current.second = rand_vertex(*gen); } while (current.first == current.second && !allow_self_loops); } RandomGenerator* gen; vertices_size_type n; vertices_size_type k; double prob; vertices_size_type source; vertices_size_type target; bool allow_self_loops; value_type current; }; } // end namespace boost #endif // BOOST_GRAPH_SMALL_WORLD_GENERATOR_HPP erdos_renyi_generator.hpp 0000644 00000016131 15125521275 0011654 0 ustar 00 // Copyright 2004, 2005 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Jeremiah Willcock // Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_ERDOS_RENYI_GENERATOR_HPP #define BOOST_GRAPH_ERDOS_RENYI_GENERATOR_HPP #include <boost/assert.hpp> #include <iterator> #include <utility> #include <boost/shared_ptr.hpp> #include <boost/random/uniform_int.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/random/geometric_distribution.hpp> #include <boost/type_traits/is_base_of.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/config/no_tr1/cmath.hpp> #include <boost/iterator/iterator_facade.hpp> namespace boost { template < typename RandomGenerator, typename Graph > class erdos_renyi_iterator : public iterator_facade< erdos_renyi_iterator< RandomGenerator, Graph >, std::pair< typename graph_traits< Graph >::vertices_size_type, typename graph_traits< Graph >::vertices_size_type >, std::input_iterator_tag, const std::pair< typename graph_traits< Graph >::vertices_size_type, typename graph_traits< Graph >::vertices_size_type >& > { typedef typename graph_traits< Graph >::directed_category directed_category; typedef typename graph_traits< Graph >::vertices_size_type vertices_size_type; typedef typename graph_traits< Graph >::edges_size_type edges_size_type; BOOST_STATIC_CONSTANT(bool, is_undirected = (is_base_of< undirected_tag, directed_category >::value)); public: erdos_renyi_iterator() : gen(), n(0), edges(0), allow_self_loops(false) {} erdos_renyi_iterator(RandomGenerator& gen, vertices_size_type n, double fraction = 0.0, bool allow_self_loops = false) : gen(&gen) , n(n) , edges(edges_size_type(fraction * n * n)) , allow_self_loops(allow_self_loops) { if (is_undirected) edges = edges / 2; next(); } erdos_renyi_iterator(RandomGenerator& gen, vertices_size_type n, edges_size_type m, bool allow_self_loops = false) : gen(&gen), n(n), edges(m), allow_self_loops(allow_self_loops) { next(); } const std::pair< vertices_size_type, vertices_size_type >& dereference() const { return current; } void increment() { --edges; next(); } bool equal(const erdos_renyi_iterator& other) const { return edges == other.edges; } private: void next() { uniform_int< vertices_size_type > rand_vertex(0, n - 1); current.first = rand_vertex(*gen); do { current.second = rand_vertex(*gen); } while (current.first == current.second && !allow_self_loops); } RandomGenerator* gen; vertices_size_type n; edges_size_type edges; bool allow_self_loops; std::pair< vertices_size_type, vertices_size_type > current; }; template < typename RandomGenerator, typename Graph > class sorted_erdos_renyi_iterator : public iterator_facade< sorted_erdos_renyi_iterator< RandomGenerator, Graph >, std::pair< typename graph_traits< Graph >::vertices_size_type, typename graph_traits< Graph >::vertices_size_type >, std::input_iterator_tag, const std::pair< typename graph_traits< Graph >::vertices_size_type, typename graph_traits< Graph >::vertices_size_type >& > { typedef typename graph_traits< Graph >::directed_category directed_category; typedef typename graph_traits< Graph >::vertices_size_type vertices_size_type; typedef typename graph_traits< Graph >::edges_size_type edges_size_type; BOOST_STATIC_CONSTANT(bool, is_undirected = (is_base_of< undirected_tag, directed_category >::value)); public: sorted_erdos_renyi_iterator() : gen() , rand_vertex(0.5) , n(0) , allow_self_loops(false) , src((std::numeric_limits< vertices_size_type >::max)()) , tgt_index(vertices_size_type(-1)) , prob(.5) { } // NOTE: The default probability has been changed to be the same as that // used by the geometic distribution. It was previously 0.0, which would // cause an assertion. sorted_erdos_renyi_iterator(RandomGenerator& gen, vertices_size_type n, double prob = 0.5, bool loops = false) : gen() , rand_vertex(1. - prob) , n(n) , allow_self_loops(loops) , src(0) , tgt_index(vertices_size_type(-1)) , prob(prob) { this->gen.reset(new uniform_01< RandomGenerator* >(&gen)); if (prob == 0.0) { src = (std::numeric_limits< vertices_size_type >::max)(); return; } next(); } const std::pair< vertices_size_type, vertices_size_type >& dereference() const { return current; } bool equal(const sorted_erdos_renyi_iterator& o) const { return src == o.src && tgt_index == o.tgt_index; } void increment() { next(); } private: void next() { // In order to get the edges from the generator in sorted order, one // effective (but slow) procedure would be to use a // bernoulli_distribution for each legal (src, tgt_index) pair. Because // of the O(|V|^2) cost of that, a geometric distribution is used. The // geometric distribution tells how many times the // bernoulli_distribution would need to be run until it returns true. // Thus, this distribution can be used to step through the edges // which are actually present. BOOST_ASSERT(src != (std::numeric_limits< vertices_size_type >::max)() && src != n); while (src != n) { vertices_size_type increment = rand_vertex(*gen); size_t tgt_index_limit = (is_undirected ? src + 1 : n) + (allow_self_loops ? 0 : -1); if (tgt_index + increment >= tgt_index_limit) { // Overflowed this source; go to the next one and try again. ++src; // This bias is because the geometric distribution always // returns values >=1, and we want to allow 0 as a valid target. tgt_index = vertices_size_type(-1); continue; } else { tgt_index += increment; current.first = src; current.second = tgt_index + (!allow_self_loops && !is_undirected && tgt_index >= src ? 1 : 0); break; } } if (src == n) src = (std::numeric_limits< vertices_size_type >::max)(); } shared_ptr< uniform_01< RandomGenerator* > > gen; geometric_distribution< vertices_size_type > rand_vertex; vertices_size_type n; bool allow_self_loops; vertices_size_type src, tgt_index; std::pair< vertices_size_type, vertices_size_type > current; double prob; }; } // end namespace boost #endif // BOOST_GRAPH_ERDOS_RENYI_GENERATOR_HPP dijkstra_shortest_paths_no_color_map.hpp 0000644 00000022624 15125521275 0014764 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Copyright 2009 Trustees of Indiana University. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Michael Hansen // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_DIJKSTRA_NO_COLOR_MAP_HPP #define BOOST_GRAPH_DIJKSTRA_NO_COLOR_MAP_HPP #include <boost/pending/indirect_cmp.hpp> #include <boost/graph/relax.hpp> #include <boost/graph/detail/d_ary_heap.hpp> #include <boost/graph/dijkstra_shortest_paths.hpp> #include <boost/graph/iteration_macros.hpp> namespace boost { // No init version template < typename Graph, typename DijkstraVisitor, typename PredecessorMap, typename DistanceMap, typename WeightMap, typename VertexIndexMap, typename DistanceCompare, typename DistanceWeightCombine, typename DistanceInfinity, typename DistanceZero > void dijkstra_shortest_paths_no_color_map_no_init(const Graph& graph, typename graph_traits< Graph >::vertex_descriptor start_vertex, PredecessorMap predecessor_map, DistanceMap distance_map, WeightMap weight_map, VertexIndexMap index_map, DistanceCompare distance_compare, DistanceWeightCombine distance_weight_combine, DistanceInfinity distance_infinity, DistanceZero distance_zero, DijkstraVisitor visitor) { typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename property_traits< DistanceMap >::value_type Distance; typedef indirect_cmp< DistanceMap, DistanceCompare > DistanceIndirectCompare; DistanceIndirectCompare distance_indirect_compare( distance_map, distance_compare); // Default - use d-ary heap (d = 4) typedef detail::vertex_property_map_generator< Graph, VertexIndexMap, std::size_t > IndexInHeapMapHelper; typedef typename IndexInHeapMapHelper::type IndexInHeapMap; typedef d_ary_heap_indirect< Vertex, 4, IndexInHeapMap, DistanceMap, DistanceCompare > VertexQueue; boost::scoped_array< std::size_t > index_in_heap_map_holder; IndexInHeapMap index_in_heap = IndexInHeapMapHelper::build( graph, index_map, index_in_heap_map_holder); VertexQueue vertex_queue(distance_map, index_in_heap, distance_compare); // Add vertex to the queue vertex_queue.push(start_vertex); // Starting vertex will always be the first discovered vertex visitor.discover_vertex(start_vertex, graph); while (!vertex_queue.empty()) { Vertex min_vertex = vertex_queue.top(); vertex_queue.pop(); visitor.examine_vertex(min_vertex, graph); // Check if any other vertices can be reached Distance min_vertex_distance = get(distance_map, min_vertex); if (!distance_compare(min_vertex_distance, distance_infinity)) { // This is the minimum vertex, so all other vertices are unreachable return; } // Examine neighbors of min_vertex BGL_FORALL_OUTEDGES_T(min_vertex, current_edge, graph, Graph) { visitor.examine_edge(current_edge, graph); // Check if the edge has a negative weight if (distance_compare(get(weight_map, current_edge), distance_zero)) { boost::throw_exception(negative_edge()); } // Extract the neighboring vertex and get its distance Vertex neighbor_vertex = target(current_edge, graph); Distance neighbor_vertex_distance = get(distance_map, neighbor_vertex); bool is_neighbor_undiscovered = !distance_compare( neighbor_vertex_distance, distance_infinity); // Attempt to relax the edge bool was_edge_relaxed = relax_target(current_edge, graph, weight_map, predecessor_map, distance_map, distance_weight_combine, distance_compare); if (was_edge_relaxed) { visitor.edge_relaxed(current_edge, graph); if (is_neighbor_undiscovered) { visitor.discover_vertex(neighbor_vertex, graph); vertex_queue.push(neighbor_vertex); } else { vertex_queue.update(neighbor_vertex); } } else { visitor.edge_not_relaxed(current_edge, graph); } } // end out edge iteration visitor.finish_vertex(min_vertex, graph); } // end while queue not empty } // Full init version template < typename Graph, typename DijkstraVisitor, typename PredecessorMap, typename DistanceMap, typename WeightMap, typename VertexIndexMap, typename DistanceCompare, typename DistanceWeightCombine, typename DistanceInfinity, typename DistanceZero > void dijkstra_shortest_paths_no_color_map(const Graph& graph, typename graph_traits< Graph >::vertex_descriptor start_vertex, PredecessorMap predecessor_map, DistanceMap distance_map, WeightMap weight_map, VertexIndexMap index_map, DistanceCompare distance_compare, DistanceWeightCombine distance_weight_combine, DistanceInfinity distance_infinity, DistanceZero distance_zero, DijkstraVisitor visitor) { // Initialize vertices BGL_FORALL_VERTICES_T(current_vertex, graph, Graph) { visitor.initialize_vertex(current_vertex, graph); // Default all distances to infinity put(distance_map, current_vertex, distance_infinity); // Default all vertex predecessors to the vertex itself put(predecessor_map, current_vertex, current_vertex); } // Set distance for start_vertex to zero put(distance_map, start_vertex, distance_zero); // Pass everything on to the no_init version dijkstra_shortest_paths_no_color_map_no_init(graph, start_vertex, predecessor_map, distance_map, weight_map, index_map, distance_compare, distance_weight_combine, distance_infinity, distance_zero, visitor); } namespace detail { // Handle defaults for PredecessorMap, DistanceCompare, // DistanceWeightCombine, DistanceInfinity and DistanceZero template < typename Graph, typename DistanceMap, typename WeightMap, typename VertexIndexMap, typename Params > inline void dijkstra_no_color_map_dispatch2(const Graph& graph, typename graph_traits< Graph >::vertex_descriptor start_vertex, DistanceMap distance_map, WeightMap weight_map, VertexIndexMap index_map, const Params& params) { // Default for predecessor map dummy_property_map predecessor_map; typedef typename property_traits< DistanceMap >::value_type DistanceType; DistanceType inf = choose_param(get_param(params, distance_inf_t()), (std::numeric_limits< DistanceType >::max)()); dijkstra_shortest_paths_no_color_map(graph, start_vertex, choose_param( get_param(params, vertex_predecessor), predecessor_map), distance_map, weight_map, index_map, choose_param(get_param(params, distance_compare_t()), std::less< DistanceType >()), choose_param(get_param(params, distance_combine_t()), std::plus< DistanceType >()), inf, choose_param(get_param(params, distance_zero_t()), DistanceType()), choose_param(get_param(params, graph_visitor), make_dijkstra_visitor(null_visitor()))); } template < typename Graph, typename DistanceMap, typename WeightMap, typename IndexMap, typename Params > inline void dijkstra_no_color_map_dispatch1(const Graph& graph, typename graph_traits< Graph >::vertex_descriptor start_vertex, DistanceMap distance_map, WeightMap weight_map, IndexMap index_map, const Params& params) { // Default for distance map typedef typename property_traits< WeightMap >::value_type DistanceType; typename std::vector< DistanceType >::size_type vertex_count = is_default_param(distance_map) ? num_vertices(graph) : 1; std::vector< DistanceType > default_distance_map(vertex_count); detail::dijkstra_no_color_map_dispatch2(graph, start_vertex, choose_param(distance_map, make_iterator_property_map(default_distance_map.begin(), index_map, default_distance_map[0])), weight_map, index_map, params); } } // namespace detail // Named parameter version template < typename Graph, typename Param, typename Tag, typename Rest > inline void dijkstra_shortest_paths_no_color_map(const Graph& graph, typename graph_traits< Graph >::vertex_descriptor start_vertex, const bgl_named_params< Param, Tag, Rest >& params) { // Default for edge weight and vertex index map is to ask for them // from the graph. Default for the visitor is null_visitor. detail::dijkstra_no_color_map_dispatch1(graph, start_vertex, get_param(params, vertex_distance), choose_const_pmap(get_param(params, edge_weight), graph, edge_weight), choose_const_pmap(get_param(params, vertex_index), graph, vertex_index), params); } } // namespace boost #endif // BOOST_GRAPH_DIJKSTRA_NO_COLOR_MAP_HPP howard_cycle_ratio.hpp 0000644 00000054637 15125521275 0011142 0 ustar 00 // Copyright (C) 2006-2009 Dmitry Bufistov and Andrey Parfenov // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GRAPH_CYCLE_RATIO_HOWARD_HPP #define BOOST_GRAPH_CYCLE_RATIO_HOWARD_HPP #include <vector> #include <list> #include <algorithm> #include <limits> #include <boost/bind.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/type_traits/remove_const.hpp> #include <boost/concept_check.hpp> #include <boost/pending/queue.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/concept/assert.hpp> /** @file howard_cycle_ratio.hpp * @brief The implementation of the maximum/minimum cycle ratio/mean algorithm. * @author Dmitry Bufistov * @author Andrey Parfenov */ namespace boost { /** * The mcr_float is like numeric_limits, but only for floating point types * and only defines infinity() and epsilon(). This class is primarily used * to encapsulate a less-precise epsilon than natively supported by the * floating point type. */ template < typename Float = double > struct mcr_float { typedef Float value_type; static Float infinity() { return std::numeric_limits< value_type >::infinity(); } static Float epsilon() { return Float(-0.005); } }; namespace detail { template < typename FloatTraits > struct min_comparator_props { typedef std::greater< typename FloatTraits::value_type > comparator; static const int multiplier = 1; }; template < typename FloatTraits > struct max_comparator_props { typedef std::less< typename FloatTraits::value_type > comparator; static const int multiplier = -1; }; template < typename FloatTraits, typename ComparatorProps > struct float_wrapper { typedef typename FloatTraits::value_type value_type; typedef ComparatorProps comparator_props_t; typedef typename ComparatorProps::comparator comparator; static value_type infinity() { return FloatTraits::infinity() * ComparatorProps::multiplier; } static value_type epsilon() { return FloatTraits::epsilon() * ComparatorProps::multiplier; } }; /*! @class mcr_howard * @brief Calculates optimum (maximum/minimum) cycle ratio of a directed * graph. Uses Howard's iteration policy algorithm. </br>(It is described * in the paper "Experimental Analysis of the Fastest Optimum Cycle Ratio * and Mean Algorithm" by Ali Dasdan). */ template < typename FloatTraits, typename Graph, typename VertexIndexMap, typename EdgeWeight1, typename EdgeWeight2 > class mcr_howard { public: typedef typename FloatTraits::value_type float_t; typedef typename FloatTraits::comparator_props_t cmp_props_t; typedef typename FloatTraits::comparator comparator_t; typedef enum { my_white = 0, my_black } my_color_type; typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::edge_descriptor edge_t; typedef typename graph_traits< Graph >::vertices_size_type vn_t; typedef std::vector< float_t > vp_t; typedef typename boost::iterator_property_map< typename vp_t::iterator, VertexIndexMap > distance_map_t; // V -> float_t typedef typename std::vector< edge_t > ve_t; typedef std::vector< my_color_type > vcol_t; typedef typename ::boost::iterator_property_map< typename ve_t::iterator, VertexIndexMap > policy_t; // Vertex -> Edge typedef typename ::boost::iterator_property_map< typename vcol_t::iterator, VertexIndexMap > color_map_t; typedef typename std::list< vertex_t > pinel_t; // The in_edges list of the policy graph typedef typename std::vector< pinel_t > inedges1_t; typedef typename ::boost::iterator_property_map< typename inedges1_t::iterator, VertexIndexMap > inedges_t; typedef typename std::vector< edge_t > critical_cycle_t; // Bad vertex flag. If true, then the vertex is "bad". // Vertex is "bad" if its out_degree is equal to zero. typedef typename boost::iterator_property_map< std::vector< int >::iterator, VertexIndexMap > badv_t; /*! * Constructor * \param g = (V, E) - a directed multigraph. * \param vim Vertex Index Map. Read property Map: V -> [0, * num_vertices(g)). \param ewm edge weight map. Read property map: E * -> R \param ew2m edge weight map. Read property map: E -> R+ \param * infty A big enough value to guaranty that there exist a cycle with * better ratio. * \param cmp The compare operator for float_ts. */ mcr_howard(const Graph& g, VertexIndexMap vim, EdgeWeight1 ewm, EdgeWeight2 ew2m) : m_g(g) , m_vim(vim) , m_ew1m(ewm) , m_ew2m(ew2m) , m_bound(mcr_bound()) , m_cr(m_bound) , m_V(num_vertices(m_g)) , m_dis(m_V, 0) , m_dm(m_dis.begin(), m_vim) , m_policyc(m_V) , m_policy(m_policyc.begin(), m_vim) , m_inelc(m_V) , m_inel(m_inelc.begin(), m_vim) , m_badvc(m_V, false) , m_badv(m_badvc.begin(), m_vim) , m_colcv(m_V) , m_col_bfs(m_V) { } /*! * \return maximum/minimum_{for all cycles C} * [sum_{e in C} w1(e)] / [sum_{e in C} w2(e)], * or FloatTraits::infinity() if graph has no cycles. */ float_t ocr_howard() { construct_policy_graph(); int k = 0; float_t mcr = 0; do { mcr = policy_mcr(); ++k; } while ( try_improve_policy(mcr) && k < 100); // To avoid infinite loop const float_t eps_ = -0.00000001 * cmp_props_t::multiplier; if (m_cmp(mcr, m_bound + eps_)) { return FloatTraits::infinity(); } else { return mcr; } } virtual ~mcr_howard() {} protected: virtual void store_critical_edge(edge_t, critical_cycle_t&) {} virtual void store_critical_cycle(critical_cycle_t&) {} private: /*! * \return lower/upper bound for the maximal/minimal cycle ratio */ float_t mcr_bound() { typename graph_traits< Graph >::vertex_iterator vi, vie; typename graph_traits< Graph >::out_edge_iterator oei, oeie; float_t cz = (std::numeric_limits< float_t >::max)(); // Closest to // zero value float_t s = 0; const float_t eps_ = std::numeric_limits< float_t >::epsilon(); for (boost::tie(vi, vie) = vertices(m_g); vi != vie; ++vi) { for (boost::tie(oei, oeie) = out_edges(*vi, m_g); oei != oeie; ++oei) { s += std::abs(m_ew1m[*oei]); float_t a = std::abs(m_ew2m[*oei]); if (a > eps_ && a < cz) { cz = a; } } } return cmp_props_t::multiplier * (s / cz); } /*! * Constructs an arbitrary policy graph. */ void construct_policy_graph() { m_sink = graph_traits< Graph >().null_vertex(); typename graph_traits< Graph >::vertex_iterator vi, vie; typename graph_traits< Graph >::out_edge_iterator oei, oeie; for (boost::tie(vi, vie) = vertices(m_g); vi != vie; ++vi) { boost::tie(oei, oeie) = out_edges(*vi, m_g); typename graph_traits< Graph >::out_edge_iterator mei = std::max_element(oei, oeie, boost::bind(m_cmp, boost::bind(&EdgeWeight1::operator[], m_ew1m, _1), boost::bind(&EdgeWeight1::operator[], m_ew1m, _2))); if (mei == oeie) { if (m_sink == graph_traits< Graph >().null_vertex()) { m_sink = *vi; } m_badv[*vi] = true; m_inel[m_sink].push_back(*vi); } else { m_inel[target(*mei, m_g)].push_back(*vi); m_policy[*vi] = *mei; } } } /*! Sets the distance value for all vertices "v" such that there is * a path from "v" to "sv". It does "inverse" breadth first visit of the * policy graph, starting from the vertex "sv". */ void mcr_bfv(vertex_t sv, float_t cr, color_map_t c) { boost::queue< vertex_t > Q; c[sv] = my_black; Q.push(sv); while (!Q.empty()) { vertex_t v = Q.top(); Q.pop(); for (typename pinel_t::const_iterator itr = m_inel[v].begin(); itr != m_inel[v].end(); ++itr) // For all in_edges of the policy graph { if (*itr != sv) { if (m_badv[*itr]) { m_dm[*itr] = m_dm[v] + m_bound - cr; } else { m_dm[*itr] = m_dm[v] + m_ew1m[m_policy[*itr]] - m_ew2m[m_policy[*itr]] * cr; } c[*itr] = my_black; Q.push(*itr); } } } } /*! * \param sv an arbitrary (undiscovered) vertex of the policy graph. * \return a vertex in the policy graph that belongs to a cycle. * Performs a depth first visit until a cycle edge is found. */ vertex_t find_cycle_vertex(vertex_t sv) { vertex_t gv = sv; std::fill(m_colcv.begin(), m_colcv.end(), my_white); color_map_t cm(m_colcv.begin(), m_vim); do { cm[gv] = my_black; if (!m_badv[gv]) { gv = target(m_policy[gv], m_g); } else { gv = m_sink; } } while (cm[gv] != my_black); return gv; } /*! * \param sv - vertex that belongs to a cycle in the policy graph. */ float_t cycle_ratio(vertex_t sv) { if (sv == m_sink) return m_bound; std::pair< float_t, float_t > sums_(float_t(0), float_t(0)); vertex_t v = sv; critical_cycle_t cc; do { store_critical_edge(m_policy[v], cc); sums_.first += m_ew1m[m_policy[v]]; sums_.second += m_ew2m[m_policy[v]]; v = target(m_policy[v], m_g); } while (v != sv); float_t cr = sums_.first / sums_.second; if (m_cmp(m_cr, cr)) { m_cr = cr; store_critical_cycle(cc); } return cr; } /*! * Finds the optimal cycle ratio of the policy graph */ float_t policy_mcr() { std::fill(m_col_bfs.begin(), m_col_bfs.end(), my_white); color_map_t vcm_ = color_map_t(m_col_bfs.begin(), m_vim); typename graph_traits< Graph >::vertex_iterator uv_itr, vie; boost::tie(uv_itr, vie) = vertices(m_g); float_t mcr = m_bound; while ((uv_itr = std::find_if(uv_itr, vie, boost::bind(std::equal_to< my_color_type >(), my_white, boost::bind(&color_map_t::operator[], vcm_, _1)))) != vie) /// While there are undiscovered vertices { vertex_t gv = find_cycle_vertex(*uv_itr); float_t cr = cycle_ratio(gv); mcr_bfv(gv, cr, vcm_); if (m_cmp(mcr, cr)) mcr = cr; ++uv_itr; } return mcr; } /*! * Changes the edge m_policy[s] to the new_edge. */ void improve_policy(vertex_t s, edge_t new_edge) { vertex_t t = target(m_policy[s], m_g); typename property_traits< VertexIndexMap >::value_type ti = m_vim[t]; m_inelc[ti].erase( std::find(m_inelc[ti].begin(), m_inelc[ti].end(), s)); m_policy[s] = new_edge; t = target(new_edge, m_g); m_inel[t].push_back(s); /// Maintain in_edge list } /*! * A negative cycle detector. */ bool try_improve_policy(float_t cr) { bool improved = false; typename graph_traits< Graph >::vertex_iterator vi, vie; typename graph_traits< Graph >::out_edge_iterator oei, oeie; const float_t eps_ = FloatTraits::epsilon(); for (boost::tie(vi, vie) = vertices(m_g); vi != vie; ++vi) { if (!m_badv[*vi]) { for (boost::tie(oei, oeie) = out_edges(*vi, m_g); oei != oeie; ++oei) { vertex_t t = target(*oei, m_g); // Current distance from *vi to some vertex float_t dis_ = m_ew1m[*oei] - m_ew2m[*oei] * cr + m_dm[t]; if (m_cmp(m_dm[*vi] + eps_, dis_)) { improve_policy(*vi, *oei); m_dm[*vi] = dis_; improved = true; } } } else { float_t dis_ = m_bound - cr + m_dm[m_sink]; if (m_cmp(m_dm[*vi] + eps_, dis_)) { m_dm[*vi] = dis_; } } } return improved; } private: const Graph& m_g; VertexIndexMap m_vim; EdgeWeight1 m_ew1m; EdgeWeight2 m_ew2m; comparator_t m_cmp; float_t m_bound; //> The lower/upper bound to the maximal/minimal cycle // ratio float_t m_cr; //>The best cycle ratio that has been found so far vn_t m_V; //>The number of the vertices in the graph vp_t m_dis; //>Container for the distance map distance_map_t m_dm; //>Distance map ve_t m_policyc; //>Container for the policy graph policy_t m_policy; //>The interface for the policy graph inedges1_t m_inelc; //>Container fot in edges list inedges_t m_inel; //>Policy graph, input edges list std::vector< int > m_badvc; badv_t m_badv; // Marks "bad" vertices vcol_t m_colcv, m_col_bfs; // Color maps vertex_t m_sink; // To convert any graph to "good" }; /*! \class mcr_howard1 * \brief Finds optimum cycle raio and a critical cycle */ template < typename FloatTraits, typename Graph, typename VertexIndexMap, typename EdgeWeight1, typename EdgeWeight2 > class mcr_howard1 : public mcr_howard< FloatTraits, Graph, VertexIndexMap, EdgeWeight1, EdgeWeight2 > { public: typedef mcr_howard< FloatTraits, Graph, VertexIndexMap, EdgeWeight1, EdgeWeight2 > inhr_t; mcr_howard1(const Graph& g, VertexIndexMap vim, EdgeWeight1 ewm, EdgeWeight2 ew2m) : inhr_t(g, vim, ewm, ew2m) { } void get_critical_cycle(typename inhr_t::critical_cycle_t& cc) { return cc.swap(m_cc); } protected: void store_critical_edge( typename inhr_t::edge_t ed, typename inhr_t::critical_cycle_t& cc) { cc.push_back(ed); } void store_critical_cycle(typename inhr_t::critical_cycle_t& cc) { m_cc.swap(cc); } private: typename inhr_t::critical_cycle_t m_cc; // Critical cycle }; /*! * \param g a directed multigraph. * \param vim Vertex Index Map. A map V->[0, num_vertices(g)) * \param ewm Edge weight1 map. * \param ew2m Edge weight2 map. * \param pcc pointer to the critical edges list. * \return Optimum cycle ratio of g or FloatTraits::infinity() if g has no * cycles. */ template < typename FT, typename TG, typename TVIM, typename TEW1, typename TEW2, typename EV > typename FT::value_type optimum_cycle_ratio( const TG& g, TVIM vim, TEW1 ewm, TEW2 ew2m, EV* pcc) { typedef typename graph_traits< TG >::directed_category DirCat; BOOST_STATIC_ASSERT( (is_convertible< DirCat*, directed_tag* >::value == true)); BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< TG >)); BOOST_CONCEPT_ASSERT((VertexListGraphConcept< TG >)); typedef typename graph_traits< TG >::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< TVIM, Vertex >)); typedef typename graph_traits< TG >::edge_descriptor Edge; BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< TEW1, Edge >)); BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< TEW2, Edge >)); if (pcc == 0) { return detail::mcr_howard< FT, TG, TVIM, TEW1, TEW2 >( g, vim, ewm, ew2m) .ocr_howard(); } detail::mcr_howard1< FT, TG, TVIM, TEW1, TEW2 > obj(g, vim, ewm, ew2m); double ocr = obj.ocr_howard(); obj.get_critical_cycle(*pcc); return ocr; } } // namespace detail // Algorithms // Maximum Cycle Ratio template < typename FloatTraits, typename Graph, typename VertexIndexMap, typename EdgeWeight1Map, typename EdgeWeight2Map > inline typename FloatTraits::value_type maximum_cycle_ratio(const Graph& g, VertexIndexMap vim, EdgeWeight1Map ew1m, EdgeWeight2Map ew2m, std::vector< typename graph_traits< Graph >::edge_descriptor >* pcc = 0, FloatTraits = FloatTraits()) { typedef detail::float_wrapper< FloatTraits, detail::max_comparator_props< FloatTraits > > Traits; return detail::optimum_cycle_ratio< Traits >(g, vim, ew1m, ew2m, pcc); } template < typename Graph, typename VertexIndexMap, typename EdgeWeight1Map, typename EdgeWeight2Map > inline double maximum_cycle_ratio(const Graph& g, VertexIndexMap vim, EdgeWeight1Map ew1m, EdgeWeight2Map ew2m, std::vector< typename graph_traits< Graph >::edge_descriptor >* pcc = 0) { return maximum_cycle_ratio(g, vim, ew1m, ew2m, pcc, mcr_float<>()); } // Minimum Cycle Ratio template < typename FloatTraits, typename Graph, typename VertexIndexMap, typename EdgeWeight1Map, typename EdgeWeight2Map > typename FloatTraits::value_type minimum_cycle_ratio(const Graph& g, VertexIndexMap vim, EdgeWeight1Map ew1m, EdgeWeight2Map ew2m, std::vector< typename graph_traits< Graph >::edge_descriptor >* pcc = 0, FloatTraits = FloatTraits()) { typedef detail::float_wrapper< FloatTraits, detail::min_comparator_props< FloatTraits > > Traits; return detail::optimum_cycle_ratio< Traits >(g, vim, ew1m, ew2m, pcc); } template < typename Graph, typename VertexIndexMap, typename EdgeWeight1Map, typename EdgeWeight2Map > inline double minimum_cycle_ratio(const Graph& g, VertexIndexMap vim, EdgeWeight1Map ew1m, EdgeWeight2Map ew2m, std::vector< typename graph_traits< Graph >::edge_descriptor >* pcc = 0) { return minimum_cycle_ratio(g, vim, ew1m, ew2m, pcc, mcr_float<>()); } // Maximum Cycle Mean template < typename FloatTraits, typename Graph, typename VertexIndexMap, typename EdgeWeightMap, typename EdgeIndexMap > inline typename FloatTraits::value_type maximum_cycle_mean(const Graph& g, VertexIndexMap vim, EdgeWeightMap ewm, EdgeIndexMap eim, std::vector< typename graph_traits< Graph >::edge_descriptor >* pcc = 0, FloatTraits ft = FloatTraits()) { typedef typename remove_const< typename property_traits< EdgeWeightMap >::value_type >::type Weight; typename std::vector< Weight > ed_w2(boost::num_edges(g), 1); return maximum_cycle_ratio( g, vim, ewm, make_iterator_property_map(ed_w2.begin(), eim), pcc, ft); } template < typename Graph, typename VertexIndexMap, typename EdgeWeightMap, typename EdgeIndexMap > inline double maximum_cycle_mean(const Graph& g, VertexIndexMap vim, EdgeWeightMap ewm, EdgeIndexMap eim, std::vector< typename graph_traits< Graph >::edge_descriptor >* pcc = 0) { return maximum_cycle_mean(g, vim, ewm, eim, pcc, mcr_float<>()); } // Minimum Cycle Mean template < typename FloatTraits, typename Graph, typename VertexIndexMap, typename EdgeWeightMap, typename EdgeIndexMap > inline typename FloatTraits::value_type minimum_cycle_mean(const Graph& g, VertexIndexMap vim, EdgeWeightMap ewm, EdgeIndexMap eim, std::vector< typename graph_traits< Graph >::edge_descriptor >* pcc = 0, FloatTraits ft = FloatTraits()) { typedef typename remove_const< typename property_traits< EdgeWeightMap >::value_type >::type Weight; typename std::vector< Weight > ed_w2(boost::num_edges(g), 1); return minimum_cycle_ratio( g, vim, ewm, make_iterator_property_map(ed_w2.begin(), eim), pcc, ft); } template < typename Graph, typename VertexIndexMap, typename EdgeWeightMap, typename EdgeIndexMap > inline double minimum_cycle_mean(const Graph& g, VertexIndexMap vim, EdgeWeightMap ewm, EdgeIndexMap eim, std::vector< typename graph_traits< Graph >::edge_descriptor >* pcc = 0) { return minimum_cycle_mean(g, vim, ewm, eim, pcc, mcr_float<>()); } } // namespace boost #endif neighbor_bfs.hpp 0000644 00000026763 15125521275 0007727 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_NEIGHBOR_BREADTH_FIRST_SEARCH_HPP #define BOOST_GRAPH_NEIGHBOR_BREADTH_FIRST_SEARCH_HPP /* Neighbor Breadth First Search Like BFS, but traverses in-edges as well as out-edges. (for directed graphs only. use normal BFS for undirected graphs) */ #include <boost/config.hpp> #include <boost/ref.hpp> #include <vector> #include <boost/pending/queue.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/visitors.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/concept/assert.hpp> namespace boost { template < class Visitor, class Graph > struct NeighborBFSVisitorConcept { void constraints() { BOOST_CONCEPT_ASSERT((CopyConstructibleConcept< Visitor >)); vis.initialize_vertex(u, g); vis.discover_vertex(u, g); vis.examine_vertex(u, g); vis.examine_out_edge(e, g); vis.examine_in_edge(e, g); vis.tree_out_edge(e, g); vis.tree_in_edge(e, g); vis.non_tree_out_edge(e, g); vis.non_tree_in_edge(e, g); vis.gray_target(e, g); vis.black_target(e, g); vis.gray_source(e, g); vis.black_source(e, g); vis.finish_vertex(u, g); } Visitor vis; Graph g; typename graph_traits< Graph >::vertex_descriptor u; typename graph_traits< Graph >::edge_descriptor e; }; template < class Visitors = null_visitor > class neighbor_bfs_visitor { public: neighbor_bfs_visitor(Visitors vis = Visitors()) : m_vis(vis) {} template < class Vertex, class Graph > void initialize_vertex(Vertex u, Graph& g) { invoke_visitors(m_vis, u, g, on_initialize_vertex()); } template < class Vertex, class Graph > void discover_vertex(Vertex u, Graph& g) { invoke_visitors(m_vis, u, g, on_discover_vertex()); } template < class Vertex, class Graph > void examine_vertex(Vertex u, Graph& g) { invoke_visitors(m_vis, u, g, on_examine_vertex()); } template < class Edge, class Graph > void examine_out_edge(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, on_examine_edge()); } template < class Edge, class Graph > void tree_out_edge(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, on_tree_edge()); } template < class Edge, class Graph > void non_tree_out_edge(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, on_non_tree_edge()); } template < class Edge, class Graph > void gray_target(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, on_gray_target()); } template < class Edge, class Graph > void black_target(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, on_black_target()); } template < class Edge, class Graph > void examine_in_edge(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, on_examine_edge()); } template < class Edge, class Graph > void tree_in_edge(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, on_tree_edge()); } template < class Edge, class Graph > void non_tree_in_edge(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, on_non_tree_edge()); } template < class Edge, class Graph > void gray_source(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, on_gray_target()); } template < class Edge, class Graph > void black_source(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, on_black_target()); } template < class Vertex, class Graph > void finish_vertex(Vertex u, Graph& g) { invoke_visitors(m_vis, u, g, on_finish_vertex()); } protected: Visitors m_vis; }; template < class Visitors > neighbor_bfs_visitor< Visitors > make_neighbor_bfs_visitor(Visitors vis) { return neighbor_bfs_visitor< Visitors >(vis); } namespace detail { template < class BidirectionalGraph, class Buffer, class BFSVisitor, class ColorMap > void neighbor_bfs_impl(const BidirectionalGraph& g, typename graph_traits< BidirectionalGraph >::vertex_descriptor s, Buffer& Q, BFSVisitor vis, ColorMap color) { BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< BidirectionalGraph >)); typedef graph_traits< BidirectionalGraph > GTraits; typedef typename GTraits::vertex_descriptor Vertex; typedef typename GTraits::edge_descriptor Edge; BOOST_CONCEPT_ASSERT( (NeighborBFSVisitorConcept< BFSVisitor, BidirectionalGraph >)); BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< ColorMap, Vertex >)); typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; put(color, s, Color::gray()); vis.discover_vertex(s, g); Q.push(s); while (!Q.empty()) { Vertex u = Q.top(); Q.pop(); // pop before push to avoid problem if Q is priority_queue. vis.examine_vertex(u, g); typename GTraits::out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) { Edge e = *ei; vis.examine_out_edge(e, g); Vertex v = target(e, g); ColorValue v_color = get(color, v); if (v_color == Color::white()) { vis.tree_out_edge(e, g); put(color, v, Color::gray()); vis.discover_vertex(v, g); Q.push(v); } else { vis.non_tree_out_edge(e, g); if (v_color == Color::gray()) vis.gray_target(e, g); else vis.black_target(e, g); } } // for out-edges typename GTraits::in_edge_iterator in_ei, in_ei_end; for (boost::tie(in_ei, in_ei_end) = in_edges(u, g); in_ei != in_ei_end; ++in_ei) { Edge e = *in_ei; vis.examine_in_edge(e, g); Vertex v = source(e, g); ColorValue v_color = get(color, v); if (v_color == Color::white()) { vis.tree_in_edge(e, g); put(color, v, Color::gray()); vis.discover_vertex(v, g); Q.push(v); } else { vis.non_tree_in_edge(e, g); if (v_color == Color::gray()) vis.gray_source(e, g); else vis.black_source(e, g); } } // for in-edges put(color, u, Color::black()); vis.finish_vertex(u, g); } // while } template < class VertexListGraph, class ColorMap, class BFSVisitor, class P, class T, class R > void neighbor_bfs_helper(VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, ColorMap color, BFSVisitor vis, const bgl_named_params< P, T, R >& params) { typedef graph_traits< VertexListGraph > Traits; // Buffer default typedef typename Traits::vertex_descriptor Vertex; typedef boost::queue< Vertex > queue_t; queue_t Q; // Initialization typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; typename boost::graph_traits< VertexListGraph >::vertex_iterator i, i_end; for (boost::tie(i, i_end) = vertices(g); i != i_end; ++i) { put(color, *i, Color::white()); vis.initialize_vertex(*i, g); } neighbor_bfs_impl(g, s, choose_param(get_param(params, buffer_param_t()), boost::ref(Q)) .get(), vis, color); } //------------------------------------------------------------------------- // Choose between default color and color parameters. Using // function dispatching so that we don't require vertex index if // the color default is not being used. template < class ColorMap > struct neighbor_bfs_dispatch { template < class VertexListGraph, class P, class T, class R > static void apply(VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, const bgl_named_params< P, T, R >& params, ColorMap color) { neighbor_bfs_helper(g, s, color, choose_param(get_param(params, graph_visitor), make_neighbor_bfs_visitor(null_visitor())), params); } }; template <> struct neighbor_bfs_dispatch< param_not_found > { template < class VertexListGraph, class P, class T, class R > static void apply(VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, const bgl_named_params< P, T, R >& params, param_not_found) { std::vector< default_color_type > color_vec(num_vertices(g)); null_visitor null_vis; neighbor_bfs_helper(g, s, make_iterator_property_map(color_vec.begin(), choose_const_pmap( get_param(params, vertex_index), g, vertex_index), color_vec[0]), choose_param(get_param(params, graph_visitor), make_neighbor_bfs_visitor(null_vis)), params); } }; } // namespace detail // Named Parameter Variant template < class VertexListGraph, class P, class T, class R > void neighbor_breadth_first_search(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, const bgl_named_params< P, T, R >& params) { // The graph is passed by *const* reference so that graph adaptors // (temporaries) can be passed into this function. However, the // graph is not really const since we may write to property maps // of the graph. VertexListGraph& ng = const_cast< VertexListGraph& >(g); typedef typename get_param_type< vertex_color_t, bgl_named_params< P, T, R > >::type C; detail::neighbor_bfs_dispatch< C >::apply( ng, s, params, get_param(params, vertex_color)); } // This version does not initialize colors, user has to. template < class IncidenceGraph, class P, class T, class R > void neighbor_breadth_first_visit(IncidenceGraph& g, typename graph_traits< IncidenceGraph >::vertex_descriptor s, const bgl_named_params< P, T, R >& params) { typedef graph_traits< IncidenceGraph > Traits; // Buffer default typedef boost::queue< typename Traits::vertex_descriptor > queue_t; queue_t Q; detail::neighbor_bfs_impl(g, s, choose_param(get_param(params, buffer_param_t()), boost::ref(Q)).get(), choose_param(get_param(params, graph_visitor), make_neighbor_bfs_visitor(null_visitor())), choose_pmap(get_param(params, vertex_color), g, vertex_color)); } } // namespace boost #endif // BOOST_GRAPH_NEIGHBOR_BREADTH_FIRST_SEARCH_HPP st_connected.hpp 0000644 00000005444 15125521275 0007741 0 ustar 00 // Copyright (C) 2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_DISTRIBUTED_ST_CONNECTED_HPP #define BOOST_GRAPH_DISTRIBUTED_ST_CONNECTED_HPP #include <boost/graph/graph_traits.hpp> #include <boost/graph/two_bit_color_map.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/pending/queue.hpp> namespace boost { namespace graph { template < typename Graph, typename ColorMap > bool st_connected(const Graph& g, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, ColorMap color) { typedef typename property_traits< ColorMap >::value_type Color; typedef color_traits< Color > ColorTraits; typedef typename graph_traits< Graph >::vertex_descriptor Vertex; // Set all vertices to white (unvisited) BGL_FORALL_VERTICES_T(v, g, Graph) put(color, v, ColorTraits::white()); // Vertices found from the source are grey put(color, s, ColorTraits::gray()); // Vertices found from the target are greeen put(color, t, ColorTraits::green()); queue< Vertex > Q; Q.push(s); Q.push(t); while (!Q.empty()) { Vertex u = Q.top(); Q.pop(); Color u_color = get(color, u); BGL_FORALL_OUTEDGES_T(u, e, g, Graph) { Vertex v = target(e, g); Color v_color = get(color, v); if (v_color == ColorTraits::white()) { // We have not seen "v" before; mark it with the same color // as u Color u_color = get(color, u); put(color, v, u_color); // Push it on the queue Q.push(v); } else if (v_color != ColorTraits::black() && u_color != v_color) { // Colors have collided. We're done! return true; } } // u is done, so mark it black put(color, u, ColorTraits::black()); } return false; } template < typename Graph > inline bool st_connected(const Graph& g, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t) { return st_connected(g, s, t, make_two_bit_color_map(num_vertices(g), get(vertex_index, g))); } } } // end namespace boost::graph #endif // BOOST_GRAPH_DISTRIBUTED_ST_CONNECTED_HPP vertex_and_edge_range.hpp 0000644 00000012630 15125521275 0011563 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_VERTEX_AND_EDGE_RANGE_HPP #define BOOST_GRAPH_VERTEX_AND_EDGE_RANGE_HPP #include <boost/graph/graph_traits.hpp> #include <iterator> namespace boost { namespace graph { template < typename Graph, typename VertexIterator, typename EdgeIterator > class vertex_and_edge_range { typedef graph_traits< Graph > traits_type; public: typedef typename traits_type::directed_category directed_category; typedef typename traits_type::edge_parallel_category edge_parallel_category; struct traversal_category : public virtual vertex_list_graph_tag, public virtual edge_list_graph_tag { }; typedef std::size_t vertices_size_type; typedef VertexIterator vertex_iterator; typedef typename std::iterator_traits< VertexIterator >::value_type vertex_descriptor; typedef EdgeIterator edge_iterator; typedef typename std::iterator_traits< EdgeIterator >::value_type edge_descriptor; typedef std::size_t edges_size_type; typedef void adjacency_iterator; typedef void out_edge_iterator; typedef void in_edge_iterator; typedef void degree_size_type; static vertex_descriptor null_vertex() { return traits_type::null_vertex(); } vertex_and_edge_range(const Graph& g, VertexIterator first_v, VertexIterator last_v, vertices_size_type n, EdgeIterator first_e, EdgeIterator last_e, edges_size_type m) : g(&g) , first_vertex(first_v) , last_vertex(last_v) , m_num_vertices(n) , first_edge(first_e) , last_edge(last_e) , m_num_edges(m) { } vertex_and_edge_range(const Graph& g, VertexIterator first_v, VertexIterator last_v, EdgeIterator first_e, EdgeIterator last_e) : g(&g) , first_vertex(first_v) , last_vertex(last_v) , first_edge(first_e) , last_edge(last_e) { m_num_vertices = std::distance(first_v, last_v); m_num_edges = std::distance(first_e, last_e); } const Graph* g; vertex_iterator first_vertex; vertex_iterator last_vertex; vertices_size_type m_num_vertices; edge_iterator first_edge; edge_iterator last_edge; edges_size_type m_num_edges; }; template < typename Graph, typename VertexIterator, typename EdgeIterator > inline std::pair< VertexIterator, VertexIterator > vertices( const vertex_and_edge_range< Graph, VertexIterator, EdgeIterator >& g) { return std::make_pair(g.first_vertex, g.last_vertex); } template < typename Graph, typename VertexIterator, typename EdgeIterator > inline typename vertex_and_edge_range< Graph, VertexIterator, EdgeIterator >::vertices_size_type num_vertices( const vertex_and_edge_range< Graph, VertexIterator, EdgeIterator >& g) { return g.m_num_vertices; } template < typename Graph, typename VertexIterator, typename EdgeIterator > inline std::pair< EdgeIterator, EdgeIterator > edges( const vertex_and_edge_range< Graph, VertexIterator, EdgeIterator >& g) { return std::make_pair(g.first_edge, g.last_edge); } template < typename Graph, typename VertexIterator, typename EdgeIterator > inline typename vertex_and_edge_range< Graph, VertexIterator, EdgeIterator >::edges_size_type num_edges( const vertex_and_edge_range< Graph, VertexIterator, EdgeIterator >& g) { return g.m_num_edges; } template < typename Graph, typename VertexIterator, typename EdgeIterator > inline typename vertex_and_edge_range< Graph, VertexIterator, EdgeIterator >::vertex_descriptor source(typename vertex_and_edge_range< Graph, VertexIterator, EdgeIterator >::edge_descriptor e, const vertex_and_edge_range< Graph, VertexIterator, EdgeIterator >& g) { return source(e, *g.g); } template < typename Graph, typename VertexIterator, typename EdgeIterator > inline typename vertex_and_edge_range< Graph, VertexIterator, EdgeIterator >::vertex_descriptor target(typename vertex_and_edge_range< Graph, VertexIterator, EdgeIterator >::edge_descriptor e, const vertex_and_edge_range< Graph, VertexIterator, EdgeIterator >& g) { return target(e, *g.g); } template < typename Graph, typename VertexIterator, typename EdgeIterator > inline vertex_and_edge_range< Graph, VertexIterator, EdgeIterator > make_vertex_and_edge_range(const Graph& g, VertexIterator first_v, VertexIterator last_v, EdgeIterator first_e, EdgeIterator last_e) { typedef vertex_and_edge_range< Graph, VertexIterator, EdgeIterator > result_type; return result_type(g, first_v, last_v, first_e, last_e); } } // end namespace graph using graph::make_vertex_and_edge_range; using graph::vertex_and_edge_range; } // end namespace boost #endif // BOOST_GRAPH_VERTEX_AND_EDGE_RANGE_HPP create_condensation_graph.hpp 0000644 00000006127 15125521275 0012460 0 ustar 00 //======================================================================= // Copyright 2002 Indiana University. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_CREATE_CONDENSATION_GRAPH_HPP #define BOOST_CREATE_CONDENSATION_GRAPH_HPP #include <boost/graph/graph_traits.hpp> #include <boost/property_map/property_map.hpp> namespace boost { template < typename Graph, typename ComponentLists, typename ComponentNumberMap, typename CondensationGraph, typename EdgeMultiplicityMap > void create_condensation_graph(const Graph& g, const ComponentLists& components, ComponentNumberMap component_number, CondensationGraph& cg, EdgeMultiplicityMap edge_mult_map) { typedef typename graph_traits< Graph >::vertex_descriptor vertex; typedef typename graph_traits< Graph >::vertices_size_type size_type; typedef typename graph_traits< CondensationGraph >::vertex_descriptor cg_vertex; std::vector< cg_vertex > to_cg_vertex(components.size()); for (size_type s = 0; s < components.size(); ++s) to_cg_vertex[s] = add_vertex(cg); for (size_type si = 0; si < components.size(); ++si) { cg_vertex s = to_cg_vertex[si]; std::vector< cg_vertex > adj; for (size_type i = 0; i < components[si].size(); ++i) { vertex u = components[s][i]; typename graph_traits< Graph >::adjacency_iterator v, v_end; for (boost::tie(v, v_end) = adjacent_vertices(u, g); v != v_end; ++v) { cg_vertex t = to_cg_vertex[component_number[*v]]; if (s != t) // Avoid loops in the condensation graph adj.push_back(t); } } std::sort(adj.begin(), adj.end()); if (!adj.empty()) { size_type i = 0; cg_vertex t = adj[i]; typename graph_traits< CondensationGraph >::edge_descriptor e; bool inserted; boost::tie(e, inserted) = add_edge(s, t, cg); put(edge_mult_map, e, 1); ++i; while (i < adj.size()) { if (adj[i] == t) put(edge_mult_map, e, get(edge_mult_map, e) + 1); else { t = adj[i]; boost::tie(e, inserted) = add_edge(s, t, cg); put(edge_mult_map, e, 1); } ++i; } } } } template < typename Graph, typename ComponentLists, typename ComponentNumberMap, typename CondensationGraph > void create_condensation_graph(const Graph& g, const ComponentLists& components, ComponentNumberMap component_number, CondensationGraph& cg) { create_condensation_graph( g, components, component_number, cg, dummy_property_map()); } } // namespace boost #endif // BOOST_CREATE_CONDENSATION_GRAPH_HPP maximum_adjacency_search.hpp 0000644 00000035425 15125521275 0012276 0 ustar 00 // //======================================================================= // Copyright 2012 Fernando Vilas // 2010 Daniel Trebbien // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // // The maximum adjacency search algorithm was originally part of the // Stoer-Wagner min cut implementation by Daniel Trebbien. It has been // broken out into its own file to be a public search algorithm, with // visitor concepts. #ifndef BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H #define BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H /** * This is an implementation of the maximum adjacency search on an * undirected graph. It allows a visitor object to perform some * operation on each vertex as that vertex is visited. * * The algorithm runs as follows: * * Initialize all nodes to be unvisited (reach count = 0) * and call vis.initialize_vertex * For i = number of nodes in graph downto 1 * Select the unvisited node with the highest reach count * The user provides the starting node to break the first tie, * but future ties are broken arbitrarily * Visit the node by calling vis.start_vertex * Increment the reach count for all unvisited neighbors * and call vis.examine_edge for each of these edges * Mark the node as visited and call vis.finish_vertex * */ #include <boost/concept_check.hpp> #include <boost/concept/assert.hpp> #include <boost/graph/buffer_concepts.hpp> #include <boost/graph/exception.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/graph/visitors.hpp> #include <boost/tuple/tuple.hpp> #include <set> namespace boost { template < class Visitor, class Graph > struct MASVisitorConcept { void constraints() { boost::function_requires< boost::CopyConstructibleConcept< Visitor > >(); vis.initialize_vertex(u, g); vis.start_vertex(u, g); vis.examine_edge(e, g); vis.finish_vertex(u, g); } Visitor vis; Graph g; typename boost::graph_traits< Graph >::vertex_descriptor u; typename boost::graph_traits< Graph >::edge_descriptor e; }; template < class Visitors = null_visitor > class mas_visitor { public: mas_visitor() {} mas_visitor(Visitors vis) : m_vis(vis) {} template < class Vertex, class Graph > void initialize_vertex(Vertex u, Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex()); } template < class Vertex, class Graph > void start_vertex(Vertex u, Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_start_vertex()); } template < class Edge, class Graph > void examine_edge(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, ::boost::on_examine_edge()); } template < class Vertex, class Graph > void finish_vertex(Vertex u, Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex()); } BOOST_GRAPH_EVENT_STUB(on_initialize_vertex, mas) BOOST_GRAPH_EVENT_STUB(on_start_vertex, mas) BOOST_GRAPH_EVENT_STUB(on_examine_edge, mas) BOOST_GRAPH_EVENT_STUB(on_finish_vertex, mas) protected: Visitors m_vis; }; template < class Visitors > mas_visitor< Visitors > make_mas_visitor(Visitors vis) { return mas_visitor< Visitors >(vis); } typedef mas_visitor<> default_mas_visitor; namespace detail { template < class Graph, class WeightMap, class MASVisitor, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue > void maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis, const typename boost::graph_traits< Graph >::vertex_descriptor start, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq) { typedef typename boost::graph_traits< Graph >::vertex_descriptor vertex_descriptor; typedef typename boost::property_traits< WeightMap >::value_type weight_type; std::set< vertex_descriptor > assignedVertices; // initialize `assignments` (all vertices are initially // assigned to themselves) BGL_FORALL_VERTICES_T(v, g, Graph) { put(assignments, v, v); } typename KeyedUpdatablePriorityQueue::key_map keys = pq.keys(); // set number of visited neighbors for all vertices to 0 BGL_FORALL_VERTICES_T(v, g, Graph) { if (v == get(assignments, v)) { // foreach u \in V do put(keys, v, weight_type(0)); vis.initialize_vertex(v, g); pq.push(v); } } BOOST_ASSERT(pq.size() >= 2); // Give the starting vertex high priority put(keys, start, get(keys, start) + num_vertices(g) + 1); pq.update(start); // start traversing the graph // vertex_descriptor s, t; // weight_type w; while (!pq.empty()) { // while PQ \neq {} do const vertex_descriptor u = pq.top(); // u = extractmax(PQ) /* weight_type w = */ get(keys, u); vis.start_vertex(u, g); pq.pop(); // vis.start_vertex(u, g); BGL_FORALL_OUTEDGES_T(u, e, g, Graph) { // foreach (u, v) \in E do vis.examine_edge(e, g); const vertex_descriptor v = get(assignments, target(e, g)); if (pq.contains(v)) { // if v \in PQ then put(keys, v, get(keys, v) + get(weights, e)); // increasekey(PQ, v, wA(v) + w(u, v)) pq.update(v); } } typename std::set< vertex_descriptor >::const_iterator assignedVertexIt, assignedVertexEnd = assignedVertices.end(); for (assignedVertexIt = assignedVertices.begin(); assignedVertexIt != assignedVertexEnd; ++assignedVertexIt) { const vertex_descriptor uPrime = *assignedVertexIt; if (get(assignments, uPrime) == u) { BGL_FORALL_OUTEDGES_T(uPrime, e, g, Graph) { // foreach (u, v) \in E do vis.examine_edge(e, g); const vertex_descriptor v = get(assignments, target(e, g)); if (pq.contains(v)) { // if v \in PQ then put(keys, v, get(keys, v) + get(weights, e)); // increasekey(PQ, v, // wA(v) + w(u, v)) pq.update(v); } } } } vis.finish_vertex(u, g); } } } // end namespace detail template < class Graph, class WeightMap, class MASVisitor, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue > void maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis, const typename boost::graph_traits< Graph >::vertex_descriptor start, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq) { BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept< Graph >)); BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept< Graph >)); typedef typename boost::graph_traits< Graph >::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits< Graph >::vertices_size_type vertices_size_type; typedef typename boost::graph_traits< Graph >::edge_descriptor edge_descriptor; BOOST_CONCEPT_ASSERT((boost::Convertible< typename boost::graph_traits< Graph >::directed_category, boost::undirected_tag >)); BOOST_CONCEPT_ASSERT( (boost::ReadablePropertyMapConcept< WeightMap, edge_descriptor >)); // typedef typename boost::property_traits<WeightMap>::value_type // weight_type; boost::function_requires< MASVisitorConcept< MASVisitor, Graph > >(); BOOST_CONCEPT_ASSERT( (boost::ReadWritePropertyMapConcept< VertexAssignmentMap, vertex_descriptor >)); BOOST_CONCEPT_ASSERT((boost::Convertible< vertex_descriptor, typename boost::property_traits< VertexAssignmentMap >::value_type >)); BOOST_CONCEPT_ASSERT( (boost::KeyedUpdatableQueueConcept< KeyedUpdatablePriorityQueue >)); vertices_size_type n = num_vertices(g); if (n < 2) throw boost::bad_graph( "the input graph must have at least two vertices."); else if (!pq.empty()) throw std::invalid_argument( "the max-priority queue must be empty initially."); detail::maximum_adjacency_search(g, weights, vis, start, assignments, pq); } namespace graph { namespace detail { template < typename WeightMap > struct mas_dispatch { typedef void result_type; template < typename Graph, typename ArgPack > static result_type apply(const Graph& g, // const bgl_named_params<P,T,R>& params, const ArgPack& params, WeightMap w) { using namespace boost::graph::keywords; typedef typename boost::graph_traits< Graph >::vertex_descriptor vertex_descriptor; typedef typename WeightMap::value_type weight_type; typedef boost::detail::make_priority_queue_from_arg_pack_gen< boost::graph::keywords::tag::max_priority_queue, weight_type, vertex_descriptor, std::greater< weight_type > > default_pq_gen_type; default_pq_gen_type pq_gen( choose_param(get_param(params, boost::distance_zero_t()), weight_type(0))); typename boost::result_of< default_pq_gen_type( const Graph&, const ArgPack&) >::type pq = pq_gen(g, params); boost::null_visitor null_vis; boost::mas_visitor< boost::null_visitor > default_visitor( null_vis); vertex_descriptor v = vertex_descriptor(); boost::detail::make_property_map_from_arg_pack_gen< boost::graph::keywords::tag::vertex_assignment_map, vertex_descriptor > map_gen(v); typename boost::detail::map_maker< Graph, ArgPack, boost::graph::keywords::tag::vertex_assignment_map, vertex_descriptor >::map_type default_map = map_gen(g, params); boost::maximum_adjacency_search(g, w, params[_visitor | default_visitor], params[_root_vertex | *vertices(g).first], params[_vertex_assignment_map | default_map], pq); } }; template <> struct mas_dispatch< boost::param_not_found > { typedef void result_type; template < typename Graph, typename ArgPack > static result_type apply( const Graph& g, const ArgPack& params, param_not_found) { using namespace boost::graph::keywords; typedef typename boost::graph_traits< Graph >::vertex_descriptor vertex_descriptor; // get edge_weight_t as the weight type typedef typename boost::property_map< Graph, edge_weight_t > WeightMap; typedef typename WeightMap::value_type weight_type; typedef boost::detail::make_priority_queue_from_arg_pack_gen< boost::graph::keywords::tag::max_priority_queue, weight_type, vertex_descriptor, std::greater< weight_type > > default_pq_gen_type; default_pq_gen_type pq_gen( choose_param(get_param(params, boost::distance_zero_t()), weight_type(0))); typename boost::result_of< default_pq_gen_type( const Graph&, const ArgPack&) >::type pq = pq_gen(g, params); boost::null_visitor null_vis; boost::mas_visitor< boost::null_visitor > default_visitor( null_vis); vertex_descriptor v = vertex_descriptor(); boost::detail::make_property_map_from_arg_pack_gen< boost::graph::keywords::tag::vertex_assignment_map, vertex_descriptor > map_gen(v); typename boost::detail::map_maker< Graph, ArgPack, boost::graph::keywords::tag::vertex_assignment_map, vertex_descriptor >::map_type default_map = map_gen(g, params); boost::maximum_adjacency_search(g, get(edge_weight, g), params[_visitor | default_visitor], params[_root_vertex | *vertices(g).first], params[_vertex_assignment_map | default_map], pq); } }; } // end namespace detail } // end namespace graph // Named parameter interface // BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(maximum_adjacency_search, 1) template < typename Graph, typename P, typename T, typename R > void maximum_adjacency_search( const Graph& g, const bgl_named_params< P, T, R >& params) { typedef bgl_named_params< P, T, R > params_type; BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params) // do the dispatch based on WeightMap typedef typename get_param_type< edge_weight_t, bgl_named_params< P, T, R > >::type W; graph::detail::mas_dispatch< W >::apply( g, arg_pack, get_param(params, edge_weight)); } namespace graph { namespace detail { template < typename Graph > struct maximum_adjacency_search_impl { typedef void result_type; template < typename ArgPack > void operator()(const Graph& g, const ArgPack& arg_pack) const { // call the function that does the dispatching typedef typename get_param_type< edge_weight_t, ArgPack >::type W; graph::detail::mas_dispatch< W >::apply( g, arg_pack, get_param(arg_pack, edge_weight)); } }; } // end namespace detail BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(maximum_adjacency_search, 1, 5) } // end namespace graph } // end namespace boost #include <boost/graph/iteration_macros_undef.hpp> #endif // BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H chrobak_payne_drawing.hpp 0000644 00000020701 15125521275 0011602 0 ustar 00 //======================================================================= // Copyright (c) Aaron Windsor 2007 // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef __CHROBAK_PAYNE_DRAWING_HPP__ #define __CHROBAK_PAYNE_DRAWING_HPP__ #include <vector> #include <list> #include <stack> #include <boost/config.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/property_map/property_map.hpp> namespace boost { namespace graph { namespace detail { template < typename Graph, typename VertexToVertexMap, typename VertexTo1DCoordMap > void accumulate_offsets( typename graph_traits< Graph >::vertex_descriptor v, std::size_t offset, const Graph& g, VertexTo1DCoordMap x, VertexTo1DCoordMap delta_x, VertexToVertexMap left, VertexToVertexMap right) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; // Suggestion of explicit stack from Aaron Windsor to avoid system // stack overflows. typedef std::pair< vertex_descriptor, std::size_t > stack_entry; std::stack< stack_entry > st; st.push(stack_entry(v, offset)); while (!st.empty()) { vertex_descriptor v = st.top().first; std::size_t offset = st.top().second; st.pop(); if (v != graph_traits< Graph >::null_vertex()) { x[v] += delta_x[v] + offset; st.push(stack_entry(left[v], x[v])); st.push(stack_entry(right[v], x[v])); } } } } /*namespace detail*/ } /*namespace graph*/ template < typename Graph, typename PlanarEmbedding, typename ForwardIterator, typename GridPositionMap, typename VertexIndexMap > void chrobak_payne_straight_line_drawing(const Graph& g, PlanarEmbedding embedding, ForwardIterator ordering_begin, ForwardIterator ordering_end, GridPositionMap drawing, VertexIndexMap vm) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; typedef typename PlanarEmbedding::value_type::const_iterator edge_permutation_iterator_t; typedef typename graph_traits< Graph >::vertices_size_type v_size_t; typedef std::vector< vertex_t > vertex_vector_t; typedef std::vector< v_size_t > vsize_vector_t; typedef std::vector< bool > bool_vector_t; typedef boost::iterator_property_map< typename vertex_vector_t::iterator, VertexIndexMap > vertex_to_vertex_map_t; typedef boost::iterator_property_map< typename vsize_vector_t::iterator, VertexIndexMap > vertex_to_vsize_map_t; typedef boost::iterator_property_map< typename bool_vector_t::iterator, VertexIndexMap > vertex_to_bool_map_t; vertex_vector_t left_vector( num_vertices(g), graph_traits< Graph >::null_vertex()); vertex_vector_t right_vector( num_vertices(g), graph_traits< Graph >::null_vertex()); vsize_vector_t seen_as_right_vector(num_vertices(g), 0); vsize_vector_t seen_vector(num_vertices(g), 0); vsize_vector_t delta_x_vector(num_vertices(g), 0); vsize_vector_t y_vector(num_vertices(g)); vsize_vector_t x_vector(num_vertices(g), 0); bool_vector_t installed_vector(num_vertices(g), false); vertex_to_vertex_map_t left(left_vector.begin(), vm); vertex_to_vertex_map_t right(right_vector.begin(), vm); vertex_to_vsize_map_t seen_as_right(seen_as_right_vector.begin(), vm); vertex_to_vsize_map_t seen(seen_vector.begin(), vm); vertex_to_vsize_map_t delta_x(delta_x_vector.begin(), vm); vertex_to_vsize_map_t y(y_vector.begin(), vm); vertex_to_vsize_map_t x(x_vector.begin(), vm); vertex_to_bool_map_t installed(installed_vector.begin(), vm); v_size_t timestamp = 1; vertex_vector_t installed_neighbors; ForwardIterator itr = ordering_begin; vertex_t v1 = *itr; ++itr; vertex_t v2 = *itr; ++itr; vertex_t v3 = *itr; ++itr; delta_x[v2] = 1; delta_x[v3] = 1; y[v1] = 0; y[v2] = 0; y[v3] = 1; right[v1] = v3; right[v3] = v2; installed[v1] = installed[v2] = installed[v3] = true; for (ForwardIterator itr_end = ordering_end; itr != itr_end; ++itr) { vertex_t v = *itr; // First, find the leftmost and rightmost neighbor of v on the outer // cycle of the embedding. // Note: since we're moving clockwise through the edges adjacent to v, // we're actually moving from right to left among v's neighbors on the // outer face (since v will be installed above them all) looking for // the leftmost and rightmost installed neigbhors vertex_t leftmost = graph_traits< Graph >::null_vertex(); vertex_t rightmost = graph_traits< Graph >::null_vertex(); installed_neighbors.clear(); vertex_t prev_vertex = graph_traits< Graph >::null_vertex(); edge_permutation_iterator_t pi, pi_end; pi_end = embedding[v].end(); for (pi = embedding[v].begin(); pi != pi_end; ++pi) { vertex_t curr_vertex = source(*pi, g) == v ? target(*pi, g) : source(*pi, g); // Skip any self-loops or parallel edges if (curr_vertex == v || curr_vertex == prev_vertex) continue; if (installed[curr_vertex]) { seen[curr_vertex] = timestamp; if (right[curr_vertex] != graph_traits< Graph >::null_vertex()) { seen_as_right[right[curr_vertex]] = timestamp; } installed_neighbors.push_back(curr_vertex); } prev_vertex = curr_vertex; } typename vertex_vector_t::iterator vi, vi_end; vi_end = installed_neighbors.end(); for (vi = installed_neighbors.begin(); vi != vi_end; ++vi) { if (right[*vi] == graph_traits< Graph >::null_vertex() || seen[right[*vi]] != timestamp) rightmost = *vi; if (seen_as_right[*vi] != timestamp) leftmost = *vi; } ++timestamp; // stretch gaps ++delta_x[right[leftmost]]; ++delta_x[rightmost]; // adjust offsets std::size_t delta_p_q = 0; vertex_t stopping_vertex = right[rightmost]; for (vertex_t temp = right[leftmost]; temp != stopping_vertex; temp = right[temp]) { delta_p_q += delta_x[temp]; } delta_x[v] = ((y[rightmost] + delta_p_q) - y[leftmost]) / 2; y[v] = y[leftmost] + delta_x[v]; delta_x[rightmost] = delta_p_q - delta_x[v]; bool leftmost_and_rightmost_adjacent = right[leftmost] == rightmost; if (!leftmost_and_rightmost_adjacent) delta_x[right[leftmost]] -= delta_x[v]; // install v if (!leftmost_and_rightmost_adjacent) { left[v] = right[leftmost]; vertex_t next_to_rightmost; for (vertex_t temp = leftmost; temp != rightmost; temp = right[temp]) { next_to_rightmost = temp; } right[next_to_rightmost] = graph_traits< Graph >::null_vertex(); } else { left[v] = graph_traits< Graph >::null_vertex(); } right[leftmost] = v; right[v] = rightmost; installed[v] = true; } graph::detail::accumulate_offsets( *ordering_begin, 0, g, x, delta_x, left, right); vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { vertex_t v(*vi); drawing[v].x = x[v]; drawing[v].y = y[v]; } } template < typename Graph, typename PlanarEmbedding, typename ForwardIterator, typename GridPositionMap > inline void chrobak_payne_straight_line_drawing(const Graph& g, PlanarEmbedding embedding, ForwardIterator ord_begin, ForwardIterator ord_end, GridPositionMap drawing) { chrobak_payne_straight_line_drawing( g, embedding, ord_begin, ord_end, drawing, get(vertex_index, g)); } } // namespace boost #endif //__CHROBAK_PAYNE_DRAWING_HPP__ graph_stats.hpp 0000644 00000010452 15125521275 0007603 0 ustar 00 // Copyright 2005 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Alex Breuer // Andrew Lumsdaine #ifndef BOOST_GRAPH_GRAPH_STATS_HPP #define BOOST_GRAPH_GRAPH_STATS_HPP #include <map> #include <list> #include <boost/graph/iteration_macros.hpp> #include <boost/assert.hpp> namespace boost { namespace graph { template < typename Graph > struct sort_edge_by_origin { public: typedef typename graph_traits< Graph >::edge_descriptor edge_type; explicit sort_edge_by_origin(Graph& g) : g(g) {} inline bool operator()(edge_type a, edge_type b) { return source(a, g) == source(b, g) ? target(a, g) < target(b, g) : source(a, g) < source(b, g); } private: Graph& g; }; template < typename Graph > struct equal_edge { public: typedef typename graph_traits< Graph >::edge_descriptor edge_type; explicit equal_edge(Graph& g) : g(g) {} inline bool operator()(edge_type a, edge_type b) { return source(a, g) == source(b, g) && target(a, g) == target(b, g); } private: Graph& g; }; template < typename Graph > unsigned long num_dup_edges(Graph& g) { typedef typename graph_traits< Graph >::edge_iterator e_iterator_type; typedef typename graph_traits< Graph >::edge_descriptor edge_type; std::list< edge_type > all_edges; BGL_FORALL_EDGES_T(e, g, Graph) { all_edges.push_back(e); } sort_edge_by_origin< Graph > cmp1(g); all_edges.sort(cmp1); equal_edge< Graph > cmp2(g); all_edges.unique(cmp2); return num_edges(g) - all_edges.size(); } template < typename Graph > std::map< unsigned long, unsigned long > dup_edge_dist(Graph& g) { std::map< unsigned long, unsigned long > dist; typedef typename graph_traits< Graph >::adjacency_iterator a_iterator_type; typedef typename graph_traits< Graph >::vertex_descriptor vertex_type; BGL_FORALL_VERTICES_T(v, g, Graph) { std::list< vertex_type > front_neighbors; a_iterator_type a_iter, a_end; for (boost::tie(a_iter, a_end) = adjacent_vertices(v, g); a_iter != a_end; ++a_iter) { front_neighbors.push_back(*a_iter); } front_neighbors.sort(); front_neighbors.unique(); dist[out_degree(v, g) - front_neighbors.size()] += 1; } return dist; } template < typename Graph > std::map< unsigned long, unsigned long > degree_dist(Graph& g) { std::map< unsigned long, unsigned long > dist; typedef typename graph_traits< Graph >::adjacency_iterator a_iterator_type; typedef typename graph_traits< Graph >::vertex_descriptor vertex_type; BGL_FORALL_VERTICES_T(v, g, Graph) { dist[out_degree(v, g)] += 1; } return dist; } template < typename Graph > std::map< unsigned long, double > weight_degree_dist(Graph& g) { std::map< unsigned long, double > dist, n; typedef typename graph_traits< Graph >::adjacency_iterator a_iterator_type; typedef typename graph_traits< Graph >::vertex_descriptor vertex_type; typedef typename property_map< Graph, edge_weight_t >::const_type edge_map_type; typedef typename property_traits< edge_map_type >::value_type edge_weight_type; typename property_map< Graph, edge_weight_t >::type em = get(edge_weight, g); BGL_FORALL_VERTICES_T(v, g, Graph) { edge_weight_type tmp = 0; BGL_FORALL_OUTEDGES_T(v, e, g, Graph) { tmp += em[e]; } n[out_degree(v, g)] += 1.; dist[out_degree(v, g)] += tmp; } for (std::map< unsigned long, double >::iterator iter = dist.begin(); iter != dist.end(); ++iter) { BOOST_ASSERT(n[iter->first] != 0); dist[iter->first] /= n[iter->first]; } return dist; } } } #endif profile.hpp 0000644 00000002457 15125521275 0006732 0 ustar 00 // //======================================================================= // Copyright 2002 Marc Wintermantel (wintermantel@even-ag.ch) // ETH Zurich, Center of Structure Technologies // (https://web.archive.org/web/20050307090307/http://www.structures.ethz.ch/) // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_PROFILE_HPP #define BOOST_GRAPH_PROFILE_HPP #include <boost/graph/graph_traits.hpp> #include <boost/detail/numeric_traits.hpp> #include <boost/graph/bandwidth.hpp> namespace boost { template < typename Graph, typename VertexIndexMap > typename graph_traits< Graph >::vertices_size_type profile( const Graph& g, VertexIndexMap index) { typename graph_traits< Graph >::vertices_size_type b = 0; typename graph_traits< Graph >::vertex_iterator i, end; for (boost::tie(i, end) = vertices(g); i != end; ++i) { b += ith_bandwidth(*i, g, index) + 1; } return b; } template < typename Graph > typename graph_traits< Graph >::vertices_size_type profile(const Graph& g) { return profile(g, get(vertex_index, g)); } } // namespace boost #endif // BOOST_GRAPH_PROFILE_HPP matrix_as_graph.hpp 0000644 00000016073 15125521275 0010441 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_MATRIX2GRAPH_HPP #define BOOST_GRAPH_MATRIX2GRAPH_HPP #include <utility> #include <cstddef> #include <iterator> #include <boost/config.hpp> #include <boost/operators.hpp> #include <boost/pending/detail/int_iterator.hpp> #include <boost/graph/graph_traits.hpp> namespace boost { template < class Iter, class Vertex > class matrix_adj_iterator; template < class Iter, class Vertex > class matrix_incidence_iterator; } #define BOOST_GRAPH_ADAPT_MATRIX_TO_GRAPH(Matrix) \ namespace boost \ { \ template <> struct graph_traits< Matrix > \ { \ typedef Matrix::OneD::const_iterator Iter; \ typedef Matrix::size_type V; \ typedef V vertex_descriptor; \ typedef Iter E; \ typedef E edge_descriptor; \ typedef boost::matrix_incidence_iterator< Iter, V > \ out_edge_iterator; \ typedef boost::matrix_adj_iterator< Iter, V > adjacency_iterator; \ typedef Matrix::size_type size_type; \ typedef boost::int_iterator< size_type > vertex_iterator; \ \ friend std::pair< vertex_iterator, vertex_iterator > vertices( \ const Matrix& g) \ { \ typedef vertex_iterator VIter; \ return std::make_pair(VIter(0), VIter(g.nrows())); \ } \ \ friend std::pair< out_edge_iterator, out_edge_iterator > \ out_edges(V v, const Matrix& g) \ { \ typedef out_edge_iterator IncIter; \ return std::make_pair( \ IncIter(g[v].begin()), IncIter(g[v].end())); \ } \ friend std::pair< adjacency_iterator, adjacency_iterator > \ adjacent_vertices(V v, const Matrix& g) \ { \ typedef adjacency_iterator AdjIter; \ return std::make_pair( \ AdjIter(g[v].begin()), AdjIter(g[v].end())); \ } \ friend vertex_descriptor source(E e, const Matrix& g) \ { \ return e.row(); \ } \ friend vertex_descriptor target(E e, const Matrix& g) \ { \ return e.column(); \ } \ friend size_type num_vertices(const Matrix& g) \ { \ return g.nrows(); \ } \ friend size_type num_edges(const Matrix& g) { return g.nnz(); } \ friend size_type out_degree(V i, const Matrix& g) \ { \ return g[i].nnz(); \ } \ }; \ } namespace boost { template < class Iter, class Vertex > class matrix_adj_iterator { typedef matrix_adj_iterator self; public: typedef std::input_iterator_tag iterator_category; typedef Vertex value_type; typedef std::ptrdiff_t difference_type; typedef Vertex* pointer; typedef Vertex& reference; matrix_adj_iterator() {} matrix_adj_iterator(Iter i) : _iter(i) {} matrix_adj_iterator(const self& x) : _iter(x._iter) {} self& operator=(const self& x) { _iter = x._iter; return *this; } Vertex operator*() { return _iter.column(); } self& operator++() { ++_iter; return *this; } self operator++(int) { self t = *this; ++_iter; return t; } bool operator==(const self& x) const { return _iter == x._iter; } bool operator!=(const self& x) const { return _iter != x._iter; } protected: Iter _iter; }; template < class Iter, class Vertex > class matrix_incidence_iterator { typedef matrix_incidence_iterator self; public: typedef std::input_iterator_tag iterator_category; typedef Iter value_type; typedef std::ptrdiff_t difference_type; typedef Iter* pointer; typedef Iter& reference; matrix_incidence_iterator() {} matrix_incidence_iterator(Iter i) : _iter(i) {} matrix_incidence_iterator(const self& x) : _iter(x._iter) {} self& operator=(const self& x) { _iter = x._iter; return *this; } Iter operator*() { return _iter; } self& operator++() { ++_iter; return *this; } self operator++(int) { self t = *this; ++_iter; return t; } bool operator==(const self& x) const { return _iter == x._iter; } bool operator!=(const self& x) const { return _iter != x._iter; } protected: Iter _iter; }; } /* namespace boost */ #endif /* BOOST_GRAPH_MATRIX2GRAPH_HPP*/ buffer_concepts.hpp 0000644 00000004575 15125521275 0010444 0 ustar 00 // Copyright Daniel Trebbien 2010. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or the copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GRAPH_BUFFER_CONCEPTS_HPP #define BOOST_GRAPH_BUFFER_CONCEPTS_HPP 1 #include <boost/concept_check.hpp> #include <boost/property_map/property_map.hpp> #include <boost/typeof/typeof.hpp> #include <boost/type_traits/add_const.hpp> #include <boost/type_traits/add_reference.hpp> #include <boost/type_traits/remove_reference.hpp> #include <boost/concept/detail/concept_def.hpp> namespace boost { BOOST_concept(Buffer, (B)) { typedef typename B::value_type value_type; typedef typename B::size_type size_type; BOOST_CONCEPT_USAGE(Buffer) { typedef typename boost::add_reference< value_type >::type reference; BOOST_CONCEPT_ASSERT((Assignable< value_type >)); buf.push(g_ct); buf.pop(); reference t = buf.top(); boost::ignore_unused_variable_warning(t); } void const_constraints(const B& cbuf) { typedef typename boost::add_const< typename boost::remove_reference< value_type >::type >::type& const_reference; const_reference ct = cbuf.top(); s = cbuf.size(); if (cbuf.empty()) dummy = __LINE__; } int dummy; static const value_type g_ct; size_type s; B buf; }; BOOST_concept(UpdatableQueue, (Q)) : Buffer< Q > { BOOST_CONCEPT_USAGE(UpdatableQueue) { q.update(g_ct); } void const_constraints(const Q& cq) { if (cq.contains(g_ct)) dummy = __LINE__; } int dummy; static const typename Buffer< Q >::value_type g_ct; Q q; }; BOOST_concept(KeyedUpdatableQueue, (Q)) : UpdatableQueue< Q > { typedef typename Q::key_type key_type; typedef typename Q::key_map key_map; BOOST_CONCEPT_USAGE(KeyedUpdatableQueue) { BOOST_CONCEPT_ASSERT((boost::ReadWritePropertyMapConcept< key_map, typename Buffer< Q >::value_type >)); } void const_constraints(const Q& cq) { km = cq.keys(); k = get(km, g_ct); } static const typename Buffer< Q >::value_type g_ct; key_type k; key_map km; Q q; }; } // end `namespace boost` #include <boost/concept/detail/concept_undef.hpp> #endif // !BOOST_GRAPH_BUFFER_CONCEPTS_HPP max_cardinality_matching.hpp 0000644 00000074430 15125521275 0012314 0 ustar 00 //======================================================================= // Copyright (c) 2005 Aaron Windsor // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // //======================================================================= #ifndef BOOST_GRAPH_MAXIMUM_CARDINALITY_MATCHING_HPP #define BOOST_GRAPH_MAXIMUM_CARDINALITY_MATCHING_HPP #include <vector> #include <list> #include <deque> #include <algorithm> // for std::sort and std::stable_sort #include <utility> // for std::pair #include <boost/property_map/property_map.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/visitors.hpp> #include <boost/graph/depth_first_search.hpp> #include <boost/graph/filtered_graph.hpp> #include <boost/pending/disjoint_sets.hpp> #include <boost/assert.hpp> namespace boost { namespace graph { namespace detail { enum VERTEX_STATE { V_EVEN, V_ODD, V_UNREACHED }; } } // end namespace graph::detail template < typename Graph, typename MateMap, typename VertexIndexMap > typename graph_traits< Graph >::vertices_size_type matching_size( const Graph& g, MateMap mate, VertexIndexMap vm) { typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t; typedef typename graph_traits< Graph >::vertices_size_type v_size_t; v_size_t size_of_matching = 0; vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { vertex_descriptor_t v = *vi; if (get(mate, v) != graph_traits< Graph >::null_vertex() && get(vm, v) < get(vm, get(mate, v))) ++size_of_matching; } return size_of_matching; } template < typename Graph, typename MateMap > inline typename graph_traits< Graph >::vertices_size_type matching_size( const Graph& g, MateMap mate) { return matching_size(g, mate, get(vertex_index, g)); } template < typename Graph, typename MateMap, typename VertexIndexMap > bool is_a_matching(const Graph& g, MateMap mate, VertexIndexMap) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { vertex_descriptor_t v = *vi; if (get(mate, v) != graph_traits< Graph >::null_vertex() && v != get(mate, get(mate, v))) return false; } return true; } template < typename Graph, typename MateMap > inline bool is_a_matching(const Graph& g, MateMap mate) { return is_a_matching(g, mate, get(vertex_index, g)); } //*************************************************************************** //*************************************************************************** // Maximum Cardinality Matching Functors //*************************************************************************** //*************************************************************************** template < typename Graph, typename MateMap, typename VertexIndexMap = dummy_property_map > struct no_augmenting_path_finder { no_augmenting_path_finder(const Graph&, MateMap, VertexIndexMap) {} inline bool augment_matching() { return false; } template < typename PropertyMap > void get_current_matching(PropertyMap) {} }; template < typename Graph, typename MateMap, typename VertexIndexMap > class edmonds_augmenting_path_finder { // This implementation of Edmonds' matching algorithm closely // follows Tarjan's description of the algorithm in "Data // Structures and Network Algorithms." public: // generates the type of an iterator property map from vertices to type X template < typename X > struct map_vertex_to_ { typedef boost::iterator_property_map< typename std::vector< X >::iterator, VertexIndexMap > type; }; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t; typedef typename std::pair< vertex_descriptor_t, vertex_descriptor_t > vertex_pair_t; typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor_t; typedef typename graph_traits< Graph >::vertices_size_type v_size_t; typedef typename graph_traits< Graph >::edges_size_type e_size_t; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; typedef typename graph_traits< Graph >::out_edge_iterator out_edge_iterator_t; typedef typename std::deque< vertex_descriptor_t > vertex_list_t; typedef typename std::vector< edge_descriptor_t > edge_list_t; typedef typename map_vertex_to_< vertex_descriptor_t >::type vertex_to_vertex_map_t; typedef typename map_vertex_to_< int >::type vertex_to_int_map_t; typedef typename map_vertex_to_< vertex_pair_t >::type vertex_to_vertex_pair_map_t; typedef typename map_vertex_to_< v_size_t >::type vertex_to_vsize_map_t; typedef typename map_vertex_to_< e_size_t >::type vertex_to_esize_map_t; edmonds_augmenting_path_finder( const Graph& arg_g, MateMap arg_mate, VertexIndexMap arg_vm) : g(arg_g) , vm(arg_vm) , n_vertices(num_vertices(arg_g)) , mate_vector(n_vertices) , ancestor_of_v_vector(n_vertices) , ancestor_of_w_vector(n_vertices) , vertex_state_vector(n_vertices) , origin_vector(n_vertices) , pred_vector(n_vertices) , bridge_vector(n_vertices) , ds_parent_vector(n_vertices) , ds_rank_vector(n_vertices) , mate(mate_vector.begin(), vm) , ancestor_of_v(ancestor_of_v_vector.begin(), vm) , ancestor_of_w(ancestor_of_w_vector.begin(), vm) , vertex_state(vertex_state_vector.begin(), vm) , origin(origin_vector.begin(), vm) , pred(pred_vector.begin(), vm) , bridge(bridge_vector.begin(), vm) , ds_parent_map(ds_parent_vector.begin(), vm) , ds_rank_map(ds_rank_vector.begin(), vm) , ds(ds_rank_map, ds_parent_map) { vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) mate[*vi] = get(arg_mate, *vi); } bool augment_matching() { // As an optimization, some of these values can be saved from one // iteration to the next instead of being re-initialized each // iteration, allowing for "lazy blossom expansion." This is not // currently implemented. e_size_t timestamp = 0; even_edges.clear(); vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { vertex_descriptor_t u = *vi; origin[u] = u; pred[u] = u; ancestor_of_v[u] = 0; ancestor_of_w[u] = 0; ds.make_set(u); if (mate[u] == graph_traits< Graph >::null_vertex()) { vertex_state[u] = graph::detail::V_EVEN; out_edge_iterator_t ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) { if (target(*ei, g) != u) { even_edges.push_back(*ei); } } } else vertex_state[u] = graph::detail::V_UNREACHED; } // end initializations vertex_descriptor_t v, w, w_free_ancestor, v_free_ancestor; w_free_ancestor = graph_traits< Graph >::null_vertex(); v_free_ancestor = graph_traits< Graph >::null_vertex(); bool found_alternating_path = false; while (!even_edges.empty() && !found_alternating_path) { // since we push even edges onto the back of the list as // they're discovered, taking them off the back will search // for augmenting paths depth-first. edge_descriptor_t current_edge = even_edges.back(); even_edges.pop_back(); v = source(current_edge, g); w = target(current_edge, g); vertex_descriptor_t v_prime = origin[ds.find_set(v)]; vertex_descriptor_t w_prime = origin[ds.find_set(w)]; // because of the way we put all of the edges on the queue, // v_prime should be labeled V_EVEN; the following is a // little paranoid but it could happen... if (vertex_state[v_prime] != graph::detail::V_EVEN) { std::swap(v_prime, w_prime); std::swap(v, w); } if (vertex_state[w_prime] == graph::detail::V_UNREACHED) { vertex_state[w_prime] = graph::detail::V_ODD; vertex_descriptor_t w_prime_mate = mate[w_prime]; vertex_state[w_prime_mate] = graph::detail::V_EVEN; out_edge_iterator_t ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(w_prime_mate, g); ei != ei_end; ++ei) { if (target(*ei, g) != w_prime_mate) { even_edges.push_back(*ei); } } pred[w_prime] = v; } // w_prime == v_prime can happen below if we get an edge that has // been shrunk into a blossom else if (vertex_state[w_prime] == graph::detail::V_EVEN && w_prime != v_prime) { vertex_descriptor_t w_up = w_prime; vertex_descriptor_t v_up = v_prime; vertex_descriptor_t nearest_common_ancestor = graph_traits< Graph >::null_vertex(); w_free_ancestor = graph_traits< Graph >::null_vertex(); v_free_ancestor = graph_traits< Graph >::null_vertex(); // We now need to distinguish between the case that // w_prime and v_prime share an ancestor under the // "parent" relation, in which case we've found a // blossom and should shrink it, or the case that // w_prime and v_prime both have distinct ancestors that // are free, in which case we've found an alternating // path between those two ancestors. ++timestamp; while (nearest_common_ancestor == graph_traits< Graph >::null_vertex() && (v_free_ancestor == graph_traits< Graph >::null_vertex() || w_free_ancestor == graph_traits< Graph >::null_vertex())) { ancestor_of_w[w_up] = timestamp; ancestor_of_v[v_up] = timestamp; if (w_free_ancestor == graph_traits< Graph >::null_vertex()) w_up = parent(w_up); if (v_free_ancestor == graph_traits< Graph >::null_vertex()) v_up = parent(v_up); if (mate[v_up] == graph_traits< Graph >::null_vertex()) v_free_ancestor = v_up; if (mate[w_up] == graph_traits< Graph >::null_vertex()) w_free_ancestor = w_up; if (ancestor_of_w[v_up] == timestamp) nearest_common_ancestor = v_up; else if (ancestor_of_v[w_up] == timestamp) nearest_common_ancestor = w_up; else if (v_free_ancestor == w_free_ancestor && v_free_ancestor != graph_traits< Graph >::null_vertex()) nearest_common_ancestor = v_up; } if (nearest_common_ancestor == graph_traits< Graph >::null_vertex()) found_alternating_path = true; // to break out of the loop else { // shrink the blossom link_and_set_bridges( w_prime, nearest_common_ancestor, std::make_pair(w, v)); link_and_set_bridges( v_prime, nearest_common_ancestor, std::make_pair(v, w)); } } } if (!found_alternating_path) return false; // retrieve the augmenting path and put it in aug_path reversed_retrieve_augmenting_path(v, v_free_ancestor); retrieve_augmenting_path(w, w_free_ancestor); // augment the matching along aug_path vertex_descriptor_t a, b; while (!aug_path.empty()) { a = aug_path.front(); aug_path.pop_front(); b = aug_path.front(); aug_path.pop_front(); mate[a] = b; mate[b] = a; } return true; } template < typename PropertyMap > void get_current_matching(PropertyMap pm) { vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) put(pm, *vi, mate[*vi]); } template < typename PropertyMap > void get_vertex_state_map(PropertyMap pm) { vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) put(pm, *vi, vertex_state[origin[ds.find_set(*vi)]]); } private: vertex_descriptor_t parent(vertex_descriptor_t x) { if (vertex_state[x] == graph::detail::V_EVEN && mate[x] != graph_traits< Graph >::null_vertex()) return mate[x]; else if (vertex_state[x] == graph::detail::V_ODD) return origin[ds.find_set(pred[x])]; else return x; } void link_and_set_bridges(vertex_descriptor_t x, vertex_descriptor_t stop_vertex, vertex_pair_t the_bridge) { for (vertex_descriptor_t v = x; v != stop_vertex; v = parent(v)) { ds.union_set(v, stop_vertex); origin[ds.find_set(stop_vertex)] = stop_vertex; if (vertex_state[v] == graph::detail::V_ODD) { bridge[v] = the_bridge; out_edge_iterator_t oei, oei_end; for (boost::tie(oei, oei_end) = out_edges(v, g); oei != oei_end; ++oei) { if (target(*oei, g) != v) { even_edges.push_back(*oei); } } } } } // Since none of the STL containers support both constant-time // concatenation and reversal, the process of expanding an // augmenting path once we know one exists is a little more // complicated than it has to be. If we know the path is from v to // w, then the augmenting path is recursively defined as: // // path(v,w) = [v], if v = w // = concat([v, mate[v]], path(pred[mate[v]], w), // if v != w and vertex_state[v] == graph::detail::V_EVEN // = concat([v], reverse(path(x,mate[v])), path(y,w)), // if v != w, vertex_state[v] == graph::detail::V_ODD, and // bridge[v] = (x,y) // // These next two mutually recursive functions implement this definition. void retrieve_augmenting_path(vertex_descriptor_t v, vertex_descriptor_t w) { if (v == w) aug_path.push_back(v); else if (vertex_state[v] == graph::detail::V_EVEN) { aug_path.push_back(v); aug_path.push_back(mate[v]); retrieve_augmenting_path(pred[mate[v]], w); } else // vertex_state[v] == graph::detail::V_ODD { aug_path.push_back(v); reversed_retrieve_augmenting_path(bridge[v].first, mate[v]); retrieve_augmenting_path(bridge[v].second, w); } } void reversed_retrieve_augmenting_path( vertex_descriptor_t v, vertex_descriptor_t w) { if (v == w) aug_path.push_back(v); else if (vertex_state[v] == graph::detail::V_EVEN) { reversed_retrieve_augmenting_path(pred[mate[v]], w); aug_path.push_back(mate[v]); aug_path.push_back(v); } else // vertex_state[v] == graph::detail::V_ODD { reversed_retrieve_augmenting_path(bridge[v].second, w); retrieve_augmenting_path(bridge[v].first, mate[v]); aug_path.push_back(v); } } // private data members const Graph& g; VertexIndexMap vm; v_size_t n_vertices; // storage for the property maps below std::vector< vertex_descriptor_t > mate_vector; std::vector< e_size_t > ancestor_of_v_vector; std::vector< e_size_t > ancestor_of_w_vector; std::vector< int > vertex_state_vector; std::vector< vertex_descriptor_t > origin_vector; std::vector< vertex_descriptor_t > pred_vector; std::vector< vertex_pair_t > bridge_vector; std::vector< vertex_descriptor_t > ds_parent_vector; std::vector< v_size_t > ds_rank_vector; // iterator property maps vertex_to_vertex_map_t mate; vertex_to_esize_map_t ancestor_of_v; vertex_to_esize_map_t ancestor_of_w; vertex_to_int_map_t vertex_state; vertex_to_vertex_map_t origin; vertex_to_vertex_map_t pred; vertex_to_vertex_pair_map_t bridge; vertex_to_vertex_map_t ds_parent_map; vertex_to_vsize_map_t ds_rank_map; vertex_list_t aug_path; edge_list_t even_edges; disjoint_sets< vertex_to_vsize_map_t, vertex_to_vertex_map_t > ds; }; //*************************************************************************** //*************************************************************************** // Initial Matching Functors //*************************************************************************** //*************************************************************************** template < typename Graph, typename MateMap > struct greedy_matching { typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor_t; typedef typename graph_traits< Graph >::edge_iterator edge_iterator_t; static void find_matching(const Graph& g, MateMap mate) { vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) put(mate, *vi, graph_traits< Graph >::null_vertex()); edge_iterator_t ei, ei_end; for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) { edge_descriptor_t e = *ei; vertex_descriptor_t u = source(e, g); vertex_descriptor_t v = target(e, g); if (u != v && get(mate, u) == get(mate, v)) // only way equality can hold is if // mate[u] == mate[v] == null_vertex { put(mate, u, v); put(mate, v, u); } } } }; template < typename Graph, typename MateMap > struct extra_greedy_matching { // The "extra greedy matching" is formed by repeating the // following procedure as many times as possible: Choose the // unmatched vertex v of minimum non-zero degree. Choose the // neighbor w of v which is unmatched and has minimum degree over // all of v's neighbors. Add (u,v) to the matching. Ties for // either choice are broken arbitrarily. This procedure takes time // O(m log n), where m is the number of edges in the graph and n // is the number of vertices. typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor_t; typedef typename graph_traits< Graph >::edge_iterator edge_iterator_t; typedef std::pair< vertex_descriptor_t, vertex_descriptor_t > vertex_pair_t; struct select_first { inline static vertex_descriptor_t select_vertex(const vertex_pair_t p) { return p.first; } }; struct select_second { inline static vertex_descriptor_t select_vertex(const vertex_pair_t p) { return p.second; } }; template < class PairSelector > class less_than_by_degree { public: less_than_by_degree(const Graph& g) : m_g(g) {} bool operator()(const vertex_pair_t x, const vertex_pair_t y) { return out_degree(PairSelector::select_vertex(x), m_g) < out_degree(PairSelector::select_vertex(y), m_g); } private: const Graph& m_g; }; static void find_matching(const Graph& g, MateMap mate) { typedef std::vector< std::pair< vertex_descriptor_t, vertex_descriptor_t > > directed_edges_vector_t; directed_edges_vector_t edge_list; vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) put(mate, *vi, graph_traits< Graph >::null_vertex()); edge_iterator_t ei, ei_end; for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) { edge_descriptor_t e = *ei; vertex_descriptor_t u = source(e, g); vertex_descriptor_t v = target(e, g); if (u == v) continue; edge_list.push_back(std::make_pair(u, v)); edge_list.push_back(std::make_pair(v, u)); } // sort the edges by the degree of the target, then (using a // stable sort) by degree of the source std::sort(edge_list.begin(), edge_list.end(), less_than_by_degree< select_second >(g)); std::stable_sort(edge_list.begin(), edge_list.end(), less_than_by_degree< select_first >(g)); // construct the extra greedy matching for (typename directed_edges_vector_t::const_iterator itr = edge_list.begin(); itr != edge_list.end(); ++itr) { if (get(mate, itr->first) == get(mate, itr->second)) // only way equality can hold is if mate[itr->first] == // mate[itr->second] == null_vertex { put(mate, itr->first, itr->second); put(mate, itr->second, itr->first); } } } }; template < typename Graph, typename MateMap > struct empty_matching { typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; static void find_matching(const Graph& g, MateMap mate) { vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) put(mate, *vi, graph_traits< Graph >::null_vertex()); } }; //*************************************************************************** //*************************************************************************** // Matching Verifiers //*************************************************************************** //*************************************************************************** namespace detail { template < typename SizeType > class odd_components_counter : public dfs_visitor<> // This depth-first search visitor will count the number of connected // components with an odd number of vertices. It's used by // maximum_matching_verifier. { public: odd_components_counter(SizeType& c_count) : m_count(c_count) { m_count = 0; } template < class Vertex, class Graph > void start_vertex(Vertex, Graph&) { m_parity = false; } template < class Vertex, class Graph > void discover_vertex(Vertex, Graph&) { m_parity = !m_parity; m_parity ? ++m_count : --m_count; } protected: SizeType& m_count; private: bool m_parity; }; } // namespace detail template < typename Graph, typename MateMap, typename VertexIndexMap = dummy_property_map > struct no_matching_verifier { inline static bool verify_matching(const Graph&, MateMap, VertexIndexMap) { return true; } }; template < typename Graph, typename MateMap, typename VertexIndexMap > struct maximum_cardinality_matching_verifier { template < typename X > struct map_vertex_to_ { typedef boost::iterator_property_map< typename std::vector< X >::iterator, VertexIndexMap > type; }; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t; typedef typename graph_traits< Graph >::vertices_size_type v_size_t; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; typedef typename map_vertex_to_< int >::type vertex_to_int_map_t; typedef typename map_vertex_to_< vertex_descriptor_t >::type vertex_to_vertex_map_t; template < typename VertexStateMap > struct non_odd_vertex { // this predicate is used to create a filtered graph that // excludes vertices labeled "graph::detail::V_ODD" non_odd_vertex() : vertex_state(0) {} non_odd_vertex(VertexStateMap* arg_vertex_state) : vertex_state(arg_vertex_state) { } template < typename Vertex > bool operator()(const Vertex& v) const { BOOST_ASSERT(vertex_state); return get(*vertex_state, v) != graph::detail::V_ODD; } VertexStateMap* vertex_state; }; static bool verify_matching(const Graph& g, MateMap mate, VertexIndexMap vm) { // For any graph G, let o(G) be the number of connected // components in G of odd size. For a subset S of G's vertex set // V(G), let (G - S) represent the subgraph of G induced by // removing all vertices in S from G. Let M(G) be the size of the // maximum cardinality matching in G. Then the Tutte-Berge // formula guarantees that // // 2 * M(G) = min ( |V(G)| + |U| + o(G - U) ) // // where the minimum is taken over all subsets U of // V(G). Edmonds' algorithm finds a set U that achieves the // minimum in the above formula, namely the vertices labeled //"ODD." This function runs one iteration of Edmonds' algorithm // to find U, then verifies that the size of the matching given // by mate satisfies the Tutte-Berge formula. // first, make sure it's a valid matching if (!is_a_matching(g, mate, vm)) return false; // We'll try to augment the matching once. This serves two // purposes: first, if we find some augmenting path, the matching // is obviously non-maximum. Second, running edmonds' algorithm // on a graph with no augmenting path will create the // Edmonds-Gallai decomposition that we need as a certificate of // maximality - we can get it by looking at the vertex_state map // that results. edmonds_augmenting_path_finder< Graph, MateMap, VertexIndexMap > augmentor(g, mate, vm); if (augmentor.augment_matching()) return false; std::vector< int > vertex_state_vector(num_vertices(g)); vertex_to_int_map_t vertex_state(vertex_state_vector.begin(), vm); augmentor.get_vertex_state_map(vertex_state); // count the number of graph::detail::V_ODD vertices v_size_t num_odd_vertices = 0; vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) if (vertex_state[*vi] == graph::detail::V_ODD) ++num_odd_vertices; // count the number of connected components with odd cardinality // in the graph without graph::detail::V_ODD vertices non_odd_vertex< vertex_to_int_map_t > filter(&vertex_state); filtered_graph< Graph, keep_all, non_odd_vertex< vertex_to_int_map_t > > fg(g, keep_all(), filter); v_size_t num_odd_components; detail::odd_components_counter< v_size_t > occ(num_odd_components); depth_first_search(fg, visitor(occ).vertex_index_map(vm)); if (2 * matching_size(g, mate, vm) == num_vertices(g) + num_odd_vertices - num_odd_components) return true; else return false; } }; template < typename Graph, typename MateMap, typename VertexIndexMap, template < typename, typename, typename > class AugmentingPathFinder, template < typename, typename > class InitialMatchingFinder, template < typename, typename, typename > class MatchingVerifier > bool matching(const Graph& g, MateMap mate, VertexIndexMap vm) { InitialMatchingFinder< Graph, MateMap >::find_matching(g, mate); AugmentingPathFinder< Graph, MateMap, VertexIndexMap > augmentor( g, mate, vm); bool not_maximum_yet = true; while (not_maximum_yet) { not_maximum_yet = augmentor.augment_matching(); } augmentor.get_current_matching(mate); return MatchingVerifier< Graph, MateMap, VertexIndexMap >::verify_matching( g, mate, vm); } template < typename Graph, typename MateMap, typename VertexIndexMap > inline bool checked_edmonds_maximum_cardinality_matching( const Graph& g, MateMap mate, VertexIndexMap vm) { return matching< Graph, MateMap, VertexIndexMap, edmonds_augmenting_path_finder, extra_greedy_matching, maximum_cardinality_matching_verifier >(g, mate, vm); } template < typename Graph, typename MateMap > inline bool checked_edmonds_maximum_cardinality_matching( const Graph& g, MateMap mate) { return checked_edmonds_maximum_cardinality_matching( g, mate, get(vertex_index, g)); } template < typename Graph, typename MateMap, typename VertexIndexMap > inline void edmonds_maximum_cardinality_matching( const Graph& g, MateMap mate, VertexIndexMap vm) { matching< Graph, MateMap, VertexIndexMap, edmonds_augmenting_path_finder, extra_greedy_matching, no_matching_verifier >(g, mate, vm); } template < typename Graph, typename MateMap > inline void edmonds_maximum_cardinality_matching(const Graph& g, MateMap mate) { edmonds_maximum_cardinality_matching(g, mate, get(vertex_index, g)); } } // namespace boost #endif // BOOST_GRAPH_MAXIMUM_CARDINALITY_MATCHING_HPP grid_graph.hpp 0000644 00000102100 15125521275 0007362 0 ustar 00 //======================================================================= // Copyright 2009 Trustees of Indiana University. // Authors: Michael Hansen, Andrew Lumsdaine // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_GRID_GRAPH_HPP #define BOOST_GRAPH_GRID_GRAPH_HPP #include <cmath> #include <functional> #include <numeric> #include <boost/array.hpp> #include <boost/bind.hpp> #include <boost/limits.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/iterator/counting_iterator.hpp> #include <boost/iterator/transform_iterator.hpp> #include <boost/property_map/property_map.hpp> #define BOOST_GRID_GRAPH_TEMPLATE_PARAMS \ std::size_t DimensionsT, typename VertexIndexT, typename EdgeIndexT #define BOOST_GRID_GRAPH_TYPE \ grid_graph< DimensionsT, VertexIndexT, EdgeIndexT > #define BOOST_GRID_GRAPH_TRAITS_T typename graph_traits< BOOST_GRID_GRAPH_TYPE > namespace boost { // Class prototype for grid_graph template < BOOST_GRID_GRAPH_TEMPLATE_PARAMS > class grid_graph; //=================== // Index Property Map //=================== template < typename Graph, typename Descriptor, typename Index > struct grid_graph_index_map { public: typedef Index value_type; typedef Index reference_type; typedef reference_type reference; typedef Descriptor key_type; typedef readable_property_map_tag category; grid_graph_index_map() {} grid_graph_index_map(const Graph& graph) : m_graph(&graph) {} value_type operator[](key_type key) const { return (m_graph->index_of(key)); } friend inline Index get( const grid_graph_index_map< Graph, Descriptor, Index >& index_map, const typename grid_graph_index_map< Graph, Descriptor, Index >::key_type& key) { return (index_map[key]); } protected: const Graph* m_graph; }; template < BOOST_GRID_GRAPH_TEMPLATE_PARAMS > struct property_map< BOOST_GRID_GRAPH_TYPE, vertex_index_t > { typedef grid_graph_index_map< BOOST_GRID_GRAPH_TYPE, BOOST_GRID_GRAPH_TRAITS_T::vertex_descriptor, BOOST_GRID_GRAPH_TRAITS_T::vertices_size_type > type; typedef type const_type; }; template < BOOST_GRID_GRAPH_TEMPLATE_PARAMS > struct property_map< BOOST_GRID_GRAPH_TYPE, edge_index_t > { typedef grid_graph_index_map< BOOST_GRID_GRAPH_TYPE, BOOST_GRID_GRAPH_TRAITS_T::edge_descriptor, BOOST_GRID_GRAPH_TRAITS_T::edges_size_type > type; typedef type const_type; }; //========================== // Reverse Edge Property Map //========================== template < typename Descriptor > struct grid_graph_reverse_edge_map { public: typedef Descriptor value_type; typedef Descriptor reference_type; typedef reference_type reference; typedef Descriptor key_type; typedef readable_property_map_tag category; grid_graph_reverse_edge_map() {} value_type operator[](const key_type& key) const { return (value_type(key.second, key.first)); } friend inline Descriptor get( const grid_graph_reverse_edge_map< Descriptor >& rev_map, const typename grid_graph_reverse_edge_map< Descriptor >::key_type& key) { return (rev_map[key]); } }; template < BOOST_GRID_GRAPH_TEMPLATE_PARAMS > struct property_map< BOOST_GRID_GRAPH_TYPE, edge_reverse_t > { typedef grid_graph_reverse_edge_map< BOOST_GRID_GRAPH_TRAITS_T::edge_descriptor > type; typedef type const_type; }; //================= // Function Objects //================= namespace detail { // vertex_at template < typename Graph > struct grid_graph_vertex_at { typedef typename graph_traits< Graph >::vertex_descriptor result_type; grid_graph_vertex_at() : m_graph(0) {} grid_graph_vertex_at(const Graph* graph) : m_graph(graph) {} result_type operator()( typename graph_traits< Graph >::vertices_size_type vertex_index) const { return (vertex(vertex_index, *m_graph)); } private: const Graph* m_graph; }; // out_edge_at template < typename Graph > struct grid_graph_out_edge_at { private: typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; public: typedef typename graph_traits< Graph >::edge_descriptor result_type; grid_graph_out_edge_at() : m_vertex(), m_graph(0) {} grid_graph_out_edge_at( vertex_descriptor source_vertex, const Graph* graph) : m_vertex(source_vertex), m_graph(graph) { } result_type operator()( typename graph_traits< Graph >::degree_size_type out_edge_index) const { return (out_edge_at(m_vertex, out_edge_index, *m_graph)); } private: vertex_descriptor m_vertex; const Graph* m_graph; }; // in_edge_at template < typename Graph > struct grid_graph_in_edge_at { private: typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; public: typedef typename graph_traits< Graph >::edge_descriptor result_type; grid_graph_in_edge_at() : m_vertex(), m_graph(0) {} grid_graph_in_edge_at( vertex_descriptor target_vertex, const Graph* graph) : m_vertex(target_vertex), m_graph(graph) { } result_type operator()( typename graph_traits< Graph >::degree_size_type in_edge_index) const { return (in_edge_at(m_vertex, in_edge_index, *m_graph)); } private: vertex_descriptor m_vertex; const Graph* m_graph; }; // edge_at template < typename Graph > struct grid_graph_edge_at { typedef typename graph_traits< Graph >::edge_descriptor result_type; grid_graph_edge_at() : m_graph(0) {} grid_graph_edge_at(const Graph* graph) : m_graph(graph) {} result_type operator()( typename graph_traits< Graph >::edges_size_type edge_index) const { return (edge_at(edge_index, *m_graph)); } private: const Graph* m_graph; }; // adjacent_vertex_at template < typename Graph > struct grid_graph_adjacent_vertex_at { public: typedef typename graph_traits< Graph >::vertex_descriptor result_type; grid_graph_adjacent_vertex_at( result_type source_vertex, const Graph* graph) : m_vertex(source_vertex), m_graph(graph) { } result_type operator()( typename graph_traits< Graph >::degree_size_type adjacent_index) const { return (target( out_edge_at(m_vertex, adjacent_index, *m_graph), *m_graph)); } private: result_type m_vertex; const Graph* m_graph; }; } // namespace detail //=========== // Grid Graph //=========== template < std::size_t Dimensions, typename VertexIndex = std::size_t, typename EdgeIndex = VertexIndex > class grid_graph { private: typedef boost::array< bool, Dimensions > WrapDimensionArray; grid_graph() {}; public: typedef grid_graph< Dimensions, VertexIndex, EdgeIndex > type; // sizes typedef VertexIndex vertices_size_type; typedef EdgeIndex edges_size_type; typedef EdgeIndex degree_size_type; // descriptors typedef boost::array< VertexIndex, Dimensions > vertex_descriptor; typedef std::pair< vertex_descriptor, vertex_descriptor > edge_descriptor; // vertex_iterator typedef counting_iterator< vertices_size_type > vertex_index_iterator; typedef detail::grid_graph_vertex_at< type > vertex_function; typedef transform_iterator< vertex_function, vertex_index_iterator > vertex_iterator; // edge_iterator typedef counting_iterator< edges_size_type > edge_index_iterator; typedef detail::grid_graph_edge_at< type > edge_function; typedef transform_iterator< edge_function, edge_index_iterator > edge_iterator; // out_edge_iterator typedef counting_iterator< degree_size_type > degree_iterator; typedef detail::grid_graph_out_edge_at< type > out_edge_function; typedef transform_iterator< out_edge_function, degree_iterator > out_edge_iterator; // in_edge_iterator typedef detail::grid_graph_in_edge_at< type > in_edge_function; typedef transform_iterator< in_edge_function, degree_iterator > in_edge_iterator; // adjacency_iterator typedef detail::grid_graph_adjacent_vertex_at< type > adjacent_vertex_function; typedef transform_iterator< adjacent_vertex_function, degree_iterator > adjacency_iterator; // categories typedef directed_tag directed_category; typedef disallow_parallel_edge_tag edge_parallel_category; struct traversal_category : virtual public incidence_graph_tag, virtual public adjacency_graph_tag, virtual public vertex_list_graph_tag, virtual public edge_list_graph_tag, virtual public bidirectional_graph_tag, virtual public adjacency_matrix_tag { }; static inline vertex_descriptor null_vertex() { vertex_descriptor maxed_out_vertex; std::fill(maxed_out_vertex.begin(), maxed_out_vertex.end(), (std::numeric_limits< vertices_size_type >::max)()); return (maxed_out_vertex); } // Constructor that defaults to no wrapping for all dimensions. grid_graph(vertex_descriptor dimension_lengths) : m_dimension_lengths(dimension_lengths) { std::fill(m_wrap_dimension.begin(), m_wrap_dimension.end(), false); precalculate(); } // Constructor that allows for wrapping to be specified for all // dimensions at once. grid_graph(vertex_descriptor dimension_lengths, bool wrap_all_dimensions) : m_dimension_lengths(dimension_lengths) { std::fill(m_wrap_dimension.begin(), m_wrap_dimension.end(), wrap_all_dimensions); precalculate(); } // Constructor that allows for individual dimension wrapping to be // specified. grid_graph( vertex_descriptor dimension_lengths, WrapDimensionArray wrap_dimension) : m_dimension_lengths(dimension_lengths), m_wrap_dimension(wrap_dimension) { precalculate(); } // Returns the number of dimensions in the graph inline std::size_t dimensions() const { return (Dimensions); } // Returns the length of dimension [dimension_index] inline vertices_size_type length(std::size_t dimension) const { return (m_dimension_lengths[dimension]); } // Returns a value indicating if dimension [dimension_index] wraps inline bool wrapped(std::size_t dimension) const { return (m_wrap_dimension[dimension]); } // Gets the vertex that is [distance] units ahead of [vertex] in // dimension [dimension_index]. vertex_descriptor next(vertex_descriptor vertex, std::size_t dimension_index, vertices_size_type distance = 1) const { vertices_size_type new_position = vertex[dimension_index] + distance; if (wrapped(dimension_index)) { new_position %= length(dimension_index); } else { // Stop at the end of this dimension if necessary. new_position = (std::min)( new_position, vertices_size_type(length(dimension_index) - 1)); } vertex[dimension_index] = new_position; return (vertex); } // Gets the vertex that is [distance] units behind [vertex] in // dimension [dimension_index]. vertex_descriptor previous(vertex_descriptor vertex, std::size_t dimension_index, vertices_size_type distance = 1) const { // We're assuming that vertices_size_type is unsigned, so we // need to be careful about the math. vertex[dimension_index] = (distance > vertex[dimension_index]) ? (wrapped(dimension_index) ? (length(dimension_index) - (distance % length(dimension_index))) : 0) : vertex[dimension_index] - distance; return (vertex); } protected: // Returns the number of vertices in the graph inline vertices_size_type num_vertices() const { return (m_num_vertices); } // Returns the number of edges in the graph inline edges_size_type num_edges() const { return (m_num_edges); } // Returns the number of edges in dimension [dimension_index] inline edges_size_type num_edges(std::size_t dimension_index) const { return (m_edge_count[dimension_index]); } // Returns the index of [vertex] (See also vertex_at) vertices_size_type index_of(vertex_descriptor vertex) const { vertices_size_type vertex_index = 0; vertices_size_type index_multiplier = 1; for (std::size_t dimension_index = 0; dimension_index < Dimensions; ++dimension_index) { vertex_index += (vertex[dimension_index] * index_multiplier); index_multiplier *= length(dimension_index); } return (vertex_index); } // Returns the vertex whose index is [vertex_index] (See also // index_of(vertex_descriptor)) vertex_descriptor vertex_at(vertices_size_type vertex_index) const { boost::array< vertices_size_type, Dimensions > vertex; vertices_size_type index_divider = 1; for (std::size_t dimension_index = 0; dimension_index < Dimensions; ++dimension_index) { vertex[dimension_index] = (vertex_index / index_divider) % length(dimension_index); index_divider *= length(dimension_index); } return (vertex); } // Returns the edge whose index is [edge_index] (See also // index_of(edge_descriptor)). NOTE: The index mapping is // dependent upon dimension wrapping. edge_descriptor edge_at(edges_size_type edge_index) const { // Edge indices are sorted into bins by dimension std::size_t dimension_index = 0; edges_size_type dimension_edges = num_edges(0); while (edge_index >= dimension_edges) { edge_index -= dimension_edges; ++dimension_index; dimension_edges = num_edges(dimension_index); } vertex_descriptor vertex_source, vertex_target; bool is_forward = ((edge_index / (num_edges(dimension_index) / 2)) == 0); if (wrapped(dimension_index)) { vertex_source = vertex_at(edge_index % num_vertices()); vertex_target = is_forward ? next(vertex_source, dimension_index) : previous(vertex_source, dimension_index); } else { // Dimensions can wrap arbitrarily, so an index needs to be // computed in a more complex manner. This is done by // grouping the edges for each dimension together into "bins" // and considering [edge_index] as an offset into the bin. // Each bin consists of two parts: the "forward" looking edges // and the "backward" looking edges for the dimension. edges_size_type vertex_offset = edge_index % num_edges(dimension_index); // Consider vertex_offset an index into the graph's vertex // space but with the dimension [dimension_index] reduced in // size by one. vertices_size_type index_divider = 1; for (std::size_t dimension_index_iter = 0; dimension_index_iter < Dimensions; ++dimension_index_iter) { std::size_t dimension_length = (dimension_index_iter == dimension_index) ? length(dimension_index_iter) - 1 : length(dimension_index_iter); vertex_source[dimension_index_iter] = (vertex_offset / index_divider) % dimension_length; index_divider *= dimension_length; } if (is_forward) { vertex_target = next(vertex_source, dimension_index); } else { // Shift forward one more unit in the dimension for backward // edges since the algorithm above will leave us one behind. vertex_target = vertex_source; ++vertex_source[dimension_index]; } } // if (wrapped(dimension_index)) return (std::make_pair(vertex_source, vertex_target)); } // Returns the index for [edge] (See also edge_at) edges_size_type index_of(edge_descriptor edge) const { vertex_descriptor source_vertex = source(edge, *this); vertex_descriptor target_vertex = target(edge, *this); BOOST_ASSERT(source_vertex != target_vertex); // Determine the dimension where the source and target vertices // differ (should only be one if this is a valid edge). std::size_t different_dimension_index = 0; while (source_vertex[different_dimension_index] == target_vertex[different_dimension_index]) { ++different_dimension_index; } edges_size_type edge_index = 0; // Offset the edge index into the appropriate "bin" (see edge_at // for a more in-depth description). for (std::size_t dimension_index = 0; dimension_index < different_dimension_index; ++dimension_index) { edge_index += num_edges(dimension_index); } // Get the position of both vertices in the differing dimension. vertices_size_type source_position = source_vertex[different_dimension_index]; vertices_size_type target_position = target_vertex[different_dimension_index]; // Determine if edge is forward or backward bool is_forward = true; if (wrapped(different_dimension_index)) { // If the dimension is wrapped, an edge is going backward if // either A: its target precedes the source in the differing // dimension and the vertices are adjacent or B: its source // precedes the target and they're not adjacent. if (((target_position < source_position) && ((source_position - target_position) == 1)) || ((source_position < target_position) && ((target_position - source_position) > 1))) { is_forward = false; } } else if (target_position < source_position) { is_forward = false; } // "Backward" edges are in the second half of the bin. if (!is_forward) { edge_index += (num_edges(different_dimension_index) / 2); } // Finally, apply the vertex offset if (wrapped(different_dimension_index)) { edge_index += index_of(source_vertex); } else { vertices_size_type index_multiplier = 1; if (!is_forward) { --source_vertex[different_dimension_index]; } for (std::size_t dimension_index = 0; dimension_index < Dimensions; ++dimension_index) { edge_index += (source_vertex[dimension_index] * index_multiplier); index_multiplier *= (dimension_index == different_dimension_index) ? length(dimension_index) - 1 : length(dimension_index); } } return (edge_index); } // Returns the number of out-edges for [vertex] degree_size_type out_degree(vertex_descriptor vertex) const { degree_size_type out_edge_count = 0; for (std::size_t dimension_index = 0; dimension_index < Dimensions; ++dimension_index) { // If the vertex is on the edge of this dimension, then its // number of out edges is dependent upon whether the dimension // wraps or not. if ((vertex[dimension_index] == 0) || (vertex[dimension_index] == (length(dimension_index) - 1))) { out_edge_count += (wrapped(dimension_index) ? 2 : 1); } else { // Next and previous edges, regardless or wrapping out_edge_count += 2; } } return (out_edge_count); } // Returns an out-edge for [vertex] by index. Indices are in the // range [0, out_degree(vertex)). edge_descriptor out_edge_at( vertex_descriptor vertex, degree_size_type out_edge_index) const { edges_size_type edges_left = out_edge_index + 1; std::size_t dimension_index = 0; bool is_forward = false; // Walks the out edges of [vertex] and accommodates for dimension // wrapping. while (edges_left > 0) { if (!wrapped(dimension_index)) { if (!is_forward && (vertex[dimension_index] == 0)) { is_forward = true; continue; } else if (is_forward && (vertex[dimension_index] == (length(dimension_index) - 1))) { is_forward = false; ++dimension_index; continue; } } --edges_left; if (edges_left > 0) { is_forward = !is_forward; if (!is_forward) { ++dimension_index; } } } return (std::make_pair(vertex, is_forward ? next(vertex, dimension_index) : previous(vertex, dimension_index))); } // Returns the number of in-edges for [vertex] inline degree_size_type in_degree(vertex_descriptor vertex) const { return (out_degree(vertex)); } // Returns an in-edge for [vertex] by index. Indices are in the // range [0, in_degree(vertex)). edge_descriptor in_edge_at( vertex_descriptor vertex, edges_size_type in_edge_index) const { edge_descriptor out_edge = out_edge_at(vertex, in_edge_index); return ( std::make_pair(target(out_edge, *this), source(out_edge, *this))); } // Pre-computes the number of vertices and edges void precalculate() { m_num_vertices = std::accumulate(m_dimension_lengths.begin(), m_dimension_lengths.end(), vertices_size_type(1), std::multiplies< vertices_size_type >()); // Calculate number of edges in each dimension m_num_edges = 0; for (std::size_t dimension_index = 0; dimension_index < Dimensions; ++dimension_index) { if (wrapped(dimension_index)) { m_edge_count[dimension_index] = num_vertices() * 2; } else { m_edge_count[dimension_index] = (num_vertices() - (num_vertices() / length(dimension_index))) * 2; } m_num_edges += num_edges(dimension_index); } } const vertex_descriptor m_dimension_lengths; WrapDimensionArray m_wrap_dimension; vertices_size_type m_num_vertices; boost::array< edges_size_type, Dimensions > m_edge_count; edges_size_type m_num_edges; public: //================ // VertexListGraph //================ friend inline std::pair< typename type::vertex_iterator, typename type::vertex_iterator > vertices(const type& graph) { typedef typename type::vertex_iterator vertex_iterator; typedef typename type::vertex_function vertex_function; typedef typename type::vertex_index_iterator vertex_index_iterator; return (std::make_pair( vertex_iterator(vertex_index_iterator(0), vertex_function(&graph)), vertex_iterator(vertex_index_iterator(graph.num_vertices()), vertex_function(&graph)))); } friend inline typename type::vertices_size_type num_vertices( const type& graph) { return (graph.num_vertices()); } friend inline typename type::vertex_descriptor vertex( typename type::vertices_size_type vertex_index, const type& graph) { return (graph.vertex_at(vertex_index)); } //=============== // IncidenceGraph //=============== friend inline std::pair< typename type::out_edge_iterator, typename type::out_edge_iterator > out_edges(typename type::vertex_descriptor vertex, const type& graph) { typedef typename type::degree_iterator degree_iterator; typedef typename type::out_edge_function out_edge_function; typedef typename type::out_edge_iterator out_edge_iterator; return (std::make_pair(out_edge_iterator(degree_iterator(0), out_edge_function(vertex, &graph)), out_edge_iterator(degree_iterator(graph.out_degree(vertex)), out_edge_function(vertex, &graph)))); } friend inline typename type::degree_size_type out_degree( typename type::vertex_descriptor vertex, const type& graph) { return (graph.out_degree(vertex)); } friend inline typename type::edge_descriptor out_edge_at( typename type::vertex_descriptor vertex, typename type::degree_size_type out_edge_index, const type& graph) { return (graph.out_edge_at(vertex, out_edge_index)); } //=============== // AdjacencyGraph //=============== friend typename std::pair< typename type::adjacency_iterator, typename type::adjacency_iterator > adjacent_vertices( typename type::vertex_descriptor vertex, const type& graph) { typedef typename type::degree_iterator degree_iterator; typedef typename type::adjacent_vertex_function adjacent_vertex_function; typedef typename type::adjacency_iterator adjacency_iterator; return (std::make_pair(adjacency_iterator(degree_iterator(0), adjacent_vertex_function(vertex, &graph)), adjacency_iterator(degree_iterator(graph.out_degree(vertex)), adjacent_vertex_function(vertex, &graph)))); } //============== // EdgeListGraph //============== friend inline typename type::edges_size_type num_edges(const type& graph) { return (graph.num_edges()); } friend inline typename type::edge_descriptor edge_at( typename type::edges_size_type edge_index, const type& graph) { return (graph.edge_at(edge_index)); } friend inline std::pair< typename type::edge_iterator, typename type::edge_iterator > edges(const type& graph) { typedef typename type::edge_index_iterator edge_index_iterator; typedef typename type::edge_function edge_function; typedef typename type::edge_iterator edge_iterator; return (std::make_pair( edge_iterator(edge_index_iterator(0), edge_function(&graph)), edge_iterator(edge_index_iterator(graph.num_edges()), edge_function(&graph)))); } //=================== // BiDirectionalGraph //=================== friend inline std::pair< typename type::in_edge_iterator, typename type::in_edge_iterator > in_edges(typename type::vertex_descriptor vertex, const type& graph) { typedef typename type::in_edge_function in_edge_function; typedef typename type::degree_iterator degree_iterator; typedef typename type::in_edge_iterator in_edge_iterator; return (std::make_pair(in_edge_iterator(degree_iterator(0), in_edge_function(vertex, &graph)), in_edge_iterator(degree_iterator(graph.in_degree(vertex)), in_edge_function(vertex, &graph)))); } friend inline typename type::degree_size_type in_degree( typename type::vertex_descriptor vertex, const type& graph) { return (graph.in_degree(vertex)); } friend inline typename type::degree_size_type degree( typename type::vertex_descriptor vertex, const type& graph) { return (graph.out_degree(vertex) * 2); } friend inline typename type::edge_descriptor in_edge_at( typename type::vertex_descriptor vertex, typename type::degree_size_type in_edge_index, const type& graph) { return (graph.in_edge_at(vertex, in_edge_index)); } //================== // Adjacency Matrix //================== friend std::pair< typename type::edge_descriptor, bool > edge( typename type::vertex_descriptor source_vertex, typename type::vertex_descriptor destination_vertex, const type& graph) { std::pair< typename type::edge_descriptor, bool > edge_exists = std::make_pair( std::make_pair(source_vertex, destination_vertex), false); for (std::size_t dimension_index = 0; dimension_index < Dimensions; ++dimension_index) { typename type::vertices_size_type dim_difference = 0; typename type::vertices_size_type source_dim = source_vertex[dimension_index], dest_dim = destination_vertex[dimension_index]; dim_difference = (source_dim > dest_dim) ? (source_dim - dest_dim) : (dest_dim - source_dim); if (dim_difference > 0) { // If we've already found a valid edge, this would mean that // the vertices are really diagonal across dimensions and // therefore not connected. if (edge_exists.second) { edge_exists.second = false; break; } // If the difference is one, the vertices are right next to // each other and the edge is valid. The edge is still // valid, though, if the dimension wraps and the vertices // are on opposite ends. if ((dim_difference == 1) || (graph.wrapped(dimension_index) && (((source_dim == 0) && (dest_dim == (graph.length(dimension_index) - 1))) || ((dest_dim == 0) && (source_dim == (graph.length(dimension_index) - 1)))))) { edge_exists.second = true; // Stay in the loop to check for diagonal vertices. } else { // Stop checking - the vertices are too far apart. edge_exists.second = false; break; } } } // for dimension_index return (edge_exists); } //============================= // Index Property Map Functions //============================= friend inline typename type::vertices_size_type get(vertex_index_t, const type& graph, typename type::vertex_descriptor vertex) { return (graph.index_of(vertex)); } friend inline typename type::edges_size_type get( edge_index_t, const type& graph, typename type::edge_descriptor edge) { return (graph.index_of(edge)); } friend inline grid_graph_index_map< type, typename type::vertex_descriptor, typename type::vertices_size_type > get(vertex_index_t, const type& graph) { return (grid_graph_index_map< type, typename type::vertex_descriptor, typename type::vertices_size_type >(graph)); } friend inline grid_graph_index_map< type, typename type::edge_descriptor, typename type::edges_size_type > get(edge_index_t, const type& graph) { return (grid_graph_index_map< type, typename type::edge_descriptor, typename type::edges_size_type >(graph)); } friend inline grid_graph_reverse_edge_map< typename type::edge_descriptor > get(edge_reverse_t, const type& graph) { return ( grid_graph_reverse_edge_map< typename type::edge_descriptor >()); } template < typename Graph, typename Descriptor, typename Index > friend struct grid_graph_index_map; template < typename Descriptor > friend struct grid_graph_reverse_edge_map; }; // grid_graph } // namespace boost #undef BOOST_GRID_GRAPH_TYPE #undef BOOST_GRID_GRAPH_TEMPLATE_PARAMS #undef BOOST_GRID_GRAPH_TRAITS_T #endif // BOOST_GRAPH_GRID_GRAPH_HPP named_graph.hpp 0000644 00000050206 15125521275 0007532 0 ustar 00 // Copyright (C) 2007 Douglas Gregor // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Provides support for named vertices in graphs, allowing one to more // easily associate unique external names (URLs, city names, employee // ID numbers, etc.) with the vertices of a graph. #ifndef BOOST_GRAPH_NAMED_GRAPH_HPP #define BOOST_GRAPH_NAMED_GRAPH_HPP #include <boost/config.hpp> #include <boost/static_assert.hpp> #include <boost/functional/hash.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/multi_index/hashed_index.hpp> #include <boost/multi_index/member.hpp> #include <boost/multi_index_container.hpp> #include <boost/optional.hpp> #include <boost/pending/property.hpp> // for boost::lookup_one_property #include <boost/pending/container_traits.hpp> #include <boost/throw_exception.hpp> #include <boost/tuple/tuple.hpp> // for boost::make_tuple #include <boost/type_traits/is_same.hpp> #include <boost/type_traits/is_base_of.hpp> #include <boost/type_traits/remove_cv.hpp> #include <boost/type_traits/remove_reference.hpp> #include <boost/utility/enable_if.hpp> #include <functional> // for std::equal_to #include <stdexcept> // for std::runtime_error #include <utility> // for std::pair namespace boost { namespace graph { /******************************************************************* * User-customized traits * *******************************************************************/ /** * @brief Trait used to extract the internal vertex name from a vertex * property. * * To enable the use of internal vertex names in a graph type, * specialize the @c internal_vertex_name trait for your graph * property (e.g., @c a City class, which stores information about the * vertices in a road map). */ template < typename VertexProperty > struct internal_vertex_name { /** * The @c type field provides a function object that extracts a key * from the @c VertexProperty. The function object type must have a * nested @c result_type that provides the type of the key. For * more information, see the @c KeyExtractor concept in the * Boost.MultiIndex documentation: @c type must either be @c void * (if @c VertexProperty does not have an internal vertex name) or * a model of @c KeyExtractor. */ typedef void type; }; /** * Extract the internal vertex name from a @c property structure by * looking at its base. */ template < typename Tag, typename T, typename Base > struct internal_vertex_name< property< Tag, T, Base > > : internal_vertex_name< Base > { }; /** * Construct an instance of @c VertexProperty directly from its * name. This function object should be used within the @c * internal_vertex_constructor trait. */ template < typename VertexProperty > struct vertex_from_name { private: typedef typename internal_vertex_name< VertexProperty >::type extract_name_type; typedef typename remove_cv< typename remove_reference< typename extract_name_type::result_type >::type >::type vertex_name_type; public: typedef vertex_name_type argument_type; typedef VertexProperty result_type; VertexProperty operator()(const vertex_name_type& name) { return VertexProperty(name); } }; /** * Throw an exception whenever one tries to construct a @c * VertexProperty instance from its name. */ template < typename VertexProperty > struct cannot_add_vertex { private: typedef typename internal_vertex_name< VertexProperty >::type extract_name_type; typedef typename remove_cv< typename remove_reference< typename extract_name_type::result_type >::type >::type vertex_name_type; public: typedef vertex_name_type argument_type; typedef VertexProperty result_type; VertexProperty operator()(const vertex_name_type&) { boost::throw_exception( std::runtime_error("add_vertex: " "unable to create a vertex from its name")); } }; /** * @brief Trait used to construct an instance of a @c VertexProperty, * which is a class type that stores the properties associated with a * vertex in a graph, from just the name of that vertex property. This * operation is used when an operation is required to map from a * vertex name to a vertex descriptor (e.g., to add an edge outgoing * from that vertex), but no vertex by the name exists. The function * object provided by this trait will be used to add new vertices * based only on their names. Since this cannot be done for arbitrary * types, the default behavior is to throw an exception when this * routine is called, which requires that all named vertices be added * before adding any edges by name. */ template < typename VertexProperty > struct internal_vertex_constructor { /** * The @c type field provides a function object that constructs a * new instance of @c VertexProperty from the name of the vertex (as * determined by @c internal_vertex_name). The function object shall * accept a vertex name and return a @c VertexProperty. Predefined * options include: * * @c vertex_from_name<VertexProperty>: construct an instance of * @c VertexProperty directly from the name. * * @c cannot_add_vertex<VertexProperty>: the default value, which * throws an @c std::runtime_error if one attempts to add a vertex * given just the name. */ typedef cannot_add_vertex< VertexProperty > type; }; /** * Extract the internal vertex constructor from a @c property structure by * looking at its base. */ template < typename Tag, typename T, typename Base > struct internal_vertex_constructor< property< Tag, T, Base > > : internal_vertex_constructor< Base > { }; /******************************************************************* * Named graph mixin * *******************************************************************/ /** * named_graph is a mixin that provides names for the vertices of a * graph, including a mapping from names to vertices. Graph types that * may or may not be have vertex names (depending on the properties * supplied by the user) should use maybe_named_graph. * * Template parameters: * * Graph: the graph type that derives from named_graph * * Vertex: the type of a vertex descriptor in Graph. Note: we cannot * use graph_traits here, because the Graph is not yet defined. * * VertexProperty: the type stored with each vertex in the Graph. */ template < typename Graph, typename Vertex, typename VertexProperty > class named_graph { public: /// The type of the function object that extracts names from vertex /// properties. typedef typename internal_vertex_name< VertexProperty >::type extract_name_type; /// The type of the "bundled" property, from which the name can be /// extracted. typedef typename lookup_one_property< VertexProperty, vertex_bundle_t >::type bundled_vertex_property_type; /// The type of the function object that generates vertex properties /// from names, for the implicit addition of vertices. typedef typename internal_vertex_constructor< VertexProperty >::type vertex_constructor_type; /// The type used to name vertices in the graph typedef typename remove_cv< typename remove_reference< typename extract_name_type::result_type >::type >::type vertex_name_type; /// The type of vertex descriptors in the graph typedef Vertex vertex_descriptor; private: /// Key extractor for use with the multi_index_container struct extract_name_from_vertex { typedef vertex_name_type result_type; extract_name_from_vertex( Graph& graph, const extract_name_type& extract) : graph(graph), extract(extract) { } const result_type& operator()(Vertex vertex) const { return extract(graph[vertex]); } Graph& graph; extract_name_type extract; }; public: /// The type that maps names to vertices typedef multi_index::multi_index_container< Vertex, multi_index::indexed_by< multi_index::hashed_unique< multi_index::tag< vertex_name_t >, extract_name_from_vertex > > > named_vertices_type; /// The set of vertices, indexed by name typedef typename named_vertices_type::template index< vertex_name_t >::type vertices_by_name_type; /// Construct an instance of the named graph mixin, using the given /// function object to extract a name from the bundled property /// associated with a vertex. named_graph(const extract_name_type& extract = extract_name_type(), const vertex_constructor_type& vertex_constructor = vertex_constructor_type()); /// Notify the named_graph that we have added the given vertex. The /// name of the vertex will be added to the mapping. void added_vertex(Vertex vertex); /// Notify the named_graph that we are removing the given /// vertex. The name of the vertex will be removed from the mapping. template < typename VertexIterStability > void removing_vertex(Vertex vertex, VertexIterStability); /// Notify the named_graph that we are clearing the graph. /// This will clear out all of the name->vertex mappings void clearing_graph(); /// Retrieve the derived instance Graph& derived() { return static_cast< Graph& >(*this); } const Graph& derived() const { return static_cast< const Graph& >(*this); } /// Extract the name from a vertex property instance typename extract_name_type::result_type extract_name( const bundled_vertex_property_type& property); /// Search for a vertex that has the given property (based on its /// name) optional< vertex_descriptor > vertex_by_property( const bundled_vertex_property_type& property); /// Mapping from names to vertices named_vertices_type named_vertices; /// Constructs a vertex from the name of that vertex vertex_constructor_type vertex_constructor; }; /// Helper macro containing the template parameters of named_graph #define BGL_NAMED_GRAPH_PARAMS \ typename Graph, typename Vertex, typename VertexProperty /// Helper macro containing the named_graph<...> instantiation #define BGL_NAMED_GRAPH named_graph< Graph, Vertex, VertexProperty > template < BGL_NAMED_GRAPH_PARAMS > BGL_NAMED_GRAPH::named_graph(const extract_name_type& extract, const vertex_constructor_type& vertex_constructor) : named_vertices(typename named_vertices_type::ctor_args_list( boost::make_tuple(boost::make_tuple(0, // initial number of buckets extract_name_from_vertex(derived(), extract), boost::hash< vertex_name_type >(), std::equal_to< vertex_name_type >())))) , vertex_constructor(vertex_constructor) { } template < BGL_NAMED_GRAPH_PARAMS > inline void BGL_NAMED_GRAPH::added_vertex(Vertex vertex) { named_vertices.insert(vertex); } template < BGL_NAMED_GRAPH_PARAMS > template < typename VertexIterStability > inline void BGL_NAMED_GRAPH::removing_vertex( Vertex vertex, VertexIterStability) { BOOST_STATIC_ASSERT_MSG( (boost::is_base_of< boost::graph_detail::stable_tag, VertexIterStability >::value), "Named graphs cannot use vecS as vertex container and remove " "vertices; the lack of vertex descriptor stability (which iterator " "stability is a proxy for) means that the name -> vertex mapping " "would need to be completely rebuilt after each deletion. See " "https://svn.boost.org/trac/boost/ticket/7863 for more information " "and a test case."); typedef typename BGL_NAMED_GRAPH::vertex_name_type vertex_name_type; const vertex_name_type& vertex_name = extract_name(derived()[vertex]); named_vertices.erase(vertex_name); } template < BGL_NAMED_GRAPH_PARAMS > inline void BGL_NAMED_GRAPH::clearing_graph() { named_vertices.clear(); } template < BGL_NAMED_GRAPH_PARAMS > typename BGL_NAMED_GRAPH::extract_name_type::result_type BGL_NAMED_GRAPH::extract_name(const bundled_vertex_property_type& property) { return named_vertices.key_extractor().extract(property); } template < BGL_NAMED_GRAPH_PARAMS > optional< typename BGL_NAMED_GRAPH::vertex_descriptor > BGL_NAMED_GRAPH::vertex_by_property( const bundled_vertex_property_type& property) { return find_vertex(extract_name(property), *this); } /// Retrieve the vertex associated with the given name template < BGL_NAMED_GRAPH_PARAMS > optional< Vertex > find_vertex( typename BGL_NAMED_GRAPH::vertex_name_type const& name, const BGL_NAMED_GRAPH& g) { typedef typename BGL_NAMED_GRAPH::vertices_by_name_type vertices_by_name_type; // Retrieve the set of vertices indexed by name vertices_by_name_type const& vertices_by_name = g.named_vertices.template get< vertex_name_t >(); /// Look for a vertex with the given name typename vertices_by_name_type::const_iterator iter = vertices_by_name.find(name); if (iter == vertices_by_name.end()) return optional< Vertex >(); // vertex not found else return *iter; } /// Retrieve the vertex associated with the given name, or add a new /// vertex with that name if no such vertex is available. /// Note: This is enabled only when the vertex property type is different /// from the vertex name to avoid ambiguous overload problems with /// the add_vertex() function that takes a vertex property. template < BGL_NAMED_GRAPH_PARAMS > typename disable_if< is_same< typename BGL_NAMED_GRAPH::vertex_name_type, VertexProperty >, Vertex >::type add_vertex(typename BGL_NAMED_GRAPH::vertex_name_type const& name, BGL_NAMED_GRAPH& g) { if (optional< Vertex > vertex = find_vertex(name, g)) /// We found the vertex, so return it return *vertex; else /// There is no vertex with the given name, so create one return add_vertex(g.vertex_constructor(name), g.derived()); } /// Add an edge using vertex names to refer to the vertices template < BGL_NAMED_GRAPH_PARAMS > std::pair< typename graph_traits< Graph >::edge_descriptor, bool > add_edge( typename BGL_NAMED_GRAPH::vertex_name_type const& u_name, typename BGL_NAMED_GRAPH::vertex_name_type const& v_name, BGL_NAMED_GRAPH& g) { return add_edge(add_vertex(u_name, g.derived()), add_vertex(v_name, g.derived()), g.derived()); } /// Add an edge using vertex descriptors or names to refer to the vertices template < BGL_NAMED_GRAPH_PARAMS > std::pair< typename graph_traits< Graph >::edge_descriptor, bool > add_edge( typename BGL_NAMED_GRAPH::vertex_descriptor const& u, typename BGL_NAMED_GRAPH::vertex_name_type const& v_name, BGL_NAMED_GRAPH& g) { return add_edge(u, add_vertex(v_name, g.derived()), g.derived()); } /// Add an edge using vertex descriptors or names to refer to the vertices template < BGL_NAMED_GRAPH_PARAMS > std::pair< typename graph_traits< Graph >::edge_descriptor, bool > add_edge( typename BGL_NAMED_GRAPH::vertex_name_type const& u_name, typename BGL_NAMED_GRAPH::vertex_descriptor const& v, BGL_NAMED_GRAPH& g) { return add_edge(add_vertex(u_name, g.derived()), v, g.derived()); } // Overloads to support EdgeMutablePropertyGraph graphs template < BGL_NAMED_GRAPH_PARAMS > std::pair< typename graph_traits< Graph >::edge_descriptor, bool > add_edge( typename BGL_NAMED_GRAPH::vertex_descriptor const& u, typename BGL_NAMED_GRAPH::vertex_name_type const& v_name, typename edge_property_type< Graph >::type const& p, BGL_NAMED_GRAPH& g) { return add_edge(u, add_vertex(v_name, g.derived()), p, g.derived()); } template < BGL_NAMED_GRAPH_PARAMS > std::pair< typename graph_traits< Graph >::edge_descriptor, bool > add_edge( typename BGL_NAMED_GRAPH::vertex_name_type const& u_name, typename BGL_NAMED_GRAPH::vertex_descriptor const& v, typename edge_property_type< Graph >::type const& p, BGL_NAMED_GRAPH& g) { return add_edge(add_vertex(u_name, g.derived()), v, p, g.derived()); } template < BGL_NAMED_GRAPH_PARAMS > std::pair< typename graph_traits< Graph >::edge_descriptor, bool > add_edge( typename BGL_NAMED_GRAPH::vertex_name_type const& u_name, typename BGL_NAMED_GRAPH::vertex_name_type const& v_name, typename edge_property_type< Graph >::type const& p, BGL_NAMED_GRAPH& g) { return add_edge(add_vertex(u_name, g.derived()), add_vertex(v_name, g.derived()), p, g.derived()); } #undef BGL_NAMED_GRAPH #undef BGL_NAMED_GRAPH_PARAMS /******************************************************************* * Maybe named graph mixin * *******************************************************************/ /** * A graph mixin that can provide a mapping from names to vertices, * and use that mapping to simplify creation and manipulation of * graphs. */ template < typename Graph, typename Vertex, typename VertexProperty, typename ExtractName = typename internal_vertex_name< VertexProperty >::type > struct maybe_named_graph : public named_graph< Graph, Vertex, VertexProperty > { }; /** * A graph mixin that can provide a mapping from names to vertices, * and use that mapping to simplify creation and manipulation of * graphs. This partial specialization turns off this functionality * when the @c VertexProperty does not have an internal vertex name. */ template < typename Graph, typename Vertex, typename VertexProperty > struct maybe_named_graph< Graph, Vertex, VertexProperty, void > { /// The type of the "bundled" property, from which the name can be /// extracted. typedef typename lookup_one_property< VertexProperty, vertex_bundle_t >::type bundled_vertex_property_type; /// Notify the named_graph that we have added the given vertex. This /// is a no-op. void added_vertex(Vertex) {} /// Notify the named_graph that we are removing the given /// vertex. This is a no-op. template < typename VertexIterStability > void removing_vertex(Vertex, VertexIterStability) { } /// Notify the named_graph that we are clearing the graph. This is a /// no-op. void clearing_graph() {} /// Search for a vertex that has the given property (based on its /// name). This always returns an empty optional<> optional< Vertex > vertex_by_property( const bundled_vertex_property_type&) { return optional< Vertex >(); } }; } } // end namespace boost::graph #endif // BOOST_GRAPH_NAMED_GRAPH_HPP degree_centrality.hpp 0000644 00000010214 15125521275 0010751 0 ustar 00 // (C) Copyright 2007-2009 Andrew Sutton // // 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_DEGREE_CENTRALITY_HPP #define BOOST_GRAPH_DEGREE_CENTRALITY_HPP #include <boost/graph/graph_concepts.hpp> #include <boost/concept/assert.hpp> namespace boost { template < typename Graph > struct degree_centrality_measure { typedef typename graph_traits< Graph >::degree_size_type degree_type; typedef typename graph_traits< Graph >::vertex_descriptor vertex_type; }; template < typename Graph > struct influence_measure : public degree_centrality_measure< Graph > { typedef degree_centrality_measure< Graph > base_type; typedef typename base_type::degree_type degree_type; typedef typename base_type::vertex_type vertex_type; inline degree_type operator()(vertex_type v, const Graph& g) { BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >)); return out_degree(v, g); } }; template < typename Graph > inline influence_measure< Graph > measure_influence(const Graph&) { return influence_measure< Graph >(); } template < typename Graph > struct prestige_measure : public degree_centrality_measure< Graph > { typedef degree_centrality_measure< Graph > base_type; typedef typename base_type::degree_type degree_type; typedef typename base_type::vertex_type vertex_type; inline degree_type operator()(vertex_type v, const Graph& g) { BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >)); return in_degree(v, g); } }; template < typename Graph > inline prestige_measure< Graph > measure_prestige(const Graph&) { return prestige_measure< Graph >(); } template < typename Graph, typename Vertex, typename Measure > inline typename Measure::degree_type degree_centrality( const Graph& g, Vertex v, Measure measure) { BOOST_CONCEPT_ASSERT((DegreeMeasureConcept< Measure, Graph >)); return measure(v, g); } template < typename Graph, typename Vertex > inline typename graph_traits< Graph >::degree_size_type degree_centrality( const Graph& g, Vertex v) { return degree_centrality(g, v, measure_influence(g)); } // These are alias functions, intended to provide a more expressive interface. template < typename Graph, typename Vertex > inline typename graph_traits< Graph >::degree_size_type influence( const Graph& g, Vertex v) { return degree_centrality(g, v, measure_influence(g)); } template < typename Graph, typename Vertex > inline typename graph_traits< Graph >::degree_size_type prestige( const Graph& g, Vertex v) { return degree_centrality(g, v, measure_prestige(g)); } template < typename Graph, typename CentralityMap, typename Measure > inline void all_degree_centralities( const Graph& g, CentralityMap cent, Measure measure) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::vertex_iterator VertexIterator; BOOST_CONCEPT_ASSERT((WritablePropertyMapConcept< CentralityMap, Vertex >)); typedef typename property_traits< CentralityMap >::value_type Centrality; VertexIterator i, end; for (boost::tie(i, end) = vertices(g); i != end; ++i) { Centrality c = degree_centrality(g, *i, measure); put(cent, *i, c); } } template < typename Graph, typename CentralityMap > inline void all_degree_centralities(const Graph& g, CentralityMap cent) { all_degree_centralities(g, cent, measure_influence(g)); } // More helper functions for computing influence and prestige. // I hate the names of these functions, but influence and prestige // don't pluralize too well. template < typename Graph, typename CentralityMap > inline void all_influence_values(const Graph& g, CentralityMap cent) { all_degree_centralities(g, cent, measure_influence(g)); } template < typename Graph, typename CentralityMap > inline void all_prestige_values(const Graph& g, CentralityMap cent) { all_degree_centralities(g, cent, measure_prestige(g)); } } /* namespace boost */ #endif edmunds_karp_max_flow.hpp 0000644 00000002006 15125521275 0011630 0 ustar 00 //======================================================================= // (c) Copyright Juergen Hunold 2008 // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_DEPRECATED_INCLUDE_EDMONDS_KARP_MAX_FLOW_HPP #define BOOST_DEPRECATED_INCLUDE_EDMONDS_KARP_MAX_FLOW_HPP #if defined(_MSC_VER) || defined(__BORLANDC__) && !defined(__clang__) || defined(__DMC__) #pragma message( \ "Warning: This header is deprecated. Please use: boost/graph/edmonds_karp_max_flow.hpp") #elif defined(__GNUC__) || defined(__HP_aCC) || defined(__SUNPRO_CC) \ || defined(__IBMCPP__) || defined(__BORLANDC__) #warning \ "This header is deprecated. Please use: boost/graph/edmonds_karp_max_flow.hpp" #endif #include <boost/graph/edmonds_karp_max_flow.hpp> #endif // BOOST_DEPRECATED_INCLUDE_EDMONDS_KARP_MAX_FLOW_HPP is_straight_line_drawing.hpp 0000644 00000016076 15125521275 0012336 0 ustar 00 //======================================================================= // Copyright 2007 Aaron Windsor // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef __IS_STRAIGHT_LINE_DRAWING_HPP__ #define __IS_STRAIGHT_LINE_DRAWING_HPP__ #include <boost/config.hpp> #include <boost/next_prior.hpp> #include <boost/tuple/tuple.hpp> #include <boost/tuple/tuple_comparison.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/planar_detail/bucket_sort.hpp> #include <algorithm> #include <vector> #include <set> #include <map> namespace boost { // Return true exactly when the line segments s1 = ((x1,y1), (x2,y2)) and // s2 = ((a1,b1), (a2,b2)) intersect in a point other than the endpoints of // the line segments. The one exception to this rule is when s1 = s2, in // which case false is returned - this is to accomodate multiple edges // between the same pair of vertices, which shouldn't invalidate the straight // line embedding. A tolerance variable epsilon can also be used, which // defines how far away from the endpoints of s1 and s2 we want to consider // an intersection. inline bool intersects(double x1, double y1, double x2, double y2, double a1, double b1, double a2, double b2, double epsilon = 0.000001) { if (x1 - x2 == 0) { std::swap(x1, a1); std::swap(y1, b1); std::swap(x2, a2); std::swap(y2, b2); } if (x1 - x2 == 0) { BOOST_USING_STD_MAX(); BOOST_USING_STD_MIN(); // two vertical line segments double min_y = min BOOST_PREVENT_MACRO_SUBSTITUTION(y1, y2); double max_y = max BOOST_PREVENT_MACRO_SUBSTITUTION(y1, y2); double min_b = min BOOST_PREVENT_MACRO_SUBSTITUTION(b1, b2); double max_b = max BOOST_PREVENT_MACRO_SUBSTITUTION(b1, b2); if ((max_y > max_b && max_b > min_y) || (max_b > max_y && max_y > min_b)) return true; else return false; } double x_diff = x1 - x2; double y_diff = y1 - y2; double a_diff = a2 - a1; double b_diff = b2 - b1; double beta_denominator = b_diff - (y_diff / ((double)x_diff)) * a_diff; if (beta_denominator == 0) { // parallel lines return false; } double beta = (b2 - y2 - (y_diff / ((double)x_diff)) * (a2 - x2)) / beta_denominator; double alpha = (a2 - x2 - beta * (a_diff)) / x_diff; double upper_bound = 1 - epsilon; double lower_bound = 0 + epsilon; return (beta < upper_bound && beta > lower_bound && alpha < upper_bound && alpha > lower_bound); } template < typename Graph, typename GridPositionMap, typename VertexIndexMap > bool is_straight_line_drawing( const Graph& g, GridPositionMap drawing, VertexIndexMap) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::edge_descriptor edge_t; typedef typename graph_traits< Graph >::edge_iterator edge_iterator_t; typedef std::size_t x_coord_t; typedef std::size_t y_coord_t; typedef boost::tuple< edge_t, x_coord_t, y_coord_t > edge_event_t; typedef typename std::vector< edge_event_t > edge_event_queue_t; typedef tuple< y_coord_t, y_coord_t, x_coord_t, x_coord_t > active_map_key_t; typedef edge_t active_map_value_t; typedef std::map< active_map_key_t, active_map_value_t > active_map_t; typedef typename active_map_t::iterator active_map_iterator_t; edge_event_queue_t edge_event_queue; active_map_t active_edges; edge_iterator_t ei, ei_end; for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) { edge_t e(*ei); vertex_t s(source(e, g)); vertex_t t(target(e, g)); edge_event_queue.push_back( make_tuple(e, static_cast< std::size_t >(drawing[s].x), static_cast< std::size_t >(drawing[s].y))); edge_event_queue.push_back( make_tuple(e, static_cast< std::size_t >(drawing[t].x), static_cast< std::size_t >(drawing[t].y))); } // Order by edge_event_queue by first, then second coordinate // (bucket_sort is a stable sort.) bucket_sort(edge_event_queue.begin(), edge_event_queue.end(), property_map_tuple_adaptor< edge_event_t, 2 >()); bucket_sort(edge_event_queue.begin(), edge_event_queue.end(), property_map_tuple_adaptor< edge_event_t, 1 >()); typedef typename edge_event_queue_t::iterator event_queue_iterator_t; event_queue_iterator_t itr_end = edge_event_queue.end(); for (event_queue_iterator_t itr = edge_event_queue.begin(); itr != itr_end; ++itr) { edge_t e(get< 0 >(*itr)); vertex_t source_v(source(e, g)); vertex_t target_v(target(e, g)); if (drawing[source_v].y > drawing[target_v].y) std::swap(source_v, target_v); active_map_key_t key(get(drawing, source_v).y, get(drawing, target_v).y, get(drawing, source_v).x, get(drawing, target_v).x); active_map_iterator_t a_itr = active_edges.find(key); if (a_itr == active_edges.end()) { active_edges[key] = e; } else { active_map_iterator_t before, after; if (a_itr == active_edges.begin()) before = active_edges.end(); else before = prior(a_itr); after = boost::next(a_itr); if (before != active_edges.end()) { edge_t f = before->second; vertex_t e_source(source(e, g)); vertex_t e_target(target(e, g)); vertex_t f_source(source(f, g)); vertex_t f_target(target(f, g)); if (intersects(drawing[e_source].x, drawing[e_source].y, drawing[e_target].x, drawing[e_target].y, drawing[f_source].x, drawing[f_source].y, drawing[f_target].x, drawing[f_target].y)) return false; } if (after != active_edges.end()) { edge_t f = after->second; vertex_t e_source(source(e, g)); vertex_t e_target(target(e, g)); vertex_t f_source(source(f, g)); vertex_t f_target(target(f, g)); if (intersects(drawing[e_source].x, drawing[e_source].y, drawing[e_target].x, drawing[e_target].y, drawing[f_source].x, drawing[f_source].y, drawing[f_target].x, drawing[f_target].y)) return false; } active_edges.erase(a_itr); } } return true; } template < typename Graph, typename GridPositionMap > bool is_straight_line_drawing(const Graph& g, GridPositionMap drawing) { return is_straight_line_drawing(g, drawing, get(vertex_index, g)); } } #endif // __IS_STRAIGHT_LINE_DRAWING_HPP__ metric_tsp_approx.hpp 0000644 00000025071 15125521275 0011031 0 ustar 00 //======================================================================= // Copyright 2008 // Author: Matyas W Egyhazy // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_METRIC_TSP_APPROX_HPP #define BOOST_GRAPH_METRIC_TSP_APPROX_HPP // metric_tsp_approx // Generates an approximate tour solution for the traveling salesperson // problem in polynomial time. The current algorithm guarantees a tour with a // length at most as long as 2x optimal solution. The graph should have // 'natural' (metric) weights such that the triangle inequality is maintained. // Graphs must be fully interconnected. // TODO: // There are a couple of improvements that could be made. // 1) Change implementation to lower uppper bound Christofides heuristic // 2) Implement a less restrictive TSP heuristic (one that does not rely on // triangle inequality). // 3) Determine if the algorithm can be implemented without creating a new // graph. #include <vector> #include <boost/shared_ptr.hpp> #include <boost/concept_check.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_as_tree.hpp> #include <boost/graph/adjacency_list.hpp> #include <boost/graph/prim_minimum_spanning_tree.hpp> #include <boost/graph/lookup_edge.hpp> #include <boost/throw_exception.hpp> namespace boost { // Define a concept for the concept-checking library. template < typename Visitor, typename Graph > struct TSPVertexVisitorConcept { private: Visitor vis_; public: typedef typename graph_traits< Graph >::vertex_descriptor Vertex; BOOST_CONCEPT_USAGE(TSPVertexVisitorConcept) { Visitor vis(vis_); // require copy construction Graph g(1); Vertex v(*vertices(g).first); vis.visit_vertex(v, g); // require visit_vertex } }; // Tree visitor that keeps track of a preorder traversal of a tree // TODO: Consider migrating this to the graph_as_tree header. // TODO: Parameterize the underlying stores so it doesn't have to be a vector. template < typename Node, typename Tree > class PreorderTraverser { private: std::vector< Node >& path_; public: typedef typename std::vector< Node >::const_iterator const_iterator; PreorderTraverser(std::vector< Node >& p) : path_(p) {} void preorder(Node n, const Tree&) { path_.push_back(n); } void inorder(Node, const Tree&) const {} void postorder(Node, const Tree&) const {} const_iterator begin() const { return path_.begin(); } const_iterator end() const { return path_.end(); } }; // Forward declarations template < typename > class tsp_tour_visitor; template < typename, typename, typename, typename > class tsp_tour_len_visitor; template < typename VertexListGraph, typename OutputIterator > void metric_tsp_approx_tour(VertexListGraph& g, OutputIterator o) { metric_tsp_approx_from_vertex(g, *vertices(g).first, get(edge_weight, g), get(vertex_index, g), tsp_tour_visitor< OutputIterator >(o)); } template < typename VertexListGraph, typename WeightMap, typename OutputIterator > void metric_tsp_approx_tour(VertexListGraph& g, WeightMap w, OutputIterator o) { metric_tsp_approx_from_vertex( g, *vertices(g).first, w, tsp_tour_visitor< OutputIterator >(o)); } template < typename VertexListGraph, typename OutputIterator > void metric_tsp_approx_tour_from_vertex(VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor start, OutputIterator o) { metric_tsp_approx_from_vertex(g, start, get(edge_weight, g), get(vertex_index, g), tsp_tour_visitor< OutputIterator >(o)); } template < typename VertexListGraph, typename WeightMap, typename OutputIterator > void metric_tsp_approx_tour_from_vertex(VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor start, WeightMap w, OutputIterator o) { metric_tsp_approx_from_vertex(g, start, w, get(vertex_index, g), tsp_tour_visitor< OutputIterator >(o)); } template < typename VertexListGraph, typename TSPVertexVisitor > void metric_tsp_approx(VertexListGraph& g, TSPVertexVisitor vis) { metric_tsp_approx_from_vertex( g, *vertices(g).first, get(edge_weight, g), get(vertex_index, g), vis); } template < typename VertexListGraph, typename Weightmap, typename VertexIndexMap, typename TSPVertexVisitor > void metric_tsp_approx(VertexListGraph& g, Weightmap w, TSPVertexVisitor vis) { metric_tsp_approx_from_vertex( g, *vertices(g).first, w, get(vertex_index, g), vis); } template < typename VertexListGraph, typename WeightMap, typename VertexIndexMap, typename TSPVertexVisitor > void metric_tsp_approx( VertexListGraph& g, WeightMap w, VertexIndexMap id, TSPVertexVisitor vis) { metric_tsp_approx_from_vertex(g, *vertices(g).first, w, id, vis); } template < typename VertexListGraph, typename WeightMap, typename TSPVertexVisitor > void metric_tsp_approx_from_vertex(VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor start, WeightMap w, TSPVertexVisitor vis) { metric_tsp_approx_from_vertex(g, start, w, get(vertex_index, g), vis); } template < typename VertexListGraph, typename WeightMap, typename VertexIndexMap, typename TSPVertexVisitor > void metric_tsp_approx_from_vertex(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor start, WeightMap weightmap, VertexIndexMap indexmap, TSPVertexVisitor vis) { using namespace boost; using namespace std; BOOST_CONCEPT_ASSERT((VertexListGraphConcept< VertexListGraph >)); BOOST_CONCEPT_ASSERT( (TSPVertexVisitorConcept< TSPVertexVisitor, VertexListGraph >)); // Types related to the input graph (GVertex is a template parameter). typedef typename graph_traits< VertexListGraph >::vertex_descriptor GVertex; typedef typename graph_traits< VertexListGraph >::vertex_iterator GVItr; // We build a custom graph in this algorithm. typedef adjacency_list< vecS, vecS, directedS, no_property, no_property > MSTImpl; typedef graph_traits< MSTImpl >::vertex_descriptor Vertex; typedef graph_traits< MSTImpl >::vertex_iterator VItr; // And then re-cast it as a tree. typedef iterator_property_map< vector< Vertex >::iterator, property_map< MSTImpl, vertex_index_t >::type > ParentMap; typedef graph_as_tree< MSTImpl, ParentMap > Tree; typedef tree_traits< Tree >::node_descriptor Node; // A predecessor map. typedef vector< GVertex > PredMap; typedef iterator_property_map< typename PredMap::iterator, VertexIndexMap > PredPMap; PredMap preds(num_vertices(g)); PredPMap pred_pmap(preds.begin(), indexmap); // Compute a spanning tree over the in put g. prim_minimum_spanning_tree(g, pred_pmap, root_vertex(start).vertex_index_map(indexmap).weight_map(weightmap)); // Build a MST using the predecessor map from prim mst MSTImpl mst(num_vertices(g)); std::size_t cnt = 0; pair< VItr, VItr > mst_verts(vertices(mst)); for (typename PredMap::iterator vi(preds.begin()); vi != preds.end(); ++vi, ++cnt) { if (indexmap[*vi] != cnt) { add_edge(*next(mst_verts.first, indexmap[*vi]), *next(mst_verts.first, cnt), mst); } } // Build a tree abstraction over the MST. vector< Vertex > parent(num_vertices(mst)); Tree t(mst, *vertices(mst).first, make_iterator_property_map(parent.begin(), get(vertex_index, mst))); // Create tour using a preorder traversal of the mst vector< Node > tour; PreorderTraverser< Node, Tree > tvis(tour); traverse_tree(indexmap[start], t, tvis); pair< GVItr, GVItr > g_verts(vertices(g)); for (PreorderTraverser< Node, Tree >::const_iterator curr(tvis.begin()); curr != tvis.end(); ++curr) { // TODO: This is will be O(n^2) if vertex storage of g != vecS. GVertex v = *next(g_verts.first, get(vertex_index, mst)[*curr]); vis.visit_vertex(v, g); } // Connect back to the start of the tour vis.visit_vertex(start, g); } // Default tsp tour visitor that puts the tour in an OutputIterator template < typename OutItr > class tsp_tour_visitor { OutItr itr_; public: tsp_tour_visitor(OutItr itr) : itr_(itr) {} template < typename Vertex, typename Graph > void visit_vertex(Vertex v, const Graph&) { BOOST_CONCEPT_ASSERT((OutputIterator< OutItr, Vertex >)); *itr_++ = v; } }; // Tsp tour visitor that adds the total tour length. template < typename Graph, typename WeightMap, typename OutIter, typename Length > class tsp_tour_len_visitor { typedef typename graph_traits< Graph >::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT((OutputIterator< OutIter, Vertex >)); OutIter iter_; Length& tourlen_; WeightMap& wmap_; Vertex previous_; // Helper function for getting the null vertex. Vertex null() { return graph_traits< Graph >::null_vertex(); } public: tsp_tour_len_visitor(Graph const&, OutIter iter, Length& l, WeightMap& map) : iter_(iter), tourlen_(l), wmap_(map), previous_(null()) { } void visit_vertex(Vertex v, const Graph& g) { typedef typename graph_traits< Graph >::edge_descriptor Edge; // If it is not the start, then there is a // previous vertex if (previous_ != null()) { // NOTE: For non-adjacency matrix graphs g, this bit of code // will be linear in the degree of previous_ or v. A better // solution would be to visit edges of the graph, but that // would require revisiting the core algorithm. Edge e; bool found; boost::tie(e, found) = lookup_edge(previous_, v, g); if (!found) { BOOST_THROW_EXCEPTION(not_complete()); } tourlen_ += wmap_[e]; } previous_ = v; *iter_++ = v; } }; // Object generator(s) template < typename OutIter > inline tsp_tour_visitor< OutIter > make_tsp_tour_visitor(OutIter iter) { return tsp_tour_visitor< OutIter >(iter); } template < typename Graph, typename WeightMap, typename OutIter, typename Length > inline tsp_tour_len_visitor< Graph, WeightMap, OutIter, Length > make_tsp_tour_len_visitor( Graph const& g, OutIter iter, Length& l, WeightMap map) { return tsp_tour_len_visitor< Graph, WeightMap, OutIter, Length >( g, iter, l, map); } } // boost #endif // BOOST_GRAPH_METRIC_TSP_APPROX_HPP sequential_vertex_coloring.hpp 0000644 00000010722 15125521275 0012727 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Copyright 2004 The Trustees of Indiana University // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_SEQUENTIAL_VERTEX_COLORING_HPP #define BOOST_GRAPH_SEQUENTIAL_VERTEX_COLORING_HPP #include <vector> #include <boost/graph/graph_traits.hpp> #include <boost/tuple/tuple.hpp> #include <boost/property_map/property_map.hpp> #include <boost/limits.hpp> #ifdef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS #include <iterator> #endif /* This algorithm is to find coloring of a graph Algorithm: Let G = (V,E) be a graph with vertices (somehow) ordered v_1, v_2, ..., v_n. For k = 1, 2, ..., n the sequential algorithm assigns v_k to the smallest possible color. Reference: Thomas F. Coleman and Jorge J. More, Estimation of sparse Jacobian matrices and graph coloring problems. J. Numer. Anal. V20, P187-209, 1983 v_k is stored as o[k] here. The color of the vertex v will be stored in color[v]. i.e., vertex v belongs to coloring color[v] */ namespace boost { template < class VertexListGraph, class OrderPA, class ColorMap > typename property_traits< ColorMap >::value_type sequential_vertex_coloring( const VertexListGraph& G, OrderPA order, ColorMap color) { typedef graph_traits< VertexListGraph > GraphTraits; typedef typename GraphTraits::vertex_descriptor Vertex; typedef typename property_traits< ColorMap >::value_type size_type; size_type max_color = 0; const size_type V = num_vertices(G); // We need to keep track of which colors are used by // adjacent vertices. We do this by marking the colors // that are used. The mark array contains the mark // for each color. The length of mark is the // number of vertices since the maximum possible number of colors // is the number of vertices. std::vector< size_type > mark(V, std::numeric_limits< size_type >::max BOOST_PREVENT_MACRO_SUBSTITUTION()); // Initialize colors typename GraphTraits::vertex_iterator v, vend; for (boost::tie(v, vend) = vertices(G); v != vend; ++v) put(color, *v, V - 1); // Determine the color for every vertex one by one for (size_type i = 0; i < V; i++) { Vertex current = get(order, i); typename GraphTraits::adjacency_iterator v, vend; // Mark the colors of vertices adjacent to current. // i can be the value for marking since i increases successively for (boost::tie(v, vend) = adjacent_vertices(current, G); v != vend; ++v) mark[get(color, *v)] = i; // Next step is to assign the smallest un-marked color // to the current vertex. size_type j = 0; // Scan through all useable colors, find the smallest possible // color that is not used by neighbors. Note that if mark[j] // is equal to i, color j is used by one of the current vertex's // neighbors. while (j < max_color && mark[j] == i) ++j; if (j == max_color) // All colors are used up. Add one more color ++max_color; // At this point, j is the smallest possible color put(color, current, j); // Save the color of vertex current } return max_color; } template < class VertexListGraph, class ColorMap > typename property_traits< ColorMap >::value_type sequential_vertex_coloring( const VertexListGraph& G, ColorMap color) { typedef typename graph_traits< VertexListGraph >::vertex_descriptor vertex_descriptor; typedef typename graph_traits< VertexListGraph >::vertex_iterator vertex_iterator; std::pair< vertex_iterator, vertex_iterator > v = vertices(G); #ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS std::vector< vertex_descriptor > order(v.first, v.second); #else std::vector< vertex_descriptor > order; order.reserve(std::distance(v.first, v.second)); while (v.first != v.second) order.push_back(*v.first++); #endif return sequential_vertex_coloring(G, make_iterator_property_map(order.begin(), identity_property_map(), graph_traits< VertexListGraph >::null_vertex()), color); } } #endif cuthill_mckee_ordering.hpp 0000644 00000013550 15125521275 0011767 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Copyright 2004, 2005 Trustees of Indiana University // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, // Doug Gregor, D. Kevin McGrath // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_CUTHILL_MCKEE_HPP #define BOOST_GRAPH_CUTHILL_MCKEE_HPP #include <boost/config.hpp> #include <boost/graph/detail/sparse_ordering.hpp> #include <boost/graph/graph_utility.hpp> #include <algorithm> /* (Reverse) Cuthill-McKee Algorithm for matrix reordering */ namespace boost { namespace detail { template < typename OutputIterator, typename Buffer, typename DegreeMap > class bfs_rcm_visitor : public default_bfs_visitor { public: bfs_rcm_visitor(OutputIterator* iter, Buffer* b, DegreeMap deg) : permutation(iter), Qptr(b), degree(deg) { } template < class Vertex, class Graph > void examine_vertex(Vertex u, Graph&) { *(*permutation)++ = u; index_begin = Qptr->size(); } template < class Vertex, class Graph > void finish_vertex(Vertex, Graph&) { using std::sort; typedef typename property_traits< DegreeMap >::value_type ds_type; typedef indirect_cmp< DegreeMap, std::less< ds_type > > Compare; Compare comp(degree); sort(Qptr->begin() + index_begin, Qptr->end(), comp); } protected: OutputIterator* permutation; int index_begin; Buffer* Qptr; DegreeMap degree; }; } // namespace detail // Reverse Cuthill-McKee algorithm with a given starting Vertex. // // If user provides a reverse iterator, this will be a reverse-cuthill-mckee // algorithm, otherwise it will be a standard CM algorithm template < class Graph, class OutputIterator, class ColorMap, class DegreeMap > OutputIterator cuthill_mckee_ordering(const Graph& g, std::deque< typename graph_traits< Graph >::vertex_descriptor > vertex_queue, OutputIterator permutation, ColorMap color, DegreeMap degree) { // create queue, visitor...don't forget namespaces! typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename boost::sparse::sparse_ordering_queue< Vertex > queue; typedef typename detail::bfs_rcm_visitor< OutputIterator, queue, DegreeMap > Visitor; typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; queue Q; // create a bfs_rcm_visitor as defined above Visitor vis(&permutation, &Q, degree); typename graph_traits< Graph >::vertex_iterator ui, ui_end; // Copy degree to pseudo_degree // initialize the color map for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { put(color, *ui, Color::white()); } while (!vertex_queue.empty()) { Vertex s = vertex_queue.front(); vertex_queue.pop_front(); // call BFS with visitor breadth_first_visit(g, s, Q, vis, color); } return permutation; } // This is the case where only a single starting vertex is supplied. template < class Graph, class OutputIterator, class ColorMap, class DegreeMap > OutputIterator cuthill_mckee_ordering(const Graph& g, typename graph_traits< Graph >::vertex_descriptor s, OutputIterator permutation, ColorMap color, DegreeMap degree) { std::deque< typename graph_traits< Graph >::vertex_descriptor > vertex_queue; vertex_queue.push_front(s); return cuthill_mckee_ordering(g, vertex_queue, permutation, color, degree); } // This is the version of CM which selects its own starting vertex template < class Graph, class OutputIterator, class ColorMap, class DegreeMap > OutputIterator cuthill_mckee_ordering(const Graph& G, OutputIterator permutation, ColorMap color, DegreeMap degree) { if (boost::graph::has_no_vertices(G)) return permutation; typedef typename boost::graph_traits< Graph >::vertex_descriptor Vertex; typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; std::deque< Vertex > vertex_queue; // Mark everything white BGL_FORALL_VERTICES_T(v, G, Graph) put(color, v, Color::white()); // Find one vertex from each connected component BGL_FORALL_VERTICES_T(v, G, Graph) { if (get(color, v) == Color::white()) { depth_first_visit(G, v, dfs_visitor<>(), color); vertex_queue.push_back(v); } } // Find starting nodes for all vertices // TBD: How to do this with a directed graph? for (typename std::deque< Vertex >::iterator i = vertex_queue.begin(); i != vertex_queue.end(); ++i) *i = find_starting_node(G, *i, color, degree); return cuthill_mckee_ordering(G, vertex_queue, permutation, color, degree); } template < typename Graph, typename OutputIterator, typename VertexIndexMap > OutputIterator cuthill_mckee_ordering( const Graph& G, OutputIterator permutation, VertexIndexMap index_map) { if (boost::graph::has_no_vertices(G)) return permutation; std::vector< default_color_type > colors(num_vertices(G)); return cuthill_mckee_ordering(G, permutation, make_iterator_property_map(&colors[0], index_map, colors[0]), make_out_degree_map(G)); } template < typename Graph, typename OutputIterator > inline OutputIterator cuthill_mckee_ordering( const Graph& G, OutputIterator permutation) { return cuthill_mckee_ordering(G, permutation, get(vertex_index, G)); } } // namespace boost #endif // BOOST_GRAPH_CUTHILL_MCKEE_HPP dijkstra_shortest_paths.hpp 0000644 00000056217 15125521275 0012242 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // // // Revision History: // 04 April 2001: Added named parameter variant. (Jeremy Siek) // 01 April 2001: Modified to use new <boost/limits.hpp> header. (JMaddock) // #ifndef BOOST_GRAPH_DIJKSTRA_HPP #define BOOST_GRAPH_DIJKSTRA_HPP #include <functional> #include <boost/limits.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/relax.hpp> #include <boost/pending/indirect_cmp.hpp> #include <boost/graph/exception.hpp> #include <boost/graph/overloading.hpp> #include <boost/smart_ptr.hpp> #include <boost/graph/detail/d_ary_heap.hpp> #include <boost/graph/two_bit_color_map.hpp> #include <boost/graph/detail/mpi_include.hpp> #include <boost/property_map/property_map.hpp> #include <boost/property_map/vector_property_map.hpp> #include <boost/type_traits.hpp> #include <boost/concept/assert.hpp> #ifdef BOOST_GRAPH_DIJKSTRA_TESTING #include <boost/pending/mutable_queue.hpp> #endif // BOOST_GRAPH_DIJKSTRA_TESTING namespace boost { /** * @brief Updates a particular value in a queue used by Dijkstra's * algorithm. * * This routine is called by Dijkstra's algorithm after it has * decreased the distance from the source vertex to the given @p * vertex. By default, this routine will just call @c * Q.update(vertex). However, other queues may provide more * specialized versions of this routine. * * @param Q the queue that will be updated. * @param vertex the vertex whose distance has been updated * @param old_distance the previous distance to @p vertex */ template < typename Buffer, typename Vertex, typename DistanceType > inline void dijkstra_queue_update( Buffer& Q, Vertex vertex, DistanceType old_distance) { (void)old_distance; Q.update(vertex); } template < class Visitor, class Graph > struct DijkstraVisitorConcept { void constraints() { BOOST_CONCEPT_ASSERT((CopyConstructibleConcept< Visitor >)); vis.initialize_vertex(u, g); vis.discover_vertex(u, g); vis.examine_vertex(u, g); vis.examine_edge(e, g); vis.edge_relaxed(e, g); vis.edge_not_relaxed(e, g); vis.finish_vertex(u, g); } Visitor vis; Graph g; typename graph_traits< Graph >::vertex_descriptor u; typename graph_traits< Graph >::edge_descriptor e; }; template < class Visitors = null_visitor > class dijkstra_visitor : public bfs_visitor< Visitors > { public: dijkstra_visitor() {} dijkstra_visitor(Visitors vis) : bfs_visitor< Visitors >(vis) {} template < class Edge, class Graph > void edge_relaxed(Edge e, Graph& g) { invoke_visitors(this->m_vis, e, g, on_edge_relaxed()); } template < class Edge, class Graph > void edge_not_relaxed(Edge e, Graph& g) { invoke_visitors(this->m_vis, e, g, on_edge_not_relaxed()); } private: template < class Edge, class Graph > void tree_edge(Edge u, Graph& g) {} }; template < class Visitors > dijkstra_visitor< Visitors > make_dijkstra_visitor(Visitors vis) { return dijkstra_visitor< Visitors >(vis); } typedef dijkstra_visitor<> default_dijkstra_visitor; namespace detail { template < class UniformCostVisitor, class UpdatableQueue, class WeightMap, class PredecessorMap, class DistanceMap, class BinaryFunction, class BinaryPredicate > struct dijkstra_bfs_visitor { typedef typename property_traits< DistanceMap >::value_type D; typedef typename property_traits< WeightMap >::value_type W; dijkstra_bfs_visitor(UniformCostVisitor vis, UpdatableQueue& Q, WeightMap w, PredecessorMap p, DistanceMap d, BinaryFunction combine, BinaryPredicate compare, D zero) : m_vis(vis) , m_Q(Q) , m_weight(w) , m_predecessor(p) , m_distance(d) , m_combine(combine) , m_compare(compare) , m_zero(zero) { } template < class Edge, class Graph > void tree_edge(Edge e, Graph& g) { bool decreased = relax_target(e, g, m_weight, m_predecessor, m_distance, m_combine, m_compare); if (decreased) m_vis.edge_relaxed(e, g); else m_vis.edge_not_relaxed(e, g); } template < class Edge, class Graph > void gray_target(Edge e, Graph& g) { D old_distance = get(m_distance, target(e, g)); bool decreased = relax_target(e, g, m_weight, m_predecessor, m_distance, m_combine, m_compare); if (decreased) { dijkstra_queue_update(m_Q, target(e, g), old_distance); m_vis.edge_relaxed(e, g); } else m_vis.edge_not_relaxed(e, g); } template < class Vertex, class Graph > void initialize_vertex(Vertex u, Graph& g) { m_vis.initialize_vertex(u, g); } template < class Edge, class Graph > void non_tree_edge(Edge, Graph&) {} template < class Vertex, class Graph > void discover_vertex(Vertex u, Graph& g) { m_vis.discover_vertex(u, g); } template < class Vertex, class Graph > void examine_vertex(Vertex u, Graph& g) { m_vis.examine_vertex(u, g); } template < class Edge, class Graph > void examine_edge(Edge e, Graph& g) { // Test for negative-weight edges: // // Reasons that other comparisons do not work: // // m_compare(e_weight, D(0)): // m_compare only needs to work on distances, not weights, and // those types do not need to be the same (bug 8398, // https://svn.boost.org/trac/boost/ticket/8398). // m_compare(m_combine(source_dist, e_weight), source_dist): // if m_combine is project2nd (as in prim_minimum_spanning_tree), // this test will claim that the edge weight is negative whenever // the edge weight is less than source_dist, even if both of // those are positive (bug 9012, // https://svn.boost.org/trac/boost/ticket/9012). // m_compare(m_combine(e_weight, source_dist), source_dist): // would fix project2nd issue, but documentation only requires // that m_combine be able to take a distance and a weight (in // that order) and return a distance. // W e_weight = get(m_weight, e); // sd_plus_ew = source_dist + e_weight. // D sd_plus_ew = m_combine(source_dist, e_weight); // sd_plus_2ew = source_dist + 2 * e_weight. // D sd_plus_2ew = m_combine(sd_plus_ew, e_weight); // The test here is equivalent to e_weight < 0 if m_combine has a // cancellation law, but always returns false when m_combine is a // projection operator. if (m_compare(m_combine(m_zero, get(m_weight, e)), m_zero)) boost::throw_exception(negative_edge()); // End of test for negative-weight edges. m_vis.examine_edge(e, g); } template < class Edge, class Graph > void black_target(Edge, Graph&) {} template < class Vertex, class Graph > void finish_vertex(Vertex u, Graph& g) { m_vis.finish_vertex(u, g); } UniformCostVisitor m_vis; UpdatableQueue& m_Q; WeightMap m_weight; PredecessorMap m_predecessor; DistanceMap m_distance; BinaryFunction m_combine; BinaryPredicate m_compare; D m_zero; }; } // namespace detail namespace detail { template < class Graph, class IndexMap, class Value, bool KnownNumVertices > struct vertex_property_map_generator_helper { }; template < class Graph, class IndexMap, class Value > struct vertex_property_map_generator_helper< Graph, IndexMap, Value, true > { typedef boost::iterator_property_map< Value*, IndexMap > type; static type build(const Graph& g, const IndexMap& index, boost::scoped_array< Value >& array_holder) { array_holder.reset(new Value[num_vertices(g)]); std::fill(array_holder.get(), array_holder.get() + num_vertices(g), Value()); return make_iterator_property_map(array_holder.get(), index); } }; template < class Graph, class IndexMap, class Value > struct vertex_property_map_generator_helper< Graph, IndexMap, Value, false > { typedef boost::vector_property_map< Value, IndexMap > type; static type build(const Graph& g, const IndexMap& index, boost::scoped_array< Value >& array_holder) { return boost::make_vector_property_map< Value >(index); } }; template < class Graph, class IndexMap, class Value > struct vertex_property_map_generator { typedef boost::is_base_and_derived< boost::vertex_list_graph_tag, typename boost::graph_traits< Graph >::traversal_category > known_num_vertices; typedef vertex_property_map_generator_helper< Graph, IndexMap, Value, known_num_vertices::value > helper; typedef typename helper::type type; static type build(const Graph& g, const IndexMap& index, boost::scoped_array< Value >& array_holder) { return helper::build(g, index, array_holder); } }; } namespace detail { template < class Graph, class IndexMap, bool KnownNumVertices > struct default_color_map_generator_helper { }; template < class Graph, class IndexMap > struct default_color_map_generator_helper< Graph, IndexMap, true > { typedef boost::two_bit_color_map< IndexMap > type; static type build(const Graph& g, const IndexMap& index) { size_t nv = num_vertices(g); return boost::two_bit_color_map< IndexMap >(nv, index); } }; template < class Graph, class IndexMap > struct default_color_map_generator_helper< Graph, IndexMap, false > { typedef boost::vector_property_map< boost::two_bit_color_type, IndexMap > type; static type build(const Graph& g, const IndexMap& index) { return boost::make_vector_property_map< boost::two_bit_color_type >( index); } }; template < class Graph, class IndexMap > struct default_color_map_generator { typedef boost::is_base_and_derived< boost::vertex_list_graph_tag, typename boost::graph_traits< Graph >::traversal_category > known_num_vertices; typedef default_color_map_generator_helper< Graph, IndexMap, known_num_vertices::value > helper; typedef typename helper::type type; static type build(const Graph& g, const IndexMap& index) { return helper::build(g, index); } }; } // Call breadth first search with default color map. template < class Graph, class SourceInputIter, class DijkstraVisitor, class PredecessorMap, class DistanceMap, class WeightMap, class IndexMap, class Compare, class Combine, class DistZero > inline void dijkstra_shortest_paths_no_init(const Graph& g, SourceInputIter s_begin, SourceInputIter s_end, PredecessorMap predecessor, DistanceMap distance, WeightMap weight, IndexMap index_map, Compare compare, Combine combine, DistZero zero, DijkstraVisitor vis) { typedef detail::default_color_map_generator< Graph, IndexMap > ColorMapHelper; typedef typename ColorMapHelper::type ColorMap; ColorMap color = ColorMapHelper::build(g, index_map); dijkstra_shortest_paths_no_init(g, s_begin, s_end, predecessor, distance, weight, index_map, compare, combine, zero, vis, color); } // Call breadth first search with default color map. template < class Graph, class DijkstraVisitor, class PredecessorMap, class DistanceMap, class WeightMap, class IndexMap, class Compare, class Combine, class DistZero > inline void dijkstra_shortest_paths_no_init(const Graph& g, typename graph_traits< Graph >::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, WeightMap weight, IndexMap index_map, Compare compare, Combine combine, DistZero zero, DijkstraVisitor vis) { dijkstra_shortest_paths_no_init(g, &s, &s + 1, predecessor, distance, weight, index_map, compare, combine, zero, vis); } // Call breadth first search template < class Graph, class SourceInputIter, class DijkstraVisitor, class PredecessorMap, class DistanceMap, class WeightMap, class IndexMap, class Compare, class Combine, class DistZero, class ColorMap > inline void dijkstra_shortest_paths_no_init(const Graph& g, SourceInputIter s_begin, SourceInputIter s_end, PredecessorMap predecessor, DistanceMap distance, WeightMap weight, IndexMap index_map, Compare compare, Combine combine, DistZero zero, DijkstraVisitor vis, ColorMap color) { typedef indirect_cmp< DistanceMap, Compare > IndirectCmp; IndirectCmp icmp(distance, compare); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; // Now the default: use a d-ary heap boost::scoped_array< std::size_t > index_in_heap_map_holder; typedef detail::vertex_property_map_generator< Graph, IndexMap, std::size_t > IndexInHeapMapHelper; typedef typename IndexInHeapMapHelper::type IndexInHeapMap; IndexInHeapMap index_in_heap = IndexInHeapMapHelper::build(g, index_map, index_in_heap_map_holder); typedef d_ary_heap_indirect< Vertex, 4, IndexInHeapMap, DistanceMap, Compare > MutableQueue; MutableQueue Q(distance, index_in_heap, compare); detail::dijkstra_bfs_visitor< DijkstraVisitor, MutableQueue, WeightMap, PredecessorMap, DistanceMap, Combine, Compare > bfs_vis(vis, Q, weight, predecessor, distance, combine, compare, zero); breadth_first_visit(g, s_begin, s_end, Q, bfs_vis, color); } // Call breadth first search template < class Graph, class DijkstraVisitor, class PredecessorMap, class DistanceMap, class WeightMap, class IndexMap, class Compare, class Combine, class DistZero, class ColorMap > inline void dijkstra_shortest_paths_no_init(const Graph& g, typename graph_traits< Graph >::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, WeightMap weight, IndexMap index_map, Compare compare, Combine combine, DistZero zero, DijkstraVisitor vis, ColorMap color) { dijkstra_shortest_paths_no_init(g, &s, &s + 1, predecessor, distance, weight, index_map, compare, combine, zero, vis, color); } // Initialize distances and call breadth first search with default color map template < class VertexListGraph, class SourceInputIter, class DijkstraVisitor, class PredecessorMap, class DistanceMap, class WeightMap, class IndexMap, class Compare, class Combine, class DistInf, class DistZero, typename T, typename Tag, typename Base > inline void dijkstra_shortest_paths(const VertexListGraph& g, SourceInputIter s_begin, SourceInputIter s_end, PredecessorMap predecessor, DistanceMap distance, WeightMap weight, IndexMap index_map, Compare compare, Combine combine, DistInf inf, DistZero zero, DijkstraVisitor vis, const bgl_named_params< T, Tag, Base >& BOOST_GRAPH_ENABLE_IF_MODELS_PARM( VertexListGraph, vertex_list_graph_tag)) { boost::two_bit_color_map< IndexMap > color(num_vertices(g), index_map); dijkstra_shortest_paths(g, s_begin, s_end, predecessor, distance, weight, index_map, compare, combine, inf, zero, vis, color); } // Initialize distances and call breadth first search with default color map template < class VertexListGraph, class DijkstraVisitor, class PredecessorMap, class DistanceMap, class WeightMap, class IndexMap, class Compare, class Combine, class DistInf, class DistZero, typename T, typename Tag, typename Base > inline void dijkstra_shortest_paths(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, WeightMap weight, IndexMap index_map, Compare compare, Combine combine, DistInf inf, DistZero zero, DijkstraVisitor vis, const bgl_named_params< T, Tag, Base >& BOOST_GRAPH_ENABLE_IF_MODELS_PARM( VertexListGraph, vertex_list_graph_tag)) { dijkstra_shortest_paths(g, &s, &s + 1, predecessor, distance, weight, index_map, compare, combine, inf, zero, vis); } // Initialize distances and call breadth first search template < class VertexListGraph, class SourceInputIter, class DijkstraVisitor, class PredecessorMap, class DistanceMap, class WeightMap, class IndexMap, class Compare, class Combine, class DistInf, class DistZero, class ColorMap > inline void dijkstra_shortest_paths(const VertexListGraph& g, SourceInputIter s_begin, SourceInputIter s_end, PredecessorMap predecessor, DistanceMap distance, WeightMap weight, IndexMap index_map, Compare compare, Combine combine, DistInf inf, DistZero zero, DijkstraVisitor vis, ColorMap color) { typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; typename graph_traits< VertexListGraph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { vis.initialize_vertex(*ui, g); put(distance, *ui, inf); put(predecessor, *ui, *ui); put(color, *ui, Color::white()); } for (SourceInputIter it = s_begin; it != s_end; ++it) { put(distance, *it, zero); } dijkstra_shortest_paths_no_init(g, s_begin, s_end, predecessor, distance, weight, index_map, compare, combine, zero, vis, color); } // Initialize distances and call breadth first search template < class VertexListGraph, class DijkstraVisitor, class PredecessorMap, class DistanceMap, class WeightMap, class IndexMap, class Compare, class Combine, class DistInf, class DistZero, class ColorMap > inline void dijkstra_shortest_paths(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, WeightMap weight, IndexMap index_map, Compare compare, Combine combine, DistInf inf, DistZero zero, DijkstraVisitor vis, ColorMap color) { dijkstra_shortest_paths(g, &s, &s + 1, predecessor, distance, weight, index_map, compare, combine, inf, zero, vis, color); } // Initialize distances and call breadth first search template < class VertexListGraph, class SourceInputIter, class DijkstraVisitor, class PredecessorMap, class DistanceMap, class WeightMap, class IndexMap, class Compare, class Combine, class DistInf, class DistZero > inline void dijkstra_shortest_paths(const VertexListGraph& g, SourceInputIter s_begin, SourceInputIter s_end, PredecessorMap predecessor, DistanceMap distance, WeightMap weight, IndexMap index_map, Compare compare, Combine combine, DistInf inf, DistZero zero, DijkstraVisitor vis) { dijkstra_shortest_paths(g, s_begin, s_end, predecessor, distance, weight, index_map, compare, combine, inf, zero, vis, no_named_parameters()); } // Initialize distances and call breadth first search template < class VertexListGraph, class DijkstraVisitor, class PredecessorMap, class DistanceMap, class WeightMap, class IndexMap, class Compare, class Combine, class DistInf, class DistZero > inline void dijkstra_shortest_paths(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, WeightMap weight, IndexMap index_map, Compare compare, Combine combine, DistInf inf, DistZero zero, DijkstraVisitor vis) { dijkstra_shortest_paths(g, &s, &s + 1, predecessor, distance, weight, index_map, compare, combine, inf, zero, vis); } namespace detail { // Handle defaults for PredecessorMap and // Distance Compare, Combine, Inf and Zero template < class VertexListGraph, class DistanceMap, class WeightMap, class IndexMap, class Params > inline void dijkstra_dispatch2(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, DistanceMap distance, WeightMap weight, IndexMap index_map, const Params& params) { // Default for predecessor map dummy_property_map p_map; typedef typename property_traits< DistanceMap >::value_type D; D inf = choose_param(get_param(params, distance_inf_t()), (std::numeric_limits< D >::max)()); dijkstra_shortest_paths(g, s, choose_param(get_param(params, vertex_predecessor), p_map), distance, weight, index_map, choose_param( get_param(params, distance_compare_t()), std::less< D >()), choose_param( get_param(params, distance_combine_t()), std::plus< D >()), inf, choose_param(get_param(params, distance_zero_t()), D()), choose_param(get_param(params, graph_visitor), make_dijkstra_visitor(null_visitor())), params); } template < class VertexListGraph, class DistanceMap, class WeightMap, class IndexMap, class Params > inline void dijkstra_dispatch1(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, DistanceMap distance, WeightMap weight, IndexMap index_map, const Params& params) { // Default for distance map typedef typename property_traits< WeightMap >::value_type D; typename std::vector< D >::size_type n = is_default_param(distance) ? num_vertices(g) : 1; std::vector< D > distance_map(n); detail::dijkstra_dispatch2(g, s, choose_param(distance, make_iterator_property_map( distance_map.begin(), index_map, distance_map[0])), weight, index_map, params); } } // namespace detail // Named Parameter Variant template < class VertexListGraph, class Param, class Tag, class Rest > inline void dijkstra_shortest_paths(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, const bgl_named_params< Param, Tag, Rest >& params) { // Default for edge weight and vertex index map is to ask for them // from the graph. Default for the visitor is null_visitor. detail::dijkstra_dispatch1(g, s, get_param(params, vertex_distance), choose_const_pmap(get_param(params, edge_weight), g, edge_weight), choose_const_pmap(get_param(params, vertex_index), g, vertex_index), params); } } // namespace boost #include BOOST_GRAPH_MPI_INCLUDE(< boost / graph / distributed / dijkstra_shortest_paths.hpp >) #endif // BOOST_GRAPH_DIJKSTRA_HPP find_flow_cost.hpp 0000644 00000003503 15125521275 0010262 0 ustar 00 //======================================================================= // Copyright 2013 University of Warsaw. // Authors: Piotr Wygocki // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_FIND_FLOW_COST_HPP #define BOOST_GRAPH_FIND_FLOW_COST_HPP #include <boost/graph/iteration_macros.hpp> namespace boost { template < class Graph, class Capacity, class ResidualCapacity, class Weight > typename property_traits< Weight >::value_type find_flow_cost(const Graph& g, Capacity capacity, ResidualCapacity residual_capacity, Weight weight) { typedef typename property_traits< Weight >::value_type Cost; Cost cost = 0; BGL_FORALL_EDGES_T(e, g, Graph) { if (get(capacity, e) > Cost(0)) { cost += (get(capacity, e) - get(residual_capacity, e)) * get(weight, e); } } return cost; } template < class Graph, class P, class T, class R > typename detail::edge_weight_value< Graph, P, T, R >::type find_flow_cost( const Graph& g, const bgl_named_params< P, T, R >& params) { return find_flow_cost(g, choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity), choose_const_pmap(get_param(params, edge_residual_capacity), g, edge_residual_capacity), choose_const_pmap(get_param(params, edge_weight), g, edge_weight)); } template < class Graph > typename property_traits< typename property_map< Graph, edge_capacity_t >::type >::value_type find_flow_cost(const Graph& g) { bgl_named_params< int, buffer_param_t > params(0); return find_flow_cost(g, params); } } // boost #endif /* BOOST_GRAPH_FIND_FLOW_COST_HPP */ exception.hpp 0000644 00000002672 15125521275 0007267 0 ustar 00 //======================================================================= // Copyright 2002 Indiana University. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_EXCEPTION_HPP #define BOOST_GRAPH_EXCEPTION_HPP #include <stdexcept> #include <string> namespace boost { struct BOOST_SYMBOL_VISIBLE bad_graph : public std::invalid_argument { bad_graph(const std::string& what_arg) : std::invalid_argument(what_arg) {} }; struct BOOST_SYMBOL_VISIBLE not_a_dag : public bad_graph { not_a_dag() : bad_graph("The graph must be a DAG.") {} }; struct BOOST_SYMBOL_VISIBLE negative_edge : public bad_graph { negative_edge() : bad_graph("The graph may not contain an edge with negative weight.") { } }; struct BOOST_SYMBOL_VISIBLE negative_cycle : public bad_graph { negative_cycle() : bad_graph("The graph may not contain negative cycles.") { } }; struct BOOST_SYMBOL_VISIBLE not_connected : public bad_graph { not_connected() : bad_graph("The graph must be connected.") {} }; struct BOOST_SYMBOL_VISIBLE not_complete : public bad_graph { not_complete() : bad_graph("The graph must be complete.") {} }; } // namespace boost #endif // BOOST_GRAPH_EXCEPTION_HPP graph_utility.hpp 0000644 00000037466 15125521275 0010166 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_UTILITY_HPP #define BOOST_GRAPH_UTILITY_HPP #include <stdlib.h> #include <iostream> #include <algorithm> #include <assert.h> #include <boost/config.hpp> #include <boost/tuple/tuple.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/pending/container_traits.hpp> #include <boost/graph/depth_first_search.hpp> // iota moved to detail/algorithm.hpp #include <boost/detail/algorithm.hpp> namespace boost { // Provide an undirected graph interface alternative to the // the source() and target() edge functions. template < class UndirectedGraph > inline std::pair< typename graph_traits< UndirectedGraph >::vertex_descriptor, typename graph_traits< UndirectedGraph >::vertex_descriptor > incident(typename graph_traits< UndirectedGraph >::edge_descriptor e, UndirectedGraph& g) { return std::make_pair(source(e, g), target(e, g)); } // Provide an undirected graph interface alternative // to the out_edges() function. template < class Graph > inline std::pair< typename graph_traits< Graph >::out_edge_iterator, typename graph_traits< Graph >::out_edge_iterator > incident_edges(typename graph_traits< Graph >::vertex_descriptor u, Graph& g) { return out_edges(u, g); } template < class Graph > inline typename graph_traits< Graph >::vertex_descriptor opposite( typename graph_traits< Graph >::edge_descriptor e, typename graph_traits< Graph >::vertex_descriptor v, const Graph& g) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; if (v == source(e, g)) return target(e, g); else if (v == target(e, g)) return source(e, g); else return vertex_descriptor(); } //=========================================================================== // Some handy predicates template < typename Vertex, typename Graph > struct incident_from_predicate { incident_from_predicate(Vertex u, const Graph& g) : m_u(u), m_g(g) {} template < class Edge > bool operator()(const Edge& e) const { return source(e, m_g) == m_u; } Vertex m_u; const Graph& m_g; }; template < typename Vertex, typename Graph > inline incident_from_predicate< Vertex, Graph > incident_from( Vertex u, const Graph& g) { return incident_from_predicate< Vertex, Graph >(u, g); } template < typename Vertex, typename Graph > struct incident_to_predicate { incident_to_predicate(Vertex u, const Graph& g) : m_u(u), m_g(g) {} template < class Edge > bool operator()(const Edge& e) const { return target(e, m_g) == m_u; } Vertex m_u; const Graph& m_g; }; template < typename Vertex, typename Graph > inline incident_to_predicate< Vertex, Graph > incident_to( Vertex u, const Graph& g) { return incident_to_predicate< Vertex, Graph >(u, g); } template < typename Vertex, typename Graph > struct incident_on_predicate { incident_on_predicate(Vertex u, const Graph& g) : m_u(u), m_g(g) {} template < class Edge > bool operator()(const Edge& e) const { return source(e, m_g) == m_u || target(e, m_g) == m_u; } Vertex m_u; const Graph& m_g; }; template < typename Vertex, typename Graph > inline incident_on_predicate< Vertex, Graph > incident_on( Vertex u, const Graph& g) { return incident_on_predicate< Vertex, Graph >(u, g); } template < typename Vertex, typename Graph > struct connects_predicate { connects_predicate(Vertex u, Vertex v, const Graph& g) : m_u(u), m_v(v), m_g(g) { } template < class Edge > bool operator()(const Edge& e) const { if (is_directed(m_g)) return source(e, m_g) == m_u && target(e, m_g) == m_v; else return (source(e, m_g) == m_u && target(e, m_g) == m_v) || (source(e, m_g) == m_v && target(e, m_g) == m_u); } Vertex m_u, m_v; const Graph& m_g; }; template < typename Vertex, typename Graph > inline connects_predicate< Vertex, Graph > connects( Vertex u, Vertex v, const Graph& g) { return connects_predicate< Vertex, Graph >(u, v, g); } // Need to convert all of these printing functions to take an ostream object // -JGS template < class IncidenceGraph, class Name > void print_in_edges( const IncidenceGraph& G, Name name, std::ostream& os = std::cout) { typename graph_traits< IncidenceGraph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(G); ui != ui_end; ++ui) { os << get(name, *ui) << " <-- "; typename graph_traits< IncidenceGraph >::in_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = in_edges(*ui, G); ei != ei_end; ++ei) os << get(name, source(*ei, G)) << " "; os << '\n'; } } template < class IncidenceGraph, class Name > void print_graph_dispatch(const IncidenceGraph& G, Name name, directed_tag, std::ostream& os = std::cout) { typename graph_traits< IncidenceGraph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(G); ui != ui_end; ++ui) { os << get(name, *ui) << " --> "; typename graph_traits< IncidenceGraph >::out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(*ui, G); ei != ei_end; ++ei) os << get(name, target(*ei, G)) << " "; os << '\n'; } } template < class IncidenceGraph, class Name > void print_graph_dispatch(const IncidenceGraph& G, Name name, undirected_tag, std::ostream& os = std::cout) { typename graph_traits< IncidenceGraph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(G); ui != ui_end; ++ui) { os << get(name, *ui) << " <--> "; typename graph_traits< IncidenceGraph >::out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(*ui, G); ei != ei_end; ++ei) os << get(name, target(*ei, G)) << " "; os << '\n'; } } template < class IncidenceGraph, class Name > void print_graph( const IncidenceGraph& G, Name name, std::ostream& os = std::cout) { typedef typename graph_traits< IncidenceGraph >::directed_category Cat; print_graph_dispatch(G, name, Cat(), os); } template < class IncidenceGraph > void print_graph(const IncidenceGraph& G, std::ostream& os = std::cout) { print_graph(G, get(vertex_index, G), os); } template < class EdgeListGraph, class Name > void print_edges( const EdgeListGraph& G, Name name, std::ostream& os = std::cout) { typename graph_traits< EdgeListGraph >::edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = edges(G); ei != ei_end; ++ei) os << "(" << get(name, source(*ei, G)) << "," << get(name, target(*ei, G)) << ") "; os << '\n'; } template < class EdgeListGraph, class VertexName, class EdgeName > void print_edges2(const EdgeListGraph& G, VertexName vname, EdgeName ename, std::ostream& os = std::cout) { typename graph_traits< EdgeListGraph >::edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = edges(G); ei != ei_end; ++ei) os << get(ename, *ei) << "(" << get(vname, source(*ei, G)) << "," << get(vname, target(*ei, G)) << ") "; os << '\n'; } template < class VertexListGraph, class Name > void print_vertices( const VertexListGraph& G, Name name, std::ostream& os = std::cout) { typename graph_traits< VertexListGraph >::vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(G); vi != vi_end; ++vi) os << get(name, *vi) << " "; os << '\n'; } template < class Graph, class Vertex > bool is_adj_dispatch(Graph& g, Vertex a, Vertex b, bidirectional_tag) { typename graph_traits< Graph >::adjacency_iterator vi, viend, adj_found; boost::tie(vi, viend) = adjacent_vertices(a, g); adj_found = std::find(vi, viend, b); if (adj_found == viend) return false; typename graph_traits< Graph >::out_edge_iterator oi, oiend, out_found; boost::tie(oi, oiend) = out_edges(a, g); out_found = std::find_if(oi, oiend, incident_to(b, g)); if (out_found == oiend) return false; typename graph_traits< Graph >::in_edge_iterator ii, iiend, in_found; boost::tie(ii, iiend) = in_edges(b, g); in_found = std::find_if(ii, iiend, incident_from(a, g)); if (in_found == iiend) return false; return true; } template < class Graph, class Vertex > bool is_adj_dispatch(Graph& g, Vertex a, Vertex b, directed_tag) { typename graph_traits< Graph >::adjacency_iterator vi, viend, found; boost::tie(vi, viend) = adjacent_vertices(a, g); found = std::find(vi, viend, b); if (found == viend) return false; typename graph_traits< Graph >::out_edge_iterator oi, oiend, out_found; boost::tie(oi, oiend) = out_edges(a, g); out_found = std::find_if(oi, oiend, incident_to(b, g)); if (out_found == oiend) return false; return true; } template < class Graph, class Vertex > bool is_adj_dispatch(Graph& g, Vertex a, Vertex b, undirected_tag) { return is_adj_dispatch(g, a, b, directed_tag()); } template < class Graph, class Vertex > bool is_adjacent(Graph& g, Vertex a, Vertex b) { typedef typename graph_traits< Graph >::directed_category Cat; return is_adj_dispatch(g, a, b, Cat()); } template < class Graph, class Edge > bool in_edge_set(Graph& g, Edge e) { typename Graph::edge_iterator ei, ei_end, found; boost::tie(ei, ei_end) = edges(g); found = std::find(ei, ei_end, e); return found != ei_end; } template < class Graph, class Vertex > bool in_vertex_set(Graph& g, Vertex v) { typename Graph::vertex_iterator vi, vi_end, found; boost::tie(vi, vi_end) = vertices(g); found = std::find(vi, vi_end, v); return found != vi_end; } template < class Graph, class Vertex > bool in_edge_set(Graph& g, Vertex u, Vertex v) { typename Graph::edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) if (source(*ei, g) == u && target(*ei, g) == v) return true; return false; } // is x a descendant of y? template < typename ParentMap > inline bool is_descendant(typename property_traits< ParentMap >::value_type x, typename property_traits< ParentMap >::value_type y, ParentMap parent) { if (get(parent, x) == x) // x is the root of the tree return false; else if (get(parent, x) == y) return true; else return is_descendant(get(parent, x), y, parent); } // is y reachable from x? template < typename IncidenceGraph, typename VertexColorMap > inline bool is_reachable( typename graph_traits< IncidenceGraph >::vertex_descriptor x, typename graph_traits< IncidenceGraph >::vertex_descriptor y, const IncidenceGraph& g, VertexColorMap color) // should start out white for every vertex { typedef typename property_traits< VertexColorMap >::value_type ColorValue; dfs_visitor<> vis; depth_first_visit(g, x, vis, color); return get(color, y) != color_traits< ColorValue >::white(); } // Is the undirected graph connected? // Is the directed graph strongly connected? template < typename VertexListGraph, typename VertexColorMap > inline bool is_connected(const VertexListGraph& g, VertexColorMap color) { typedef typename property_traits< VertexColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; typename graph_traits< VertexListGraph >::vertex_iterator ui, ui_end, vi, vi_end, ci, ci_end; for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) if (*ui != *vi) { for (boost::tie(ci, ci_end) = vertices(g); ci != ci_end; ++ci) put(color, *ci, Color::white()); if (!is_reachable(*ui, *vi, g, color)) return false; } return true; } template < typename Graph > bool is_self_loop( typename graph_traits< Graph >::edge_descriptor e, const Graph& g) { return source(e, g) == target(e, g); } template < class T1, class T2 > std::pair< T1, T2 > make_list(const T1& t1, const T2& t2) { return std::make_pair(t1, t2); } template < class T1, class T2, class T3 > std::pair< T1, std::pair< T2, T3 > > make_list( const T1& t1, const T2& t2, const T3& t3) { return std::make_pair(t1, std::make_pair(t2, t3)); } template < class T1, class T2, class T3, class T4 > std::pair< T1, std::pair< T2, std::pair< T3, T4 > > > make_list( const T1& t1, const T2& t2, const T3& t3, const T4& t4) { return std::make_pair(t1, std::make_pair(t2, std::make_pair(t3, t4))); } template < class T1, class T2, class T3, class T4, class T5 > std::pair< T1, std::pair< T2, std::pair< T3, std::pair< T4, T5 > > > > make_list(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) { return std::make_pair( t1, std::make_pair(t2, std::make_pair(t3, std::make_pair(t4, t5)))); } namespace graph { // Functor for remove_parallel_edges: edge property of the removed edge is // added to the remaining template < typename EdgeProperty > struct add_removed_edge_property { add_removed_edge_property(EdgeProperty ep) : ep(ep) {} template < typename Edge > void operator()(Edge stay, Edge away) { put(ep, stay, get(ep, stay) + get(ep, away)); } EdgeProperty ep; }; // Same as above: edge property is capacity here template < typename Graph > struct add_removed_edge_capacity : add_removed_edge_property< typename property_map< Graph, edge_capacity_t >::type > { typedef add_removed_edge_property< typename property_map< Graph, edge_capacity_t >::type > base; add_removed_edge_capacity(Graph& g) : base(get(edge_capacity, g)) {} }; template < typename Graph > bool has_no_vertices(const Graph& g) { typedef typename boost::graph_traits< Graph >::vertex_iterator vi; std::pair< vi, vi > p = vertices(g); return (p.first == p.second); } template < typename Graph > bool has_no_edges(const Graph& g) { typedef typename boost::graph_traits< Graph >::edge_iterator ei; std::pair< ei, ei > p = edges(g); return (p.first == p.second); } template < typename Graph > bool has_no_out_edges( const typename boost::graph_traits< Graph >::vertex_descriptor& v, const Graph& g) { typedef typename boost::graph_traits< Graph >::out_edge_iterator ei; std::pair< ei, ei > p = out_edges(v, g); return (p.first == p.second); } } // namespace graph #include <boost/graph/iteration_macros.hpp> template < class PropertyIn, class PropertyOut, class Graph > void copy_vertex_property(PropertyIn p_in, PropertyOut p_out, Graph& g) { BGL_FORALL_VERTICES_T(u, g, Graph) put(p_out, u, get(p_in, g)); } template < class PropertyIn, class PropertyOut, class Graph > void copy_edge_property(PropertyIn p_in, PropertyOut p_out, Graph& g) { BGL_FORALL_EDGES_T(e, g, Graph) put(p_out, e, get(p_in, g)); } // Return true if property_map1 and property_map2 differ // for any of the vertices in graph. template < typename PropertyMapFirst, typename PropertyMapSecond, typename Graph > bool are_property_maps_different(const PropertyMapFirst property_map1, const PropertyMapSecond property_map2, const Graph& graph) { BGL_FORALL_VERTICES_T(vertex, graph, Graph) { if (get(property_map1, vertex) != get(property_map2, vertex)) { return (true); } } return (false); } } /* namespace boost */ #endif /* BOOST_GRAPH_UTILITY_HPP*/ property_maps/constant_property_map.hpp 0000644 00000004635 15125521275 0014630 0 ustar 00 // (C) Copyright 2007-2009 Andrew Sutton // // 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_CONSTANT_PROPERTY_HPP #define BOOST_GRAPH_CONSTANT_PROPERTY_HPP #include <boost/property_map/property_map.hpp> // TODO: This should really be part of the property maps library rather than // the Boost.Graph library. namespace boost { /** * A constant property is one, that regardless of the edge or vertex given, * will always return a constant value. */ template < typename Key, typename Value > struct constant_property_map : public boost::put_get_helper< const Value&, constant_property_map< Key, Value > > { typedef Key key_type; typedef Value value_type; typedef const Value& reference; typedef boost::readable_property_map_tag category; constant_property_map() : m_value() {} constant_property_map(const value_type& value) : m_value(value) {} constant_property_map(const constant_property_map& copy) : m_value(copy.m_value) { } inline reference operator[](const key_type&) const { return m_value; } value_type m_value; }; template < typename Key, typename Value > inline constant_property_map< Key, Value > make_constant_property( const Value& value) { return constant_property_map< Key, Value >(value); } /** * Same as above, but pretends to be writable as well. */ template < typename Key, typename Value > struct constant_writable_property_map { typedef Key key_type; typedef Value value_type; typedef Value& reference; typedef boost::read_write_property_map_tag category; constant_writable_property_map() : m_value() {} constant_writable_property_map(const value_type& value) : m_value(value) {} constant_writable_property_map(const constant_writable_property_map& copy) : m_value(copy.m_value) { } friend Value get(const constant_writable_property_map& me, Key) { return me.m_value; } friend void put(const constant_writable_property_map&, Key, Value) {} value_type m_value; }; template < typename Key, typename Value > inline constant_writable_property_map< Key, Value > make_constant_writable_property(const Value& value) { return constant_writable_property_map< Key, Value >(value); } } /* namespace boost */ #endif property_maps/container_property_map.hpp 0000644 00000005175 15125521275 0014761 0 ustar 00 // (C) Copyright 2007-2009 Andrew Sutton // // 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_CONTAINER_PROPERTY_MAP_HPP #define BOOST_GRAPH_CONTAINER_PROPERTY_MAP_HPP #include <boost/graph/detail/index.hpp> #include <boost/property_map/property_map.hpp> namespace boost { // This is an adapter built over the iterator property map with // more useful uniform construction semantics. Specifically, this // requires the container rather than the iterator and the graph // rather than the optional index map. template < typename Graph, typename Key, typename Container > struct container_property_map : public boost::put_get_helper< typename iterator_property_map< typename Container::iterator, typename property_map< Graph, typename detail::choose_indexer< Graph, Key >::index_type >::type >::reference, container_property_map< Graph, Key, Container > > { typedef typename detail::choose_indexer< Graph, Key >::indexer_type indexer_type; typedef typename indexer_type::index_type index_type; typedef iterator_property_map< typename Container::iterator, typename property_map< Graph, index_type >::type > map_type; typedef typename map_type::key_type key_type; typedef typename map_type::value_type value_type; typedef typename map_type::reference reference; typedef typename map_type::category category; // The default constructor will *probably* crash if its actually // used for referencing vertices since the underlying iterator // map points past the end of an unknown container. inline container_property_map() : m_map() {} // This is the preferred constructor. It is invoked over the container // and the graph explicitly. This requires that the underlying iterator // map use the indices of the vertices in g rather than the default // identity map. // // Note the const-cast this ensures the reference type of the // vertex index map is non-const, which happens to be an // artifact of passing const graph references. inline container_property_map(Container& c, const Graph& g) : m_map(c.begin(), indexer_type::index_map(const_cast< Graph& >(g))) { } // Typical copy constructor. inline container_property_map(const container_property_map& x) : m_map(x.m_map) { } // The [] operator delegates to the underlying map/ inline reference operator[](const key_type& k) const { return m_map[k]; } map_type m_map; }; } #endif property_maps/matrix_property_map.hpp 0000644 00000004417 15125521275 0014301 0 ustar 00 // (C) Copyright 2007-2009 Andrew Sutton // // 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_MATRIX_PROPERTY_MAP_HPP #define BOOST_GRAPH_MATRIX_PROPERTY_MAP_HPP #include <boost/graph/property_maps/container_property_map.hpp> namespace boost { // This property map is built specifically for property maps over // matrices. Like the basic property map over a container, this builds // the property abstraction over a matrix (usually a vector of vectors) // and returns property maps over the nested containers. template < typename Graph, typename Key, typename Matrix > struct matrix_property_map : boost::put_get_helper< container_property_map< Graph, Key, typename Matrix::value_type >, matrix_property_map< Graph, Key, Matrix > > { // abstract the indexing keys typedef typename detail::choose_indexer< Graph, Key >::indexer_type indexer_type; // aliases for the nested container and its corresponding map typedef typename Matrix::value_type container_type; typedef container_property_map< Graph, Key, container_type > map_type; typedef Key key_type; // This property map doesn't really provide access to nested containers, // but returns property maps over them. Since property maps are all // copy-constructible (or should be anyways), we never return references. // As such, this property is only readable, but not writable. Curiously, // the inner property map is actually an lvalue pmap. typedef map_type value_type; typedef map_type reference; typedef readable_property_map_tag category; matrix_property_map() : m_matrix(0), m_graph(0) {} matrix_property_map(Matrix& m, const Graph& g) : m_matrix(&m), m_graph(const_cast< Graph* >(&g)) { } matrix_property_map(const matrix_property_map& x) : m_matrix(x.m_matrix), m_graph(x.m_graph) { } inline reference operator[](key_type k) const { typedef typename indexer_type::value_type Index; Index x = indexer_type::index(k, *m_graph); return map_type((*m_matrix)[x], *m_graph); } private: mutable Matrix* m_matrix; mutable Graph* m_graph; }; } #endif property_maps/null_property_map.hpp 0000644 00000002360 15125521275 0013742 0 ustar 00 // (C) Copyright Andrew Sutton 2007 // // 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_NULL_PROPERTY_HPP #define BOOST_GRAPH_NULL_PROPERTY_HPP #include <boost/property_map/property_map.hpp> // TODO: This should really be part of the property maps library rather than // the Boost.Graph library. namespace boost { // A null property is somewhat like the inverse of the constant // property map except that instead of returning a single value, // this eats any writes and cannot be read from. template < typename Key, typename Value > struct null_property_map { typedef Key key_type; typedef Value value_type; typedef void reference; typedef boost::writable_property_map_tag category; }; // The null_property_map<K,V> only has a put() function. template < typename K, typename V > void put( null_property_map< K, V >& /*pm*/, const K& /*key*/, const V& /*value*/) { } // A helper function for intantiating null property maps. template < typename Key, typename Value > inline null_property_map< Key, Value > make_null_property() { return null_property_map< Key, Value >(); } } #endif adjacency_matrix.hpp 0000644 00000131257 15125521275 0010600 0 ustar 00 //======================================================================= // Copyright 2001 University of Notre Dame. // Copyright 2006 Trustees of Indiana University // Authors: Jeremy G. Siek and Douglas Gregor <dgregor@cs.indiana.edu> // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_ADJACENCY_MATRIX_HPP #define BOOST_ADJACENCY_MATRIX_HPP #include <boost/config.hpp> #include <vector> #include <memory> #include <iterator> #include <boost/assert.hpp> #include <boost/limits.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_mutability_traits.hpp> #include <boost/graph/graph_selectors.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/bool.hpp> #include <boost/graph/adjacency_iterator.hpp> #include <boost/graph/detail/edge.hpp> #include <boost/iterator/iterator_adaptor.hpp> #include <boost/iterator/filter_iterator.hpp> #include <boost/range/irange.hpp> #include <boost/graph/properties.hpp> #include <boost/tuple/tuple.hpp> #include <boost/static_assert.hpp> #include <boost/type_traits.hpp> #include <boost/property_map/property_map.hpp> #include <boost/property_map/transform_value_property_map.hpp> #include <boost/property_map/function_property_map.hpp> namespace boost { namespace detail { template < class Directed, class Vertex > class matrix_edge_desc_impl : public edge_desc_impl< Directed, Vertex > { typedef edge_desc_impl< Directed, Vertex > Base; public: matrix_edge_desc_impl() {} matrix_edge_desc_impl( bool exists, Vertex s, Vertex d, const void* ep = 0) : Base(s, d, ep), m_exists(exists) { } bool exists() const { return m_exists; } private: bool m_exists; }; struct does_edge_exist { template < class Edge > bool operator()(const Edge& e) const { return e.exists(); } }; // Note to self... The int for get_edge_exists and set_edge exist helps // make these calls unambiguous. template < typename EdgeProperty > bool get_edge_exists( const std::pair< bool, EdgeProperty >& stored_edge, int) { return stored_edge.first; } template < typename EdgeProperty > void set_edge_exists( std::pair< bool, EdgeProperty >& stored_edge, bool flag, int) { stored_edge.first = flag; } template < typename EdgeProxy > bool get_edge_exists(const EdgeProxy& edge_proxy, ...) { return edge_proxy; } template < typename EdgeProxy > EdgeProxy& set_edge_exists(EdgeProxy& edge_proxy, bool flag, ...) { edge_proxy = flag; return edge_proxy; // just to avoid never used warning } // NOTE: These functions collide with the get_property function for // accessing bundled graph properties. Be excplicit when using them. template < typename EdgeProperty > const EdgeProperty& get_edge_property( const std::pair< bool, EdgeProperty >& stored_edge) { return stored_edge.second; } template < typename EdgeProperty > EdgeProperty& get_edge_property( std::pair< bool, EdgeProperty >& stored_edge) { return stored_edge.second; } template < typename StoredEdgeProperty, typename EdgeProperty > inline void set_edge_property( std::pair< bool, StoredEdgeProperty >& stored_edge, const EdgeProperty& ep, int) { stored_edge.second = ep; } inline const no_property& get_edge_property(const char&) { static no_property s_prop; return s_prop; } inline no_property& get_edge_property(char&) { static no_property s_prop; return s_prop; } template < typename EdgeProxy, typename EdgeProperty > inline void set_edge_property(EdgeProxy, const EdgeProperty&, ...) { } //======================================================================= // Directed Out Edge Iterator template < typename VertexDescriptor, typename MatrixIter, typename VerticesSizeType, typename EdgeDescriptor > struct dir_adj_matrix_out_edge_iter : iterator_adaptor< dir_adj_matrix_out_edge_iter< VertexDescriptor, MatrixIter, VerticesSizeType, EdgeDescriptor >, MatrixIter, EdgeDescriptor, use_default, EdgeDescriptor, std::ptrdiff_t > { typedef iterator_adaptor< dir_adj_matrix_out_edge_iter< VertexDescriptor, MatrixIter, VerticesSizeType, EdgeDescriptor >, MatrixIter, EdgeDescriptor, use_default, EdgeDescriptor, std::ptrdiff_t > super_t; dir_adj_matrix_out_edge_iter() {} dir_adj_matrix_out_edge_iter(const MatrixIter& i, const VertexDescriptor& src, const VerticesSizeType& n) : super_t(i), m_src(src), m_targ(0), m_n(n) { } void increment() { ++this->base_reference(); ++m_targ; } inline EdgeDescriptor dereference() const { return EdgeDescriptor(get_edge_exists(*this->base(), 0), m_src, m_targ, &get_edge_property(*this->base())); } VertexDescriptor m_src, m_targ; VerticesSizeType m_n; }; //======================================================================= // Directed In Edge Iterator template < typename VertexDescriptor, typename MatrixIter, typename VerticesSizeType, typename EdgeDescriptor > struct dir_adj_matrix_in_edge_iter : iterator_adaptor< dir_adj_matrix_in_edge_iter< VertexDescriptor, MatrixIter, VerticesSizeType, EdgeDescriptor >, MatrixIter, EdgeDescriptor, use_default, EdgeDescriptor, std::ptrdiff_t > { typedef iterator_adaptor< dir_adj_matrix_in_edge_iter< VertexDescriptor, MatrixIter, VerticesSizeType, EdgeDescriptor >, MatrixIter, EdgeDescriptor, use_default, EdgeDescriptor, std::ptrdiff_t > super_t; dir_adj_matrix_in_edge_iter() {} dir_adj_matrix_in_edge_iter(const MatrixIter& i, const MatrixIter& last, const VertexDescriptor& tgt, const VerticesSizeType& n) : super_t(i), m_last(last), m_src(0), m_targ(tgt), m_n(n) { } void increment() { if (VerticesSizeType(m_last - this->base_reference()) >= m_n) { this->base_reference() += m_n; ++m_src; } else { this->base_reference() = m_last; } } inline EdgeDescriptor dereference() const { return EdgeDescriptor(get_edge_exists(*this->base(), 0), m_src, m_targ, &get_edge_property(*this->base())); } MatrixIter m_last; VertexDescriptor m_src, m_targ; VerticesSizeType m_n; }; //======================================================================= // Undirected Out Edge Iterator template < typename VertexDescriptor, typename MatrixIter, typename VerticesSizeType, typename EdgeDescriptor > struct undir_adj_matrix_out_edge_iter : iterator_adaptor< undir_adj_matrix_out_edge_iter< VertexDescriptor, MatrixIter, VerticesSizeType, EdgeDescriptor >, MatrixIter, EdgeDescriptor, use_default, EdgeDescriptor, std::ptrdiff_t > { typedef iterator_adaptor< undir_adj_matrix_out_edge_iter< VertexDescriptor, MatrixIter, VerticesSizeType, EdgeDescriptor >, MatrixIter, EdgeDescriptor, use_default, EdgeDescriptor, std::ptrdiff_t > super_t; undir_adj_matrix_out_edge_iter() {} undir_adj_matrix_out_edge_iter(const MatrixIter& i, const VertexDescriptor& src, const VerticesSizeType& n) : super_t(i), m_src(src), m_inc(src), m_targ(0), m_n(n) { } void increment() { if (m_targ < m_src) // first half { ++this->base_reference(); } else if (m_targ < m_n - 1) { // second half ++m_inc; this->base_reference() += m_inc; } else { // past-the-end this->base_reference() += m_n - m_src; } ++m_targ; } inline EdgeDescriptor dereference() const { return EdgeDescriptor(get_edge_exists(*this->base(), 0), m_src, m_targ, &get_edge_property(*this->base())); } VertexDescriptor m_src, m_inc, m_targ; VerticesSizeType m_n; }; //======================================================================= // Undirected In Edge Iterator template < typename VertexDescriptor, typename MatrixIter, typename VerticesSizeType, typename EdgeDescriptor > struct undir_adj_matrix_in_edge_iter : iterator_adaptor< undir_adj_matrix_in_edge_iter< VertexDescriptor, MatrixIter, VerticesSizeType, EdgeDescriptor >, MatrixIter, EdgeDescriptor, use_default, EdgeDescriptor, std::ptrdiff_t > { typedef iterator_adaptor< undir_adj_matrix_in_edge_iter< VertexDescriptor, MatrixIter, VerticesSizeType, EdgeDescriptor >, MatrixIter, EdgeDescriptor, use_default, EdgeDescriptor, std::ptrdiff_t > super_t; undir_adj_matrix_in_edge_iter() {} undir_adj_matrix_in_edge_iter(const MatrixIter& i, const VertexDescriptor& src, const VerticesSizeType& n) : super_t(i), m_src(src), m_inc(src), m_targ(0), m_n(n) { } void increment() { if (m_targ < m_src) // first half { ++this->base_reference(); } else if (m_targ < m_n - 1) { // second half ++m_inc; this->base_reference() += m_inc; } else { // past-the-end this->base_reference() += m_n - m_src; } ++m_targ; } inline EdgeDescriptor dereference() const { return EdgeDescriptor(get_edge_exists(*this->base(), 0), m_targ, m_src, &get_edge_property(*this->base())); } VertexDescriptor m_src, m_inc, m_targ; VerticesSizeType m_n; }; //======================================================================= // Edge Iterator template < typename Directed, typename MatrixIter, typename VerticesSizeType, typename EdgeDescriptor > struct adj_matrix_edge_iter : iterator_adaptor< adj_matrix_edge_iter< Directed, MatrixIter, VerticesSizeType, EdgeDescriptor >, MatrixIter, EdgeDescriptor, use_default, EdgeDescriptor, std::ptrdiff_t > { typedef iterator_adaptor< adj_matrix_edge_iter< Directed, MatrixIter, VerticesSizeType, EdgeDescriptor >, MatrixIter, EdgeDescriptor, use_default, EdgeDescriptor, std::ptrdiff_t > super_t; adj_matrix_edge_iter() {} adj_matrix_edge_iter(const MatrixIter& i, const MatrixIter& start, const VerticesSizeType& n) : super_t(i), m_start(start), m_src(0), m_targ(0), m_n(n) { } void increment() { increment_dispatch(this->base_reference(), Directed()); } void increment_dispatch(MatrixIter& i, directedS) { ++i; if (m_targ == m_n - 1) { m_targ = 0; ++m_src; } else { ++m_targ; } } void increment_dispatch(MatrixIter& i, undirectedS) { ++i; if (m_targ == m_src) { m_targ = 0; ++m_src; } else { ++m_targ; } } inline EdgeDescriptor dereference() const { return EdgeDescriptor(get_edge_exists(*this->base(), 0), m_src, m_targ, &get_edge_property(*this->base())); } MatrixIter m_start; VerticesSizeType m_src, m_targ, m_n; }; } // namespace detail //========================================================================= // Adjacency Matrix Traits template < typename Directed = directedS > class adjacency_matrix_traits { typedef typename Directed::is_directed_t is_directed; public: // The bidirectionalS tag is not allowed with the adjacency_matrix // graph type. Instead, use directedS, which also provides the // functionality required for a Bidirectional Graph (in_edges, // in_degree, etc.). BOOST_STATIC_ASSERT(!(is_same< Directed, bidirectionalS >::value)); typedef typename mpl::if_< is_directed, bidirectional_tag, undirected_tag >::type directed_category; typedef disallow_parallel_edge_tag edge_parallel_category; typedef std::size_t vertex_descriptor; typedef detail::matrix_edge_desc_impl< directed_category, vertex_descriptor > edge_descriptor; }; struct adjacency_matrix_class_tag { }; struct adj_matrix_traversal_tag : public virtual adjacency_matrix_tag, public virtual vertex_list_graph_tag, public virtual incidence_graph_tag, public virtual adjacency_graph_tag, public virtual edge_list_graph_tag { }; //========================================================================= // Adjacency Matrix Class template < typename Directed = directedS, typename VertexProperty = no_property, typename EdgeProperty = no_property, typename GraphProperty = no_property, typename Allocator = std::allocator< bool > > class adjacency_matrix { typedef adjacency_matrix self; typedef adjacency_matrix_traits< Directed > Traits; public: // The bidirectionalS tag is not allowed with the adjacency_matrix // graph type. Instead, use directedS, which also provides the // functionality required for a Bidirectional Graph (in_edges, // in_degree, etc.). BOOST_STATIC_ASSERT(!(is_same< Directed, bidirectionalS >::value)); typedef GraphProperty graph_property_type; typedef typename lookup_one_property< GraphProperty, graph_bundle_t >::type graph_bundled; typedef VertexProperty vertex_property_type; typedef typename lookup_one_property< VertexProperty, vertex_bundle_t >::type vertex_bundled; typedef EdgeProperty edge_property_type; typedef typename lookup_one_property< EdgeProperty, edge_bundle_t >::type edge_bundled; public: // should be private typedef typename mpl::if_< typename has_property< edge_property_type >::type, std::pair< bool, edge_property_type >, char >::type StoredEdge; #if defined(BOOST_NO_STD_ALLOCATOR) typedef std::vector< StoredEdge > Matrix; #else #if defined(BOOST_NO_CXX11_ALLOCATOR) typedef typename Allocator::template rebind< StoredEdge >::other Alloc; #else typedef typename std::allocator_traits< Allocator >::template rebind_alloc< StoredEdge > Alloc; #endif typedef std::vector< StoredEdge, Alloc > Matrix; #endif typedef typename Matrix::iterator MatrixIter; typedef typename Matrix::size_type size_type; public: // Graph concept required types typedef typename Traits::vertex_descriptor vertex_descriptor; typedef typename Traits::edge_descriptor edge_descriptor; typedef typename Traits::directed_category directed_category; typedef typename Traits::edge_parallel_category edge_parallel_category; typedef adj_matrix_traversal_tag traversal_category; static vertex_descriptor null_vertex() { return (std::numeric_limits< vertex_descriptor >::max)(); } // private: if friends worked, these would be private typedef detail::dir_adj_matrix_out_edge_iter< vertex_descriptor, MatrixIter, size_type, edge_descriptor > DirOutEdgeIter; typedef detail::undir_adj_matrix_out_edge_iter< vertex_descriptor, MatrixIter, size_type, edge_descriptor > UnDirOutEdgeIter; typedef typename mpl::if_< typename Directed::is_directed_t, DirOutEdgeIter, UnDirOutEdgeIter >::type unfiltered_out_edge_iter; typedef detail::dir_adj_matrix_in_edge_iter< vertex_descriptor, MatrixIter, size_type, edge_descriptor > DirInEdgeIter; typedef detail::undir_adj_matrix_in_edge_iter< vertex_descriptor, MatrixIter, size_type, edge_descriptor > UnDirInEdgeIter; typedef typename mpl::if_< typename Directed::is_directed_t, DirInEdgeIter, UnDirInEdgeIter >::type unfiltered_in_edge_iter; typedef detail::adj_matrix_edge_iter< Directed, MatrixIter, size_type, edge_descriptor > unfiltered_edge_iter; public: // IncidenceGraph concept required types typedef filter_iterator< detail::does_edge_exist, unfiltered_out_edge_iter > out_edge_iterator; typedef size_type degree_size_type; // BidirectionalGraph required types typedef filter_iterator< detail::does_edge_exist, unfiltered_in_edge_iter > in_edge_iterator; // AdjacencyGraph required types typedef typename adjacency_iterator_generator< self, vertex_descriptor, out_edge_iterator >::type adjacency_iterator; // VertexListGraph required types typedef size_type vertices_size_type; typedef integer_range< vertex_descriptor > VertexList; typedef typename VertexList::iterator vertex_iterator; // EdgeListGraph required types typedef size_type edges_size_type; typedef filter_iterator< detail::does_edge_exist, unfiltered_edge_iter > edge_iterator; // PropertyGraph required types typedef adjacency_matrix_class_tag graph_tag; // Constructor required by MutableGraph adjacency_matrix( vertices_size_type n_vertices, const GraphProperty& p = GraphProperty()) : m_matrix(Directed::is_directed ? (n_vertices * n_vertices) : (n_vertices * (n_vertices + 1) / 2)) , m_vertex_set(0, n_vertices) , m_vertex_properties(n_vertices) , m_num_edges(0) , m_property(p) { } template < typename EdgeIterator > adjacency_matrix(EdgeIterator first, EdgeIterator last, vertices_size_type n_vertices, const GraphProperty& p = GraphProperty()) : m_matrix(Directed::is_directed ? (n_vertices * n_vertices) : (n_vertices * (n_vertices + 1) / 2)) , m_vertex_set(0, n_vertices) , m_vertex_properties(n_vertices) , m_num_edges(0) , m_property(p) { for (; first != last; ++first) { add_edge(first->first, first->second, *this); } } template < typename EdgeIterator, typename EdgePropertyIterator > adjacency_matrix(EdgeIterator first, EdgeIterator last, EdgePropertyIterator ep_iter, vertices_size_type n_vertices, const GraphProperty& p = GraphProperty()) : m_matrix(Directed::is_directed ? (n_vertices * n_vertices) : (n_vertices * (n_vertices + 1) / 2)) , m_vertex_set(0, n_vertices) , m_vertex_properties(n_vertices) , m_num_edges(0) , m_property(p) { for (; first != last; ++first, ++ep_iter) { add_edge(first->first, first->second, *ep_iter, *this); } } #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES // Directly access a vertex or edge bundle vertex_bundled& operator[](vertex_descriptor v) { return get(vertex_bundle, *this, v); } const vertex_bundled& operator[](vertex_descriptor v) const { return get(vertex_bundle, *this, v); } edge_bundled& operator[](edge_descriptor e) { return get(edge_bundle, *this, e); } const edge_bundled& operator[](edge_descriptor e) const { return get(edge_bundle, *this, e); } graph_bundled& operator[](graph_bundle_t) { return get_property(*this); } const graph_bundled& operator[](graph_bundle_t) const { return get_property(*this); } #endif // private: if friends worked, these would be private typename Matrix::const_reference get_edge( vertex_descriptor u, vertex_descriptor v) const { if (Directed::is_directed) return m_matrix[u * m_vertex_set.size() + v]; else { if (v > u) std::swap(u, v); return m_matrix[u * (u + 1) / 2 + v]; } } typename Matrix::reference get_edge( vertex_descriptor u, vertex_descriptor v) { if (Directed::is_directed) return m_matrix[u * m_vertex_set.size() + v]; else { if (v > u) std::swap(u, v); return m_matrix[u * (u + 1) / 2 + v]; } } Matrix m_matrix; VertexList m_vertex_set; std::vector< vertex_property_type > m_vertex_properties; size_type m_num_edges; graph_property_type m_property; }; //========================================================================= // Functions required by the AdjacencyMatrix concept template < typename D, typename VP, typename EP, typename GP, typename A > std::pair< typename adjacency_matrix< D, VP, EP, GP, A >::edge_descriptor, bool > edge(typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor u, typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor v, const adjacency_matrix< D, VP, EP, GP, A >& g) { bool exists = detail::get_edge_exists(g.get_edge(u, v), 0); typename adjacency_matrix< D, VP, EP, GP, A >::edge_descriptor e( exists, u, v, &detail::get_edge_property(g.get_edge(u, v))); return std::make_pair(e, exists); } //========================================================================= // Functions required by the IncidenceGraph concept // O(1) template < typename VP, typename EP, typename GP, typename A > std::pair< typename adjacency_matrix< directedS, VP, EP, GP, A >::out_edge_iterator, typename adjacency_matrix< directedS, VP, EP, GP, A >::out_edge_iterator > out_edges( typename adjacency_matrix< directedS, VP, EP, GP, A >::vertex_descriptor u, const adjacency_matrix< directedS, VP, EP, GP, A >& g_) { typedef adjacency_matrix< directedS, VP, EP, GP, A > Graph; Graph& g = const_cast< Graph& >(g_); typename Graph::vertices_size_type offset = u * g.m_vertex_set.size(); typename Graph::MatrixIter f = g.m_matrix.begin() + offset; typename Graph::MatrixIter l = f + g.m_vertex_set.size(); typename Graph::unfiltered_out_edge_iter first(f, u, g.m_vertex_set.size()), last(l, u, g.m_vertex_set.size()); detail::does_edge_exist pred; typedef typename Graph::out_edge_iterator out_edge_iterator; return std::make_pair(out_edge_iterator(pred, first, last), out_edge_iterator(pred, last, last)); } // O(1) template < typename VP, typename EP, typename GP, typename A > std::pair< typename adjacency_matrix< undirectedS, VP, EP, GP, A >::out_edge_iterator, typename adjacency_matrix< undirectedS, VP, EP, GP, A >::out_edge_iterator > out_edges( typename adjacency_matrix< undirectedS, VP, EP, GP, A >::vertex_descriptor u, const adjacency_matrix< undirectedS, VP, EP, GP, A >& g_) { typedef adjacency_matrix< undirectedS, VP, EP, GP, A > Graph; Graph& g = const_cast< Graph& >(g_); typename Graph::vertices_size_type offset = u * (u + 1) / 2; typename Graph::MatrixIter f = g.m_matrix.begin() + offset; typename Graph::MatrixIter l = g.m_matrix.end(); typename Graph::unfiltered_out_edge_iter first(f, u, g.m_vertex_set.size()), last(l, u, g.m_vertex_set.size()); detail::does_edge_exist pred; typedef typename Graph::out_edge_iterator out_edge_iterator; return std::make_pair(out_edge_iterator(pred, first, last), out_edge_iterator(pred, last, last)); } // O(N) template < typename D, typename VP, typename EP, typename GP, typename A > typename adjacency_matrix< D, VP, EP, GP, A >::degree_size_type out_degree( typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor u, const adjacency_matrix< D, VP, EP, GP, A >& g) { typename adjacency_matrix< D, VP, EP, GP, A >::degree_size_type n = 0; typename adjacency_matrix< D, VP, EP, GP, A >::out_edge_iterator f, l; for (boost::tie(f, l) = out_edges(u, g); f != l; ++f) ++n; return n; } // O(1) template < typename D, typename VP, typename EP, typename GP, typename A, typename Dir, typename Vertex > typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor source( const detail::matrix_edge_desc_impl< Dir, Vertex >& e, const adjacency_matrix< D, VP, EP, GP, A >&) { return e.m_source; } // O(1) template < typename D, typename VP, typename EP, typename GP, typename A, typename Dir, typename Vertex > typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor target( const detail::matrix_edge_desc_impl< Dir, Vertex >& e, const adjacency_matrix< D, VP, EP, GP, A >&) { return e.m_target; } //========================================================================= // Functions required by the BidirectionalGraph concept // O(1) template < typename VP, typename EP, typename GP, typename A > std::pair< typename adjacency_matrix< directedS, VP, EP, GP, A >::in_edge_iterator, typename adjacency_matrix< directedS, VP, EP, GP, A >::in_edge_iterator > in_edges( typename adjacency_matrix< directedS, VP, EP, GP, A >::vertex_descriptor u, const adjacency_matrix< directedS, VP, EP, GP, A >& g_) { typedef adjacency_matrix< directedS, VP, EP, GP, A > Graph; Graph& g = const_cast< Graph& >(g_); typename Graph::MatrixIter f = g.m_matrix.begin() + u; typename Graph::MatrixIter l = g.m_matrix.end(); typename Graph::unfiltered_in_edge_iter first( f, l, u, g.m_vertex_set.size()), last(l, l, u, g.m_vertex_set.size()); detail::does_edge_exist pred; typedef typename Graph::in_edge_iterator in_edge_iterator; return std::make_pair(in_edge_iterator(pred, first, last), in_edge_iterator(pred, last, last)); } // O(1) template < typename VP, typename EP, typename GP, typename A > std::pair< typename adjacency_matrix< undirectedS, VP, EP, GP, A >::in_edge_iterator, typename adjacency_matrix< undirectedS, VP, EP, GP, A >::in_edge_iterator > in_edges( typename adjacency_matrix< undirectedS, VP, EP, GP, A >::vertex_descriptor u, const adjacency_matrix< undirectedS, VP, EP, GP, A >& g_) { typedef adjacency_matrix< undirectedS, VP, EP, GP, A > Graph; Graph& g = const_cast< Graph& >(g_); typename Graph::vertices_size_type offset = u * (u + 1) / 2; typename Graph::MatrixIter f = g.m_matrix.begin() + offset; typename Graph::MatrixIter l = g.m_matrix.end(); typename Graph::unfiltered_in_edge_iter first(f, u, g.m_vertex_set.size()), last(l, u, g.m_vertex_set.size()); detail::does_edge_exist pred; typedef typename Graph::in_edge_iterator in_edge_iterator; return std::make_pair(in_edge_iterator(pred, first, last), in_edge_iterator(pred, last, last)); } // O(N) template < typename D, typename VP, typename EP, typename GP, typename A > typename adjacency_matrix< D, VP, EP, GP, A >::degree_size_type in_degree( typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor u, const adjacency_matrix< D, VP, EP, GP, A >& g) { typename adjacency_matrix< D, VP, EP, GP, A >::degree_size_type n = 0; typename adjacency_matrix< D, VP, EP, GP, A >::in_edge_iterator f, l; for (boost::tie(f, l) = in_edges(u, g); f != l; ++f) ++n; return n; } //========================================================================= // Functions required by the AdjacencyGraph concept template < typename D, typename VP, typename EP, typename GP, typename A > std::pair< typename adjacency_matrix< D, VP, EP, GP, A >::adjacency_iterator, typename adjacency_matrix< D, VP, EP, GP, A >::adjacency_iterator > adjacent_vertices( typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor u, const adjacency_matrix< D, VP, EP, GP, A >& g_) { typedef adjacency_matrix< D, VP, EP, GP, A > Graph; const Graph& cg = static_cast< const Graph& >(g_); Graph& g = const_cast< Graph& >(cg); typedef typename Graph::adjacency_iterator adjacency_iterator; typename Graph::out_edge_iterator first, last; boost::tie(first, last) = out_edges(u, g); return std::make_pair( adjacency_iterator(first, &g), adjacency_iterator(last, &g)); } //========================================================================= // Functions required by the VertexListGraph concept template < typename D, typename VP, typename EP, typename GP, typename A > std::pair< typename adjacency_matrix< D, VP, EP, GP, A >::vertex_iterator, typename adjacency_matrix< D, VP, EP, GP, A >::vertex_iterator > vertices(const adjacency_matrix< D, VP, EP, GP, A >& g_) { typedef adjacency_matrix< D, VP, EP, GP, A > Graph; Graph& g = const_cast< Graph& >(g_); return std::make_pair(g.m_vertex_set.begin(), g.m_vertex_set.end()); } template < typename D, typename VP, typename EP, typename GP, typename A > typename adjacency_matrix< D, VP, EP, GP, A >::vertices_size_type num_vertices( const adjacency_matrix< D, VP, EP, GP, A >& g) { return g.m_vertex_set.size(); } //========================================================================= // Functions required by the EdgeListGraph concept template < typename D, typename VP, typename EP, typename GP, typename A > std::pair< typename adjacency_matrix< D, VP, EP, GP, A >::edge_iterator, typename adjacency_matrix< D, VP, EP, GP, A >::edge_iterator > edges(const adjacency_matrix< D, VP, EP, GP, A >& g_) { typedef adjacency_matrix< D, VP, EP, GP, A > Graph; Graph& g = const_cast< Graph& >(g_); typename Graph::unfiltered_edge_iter first( g.m_matrix.begin(), g.m_matrix.begin(), g.m_vertex_set.size()), last(g.m_matrix.end(), g.m_matrix.begin(), g.m_vertex_set.size()); detail::does_edge_exist pred; typedef typename Graph::edge_iterator edge_iterator; return std::make_pair( edge_iterator(pred, first, last), edge_iterator(pred, last, last)); } // O(1) template < typename D, typename VP, typename EP, typename GP, typename A > typename adjacency_matrix< D, VP, EP, GP, A >::edges_size_type num_edges( const adjacency_matrix< D, VP, EP, GP, A >& g) { return g.m_num_edges; } //========================================================================= // Functions required by the MutableGraph concept // O(1) template < typename D, typename VP, typename EP, typename GP, typename A, typename EP2 > std::pair< typename adjacency_matrix< D, VP, EP, GP, A >::edge_descriptor, bool > add_edge(typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor u, typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor v, const EP2& ep, adjacency_matrix< D, VP, EP, GP, A >& g) { typedef typename adjacency_matrix< D, VP, EP, GP, A >::edge_descriptor edge_descriptor; if (detail::get_edge_exists(g.get_edge(u, v), 0) == false) { ++(g.m_num_edges); detail::set_edge_property(g.get_edge(u, v), EP(ep), 0); detail::set_edge_exists(g.get_edge(u, v), true, 0); return std::make_pair(edge_descriptor(true, u, v, &detail::get_edge_property(g.get_edge(u, v))), true); } else return std::make_pair(edge_descriptor(true, u, v, &detail::get_edge_property(g.get_edge(u, v))), false); } // O(1) template < typename D, typename VP, typename EP, typename GP, typename A > std::pair< typename adjacency_matrix< D, VP, EP, GP, A >::edge_descriptor, bool > add_edge(typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor u, typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor v, adjacency_matrix< D, VP, EP, GP, A >& g) { EP ep; return add_edge(u, v, ep, g); } // O(1) template < typename D, typename VP, typename EP, typename GP, typename A > void remove_edge( typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor u, typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor v, adjacency_matrix< D, VP, EP, GP, A >& g) { // Don'remove the edge unless it already exists. if (detail::get_edge_exists(g.get_edge(u, v), 0)) { --(g.m_num_edges); detail::set_edge_exists(g.get_edge(u, v), false, 0); } } // O(1) template < typename D, typename VP, typename EP, typename GP, typename A > void remove_edge( typename adjacency_matrix< D, VP, EP, GP, A >::edge_descriptor e, adjacency_matrix< D, VP, EP, GP, A >& g) { remove_edge(source(e, g), target(e, g), g); } template < typename D, typename VP, typename EP, typename GP, typename A > inline typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor add_vertex(adjacency_matrix< D, VP, EP, GP, A >& g) { // UNDER CONSTRUCTION BOOST_ASSERT(false); return *vertices(g).first; } template < typename D, typename VP, typename EP, typename GP, typename A, typename VP2 > inline typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor add_vertex(const VP2& /*vp*/, adjacency_matrix< D, VP, EP, GP, A >& g) { // UNDER CONSTRUCTION BOOST_ASSERT(false); return *vertices(g).first; } template < typename D, typename VP, typename EP, typename GP, typename A > inline void remove_vertex( typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor /*u*/, adjacency_matrix< D, VP, EP, GP, A >& /*g*/) { // UNDER CONSTRUCTION BOOST_ASSERT(false); } // O(V) template < typename VP, typename EP, typename GP, typename A > void clear_vertex( typename adjacency_matrix< directedS, VP, EP, GP, A >::vertex_descriptor u, adjacency_matrix< directedS, VP, EP, GP, A >& g) { typename adjacency_matrix< directedS, VP, EP, GP, A >::vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) remove_edge(u, *vi, g); for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) remove_edge(*vi, u, g); } // O(V) template < typename VP, typename EP, typename GP, typename A > void clear_vertex( typename adjacency_matrix< undirectedS, VP, EP, GP, A >::vertex_descriptor u, adjacency_matrix< undirectedS, VP, EP, GP, A >& g) { typename adjacency_matrix< undirectedS, VP, EP, GP, A >::vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) remove_edge(u, *vi, g); } //========================================================================= // Functions required by the PropertyGraph concept template < typename D, typename VP, typename EP, typename GP, typename A, typename Prop, typename Kind > struct adj_mat_pm_helper; template < typename D, typename VP, typename EP, typename GP, typename A, typename Prop > struct adj_mat_pm_helper< D, VP, EP, GP, A, Prop, vertex_property_tag > { typedef typename graph_traits< adjacency_matrix< D, VP, EP, GP, A > >::vertex_descriptor arg_type; typedef typed_identity_property_map< arg_type > vi_map_type; typedef iterator_property_map< typename std::vector< VP >::iterator, vi_map_type > all_map_type; typedef iterator_property_map< typename std::vector< VP >::const_iterator, vi_map_type > all_map_const_type; typedef transform_value_property_map< detail::lookup_one_property_f< VP, Prop >, all_map_type > type; typedef transform_value_property_map< detail::lookup_one_property_f< const VP, Prop >, all_map_const_type > const_type; typedef typename property_traits< type >::reference single_nonconst_type; typedef typename property_traits< const_type >::reference single_const_type; static type get_nonconst(adjacency_matrix< D, VP, EP, GP, A >& g, Prop prop) { return type( prop, all_map_type(g.m_vertex_properties.begin(), vi_map_type())); } static const_type get_const( const adjacency_matrix< D, VP, EP, GP, A >& g, Prop prop) { return const_type(prop, all_map_const_type(g.m_vertex_properties.begin(), vi_map_type())); } static single_nonconst_type get_nonconst_one( adjacency_matrix< D, VP, EP, GP, A >& g, Prop prop, arg_type v) { return lookup_one_property< VP, Prop >::lookup( g.m_vertex_properties[v], prop); } static single_const_type get_const_one( const adjacency_matrix< D, VP, EP, GP, A >& g, Prop prop, arg_type v) { return lookup_one_property< const VP, Prop >::lookup( g.m_vertex_properties[v], prop); } }; template < typename D, typename VP, typename EP, typename GP, typename A, typename Tag > struct adj_mat_pm_helper< D, VP, EP, GP, A, Tag, edge_property_tag > { typedef typename graph_traits< adjacency_matrix< D, VP, EP, GP, A > >::edge_descriptor edge_descriptor; template < typename IsConst > struct lookup_property_from_edge { Tag tag; lookup_property_from_edge(Tag tag) : tag(tag) {} typedef typename boost::mpl::if_< IsConst, const EP, EP >::type ep_type_nonref; typedef ep_type_nonref& ep_type; typedef typename lookup_one_property< ep_type_nonref, Tag >::type& result_type; result_type operator()(edge_descriptor e) const { return lookup_one_property< ep_type_nonref, Tag >::lookup( *static_cast< ep_type_nonref* >(e.get_property()), tag); } }; typedef function_property_map< lookup_property_from_edge< boost::mpl::false_ >, typename graph_traits< adjacency_matrix< D, VP, EP, GP, A > >::edge_descriptor > type; typedef function_property_map< lookup_property_from_edge< boost::mpl::true_ >, typename graph_traits< adjacency_matrix< D, VP, EP, GP, A > >::edge_descriptor > const_type; typedef edge_descriptor arg_type; typedef typename lookup_property_from_edge< boost::mpl::false_ >::result_type single_nonconst_type; typedef typename lookup_property_from_edge< boost::mpl::true_ >::result_type single_const_type; static type get_nonconst(adjacency_matrix< D, VP, EP, GP, A >& g, Tag tag) { return type(tag); } static const_type get_const( const adjacency_matrix< D, VP, EP, GP, A >& g, Tag tag) { return const_type(tag); } static single_nonconst_type get_nonconst_one( adjacency_matrix< D, VP, EP, GP, A >& g, Tag tag, edge_descriptor e) { return lookup_one_property< EP, Tag >::lookup( *static_cast< EP* >(e.get_property()), tag); } static single_const_type get_const_one( const adjacency_matrix< D, VP, EP, GP, A >& g, Tag tag, edge_descriptor e) { return lookup_one_property< const EP, Tag >::lookup( *static_cast< const EP* >(e.get_property()), tag); } }; template < typename D, typename VP, typename EP, typename GP, typename A, typename Tag > struct property_map< adjacency_matrix< D, VP, EP, GP, A >, Tag > : adj_mat_pm_helper< D, VP, EP, GP, A, Tag, typename detail::property_kind_from_graph< adjacency_matrix< D, VP, EP, GP, A >, Tag >::type > { }; template < typename D, typename VP, typename EP, typename GP, typename A, typename Tag > typename property_map< adjacency_matrix< D, VP, EP, GP, A >, Tag >::type get( Tag tag, adjacency_matrix< D, VP, EP, GP, A >& g) { return property_map< adjacency_matrix< D, VP, EP, GP, A >, Tag >::get_nonconst(g, tag); } template < typename D, typename VP, typename EP, typename GP, typename A, typename Tag > typename property_map< adjacency_matrix< D, VP, EP, GP, A >, Tag >::const_type get(Tag tag, const adjacency_matrix< D, VP, EP, GP, A >& g) { return property_map< adjacency_matrix< D, VP, EP, GP, A >, Tag >::get_const( g, tag); } template < typename D, typename VP, typename EP, typename GP, typename A, typename Tag > typename property_map< adjacency_matrix< D, VP, EP, GP, A >, Tag >::single_nonconst_type get(Tag tag, adjacency_matrix< D, VP, EP, GP, A >& g, typename property_map< adjacency_matrix< D, VP, EP, GP, A >, Tag >::arg_type a) { return property_map< adjacency_matrix< D, VP, EP, GP, A >, Tag >::get_nonconst_one(g, tag, a); } template < typename D, typename VP, typename EP, typename GP, typename A, typename Tag > typename property_map< adjacency_matrix< D, VP, EP, GP, A >, Tag >::single_const_type get(Tag tag, const adjacency_matrix< D, VP, EP, GP, A >& g, typename property_map< adjacency_matrix< D, VP, EP, GP, A >, Tag >::arg_type a) { return property_map< adjacency_matrix< D, VP, EP, GP, A >, Tag >::get_const_one(g, tag, a); } template < typename D, typename VP, typename EP, typename GP, typename A, typename Tag > void put(Tag tag, adjacency_matrix< D, VP, EP, GP, A >& g, typename property_map< adjacency_matrix< D, VP, EP, GP, A >, Tag >::arg_type a, typename property_map< adjacency_matrix< D, VP, EP, GP, A >, Tag >::single_const_type val) { property_map< adjacency_matrix< D, VP, EP, GP, A >, Tag >::get_nonconst_one( g, tag, a) = val; } // O(1) template < typename D, typename VP, typename EP, typename GP, typename A, typename Tag, typename Value > inline void set_property( adjacency_matrix< D, VP, EP, GP, A >& g, Tag tag, const Value& value) { get_property_value(g.m_property, tag) = value; } template < typename D, typename VP, typename EP, typename GP, typename A, typename Tag > inline typename graph_property< adjacency_matrix< D, VP, EP, GP, A >, Tag >::type& get_property(adjacency_matrix< D, VP, EP, GP, A >& g, Tag tag) { return get_property_value(g.m_property, tag); } template < typename D, typename VP, typename EP, typename GP, typename A, typename Tag > inline const typename graph_property< adjacency_matrix< D, VP, EP, GP, A >, Tag >::type& get_property(const adjacency_matrix< D, VP, EP, GP, A >& g, Tag tag) { return get_property_value(g.m_property, tag); } //========================================================================= // Vertex Property Map template < typename D, typename VP, typename EP, typename GP, typename A > struct property_map< adjacency_matrix< D, VP, EP, GP, A >, vertex_index_t > { typedef typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor Vertex; typedef typed_identity_property_map< Vertex > type; typedef type const_type; }; template < typename D, typename VP, typename EP, typename GP, typename A > typename property_map< adjacency_matrix< D, VP, EP, GP, A >, vertex_index_t >::const_type get(vertex_index_t, adjacency_matrix< D, VP, EP, GP, A >&) { return typename property_map< adjacency_matrix< D, VP, EP, GP, A >, vertex_index_t >::const_type(); } template < typename D, typename VP, typename EP, typename GP, typename A > typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor get( vertex_index_t, adjacency_matrix< D, VP, EP, GP, A >&, typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor v) { return v; } template < typename D, typename VP, typename EP, typename GP, typename A > typename property_map< adjacency_matrix< D, VP, EP, GP, A >, vertex_index_t >::const_type get(vertex_index_t, const adjacency_matrix< D, VP, EP, GP, A >&) { return typename property_map< adjacency_matrix< D, VP, EP, GP, A >, vertex_index_t >::const_type(); } template < typename D, typename VP, typename EP, typename GP, typename A > typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor get( vertex_index_t, const adjacency_matrix< D, VP, EP, GP, A >&, typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor v) { return v; } //========================================================================= // Other Functions template < typename D, typename VP, typename EP, typename GP, typename A > typename adjacency_matrix< D, VP, EP, GP, A >::vertex_descriptor vertex( typename adjacency_matrix< D, VP, EP, GP, A >::vertices_size_type n, const adjacency_matrix< D, VP, EP, GP, A >&) { return n; } template < typename D, typename VP, typename EP, typename GP, typename A > struct graph_mutability_traits< adjacency_matrix< D, VP, EP, GP, A > > { typedef mutable_edge_property_graph_tag category; }; } // namespace boost #endif // BOOST_ADJACENCY_MATRIX_HPP random_layout.hpp 0000644 00000001734 15125521275 0010144 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_RANDOM_LAYOUT_HPP #define BOOST_GRAPH_RANDOM_LAYOUT_HPP #include <boost/graph/graph_traits.hpp> #include <boost/random/uniform_int.hpp> #include <boost/random/uniform_01.hpp> #include <boost/random/uniform_real.hpp> #include <boost/type_traits/is_integral.hpp> #include <boost/mpl/if.hpp> #include <boost/graph/iteration_macros.hpp> namespace boost { template < typename Topology, typename Graph, typename PositionMap > void random_graph_layout( const Graph& g, PositionMap position_map, const Topology& topology) { BGL_FORALL_VERTICES_T(v, g, Graph) { put(position_map, v, topology.random_point()); } } } // end namespace boost #endif // BOOST_GRAPH_RANDOM_LAYOUT_HPP dll_import_export.hpp 0000644 00000001574 15125521275 0011037 0 ustar 00 //======================================================================= // Copyright 2001 University of Notre Dame. // Copyright 2003 Jeremy Siek // Authors: Lie-Quan Lee, Jeremy Siek, and Douglas Gregor // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_DLL_IMPORT_EXPORT_HPP #define BOOST_GRAPH_DLL_IMPORT_EXPORT_HPP #include <boost/config.hpp> #if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_GRAPH_DYN_LINK) #ifdef BOOST_GRAPH_SOURCE #define BOOST_GRAPH_DECL BOOST_SYMBOL_EXPORT #else #define BOOST_GRAPH_DECL BOOST_SYMBOL_IMPORT #endif // BOOST_GRAPH_SOURCE #endif // DYN_LINK #ifndef BOOST_GRAPH_DECL #define BOOST_GRAPH_DECL #endif #endif // BOOST_GRAPH_DLL_IMPORT_EXPORT_HPP undirected_dfs.hpp 0000644 00000024660 15125521275 0010254 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_UNDIRECTED_DFS_HPP #define BOOST_GRAPH_UNDIRECTED_DFS_HPP #include <boost/graph/depth_first_search.hpp> #include <vector> #include <boost/concept/assert.hpp> namespace boost { namespace detail { // Define BOOST_RECURSIVE_DFS to use older, recursive version. // It is retained for a while in order to perform performance // comparison. #ifndef BOOST_RECURSIVE_DFS template < typename IncidenceGraph, typename DFSVisitor, typename VertexColorMap, typename EdgeColorMap > void undir_dfv_impl(const IncidenceGraph& g, typename graph_traits< IncidenceGraph >::vertex_descriptor u, DFSVisitor& vis, VertexColorMap vertex_color, EdgeColorMap edge_color) { BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< IncidenceGraph >)); BOOST_CONCEPT_ASSERT((DFSVisitorConcept< DFSVisitor, IncidenceGraph >)); typedef typename graph_traits< IncidenceGraph >::vertex_descriptor Vertex; typedef typename graph_traits< IncidenceGraph >::edge_descriptor Edge; BOOST_CONCEPT_ASSERT( (ReadWritePropertyMapConcept< VertexColorMap, Vertex >)); BOOST_CONCEPT_ASSERT( (ReadWritePropertyMapConcept< EdgeColorMap, Edge >)); typedef typename property_traits< VertexColorMap >::value_type ColorValue; typedef typename property_traits< EdgeColorMap >::value_type EColorValue; BOOST_CONCEPT_ASSERT((ColorValueConcept< ColorValue >)); BOOST_CONCEPT_ASSERT((ColorValueConcept< EColorValue >)); typedef color_traits< ColorValue > Color; typedef color_traits< EColorValue > EColor; typedef typename graph_traits< IncidenceGraph >::out_edge_iterator Iter; typedef std::pair< Vertex, std::pair< boost::optional< Edge >, std::pair< Iter, Iter > > > VertexInfo; std::vector< VertexInfo > stack; put(vertex_color, u, Color::gray()); vis.discover_vertex(u, g); stack.push_back(std::make_pair( u, std::make_pair(boost::optional< Edge >(), out_edges(u, g)))); while (!stack.empty()) { VertexInfo& back = stack.back(); u = back.first; boost::optional< Edge > src_e = back.second.first; Iter ei = back.second.second.first, ei_end = back.second.second.second; stack.pop_back(); while (ei != ei_end) { Vertex v = target(*ei, g); vis.examine_edge(*ei, g); ColorValue v_color = get(vertex_color, v); EColorValue uv_color = get(edge_color, *ei); put(edge_color, *ei, EColor::black()); if (v_color == Color::white()) { vis.tree_edge(*ei, g); src_e = *ei; stack.push_back(std::make_pair(u, std::make_pair(src_e, std::make_pair(++ei, ei_end)))); u = v; put(vertex_color, u, Color::gray()); vis.discover_vertex(u, g); boost::tie(ei, ei_end) = out_edges(u, g); } else if (v_color == Color::gray()) { if (uv_color == EColor::white()) vis.back_edge(*ei, g); call_finish_edge(vis, *ei, g); ++ei; } else { // if (v_color == Color::black()) call_finish_edge(vis, *ei, g); ++ei; } } put(vertex_color, u, Color::black()); vis.finish_vertex(u, g); if (src_e) call_finish_edge(vis, src_e.get(), g); } } #else // BOOST_RECURSIVE_DFS template < typename IncidenceGraph, typename DFSVisitor, typename VertexColorMap, typename EdgeColorMap > void undir_dfv_impl(const IncidenceGraph& g, typename graph_traits< IncidenceGraph >::vertex_descriptor u, DFSVisitor& vis, // pass-by-reference here, important! VertexColorMap vertex_color, EdgeColorMap edge_color) { BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< IncidenceGraph >)); BOOST_CONCEPT_ASSERT((DFSVisitorConcept< DFSVisitor, IncidenceGraph >)); typedef typename graph_traits< IncidenceGraph >::vertex_descriptor Vertex; typedef typename graph_traits< IncidenceGraph >::edge_descriptor Edge; BOOST_CONCEPT_ASSERT( (ReadWritePropertyMapConcept< VertexColorMap, Vertex >)); BOOST_CONCEPT_ASSERT( (ReadWritePropertyMapConcept< EdgeColorMap, Edge >)); typedef typename property_traits< VertexColorMap >::value_type ColorValue; typedef typename property_traits< EdgeColorMap >::value_type EColorValue; BOOST_CONCEPT_ASSERT((ColorValueConcept< ColorValue >)); BOOST_CONCEPT_ASSERT((ColorValueConcept< EColorValue >)); typedef color_traits< ColorValue > Color; typedef color_traits< EColorValue > EColor; typename graph_traits< IncidenceGraph >::out_edge_iterator ei, ei_end; put(vertex_color, u, Color::gray()); vis.discover_vertex(u, g); for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) { Vertex v = target(*ei, g); vis.examine_edge(*ei, g); ColorValue v_color = get(vertex_color, v); EColorValue uv_color = get(edge_color, *ei); put(edge_color, *ei, EColor::black()); if (v_color == Color::white()) { vis.tree_edge(*ei, g); undir_dfv_impl(g, v, vis, vertex_color, edge_color); } else if (v_color == Color::gray() && uv_color == EColor::white()) vis.back_edge(*ei, g); call_finish_edge(vis, *ei, g); } put(vertex_color, u, Color::black()); vis.finish_vertex(u, g); } #endif // ! BOOST_RECURSIVE_DFS } // namespace detail template < typename Graph, typename DFSVisitor, typename VertexColorMap, typename EdgeColorMap, typename Vertex > void undirected_dfs(const Graph& g, DFSVisitor vis, VertexColorMap vertex_color, EdgeColorMap edge_color, Vertex start_vertex) { BOOST_CONCEPT_ASSERT((DFSVisitorConcept< DFSVisitor, Graph >)); BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph >)); typedef typename property_traits< VertexColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; typename graph_traits< Graph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { put(vertex_color, *ui, Color::white()); vis.initialize_vertex(*ui, g); } typename graph_traits< Graph >::edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) put(edge_color, *ei, Color::white()); if (start_vertex != *vertices(g).first) { vis.start_vertex(start_vertex, g); detail::undir_dfv_impl(g, start_vertex, vis, vertex_color, edge_color); } for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { ColorValue u_color = get(vertex_color, *ui); if (u_color == Color::white()) { vis.start_vertex(*ui, g); detail::undir_dfv_impl(g, *ui, vis, vertex_color, edge_color); } } } template < typename Graph, typename DFSVisitor, typename VertexColorMap, typename EdgeColorMap > void undirected_dfs(const Graph& g, DFSVisitor vis, VertexColorMap vertex_color, EdgeColorMap edge_color) { undirected_dfs(g, vis, vertex_color, edge_color, *vertices(g).first); } namespace detail { template < typename VertexColorMap > struct udfs_dispatch { template < typename Graph, typename Vertex, typename DFSVisitor, typename EdgeColorMap, typename P, typename T, typename R > static void apply(const Graph& g, DFSVisitor vis, Vertex start_vertex, const bgl_named_params< P, T, R >&, EdgeColorMap edge_color, VertexColorMap vertex_color) { undirected_dfs(g, vis, vertex_color, edge_color, start_vertex); } }; template <> struct udfs_dispatch< param_not_found > { template < typename Graph, typename Vertex, typename DFSVisitor, typename EdgeColorMap, typename P, typename T, typename R > static void apply(const Graph& g, DFSVisitor vis, Vertex start_vertex, const bgl_named_params< P, T, R >& params, EdgeColorMap edge_color, param_not_found) { std::vector< default_color_type > color_vec(num_vertices(g)); default_color_type c = white_color; // avoid warning about un-init undirected_dfs(g, vis, make_iterator_property_map(color_vec.begin(), choose_const_pmap( get_param(params, vertex_index), g, vertex_index), c), edge_color, start_vertex); } }; } // namespace detail // Named Parameter Variant template < typename Graph, typename P, typename T, typename R > void undirected_dfs(const Graph& g, const bgl_named_params< P, T, R >& params) { typedef typename get_param_type< vertex_color_t, bgl_named_params< P, T, R > >::type C; detail::udfs_dispatch< C >::apply(g, choose_param( get_param(params, graph_visitor), make_dfs_visitor(null_visitor())), choose_param(get_param(params, root_vertex_t()), *vertices(g).first), params, get_param(params, edge_color), get_param(params, vertex_color)); } template < typename IncidenceGraph, typename DFSVisitor, typename VertexColorMap, typename EdgeColorMap > void undirected_depth_first_visit(const IncidenceGraph& g, typename graph_traits< IncidenceGraph >::vertex_descriptor u, DFSVisitor vis, VertexColorMap vertex_color, EdgeColorMap edge_color) { detail::undir_dfv_impl(g, u, vis, vertex_color, edge_color); } } // namespace boost #endif mesh_graph_generator.hpp 0000644 00000012760 15125521275 0011453 0 ustar 00 // Copyright 2004, 2005 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Nick Edmonds // Andrew Lumsdaine #ifndef BOOST_GRAPH_MESH_GENERATOR_HPP #define BOOST_GRAPH_MESH_GENERATOR_HPP #include <iterator> #include <utility> #include <boost/assert.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/type_traits/is_base_and_derived.hpp> #include <boost/type_traits/is_same.hpp> namespace boost { template < typename Graph > class mesh_iterator { typedef typename graph_traits< Graph >::directed_category directed_category; typedef typename graph_traits< Graph >::vertices_size_type vertices_size_type; BOOST_STATIC_CONSTANT(bool, is_undirected = (is_base_and_derived< undirected_tag, directed_category >::value || is_same< undirected_tag, directed_category >::value)); public: typedef std::input_iterator_tag iterator_category; typedef std::pair< vertices_size_type, vertices_size_type > value_type; typedef const value_type& reference; typedef const value_type* pointer; typedef void difference_type; mesh_iterator() : x(0), y(0), done(true) {} // Vertices are numbered in row-major order // Assumes directed mesh_iterator( vertices_size_type x, vertices_size_type y, bool toroidal = true) : x(x) , y(y) , n(x * y) , source(0) , target(1) , current(0, 1) , toroidal(toroidal) , done(false) { BOOST_ASSERT(x > 1 && y > 1); } reference operator*() const { return current; } pointer operator->() const { return ¤t; } mesh_iterator& operator++() { if (is_undirected) { if (!toroidal) { if (target == source + 1) if (source < x * (y - 1)) target = source + x; else { source++; target = (source % x) < x - 1 ? source + 1 : source + x; if (target > n) done = true; } else if (target == source + x) { source++; target = (source % x) < x - 1 ? source + 1 : source + x; } } else { if (target == source + 1 || target == source - (source % x)) target = (source + x) % n; else if (target == (source + x) % n) { if (source == n - 1) done = true; else { source++; target = (source % x) < (x - 1) ? source + 1 : source - (source % x); } } } } else { // Directed if (!toroidal) { if (target == source - x) target = source % x > 0 ? source - 1 : source + 1; else if (target == source - 1) if ((source % x) < (x - 1)) target = source + 1; else if (source < x * (y - 1)) target = source + x; else { done = true; } else if (target == source + 1) if (source < x * (y - 1)) target = source + x; else { source++; target = source - x; } else if (target == source + x) { source++; target = (source >= x) ? source - x : source - 1; } } else { if (source == n - 1 && target == (source + x) % n) done = true; else if (target == source - 1 || target == source + x - 1) target = (source + x) % n; else if (target == source + 1 || target == source - (source % x)) target = (source - x + n) % n; else if (target == (source - x + n) % n) target = (source % x > 0) ? source - 1 : source + x - 1; else if (target == (source + x) % n) { source++; target = (source % x) < (x - 1) ? source + 1 : source - (source % x); } } } current.first = source; current.second = target; return *this; } mesh_iterator operator++(int) { mesh_iterator temp(*this); ++(*this); return temp; } bool operator==(const mesh_iterator& other) const { return done == other.done; } bool operator!=(const mesh_iterator& other) const { return !(*this == other); } private: vertices_size_type x, y; vertices_size_type n; vertices_size_type source; vertices_size_type target; value_type current; bool toroidal; bool done; }; } // end namespace boost #endif // BOOST_GRAPH_MESH_GENERATOR_HPP successive_shortest_path_nonnegative_weights.hpp 0000644 00000024255 15125521275 0016544 0 ustar 00 //======================================================================= // Copyright 2013 University of Warsaw. // Authors: Piotr Wygocki // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // // This algorithm is described in "Network Flows: Theory, Algorithms, and // Applications" // by Ahuja, Magnanti, Orlin. #ifndef BOOST_GRAPH_SUCCESSIVE_SHORTEST_PATH_HPP #define BOOST_GRAPH_SUCCESSIVE_SHORTEST_PATH_HPP #include <numeric> #include <boost/property_map/property_map.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/pending/indirect_cmp.hpp> #include <boost/graph/dijkstra_shortest_paths.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/graph/detail/augment.hpp> namespace boost { namespace detail { template < class Graph, class Weight, class Distance, class Reversed > class MapReducedWeight : public put_get_helper< typename property_traits< Weight >::value_type, MapReducedWeight< Graph, Weight, Distance, Reversed > > { typedef graph_traits< Graph > gtraits; public: typedef boost::readable_property_map_tag category; typedef typename property_traits< Weight >::value_type value_type; typedef value_type reference; typedef typename gtraits::edge_descriptor key_type; MapReducedWeight(const Graph& g, Weight w, Distance d, Reversed r) : g_(g), weight_(w), distance_(d), rev_(r) { } reference operator[](key_type v) const { return get(distance_, source(v, g_)) - get(distance_, target(v, g_)) + get(weight_, v); } private: const Graph& g_; Weight weight_; Distance distance_; Reversed rev_; }; template < class Graph, class Weight, class Distance, class Reversed > MapReducedWeight< Graph, Weight, Distance, Reversed > make_mapReducedWeight( const Graph& g, Weight w, Distance d, Reversed r) { return MapReducedWeight< Graph, Weight, Distance, Reversed >( g, w, d, r); } } // detail template < class Graph, class Capacity, class ResidualCapacity, class Reversed, class Pred, class Weight, class Distance, class Distance2, class VertexIndex > void successive_shortest_path_nonnegative_weights(const Graph& g, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, Capacity capacity, ResidualCapacity residual_capacity, Weight weight, Reversed rev, VertexIndex index, Pred pred, Distance distance, Distance2 distance_prev) { filtered_graph< const Graph, is_residual_edge< ResidualCapacity > > gres = detail::residual_graph(g, residual_capacity); typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor; BGL_FORALL_EDGES_T(e, g, Graph) { put(residual_capacity, e, get(capacity, e)); } BGL_FORALL_VERTICES_T(v, g, Graph) { put(distance_prev, v, 0); } while (true) { BGL_FORALL_VERTICES_T(v, g, Graph) { put(pred, v, edge_descriptor()); } dijkstra_shortest_paths(gres, s, weight_map( detail::make_mapReducedWeight(gres, weight, distance_prev, rev)) .distance_map(distance) .vertex_index_map(index) .visitor(make_dijkstra_visitor( record_edge_predecessors(pred, on_edge_relaxed())))); if (get(pred, t) == edge_descriptor()) { break; } BGL_FORALL_VERTICES_T(v, g, Graph) { put(distance_prev, v, get(distance_prev, v) + get(distance, v)); } detail::augment(g, s, t, pred, residual_capacity, rev); } } // in this namespace argument dispatching tak place namespace detail { template < class Graph, class Capacity, class ResidualCapacity, class Weight, class Reversed, class Pred, class Distance, class Distance2, class VertexIndex > void successive_shortest_path_nonnegative_weights_dispatch3(const Graph& g, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, Capacity capacity, ResidualCapacity residual_capacity, Weight weight, Reversed rev, VertexIndex index, Pred pred, Distance dist, Distance2 dist_pred) { successive_shortest_path_nonnegative_weights(g, s, t, capacity, residual_capacity, weight, rev, index, pred, dist, dist_pred); } // setting default distance map template < class Graph, class Capacity, class ResidualCapacity, class Weight, class Reversed, class Pred, class Distance, class VertexIndex > void successive_shortest_path_nonnegative_weights_dispatch3(Graph& g, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, Capacity capacity, ResidualCapacity residual_capacity, Weight weight, Reversed rev, VertexIndex index, Pred pred, Distance dist, param_not_found) { typedef typename property_traits< Weight >::value_type D; std::vector< D > d_map(num_vertices(g)); successive_shortest_path_nonnegative_weights(g, s, t, capacity, residual_capacity, weight, rev, index, pred, dist, make_iterator_property_map(d_map.begin(), index)); } template < class Graph, class P, class T, class R, class Capacity, class ResidualCapacity, class Weight, class Reversed, class Pred, class Distance, class VertexIndex > void successive_shortest_path_nonnegative_weights_dispatch2(Graph& g, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, Capacity capacity, ResidualCapacity residual_capacity, Weight weight, Reversed rev, VertexIndex index, Pred pred, Distance dist, const bgl_named_params< P, T, R >& params) { successive_shortest_path_nonnegative_weights_dispatch3(g, s, t, capacity, residual_capacity, weight, rev, index, pred, dist, get_param(params, vertex_distance2)); } // setting default distance map template < class Graph, class P, class T, class R, class Capacity, class ResidualCapacity, class Weight, class Reversed, class Pred, class VertexIndex > void successive_shortest_path_nonnegative_weights_dispatch2(Graph& g, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, Capacity capacity, ResidualCapacity residual_capacity, Weight weight, Reversed rev, VertexIndex index, Pred pred, param_not_found, const bgl_named_params< P, T, R >& params) { typedef typename property_traits< Weight >::value_type D; std::vector< D > d_map(num_vertices(g)); successive_shortest_path_nonnegative_weights_dispatch3(g, s, t, capacity, residual_capacity, weight, rev, index, pred, make_iterator_property_map(d_map.begin(), index), get_param(params, vertex_distance2)); } template < class Graph, class P, class T, class R, class Capacity, class ResidualCapacity, class Weight, class Reversed, class Pred, class VertexIndex > void successive_shortest_path_nonnegative_weights_dispatch1(Graph& g, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, Capacity capacity, ResidualCapacity residual_capacity, Weight weight, Reversed rev, VertexIndex index, Pred pred, const bgl_named_params< P, T, R >& params) { successive_shortest_path_nonnegative_weights_dispatch2(g, s, t, capacity, residual_capacity, weight, rev, index, pred, get_param(params, vertex_distance), params); } // setting default predecessors map template < class Graph, class P, class T, class R, class Capacity, class ResidualCapacity, class Weight, class Reversed, class VertexIndex > void successive_shortest_path_nonnegative_weights_dispatch1(Graph& g, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, Capacity capacity, ResidualCapacity residual_capacity, Weight weight, Reversed rev, VertexIndex index, param_not_found, const bgl_named_params< P, T, R >& params) { typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor; std::vector< edge_descriptor > pred_vec(num_vertices(g)); successive_shortest_path_nonnegative_weights_dispatch2(g, s, t, capacity, residual_capacity, weight, rev, index, make_iterator_property_map(pred_vec.begin(), index), get_param(params, vertex_distance), params); } } // detail template < class Graph, class P, class T, class R > void successive_shortest_path_nonnegative_weights(Graph& g, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, const bgl_named_params< P, T, R >& params) { return detail::successive_shortest_path_nonnegative_weights_dispatch1(g, s, t, choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity), choose_pmap(get_param(params, edge_residual_capacity), g, edge_residual_capacity), choose_const_pmap(get_param(params, edge_weight), g, edge_weight), choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse), choose_const_pmap(get_param(params, vertex_index), g, vertex_index), get_param(params, vertex_predecessor), params); } template < class Graph > void successive_shortest_path_nonnegative_weights(Graph& g, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t) { bgl_named_params< int, buffer_param_t > params(0); successive_shortest_path_nonnegative_weights(g, s, t, params); } } // boost #endif /* BOOST_GRAPH_SUCCESSIVE_SHORTEST_PATH_HPP */ boyer_myrvold_planar_test.hpp 0000644 00000023171 15125521275 0012556 0 ustar 00 //======================================================================= // Copyright 2007 Aaron Windsor // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef __BOYER_MYRVOLD_PLANAR_TEST_HPP__ #define __BOYER_MYRVOLD_PLANAR_TEST_HPP__ #include <boost/graph/planar_detail/boyer_myrvold_impl.hpp> #include <boost/parameter.hpp> #include <boost/type_traits.hpp> #include <boost/mpl/bool.hpp> namespace boost { struct no_kuratowski_subgraph_isolation { }; struct no_planar_embedding { }; namespace boyer_myrvold_params { BOOST_PARAMETER_KEYWORD(tag, graph) BOOST_PARAMETER_KEYWORD(tag, embedding) BOOST_PARAMETER_KEYWORD(tag, kuratowski_subgraph) BOOST_PARAMETER_KEYWORD(tag, vertex_index_map) BOOST_PARAMETER_KEYWORD(tag, edge_index_map) typedef parameter::parameters< parameter::required< tag::graph >, tag::embedding, tag::kuratowski_subgraph, tag::vertex_index_map, tag::edge_index_map > boyer_myrvold_params_t; namespace core { template < typename ArgumentPack > bool dispatched_boyer_myrvold( ArgumentPack const& args, mpl::true_, mpl::true_) { // Dispatch for no planar embedding, no kuratowski subgraph // isolation typedef typename remove_const< typename parameter::value_type< ArgumentPack, tag::graph >::type >::type graph_t; typedef typename property_map< graph_t, vertex_index_t >::const_type vertex_default_index_map_t; typedef typename parameter::value_type< ArgumentPack, tag::vertex_index_map, vertex_default_index_map_t >::type vertex_index_map_t; graph_t const& g = args[graph]; vertex_default_index_map_t v_d_map = get(vertex_index, g); vertex_index_map_t v_i_map = args[vertex_index_map | v_d_map]; boyer_myrvold_impl< graph_t, vertex_index_map_t, graph::detail::no_old_handles, graph::detail::no_embedding > planarity_tester(g, v_i_map); return planarity_tester.is_planar() ? true : false; } template < typename ArgumentPack > bool dispatched_boyer_myrvold( ArgumentPack const& args, mpl::true_, mpl::false_) { // Dispatch for no planar embedding, kuratowski subgraph isolation typedef typename remove_const< typename parameter::value_type< ArgumentPack, tag::graph >::type >::type graph_t; typedef typename property_map< graph_t, vertex_index_t >::const_type vertex_default_index_map_t; typedef typename parameter::value_type< ArgumentPack, tag::vertex_index_map, vertex_default_index_map_t >::type vertex_index_map_t; typedef typename property_map< graph_t, edge_index_t >::const_type edge_default_index_map_t; typedef typename parameter::value_type< ArgumentPack, tag::edge_index_map, edge_default_index_map_t >::type edge_index_map_t; graph_t const& g = args[graph]; vertex_default_index_map_t v_d_map = get(vertex_index, g); vertex_index_map_t v_i_map = args[vertex_index_map | v_d_map]; edge_default_index_map_t e_d_map = get(edge_index, g); edge_index_map_t e_i_map = args[edge_index_map | e_d_map]; boyer_myrvold_impl< graph_t, vertex_index_map_t, graph::detail::store_old_handles, graph::detail::no_embedding > planarity_tester(g, v_i_map); if (planarity_tester.is_planar()) return true; else { planarity_tester.extract_kuratowski_subgraph( args[kuratowski_subgraph], e_i_map); return false; } } template < typename ArgumentPack > bool dispatched_boyer_myrvold( ArgumentPack const& args, mpl::false_, mpl::true_) { // Dispatch for planar embedding, no kuratowski subgraph isolation typedef typename remove_const< typename parameter::value_type< ArgumentPack, tag::graph >::type >::type graph_t; typedef typename property_map< graph_t, vertex_index_t >::const_type vertex_default_index_map_t; typedef typename parameter::value_type< ArgumentPack, tag::vertex_index_map, vertex_default_index_map_t >::type vertex_index_map_t; graph_t const& g = args[graph]; vertex_default_index_map_t v_d_map = get(vertex_index, g); vertex_index_map_t v_i_map = args[vertex_index_map | v_d_map]; boyer_myrvold_impl< graph_t, vertex_index_map_t, graph::detail::no_old_handles, #ifdef BOOST_GRAPH_PREFER_STD_LIB graph::detail::std_list #else graph::detail::recursive_lazy_list #endif > planarity_tester(g, v_i_map); if (planarity_tester.is_planar()) { planarity_tester.make_edge_permutation(args[embedding]); return true; } else return false; } template < typename ArgumentPack > bool dispatched_boyer_myrvold( ArgumentPack const& args, mpl::false_, mpl::false_) { // Dispatch for planar embedding, kuratowski subgraph isolation typedef typename remove_const< typename parameter::value_type< ArgumentPack, tag::graph >::type >::type graph_t; typedef typename property_map< graph_t, vertex_index_t >::const_type vertex_default_index_map_t; typedef typename parameter::value_type< ArgumentPack, tag::vertex_index_map, vertex_default_index_map_t >::type vertex_index_map_t; typedef typename property_map< graph_t, edge_index_t >::const_type edge_default_index_map_t; typedef typename parameter::value_type< ArgumentPack, tag::edge_index_map, edge_default_index_map_t >::type edge_index_map_t; graph_t const& g = args[graph]; vertex_default_index_map_t v_d_map = get(vertex_index, g); vertex_index_map_t v_i_map = args[vertex_index_map | v_d_map]; edge_default_index_map_t e_d_map = get(edge_index, g); edge_index_map_t e_i_map = args[edge_index_map | e_d_map]; boyer_myrvold_impl< graph_t, vertex_index_map_t, graph::detail::store_old_handles, #ifdef BOOST_BGL_PREFER_STD_LIB graph::detail::std_list #else graph::detail::recursive_lazy_list #endif > planarity_tester(g, v_i_map); if (planarity_tester.is_planar()) { planarity_tester.make_edge_permutation(args[embedding]); return true; } else { planarity_tester.extract_kuratowski_subgraph( args[kuratowski_subgraph], e_i_map); return false; } } template < typename ArgumentPack > bool boyer_myrvold_planarity_test(ArgumentPack const& args) { typedef typename parameter::binding< ArgumentPack, tag::kuratowski_subgraph, const no_kuratowski_subgraph_isolation& >::type kuratowski_arg_t; typedef typename parameter::binding< ArgumentPack, tag::embedding, const no_planar_embedding& >::type embedding_arg_t; return dispatched_boyer_myrvold(args, boost::is_same< embedding_arg_t, const no_planar_embedding& >(), boost::is_same< kuratowski_arg_t, const no_kuratowski_subgraph_isolation& >()); } } // namespace core } // namespace boyer_myrvold_params template < typename A0 > bool boyer_myrvold_planarity_test(A0 const& arg0) { return boyer_myrvold_params::core::boyer_myrvold_planarity_test( boyer_myrvold_params::boyer_myrvold_params_t()(arg0)); } template < typename A0, typename A1 > // bool boyer_myrvold_planarity_test(A0 const& arg0, A1 const& arg1) bool boyer_myrvold_planarity_test(A0 const& arg0, A1 const& arg1) { return boyer_myrvold_params::core::boyer_myrvold_planarity_test( boyer_myrvold_params::boyer_myrvold_params_t()(arg0, arg1)); } template < typename A0, typename A1, typename A2 > bool boyer_myrvold_planarity_test( A0 const& arg0, A1 const& arg1, A2 const& arg2) { return boyer_myrvold_params::core::boyer_myrvold_planarity_test( boyer_myrvold_params::boyer_myrvold_params_t()(arg0, arg1, arg2)); } template < typename A0, typename A1, typename A2, typename A3 > bool boyer_myrvold_planarity_test( A0 const& arg0, A1 const& arg1, A2 const& arg2, A3 const& arg3) { return boyer_myrvold_params::core::boyer_myrvold_planarity_test( boyer_myrvold_params::boyer_myrvold_params_t()(arg0, arg1, arg2, arg3)); } template < typename A0, typename A1, typename A2, typename A3, typename A4 > bool boyer_myrvold_planarity_test(A0 const& arg0, A1 const& arg1, A2 const& arg2, A3 const& arg3, A4 const& arg4) { return boyer_myrvold_params::core::boyer_myrvold_planarity_test( boyer_myrvold_params::boyer_myrvold_params_t()( arg0, arg1, arg2, arg3, arg4)); } } #endif //__BOYER_MYRVOLD_PLANAR_TEST_HPP__ numeric_values.hpp 0000644 00000003426 15125521275 0010310 0 ustar 00 // (C) Copyright 2007-2009 Andrew Sutton // // 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_NUMERIC_VALUES_HPP #define BOOST_GRAPH_NUMERIC_VALUES_HPP #include <limits> namespace boost { #define BOOST_GRAPH_SPECIALIZE_NUMERIC_FLOAT(type) \ template <> struct numeric_values< type > \ { \ typedef type value_type; \ static type zero() { return 0.0; } \ static type infinity() \ { \ return std::numeric_limits< type >::infinity(); \ } \ }; /** * This generic type reports various numeric values for some type. In the * general case, numeric values simply treat their maximum value as infinity * and the default-constructed value as 0. * * Specializations of this template can redefine the notions of zero and * infinity for various types. For example, the class is specialized for * floating point types to use the built in notion of infinity. */ template < typename T > struct numeric_values { typedef T value_type; static T zero() { return T(); } static T infinity() { return (std::numeric_limits< T >::max)(); } }; // Specializations for floating point types refer to 0.0 and their infinity // value defined by numeric_limits. BOOST_GRAPH_SPECIALIZE_NUMERIC_FLOAT(float) BOOST_GRAPH_SPECIALIZE_NUMERIC_FLOAT(double) BOOST_GRAPH_SPECIALIZE_NUMERIC_FLOAT(long double) #undef BOOST_GRAPH_SPECIALIZE_NUMERIC_VALUE } #endif geodesic_distance.hpp 0000644 00000017517 15125521275 0010731 0 ustar 00 // (C) Copyright Andrew Sutton 2007 // // 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_GEODESIC_DISTANCE_HPP #define BOOST_GRAPH_GEODESIC_DISTANCE_HPP #include <boost/graph/detail/geodesic.hpp> #include <boost/graph/exterior_property.hpp> #include <boost/concept/assert.hpp> namespace boost { template < typename Graph, typename DistanceType, typename ResultType, typename Divides = std::divides< ResultType > > struct mean_geodesic_measure : public geodesic_measure< Graph, DistanceType, ResultType > { typedef geodesic_measure< Graph, DistanceType, ResultType > base_type; typedef typename base_type::distance_type distance_type; typedef typename base_type::result_type result_type; result_type operator()(distance_type d, const Graph& g) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); BOOST_CONCEPT_ASSERT((NumericValueConcept< DistanceType >)); BOOST_CONCEPT_ASSERT((NumericValueConcept< ResultType >)); BOOST_CONCEPT_ASSERT((AdaptableBinaryFunctionConcept< Divides, ResultType, ResultType, ResultType >)); return (d == base_type::infinite_distance()) ? base_type::infinite_result() : div(result_type(d), result_type(num_vertices(g) - 1)); } Divides div; }; template < typename Graph, typename DistanceMap > inline mean_geodesic_measure< Graph, typename property_traits< DistanceMap >::value_type, double > measure_mean_geodesic(const Graph&, DistanceMap) { return mean_geodesic_measure< Graph, typename property_traits< DistanceMap >::value_type, double >(); } template < typename T, typename Graph, typename DistanceMap > inline mean_geodesic_measure< Graph, typename property_traits< DistanceMap >::value_type, T > measure_mean_geodesic(const Graph&, DistanceMap) { return mean_geodesic_measure< Graph, typename property_traits< DistanceMap >::value_type, T >(); } // This is a little different because it's expected that the result type // should (must?) be the same as the distance type. There's a type of // transitivity in this thinking... If the average of distances has type // X then the average of x's should also be type X. Is there a case where this // is not true? // // This type is a little under-genericized... It needs generic parameters // for addition and division. template < typename Graph, typename DistanceType > struct mean_graph_distance_measure : public geodesic_measure< Graph, DistanceType, DistanceType > { typedef geodesic_measure< Graph, DistanceType, DistanceType > base_type; typedef typename base_type::distance_type distance_type; typedef typename base_type::result_type result_type; inline result_type operator()(distance_type d, const Graph& g) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); BOOST_CONCEPT_ASSERT((NumericValueConcept< DistanceType >)); if (d == base_type::infinite_distance()) { return base_type::infinite_result(); } else { return d / result_type(num_vertices(g)); } } }; template < typename Graph, typename DistanceMap > inline mean_graph_distance_measure< Graph, typename property_traits< DistanceMap >::value_type > measure_graph_mean_geodesic(const Graph&, DistanceMap) { typedef typename property_traits< DistanceMap >::value_type T; return mean_graph_distance_measure< Graph, T >(); } template < typename Graph, typename DistanceMap, typename Measure, typename Combinator > inline typename Measure::result_type mean_geodesic( const Graph& g, DistanceMap dist, Measure measure, Combinator combine) { BOOST_CONCEPT_ASSERT((DistanceMeasureConcept< Measure, Graph >)); typedef typename Measure::distance_type Distance; Distance n = detail::combine_distances(g, dist, combine, Distance(0)); return measure(n, g); } template < typename Graph, typename DistanceMap, typename Measure > inline typename Measure::result_type mean_geodesic( const Graph& g, DistanceMap dist, Measure measure) { BOOST_CONCEPT_ASSERT((DistanceMeasureConcept< Measure, Graph >)); typedef typename Measure::distance_type Distance; return mean_geodesic(g, dist, measure, std::plus< Distance >()); } template < typename Graph, typename DistanceMap > inline double mean_geodesic(const Graph& g, DistanceMap dist) { return mean_geodesic(g, dist, measure_mean_geodesic(g, dist)); } template < typename T, typename Graph, typename DistanceMap > inline T mean_geodesic(const Graph& g, DistanceMap dist) { return mean_geodesic(g, dist, measure_mean_geodesic< T >(g, dist)); } template < typename Graph, typename DistanceMatrixMap, typename GeodesicMap, typename Measure > inline typename property_traits< GeodesicMap >::value_type all_mean_geodesics( const Graph& g, DistanceMatrixMap dist, GeodesicMap geo, Measure measure) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::vertex_iterator VertexIterator; BOOST_CONCEPT_ASSERT( (ReadablePropertyMapConcept< DistanceMatrixMap, Vertex >)); typedef typename property_traits< DistanceMatrixMap >::value_type DistanceMap; BOOST_CONCEPT_ASSERT((DistanceMeasureConcept< Measure, Graph >)); typedef typename Measure::result_type Result; BOOST_CONCEPT_ASSERT((WritablePropertyMapConcept< GeodesicMap, Vertex >)); BOOST_CONCEPT_ASSERT((NumericValueConcept< Result >)); // NOTE: We could compute the mean geodesic here by performing additional // computations (i.e., adding and dividing). However, I don't really feel // like fully genericizing the entire operation yet so I'm not going to. Result inf = numeric_values< Result >::infinity(); Result sum = numeric_values< Result >::zero(); VertexIterator i, end; for (boost::tie(i, end) = vertices(g); i != end; ++i) { DistanceMap dm = get(dist, *i); Result r = mean_geodesic(g, dm, measure); put(geo, *i, r); // compute the sum along with geodesics if (r == inf) { sum = inf; } else if (sum != inf) { sum += r; } } // return the average of averages. return sum / Result(num_vertices(g)); } template < typename Graph, typename DistanceMatrixMap, typename GeodesicMap > inline typename property_traits< GeodesicMap >::value_type all_mean_geodesics( const Graph& g, DistanceMatrixMap dist, GeodesicMap geo) { BOOST_CONCEPT_ASSERT((GraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT( (ReadablePropertyMapConcept< DistanceMatrixMap, Vertex >)); typedef typename property_traits< DistanceMatrixMap >::value_type DistanceMap; BOOST_CONCEPT_ASSERT((WritablePropertyMapConcept< GeodesicMap, Vertex >)); typedef typename property_traits< GeodesicMap >::value_type Result; return all_mean_geodesics( g, dist, geo, measure_mean_geodesic< Result >(g, DistanceMap())); } template < typename Graph, typename GeodesicMap, typename Measure > inline typename Measure::result_type small_world_distance( const Graph& g, GeodesicMap geo, Measure measure) { BOOST_CONCEPT_ASSERT((DistanceMeasureConcept< Measure, Graph >)); typedef typename Measure::result_type Result; Result sum = detail::combine_distances(g, geo, std::plus< Result >(), Result(0)); return measure(sum, g); } template < typename Graph, typename GeodesicMap > inline typename property_traits< GeodesicMap >::value_type small_world_distance( const Graph& g, GeodesicMap geo) { return small_world_distance(g, geo, measure_graph_mean_geodesic(g, geo)); } } #endif detail/index.hpp 0000644 00000005077 15125521275 0007644 0 ustar 00 // (C) Copyright 2007-2009 Andrew Sutton // // 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_DETAIL_INDEX_HPP #define BOOST_GRAPH_DETAIL_INDEX_HPP #include <boost/graph/graph_traits.hpp> // The structures in this module are responsible for selecting and defining // types for accessing a builting index map. Note that the selection of these // types requires the Graph parameter to model either VertexIndexGraph or // EdgeIndexGraph. namespace boost { namespace detail { template < typename Graph > struct vertex_indexer { typedef vertex_index_t index_type; typedef typename property_map< Graph, vertex_index_t >::type map_type; typedef typename property_map< Graph, vertex_index_t >::const_type const_map_type; typedef typename property_traits< map_type >::value_type value_type; typedef typename graph_traits< Graph >::vertex_descriptor key_type; static const_map_type index_map(const Graph& g) { return get(vertex_index, g); } static map_type index_map(Graph& g) { return get(vertex_index, g); } static value_type index(key_type k, const Graph& g) { return get(vertex_index, g, k); } }; template < typename Graph > struct edge_indexer { typedef edge_index_t index_type; typedef typename property_map< Graph, edge_index_t >::type map_type; typedef typename property_map< Graph, edge_index_t >::const_type const_map_type; typedef typename property_traits< map_type >::value_type value_type; typedef typename graph_traits< Graph >::edge_descriptor key_type; static const_map_type index_map(const Graph& g) { return get(edge_index, g); } static map_type index_map(Graph& g) { return get(edge_index, g); } static value_type index(key_type k, const Graph& g) { return get(edge_index, g, k); } }; // NOTE: The Graph parameter MUST be a model of VertexIndexGraph or // VertexEdgeGraph - whichever type Key is selecting. template < typename Graph, typename Key > struct choose_indexer { typedef typename mpl::if_< is_same< Key, typename graph_traits< Graph >::vertex_descriptor >, vertex_indexer< Graph >, edge_indexer< Graph > >::type indexer_type; typedef typename indexer_type::index_type index_type; }; } } #endif detail/read_graphviz_new.hpp 0000644 00000006743 15125521275 0012234 0 ustar 00 // Copyright 2004-9 Trustees of Indiana University // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // read_graphviz_new.hpp - // Initialize a model of the BGL's MutableGraph concept and an associated // collection of property maps using a graph expressed in the GraphViz // DOT Language. // // Based on the grammar found at: // https://web.archive.org/web/20041213234742/http://www.graphviz.org/cvs/doc/info/lang.html // // Jeremiah rewrite used grammar found at: // http://www.graphviz.org/doc/info/lang.html // and page 34 or http://www.graphviz.org/pdf/dotguide.pdf // // See documentation for this code at: // http://www.boost.org/libs/graph/doc/read_graphviz.html // // Author: Jeremiah Willcock // Ronald Garcia // #ifndef BOOST_READ_GRAPHVIZ_NEW_HPP #define BOOST_READ_GRAPHVIZ_NEW_HPP #include <boost/ref.hpp> #include <boost/property_map/dynamic_property_map.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/detail/workaround.hpp> #include <algorithm> #include <string> #include <vector> #include <set> #include <utility> #include <map> #include <iostream> #include <cstdlib> namespace boost { namespace read_graphviz_detail { typedef std::string node_name; typedef std::string subgraph_name; typedef std::map< std::string, std::string > properties; struct node_and_port { node_name name; std::string angle; // Or empty if no angle std::vector< std::string > location; // Up to two identifiers friend inline bool operator==( const node_and_port& a, const node_and_port& b) { return a.name == b.name && a.angle == b.angle && a.location == b.location; } friend inline bool operator<( const node_and_port& a, const node_and_port& b) { if (a.name != b.name) return a.name < b.name; if (a.angle != b.angle) return a.angle < b.angle; return a.location < b.location; } }; struct edge_info { node_and_port source; node_and_port target; properties props; }; struct parser_result { bool graph_is_directed; bool graph_is_strict; std::map< node_name, properties > nodes; // Global set std::vector< edge_info > edges; std::map< subgraph_name, properties > graph_props; // Root and subgraphs }; // The actual parser, from libs/graph/src/read_graphviz_new.cpp void parse_graphviz_from_string( const std::string& str, parser_result& result, bool want_directed); // Translate from those results to a graph void translate_results_to_graph( const parser_result& r, ::boost::detail::graph::mutate_graph* mg); } // namespace read_graphviz_detail namespace detail { namespace graph { BOOST_GRAPH_DECL bool read_graphviz_new( const std::string& str, boost::detail::graph::mutate_graph* mg); } // end namespace graph } // end namespace detail template < typename MutableGraph > bool read_graphviz_new(const std::string& str, MutableGraph& graph, boost::dynamic_properties& dp, std::string const& node_id = "node_id") { boost::detail::graph::mutate_graph_impl< MutableGraph > mg( graph, dp, node_id); return detail::graph::read_graphviz_new(str, &mg); } } // namespace boost #endif // BOOST_READ_GRAPHVIZ_NEW_HPP detail/is_distributed_selector.hpp 0000644 00000001527 15125521275 0013446 0 ustar 00 // Copyright 2012 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Jeremiah Willcock // Andrew Lumsdaine // Selector to determine whether a selector is distributedS (can only be true // if <boost/graph/distributed/selector.hpp> has been included) so that we can // disable various sequential-graph-only traits specializations for distributed // graphs. #ifndef BOOST_GRAPH_DETAIL_IS_DISTRIBUTED_SELECTOR_HPP #define BOOST_GRAPH_DETAIL_IS_DISTRIBUTED_SELECTOR_HPP #include <boost/mpl/bool.hpp> namespace boost { namespace detail { template < typename > struct is_distributed_selector : boost::mpl::false_ { }; } } #endif // BOOST_GRAPH_DETAIL_IS_DISTRIBUTED_SELECTOR_HPP detail/histogram_sort.hpp 0000644 00000031334 15125521275 0011574 0 ustar 00 // Copyright 2009 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Jeremiah Willcock // Andrew Lumsdaine #ifndef BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP #define BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP #include <boost/assert.hpp> namespace boost { namespace graph { namespace detail { template < typename InputIterator > size_t reserve_count_for_single_pass_helper( InputIterator, InputIterator, std::input_iterator_tag) { // Do nothing: we have no idea how much storage to reserve. return 0; } template < typename InputIterator > size_t reserve_count_for_single_pass_helper(InputIterator first, InputIterator last, std::random_access_iterator_tag) { using std::distance; typename std::iterator_traits< InputIterator >::difference_type n = distance(first, last); return (size_t)n; } template < typename InputIterator > size_t reserve_count_for_single_pass( InputIterator first, InputIterator last) { typedef typename std::iterator_traits< InputIterator >::iterator_category category; return reserve_count_for_single_pass_helper( first, last, category()); } template < typename KeyIterator, typename RowstartIterator, typename VerticesSize, typename KeyFilter, typename KeyTransform > void count_starts(KeyIterator begin, KeyIterator end, RowstartIterator starts, // Must support numverts + 1 elements VerticesSize numkeys, KeyFilter key_filter, KeyTransform key_transform) { typedef typename std::iterator_traits< RowstartIterator >::value_type EdgeIndex; // Put the degree of each vertex v into m_rowstart[v + 1] for (KeyIterator i = begin; i != end; ++i) { if (key_filter(*i)) { BOOST_ASSERT(key_transform(*i) < numkeys); ++starts[key_transform(*i) + 1]; } } // Compute the partial sum of the degrees to get the actual values // of m_rowstart EdgeIndex start_of_this_row = 0; starts[0] = start_of_this_row; for (VerticesSize i = 1; i < numkeys + 1; ++i) { start_of_this_row += starts[i]; starts[i] = start_of_this_row; } } template < typename KeyIterator, typename RowstartIterator, typename NumKeys, typename Value1InputIter, typename Value1OutputIter, typename KeyFilter, typename KeyTransform > void histogram_sort(KeyIterator key_begin, KeyIterator key_end, RowstartIterator rowstart, // Must support numkeys + 1 elements and // be precomputed NumKeys numkeys, Value1InputIter values1_begin, Value1OutputIter values1_out, KeyFilter key_filter, KeyTransform key_transform) { typedef typename std::iterator_traits< RowstartIterator >::value_type EdgeIndex; // Histogram sort the edges by their source vertices, putting the // targets into m_column. The index current_insert_positions[v] // contains the next location to insert out edges for vertex v. std::vector< EdgeIndex > current_insert_positions( rowstart, rowstart + numkeys); Value1InputIter v1i = values1_begin; for (KeyIterator i = key_begin; i != key_end; ++i, ++v1i) { if (key_filter(*i)) { NumKeys source = key_transform(*i); BOOST_ASSERT(source < numkeys); EdgeIndex insert_pos = current_insert_positions[source]; ++current_insert_positions[source]; values1_out[insert_pos] = *v1i; } } } template < typename KeyIterator, typename RowstartIterator, typename NumKeys, typename Value1InputIter, typename Value1OutputIter, typename Value2InputIter, typename Value2OutputIter, typename KeyFilter, typename KeyTransform > void histogram_sort(KeyIterator key_begin, KeyIterator key_end, RowstartIterator rowstart, // Must support numkeys + 1 elements and // be precomputed NumKeys numkeys, Value1InputIter values1_begin, Value1OutputIter values1_out, Value2InputIter values2_begin, Value2OutputIter values2_out, KeyFilter key_filter, KeyTransform key_transform) { typedef typename std::iterator_traits< RowstartIterator >::value_type EdgeIndex; // Histogram sort the edges by their source vertices, putting the // targets into m_column. The index current_insert_positions[v] // contains the next location to insert out edges for vertex v. std::vector< EdgeIndex > current_insert_positions( rowstart, rowstart + numkeys); Value1InputIter v1i = values1_begin; Value2InputIter v2i = values2_begin; for (KeyIterator i = key_begin; i != key_end; ++i, ++v1i, ++v2i) { if (key_filter(*i)) { NumKeys source = key_transform(*i); BOOST_ASSERT(source < numkeys); EdgeIndex insert_pos = current_insert_positions[source]; ++current_insert_positions[source]; values1_out[insert_pos] = *v1i; values2_out[insert_pos] = *v2i; } } } template < typename KeyIterator, typename RowstartIterator, typename NumKeys, typename Value1Iter, typename KeyTransform > void histogram_sort_inplace(KeyIterator key_begin, RowstartIterator rowstart, // Must support numkeys + 1 elements and // be precomputed NumKeys numkeys, Value1Iter values1, KeyTransform key_transform) { typedef typename std::iterator_traits< RowstartIterator >::value_type EdgeIndex; // 1. Copy m_rowstart (except last element) to get insert positions std::vector< EdgeIndex > insert_positions( rowstart, rowstart + numkeys); // 2. Swap the sources and targets into place for (size_t i = 0; i < rowstart[numkeys]; ++i) { BOOST_ASSERT(key_transform(key_begin[i]) < numkeys); // While edge i is not in the right bucket: while (!(i >= rowstart[key_transform(key_begin[i])] && i < insert_positions[key_transform(key_begin[i])])) { // Add a slot in the right bucket size_t target_pos = insert_positions[key_transform(key_begin[i])]++; BOOST_ASSERT( target_pos < rowstart[key_transform(key_begin[i]) + 1]); if (target_pos == i) continue; // Swap this edge into place using std::swap; swap(key_begin[i], key_begin[target_pos]); swap(values1[i], values1[target_pos]); } } } template < typename KeyIterator, typename RowstartIterator, typename NumKeys, typename Value1Iter, typename Value2Iter, typename KeyTransform > void histogram_sort_inplace(KeyIterator key_begin, RowstartIterator rowstart, // Must support numkeys + 1 elements and // be precomputed NumKeys numkeys, Value1Iter values1, Value2Iter values2, KeyTransform key_transform) { typedef typename std::iterator_traits< RowstartIterator >::value_type EdgeIndex; // 1. Copy m_rowstart (except last element) to get insert positions std::vector< EdgeIndex > insert_positions( rowstart, rowstart + numkeys); // 2. Swap the sources and targets into place for (size_t i = 0; i < rowstart[numkeys]; ++i) { BOOST_ASSERT(key_transform(key_begin[i]) < numkeys); // While edge i is not in the right bucket: while (!(i >= rowstart[key_transform(key_begin[i])] && i < insert_positions[key_transform(key_begin[i])])) { // Add a slot in the right bucket size_t target_pos = insert_positions[key_transform(key_begin[i])]++; BOOST_ASSERT( target_pos < rowstart[key_transform(key_begin[i]) + 1]); if (target_pos == i) continue; // Swap this edge into place using std::swap; swap(key_begin[i], key_begin[target_pos]); swap(values1[i], values1[target_pos]); swap(values2[i], values2[target_pos]); } } } template < typename InputIterator, typename VerticesSize > void split_into_separate_coords(InputIterator begin, InputIterator end, std::vector< VerticesSize >& firsts, std::vector< VerticesSize >& seconds) { firsts.clear(); seconds.clear(); size_t reserve_size = detail::reserve_count_for_single_pass(begin, end); firsts.reserve(reserve_size); seconds.reserve(reserve_size); for (; begin != end; ++begin) { std::pair< VerticesSize, VerticesSize > edge = *begin; firsts.push_back(edge.first); seconds.push_back(edge.second); } } template < typename InputIterator, typename VerticesSize, typename SourceFilter > void split_into_separate_coords_filtered(InputIterator begin, InputIterator end, std::vector< VerticesSize >& firsts, std::vector< VerticesSize >& seconds, const SourceFilter& filter) { firsts.clear(); seconds.clear(); for (; begin != end; ++begin) { std::pair< VerticesSize, VerticesSize > edge = *begin; if (filter(edge.first)) { firsts.push_back(edge.first); seconds.push_back(edge.second); } } } template < typename InputIterator, typename PropInputIterator, typename VerticesSize, typename PropType, typename SourceFilter > void split_into_separate_coords_filtered(InputIterator begin, InputIterator end, PropInputIterator props, std::vector< VerticesSize >& firsts, std::vector< VerticesSize >& seconds, std::vector< PropType >& props_out, const SourceFilter& filter) { firsts.clear(); seconds.clear(); props_out.clear(); for (; begin != end; ++begin) { std::pair< VerticesSize, VerticesSize > edge = *begin; if (filter(edge.first)) { firsts.push_back(edge.first); seconds.push_back(edge.second); props_out.push_back(*props); } ++props; } } // The versions of operator()() here can't return by reference because // the actual type passed in may not match Pair, in which case the // reference parameter is bound to a temporary that could end up // dangling after the operator returns. template < typename Pair > struct project1st { typedef typename Pair::first_type result_type; result_type operator()(const Pair& p) const { return p.first; } }; template < typename Pair > struct project2nd { typedef typename Pair::second_type result_type; result_type operator()(const Pair& p) const { return p.second; } }; } } } #endif // BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP detail/shadow_iterator.hpp 0000644 00000012571 15125521275 0011730 0 ustar 00 // (C) Copyright Jeremy Siek 2001. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_SHADOW_ITERATOR_HPP #define BOOST_SHADOW_ITERATOR_HPP #include <boost/iterator_adaptors.hpp> #include <boost/operators.hpp> namespace boost { namespace detail { template < class A, class B, class D > class shadow_proxy : boost::operators< shadow_proxy< A, B, D > > { typedef shadow_proxy self; public: inline shadow_proxy(A aa, B bb) : a(aa), b(bb) {} inline shadow_proxy(const self& x) : a(x.a), b(x.b) {} template < class Self > inline shadow_proxy(Self x) : a(x.a), b(x.b) {} inline self& operator=(const self& x) { a = x.a; b = x.b; return *this; } inline self& operator++() { ++a; return *this; } inline self& operator--() { --a; return *this; } inline self& operator+=(const self& x) { a += x.a; return *this; } inline self& operator-=(const self& x) { a -= x.a; return *this; } inline self& operator*=(const self& x) { a *= x.a; return *this; } inline self& operator/=(const self& x) { a /= x.a; return *this; } inline self& operator%=(const self& x) { return *this; } // JGS inline self& operator&=(const self& x) { return *this; } // JGS inline self& operator|=(const self& x) { return *this; } // JGS inline self& operator^=(const self& x) { return *this; } // JGS inline friend D operator-(const self& x, const self& y) { return x.a - y.a; } inline bool operator==(const self& x) const { return a == x.a; } inline bool operator<(const self& x) const { return a < x.a; } // protected: A a; B b; }; struct shadow_iterator_policies { template < typename iter_pair > void initialize(const iter_pair&) {} template < typename Iter > typename Iter::reference dereference(const Iter& i) const { typedef typename Iter::reference R; return R(*i.base().first, *i.base().second); } template < typename Iter > bool equal(const Iter& p1, const Iter& p2) const { return p1.base().first == p2.base().first; } template < typename Iter > void increment(Iter& i) { ++i.base().first; ++i.base().second; } template < typename Iter > void decrement(Iter& i) { --i.base().first; --i.base().second; } template < typename Iter > bool less(const Iter& x, const Iter& y) const { return x.base().first < y.base().first; } template < typename Iter > typename Iter::difference_type distance( const Iter& x, const Iter& y) const { return y.base().first - x.base().first; } template < typename D, typename Iter > void advance(Iter& p, D n) { p.base().first += n; p.base().second += n; } }; } // namespace detail template < typename IterA, typename IterB > struct shadow_iterator_generator { // To use the iterator_adaptor we can't derive from // random_access_iterator because we don't have a real reference. // However, we want the STL algorithms to treat the shadow // iterator like a random access iterator. struct shadow_iterator_tag : public std::input_iterator_tag { operator std::random_access_iterator_tag() { return std::random_access_iterator_tag(); }; }; typedef typename std::iterator_traits< IterA >::value_type Aval; typedef typename std::iterator_traits< IterB >::value_type Bval; typedef typename std::iterator_traits< IterA >::reference Aref; typedef typename std::iterator_traits< IterB >::reference Bref; typedef typename std::iterator_traits< IterA >::difference_type D; typedef detail::shadow_proxy< Aval, Bval, Aval > V; typedef detail::shadow_proxy< Aref, Bref, Aval > R; typedef iterator_adaptor< std::pair< IterA, IterB >, detail::shadow_iterator_policies, V, R, V*, shadow_iterator_tag, D > type; }; // short cut for creating a shadow iterator template < class IterA, class IterB > inline typename shadow_iterator_generator< IterA, IterB >::type make_shadow_iter(IterA a, IterB b) { typedef typename shadow_iterator_generator< IterA, IterB >::type Iter; return Iter(std::make_pair(a, b)); } template < class Cmp > struct shadow_cmp { inline shadow_cmp(const Cmp& c) : cmp(c) {} template < class ShadowProxy1, class ShadowProxy2 > inline bool operator()(const ShadowProxy1& x, const ShadowProxy2& y) const { return cmp(x.a, y.a); } Cmp cmp; }; } // namespace boost namespace std { template < class A1, class B1, class D1, class A2, class B2, class D2 > void swap(boost::detail::shadow_proxy< A1&, B1&, D1 > x, boost::detail::shadow_proxy< A2&, B2&, D2 > y) { std::swap(x.a, y.a); std::swap(x.b, y.b); } } #endif // BOOST_SHADOW_ITERATOR_HPP detail/edge.hpp 0000644 00000006736 15125521275 0007444 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_DETAIL_EDGE_HPP #define BOOST_GRAPH_DETAIL_EDGE_HPP #include <iosfwd> #include <boost/functional/hash.hpp> namespace boost { namespace detail { template < typename Directed, typename Vertex > struct edge_base { inline edge_base() {} inline edge_base(Vertex s, Vertex d) : m_source(s), m_target(d) {} Vertex m_source; Vertex m_target; }; template < typename Directed, typename Vertex > class edge_desc_impl : public edge_base< Directed, Vertex > { typedef edge_desc_impl self; typedef edge_base< Directed, Vertex > Base; public: typedef void property_type; inline edge_desc_impl() : m_eproperty(0) {} inline edge_desc_impl(Vertex s, Vertex d, const property_type* eplug) : Base(s, d), m_eproperty(const_cast< property_type* >(eplug)) { } property_type* get_property() { return m_eproperty; } const property_type* get_property() const { return m_eproperty; } // protected: property_type* m_eproperty; }; template < class D, class V > inline bool operator==(const detail::edge_desc_impl< D, V >& a, const detail::edge_desc_impl< D, V >& b) { return a.get_property() == b.get_property(); } template < class D, class V > inline bool operator!=(const detail::edge_desc_impl< D, V >& a, const detail::edge_desc_impl< D, V >& b) { return !(a.get_property() == b.get_property()); } // Order edges according to the address of their property object template < class D, class V > inline bool operator<(const detail::edge_desc_impl< D, V >& a, const detail::edge_desc_impl< D, V >& b) { return a.get_property() < b.get_property(); } template < class D, class V > inline bool operator<=(const detail::edge_desc_impl< D, V >& a, const detail::edge_desc_impl< D, V >& b) { return a.get_property() <= b.get_property(); } template < class D, class V > inline bool operator>(const detail::edge_desc_impl< D, V >& a, const detail::edge_desc_impl< D, V >& b) { return a.get_property() > b.get_property(); } template < class D, class V > inline bool operator>=(const detail::edge_desc_impl< D, V >& a, const detail::edge_desc_impl< D, V >& b) { return a.get_property() >= b.get_property(); } } // namespace detail } // namespace boost namespace std { template < class Char, class Traits, class D, class V > std::basic_ostream< Char, Traits >& operator<<( std::basic_ostream< Char, Traits >& os, const boost::detail::edge_desc_impl< D, V >& e) { return os << "(" << e.m_source << "," << e.m_target << ")"; } } // Boost's functional/hash namespace boost { template < typename D, typename V > struct hash< boost::detail::edge_desc_impl< D, V > > { std::size_t operator()(const boost::detail::edge_desc_impl< D, V >& x) const { return hash_value(x.get_property()); } }; } #endif // BOOST_GRAPH_DETAIL_DETAIL_EDGE_HPP detail/connected_components.hpp 0000644 00000015074 15125521275 0012742 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_DETAIL_CONNECTED_COMPONENTS_HPP #define BOOST_GRAPH_DETAIL_CONNECTED_COMPONENTS_HPP #if defined(__sgi) && !defined(__GNUC__) #pragma set woff 1234 #endif #include <boost/operators.hpp> namespace boost { namespace detail { //========================================================================= // Implementation details of connected_components // This is used both in the connected_components algorithm and in // the kosaraju strong components algorithm during the second DFS // traversal. template < class ComponentsPA, class DFSVisitor > class components_recorder : public DFSVisitor { typedef typename property_traits< ComponentsPA >::value_type comp_type; public: components_recorder(ComponentsPA c, comp_type& c_count, DFSVisitor v) : DFSVisitor(v), m_component(c), m_count(c_count) { } template < class Vertex, class Graph > void start_vertex(Vertex u, Graph& g) { ++m_count; DFSVisitor::start_vertex(u, g); } template < class Vertex, class Graph > void discover_vertex(Vertex u, Graph& g) { put(m_component, u, m_count); DFSVisitor::discover_vertex(u, g); } protected: ComponentsPA m_component; comp_type& m_count; }; template < class DiscoverTimeMap, class FinishTimeMap, class TimeT, class DFSVisitor > class time_recorder : public DFSVisitor { public: time_recorder( DiscoverTimeMap d, FinishTimeMap f, TimeT& t, DFSVisitor v) : DFSVisitor(v), m_discover_time(d), m_finish_time(f), m_t(t) { } template < class Vertex, class Graph > void discover_vertex(Vertex u, Graph& g) { put(m_discover_time, u, ++m_t); DFSVisitor::discover_vertex(u, g); } template < class Vertex, class Graph > void finish_vertex(Vertex u, Graph& g) { put(m_finish_time, u, ++m_t); DFSVisitor::discover_vertex(u, g); } protected: DiscoverTimeMap m_discover_time; FinishTimeMap m_finish_time; TimeT m_t; }; template < class DiscoverTimeMap, class FinishTimeMap, class TimeT, class DFSVisitor > time_recorder< DiscoverTimeMap, FinishTimeMap, TimeT, DFSVisitor > record_times(DiscoverTimeMap d, FinishTimeMap f, TimeT& t, DFSVisitor vis) { return time_recorder< DiscoverTimeMap, FinishTimeMap, TimeT, DFSVisitor >(d, f, t, vis); } //========================================================================= // Implementation detail of dynamic_components //------------------------------------------------------------------------- // Helper functions for the component_index class // Record the representative vertices in the header array. // Representative vertices now point to the component number. template < class Parent, class OutputIterator, class Integer > inline void build_components_header( Parent p, OutputIterator header, Integer num_nodes) { Parent component = p; Integer component_num = 0; for (Integer v = 0; v != num_nodes; ++v) if (p[v] == v) { *header++ = v; component[v] = component_num++; } } // Pushes x onto the front of the list. The list is represented in // an array. template < class Next, class T, class V > inline void push_front(Next next, T& head, V x) { T tmp = head; head = x; next[x] = tmp; } // Create a linked list of the vertices in each component // by reusing the representative array. template < class Parent1, class Parent2, class Integer > void link_components(Parent1 component, Parent2 header, Integer num_nodes, Integer num_components) { // Make the non-representative vertices point to their component Parent1 representative = component; for (Integer v = 0; v != num_nodes; ++v) if (component[v] >= num_components || header[component[v]] != v) component[v] = component[representative[v]]; // initialize the "head" of the lists to "NULL" std::fill_n(header, num_components, num_nodes); // Add each vertex to the linked list for its component Parent1 next = component; for (Integer k = 0; k != num_nodes; ++k) push_front(next, header[component[k]], k); } template < class IndexContainer, class HeaderContainer > void construct_component_index( IndexContainer& index, HeaderContainer& header) { build_components_header(index.begin(), std::back_inserter(header), index.end() - index.begin()); link_components(index.begin(), header.begin(), index.end() - index.begin(), header.end() - header.begin()); } template < class IndexIterator, class Integer, class Distance > class component_iterator : boost::forward_iterator_helper< component_iterator< IndexIterator, Integer, Distance >, Integer, Distance, Integer*, Integer& > { public: typedef component_iterator self; IndexIterator next; Integer node; typedef std::forward_iterator_tag iterator_category; typedef Integer value_type; typedef Integer& reference; typedef Integer* pointer; typedef Distance difference_type; component_iterator() {} component_iterator(IndexIterator x, Integer i) : next(x), node(i) {} Integer operator*() const { return node; } self& operator++() { node = next[node]; return *this; } }; template < class IndexIterator, class Integer, class Distance > inline bool operator==( const component_iterator< IndexIterator, Integer, Distance >& x, const component_iterator< IndexIterator, Integer, Distance >& y) { return x.node == y.node; } } // namespace detail } // namespace detail #if defined(__sgi) && !defined(__GNUC__) #pragma reset woff 1234 #endif #endif detail/adjacency_list.hpp 0000644 00000317152 15125521275 0011511 0 ustar 00 // -*- c++ -*- //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Copyright 2010 Thomas Claveirole // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Thomas Claveirole // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_DETAIL_ADJACENCY_LIST_HPP #define BOOST_GRAPH_DETAIL_ADJACENCY_LIST_HPP #include <map> // for vertex_map in copy_impl #include <boost/config.hpp> #include <boost/detail/workaround.hpp> #include <boost/operators.hpp> #include <boost/property_map/property_map.hpp> #include <boost/pending/container_traits.hpp> #include <boost/range/irange.hpp> #include <boost/graph/graph_traits.hpp> #include <memory> #include <algorithm> #include <boost/limits.hpp> #include <boost/iterator/iterator_adaptor.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/not.hpp> #include <boost/mpl/and.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/pending/container_traits.hpp> #include <boost/graph/detail/adj_list_edge_iterator.hpp> #include <boost/graph/properties.hpp> #include <boost/pending/property.hpp> #include <boost/graph/adjacency_iterator.hpp> #include <boost/static_assert.hpp> #include <boost/assert.hpp> #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES #define BOOST_GRAPH_MOVE_IF_POSSIBLE(x) (x) #else #include <utility> #define BOOST_GRAPH_MOVE_IF_POSSIBLE(x) (std::move((x))) #endif /* Outline for this file: out_edge_iterator and in_edge_iterator implementation edge_iterator for undirected graph stored edge types (these object live in the out-edge/in-edge lists) directed edges helper class directed graph helper class undirected graph helper class bidirectional graph helper class bidirectional graph helper class (without edge properties) bidirectional graph helper class (with edge properties) adjacency_list helper class adj_list_impl class vec_adj_list_impl class adj_list_gen class vertex property map edge property map Note: it would be nice to merge some of the undirected and bidirectional code... it is awful similar. */ namespace boost { namespace detail { template < typename DirectedS > struct directed_category_traits { typedef directed_tag directed_category; }; template <> struct directed_category_traits< directedS > { typedef directed_tag directed_category; }; template <> struct directed_category_traits< undirectedS > { typedef undirected_tag directed_category; }; template <> struct directed_category_traits< bidirectionalS > { typedef bidirectional_tag directed_category; }; template < class Vertex > struct target_is { target_is(const Vertex& v) : m_target(v) {} template < class StoredEdge > bool operator()(const StoredEdge& e) const { return e.get_target() == m_target; } Vertex m_target; }; // O(E/V) template < class EdgeList, class vertex_descriptor > void erase_from_incidence_list( EdgeList& el, vertex_descriptor v, allow_parallel_edge_tag) { boost::graph_detail::erase_if( el, detail::target_is< vertex_descriptor >(v)); } // O(log(E/V)) template < class EdgeList, class vertex_descriptor > void erase_from_incidence_list( EdgeList& el, vertex_descriptor v, disallow_parallel_edge_tag) { typedef typename EdgeList::value_type StoredEdge; el.erase(StoredEdge(v)); } //========================================================================= // Out-Edge and In-Edge Iterator Implementation template < class BaseIter, class VertexDescriptor, class EdgeDescriptor, class Difference > struct out_edge_iter : iterator_adaptor< out_edge_iter< BaseIter, VertexDescriptor, EdgeDescriptor, Difference >, BaseIter, EdgeDescriptor, use_default, EdgeDescriptor, Difference > { typedef iterator_adaptor< out_edge_iter< BaseIter, VertexDescriptor, EdgeDescriptor, Difference >, BaseIter, EdgeDescriptor, use_default, EdgeDescriptor, Difference > super_t; inline out_edge_iter() {} inline out_edge_iter(const BaseIter& i, const VertexDescriptor& src) : super_t(i), m_src(src) { } inline EdgeDescriptor dereference() const { return EdgeDescriptor(m_src, (*this->base()).get_target(), &(*this->base()).get_property()); } VertexDescriptor m_src; }; template < class BaseIter, class VertexDescriptor, class EdgeDescriptor, class Difference > struct in_edge_iter : iterator_adaptor< in_edge_iter< BaseIter, VertexDescriptor, EdgeDescriptor, Difference >, BaseIter, EdgeDescriptor, use_default, EdgeDescriptor, Difference > { typedef iterator_adaptor< in_edge_iter< BaseIter, VertexDescriptor, EdgeDescriptor, Difference >, BaseIter, EdgeDescriptor, use_default, EdgeDescriptor, Difference > super_t; inline in_edge_iter() {} inline in_edge_iter(const BaseIter& i, const VertexDescriptor& src) : super_t(i), m_src(src) { } inline EdgeDescriptor dereference() const { return EdgeDescriptor((*this->base()).get_target(), m_src, &this->base()->get_property()); } VertexDescriptor m_src; }; //========================================================================= // Undirected Edge Iterator Implementation template < class EdgeIter, class EdgeDescriptor, class Difference > struct undirected_edge_iter : iterator_adaptor< undirected_edge_iter< EdgeIter, EdgeDescriptor, Difference >, EdgeIter, EdgeDescriptor, use_default, EdgeDescriptor, Difference > { typedef iterator_adaptor< undirected_edge_iter< EdgeIter, EdgeDescriptor, Difference >, EdgeIter, EdgeDescriptor, use_default, EdgeDescriptor, Difference > super_t; undirected_edge_iter() {} explicit undirected_edge_iter(EdgeIter i) : super_t(i) {} inline EdgeDescriptor dereference() const { return EdgeDescriptor((*this->base()).m_source, (*this->base()).m_target, &this->base()->get_property()); } }; //========================================================================= // Edge Storage Types (stored in the out-edge/in-edge lists) template < class Vertex > class stored_edge : public boost::equality_comparable1< stored_edge< Vertex >, boost::less_than_comparable1< stored_edge< Vertex > > > { public: typedef no_property property_type; inline stored_edge() {} inline stored_edge(Vertex target, const no_property& = no_property()) : m_target(target) { } inline Vertex& get_target() const { return m_target; } inline const no_property& get_property() const { return s_prop; } inline bool operator==(const stored_edge& x) const { return m_target == x.get_target(); } inline bool operator<(const stored_edge& x) const { return m_target < x.get_target(); } // protected: need to add hash<> as a friend static no_property s_prop; // Sometimes target not used as key in the set, and in that case // it is ok to change the target. mutable Vertex m_target; }; template < class Vertex > no_property stored_edge< Vertex >::s_prop; #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) \ || defined(BOOST_NO_CXX11_SMART_PTR) template < class Vertex, class Property > class stored_edge_property : public stored_edge< Vertex > { typedef stored_edge_property self; typedef stored_edge< Vertex > Base; public: typedef Property property_type; inline stored_edge_property() {} inline stored_edge_property( Vertex target, const Property& p = Property()) : stored_edge< Vertex >(target), m_property(new Property(p)) { } stored_edge_property(const self& x) : Base(static_cast< Base const& >(x)) , m_property(const_cast< self& >(x).m_property) { } self& operator=(const self& x) { // NOTE: avoid 'Base::operator=(x);' broken on SGI MIPSpro (bug // 55771 of Mozilla). static_cast< Base& >(*this) = static_cast< Base const& >(x); m_property = const_cast< self& >(x).m_property; return *this; } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) // NOTE Don't rely on default operators, their behavior is broken on // several compilers (GCC 4.6). stored_edge_property(self&& x) : Base(static_cast< Base&& >(x)), m_property(std::move(x.m_property)) { } self& operator=(self&& x) { // NOTE: avoid 'Base::operator=(x);' broken on SGI MIPSpro (bug // 55771 of Mozilla). static_cast< Base& >(*this) = static_cast< Base&& >(x); m_property = std::move(x.m_property); return *this; } #endif inline Property& get_property() { return *m_property; } inline const Property& get_property() const { return *m_property; } protected: // Holding the property by-value causes edge-descriptor // invalidation for add_edge() with EdgeList=vecS. Instead we // hold a pointer to the property. std::auto_ptr is not // a perfect fit for the job, but it is darn close. #ifdef BOOST_NO_AUTO_PTR std::unique_ptr< Property > m_property; #else std::auto_ptr< Property > m_property; #endif }; #else template < class Vertex, class Property > class stored_edge_property : public stored_edge< Vertex > { typedef stored_edge_property self; typedef stored_edge< Vertex > Base; public: typedef Property property_type; inline stored_edge_property() {} inline stored_edge_property( Vertex target, const Property& p = Property()) : stored_edge< Vertex >(target), m_property(new Property(p)) { } stored_edge_property(self&& x) : Base(static_cast< Base&& >(x)), m_property(std::move(x.m_property)) { } stored_edge_property(self const& x) : Base(static_cast< Base const& >(x)) , m_property(std::move(const_cast< self& >(x).m_property)) { } self& operator=(self&& x) { // NOTE: avoid 'Base::operator=(x);' broken on SGI MIPSpro (bug // 55771 of Mozilla). static_cast< Base& >(*this) = static_cast< Base&& >(x); m_property = std::move(x.m_property); return *this; } self& operator=(self const& x) { // NOTE: avoid 'Base::operator=(x);' broken on SGI MIPSpro (bug // 55771 of Mozilla). static_cast< Base& >(*this) = static_cast< Base const& >(x); m_property = std::move(const_cast< self& >(x).m_property); return *this; } inline Property& get_property() { return *m_property; } inline const Property& get_property() const { return *m_property; } protected: std::unique_ptr< Property > m_property; }; #endif template < class Vertex, class Iter, class Property > class stored_edge_iter : public stored_edge< Vertex > { public: typedef Property property_type; inline stored_edge_iter() {} inline stored_edge_iter(Vertex v) : stored_edge< Vertex >(v) {} inline stored_edge_iter(Vertex v, Iter i, void* = 0) : stored_edge< Vertex >(v), m_iter(i) { } inline Property& get_property() { return m_iter->get_property(); } inline const Property& get_property() const { return m_iter->get_property(); } inline Iter get_iter() const { return m_iter; } protected: Iter m_iter; }; // For when the EdgeList is a std::vector. // Want to make the iterator stable, so use an offset // instead of an iterator into a std::vector template < class Vertex, class EdgeVec, class Property > class stored_ra_edge_iter : public stored_edge< Vertex > { typedef typename EdgeVec::iterator Iter; public: typedef Property property_type; inline stored_ra_edge_iter() {} inline explicit stored_ra_edge_iter( Vertex v) // Only used for comparisons : stored_edge< Vertex >(v), m_i(0), m_vec(0) { } inline stored_ra_edge_iter(Vertex v, Iter i, EdgeVec* edge_vec) : stored_edge< Vertex >(v), m_i(i - edge_vec->begin()), m_vec(edge_vec) { } inline Property& get_property() { BOOST_ASSERT((m_vec != 0)); return (*m_vec)[m_i].get_property(); } inline const Property& get_property() const { BOOST_ASSERT((m_vec != 0)); return (*m_vec)[m_i].get_property(); } inline Iter get_iter() const { BOOST_ASSERT((m_vec != 0)); return m_vec->begin() + m_i; } protected: std::size_t m_i; EdgeVec* m_vec; }; } // namespace detail template < class Tag, class Vertex, class Property > const typename property_value< Property, Tag >::type& get( Tag property_tag, const detail::stored_edge_property< Vertex, Property >& e) { return get_property_value(e.get_property(), property_tag); } template < class Tag, class Vertex, class Iter, class Property > const typename property_value< Property, Tag >::type& get(Tag property_tag, const detail::stored_edge_iter< Vertex, Iter, Property >& e) { return get_property_value(e.get_property(), property_tag); } template < class Tag, class Vertex, class EdgeVec, class Property > const typename property_value< Property, Tag >::type& get(Tag property_tag, const detail::stored_ra_edge_iter< Vertex, EdgeVec, Property >& e) { return get_property_value(e.get_property(), property_tag); } //========================================================================= // Directed Edges Helper Class namespace detail { // O(E/V) template < class edge_descriptor, class EdgeList, class StoredProperty > inline void remove_directed_edge_dispatch( edge_descriptor, EdgeList& el, StoredProperty& p) { for (typename EdgeList::iterator i = el.begin(); i != el.end(); ++i) if (&(*i).get_property() == &p) { el.erase(i); return; } } template < class incidence_iterator, class EdgeList, class Predicate > inline void remove_directed_edge_if_dispatch(incidence_iterator first, incidence_iterator last, EdgeList& el, Predicate pred, boost::allow_parallel_edge_tag) { // remove_if while (first != last && !pred(*first)) ++first; incidence_iterator i = first; if (first != last) for (++i; i != last; ++i) if (!pred(*i)) { *first.base() = BOOST_GRAPH_MOVE_IF_POSSIBLE(*i.base()); ++first; } el.erase(first.base(), el.end()); } template < class incidence_iterator, class EdgeList, class Predicate > inline void remove_directed_edge_if_dispatch(incidence_iterator first, incidence_iterator last, EdgeList& el, Predicate pred, boost::disallow_parallel_edge_tag) { for (incidence_iterator next = first; first != last; first = next) { ++next; if (pred(*first)) el.erase(first.base()); } } template < class PropT, class Graph, class incidence_iterator, class EdgeList, class Predicate > inline void undirected_remove_out_edge_if_dispatch(Graph& g, incidence_iterator first, incidence_iterator last, EdgeList& el, Predicate pred, boost::allow_parallel_edge_tag) { typedef typename Graph::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); // remove_if while (first != last && !pred(*first)) ++first; incidence_iterator i = first; bool self_loop_removed = false; if (first != last) for (; i != last; ++i) { if (self_loop_removed) { /* With self loops, the descriptor will show up * twice. The first time it will be removed, and now it * will be skipped. */ self_loop_removed = false; } else if (!pred(*i)) { *first.base() = BOOST_GRAPH_MOVE_IF_POSSIBLE(*i.base()); ++first; } else { if (source(*i, g) == target(*i, g)) self_loop_removed = true; else { // Remove the edge from the target detail::remove_directed_edge_dispatch(*i, g.out_edge_list(target(*i, g)), *(PropT*)(*i).get_property()); } // Erase the edge property g.m_edges.erase((*i.base()).get_iter()); } } el.erase(first.base(), el.end()); } template < class PropT, class Graph, class incidence_iterator, class EdgeList, class Predicate > inline void undirected_remove_out_edge_if_dispatch(Graph& g, incidence_iterator first, incidence_iterator last, EdgeList& el, Predicate pred, boost::disallow_parallel_edge_tag) { typedef typename Graph::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); for (incidence_iterator next = first; first != last; first = next) { ++next; if (pred(*first)) { if (source(*first, g) != target(*first, g)) { // Remove the edge from the target detail::remove_directed_edge_dispatch(*first, g.out_edge_list(target(*first, g)), *(PropT*)(*first).get_property()); } // Erase the edge property g.m_edges.erase((*first.base()).get_iter()); // Erase the edge in the source el.erase(first.base()); } } } // O(E/V) template < class edge_descriptor, class EdgeList, class StoredProperty > inline void remove_directed_edge_dispatch( edge_descriptor e, EdgeList& el, no_property&) { for (typename EdgeList::iterator i = el.begin(); i != el.end(); ++i) if ((*i).get_target() == e.m_target) { el.erase(i); return; } } } // namespace detail template < class Config > struct directed_edges_helper { // Placement of these overloaded remove_edge() functions // inside the class avoids a VC++ bug. // O(E/V) inline void remove_edge(typename Config::edge_descriptor e) { typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(*this); typename Config::OutEdgeList& el = g.out_edge_list(source(e, g)); typedef typename Config::OutEdgeList::value_type::property_type PType; detail::remove_directed_edge_dispatch(e, el, *(PType*)e.get_property()); } // O(1) inline void remove_edge(typename Config::out_edge_iterator iter) { typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(*this); typename Config::edge_descriptor e = *iter; typename Config::OutEdgeList& el = g.out_edge_list(source(e, g)); el.erase(iter.base()); } }; // O(1) template < class Config > inline std::pair< typename Config::edge_iterator, typename Config::edge_iterator > edges(const directed_edges_helper< Config >& g_) { typedef typename Config::graph_type graph_type; typedef typename Config::edge_iterator edge_iterator; const graph_type& cg = static_cast< const graph_type& >(g_); graph_type& g = const_cast< graph_type& >(cg); return std::make_pair(edge_iterator(g.vertex_set().begin(), g.vertex_set().begin(), g.vertex_set().end(), g), edge_iterator(g.vertex_set().begin(), g.vertex_set().end(), g.vertex_set().end(), g)); } //========================================================================= // Directed Graph Helper Class struct adj_list_dir_traversal_tag : public virtual vertex_list_graph_tag, public virtual incidence_graph_tag, public virtual adjacency_graph_tag, public virtual edge_list_graph_tag { }; template < class Config > struct directed_graph_helper : public directed_edges_helper< Config > { typedef typename Config::edge_descriptor edge_descriptor; typedef adj_list_dir_traversal_tag traversal_category; }; // O(E/V) template < class Config > inline void remove_edge(typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, directed_graph_helper< Config >& g_) { typedef typename Config::graph_type graph_type; typedef typename Config::edge_parallel_category Cat; graph_type& g = static_cast< graph_type& >(g_); detail::erase_from_incidence_list(g.out_edge_list(u), v, Cat()); } template < class Config, class Predicate > inline void remove_out_edge_if(typename Config::vertex_descriptor u, Predicate pred, directed_graph_helper< Config >& g_) { typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(g_); typename Config::out_edge_iterator first, last; boost::tie(first, last) = out_edges(u, g); typedef typename Config::edge_parallel_category edge_parallel_category; detail::remove_directed_edge_if_dispatch( first, last, g.out_edge_list(u), pred, edge_parallel_category()); } template < class Config, class Predicate > inline void remove_edge_if(Predicate pred, directed_graph_helper< Config >& g_) { typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(g_); typename Config::vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) remove_out_edge_if(*vi, pred, g); } template < class EdgeOrIter, class Config > inline void remove_edge( EdgeOrIter e_or_iter, directed_graph_helper< Config >& g_) { g_.remove_edge(e_or_iter); } // O(V + E) for allow_parallel_edges // O(V * log(E/V)) for disallow_parallel_edges template < class Config > inline void clear_vertex( typename Config::vertex_descriptor u, directed_graph_helper< Config >& g_) { typedef typename Config::graph_type graph_type; typedef typename Config::edge_parallel_category Cat; graph_type& g = static_cast< graph_type& >(g_); typename Config::vertex_iterator vi, viend; for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi) detail::erase_from_incidence_list(g.out_edge_list(*vi), u, Cat()); g.out_edge_list(u).clear(); // clear() should be a req of Sequence and AssociativeContainer, // or maybe just Container } template < class Config > inline void clear_out_edges( typename Config::vertex_descriptor u, directed_graph_helper< Config >& g_) { typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(g_); g.out_edge_list(u).clear(); // clear() should be a req of Sequence and AssociativeContainer, // or maybe just Container } // O(V), could do better... template < class Config > inline typename Config::edges_size_type num_edges( const directed_graph_helper< Config >& g_) { typedef typename Config::graph_type graph_type; const graph_type& g = static_cast< const graph_type& >(g_); typename Config::edges_size_type num_e = 0; typename Config::vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) num_e += out_degree(*vi, g); return num_e; } // O(1) for allow_parallel_edge_tag // O(log(E/V)) for disallow_parallel_edge_tag template < class Config > inline std::pair< typename directed_graph_helper< Config >::edge_descriptor, bool > add_edge(typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, const typename Config::edge_property_type& p, directed_graph_helper< Config >& g_) { typedef typename Config::edge_descriptor edge_descriptor; typedef typename Config::graph_type graph_type; typedef typename Config::StoredEdge StoredEdge; graph_type& g = static_cast< graph_type& >(g_); typename Config::OutEdgeList::iterator i; bool inserted; boost::tie(i, inserted) = boost::graph_detail::push(g.out_edge_list(u), StoredEdge(v, p)); return std::make_pair( edge_descriptor(u, v, &(*i).get_property()), inserted); } // Did not use default argument here because that // causes Visual C++ to get confused. template < class Config > inline std::pair< typename Config::edge_descriptor, bool > add_edge( typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, directed_graph_helper< Config >& g_) { typename Config::edge_property_type p; return add_edge(u, v, p, g_); } //========================================================================= // Undirected Graph Helper Class template < class Config > struct undirected_graph_helper; struct undir_adj_list_traversal_tag : public virtual vertex_list_graph_tag, public virtual incidence_graph_tag, public virtual adjacency_graph_tag, public virtual edge_list_graph_tag, public virtual bidirectional_graph_tag { }; namespace detail { // using class with specialization for dispatch is a VC++ workaround. template < class StoredProperty > struct remove_undirected_edge_dispatch { // O(E/V) template < class edge_descriptor, class Config > static void apply(edge_descriptor e, undirected_graph_helper< Config >& g_, StoredProperty& p) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(g_); typename Config::OutEdgeList& out_el = g.out_edge_list(source(e, g)); typename Config::OutEdgeList::iterator out_i = out_el.begin(); typename Config::EdgeIter edge_iter_to_erase; for (; out_i != out_el.end(); ++out_i) if (&(*out_i).get_property() == &p) { edge_iter_to_erase = (*out_i).get_iter(); out_el.erase(out_i); break; } typename Config::OutEdgeList& in_el = g.out_edge_list(target(e, g)); typename Config::OutEdgeList::iterator in_i = in_el.begin(); for (; in_i != in_el.end(); ++in_i) if (&(*in_i).get_property() == &p) { in_el.erase(in_i); break; } g.m_edges.erase(edge_iter_to_erase); } }; template <> struct remove_undirected_edge_dispatch< no_property > { // O(E/V) template < class edge_descriptor, class Config > static void apply(edge_descriptor e, undirected_graph_helper< Config >& g_, no_property&) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(g_); no_property* p = (no_property*)e.get_property(); typename Config::OutEdgeList& out_el = g.out_edge_list(source(e, g)); typename Config::OutEdgeList::iterator out_i = out_el.begin(); typename Config::EdgeIter edge_iter_to_erase; for (; out_i != out_el.end(); ++out_i) if (&(*out_i).get_property() == p) { edge_iter_to_erase = (*out_i).get_iter(); out_el.erase(out_i); break; } typename Config::OutEdgeList& in_el = g.out_edge_list(target(e, g)); typename Config::OutEdgeList::iterator in_i = in_el.begin(); for (; in_i != in_el.end(); ++in_i) if (&(*in_i).get_property() == p) { in_el.erase(in_i); break; } g.m_edges.erase(edge_iter_to_erase); } }; // O(E/V) template < class Graph, class EdgeList, class Vertex > inline void remove_edge_and_property( Graph& g, EdgeList& el, Vertex v, boost::allow_parallel_edge_tag cat) { typedef typename Graph::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typename EdgeList::iterator i = el.begin(), end = el.end(); for (; i != end; ++i) { if ((*i).get_target() == v) { // NOTE: Wihtout this skip, this loop will double-delete // properties of loop edges. This solution is based on the // observation that the incidence edges of a vertex with a loop // are adjacent in the out edge list. This *may* actually hold // for multisets also. bool skip = (boost::next(i) != end && i->get_iter() == boost::next(i)->get_iter()); g.m_edges.erase((*i).get_iter()); if (skip) ++i; } } detail::erase_from_incidence_list(el, v, cat); } // O(log(E/V)) template < class Graph, class EdgeList, class Vertex > inline void remove_edge_and_property( Graph& g, EdgeList& el, Vertex v, boost::disallow_parallel_edge_tag) { typedef typename Graph::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename EdgeList::value_type StoredEdge; typename EdgeList::iterator i = el.find(StoredEdge(v)), end = el.end(); if (i != end) { g.m_edges.erase((*i).get_iter()); el.erase(i); } } } // namespace detail template < class Vertex, class EdgeProperty > struct list_edge // short name due to VC++ truncation and linker problems : public boost::detail::edge_base< boost::undirected_tag, Vertex > { typedef EdgeProperty property_type; typedef boost::detail::edge_base< boost::undirected_tag, Vertex > Base; list_edge(Vertex u, Vertex v, const EdgeProperty& p = EdgeProperty()) : Base(u, v), m_property(p) { } EdgeProperty& get_property() { return m_property; } const EdgeProperty& get_property() const { return m_property; } // the following methods should never be used, but are needed // to make SGI MIPSpro C++ happy list_edge() {} bool operator==(const list_edge&) const { return false; } bool operator<(const list_edge&) const { return false; } EdgeProperty m_property; }; template < class Config > struct undirected_graph_helper { typedef undir_adj_list_traversal_tag traversal_category; // Placement of these overloaded remove_edge() functions // inside the class avoids a VC++ bug. // O(E/V) inline void remove_edge(typename Config::edge_descriptor e) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::OutEdgeList::value_type::property_type PType; detail::remove_undirected_edge_dispatch< PType >::apply( e, *this, *(PType*)e.get_property()); } // O(E/V) inline void remove_edge(typename Config::out_edge_iterator iter) { this->remove_edge(*iter); } }; // Had to make these non-members to avoid accidental instantiation // on SGI MIPSpro C++ template < class C > inline typename C::InEdgeList& in_edge_list( undirected_graph_helper< C >&, typename C::vertex_descriptor v) { typename C::stored_vertex* sv = (typename C::stored_vertex*)v; return sv->m_out_edges; } template < class C > inline const typename C::InEdgeList& in_edge_list( const undirected_graph_helper< C >&, typename C::vertex_descriptor v) { typename C::stored_vertex* sv = (typename C::stored_vertex*)v; return sv->m_out_edges; } // O(E/V) template < class EdgeOrIter, class Config > inline void remove_edge(EdgeOrIter e, undirected_graph_helper< Config >& g_) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); g_.remove_edge(e); } // O(E/V) or O(log(E/V)) template < class Config > void remove_edge(typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, undirected_graph_helper< Config >& g_) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(g_); typedef typename Config::edge_parallel_category Cat; detail::remove_edge_and_property(g, g.out_edge_list(u), v, Cat()); detail::erase_from_incidence_list(g.out_edge_list(v), u, Cat()); } template < class Config, class Predicate > void remove_out_edge_if(typename Config::vertex_descriptor u, Predicate pred, undirected_graph_helper< Config >& g_) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::graph_type graph_type; typedef typename Config::OutEdgeList::value_type::property_type PropT; graph_type& g = static_cast< graph_type& >(g_); typename Config::out_edge_iterator first, last; boost::tie(first, last) = out_edges(u, g); typedef typename Config::edge_parallel_category Cat; detail::undirected_remove_out_edge_if_dispatch< PropT >( g, first, last, g.out_edge_list(u), pred, Cat()); } template < class Config, class Predicate > void remove_in_edge_if(typename Config::vertex_descriptor u, Predicate pred, undirected_graph_helper< Config >& g_) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); remove_out_edge_if(u, pred, g_); } // O(E/V * E) or O(log(E/V) * E) template < class Predicate, class Config > void remove_edge_if(Predicate pred, undirected_graph_helper< Config >& g_) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(g_); typename Config::edge_iterator ei, ei_end, next; boost::tie(ei, ei_end) = edges(g); for (next = ei; ei != ei_end; ei = next) { ++next; if (pred(*ei)) remove_edge(*ei, g); } } // O(1) template < class Config > inline std::pair< typename Config::edge_iterator, typename Config::edge_iterator > edges(const undirected_graph_helper< Config >& g_) { typedef typename Config::graph_type graph_type; typedef typename Config::edge_iterator edge_iterator; const graph_type& cg = static_cast< const graph_type& >(g_); graph_type& g = const_cast< graph_type& >(cg); return std::make_pair( edge_iterator(g.m_edges.begin()), edge_iterator(g.m_edges.end())); } // O(1) template < class Config > inline typename Config::edges_size_type num_edges( const undirected_graph_helper< Config >& g_) { typedef typename Config::graph_type graph_type; const graph_type& g = static_cast< const graph_type& >(g_); return g.m_edges.size(); } // O(E/V * E/V) template < class Config > inline void clear_vertex( typename Config::vertex_descriptor u, undirected_graph_helper< Config >& g_) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(g_); while (true) { typename Config::out_edge_iterator ei, ei_end; boost::tie(ei, ei_end) = out_edges(u, g); if (ei == ei_end) break; remove_edge(*ei, g); } } // O(1) for allow_parallel_edge_tag // O(log(E/V)) for disallow_parallel_edge_tag template < class Config > inline std::pair< typename Config::edge_descriptor, bool > add_edge( typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, const typename Config::edge_property_type& p, undirected_graph_helper< Config >& g_) { typedef typename Config::StoredEdge StoredEdge; typedef typename Config::edge_descriptor edge_descriptor; typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(g_); bool inserted; typename Config::EdgeContainer::value_type e(u, v, p); typename Config::EdgeContainer::iterator p_iter = graph_detail::push(g.m_edges, e).first; typename Config::OutEdgeList::iterator i; boost::tie(i, inserted) = boost::graph_detail::push( g.out_edge_list(u), StoredEdge(v, p_iter, &g.m_edges)); if (inserted) { boost::graph_detail::push( g.out_edge_list(v), StoredEdge(u, p_iter, &g.m_edges)); return std::make_pair( edge_descriptor(u, v, &p_iter->get_property()), true); } else { g.m_edges.erase(p_iter); return std::make_pair( edge_descriptor(u, v, &i->get_iter()->get_property()), false); } } template < class Config > inline std::pair< typename Config::edge_descriptor, bool > add_edge( typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, undirected_graph_helper< Config >& g_) { typename Config::edge_property_type p; return add_edge(u, v, p, g_); } // O(1) template < class Config > inline typename Config::degree_size_type degree( typename Config::vertex_descriptor u, const undirected_graph_helper< Config >& g_) { typedef typename Config::graph_type Graph; const Graph& g = static_cast< const Graph& >(g_); return out_degree(u, g); } template < class Config > inline std::pair< typename Config::in_edge_iterator, typename Config::in_edge_iterator > in_edges(typename Config::vertex_descriptor u, const undirected_graph_helper< Config >& g_) { typedef typename Config::graph_type Graph; const Graph& cg = static_cast< const Graph& >(g_); Graph& g = const_cast< Graph& >(cg); typedef typename Config::in_edge_iterator in_edge_iterator; return std::make_pair(in_edge_iterator(g.out_edge_list(u).begin(), u), in_edge_iterator(g.out_edge_list(u).end(), u)); } template < class Config > inline typename Config::degree_size_type in_degree( typename Config::vertex_descriptor u, const undirected_graph_helper< Config >& g_) { return degree(u, g_); } //========================================================================= // Bidirectional Graph Helper Class struct bidir_adj_list_traversal_tag : public virtual vertex_list_graph_tag, public virtual incidence_graph_tag, public virtual adjacency_graph_tag, public virtual edge_list_graph_tag, public virtual bidirectional_graph_tag { }; template < class Config > struct bidirectional_graph_helper : public directed_edges_helper< Config > { typedef bidir_adj_list_traversal_tag traversal_category; }; // Had to make these non-members to avoid accidental instantiation // on SGI MIPSpro C++ template < class C > inline typename C::InEdgeList& in_edge_list( bidirectional_graph_helper< C >&, typename C::vertex_descriptor v) { typename C::stored_vertex* sv = (typename C::stored_vertex*)v; return sv->m_in_edges; } template < class C > inline const typename C::InEdgeList& in_edge_list( const bidirectional_graph_helper< C >&, typename C::vertex_descriptor v) { typename C::stored_vertex* sv = (typename C::stored_vertex*)v; return sv->m_in_edges; } template < class Predicate, class Config > inline void remove_edge_if( Predicate pred, bidirectional_graph_helper< Config >& g_) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(g_); typename Config::edge_iterator ei, ei_end, next; boost::tie(ei, ei_end) = edges(g); for (next = ei; ei != ei_end; ei = next) { ++next; if (pred(*ei)) remove_edge(*ei, g); } } template < class Config > inline std::pair< typename Config::in_edge_iterator, typename Config::in_edge_iterator > in_edges(typename Config::vertex_descriptor u, const bidirectional_graph_helper< Config >& g_) { typedef typename Config::graph_type graph_type; const graph_type& cg = static_cast< const graph_type& >(g_); graph_type& g = const_cast< graph_type& >(cg); typedef typename Config::in_edge_iterator in_edge_iterator; return std::make_pair(in_edge_iterator(in_edge_list(g, u).begin(), u), in_edge_iterator(in_edge_list(g, u).end(), u)); } // O(1) template < class Config > inline std::pair< typename Config::edge_iterator, typename Config::edge_iterator > edges(const bidirectional_graph_helper< Config >& g_) { typedef typename Config::graph_type graph_type; typedef typename Config::edge_iterator edge_iterator; const graph_type& cg = static_cast< const graph_type& >(g_); graph_type& g = const_cast< graph_type& >(cg); return std::make_pair( edge_iterator(g.m_edges.begin()), edge_iterator(g.m_edges.end())); } //========================================================================= // Bidirectional Graph Helper Class (with edge properties) template < class Config > struct bidirectional_graph_helper_with_property : public bidirectional_graph_helper< Config > { typedef typename Config::graph_type graph_type; typedef typename Config::out_edge_iterator out_edge_iterator; std::pair< out_edge_iterator, out_edge_iterator > get_parallel_edge_sublist( typename Config::edge_descriptor e, const graph_type& g, void*) { return out_edges(source(e, g), g); } std::pair< out_edge_iterator, out_edge_iterator > get_parallel_edge_sublist( typename Config::edge_descriptor e, const graph_type& g, setS*) { return edge_range(source(e, g), target(e, g), g); } std::pair< out_edge_iterator, out_edge_iterator > get_parallel_edge_sublist( typename Config::edge_descriptor e, const graph_type& g, multisetS*) { return edge_range(source(e, g), target(e, g), g); } std::pair< out_edge_iterator, out_edge_iterator > get_parallel_edge_sublist( typename Config::edge_descriptor e, const graph_type& g, hash_setS*) { return edge_range(source(e, g), target(e, g), g); } // Placement of these overloaded remove_edge() functions // inside the class avoids a VC++ bug. // O(E/V) or O(log(E/V)) void remove_edge(typename Config::edge_descriptor e) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); graph_type& g = static_cast< graph_type& >(*this); typedef typename Config::edgelist_selector OutEdgeListS; std::pair< out_edge_iterator, out_edge_iterator > rng = get_parallel_edge_sublist(e, g, (OutEdgeListS*)(0)); rng.first = std::find(rng.first, rng.second, e); BOOST_ASSERT(rng.first != rng.second); remove_edge(rng.first); } inline void remove_edge(typename Config::out_edge_iterator iter) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(*this); typename Config::edge_descriptor e = *iter; typename Config::OutEdgeList& oel = g.out_edge_list(source(e, g)); typename Config::InEdgeList& iel = in_edge_list(g, target(e, g)); typedef typename Config::OutEdgeList::value_type::property_type PType; PType& p = *(PType*)e.get_property(); detail::remove_directed_edge_dispatch(*iter, iel, p); g.m_edges.erase(iter.base()->get_iter()); oel.erase(iter.base()); } }; // O(E/V) for allow_parallel_edge_tag // O(log(E/V)) for disallow_parallel_edge_tag template < class Config > inline void remove_edge(typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, bidirectional_graph_helper_with_property< Config >& g_) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(g_); typedef typename Config::edge_parallel_category Cat; detail::remove_edge_and_property(g, g.out_edge_list(u), v, Cat()); detail::erase_from_incidence_list(in_edge_list(g, v), u, Cat()); } // O(E/V) or O(log(E/V)) template < class EdgeOrIter, class Config > inline void remove_edge( EdgeOrIter e, bidirectional_graph_helper_with_property< Config >& g_) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); g_.remove_edge(e); } template < class Config, class Predicate > inline void remove_out_edge_if(typename Config::vertex_descriptor u, Predicate pred, bidirectional_graph_helper_with_property< Config >& g_) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::graph_type graph_type; typedef typename Config::OutEdgeList::value_type::property_type PropT; graph_type& g = static_cast< graph_type& >(g_); typedef typename Config::EdgeIter EdgeIter; typedef std::vector< EdgeIter > Garbage; Garbage garbage; // First remove the edges from the targets' in-edge lists and // from the graph's edge set list. typename Config::out_edge_iterator out_i, out_end; for (boost::tie(out_i, out_end) = out_edges(u, g); out_i != out_end; ++out_i) if (pred(*out_i)) { detail::remove_directed_edge_dispatch(*out_i, in_edge_list(g, target(*out_i, g)), *(PropT*)(*out_i).get_property()); // Put in garbage to delete later. Will need the properties // for the remove_if of the out-edges. garbage.push_back((*out_i.base()).get_iter()); } // Now remove the edges from this out-edge list. typename Config::out_edge_iterator first, last; boost::tie(first, last) = out_edges(u, g); typedef typename Config::edge_parallel_category Cat; detail::remove_directed_edge_if_dispatch( first, last, g.out_edge_list(u), pred, Cat()); // Now delete the edge properties from the g.m_edges list for (typename Garbage::iterator i = garbage.begin(); i != garbage.end(); ++i) g.m_edges.erase(*i); } template < class Config, class Predicate > inline void remove_in_edge_if(typename Config::vertex_descriptor v, Predicate pred, bidirectional_graph_helper_with_property< Config >& g_) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::graph_type graph_type; typedef typename Config::OutEdgeList::value_type::property_type PropT; graph_type& g = static_cast< graph_type& >(g_); typedef typename Config::EdgeIter EdgeIter; typedef std::vector< EdgeIter > Garbage; Garbage garbage; // First remove the edges from the sources' out-edge lists and // from the graph's edge set list. typename Config::in_edge_iterator in_i, in_end; for (boost::tie(in_i, in_end) = in_edges(v, g); in_i != in_end; ++in_i) if (pred(*in_i)) { typename Config::vertex_descriptor u = source(*in_i, g); detail::remove_directed_edge_dispatch( *in_i, g.out_edge_list(u), *(PropT*)(*in_i).get_property()); // Put in garbage to delete later. Will need the properties // for the remove_if of the out-edges. garbage.push_back((*in_i.base()).get_iter()); } // Now remove the edges from this in-edge list. typename Config::in_edge_iterator first, last; boost::tie(first, last) = in_edges(v, g); typedef typename Config::edge_parallel_category Cat; detail::remove_directed_edge_if_dispatch( first, last, in_edge_list(g, v), pred, Cat()); // Now delete the edge properties from the g.m_edges list for (typename Garbage::iterator i = garbage.begin(); i != garbage.end(); ++i) g.m_edges.erase(*i); } // O(1) template < class Config > inline typename Config::edges_size_type num_edges( const bidirectional_graph_helper_with_property< Config >& g_) { typedef typename Config::graph_type graph_type; const graph_type& g = static_cast< const graph_type& >(g_); return g.m_edges.size(); } // O(E/V * E/V) for allow_parallel_edge_tag // O(E/V * log(E/V)) for disallow_parallel_edge_tag template < class Config > inline void clear_vertex(typename Config::vertex_descriptor u, bidirectional_graph_helper_with_property< Config >& g_) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::graph_type graph_type; typedef typename Config::edge_parallel_category Cat; graph_type& g = static_cast< graph_type& >(g_); typename Config::OutEdgeList& el = g.out_edge_list(u); typename Config::OutEdgeList::iterator ei = el.begin(), ei_end = el.end(); for (; ei != ei_end; ++ei) { detail::erase_from_incidence_list( in_edge_list(g, (*ei).get_target()), u, Cat()); g.m_edges.erase((*ei).get_iter()); } typename Config::InEdgeList& in_el = in_edge_list(g, u); typename Config::InEdgeList::iterator in_ei = in_el.begin(), in_ei_end = in_el.end(); for (; in_ei != in_ei_end; ++in_ei) { detail::erase_from_incidence_list( g.out_edge_list((*in_ei).get_target()), u, Cat()); g.m_edges.erase((*in_ei).get_iter()); } g.out_edge_list(u).clear(); in_edge_list(g, u).clear(); } template < class Config > inline void clear_out_edges(typename Config::vertex_descriptor u, bidirectional_graph_helper_with_property< Config >& g_) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::graph_type graph_type; typedef typename Config::edge_parallel_category Cat; graph_type& g = static_cast< graph_type& >(g_); typename Config::OutEdgeList& el = g.out_edge_list(u); typename Config::OutEdgeList::iterator ei = el.begin(), ei_end = el.end(); for (; ei != ei_end; ++ei) { detail::erase_from_incidence_list( in_edge_list(g, (*ei).get_target()), u, Cat()); g.m_edges.erase((*ei).get_iter()); } g.out_edge_list(u).clear(); } template < class Config > inline void clear_in_edges(typename Config::vertex_descriptor u, bidirectional_graph_helper_with_property< Config >& g_) { typedef typename Config::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Config::graph_type graph_type; typedef typename Config::edge_parallel_category Cat; graph_type& g = static_cast< graph_type& >(g_); typename Config::InEdgeList& in_el = in_edge_list(g, u); typename Config::InEdgeList::iterator in_ei = in_el.begin(), in_ei_end = in_el.end(); for (; in_ei != in_ei_end; ++in_ei) { detail::erase_from_incidence_list( g.out_edge_list((*in_ei).get_target()), u, Cat()); g.m_edges.erase((*in_ei).get_iter()); } in_edge_list(g, u).clear(); } // O(1) for allow_parallel_edge_tag // O(log(E/V)) for disallow_parallel_edge_tag template < class Config > inline std::pair< typename Config::edge_descriptor, bool > add_edge( typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, const typename Config::edge_property_type& p, bidirectional_graph_helper_with_property< Config >& g_) { typedef typename Config::graph_type graph_type; graph_type& g = static_cast< graph_type& >(g_); typedef typename Config::edge_descriptor edge_descriptor; typedef typename Config::StoredEdge StoredEdge; bool inserted; typename Config::EdgeContainer::value_type e(u, v, p); typename Config::EdgeContainer::iterator p_iter = graph_detail::push(g.m_edges, e).first; typename Config::OutEdgeList::iterator i; boost::tie(i, inserted) = boost::graph_detail::push( g.out_edge_list(u), StoredEdge(v, p_iter, &g.m_edges)); if (inserted) { boost::graph_detail::push( in_edge_list(g, v), StoredEdge(u, p_iter, &g.m_edges)); return std::make_pair(edge_descriptor(u, v, &p_iter->m_property), true); } else { g.m_edges.erase(p_iter); return std::make_pair( edge_descriptor(u, v, &i->get_iter()->get_property()), false); } } template < class Config > inline std::pair< typename Config::edge_descriptor, bool > add_edge( typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, bidirectional_graph_helper_with_property< Config >& g_) { typename Config::edge_property_type p; return add_edge(u, v, p, g_); } // O(1) template < class Config > inline typename Config::degree_size_type degree( typename Config::vertex_descriptor u, const bidirectional_graph_helper_with_property< Config >& g_) { typedef typename Config::graph_type graph_type; const graph_type& g = static_cast< const graph_type& >(g_); return in_degree(u, g) + out_degree(u, g); } //========================================================================= // Adjacency List Helper Class template < class Config, class Base > struct adj_list_helper : public Base { typedef typename Config::graph_type AdjList; typedef typename Config::vertex_descriptor vertex_descriptor; typedef typename Config::edge_descriptor edge_descriptor; typedef typename Config::out_edge_iterator out_edge_iterator; typedef typename Config::in_edge_iterator in_edge_iterator; typedef typename Config::adjacency_iterator adjacency_iterator; typedef typename Config::inv_adjacency_iterator inv_adjacency_iterator; typedef typename Config::vertex_iterator vertex_iterator; typedef typename Config::edge_iterator edge_iterator; typedef typename Config::directed_category directed_category; typedef typename Config::edge_parallel_category edge_parallel_category; typedef typename Config::vertices_size_type vertices_size_type; typedef typename Config::edges_size_type edges_size_type; typedef typename Config::degree_size_type degree_size_type; typedef typename Config::StoredEdge StoredEdge; typedef typename Config::vertex_property_type vertex_property_type; typedef typename Config::edge_property_type edge_property_type; typedef typename Config::graph_property_type graph_property_type; typedef typename Config::global_edgelist_selector global_edgelist_selector; typedef typename lookup_one_property< vertex_property_type, vertex_bundle_t >::type vertex_bundled; typedef typename lookup_one_property< edge_property_type, edge_bundle_t >::type edge_bundled; typedef typename lookup_one_property< graph_property_type, graph_bundle_t >::type graph_bundled; }; template < class Config, class Base > inline std::pair< typename Config::adjacency_iterator, typename Config::adjacency_iterator > adjacent_vertices(typename Config::vertex_descriptor u, const adj_list_helper< Config, Base >& g_) { typedef typename Config::graph_type AdjList; const AdjList& cg = static_cast< const AdjList& >(g_); AdjList& g = const_cast< AdjList& >(cg); typedef typename Config::adjacency_iterator adjacency_iterator; typename Config::out_edge_iterator first, last; boost::tie(first, last) = out_edges(u, g); return std::make_pair( adjacency_iterator(first, &g), adjacency_iterator(last, &g)); } template < class Config, class Base > inline std::pair< typename Config::inv_adjacency_iterator, typename Config::inv_adjacency_iterator > inv_adjacent_vertices(typename Config::vertex_descriptor u, const adj_list_helper< Config, Base >& g_) { typedef typename Config::graph_type AdjList; const AdjList& cg = static_cast< const AdjList& >(g_); AdjList& g = const_cast< AdjList& >(cg); typedef typename Config::inv_adjacency_iterator inv_adjacency_iterator; typename Config::in_edge_iterator first, last; boost::tie(first, last) = in_edges(u, g); return std::make_pair( inv_adjacency_iterator(first, &g), inv_adjacency_iterator(last, &g)); } template < class Config, class Base > inline std::pair< typename Config::out_edge_iterator, typename Config::out_edge_iterator > out_edges(typename Config::vertex_descriptor u, const adj_list_helper< Config, Base >& g_) { typedef typename Config::graph_type AdjList; typedef typename Config::out_edge_iterator out_edge_iterator; const AdjList& cg = static_cast< const AdjList& >(g_); AdjList& g = const_cast< AdjList& >(cg); return std::make_pair(out_edge_iterator(g.out_edge_list(u).begin(), u), out_edge_iterator(g.out_edge_list(u).end(), u)); } template < class Config, class Base > inline std::pair< typename Config::vertex_iterator, typename Config::vertex_iterator > vertices(const adj_list_helper< Config, Base >& g_) { typedef typename Config::graph_type AdjList; const AdjList& cg = static_cast< const AdjList& >(g_); AdjList& g = const_cast< AdjList& >(cg); return std::make_pair(g.vertex_set().begin(), g.vertex_set().end()); } template < class Config, class Base > inline typename Config::vertices_size_type num_vertices( const adj_list_helper< Config, Base >& g_) { typedef typename Config::graph_type AdjList; const AdjList& g = static_cast< const AdjList& >(g_); return g.vertex_set().size(); } template < class Config, class Base > inline typename Config::degree_size_type out_degree( typename Config::vertex_descriptor u, const adj_list_helper< Config, Base >& g_) { typedef typename Config::graph_type AdjList; const AdjList& g = static_cast< const AdjList& >(g_); return g.out_edge_list(u).size(); } template < class Config, class Base > inline std::pair< typename Config::edge_descriptor, bool > edge( typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, const adj_list_helper< Config, Base >& g_) { typedef typename Config::graph_type Graph; typedef typename Config::StoredEdge StoredEdge; const Graph& cg = static_cast< const Graph& >(g_); const typename Config::OutEdgeList& el = cg.out_edge_list(u); typename Config::OutEdgeList::const_iterator it = graph_detail::find(el, StoredEdge(v)); return std::make_pair(typename Config::edge_descriptor(u, v, (it == el.end() ? 0 : &(*it).get_property())), (it != el.end())); } template < class Config, class Base > inline std::pair< typename Config::out_edge_iterator, typename Config::out_edge_iterator > edge_range(typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, const adj_list_helper< Config, Base >& g_) { typedef typename Config::graph_type Graph; typedef typename Config::StoredEdge StoredEdge; const Graph& cg = static_cast< const Graph& >(g_); Graph& g = const_cast< Graph& >(cg); typedef typename Config::out_edge_iterator out_edge_iterator; typename Config::OutEdgeList& el = g.out_edge_list(u); typename Config::OutEdgeList::iterator first, last; typename Config::EdgeContainer fake_edge_container; boost::tie(first, last) = graph_detail::equal_range(el, StoredEdge(v)); return std::make_pair( out_edge_iterator(first, u), out_edge_iterator(last, u)); } template < class Config > inline typename Config::degree_size_type in_degree( typename Config::vertex_descriptor u, const directed_edges_helper< Config >& g_) { typedef typename Config::graph_type Graph; const Graph& cg = static_cast< const Graph& >(g_); Graph& g = const_cast< Graph& >(cg); return in_edge_list(g, u).size(); } namespace detail { template < class Config, class Base, class Property > inline typename boost::property_map< typename Config::graph_type, Property >::type get_dispatch( adj_list_helper< Config, Base >&, Property p, boost::edge_property_tag) { typedef typename Config::graph_type Graph; typedef typename boost::property_map< Graph, Property >::type PA; return PA(p); } template < class Config, class Base, class Property > inline typename boost::property_map< typename Config::graph_type, Property >::const_type get_dispatch(const adj_list_helper< Config, Base >&, Property p, boost::edge_property_tag) { typedef typename Config::graph_type Graph; typedef typename boost::property_map< Graph, Property >::const_type PA; return PA(p); } template < class Config, class Base, class Property > inline typename boost::property_map< typename Config::graph_type, Property >::type get_dispatch(adj_list_helper< Config, Base >& g, Property p, boost::vertex_property_tag) { typedef typename Config::graph_type Graph; typedef typename boost::property_map< Graph, Property >::type PA; return PA(&static_cast< Graph& >(g), p); } template < class Config, class Base, class Property > inline typename boost::property_map< typename Config::graph_type, Property >::const_type get_dispatch(const adj_list_helper< Config, Base >& g, Property p, boost::vertex_property_tag) { typedef typename Config::graph_type Graph; typedef typename boost::property_map< Graph, Property >::const_type PA; const Graph& cg = static_cast< const Graph& >(g); return PA(&cg, p); } } // namespace detail // Implementation of the PropertyGraph interface template < class Config, class Base, class Property > inline typename boost::property_map< typename Config::graph_type, Property >::type get(Property p, adj_list_helper< Config, Base >& g) { typedef typename detail::property_kind_from_graph< adj_list_helper< Config, Base >, Property >::type Kind; return detail::get_dispatch(g, p, Kind()); } template < class Config, class Base, class Property > inline typename boost::property_map< typename Config::graph_type, Property >::const_type get(Property p, const adj_list_helper< Config, Base >& g) { typedef typename detail::property_kind_from_graph< adj_list_helper< Config, Base >, Property >::type Kind; return detail::get_dispatch(g, p, Kind()); } template < class Config, class Base, class Property, class Key > inline typename boost::property_traits< typename boost::property_map< typename Config::graph_type, Property >::type >::reference get(Property p, adj_list_helper< Config, Base >& g, const Key& key) { return get(get(p, g), key); } template < class Config, class Base, class Property, class Key > inline typename boost::property_traits< typename boost::property_map< typename Config::graph_type, Property >::const_type >::reference get(Property p, const adj_list_helper< Config, Base >& g, const Key& key) { return get(get(p, g), key); } template < class Config, class Base, class Property, class Key, class Value > inline void put(Property p, adj_list_helper< Config, Base >& g, const Key& key, const Value& value) { typedef typename Config::graph_type Graph; typedef typename boost::property_map< Graph, Property >::type Map; Map pmap = get(p, static_cast< Graph& >(g)); put(pmap, key, value); } //========================================================================= // Generalize Adjacency List Implementation struct adj_list_tag { }; template < class Derived, class Config, class Base > class adj_list_impl : public adj_list_helper< Config, Base > { typedef typename Config::OutEdgeList OutEdgeList; typedef typename Config::InEdgeList InEdgeList; typedef typename Config::StoredVertexList StoredVertexList; public: typedef typename Config::stored_vertex stored_vertex; typedef typename Config::EdgeContainer EdgeContainer; typedef typename Config::vertex_descriptor vertex_descriptor; typedef typename Config::edge_descriptor edge_descriptor; typedef typename Config::vertex_iterator vertex_iterator; typedef typename Config::edge_iterator edge_iterator; typedef typename Config::edge_parallel_category edge_parallel_category; typedef typename Config::vertices_size_type vertices_size_type; typedef typename Config::edges_size_type edges_size_type; typedef typename Config::degree_size_type degree_size_type; typedef typename Config::edge_property_type edge_property_type; typedef adj_list_tag graph_tag; static vertex_descriptor null_vertex() { return 0; } inline adj_list_impl() {} inline adj_list_impl(const adj_list_impl& x) { copy_impl(x); } inline adj_list_impl& operator=(const adj_list_impl& x) { this->clear(); copy_impl(x); return *this; } inline void clear() { for (typename StoredVertexList::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i) delete (stored_vertex*)*i; m_vertices.clear(); m_edges.clear(); } inline adj_list_impl(vertices_size_type num_vertices) { for (vertices_size_type i = 0; i < num_vertices; ++i) add_vertex(static_cast< Derived& >(*this)); } template < class EdgeIterator > inline adj_list_impl( vertices_size_type num_vertices, EdgeIterator first, EdgeIterator last) { vertex_descriptor* v = new vertex_descriptor[num_vertices]; for (vertices_size_type i = 0; i < num_vertices; ++i) v[i] = add_vertex(static_cast< Derived& >(*this)); while (first != last) { add_edge(v[(*first).first], v[(*first).second], *this); ++first; } delete[] v; } template < class EdgeIterator, class EdgePropertyIterator > inline adj_list_impl(vertices_size_type num_vertices, EdgeIterator first, EdgeIterator last, EdgePropertyIterator ep_iter) { vertex_descriptor* v = new vertex_descriptor[num_vertices]; for (vertices_size_type i = 0; i < num_vertices; ++i) v[i] = add_vertex(static_cast< Derived& >(*this)); while (first != last) { add_edge(v[(*first).first], v[(*first).second], *ep_iter, *this); ++first; ++ep_iter; } delete[] v; } ~adj_list_impl() { for (typename StoredVertexList::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i) delete (stored_vertex*)*i; } // protected: inline OutEdgeList& out_edge_list(vertex_descriptor v) { stored_vertex* sv = (stored_vertex*)v; return sv->m_out_edges; } inline const OutEdgeList& out_edge_list(vertex_descriptor v) const { stored_vertex* sv = (stored_vertex*)v; return sv->m_out_edges; } inline StoredVertexList& vertex_set() { return m_vertices; } inline const StoredVertexList& vertex_set() const { return m_vertices; } inline void copy_impl(const adj_list_impl& x_) { const Derived& x = static_cast< const Derived& >(x_); // Would be better to have a constant time way to get from // vertices in x to the corresponding vertices in *this. std::map< stored_vertex*, stored_vertex* > vertex_map; // Copy the stored vertex objects by adding each vertex // and copying its property object. vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(x); vi != vi_end; ++vi) { stored_vertex* v = (stored_vertex*)add_vertex(*this); v->m_property = ((stored_vertex*)*vi)->m_property; vertex_map[(stored_vertex*)*vi] = v; } // Copy the edges by adding each edge and copying its // property object. edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = edges(x); ei != ei_end; ++ei) { edge_descriptor e; bool inserted; vertex_descriptor s = source(*ei, x), t = target(*ei, x); boost::tie(e, inserted) = add_edge(vertex_map[(stored_vertex*)s], vertex_map[(stored_vertex*)t], *this); *((edge_property_type*)e.m_eproperty) = *((edge_property_type*)(*ei).m_eproperty); } } typename Config::EdgeContainer m_edges; StoredVertexList m_vertices; }; // O(1) template < class Derived, class Config, class Base > inline typename Config::vertex_descriptor add_vertex( adj_list_impl< Derived, Config, Base >& g_) { Derived& g = static_cast< Derived& >(g_); typedef typename Config::stored_vertex stored_vertex; stored_vertex* v = new stored_vertex; typename Config::StoredVertexList::iterator pos; bool inserted; boost::tie(pos, inserted) = boost::graph_detail::push(g.m_vertices, v); v->m_position = pos; g.added_vertex(v); return v; } // O(1) template < class Derived, class Config, class Base > inline typename Config::vertex_descriptor add_vertex( const typename Config::vertex_property_type& p, adj_list_impl< Derived, Config, Base >& g_) { typedef typename Config::vertex_descriptor vertex_descriptor; Derived& g = static_cast< Derived& >(g_); if (optional< vertex_descriptor > v = g.vertex_by_property(get_property_value(p, vertex_bundle))) return *v; typedef typename Config::stored_vertex stored_vertex; stored_vertex* v = new stored_vertex(p); typename Config::StoredVertexList::iterator pos; bool inserted; boost::tie(pos, inserted) = boost::graph_detail::push(g.m_vertices, v); v->m_position = pos; g.added_vertex(v); return v; } // O(1) template < class Derived, class Config, class Base > inline void remove_vertex(typename Config::vertex_descriptor u, adj_list_impl< Derived, Config, Base >& g_) { typedef typename Config::stored_vertex stored_vertex; Derived& g = static_cast< Derived& >(g_); g.removing_vertex( u, boost::graph_detail::iterator_stability(g_.m_vertices)); stored_vertex* su = (stored_vertex*)u; g.m_vertices.erase(su->m_position); delete su; } // O(V) template < class Derived, class Config, class Base > inline typename Config::vertex_descriptor vertex( typename Config::vertices_size_type n, const adj_list_impl< Derived, Config, Base >& g_) { const Derived& g = static_cast< const Derived& >(g_); typename Config::vertex_iterator i = vertices(g).first; while (n--) ++i; // std::advance(i, n); (not VC++ portable) return *i; } //========================================================================= // Vector-Backbone Adjacency List Implementation namespace detail { template < class Graph, class vertex_descriptor > inline void remove_vertex_dispatch( Graph& g, vertex_descriptor u, boost::directed_tag) { typedef typename Graph::edge_parallel_category edge_parallel_category; g.m_vertices.erase(g.m_vertices.begin() + u); vertex_descriptor V = num_vertices(g); if (u != V) { for (vertex_descriptor v = 0; v < V; ++v) reindex_edge_list( g.out_edge_list(v), u, edge_parallel_category()); } } template < class Graph, class vertex_descriptor > inline void remove_vertex_dispatch( Graph& g, vertex_descriptor u, boost::undirected_tag) { typedef typename Graph::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Graph::edge_parallel_category edge_parallel_category; g.m_vertices.erase(g.m_vertices.begin() + u); vertex_descriptor V = num_vertices(g); for (vertex_descriptor v = 0; v < V; ++v) reindex_edge_list(g.out_edge_list(v), u, edge_parallel_category()); typedef typename Graph::EdgeContainer Container; typedef typename Container::iterator Iter; Iter ei = g.m_edges.begin(), ei_end = g.m_edges.end(); for (; ei != ei_end; ++ei) { if (ei->m_source > u) --ei->m_source; if (ei->m_target > u) --ei->m_target; } } template < class Graph, class vertex_descriptor > inline void remove_vertex_dispatch( Graph& g, vertex_descriptor u, boost::bidirectional_tag) { typedef typename Graph::global_edgelist_selector EdgeListS; BOOST_STATIC_ASSERT((!is_same< EdgeListS, vecS >::value)); typedef typename Graph::edge_parallel_category edge_parallel_category; g.m_vertices.erase(g.m_vertices.begin() + u); vertex_descriptor V = num_vertices(g); vertex_descriptor v; if (u != V) { for (v = 0; v < V; ++v) reindex_edge_list( g.out_edge_list(v), u, edge_parallel_category()); for (v = 0; v < V; ++v) reindex_edge_list( in_edge_list(g, v), u, edge_parallel_category()); typedef typename Graph::EdgeContainer Container; typedef typename Container::iterator Iter; Iter ei = g.m_edges.begin(), ei_end = g.m_edges.end(); for (; ei != ei_end; ++ei) { if (ei->m_source > u) --ei->m_source; if (ei->m_target > u) --ei->m_target; } } } template < class EdgeList, class vertex_descriptor > inline void reindex_edge_list( EdgeList& el, vertex_descriptor u, boost::allow_parallel_edge_tag) { typename EdgeList::iterator ei = el.begin(), e_end = el.end(); for (; ei != e_end; ++ei) if ((*ei).get_target() > u) --(*ei).get_target(); } template < class EdgeList, class vertex_descriptor > inline void reindex_edge_list( EdgeList& el, vertex_descriptor u, boost::disallow_parallel_edge_tag) { for (typename EdgeList::iterator ei = el.begin(); ei != el.end(); ++ei) { if (ei->get_target() > u) { typename EdgeList::value_type ce = *ei; el.erase(ce); --ce.get_target(); el.insert(ce); } } } } // namespace detail struct vec_adj_list_tag { }; template < class Graph, class Config, class Base > class vec_adj_list_impl : public adj_list_helper< Config, Base > { typedef typename Config::OutEdgeList OutEdgeList; typedef typename Config::InEdgeList InEdgeList; typedef typename Config::StoredVertexList StoredVertexList; public: typedef typename Config::vertex_descriptor vertex_descriptor; typedef typename Config::edge_descriptor edge_descriptor; typedef typename Config::out_edge_iterator out_edge_iterator; typedef typename Config::edge_iterator edge_iterator; typedef typename Config::directed_category directed_category; typedef typename Config::vertices_size_type vertices_size_type; typedef typename Config::edges_size_type edges_size_type; typedef typename Config::degree_size_type degree_size_type; typedef typename Config::StoredEdge StoredEdge; typedef typename Config::stored_vertex stored_vertex; typedef typename Config::EdgeContainer EdgeContainer; typedef typename Config::edge_property_type edge_property_type; typedef vec_adj_list_tag graph_tag; static vertex_descriptor null_vertex() { return (std::numeric_limits< vertex_descriptor >::max)(); } inline vec_adj_list_impl() {} inline vec_adj_list_impl(const vec_adj_list_impl& x) { copy_impl(x); } inline vec_adj_list_impl& operator=(const vec_adj_list_impl& x) { this->clear(); copy_impl(x); return *this; } inline void clear() { m_vertices.clear(); m_edges.clear(); } inline vec_adj_list_impl(vertices_size_type _num_vertices) : m_vertices(_num_vertices) { } template < class EdgeIterator > inline vec_adj_list_impl( vertices_size_type num_vertices, EdgeIterator first, EdgeIterator last) : m_vertices(num_vertices) { while (first != last) { add_edge( (*first).first, (*first).second, static_cast< Graph& >(*this)); ++first; } } template < class EdgeIterator, class EdgePropertyIterator > inline vec_adj_list_impl(vertices_size_type num_vertices, EdgeIterator first, EdgeIterator last, EdgePropertyIterator ep_iter) : m_vertices(num_vertices) { while (first != last) { add_edge((*first).first, (*first).second, *ep_iter, static_cast< Graph& >(*this)); ++first; ++ep_iter; } } // protected: inline boost::integer_range< vertex_descriptor > vertex_set() const { return boost::integer_range< vertex_descriptor >(0, m_vertices.size()); } inline OutEdgeList& out_edge_list(vertex_descriptor v) { return m_vertices[v].m_out_edges; } inline const OutEdgeList& out_edge_list(vertex_descriptor v) const { return m_vertices[v].m_out_edges; } inline void copy_impl(const vec_adj_list_impl& x_) { const Graph& x = static_cast< const Graph& >(x_); // Copy the stored vertex objects by adding each vertex // and copying its property object. for (vertices_size_type i = 0; i < num_vertices(x); ++i) { vertex_descriptor v = add_vertex(*this); m_vertices[v].m_property = x.m_vertices[i].m_property; } // Copy the edges by adding each edge and copying its // property object. edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = edges(x); ei != ei_end; ++ei) { edge_descriptor e; bool inserted; boost::tie(e, inserted) = add_edge(source(*ei, x), target(*ei, x), *this); *((edge_property_type*)e.m_eproperty) = *((edge_property_type*)(*ei).m_eproperty); } } typename Config::EdgeContainer m_edges; StoredVertexList m_vertices; }; // Had to make these non-members to avoid accidental instantiation // on SGI MIPSpro C++ template < class G, class C, class B > inline typename C::InEdgeList& in_edge_list( vec_adj_list_impl< G, C, B >& g, typename C::vertex_descriptor v) { return g.m_vertices[v].m_in_edges; } template < class G, class C, class B > inline const typename C::InEdgeList& in_edge_list( const vec_adj_list_impl< G, C, B >& g, typename C::vertex_descriptor v) { return g.m_vertices[v].m_in_edges; } // O(1) template < class Graph, class Config, class Base > inline typename Config::vertex_descriptor add_vertex( vec_adj_list_impl< Graph, Config, Base >& g_) { Graph& g = static_cast< Graph& >(g_); g.m_vertices.resize(g.m_vertices.size() + 1); g.added_vertex(g.m_vertices.size() - 1); return g.m_vertices.size() - 1; } template < class Graph, class Config, class Base > inline typename Config::vertex_descriptor add_vertex( const typename Config::vertex_property_type& p, vec_adj_list_impl< Graph, Config, Base >& g_) { typedef typename Config::vertex_descriptor vertex_descriptor; Graph& g = static_cast< Graph& >(g_); if (optional< vertex_descriptor > v = g.vertex_by_property(get_property_value(p, vertex_bundle))) return *v; typedef typename Config::stored_vertex stored_vertex; g.m_vertices.push_back(stored_vertex(p)); g.added_vertex(g.m_vertices.size() - 1); return g.m_vertices.size() - 1; } // Here we override the directed_graph_helper add_edge() function // so that the number of vertices is automatically changed if // either u or v is greater than the number of vertices. template < class Graph, class Config, class Base > inline std::pair< typename Config::edge_descriptor, bool > add_edge( typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, const typename Config::edge_property_type& p, vec_adj_list_impl< Graph, Config, Base >& g_) { BOOST_USING_STD_MAX(); typename Config::vertex_descriptor x = max BOOST_PREVENT_MACRO_SUBSTITUTION(u, v); if (x >= num_vertices(g_)) g_.m_vertices.resize(x + 1); adj_list_helper< Config, Base >& g = g_; return add_edge(u, v, p, g); } template < class Graph, class Config, class Base > inline std::pair< typename Config::edge_descriptor, bool > add_edge( typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, vec_adj_list_impl< Graph, Config, Base >& g_) { typename Config::edge_property_type p; return add_edge(u, v, p, g_); } // O(V + E) template < class Graph, class Config, class Base > inline void remove_vertex(typename Config::vertex_descriptor v, vec_adj_list_impl< Graph, Config, Base >& g_) { typedef typename Config::directed_category Cat; Graph& g = static_cast< Graph& >(g_); g.removing_vertex( v, boost::graph_detail::iterator_stability(g_.m_vertices)); detail::remove_vertex_dispatch(g, v, Cat()); } // O(1) template < class Graph, class Config, class Base > inline typename Config::vertex_descriptor vertex( typename Config::vertices_size_type n, const vec_adj_list_impl< Graph, Config, Base >&) { return n; } namespace detail { //========================================================================= // Adjacency List Generator template < class Graph, class VertexListS, class OutEdgeListS, class DirectedS, class VertexProperty, class EdgeProperty, class GraphProperty, class EdgeListS > struct adj_list_gen { typedef typename detail::is_random_access< VertexListS >::type is_rand_access; typedef typename has_property< EdgeProperty >::type has_edge_property; typedef typename DirectedS::is_directed_t DirectedT; typedef typename DirectedS::is_bidir_t BidirectionalT; struct config { typedef OutEdgeListS edgelist_selector; typedef EdgeListS global_edgelist_selector; typedef Graph graph_type; typedef EdgeProperty edge_property_type; typedef VertexProperty vertex_property_type; typedef GraphProperty graph_property_type; typedef std::size_t vertices_size_type; typedef adjacency_list_traits< OutEdgeListS, VertexListS, DirectedS > Traits; typedef typename Traits::directed_category directed_category; typedef typename Traits::edge_parallel_category edge_parallel_category; typedef typename Traits::vertex_descriptor vertex_descriptor; typedef typename Traits::edge_descriptor edge_descriptor; typedef void* vertex_ptr; // need to reorganize this to avoid instantiating stuff // that doesn't get used -JGS // VertexList and vertex_iterator typedef typename container_gen< VertexListS, vertex_ptr >::type SeqVertexList; typedef boost::integer_range< vertex_descriptor > RandVertexList; typedef typename mpl::if_< is_rand_access, RandVertexList, SeqVertexList >::type VertexList; typedef typename VertexList::iterator vertex_iterator; // EdgeContainer and StoredEdge typedef typename container_gen< EdgeListS, list_edge< vertex_descriptor, EdgeProperty > >::type EdgeContainer; typedef typename mpl::and_< DirectedT, typename mpl::not_< BidirectionalT >::type >::type on_edge_storage; typedef typename mpl::if_< on_edge_storage, std::size_t, typename EdgeContainer::size_type >::type edges_size_type; typedef typename EdgeContainer::iterator EdgeIter; typedef typename detail::is_random_access< EdgeListS >::type is_edge_ra; typedef typename mpl::if_< on_edge_storage, stored_edge_property< vertex_descriptor, EdgeProperty >, typename mpl::if_< is_edge_ra, stored_ra_edge_iter< vertex_descriptor, EdgeContainer, EdgeProperty >, stored_edge_iter< vertex_descriptor, EdgeIter, EdgeProperty > >::type >::type StoredEdge; // Adjacency Types typedef typename container_gen< OutEdgeListS, StoredEdge >::type OutEdgeList; typedef typename OutEdgeList::size_type degree_size_type; typedef typename OutEdgeList::iterator OutEdgeIter; typedef boost::detail::iterator_traits< OutEdgeIter > OutEdgeIterTraits; typedef typename OutEdgeIterTraits::iterator_category OutEdgeIterCat; typedef typename OutEdgeIterTraits::difference_type OutEdgeIterDiff; typedef out_edge_iter< OutEdgeIter, vertex_descriptor, edge_descriptor, OutEdgeIterDiff > out_edge_iterator; typedef typename adjacency_iterator_generator< graph_type, vertex_descriptor, out_edge_iterator >::type adjacency_iterator; typedef OutEdgeList InEdgeList; typedef OutEdgeIter InEdgeIter; typedef OutEdgeIterCat InEdgeIterCat; typedef OutEdgeIterDiff InEdgeIterDiff; typedef in_edge_iter< InEdgeIter, vertex_descriptor, edge_descriptor, InEdgeIterDiff > in_edge_iterator; typedef typename inv_adjacency_iterator_generator< graph_type, vertex_descriptor, in_edge_iterator >::type inv_adjacency_iterator; // Edge Iterator typedef boost::detail::iterator_traits< EdgeIter > EdgeIterTraits; typedef typename EdgeIterTraits::iterator_category EdgeIterCat; typedef typename EdgeIterTraits::difference_type EdgeIterDiff; typedef undirected_edge_iter< EdgeIter, edge_descriptor, EdgeIterDiff > UndirectedEdgeIter; // also used for bidirectional typedef adj_list_edge_iterator< vertex_iterator, out_edge_iterator, graph_type > DirectedEdgeIter; typedef typename mpl::if_< on_edge_storage, DirectedEdgeIter, UndirectedEdgeIter >::type edge_iterator; // stored_vertex and StoredVertexList typedef typename container_gen< VertexListS, vertex_ptr >::type SeqStoredVertexList; struct seq_stored_vertex { seq_stored_vertex() {} seq_stored_vertex(const VertexProperty& p) : m_property(p) {} OutEdgeList m_out_edges; VertexProperty m_property; typename SeqStoredVertexList::iterator m_position; }; struct bidir_seq_stored_vertex { bidir_seq_stored_vertex() {} bidir_seq_stored_vertex(const VertexProperty& p) : m_property(p) { } OutEdgeList m_out_edges; InEdgeList m_in_edges; VertexProperty m_property; typename SeqStoredVertexList::iterator m_position; }; struct rand_stored_vertex { rand_stored_vertex() {} rand_stored_vertex(const VertexProperty& p) : m_property(p) {} OutEdgeList m_out_edges; VertexProperty m_property; }; struct bidir_rand_stored_vertex { bidir_rand_stored_vertex() {} bidir_rand_stored_vertex(const VertexProperty& p) : m_property(p) { } OutEdgeList m_out_edges; InEdgeList m_in_edges; VertexProperty m_property; }; typedef typename mpl::if_< is_rand_access, typename mpl::if_< BidirectionalT, bidir_rand_stored_vertex, rand_stored_vertex >::type, typename mpl::if_< BidirectionalT, bidir_seq_stored_vertex, seq_stored_vertex >::type >::type StoredVertex; struct stored_vertex : public StoredVertex { stored_vertex() {} stored_vertex(const VertexProperty& p) : StoredVertex(p) {} }; typedef typename container_gen< VertexListS, stored_vertex >::type RandStoredVertexList; typedef typename mpl::if_< is_rand_access, RandStoredVertexList, SeqStoredVertexList >::type StoredVertexList; }; // end of config typedef typename mpl::if_< BidirectionalT, bidirectional_graph_helper_with_property< config >, typename mpl::if_< DirectedT, directed_graph_helper< config >, undirected_graph_helper< config > >::type >::type DirectedHelper; typedef typename mpl::if_< is_rand_access, vec_adj_list_impl< Graph, config, DirectedHelper >, adj_list_impl< Graph, config, DirectedHelper > >::type type; }; } // namespace detail //========================================================================= // Vertex Property Maps template < class Graph, class ValueType, class Reference, class Tag > struct adj_list_vertex_property_map : public boost::put_get_helper< Reference, adj_list_vertex_property_map< Graph, ValueType, Reference, Tag > > { typedef typename Graph::stored_vertex StoredVertex; typedef ValueType value_type; typedef Reference reference; typedef typename Graph::vertex_descriptor key_type; typedef boost::lvalue_property_map_tag category; inline adj_list_vertex_property_map(const Graph* = 0, Tag tag = Tag()) : m_tag(tag) { } inline Reference operator[](key_type v) const { StoredVertex* sv = (StoredVertex*)v; return get_property_value(sv->m_property, m_tag); } inline Reference operator()(key_type v) const { return this->operator[](v); } Tag m_tag; }; template < class Graph, class Property, class PropRef > struct adj_list_vertex_all_properties_map : public boost::put_get_helper< PropRef, adj_list_vertex_all_properties_map< Graph, Property, PropRef > > { typedef typename Graph::stored_vertex StoredVertex; typedef Property value_type; typedef PropRef reference; typedef typename Graph::vertex_descriptor key_type; typedef boost::lvalue_property_map_tag category; inline adj_list_vertex_all_properties_map( const Graph* = 0, vertex_all_t = vertex_all_t()) { } inline PropRef operator[](key_type v) const { StoredVertex* sv = (StoredVertex*)v; return sv->m_property; } inline PropRef operator()(key_type v) const { return this->operator[](v); } }; template < class Graph, class GraphPtr, class ValueType, class Reference, class Tag > struct vec_adj_list_vertex_property_map : public boost::put_get_helper< Reference, vec_adj_list_vertex_property_map< Graph, GraphPtr, ValueType, Reference, Tag > > { typedef ValueType value_type; typedef Reference reference; typedef typename boost::graph_traits< Graph >::vertex_descriptor key_type; typedef boost::lvalue_property_map_tag category; vec_adj_list_vertex_property_map(GraphPtr g = 0, Tag tag = Tag()) : m_g(g), m_tag(tag) { } inline Reference operator[](key_type v) const { return get_property_value(m_g->m_vertices[v].m_property, m_tag); } inline Reference operator()(key_type v) const { return this->operator[](v); } GraphPtr m_g; Tag m_tag; }; template < class Graph, class GraphPtr, class Property, class PropertyRef > struct vec_adj_list_vertex_all_properties_map : public boost::put_get_helper< PropertyRef, vec_adj_list_vertex_all_properties_map< Graph, GraphPtr, Property, PropertyRef > > { typedef Property value_type; typedef PropertyRef reference; typedef typename boost::graph_traits< Graph >::vertex_descriptor key_type; typedef boost::lvalue_property_map_tag category; vec_adj_list_vertex_all_properties_map( GraphPtr g = 0, vertex_all_t = vertex_all_t()) : m_g(g) { } inline PropertyRef operator[](key_type v) const { return m_g->m_vertices[v].m_property; } inline PropertyRef operator()(key_type v) const { return this->operator[](v); } GraphPtr m_g; }; struct adj_list_any_vertex_pa { template < class Tag, class Graph, class Property > struct bind_ { typedef typename property_value< Property, Tag >::type value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef adj_list_vertex_property_map< Graph, value_type, reference, Tag > type; typedef adj_list_vertex_property_map< Graph, value_type, const_reference, Tag > const_type; }; }; struct adj_list_all_vertex_pa { template < class Tag, class Graph, class Property > struct bind_ { typedef typename Graph::vertex_descriptor Vertex; typedef adj_list_vertex_all_properties_map< Graph, Property, Property& > type; typedef adj_list_vertex_all_properties_map< Graph, Property, const Property& > const_type; }; }; template < class Property, class Vertex > struct vec_adj_list_vertex_id_map : public boost::put_get_helper< Vertex, vec_adj_list_vertex_id_map< Property, Vertex > > { typedef Vertex value_type; typedef Vertex key_type; typedef Vertex reference; typedef boost::readable_property_map_tag category; inline vec_adj_list_vertex_id_map() {} template < class Graph > inline vec_adj_list_vertex_id_map(const Graph&, vertex_index_t) { } inline value_type operator[](key_type v) const { return v; } inline value_type operator()(key_type v) const { return v; } }; struct vec_adj_list_any_vertex_pa { template < class Tag, class Graph, class Property > struct bind_ { typedef typename property_value< Property, Tag >::type value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef vec_adj_list_vertex_property_map< Graph, Graph*, value_type, reference, Tag > type; typedef vec_adj_list_vertex_property_map< Graph, const Graph*, value_type, const_reference, Tag > const_type; }; }; struct vec_adj_list_id_vertex_pa { template < class Tag, class Graph, class Property > struct bind_ { typedef typename Graph::vertex_descriptor Vertex; typedef vec_adj_list_vertex_id_map< Property, Vertex > type; typedef vec_adj_list_vertex_id_map< Property, Vertex > const_type; }; }; struct vec_adj_list_all_vertex_pa { template < class Tag, class Graph, class Property > struct bind_ { typedef typename Graph::vertex_descriptor Vertex; typedef vec_adj_list_vertex_all_properties_map< Graph, Graph*, Property, Property& > type; typedef vec_adj_list_vertex_all_properties_map< Graph, const Graph*, Property, const Property& > const_type; }; }; namespace detail { template < class Tag, class Graph, class Property > struct adj_list_choose_vertex_pa : boost::mpl::if_< boost::is_same< Tag, vertex_all_t >, adj_list_all_vertex_pa, adj_list_any_vertex_pa >::type :: template bind_< Tag, Graph, Property > { }; template < class Tag > struct vec_adj_list_choose_vertex_pa_helper { typedef vec_adj_list_any_vertex_pa type; }; template <> struct vec_adj_list_choose_vertex_pa_helper< vertex_index_t > { typedef vec_adj_list_id_vertex_pa type; }; template <> struct vec_adj_list_choose_vertex_pa_helper< vertex_all_t > { typedef vec_adj_list_all_vertex_pa type; }; template < class Tag, class Graph, class Property > struct vec_adj_list_choose_vertex_pa : vec_adj_list_choose_vertex_pa_helper< Tag >::type::template bind_< Tag, Graph, Property > { }; } // namespace detail //========================================================================= // Edge Property Map template < class Directed, class Value, class Ref, class Vertex, class Property, class Tag > struct adj_list_edge_property_map : public put_get_helper< Ref, adj_list_edge_property_map< Directed, Value, Ref, Vertex, Property, Tag > > { Tag tag; explicit adj_list_edge_property_map(Tag tag = Tag()) : tag(tag) {} typedef Value value_type; typedef Ref reference; typedef detail::edge_desc_impl< Directed, Vertex > key_type; typedef boost::lvalue_property_map_tag category; inline Ref operator[](key_type e) const { Property& p = *(Property*)e.get_property(); return get_property_value(p, tag); } inline Ref operator()(key_type e) const { return this->operator[](e); } }; template < class Directed, class Property, class PropRef, class PropPtr, class Vertex > struct adj_list_edge_all_properties_map : public put_get_helper< PropRef, adj_list_edge_all_properties_map< Directed, Property, PropRef, PropPtr, Vertex > > { explicit adj_list_edge_all_properties_map(edge_all_t = edge_all_t()) {} typedef Property value_type; typedef PropRef reference; typedef detail::edge_desc_impl< Directed, Vertex > key_type; typedef boost::lvalue_property_map_tag category; inline PropRef operator[](key_type e) const { return *(PropPtr)e.get_property(); } inline PropRef operator()(key_type e) const { return this->operator[](e); } }; // Edge Property Maps namespace detail { struct adj_list_any_edge_pmap { template < class Graph, class Property, class Tag > struct bind_ { typedef typename property_value< Property, Tag >::type value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef adj_list_edge_property_map< typename Graph::directed_category, value_type, reference, typename Graph::vertex_descriptor, Property, Tag > type; typedef adj_list_edge_property_map< typename Graph::directed_category, value_type, const_reference, typename Graph::vertex_descriptor, const Property, Tag > const_type; }; }; struct adj_list_all_edge_pmap { template < class Graph, class Property, class Tag > struct bind_ { typedef adj_list_edge_all_properties_map< typename Graph::directed_category, Property, Property&, Property*, typename Graph::vertex_descriptor > type; typedef adj_list_edge_all_properties_map< typename Graph::directed_category, Property, const Property&, const Property*, typename Graph::vertex_descriptor > const_type; }; }; template < class Tag > struct adj_list_choose_edge_pmap_helper { typedef adj_list_any_edge_pmap type; }; template <> struct adj_list_choose_edge_pmap_helper< edge_all_t > { typedef adj_list_all_edge_pmap type; }; template < class Tag, class Graph, class Property > struct adj_list_choose_edge_pmap : adj_list_choose_edge_pmap_helper< Tag >::type::template bind_< Graph, Property, Tag > { }; struct adj_list_edge_property_selector { template < class Graph, class Property, class Tag > struct bind_ : adj_list_choose_edge_pmap< Tag, Graph, Property > { }; }; } // namespace detail template <> struct edge_property_selector< adj_list_tag > { typedef detail::adj_list_edge_property_selector type; }; template <> struct edge_property_selector< vec_adj_list_tag > { typedef detail::adj_list_edge_property_selector type; }; // Vertex Property Maps struct adj_list_vertex_property_selector { template < class Graph, class Property, class Tag > struct bind_ : detail::adj_list_choose_vertex_pa< Tag, Graph, Property > { }; }; template <> struct vertex_property_selector< adj_list_tag > { typedef adj_list_vertex_property_selector type; }; struct vec_adj_list_vertex_property_selector { template < class Graph, class Property, class Tag > struct bind_ : detail::vec_adj_list_choose_vertex_pa< Tag, Graph, Property > { }; }; template <> struct vertex_property_selector< vec_adj_list_tag > { typedef vec_adj_list_vertex_property_selector type; }; } // namespace boost namespace boost { template < typename V > struct hash< boost::detail::stored_edge< V > > { std::size_t operator()(const boost::detail::stored_edge< V >& e) const { return hash< V >()(e.m_target); } }; template < typename V, typename P > struct hash< boost::detail::stored_edge_property< V, P > > { std::size_t operator()( const boost::detail::stored_edge_property< V, P >& e) const { return hash< V >()(e.m_target); } }; template < typename V, typename I, typename P > struct hash< boost::detail::stored_edge_iter< V, I, P > > { std::size_t operator()( const boost::detail::stored_edge_iter< V, I, P >& e) const { return hash< V >()(e.m_target); } }; } #endif // BOOST_GRAPH_DETAIL_DETAIL_ADJACENCY_LIST_CCT /* Implementation Notes: Many of the public interface functions in this file would have been more conveniently implemented as inline friend functions. However there are a few compiler bugs that make that approach non-portable. 1. g++ inline friend in namespace bug 2. g++ using clause doesn't work with inline friends 3. VC++ doesn't have Koenig lookup For these reasons, the functions were all written as non-inline free functions, and static cast was used to convert from the helper class to the adjacency_list derived class. Looking back, it might have been better to write out all functions in terms of the adjacency_list, and then use a tag to dispatch to the various helpers instead of using inheritance. */ detail/array_binary_tree.hpp 0000644 00000015547 15125521275 0012241 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_ARRAY_BINARY_TREE_HPP #define BOOST_ARRAY_BINARY_TREE_HPP #include <iterator> #include <functional> #include <boost/config.hpp> namespace boost { /* * Note: array_binary_tree is a completey balanced binary tree. */ #if !defined BOOST_NO_STD_ITERATOR_TRAITS template < class RandomAccessIterator, class ID > #else template < class RandomAccessIterator, class ValueType, class ID > #endif class array_binary_tree_node { public: typedef array_binary_tree_node ArrayBinaryTreeNode; typedef RandomAccessIterator rep_iterator; #if !defined BOOST_NO_STD_ITERATOR_TRAITS typedef typename std::iterator_traits< RandomAccessIterator >::difference_type difference_type; typedef typename std::iterator_traits< RandomAccessIterator >::value_type value_type; #else typedef int difference_type; typedef ValueType value_type; #endif typedef difference_type size_type; struct children_type { struct iterator { // replace with iterator_adaptor implementation -JGS typedef std::bidirectional_iterator_tag iterator_category; typedef ArrayBinaryTreeNode value_type; typedef size_type difference_type; typedef array_binary_tree_node* pointer; typedef ArrayBinaryTreeNode& reference; inline iterator() : i(0), n(0) {} inline iterator(const iterator& x) : r(x.r), i(x.i), n(x.n), id(x.id) { } inline iterator& operator=(const iterator& x) { r = x.r; i = x.i; n = x.n; /*egcs generate a warning*/ id = x.id; return *this; } inline iterator( rep_iterator rr, size_type ii, size_type nn, const ID& _id) : r(rr), i(ii), n(nn), id(_id) { } inline array_binary_tree_node operator*() { return ArrayBinaryTreeNode(r, i, n, id); } inline iterator& operator++() { ++i; return *this; } inline iterator operator++(int) { iterator t = *this; ++(*this); return t; } inline iterator& operator--() { --i; return *this; } inline iterator operator--(int) { iterator t = *this; --(*this); return t; } inline bool operator==(const iterator& x) const { return i == x.i; } inline bool operator!=(const iterator& x) const { return !(*this == x); } rep_iterator r; size_type i; size_type n; ID id; }; inline children_type() : i(0), n(0) {} inline children_type(const children_type& x) : r(x.r), i(x.i), n(x.n), id(x.id) { } inline children_type& operator=(const children_type& x) { r = x.r; i = x.i; n = x.n; /*egcs generate a warning*/ id = x.id; return *this; } inline children_type( rep_iterator rr, size_type ii, size_type nn, const ID& _id) : r(rr), i(ii), n(nn), id(_id) { } inline iterator begin() { return iterator(r, 2 * i + 1, n, id); } inline iterator end() { return iterator(r, 2 * i + 1 + size(), n, id); } inline size_type size() const { size_type c = 2 * i + 1; size_type s; if (c + 1 < n) s = 2; else if (c < n) s = 1; else s = 0; return s; } rep_iterator r; size_type i; size_type n; ID id; }; inline array_binary_tree_node() : i(0), n(0) {} inline array_binary_tree_node(const array_binary_tree_node& x) : r(x.r), i(x.i), n(x.n), id(x.id) { } inline ArrayBinaryTreeNode& operator=(const ArrayBinaryTreeNode& x) { r = x.r; i = x.i; n = x.n; /*egcs generate a warning*/ id = x.id; return *this; } inline array_binary_tree_node( rep_iterator start, rep_iterator end, rep_iterator pos, const ID& _id) : r(start), i(pos - start), n(end - start), id(_id) { } inline array_binary_tree_node( rep_iterator rr, size_type ii, size_type nn, const ID& _id) : r(rr), i(ii), n(nn), id(_id) { } inline value_type& value() { return *(r + i); } inline const value_type& value() const { return *(r + i); } inline ArrayBinaryTreeNode parent() const { return ArrayBinaryTreeNode(r, (i - 1) / 2, n, id); } inline bool has_parent() const { return i != 0; } inline children_type children() { return children_type(r, i, n, id); } /* inline void swap(array_binary_tree_node x) { value_type tmp = x.value(); x.value() = value(); value() = tmp; i = x.i; } */ template < class ExternalData > inline void swap(ArrayBinaryTreeNode x, ExternalData& edata) { using boost::get; value_type tmp = x.value(); /*swap external data*/ edata[get(id, tmp)] = i; edata[get(id, value())] = x.i; x.value() = value(); value() = tmp; i = x.i; } inline const children_type children() const { return children_type(r, i, n); } inline size_type index() const { return i; } rep_iterator r; size_type i; size_type n; ID id; }; template < class RandomAccessContainer, class Compare = std::less< typename RandomAccessContainer::value_type > > struct compare_array_node { typedef typename RandomAccessContainer::value_type value_type; compare_array_node(const Compare& x) : comp(x) {} compare_array_node(const compare_array_node& x) : comp(x.comp) {} template < class node_type > inline bool operator()(const node_type& x, const node_type& y) { return comp(x.value(), y.value()); } template < class node_type > inline bool operator()(const node_type& x, const node_type& y) const { return comp(x.value(), y.value()); } Compare comp; }; } // namespace boost #endif /* BOOST_ARRAY_BINARY_TREE_HPP */ detail/d_ary_heap.hpp 0000644 00000027737 15125521275 0010637 0 ustar 00 // //======================================================================= // Copyright 2009 Trustees of Indiana University // Authors: Jeremiah J. Willcock, Andrew Lumsdaine // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_D_ARY_HEAP_HPP #define BOOST_D_ARY_HEAP_HPP #include <vector> #include <cstddef> #include <algorithm> #include <utility> #include <boost/assert.hpp> #include <boost/static_assert.hpp> #include <boost/shared_array.hpp> #include <boost/property_map/property_map.hpp> // WARNING: it is not safe to copy a d_ary_heap_indirect and then modify one of // the copies. The class is required to be copyable so it can be passed around // (without move support from C++11), but it deep-copies the heap contents yet // shallow-copies the index_in_heap_map. namespace boost { // Swap two elements in a property map without assuming they model // LvaluePropertyMap -- currently not used template < typename PropMap > inline void property_map_swap(PropMap prop_map, const typename boost::property_traits< PropMap >::key_type& ka, const typename boost::property_traits< PropMap >::key_type& kb) { typename boost::property_traits< PropMap >::value_type va = get(prop_map, ka); put(prop_map, ka, get(prop_map, kb)); put(prop_map, kb, va); } namespace detail { template < typename Value > class fixed_max_size_vector { boost::shared_array< Value > m_data; std::size_t m_size; public: typedef std::size_t size_type; fixed_max_size_vector(std::size_t max_size) : m_data(new Value[max_size]), m_size(0) { } std::size_t size() const { return m_size; } bool empty() const { return m_size == 0; } Value& operator[](std::size_t i) { return m_data[i]; } const Value& operator[](std::size_t i) const { return m_data[i]; } void push_back(Value v) { m_data[m_size++] = v; } void pop_back() { --m_size; } Value& back() { return m_data[m_size - 1]; } const Value& back() const { return m_data[m_size - 1]; } }; } // D-ary heap using an indirect compare operator (use identity_property_map // as DistanceMap to get a direct compare operator). This heap appears to be // commonly used for Dijkstra's algorithm for its good practical performance // on some platforms; asymptotically, it has an O(lg N) decrease-key // operation while that can be done in constant time on a relaxed heap. The // implementation is mostly based on the binary heap page on Wikipedia and // online sources that state that the operations are the same for d-ary // heaps. This code is not based on the old Boost d-ary heap code. // // - d_ary_heap_indirect is a model of UpdatableQueue as is needed for // dijkstra_shortest_paths. // // - Value must model Assignable. // - Arity must be at least 2 (optimal value appears to be 4, both in my and // third-party experiments). // - IndexInHeapMap must be a ReadWritePropertyMap from Value to // Container::size_type (to store the index of each stored value within the // heap for decrease-key aka update). // - DistanceMap must be a ReadablePropertyMap from Value to something // (typedef'ed as distance_type). // - Compare must be a BinaryPredicate used as a less-than operator on // distance_type. // - Container must be a random-access, contiguous container (in practice, // the operations used probably require that it is std::vector<Value>). // template < typename Value, std::size_t Arity, typename IndexInHeapPropertyMap, typename DistanceMap, typename Compare = std::less< Value >, typename Container = std::vector< Value > > class d_ary_heap_indirect { BOOST_STATIC_ASSERT(Arity >= 2); public: typedef typename Container::size_type size_type; typedef Value value_type; typedef typename boost::property_traits< DistanceMap >::value_type key_type; typedef DistanceMap key_map; d_ary_heap_indirect(DistanceMap distance, IndexInHeapPropertyMap index_in_heap, const Compare& compare = Compare(), const Container& data = Container()) : compare(compare) , data(data) , distance(distance) , index_in_heap(index_in_heap) { } /* Implicit copy constructor */ /* Implicit assignment operator */ size_type size() const { return data.size(); } bool empty() const { return data.empty(); } void push(const Value& v) { size_type index = data.size(); data.push_back(v); put(index_in_heap, v, index); preserve_heap_property_up(index); verify_heap(); } Value& top() { BOOST_ASSERT(!this->empty()); return data[0]; } const Value& top() const { BOOST_ASSERT(!this->empty()); return data[0]; } void pop() { BOOST_ASSERT(!this->empty()); put(index_in_heap, data[0], (size_type)(-1)); if (data.size() != 1) { data[0] = data.back(); put(index_in_heap, data[0], (size_type)(0)); data.pop_back(); preserve_heap_property_down(); verify_heap(); } else { data.pop_back(); } } // This function assumes the key has been updated (using an external write // to the distance map or such) // See // http://coding.derkeiler.com/Archive/General/comp.theory/2007-05/msg00043.html void update(const Value& v) { /* decrease-key */ size_type index = get(index_in_heap, v); preserve_heap_property_up(index); verify_heap(); } bool contains(const Value& v) const { size_type index = get(index_in_heap, v); return (index != (size_type)(-1)); } void push_or_update(const Value& v) { /* insert if not present, else update */ size_type index = get(index_in_heap, v); if (index == (size_type)(-1)) { index = data.size(); data.push_back(v); put(index_in_heap, v, index); } preserve_heap_property_up(index); verify_heap(); } DistanceMap keys() const { return distance; } private: Compare compare; Container data; DistanceMap distance; IndexInHeapPropertyMap index_in_heap; // The distances being compared using compare and that are stored in the // distance map typedef typename boost::property_traits< DistanceMap >::value_type distance_type; // Get the parent of a given node in the heap static size_type parent(size_type index) { return (index - 1) / Arity; } // Get the child_idx'th child of a given node; 0 <= child_idx < Arity static size_type child(size_type index, std::size_t child_idx) { return index * Arity + child_idx + 1; } // Swap two elements in the heap by index, updating index_in_heap void swap_heap_elements(size_type index_a, size_type index_b) { using std::swap; Value value_a = data[index_a]; Value value_b = data[index_b]; data[index_a] = value_b; data[index_b] = value_a; put(index_in_heap, value_a, index_b); put(index_in_heap, value_b, index_a); } // Emulate the indirect_cmp that is now folded into this heap class bool compare_indirect(const Value& a, const Value& b) const { return compare(get(distance, a), get(distance, b)); } // Verify that the array forms a heap; commented out by default void verify_heap() const { // This is a very expensive test so it should be disabled even when // NDEBUG is not defined #if 0 for (size_t i = 1; i < data.size(); ++i) { if (compare_indirect(data[i], data[parent(i)])) { BOOST_ASSERT (!"Element is smaller than its parent"); } } #endif } // Starting at a node, move up the tree swapping elements to preserve the // heap property void preserve_heap_property_up(size_type index) { size_type orig_index = index; size_type num_levels_moved = 0; // The first loop just saves swaps that need to be done in order to // avoid aliasing issues in its search; there is a second loop that does // the necessary swap operations if (index == 0) return; // Do nothing on root Value currently_being_moved = data[index]; distance_type currently_being_moved_dist = get(distance, currently_being_moved); for (;;) { if (index == 0) break; // Stop at root size_type parent_index = parent(index); Value parent_value = data[parent_index]; if (compare( currently_being_moved_dist, get(distance, parent_value))) { ++num_levels_moved; index = parent_index; continue; } else { break; // Heap property satisfied } } // Actually do the moves -- move num_levels_moved elements down in the // tree, then put currently_being_moved at the top index = orig_index; for (size_type i = 0; i < num_levels_moved; ++i) { size_type parent_index = parent(index); Value parent_value = data[parent_index]; put(index_in_heap, parent_value, index); data[index] = parent_value; index = parent_index; } data[index] = currently_being_moved; put(index_in_heap, currently_being_moved, index); verify_heap(); } // From the root, swap elements (each one with its smallest child) if there // are any parent-child pairs that violate the heap property void preserve_heap_property_down() { if (data.empty()) return; size_type index = 0; Value currently_being_moved = data[0]; distance_type currently_being_moved_dist = get(distance, currently_being_moved); size_type heap_size = data.size(); Value* data_ptr = &data[0]; for (;;) { size_type first_child_index = child(index, 0); if (first_child_index >= heap_size) break; /* No children */ Value* child_base_ptr = data_ptr + first_child_index; size_type smallest_child_index = 0; distance_type smallest_child_dist = get(distance, child_base_ptr[smallest_child_index]); if (first_child_index + Arity <= heap_size) { // Special case for a statically known loop count (common case) for (size_t i = 1; i < Arity; ++i) { Value i_value = child_base_ptr[i]; distance_type i_dist = get(distance, i_value); if (compare(i_dist, smallest_child_dist)) { smallest_child_index = i; smallest_child_dist = i_dist; } } } else { for (size_t i = 1; i < heap_size - first_child_index; ++i) { distance_type i_dist = get(distance, child_base_ptr[i]); if (compare(i_dist, smallest_child_dist)) { smallest_child_index = i; smallest_child_dist = i_dist; } } } if (compare(smallest_child_dist, currently_being_moved_dist)) { swap_heap_elements( smallest_child_index + first_child_index, index); index = smallest_child_index + first_child_index; continue; } else { break; // Heap property satisfied } } verify_heap(); } }; } // namespace boost #endif // BOOST_D_ARY_HEAP_HPP detail/geodesic.hpp 0000644 00000011331 15125521275 0010305 0 ustar 00 // (C) Copyright 2007 Andrew Sutton // // 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_DETAIL_GEODESIC_HPP #define BOOST_GRAPH_DETAIL_GEODESIC_HPP #include <functional> #include <boost/config.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/numeric_values.hpp> #include <boost/concept/assert.hpp> // TODO: Should this really be in detail? namespace boost { // This is a very good discussion on centrality measures. While I can't // say that this has been the motivating factor for the design and // implementation of ths centrality framework, it does provide a single // point of reference for defining things like degree and closeness // centrality. Plus, the bibliography seems fairly complete. // // @article{citeulike:1144245, // author = {Borgatti, Stephen P. and Everett, Martin G.}, // citeulike-article-id = {1144245}, // doi = {10.1016/j.socnet.2005.11.005}, // journal = {Social Networks}, // month = {October}, // number = {4}, // pages = {466--484}, // priority = {0}, // title = {A Graph-theoretic perspective on centrality}, // url = {https://doi.org/10.1016/j.socnet.2005.11.005}, // volume = {28}, // year = {2006} // } // } namespace detail { // Note that this assumes T == property_traits<DistanceMap>::value_type // and that the args and return of combine are also T. template < typename Graph, typename DistanceMap, typename Combinator, typename Distance > inline Distance combine_distances( const Graph& g, DistanceMap dist, Combinator combine, Distance init) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::vertex_iterator VertexIterator; BOOST_CONCEPT_ASSERT( (ReadablePropertyMapConcept< DistanceMap, Vertex >)); BOOST_CONCEPT_ASSERT((NumericValueConcept< Distance >)); typedef numeric_values< Distance > DistanceNumbers; BOOST_CONCEPT_ASSERT((AdaptableBinaryFunction< Combinator, Distance, Distance, Distance >)); // If there's ever an infinite distance, then we simply return // infinity. Note that this /will/ include the a non-zero // distance-to-self in the combined values. However, this is usually // zero, so it shouldn't be too problematic. Distance ret = init; VertexIterator i, end; for (boost::tie(i, end) = vertices(g); i != end; ++i) { Vertex v = *i; if (get(dist, v) != DistanceNumbers::infinity()) { ret = combine(ret, get(dist, v)); } else { ret = DistanceNumbers::infinity(); break; } } return ret; } // Similar to std::plus<T>, but maximizes parameters // rather than adding them. template < typename T > struct maximize { typedef T result_type; typedef T first_argument_type; typedef T second_argument_type; T operator()(T x, T y) const { BOOST_USING_STD_MAX(); return max BOOST_PREVENT_MACRO_SUBSTITUTION(x, y); } }; // Another helper, like maximize() to help abstract functional // concepts. This is trivially instantiated for builtin numeric // types, but should be specialized for those types that have // discrete notions of reciprocals. template < typename T > struct reciprocal { typedef T result_type; typedef T argument_type; T operator()(T t) { return T(1) / t; } }; } /* namespace detail */ // This type defines the basic facilities used for computing values // based on the geodesic distances between vertices. Examples include // closeness centrality and mean geodesic distance. template < typename Graph, typename DistanceType, typename ResultType > struct geodesic_measure { typedef DistanceType distance_type; typedef ResultType result_type; typedef typename graph_traits< Graph >::vertices_size_type size_type; typedef numeric_values< distance_type > distance_values; typedef numeric_values< result_type > result_values; static inline distance_type infinite_distance() { return distance_values::infinity(); } static inline result_type infinite_result() { return result_values::infinity(); } static inline result_type zero_result() { return result_values::zero(); } }; } /* namespace boost */ #endif detail/empty_header.hpp 0000644 00000000577 15125521275 0011203 0 ustar 00 #ifndef BOOST_GRAPH_DETAIL_EMPTY_HEADER_HPP_INCLUDED #define BOOST_GRAPH_DETAIL_EMPTY_HEADER_HPP_INCLUDED // Copyright 2018 Peter Dimov // // 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) #endif // #ifndef BOOST_GRAPH_DETAIL_EMPTY_HEADER_HPP_INCLUDED detail/compressed_sparse_row_struct.hpp 0000644 00000072624 15125521275 0014553 0 ustar 00 // Copyright 2005-2009 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Jeremiah Willcock // Douglas Gregor // Andrew Lumsdaine // Compressed sparse row graph type internal structure #ifndef BOOST_GRAPH_COMPRESSED_SPARSE_ROW_STRUCT_HPP #define BOOST_GRAPH_COMPRESSED_SPARSE_ROW_STRUCT_HPP #ifndef BOOST_GRAPH_COMPRESSED_SPARSE_ROW_GRAPH_HPP #error This file should only be included from boost/graph/compressed_sparse_row_graph.hpp #endif #include <vector> #include <utility> #include <algorithm> #include <climits> #include <boost/assert.hpp> #include <iterator> #if 0 #include <iostream> // For some debugging code below #endif #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/filtered_graph.hpp> // For keep_all #include <boost/graph/detail/indexed_properties.hpp> #include <boost/graph/detail/histogram_sort.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/iterator/counting_iterator.hpp> #include <boost/iterator/reverse_iterator.hpp> #include <boost/iterator/zip_iterator.hpp> #include <boost/iterator/transform_iterator.hpp> #include <boost/tuple/tuple.hpp> #include <boost/property_map/property_map.hpp> #include <boost/integer.hpp> #include <boost/iterator/iterator_facade.hpp> #include <boost/mpl/if.hpp> #include <boost/graph/graph_selectors.hpp> #include <boost/static_assert.hpp> #include <boost/functional/hash.hpp> namespace boost { namespace detail { // Forward declaration of CSR edge descriptor type, needed to pass to // indexed_edge_properties. template < typename Vertex, typename EdgeIndex > class csr_edge_descriptor; // Add edge_index property map template < typename Vertex, typename EdgeIndex > struct csr_edge_index_map { typedef EdgeIndex value_type; typedef EdgeIndex reference; typedef csr_edge_descriptor< Vertex, EdgeIndex > key_type; typedef readable_property_map_tag category; }; template < typename Vertex, typename EdgeIndex > inline EdgeIndex get(const csr_edge_index_map< Vertex, EdgeIndex >&, const csr_edge_descriptor< Vertex, EdgeIndex >& key) { return key.idx; } /** Compressed sparse row graph internal structure. * * Vertex and EdgeIndex should be unsigned integral types and should * specialize numeric_limits. */ template < typename EdgeProperty, typename Vertex = std::size_t, typename EdgeIndex = Vertex > class compressed_sparse_row_structure : public detail::indexed_edge_properties< compressed_sparse_row_structure< EdgeProperty, Vertex, EdgeIndex >, EdgeProperty, csr_edge_descriptor< Vertex, EdgeIndex >, csr_edge_index_map< Vertex, EdgeIndex > > { public: typedef detail::indexed_edge_properties< compressed_sparse_row_structure< EdgeProperty, Vertex, EdgeIndex >, EdgeProperty, csr_edge_descriptor< Vertex, EdgeIndex >, csr_edge_index_map< Vertex, EdgeIndex > > inherited_edge_properties; typedef Vertex vertices_size_type; typedef Vertex vertex_descriptor; typedef EdgeIndex edges_size_type; static vertex_descriptor null_vertex() { return vertex_descriptor(-1); } std::vector< EdgeIndex > m_rowstart; std::vector< Vertex > m_column; compressed_sparse_row_structure(Vertex numverts = 0) : m_rowstart(numverts + 1, EdgeIndex(0)), m_column() { } // Rebuild graph from number of vertices and multi-pass unsorted list // of edges (filtered using source_pred and mapped using // global_to_local) template < typename MultiPassInputIterator, typename GlobalToLocal, typename SourcePred > void assign_unsorted_multi_pass_edges(MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, vertices_size_type numlocalverts, const GlobalToLocal& global_to_local, const SourcePred& source_pred) { m_rowstart.clear(); m_rowstart.resize(numlocalverts + 1, 0); typedef std::pair< vertices_size_type, vertices_size_type > edge_type; typedef boost::transform_iterator< boost::graph::detail::project1st< edge_type >, MultiPassInputIterator > source_iterator; typedef boost::transform_iterator< boost::graph::detail::project2nd< edge_type >, MultiPassInputIterator > target_iterator; source_iterator sources_begin( edge_begin, boost::graph::detail::project1st< edge_type >()); source_iterator sources_end( edge_end, boost::graph::detail::project1st< edge_type >()); target_iterator targets_begin( edge_begin, boost::graph::detail::project2nd< edge_type >()); target_iterator targets_end( edge_end, boost::graph::detail::project2nd< edge_type >()); boost::graph::detail::count_starts(sources_begin, sources_end, m_rowstart.begin(), numlocalverts, source_pred, boost::make_property_map_function(global_to_local)); m_column.resize(m_rowstart.back()); inherited_edge_properties::resize(m_rowstart.back()); boost::graph::detail::histogram_sort(sources_begin, sources_end, m_rowstart.begin(), numlocalverts, targets_begin, m_column.begin(), source_pred, boost::make_property_map_function(global_to_local)); } // Rebuild graph from number of vertices and multi-pass unsorted list // of edges and their properties (filtered using source_pred and mapped // using global_to_local) template < typename MultiPassInputIterator, typename EdgePropertyIterator, typename GlobalToLocal, typename SourcePred > void assign_unsorted_multi_pass_edges(MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numlocalverts, const GlobalToLocal& global_to_local, const SourcePred& source_pred) { m_rowstart.clear(); m_rowstart.resize(numlocalverts + 1, 0); typedef std::pair< vertices_size_type, vertices_size_type > edge_type; typedef boost::transform_iterator< boost::graph::detail::project1st< edge_type >, MultiPassInputIterator > source_iterator; typedef boost::transform_iterator< boost::graph::detail::project2nd< edge_type >, MultiPassInputIterator > target_iterator; source_iterator sources_begin( edge_begin, boost::graph::detail::project1st< edge_type >()); source_iterator sources_end( edge_end, boost::graph::detail::project1st< edge_type >()); target_iterator targets_begin( edge_begin, boost::graph::detail::project2nd< edge_type >()); target_iterator targets_end( edge_end, boost::graph::detail::project2nd< edge_type >()); boost::graph::detail::count_starts(sources_begin, sources_end, m_rowstart.begin(), numlocalverts, source_pred, boost::make_property_map_function(global_to_local)); m_column.resize(m_rowstart.back()); inherited_edge_properties::resize(m_rowstart.back()); boost::graph::detail::histogram_sort(sources_begin, sources_end, m_rowstart.begin(), numlocalverts, targets_begin, m_column.begin(), ep_iter, inherited_edge_properties::begin(), source_pred, boost::make_property_map_function(global_to_local)); } // Assign from number of vertices and sorted list of edges template < typename InputIterator, typename GlobalToLocal, typename SourcePred > void assign_from_sorted_edges(InputIterator edge_begin, InputIterator edge_end, const GlobalToLocal& global_to_local, const SourcePred& source_pred, vertices_size_type numlocalverts, edges_size_type numedges_or_zero) { m_column.clear(); m_column.reserve(numedges_or_zero); m_rowstart.resize(numlocalverts + 1); EdgeIndex current_edge = 0; Vertex current_vertex_plus_one = 1; m_rowstart[0] = 0; for (InputIterator ei = edge_begin; ei != edge_end; ++ei) { if (!source_pred(ei->first)) continue; Vertex src = get(global_to_local, ei->first); Vertex tgt = ei->second; for (; current_vertex_plus_one != src + 1; ++current_vertex_plus_one) m_rowstart[current_vertex_plus_one] = current_edge; m_column.push_back(tgt); ++current_edge; } // The remaining vertices have no edges for (; current_vertex_plus_one != numlocalverts + 1; ++current_vertex_plus_one) m_rowstart[current_vertex_plus_one] = current_edge; // Default-construct properties for edges inherited_edge_properties::resize(m_column.size()); } // Assign from number of vertices and sorted list of edges template < typename InputIterator, typename EdgePropertyIterator, typename GlobalToLocal, typename SourcePred > void assign_from_sorted_edges(InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, const GlobalToLocal& global_to_local, const SourcePred& source_pred, vertices_size_type numlocalverts, edges_size_type numedges_or_zero) { // Reserving storage in advance can save us lots of time and // memory, but it can only be done if we have forward iterators or // the user has supplied the number of edges. edges_size_type numedges = numedges_or_zero; if (numedges == 0) { numedges = boost::graph::detail::reserve_count_for_single_pass( edge_begin, edge_end); } m_column.clear(); m_column.reserve(numedges_or_zero); inherited_edge_properties::clear(); inherited_edge_properties::reserve(numedges_or_zero); m_rowstart.resize(numlocalverts + 1); EdgeIndex current_edge = 0; Vertex current_vertex_plus_one = 1; m_rowstart[0] = 0; for (InputIterator ei = edge_begin; ei != edge_end; ++ei, ++ep_iter) { if (!source_pred(ei->first)) continue; Vertex src = get(global_to_local, ei->first); Vertex tgt = ei->second; for (; current_vertex_plus_one != src + 1; ++current_vertex_plus_one) m_rowstart[current_vertex_plus_one] = current_edge; m_column.push_back(tgt); inherited_edge_properties::push_back(*ep_iter); ++current_edge; } // The remaining vertices have no edges for (; current_vertex_plus_one != numlocalverts + 1; ++current_vertex_plus_one) m_rowstart[current_vertex_plus_one] = current_edge; } // Replace graph with sources and targets given, sorting them in-place, // and using the given global-to-local property map to get local indices // from global ones in the two arrays. template < typename GlobalToLocal > void assign_sources_and_targets_global( std::vector< vertex_descriptor >& sources, std::vector< vertex_descriptor >& targets, vertices_size_type numverts, GlobalToLocal global_to_local) { BOOST_ASSERT(sources.size() == targets.size()); // Do an in-place histogram sort (at least that's what I think it // is) to sort sources and targets m_rowstart.clear(); m_rowstart.resize(numverts + 1); boost::graph::detail::count_starts(sources.begin(), sources.end(), m_rowstart.begin(), numverts, keep_all(), boost::make_property_map_function(global_to_local)); boost::graph::detail::histogram_sort_inplace(sources.begin(), m_rowstart.begin(), numverts, targets.begin(), boost::make_property_map_function(global_to_local)); // Now targets is the correct vector (properly sorted by source) for // m_column m_column.swap(targets); inherited_edge_properties::resize(m_rowstart.back()); } // Replace graph with sources and targets and edge properties given, // sorting them in-place, and using the given global-to-local property // map to get local indices from global ones in the two arrays. template < typename GlobalToLocal > void assign_sources_and_targets_global( std::vector< vertex_descriptor >& sources, std::vector< vertex_descriptor >& targets, std::vector< typename inherited_edge_properties::edge_bundled >& edge_props, vertices_size_type numverts, GlobalToLocal global_to_local) { BOOST_ASSERT(sources.size() == targets.size()); BOOST_ASSERT(sources.size() == edge_props.size()); // Do an in-place histogram sort (at least that's what I think it // is) to sort sources and targets m_rowstart.clear(); m_rowstart.resize(numverts + 1); boost::graph::detail::count_starts(sources.begin(), sources.end(), m_rowstart.begin(), numverts, keep_all(), boost::make_property_map_function(global_to_local)); boost::graph::detail::histogram_sort_inplace(sources.begin(), m_rowstart.begin(), numverts, targets.begin(), edge_props.begin(), boost::make_property_map_function(global_to_local)); // Now targets is the correct vector (properly sorted by source) for // m_column, and edge_props for m_edge_properties m_column.swap(targets); this->m_edge_properties.swap(edge_props); } // From any graph (slow and uses a lot of memory) // Requires IncidenceGraph and a vertex index map // Internal helper function // Note that numedges must be doubled for undirected source graphs template < typename Graph, typename VertexIndexMap > void assign(const Graph& g, const VertexIndexMap& vi, vertices_size_type numverts, edges_size_type numedges) { m_rowstart.resize(numverts + 1); m_column.resize(numedges); inherited_edge_properties::resize(numedges); EdgeIndex current_edge = 0; typedef typename boost::graph_traits< Graph >::vertex_descriptor g_vertex; typedef typename boost::graph_traits< Graph >::out_edge_iterator g_out_edge_iter; std::vector< g_vertex > ordered_verts_of_g(numverts); BGL_FORALL_VERTICES_T(v, g, Graph) { ordered_verts_of_g[get(vertex_index, g, v)] = v; } for (Vertex i = 0; i != numverts; ++i) { m_rowstart[i] = current_edge; g_vertex v = ordered_verts_of_g[i]; g_out_edge_iter ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(v, g); ei != ei_end; ++ei) { m_column[current_edge++] = get(vi, target(*ei, g)); } } m_rowstart[numverts] = current_edge; } // Add edges from a sorted (smallest sources first) range of pairs and // edge properties template < typename BidirectionalIteratorOrig, typename EPIterOrig, typename GlobalToLocal > void add_edges_sorted_internal(BidirectionalIteratorOrig first_sorted, BidirectionalIteratorOrig last_sorted, EPIterOrig ep_iter_sorted, const GlobalToLocal& global_to_local) { typedef boost::reverse_iterator< BidirectionalIteratorOrig > BidirectionalIterator; typedef boost::reverse_iterator< EPIterOrig > EPIter; // Flip sequence BidirectionalIterator first(last_sorted); BidirectionalIterator last(first_sorted); typedef Vertex vertex_num; typedef EdgeIndex edge_num; edge_num new_edge_count = std::distance(first, last); EPIter ep_iter(ep_iter_sorted); std::advance(ep_iter, -(std::ptrdiff_t)new_edge_count); edge_num edges_added_before_i = new_edge_count; // Count increment to add to rowstarts m_column.resize(m_column.size() + new_edge_count); inherited_edge_properties::resize( inherited_edge_properties::size() + new_edge_count); BidirectionalIterator current_new_edge = first, prev_new_edge = first; EPIter current_new_edge_prop = ep_iter; for (vertex_num i_plus_1 = m_rowstart.size() - 1; i_plus_1 > 0; --i_plus_1) { vertex_num i = i_plus_1 - 1; prev_new_edge = current_new_edge; // edges_added_to_this_vertex = #mbrs of new_edges with first == // i edge_num edges_added_to_this_vertex = 0; while (current_new_edge != last) { if (get(global_to_local, current_new_edge->first) != i) break; ++current_new_edge; ++current_new_edge_prop; ++edges_added_to_this_vertex; } edges_added_before_i -= edges_added_to_this_vertex; // Invariant: edges_added_before_i = #mbrs of new_edges with // first < i edge_num old_rowstart = m_rowstart[i]; edge_num new_rowstart = m_rowstart[i] + edges_added_before_i; edge_num old_degree = m_rowstart[i + 1] - m_rowstart[i]; edge_num new_degree = old_degree + edges_added_to_this_vertex; // Move old edges forward (by #new_edges before this i) to make // room new_rowstart > old_rowstart, so use copy_backwards if (old_rowstart != new_rowstart) { std::copy_backward(m_column.begin() + old_rowstart, m_column.begin() + old_rowstart + old_degree, m_column.begin() + new_rowstart + old_degree); inherited_edge_properties::move_range( old_rowstart, old_rowstart + old_degree, new_rowstart); } // Add new edges (reversed because current_new_edge is a // const_reverse_iterator) BidirectionalIterator temp = current_new_edge; EPIter temp_prop = current_new_edge_prop; for (; temp != prev_new_edge; ++old_degree) { --temp; --temp_prop; m_column[new_rowstart + old_degree] = temp->second; inherited_edge_properties::write_by_index( new_rowstart + old_degree, *temp_prop); } m_rowstart[i + 1] = new_rowstart + new_degree; if (edges_added_before_i == 0) break; // No more edges inserted before this point // m_rowstart[i] will be fixed up on the next iteration (to // avoid changing the degree of vertex i - 1); the last // iteration never changes it (either because of the condition // of the break or because m_rowstart[0] is always 0) } } }; template < typename Vertex, typename EdgeIndex > class csr_edge_descriptor { public: Vertex src; EdgeIndex idx; csr_edge_descriptor(Vertex src, EdgeIndex idx) : src(src), idx(idx) {} csr_edge_descriptor() : src(0), idx(0) {} bool operator==(const csr_edge_descriptor& e) const { return idx == e.idx; } bool operator!=(const csr_edge_descriptor& e) const { return idx != e.idx; } bool operator<(const csr_edge_descriptor& e) const { return idx < e.idx; } bool operator>(const csr_edge_descriptor& e) const { return idx > e.idx; } bool operator<=(const csr_edge_descriptor& e) const { return idx <= e.idx; } bool operator>=(const csr_edge_descriptor& e) const { return idx >= e.idx; } template < typename Archiver > void serialize(Archiver& ar, const unsigned int /*version*/) { ar& src& idx; } }; // Common out edge and edge iterators template < typename CSRGraph > class csr_out_edge_iterator : public iterator_facade< csr_out_edge_iterator< CSRGraph >, typename CSRGraph::edge_descriptor, std::random_access_iterator_tag, const typename CSRGraph::edge_descriptor&, typename int_t< CHAR_BIT * sizeof(typename CSRGraph::edges_size_type) >::fast > { public: typedef typename CSRGraph::edges_size_type EdgeIndex; typedef typename CSRGraph::edge_descriptor edge_descriptor; typedef typename int_t< CHAR_BIT * sizeof(EdgeIndex) >::fast difference_type; csr_out_edge_iterator() {} // Implicit copy constructor OK explicit csr_out_edge_iterator(edge_descriptor edge) : m_edge(edge) {} public: // GCC 4.2.1 doesn't like the private-and-friend thing // iterator_facade requirements const edge_descriptor& dereference() const { return m_edge; } bool equal(const csr_out_edge_iterator& other) const { return m_edge == other.m_edge; } void increment() { ++m_edge.idx; } void decrement() { --m_edge.idx; } void advance(difference_type n) { m_edge.idx += n; } difference_type distance_to(const csr_out_edge_iterator& other) const { return other.m_edge.idx - m_edge.idx; } edge_descriptor m_edge; friend class boost::iterator_core_access; }; template < typename CSRGraph > class csr_edge_iterator : public iterator_facade< csr_edge_iterator< CSRGraph >, typename CSRGraph::edge_descriptor, boost::forward_traversal_tag, typename CSRGraph::edge_descriptor > { private: typedef typename CSRGraph::edge_descriptor edge_descriptor; typedef typename CSRGraph::edges_size_type EdgeIndex; public: csr_edge_iterator() : rowstart_array(0) , current_edge() , end_of_this_vertex(0) , total_num_edges(0) { } csr_edge_iterator(const CSRGraph& graph, edge_descriptor current_edge, EdgeIndex end_of_this_vertex) : rowstart_array(&graph.m_forward.m_rowstart[0]) , current_edge(current_edge) , end_of_this_vertex(end_of_this_vertex) , total_num_edges(num_edges(graph)) { } public: // See above friend class boost::iterator_core_access; edge_descriptor dereference() const { return current_edge; } bool equal(const csr_edge_iterator& o) const { return current_edge == o.current_edge; } void increment() { ++current_edge.idx; if (current_edge.idx == total_num_edges) return; while (current_edge.idx == end_of_this_vertex) { ++current_edge.src; end_of_this_vertex = rowstart_array[current_edge.src + 1]; } } const EdgeIndex* rowstart_array; edge_descriptor current_edge; EdgeIndex end_of_this_vertex; EdgeIndex total_num_edges; }; // Only for bidirectional graphs template < typename CSRGraph > class csr_in_edge_iterator : public iterator_facade< csr_in_edge_iterator< CSRGraph >, typename CSRGraph::edge_descriptor, boost::forward_traversal_tag, typename CSRGraph::edge_descriptor > { public: typedef typename CSRGraph::edges_size_type EdgeIndex; typedef typename CSRGraph::edge_descriptor edge_descriptor; csr_in_edge_iterator() : m_graph(0) {} // Implicit copy constructor OK csr_in_edge_iterator( const CSRGraph& graph, EdgeIndex index_in_backward_graph) : m_index_in_backward_graph(index_in_backward_graph), m_graph(&graph) { } public: // See above // iterator_facade requirements edge_descriptor dereference() const { return edge_descriptor( m_graph->m_backward.m_column[m_index_in_backward_graph], m_graph->m_backward .m_edge_properties[m_index_in_backward_graph]); } bool equal(const csr_in_edge_iterator& other) const { return m_index_in_backward_graph == other.m_index_in_backward_graph; } void increment() { ++m_index_in_backward_graph; } void decrement() { --m_index_in_backward_graph; } void advance(std::ptrdiff_t n) { m_index_in_backward_graph += n; } std::ptrdiff_t distance_to(const csr_in_edge_iterator& other) const { return other.m_index_in_backward_graph - m_index_in_backward_graph; } EdgeIndex m_index_in_backward_graph; const CSRGraph* m_graph; friend class boost::iterator_core_access; }; template < typename A, typename B > struct transpose_pair { typedef std::pair< B, A > result_type; result_type operator()(const std::pair< A, B >& p) const { return result_type(p.second, p.first); } }; template < typename Iter > struct transpose_iterator_gen { typedef typename std::iterator_traits< Iter >::value_type vt; typedef typename vt::first_type first_type; typedef typename vt::second_type second_type; typedef transpose_pair< first_type, second_type > transpose; typedef boost::transform_iterator< transpose, Iter > type; static type make(Iter it) { return type(it, transpose()); } }; template < typename Iter > typename transpose_iterator_gen< Iter >::type transpose_edges(Iter i) { return transpose_iterator_gen< Iter >::make(i); } template < typename GraphT, typename VertexIndexMap > class edge_to_index_pair { typedef typename boost::graph_traits< GraphT >::vertices_size_type vertices_size_type; typedef typename boost::graph_traits< GraphT >::edge_descriptor edge_descriptor; public: typedef std::pair< vertices_size_type, vertices_size_type > result_type; edge_to_index_pair() : g(0), index() {} edge_to_index_pair(const GraphT& g, const VertexIndexMap& index) : g(&g), index(index) { } result_type operator()(edge_descriptor e) const { return result_type( get(index, source(e, *g)), get(index, target(e, *g))); } private: const GraphT* g; VertexIndexMap index; }; template < typename GraphT, typename VertexIndexMap > edge_to_index_pair< GraphT, VertexIndexMap > make_edge_to_index_pair( const GraphT& g, const VertexIndexMap& index) { return edge_to_index_pair< GraphT, VertexIndexMap >(g, index); } template < typename GraphT > edge_to_index_pair< GraphT, typename boost::property_map< GraphT, boost::vertex_index_t >::const_type > make_edge_to_index_pair(const GraphT& g) { typedef typename boost::property_map< GraphT, boost::vertex_index_t >::const_type VertexIndexMap; return edge_to_index_pair< GraphT, VertexIndexMap >( g, get(boost::vertex_index, g)); } template < typename GraphT, typename VertexIndexMap, typename Iter > boost::transform_iterator< edge_to_index_pair< GraphT, VertexIndexMap >, Iter > make_edge_to_index_pair_iter( const GraphT& g, const VertexIndexMap& index, Iter it) { return boost::transform_iterator< edge_to_index_pair< GraphT, VertexIndexMap >, Iter >( it, edge_to_index_pair< GraphT, VertexIndexMap >(g, index)); } } // namespace detail template < typename Vertex, typename EdgeIndex > struct hash< detail::csr_edge_descriptor< Vertex, EdgeIndex > > { std::size_t operator()( detail::csr_edge_descriptor< Vertex, EdgeIndex > const& x) const { std::size_t hash = hash_value(x.src); hash_combine(hash, x.idx); return hash; } }; } // namespace boost #endif // BOOST_GRAPH_COMPRESSED_SPARSE_ROW_STRUCT_HPP detail/list_base.hpp 0000644 00000012756 15125521275 0010504 0 ustar 00 //======================================================================= // Copyright 2002 Indiana University. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_LIST_BASE_HPP #define BOOST_LIST_BASE_HPP #include <boost/iterator_adaptors.hpp> // Perhaps this should go through formal review, and move to <boost/>. /* An alternate interface idea: Extend the std::list functionality by creating remove/insert functions that do not require the container object! */ namespace boost { namespace detail { //========================================================================= // Linked-List Generic Implementation Functions template < class Node, class Next > inline Node slist_insert_after(Node pos, Node x, Next next) { next(x) = next(pos); next(pos) = x; return x; } // return next(pos) or next(next(pos)) ? template < class Node, class Next > inline Node slist_remove_after(Node pos, Next next) { Node n = next(pos); next(pos) = next(n); return n; } template < class Node, class Next > inline Node slist_remove_range(Node before_first, Node last, Next next) { next(before_first) = last; return last; } template < class Node, class Next > inline Node slist_previous(Node head, Node x, Node empty, Next next) { while (head != empty && next(head) != x) head = next(head); return head; } template < class Node, class Next > inline void slist_splice_after( Node pos, Node before_first, Node before_last, Next next) { if (pos != before_first && pos != before_last) { Node first = next(before_first); Node after = next(pos); next(before_first) = next(before_last); next(pos) = first; next(before_last) = after; } } template < class Node, class Next > inline Node slist_reverse(Node node, Node empty, Next next) { Node result = node; node = next(node); next(result) = empty; while (node) { Node next = next(node); next(node) = result; result = node; node = next; } return result; } template < class Node, class Next > inline std::size_t slist_size(Node head, Node empty, Next next) { std::size_t s = 0; for (; head != empty; head = next(head)) ++s; return s; } template < class Next, class Data > class slist_iterator_policies { public: explicit slist_iterator_policies(const Next& n, const Data& d) : m_next(n), m_data(d) { } template < class Reference, class Node > Reference dereference(type< Reference >, const Node& x) const { return m_data(x); } template < class Node > void increment(Node& x) const { x = m_next(x); } template < class Node > bool equal(Node& x, Node& y) const { return x == y; } protected: Next m_next; Data m_data; }; //=========================================================================== // Doubly-Linked List Generic Implementation Functions template < class Node, class Next, class Prev > inline void dlist_insert_before(Node pos, Node x, Next next, Prev prev) { next(x) = pos; prev(x) = prev(pos); next(prev(pos)) = x; prev(pos) = x; } template < class Node, class Next, class Prev > void dlist_remove(Node pos, Next next, Prev prev) { Node next_node = next(pos); Node prev_node = prev(pos); next(prev_node) = next_node; prev(next_node) = prev_node; } // This deletes every node in the list except the // sentinel node. template < class Node, class Delete > inline void dlist_clear(Node sentinel, Delete del) { Node i, tmp; i = next(sentinel); while (i != sentinel) { tmp = i; i = next(i); del(tmp); } } template < class Node > inline bool dlist_empty(Node dummy) { return next(dummy) == dummy; } template < class Node, class Next, class Prev > void dlist_transfer(Node pos, Node first, Node last, Next next, Prev prev) { if (pos != last) { // Remove [first,last) from its old position next(prev(last)) = pos; next(prev(first)) = last; next(prev(pos)) = first; // Splice [first,last) into its new position Node tmp = prev(pos); prev(pos) = prev(last); prev(last) = prev(first); prev(first) = tmp; } } template < class Next, class Prev, class Data > class dlist_iterator_policies : public slist_iterator_policies< Next, Data > { typedef slist_iterator_policies< Next, Data > Base; public: template < class Node > void decrement(Node& x) const { x = m_prev(x); } dlist_iterator_policies(Next n, Prev p, Data d) : Base(n, d), m_prev(p) { } protected: Prev m_prev; }; } // namespace detail } // namespace boost #endif // BOOST_LIST_BASE_HPP detail/read_graphviz_spirit.hpp 0000644 00000066563 15125521275 0012763 0 ustar 00 // Copyright 2004-9 Trustees of Indiana University // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // read_graphviz_spirit.hpp - // Initialize a model of the BGL's MutableGraph concept and an associated // collection of property maps using a graph expressed in the GraphViz // DOT Language. // // Based on the grammar found at: // https://web.archive.org/web/20041213234742/http://www.graphviz.org/cvs/doc/info/lang.html // // See documentation for this code at: // http://www.boost.org/libs/graph/doc/read_graphviz.html // // Author: Ronald Garcia // #ifndef BOOST_READ_GRAPHVIZ_SPIRIT_HPP #define BOOST_READ_GRAPHVIZ_SPIRIT_HPP // Phoenix/Spirit set these limits to 3, but I need more. #define PHOENIX_LIMIT 6 #define BOOST_SPIRIT_CLOSURE_LIMIT 6 #include <boost/spirit/include/classic_multi_pass.hpp> #include <boost/spirit/include/classic_core.hpp> #include <boost/spirit/include/classic_confix.hpp> #include <boost/spirit/include/classic_distinct.hpp> #include <boost/spirit/include/classic_lists.hpp> #include <boost/spirit/include/classic_escape_char.hpp> #include <boost/spirit/include/classic_attribute.hpp> #include <boost/spirit/include/classic_dynamic.hpp> #include <boost/spirit/include/classic_actor.hpp> #include <boost/spirit/include/classic_closure.hpp> #include <boost/spirit/include/phoenix1.hpp> #include <boost/spirit/include/phoenix1_binders.hpp> #include <boost/ref.hpp> #include <boost/function/function2.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/property_map/dynamic_property_map.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/detail/workaround.hpp> #include <algorithm> #include <exception> // for std::exception #include <string> #include <vector> #include <set> #include <utility> #include <map> #include <boost/graph/graphviz.hpp> #include <boost/throw_exception.hpp> namespace phoenix { // Workaround: std::map::operator[] uses a different return type than all // other standard containers. Phoenix doesn't account for that. template < typename TK, typename T0, typename T1 > struct binary_operator< index_op, std::map< TK, T0 >, T1 > { typedef typename std::map< TK, T0 >::mapped_type& result_type; static result_type eval(std::map< TK, T0 >& container, T1 const& index) { return container[index]; } }; } // namespace phoenix namespace boost { namespace detail { namespace graph { ///////////////////////////////////////////////////////////////////////////// // Application-specific type definitions ///////////////////////////////////////////////////////////////////////////// typedef std::set< edge_t > edges_t; typedef std::set< node_t > nodes_t; typedef std::set< id_t > ids_t; typedef std::map< edge_t, ids_t > edge_map_t; typedef std::map< node_t, ids_t > node_map_t; typedef std::map< id_t, id_t > props_t; typedef std::map< id_t, props_t > subgraph_props_t; typedef boost::function2< void, id_t const&, id_t const& > actor_t; typedef std::vector< edge_t > edge_stack_t; typedef std::map< id_t, nodes_t > subgraph_nodes_t; typedef std::map< id_t, edges_t > subgraph_edges_t; ///////////////////////////////////////////////////////////////////////////// // Stack frames used by semantic actions ///////////////////////////////////////////////////////////////////////////// struct id_closure : boost::spirit::classic::closure< id_closure, node_t > { member1 name; }; struct node_id_closure : boost::spirit::classic::closure< node_id_closure, node_t > { member1 name; }; struct attr_list_closure : boost::spirit::classic::closure< attr_list_closure, actor_t > { member1 prop_actor; }; struct property_closure : boost::spirit::classic::closure< property_closure, id_t, id_t > { member1 key; member2 value; }; struct data_stmt_closure : boost::spirit::classic::closure< data_stmt_closure, nodes_t, nodes_t, edge_stack_t, bool, node_t > { member1 sources; member2 dests; member3 edge_stack; member4 saw_node; member5 active_node; }; struct subgraph_closure : boost::spirit::classic::closure< subgraph_closure, nodes_t, edges_t, node_t > { member1 nodes; member2 edges; member3 name; }; ///////////////////////////////////////////////////////////////////////////// // Grammar and Actions for the DOT Language ///////////////////////////////////////////////////////////////////////////// // Grammar for a dot file. struct dot_grammar : public boost::spirit::classic::grammar< dot_grammar > { mutate_graph& graph_; explicit dot_grammar(mutate_graph& graph) : graph_(graph) {} template < class ScannerT > struct definition { definition(dot_grammar const& self) : self(self), subgraph_depth(0), keyword_p("0-9a-zA-Z_") { using namespace boost::spirit::classic; using namespace phoenix; // RG - Future Work // - Handle multi-line strings using \ line continuation // - Make keywords case insensitive ID = (lexeme_d[( (alpha_p | ch_p('_')) >> *(alnum_p | ch_p('_')))] | real_p | lexeme_d[confix_p('"', *c_escape_ch_p, '"')] | comment_nest_p('<', '>'))[ID.name = construct_< std::string >(arg1, arg2)]; a_list = list_p( ID[(a_list.key = arg1), (a_list.value = "true")] >> !( ch_p('=') >> ID[a_list.value = arg1])[phoenix::bind( &definition::call_prop_actor)( var(*this), a_list.key, a_list.value)], !ch_p(',')); attr_list = +(ch_p('[') >> !a_list >> ch_p(']')); // RG - disregard port id's for now. port_location = (ch_p(':') >> ID) | (ch_p(':') >> ch_p('(') >> ID >> ch_p(',') >> ID >> ch_p(')')); port_angle = ch_p('@') >> ID; port = port_location >> (!port_angle) | port_angle >> (!port_location); node_id = (ID[node_id.name = arg1] >> (!port))[phoenix::bind( &definition::memoize_node)(var(*this))]; graph_stmt = (ID[graph_stmt.key = arg1] >> ch_p('=') >> ID[graph_stmt.value = arg1])[phoenix::bind( &definition::call_graph_prop)(var(*this), graph_stmt.key, graph_stmt.value)]; // Graph property. attr_stmt = (as_lower_d[keyword_p("graph")] >> attr_list(actor_t( phoenix::bind(&definition::default_graph_prop)( var(*this), arg1, arg2)))) | (as_lower_d[keyword_p("node")] >> attr_list(actor_t( phoenix::bind(&definition::default_node_prop)( var(*this), arg1, arg2)))) | (as_lower_d[keyword_p("edge")] >> attr_list(actor_t( phoenix::bind(&definition::default_edge_prop)( var(*this), arg1, arg2)))); // edge_head is set depending on the graph type // (directed/undirected) edgeop = ch_p('-') >> ch_p(boost::ref(edge_head)); edgeRHS = +(edgeop[(data_stmt.sources = data_stmt.dests), (data_stmt.dests = construct_< nodes_t >())] >> (subgraph[data_stmt.dests = arg1] | node_id[phoenix::bind(&definition::insert_node)( var(*this), data_stmt.dests, arg1)]) [phoenix::bind(&definition::activate_edge)( var(*this), data_stmt.sources, data_stmt.dests, var(edges), var(default_edge_props))]); // To avoid backtracking, edge, node, and subgraph // statements are processed as one nonterminal. data_stmt = (subgraph[(data_stmt.dests = arg1), // will get moved in rhs (data_stmt.saw_node = false)] | node_id[(phoenix::bind( &definition::insert_node)( var(*this), data_stmt.dests, arg1)), (data_stmt.saw_node = true), #ifdef BOOST_GRAPH_DEBUG (std::cout << val("AcTive Node: ") << arg1 << "\n"), #endif // BOOST_GRAPH_DEBUG (data_stmt.active_node = arg1)]) >> if_p(edgeRHS)[!attr_list(actor_t(phoenix::bind( &definition::edge_prop)( var(*this), arg1, arg2)))] .else_p[if_p(data_stmt.saw_node)[!attr_list( actor_t(phoenix::bind( &definition::node_prop)(var(*this), arg1, arg2)))] // otherwise it's a subgraph, // nothing more to do. ]; stmt = graph_stmt | attr_stmt | data_stmt; stmt_list = *(stmt >> !ch_p(';')); subgraph = !(as_lower_d[keyword_p("subgraph")] >> (!ID[(subgraph.name = arg1), (subgraph.nodes = (var(subgraph_nodes))[arg1]), (subgraph.edges = (var(subgraph_edges))[arg1])])) >> ch_p('{')[++var(subgraph_depth)] >> stmt_list >> ch_p('}')[--var(subgraph_depth)] [(var(subgraph_nodes))[subgraph.name] = subgraph.nodes] [(var(subgraph_edges))[subgraph.name] = subgraph.edges] | as_lower_d[keyword_p("subgraph")] >> ID[(subgraph.nodes = (var(subgraph_nodes))[arg1]), (subgraph.edges = (var(subgraph_edges))[arg1])]; the_grammar = (!as_lower_d[keyword_p("strict")]) >> (as_lower_d[keyword_p( "graph")][(var(edge_head) = '-'), (phoenix::bind(&definition::check_undirected)( var(*this)))] | as_lower_d[keyword_p( "digraph")][(var(edge_head) = '>'), (phoenix::bind(&definition::check_directed)( var(*this)))]) >> (!ID) >> ch_p('{') >> stmt_list >> ch_p('}'); } // definition() typedef boost::spirit::classic::rule< ScannerT > rule_t; rule_t const& start() const { return the_grammar; } // // Semantic actions // void check_undirected() { if (self.graph_.is_directed()) boost::throw_exception(boost::undirected_graph_error()); } void check_directed() { if (!self.graph_.is_directed()) boost::throw_exception(boost::directed_graph_error()); } void memoize_node() { id_t const& node = node_id.name(); props_t& node_props = default_node_props; if (nodes.find(node) == nodes.end()) { nodes.insert(node); self.graph_.do_add_vertex(node); node_map.insert(std::make_pair(node, ids_t())); #ifdef BOOST_GRAPH_DEBUG std::cout << "Add new node " << node << std::endl; #endif // BOOST_GRAPH_DEBUG // Set the default properties for this edge // RG: Here I would actually set the properties for (props_t::iterator i = node_props.begin(); i != node_props.end(); ++i) { set_node_property(node, i->first, i->second); } if (subgraph_depth > 0) { subgraph.nodes().insert(node); // Set the subgraph's default properties as well props_t& props = subgraph_node_props[subgraph.name()]; for (props_t::iterator i = props.begin(); i != props.end(); ++i) { set_node_property(node, i->first, i->second); } } } else { #ifdef BOOST_GRAPH_DEBUG std::cout << "See node " << node << std::endl; #endif // BOOST_GRAPH_DEBUG } } void activate_edge(nodes_t& sources, nodes_t& dests, edges_t& edges, props_t& edge_props) { edge_stack_t& edge_stack = data_stmt.edge_stack(); for (nodes_t::iterator i = sources.begin(); i != sources.end(); ++i) { for (nodes_t::iterator j = dests.begin(); j != dests.end(); ++j) { // Create the edge and push onto the edge stack. #ifdef BOOST_GRAPH_DEBUG std::cout << "Edge " << *i << " to " << *j << std::endl; #endif // BOOST_GRAPH_DEBUG edge_t edge = edge_t::new_edge(); edge_stack.push_back(edge); edges.insert(edge); edge_map.insert(std::make_pair(edge, ids_t())); // Add the real edge. self.graph_.do_add_edge(edge, *i, *j); // Set the default properties for this edge for (props_t::iterator k = edge_props.begin(); k != edge_props.end(); ++k) { set_edge_property(edge, k->first, k->second); } if (subgraph_depth > 0) { subgraph.edges().insert(edge); // Set the subgraph's default properties as well props_t& props = subgraph_edge_props[subgraph.name()]; for (props_t::iterator k = props.begin(); k != props.end(); ++k) { set_edge_property( edge, k->first, k->second); } } } } } // node_prop - Assign the property for the current active node. void node_prop(id_t const& key, id_t const& value) { node_t& active_object = data_stmt.active_node(); set_node_property(active_object, key, value); } // edge_prop - Assign the property for the current active edges. void edge_prop(id_t const& key, id_t const& value) { edge_stack_t const& active_edges_ = data_stmt.edge_stack(); for (edge_stack_t::const_iterator i = active_edges_.begin(); i != active_edges_.end(); ++i) { set_edge_property(*i, key, value); } } // default_graph_prop - Store as a graph property. void default_graph_prop(id_t const& key, id_t const& value) { #ifdef BOOST_GRAPH_DEBUG std::cout << key << " = " << value << std::endl; #endif // BOOST_GRAPH_DEBUG self.graph_.set_graph_property(key, value); } // default_node_prop - declare default properties for any future // new nodes void default_node_prop(id_t const& key, id_t const& value) { nodes_t& nodes_ = subgraph_depth == 0 ? nodes : subgraph.nodes(); props_t& node_props_ = subgraph_depth == 0 ? default_node_props : subgraph_node_props[subgraph.name()]; // add this to the selected list of default node properties. node_props_[key] = value; // for each node, set its property to default-constructed // value // if it hasn't been set already. // set the dynamic property map value for (nodes_t::iterator i = nodes_.begin(); i != nodes_.end(); ++i) if (node_map[*i].find(key) == node_map[*i].end()) { set_node_property(*i, key, id_t()); } } // default_edge_prop - declare default properties for any future // new edges void default_edge_prop(id_t const& key, id_t const& value) { edges_t& edges_ = subgraph_depth == 0 ? edges : subgraph.edges(); props_t& edge_props_ = subgraph_depth == 0 ? default_edge_props : subgraph_edge_props[subgraph.name()]; // add this to the list of default edge properties. edge_props_[key] = value; // for each edge, set its property to be empty string // set the dynamic property map value for (edges_t::iterator i = edges_.begin(); i != edges_.end(); ++i) if (edge_map[*i].find(key) == edge_map[*i].end()) set_edge_property(*i, key, id_t()); } // helper function void insert_node(nodes_t& nodes, id_t const& name) { nodes.insert(name); } void call_prop_actor( std::string const& lhs, std::string const& rhs) { actor_t& actor = attr_list.prop_actor(); // If first and last characters of the rhs are // double-quotes, remove them. if (!rhs.empty() && rhs[0] == '"' && rhs[rhs.size() - 1] == '"') actor(lhs, rhs.substr(1, rhs.size() - 2)); else actor(lhs, rhs); } void call_graph_prop( std::string const& lhs, std::string const& rhs) { // If first and last characters of the rhs are // double-quotes, remove them. if (!rhs.empty() && rhs[0] == '"' && rhs[rhs.size() - 1] == '"') this->default_graph_prop( lhs, rhs.substr(1, rhs.size() - 2)); else this->default_graph_prop(lhs, rhs); } void set_node_property( node_t const& node, id_t const& key, id_t const& value) { // Add the property key to the "set" table to avoid default // overwrite node_map[node].insert(key); // Set the user's property map self.graph_.set_node_property(key, node, value); #ifdef BOOST_GRAPH_DEBUG // Tell the world std::cout << node << ": " << key << " = " << value << std::endl; #endif // BOOST_GRAPH_DEBUG } void set_edge_property( edge_t const& edge, id_t const& key, id_t const& value) { // Add the property key to the "set" table to avoid default // overwrite edge_map[edge].insert(key); // Set the user's property map self.graph_.set_edge_property(key, edge, value); #ifdef BOOST_GRAPH_DEBUG // Tell the world #if 0 // RG - edge representation changed, std::cout << "(" << edge.first << "," << edge.second << "): " #else std::cout << "an edge: " #endif // 0 << key << " = " << value << std::endl; #endif // BOOST_GRAPH_DEBUG } // Variables explicitly initialized dot_grammar const& self; // if subgraph_depth > 0, then we're processing a subgraph. int subgraph_depth; // Keywords; const boost::spirit::classic::distinct_parser<> keyword_p; // // rules that make up the grammar // boost::spirit::classic::rule< ScannerT, id_closure::context_t > ID; boost::spirit::classic::rule< ScannerT, property_closure::context_t > a_list; boost::spirit::classic::rule< ScannerT, attr_list_closure::context_t > attr_list; rule_t port_location; rule_t port_angle; rule_t port; boost::spirit::classic::rule< ScannerT, node_id_closure::context_t > node_id; boost::spirit::classic::rule< ScannerT, property_closure::context_t > graph_stmt; rule_t attr_stmt; boost::spirit::classic::rule< ScannerT, data_stmt_closure::context_t > data_stmt; boost::spirit::classic::rule< ScannerT, subgraph_closure::context_t > subgraph; rule_t edgeop; rule_t edgeRHS; rule_t stmt; rule_t stmt_list; rule_t the_grammar; // The grammar uses edge_head to dynamically set the syntax for // edges directed graphs: edge_head = '>', and so edgeop = "->" // undirected graphs: edge_head = '-', and so edgeop = "--" char edge_head; // // Support data structures // nodes_t nodes; // list of node names seen edges_t edges; // list of edges seen node_map_t node_map; // remember the properties set for each node edge_map_t edge_map; // remember the properties set for each edge subgraph_nodes_t subgraph_nodes; // per-subgraph lists of nodes subgraph_edges_t subgraph_edges; // per-subgraph lists of edges props_t default_node_props; // global default node properties props_t default_edge_props; // global default edge properties subgraph_props_t subgraph_node_props; // per-subgraph default node properties subgraph_props_t subgraph_edge_props; // per-subgraph default edge properties }; // struct definition }; // struct dot_grammar // // dot_skipper - GraphViz whitespace and comment skipper // struct dot_skipper : public boost::spirit::classic::grammar< dot_skipper > { dot_skipper() {} template < typename ScannerT > struct definition { definition(dot_skipper const& /*self*/) { using namespace boost::spirit::classic; using namespace phoenix; // comment forms skip = eol_p >> comment_p("#") | space_p | comment_p("//") #if BOOST_WORKAROUND(BOOST_MSVC, <= 1400) | confix_p(str_p("/*"), *anychar_p, str_p("*/")) #else | confix_p("/*", *anychar_p, "*/") #endif ; #ifdef BOOST_SPIRIT_DEBUG BOOST_SPIRIT_DEBUG_RULE(skip); #endif } boost::spirit::classic::rule< ScannerT > skip; boost::spirit::classic::rule< ScannerT > const& start() const { return skip; } }; // definition }; // dot_skipper } // namespace graph } // namespace detail template < typename MultiPassIterator, typename MutableGraph > bool read_graphviz_spirit(MultiPassIterator begin, MultiPassIterator end, MutableGraph& graph, dynamic_properties& dp, std::string const& node_id = "node_id") { using namespace boost; using namespace boost::spirit::classic; typedef MultiPassIterator iterator_t; typedef skip_parser_iteration_policy< boost::detail::graph::dot_skipper > iter_policy_t; typedef scanner_policies< iter_policy_t > scanner_policies_t; typedef scanner< iterator_t, scanner_policies_t > scanner_t; ::boost::detail::graph::mutate_graph_impl< MutableGraph > m_graph( graph, dp, node_id); ::boost::detail::graph::dot_grammar p(m_graph); ::boost::detail::graph::dot_skipper skip_p; iter_policy_t iter_policy(skip_p); scanner_policies_t policies(iter_policy); scanner_t scan(begin, end, policies); bool ok = p.parse(scan); m_graph.finish_building_graph(); return ok; } } // namespace boost #endif // BOOST_READ_GRAPHVIZ_SPIRIT_HPP detail/incidence_iterator.hpp 0000644 00000005171 15125521275 0012362 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_DETAIL_INCIDENCE_ITERATOR_HPP #define BOOST_GRAPH_DETAIL_INCIDENCE_ITERATOR_HPP #include <utility> #include <iterator> // OBSOLETE namespace boost { namespace detail { // EdgeDir tags struct in_edge_tag { }; struct out_edge_tag { }; template < class Vertex, class Edge, class Iterator1D, class EdgeDir > struct bidir_incidence_iterator { typedef bidir_incidence_iterator self; typedef Edge edge_type; typedef typename Edge::property_type EdgeProperty; public: typedef int difference_type; typedef std::forward_iterator_tag iterator_category; typedef edge_type reference; typedef edge_type value_type; typedef value_type* pointer; inline bidir_incidence_iterator() {} inline bidir_incidence_iterator(Iterator1D ii, Vertex src) : i(ii), _src(src) { } inline self& operator++() { ++i; return *this; } inline self operator++(int) { self tmp = *this; ++(*this); return tmp; } inline reference operator*() const { return deref_helper(EdgeDir()); } inline self* operator->() { return this; } Iterator1D& iter() { return i; } const Iterator1D& iter() const { return i; } Iterator1D i; Vertex _src; protected: inline reference deref_helper(out_edge_tag) const { return edge_type(_src, (*i).get_target(), &(*i).get_property()); } inline reference deref_helper(in_edge_tag) const { return edge_type((*i).get_target(), _src, &(*i).get_property()); } }; template < class V, class E, class Iter, class Dir > inline bool operator==(const bidir_incidence_iterator< V, E, Iter, Dir >& x, const bidir_incidence_iterator< V, E, Iter, Dir >& y) { return x.i == y.i; } template < class V, class E, class Iter, class Dir > inline bool operator!=(const bidir_incidence_iterator< V, E, Iter, Dir >& x, const bidir_incidence_iterator< V, E, Iter, Dir >& y) { return x.i != y.i; } } } #endif detail/adj_list_edge_iterator.hpp 0000644 00000007623 15125521275 0013222 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_DETAIL_ADJ_LIST_EDGE_ITERATOR_HPP #define BOOST_GRAPH_DETAIL_ADJ_LIST_EDGE_ITERATOR_HPP #include <iterator> #include <utility> #include <boost/detail/workaround.hpp> #if BOOST_WORKAROUND(__IBMCPP__, <= 600) #define BOOST_GRAPH_NO_OPTIONAL #endif #ifdef BOOST_GRAPH_NO_OPTIONAL #define BOOST_GRAPH_MEMBER . #else #define BOOST_GRAPH_MEMBER -> #include <boost/optional.hpp> #endif // ndef BOOST_GRAPH_NO_OPTIONAL namespace boost { namespace detail { template < class VertexIterator, class OutEdgeIterator, class Graph > class adj_list_edge_iterator { typedef adj_list_edge_iterator self; public: typedef std::forward_iterator_tag iterator_category; typedef typename OutEdgeIterator::value_type value_type; typedef typename OutEdgeIterator::reference reference; typedef typename OutEdgeIterator::pointer pointer; typedef typename OutEdgeIterator::difference_type difference_type; typedef difference_type distance_type; inline adj_list_edge_iterator() {} inline adj_list_edge_iterator(const self& x) : vBegin(x.vBegin) , vCurr(x.vCurr) , vEnd(x.vEnd) , edges(x.edges) , m_g(x.m_g) { } template < class G > inline adj_list_edge_iterator( VertexIterator b, VertexIterator c, VertexIterator e, const G& g) : vBegin(b), vCurr(c), vEnd(e), m_g(&g) { if (vCurr != vEnd) { while (vCurr != vEnd && out_degree(*vCurr, *m_g) == 0) ++vCurr; if (vCurr != vEnd) edges = out_edges(*vCurr, *m_g); } } /*Note: In the directed graph cases, it is fine. For undirected graphs, one edge go through twice. */ inline self& operator++() { ++edges BOOST_GRAPH_MEMBER first; if (edges BOOST_GRAPH_MEMBER first == edges BOOST_GRAPH_MEMBER second) { ++vCurr; while (vCurr != vEnd && out_degree(*vCurr, *m_g) == 0) ++vCurr; if (vCurr != vEnd) edges = out_edges(*vCurr, *m_g); } return *this; } inline self operator++(int) { self tmp = *this; ++(*this); return tmp; } inline value_type operator*() const { return *edges BOOST_GRAPH_MEMBER first; } inline bool operator==(const self& x) const { return vCurr == x.vCurr && (vCurr == vEnd || edges BOOST_GRAPH_MEMBER first == x.edges BOOST_GRAPH_MEMBER first); } inline bool operator!=(const self& x) const { return vCurr != x.vCurr || (vCurr != vEnd && edges BOOST_GRAPH_MEMBER first != x.edges BOOST_GRAPH_MEMBER first); } protected: VertexIterator vBegin; VertexIterator vCurr; VertexIterator vEnd; #ifdef BOOST_GRAPH_NO_OPTIONAL std::pair< OutEdgeIterator, OutEdgeIterator > edges; #else boost::optional< std::pair< OutEdgeIterator, OutEdgeIterator > > edges; #endif // ndef BOOST_GRAPH_NO_OPTIONAL const Graph* m_g; }; } // namespace detail } #undef BOOST_GRAPH_MEMBER #endif // BOOST_GRAPH_DETAIL_ADJ_LIST_EDGE_ITERATOR_HPP detail/sparse_ordering.hpp 0000644 00000014343 15125521275 0011717 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Copyright 2004, 2005 Trustees of Indiana University // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, // Doug Gregor, D. Kevin McGrath // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //=======================================================================// #ifndef BOOST_GRAPH_DETAIL_SPARSE_ORDERING_HPP #define BOOST_GRAPH_DETAIL_SPARSE_ORDERING_HPP #include <boost/config.hpp> #include <vector> #include <queue> #include <boost/pending/queue.hpp> #include <boost/pending/mutable_queue.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/properties.hpp> #include <boost/pending/indirect_cmp.hpp> #include <boost/property_map/property_map.hpp> #include <boost/bind.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/graph/depth_first_search.hpp> namespace boost { namespace sparse { // rcm_queue // // This is a custom queue type used in the // *_ordering algorithms. // In addition to the normal queue operations, the // rcm_queue provides: // // int eccentricity() const; // value_type spouse() const; // // yes, it's a bad name...but it works, so use it template < class Vertex, class DegreeMap, class Container = std::deque< Vertex > > class rcm_queue : public std::queue< Vertex, Container > { typedef std::queue< Vertex > base; public: typedef typename base::value_type value_type; typedef typename base::size_type size_type; /* SGI queue has not had a contructor queue(const Container&) */ inline rcm_queue(DegreeMap deg) : _size(0), Qsize(1), eccen(-1), degree(deg) { } inline void pop() { if (!_size) Qsize = base::size(); base::pop(); if (_size == Qsize - 1) { _size = 0; ++eccen; } else ++_size; } inline value_type& front() { value_type& u = base::front(); if (_size == 0) w = u; else if (get(degree, u) < get(degree, w)) w = u; return u; } inline const value_type& front() const { const value_type& u = base::front(); if (_size == 0) w = u; else if (get(degree, u) < get(degree, w)) w = u; return u; } inline value_type& top() { return front(); } inline const value_type& top() const { return front(); } inline size_type size() const { return base::size(); } inline size_type eccentricity() const { return eccen; } inline value_type spouse() const { return w; } protected: size_type _size; size_type Qsize; int eccen; mutable value_type w; DegreeMap degree; }; template < typename Tp, typename Sequence = std::deque< Tp > > class sparse_ordering_queue : public boost::queue< Tp, Sequence > { public: typedef typename Sequence::iterator iterator; typedef typename Sequence::reverse_iterator reverse_iterator; typedef queue< Tp, Sequence > base; typedef typename Sequence::size_type size_type; inline iterator begin() { return this->c.begin(); } inline reverse_iterator rbegin() { return this->c.rbegin(); } inline iterator end() { return this->c.end(); } inline reverse_iterator rend() { return this->c.rend(); } inline Tp& operator[](int n) { return this->c[n]; } inline size_type size() { return this->c.size(); } protected: // nothing }; } // namespace sparse // Compute Pseudo peripheral // // To compute an approximated peripheral for a given vertex. // Used in <tt>king_ordering</tt> algorithm. // template < class Graph, class Vertex, class ColorMap, class DegreeMap > Vertex pseudo_peripheral_pair( Graph const& G, const Vertex& u, int& ecc, ColorMap color, DegreeMap degree) { typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; sparse::rcm_queue< Vertex, DegreeMap > Q(degree); typename boost::graph_traits< Graph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(G); ui != ui_end; ++ui) if (get(color, *ui) != Color::red()) put(color, *ui, Color::white()); breadth_first_visit(G, u, buffer(Q).color_map(color)); ecc = Q.eccentricity(); return Q.spouse(); } // Find a good starting node // // This is to find a good starting node for the // king_ordering algorithm. "good" is in the sense // of the ordering generated by RCM. // template < class Graph, class Vertex, class Color, class Degree > Vertex find_starting_node(Graph const& G, Vertex r, Color color, Degree degree) { Vertex x, y; int eccen_r, eccen_x; x = pseudo_peripheral_pair(G, r, eccen_r, color, degree); y = pseudo_peripheral_pair(G, x, eccen_x, color, degree); while (eccen_x > eccen_r) { r = x; eccen_r = eccen_x; x = y; y = pseudo_peripheral_pair(G, x, eccen_x, color, degree); } return x; } template < typename Graph > class out_degree_property_map : public put_get_helper< typename graph_traits< Graph >::degree_size_type, out_degree_property_map< Graph > > { public: typedef typename graph_traits< Graph >::vertex_descriptor key_type; typedef typename graph_traits< Graph >::degree_size_type value_type; typedef value_type reference; typedef readable_property_map_tag category; out_degree_property_map(const Graph& g) : m_g(g) {} value_type operator[](const key_type& v) const { return out_degree(v, m_g); } private: const Graph& m_g; }; template < typename Graph > inline out_degree_property_map< Graph > make_out_degree_map(const Graph& g) { return out_degree_property_map< Graph >(g); } } // namespace boost #endif // BOOST_GRAPH_KING_HPP detail/mpi_include.hpp 0000644 00000001030 15125521275 0011006 0 ustar 00 #ifndef BOOST_GRAPH_DETAIL_MPI_INCLUDE_HPP_INCLUDED #define BOOST_GRAPH_DETAIL_MPI_INCLUDE_HPP_INCLUDED // Copyright 2018 Peter Dimov // // 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) #if defined BOOST_GRAPH_USE_MPI #define BOOST_GRAPH_MPI_INCLUDE(x) x #else #define BOOST_GRAPH_MPI_INCLUDE(x) <boost/graph/detail/empty_header.hpp> #endif #endif // #ifndef BOOST_GRAPH_DETAIL_MPI_INCLUDE_HPP_INCLUDED detail/indexed_properties.hpp 0000644 00000022314 15125521275 0012422 0 ustar 00 // Copyright 2005 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Jeremiah Willcock // Douglas Gregor // Andrew Lumsdaine // Indexed properties -- used for CSR and CSR-like graphs #ifndef BOOST_GRAPH_INDEXED_PROPERTIES_HPP #define BOOST_GRAPH_INDEXED_PROPERTIES_HPP #include <vector> #include <utility> #include <algorithm> #include <climits> #include <iterator> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/iterator/counting_iterator.hpp> #include <boost/integer.hpp> #include <boost/iterator/iterator_facade.hpp> #include <boost/property_map/property_map.hpp> #include <boost/mpl/if.hpp> namespace boost { namespace detail { template < typename Derived, typename Property, typename Descriptor, typename IndexMap > class indexed_vertex_properties { public: typedef no_property vertex_property_type; typedef Property vertex_bundled; typedef iterator_property_map< typename std::vector< Property >::iterator, IndexMap > vertex_map_type; typedef iterator_property_map< typename std::vector< Property >::const_iterator, IndexMap > const_vertex_map_type; // Directly access a vertex or edge bundle Property& operator[](Descriptor v) { return m_vertex_properties[get(vertex_index, derived(), v)]; } const Property& operator[](Descriptor v) const { return m_vertex_properties[get(vertex_index, derived(), v)]; } vertex_map_type get_vertex_bundle( const IndexMap& index_map = IndexMap()) { return vertex_map_type(m_vertex_properties.begin(), index_map); } const_vertex_map_type get_vertex_bundle( const IndexMap& index_map = IndexMap()) const { return const_vertex_map_type( m_vertex_properties.begin(), index_map); } protected: // Default-construct with no property values indexed_vertex_properties() {} // Initialize with n default-constructed property values indexed_vertex_properties(std::size_t n) : m_vertex_properties(n) {} public: // Clear the properties vector void clear() { m_vertex_properties.clear(); } // Resize the properties vector void resize(std::size_t n) { m_vertex_properties.resize(n); } // Reserve space in the vector of properties void reserve(std::size_t n) { m_vertex_properties.reserve(n); } // Add a new property value to the back void push_back(const Property& prop) { m_vertex_properties.push_back(prop); } // Write an element by raw index void write_by_index(std::size_t idx, const Property& prop) { m_vertex_properties[idx] = prop; } // Access to the derived object Derived& derived() { return *static_cast< Derived* >(this); } const Derived& derived() const { return *static_cast< const Derived* >(this); } public: // should be private, but friend templates not portable std::vector< Property > m_vertex_properties; }; template < typename Derived, typename Descriptor, typename IndexMap > class indexed_vertex_properties< Derived, void, Descriptor, IndexMap > { struct secret { }; public: typedef no_property vertex_property_type; typedef void vertex_bundled; typedef secret vertex_map_type; typedef secret const_vertex_map_type; secret operator[](secret) { return secret(); } vertex_map_type get_vertex_bundle() const { return vertex_map_type(); } protected: // All operations do nothing. indexed_vertex_properties() {} indexed_vertex_properties(std::size_t) {} public: void clear() {} void resize(std::size_t) {} void reserve(std::size_t) {} }; template < typename Derived, typename Property, typename Descriptor, typename IndexMap > class indexed_edge_properties { public: typedef no_property edge_property_type; typedef Property edge_bundled; typedef Property edge_push_back_type; typedef iterator_property_map< typename std::vector< Property >::iterator, IndexMap > edge_map_type; typedef iterator_property_map< typename std::vector< Property >::const_iterator, IndexMap > const_edge_map_type; // Directly access a edge or edge bundle Property& operator[](Descriptor v) { return m_edge_properties[get(edge_index, derived(), v)]; } const Property& operator[](Descriptor v) const { return m_edge_properties[get(edge_index, derived(), v)]; } edge_map_type get_edge_bundle(const IndexMap& index_map = IndexMap()) { return edge_map_type(m_edge_properties.begin(), index_map); } const_edge_map_type get_edge_bundle( const IndexMap& index_map = IndexMap()) const { return const_edge_map_type(m_edge_properties.begin(), index_map); } protected: // Default-construct with no property values indexed_edge_properties() {} // Initialize with n default-constructed property values indexed_edge_properties(std::size_t n) : m_edge_properties(n) {} // Get the size of the properties vector std::size_t size() const { return m_edge_properties.size(); } // Clear the properties vector void clear() { m_edge_properties.clear(); } // Resize the properties vector void resize(std::size_t n) { m_edge_properties.resize(n); } // Reserve space in the vector of properties void reserve(std::size_t n) { m_edge_properties.reserve(n); } // Write an element by raw index void write_by_index(std::size_t idx, const Property& prop) { m_edge_properties[idx] = prop; } public: // Add a new property value to the back void push_back(const Property& prop) { m_edge_properties.push_back(prop); } // Move range of properties backwards void move_range( std::size_t src_begin, std::size_t src_end, std::size_t dest_begin) { std::copy_backward(m_edge_properties.begin() + src_begin, m_edge_properties.begin() + src_end, m_edge_properties.begin() + dest_begin + (src_end - src_begin)); } typedef typename std::vector< Property >::iterator iterator; iterator begin() { return m_edge_properties.begin(); } iterator end() { return m_edge_properties.end(); } private: // Access to the derived object Derived& derived() { return *static_cast< Derived* >(this); } const Derived& derived() const { return *static_cast< const Derived* >(this); } public: // should be private, but friend templates not portable std::vector< Property > m_edge_properties; }; struct dummy_no_property_iterator : public boost::iterator_facade< dummy_no_property_iterator, no_property, std::random_access_iterator_tag > { mutable no_property prop; no_property& dereference() const { return prop; } bool equal(const dummy_no_property_iterator&) const { return true; } void increment() {} void decrement() {} void advance(std::ptrdiff_t) {} std::ptrdiff_t distance_to(const dummy_no_property_iterator) const { return 0; } }; template < typename Derived, typename Descriptor, typename IndexMap > class indexed_edge_properties< Derived, void, Descriptor, IndexMap > { struct secret { }; public: typedef no_property edge_property_type; typedef void edge_bundled; typedef void* edge_push_back_type; typedef secret edge_map_type; typedef secret const_edge_map_type; secret operator[](secret) { return secret(); } void write_by_index(std::size_t /*idx*/, const no_property& /*prop*/) {} edge_map_type get_edge_bundle(const IndexMap& = IndexMap()) const { return edge_map_type(); } protected: // All operations do nothing. indexed_edge_properties() {} indexed_edge_properties(std::size_t) {} std::size_t size() const { return 0; } void clear() {} void resize(std::size_t) {} void reserve(std::size_t) {} public: void push_back(const edge_push_back_type&) {} void move_range(std::size_t /*src_begin*/, std::size_t /*src_end*/, std::size_t /*dest_begin*/) { } typedef dummy_no_property_iterator iterator; iterator begin() { return dummy_no_property_iterator(); } iterator end() { return dummy_no_property_iterator(); } }; } } #endif // BOOST_GRAPH_INDEXED_PROPERTIES_HPP detail/self_avoiding_walk.hpp 0000644 00000036760 15125521275 0012367 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_SELF_AVOIDING_WALK_HPP #define BOOST_SELF_AVOIDING_WALK_HPP /* This file defines necessary components for SAW. mesh language: (defined by myself to clearify what is what) A triangle in mesh is called an triangle. An edge in mesh is called an line. A vertex in mesh is called a point. A triangular mesh corresponds to a graph in which a vertex is a triangle and an edge(u, v) stands for triangle u and triangle v share an line. After this point, a vertex always refers to vertex in graph, therefore it is a traingle in mesh. */ #include <utility> #include <boost/config.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/property_map/property_map.hpp> #define SAW_SENTINAL -1 namespace boost { template < class T1, class T2, class T3 > struct triple { T1 first; T2 second; T3 third; triple(const T1& a, const T2& b, const T3& c) : first(a), second(b), third(c) { } triple() : first(SAW_SENTINAL), second(SAW_SENTINAL), third(SAW_SENTINAL) {} }; typedef triple< int, int, int > Triple; /* Define a vertex property which has a triangle inside. Triangle is represented by a triple. */ struct triangle_tag { enum { num = 100 }; }; typedef property< triangle_tag, Triple > triangle_property; /* Define an edge property with a line. A line is represented by a pair. This is not required for SAW though. */ struct line_tag { enum { num = 101 }; }; template < class T > struct line_property : public property< line_tag, std::pair< T, T > > { }; /*Precondition: Points in a Triangle are in order */ template < class Triangle, class Line > inline void get_sharing(const Triangle& a, const Triangle& b, Line& l) { l.first = SAW_SENTINAL; l.second = SAW_SENTINAL; if (a.first == b.first) { l.first = a.first; if (a.second == b.second || a.second == b.third) l.second = a.second; else if (a.third == b.second || a.third == b.third) l.second = a.third; } else if (a.first == b.second) { l.first = a.first; if (a.second == b.third) l.second = a.second; else if (a.third == b.third) l.second = a.third; } else if (a.first == b.third) { l.first = a.first; } else if (a.second == b.first) { l.first = a.second; if (a.third == b.second || a.third == b.third) l.second = a.third; } else if (a.second == b.second) { l.first = a.second; if (a.third == b.third) l.second = a.third; } else if (a.second == b.third) { l.first = a.second; } else if (a.third == b.first || a.third == b.second || a.third == b.third) l.first = a.third; /*Make it in order*/ if (l.first > l.second) { typename Line::first_type i = l.first; l.first = l.second; l.second = i; } } template < class TriangleDecorator, class Vertex, class Line > struct get_vertex_sharing { typedef std::pair< Vertex, Line > Pair; get_vertex_sharing(const TriangleDecorator& _td) : td(_td) {} inline Line operator()(const Vertex& u, const Vertex& v) const { Line l; get_sharing(td[u], td[v], l); return l; } inline Line operator()(const Pair& u, const Vertex& v) const { Line l; get_sharing(td[u.first], td[v], l); return l; } inline Line operator()(const Pair& u, const Pair& v) const { Line l; get_sharing(td[u.first], td[v.first], l); return l; } TriangleDecorator td; }; /* HList has to be a handle of data holder so that pass-by-value is * in right logic. * * The element of HList is a pair of vertex and line. (remember a * line is a pair of two ints.). That indicates the walk w from * current vertex is across line. (If the first of line is -1, it is * a point though. */ template < class TriangleDecorator, class HList, class IteratorD > class SAW_visitor : public bfs_visitor<>, public dfs_visitor<> { typedef typename boost::property_traits< IteratorD >::value_type iter; /*use boost shared_ptr*/ typedef typename HList::element_type::value_type::second_type Line; public: typedef tree_edge_tag category; inline SAW_visitor(TriangleDecorator _td, HList _hlist, IteratorD ia) : td(_td), hlist(_hlist), iter_d(ia) { } template < class Vertex, class Graph > inline void start_vertex(Vertex v, Graph&) { Line l1; l1.first = SAW_SENTINAL; l1.second = SAW_SENTINAL; hlist->push_front(std::make_pair(v, l1)); iter_d[v] = hlist->begin(); } /*Several symbols: w(i): i-th triangle in walk w w(i) |- w(i+1): w enter w(i+1) from w(i) over a line w(i) ~> w(i+1): w enter w(i+1) from w(i) over a point w(i) -> w(i+1): w enter w(i+1) from w(i) w(i) ^ w(i+1): the line or point w go over from w(i) to w(i+1) */ template < class Edge, class Graph > bool tree_edge(Edge e, Graph& G) { using std::make_pair; typedef typename boost::graph_traits< Graph >::vertex_descriptor Vertex; Vertex tau = target(e, G); Vertex i = source(e, G); get_vertex_sharing< TriangleDecorator, Vertex, Line > get_sharing_line( td); Line tau_i = get_sharing_line(tau, i); iter w_end = hlist->end(); iter w_i = iter_d[i]; iter w_i_m_1 = w_i; iter w_i_p_1 = w_i; /*---------------------------------------------------------- * true false *========================================================== *a w(i-1) |- w(i) w(i-1) ~> w(i) or w(i-1) is null *---------------------------------------------------------- *b w(i) |- w(i+1) w(i) ~> w(i+1) or no w(i+1) yet *---------------------------------------------------------- */ bool a = false, b = false; --w_i_m_1; ++w_i_p_1; b = (w_i->second.first != SAW_SENTINAL); if (w_i_m_1 != w_end) { a = (w_i_m_1->second.first != SAW_SENTINAL); } if (a) { if (b) { /*Case 1: w(i-1) |- w(i) |- w(i+1) */ Line l1 = get_sharing_line(*w_i_m_1, tau); iter w_i_m_2 = w_i_m_1; --w_i_m_2; bool c = true; if (w_i_m_2 != w_end) { c = w_i_m_2->second != l1; } if (c) { /* w(i-1) ^ tau != w(i-2) ^ w(i-1) */ /*extension: w(i-1) -> tau |- w(i) */ w_i_m_1->second = l1; /*insert(pos, const T&) is to insert before pos*/ iter_d[tau] = hlist->insert(w_i, make_pair(tau, tau_i)); } else { /* w(i-1) ^ tau == w(i-2) ^ w(i-1) */ /*must be w(i-2) ~> w(i-1) */ bool d = true; // need to handle the case when w_i_p_1 is null Line l3 = get_sharing_line(*w_i_p_1, tau); if (w_i_p_1 != w_end) d = w_i_p_1->second != l3; if (d) { /* w(i+1) ^ tau != w(i+1) ^ w(i+2) */ /*extension: w(i) |- tau -> w(i+1) */ w_i->second = tau_i; iter_d[tau] = hlist->insert(w_i_p_1, make_pair(tau, l3)); } else { /* w(i+1) ^ tau == w(i+1) ^ w(i+2) */ /*must be w(1+1) ~> w(i+2) */ Line l5 = get_sharing_line(*w_i_m_1, *w_i_p_1); if (l5 != w_i_p_1->second) { /* w(i-1) ^ w(i+1) != w(i+1) ^ w(i+2) */ /*extension: w(i-2) -> tau |- w(i) |- w(i-1) -> * w(i+1) */ w_i_m_2->second = get_sharing_line(*w_i_m_2, tau); iter_d[tau] = hlist->insert(w_i, make_pair(tau, tau_i)); w_i->second = w_i_m_1->second; w_i_m_1->second = l5; iter_d[w_i_m_1->first] = hlist->insert(w_i_p_1, *w_i_m_1); hlist->erase(w_i_m_1); } else { /*mesh is tetrahedral*/ // dont know what that means. ; } } } } else { /*Case 2: w(i-1) |- w(i) ~> w(1+1) */ if (w_i->second.second == tau_i.first || w_i->second.second == tau_i.second) { /*w(i) ^ w(i+1) < w(i) ^ tau*/ /*extension: w(i) |- tau -> w(i+1) */ w_i->second = tau_i; Line l1 = get_sharing_line(*w_i_p_1, tau); iter_d[tau] = hlist->insert(w_i_p_1, make_pair(tau, l1)); } else { /*w(i) ^ w(i+1) !< w(i) ^ tau*/ Line l1 = get_sharing_line(*w_i_m_1, tau); bool c = true; iter w_i_m_2 = w_i_m_1; --w_i_m_2; if (w_i_m_2 != w_end) c = l1 != w_i_m_2->second; if (c) { /*w(i-1) ^ tau != w(i-2) ^ w(i-1)*/ /*extension: w(i-1) -> tau |- w(i)*/ w_i_m_1->second = l1; iter_d[tau] = hlist->insert(w_i, make_pair(tau, tau_i)); } else { /*w(i-1) ^ tau == w(i-2) ^ w(i-1)*/ /*must be w(i-2)~>w(i-1)*/ /*extension: w(i-2) -> tau |- w(i) |- w(i-1) -> w(i+1)*/ w_i_m_2->second = get_sharing_line(*w_i_m_2, tau); iter_d[tau] = hlist->insert(w_i, make_pair(tau, tau_i)); w_i->second = w_i_m_1->second; w_i_m_1->second = get_sharing_line(*w_i_m_1, *w_i_p_1); iter_d[w_i_m_1->first] = hlist->insert(w_i_p_1, *w_i_m_1); hlist->erase(w_i_m_1); } } } } else { if (b) { /*Case 3: w(i-1) ~> w(i) |- w(i+1) */ bool c = false; if (w_i_m_1 != w_end) c = (w_i_m_1->second.second == tau_i.first) || (w_i_m_1->second.second == tau_i.second); if (c) { /*w(i-1) ^ w(i) < w(i) ^ tau*/ /* extension: w(i-1) -> tau |- w(i) */ if (w_i_m_1 != w_end) w_i_m_1->second = get_sharing_line(*w_i_m_1, tau); iter_d[tau] = hlist->insert(w_i, make_pair(tau, tau_i)); } else { bool d = true; Line l1; l1.first = SAW_SENTINAL; l1.second = SAW_SENTINAL; if (w_i_p_1 != w_end) { l1 = get_sharing_line(*w_i_p_1, tau); d = l1 != w_i_p_1->second; } if (d) { /*w(i+1) ^ tau != w(i+1) ^ w(i+2)*/ /*extension: w(i) |- tau -> w(i+1) */ w_i->second = tau_i; iter_d[tau] = hlist->insert(w_i_p_1, make_pair(tau, l1)); } else { /*must be w(i+1) ~> w(i+2)*/ /*extension: w(i-1) -> w(i+1) |- w(i) |- tau -> w(i+2) */ iter w_i_p_2 = w_i_p_1; ++w_i_p_2; w_i_p_1->second = w_i->second; iter_d[i] = hlist->insert(w_i_p_2, make_pair(i, tau_i)); hlist->erase(w_i); Line l2 = get_sharing_line(*w_i_p_2, tau); iter_d[tau] = hlist->insert(w_i_p_2, make_pair(tau, l2)); } } } else { /*Case 4: w(i-1) ~> w(i) ~> w(i+1) */ bool c = false; if (w_i_m_1 != w_end) { c = (w_i_m_1->second.second == tau_i.first) || (w_i_m_1->second.second == tau_i.second); } if (c) { /*w(i-1) ^ w(i) < w(i) ^ tau */ /*extension: w(i-1) -> tau |- w(i) */ if (w_i_m_1 != w_end) w_i_m_1->second = get_sharing_line(*w_i_m_1, tau); iter_d[tau] = hlist->insert(w_i, make_pair(tau, tau_i)); } else { /*extension: w(i) |- tau -> w(i+1) */ w_i->second = tau_i; Line l1; l1.first = SAW_SENTINAL; l1.second = SAW_SENTINAL; if (w_i_p_1 != w_end) l1 = get_sharing_line(*w_i_p_1, tau); iter_d[tau] = hlist->insert(w_i_p_1, make_pair(tau, l1)); } } } return true; } protected: TriangleDecorator td; /*a decorator for vertex*/ HList hlist; /*This must be a handle of list to record the SAW The element type of the list is pair<Vertex, Line> */ IteratorD iter_d; /*Problem statement: Need a fast access to w for triangle i. *Possible solution: mantain an array to record. iter_d[i] will return an iterator which points to w(i), where i is a vertex representing triangle i. */ }; template < class Triangle, class HList, class Iterator > inline SAW_visitor< Triangle, HList, Iterator > visit_SAW( Triangle t, HList hl, Iterator i) { return SAW_visitor< Triangle, HList, Iterator >(t, hl, i); } template < class Tri, class HList, class Iter > inline SAW_visitor< random_access_iterator_property_map< Tri*, Tri, Tri& >, HList, random_access_iterator_property_map< Iter*, Iter, Iter& > > visit_SAW_ptr(Tri* t, HList hl, Iter* i) { typedef random_access_iterator_property_map< Tri*, Tri, Tri& > TriD; typedef random_access_iterator_property_map< Iter*, Iter, Iter& > IterD; return SAW_visitor< TriD, HList, IterD >(t, hl, i); } // should also have combo's of pointers, and also const :( } #endif /*BOOST_SAW_H*/ detail/augment.hpp 0000644 00000004365 15125521275 0010174 0 ustar 00 //======================================================================= // Copyright 2013 University of Warsaw. // Authors: Piotr Wygocki // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_AUGMENT_HPP #define BOOST_GRAPH_AUGMENT_HPP #include <boost/graph/filtered_graph.hpp> namespace boost { namespace detail { template < class Graph, class ResCapMap > filtered_graph< const Graph, is_residual_edge< ResCapMap > > residual_graph( const Graph& g, ResCapMap residual_capacity) { return filtered_graph< const Graph, is_residual_edge< ResCapMap > >( g, is_residual_edge< ResCapMap >(residual_capacity)); } template < class Graph, class PredEdgeMap, class ResCapMap, class RevEdgeMap > inline void augment(const Graph& g, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink, PredEdgeMap p, ResCapMap residual_capacity, RevEdgeMap reverse_edge) { typename graph_traits< Graph >::edge_descriptor e; typename graph_traits< Graph >::vertex_descriptor u; typedef typename property_traits< ResCapMap >::value_type FlowValue; // find minimum residual capacity along the augmenting path FlowValue delta = (std::numeric_limits< FlowValue >::max)(); e = get(p, sink); do { BOOST_USING_STD_MIN(); delta = min BOOST_PREVENT_MACRO_SUBSTITUTION( delta, get(residual_capacity, e)); u = source(e, g); e = get(p, u); } while (u != src); // push delta units of flow along the augmenting path e = get(p, sink); do { put(residual_capacity, e, get(residual_capacity, e) - delta); put(residual_capacity, get(reverse_edge, e), get(residual_capacity, get(reverse_edge, e)) + delta); u = source(e, g); e = get(p, u); } while (u != src); } } // namespace detail } // namespace boost #endif /* BOOST_GRAPH_AUGMENT_HPP */ detail/set_adaptor.hpp 0000644 00000006024 15125521275 0011033 0 ustar 00 // (C) Copyright Jeremy Siek 2001. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_SET_ADAPTOR_HPP #define BOOST_SET_ADAPTOR_HPP #include <set> #include <boost/unordered_set.hpp> namespace boost { template < class K, class C, class A, class T > bool set_contains(const std::set< K, C, A >& s, const T& x) { return s.find(x) != s.end(); } template < class K, class H, class C, class A, class T > bool set_contains(const boost::unordered_set< K, H, C, A >& s, const T& x) { return s.find(x) != s.end(); } template < class K, class C, class A > bool set_equal(const std::set< K, C, A >& x, const std::set< K, C, A >& y) { return x == y; } // Not the same as lexicographical_compare_3way applied to std::set. // this is equivalent semantically to bitset::operator<() template < class K, class C, class A > int set_lex_order(const std::set< K, C, A >& x, const std::set< K, C, A >& y) { typename std::set< K, C, A >::iterator xi = x.begin(), yi = y.begin(), xend = x.end(), yend = y.end(); for (; xi != xend && yi != yend; ++xi, ++yi) { if (*xi < *yi) return 1; else if (*yi < *xi) return -1; } if (xi == xend) return (yi == yend) ? 0 : -1; else return 1; } template < class K, class C, class A > void set_clear(std::set< K, C, A >& x) { x.clear(); } template < class K, class C, class A > bool set_empty(const std::set< K, C, A >& x) { return x.empty(); } template < class K, class C, class A, class T > void set_insert(std::set< K, C, A >& x, const T& a) { x.insert(a); } template < class K, class C, class A, class T > void set_remove(std::set< K, C, A >& x, const T& a) { x.erase(a); } template < class K, class C, class A > void set_intersect(const std::set< K, C, A >& x, const std::set< K, C, A >& y, std::set< K, C, A >& z) { z.clear(); std::set_intersection( x.begin(), x.end(), y.begin(), y.end(), std::inserter(z)); } template < class K, class C, class A > void set_union(const std::set< K, C, A >& x, const std::set< K, C, A >& y, std::set< K, C, A >& z) { z.clear(); std::set_union(x.begin(), x.end(), y.begin(), y.end(), std::inserter(z)); } template < class K, class C, class A > void set_difference(const std::set< K, C, A >& x, const std::set< K, C, A >& y, std::set< K, C, A >& z) { z.clear(); std::set_difference( x.begin(), x.end(), y.begin(), y.end(), std::inserter(z, z.begin())); } template < class K, class C, class A > bool set_subset(const std::set< K, C, A >& x, const std::set< K, C, A >& y) { return std::includes(x.begin(), x.end(), y.begin(), y.end()); } // Shit, can't implement this without knowing the size of the // universe. template < class K, class C, class A > void set_compliment(const std::set< K, C, A >& /*x*/, std::set< K, C, A >& z) { z.clear(); } } // namespace boost #endif // BOOST_SET_ADAPTOR_HPP detail/incremental_components.hpp 0000644 00000006163 15125521275 0013300 0 ustar 00 //======================================================================= // Copyright 2002 Indiana University. // Copyright 2009 Trustees of Indiana University. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Michael Hansen // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_DETAIL_INCREMENTAL_COMPONENTS_HPP #define BOOST_GRAPH_DETAIL_INCREMENTAL_COMPONENTS_HPP #include <boost/operators.hpp> namespace boost { namespace detail { // Iterator for a component index linked list. The contents of // each array element represent the next index in the list. A // special value (the maximum index + 1) is used to terminate a // list. template < typename IndexRandomAccessIterator > class component_index_iterator : boost::forward_iterator_helper< component_index_iterator< IndexRandomAccessIterator >, typename std::iterator_traits< IndexRandomAccessIterator >::value_type, typename std::iterator_traits< IndexRandomAccessIterator >::difference_type, typename std::iterator_traits< IndexRandomAccessIterator >::pointer, typename std::iterator_traits< IndexRandomAccessIterator >::reference > { private: typedef component_index_iterator< IndexRandomAccessIterator > self; public: typedef std::forward_iterator_tag iterator_category; typedef typename std::iterator_traits< IndexRandomAccessIterator >::value_type value_type; typedef typename std::iterator_traits< IndexRandomAccessIterator >::difference_type reference; typedef typename std::iterator_traits< IndexRandomAccessIterator >::pointer pointer; typedef typename std::iterator_traits< IndexRandomAccessIterator >::reference difference_type; // Constructor for "begin" iterator component_index_iterator( IndexRandomAccessIterator index_iterator, value_type begin_index) : m_index_iterator(index_iterator), m_current_index(begin_index) { } // Constructor for "end" iterator (end_index should be the linked // list terminator). component_index_iterator(value_type end_index) : m_current_index(end_index) { } inline value_type operator*() const { return (m_current_index); } self& operator++() { // Move to the next element in the linked list m_current_index = m_index_iterator[m_current_index]; return (*this); } bool operator==(const self& other_iterator) const { return (m_current_index == *other_iterator); } protected: IndexRandomAccessIterator m_index_iterator; value_type m_current_index; }; // class component_index_iterator } // namespace detail } // namespace detail #endif // BOOST_GRAPH_DETAIL_INCREMENTAL_COMPONENTS_HPP detail/permutation.hpp 0000644 00000013604 15125521275 0011077 0 ustar 00 // (C) Copyright Jeremy Siek 2001. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_PERMUTATION_HPP #define BOOST_PERMUTATION_HPP #include <vector> #include <memory> #include <functional> #include <algorithm> #include <boost/graph/detail/shadow_iterator.hpp> namespace boost { template < class Iter1, class Iter2 > void permute_serial(Iter1 permuter, Iter1 last, Iter2 result) { #ifdef BOOST_NO_STD_ITERATOR_TRAITS typedef std::ptrdiff_t D : #else typedef typename std::iterator_traits< Iter1 >::difference_type D; #endif D n = 0; while (permuter != last) { std::swap(result[n], result[*permuter]); ++n; ++permuter; } } template < class InIter, class RandIterP, class RandIterR > void permute_copy(InIter first, InIter last, RandIterP p, RandIterR result) { #ifdef BOOST_NO_STD_ITERATOR_TRAITS typedef std::ptrdiff_t i = 0; #else typename std::iterator_traits< RandIterP >::difference_type i = 0; #endif for (; first != last; ++first, ++i) result[p[i]] = *first; } namespace detail { template < class RandIter, class RandIterPerm, class D, class T > void permute_helper(RandIter first, RandIter last, RandIterPerm p, D, T) { D i = 0, pi, n = last - first, cycle_start; T tmp; std::vector< int > visited(n, false); while (i != n) { // continue until all elements have been processed cycle_start = i; tmp = first[i]; do { // walk around a cycle pi = p[i]; visited[pi] = true; std::swap(tmp, first[pi]); i = pi; } while (i != cycle_start); // find the next cycle for (i = 0; i < n; ++i) if (visited[i] == false) break; } } } // namespace detail template < class RandIter, class RandIterPerm > void permute(RandIter first, RandIter last, RandIterPerm p) { detail::permute_helper(first, last, p, last - first, *first); } // Knuth 1.3.3, Vol. 1 p 176 // modified for zero-based arrays // time complexity? // // WARNING: T must be a signed integer! template < class PermIter > void invert_permutation(PermIter X, PermIter Xend) { #ifdef BOOST_NO_STD_ITERATOR_TRAITS typedef std::ptrdiff_t T : #else typedef typename std::iterator_traits< PermIter >::value_type T; #endif T n = Xend - X; T m = n; T j = -1; while (m > 0) { T i = X[m - 1] + 1; if (i > 0) { do { X[m - 1] = j - 1; j = -m; m = i; i = X[m - 1] + 1; } while (i > 0); i = j; } X[m - 1] = -i - 1; --m; } } // Takes a "normal" permutation array (and its inverse), and turns it // into a BLAS-style permutation array (which can be thought of as a // serialized permutation). template < class Iter1, class Iter2, class Iter3 > inline void serialize_permutation(Iter1 q, Iter1 q_end, Iter2 q_inv, Iter3 p) { #ifdef BOOST_NO_STD_ITERATOR_TRAITS typedef std::ptrdiff_t P1; typedef std::ptrdiff_t P2; typedef std::ptrdiff_t D; #else typedef typename std::iterator_traits< Iter1 >::value_type P1; typedef typename std::iterator_traits< Iter2 >::value_type P2; typedef typename std::iterator_traits< Iter1 >::difference_type D; #endif D n = q_end - q; for (D i = 0; i < n; ++i) { P1 qi = q[i]; P2 qii = q_inv[i]; *p++ = qii; std::swap(q[i], q[qii]); std::swap(q_inv[i], q_inv[qi]); } } // Not used anymore, leaving it here for future reference. template < typename Iter, typename Compare > void merge_sort(Iter first, Iter last, Compare cmp) { if (first + 1 < last) { Iter mid = first + (last - first) / 2; merge_sort(first, mid, cmp); merge_sort(mid, last, cmp); std::inplace_merge(first, mid, last, cmp); } } // time: N log N + 3N + ? // space: 2N template < class Iter, class IterP, class Cmp, class Alloc > inline void sortp(Iter first, Iter last, IterP p, Cmp cmp, Alloc alloc) { typedef typename std::iterator_traits< IterP >::value_type P; typedef typename std::iterator_traits< IterP >::difference_type D; D n = last - first; std::vector< P, Alloc > q(n); for (D i = 0; i < n; ++i) q[i] = i; std::sort(make_shadow_iter(first, q.begin()), make_shadow_iter(last, q.end()), shadow_cmp< Cmp >(cmp)); invert_permutation(q.begin(), q.end()); std::copy(q.begin(), q.end(), p); } template < class Iter, class IterP, class Cmp > inline void sortp(Iter first, Iter last, IterP p, Cmp cmp) { typedef typename std::iterator_traits< IterP >::value_type P; sortp(first, last, p, cmp, std::allocator< P >()); } template < class Iter, class IterP > inline void sortp(Iter first, Iter last, IterP p) { typedef typename std::iterator_traits< Iter >::value_type T; typedef typename std::iterator_traits< IterP >::value_type P; sortp(first, last, p, std::less< T >(), std::allocator< P >()); } template < class Iter, class IterP, class Cmp, class Alloc > inline void sortv(Iter first, Iter last, IterP p, Cmp cmp, Alloc alloc) { typedef typename std::iterator_traits< IterP >::value_type P; typedef typename std::iterator_traits< IterP >::difference_type D; D n = last - first; std::vector< P, Alloc > q(n), q_inv(n); for (D i = 0; i < n; ++i) q_inv[i] = i; std::sort(make_shadow_iter(first, q_inv.begin()), make_shadow_iter(last, q_inv.end()), shadow_cmp< Cmp >(cmp)); std::copy(q_inv, q_inv.end(), q.begin()); invert_permutation(q.begin(), q.end()); serialize_permutation(q.begin(), q.end(), q_inv.end(), p); } } // namespace boost #endif // BOOST_PERMUTATION_HPP detail/labeled_graph_traits.hpp 0000644 00000014732 15125521275 0012672 0 ustar 00 // Copyright (C) 2009 Andrew Sutton // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GRAPH_LABELED_GRAPH_TRAITS_HPP #define BOOST_GRAPH_LABELED_GRAPH_TRAITS_HPP #include <boost/graph/graph_mutability_traits.hpp> namespace boost { // Extend the graph mutability traits (and metafunctions) to include options // for labeled graphs. // NOTE: the label_vertex tag denotes the fact that you can basically assign // arbitrary labels to vertices without modifying the actual graph. // TODO: We might also overlay the uniqueness/multiplicity of labels in this // hierarchy also. For now, we just assumed that labels are unique. struct label_vertex_tag { }; struct labeled_add_vertex_tag : virtual label_vertex_tag { }; struct labeled_add_vertex_property_tag : virtual labeled_add_vertex_tag { }; struct labeled_remove_vertex_tag { }; struct labeled_add_edge_tag : virtual label_vertex_tag { }; struct labeled_add_edge_property_tag : virtual labeled_add_edge_tag { }; struct labeled_remove_edge_tag { }; struct labeled_mutable_vertex_graph_tag : virtual labeled_add_vertex_tag, virtual labeled_remove_vertex_tag { }; struct labeled_mutable_vertex_property_graph_tag : virtual labeled_add_vertex_property_tag, virtual labeled_remove_vertex_tag { }; struct labeled_mutable_edge_graph_tag : virtual labeled_add_edge_tag, virtual labeled_remove_edge_tag { }; struct labeled_mutable_edge_property_graph_tag : virtual labeled_add_edge_property_tag, virtual labeled_remove_edge_tag { }; struct labeled_graph_tag : virtual label_vertex_tag { }; struct labeled_mutable_graph_tag : virtual labeled_mutable_vertex_graph_tag, virtual labeled_mutable_edge_graph_tag { }; struct labeled_mutable_property_graph_tag : virtual labeled_mutable_vertex_property_graph_tag, virtual labeled_mutable_edge_property_graph_tag { }; struct labeled_add_only_property_graph_tag : virtual labeled_add_vertex_property_tag, virtual labeled_mutable_edge_property_graph_tag { }; // Metafunctions template < typename Graph > struct graph_has_add_vertex_by_label : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, labeled_add_vertex_tag >::value > { }; template < typename Graph > struct graph_has_add_vertex_by_label_with_property : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, labeled_add_vertex_property_tag >::value > { }; template < typename Graph > struct graph_has_remove_vertex_by_label : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, labeled_remove_vertex_tag >::value > { }; template < typename Graph > struct graph_has_add_edge_by_label : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, labeled_add_edge_tag >::value > { }; template < typename Graph > struct graph_has_add_edge_by_label_with_property : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, labeled_add_edge_property_tag >::value > { }; template < typename Graph > struct graph_has_remove_edge_by_label : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, labeled_remove_edge_tag >::value > { }; template < typename Graph > struct is_labeled_mutable_vertex_graph : mpl::and_< graph_has_add_vertex_by_label< Graph >, graph_has_remove_vertex_by_label< Graph > > { }; template < typename Graph > struct is_labeled_mutable_vertex_property_graph : mpl::and_< graph_has_add_vertex_by_label< Graph >, graph_has_remove_vertex_by_label< Graph > > { }; template < typename Graph > struct is_labeled_mutable_edge_graph : mpl::and_< graph_has_add_edge_by_label< Graph >, graph_has_remove_edge_by_label< Graph > > { }; template < typename Graph > struct is_labeled_mutable_edge_property_graph : mpl::and_< graph_has_add_edge_by_label< Graph >, graph_has_remove_edge_by_label< Graph > > { }; template < typename Graph > struct is_labeled_mutable_graph : mpl::and_< is_labeled_mutable_vertex_graph< Graph >, is_labeled_mutable_edge_graph< Graph > > { }; template < typename Graph > struct is_labeled_mutable_property_graph : mpl::and_< is_labeled_mutable_vertex_property_graph< Graph >, is_labeled_mutable_edge_property_graph< Graph > > { }; template < typename Graph > struct is_labeled_add_only_property_graph : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, labeled_add_only_property_graph_tag >::value > { }; template < typename Graph > struct is_labeled_graph : mpl::bool_< is_convertible< typename graph_mutability_traits< Graph >::category, label_vertex_tag >::value > { }; template < typename > struct graph_mutability_traits; namespace graph_detail { // The determine mutability metafunction computes a labeled mutability tag // based on the mutability of the given graph type. This is used by the // graph_mutability_traits specialization below. template < typename Graph > struct determine_mutability { typedef typename mpl::if_< is_add_only_property_graph< Graph >, labeled_add_only_property_graph_tag, typename mpl::if_< is_mutable_property_graph< Graph >, labeled_mutable_property_graph_tag, typename mpl::if_< is_mutable_graph< Graph >, labeled_mutable_graph_tag, typename mpl::if_< is_mutable_edge_graph< Graph >, labeled_graph_tag, typename graph_mutability_traits< Graph >::category >:: type >::type >::type >::type type; }; } // namespace graph_detail #define LABELED_GRAPH_PARAMS typename G, typename L, typename S #define LABELED_GRAPH labeled_graph< G, L, S > // Specialize mutability traits for the labeled graph. // This specialization depends on the mutability of the underlying graph type. // If the underlying graph is fully mutable, this is also fully mutable. // Otherwise, it's different. template < LABELED_GRAPH_PARAMS > struct graph_mutability_traits< LABELED_GRAPH > { typedef typename graph_detail::determine_mutability< typename LABELED_GRAPH::graph_type >::type category; }; #undef LABELED_GRAPH_PARAMS #undef LABELED_GRAPH } // namespace boost #endif betweenness_centrality.hpp 0000644 00000063262 15125521275 0012053 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP #define BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP #include <stack> #include <vector> #include <boost/graph/overloading.hpp> #include <boost/graph/dijkstra_shortest_paths.hpp> #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/relax.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/tuple/tuple.hpp> #include <boost/type_traits/is_convertible.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/mpl/if.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/named_function_params.hpp> #include <algorithm> namespace boost { namespace detail { namespace graph { /** * Customized visitor passed to Dijkstra's algorithm by Brandes' * betweenness centrality algorithm. This visitor is responsible for * keeping track of the order in which vertices are discovered, the * predecessors on the shortest path(s) to a vertex, and the number * of shortest paths. */ template < typename Graph, typename WeightMap, typename IncomingMap, typename DistanceMap, typename PathCountMap > struct brandes_dijkstra_visitor : public bfs_visitor<> { typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor; brandes_dijkstra_visitor( std::stack< vertex_descriptor >& ordered_vertices, WeightMap weight, IncomingMap incoming, DistanceMap distance, PathCountMap path_count) : ordered_vertices(ordered_vertices) , weight(weight) , incoming(incoming) , distance(distance) , path_count(path_count) { } /** * Whenever an edge e = (v, w) is relaxed, the incoming edge list * for w is set to {(v, w)} and the shortest path count of w is set * to the number of paths that reach {v}. */ void edge_relaxed(edge_descriptor e, const Graph& g) { vertex_descriptor v = source(e, g), w = target(e, g); incoming[w].clear(); incoming[w].push_back(e); put(path_count, w, get(path_count, v)); } /** * If an edge e = (v, w) was not relaxed, it may still be the case * that we've found more equally-short paths, so include {(v, w)} in * the incoming edges of w and add all of the shortest paths to v to * the shortest path count of w. */ void edge_not_relaxed(edge_descriptor e, const Graph& g) { typedef typename property_traits< WeightMap >::value_type weight_type; typedef typename property_traits< DistanceMap >::value_type distance_type; vertex_descriptor v = source(e, g), w = target(e, g); distance_type d_v = get(distance, v), d_w = get(distance, w); weight_type w_e = get(weight, e); closed_plus< distance_type > combine; if (d_w == combine(d_v, w_e)) { put(path_count, w, get(path_count, w) + get(path_count, v)); incoming[w].push_back(e); } } /// Keep track of vertices as they are reached void examine_vertex(vertex_descriptor w, const Graph&) { ordered_vertices.push(w); } private: std::stack< vertex_descriptor >& ordered_vertices; WeightMap weight; IncomingMap incoming; DistanceMap distance; PathCountMap path_count; }; /** * Function object that calls Dijkstra's shortest paths algorithm * using the Dijkstra visitor for the Brandes betweenness centrality * algorithm. */ template < typename WeightMap > struct brandes_dijkstra_shortest_paths { brandes_dijkstra_shortest_paths(WeightMap weight_map) : weight_map(weight_map) { } template < typename Graph, typename IncomingMap, typename DistanceMap, typename PathCountMap, typename VertexIndexMap > void operator()(Graph& g, typename graph_traits< Graph >::vertex_descriptor s, std::stack< typename graph_traits< Graph >::vertex_descriptor >& ov, IncomingMap incoming, DistanceMap distance, PathCountMap path_count, VertexIndexMap vertex_index) { typedef brandes_dijkstra_visitor< Graph, WeightMap, IncomingMap, DistanceMap, PathCountMap > visitor_type; visitor_type visitor( ov, weight_map, incoming, distance, path_count); dijkstra_shortest_paths(g, s, boost::weight_map(weight_map) .vertex_index_map(vertex_index) .distance_map(distance) .visitor(visitor)); } private: WeightMap weight_map; }; /** * Function object that invokes breadth-first search for the * unweighted form of the Brandes betweenness centrality algorithm. */ struct brandes_unweighted_shortest_paths { /** * Customized visitor passed to breadth-first search, which * records predecessor and the number of shortest paths to each * vertex. */ template < typename Graph, typename IncomingMap, typename DistanceMap, typename PathCountMap > struct visitor_type : public bfs_visitor<> { typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; visitor_type(IncomingMap incoming, DistanceMap distance, PathCountMap path_count, std::stack< vertex_descriptor >& ordered_vertices) : incoming(incoming) , distance(distance) , path_count(path_count) , ordered_vertices(ordered_vertices) { } /// Keep track of vertices as they are reached void examine_vertex(vertex_descriptor v, Graph&) { ordered_vertices.push(v); } /** * Whenever an edge e = (v, w) is labelled a tree edge, the * incoming edge list for w is set to {(v, w)} and the shortest * path count of w is set to the number of paths that reach {v}. */ void tree_edge(edge_descriptor e, Graph& g) { vertex_descriptor v = source(e, g); vertex_descriptor w = target(e, g); put(distance, w, get(distance, v) + 1); put(path_count, w, get(path_count, v)); incoming[w].push_back(e); } /** * If an edge e = (v, w) is not a tree edge, it may still be the * case that we've found more equally-short paths, so include * (v, w) in the incoming edge list of w and add all of the * shortest paths to v to the shortest path count of w. */ void non_tree_edge(edge_descriptor e, Graph& g) { vertex_descriptor v = source(e, g); vertex_descriptor w = target(e, g); if (get(distance, w) == get(distance, v) + 1) { put(path_count, w, get(path_count, w) + get(path_count, v)); incoming[w].push_back(e); } } private: IncomingMap incoming; DistanceMap distance; PathCountMap path_count; std::stack< vertex_descriptor >& ordered_vertices; }; template < typename Graph, typename IncomingMap, typename DistanceMap, typename PathCountMap, typename VertexIndexMap > void operator()(Graph& g, typename graph_traits< Graph >::vertex_descriptor s, std::stack< typename graph_traits< Graph >::vertex_descriptor >& ov, IncomingMap incoming, DistanceMap distance, PathCountMap path_count, VertexIndexMap vertex_index) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; visitor_type< Graph, IncomingMap, DistanceMap, PathCountMap > visitor(incoming, distance, path_count, ov); std::vector< default_color_type > colors(num_vertices(g), color_traits< default_color_type >::white()); boost::queue< vertex_descriptor > Q; breadth_first_visit(g, s, Q, visitor, make_iterator_property_map(colors.begin(), vertex_index)); } }; // When the edge centrality map is a dummy property map, no // initialization is needed. template < typename Iter > inline void init_centrality_map( std::pair< Iter, Iter >, dummy_property_map) { } // When we have a real edge centrality map, initialize all of the // centralities to zero. template < typename Iter, typename Centrality > void init_centrality_map( std::pair< Iter, Iter > keys, Centrality centrality_map) { typedef typename property_traits< Centrality >::value_type centrality_type; while (keys.first != keys.second) { put(centrality_map, *keys.first, centrality_type(0)); ++keys.first; } } // When the edge centrality map is a dummy property map, no update // is performed. template < typename Key, typename T > inline void update_centrality(dummy_property_map, const Key&, const T&) { } // When we have a real edge centrality map, add the value to the map template < typename CentralityMap, typename Key, typename T > inline void update_centrality( CentralityMap centrality_map, Key k, const T& x) { put(centrality_map, k, get(centrality_map, k) + x); } template < typename Iter > inline void divide_centrality_by_two( std::pair< Iter, Iter >, dummy_property_map) { } template < typename Iter, typename CentralityMap > inline void divide_centrality_by_two( std::pair< Iter, Iter > keys, CentralityMap centrality_map) { typename property_traits< CentralityMap >::value_type two(2); while (keys.first != keys.second) { put(centrality_map, *keys.first, get(centrality_map, *keys.first) / two); ++keys.first; } } template < typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename IncomingMap, typename DistanceMap, typename DependencyMap, typename PathCountMap, typename VertexIndexMap, typename ShortestPaths > void brandes_betweenness_centrality_impl(const Graph& g, CentralityMap centrality, // C_B EdgeCentralityMap edge_centrality_map, IncomingMap incoming, // P DistanceMap distance, // d DependencyMap dependency, // delta PathCountMap path_count, // sigma VertexIndexMap vertex_index, ShortestPaths shortest_paths) { typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; // Initialize centrality init_centrality_map(vertices(g), centrality); init_centrality_map(edges(g), edge_centrality_map); std::stack< vertex_descriptor > ordered_vertices; vertex_iterator s, s_end; for (boost::tie(s, s_end) = vertices(g); s != s_end; ++s) { // Initialize for this iteration vertex_iterator w, w_end; for (boost::tie(w, w_end) = vertices(g); w != w_end; ++w) { incoming[*w].clear(); put(path_count, *w, 0); put(dependency, *w, 0); } put(path_count, *s, 1); // Execute the shortest paths algorithm. This will be either // Dijkstra's algorithm or a customized breadth-first search, // depending on whether the graph is weighted or unweighted. shortest_paths(g, *s, ordered_vertices, incoming, distance, path_count, vertex_index); while (!ordered_vertices.empty()) { vertex_descriptor w = ordered_vertices.top(); ordered_vertices.pop(); typedef typename property_traits< IncomingMap >::value_type incoming_type; typedef typename incoming_type::iterator incoming_iterator; typedef typename property_traits< DependencyMap >::value_type dependency_type; for (incoming_iterator vw = incoming[w].begin(); vw != incoming[w].end(); ++vw) { vertex_descriptor v = source(*vw, g); dependency_type factor = dependency_type(get(path_count, v)) / dependency_type(get(path_count, w)); factor *= (dependency_type(1) + get(dependency, w)); put(dependency, v, get(dependency, v) + factor); update_centrality(edge_centrality_map, *vw, factor); } if (w != *s) { update_centrality(centrality, w, get(dependency, w)); } } } typedef typename graph_traits< Graph >::directed_category directed_category; const bool is_undirected = is_convertible< directed_category*, undirected_tag* >::value; if (is_undirected) { divide_centrality_by_two(vertices(g), centrality); divide_centrality_by_two(edges(g), edge_centrality_map); } } } } // end namespace detail::graph template < typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename IncomingMap, typename DistanceMap, typename DependencyMap, typename PathCountMap, typename VertexIndexMap > void brandes_betweenness_centrality(const Graph& g, CentralityMap centrality, // C_B EdgeCentralityMap edge_centrality_map, IncomingMap incoming, // P DistanceMap distance, // d DependencyMap dependency, // delta PathCountMap path_count, // sigma VertexIndexMap vertex_index BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { detail::graph::brandes_unweighted_shortest_paths shortest_paths; detail::graph::brandes_betweenness_centrality_impl(g, centrality, edge_centrality_map, incoming, distance, dependency, path_count, vertex_index, shortest_paths); } template < typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename IncomingMap, typename DistanceMap, typename DependencyMap, typename PathCountMap, typename VertexIndexMap, typename WeightMap > void brandes_betweenness_centrality(const Graph& g, CentralityMap centrality, // C_B EdgeCentralityMap edge_centrality_map, IncomingMap incoming, // P DistanceMap distance, // d DependencyMap dependency, // delta PathCountMap path_count, // sigma VertexIndexMap vertex_index, WeightMap weight_map BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { detail::graph::brandes_dijkstra_shortest_paths< WeightMap > shortest_paths( weight_map); detail::graph::brandes_betweenness_centrality_impl(g, centrality, edge_centrality_map, incoming, distance, dependency, path_count, vertex_index, shortest_paths); } namespace detail { namespace graph { template < typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename WeightMap, typename VertexIndexMap > void brandes_betweenness_centrality_dispatch2(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, WeightMap weight_map, VertexIndexMap vertex_index) { typedef typename graph_traits< Graph >::degree_size_type degree_size_type; typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor; typedef typename mpl::if_c< (is_same< CentralityMap, dummy_property_map >::value), EdgeCentralityMap, CentralityMap >::type a_centrality_map; typedef typename property_traits< a_centrality_map >::value_type centrality_type; typename graph_traits< Graph >::vertices_size_type V = num_vertices(g); std::vector< std::vector< edge_descriptor > > incoming(V); std::vector< centrality_type > distance(V); std::vector< centrality_type > dependency(V); std::vector< degree_size_type > path_count(V); brandes_betweenness_centrality(g, centrality, edge_centrality_map, make_iterator_property_map(incoming.begin(), vertex_index), make_iterator_property_map(distance.begin(), vertex_index), make_iterator_property_map(dependency.begin(), vertex_index), make_iterator_property_map(path_count.begin(), vertex_index), vertex_index, weight_map); } template < typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename VertexIndexMap > void brandes_betweenness_centrality_dispatch2(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index) { typedef typename graph_traits< Graph >::degree_size_type degree_size_type; typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor; typedef typename mpl::if_c< (is_same< CentralityMap, dummy_property_map >::value), EdgeCentralityMap, CentralityMap >::type a_centrality_map; typedef typename property_traits< a_centrality_map >::value_type centrality_type; typename graph_traits< Graph >::vertices_size_type V = num_vertices(g); std::vector< std::vector< edge_descriptor > > incoming(V); std::vector< centrality_type > distance(V); std::vector< centrality_type > dependency(V); std::vector< degree_size_type > path_count(V); brandes_betweenness_centrality(g, centrality, edge_centrality_map, make_iterator_property_map(incoming.begin(), vertex_index), make_iterator_property_map(distance.begin(), vertex_index), make_iterator_property_map(dependency.begin(), vertex_index), make_iterator_property_map(path_count.begin(), vertex_index), vertex_index); } template < typename WeightMap > struct brandes_betweenness_centrality_dispatch1 { template < typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename VertexIndexMap > static void run(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index, WeightMap weight_map) { brandes_betweenness_centrality_dispatch2(g, centrality, edge_centrality_map, weight_map, vertex_index); } }; template <> struct brandes_betweenness_centrality_dispatch1< param_not_found > { template < typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename VertexIndexMap > static void run(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index, param_not_found) { brandes_betweenness_centrality_dispatch2( g, centrality, edge_centrality_map, vertex_index); } }; template < typename T > struct is_bgl_named_params { BOOST_STATIC_CONSTANT(bool, value = false); }; template < typename Param, typename Tag, typename Rest > struct is_bgl_named_params< bgl_named_params< Param, Tag, Rest > > { BOOST_STATIC_CONSTANT(bool, value = true); }; } } // end namespace detail::graph template < typename Graph, typename Param, typename Tag, typename Rest > void brandes_betweenness_centrality(const Graph& g, const bgl_named_params< Param, Tag, Rest >& params BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, vertex_list_graph_tag)) { typedef bgl_named_params< Param, Tag, Rest > named_params; typedef typename get_param_type< edge_weight_t, named_params >::type ew; detail::graph::brandes_betweenness_centrality_dispatch1< ew >::run(g, choose_param( get_param(params, vertex_centrality), dummy_property_map()), choose_param(get_param(params, edge_centrality), dummy_property_map()), choose_const_pmap(get_param(params, vertex_index), g, vertex_index), get_param(params, edge_weight)); } // disable_if is required to work around problem with MSVC 7.1 (it seems to not // get partial ordering getween this overload and the previous one correct) template < typename Graph, typename CentralityMap > typename disable_if< detail::graph::is_bgl_named_params< CentralityMap >, void >::type brandes_betweenness_centrality(const Graph& g, CentralityMap centrality BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { detail::graph::brandes_betweenness_centrality_dispatch2( g, centrality, dummy_property_map(), get(vertex_index, g)); } template < typename Graph, typename CentralityMap, typename EdgeCentralityMap > void brandes_betweenness_centrality(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { detail::graph::brandes_betweenness_centrality_dispatch2( g, centrality, edge_centrality_map, get(vertex_index, g)); } /** * Converts "absolute" betweenness centrality (as computed by the * brandes_betweenness_centrality algorithm) in the centrality map * into "relative" centrality. The result is placed back into the * given centrality map. */ template < typename Graph, typename CentralityMap > void relative_betweenness_centrality(const Graph& g, CentralityMap centrality) { typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator; typedef typename property_traits< CentralityMap >::value_type centrality_type; typename graph_traits< Graph >::vertices_size_type n = num_vertices(g); centrality_type factor = centrality_type(2) / centrality_type(n * n - 3 * n + 2); vertex_iterator v, v_end; for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) { put(centrality, *v, factor * get(centrality, *v)); } } // Compute the central point dominance of a graph. template < typename Graph, typename CentralityMap > typename property_traits< CentralityMap >::value_type central_point_dominance( const Graph& g, CentralityMap centrality BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { using std::max; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator; typedef typename property_traits< CentralityMap >::value_type centrality_type; typename graph_traits< Graph >::vertices_size_type n = num_vertices(g); // Find max centrality centrality_type max_centrality(0); vertex_iterator v, v_end; for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) { max_centrality = (max)(max_centrality, get(centrality, *v)); } // Compute central point dominance centrality_type sum(0); for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) { sum += (max_centrality - get(centrality, *v)); } return sum / (n - 1); } } // end namespace boost #endif // BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP subgraph.hpp 0000644 00000116074 15125521275 0007106 0 ustar 00 //======================================================================= // Copyright 2001 University of Notre Dame. // Authors: Jeremy G. Siek and Lie-Quan Lee // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_SUBGRAPH_HPP #define BOOST_SUBGRAPH_HPP // UNDER CONSTRUCTION #include <boost/config.hpp> #include <list> #include <vector> #include <map> #include <boost/assert.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_mutability_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/iterator/indirect_iterator.hpp> #include <boost/static_assert.hpp> #include <boost/assert.hpp> #include <boost/type_traits.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/or.hpp> namespace boost { struct subgraph_tag { }; /** @name Property Lookup * The local_property and global_property functions are used to create * structures that determine the lookup strategy for properties in subgraphs. * Note that the nested kind member is used to help interoperate with actual * Property types. */ //@{ template < typename T > struct local_property { typedef T kind; local_property(T x) : value(x) {} T value; }; template < typename T > inline local_property< T > local(T x) { return local_property< T >(x); } template < typename T > struct global_property { typedef T kind; global_property(T x) : value(x) {} T value; }; template < typename T > inline global_property< T > global(T x) { return global_property< T >(x); } //@} // Invariants of an induced subgraph: // - If vertex u is in subgraph g, then u must be in g.parent(). // - If edge e is in subgraph g, then e must be in g.parent(). // - If edge e=(u,v) is in the root graph, then edge e // is also in any subgraph that contains both vertex u and v. // The Graph template parameter must have a vertex_index and edge_index // internal property. It is assumed that the vertex indices are assigned // automatically by the graph during a call to add_vertex(). It is not // assumed that the edge vertices are assigned automatically, they are // explicitly assigned here. template < typename Graph > class subgraph { typedef graph_traits< Graph > Traits; typedef std::list< subgraph< Graph >* > ChildrenList; public: // Graph requirements typedef typename Traits::vertex_descriptor vertex_descriptor; typedef typename Traits::edge_descriptor edge_descriptor; typedef typename Traits::directed_category directed_category; typedef typename Traits::edge_parallel_category edge_parallel_category; typedef typename Traits::traversal_category traversal_category; // IncidenceGraph requirements typedef typename Traits::out_edge_iterator out_edge_iterator; typedef typename Traits::degree_size_type degree_size_type; // AdjacencyGraph requirements typedef typename Traits::adjacency_iterator adjacency_iterator; // VertexListGraph requirements typedef typename Traits::vertex_iterator vertex_iterator; typedef typename Traits::vertices_size_type vertices_size_type; // EdgeListGraph requirements typedef typename Traits::edge_iterator edge_iterator; typedef typename Traits::edges_size_type edges_size_type; typedef typename Traits::in_edge_iterator in_edge_iterator; typedef typename edge_property_type< Graph >::type edge_property_type; typedef typename vertex_property_type< Graph >::type vertex_property_type; typedef subgraph_tag graph_tag; typedef Graph graph_type; typedef typename graph_property_type< Graph >::type graph_property_type; // Create the main graph, the root of the subgraph tree subgraph() : m_parent(0), m_edge_counter(0) {} subgraph(const graph_property_type& p) : m_graph(p), m_parent(0), m_edge_counter(0) { } subgraph(vertices_size_type n, const graph_property_type& p = graph_property_type()) : m_graph(n, p), m_parent(0), m_edge_counter(0), m_global_vertex(n) { typename Graph::vertex_iterator v, v_end; vertices_size_type i = 0; for (boost::tie(v, v_end) = vertices(m_graph); v != v_end; ++v) m_global_vertex[i++] = *v; } // copy constructor subgraph(const subgraph& x) : m_parent(x.m_parent), m_edge_counter(0) { if (x.is_root()) { m_graph = x.m_graph; m_edge_counter = x.m_edge_counter; m_global_vertex = x.m_global_vertex; m_global_edge = x.m_global_edge; } else { get_property(*this) = get_property(x); typename subgraph< Graph >::vertex_iterator vi, vi_end; boost::tie(vi, vi_end) = vertices(x); for (; vi != vi_end; ++vi) { add_vertex(x.local_to_global(*vi), *this); } } // Do a deep copy (recursive). // Only the root graph is copied, the subgraphs contain // only references to the global vertices they own. typename subgraph< Graph >::children_iterator i, i_end; boost::tie(i, i_end) = x.children(); for (; i != i_end; ++i) { m_children.push_back(new subgraph< Graph >(*i)); m_children.back()->m_parent = this; } } ~subgraph() { for (typename ChildrenList::iterator i = m_children.begin(); i != m_children.end(); ++i) { delete *i; } } // Return a null vertex descriptor for the graph. static vertex_descriptor null_vertex() { return Traits::null_vertex(); } // Create a subgraph subgraph< Graph >& create_subgraph() { m_children.push_back(new subgraph< Graph >()); m_children.back()->m_parent = this; return *m_children.back(); } // Create a subgraph with the specified vertex set. template < typename VertexIterator > subgraph< Graph >& create_subgraph( VertexIterator first, VertexIterator last) { m_children.push_back(new subgraph< Graph >()); m_children.back()->m_parent = this; for (; first != last; ++first) { add_vertex(*first, *m_children.back()); } return *m_children.back(); } // local <-> global descriptor conversion functions vertex_descriptor local_to_global(vertex_descriptor u_local) const { return is_root() ? u_local : m_global_vertex[u_local]; } vertex_descriptor global_to_local(vertex_descriptor u_global) const { vertex_descriptor u_local; bool in_subgraph; if (is_root()) return u_global; boost::tie(u_local, in_subgraph) = this->find_vertex(u_global); BOOST_ASSERT(in_subgraph == true); return u_local; } edge_descriptor local_to_global(edge_descriptor e_local) const { return is_root() ? e_local : m_global_edge[get(get(edge_index, m_graph), e_local)]; } edge_descriptor global_to_local(edge_descriptor e_global) const { return is_root() ? e_global : (*m_local_edge.find( get(get(edge_index, root().m_graph), e_global))) .second; } // Is vertex u (of the root graph) contained in this subgraph? // If so, return the matching local vertex. std::pair< vertex_descriptor, bool > find_vertex( vertex_descriptor u_global) const { if (is_root()) return std::make_pair(u_global, true); typename LocalVertexMap::const_iterator i = m_local_vertex.find(u_global); bool valid = i != m_local_vertex.end(); return std::make_pair((valid ? (*i).second : null_vertex()), valid); } // Is edge e (of the root graph) contained in this subgraph? // If so, return the matching local edge. std::pair< edge_descriptor, bool > find_edge(edge_descriptor e_global) const { if (is_root()) return std::make_pair(e_global, true); typename LocalEdgeMap::const_iterator i = m_local_edge.find(get(get(edge_index, root().m_graph), e_global)); bool valid = i != m_local_edge.end(); return std::make_pair((valid ? (*i).second : edge_descriptor()), valid); } // Return the parent graph. subgraph& parent() { return *m_parent; } const subgraph& parent() const { return *m_parent; } // Return true if this is the root subgraph bool is_root() const { return m_parent == 0; } // Return the root graph of the subgraph tree. subgraph& root() { return is_root() ? *this : m_parent->root(); } const subgraph& root() const { return is_root() ? *this : m_parent->root(); } // Return the children subgraphs of this graph/subgraph. // Use a list of pointers because the VC++ std::list doesn't like // storing incomplete type. typedef indirect_iterator< typename ChildrenList::const_iterator, subgraph< Graph >, std::bidirectional_iterator_tag > children_iterator; typedef indirect_iterator< typename ChildrenList::const_iterator, subgraph< Graph > const, std::bidirectional_iterator_tag > const_children_iterator; std::pair< const_children_iterator, const_children_iterator > children() const { return std::make_pair(const_children_iterator(m_children.begin()), const_children_iterator(m_children.end())); } std::pair< children_iterator, children_iterator > children() { return std::make_pair(children_iterator(m_children.begin()), children_iterator(m_children.end())); } std::size_t num_children() const { return m_children.size(); } #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES // Defualt property access delegates the lookup to global properties. template < typename Descriptor > typename graph::detail::bundled_result< Graph, Descriptor >::type& operator[](Descriptor x) { return is_root() ? m_graph[x] : root().m_graph[local_to_global(x)]; } template < typename Descriptor > typename graph::detail::bundled_result< Graph, Descriptor >::type const& operator[](Descriptor x) const { return is_root() ? m_graph[x] : root().m_graph[local_to_global(x)]; } // Local property access returns the local property of the given descripor. template < typename Descriptor > typename graph::detail::bundled_result< Graph, Descriptor >::type& operator[](local_property< Descriptor > x) { return m_graph[x.value]; } template < typename Descriptor > typename graph::detail::bundled_result< Graph, Descriptor >::type const& operator[](local_property< Descriptor > x) const { return m_graph[x.value]; } // Global property access returns the global property associated with the // given descriptor. This is an alias for the default bundled property // access operations. template < typename Descriptor > typename graph::detail::bundled_result< Graph, Descriptor >::type& operator[](global_property< Descriptor > x) { return (*this)[x.value]; } template < typename Descriptor > typename graph::detail::bundled_result< Graph, Descriptor >::type const& operator[](global_property< Descriptor > x) const { return (*this)[x.value]; } #endif // BOOST_GRAPH_NO_BUNDLED_PROPERTIES // private: typedef typename property_map< Graph, edge_index_t >::type EdgeIndexMap; typedef typename property_traits< EdgeIndexMap >::value_type edge_index_type; BOOST_STATIC_ASSERT((!is_same< edge_index_type, boost::detail::error_property_not_found >::value)); private: typedef std::vector< vertex_descriptor > GlobalVertexList; typedef std::vector< edge_descriptor > GlobalEdgeList; typedef std::map< vertex_descriptor, vertex_descriptor > LocalVertexMap; typedef std::map< edge_index_type, edge_descriptor > LocalEdgeMap; // TODO: Should the LocalVertexMap be: map<index_type, descriptor>? // TODO: Can we relax the indexing requirement if both descriptors are // LessThanComparable? // TODO: Should we really be using unorderd_map for improved lookup times? public: // Probably shouldn't be public.... Graph m_graph; subgraph< Graph >* m_parent; edge_index_type m_edge_counter; // for generating unique edge indices ChildrenList m_children; GlobalVertexList m_global_vertex; // local -> global LocalVertexMap m_local_vertex; // global -> local GlobalEdgeList m_global_edge; // local -> global LocalEdgeMap m_local_edge; // global -> local edge_descriptor local_add_edge(vertex_descriptor u_local, vertex_descriptor v_local, edge_descriptor e_global) { edge_descriptor e_local; bool inserted; boost::tie(e_local, inserted) = add_edge(u_local, v_local, m_graph); put(edge_index, m_graph, e_local, m_edge_counter++); m_global_edge.push_back(e_global); m_local_edge[get(get(edge_index, this->root()), e_global)] = e_local; return e_local; } }; template < typename Graph > struct vertex_bundle_type< subgraph< Graph > > : vertex_bundle_type< Graph > { }; template < typename Graph > struct edge_bundle_type< subgraph< Graph > > : edge_bundle_type< Graph > { }; template < typename Graph > struct graph_bundle_type< subgraph< Graph > > : graph_bundle_type< Graph > { }; //=========================================================================== // Functions special to the Subgraph Class template < typename G > typename subgraph< G >::vertex_descriptor add_vertex( typename subgraph< G >::vertex_descriptor u_global, subgraph< G >& g) { BOOST_ASSERT(!g.is_root()); typename subgraph< G >::vertex_descriptor u_local; bool exists_local; boost::tie(u_local, exists_local) = g.find_vertex(u_global); if (!exists_local) { typename subgraph< G >::vertex_descriptor v_global; typename subgraph< G >::edge_descriptor e_global; // call recursion for parent subgraph if (!g.parent().is_root()) add_vertex(u_global, g.parent()); u_local = add_vertex(g.m_graph); g.m_global_vertex.push_back(u_global); g.m_local_vertex[u_global] = u_local; subgraph< G >& r = g.root(); // remember edge global and local maps { typename subgraph< G >::out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(u_global, r); ei != ei_end; ++ei) { e_global = *ei; v_global = target(e_global, r); if (g.find_vertex(v_global).second == true) g.local_add_edge( u_local, g.global_to_local(v_global), e_global); } } if (is_directed(g)) { // not necessary for undirected graph typename subgraph< G >::vertex_iterator vi, vi_end; typename subgraph< G >::out_edge_iterator ei, ei_end; for (boost::tie(vi, vi_end) = vertices(r); vi != vi_end; ++vi) { v_global = *vi; if (v_global == u_global) continue; // don't insert self loops twice! if (!g.find_vertex(v_global).second) continue; // not a subgraph vertex => try next one for (boost::tie(ei, ei_end) = out_edges(*vi, r); ei != ei_end; ++ei) { e_global = *ei; if (target(e_global, r) == u_global) { g.local_add_edge( g.global_to_local(v_global), u_local, e_global); } } } } } return u_local; } // NOTE: Descriptors are local unless otherwise noted. //=========================================================================== // Functions required by the IncidenceGraph concept template < typename G > std::pair< typename graph_traits< G >::out_edge_iterator, typename graph_traits< G >::out_edge_iterator > out_edges( typename graph_traits< G >::vertex_descriptor v, const subgraph< G >& g) { return out_edges(v, g.m_graph); } template < typename G > typename graph_traits< G >::degree_size_type out_degree( typename graph_traits< G >::vertex_descriptor v, const subgraph< G >& g) { return out_degree(v, g.m_graph); } template < typename G > typename graph_traits< G >::vertex_descriptor source( typename graph_traits< G >::edge_descriptor e, const subgraph< G >& g) { return source(e, g.m_graph); } template < typename G > typename graph_traits< G >::vertex_descriptor target( typename graph_traits< G >::edge_descriptor e, const subgraph< G >& g) { return target(e, g.m_graph); } //=========================================================================== // Functions required by the BidirectionalGraph concept template < typename G > std::pair< typename graph_traits< G >::in_edge_iterator, typename graph_traits< G >::in_edge_iterator > in_edges( typename graph_traits< G >::vertex_descriptor v, const subgraph< G >& g) { return in_edges(v, g.m_graph); } template < typename G > typename graph_traits< G >::degree_size_type in_degree( typename graph_traits< G >::vertex_descriptor v, const subgraph< G >& g) { return in_degree(v, g.m_graph); } template < typename G > typename graph_traits< G >::degree_size_type degree( typename graph_traits< G >::vertex_descriptor v, const subgraph< G >& g) { return degree(v, g.m_graph); } //=========================================================================== // Functions required by the AdjacencyGraph concept template < typename G > std::pair< typename subgraph< G >::adjacency_iterator, typename subgraph< G >::adjacency_iterator > adjacent_vertices( typename subgraph< G >::vertex_descriptor v, const subgraph< G >& g) { return adjacent_vertices(v, g.m_graph); } //=========================================================================== // Functions required by the VertexListGraph concept template < typename G > std::pair< typename subgraph< G >::vertex_iterator, typename subgraph< G >::vertex_iterator > vertices(const subgraph< G >& g) { return vertices(g.m_graph); } template < typename G > typename subgraph< G >::vertices_size_type num_vertices(const subgraph< G >& g) { return num_vertices(g.m_graph); } //=========================================================================== // Functions required by the EdgeListGraph concept template < typename G > std::pair< typename subgraph< G >::edge_iterator, typename subgraph< G >::edge_iterator > edges(const subgraph< G >& g) { return edges(g.m_graph); } template < typename G > typename subgraph< G >::edges_size_type num_edges(const subgraph< G >& g) { return num_edges(g.m_graph); } //=========================================================================== // Functions required by the AdjacencyMatrix concept template < typename G > std::pair< typename subgraph< G >::edge_descriptor, bool > edge( typename subgraph< G >::vertex_descriptor u, typename subgraph< G >::vertex_descriptor v, const subgraph< G >& g) { return edge(u, v, g.m_graph); } //=========================================================================== // Functions required by the MutableGraph concept namespace detail { template < typename Vertex, typename Edge, typename Graph > void add_edge_recur_down( Vertex u_global, Vertex v_global, Edge e_global, subgraph< Graph >& g); template < typename Vertex, typename Edge, typename Children, typename G > void children_add_edge(Vertex u_global, Vertex v_global, Edge e_global, Children& c, subgraph< G >* orig) { for (typename Children::iterator i = c.begin(); i != c.end(); ++i) { if ((*i)->find_vertex(u_global).second && (*i)->find_vertex(v_global).second) { add_edge_recur_down(u_global, v_global, e_global, **i, orig); } } } template < typename Vertex, typename Edge, typename Graph > void add_edge_recur_down(Vertex u_global, Vertex v_global, Edge e_global, subgraph< Graph >& g, subgraph< Graph >* orig) { if (&g != orig) { // add local edge only if u_global and v_global are in subgraph g Vertex u_local, v_local; bool u_in_subgraph, v_in_subgraph; boost::tie(u_local, u_in_subgraph) = g.find_vertex(u_global); boost::tie(v_local, v_in_subgraph) = g.find_vertex(v_global); if (u_in_subgraph && v_in_subgraph) { g.local_add_edge(u_local, v_local, e_global); } } children_add_edge(u_global, v_global, e_global, g.m_children, orig); } template < typename Vertex, typename Graph > std::pair< typename subgraph< Graph >::edge_descriptor, bool > add_edge_recur_up(Vertex u_global, Vertex v_global, const typename Graph::edge_property_type& ep, subgraph< Graph >& g, subgraph< Graph >* orig) { if (g.is_root()) { typename subgraph< Graph >::edge_descriptor e_global; bool inserted; boost::tie(e_global, inserted) = add_edge(u_global, v_global, ep, g.m_graph); put(edge_index, g.m_graph, e_global, g.m_edge_counter++); g.m_global_edge.push_back(e_global); children_add_edge(u_global, v_global, e_global, g.m_children, orig); return std::make_pair(e_global, inserted); } else { return add_edge_recur_up(u_global, v_global, ep, *g.m_parent, orig); } } } // namespace detail // Add an edge to the subgraph g, specified by the local vertex descriptors u // and v. In addition, the edge will be added to any (all) other subgraphs that // contain vertex descriptors u and v. template < typename G > std::pair< typename subgraph< G >::edge_descriptor, bool > add_edge( typename subgraph< G >::vertex_descriptor u, typename subgraph< G >::vertex_descriptor v, const typename G::edge_property_type& ep, subgraph< G >& g) { if (g.is_root()) { // u and v are really global return detail::add_edge_recur_up(u, v, ep, g, &g); } else { typename subgraph< G >::edge_descriptor e_local, e_global; bool inserted; boost::tie(e_global, inserted) = detail::add_edge_recur_up( g.local_to_global(u), g.local_to_global(v), ep, g, &g); e_local = g.local_add_edge(u, v, e_global); return std::make_pair(e_local, inserted); } } template < typename G > std::pair< typename subgraph< G >::edge_descriptor, bool > add_edge( typename subgraph< G >::vertex_descriptor u, typename subgraph< G >::vertex_descriptor v, subgraph< G >& g) { return add_edge(u, v, typename G::edge_property_type(), g); } namespace detail { //------------------------------------------------------------------------- // implementation of remove_edge(u,v,g) template < typename Vertex, typename Graph > void remove_edge_recur_down( Vertex u_global, Vertex v_global, subgraph< Graph >& g); template < typename Vertex, typename Children > void children_remove_edge(Vertex u_global, Vertex v_global, Children& c) { for (typename Children::iterator i = c.begin(); i != c.end(); ++i) { if ((*i)->find_vertex(u_global).second && (*i)->find_vertex(v_global).second) { remove_edge_recur_down(u_global, v_global, **i); } } } template < typename Vertex, typename Graph > void remove_edge_recur_down( Vertex u_global, Vertex v_global, subgraph< Graph >& g) { Vertex u_local, v_local; u_local = g.m_local_vertex[u_global]; v_local = g.m_local_vertex[v_global]; remove_edge(u_local, v_local, g.m_graph); children_remove_edge(u_global, v_global, g.m_children); } template < typename Vertex, typename Graph > void remove_edge_recur_up( Vertex u_global, Vertex v_global, subgraph< Graph >& g) { if (g.is_root()) { remove_edge(u_global, v_global, g.m_graph); children_remove_edge(u_global, v_global, g.m_children); } else { remove_edge_recur_up(u_global, v_global, *g.m_parent); } } //------------------------------------------------------------------------- // implementation of remove_edge(e,g) template < typename G, typename Edge, typename Children > void children_remove_edge(Edge e_global, Children& c) { for (typename Children::iterator i = c.begin(); i != c.end(); ++i) { std::pair< typename subgraph< G >::edge_descriptor, bool > found = (*i)->find_edge(e_global); if (!found.second) { continue; } children_remove_edge< G >(e_global, (*i)->m_children); remove_edge(found.first, (*i)->m_graph); } } } // namespace detail template < typename G > void remove_edge(typename subgraph< G >::vertex_descriptor u, typename subgraph< G >::vertex_descriptor v, subgraph< G >& g) { if (g.is_root()) { detail::remove_edge_recur_up(u, v, g); } else { detail::remove_edge_recur_up( g.local_to_global(u), g.local_to_global(v), g); } } template < typename G > void remove_edge(typename subgraph< G >::edge_descriptor e, subgraph< G >& g) { typename subgraph< G >::edge_descriptor e_global = g.local_to_global(e); #ifndef NDEBUG std::pair< typename subgraph< G >::edge_descriptor, bool > fe = g.find_edge(e_global); BOOST_ASSERT(fe.second && fe.first == e); #endif // NDEBUG subgraph< G >& root = g.root(); // chase to root detail::children_remove_edge< G >(e_global, root.m_children); remove_edge(e_global, root.m_graph); // kick edge from root } // This is slow, but there may not be a good way to do it safely otherwise template < typename Predicate, typename G > void remove_edge_if(Predicate p, subgraph< G >& g) { while (true) { bool any_removed = false; typedef typename subgraph< G >::edge_iterator ei_type; for (std::pair< ei_type, ei_type > ep = edges(g); ep.first != ep.second; ++ep.first) { if (p(*ep.first)) { any_removed = true; remove_edge(*ep.first, g); break; /* Since iterators may be invalidated */ } } if (!any_removed) break; } } template < typename G > void clear_vertex(typename subgraph< G >::vertex_descriptor v, subgraph< G >& g) { while (true) { typedef typename subgraph< G >::out_edge_iterator oei_type; std::pair< oei_type, oei_type > p = out_edges(v, g); if (p.first == p.second) break; remove_edge(*p.first, g); } } namespace detail { template < typename G > typename subgraph< G >::vertex_descriptor add_vertex_recur_up( subgraph< G >& g) { typename subgraph< G >::vertex_descriptor u_local, u_global; if (g.is_root()) { u_global = add_vertex(g.m_graph); g.m_global_vertex.push_back(u_global); } else { u_global = add_vertex_recur_up(*g.m_parent); u_local = add_vertex(g.m_graph); g.m_global_vertex.push_back(u_global); g.m_local_vertex[u_global] = u_local; } return u_global; } } // namespace detail template < typename G > typename subgraph< G >::vertex_descriptor add_vertex(subgraph< G >& g) { typename subgraph< G >::vertex_descriptor u_local, u_global; if (g.is_root()) { u_global = add_vertex(g.m_graph); g.m_global_vertex.push_back(u_global); u_local = u_global; } else { u_global = detail::add_vertex_recur_up(g.parent()); u_local = add_vertex(g.m_graph); g.m_global_vertex.push_back(u_global); g.m_local_vertex[u_global] = u_local; } return u_local; } #if 0 // TODO: Under Construction template <typename G> void remove_vertex(typename subgraph<G>::vertex_descriptor u, subgraph<G>& g) { BOOST_ASSERT(false); } #endif //=========================================================================== // Functions required by the PropertyGraph concept /** * The global property map returns the global properties associated with local * descriptors. */ template < typename GraphPtr, typename PropertyMap, typename Tag > class subgraph_global_property_map : public put_get_helper< typename property_traits< PropertyMap >::reference, subgraph_global_property_map< GraphPtr, PropertyMap, Tag > > { typedef property_traits< PropertyMap > Traits; public: typedef typename mpl::if_< is_const< typename remove_pointer< GraphPtr >::type >, readable_property_map_tag, typename Traits::category >::type category; typedef typename Traits::value_type value_type; typedef typename Traits::key_type key_type; typedef typename Traits::reference reference; subgraph_global_property_map() {} subgraph_global_property_map(GraphPtr g, Tag tag) : m_g(g), m_tag(tag) {} reference operator[](key_type e) const { PropertyMap pmap = get(m_tag, m_g->root().m_graph); return m_g->is_root() ? pmap[e] : pmap[m_g->local_to_global(e)]; } GraphPtr m_g; Tag m_tag; }; /** * The local property map returns the local property associated with the local * descriptors. */ template < typename GraphPtr, typename PropertyMap, typename Tag > class subgraph_local_property_map : public put_get_helper< typename property_traits< PropertyMap >::reference, subgraph_local_property_map< GraphPtr, PropertyMap, Tag > > { typedef property_traits< PropertyMap > Traits; public: typedef typename mpl::if_< is_const< typename remove_pointer< GraphPtr >::type >, readable_property_map_tag, typename Traits::category >::type category; typedef typename Traits::value_type value_type; typedef typename Traits::key_type key_type; typedef typename Traits::reference reference; typedef Tag tag; typedef PropertyMap pmap; subgraph_local_property_map() {} subgraph_local_property_map(GraphPtr g, Tag tag) : m_g(g), m_tag(tag) {} reference operator[](key_type e) const { // Get property map on the underlying graph. PropertyMap pmap = get(m_tag, m_g->m_graph); return pmap[e]; } GraphPtr m_g; Tag m_tag; }; namespace detail { // Extract the actual tags from local or global property maps so we don't // try to find non-properties. template < typename P > struct extract_lg_tag { typedef P type; }; template < typename P > struct extract_lg_tag< local_property< P > > { typedef P type; }; template < typename P > struct extract_lg_tag< global_property< P > > { typedef P type; }; // NOTE: Mysterious Property template parameter unused in both metafunction // classes. struct subgraph_global_pmap { template < class Tag, class SubGraph, class Property > struct bind_ { typedef typename SubGraph::graph_type Graph; typedef SubGraph* SubGraphPtr; typedef const SubGraph* const_SubGraphPtr; typedef typename extract_lg_tag< Tag >::type TagType; typedef typename property_map< Graph, TagType >::type PMap; typedef typename property_map< Graph, TagType >::const_type const_PMap; public: typedef subgraph_global_property_map< SubGraphPtr, PMap, TagType > type; typedef subgraph_global_property_map< const_SubGraphPtr, const_PMap, TagType > const_type; }; }; struct subgraph_local_pmap { template < class Tag, class SubGraph, class Property > struct bind_ { typedef typename SubGraph::graph_type Graph; typedef SubGraph* SubGraphPtr; typedef const SubGraph* const_SubGraphPtr; typedef typename extract_lg_tag< Tag >::type TagType; typedef typename property_map< Graph, TagType >::type PMap; typedef typename property_map< Graph, TagType >::const_type const_PMap; public: typedef subgraph_local_property_map< SubGraphPtr, PMap, TagType > type; typedef subgraph_local_property_map< const_SubGraphPtr, const_PMap, TagType > const_type; }; }; // These metafunctions select the corresponding metafunctions above, and // are used by the choose_pmap metafunction below to specialize the choice // of local/global property map. By default, we defer to the global // property. template < class Tag > struct subgraph_choose_pmap_helper { typedef subgraph_global_pmap type; }; template < class Tag > struct subgraph_choose_pmap_helper< local_property< Tag > > { typedef subgraph_local_pmap type; }; template < class Tag > struct subgraph_choose_pmap_helper< global_property< Tag > > { typedef subgraph_global_pmap type; }; // As above, unless we're requesting vertex_index_t. Then it's always a // local property map. This enables the correct translation of descriptors // between local and global layers. template <> struct subgraph_choose_pmap_helper< vertex_index_t > { typedef subgraph_local_pmap type; }; template <> struct subgraph_choose_pmap_helper< local_property< vertex_index_t > > { typedef subgraph_local_pmap type; }; template <> struct subgraph_choose_pmap_helper< global_property< vertex_index_t > > { typedef subgraph_local_pmap type; }; // Determine the kind of property. If SameType<Tag, vertex_index_t>, then // the property lookup is always local. Otherwise, the lookup is global. // NOTE: Property parameter is basically unused. template < class Tag, class Graph, class Property > struct subgraph_choose_pmap { typedef typename subgraph_choose_pmap_helper< Tag >::type Helper; typedef typename Helper::template bind_< Tag, Graph, Property > Bind; typedef typename Bind::type type; typedef typename Bind::const_type const_type; }; // Used by the vertex/edge property selectors to determine the kind(s) of // property maps used by the property_map type generator. struct subgraph_property_generator { template < class SubGraph, class Property, class Tag > struct bind_ { typedef subgraph_choose_pmap< Tag, SubGraph, Property > Choice; typedef typename Choice::type type; typedef typename Choice::const_type const_type; }; }; } // namespace detail template <> struct vertex_property_selector< subgraph_tag > { typedef detail::subgraph_property_generator type; }; template <> struct edge_property_selector< subgraph_tag > { typedef detail::subgraph_property_generator type; }; // ================================================== // get(p, g), get(p, g, k), and put(p, g, k, v) // ================================================== template < typename G, typename Property > typename property_map< subgraph< G >, Property >::type get( Property p, subgraph< G >& g) { typedef typename property_map< subgraph< G >, Property >::type PMap; return PMap(&g, p); } template < typename G, typename Property > typename property_map< subgraph< G >, Property >::const_type get( Property p, const subgraph< G >& g) { typedef typename property_map< subgraph< G >, Property >::const_type PMap; return PMap(&g, p); } template < typename G, typename Property, typename Key > typename property_traits< typename property_map< subgraph< G >, Property >::const_type >::value_type get(Property p, const subgraph< G >& g, const Key& k) { typedef typename property_map< subgraph< G >, Property >::const_type PMap; PMap pmap(&g, p); return pmap[k]; } template < typename G, typename Property, typename Key, typename Value > void put(Property p, subgraph< G >& g, const Key& k, const Value& val) { typedef typename property_map< subgraph< G >, Property >::type PMap; PMap pmap(&g, p); pmap[k] = val; } // ================================================== // get(global(p), g) // NOTE: get(global(p), g, k) and put(global(p), g, k, v) not supported // ================================================== template < typename G, typename Property > typename property_map< subgraph< G >, global_property< Property > >::type get( global_property< Property > p, subgraph< G >& g) { typedef typename property_map< subgraph< G >, global_property< Property > >::type Map; return Map(&g, p.value); } template < typename G, typename Property > typename property_map< subgraph< G >, global_property< Property > >::const_type get(global_property< Property > p, const subgraph< G >& g) { typedef typename property_map< subgraph< G >, global_property< Property > >::const_type Map; return Map(&g, p.value); } // ================================================== // get(local(p), g) // NOTE: get(local(p), g, k) and put(local(p), g, k, v) not supported // ================================================== template < typename G, typename Property > typename property_map< subgraph< G >, local_property< Property > >::type get( local_property< Property > p, subgraph< G >& g) { typedef typename property_map< subgraph< G >, local_property< Property > >::type Map; return Map(&g, p.value); } template < typename G, typename Property > typename property_map< subgraph< G >, local_property< Property > >::const_type get(local_property< Property > p, const subgraph< G >& g) { typedef typename property_map< subgraph< G >, local_property< Property > >::const_type Map; return Map(&g, p.value); } template < typename G, typename Tag > inline typename graph_property< G, Tag >::type& get_property( subgraph< G >& g, Tag tag) { return get_property(g.m_graph, tag); } template < typename G, typename Tag > inline const typename graph_property< G, Tag >::type& get_property( const subgraph< G >& g, Tag tag) { return get_property(g.m_graph, tag); } //=========================================================================== // Miscellaneous Functions template < typename G > typename subgraph< G >::vertex_descriptor vertex( typename subgraph< G >::vertices_size_type n, const subgraph< G >& g) { return vertex(n, g.m_graph); } //=========================================================================== // Mutability Traits // Just pull the mutability traits form the underlying graph. Note that this // will probably fail (badly) for labeled graphs. template < typename G > struct graph_mutability_traits< subgraph< G > > { typedef typename graph_mutability_traits< G >::category category; }; } // namespace boost #endif // BOOST_SUBGRAPH_HPP adjacency_list_io.hpp 0000644 00000027111 15125521275 0010727 0 ustar 00 //======================================================================= // Copyright 2001 Universite Joseph Fourier, Grenoble. // Author: Francois Faure // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_ADJACENCY_LIST_IO_HPP #define BOOST_GRAPH_ADJACENCY_LIST_IO_HPP #include <iostream> #include <vector> #include <boost/graph/adjacency_list.hpp> #include <boost/graph/iteration_macros.hpp> #include <cctype> // Method read to parse an adjacency list from an input stream. Examples: // cin >> read( G ); // cin >> read( G, NodePropertySubset(), EdgepropertySubset() ); // // Method write to print an adjacency list to an output stream. Examples: // cout << write( G ); // cout << write( G, NodePropertySubset(), EdgepropertySubset() ); namespace boost { /* outline - basic property input - get property subset - graph parser - property printer - graph printer - user methods */ //=========================================================================== // basic property input template < class Tag, class Value, class Next > std::istream& operator>>(std::istream& in, property< Tag, Value, Next >& p) { in >> p.m_value >> p.m_base; // houpla !! return in; } template < class Tag, class Value > std::istream& operator>>( std::istream& in, property< Tag, Value, no_property >& p) { in >> p.m_value; return in; } inline std::istream& operator>>(std::istream& in, no_property&) { return in; } // basic property input //=========================================================================== // get property subsets // get a single property tagged Stag template < class Tag, class Value, class Next, class V, class Stag > void get(property< Tag, Value, Next >& p, const V& v, Stag s) { get(p.m_base, v, s); } template < class Value, class Next, class V, class Stag > void get(property< Stag, Value, Next >& p, const V& v, Stag) { p.m_value = v; } // get a subset of properties tagged Stag template < class Tag, class Value, class Next, class Stag, class Svalue, class Snext > void getSubset( property< Tag, Value, Next >& p, const property< Stag, Svalue, Snext >& s) { get(p, s.m_value, Stag()); getSubset(p, s.m_base); } template < class Tag, class Value, class Next, class Stag, class Svalue > void getSubset(property< Tag, Value, Next >& p, const property< Stag, Svalue, no_property >& s) { get(p, s.m_value, Stag()); } inline void getSubset(no_property&, const no_property&) {} #if !defined(BOOST_GRAPH_NO_BUNDLED_PROPERTIES) template < typename T, typename U > void getSubset(T& p, const U& s) { p = s; } template < typename T > void getSubset(T&, const no_property&) {} #endif // get property subset //=========================================================================== // graph parser typedef enum { PARSE_NUM_NODES, PARSE_VERTEX, PARSE_EDGE } GraphParserState; template < class Graph_t, class VertexProperty, class EdgeProperty, class VertexPropertySubset, class EdgePropertySubset > struct GraphParser { typedef Graph_t Graph; GraphParser(Graph* g) : graph(g) {} GraphParser& operator()(std::istream& in) { typedef typename graph_traits< Graph >::vertex_descriptor Vertex; std::vector< Vertex > nodes; GraphParserState state = PARSE_VERTEX; unsigned int numLine = 1; char c; while (in.get(c)) { if (c == '#') skip(in); else if (c == 'n') state = PARSE_NUM_NODES; else if (c == 'v') state = PARSE_VERTEX; else if (c == 'e') state = PARSE_EDGE; else if (c == '\n') numLine++; else if (!std::isspace(c)) { in.putback(c); if (state == PARSE_VERTEX) { VertexPropertySubset readProp; if (in >> readProp) { VertexProperty vp; getSubset(vp, readProp); nodes.push_back(add_vertex(vp, *graph)); } else std::cerr << "read vertex, parse error at line" << numLine << std::endl; } else if (state == PARSE_EDGE) { int source, target; EdgePropertySubset readProp; in >> source >> target; if (in >> readProp) { EdgeProperty ep; getSubset(ep, readProp); add_edge(nodes[source], nodes[target], ep, *graph); } else std::cerr << "read edge, parse error at line" << numLine << std::endl; } else { // state == PARSE_NUM_NODES int n; if (in >> n) { for (int i = 0; i < n; ++i) nodes.push_back(add_vertex(*graph)); } else std::cerr << "read num_nodes, parse error at line " << numLine << std::endl; } } } return (*this); } protected: Graph* graph; void skip(std::istream& in) { char c = 0; while (c != '\n' && !in.eof()) in.get(c); in.putback(c); } }; // parser //======================================================================= // property printer #if defined(BOOST_GRAPH_NO_BUNDLED_PROPERTIES) template < class Graph, class Property > struct PropertyPrinter { typedef typename Property::value_type Value; typedef typename Property::tag_type Tag; typedef typename Property::next_type Next; PropertyPrinter(const Graph& g) : graph(&g) {} template < class Val > PropertyPrinter& operator()(std::ostream& out, const Val& v) { typename property_map< Graph, Tag >::const_type ps = get(Tag(), *graph); out << ps[v] << " "; PropertyPrinter< Graph, Next > print(*graph); print(out, v); return (*this); } private: const Graph* graph; }; #else template < class Graph, typename Property > struct PropertyPrinter { PropertyPrinter(const Graph& g) : graph(&g) {} template < class Val > PropertyPrinter& operator()(std::ostream& out, const Val& v) { out << (*graph)[v] << " "; return (*this); } private: const Graph* graph; }; template < class Graph, typename Tag, typename Value, typename Next > struct PropertyPrinter< Graph, property< Tag, Value, Next > > { PropertyPrinter(const Graph& g) : graph(&g) {} template < class Val > PropertyPrinter& operator()(std::ostream& out, const Val& v) { typename property_map< Graph, Tag >::const_type ps = get(Tag(), *graph); out << ps[v] << " "; PropertyPrinter< Graph, Next > print(*graph); print(out, v); return (*this); } private: const Graph* graph; }; #endif template < class Graph > struct PropertyPrinter< Graph, no_property > { PropertyPrinter(const Graph&) {} template < class Val > PropertyPrinter& operator()(std::ostream&, const Val&) { return *this; } }; // property printer //========================================================================= // graph printer template < class Graph_t, class EdgeProperty > struct EdgePrinter { typedef Graph_t Graph; typedef typename graph_traits< Graph >::vertex_descriptor Vertex; EdgePrinter(const Graph& g) : graph(g) {} const EdgePrinter& operator()(std::ostream& out) const { // assign indices to vertices std::map< Vertex, int > indices; int num = 0; BGL_FORALL_VERTICES_T(v, graph, Graph) { indices[v] = num++; } // write edges PropertyPrinter< Graph, EdgeProperty > print_Edge(graph); out << "e" << std::endl; BGL_FORALL_EDGES_T(e, graph, Graph) { out << indices[source(e, graph)] << " " << indices[target(e, graph)] << " "; print_Edge(out, e); out << std::endl; } out << std::endl; return (*this); } protected: const Graph& graph; }; template < class Graph, class V, class E > struct GraphPrinter : public EdgePrinter< Graph, E > { GraphPrinter(const Graph& g) : EdgePrinter< Graph, E >(g) {} const GraphPrinter& operator()(std::ostream& out) const { PropertyPrinter< Graph, V > printNode(this->graph); out << "v" << std::endl; BGL_FORALL_VERTICES_T(v, this->graph, Graph) { printNode(out, v); out << std::endl; } EdgePrinter< Graph, E >::operator()(out); return (*this); } }; template < class Graph, class E > struct GraphPrinter< Graph, no_property, E > : public EdgePrinter< Graph, E > { GraphPrinter(const Graph& g) : EdgePrinter< Graph, E >(g) {} const GraphPrinter& operator()(std::ostream& out) const { out << "n " << num_vertices(this->graph) << std::endl; EdgePrinter< Graph, E >::operator()(out); return (*this); } }; // graph printer //========================================================================= // user methods /// input stream for reading a graph template < class Graph, class VP, class EP, class VPS, class EPS > std::istream& operator>>( std::istream& in, GraphParser< Graph, VP, EP, VPS, EPS > gp) { gp(in); return in; } /// graph parser for given subsets of internal vertex and edge properties template < class EL, class VL, class D, class VP, class EP, class GP, class VPS, class EPS > GraphParser< adjacency_list< EL, VL, D, VP, EP, GP >, VP, EP, VPS, EPS > read( adjacency_list< EL, VL, D, VP, EP, GP >& g, VPS vps, EPS eps) { return GraphParser< adjacency_list< EL, VL, D, VP, EP, GP >, VP, EP, VPS, EPS >(&g); } /// graph parser for all internal vertex and edge properties template < class EL, class VL, class D, class VP, class EP, class GP > GraphParser< adjacency_list< EL, VL, D, VP, EP, GP >, VP, EP, VP, EP > read( adjacency_list< EL, VL, D, VP, EP, GP >& g) { return GraphParser< adjacency_list< EL, VL, D, VP, EP, GP >, VP, EP, VP, EP >(&g); } /// output stream for writing a graph template < class Graph, class VP, class EP > std::ostream& operator<<( std::ostream& out, const GraphPrinter< Graph, VP, EP >& gp) { gp(out); return out; } /// write the graph with given property subsets template < class EL, class VL, class D, class VP, class EP, class GP, class VPS, class EPS > GraphPrinter< adjacency_list< EL, VL, D, VP, EP, GP >, VPS, EPS > write( const adjacency_list< EL, VL, D, VP, EP, GP >& g, VPS, EPS) { return GraphPrinter< adjacency_list< EL, VL, D, VP, EP, GP >, VPS, EPS >(g); } /// write the graph with all internal vertex and edge properties template < class EL, class VL, class D, class VP, class EP, class GP > GraphPrinter< adjacency_list< EL, VL, D, VP, EP, GP >, VP, EP > write( const adjacency_list< EL, VL, D, VP, EP, GP >& g) { return GraphPrinter< adjacency_list< EL, VL, D, VP, EP, GP >, VP, EP >(g); } // user methods //========================================================================= } // boost #endif one_bit_color_map.hpp 0000644 00000006325 15125521275 0010742 0 ustar 00 // Copyright (C) 2005-2010 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Jeremiah Willcock // Douglas Gregor // Andrew Lumsdaine // One bit per color property map (gray and black are the same, green is not // supported) #ifndef BOOST_ONE_BIT_COLOR_MAP_HPP #define BOOST_ONE_BIT_COLOR_MAP_HPP #include <boost/property_map/property_map.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/detail/mpi_include.hpp> #include <boost/shared_array.hpp> #include <boost/config.hpp> #include <boost/assert.hpp> #include <algorithm> #include <limits> namespace boost { enum one_bit_color_type { one_bit_white = 0, one_bit_not_white = 1 }; template <> struct color_traits< one_bit_color_type > { static one_bit_color_type white() { return one_bit_white; } static one_bit_color_type gray() { return one_bit_not_white; } static one_bit_color_type black() { return one_bit_not_white; } }; template < typename IndexMap = identity_property_map > struct one_bit_color_map { BOOST_STATIC_CONSTANT( int, bits_per_char = std::numeric_limits< unsigned char >::digits); std::size_t n; IndexMap index; shared_array< unsigned char > data; typedef typename property_traits< IndexMap >::key_type key_type; typedef one_bit_color_type value_type; typedef void reference; typedef read_write_property_map_tag category; explicit one_bit_color_map( std::size_t n, const IndexMap& index = IndexMap()) : n(n) , index(index) , data(new unsigned char[(n + bits_per_char - 1) / bits_per_char]()) { } }; template < typename IndexMap > inline one_bit_color_type get(const one_bit_color_map< IndexMap >& pm, typename property_traits< IndexMap >::key_type key) { BOOST_STATIC_CONSTANT( int, bits_per_char = one_bit_color_map< IndexMap >::bits_per_char); typename property_traits< IndexMap >::value_type i = get(pm.index, key); BOOST_ASSERT((std::size_t)i < pm.n); return one_bit_color_type( (pm.data.get()[i / bits_per_char] >> (i % bits_per_char)) & 1); } template < typename IndexMap > inline void put(const one_bit_color_map< IndexMap >& pm, typename property_traits< IndexMap >::key_type key, one_bit_color_type value) { BOOST_STATIC_CONSTANT( int, bits_per_char = one_bit_color_map< IndexMap >::bits_per_char); typename property_traits< IndexMap >::value_type i = get(pm.index, key); BOOST_ASSERT((std::size_t)i < pm.n); BOOST_ASSERT(value >= 0 && value < 2); std::size_t byte_num = i / bits_per_char; std::size_t bit_position = (i % bits_per_char); pm.data.get()[byte_num] = (unsigned char)((pm.data.get()[byte_num] & ~(1 << bit_position)) | (value << bit_position)); } template < typename IndexMap > inline one_bit_color_map< IndexMap > make_one_bit_color_map( std::size_t n, const IndexMap& index_map) { return one_bit_color_map< IndexMap >(n, index_map); } } // end namespace boost #include BOOST_GRAPH_MPI_INCLUDE(< boost / graph / distributed / one_bit_color_map.hpp >) #endif // BOOST_ONE_BIT_COLOR_MAP_HPP point_traits.hpp 0000644 00000001416 15125521275 0010003 0 ustar 00 // Copyright 2004, 2005 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_POINT_TRAITS_HPP #define BOOST_GRAPH_POINT_TRAITS_HPP namespace boost { namespace graph { template < typename Point > struct point_traits { // The type of each component of the point typedef typename Point::component_type component_type; // The number of dimensions in the point static std::size_t dimensions(const Point& point); }; } } // end namespace boost::graph #endif // BOOST_GRAPH_POINT_TRAITS_HPP two_bit_color_map.hpp 0000644 00000006676 15125521275 0011003 0 ustar 00 // Copyright (C) 2005-2006 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Jeremiah Willcock // Douglas Gregor // Andrew Lumsdaine // Two bit per color property map #ifndef BOOST_TWO_BIT_COLOR_MAP_HPP #define BOOST_TWO_BIT_COLOR_MAP_HPP #include <boost/property_map/property_map.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/detail/mpi_include.hpp> #include <boost/shared_array.hpp> #include <boost/config.hpp> #include <boost/assert.hpp> #include <algorithm> #include <limits> namespace boost { enum two_bit_color_type { two_bit_white = 0, two_bit_gray = 1, two_bit_green = 2, two_bit_black = 3 }; template <> struct color_traits< two_bit_color_type > { static two_bit_color_type white() { return two_bit_white; } static two_bit_color_type gray() { return two_bit_gray; } static two_bit_color_type green() { return two_bit_green; } static two_bit_color_type black() { return two_bit_black; } }; template < typename IndexMap = identity_property_map > struct two_bit_color_map { std::size_t n; IndexMap index; shared_array< unsigned char > data; BOOST_STATIC_CONSTANT( int, bits_per_char = std::numeric_limits< unsigned char >::digits); BOOST_STATIC_CONSTANT(int, elements_per_char = bits_per_char / 2); typedef typename property_traits< IndexMap >::key_type key_type; typedef two_bit_color_type value_type; typedef void reference; typedef read_write_property_map_tag category; explicit two_bit_color_map( std::size_t n, const IndexMap& index = IndexMap()) : n(n) , index(index) , data(new unsigned char[(n + elements_per_char - 1) / elements_per_char]()) { } }; template < typename IndexMap > inline two_bit_color_type get(const two_bit_color_map< IndexMap >& pm, typename property_traits< IndexMap >::key_type key) { BOOST_STATIC_CONSTANT(int, elements_per_char = two_bit_color_map< IndexMap >::elements_per_char); typename property_traits< IndexMap >::value_type i = get(pm.index, key); BOOST_ASSERT((std::size_t)i < pm.n); std::size_t byte_num = i / elements_per_char; std::size_t bit_position = ((i % elements_per_char) * 2); return two_bit_color_type((pm.data.get()[byte_num] >> bit_position) & 3); } template < typename IndexMap > inline void put(const two_bit_color_map< IndexMap >& pm, typename property_traits< IndexMap >::key_type key, two_bit_color_type value) { BOOST_STATIC_CONSTANT(int, elements_per_char = two_bit_color_map< IndexMap >::elements_per_char); typename property_traits< IndexMap >::value_type i = get(pm.index, key); BOOST_ASSERT((std::size_t)i < pm.n); BOOST_ASSERT(value >= 0 && value < 4); std::size_t byte_num = i / elements_per_char; std::size_t bit_position = ((i % elements_per_char) * 2); pm.data.get()[byte_num] = (unsigned char)((pm.data.get()[byte_num] & ~(3 << bit_position)) | (value << bit_position)); } template < typename IndexMap > inline two_bit_color_map< IndexMap > make_two_bit_color_map( std::size_t n, const IndexMap& index_map) { return two_bit_color_map< IndexMap >(n, index_map); } } // end namespace boost #include BOOST_GRAPH_MPI_INCLUDE(< boost / graph / distributed / two_bit_color_map.hpp >) #endif // BOOST_TWO_BIT_COLOR_MAP_HPP tree_traits.hpp 0000644 00000002472 15125521275 0007614 0 ustar 00 // (C) Copyright Jeremy Siek 1999. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_TREE_STRUCTURE_HPP #define BOOST_TREE_STRUCTURE_HPP #include <boost/tuple/tuple.hpp> //For boost::tie() namespace boost { template < class T > struct tree_traits { typedef typename T::node_descriptor node_descriptor; typedef typename T::children_iterator children_iterator; }; template < class Tree, class TreeVisitor > void traverse_tree(typename tree_traits< Tree >::node_descriptor v, Tree& t, TreeVisitor visitor) { visitor.preorder(v, t); typename tree_traits< Tree >::children_iterator i, end; boost::tie(i, end) = children(v, t); if (i != end) { traverse_tree(*i++, t, visitor); visitor.inorder(v, t); while (i != end) traverse_tree(*i++, t, visitor); } else visitor.inorder(v, t); visitor.postorder(v, t); } struct null_tree_visitor { template < typename Node, typename Tree > void preorder(Node, Tree&) {} template < typename Node, typename Tree > void inorder(Node, Tree&) {} template < typename Node, typename Tree > void postorder(Node, Tree&) {} }; } /* namespace boost */ #endif /* BOOST_TREE_STRUCTURE_HPP */ isomorphism.hpp 0000644 00000063304 15125521275 0007641 0 ustar 00 // Copyright (C) 2001 Jeremy Siek, Douglas Gregor, Brian Osman // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GRAPH_ISOMORPHISM_HPP #define BOOST_GRAPH_ISOMORPHISM_HPP #include <utility> #include <vector> #include <iterator> #include <algorithm> #include <boost/config.hpp> #include <boost/assert.hpp> #include <boost/smart_ptr.hpp> #include <boost/graph/depth_first_search.hpp> #include <boost/detail/algorithm.hpp> #include <boost/pending/indirect_cmp.hpp> // for make_indirect_pmap #include <boost/concept/assert.hpp> #ifndef BOOST_GRAPH_ITERATION_MACROS_HPP #define BOOST_ISO_INCLUDED_ITER_MACROS // local macro, see bottom of file #include <boost/graph/iteration_macros.hpp> #endif namespace boost { namespace detail { template < typename Graph1, typename Graph2, typename IsoMapping, typename Invariant1, typename Invariant2, typename IndexMap1, typename IndexMap2 > class isomorphism_algo { typedef typename graph_traits< Graph1 >::vertex_descriptor vertex1_t; typedef typename graph_traits< Graph2 >::vertex_descriptor vertex2_t; typedef typename graph_traits< Graph1 >::edge_descriptor edge1_t; typedef typename graph_traits< Graph1 >::vertices_size_type size_type; typedef typename Invariant1::result_type invar1_value; typedef typename Invariant2::result_type invar2_value; const Graph1& G1; const Graph2& G2; IsoMapping f; Invariant1 invariant1; Invariant2 invariant2; std::size_t max_invariant; IndexMap1 index_map1; IndexMap2 index_map2; std::vector< vertex1_t > dfs_vertices; typedef typename std::vector< vertex1_t >::iterator vertex_iter; std::vector< int > dfs_num_vec; typedef safe_iterator_property_map< typename std::vector< int >::iterator, IndexMap1 #ifdef BOOST_NO_STD_ITERATOR_TRAITS , int, int& #endif /* BOOST_NO_STD_ITERATOR_TRAITS */ > DFSNumMap; DFSNumMap dfs_num; std::vector< edge1_t > ordered_edges; typedef typename std::vector< edge1_t >::iterator edge_iter; std::vector< char > in_S_vec; typedef safe_iterator_property_map< typename std::vector< char >::iterator, IndexMap2 #ifdef BOOST_NO_STD_ITERATOR_TRAITS , char, char& #endif /* BOOST_NO_STD_ITERATOR_TRAITS */ > InSMap; InSMap in_S; int num_edges_on_k; friend struct compare_multiplicity; struct compare_multiplicity { compare_multiplicity(Invariant1 invariant1, size_type* multiplicity) : invariant1(invariant1), multiplicity(multiplicity) { } bool operator()(const vertex1_t& x, const vertex1_t& y) const { return multiplicity[invariant1(x)] < multiplicity[invariant1(y)]; } Invariant1 invariant1; size_type* multiplicity; }; struct record_dfs_order : default_dfs_visitor { record_dfs_order( std::vector< vertex1_t >& v, std::vector< edge1_t >& e) : vertices(v), edges(e) { } void discover_vertex(vertex1_t v, const Graph1&) const { vertices.push_back(v); } void examine_edge(edge1_t e, const Graph1&) const { edges.push_back(e); } std::vector< vertex1_t >& vertices; std::vector< edge1_t >& edges; }; struct edge_cmp { edge_cmp(const Graph1& G1, DFSNumMap dfs_num) : G1(G1), dfs_num(dfs_num) { } bool operator()(const edge1_t& e1, const edge1_t& e2) const { using namespace std; int u1 = dfs_num[source(e1, G1)], v1 = dfs_num[target(e1, G1)]; int u2 = dfs_num[source(e2, G1)], v2 = dfs_num[target(e2, G1)]; int m1 = (max)(u1, v1); int m2 = (max)(u2, v2); // lexicographical comparison return std::make_pair(m1, std::make_pair(u1, v1)) < std::make_pair(m2, std::make_pair(u2, v2)); } const Graph1& G1; DFSNumMap dfs_num; }; public: isomorphism_algo(const Graph1& G1, const Graph2& G2, IsoMapping f, Invariant1 invariant1, Invariant2 invariant2, std::size_t max_invariant, IndexMap1 index_map1, IndexMap2 index_map2) : G1(G1) , G2(G2) , f(f) , invariant1(invariant1) , invariant2(invariant2) , max_invariant(max_invariant) , index_map1(index_map1) , index_map2(index_map2) { in_S_vec.resize(num_vertices(G1)); in_S = make_safe_iterator_property_map( in_S_vec.begin(), in_S_vec.size(), index_map2 #ifdef BOOST_NO_STD_ITERATOR_TRAITS , in_S_vec.front() #endif /* BOOST_NO_STD_ITERATOR_TRAITS */ ); } bool test_isomorphism() { // reset isomapping BGL_FORALL_VERTICES_T(v, G1, Graph1) f[v] = graph_traits< Graph2 >::null_vertex(); { std::vector< invar1_value > invar1_array; BGL_FORALL_VERTICES_T(v, G1, Graph1) invar1_array.push_back(invariant1(v)); sort(invar1_array); std::vector< invar2_value > invar2_array; BGL_FORALL_VERTICES_T(v, G2, Graph2) invar2_array.push_back(invariant2(v)); sort(invar2_array); if (!equal(invar1_array, invar2_array)) return false; } std::vector< vertex1_t > V_mult; BGL_FORALL_VERTICES_T(v, G1, Graph1) V_mult.push_back(v); { std::vector< size_type > multiplicity(max_invariant, 0); BGL_FORALL_VERTICES_T(v, G1, Graph1) ++multiplicity.at(invariant1(v)); sort( V_mult, compare_multiplicity(invariant1, &multiplicity[0])); } std::vector< default_color_type > color_vec(num_vertices(G1)); safe_iterator_property_map< std::vector< default_color_type >::iterator, IndexMap1 #ifdef BOOST_NO_STD_ITERATOR_TRAITS , default_color_type, default_color_type& #endif /* BOOST_NO_STD_ITERATOR_TRAITS */ > color_map(color_vec.begin(), color_vec.size(), index_map1); record_dfs_order dfs_visitor(dfs_vertices, ordered_edges); typedef color_traits< default_color_type > Color; for (vertex_iter u = V_mult.begin(); u != V_mult.end(); ++u) { if (color_map[*u] == Color::white()) { dfs_visitor.start_vertex(*u, G1); depth_first_visit(G1, *u, dfs_visitor, color_map); } } // Create the dfs_num array and dfs_num_map dfs_num_vec.resize(num_vertices(G1)); dfs_num = make_safe_iterator_property_map( dfs_num_vec.begin(), dfs_num_vec.size(), index_map1 #ifdef BOOST_NO_STD_ITERATOR_TRAITS , dfs_num_vec.front() #endif /* BOOST_NO_STD_ITERATOR_TRAITS */ ); size_type n = 0; for (vertex_iter v = dfs_vertices.begin(); v != dfs_vertices.end(); ++v) dfs_num[*v] = n++; sort(ordered_edges, edge_cmp(G1, dfs_num)); int dfs_num_k = -1; return this->match(ordered_edges.begin(), dfs_num_k); } private: struct match_continuation { enum { pos_G2_vertex_loop, pos_fi_adj_loop, pos_dfs_num } position; typedef typename graph_traits< Graph2 >::vertex_iterator vertex_iterator; std::pair< vertex_iterator, vertex_iterator > G2_verts; typedef typename graph_traits< Graph2 >::adjacency_iterator adjacency_iterator; std::pair< adjacency_iterator, adjacency_iterator > fi_adj; edge_iter iter; int dfs_num_k; }; bool match(edge_iter iter, int dfs_num_k) { std::vector< match_continuation > k; typedef typename graph_traits< Graph2 >::vertex_iterator vertex_iterator; std::pair< vertex_iterator, vertex_iterator > G2_verts( vertices(G2)); typedef typename graph_traits< Graph2 >::adjacency_iterator adjacency_iterator; std::pair< adjacency_iterator, adjacency_iterator > fi_adj; vertex1_t i, j; recur: if (iter != ordered_edges.end()) { i = source(*iter, G1); j = target(*iter, G1); if (dfs_num[i] > dfs_num_k) { G2_verts = vertices(G2); while (G2_verts.first != G2_verts.second) { { vertex2_t u = *G2_verts.first; vertex1_t kp1 = dfs_vertices[dfs_num_k + 1]; if (invariant1(kp1) == invariant2(u) && in_S[u] == false) { { f[kp1] = u; in_S[u] = true; num_edges_on_k = 0; match_continuation new_k; new_k.position = match_continuation:: pos_G2_vertex_loop; new_k.G2_verts = G2_verts; new_k.iter = iter; new_k.dfs_num_k = dfs_num_k; k.push_back(new_k); ++dfs_num_k; goto recur; } } } G2_loop_k: ++G2_verts.first; } } else if (dfs_num[j] > dfs_num_k) { { vertex1_t vk = dfs_vertices[dfs_num_k]; num_edges_on_k -= count_if(adjacent_vertices(f[vk], G2), make_indirect_pmap(in_S)); for (int jj = 0; jj < dfs_num_k; ++jj) { vertex1_t j = dfs_vertices[jj]; num_edges_on_k -= count(adjacent_vertices(f[j], G2), f[vk]); } } if (num_edges_on_k != 0) goto return_point_false; fi_adj = adjacent_vertices(f[i], G2); while (fi_adj.first != fi_adj.second) { { vertex2_t v = *fi_adj.first; if (invariant2(v) == invariant1(j) && in_S[v] == false) { f[j] = v; in_S[v] = true; num_edges_on_k = 1; BOOST_USING_STD_MAX(); int next_k = max BOOST_PREVENT_MACRO_SUBSTITUTION( dfs_num_k, max BOOST_PREVENT_MACRO_SUBSTITUTION( dfs_num[i], dfs_num[j])); match_continuation new_k; new_k.position = match_continuation::pos_fi_adj_loop; new_k.fi_adj = fi_adj; new_k.iter = iter; new_k.dfs_num_k = dfs_num_k; ++iter; dfs_num_k = next_k; k.push_back(new_k); goto recur; } } fi_adj_loop_k: ++fi_adj.first; } } else { if (container_contains(adjacent_vertices(f[i], G2), f[j])) { ++num_edges_on_k; match_continuation new_k; new_k.position = match_continuation::pos_dfs_num; k.push_back(new_k); ++iter; goto recur; } } } else goto return_point_true; goto return_point_false; { return_point_true: return true; return_point_false: if (k.empty()) return false; const match_continuation& this_k = k.back(); switch (this_k.position) { case match_continuation::pos_G2_vertex_loop: { G2_verts = this_k.G2_verts; iter = this_k.iter; dfs_num_k = this_k.dfs_num_k; k.pop_back(); in_S[*G2_verts.first] = false; i = source(*iter, G1); j = target(*iter, G1); goto G2_loop_k; } case match_continuation::pos_fi_adj_loop: { fi_adj = this_k.fi_adj; iter = this_k.iter; dfs_num_k = this_k.dfs_num_k; k.pop_back(); in_S[*fi_adj.first] = false; i = source(*iter, G1); j = target(*iter, G1); goto fi_adj_loop_k; } case match_continuation::pos_dfs_num: { k.pop_back(); goto return_point_false; } default: { BOOST_ASSERT(!"Bad position"); #ifdef UNDER_CE exit(-1); #else abort(); #endif } } } } }; template < typename Graph, typename InDegreeMap > void compute_in_degree(const Graph& g, InDegreeMap in_degree_map) { BGL_FORALL_VERTICES_T(v, g, Graph) put(in_degree_map, v, 0); BGL_FORALL_VERTICES_T(u, g, Graph) BGL_FORALL_ADJ_T(u, v, g, Graph) put(in_degree_map, v, get(in_degree_map, v) + 1); } } // namespace detail template < typename InDegreeMap, typename Graph > class degree_vertex_invariant { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::degree_size_type size_type; public: typedef vertex_t argument_type; typedef size_type result_type; degree_vertex_invariant(const InDegreeMap& in_degree_map, const Graph& g) : m_in_degree_map(in_degree_map) , m_max_vertex_in_degree(0) , m_max_vertex_out_degree(0) , m_g(g) { BGL_FORALL_VERTICES_T(v, g, Graph) { m_max_vertex_in_degree = (std::max)(m_max_vertex_in_degree, get(m_in_degree_map, v)); m_max_vertex_out_degree = (std::max)(m_max_vertex_out_degree, out_degree(v, g)); } } size_type operator()(vertex_t v) const { return (m_max_vertex_in_degree + 1) * out_degree(v, m_g) + get(m_in_degree_map, v); } // The largest possible vertex invariant number size_type max BOOST_PREVENT_MACRO_SUBSTITUTION() const { return (m_max_vertex_in_degree + 1) * (m_max_vertex_out_degree + 1); } private: InDegreeMap m_in_degree_map; size_type m_max_vertex_in_degree; size_type m_max_vertex_out_degree; const Graph& m_g; }; // Count actual number of vertices, even in filtered graphs. template < typename Graph > size_t count_vertices(const Graph& g) { size_t n = 0; BGL_FORALL_VERTICES_T(v, g, Graph) { (void)v; ++n; } return n; } template < typename Graph1, typename Graph2, typename IsoMapping, typename Invariant1, typename Invariant2, typename IndexMap1, typename IndexMap2 > bool isomorphism(const Graph1& G1, const Graph2& G2, IsoMapping f, Invariant1 invariant1, Invariant2 invariant2, std::size_t max_invariant, IndexMap1 index_map1, IndexMap2 index_map2) { // Graph requirements BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph1 >)); BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph1 >)); BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph2 >)); // BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept<Graph2> )); typedef typename graph_traits< Graph1 >::vertex_descriptor vertex1_t; typedef typename graph_traits< Graph2 >::vertex_descriptor vertex2_t; typedef typename graph_traits< Graph1 >::vertices_size_type size_type; // Vertex invariant requirement BOOST_CONCEPT_ASSERT( (AdaptableUnaryFunctionConcept< Invariant1, size_type, vertex1_t >)); BOOST_CONCEPT_ASSERT( (AdaptableUnaryFunctionConcept< Invariant2, size_type, vertex2_t >)); // Property map requirements BOOST_CONCEPT_ASSERT( (ReadWritePropertyMapConcept< IsoMapping, vertex1_t >)); typedef typename property_traits< IsoMapping >::value_type IsoMappingValue; BOOST_STATIC_ASSERT((is_convertible< IsoMappingValue, vertex2_t >::value)); BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< IndexMap1, vertex1_t >)); typedef typename property_traits< IndexMap1 >::value_type IndexMap1Value; BOOST_STATIC_ASSERT((is_convertible< IndexMap1Value, size_type >::value)); BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< IndexMap2, vertex2_t >)); typedef typename property_traits< IndexMap2 >::value_type IndexMap2Value; BOOST_STATIC_ASSERT((is_convertible< IndexMap2Value, size_type >::value)); if (count_vertices(G1) != count_vertices(G2)) return false; if (count_vertices(G1) == 0 && count_vertices(G2) == 0) return true; detail::isomorphism_algo< Graph1, Graph2, IsoMapping, Invariant1, Invariant2, IndexMap1, IndexMap2 > algo(G1, G2, f, invariant1, invariant2, max_invariant, index_map1, index_map2); return algo.test_isomorphism(); } namespace detail { template < typename Graph1, typename Graph2, typename IsoMapping, typename IndexMap1, typename IndexMap2, typename P, typename T, typename R > bool isomorphism_impl(const Graph1& G1, const Graph2& G2, IsoMapping f, IndexMap1 index_map1, IndexMap2 index_map2, const bgl_named_params< P, T, R >& params) { std::vector< std::size_t > in_degree1_vec(num_vertices(G1)); typedef safe_iterator_property_map< std::vector< std::size_t >::iterator, IndexMap1 #ifdef BOOST_NO_STD_ITERATOR_TRAITS , std::size_t, std::size_t& #endif /* BOOST_NO_STD_ITERATOR_TRAITS */ > InDeg1; InDeg1 in_degree1( in_degree1_vec.begin(), in_degree1_vec.size(), index_map1); compute_in_degree(G1, in_degree1); std::vector< std::size_t > in_degree2_vec(num_vertices(G2)); typedef safe_iterator_property_map< std::vector< std::size_t >::iterator, IndexMap2 #ifdef BOOST_NO_STD_ITERATOR_TRAITS , std::size_t, std::size_t& #endif /* BOOST_NO_STD_ITERATOR_TRAITS */ > InDeg2; InDeg2 in_degree2( in_degree2_vec.begin(), in_degree2_vec.size(), index_map2); compute_in_degree(G2, in_degree2); degree_vertex_invariant< InDeg1, Graph1 > invariant1(in_degree1, G1); degree_vertex_invariant< InDeg2, Graph2 > invariant2(in_degree2, G2); return isomorphism(G1, G2, f, choose_param(get_param(params, vertex_invariant1_t()), invariant1), choose_param(get_param(params, vertex_invariant2_t()), invariant2), choose_param(get_param(params, vertex_max_invariant_t()), (invariant2.max)()), index_map1, index_map2); } template < typename G, typename Index > struct make_degree_invariant { const G& g; const Index& index; make_degree_invariant(const G& g, const Index& index) : g(g), index(index) { } typedef typename boost::graph_traits< G >::degree_size_type degree_size_type; typedef shared_array_property_map< degree_size_type, Index > prop_map_type; typedef degree_vertex_invariant< prop_map_type, G > result_type; result_type operator()() const { prop_map_type pm = make_shared_array_property_map( num_vertices(g), degree_size_type(), index); compute_in_degree(g, pm); return result_type(pm, g); } }; } // namespace detail namespace graph { namespace detail { template < typename Graph1, typename Graph2 > struct isomorphism_impl { typedef bool result_type; typedef result_type type; template < typename ArgPack > bool operator()(const Graph1& g1, const Graph2& g2, const ArgPack& arg_pack) const { using namespace boost::graph::keywords; typedef typename boost::detail::override_const_property_result< ArgPack, tag::vertex_index1_map, boost::vertex_index_t, Graph1 >::type index1_map_type; typedef typename boost::detail::override_const_property_result< ArgPack, tag::vertex_index2_map, boost::vertex_index_t, Graph2 >::type index2_map_type; index1_map_type index1_map = boost::detail::override_const_property( arg_pack, _vertex_index1_map, g1, boost::vertex_index); index2_map_type index2_map = boost::detail::override_const_property( arg_pack, _vertex_index2_map, g2, boost::vertex_index); typedef typename graph_traits< Graph2 >::vertex_descriptor vertex2_t; typename std::vector< vertex2_t >::size_type n = (typename std::vector< vertex2_t >::size_type) num_vertices(g1); std::vector< vertex2_t > f(n); typename boost::parameter::lazy_binding< ArgPack, tag::vertex_invariant1, boost::detail::make_degree_invariant< Graph1, index1_map_type > >::type invariant1 = arg_pack[_vertex_invariant1 || boost::detail::make_degree_invariant< Graph1, index1_map_type >(g1, index1_map)]; typename boost::parameter::lazy_binding< ArgPack, tag::vertex_invariant2, boost::detail::make_degree_invariant< Graph2, index2_map_type > >::type invariant2 = arg_pack[_vertex_invariant2 || boost::detail::make_degree_invariant< Graph2, index2_map_type >(g2, index2_map)]; return boost::isomorphism(g1, g2, choose_param( arg_pack[_isomorphism_map | boost::param_not_found()], make_shared_array_property_map( num_vertices(g1), vertex2_t(), index1_map)), invariant1, invariant2, arg_pack[_vertex_max_invariant | (invariant2.max)()], index1_map, index2_map); } }; } BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(isomorphism, 2, 6) } // Named parameter interface BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(isomorphism, 2) // Verify that the given mapping iso_map from the vertices of g1 to the // vertices of g2 describes an isomorphism. // Note: this could be made much faster by specializing based on the graph // concepts modeled, but since we're verifying an O(n^(lg n)) algorithm, // O(n^4) won't hurt us. template < typename Graph1, typename Graph2, typename IsoMap > inline bool verify_isomorphism( const Graph1& g1, const Graph2& g2, IsoMap iso_map) { #if 0 // problematic for filtered_graph! if (num_vertices(g1) != num_vertices(g2) || num_edges(g1) != num_edges(g2)) return false; #endif BGL_FORALL_EDGES_T(e1, g1, Graph1) { bool found_edge = false; BGL_FORALL_EDGES_T(e2, g2, Graph2) { if (source(e2, g2) == get(iso_map, source(e1, g1)) && target(e2, g2) == get(iso_map, target(e1, g1))) { found_edge = true; } } if (!found_edge) return false; } return true; } } // namespace boost #ifdef BOOST_ISO_INCLUDED_ITER_MACROS #undef BOOST_ISO_INCLUDED_ITER_MACROS #include <boost/graph/iteration_macros_undef.hpp> #endif #endif // BOOST_GRAPH_ISOMORPHISM_HPP biconnected_components.hpp 0000644 00000040475 15125521275 0012016 0 ustar 00 // Copyright (c) Jeremy Siek 2001 // Copyright (c) Douglas Gregor 2004 // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // NOTE: this final is generated by libs/graph/doc/biconnected_components.w #ifndef BOOST_GRAPH_BICONNECTED_COMPONENTS_HPP #define BOOST_GRAPH_BICONNECTED_COMPONENTS_HPP #include <stack> #include <vector> #include <algorithm> // for std::min and std::max #include <boost/config.hpp> #include <boost/limits.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/depth_first_search.hpp> #include <boost/graph/graph_utility.hpp> #include <boost/concept/assert.hpp> #include <boost/assert.hpp> namespace boost { namespace detail { template < typename ComponentMap, typename DiscoverTimeMap, typename LowPointMap, typename PredecessorMap, typename OutputIterator, typename Stack, typename ArticulationVector, typename IndexMap, typename DFSVisitor > struct biconnected_components_visitor : public dfs_visitor<> { biconnected_components_visitor(ComponentMap comp, std::size_t& c, std::size_t& children_of_root, DiscoverTimeMap dtm, std::size_t& dfs_time, LowPointMap lowpt, PredecessorMap pred, OutputIterator out, Stack& S, ArticulationVector& is_articulation_point, IndexMap index_map, DFSVisitor vis) : comp(comp) , c(c) , children_of_root(children_of_root) , dtm(dtm) , dfs_time(dfs_time) , lowpt(lowpt) , pred(pred) , out(out) , S(S) , is_articulation_point(is_articulation_point) , index_map(index_map) , vis(vis) { } template < typename Vertex, typename Graph > void initialize_vertex(const Vertex& u, Graph& g) { put(pred, u, u); vis.initialize_vertex(u, g); } template < typename Vertex, typename Graph > void start_vertex(const Vertex& u, Graph& g) { children_of_root = 0; vis.start_vertex(u, g); } template < typename Vertex, typename Graph > void discover_vertex(const Vertex& u, Graph& g) { put(dtm, u, ++dfs_time); put(lowpt, u, get(dtm, u)); vis.discover_vertex(u, g); } template < typename Edge, typename Graph > void examine_edge(const Edge& e, Graph& g) { vis.examine_edge(e, g); } template < typename Edge, typename Graph > void tree_edge(const Edge& e, Graph& g) { typename boost::graph_traits< Graph >::vertex_descriptor src = source(e, g); typename boost::graph_traits< Graph >::vertex_descriptor tgt = target(e, g); S.push(e); put(pred, tgt, src); if (get(pred, src) == src) { ++children_of_root; } vis.tree_edge(e, g); } template < typename Edge, typename Graph > void back_edge(const Edge& e, Graph& g) { BOOST_USING_STD_MIN(); typename boost::graph_traits< Graph >::vertex_descriptor src = source(e, g); typename boost::graph_traits< Graph >::vertex_descriptor tgt = target(e, g); if (tgt != get(pred, src)) { S.push(e); put(lowpt, src, min BOOST_PREVENT_MACRO_SUBSTITUTION( get(lowpt, src), get(dtm, tgt))); } vis.back_edge(e, g); } template < typename Edge, typename Graph > void forward_or_cross_edge(const Edge& e, Graph& g) { vis.forward_or_cross_edge(e, g); } template < typename Vertex, typename Graph > void finish_vertex(const Vertex& u, Graph& g) { BOOST_USING_STD_MIN(); Vertex parent = get(pred, u); if (parent == u) { // Root of tree is special is_articulation_point[get(index_map, u)] = (children_of_root > 1); } else { put(lowpt, parent, min BOOST_PREVENT_MACRO_SUBSTITUTION( get(lowpt, parent), get(lowpt, u))); if (get(lowpt, u) >= get(dtm, parent)) { is_articulation_point[get(index_map, parent)] = true; while (get(dtm, source(S.top(), g)) >= get(dtm, u)) { put(comp, S.top(), c); S.pop(); } BOOST_ASSERT(source(S.top(), g) == parent); BOOST_ASSERT(target(S.top(), g) == u); put(comp, S.top(), c); S.pop(); ++c; } } if (is_articulation_point[get(index_map, u)]) { *out++ = u; } vis.finish_vertex(u, g); } ComponentMap comp; std::size_t& c; std::size_t& children_of_root; DiscoverTimeMap dtm; std::size_t& dfs_time; LowPointMap lowpt; PredecessorMap pred; OutputIterator out; Stack& S; ArticulationVector& is_articulation_point; IndexMap index_map; DFSVisitor vis; }; template < typename Graph, typename ComponentMap, typename OutputIterator, typename VertexIndexMap, typename DiscoverTimeMap, typename LowPointMap, typename PredecessorMap, typename DFSVisitor > std::pair< std::size_t, OutputIterator > biconnected_components_impl( const Graph& g, ComponentMap comp, OutputIterator out, VertexIndexMap index_map, DiscoverTimeMap dtm, LowPointMap lowpt, PredecessorMap pred, DFSVisitor dfs_vis) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::edge_descriptor edge_t; BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >)); BOOST_CONCEPT_ASSERT( (WritablePropertyMapConcept< ComponentMap, edge_t >)); BOOST_CONCEPT_ASSERT( (ReadWritePropertyMapConcept< DiscoverTimeMap, vertex_t >)); BOOST_CONCEPT_ASSERT( (ReadWritePropertyMapConcept< LowPointMap, vertex_t >)); BOOST_CONCEPT_ASSERT( (ReadWritePropertyMapConcept< PredecessorMap, vertex_t >)); std::size_t num_components = 0; std::size_t children_of_root; std::size_t dfs_time = 0; std::stack< edge_t > S; std::vector< char > is_articulation_point(num_vertices(g)); biconnected_components_visitor< ComponentMap, DiscoverTimeMap, LowPointMap, PredecessorMap, OutputIterator, std::stack< edge_t >, std::vector< char >, VertexIndexMap, DFSVisitor > vis(comp, num_components, children_of_root, dtm, dfs_time, lowpt, pred, out, S, is_articulation_point, index_map, dfs_vis); depth_first_search(g, visitor(vis).vertex_index_map(index_map)); return std::pair< std::size_t, OutputIterator >( num_components, vis.out); } template < typename PredecessorMap > struct bicomp_dispatch3 { template < typename Graph, typename ComponentMap, typename OutputIterator, typename VertexIndexMap, typename DiscoverTimeMap, typename LowPointMap, class P, class T, class R > static std::pair< std::size_t, OutputIterator > apply(const Graph& g, ComponentMap comp, OutputIterator out, VertexIndexMap index_map, DiscoverTimeMap dtm, LowPointMap lowpt, const bgl_named_params< P, T, R >& params, PredecessorMap pred) { return biconnected_components_impl(g, comp, out, index_map, dtm, lowpt, pred, choose_param(get_param(params, graph_visitor), make_dfs_visitor(null_visitor()))); } }; template <> struct bicomp_dispatch3< param_not_found > { template < typename Graph, typename ComponentMap, typename OutputIterator, typename VertexIndexMap, typename DiscoverTimeMap, typename LowPointMap, class P, class T, class R > static std::pair< std::size_t, OutputIterator > apply(const Graph& g, ComponentMap comp, OutputIterator out, VertexIndexMap index_map, DiscoverTimeMap dtm, LowPointMap lowpt, const bgl_named_params< P, T, R >& params, param_not_found) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; std::vector< vertex_t > pred(num_vertices(g)); vertex_t vert = graph_traits< Graph >::null_vertex(); return biconnected_components_impl(g, comp, out, index_map, dtm, lowpt, make_iterator_property_map(pred.begin(), index_map, vert), choose_param(get_param(params, graph_visitor), make_dfs_visitor(null_visitor()))); } }; template < typename LowPointMap > struct bicomp_dispatch2 { template < typename Graph, typename ComponentMap, typename OutputIterator, typename VertexIndexMap, typename DiscoverTimeMap, typename P, typename T, typename R > static std::pair< std::size_t, OutputIterator > apply(const Graph& g, ComponentMap comp, OutputIterator out, VertexIndexMap index_map, DiscoverTimeMap dtm, const bgl_named_params< P, T, R >& params, LowPointMap lowpt) { typedef typename get_param_type< vertex_predecessor_t, bgl_named_params< P, T, R > >::type dispatch_type; return bicomp_dispatch3< dispatch_type >::apply(g, comp, out, index_map, dtm, lowpt, params, get_param(params, vertex_predecessor)); } }; template <> struct bicomp_dispatch2< param_not_found > { template < typename Graph, typename ComponentMap, typename OutputIterator, typename VertexIndexMap, typename DiscoverTimeMap, typename P, typename T, typename R > static std::pair< std::size_t, OutputIterator > apply(const Graph& g, ComponentMap comp, OutputIterator out, VertexIndexMap index_map, DiscoverTimeMap dtm, const bgl_named_params< P, T, R >& params, param_not_found) { typedef typename graph_traits< Graph >::vertices_size_type vertices_size_type; std::vector< vertices_size_type > lowpt(num_vertices(g)); vertices_size_type vst(0); typedef typename get_param_type< vertex_predecessor_t, bgl_named_params< P, T, R > >::type dispatch_type; return bicomp_dispatch3< dispatch_type >::apply(g, comp, out, index_map, dtm, make_iterator_property_map(lowpt.begin(), index_map, vst), params, get_param(params, vertex_predecessor)); } }; template < typename DiscoverTimeMap > struct bicomp_dispatch1 { template < typename Graph, typename ComponentMap, typename OutputIterator, typename VertexIndexMap, class P, class T, class R > static std::pair< std::size_t, OutputIterator > apply(const Graph& g, ComponentMap comp, OutputIterator out, VertexIndexMap index_map, const bgl_named_params< P, T, R >& params, DiscoverTimeMap dtm) { typedef typename get_param_type< vertex_lowpoint_t, bgl_named_params< P, T, R > >::type dispatch_type; return bicomp_dispatch2< dispatch_type >::apply(g, comp, out, index_map, dtm, params, get_param(params, vertex_lowpoint)); } }; template <> struct bicomp_dispatch1< param_not_found > { template < typename Graph, typename ComponentMap, typename OutputIterator, typename VertexIndexMap, class P, class T, class R > static std::pair< std::size_t, OutputIterator > apply(const Graph& g, ComponentMap comp, OutputIterator out, VertexIndexMap index_map, const bgl_named_params< P, T, R >& params, param_not_found) { typedef typename graph_traits< Graph >::vertices_size_type vertices_size_type; std::vector< vertices_size_type > discover_time(num_vertices(g)); vertices_size_type vst(0); typedef typename get_param_type< vertex_lowpoint_t, bgl_named_params< P, T, R > >::type dispatch_type; return bicomp_dispatch2< dispatch_type >::apply(g, comp, out, index_map, make_iterator_property_map( discover_time.begin(), index_map, vst), params, get_param(params, vertex_lowpoint)); } }; } template < typename Graph, typename ComponentMap, typename OutputIterator, typename DiscoverTimeMap, typename LowPointMap > std::pair< std::size_t, OutputIterator > biconnected_components(const Graph& g, ComponentMap comp, OutputIterator out, DiscoverTimeMap dtm, LowPointMap lowpt) { typedef param_not_found dispatch_type; return detail::bicomp_dispatch3< dispatch_type >::apply(g, comp, out, get(vertex_index, g), dtm, lowpt, bgl_named_params< int, buffer_param_t >(0), param_not_found()); } template < typename Graph, typename ComponentMap, typename OutputIterator, typename P, typename T, typename R > std::pair< std::size_t, OutputIterator > biconnected_components(const Graph& g, ComponentMap comp, OutputIterator out, const bgl_named_params< P, T, R >& params) { typedef typename get_param_type< vertex_discover_time_t, bgl_named_params< P, T, R > >::type dispatch_type; return detail::bicomp_dispatch1< dispatch_type >::apply(g, comp, out, choose_const_pmap(get_param(params, vertex_index), g, vertex_index), params, get_param(params, vertex_discover_time)); } template < typename Graph, typename ComponentMap, typename OutputIterator > std::pair< std::size_t, OutputIterator > biconnected_components( const Graph& g, ComponentMap comp, OutputIterator out) { return biconnected_components( g, comp, out, bgl_named_params< int, buffer_param_t >(0)); } namespace graph_detail { struct dummy_output_iterator { typedef std::output_iterator_tag iterator_category; typedef void value_type; typedef void pointer; typedef void difference_type; struct reference { template < typename T > reference& operator=(const T&) { return *this; } }; reference operator*() const { return reference(); } dummy_output_iterator& operator++() { return *this; } dummy_output_iterator operator++(int) { return *this; } }; } // end namespace graph_detail template < typename Graph, typename ComponentMap, typename P, typename T, typename R > std::size_t biconnected_components(const Graph& g, ComponentMap comp, const bgl_named_params< P, T, R >& params) { return biconnected_components( g, comp, graph_detail::dummy_output_iterator(), params) .first; } template < typename Graph, typename ComponentMap > std::size_t biconnected_components(const Graph& g, ComponentMap comp) { return biconnected_components( g, comp, graph_detail::dummy_output_iterator()) .first; } template < typename Graph, typename OutputIterator, typename P, typename T, typename R > OutputIterator articulation_points(const Graph& g, OutputIterator out, const bgl_named_params< P, T, R >& params) { return biconnected_components(g, dummy_property_map(), out, params).second; } template < typename Graph, typename OutputIterator > OutputIterator articulation_points(const Graph& g, OutputIterator out) { return biconnected_components(g, dummy_property_map(), out, bgl_named_params< int, buffer_param_t >(0)) .second; } } // namespace boost #endif /* BOOST_GRAPH_BICONNECTED_COMPONENTS_HPP */ graphviz.hpp 0000644 00000101347 15125521275 0007122 0 ustar 00 //======================================================================= // Copyright 2001 University of Notre Dame. // Copyright 2003 Jeremy Siek // Authors: Lie-Quan Lee, Jeremy Siek, and Douglas Gregor // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPHVIZ_HPP #define BOOST_GRAPHVIZ_HPP #include <boost/config.hpp> #include <string> #include <map> #include <iostream> #include <fstream> #include <stdio.h> // for FILE #include <boost/property_map/property_map.hpp> #include <boost/tuple/tuple.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/subgraph.hpp> #include <boost/graph/adjacency_list.hpp> #include <boost/property_map/dynamic_property_map.hpp> #include <boost/graph/overloading.hpp> #include <boost/graph/dll_import_export.hpp> #include <boost/graph/compressed_sparse_row_graph.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/graph/detail/mpi_include.hpp> #include <boost/spirit/include/classic_multi_pass.hpp> #include <boost/lexical_cast.hpp> #include <boost/static_assert.hpp> #include <boost/algorithm/string/replace.hpp> #include <boost/xpressive/xpressive_static.hpp> #include <boost/foreach.hpp> namespace boost { template < typename directed_category > struct graphviz_io_traits { static std::string name() { return "digraph"; } static std::string delimiter() { return "->"; } }; template <> struct graphviz_io_traits< undirected_tag > { static std::string name() { return "graph"; } static std::string delimiter() { return "--"; } }; struct default_writer { void operator()(std::ostream&) const {} template < class VorE > void operator()(std::ostream&, const VorE&) const {} }; template < typename T > inline std::string escape_dot_string(const T& obj) { using namespace boost::xpressive; static sregex valid_unquoted_id = (((alpha | '_') >> *_w) | (!as_xpr('-') >> (('.' >> *_d) | (+_d >> !('.' >> *_d))))); std::string s(boost::lexical_cast< std::string >(obj)); if (regex_match(s, valid_unquoted_id)) { return s; } else { boost::algorithm::replace_all(s, "\"", "\\\""); return "\"" + s + "\""; } } template < class Name > class label_writer { public: label_writer(Name _name) : name(_name) {} template < class VertexOrEdge > void operator()(std::ostream& out, const VertexOrEdge& v) const { out << "[label=" << escape_dot_string(get(name, v)) << "]"; } private: Name name; }; template < class Name > inline label_writer< Name > make_label_writer(Name n) { return label_writer< Name >(n); } enum edge_attribute_t { edge_attribute = 1111 }; enum vertex_attribute_t { vertex_attribute = 2222 }; enum graph_graph_attribute_t { graph_graph_attribute = 3333 }; enum graph_vertex_attribute_t { graph_vertex_attribute = 4444 }; enum graph_edge_attribute_t { graph_edge_attribute = 5555 }; BOOST_INSTALL_PROPERTY(edge, attribute); BOOST_INSTALL_PROPERTY(vertex, attribute); BOOST_INSTALL_PROPERTY(graph, graph_attribute); BOOST_INSTALL_PROPERTY(graph, vertex_attribute); BOOST_INSTALL_PROPERTY(graph, edge_attribute); template < class Attribute > inline void write_attributes(const Attribute& attr, std::ostream& out) { typename Attribute::const_iterator i, iend; i = attr.begin(); iend = attr.end(); while (i != iend) { out << i->first << "=" << escape_dot_string(i->second); ++i; if (i != iend) out << ", "; } } template < typename Attributes > inline void write_all_attributes( Attributes attributes, const std::string& name, std::ostream& out) { typename Attributes::const_iterator i = attributes.begin(), end = attributes.end(); if (i != end) { out << name << " [\n"; write_attributes(attributes, out); out << "];\n"; } } inline void write_all_attributes( detail::error_property_not_found, const std::string&, std::ostream&) { // Do nothing - no attributes exist } template < typename GraphGraphAttributes, typename GraphNodeAttributes, typename GraphEdgeAttributes > struct graph_attributes_writer { graph_attributes_writer( GraphGraphAttributes gg, GraphNodeAttributes gn, GraphEdgeAttributes ge) : g_attributes(gg), n_attributes(gn), e_attributes(ge) { } void operator()(std::ostream& out) const { write_all_attributes(g_attributes, "graph", out); write_all_attributes(n_attributes, "node", out); write_all_attributes(e_attributes, "edge", out); } GraphGraphAttributes g_attributes; GraphNodeAttributes n_attributes; GraphEdgeAttributes e_attributes; }; template < typename GAttrMap, typename NAttrMap, typename EAttrMap > graph_attributes_writer< GAttrMap, NAttrMap, EAttrMap > make_graph_attributes_writer( const GAttrMap& g_attr, const NAttrMap& n_attr, const EAttrMap& e_attr) { return graph_attributes_writer< GAttrMap, NAttrMap, EAttrMap >( g_attr, n_attr, e_attr); } template < typename Graph > graph_attributes_writer< typename graph_property< Graph, graph_graph_attribute_t >::type, typename graph_property< Graph, graph_vertex_attribute_t >::type, typename graph_property< Graph, graph_edge_attribute_t >::type > make_graph_attributes_writer(const Graph& g) { typedef typename graph_property< Graph, graph_graph_attribute_t >::type GAttrMap; typedef typename graph_property< Graph, graph_vertex_attribute_t >::type NAttrMap; typedef typename graph_property< Graph, graph_edge_attribute_t >::type EAttrMap; GAttrMap gam = get_property(g, graph_graph_attribute); NAttrMap nam = get_property(g, graph_vertex_attribute); EAttrMap eam = get_property(g, graph_edge_attribute); graph_attributes_writer< GAttrMap, NAttrMap, EAttrMap > writer( gam, nam, eam); return writer; } template < typename AttributeMap > struct attributes_writer { attributes_writer(AttributeMap attr) : attributes(attr) {} template < class VorE > void operator()(std::ostream& out, const VorE& e) const { this->write_attribute(out, attributes[e]); } private: template < typename AttributeSequence > void write_attribute(std::ostream& out, const AttributeSequence& seq) const { if (!seq.empty()) { out << "["; write_attributes(seq, out); out << "]"; } } void write_attribute(std::ostream&, detail::error_property_not_found) const { } AttributeMap attributes; }; template < typename Graph > attributes_writer< typename property_map< Graph, edge_attribute_t >::const_type > make_edge_attributes_writer(const Graph& g) { typedef typename property_map< Graph, edge_attribute_t >::const_type EdgeAttributeMap; return attributes_writer< EdgeAttributeMap >(get(edge_attribute, g)); } template < typename Graph > attributes_writer< typename property_map< Graph, vertex_attribute_t >::const_type > make_vertex_attributes_writer(const Graph& g) { typedef typename property_map< Graph, vertex_attribute_t >::const_type VertexAttributeMap; return attributes_writer< VertexAttributeMap >(get(vertex_attribute, g)); } template < typename Graph, typename VertexPropertiesWriter, typename EdgePropertiesWriter, typename GraphPropertiesWriter, typename VertexID > inline void write_graphviz(std::ostream& out, const Graph& g, VertexPropertiesWriter vpw, EdgePropertiesWriter epw, GraphPropertiesWriter gpw, VertexID vertex_id BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph >)); typedef typename graph_traits< Graph >::directed_category cat_type; typedef graphviz_io_traits< cat_type > Traits; std::string name = "G"; out << Traits::name() << " " << escape_dot_string(name) << " {" << std::endl; gpw(out); // print graph properties typename graph_traits< Graph >::vertex_iterator i, end; for (boost::tie(i, end) = vertices(g); i != end; ++i) { out << escape_dot_string(get(vertex_id, *i)); vpw(out, *i); // print vertex attributes out << ";" << std::endl; } typename graph_traits< Graph >::edge_iterator ei, edge_end; for (boost::tie(ei, edge_end) = edges(g); ei != edge_end; ++ei) { out << escape_dot_string(get(vertex_id, source(*ei, g))) << Traits::delimiter() << escape_dot_string(get(vertex_id, target(*ei, g))) << " "; epw(out, *ei); // print edge attributes out << ";" << std::endl; } out << "}" << std::endl; } template < typename Graph, typename VertexPropertiesWriter, typename EdgePropertiesWriter, typename GraphPropertiesWriter > inline void write_graphviz(std::ostream& out, const Graph& g, VertexPropertiesWriter vpw, EdgePropertiesWriter epw, GraphPropertiesWriter gpw BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { write_graphviz(out, g, vpw, epw, gpw, get(vertex_index, g)); } template < typename Graph > inline void write_graphviz(std::ostream& out, const Graph& g BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { default_writer dw; default_writer gw; write_graphviz(out, g, dw, dw, gw); } template < typename Graph, typename VertexWriter > inline void write_graphviz(std::ostream& out, const Graph& g, VertexWriter vw BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { default_writer dw; default_writer gw; write_graphviz(out, g, vw, dw, gw); } template < typename Graph, typename VertexWriter, typename EdgeWriter > inline void write_graphviz(std::ostream& out, const Graph& g, VertexWriter vw, EdgeWriter ew BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { default_writer gw; write_graphviz(out, g, vw, ew, gw); } namespace detail { template < class Graph_, class RandomAccessIterator, class VertexID > void write_graphviz_subgraph(std::ostream& out, const subgraph< Graph_ >& g, RandomAccessIterator vertex_marker, RandomAccessIterator edge_marker, VertexID vertex_id) { typedef subgraph< Graph_ > Graph; typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::directed_category cat_type; typedef graphviz_io_traits< cat_type > Traits; typedef typename graph_property< Graph, graph_name_t >::type NameType; const NameType& g_name = get_property(g, graph_name); if (g.is_root()) out << Traits::name(); else out << "subgraph"; out << " " << escape_dot_string(g_name) << " {" << std::endl; typename Graph::const_children_iterator i_child, j_child; // print graph/node/edge attributes make_graph_attributes_writer(g)(out); // print subgraph for (boost::tie(i_child, j_child) = g.children(); i_child != j_child; ++i_child) write_graphviz_subgraph( out, *i_child, vertex_marker, edge_marker, vertex_id); // Print out vertices and edges not in the subgraphs. typename graph_traits< Graph >::vertex_iterator i, end; typename graph_traits< Graph >::edge_iterator ei, edge_end; for (boost::tie(i, end) = vertices(g); i != end; ++i) { Vertex v = g.local_to_global(*i); int pos = get(vertex_id, v); if (vertex_marker[pos]) { vertex_marker[pos] = false; out << escape_dot_string(pos); make_vertex_attributes_writer(g.root())(out, v); out << ";" << std::endl; } } for (boost::tie(ei, edge_end) = edges(g); ei != edge_end; ++ei) { Vertex u = g.local_to_global(source(*ei, g)), v = g.local_to_global(target(*ei, g)); int pos = get(get(edge_index, g.root()), g.local_to_global(*ei)); if (edge_marker[pos]) { edge_marker[pos] = false; out << escape_dot_string(get(vertex_id, u)) << " " << Traits::delimiter() << " " << escape_dot_string(get(vertex_id, v)); make_edge_attributes_writer(g)( out, *ei); // print edge properties out << ";" << std::endl; } } out << "}" << std::endl; } } // namespace detail // requires graph_name graph property template < typename Graph > void write_graphviz(std::ostream& out, const subgraph< Graph >& g) { std::vector< bool > edge_marker(num_edges(g), true); std::vector< bool > vertex_marker(num_vertices(g), true); detail::write_graphviz_subgraph(out, g, vertex_marker.begin(), edge_marker.begin(), get(vertex_index, g)); } template < typename Graph > void write_graphviz(const std::string& filename, const subgraph< Graph >& g) { std::ofstream out(filename.c_str()); std::vector< bool > edge_marker(num_edges(g), true); std::vector< bool > vertex_marker(num_vertices(g), true); detail::write_graphviz_subgraph(out, g, vertex_marker.begin(), edge_marker.begin(), get(vertex_index, g)); } template < typename Graph, typename VertexID > void write_graphviz( std::ostream& out, const subgraph< Graph >& g, VertexID vertex_id) { std::vector< bool > edge_marker(num_edges(g), true); std::vector< bool > vertex_marker(num_vertices(g), true); detail::write_graphviz_subgraph( out, g, vertex_marker.begin(), edge_marker.begin(), vertex_id); } template < typename Graph, typename VertexID > void write_graphviz( const std::string& filename, const subgraph< Graph >& g, VertexID vertex_id) { std::ofstream out(filename.c_str()); std::vector< bool > edge_marker(num_edges(g), true); std::vector< bool > vertex_marker(num_vertices(g), true); detail::write_graphviz_subgraph( out, g, vertex_marker.begin(), edge_marker.begin(), vertex_id); } #if 0 // This interface has not worked for a long time typedef std::map<std::string, std::string> GraphvizAttrList; typedef property<vertex_attribute_t, GraphvizAttrList> GraphvizVertexProperty; typedef property<edge_attribute_t, GraphvizAttrList, property<edge_index_t, int> > GraphvizEdgeProperty; typedef property<graph_graph_attribute_t, GraphvizAttrList, property<graph_vertex_attribute_t, GraphvizAttrList, property<graph_edge_attribute_t, GraphvizAttrList, property<graph_name_t, std::string> > > > GraphvizGraphProperty; typedef subgraph<adjacency_list<vecS, vecS, directedS, GraphvizVertexProperty, GraphvizEdgeProperty, GraphvizGraphProperty> > GraphvizDigraph; typedef subgraph<adjacency_list<vecS, vecS, undirectedS, GraphvizVertexProperty, GraphvizEdgeProperty, GraphvizGraphProperty> > GraphvizGraph; // These four require linking the BGL-Graphviz library: libbgl-viz.a // from the /src directory. // Library has not existed for a while extern void read_graphviz(const std::string& file, GraphvizDigraph& g); extern void read_graphviz(FILE* file, GraphvizDigraph& g); extern void read_graphviz(const std::string& file, GraphvizGraph& g); extern void read_graphviz(FILE* file, GraphvizGraph& g); #endif class dynamic_properties_writer { public: dynamic_properties_writer(const dynamic_properties& dp) : dp(&dp) {} template < typename Descriptor > void operator()(std::ostream& out, Descriptor key) const { bool first = true; for (dynamic_properties::const_iterator i = dp->begin(); i != dp->end(); ++i) { if (typeid(key) == i->second->key()) { if (first) out << " ["; else out << ", "; first = false; out << i->first << "=" << escape_dot_string(i->second->get_string(key)); } } if (!first) out << "]"; } private: const dynamic_properties* dp; }; class dynamic_vertex_properties_writer { public: dynamic_vertex_properties_writer( const dynamic_properties& dp, const std::string& node_id) : dp(&dp), node_id(&node_id) { } template < typename Descriptor > void operator()(std::ostream& out, Descriptor key) const { bool first = true; for (dynamic_properties::const_iterator i = dp->begin(); i != dp->end(); ++i) { if (typeid(key) == i->second->key() && i->first != *node_id) { if (first) out << " ["; else out << ", "; first = false; out << i->first << "=" << escape_dot_string(i->second->get_string(key)); } } if (!first) out << "]"; } private: const dynamic_properties* dp; const std::string* node_id; }; template < typename Graph > class dynamic_graph_properties_writer { public: dynamic_graph_properties_writer( const dynamic_properties& dp, const Graph& g) : g(&g), dp(&dp) { } void operator()(std::ostream& out) const { for (dynamic_properties::const_iterator i = dp->begin(); i != dp->end(); ++i) { if (typeid(Graph*) == i->second->key()) { // const_cast here is to match interface used in read_graphviz out << i->first << "=" << escape_dot_string( i->second->get_string(const_cast< Graph* >(g))) << ";\n"; } } } private: const Graph* g; const dynamic_properties* dp; }; namespace graph { namespace detail { template < typename Vertex > struct node_id_property_map { typedef std::string value_type; typedef value_type reference; typedef Vertex key_type; typedef readable_property_map_tag category; node_id_property_map() {} node_id_property_map( const dynamic_properties& dp, const std::string& node_id) : dp(&dp), node_id(&node_id) { } const dynamic_properties* dp; const std::string* node_id; }; template < typename Vertex > inline std::string get(node_id_property_map< Vertex > pm, typename node_id_property_map< Vertex >::key_type v) { return get(*pm.node_id, *pm.dp, v); } } } // end namespace graph::detail template < typename Graph > inline void write_graphviz_dp(std::ostream& out, const Graph& g, const dynamic_properties& dp, const std::string& node_id = "node_id" BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, vertex_list_graph_tag)) { typedef typename graph_traits< Graph >::vertex_descriptor Vertex; write_graphviz_dp(out, g, dp, node_id, graph::detail::node_id_property_map< Vertex >(dp, node_id)); } template < typename Graph, typename VertexID > void write_graphviz_dp(std::ostream& out, const Graph& g, const dynamic_properties& dp, const std::string& node_id, VertexID id BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, vertex_list_graph_tag)) { write_graphviz(out, g, /*vertex_writer=*/dynamic_vertex_properties_writer(dp, node_id), /*edge_writer=*/dynamic_properties_writer(dp), /*graph_writer=*/dynamic_graph_properties_writer< Graph >(dp, g), id); } ///////////////////////////////////////////////////////////////////////////// // Graph reader exceptions ///////////////////////////////////////////////////////////////////////////// struct BOOST_SYMBOL_VISIBLE graph_exception : public std::exception { virtual ~graph_exception() throw() {} virtual const char* what() const throw() = 0; }; struct BOOST_SYMBOL_VISIBLE bad_parallel_edge : public graph_exception { std::string from; std::string to; mutable std::string statement; bad_parallel_edge(const std::string& i, const std::string& j) : from(i), to(j) { } virtual ~bad_parallel_edge() throw() {} const char* what() const throw() { if (statement.empty()) statement = std::string("Failed to add parallel edge: (") + from + "," + to + ")\n"; return statement.c_str(); } }; struct BOOST_SYMBOL_VISIBLE directed_graph_error : public graph_exception { virtual ~directed_graph_error() throw() {} virtual const char* what() const throw() { return "read_graphviz: " "Tried to read a directed graph into an undirected graph."; } }; struct BOOST_SYMBOL_VISIBLE undirected_graph_error : public graph_exception { virtual ~undirected_graph_error() throw() {} virtual const char* what() const throw() { return "read_graphviz: " "Tried to read an undirected graph into a directed graph."; } }; struct BOOST_SYMBOL_VISIBLE bad_graphviz_syntax : public graph_exception { std::string errmsg; bad_graphviz_syntax(const std::string& errmsg) : errmsg(errmsg) {} const char* what() const throw() { return errmsg.c_str(); } ~bad_graphviz_syntax() throw() {}; }; namespace detail { namespace graph { typedef std::string id_t; typedef id_t node_t; // edges are not uniquely determined by adjacent nodes class edge_t { int idx_; explicit edge_t(int i) : idx_(i) {} public: static edge_t new_edge() { static int idx = 0; return edge_t(idx++); }; bool operator==(const edge_t& rhs) const { return idx_ == rhs.idx_; } bool operator<(const edge_t& rhs) const { return idx_ < rhs.idx_; } }; class mutate_graph { public: virtual ~mutate_graph() {} virtual bool is_directed() const = 0; virtual void do_add_vertex(const node_t& node) = 0; virtual void do_add_edge( const edge_t& edge, const node_t& source, const node_t& target) = 0; virtual void set_node_property( const id_t& key, const node_t& node, const id_t& value) = 0; virtual void set_edge_property( const id_t& key, const edge_t& edge, const id_t& value) = 0; virtual void // RG: need new second parameter to support BGL // subgraphs set_graph_property(const id_t& key, const id_t& value) = 0; virtual void finish_building_graph() = 0; }; template < typename MutableGraph > class mutate_graph_impl : public mutate_graph { typedef typename graph_traits< MutableGraph >::vertex_descriptor bgl_vertex_t; typedef typename graph_traits< MutableGraph >::edge_descriptor bgl_edge_t; public: mutate_graph_impl(MutableGraph& graph, dynamic_properties& dp, std::string node_id_prop) : graph_(graph), dp_(dp), node_id_prop_(node_id_prop) { } ~mutate_graph_impl() {} bool is_directed() const { return boost::is_convertible< typename boost::graph_traits< MutableGraph >::directed_category, boost::directed_tag >::value; } virtual void do_add_vertex(const node_t& node) { // Add the node to the graph. bgl_vertex_t v = add_vertex(graph_); // Set up a mapping from name to BGL vertex. bgl_nodes.insert(std::make_pair(node, v)); // node_id_prop_ allows the caller to see the real id names for // nodes. put(node_id_prop_, dp_, v, node); } void do_add_edge( const edge_t& edge, const node_t& source, const node_t& target) { std::pair< bgl_edge_t, bool > result = add_edge(bgl_nodes[source], bgl_nodes[target], graph_); if (!result.second) { // In the case of no parallel edges allowed boost::throw_exception(bad_parallel_edge(source, target)); } else { bgl_edges.insert(std::make_pair(edge, result.first)); } } void set_node_property( const id_t& key, const node_t& node, const id_t& value) { put(key, dp_, bgl_nodes[node], value); } void set_edge_property( const id_t& key, const edge_t& edge, const id_t& value) { put(key, dp_, bgl_edges[edge], value); } void set_graph_property(const id_t& key, const id_t& value) { /* RG: pointer to graph prevents copying */ put(key, dp_, &graph_, value); } void finish_building_graph() {} protected: MutableGraph& graph_; dynamic_properties& dp_; std::string node_id_prop_; std::map< node_t, bgl_vertex_t > bgl_nodes; std::map< edge_t, bgl_edge_t > bgl_edges; }; template < typename Directed, typename VertexProperty, typename EdgeProperty, typename GraphProperty, typename Vertex, typename EdgeIndex > class mutate_graph_impl< compressed_sparse_row_graph< Directed, VertexProperty, EdgeProperty, GraphProperty, Vertex, EdgeIndex > > : public mutate_graph { typedef compressed_sparse_row_graph< Directed, VertexProperty, EdgeProperty, GraphProperty, Vertex, EdgeIndex > CSRGraph; typedef typename graph_traits< CSRGraph >::vertices_size_type bgl_vertex_t; typedef typename graph_traits< CSRGraph >::edges_size_type bgl_edge_t; typedef typename graph_traits< CSRGraph >::edge_descriptor edge_descriptor; public: mutate_graph_impl(CSRGraph& graph, dynamic_properties& dp, std::string node_id_prop) : graph_(graph) , dp_(dp) , vertex_count(0) , node_id_prop_(node_id_prop) { } ~mutate_graph_impl() {} void finish_building_graph() { typedef compressed_sparse_row_graph< directedS, no_property, bgl_edge_t, GraphProperty, Vertex, EdgeIndex > TempCSRGraph; TempCSRGraph temp(edges_are_unsorted_multi_pass, edges_to_add.begin(), edges_to_add.end(), counting_iterator< bgl_edge_t >(0), vertex_count); set_property(temp, graph_all, get_property(graph_, graph_all)); graph_.assign(temp); // Copies structure, not properties std::vector< edge_descriptor > edge_permutation_from_sorting( num_edges(temp)); BGL_FORALL_EDGES_T(e, temp, TempCSRGraph) { edge_permutation_from_sorting[temp[e]] = e; } typedef boost::tuple< id_t, bgl_vertex_t, id_t > v_prop; BOOST_FOREACH (const v_prop& t, vertex_props) { put(boost::get< 0 >(t), dp_, boost::get< 1 >(t), boost::get< 2 >(t)); } typedef boost::tuple< id_t, bgl_edge_t, id_t > e_prop; BOOST_FOREACH (const e_prop& t, edge_props) { put(boost::get< 0 >(t), dp_, edge_permutation_from_sorting[boost::get< 1 >(t)], boost::get< 2 >(t)); } } bool is_directed() const { return boost::is_convertible< typename boost::graph_traits< CSRGraph >::directed_category, boost::directed_tag >::value; } virtual void do_add_vertex(const node_t& node) { // Add the node to the graph. bgl_vertex_t v = vertex_count++; // Set up a mapping from name to BGL vertex. bgl_nodes.insert(std::make_pair(node, v)); // node_id_prop_ allows the caller to see the real id names for // nodes. vertex_props.push_back( boost::make_tuple(node_id_prop_, v, node)); } void do_add_edge( const edge_t& edge, const node_t& source, const node_t& target) { bgl_edge_t result = edges_to_add.size(); edges_to_add.push_back( std::make_pair(bgl_nodes[source], bgl_nodes[target])); bgl_edges.insert(std::make_pair(edge, result)); } void set_node_property( const id_t& key, const node_t& node, const id_t& value) { vertex_props.push_back( boost::make_tuple(key, bgl_nodes[node], value)); } void set_edge_property( const id_t& key, const edge_t& edge, const id_t& value) { edge_props.push_back( boost::make_tuple(key, bgl_edges[edge], value)); } void set_graph_property(const id_t& key, const id_t& value) { /* RG: pointer to graph prevents copying */ put(key, dp_, &graph_, value); } protected: CSRGraph& graph_; dynamic_properties& dp_; bgl_vertex_t vertex_count; std::string node_id_prop_; std::vector< boost::tuple< id_t, bgl_vertex_t, id_t > > vertex_props; std::vector< boost::tuple< id_t, bgl_edge_t, id_t > > edge_props; std::vector< std::pair< bgl_vertex_t, bgl_vertex_t > > edges_to_add; std::map< node_t, bgl_vertex_t > bgl_nodes; std::map< edge_t, bgl_edge_t > bgl_edges; }; } } } // end namespace boost::detail::graph #ifdef BOOST_GRAPH_USE_SPIRIT_PARSER #ifndef BOOST_GRAPH_READ_GRAPHVIZ_ITERATORS #define BOOST_GRAPH_READ_GRAPHVIZ_ITERATORS #endif #include <boost/graph/detail/read_graphviz_spirit.hpp> #else // New default parser #include <boost/graph/detail/read_graphviz_new.hpp> #endif // BOOST_GRAPH_USE_SPIRIT_PARSER namespace boost { // Parse the passed string as a GraphViz dot file. template < typename MutableGraph > bool read_graphviz(const std::string& data, MutableGraph& graph, dynamic_properties& dp, std::string const& node_id = "node_id") { #ifdef BOOST_GRAPH_USE_SPIRIT_PARSER return read_graphviz_spirit(data.begin(), data.end(), graph, dp, node_id); #else // Non-Spirit parser return read_graphviz_new(data, graph, dp, node_id); #endif } // Parse the passed iterator range as a GraphViz dot file. template < typename InputIterator, typename MutableGraph > bool read_graphviz(InputIterator user_first, InputIterator user_last, MutableGraph& graph, dynamic_properties& dp, std::string const& node_id = "node_id") { #ifdef BOOST_GRAPH_USE_SPIRIT_PARSER typedef InputIterator is_t; typedef boost::spirit::classic::multi_pass< is_t > iterator_t; iterator_t first(boost::spirit::classic::make_multi_pass(user_first)); iterator_t last(boost::spirit::classic::make_multi_pass(user_last)); return read_graphviz_spirit(first, last, graph, dp, node_id); #else // Non-Spirit parser return read_graphviz_new( std::string(user_first, user_last), graph, dp, node_id); #endif } // Parse the passed stream as a GraphViz dot file. template < typename MutableGraph > bool read_graphviz(std::istream& in, MutableGraph& graph, dynamic_properties& dp, std::string const& node_id = "node_id") { typedef std::istream_iterator< char > is_t; in >> std::noskipws; return read_graphviz(is_t(in), is_t(), graph, dp, node_id); } } // namespace boost #include BOOST_GRAPH_MPI_INCLUDE(< boost / graph / distributed / graphviz.hpp >) #endif // BOOST_GRAPHVIZ_HPP kruskal_min_spanning_tree.hpp 0000644 00000013157 15125521275 0012524 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_MST_KRUSKAL_HPP #define BOOST_GRAPH_MST_KRUSKAL_HPP /* *Minimum Spanning Tree * Kruskal Algorithm * *Requirement: * undirected graph */ #include <vector> #include <queue> #include <functional> #include <boost/property_map/property_map.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/pending/disjoint_sets.hpp> #include <boost/pending/indirect_cmp.hpp> #include <boost/concept/assert.hpp> namespace boost { // Kruskal's algorithm for Minimum Spanning Tree // // This is a greedy algorithm to calculate the Minimum Spanning Tree // for an undirected graph with weighted edges. The output will be a // set of edges. // namespace detail { template < class Graph, class OutputIterator, class Rank, class Parent, class Weight > void kruskal_mst_impl(const Graph& G, OutputIterator spanning_tree_edges, Rank rank, Parent parent, Weight weight) { if (num_vertices(G) == 0) return; // Nothing to do in this case typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::edge_descriptor Edge; BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph >)); BOOST_CONCEPT_ASSERT((OutputIteratorConcept< OutputIterator, Edge >)); BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< Rank, Vertex >)); BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< Parent, Vertex >)); BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< Weight, Edge >)); typedef typename property_traits< Weight >::value_type W_value; typedef typename property_traits< Rank >::value_type R_value; typedef typename property_traits< Parent >::value_type P_value; BOOST_CONCEPT_ASSERT((ComparableConcept< W_value >)); BOOST_CONCEPT_ASSERT((ConvertibleConcept< P_value, Vertex >)); BOOST_CONCEPT_ASSERT((IntegerConcept< R_value >)); disjoint_sets< Rank, Parent > dset(rank, parent); typename graph_traits< Graph >::vertex_iterator ui, uiend; for (boost::tie(ui, uiend) = vertices(G); ui != uiend; ++ui) dset.make_set(*ui); typedef indirect_cmp< Weight, std::greater< W_value > > weight_greater; weight_greater wl(weight); std::priority_queue< Edge, std::vector< Edge >, weight_greater > Q(wl); /*push all edge into Q*/ typename graph_traits< Graph >::edge_iterator ei, eiend; for (boost::tie(ei, eiend) = edges(G); ei != eiend; ++ei) Q.push(*ei); while (!Q.empty()) { Edge e = Q.top(); Q.pop(); Vertex u = dset.find_set(source(e, G)); Vertex v = dset.find_set(target(e, G)); if (u != v) { *spanning_tree_edges++ = e; dset.link(u, v); } } } } // namespace detail // Named Parameters Variants template < class Graph, class OutputIterator > inline void kruskal_minimum_spanning_tree( const Graph& g, OutputIterator spanning_tree_edges) { typedef typename graph_traits< Graph >::vertices_size_type size_type; typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; if (num_vertices(g) == 0) return; // Nothing to do in this case typename graph_traits< Graph >::vertices_size_type n = num_vertices(g); std::vector< size_type > rank_map(n); std::vector< vertex_t > pred_map(n); detail::kruskal_mst_impl(g, spanning_tree_edges, make_iterator_property_map( rank_map.begin(), get(vertex_index, g), rank_map[0]), make_iterator_property_map( pred_map.begin(), get(vertex_index, g), pred_map[0]), get(edge_weight, g)); } template < class Graph, class OutputIterator, class P, class T, class R > inline void kruskal_minimum_spanning_tree(const Graph& g, OutputIterator spanning_tree_edges, const bgl_named_params< P, T, R >& params) { typedef typename graph_traits< Graph >::vertices_size_type size_type; typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; if (num_vertices(g) == 0) return; // Nothing to do in this case typename graph_traits< Graph >::vertices_size_type n; n = is_default_param(get_param(params, vertex_rank)) ? num_vertices(g) : 1; std::vector< size_type > rank_map(n); n = is_default_param(get_param(params, vertex_predecessor)) ? num_vertices(g) : 1; std::vector< vertex_t > pred_map(n); detail::kruskal_mst_impl(g, spanning_tree_edges, choose_param(get_param(params, vertex_rank), make_iterator_property_map(rank_map.begin(), choose_pmap(get_param(params, vertex_index), g, vertex_index), rank_map[0])), choose_param(get_param(params, vertex_predecessor), make_iterator_property_map(pred_map.begin(), choose_const_pmap( get_param(params, vertex_index), g, vertex_index), pred_map[0])), choose_const_pmap(get_param(params, edge_weight), g, edge_weight)); } } // namespace boost #endif // BOOST_GRAPH_MST_KRUSKAL_HPP adj_list_serialize.hpp 0000644 00000010653 15125521275 0011127 0 ustar 00 //======================================================================= // Copyright 2005 Jeremy G. Siek // Authors: Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_ADJ_LIST_SERIALIZE_HPP #define BOOST_GRAPH_ADJ_LIST_SERIALIZE_HPP #include <boost/graph/adjacency_list.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/pending/property_serialize.hpp> #include <boost/config.hpp> #include <boost/detail/workaround.hpp> #include <boost/serialization/collections_save_imp.hpp> #include <boost/serialization/collections_load_imp.hpp> #include <boost/serialization/split_free.hpp> namespace boost { namespace serialization { // Turn off tracking for adjacency_list. It's not polymorphic, and we // need to do this to enable saving of non-const adjacency lists. template < class OEL, class VL, class D, class VP, class EP, class GP, class EL > struct tracking_level< boost::adjacency_list< OEL, VL, D, VP, EP, GP, EL > > { typedef mpl::integral_c_tag tag; typedef mpl::int_< track_never > type; BOOST_STATIC_CONSTANT(int, value = tracking_level::type::value); }; template < class Archive, class OEL, class VL, class D, class VP, class EP, class GP, class EL > inline void save(Archive& ar, const boost::adjacency_list< OEL, VL, D, VP, EP, GP, EL >& graph, const unsigned int /* file_version */ ) { typedef adjacency_list< OEL, VL, D, VP, EP, GP, EL > Graph; typedef typename graph_traits< Graph >::vertex_descriptor Vertex; int V = num_vertices(graph); int E = num_edges(graph); ar << BOOST_SERIALIZATION_NVP(V); ar << BOOST_SERIALIZATION_NVP(E); // assign indices to vertices std::map< Vertex, int > indices; int num = 0; BGL_FORALL_VERTICES_T(v, graph, Graph) { indices[v] = num++; ar << serialization::make_nvp( "vertex_property", get(vertex_all_t(), graph, v)); } // write edges BGL_FORALL_EDGES_T(e, graph, Graph) { ar << serialization::make_nvp("u", indices[source(e, graph)]); ar << serialization::make_nvp("v", indices[target(e, graph)]); ar << serialization::make_nvp( "edge_property", get(edge_all_t(), graph, e)); } ar << serialization::make_nvp( "graph_property", get_property(graph, graph_all_t())); } template < class Archive, class OEL, class VL, class D, class VP, class EP, class GP, class EL > inline void load( Archive& ar, boost::adjacency_list< OEL, VL, D, VP, EP, GP, EL >& graph, const unsigned int /* file_version */ ) { typedef adjacency_list< OEL, VL, D, VP, EP, GP, EL > Graph; typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::edge_descriptor Edge; unsigned int V; ar >> BOOST_SERIALIZATION_NVP(V); unsigned int E; ar >> BOOST_SERIALIZATION_NVP(E); std::vector< Vertex > verts(V); int i = 0; while (V-- > 0) { Vertex v = add_vertex(graph); verts[i++] = v; ar >> serialization::make_nvp( "vertex_property", get(vertex_all_t(), graph, v)); } while (E-- > 0) { int u; int v; ar >> BOOST_SERIALIZATION_NVP(u); ar >> BOOST_SERIALIZATION_NVP(v); Edge e; bool inserted; boost::tie(e, inserted) = add_edge(verts[u], verts[v], graph); ar >> serialization::make_nvp( "edge_property", get(edge_all_t(), graph, e)); } ar >> serialization::make_nvp( "graph_property", get_property(graph, graph_all_t())); } template < class Archive, class OEL, class VL, class D, class VP, class EP, class GP, class EL > inline void serialize(Archive& ar, boost::adjacency_list< OEL, VL, D, VP, EP, GP, EL >& graph, const unsigned int file_version) { boost::serialization::split_free(ar, graph, file_version); } } // serialization } // boost #endif // BOOST_GRAPH_ADJ_LIST_SERIALIZE_HPP dominator_tree.hpp 0000644 00000042221 15125521275 0010276 0 ustar 00 //======================================================================= // Copyright (C) 2005-2009 Jongsoo Park <jongsoo.park -at- gmail.com> // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_DOMINATOR_HPP #define BOOST_GRAPH_DOMINATOR_HPP #include <boost/config.hpp> #include <deque> #include <set> #include <boost/graph/depth_first_search.hpp> #include <boost/concept/assert.hpp> // Dominator tree computation namespace boost { namespace detail { /** * An extended time_stamper which also records vertices for each dfs number */ template < class TimeMap, class VertexVector, class TimeT, class Tag > class time_stamper_with_vertex_vector : public base_visitor< time_stamper_with_vertex_vector< TimeMap, VertexVector, TimeT, Tag > > { public: typedef Tag event_filter; time_stamper_with_vertex_vector( TimeMap timeMap, VertexVector& v, TimeT& t) : timeStamper_(timeMap, t), v_(v) { } template < class Graph > void operator()(const typename property_traits< TimeMap >::key_type& v, const Graph& g) { timeStamper_(v, g); v_[timeStamper_.m_time] = v; } private: time_stamper< TimeMap, TimeT, Tag > timeStamper_; VertexVector& v_; }; /** * A convenient way to create a time_stamper_with_vertex_vector */ template < class TimeMap, class VertexVector, class TimeT, class Tag > time_stamper_with_vertex_vector< TimeMap, VertexVector, TimeT, Tag > stamp_times_with_vertex_vector( TimeMap timeMap, VertexVector& v, TimeT& t, Tag) { return time_stamper_with_vertex_vector< TimeMap, VertexVector, TimeT, Tag >(timeMap, v, t); } template < class Graph, class IndexMap, class TimeMap, class PredMap, class DomTreePredMap > class dominator_visitor { typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType; public: /** * @param g [in] the target graph of the dominator tree * @param entry [in] the entry node of g * @param indexMap [in] the vertex index map for g * @param domTreePredMap [out] the immediate dominator map * (parent map in dominator tree) */ dominator_visitor(const Graph& g, const Vertex& entry, const IndexMap& indexMap, DomTreePredMap domTreePredMap) : semi_(num_vertices(g)) , ancestor_(num_vertices(g), graph_traits< Graph >::null_vertex()) , samedom_(ancestor_) , best_(semi_) , semiMap_(make_iterator_property_map(semi_.begin(), indexMap)) , ancestorMap_(make_iterator_property_map(ancestor_.begin(), indexMap)) , bestMap_(make_iterator_property_map(best_.begin(), indexMap)) , buckets_(num_vertices(g)) , bucketMap_(make_iterator_property_map(buckets_.begin(), indexMap)) , entry_(entry) , domTreePredMap_(domTreePredMap) , numOfVertices_(num_vertices(g)) , samedomMap(make_iterator_property_map(samedom_.begin(), indexMap)) { } void operator()(const Vertex& n, const TimeMap& dfnumMap, const PredMap& parentMap, const Graph& g) { if (n == entry_) return; const Vertex p(get(parentMap, n)); Vertex s(p); // 1. Calculate the semidominator of n, // based on the semidominator thm. // * Semidominator thm. : To find the semidominator of a node n, // consider all predecessors v of n in the CFG (Control Flow // Graph). // - If v is a proper ancestor of n in the spanning tree // (so dfnum(v) < dfnum(n)), then v is a candidate for semi(n) // - If v is a non-ancestor of n (so dfnum(v) > dfnum(n)) // then for each u that is an ancestor of v (or u = v), // Let semi(u) be a candidate for semi(n) // of all these candidates, the one with lowest dfnum is // the semidominator of n. // For each predecessor of n typename graph_traits< Graph >::in_edge_iterator inItr, inEnd; for (boost::tie(inItr, inEnd) = in_edges(n, g); inItr != inEnd; ++inItr) { const Vertex v = source(*inItr, g); // To deal with unreachable nodes if (get(dfnumMap, v) < 0 || get(dfnumMap, v) >= numOfVertices_) continue; Vertex s2; if (get(dfnumMap, v) <= get(dfnumMap, n)) s2 = v; else s2 = get(semiMap_, ancestor_with_lowest_semi_(v, dfnumMap)); if (get(dfnumMap, s2) < get(dfnumMap, s)) s = s2; } put(semiMap_, n, s); // 2. Calculation of n's dominator is deferred until // the path from s to n has been linked into the forest get(bucketMap_, s).push_back(n); get(ancestorMap_, n) = p; get(bestMap_, n) = n; // 3. Now that the path from p to v has been linked into // the spanning forest, these lines calculate the dominator of v, // based on the dominator thm., or else defer the calculation // until y's dominator is known // * Dominator thm. : On the spanning-tree path below semi(n) and // above or including n, let y be the node // with the smallest-numbered semidominator. Then, // // idom(n) = semi(n) if semi(y)=semi(n) or // idom(y) if semi(y) != semi(n) typename std::deque< Vertex >::iterator buckItr; for (buckItr = get(bucketMap_, p).begin(); buckItr != get(bucketMap_, p).end(); ++buckItr) { const Vertex v(*buckItr); const Vertex y(ancestor_with_lowest_semi_(v, dfnumMap)); if (get(semiMap_, y) == get(semiMap_, v)) put(domTreePredMap_, v, p); else put(samedomMap, v, y); } get(bucketMap_, p).clear(); } protected: /** * Evaluate function in Tarjan's path compression */ const Vertex ancestor_with_lowest_semi_( const Vertex& v, const TimeMap& dfnumMap) { const Vertex a(get(ancestorMap_, v)); if (get(ancestorMap_, a) != graph_traits< Graph >::null_vertex()) { const Vertex b(ancestor_with_lowest_semi_(a, dfnumMap)); put(ancestorMap_, v, get(ancestorMap_, a)); if (get(dfnumMap, get(semiMap_, b)) < get(dfnumMap, get(semiMap_, get(bestMap_, v)))) put(bestMap_, v, b); } return get(bestMap_, v); } std::vector< Vertex > semi_, ancestor_, samedom_, best_; PredMap semiMap_, ancestorMap_, bestMap_; std::vector< std::deque< Vertex > > buckets_; iterator_property_map< typename std::vector< std::deque< Vertex > >::iterator, IndexMap > bucketMap_; const Vertex& entry_; DomTreePredMap domTreePredMap_; const VerticesSizeType numOfVertices_; public: PredMap samedomMap; }; } // namespace detail /** * @brief Build dominator tree using Lengauer-Tarjan algorithm. * It takes O((V+E)log(V+E)) time. * * @pre dfnumMap, parentMap and verticesByDFNum have dfs results corresponding * indexMap. * If dfs has already run before, * this function would be good for saving computations. * @pre Unreachable nodes must be masked as * graph_traits<Graph>::null_vertex in parentMap. * @pre Unreachable nodes must be masked as * (std::numeric_limits<VerticesSizeType>::max)() in dfnumMap. * * @param domTreePredMap [out] : immediate dominator map (parent map * in dom. tree) * * @note reference Appel. p. 452~453. algorithm 19.9, 19.10. * * @todo : Optimization in Finding Dominators in Practice, Loukas Georgiadis */ template < class Graph, class IndexMap, class TimeMap, class PredMap, class VertexVector, class DomTreePredMap > void lengauer_tarjan_dominator_tree_without_dfs(const Graph& g, const typename graph_traits< Graph >::vertex_descriptor& entry, const IndexMap& indexMap, TimeMap dfnumMap, PredMap parentMap, VertexVector& verticesByDFNum, DomTreePredMap domTreePredMap) { // Typedefs and concept check typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType; BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >)); const VerticesSizeType numOfVertices = num_vertices(g); if (numOfVertices == 0) return; // 1. Visit each vertex in reverse post order and calculate sdom. detail::dominator_visitor< Graph, IndexMap, TimeMap, PredMap, DomTreePredMap > visitor(g, entry, indexMap, domTreePredMap); VerticesSizeType i; for (i = 0; i < numOfVertices; ++i) { const Vertex u(verticesByDFNum[numOfVertices - 1 - i]); if (u != graph_traits< Graph >::null_vertex()) visitor(u, dfnumMap, parentMap, g); } // 2. Now all the deferred dominator calculations, // based on the second clause of the dominator thm., are performed for (i = 0; i < numOfVertices; ++i) { const Vertex n(verticesByDFNum[i]); if (n == entry || n == graph_traits< Graph >::null_vertex()) continue; Vertex u = get(visitor.samedomMap, n); if (u != graph_traits< Graph >::null_vertex()) { put(domTreePredMap, n, get(domTreePredMap, u)); } } } /** * Unlike lengauer_tarjan_dominator_tree_without_dfs, * dfs is run in this function and * the result is written to dfnumMap, parentMap, vertices. * * If the result of dfs required after this algorithm, * this function can eliminate the need of rerunning dfs. */ template < class Graph, class IndexMap, class TimeMap, class PredMap, class VertexVector, class DomTreePredMap > void lengauer_tarjan_dominator_tree(const Graph& g, const typename graph_traits< Graph >::vertex_descriptor& entry, const IndexMap& indexMap, TimeMap dfnumMap, PredMap parentMap, VertexVector& verticesByDFNum, DomTreePredMap domTreePredMap) { // Typedefs and concept check typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType; BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >)); // 1. Depth first visit const VerticesSizeType numOfVertices = num_vertices(g); if (numOfVertices == 0) return; VerticesSizeType time = (std::numeric_limits< VerticesSizeType >::max)(); std::vector< default_color_type > colors( numOfVertices, color_traits< default_color_type >::white()); depth_first_visit(g, entry, make_dfs_visitor( make_pair(record_predecessors(parentMap, on_tree_edge()), detail::stamp_times_with_vertex_vector( dfnumMap, verticesByDFNum, time, on_discover_vertex()))), make_iterator_property_map(colors.begin(), indexMap)); // 2. Run main algorithm. lengauer_tarjan_dominator_tree_without_dfs(g, entry, indexMap, dfnumMap, parentMap, verticesByDFNum, domTreePredMap); } /** * Use vertex_index as IndexMap and make dfnumMap, parentMap, verticesByDFNum * internally. * If we don't need the result of dfs (dfnumMap, parentMap, verticesByDFNum), * this function would be more convenient one. */ template < class Graph, class DomTreePredMap > void lengauer_tarjan_dominator_tree(const Graph& g, const typename graph_traits< Graph >::vertex_descriptor& entry, DomTreePredMap domTreePredMap) { // typedefs typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType; typedef typename property_map< Graph, vertex_index_t >::const_type IndexMap; typedef iterator_property_map< typename std::vector< VerticesSizeType >::iterator, IndexMap > TimeMap; typedef iterator_property_map< typename std::vector< Vertex >::iterator, IndexMap > PredMap; // Make property maps const VerticesSizeType numOfVertices = num_vertices(g); if (numOfVertices == 0) return; const IndexMap indexMap = get(vertex_index, g); std::vector< VerticesSizeType > dfnum(numOfVertices, 0); TimeMap dfnumMap(make_iterator_property_map(dfnum.begin(), indexMap)); std::vector< Vertex > parent( numOfVertices, graph_traits< Graph >::null_vertex()); PredMap parentMap(make_iterator_property_map(parent.begin(), indexMap)); std::vector< Vertex > verticesByDFNum(parent); // Run main algorithm lengauer_tarjan_dominator_tree(g, entry, indexMap, dfnumMap, parentMap, verticesByDFNum, domTreePredMap); } /** * Muchnick. p. 182, 184 * * using iterative bit vector analysis */ template < class Graph, class IndexMap, class DomTreePredMap > void iterative_bit_vector_dominator_tree(const Graph& g, const typename graph_traits< Graph >::vertex_descriptor& entry, const IndexMap& indexMap, DomTreePredMap domTreePredMap) { typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::vertex_iterator vertexItr; typedef typename graph_traits< Graph >::vertices_size_type VerticesSizeType; typedef iterator_property_map< typename std::vector< std::set< Vertex > >::iterator, IndexMap > vertexSetMap; BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >)); // 1. Finding dominator // 1.1. Initialize const VerticesSizeType numOfVertices = num_vertices(g); if (numOfVertices == 0) return; vertexItr vi, viend; boost::tie(vi, viend) = vertices(g); const std::set< Vertex > N(vi, viend); bool change = true; std::vector< std::set< Vertex > > dom(numOfVertices, N); vertexSetMap domMap(make_iterator_property_map(dom.begin(), indexMap)); get(domMap, entry).clear(); get(domMap, entry).insert(entry); while (change) { change = false; for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi) { if (*vi == entry) continue; std::set< Vertex > T(N); typename graph_traits< Graph >::in_edge_iterator inItr, inEnd; for (boost::tie(inItr, inEnd) = in_edges(*vi, g); inItr != inEnd; ++inItr) { const Vertex p = source(*inItr, g); std::set< Vertex > tempSet; std::set_intersection(T.begin(), T.end(), get(domMap, p).begin(), get(domMap, p).end(), std::inserter(tempSet, tempSet.begin())); T.swap(tempSet); } T.insert(*vi); if (T != get(domMap, *vi)) { change = true; get(domMap, *vi).swap(T); } } // end of for (boost::tie(vi, viend) = vertices(g) } // end of while(change) // 2. Build dominator tree for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi) get(domMap, *vi).erase(*vi); Graph domTree(numOfVertices); for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi) { if (*vi == entry) continue; // We have to iterate through copied dominator set const std::set< Vertex > tempSet(get(domMap, *vi)); typename std::set< Vertex >::const_iterator s; for (s = tempSet.begin(); s != tempSet.end(); ++s) { typename std::set< Vertex >::iterator t; for (t = get(domMap, *vi).begin(); t != get(domMap, *vi).end();) { typename std::set< Vertex >::iterator old_t = t; ++t; // Done early because t may become invalid if (*old_t == *s) continue; if (get(domMap, *s).find(*old_t) != get(domMap, *s).end()) get(domMap, *vi).erase(old_t); } } } for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi) { if (*vi != entry && get(domMap, *vi).size() == 1) { Vertex temp = *get(domMap, *vi).begin(); put(domTreePredMap, *vi, temp); } } } template < class Graph, class DomTreePredMap > void iterative_bit_vector_dominator_tree(const Graph& g, const typename graph_traits< Graph >::vertex_descriptor& entry, DomTreePredMap domTreePredMap) { typename property_map< Graph, vertex_index_t >::const_type indexMap = get(vertex_index, g); iterative_bit_vector_dominator_tree(g, entry, indexMap, domTreePredMap); } } // namespace boost #endif // BOOST_GRAPH_DOMINATOR_HPP loop_erased_random_walk.hpp 0000644 00000010524 15125521275 0012136 0 ustar 00 // Copyright 2010 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Jeremiah Willcock // Andrew Lumsdaine #ifndef BOOST_GRAPH_LOOP_ERASED_RANDOM_WALK_HPP #define BOOST_GRAPH_LOOP_ERASED_RANDOM_WALK_HPP #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/random.hpp> #include <boost/next_prior.hpp> #include <vector> #include <boost/assert.hpp> namespace boost { struct BOOST_SYMBOL_VISIBLE loop_erased_random_walk_stuck : public std::exception { virtual ~loop_erased_random_walk_stuck() throw() {} inline virtual const char* what() const throw() { return "Loop-erased random walk found a vertex with no out-edges"; } }; // Do a loop-erased random walk from vertex s to any vertex colored black (or // actually any color other than white or gray) in the color map. The color // white is for vertices that are not part of the path, while gray is for // those that are on the path (for cycle detection). The vector path is used // for temporary storage and as the result of the algorithm; while all // elements of the path except the last have their colors set to gray upon // return. Vertex s must start off colored white. // // Useful references: // http://everything2.com/title/loop-erased+random+walk // Wikipedia page on "Loop-Erased Random Walk" template < typename Graph, typename ColorMap, typename NextEdge > void loop_erased_random_walk(const Graph& g, typename boost::graph_traits< Graph >::vertex_descriptor s, NextEdge next_edge, ColorMap color, std::vector< typename boost::graph_traits< Graph >::vertex_descriptor >& path) { typedef typename boost::graph_traits< Graph >::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits< Graph >::edge_descriptor edge_descriptor; typedef typename boost::property_traits< ColorMap >::value_type color_t; typedef boost::color_traits< color_t > color_gen; BOOST_ASSERT(get(color, s) == color_gen::white()); path.clear(); path.push_back(s); put(color, s, color_gen::gray()); while (true) { edge_descriptor e = next_edge(s, g); vertex_descriptor t = target(e, g); color_t t_color = get(color, t); if (t_color == color_gen::white()) { path.push_back(t); put(color, t, color_gen::gray()); s = t; } else if (t_color == color_gen::gray()) { // Found a loop; delete from path from the first occurrence of t to // the end, coloring vertices white. typename std::vector< vertex_descriptor >::iterator it = std::find(path.begin(), path.end(), t); BOOST_ASSERT(it != path.end()); ++it; for (typename std::vector< vertex_descriptor >::iterator j = it; j != path.end(); ++j) { put(color, *j, color_gen::white()); } path.erase(it, path.end()); s = t; } else { // Done path.push_back(t); break; } } } template < typename Graph, typename Gen > class unweighted_random_out_edge_gen { Gen& gen; typedef boost::graph_traits< Graph > gt; public: unweighted_random_out_edge_gen(Gen& gen) : gen(gen) {} typename gt::edge_descriptor operator()( typename gt::vertex_descriptor src, const Graph& g) const { if (out_degree(src, g) == 0) throw loop_erased_random_walk_stuck(); return boost::random_out_edge(g, src, gen); } }; template < typename Graph, typename WeightMap, typename Gen > class weighted_random_out_edge_gen { WeightMap weight; Gen& gen; typedef boost::graph_traits< Graph > gt; public: weighted_random_out_edge_gen(const WeightMap& weight, Gen& gen) : weight(weight), gen(gen) { } typename gt::edge_descriptor operator()( typename gt::vertex_descriptor src, const Graph& g) const { if (out_degree(src, g) == 0) throw loop_erased_random_walk_stuck(); return boost::weighted_random_out_edge(g, src, weight, gen); } }; } #endif // BOOST_GRAPH_LOOP_ERASED_RANDOM_WALK_HPP strong_components.hpp 0000644 00000031331 15125521275 0011044 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_STRONG_COMPONENTS_HPP #define BOOST_GRAPH_STRONG_COMPONENTS_HPP #include <stack> #include <boost/config.hpp> #include <boost/graph/depth_first_search.hpp> #include <boost/type_traits/conversion_traits.hpp> #include <boost/static_assert.hpp> #include <boost/graph/overloading.hpp> #include <boost/graph/detail/mpi_include.hpp> #include <boost/concept/assert.hpp> namespace boost { //========================================================================== // This is Tarjan's algorithm for strongly connected components // from his paper "Depth first search and linear graph algorithms". // It calculates the components in a single application of DFS. // We implement the algorithm as a dfs-visitor. namespace detail { template < typename ComponentMap, typename RootMap, typename DiscoverTime, typename Stack > class tarjan_scc_visitor : public dfs_visitor<> { typedef typename property_traits< ComponentMap >::value_type comp_type; typedef typename property_traits< DiscoverTime >::value_type time_type; public: tarjan_scc_visitor(ComponentMap comp_map, RootMap r, DiscoverTime d, comp_type& c_, Stack& s_) : c(c_) , comp(comp_map) , root(r) , discover_time(d) , dfs_time(time_type()) , s(s_) { } template < typename Graph > void discover_vertex( typename graph_traits< Graph >::vertex_descriptor v, const Graph&) { put(root, v, v); put(comp, v, (std::numeric_limits< comp_type >::max)()); put(discover_time, v, dfs_time++); s.push(v); } template < typename Graph > void finish_vertex( typename graph_traits< Graph >::vertex_descriptor v, const Graph& g) { typename graph_traits< Graph >::vertex_descriptor w; typename graph_traits< Graph >::out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(v, g); ei != ei_end; ++ei) { w = target(*ei, g); if (get(comp, w) == (std::numeric_limits< comp_type >::max)()) put(root, v, this->min_discover_time(get(root, v), get(root, w))); } if (get(root, v) == v) { do { w = s.top(); s.pop(); put(comp, w, c); put(root, w, v); } while (w != v); ++c; } } private: template < typename Vertex > Vertex min_discover_time(Vertex u, Vertex v) { return get(discover_time, u) < get(discover_time, v) ? u : v; } comp_type& c; ComponentMap comp; RootMap root; DiscoverTime discover_time; time_type dfs_time; Stack& s; }; template < class Graph, class ComponentMap, class RootMap, class DiscoverTime, class P, class T, class R > typename property_traits< ComponentMap >::value_type strong_components_impl( const Graph& g, // Input ComponentMap comp, // Output // Internal record keeping RootMap root, DiscoverTime discover_time, const bgl_named_params< P, T, R >& params) { typedef typename graph_traits< Graph >::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT( (ReadWritePropertyMapConcept< ComponentMap, Vertex >)); BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< RootMap, Vertex >)); typedef typename property_traits< RootMap >::value_type RootV; BOOST_CONCEPT_ASSERT((ConvertibleConcept< RootV, Vertex >)); BOOST_CONCEPT_ASSERT( (ReadWritePropertyMapConcept< DiscoverTime, Vertex >)); typename property_traits< ComponentMap >::value_type total = 0; std::stack< Vertex > s; detail::tarjan_scc_visitor< ComponentMap, RootMap, DiscoverTime, std::stack< Vertex > > vis(comp, root, discover_time, total, s); depth_first_search(g, params.visitor(vis)); return total; } //------------------------------------------------------------------------- // The dispatch functions handle the defaults for the rank and discover // time property maps. // dispatch with class specialization to avoid VC++ bug template < class DiscoverTimeMap > struct strong_comp_dispatch2 { template < class Graph, class ComponentMap, class RootMap, class P, class T, class R > inline static typename property_traits< ComponentMap >::value_type apply(const Graph& g, ComponentMap comp, RootMap r_map, const bgl_named_params< P, T, R >& params, DiscoverTimeMap time_map) { return strong_components_impl(g, comp, r_map, time_map, params); } }; template <> struct strong_comp_dispatch2< param_not_found > { template < class Graph, class ComponentMap, class RootMap, class P, class T, class R > inline static typename property_traits< ComponentMap >::value_type apply(const Graph& g, ComponentMap comp, RootMap r_map, const bgl_named_params< P, T, R >& params, param_not_found) { typedef typename graph_traits< Graph >::vertices_size_type size_type; size_type n = num_vertices(g) > 0 ? num_vertices(g) : 1; std::vector< size_type > time_vec(n); return strong_components_impl(g, comp, r_map, make_iterator_property_map(time_vec.begin(), choose_const_pmap( get_param(params, vertex_index), g, vertex_index), time_vec[0]), params); } }; template < class Graph, class ComponentMap, class RootMap, class P, class T, class R, class DiscoverTimeMap > inline typename property_traits< ComponentMap >::value_type scc_helper2( const Graph& g, ComponentMap comp, RootMap r_map, const bgl_named_params< P, T, R >& params, DiscoverTimeMap time_map) { return strong_comp_dispatch2< DiscoverTimeMap >::apply( g, comp, r_map, params, time_map); } template < class RootMap > struct strong_comp_dispatch1 { template < class Graph, class ComponentMap, class P, class T, class R > inline static typename property_traits< ComponentMap >::value_type apply(const Graph& g, ComponentMap comp, const bgl_named_params< P, T, R >& params, RootMap r_map) { return scc_helper2(g, comp, r_map, params, get_param(params, vertex_discover_time)); } }; template <> struct strong_comp_dispatch1< param_not_found > { template < class Graph, class ComponentMap, class P, class T, class R > inline static typename property_traits< ComponentMap >::value_type apply(const Graph& g, ComponentMap comp, const bgl_named_params< P, T, R >& params, param_not_found) { typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typename std::vector< Vertex >::size_type n = num_vertices(g) > 0 ? num_vertices(g) : 1; std::vector< Vertex > root_vec(n); return scc_helper2(g, comp, make_iterator_property_map(root_vec.begin(), choose_const_pmap( get_param(params, vertex_index), g, vertex_index), root_vec[0]), params, get_param(params, vertex_discover_time)); } }; template < class Graph, class ComponentMap, class RootMap, class P, class T, class R > inline typename property_traits< ComponentMap >::value_type scc_helper1( const Graph& g, ComponentMap comp, const bgl_named_params< P, T, R >& params, RootMap r_map) { return detail::strong_comp_dispatch1< RootMap >::apply( g, comp, params, r_map); } } // namespace detail template < class Graph, class ComponentMap, class P, class T, class R > inline typename property_traits< ComponentMap >::value_type strong_components( const Graph& g, ComponentMap comp, const bgl_named_params< P, T, R >& params BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { typedef typename graph_traits< Graph >::directed_category DirCat; BOOST_STATIC_ASSERT( (is_convertible< DirCat*, directed_tag* >::value == true)); return detail::scc_helper1( g, comp, params, get_param(params, vertex_root_t())); } template < class Graph, class ComponentMap > inline typename property_traits< ComponentMap >::value_type strong_components( const Graph& g, ComponentMap comp BOOST_GRAPH_ENABLE_IF_MODELS_PARM( Graph, vertex_list_graph_tag)) { typedef typename graph_traits< Graph >::directed_category DirCat; BOOST_STATIC_ASSERT( (is_convertible< DirCat*, directed_tag* >::value == true)); bgl_named_params< int, int > params(0); return strong_components(g, comp, params); } template < typename Graph, typename ComponentMap, typename ComponentLists > void build_component_lists(const Graph& g, typename graph_traits< Graph >::vertices_size_type num_scc, ComponentMap component_number, ComponentLists& components) { components.resize(num_scc); typename graph_traits< Graph >::vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) components[component_number[*vi]].push_back(*vi); } } // namespace boost #include <queue> #include <vector> #include <boost/graph/transpose_graph.hpp> #include <boost/pending/indirect_cmp.hpp> #include <boost/graph/connected_components.hpp> // for components_recorder namespace boost { //========================================================================== // This is the version of strongly connected components from // "Intro. to Algorithms" by Cormen, Leiserson, Rivest, which was // adapted from "Data Structure and Algorithms" by Aho, Hopcroft, // and Ullman, who credit the algorithm to S.R. Kosaraju and M. Sharir. // The algorithm is based on computing DFS forests the graph // and its transpose. // This algorithm is slower than Tarjan's by a constant factor, uses // more memory, and puts more requirements on the graph type. template < class Graph, class DFSVisitor, class ComponentsMap, class DiscoverTime, class FinishTime, class ColorMap > typename property_traits< ComponentsMap >::value_type kosaraju_strong_components( Graph& G, ComponentsMap c, FinishTime finish_time, ColorMap color) { BOOST_CONCEPT_ASSERT((MutableGraphConcept< Graph >)); // ... typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; typename property_traits< FinishTime >::value_type time = 0; depth_first_search(G, make_dfs_visitor(stamp_times(finish_time, time, on_finish_vertex())), color); Graph G_T(num_vertices(G)); transpose_graph(G, G_T); typedef typename property_traits< ComponentsMap >::value_type count_type; count_type c_count(0); detail::components_recorder< ComponentsMap > vis(c, c_count); // initialize G_T typename graph_traits< Graph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(G_T); ui != ui_end; ++ui) put(color, *ui, Color::white()); typedef typename property_traits< FinishTime >::value_type D; typedef indirect_cmp< FinishTime, std::less< D > > Compare; Compare fl(finish_time); std::priority_queue< Vertex, std::vector< Vertex >, Compare > Q(fl); typename graph_traits< Graph >::vertex_iterator i, j, iend, jend; boost::tie(i, iend) = vertices(G_T); boost::tie(j, jend) = vertices(G); for (; i != iend; ++i, ++j) { put(finish_time, *i, get(finish_time, *j)); Q.push(*i); } while (!Q.empty()) { Vertex u = Q.top(); Q.pop(); if (get(color, u) == Color::white()) { depth_first_visit(G_T, u, vis, color); ++c_count; } } return c_count; } } // namespace boost #include BOOST_GRAPH_MPI_INCLUDE(< boost / graph / distributed / strong_components.hpp >) #endif // BOOST_GRAPH_STRONG_COMPONENTS_HPP planar_detail/bucket_sort.hpp 0000644 00000006747 15125521275 0012423 0 ustar 00 //======================================================================= // Copyright 2007 Aaron Windsor // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef __BUCKET_SORT_HPP__ #define __BUCKET_SORT_HPP__ #include <vector> #include <algorithm> #include <boost/property_map/property_map.hpp> namespace boost { template < typename ItemToRankMap > struct rank_comparison { rank_comparison(ItemToRankMap arg_itrm) : itrm(arg_itrm) {} template < typename Item > bool operator()(Item x, Item y) const { return get(itrm, x) < get(itrm, y); } private: ItemToRankMap itrm; }; template < typename TupleType, int N, typename PropertyMapWrapper = identity_property_map > struct property_map_tuple_adaptor : public put_get_helper< typename PropertyMapWrapper::value_type, property_map_tuple_adaptor< TupleType, N, PropertyMapWrapper > > { typedef typename PropertyMapWrapper::reference reference; typedef typename PropertyMapWrapper::value_type value_type; typedef TupleType key_type; typedef readable_property_map_tag category; property_map_tuple_adaptor() {} property_map_tuple_adaptor(PropertyMapWrapper wrapper_map) : m_wrapper_map(wrapper_map) { } inline value_type operator[](const key_type& x) const { return get(m_wrapper_map, get< n >(x)); } static const int n = N; PropertyMapWrapper m_wrapper_map; }; // This function sorts a sequence of n items by their ranks in linear time, // given that all ranks are in the range [0, range). This sort is stable. template < typename ForwardIterator, typename ItemToRankMap, typename SizeType > void bucket_sort(ForwardIterator begin, ForwardIterator end, ItemToRankMap rank, SizeType range = 0) { #ifdef BOOST_GRAPH_PREFER_STD_LIB std::stable_sort(begin, end, rank_comparison< ItemToRankMap >(rank)); #else typedef std::vector< typename boost::property_traits< ItemToRankMap >::key_type > vector_of_values_t; typedef std::vector< vector_of_values_t > vector_of_vectors_t; if (!range) { rank_comparison< ItemToRankMap > cmp(rank); ForwardIterator max_by_rank = std::max_element(begin, end, cmp); if (max_by_rank == end) return; range = get(rank, *max_by_rank) + 1; } vector_of_vectors_t temp_values(range); for (ForwardIterator itr = begin; itr != end; ++itr) { temp_values[get(rank, *itr)].push_back(*itr); } ForwardIterator orig_seq_itr = begin; typename vector_of_vectors_t::iterator itr_end = temp_values.end(); for (typename vector_of_vectors_t::iterator itr = temp_values.begin(); itr != itr_end; ++itr) { typename vector_of_values_t::iterator jtr_end = itr->end(); for (typename vector_of_values_t::iterator jtr = itr->begin(); jtr != jtr_end; ++jtr) { *orig_seq_itr = *jtr; ++orig_seq_itr; } } #endif } template < typename ForwardIterator, typename ItemToRankMap > void bucket_sort(ForwardIterator begin, ForwardIterator end, ItemToRankMap rank) { bucket_sort(begin, end, rank, 0); } template < typename ForwardIterator > void bucket_sort(ForwardIterator begin, ForwardIterator end) { bucket_sort(begin, end, identity_property_map()); } } // namespace boost #endif //__BUCKET_SORT_HPP__ planar_detail/boyer_myrvold_impl.hpp 0000644 00000215612 15125521275 0014005 0 ustar 00 //======================================================================= // Copyright (c) Aaron Windsor 2007 // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef __BOYER_MYRVOLD_IMPL_HPP__ #define __BOYER_MYRVOLD_IMPL_HPP__ #include <vector> #include <list> #include <boost/next_prior.hpp> #include <boost/config.hpp> //for std::min macros #include <boost/shared_ptr.hpp> #include <boost/tuple/tuple.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/depth_first_search.hpp> #include <boost/graph/planar_detail/face_handles.hpp> #include <boost/graph/planar_detail/face_iterators.hpp> #include <boost/graph/planar_detail/bucket_sort.hpp> namespace boost { namespace detail { enum bm_case_t { BM_NO_CASE_CHOSEN, BM_CASE_A, BM_CASE_B, BM_CASE_C, BM_CASE_D, BM_CASE_E }; } template < typename LowPointMap, typename DFSParentMap, typename DFSNumberMap, typename LeastAncestorMap, typename DFSParentEdgeMap, typename SizeType > struct planar_dfs_visitor : public dfs_visitor<> { planar_dfs_visitor(LowPointMap lpm, DFSParentMap dfs_p, DFSNumberMap dfs_n, LeastAncestorMap lam, DFSParentEdgeMap dfs_edge) : low(lpm) , parent(dfs_p) , df_number(dfs_n) , least_ancestor(lam) , df_edge(dfs_edge) , count(0) { } template < typename Vertex, typename Graph > void start_vertex(const Vertex& u, Graph&) { put(parent, u, u); put(least_ancestor, u, count); } template < typename Vertex, typename Graph > void discover_vertex(const Vertex& u, Graph&) { put(low, u, count); put(df_number, u, count); ++count; } template < typename Edge, typename Graph > void tree_edge(const Edge& e, Graph& g) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; vertex_t s(source(e, g)); vertex_t t(target(e, g)); put(parent, t, s); put(df_edge, t, e); put(least_ancestor, t, get(df_number, s)); } template < typename Edge, typename Graph > void back_edge(const Edge& e, Graph& g) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::vertices_size_type v_size_t; vertex_t s(source(e, g)); vertex_t t(target(e, g)); BOOST_USING_STD_MIN(); if (t != get(parent, s)) { v_size_t s_low_df_number = get(low, s); v_size_t t_df_number = get(df_number, t); v_size_t s_least_ancestor_df_number = get(least_ancestor, s); put(low, s, min BOOST_PREVENT_MACRO_SUBSTITUTION( s_low_df_number, t_df_number)); put(least_ancestor, s, min BOOST_PREVENT_MACRO_SUBSTITUTION( s_least_ancestor_df_number, t_df_number)); } } template < typename Vertex, typename Graph > void finish_vertex(const Vertex& u, Graph&) { typedef typename graph_traits< Graph >::vertices_size_type v_size_t; Vertex u_parent = get(parent, u); v_size_t u_parent_lowpoint = get(low, u_parent); v_size_t u_lowpoint = get(low, u); BOOST_USING_STD_MIN(); if (u_parent != u) { put(low, u_parent, min BOOST_PREVENT_MACRO_SUBSTITUTION( u_lowpoint, u_parent_lowpoint)); } } LowPointMap low; DFSParentMap parent; DFSNumberMap df_number; LeastAncestorMap least_ancestor; DFSParentEdgeMap df_edge; SizeType count; }; template < typename Graph, typename VertexIndexMap, typename StoreOldHandlesPolicy = graph::detail::store_old_handles, typename StoreEmbeddingPolicy = graph::detail::recursive_lazy_list > class boyer_myrvold_impl { typedef typename graph_traits< Graph >::vertices_size_type v_size_t; typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::edge_descriptor edge_t; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; typedef typename graph_traits< Graph >::edge_iterator edge_iterator_t; typedef typename graph_traits< Graph >::out_edge_iterator out_edge_iterator_t; typedef graph::detail::face_handle< Graph, StoreOldHandlesPolicy, StoreEmbeddingPolicy > face_handle_t; typedef std::vector< vertex_t > vertex_vector_t; typedef std::vector< edge_t > edge_vector_t; typedef std::list< vertex_t > vertex_list_t; typedef std::list< face_handle_t > face_handle_list_t; typedef boost::shared_ptr< face_handle_list_t > face_handle_list_ptr_t; typedef boost::shared_ptr< vertex_list_t > vertex_list_ptr_t; typedef boost::tuple< vertex_t, bool, bool > merge_stack_frame_t; typedef std::vector< merge_stack_frame_t > merge_stack_t; template < typename T > struct map_vertex_to_ { typedef iterator_property_map< typename std::vector< T >::iterator, VertexIndexMap > type; }; typedef typename map_vertex_to_< v_size_t >::type vertex_to_v_size_map_t; typedef typename map_vertex_to_< vertex_t >::type vertex_to_vertex_map_t; typedef typename map_vertex_to_< edge_t >::type vertex_to_edge_map_t; typedef typename map_vertex_to_< vertex_list_ptr_t >::type vertex_to_vertex_list_ptr_map_t; typedef typename map_vertex_to_< edge_vector_t >::type vertex_to_edge_vector_map_t; typedef typename map_vertex_to_< bool >::type vertex_to_bool_map_t; typedef typename map_vertex_to_< face_handle_t >::type vertex_to_face_handle_map_t; typedef typename map_vertex_to_< face_handle_list_ptr_t >::type vertex_to_face_handle_list_ptr_map_t; typedef typename map_vertex_to_< typename vertex_list_t::iterator >::type vertex_to_separated_node_map_t; template < typename BicompSideToTraverse = single_side, typename VisitorType = lead_visitor, typename Time = current_iteration > struct face_vertex_iterator { typedef face_iterator< Graph, vertex_to_face_handle_map_t, vertex_t, BicompSideToTraverse, VisitorType, Time > type; }; template < typename BicompSideToTraverse = single_side, typename Time = current_iteration > struct face_edge_iterator { typedef face_iterator< Graph, vertex_to_face_handle_map_t, edge_t, BicompSideToTraverse, lead_visitor, Time > type; }; public: boyer_myrvold_impl(const Graph& arg_g, VertexIndexMap arg_vm) : g(arg_g) , vm(arg_vm) , low_point_vector(num_vertices(g)) , dfs_parent_vector(num_vertices(g)) , dfs_number_vector(num_vertices(g)) , least_ancestor_vector(num_vertices(g)) , pertinent_roots_vector(num_vertices(g)) , backedge_flag_vector(num_vertices(g), num_vertices(g) + 1) , visited_vector(num_vertices(g), num_vertices(g) + 1) , face_handles_vector(num_vertices(g)) , dfs_child_handles_vector(num_vertices(g)) , separated_dfs_child_list_vector(num_vertices(g)) , separated_node_in_parent_list_vector(num_vertices(g)) , canonical_dfs_child_vector(num_vertices(g)) , flipped_vector(num_vertices(g), false) , backedges_vector(num_vertices(g)) , dfs_parent_edge_vector(num_vertices(g)) , vertices_by_dfs_num(num_vertices(g)) , low_point(low_point_vector.begin(), vm) , dfs_parent(dfs_parent_vector.begin(), vm) , dfs_number(dfs_number_vector.begin(), vm) , least_ancestor(least_ancestor_vector.begin(), vm) , pertinent_roots(pertinent_roots_vector.begin(), vm) , backedge_flag(backedge_flag_vector.begin(), vm) , visited(visited_vector.begin(), vm) , face_handles(face_handles_vector.begin(), vm) , dfs_child_handles(dfs_child_handles_vector.begin(), vm) , separated_dfs_child_list(separated_dfs_child_list_vector.begin(), vm) , separated_node_in_parent_list( separated_node_in_parent_list_vector.begin(), vm) , canonical_dfs_child(canonical_dfs_child_vector.begin(), vm) , flipped(flipped_vector.begin(), vm) , backedges(backedges_vector.begin(), vm) , dfs_parent_edge(dfs_parent_edge_vector.begin(), vm) { planar_dfs_visitor< vertex_to_v_size_map_t, vertex_to_vertex_map_t, vertex_to_v_size_map_t, vertex_to_v_size_map_t, vertex_to_edge_map_t, v_size_t > vis(low_point, dfs_parent, dfs_number, least_ancestor, dfs_parent_edge); // Perform a depth-first search to find each vertex's low point, least // ancestor, and dfs tree information depth_first_search(g, visitor(vis).vertex_index_map(vm)); // Sort vertices by their lowpoint - need this later in the constructor vertex_vector_t vertices_by_lowpoint(num_vertices(g)); std::copy(vertices(g).first, vertices(g).second, vertices_by_lowpoint.begin()); bucket_sort(vertices_by_lowpoint.begin(), vertices_by_lowpoint.end(), low_point, num_vertices(g)); // Sort vertices by their dfs number - need this to iterate by reverse // DFS number in the main loop. std::copy( vertices(g).first, vertices(g).second, vertices_by_dfs_num.begin()); bucket_sort(vertices_by_dfs_num.begin(), vertices_by_dfs_num.end(), dfs_number, num_vertices(g)); // Initialize face handles. A face handle is an abstraction that serves // two uses in our implementation - it allows us to efficiently move // along the outer face of embedded bicomps in a partially embedded // graph, and it provides storage for the planar embedding. Face // handles are implemented by a sequence of edges and are associated // with a particular vertex - the sequence of edges represents the // current embedding of edges around that vertex, and the first and // last edges in the sequence represent the pair of edges on the outer // face that are adjacent to the associated vertex. This lets us embed // edges in the graph by just pushing them on the front or back of the // sequence of edges held by the face handles. // // Our algorithm starts with a DFS tree of edges (where every vertex is // an articulation point and every edge is a singleton bicomp) and // repeatedly merges bicomps by embedding additional edges. Note that // any bicomp at any point in the algorithm can be associated with a // unique edge connecting the vertex of that bicomp with the lowest DFS // number (which we refer to as the "root" of the bicomp) with its DFS // child in the bicomp: the existence of two such edges would contradict // the properties of a DFS tree. We refer to the DFS child of the root // of a bicomp as the "canonical DFS child" of the bicomp. Note that a // vertex can be the root of more than one bicomp. // // We move around the external faces of a bicomp using a few property // maps, which we'll initialize presently: // // - face_handles: maps a vertex to a face handle that can be used to // move "up" a bicomp. For a vertex that isn't an articulation point, // this holds the face handles that can be used to move around that // vertex's unique bicomp. For a vertex that is an articulation point, // this holds the face handles associated with the unique bicomp that // the vertex is NOT the root of. These handles can therefore be used // to move from any point on the outer face of the tree of bicomps // around the current outer face towards the root of the DFS tree. // // - dfs_child_handles: these are used to hold face handles for // vertices that are articulation points - dfs_child_handles[v] holds // the face handles corresponding to vertex u in the bicomp with root // u and canonical DFS child v. // // - canonical_dfs_child: this property map allows one to determine the // canonical DFS child of a bicomp while traversing the outer face. // This property map is only valid when applied to one of the two // vertices adjacent to the root of the bicomp on the outer face. To // be more precise, if v is the canonical DFS child of a bicomp, // canonical_dfs_child[dfs_child_handles[v].first_vertex()] == v and // canonical_dfs_child[dfs_child_handles[v].second_vertex()] == v. // // - pertinent_roots: given a vertex v, pertinent_roots[v] contains a // list of face handles pointing to the top of bicomps that need to // be visited by the current walkdown traversal (since they lead to // backedges that need to be embedded). These lists are populated by // the walkup and consumed by the walkdown. vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { vertex_t v(*vi); vertex_t parent = dfs_parent[v]; if (parent != v) { edge_t parent_edge = dfs_parent_edge[v]; add_to_embedded_edges(parent_edge, StoreOldHandlesPolicy()); face_handles[v] = face_handle_t(v, parent_edge, g); dfs_child_handles[v] = face_handle_t(parent, parent_edge, g); } else { face_handles[v] = face_handle_t(v); dfs_child_handles[v] = face_handle_t(parent); } canonical_dfs_child[v] = v; pertinent_roots[v] = face_handle_list_ptr_t(new face_handle_list_t); separated_dfs_child_list[v] = vertex_list_ptr_t(new vertex_list_t); } // We need to create a list of not-yet-merged depth-first children for // each vertex that will be updated as bicomps get merged. We sort each // list by ascending lowpoint, which allows the externally_active // function to run in constant time, and we keep a pointer to each // vertex's representation in its parent's list, which allows merging // in constant time. for (typename vertex_vector_t::iterator itr = vertices_by_lowpoint.begin(); itr != vertices_by_lowpoint.end(); ++itr) { vertex_t v(*itr); vertex_t parent(dfs_parent[v]); if (v != parent) { separated_node_in_parent_list[v] = separated_dfs_child_list[parent]->insert( separated_dfs_child_list[parent]->end(), v); } } // The merge stack holds path information during a walkdown iteration merge_stack.reserve(num_vertices(g)); } bool is_planar() { // This is the main algorithm: starting with a DFS tree of embedded // edges (which, since it's a tree, is planar), iterate through all // vertices by reverse DFS number, attempting to embed all backedges // connecting the current vertex to vertices with higher DFS numbers. // // The walkup is a procedure that examines all such backedges and sets // up the required data structures so that they can be searched by the // walkdown in linear time. The walkdown does the actual work of // embedding edges and flipping bicomps, and can identify when it has // come across a kuratowski subgraph. // // store_old_face_handles caches face handles from the previous // iteration - this is used only for the kuratowski subgraph isolation, // and is therefore dispatched based on the StoreOldHandlesPolicy. // // clean_up_embedding does some clean-up and fills in values that have // to be computed lazily during the actual execution of the algorithm // (for instance, whether or not a bicomp is flipped in the final // embedding). It's dispatched on the the StoreEmbeddingPolicy, since // it's not needed if an embedding isn't desired. typename vertex_vector_t::reverse_iterator vi, vi_end; vi_end = vertices_by_dfs_num.rend(); for (vi = vertices_by_dfs_num.rbegin(); vi != vi_end; ++vi) { store_old_face_handles(StoreOldHandlesPolicy()); vertex_t v(*vi); walkup(v); if (!walkdown(v)) return false; } clean_up_embedding(StoreEmbeddingPolicy()); return true; } private: void walkup(vertex_t v) { // The point of the walkup is to follow all backedges from v to // vertices with higher DFS numbers, and update pertinent_roots // for the bicomp roots on the path from backedge endpoints up // to v. This will set the stage for the walkdown to efficiently // traverse the graph of bicomps down from v. typedef typename face_vertex_iterator< both_sides >::type walkup_iterator_t; out_edge_iterator_t oi, oi_end; for (boost::tie(oi, oi_end) = out_edges(v, g); oi != oi_end; ++oi) { edge_t e(*oi); vertex_t e_source(source(e, g)); vertex_t e_target(target(e, g)); if (e_source == e_target) { self_loops.push_back(e); continue; } vertex_t w(e_source == v ? e_target : e_source); // continue if not a back edge or already embedded if (dfs_number[w] < dfs_number[v] || e == dfs_parent_edge[w]) continue; backedges[w].push_back(e); v_size_t timestamp = dfs_number[v]; backedge_flag[w] = timestamp; walkup_iterator_t walkup_itr(w, face_handles); walkup_iterator_t walkup_end; vertex_t lead_vertex = w; while (true) { // Move to the root of the current bicomp or the first visited // vertex on the bicomp by going up each side in parallel while (walkup_itr != walkup_end && visited[*walkup_itr] != timestamp) { lead_vertex = *walkup_itr; visited[lead_vertex] = timestamp; ++walkup_itr; } // If we've found the root of a bicomp through a path we haven't // seen before, update pertinent_roots with a handle to the // current bicomp. Otherwise, we've just seen a path we've been // up before, so break out of the main while loop. if (walkup_itr == walkup_end) { vertex_t dfs_child = canonical_dfs_child[lead_vertex]; vertex_t parent = dfs_parent[dfs_child]; visited[dfs_child_handles[dfs_child].first_vertex()] = timestamp; visited[dfs_child_handles[dfs_child].second_vertex()] = timestamp; if (low_point[dfs_child] < dfs_number[v] || least_ancestor[dfs_child] < dfs_number[v]) { pertinent_roots[parent]->push_back( dfs_child_handles[dfs_child]); } else { pertinent_roots[parent]->push_front( dfs_child_handles[dfs_child]); } if (parent != v && visited[parent] != timestamp) { walkup_itr = walkup_iterator_t(parent, face_handles); lead_vertex = parent; } else break; } else break; } } } bool walkdown(vertex_t v) { // This procedure is where all of the action is - pertinent_roots // has already been set up by the walkup, so we just need to move // down bicomps from v until we find vertices that have been // labeled as backedge endpoints. Once we find such a vertex, we // embed the corresponding edge and glue together the bicomps on // the path connecting the two vertices in the edge. This may // involve flipping bicomps along the way. vertex_t w; // the other endpoint of the edge we're embedding while (!pertinent_roots[v]->empty()) { face_handle_t root_face_handle = pertinent_roots[v]->front(); face_handle_t curr_face_handle = root_face_handle; pertinent_roots[v]->pop_front(); merge_stack.clear(); while (true) { typename face_vertex_iterator<>::type first_face_itr, second_face_itr, face_end; vertex_t first_side_vertex = graph_traits< Graph >::null_vertex(); vertex_t second_side_vertex = graph_traits< Graph >::null_vertex(); vertex_t first_tail, second_tail; first_tail = second_tail = curr_face_handle.get_anchor(); first_face_itr = typename face_vertex_iterator<>::type( curr_face_handle, face_handles, first_side()); second_face_itr = typename face_vertex_iterator<>::type( curr_face_handle, face_handles, second_side()); for (; first_face_itr != face_end; ++first_face_itr) { vertex_t face_vertex(*first_face_itr); if (pertinent(face_vertex, v) || externally_active(face_vertex, v)) { first_side_vertex = face_vertex; second_side_vertex = face_vertex; break; } first_tail = face_vertex; } if (first_side_vertex == graph_traits< Graph >::null_vertex() || first_side_vertex == curr_face_handle.get_anchor()) break; for (; second_face_itr != face_end; ++second_face_itr) { vertex_t face_vertex(*second_face_itr); if (pertinent(face_vertex, v) || externally_active(face_vertex, v)) { second_side_vertex = face_vertex; break; } second_tail = face_vertex; } vertex_t chosen; bool chose_first_upper_path; if (internally_active(first_side_vertex, v)) { chosen = first_side_vertex; chose_first_upper_path = true; } else if (internally_active(second_side_vertex, v)) { chosen = second_side_vertex; chose_first_upper_path = false; } else if (pertinent(first_side_vertex, v)) { chosen = first_side_vertex; chose_first_upper_path = true; } else if (pertinent(second_side_vertex, v)) { chosen = second_side_vertex; chose_first_upper_path = false; } else { // If there's a pertinent vertex on the lower face // between the first_face_itr and the second_face_itr, // this graph isn't planar. for (; *first_face_itr != second_side_vertex; ++first_face_itr) { vertex_t p(*first_face_itr); if (pertinent(p, v)) { // Found a Kuratowski subgraph kuratowski_v = v; kuratowski_x = first_side_vertex; kuratowski_y = second_side_vertex; return false; } } // Otherwise, the fact that we didn't find a pertinent // vertex on this face is fine - we should set the // short-circuit edges and break out of this loop to // start looking at a different pertinent root. if (first_side_vertex == second_side_vertex) { if (first_tail != v) { vertex_t first = face_handles[first_tail].first_vertex(); vertex_t second = face_handles[first_tail].second_vertex(); boost::tie(first_side_vertex, first_tail) = make_tuple(first_tail, first == first_side_vertex ? second : first); } else if (second_tail != v) { vertex_t first = face_handles[second_tail].first_vertex(); vertex_t second = face_handles[second_tail].second_vertex(); boost::tie(second_side_vertex, second_tail) = make_tuple(second_tail, first == second_side_vertex ? second : first); } else break; } canonical_dfs_child[first_side_vertex] = canonical_dfs_child[root_face_handle.first_vertex()]; canonical_dfs_child[second_side_vertex] = canonical_dfs_child[root_face_handle.second_vertex()]; root_face_handle.set_first_vertex(first_side_vertex); root_face_handle.set_second_vertex(second_side_vertex); if (face_handles[first_side_vertex].first_vertex() == first_tail) face_handles[first_side_vertex].set_first_vertex(v); else face_handles[first_side_vertex].set_second_vertex(v); if (face_handles[second_side_vertex].first_vertex() == second_tail) face_handles[second_side_vertex].set_first_vertex(v); else face_handles[second_side_vertex].set_second_vertex(v); break; } // When we unwind the stack, we need to know which direction // we came down from on the top face handle bool chose_first_lower_path = (chose_first_upper_path && face_handles[chosen].first_vertex() == first_tail) || (!chose_first_upper_path && face_handles[chosen].first_vertex() == second_tail); // If there's a backedge at the chosen vertex, embed it now if (backedge_flag[chosen] == dfs_number[v]) { w = chosen; backedge_flag[chosen] = num_vertices(g) + 1; add_to_merge_points(chosen, StoreOldHandlesPolicy()); typename edge_vector_t::iterator ei, ei_end; ei_end = backedges[chosen].end(); for (ei = backedges[chosen].begin(); ei != ei_end; ++ei) { edge_t e(*ei); add_to_embedded_edges(e, StoreOldHandlesPolicy()); if (chose_first_lower_path) face_handles[chosen].push_first(e, g); else face_handles[chosen].push_second(e, g); } } else { merge_stack.push_back(make_tuple(chosen, chose_first_upper_path, chose_first_lower_path)); curr_face_handle = *pertinent_roots[chosen]->begin(); continue; } // Unwind the merge stack to the root, merging all bicomps bool bottom_path_follows_first; bool top_path_follows_first; bool next_bottom_follows_first = chose_first_upper_path; vertex_t merge_point = chosen; while (!merge_stack.empty()) { bottom_path_follows_first = next_bottom_follows_first; boost::tie(merge_point, next_bottom_follows_first, top_path_follows_first) = merge_stack.back(); merge_stack.pop_back(); face_handle_t top_handle(face_handles[merge_point]); face_handle_t bottom_handle( *pertinent_roots[merge_point]->begin()); vertex_t bottom_dfs_child = canonical_dfs_child [pertinent_roots[merge_point]->begin()->first_vertex()]; remove_vertex_from_separated_dfs_child_list( canonical_dfs_child[pertinent_roots[merge_point] ->begin() ->first_vertex()]); pertinent_roots[merge_point]->pop_front(); add_to_merge_points( top_handle.get_anchor(), StoreOldHandlesPolicy()); if (top_path_follows_first && bottom_path_follows_first) { bottom_handle.flip(); top_handle.glue_first_to_second(bottom_handle); } else if (!top_path_follows_first && bottom_path_follows_first) { flipped[bottom_dfs_child] = true; top_handle.glue_second_to_first(bottom_handle); } else if (top_path_follows_first && !bottom_path_follows_first) { flipped[bottom_dfs_child] = true; top_handle.glue_first_to_second(bottom_handle); } else //! top_path_follows_first && //! !bottom_path_follows_first { bottom_handle.flip(); top_handle.glue_second_to_first(bottom_handle); } } // Finally, embed all edges (v,w) at their upper end points canonical_dfs_child[w] = canonical_dfs_child[root_face_handle.first_vertex()]; add_to_merge_points( root_face_handle.get_anchor(), StoreOldHandlesPolicy()); typename edge_vector_t::iterator ei, ei_end; ei_end = backedges[chosen].end(); for (ei = backedges[chosen].begin(); ei != ei_end; ++ei) { if (next_bottom_follows_first) root_face_handle.push_first(*ei, g); else root_face_handle.push_second(*ei, g); } backedges[chosen].clear(); curr_face_handle = root_face_handle; } // while(true) } // while(!pertinent_roots[v]->empty()) return true; } void store_old_face_handles(graph::detail::no_old_handles) {} void store_old_face_handles(graph::detail::store_old_handles) { for (typename std::vector< vertex_t >::iterator mp_itr = current_merge_points.begin(); mp_itr != current_merge_points.end(); ++mp_itr) { face_handles[*mp_itr].store_old_face_handles(); } current_merge_points.clear(); } void add_to_merge_points(vertex_t, graph::detail::no_old_handles) {} void add_to_merge_points(vertex_t v, graph::detail::store_old_handles) { current_merge_points.push_back(v); } void add_to_embedded_edges(edge_t, graph::detail::no_old_handles) {} void add_to_embedded_edges(edge_t e, graph::detail::store_old_handles) { embedded_edges.push_back(e); } void clean_up_embedding(graph::detail::no_embedding) {} void clean_up_embedding(graph::detail::store_embedding) { // If the graph isn't biconnected, we'll still have entries // in the separated_dfs_child_list for some vertices. Since // these represent articulation points, we can obtain a // planar embedding no matter what order we embed them in. vertex_iterator_t xi, xi_end; for (boost::tie(xi, xi_end) = vertices(g); xi != xi_end; ++xi) { if (!separated_dfs_child_list[*xi]->empty()) { typename vertex_list_t::iterator yi, yi_end; yi_end = separated_dfs_child_list[*xi]->end(); for (yi = separated_dfs_child_list[*xi]->begin(); yi != yi_end; ++yi) { dfs_child_handles[*yi].flip(); face_handles[*xi].glue_first_to_second( dfs_child_handles[*yi]); } } } // Up until this point, we've flipped bicomps lazily by setting // flipped[v] to true if the bicomp rooted at v was flipped (the // lazy aspect of this flip is that all descendents of that vertex // need to have their orientations reversed as well). Now, we // traverse the DFS tree by DFS number and perform the actual // flipping as needed typedef typename vertex_vector_t::iterator vertex_vector_itr_t; vertex_vector_itr_t vi_end = vertices_by_dfs_num.end(); for (vertex_vector_itr_t vi = vertices_by_dfs_num.begin(); vi != vi_end; ++vi) { vertex_t v(*vi); bool v_flipped = flipped[v]; bool p_flipped = flipped[dfs_parent[v]]; if (v_flipped && !p_flipped) { face_handles[v].flip(); } else if (p_flipped && !v_flipped) { face_handles[v].flip(); flipped[v] = true; } else { flipped[v] = false; } } // If there are any self-loops in the graph, they were flagged // during the walkup, and we should add them to the embedding now. // Adding a self loop anywhere in the embedding could never // invalidate the embedding, but they would complicate the traversal // if they were added during the walkup/walkdown. typename edge_vector_t::iterator ei, ei_end; ei_end = self_loops.end(); for (ei = self_loops.begin(); ei != ei_end; ++ei) { edge_t e(*ei); face_handles[source(e, g)].push_second(e, g); } } bool pertinent(vertex_t w, vertex_t v) { // w is pertinent with respect to v if there is a backedge (v,w) or if // w is the root of a bicomp that contains a pertinent vertex. return backedge_flag[w] == dfs_number[v] || !pertinent_roots[w]->empty(); } bool externally_active(vertex_t w, vertex_t v) { // Let a be any proper depth-first search ancestor of v. w is externally // active with respect to v if there exists a backedge (a,w) or a // backedge (a,w_0) for some w_0 in a descendent bicomp of w. v_size_t dfs_number_of_v = dfs_number[v]; return (least_ancestor[w] < dfs_number_of_v) || (!separated_dfs_child_list[w]->empty() && low_point[separated_dfs_child_list[w]->front()] < dfs_number_of_v); } bool internally_active(vertex_t w, vertex_t v) { return pertinent(w, v) && !externally_active(w, v); } void remove_vertex_from_separated_dfs_child_list(vertex_t v) { typename vertex_list_t::iterator to_delete = separated_node_in_parent_list[v]; garbage.splice(garbage.end(), *separated_dfs_child_list[dfs_parent[v]], to_delete, boost::next(to_delete)); } // End of the implementation of the basic Boyer-Myrvold Algorithm. The rest // of the code below implements the isolation of a Kuratowski subgraph in // the case that the input graph is not planar. This is by far the most // complicated part of the implementation. public: template < typename EdgeToBoolPropertyMap, typename EdgeContainer > vertex_t kuratowski_walkup(vertex_t v, EdgeToBoolPropertyMap forbidden_edge, EdgeToBoolPropertyMap goal_edge, EdgeToBoolPropertyMap is_embedded, EdgeContainer& path_edges) { vertex_t current_endpoint; bool seen_goal_edge = false; out_edge_iterator_t oi, oi_end; for (boost::tie(oi, oi_end) = out_edges(v, g); oi != oi_end; ++oi) forbidden_edge[*oi] = true; for (boost::tie(oi, oi_end) = out_edges(v, g); oi != oi_end; ++oi) { path_edges.clear(); edge_t e(*oi); current_endpoint = target(*oi, g) == v ? source(*oi, g) : target(*oi, g); if (dfs_number[current_endpoint] < dfs_number[v] || is_embedded[e] || v == current_endpoint // self-loop ) { // Not a backedge continue; } path_edges.push_back(e); if (goal_edge[e]) { return current_endpoint; } typedef typename face_edge_iterator<>::type walkup_itr_t; walkup_itr_t walkup_itr( current_endpoint, face_handles, first_side()); walkup_itr_t walkup_end; seen_goal_edge = false; while (true) { if (walkup_itr != walkup_end && forbidden_edge[*walkup_itr]) break; while (walkup_itr != walkup_end && !goal_edge[*walkup_itr] && !forbidden_edge[*walkup_itr]) { edge_t f(*walkup_itr); forbidden_edge[f] = true; path_edges.push_back(f); current_endpoint = source(f, g) == current_endpoint ? target(f, g) : source(f, g); ++walkup_itr; } if (walkup_itr != walkup_end && goal_edge[*walkup_itr]) { path_edges.push_back(*walkup_itr); seen_goal_edge = true; break; } walkup_itr = walkup_itr_t( current_endpoint, face_handles, first_side()); } if (seen_goal_edge) break; } if (seen_goal_edge) return current_endpoint; else return graph_traits< Graph >::null_vertex(); } template < typename OutputIterator, typename EdgeIndexMap > void extract_kuratowski_subgraph(OutputIterator o_itr, EdgeIndexMap em) { // If the main algorithm has failed to embed one of the back-edges from // a vertex v, we can use the current state of the algorithm to isolate // a Kuratowksi subgraph. The isolation process breaks down into five // cases, A - E. The general configuration of all five cases is shown in // figure 1. There is a vertex v from which the planar // v embedding process could not proceed. This means that // | there exists some bicomp containing three vertices // ----- x,y, and z as shown such that x and y are externally // | | active with respect to v (which means that there are // x y two vertices x_0 and y_0 such that (1) both x_0 and // | | y_0 are proper depth-first search ancestors of v and // --z-- (2) there are two disjoint paths, one connecting x // and x_0 and one connecting y and y_0, both // consisting // fig. 1 entirely of unembedded edges). Furthermore, there // exists a vertex z_0 such that z is a depth-first // search ancestor of z_0 and (v,z_0) is an unembedded back-edge from v. // x,y and z all exist on the same bicomp, which consists entirely of // embedded edges. The five subcases break down as follows, and are // handled by the algorithm logically in the order A-E: First, if v is // not on the same bicomp as x,y, and z, a K_3_3 can be isolated - this // is case A. So, we'll assume that v is on the same bicomp as x,y, and // z. If z_0 is on a different bicomp than x,y, and z, a K_3_3 can also // be isolated - this is a case B - so we'll assume from now on that v // is on the same bicomp as x, y, and z=z_0. In this case, one can use // properties of the Boyer-Myrvold algorithm to show the existence of an // "x-y path" connecting some vertex on the "left side" of the x,y,z // bicomp with some vertex on the "right side" of the bicomp (where the // left and right are split by a line drawn through v and z.If either of // the endpoints of the x-y path is above x or y on the bicomp, a K_3_3 // can be isolated - this is a case C. Otherwise, both endpoints are at // or below x and y on the bicomp. If there is a vertex alpha on the x-y // path such that alpha is not x or y and there's a path from alpha to v // that's disjoint from any of the edges on the bicomp and the x-y path, // a K_3_3 can be isolated - this is a case D. Otherwise, properties of // the Boyer-Myrvold algorithm can be used to show that another vertex // w exists on the lower half of the bicomp such that w is externally // active with respect to v. w can then be used to isolate a K_5 - this // is the configuration of case E. vertex_iterator_t vi, vi_end; edge_iterator_t ei, ei_end; out_edge_iterator_t oei, oei_end; typename std::vector< edge_t >::iterator xi, xi_end; // Clear the short-circuit edges - these are needed for the planar // testing/embedding algorithm to run in linear time, but they'll // complicate the kuratowski subgraph isolation for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { face_handles[*vi].reset_vertex_cache(); dfs_child_handles[*vi].reset_vertex_cache(); } vertex_t v = kuratowski_v; vertex_t x = kuratowski_x; vertex_t y = kuratowski_y; typedef iterator_property_map< typename std::vector< bool >::iterator, EdgeIndexMap > edge_to_bool_map_t; std::vector< bool > is_in_subgraph_vector(num_edges(g), false); edge_to_bool_map_t is_in_subgraph(is_in_subgraph_vector.begin(), em); std::vector< bool > is_embedded_vector(num_edges(g), false); edge_to_bool_map_t is_embedded(is_embedded_vector.begin(), em); typename std::vector< edge_t >::iterator embedded_itr, embedded_end; embedded_end = embedded_edges.end(); for (embedded_itr = embedded_edges.begin(); embedded_itr != embedded_end; ++embedded_itr) is_embedded[*embedded_itr] = true; // upper_face_vertex is true for x,y, and all vertices above x and y in // the bicomp std::vector< bool > upper_face_vertex_vector(num_vertices(g), false); vertex_to_bool_map_t upper_face_vertex( upper_face_vertex_vector.begin(), vm); std::vector< bool > lower_face_vertex_vector(num_vertices(g), false); vertex_to_bool_map_t lower_face_vertex( lower_face_vertex_vector.begin(), vm); // These next few variable declarations are all things that we need // to find. vertex_t z = graph_traits< Graph >::null_vertex(); vertex_t bicomp_root; vertex_t w = graph_traits< Graph >::null_vertex(); face_handle_t w_handle; face_handle_t v_dfchild_handle; vertex_t first_x_y_path_endpoint = graph_traits< Graph >::null_vertex(); vertex_t second_x_y_path_endpoint = graph_traits< Graph >::null_vertex(); vertex_t w_ancestor = v; detail::bm_case_t chosen_case = detail::BM_NO_CASE_CHOSEN; std::vector< edge_t > x_external_path; std::vector< edge_t > y_external_path; std::vector< edge_t > case_d_edges; std::vector< edge_t > z_v_path; std::vector< edge_t > w_path; // first, use a walkup to find a path from V that starts with a // backedge from V, then goes up until it hits either X or Y //(but doesn't find X or Y as the root of a bicomp) typename face_vertex_iterator<>::type x_upper_itr( x, face_handles, first_side()); typename face_vertex_iterator<>::type x_lower_itr( x, face_handles, second_side()); typename face_vertex_iterator<>::type face_itr, face_end; // Don't know which path from x is the upper or lower path - // we'll find out here for (face_itr = x_upper_itr; face_itr != face_end; ++face_itr) { if (*face_itr == y) { std::swap(x_upper_itr, x_lower_itr); break; } } upper_face_vertex[x] = true; vertex_t current_vertex = x; vertex_t previous_vertex; for (face_itr = x_upper_itr; face_itr != face_end; ++face_itr) { previous_vertex = current_vertex; current_vertex = *face_itr; upper_face_vertex[current_vertex] = true; } v_dfchild_handle = dfs_child_handles[canonical_dfs_child[previous_vertex]]; for (face_itr = x_lower_itr; *face_itr != y; ++face_itr) { vertex_t current_vertex(*face_itr); lower_face_vertex[current_vertex] = true; typename face_handle_list_t::iterator roots_itr, roots_end; if (w == graph_traits< Graph >::null_vertex()) // haven't found a w // yet { roots_end = pertinent_roots[current_vertex]->end(); for (roots_itr = pertinent_roots[current_vertex]->begin(); roots_itr != roots_end; ++roots_itr) { if (low_point [canonical_dfs_child[roots_itr->first_vertex()]] < dfs_number[v]) { w = current_vertex; w_handle = *roots_itr; break; } } } } for (; face_itr != face_end; ++face_itr) { vertex_t current_vertex(*face_itr); upper_face_vertex[current_vertex] = true; bicomp_root = current_vertex; } typedef typename face_edge_iterator<>::type walkup_itr_t; std::vector< bool > outer_face_edge_vector(num_edges(g), false); edge_to_bool_map_t outer_face_edge(outer_face_edge_vector.begin(), em); walkup_itr_t walkup_end; for (walkup_itr_t walkup_itr(x, face_handles, first_side()); walkup_itr != walkup_end; ++walkup_itr) { outer_face_edge[*walkup_itr] = true; is_in_subgraph[*walkup_itr] = true; } for (walkup_itr_t walkup_itr(x, face_handles, second_side()); walkup_itr != walkup_end; ++walkup_itr) { outer_face_edge[*walkup_itr] = true; is_in_subgraph[*walkup_itr] = true; } std::vector< bool > forbidden_edge_vector(num_edges(g), false); edge_to_bool_map_t forbidden_edge(forbidden_edge_vector.begin(), em); std::vector< bool > goal_edge_vector(num_edges(g), false); edge_to_bool_map_t goal_edge(goal_edge_vector.begin(), em); // Find external path to x and to y for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) { edge_t e(*ei); goal_edge[e] = !outer_face_edge[e] && (source(e, g) == x || target(e, g) == x); forbidden_edge[*ei] = outer_face_edge[*ei]; } vertex_t x_ancestor = v; vertex_t x_endpoint = graph_traits< Graph >::null_vertex(); while (x_endpoint == graph_traits< Graph >::null_vertex()) { x_ancestor = dfs_parent[x_ancestor]; x_endpoint = kuratowski_walkup(x_ancestor, forbidden_edge, goal_edge, is_embedded, x_external_path); } for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) { edge_t e(*ei); goal_edge[e] = !outer_face_edge[e] && (source(e, g) == y || target(e, g) == y); forbidden_edge[*ei] = outer_face_edge[*ei]; } vertex_t y_ancestor = v; vertex_t y_endpoint = graph_traits< Graph >::null_vertex(); while (y_endpoint == graph_traits< Graph >::null_vertex()) { y_ancestor = dfs_parent[y_ancestor]; y_endpoint = kuratowski_walkup(y_ancestor, forbidden_edge, goal_edge, is_embedded, y_external_path); } vertex_t parent, child; // If v isn't on the same bicomp as x and y, it's a case A if (bicomp_root != v) { chosen_case = detail::BM_CASE_A; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) if (lower_face_vertex[*vi]) for (boost::tie(oei, oei_end) = out_edges(*vi, g); oei != oei_end; ++oei) if (!outer_face_edge[*oei]) goal_edge[*oei] = true; for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) forbidden_edge[*ei] = outer_face_edge[*ei]; z = kuratowski_walkup( v, forbidden_edge, goal_edge, is_embedded, z_v_path); } else if (w != graph_traits< Graph >::null_vertex()) { chosen_case = detail::BM_CASE_B; for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) { edge_t e(*ei); goal_edge[e] = false; forbidden_edge[e] = outer_face_edge[e]; } goal_edge[w_handle.first_edge()] = true; goal_edge[w_handle.second_edge()] = true; z = kuratowski_walkup( v, forbidden_edge, goal_edge, is_embedded, z_v_path); for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) { forbidden_edge[*ei] = outer_face_edge[*ei]; } typename std::vector< edge_t >::iterator pi, pi_end; pi_end = z_v_path.end(); for (pi = z_v_path.begin(); pi != pi_end; ++pi) { goal_edge[*pi] = true; } w_ancestor = v; vertex_t w_endpoint = graph_traits< Graph >::null_vertex(); while (w_endpoint == graph_traits< Graph >::null_vertex()) { w_ancestor = dfs_parent[w_ancestor]; w_endpoint = kuratowski_walkup( w_ancestor, forbidden_edge, goal_edge, is_embedded, w_path); } // We really want both the w walkup and the z walkup to finish on // exactly the same edge, but for convenience (since we don't have // control over which side of a bicomp a walkup moves up) we've // defined the walkup to either end at w_handle.first_edge() or // w_handle.second_edge(). If both walkups ended at different edges, // we'll do a little surgery on the w walkup path to make it follow // the other side of the final bicomp. if ((w_path.back() == w_handle.first_edge() && z_v_path.back() == w_handle.second_edge()) || (w_path.back() == w_handle.second_edge() && z_v_path.back() == w_handle.first_edge())) { walkup_itr_t wi, wi_end; edge_t final_edge = w_path.back(); vertex_t anchor = source(final_edge, g) == w_handle.get_anchor() ? target(final_edge, g) : source(final_edge, g); if (face_handles[anchor].first_edge() == final_edge) wi = walkup_itr_t(anchor, face_handles, second_side()); else wi = walkup_itr_t(anchor, face_handles, first_side()); w_path.pop_back(); for (; wi != wi_end; ++wi) { edge_t e(*wi); if (w_path.back() == e) w_path.pop_back(); else w_path.push_back(e); } } } else { // We need to find a valid z, since the x-y path re-defines the // lower face, and the z we found earlier may now be on the upper // face. chosen_case = detail::BM_CASE_E; // The z we've used so far is just an externally active vertex on // the lower face path, but may not be the z we need for a case C, // D, or E subgraph. the z we need now is any externally active // vertex on the lower face path with both old_face_handles edges on // the outer face. Since we know an x-y path exists, such a z must // also exist. // TODO: find this z in the first place. // find the new z for (face_itr = x_lower_itr; *face_itr != y; ++face_itr) { vertex_t possible_z(*face_itr); if (pertinent(possible_z, v) && outer_face_edge[face_handles[possible_z] .old_first_edge()] && outer_face_edge[face_handles[possible_z] .old_second_edge()]) { z = possible_z; break; } } // find x-y path, and a w if one exists. if (externally_active(z, v)) w = z; typedef typename face_edge_iterator< single_side, previous_iteration >::type old_face_iterator_t; old_face_iterator_t first_old_face_itr( z, face_handles, first_side()); old_face_iterator_t second_old_face_itr( z, face_handles, second_side()); old_face_iterator_t old_face_itr, old_face_end; std::vector< old_face_iterator_t > old_face_iterators; old_face_iterators.push_back(first_old_face_itr); old_face_iterators.push_back(second_old_face_itr); std::vector< bool > x_y_path_vertex_vector(num_vertices(g), false); vertex_to_bool_map_t x_y_path_vertex( x_y_path_vertex_vector.begin(), vm); typename std::vector< old_face_iterator_t >::iterator of_itr, of_itr_end; of_itr_end = old_face_iterators.end(); for (of_itr = old_face_iterators.begin(); of_itr != of_itr_end; ++of_itr) { old_face_itr = *of_itr; vertex_t previous_vertex; bool seen_x_or_y = false; vertex_t current_vertex = z; for (; old_face_itr != old_face_end; ++old_face_itr) { edge_t e(*old_face_itr); previous_vertex = current_vertex; current_vertex = source(e, g) == current_vertex ? target(e, g) : source(e, g); if (current_vertex == x || current_vertex == y) seen_x_or_y = true; if (w == graph_traits< Graph >::null_vertex() && externally_active(current_vertex, v) && outer_face_edge[e] && outer_face_edge[*boost::next(old_face_itr)] && !seen_x_or_y) { w = current_vertex; } if (!outer_face_edge[e]) { if (!upper_face_vertex[current_vertex] && !lower_face_vertex[current_vertex]) { x_y_path_vertex[current_vertex] = true; } is_in_subgraph[e] = true; if (upper_face_vertex[source(e, g)] || lower_face_vertex[source(e, g)]) { if (first_x_y_path_endpoint == graph_traits< Graph >::null_vertex()) first_x_y_path_endpoint = source(e, g); else second_x_y_path_endpoint = source(e, g); } if (upper_face_vertex[target(e, g)] || lower_face_vertex[target(e, g)]) { if (first_x_y_path_endpoint == graph_traits< Graph >::null_vertex()) first_x_y_path_endpoint = target(e, g); else second_x_y_path_endpoint = target(e, g); } } else if (previous_vertex == x || previous_vertex == y) { chosen_case = detail::BM_CASE_C; } } } // Look for a case D - one of v's embedded edges will connect to the // x-y path along an inner face path. // First, get a list of all of v's embedded child edges out_edge_iterator_t v_edge_itr, v_edge_end; for (boost::tie(v_edge_itr, v_edge_end) = out_edges(v, g); v_edge_itr != v_edge_end; ++v_edge_itr) { edge_t embedded_edge(*v_edge_itr); if (!is_embedded[embedded_edge] || embedded_edge == dfs_parent_edge[v]) continue; case_d_edges.push_back(embedded_edge); vertex_t current_vertex = source(embedded_edge, g) == v ? target(embedded_edge, g) : source(embedded_edge, g); typename face_edge_iterator<>::type internal_face_itr, internal_face_end; if (face_handles[current_vertex].first_vertex() == v) { internal_face_itr = typename face_edge_iterator<>::type( current_vertex, face_handles, second_side()); } else { internal_face_itr = typename face_edge_iterator<>::type( current_vertex, face_handles, first_side()); } while (internal_face_itr != internal_face_end && !outer_face_edge[*internal_face_itr] && !x_y_path_vertex[current_vertex]) { edge_t e(*internal_face_itr); case_d_edges.push_back(e); current_vertex = source(e, g) == current_vertex ? target(e, g) : source(e, g); ++internal_face_itr; } if (x_y_path_vertex[current_vertex]) { chosen_case = detail::BM_CASE_D; break; } else { case_d_edges.clear(); } } } if (chosen_case != detail::BM_CASE_B && chosen_case != detail::BM_CASE_A) { // Finding z and w. for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) { edge_t e(*ei); goal_edge[e] = !outer_face_edge[e] && (source(e, g) == z || target(e, g) == z); forbidden_edge[e] = outer_face_edge[e]; } kuratowski_walkup( v, forbidden_edge, goal_edge, is_embedded, z_v_path); if (chosen_case == detail::BM_CASE_E) { for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) { forbidden_edge[*ei] = outer_face_edge[*ei]; goal_edge[*ei] = !outer_face_edge[*ei] && (source(*ei, g) == w || target(*ei, g) == w); } for (boost::tie(oei, oei_end) = out_edges(w, g); oei != oei_end; ++oei) { if (!outer_face_edge[*oei]) goal_edge[*oei] = true; } typename std::vector< edge_t >::iterator pi, pi_end; pi_end = z_v_path.end(); for (pi = z_v_path.begin(); pi != pi_end; ++pi) { goal_edge[*pi] = true; } w_ancestor = v; vertex_t w_endpoint = graph_traits< Graph >::null_vertex(); while (w_endpoint == graph_traits< Graph >::null_vertex()) { w_ancestor = dfs_parent[w_ancestor]; w_endpoint = kuratowski_walkup(w_ancestor, forbidden_edge, goal_edge, is_embedded, w_path); } } } // We're done isolating the Kuratowski subgraph at this point - // but there's still some cleaning up to do. // Update is_in_subgraph with the paths we just found xi_end = x_external_path.end(); for (xi = x_external_path.begin(); xi != xi_end; ++xi) is_in_subgraph[*xi] = true; xi_end = y_external_path.end(); for (xi = y_external_path.begin(); xi != xi_end; ++xi) is_in_subgraph[*xi] = true; xi_end = z_v_path.end(); for (xi = z_v_path.begin(); xi != xi_end; ++xi) is_in_subgraph[*xi] = true; xi_end = case_d_edges.end(); for (xi = case_d_edges.begin(); xi != xi_end; ++xi) is_in_subgraph[*xi] = true; xi_end = w_path.end(); for (xi = w_path.begin(); xi != xi_end; ++xi) is_in_subgraph[*xi] = true; child = bicomp_root; parent = dfs_parent[child]; while (child != parent) { is_in_subgraph[dfs_parent_edge[child]] = true; boost::tie(parent, child) = std::make_pair(dfs_parent[parent], parent); } // At this point, we've already isolated the Kuratowski subgraph and // collected all of the edges that compose it in the is_in_subgraph // property map. But we want the verification of such a subgraph to be // a deterministic process, and we can simplify the function // is_kuratowski_subgraph by cleaning up some edges here. if (chosen_case == detail::BM_CASE_B) { is_in_subgraph[dfs_parent_edge[v]] = false; } else if (chosen_case == detail::BM_CASE_C) { // In a case C subgraph, at least one of the x-y path endpoints // (call it alpha) is above either x or y on the outer face. The // other endpoint may be attached at x or y OR above OR below. In // any of these three cases, we can form a K_3_3 by removing the // edge attached to v on the outer face that is NOT on the path to // alpha. typename face_vertex_iterator< single_side, follow_visitor >::type face_itr, face_end; if (face_handles[v_dfchild_handle.first_vertex()].first_edge() == v_dfchild_handle.first_edge()) { face_itr = typename face_vertex_iterator< single_side, follow_visitor >::type(v_dfchild_handle.first_vertex(), face_handles, second_side()); } else { face_itr = typename face_vertex_iterator< single_side, follow_visitor >::type(v_dfchild_handle.first_vertex(), face_handles, first_side()); } for (; true; ++face_itr) { vertex_t current_vertex(*face_itr); if (current_vertex == x || current_vertex == y) { is_in_subgraph[v_dfchild_handle.first_edge()] = false; break; } else if (current_vertex == first_x_y_path_endpoint || current_vertex == second_x_y_path_endpoint) { is_in_subgraph[v_dfchild_handle.second_edge()] = false; break; } } } else if (chosen_case == detail::BM_CASE_D) { // Need to remove both of the edges adjacent to v on the outer face. // remove the connecting edges from v to bicomp, then // is_kuratowski_subgraph will shrink vertices of degree 1 // automatically... is_in_subgraph[v_dfchild_handle.first_edge()] = false; is_in_subgraph[v_dfchild_handle.second_edge()] = false; } else if (chosen_case == detail::BM_CASE_E) { // Similarly to case C, if the endpoints of the x-y path are both // below x and y, we should remove an edge to allow the subgraph to // contract to a K_3_3. if ((first_x_y_path_endpoint != x && first_x_y_path_endpoint != y) || (second_x_y_path_endpoint != x && second_x_y_path_endpoint != y)) { is_in_subgraph[dfs_parent_edge[v]] = false; vertex_t deletion_endpoint, other_endpoint; if (lower_face_vertex[first_x_y_path_endpoint]) { deletion_endpoint = second_x_y_path_endpoint; other_endpoint = first_x_y_path_endpoint; } else { deletion_endpoint = first_x_y_path_endpoint; other_endpoint = second_x_y_path_endpoint; } typename face_edge_iterator<>::type face_itr, face_end; bool found_other_endpoint = false; for (face_itr = typename face_edge_iterator<>::type( deletion_endpoint, face_handles, first_side()); face_itr != face_end; ++face_itr) { edge_t e(*face_itr); if (source(e, g) == other_endpoint || target(e, g) == other_endpoint) { found_other_endpoint = true; break; } } if (found_other_endpoint) { is_in_subgraph[face_handles[deletion_endpoint].first_edge()] = false; } else { is_in_subgraph[face_handles[deletion_endpoint] .second_edge()] = false; } } } for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) if (is_in_subgraph[*ei]) *o_itr = *ei; } template < typename EdgePermutation > void make_edge_permutation(EdgePermutation perm) { vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { vertex_t v(*vi); perm[v].clear(); face_handles[v].get_list(std::back_inserter(perm[v])); } } private: const Graph& g; VertexIndexMap vm; vertex_t kuratowski_v; vertex_t kuratowski_x; vertex_t kuratowski_y; vertex_list_t garbage; // we delete items from linked lists by // splicing them into garbage // only need these two for kuratowski subgraph isolation std::vector< vertex_t > current_merge_points; std::vector< edge_t > embedded_edges; // property map storage std::vector< v_size_t > low_point_vector; std::vector< vertex_t > dfs_parent_vector; std::vector< v_size_t > dfs_number_vector; std::vector< v_size_t > least_ancestor_vector; std::vector< face_handle_list_ptr_t > pertinent_roots_vector; std::vector< v_size_t > backedge_flag_vector; std::vector< v_size_t > visited_vector; std::vector< face_handle_t > face_handles_vector; std::vector< face_handle_t > dfs_child_handles_vector; std::vector< vertex_list_ptr_t > separated_dfs_child_list_vector; std::vector< typename vertex_list_t::iterator > separated_node_in_parent_list_vector; std::vector< vertex_t > canonical_dfs_child_vector; std::vector< bool > flipped_vector; std::vector< edge_vector_t > backedges_vector; edge_vector_t self_loops; std::vector< edge_t > dfs_parent_edge_vector; vertex_vector_t vertices_by_dfs_num; // property maps vertex_to_v_size_map_t low_point; vertex_to_vertex_map_t dfs_parent; vertex_to_v_size_map_t dfs_number; vertex_to_v_size_map_t least_ancestor; vertex_to_face_handle_list_ptr_map_t pertinent_roots; vertex_to_v_size_map_t backedge_flag; vertex_to_v_size_map_t visited; vertex_to_face_handle_map_t face_handles; vertex_to_face_handle_map_t dfs_child_handles; vertex_to_vertex_list_ptr_map_t separated_dfs_child_list; vertex_to_separated_node_map_t separated_node_in_parent_list; vertex_to_vertex_map_t canonical_dfs_child; vertex_to_bool_map_t flipped; vertex_to_edge_vector_map_t backedges; vertex_to_edge_map_t dfs_parent_edge; // only need for kuratowski merge_stack_t merge_stack; }; } // namespace boost #endif //__BOYER_MYRVOLD_IMPL_HPP__ planar_detail/face_iterators.hpp 0000644 00000022716 15125521275 0013063 0 ustar 00 //======================================================================= // Copyright (c) Aaron Windsor 2007 // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef __FACE_ITERATORS_HPP__ #define __FACE_ITERATORS_HPP__ #include <boost/iterator/iterator_facade.hpp> #include <boost/mpl/bool.hpp> #include <boost/graph/graph_traits.hpp> namespace boost { // tags for defining traversal properties // VisitorType struct lead_visitor { }; struct follow_visitor { }; // TraversalType struct single_side { }; struct both_sides { }; // TraversalSubType struct first_side { }; // for single_side struct second_side { }; // for single_side struct alternating { }; // for both_sides // Time struct current_iteration { }; struct previous_iteration { }; // Why TraversalType AND TraversalSubType? TraversalSubType is a function // template parameter passed in to the constructor of the face iterator, // whereas TraversalType is a class template parameter. This lets us decide // at runtime whether to move along the first or second side of a bicomp (by // assigning a face_iterator that has been constructed with TraversalSubType // = first_side or second_side to a face_iterator variable) without any of // the virtual function overhead that comes with implementing this // functionality as a more structured form of type erasure. It also allows // a single face_iterator to be the end iterator of two iterators traversing // both sides of a bicomp. // ValueType is either graph_traits<Graph>::vertex_descriptor // or graph_traits<Graph>::edge_descriptor // forward declaration (defining defaults) template < typename Graph, typename FaceHandlesMap, typename ValueType, typename BicompSideToTraverse = single_side, typename VisitorType = lead_visitor, typename Time = current_iteration > class face_iterator; template < typename Graph, bool StoreEdge > struct edge_storage { }; template < typename Graph > struct edge_storage< Graph, true > { typename graph_traits< Graph >::edge_descriptor value; }; // specialization for TraversalType = traverse_vertices template < typename Graph, typename FaceHandlesMap, typename ValueType, typename TraversalType, typename VisitorType, typename Time > class face_iterator : public boost::iterator_facade< face_iterator< Graph, FaceHandlesMap, ValueType, TraversalType, VisitorType, Time >, ValueType, boost::forward_traversal_tag, ValueType > { public: typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::edge_descriptor edge_t; typedef face_iterator< Graph, FaceHandlesMap, ValueType, TraversalType, VisitorType, Time > self; typedef typename FaceHandlesMap::value_type face_handle_t; face_iterator() : m_lead(graph_traits< Graph >::null_vertex()) , m_follow(graph_traits< Graph >::null_vertex()) { } template < typename TraversalSubType > face_iterator(face_handle_t anchor_handle, FaceHandlesMap face_handles, TraversalSubType traversal_type) : m_follow(anchor_handle.get_anchor()), m_face_handles(face_handles) { set_lead_dispatch(anchor_handle, traversal_type); } template < typename TraversalSubType > face_iterator(vertex_t anchor, FaceHandlesMap face_handles, TraversalSubType traversal_type) : m_follow(anchor), m_face_handles(face_handles) { set_lead_dispatch(m_face_handles[anchor], traversal_type); } private: friend class boost::iterator_core_access; inline vertex_t get_first_vertex( face_handle_t anchor_handle, current_iteration) { return anchor_handle.first_vertex(); } inline vertex_t get_second_vertex( face_handle_t anchor_handle, current_iteration) { return anchor_handle.second_vertex(); } inline vertex_t get_first_vertex( face_handle_t anchor_handle, previous_iteration) { return anchor_handle.old_first_vertex(); } inline vertex_t get_second_vertex( face_handle_t anchor_handle, previous_iteration) { return anchor_handle.old_second_vertex(); } inline void set_lead_dispatch(face_handle_t anchor_handle, first_side) { m_lead = get_first_vertex(anchor_handle, Time()); set_edge_to_first_dispatch(anchor_handle, ValueType(), Time()); } inline void set_lead_dispatch(face_handle_t anchor_handle, second_side) { m_lead = get_second_vertex(anchor_handle, Time()); set_edge_to_second_dispatch(anchor_handle, ValueType(), Time()); } inline void set_edge_to_first_dispatch( face_handle_t anchor_handle, edge_t, current_iteration) { m_edge.value = anchor_handle.first_edge(); } inline void set_edge_to_second_dispatch( face_handle_t anchor_handle, edge_t, current_iteration) { m_edge.value = anchor_handle.second_edge(); } inline void set_edge_to_first_dispatch( face_handle_t anchor_handle, edge_t, previous_iteration) { m_edge.value = anchor_handle.old_first_edge(); } inline void set_edge_to_second_dispatch( face_handle_t anchor_handle, edge_t, previous_iteration) { m_edge.value = anchor_handle.old_second_edge(); } template < typename T > inline void set_edge_to_first_dispatch(face_handle_t, vertex_t, T) { } template < typename T > inline void set_edge_to_second_dispatch(face_handle_t, vertex_t, T) { } void increment() { face_handle_t curr_face_handle(m_face_handles[m_lead]); vertex_t first = get_first_vertex(curr_face_handle, Time()); vertex_t second = get_second_vertex(curr_face_handle, Time()); if (first == m_follow) { m_follow = m_lead; set_edge_to_second_dispatch(curr_face_handle, ValueType(), Time()); m_lead = second; } else if (second == m_follow) { m_follow = m_lead; set_edge_to_first_dispatch(curr_face_handle, ValueType(), Time()); m_lead = first; } else m_lead = m_follow = graph_traits< Graph >::null_vertex(); } bool equal(self const& other) const { return m_lead == other.m_lead && m_follow == other.m_follow; } ValueType dereference() const { return dereference_dispatch(VisitorType(), ValueType()); } inline ValueType dereference_dispatch(lead_visitor, vertex_t) const { return m_lead; } inline ValueType dereference_dispatch(follow_visitor, vertex_t) const { return m_follow; } inline ValueType dereference_dispatch(lead_visitor, edge_t) const { return m_edge.value; } inline ValueType dereference_dispatch(follow_visitor, edge_t) const { return m_edge.value; } vertex_t m_lead; vertex_t m_follow; edge_storage< Graph, boost::is_same< ValueType, edge_t >::value > m_edge; FaceHandlesMap m_face_handles; }; template < typename Graph, typename FaceHandlesMap, typename ValueType, typename VisitorType, typename Time > class face_iterator< Graph, FaceHandlesMap, ValueType, both_sides, VisitorType, Time > : public boost::iterator_facade< face_iterator< Graph, FaceHandlesMap, ValueType, both_sides, VisitorType, Time >, ValueType, boost::forward_traversal_tag, ValueType > { public: typedef face_iterator< Graph, FaceHandlesMap, ValueType, both_sides, VisitorType, Time > self; typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename FaceHandlesMap::value_type face_handle_t; face_iterator() {} face_iterator(face_handle_t anchor_handle, FaceHandlesMap face_handles) : first_itr(anchor_handle, face_handles, first_side()) , second_itr(anchor_handle, face_handles, second_side()) , first_is_active(true) , first_increment(true) { } face_iterator(vertex_t anchor, FaceHandlesMap face_handles) : first_itr(face_handles[anchor], face_handles, first_side()) , second_itr(face_handles[anchor], face_handles, second_side()) , first_is_active(true) , first_increment(true) { } private: friend class boost::iterator_core_access; typedef face_iterator< Graph, FaceHandlesMap, ValueType, single_side, follow_visitor, Time > inner_itr_t; void increment() { if (first_increment) { ++first_itr; ++second_itr; first_increment = false; } else if (first_is_active) ++first_itr; else ++second_itr; first_is_active = !first_is_active; } bool equal(self const& other) const { // Want this iterator to be equal to the "end" iterator when at least // one of the iterators has reached the root of the current bicomp. // This isn't ideal, but it works. return (first_itr == other.first_itr || second_itr == other.second_itr); } ValueType dereference() const { return first_is_active ? *first_itr : *second_itr; } inner_itr_t first_itr; inner_itr_t second_itr; inner_itr_t face_end; bool first_is_active; bool first_increment; }; } /* namespace boost */ #endif //__FACE_ITERATORS_HPP__ planar_detail/face_handles.hpp 0000644 00000037121 15125521275 0012461 0 ustar 00 //======================================================================= // Copyright (c) Aaron Windsor 2007 // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef __FACE_HANDLES_HPP__ #define __FACE_HANDLES_HPP__ #include <list> #include <boost/graph/graph_traits.hpp> #include <boost/shared_ptr.hpp> // A "face handle" is an optimization meant to serve two purposes in // the implementation of the Boyer-Myrvold planarity test: (1) it holds // the partial planar embedding of a particular vertex as it's being // constructed, and (2) it allows for efficient traversal around the // outer face of the partial embedding at that particular vertex. A face // handle is lightweight, just a shared pointer to the actual implementation, // since it is passed around/copied liberally in the algorithm. It consists // of an "anchor" (the actual vertex it's associated with) as well as a // sequence of edges. The functions first_vertex/second_vertex and // first_edge/second_edge allow fast access to the beginning and end of the // stored sequence, which allows one to traverse the outer face of the partial // planar embedding as it's being created. // // There are some policies below that define the contents of the face handles: // in the case no embedding is needed (for example, if one just wants to use // the Boyer-Myrvold algorithm as a true/false test for planarity, the // no_embedding class can be passed as the StoreEmbedding policy. Otherwise, // either std_list (which uses as std::list) or recursive_lazy_list can be // passed as this policy. recursive_lazy_list has the best theoretical // performance (O(n) for a sequence of interleaved concatenations and reversals // of the underlying list), but I've noticed little difference between std_list // and recursive_lazy_list in my tests, even though using std_list changes // the worst-case complexity of the planarity test to O(n^2) // // Another policy is StoreOldHandlesPolicy, which specifies whether or not // to keep a record of the previous first/second vertex/edge - this is needed // if a Kuratowski subgraph needs to be isolated. namespace boost { namespace graph { namespace detail { // face handle policies // EmbeddingStorage policy struct store_embedding { }; struct recursive_lazy_list : public store_embedding { }; struct std_list : public store_embedding { }; struct no_embedding { }; // StoreOldHandlesPolicy struct store_old_handles { }; struct no_old_handles { }; template < typename DataType > struct lazy_list_node { typedef shared_ptr< lazy_list_node< DataType > > ptr_t; lazy_list_node(const DataType& data) : m_reversed(false), m_data(data), m_has_data(true) { } lazy_list_node(ptr_t left_child, ptr_t right_child) : m_reversed(false) , m_has_data(false) , m_left_child(left_child) , m_right_child(right_child) { } bool m_reversed; DataType m_data; bool m_has_data; shared_ptr< lazy_list_node > m_left_child; shared_ptr< lazy_list_node > m_right_child; }; template < typename StoreOldHandlesPolicy, typename Vertex, typename Edge > struct old_handles_storage; template < typename Vertex, typename Edge > struct old_handles_storage< store_old_handles, Vertex, Edge > { Vertex first_vertex; Vertex second_vertex; Edge first_edge; Edge second_edge; }; template < typename Vertex, typename Edge > struct old_handles_storage< no_old_handles, Vertex, Edge > { }; template < typename StoreEmbeddingPolicy, typename Edge > struct edge_list_storage; template < typename Edge > struct edge_list_storage< no_embedding, Edge > { typedef void type; void push_back(Edge) {} void push_front(Edge) {} void reverse() {} void concat_front(edge_list_storage< no_embedding, Edge >) {} void concat_back(edge_list_storage< no_embedding, Edge >) {} template < typename OutputIterator > void get_list(OutputIterator) { } }; template < typename Edge > struct edge_list_storage< recursive_lazy_list, Edge > { typedef lazy_list_node< Edge > node_type; typedef shared_ptr< node_type > type; type value; void push_back(Edge e) { type new_node(new node_type(e)); value = type(new node_type(value, new_node)); } void push_front(Edge e) { type new_node(new node_type(e)); value = type(new node_type(new_node, value)); } void reverse() { value->m_reversed = !value->m_reversed; } void concat_front( edge_list_storage< recursive_lazy_list, Edge > other) { value = type(new node_type(other.value, value)); } void concat_back( edge_list_storage< recursive_lazy_list, Edge > other) { value = type(new node_type(value, other.value)); } template < typename OutputIterator > void get_list(OutputIterator out) { get_list_helper(out, value); } private: template < typename OutputIterator > void get_list_helper( OutputIterator o_itr, type root, bool flipped = false) { if (!root) return; if (root->m_has_data) *o_itr = root->m_data; if ((flipped && !root->m_reversed) || (!flipped && root->m_reversed)) { get_list_helper(o_itr, root->m_right_child, true); get_list_helper(o_itr, root->m_left_child, true); } else { get_list_helper(o_itr, root->m_left_child, false); get_list_helper(o_itr, root->m_right_child, false); } } }; template < typename Edge > struct edge_list_storage< std_list, Edge > { typedef std::list< Edge > type; type value; void push_back(Edge e) { value.push_back(e); } void push_front(Edge e) { value.push_front(e); } void reverse() { value.reverse(); } void concat_front(edge_list_storage< std_list, Edge > other) { value.splice(value.begin(), other.value); } void concat_back(edge_list_storage< std_list, Edge > other) { value.splice(value.end(), other.value); } template < typename OutputIterator > void get_list(OutputIterator out) { std::copy(value.begin(), value.end(), out); } }; template < typename Graph, typename StoreOldHandlesPolicy, typename StoreEmbeddingPolicy > struct face_handle_impl { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::edge_descriptor edge_t; typedef typename edge_list_storage< StoreEmbeddingPolicy, edge_t >::type edge_list_storage_t; face_handle_impl() : cached_first_vertex(graph_traits< Graph >::null_vertex()) , cached_second_vertex(graph_traits< Graph >::null_vertex()) , true_first_vertex(graph_traits< Graph >::null_vertex()) , true_second_vertex(graph_traits< Graph >::null_vertex()) , anchor(graph_traits< Graph >::null_vertex()) { initialize_old_vertices_dispatch(StoreOldHandlesPolicy()); } void initialize_old_vertices_dispatch(store_old_handles) { old_handles.first_vertex = graph_traits< Graph >::null_vertex(); old_handles.second_vertex = graph_traits< Graph >::null_vertex(); } void initialize_old_vertices_dispatch(no_old_handles) {} vertex_t cached_first_vertex; vertex_t cached_second_vertex; vertex_t true_first_vertex; vertex_t true_second_vertex; vertex_t anchor; edge_t cached_first_edge; edge_t cached_second_edge; edge_list_storage< StoreEmbeddingPolicy, edge_t > edge_list; old_handles_storage< StoreOldHandlesPolicy, vertex_t, edge_t > old_handles; }; template < typename Graph, typename StoreOldHandlesPolicy = store_old_handles, typename StoreEmbeddingPolicy = recursive_lazy_list > class face_handle { public: typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::edge_descriptor edge_t; typedef face_handle_impl< Graph, StoreOldHandlesPolicy, StoreEmbeddingPolicy > impl_t; typedef face_handle< Graph, StoreOldHandlesPolicy, StoreEmbeddingPolicy > self_t; face_handle(vertex_t anchor = graph_traits< Graph >::null_vertex()) : pimpl(new impl_t()) { pimpl->anchor = anchor; } face_handle(vertex_t anchor, edge_t initial_edge, const Graph& g) : pimpl(new impl_t()) { vertex_t s(source(initial_edge, g)); vertex_t t(target(initial_edge, g)); vertex_t other_vertex = s == anchor ? t : s; pimpl->anchor = anchor; pimpl->cached_first_edge = initial_edge; pimpl->cached_second_edge = initial_edge; pimpl->cached_first_vertex = other_vertex; pimpl->cached_second_vertex = other_vertex; pimpl->true_first_vertex = other_vertex; pimpl->true_second_vertex = other_vertex; pimpl->edge_list.push_back(initial_edge); store_old_face_handles_dispatch(StoreOldHandlesPolicy()); } // default copy construction, assignment okay. void push_first(edge_t e, const Graph& g) { pimpl->edge_list.push_front(e); pimpl->cached_first_vertex = pimpl->true_first_vertex = source(e, g) == pimpl->anchor ? target(e, g) : source(e, g); pimpl->cached_first_edge = e; } void push_second(edge_t e, const Graph& g) { pimpl->edge_list.push_back(e); pimpl->cached_second_vertex = pimpl->true_second_vertex = source(e, g) == pimpl->anchor ? target(e, g) : source(e, g); pimpl->cached_second_edge = e; } inline void store_old_face_handles() { store_old_face_handles_dispatch(StoreOldHandlesPolicy()); } inline vertex_t first_vertex() const { return pimpl->cached_first_vertex; } inline vertex_t second_vertex() const { return pimpl->cached_second_vertex; } inline vertex_t true_first_vertex() const { return pimpl->true_first_vertex; } inline vertex_t true_second_vertex() const { return pimpl->true_second_vertex; } inline vertex_t old_first_vertex() const { return pimpl->old_handles.first_vertex; } inline vertex_t old_second_vertex() const { return pimpl->old_handles.second_vertex; } inline edge_t old_first_edge() const { return pimpl->old_handles.first_edge; } inline edge_t old_second_edge() const { return pimpl->old_handles.second_edge; } inline edge_t first_edge() const { return pimpl->cached_first_edge; } inline edge_t second_edge() const { return pimpl->cached_second_edge; } inline vertex_t get_anchor() const { return pimpl->anchor; } void glue_first_to_second(face_handle< Graph, StoreOldHandlesPolicy, StoreEmbeddingPolicy >& bottom) { pimpl->edge_list.concat_front(bottom.pimpl->edge_list); pimpl->true_first_vertex = bottom.pimpl->true_first_vertex; pimpl->cached_first_vertex = bottom.pimpl->cached_first_vertex; pimpl->cached_first_edge = bottom.pimpl->cached_first_edge; } void glue_second_to_first(face_handle< Graph, StoreOldHandlesPolicy, StoreEmbeddingPolicy >& bottom) { pimpl->edge_list.concat_back(bottom.pimpl->edge_list); pimpl->true_second_vertex = bottom.pimpl->true_second_vertex; pimpl->cached_second_vertex = bottom.pimpl->cached_second_vertex; pimpl->cached_second_edge = bottom.pimpl->cached_second_edge; } void flip() { pimpl->edge_list.reverse(); std::swap(pimpl->true_first_vertex, pimpl->true_second_vertex); std::swap( pimpl->cached_first_vertex, pimpl->cached_second_vertex); std::swap(pimpl->cached_first_edge, pimpl->cached_second_edge); } template < typename OutputIterator > void get_list(OutputIterator o_itr) { pimpl->edge_list.get_list(o_itr); } void reset_vertex_cache() { pimpl->cached_first_vertex = pimpl->true_first_vertex; pimpl->cached_second_vertex = pimpl->true_second_vertex; } inline void set_first_vertex(vertex_t v) { pimpl->cached_first_vertex = v; } inline void set_second_vertex(vertex_t v) { pimpl->cached_second_vertex = v; } private: void store_old_face_handles_dispatch(store_old_handles) { pimpl->old_handles.first_vertex = pimpl->true_first_vertex; pimpl->old_handles.second_vertex = pimpl->true_second_vertex; pimpl->old_handles.first_edge = pimpl->cached_first_edge; pimpl->old_handles.second_edge = pimpl->cached_second_edge; } void store_old_face_handles_dispatch(no_old_handles) {} boost::shared_ptr< impl_t > pimpl; }; } /* namespace detail */ } /* namespace graph */ } /* namespace boost */ #endif //__FACE_HANDLES_HPP__ planar_detail/add_edge_visitors.hpp 0000644 00000002672 15125521275 0013546 0 ustar 00 //======================================================================= // Copyright 2007 Aaron Windsor // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef __ADD_EDGE_VISITORS_HPP__ #define __ADD_EDGE_VISITORS_HPP__ #include <boost/property_map/property_map.hpp> namespace boost { struct default_add_edge_visitor { template < typename Graph, typename Vertex > void visit_vertex_pair(Vertex u, Vertex v, Graph& g) { add_edge(u, v, g); } }; template < typename EdgeIndexMap > struct edge_index_update_visitor { typedef typename property_traits< EdgeIndexMap >::value_type edge_index_value_t; edge_index_update_visitor( EdgeIndexMap em, edge_index_value_t next_index_available) : m_em(em), m_next_index(next_index_available) { } template < typename Graph, typename Vertex > void visit_vertex_pair(Vertex u, Vertex v, Graph& g) { typedef typename graph_traits< Graph >::edge_descriptor edge_t; std::pair< edge_t, bool > return_value = add_edge(u, v, g); if (return_value.second) put(m_em, return_value.first, m_next_index++); } private: EdgeIndexMap m_em; edge_index_value_t m_next_index; }; } // namespace boost #endif //__ADD_EDGE_VISITORS_HPP__ random.hpp 0000644 00000022714 15125521275 0006550 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Copyright (C) Vladimir Prus 2003 // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_RANDOM_HPP #define BOOST_GRAPH_RANDOM_HPP #include <boost/graph/graph_traits.hpp> #include <boost/random/uniform_int.hpp> #include <boost/random/uniform_real.hpp> #include <boost/random/variate_generator.hpp> #include <boost/pending/property.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/next_prior.hpp> #include <boost/graph/adjacency_list.hpp> #include <boost/graph/copy.hpp> #include <boost/mpl/if.hpp> #include <boost/type_traits/is_convertible.hpp> #include <iostream> #include <boost/assert.hpp> namespace boost { // grab a random vertex from the graph's vertex set template < class Graph, class RandomNumGen > typename graph_traits< Graph >::vertex_descriptor random_vertex( Graph& g, RandomNumGen& gen) { if (num_vertices(g) > 1) { #if BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x581)) std::size_t n = std::random(num_vertices(g)); #else uniform_int<> distrib(0, num_vertices(g) - 1); variate_generator< RandomNumGen&, uniform_int<> > rand_gen( gen, distrib); std::size_t n = rand_gen(); #endif typename graph_traits< Graph >::vertex_iterator i = vertices(g).first; return *(boost::next(i, n)); } else return *vertices(g).first; } template < class Graph, class RandomNumGen > typename graph_traits< Graph >::edge_descriptor random_edge( Graph& g, RandomNumGen& gen) { if (num_edges(g) > 1) { #if BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x581)) typename graph_traits< Graph >::edges_size_type n = std::random(num_edges(g)); #else uniform_int<> distrib(0, num_edges(g) - 1); variate_generator< RandomNumGen&, uniform_int<> > rand_gen( gen, distrib); typename graph_traits< Graph >::edges_size_type n = rand_gen(); #endif typename graph_traits< Graph >::edge_iterator i = edges(g).first; return *(boost::next(i, n)); } else return *edges(g).first; } template < typename Graph, typename RandomNumGen > typename graph_traits< Graph >::edge_descriptor random_out_edge(Graph& g, typename graph_traits< Graph >::vertex_descriptor src, RandomNumGen& gen) { typedef typename graph_traits< Graph >::degree_size_type degree_size_type; typedef boost::uniform_int< degree_size_type > ui_type; ui_type ui(0, out_degree(src, g) - 1); boost::variate_generator< RandomNumGen&, ui_type > variate(gen, ui); typename graph_traits< Graph >::out_edge_iterator it = out_edges(src, g).first; std::advance(it, variate()); return *it; } template < typename Graph, typename WeightMap, typename RandomNumGen > typename graph_traits< Graph >::edge_descriptor weighted_random_out_edge( Graph& g, typename graph_traits< Graph >::vertex_descriptor src, WeightMap weight, RandomNumGen& gen) { typedef typename property_traits< WeightMap >::value_type weight_type; weight_type weight_sum(0); BGL_FORALL_OUTEDGES_T(src, e, g, Graph) { weight_sum += get(weight, e); } typedef boost::uniform_real<> ur_type; ur_type ur(0, weight_sum); boost::variate_generator< RandomNumGen&, ur_type > variate(gen, ur); weight_type chosen_weight = variate(); BGL_FORALL_OUTEDGES_T(src, e, g, Graph) { weight_type w = get(weight, e); if (chosen_weight < w) { return e; } else { chosen_weight -= w; } } BOOST_ASSERT(false); // Should not get here return typename graph_traits< Graph >::edge_descriptor(); } namespace detail { class dummy_property_copier { public: template < class V1, class V2 > void operator()(const V1&, const V2&) const { } }; } template < typename MutableGraph, class RandNumGen > void generate_random_graph1(MutableGraph& g, typename graph_traits< MutableGraph >::vertices_size_type V, typename graph_traits< MutableGraph >::vertices_size_type E, RandNumGen& gen, bool allow_parallel = true, bool self_edges = false) { typedef graph_traits< MutableGraph > Traits; typedef typename Traits::edge_descriptor edge_t; typedef typename Traits::vertices_size_type v_size_t; typedef typename Traits::edges_size_type e_size_t; typedef typename Traits::vertex_descriptor vertex_descriptor; // When parallel edges are not allowed, we create a new graph which // does not allow parallel edges, construct it and copy back. // This is not efficient if 'g' already disallow parallel edges, // but that's task for later. if (!allow_parallel) { typedef typename boost::graph_traits< MutableGraph >::directed_category dir; typedef typename mpl::if_< is_convertible< dir, directed_tag >, directedS, undirectedS >::type select; adjacency_list< setS, vecS, select > g2; generate_random_graph1(g2, V, E, gen, true, self_edges); copy_graph(g2, g, vertex_copy(detail::dummy_property_copier()) .edge_copy(detail::dummy_property_copier())); } else { for (v_size_t i = 0; i < V; ++i) add_vertex(g); e_size_t not_inserted_counter = 0; /* Number of edge insertion failures */ e_size_t num_vertices_squared = num_vertices(g) * num_vertices(g); for (e_size_t j = 0; j < E; /* Increment in body */) { vertex_descriptor a = random_vertex(g, gen), b; do { b = random_vertex(g, gen); } while (self_edges == false && a == b); edge_t e; bool inserted; boost::tie(e, inserted) = add_edge(a, b, g); if (inserted) { ++j; } else { ++not_inserted_counter; } if (not_inserted_counter >= num_vertices_squared) { return; /* Rather than looping forever on complete graph */ } } } } template < typename MutableGraph, class RandNumGen > void generate_random_graph(MutableGraph& g, typename graph_traits< MutableGraph >::vertices_size_type V, typename graph_traits< MutableGraph >::vertices_size_type E, RandNumGen& gen, bool allow_parallel = true, bool self_edges = false) { generate_random_graph1(g, V, E, gen, allow_parallel, self_edges); } template < typename MutableGraph, typename RandNumGen, typename VertexOutputIterator, typename EdgeOutputIterator > void generate_random_graph(MutableGraph& g, typename graph_traits< MutableGraph >::vertices_size_type V, typename graph_traits< MutableGraph >::vertices_size_type E, RandNumGen& gen, VertexOutputIterator vertex_out, EdgeOutputIterator edge_out, bool self_edges = false) { typedef graph_traits< MutableGraph > Traits; typedef typename Traits::vertices_size_type v_size_t; typedef typename Traits::edges_size_type e_size_t; typedef typename Traits::vertex_descriptor vertex_t; typedef typename Traits::edge_descriptor edge_t; for (v_size_t i = 0; i < V; ++i) *vertex_out++ = add_vertex(g); e_size_t not_inserted_counter = 0; /* Number of edge insertion failures */ e_size_t num_vertices_squared = num_vertices(g) * num_vertices(g); for (e_size_t j = 0; j < E; /* Increment in body */) { vertex_t a = random_vertex(g, gen), b; do { b = random_vertex(g, gen); } while (self_edges == false && a == b); edge_t e; bool inserted; boost::tie(e, inserted) = add_edge(a, b, g); if (inserted) { *edge_out++ = std::make_pair(source(e, g), target(e, g)); ++j; } else { ++not_inserted_counter; } if (not_inserted_counter >= num_vertices_squared) { return; /* Rather than looping forever on complete graph */ } } } namespace detail { template < class Property, class G, class RandomGenerator > void randomize_property( G& g, RandomGenerator& rg, Property, vertex_property_tag) { typename property_map< G, Property >::type pm = get(Property(), g); typename graph_traits< G >::vertex_iterator vi, ve; for (boost::tie(vi, ve) = vertices(g); vi != ve; ++vi) { pm[*vi] = rg(); } } template < class Property, class G, class RandomGenerator > void randomize_property( G& g, RandomGenerator& rg, Property, edge_property_tag) { typename property_map< G, Property >::type pm = get(Property(), g); typename graph_traits< G >::edge_iterator ei, ee; for (boost::tie(ei, ee) = edges(g); ei != ee; ++ei) { pm[*ei] = rg(); } } } template < class Property, class G, class RandomGenerator > void randomize_property(G& g, RandomGenerator& rg) { detail::randomize_property( g, rg, Property(), typename property_kind< Property >::type()); } } #include <boost/graph/iteration_macros_undef.hpp> #endif prim_minimum_spanning_tree.hpp 0000644 00000005620 15125521275 0012703 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_MST_PRIM_HPP #define BOOST_GRAPH_MST_PRIM_HPP #include <functional> #include <boost/graph/graph_traits.hpp> #include <boost/graph/dijkstra_shortest_paths.hpp> namespace boost { namespace detail { // this should be somewhere else in boost... template < class U, class V > struct _project2nd { V operator()(U, V v) const { return v; } }; } namespace detail { // This is Prim's algorithm to calculate the Minimum Spanning Tree // for an undirected graph with weighted edges. template < class Graph, class P, class T, class R, class Weight > inline void prim_mst_impl(const Graph& G, typename graph_traits< Graph >::vertex_descriptor s, const bgl_named_params< P, T, R >& params, Weight) { typedef typename property_traits< Weight >::value_type W; std::less< W > compare; detail::_project2nd< W, W > combine; dijkstra_shortest_paths( G, s, params.distance_compare(compare).distance_combine(combine)); } } // namespace detail template < class VertexListGraph, class DijkstraVisitor, class PredecessorMap, class DistanceMap, class WeightMap, class IndexMap > inline void prim_minimum_spanning_tree(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, WeightMap weight, IndexMap index_map, DijkstraVisitor vis) { typedef typename property_traits< WeightMap >::value_type W; std::less< W > compare; detail::_project2nd< W, W > combine; dijkstra_shortest_paths(g, s, predecessor, distance, weight, index_map, compare, combine, (std::numeric_limits< W >::max)(), 0, vis); } template < class VertexListGraph, class PredecessorMap, class P, class T, class R > inline void prim_minimum_spanning_tree(const VertexListGraph& g, PredecessorMap p_map, const bgl_named_params< P, T, R >& params) { detail::prim_mst_impl(g, choose_param(get_param(params, root_vertex_t()), *vertices(g).first), params.predecessor_map(p_map), choose_const_pmap(get_param(params, edge_weight), g, edge_weight)); } template < class VertexListGraph, class PredecessorMap > inline void prim_minimum_spanning_tree( const VertexListGraph& g, PredecessorMap p_map) { detail::prim_mst_impl(g, *vertices(g).first, predecessor_map(p_map).weight_map(get(edge_weight, g)), get(edge_weight, g)); } } // namespace boost #endif // BOOST_GRAPH_MST_PRIM_HPP graph_concepts.hpp 0000644 00000046513 15125521275 0010272 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Copyright 2009, Andrew Sutton // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_CONCEPTS_HPP #define BOOST_GRAPH_CONCEPTS_HPP #include <boost/config.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/numeric_values.hpp> #include <boost/graph/buffer_concepts.hpp> #include <boost/concept_check.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/mpl/not.hpp> #include <boost/static_assert.hpp> #include <boost/detail/workaround.hpp> #include <boost/concept/assert.hpp> #include <boost/concept/detail/concept_def.hpp> namespace boost { // dwa 2003/7/11 -- This clearly shouldn't be necessary, but if // you want to use vector_as_graph, it is! I'm sure the graph // library leaves these out all over the place. Probably a // redesign involving specializing a template with a static // member function is in order :( // // It is needed in order to allow us to write using boost::vertices as // needed for ADL when using vector_as_graph below. #if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) \ && !BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x564)) #define BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK #endif #ifdef BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK template < class T > typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); #endif namespace concepts { BOOST_concept(MultiPassInputIterator, (T)) { BOOST_CONCEPT_USAGE( MultiPassInputIterator) { BOOST_CONCEPT_ASSERT((InputIterator< T >)); } }; BOOST_concept(Graph, (G)) { typedef typename graph_traits< G >::vertex_descriptor vertex_descriptor; typedef typename graph_traits< G >::edge_descriptor edge_descriptor; typedef typename graph_traits< G >::directed_category directed_category; typedef typename graph_traits< G >::edge_parallel_category edge_parallel_category; typedef typename graph_traits< G >::traversal_category traversal_category; BOOST_CONCEPT_USAGE(Graph) { BOOST_CONCEPT_ASSERT((DefaultConstructible< vertex_descriptor >)); BOOST_CONCEPT_ASSERT((EqualityComparable< vertex_descriptor >)); BOOST_CONCEPT_ASSERT((Assignable< vertex_descriptor >)); } G g; }; BOOST_concept(IncidenceGraph, (G)) : Graph< G > { typedef typename graph_traits< G >::edge_descriptor edge_descriptor; typedef typename graph_traits< G >::out_edge_iterator out_edge_iterator; typedef typename graph_traits< G >::degree_size_type degree_size_type; typedef typename graph_traits< G >::traversal_category traversal_category; BOOST_STATIC_ASSERT( (boost::mpl::not_< boost::is_same< out_edge_iterator, void > >::value)); BOOST_STATIC_ASSERT( (boost::mpl::not_< boost::is_same< degree_size_type, void > >::value)); BOOST_CONCEPT_USAGE(IncidenceGraph) { BOOST_CONCEPT_ASSERT((MultiPassInputIterator< out_edge_iterator >)); BOOST_CONCEPT_ASSERT((DefaultConstructible< edge_descriptor >)); BOOST_CONCEPT_ASSERT((EqualityComparable< edge_descriptor >)); BOOST_CONCEPT_ASSERT((Assignable< edge_descriptor >)); BOOST_CONCEPT_ASSERT( (Convertible< traversal_category, incidence_graph_tag >)); p = out_edges(u, g); n = out_degree(u, g); e = *p.first; u = source(e, g); v = target(e, g); const_constraints(g); } void const_constraints(const G& cg) { p = out_edges(u, cg); n = out_degree(u, cg); e = *p.first; u = source(e, cg); v = target(e, cg); } std::pair< out_edge_iterator, out_edge_iterator > p; typename graph_traits< G >::vertex_descriptor u, v; typename graph_traits< G >::edge_descriptor e; typename graph_traits< G >::degree_size_type n; G g; }; BOOST_concept(BidirectionalGraph, (G)) : IncidenceGraph< G > { typedef typename graph_traits< G >::in_edge_iterator in_edge_iterator; typedef typename graph_traits< G >::traversal_category traversal_category; BOOST_CONCEPT_USAGE(BidirectionalGraph) { BOOST_CONCEPT_ASSERT((MultiPassInputIterator< in_edge_iterator >)); BOOST_CONCEPT_ASSERT( (Convertible< traversal_category, bidirectional_graph_tag >)); BOOST_STATIC_ASSERT((boost::mpl::not_< boost::is_same< in_edge_iterator, void > >::value)); p = in_edges(v, g); n = in_degree(v, g); n = degree(v, g); e = *p.first; const_constraints(g); } void const_constraints(const G& cg) { p = in_edges(v, cg); n = in_degree(v, cg); n = degree(v, cg); e = *p.first; } std::pair< in_edge_iterator, in_edge_iterator > p; typename graph_traits< G >::vertex_descriptor v; typename graph_traits< G >::edge_descriptor e; typename graph_traits< G >::degree_size_type n; G g; }; BOOST_concept(AdjacencyGraph, (G)) : Graph< G > { typedef typename graph_traits< G >::adjacency_iterator adjacency_iterator; typedef typename graph_traits< G >::traversal_category traversal_category; BOOST_CONCEPT_USAGE(AdjacencyGraph) { BOOST_CONCEPT_ASSERT((MultiPassInputIterator< adjacency_iterator >)); BOOST_CONCEPT_ASSERT( (Convertible< traversal_category, adjacency_graph_tag >)); BOOST_STATIC_ASSERT((boost::mpl::not_< boost::is_same< adjacency_iterator, void > >::value)); p = adjacent_vertices(v, g); v = *p.first; const_constraints(g); } void const_constraints(const G& cg) { p = adjacent_vertices(v, cg); } std::pair< adjacency_iterator, adjacency_iterator > p; typename graph_traits< G >::vertex_descriptor v; G g; }; BOOST_concept(VertexListGraph, (G)) : Graph< G > { typedef typename graph_traits< G >::vertex_iterator vertex_iterator; typedef typename graph_traits< G >::vertices_size_type vertices_size_type; typedef typename graph_traits< G >::traversal_category traversal_category; BOOST_CONCEPT_USAGE(VertexListGraph) { BOOST_CONCEPT_ASSERT((MultiPassInputIterator< vertex_iterator >)); BOOST_CONCEPT_ASSERT( (Convertible< traversal_category, vertex_list_graph_tag >)); BOOST_STATIC_ASSERT((boost::mpl::not_< boost::is_same< vertex_iterator, void > >::value)); BOOST_STATIC_ASSERT((boost::mpl::not_< boost::is_same< vertices_size_type, void > >::value)); #ifdef BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK // dwa 2003/7/11 -- This clearly shouldn't be necessary, but if // you want to use vector_as_graph, it is! I'm sure the graph // library leaves these out all over the place. Probably a // redesign involving specializing a template with a static // member function is in order :( using boost::vertices; #endif p = vertices(g); v = *p.first; const_constraints(g); } void const_constraints(const G& cg) { #ifdef BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK // dwa 2003/7/11 -- This clearly shouldn't be necessary, but if // you want to use vector_as_graph, it is! I'm sure the graph // library leaves these out all over the place. Probably a // redesign involving specializing a template with a static // member function is in order :( using boost::vertices; #endif p = vertices(cg); v = *p.first; V = num_vertices(cg); } std::pair< vertex_iterator, vertex_iterator > p; typename graph_traits< G >::vertex_descriptor v; G g; vertices_size_type V; }; BOOST_concept(EdgeListGraph, (G)) : Graph< G > { typedef typename graph_traits< G >::edge_descriptor edge_descriptor; typedef typename graph_traits< G >::edge_iterator edge_iterator; typedef typename graph_traits< G >::edges_size_type edges_size_type; typedef typename graph_traits< G >::traversal_category traversal_category; BOOST_CONCEPT_USAGE(EdgeListGraph) { BOOST_CONCEPT_ASSERT((MultiPassInputIterator< edge_iterator >)); BOOST_CONCEPT_ASSERT((DefaultConstructible< edge_descriptor >)); BOOST_CONCEPT_ASSERT((EqualityComparable< edge_descriptor >)); BOOST_CONCEPT_ASSERT((Assignable< edge_descriptor >)); BOOST_CONCEPT_ASSERT( (Convertible< traversal_category, edge_list_graph_tag >)); BOOST_STATIC_ASSERT( (boost::mpl::not_< boost::is_same< edge_iterator, void > >::value)); BOOST_STATIC_ASSERT((boost::mpl::not_< boost::is_same< edges_size_type, void > >::value)); p = edges(g); e = *p.first; u = source(e, g); v = target(e, g); const_constraints(g); } void const_constraints(const G& cg) { p = edges(cg); E = num_edges(cg); e = *p.first; u = source(e, cg); v = target(e, cg); } std::pair< edge_iterator, edge_iterator > p; typename graph_traits< G >::vertex_descriptor u, v; typename graph_traits< G >::edge_descriptor e; edges_size_type E; G g; }; BOOST_concept(VertexAndEdgeListGraph, (G)) : VertexListGraph< G >, EdgeListGraph< G > {}; // Where to put the requirement for this constructor? // G g(n_vertices); // Not in mutable graph, then LEDA graph's can't be models of // MutableGraph. BOOST_concept(EdgeMutableGraph, (G)) { typedef typename graph_traits< G >::edge_descriptor edge_descriptor; BOOST_CONCEPT_USAGE(EdgeMutableGraph) { p = add_edge(u, v, g); remove_edge(u, v, g); remove_edge(e, g); clear_vertex(v, g); } G g; edge_descriptor e; std::pair< edge_descriptor, bool > p; typename graph_traits< G >::vertex_descriptor u, v; }; BOOST_concept(VertexMutableGraph, (G)) { BOOST_CONCEPT_USAGE(VertexMutableGraph) { v = add_vertex(g); remove_vertex(v, g); } G g; typename graph_traits< G >::vertex_descriptor u, v; }; BOOST_concept(MutableGraph, (G)) : EdgeMutableGraph< G >, VertexMutableGraph< G > {}; template < class edge_descriptor > struct dummy_edge_predicate { bool operator()(const edge_descriptor&) const { return false; } }; BOOST_concept(MutableIncidenceGraph, (G)) : MutableGraph< G > { BOOST_CONCEPT_USAGE(MutableIncidenceGraph) { remove_edge(iter, g); remove_out_edge_if(u, p, g); } G g; typedef typename graph_traits< G >::edge_descriptor edge_descriptor; dummy_edge_predicate< edge_descriptor > p; typename boost::graph_traits< G >::vertex_descriptor u; typename boost::graph_traits< G >::out_edge_iterator iter; }; BOOST_concept(MutableBidirectionalGraph, (G)) : MutableIncidenceGraph< G > { BOOST_CONCEPT_USAGE(MutableBidirectionalGraph) { remove_in_edge_if(u, p, g); } G g; typedef typename graph_traits< G >::edge_descriptor edge_descriptor; dummy_edge_predicate< edge_descriptor > p; typename boost::graph_traits< G >::vertex_descriptor u; }; BOOST_concept(MutableEdgeListGraph, (G)) : EdgeMutableGraph< G > { BOOST_CONCEPT_USAGE(MutableEdgeListGraph) { remove_edge_if(p, g); } G g; typedef typename graph_traits< G >::edge_descriptor edge_descriptor; dummy_edge_predicate< edge_descriptor > p; }; BOOST_concept(VertexMutablePropertyGraph, (G)) : VertexMutableGraph< G > { BOOST_CONCEPT_USAGE(VertexMutablePropertyGraph) { v = add_vertex(vp, g); } G g; typename graph_traits< G >::vertex_descriptor v; typename vertex_property_type< G >::type vp; }; BOOST_concept(EdgeMutablePropertyGraph, (G)) : EdgeMutableGraph< G > { typedef typename graph_traits< G >::edge_descriptor edge_descriptor; BOOST_CONCEPT_USAGE(EdgeMutablePropertyGraph) { p = add_edge(u, v, ep, g); } G g; std::pair< edge_descriptor, bool > p; typename graph_traits< G >::vertex_descriptor u, v; typename edge_property_type< G >::type ep; }; BOOST_concept(AdjacencyMatrix, (G)) : Graph< G > { typedef typename graph_traits< G >::edge_descriptor edge_descriptor; BOOST_CONCEPT_USAGE(AdjacencyMatrix) { p = edge(u, v, g); const_constraints(g); } void const_constraints(const G& cg) { p = edge(u, v, cg); } typename graph_traits< G >::vertex_descriptor u, v; std::pair< edge_descriptor, bool > p; G g; }; BOOST_concept(ReadablePropertyGraph, (G)(X)(Property)) : Graph< G > { typedef typename property_map< G, Property >::const_type const_Map; BOOST_CONCEPT_USAGE(ReadablePropertyGraph) { BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< const_Map, X >)); const_constraints(g); } void const_constraints(const G& cg) { const_Map pmap = get(Property(), cg); pval = get(Property(), cg, x); ignore_unused_variable_warning(pmap); } G g; X x; typename property_traits< const_Map >::value_type pval; }; BOOST_concept(PropertyGraph, (G)(X)(Property)) : ReadablePropertyGraph< G, X, Property > { typedef typename property_map< G, Property >::type Map; BOOST_CONCEPT_USAGE(PropertyGraph) { BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< Map, X >)); Map pmap = get(Property(), g); pval = get(Property(), g, x); put(Property(), g, x, pval); ignore_unused_variable_warning(pmap); } G g; X x; typename property_traits< Map >::value_type pval; }; BOOST_concept(LvaluePropertyGraph, (G)(X)(Property)) : ReadablePropertyGraph< G, X, Property > { typedef typename property_map< G, Property >::type Map; typedef typename property_map< G, Property >::const_type const_Map; BOOST_CONCEPT_USAGE(LvaluePropertyGraph) { BOOST_CONCEPT_ASSERT((LvaluePropertyMapConcept< const_Map, X >)); pval = get(Property(), g, x); put(Property(), g, x, pval); } G g; X x; typename property_traits< Map >::value_type pval; }; // The *IndexGraph concepts are "semantic" graph concpepts. These can be // applied to describe any graph that has an index map that can be accessed // using the get(*_index, g) method. For example, adjacency lists with // VertexSet == vecS are implicitly models of this concept. // // NOTE: We could require an associated type vertex_index_type, but that // would mean propagating that type name into graph_traits and all of the // other graph implementations. Much easier to simply call it unsigned. BOOST_concept(VertexIndexGraph, (Graph)) { BOOST_CONCEPT_USAGE(VertexIndexGraph) { typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename property_map< Graph, vertex_index_t >::type Map; typedef unsigned Index; // This could be Graph::vertex_index_type Map m = get(vertex_index, g); Index x = get(vertex_index, g, Vertex()); ignore_unused_variable_warning(m); ignore_unused_variable_warning(x); // This is relaxed renumber_vertex_indices(g); const_constraints(g); } void const_constraints(const Graph& g_) { typedef typename property_map< Graph, vertex_index_t >::const_type Map; Map m = get(vertex_index, g_); ignore_unused_variable_warning(m); } private: Graph g; }; BOOST_concept(EdgeIndexGraph, (Graph)) { BOOST_CONCEPT_USAGE(EdgeIndexGraph) { typedef typename graph_traits< Graph >::edge_descriptor Edge; typedef typename property_map< Graph, edge_index_t >::type Map; typedef unsigned Index; // This could be Graph::vertex_index_type Map m = get(edge_index, g); Index x = get(edge_index, g, Edge()); ignore_unused_variable_warning(m); ignore_unused_variable_warning(x); // This is relaxed renumber_edge_indices(g); const_constraints(g); } void const_constraints(const Graph& g_) { typedef typename property_map< Graph, edge_index_t >::const_type Map; Map m = get(edge_index, g_); ignore_unused_variable_warning(m); } private: Graph g; }; BOOST_concept(ColorValue, (C)) : EqualityComparable< C >, DefaultConstructible< C > { BOOST_CONCEPT_USAGE(ColorValue) { c = color_traits< C >::white(); c = color_traits< C >::gray(); c = color_traits< C >::black(); } C c; }; BOOST_concept(BasicMatrix, (M)(I)(V)) { BOOST_CONCEPT_USAGE(BasicMatrix) { V& elt = A[i][j]; const_constraints(A); ignore_unused_variable_warning(elt); } void const_constraints(const M& cA) { const V& elt = cA[i][j]; ignore_unused_variable_warning(elt); } M A; I i, j; }; // The following concepts describe aspects of numberic values and measure // functions. We're extending the notion of numeric values to include // emulation for zero and infinity. BOOST_concept(NumericValue, (Numeric)) { BOOST_CONCEPT_USAGE(NumericValue) { BOOST_CONCEPT_ASSERT((DefaultConstructible< Numeric >)); BOOST_CONCEPT_ASSERT((CopyConstructible< Numeric >)); numeric_values< Numeric >::zero(); numeric_values< Numeric >::infinity(); } } ; BOOST_concept(DegreeMeasure, (Measure)(Graph)) { BOOST_CONCEPT_USAGE(DegreeMeasure) { typedef typename Measure::degree_type Degree; typedef typename Measure::vertex_type Vertex; Degree d = m(Vertex(), g); ignore_unused_variable_warning(d); } private: Measure m; Graph g; }; BOOST_concept(DistanceMeasure, (Measure)(Graph)) { BOOST_CONCEPT_USAGE(DistanceMeasure) { typedef typename Measure::distance_type Distance; typedef typename Measure::result_type Result; Result r = m(Distance(), g); ignore_unused_variable_warning(r); } private: Measure m; Graph g; }; } /* namespace concepts */ using boost::concepts::MultiPassInputIteratorConcept; // Graph concepts using boost::concepts::AdjacencyGraphConcept; using boost::concepts::AdjacencyMatrixConcept; using boost::concepts::BidirectionalGraphConcept; using boost::concepts::EdgeIndexGraphConcept; using boost::concepts::EdgeListGraphConcept; using boost::concepts::EdgeMutableGraphConcept; using boost::concepts::EdgeMutablePropertyGraphConcept; using boost::concepts::GraphConcept; using boost::concepts::IncidenceGraphConcept; using boost::concepts::LvaluePropertyGraphConcept; using boost::concepts::MutableBidirectionalGraphConcept; using boost::concepts::MutableEdgeListGraphConcept; using boost::concepts::MutableGraphConcept; using boost::concepts::MutableIncidenceGraphConcept; using boost::concepts::PropertyGraphConcept; using boost::concepts::ReadablePropertyGraphConcept; using boost::concepts::VertexAndEdgeListGraphConcept; using boost::concepts::VertexIndexGraphConcept; using boost::concepts::VertexListGraphConcept; using boost::concepts::VertexMutableGraphConcept; using boost::concepts::VertexMutablePropertyGraphConcept; // Utility concepts using boost::concepts::BasicMatrixConcept; using boost::concepts::ColorValueConcept; using boost::concepts::DegreeMeasureConcept; using boost::concepts::DistanceMeasureConcept; using boost::concepts::NumericValueConcept; } /* namespace boost */ #include <boost/concept/detail/concept_undef.hpp> #endif /* BOOST_GRAPH_CONCEPTS_H */ graph_as_tree.hpp 0000644 00000010664 15125521275 0010074 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_GRAPH_AS_TREE_HPP #define BOOST_GRAPH_GRAPH_AS_TREE_HPP #include <vector> #include <boost/config.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/tree_traits.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/visitors.hpp> namespace boost { template < class Graph, class Node, class ChIt, class Derived > class graph_as_tree_base { typedef Derived Tree; public: typedef Node node_descriptor; typedef ChIt children_iterator; graph_as_tree_base(Graph& g, Node root) : _g(g), _root(root) {} friend Node root(const Tree& t) { return t._root; } template < class N > friend std::pair< ChIt, ChIt > children(N n, const Tree& t) { return adjacent_vertices(n, t._g); } template < class N > friend Node parent(N n, const Tree& t) { return boost::get(t.parent_pa(), n); } Graph& _g; Node _root; }; struct graph_as_tree_tag { }; template < class Graph, class ParentMap, class Node = typename graph_traits< Graph >::vertex_descriptor, class ChIt = typename graph_traits< Graph >::adjacency_iterator > class graph_as_tree : public graph_as_tree_base< Graph, Node, ChIt, graph_as_tree< Graph, ParentMap, Node, ChIt > > { typedef graph_as_tree self; typedef graph_as_tree_base< Graph, Node, ChIt, self > super; public: graph_as_tree(Graph& g, Node root) : super(g, root) {} graph_as_tree(Graph& g, Node root, ParentMap p) : super(g, root), _p(p) { breadth_first_search(g, root, visitor(make_bfs_visitor( record_predecessors(p, boost::on_tree_edge())))); } ParentMap parent_pa() const { return _p; } typedef graph_as_tree_tag graph_tag; // for property_map protected: ParentMap _p; }; namespace detail { struct graph_as_tree_vertex_property_selector { template < typename GraphAsTree, typename Property, typename Tag > struct bind_ { typedef typename GraphAsTree::base_type Graph; typedef property_map< Graph, Tag > PMap; typedef typename PMap::type type; typedef typename PMap::const_type const_type; }; }; struct graph_as_tree_edge_property_selector { template < typename GraphAsTree, typename Property, typename Tag > struct bind_ { typedef typename GraphAsTree::base_type Graph; typedef property_map< Graph, Tag > PMap; typedef typename PMap::type type; typedef typename PMap::const_type const_type; }; }; } // namespace detail template <> struct vertex_property_selector< graph_as_tree_tag > { typedef detail::graph_as_tree_vertex_property_selector type; }; template <> struct edge_property_selector< graph_as_tree_tag > { typedef detail::graph_as_tree_edge_property_selector type; }; template < typename Graph, typename P, typename N, typename C, typename Property > typename property_map< Graph, Property >::type get( Property p, graph_as_tree< Graph, P, N, C >& g) { return get(p, g._g); } template < typename Graph, typename P, typename N, typename C, typename Property > typename property_map< Graph, Property >::const_type get( Property p, const graph_as_tree< Graph, P, N, C >& g) { const Graph& gref = g._g; // in case GRef is non-const return get(p, gref); } template < typename Graph, typename P, typename N, typename C, typename Property, typename Key > typename property_traits< typename property_map< Graph, Property >::const_type >::value_type get(Property p, const graph_as_tree< Graph, P, N, C >& g, const Key& k) { return get(p, g._g, k); } template < typename Graph, typename P, typename N, typename C, typename Property, typename Key, typename Value > void put(Property p, const graph_as_tree< Graph, P, N, C >& g, const Key& k, const Value& val) { put(p, g._g, k, val); } } // namespace boost #endif // BOOST_GRAPH_GRAPH_AS_TREE_HPP maximum_weighted_matching.hpp 0000644 00000141072 15125521275 0012476 0 ustar 00 //======================================================================= // Copyright (c) 2018 Yi Ji // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // //======================================================================= #ifndef BOOST_GRAPH_MAXIMUM_WEIGHTED_MATCHING_HPP #define BOOST_GRAPH_MAXIMUM_WEIGHTED_MATCHING_HPP #include <algorithm> // for std::iter_swap #include <boost/shared_ptr.hpp> #include <boost/make_shared.hpp> #include <boost/graph/max_cardinality_matching.hpp> namespace boost { template < typename Graph, typename MateMap, typename VertexIndexMap > typename property_traits< typename property_map< Graph, edge_weight_t >::type >::value_type matching_weight_sum(const Graph& g, MateMap mate, VertexIndexMap vm) { typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t; typedef typename property_traits< typename property_map< Graph, edge_weight_t >::type >::value_type edge_property_t; edge_property_t weight_sum = 0; vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { vertex_descriptor_t v = *vi; if (get(mate, v) != graph_traits< Graph >::null_vertex() && get(vm, v) < get(vm, get(mate, v))) weight_sum += get(edge_weight, g, edge(v, mate[v], g).first); } return weight_sum; } template < typename Graph, typename MateMap > inline typename property_traits< typename property_map< Graph, edge_weight_t >::type >::value_type matching_weight_sum(const Graph& g, MateMap mate) { return matching_weight_sum(g, mate, get(vertex_index, g)); } template < typename Graph, typename MateMap, typename VertexIndexMap > class weighted_augmenting_path_finder { public: template < typename T > struct map_vertex_to_ { typedef boost::iterator_property_map< typename std::vector< T >::iterator, VertexIndexMap > type; }; typedef typename graph::detail::VERTEX_STATE vertex_state_t; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t; typedef typename std::vector< vertex_descriptor_t >::const_iterator vertex_vec_iter_t; typedef typename graph_traits< Graph >::out_edge_iterator out_edge_iterator_t; typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor_t; typedef typename graph_traits< Graph >::edge_iterator edge_iterator_t; typedef typename property_traits< typename property_map< Graph, edge_weight_t >::type >::value_type edge_property_t; typedef std::deque< vertex_descriptor_t > vertex_list_t; typedef std::vector< edge_descriptor_t > edge_list_t; typedef typename map_vertex_to_< vertex_descriptor_t >::type vertex_to_vertex_map_t; typedef typename map_vertex_to_< edge_property_t >::type vertex_to_weight_map_t; typedef typename map_vertex_to_< bool >::type vertex_to_bool_map_t; typedef typename map_vertex_to_< std::pair< vertex_descriptor_t, vertex_descriptor_t > >::type vertex_to_pair_map_t; typedef typename map_vertex_to_< std::pair< edge_descriptor_t, bool > >::type vertex_to_edge_map_t; typedef typename map_vertex_to_< vertex_to_edge_map_t >::type vertex_pair_to_edge_map_t; class blossom { public: typedef boost::shared_ptr< blossom > blossom_ptr_t; std::vector< blossom_ptr_t > sub_blossoms; edge_property_t dual_var; blossom_ptr_t father; blossom() : dual_var(0), father(blossom_ptr_t()) {} // get the base vertex of a blossom by recursively getting // its base sub-blossom, which is always the first one in // sub_blossoms because of how we create and maintain blossoms virtual vertex_descriptor_t get_base() const { const blossom* b = this; while (!b->sub_blossoms.empty()) b = b->sub_blossoms[0].get(); return b->get_base(); } // set a sub-blossom as a blossom's base by exchanging it // with its first sub-blossom void set_base(const blossom_ptr_t& sub) { for (blossom_iterator_t bi = sub_blossoms.begin(); bi != sub_blossoms.end(); ++bi) { if (sub.get() == bi->get()) { std::iter_swap(sub_blossoms.begin(), bi); break; } } } // get all vertices inside recursively virtual std::vector< vertex_descriptor_t > vertices() const { std::vector< vertex_descriptor_t > all_vertices; for (typename std::vector< blossom_ptr_t >::const_iterator bi = sub_blossoms.begin(); bi != sub_blossoms.end(); ++bi) { std::vector< vertex_descriptor_t > some_vertices = (*bi)->vertices(); all_vertices.insert(all_vertices.end(), some_vertices.begin(), some_vertices.end()); } return all_vertices; } }; // a trivial_blossom only has one vertex and no sub-blossom; // for each vertex v, in_blossom[v] is the trivial_blossom that contains it // directly class trivial_blossom : public blossom { public: trivial_blossom(vertex_descriptor_t v) : trivial_vertex(v) {} virtual vertex_descriptor_t get_base() const { return trivial_vertex; } virtual std::vector< vertex_descriptor_t > vertices() const { std::vector< vertex_descriptor_t > all_vertices; all_vertices.push_back(trivial_vertex); return all_vertices; } private: vertex_descriptor_t trivial_vertex; }; typedef boost::shared_ptr< blossom > blossom_ptr_t; typedef typename std::vector< blossom_ptr_t >::iterator blossom_iterator_t; typedef typename map_vertex_to_< blossom_ptr_t >::type vertex_to_blossom_map_t; weighted_augmenting_path_finder( const Graph& arg_g, MateMap arg_mate, VertexIndexMap arg_vm) : g(arg_g) , vm(arg_vm) , null_edge(std::pair< edge_descriptor_t, bool >( num_edges(g) == 0 ? edge_descriptor_t() : *edges(g).first, false)) , mate_vector(num_vertices(g)) , label_S_vector(num_vertices(g), graph_traits< Graph >::null_vertex()) , label_T_vector(num_vertices(g), graph_traits< Graph >::null_vertex()) , outlet_vector(num_vertices(g), graph_traits< Graph >::null_vertex()) , tau_idx_vector(num_vertices(g), graph_traits< Graph >::null_vertex()) , dual_var_vector(std::vector< edge_property_t >( num_vertices(g), std::numeric_limits< edge_property_t >::min())) , pi_vector(std::vector< edge_property_t >( num_vertices(g), std::numeric_limits< edge_property_t >::max())) , gamma_vector(std::vector< edge_property_t >( num_vertices(g), std::numeric_limits< edge_property_t >::max())) , tau_vector(std::vector< edge_property_t >( num_vertices(g), std::numeric_limits< edge_property_t >::max())) , in_blossom_vector(num_vertices(g)) , old_label_vector(num_vertices(g)) , critical_edge_vectors(num_vertices(g), std::vector< std::pair< edge_descriptor_t, bool > >( num_vertices(g), null_edge)) , mate(mate_vector.begin(), vm) , label_S(label_S_vector.begin(), vm) , label_T(label_T_vector.begin(), vm) , outlet(outlet_vector.begin(), vm) , tau_idx(tau_idx_vector.begin(), vm) , dual_var(dual_var_vector.begin(), vm) , pi(pi_vector.begin(), vm) , gamma(gamma_vector.begin(), vm) , tau(tau_vector.begin(), vm) , in_blossom(in_blossom_vector.begin(), vm) , old_label(old_label_vector.begin(), vm) { vertex_iterator_t vi, vi_end; edge_iterator_t ei, ei_end; edge_property_t max_weight = std::numeric_limits< edge_property_t >::min(); for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) max_weight = std::max(max_weight, get(edge_weight, g, *ei)); typename std::vector< std::vector< std::pair< edge_descriptor_t, bool > > >::iterator vei; for (boost::tie(vi, vi_end) = vertices(g), vei = critical_edge_vectors.begin(); vi != vi_end; ++vi, ++vei) { vertex_descriptor_t u = *vi; mate[u] = get(arg_mate, u); dual_var[u] = 2 * max_weight; in_blossom[u] = boost::make_shared< trivial_blossom >(u); outlet[u] = u; critical_edge_vector.push_back( vertex_to_edge_map_t(vei->begin(), vm)); } critical_edge = vertex_pair_to_edge_map_t(critical_edge_vector.begin(), vm); init(); } // return the top blossom where v is contained inside blossom_ptr_t in_top_blossom(vertex_descriptor_t v) const { blossom_ptr_t b = in_blossom[v]; while (b->father != blossom_ptr_t()) b = b->father; return b; } // check if vertex v is in blossom b bool is_in_blossom(blossom_ptr_t b, vertex_descriptor_t v) const { if (v == graph_traits< Graph >::null_vertex()) return false; blossom_ptr_t vb = in_blossom[v]->father; while (vb != blossom_ptr_t()) { if (vb.get() == b.get()) return true; vb = vb->father; } return false; } // return the base vertex of the top blossom that contains v inline vertex_descriptor_t base_vertex(vertex_descriptor_t v) const { return in_top_blossom(v)->get_base(); } // add an existed top blossom of base vertex v into new top // blossom b as its sub-blossom void add_sub_blossom(blossom_ptr_t b, vertex_descriptor_t v) { blossom_ptr_t sub = in_top_blossom(v); sub->father = b; b->sub_blossoms.push_back(sub); if (sub->sub_blossoms.empty()) return; for (blossom_iterator_t bi = top_blossoms.begin(); bi != top_blossoms.end(); ++bi) { if (bi->get() == sub.get()) { top_blossoms.erase(bi); break; } } } // when a top blossom is created or its base vertex getting an S-label, // add all edges incident to this blossom into even_edges void bloom(blossom_ptr_t b) { std::vector< vertex_descriptor_t > vertices_of_b = b->vertices(); vertex_vec_iter_t vi; for (vi = vertices_of_b.begin(); vi != vertices_of_b.end(); ++vi) { out_edge_iterator_t oei, oei_end; for (boost::tie(oei, oei_end) = out_edges(*vi, g); oei != oei_end; ++oei) { if (target(*oei, g) != *vi && mate[*vi] != target(*oei, g)) even_edges.push_back(*oei); } } } // assigning a T-label to a non S-vertex, along with outlet and updating pi // value if updated pi[v] equals zero, augment the matching from its mate // vertex void put_T_label(vertex_descriptor_t v, vertex_descriptor_t T_label, vertex_descriptor_t outlet_v, edge_property_t pi_v) { if (label_S[v] != graph_traits< Graph >::null_vertex()) return; label_T[v] = T_label; outlet[v] = outlet_v; pi[v] = pi_v; vertex_descriptor_t v_mate = mate[v]; if (pi[v] == 0) { label_T[v_mate] = graph_traits< Graph >::null_vertex(); label_S[v_mate] = v; bloom(in_top_blossom(v_mate)); } } // get the missing T-label for a to-be-expanded base vertex // the missing T-label is the last vertex of the path from outlet[v] to v std::pair< vertex_descriptor_t, vertex_descriptor_t > missing_label( vertex_descriptor_t b_base) { vertex_descriptor_t missing_outlet = outlet[b_base]; if (outlet[b_base] == b_base) return std::make_pair( graph_traits< Graph >::null_vertex(), missing_outlet); vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) old_label[*vi] = std::make_pair(label_T[*vi], outlet[*vi]); std::pair< vertex_descriptor_t, vertex_state_t > child( outlet[b_base], graph::detail::V_EVEN); blossom_ptr_t b = in_blossom[child.first]; for (; b->father->father != blossom_ptr_t(); b = b->father) ; child.first = b->get_base(); if (child.first == b_base) return std::make_pair( graph_traits< Graph >::null_vertex(), missing_outlet); while (true) { std::pair< vertex_descriptor_t, vertex_state_t > child_parent = parent(child, true); for (b = in_blossom[child_parent.first]; b->father->father != blossom_ptr_t(); b = b->father) ; missing_outlet = child_parent.first; child_parent.first = b->get_base(); if (child_parent.first == b_base) break; else child = child_parent; } return std::make_pair(child.first, missing_outlet); } // expand a top blossom, put all its non-trivial sub-blossoms into // top_blossoms blossom_iterator_t expand_blossom( blossom_iterator_t bi, std::vector< blossom_ptr_t >& new_ones) { blossom_ptr_t b = *bi; for (blossom_iterator_t i = b->sub_blossoms.begin(); i != b->sub_blossoms.end(); ++i) { blossom_ptr_t sub_blossom = *i; vertex_descriptor_t sub_base = sub_blossom->get_base(); label_S[sub_base] = label_T[sub_base] = graph_traits< Graph >::null_vertex(); outlet[sub_base] = sub_base; sub_blossom->father = blossom_ptr_t(); // new top blossoms cannot be pushed back into top_blossoms // immediately, because push_back() may cause reallocation and then // invalid iterators if (!sub_blossom->sub_blossoms.empty()) new_ones.push_back(sub_blossom); } return top_blossoms.erase(bi); } // when expanding a T-blossom with base v, it requires more operations: // supply the missing T-labels for new base vertices by picking the minimum // tau from vertices of each corresponding new top-blossoms; when label_T[v] // is null or we have a smaller tau from missing_label(v), replace T-label // and outlet of v (but don't bloom v) blossom_iterator_t expand_T_blossom( blossom_iterator_t bi, std::vector< blossom_ptr_t >& new_ones) { blossom_ptr_t b = *bi; vertex_descriptor_t b_base = b->get_base(); std::pair< vertex_descriptor_t, vertex_descriptor_t > T_and_outlet = missing_label(b_base); blossom_iterator_t next_bi = expand_blossom(bi, new_ones); for (blossom_iterator_t i = b->sub_blossoms.begin(); i != b->sub_blossoms.end(); ++i) { blossom_ptr_t sub_blossom = *i; vertex_descriptor_t sub_base = sub_blossom->get_base(); vertex_descriptor_t min_tau_v = graph_traits< Graph >::null_vertex(); edge_property_t min_tau = std::numeric_limits< edge_property_t >::max(); std::vector< vertex_descriptor_t > sub_vertices = sub_blossom->vertices(); for (vertex_vec_iter_t v = sub_vertices.begin(); v != sub_vertices.end(); ++v) { if (tau[*v] < min_tau) { min_tau = tau[*v]; min_tau_v = *v; } } if (min_tau < std::numeric_limits< edge_property_t >::max()) put_T_label( sub_base, tau_idx[min_tau_v], min_tau_v, tau[min_tau_v]); } if (label_T[b_base] == graph_traits< Graph >::null_vertex() || tau[old_label[b_base].second] < pi[b_base]) boost::tie(label_T[b_base], outlet[b_base]) = T_and_outlet; return next_bi; } // when vertices v and w are matched to each other by augmenting, // we must set v/w as base vertex of any blossom who contains v/w and // is a sub-blossom of their lowest (smallest) common blossom void adjust_blossom(vertex_descriptor_t v, vertex_descriptor_t w) { blossom_ptr_t vb = in_blossom[v], wb = in_blossom[w], lowest_common_blossom; std::vector< blossom_ptr_t > v_ancestors, w_ancestors; while (vb->father != blossom_ptr_t()) { v_ancestors.push_back(vb->father); vb = vb->father; } while (wb->father != blossom_ptr_t()) { w_ancestors.push_back(wb->father); wb = wb->father; } typename std::vector< blossom_ptr_t >::reverse_iterator i, j; i = v_ancestors.rbegin(); j = w_ancestors.rbegin(); while (i != v_ancestors.rend() && j != w_ancestors.rend() && i->get() == j->get()) { lowest_common_blossom = *i; ++i; ++j; } vb = in_blossom[v]; wb = in_blossom[w]; while (vb->father != lowest_common_blossom) { vb->father->set_base(vb); vb = vb->father; } while (wb->father != lowest_common_blossom) { wb->father->set_base(wb); wb = wb->father; } } // every edge weight is multiplied by 4 to ensure integer weights // throughout the algorithm if all input weights are integers inline edge_property_t slack(const edge_descriptor_t& e) const { vertex_descriptor_t v, w; v = source(e, g); w = target(e, g); return dual_var[v] + dual_var[w] - 4 * get(edge_weight, g, e); } // backtrace one step on vertex v along the augmenting path // by its labels and its vertex state; // boolean parameter "use_old" means whether we are updating labels, // if we are, then we use old labels to backtrace and also we // don't jump to its base vertex when we reach an odd vertex std::pair< vertex_descriptor_t, vertex_state_t > parent( std::pair< vertex_descriptor_t, vertex_state_t > v, bool use_old = false) const { if (v.second == graph::detail::V_EVEN) { // a paranoid check: label_S shoule be the same as mate in // backtracing if (label_S[v.first] == graph_traits< Graph >::null_vertex()) label_S[v.first] = mate[v.first]; return std::make_pair(label_S[v.first], graph::detail::V_ODD); } else if (v.second == graph::detail::V_ODD) { vertex_descriptor_t w = use_old ? old_label[v.first].first : base_vertex(label_T[v.first]); return std::make_pair(w, graph::detail::V_EVEN); } return std::make_pair(v.first, graph::detail::V_UNREACHED); } // backtrace from vertices v and w to their free (unmatched) ancesters, // return the nearest common ancestor (null_vertex if none) of v and w vertex_descriptor_t nearest_common_ancestor(vertex_descriptor_t v, vertex_descriptor_t w, vertex_descriptor_t& v_free_ancestor, vertex_descriptor_t& w_free_ancestor) const { std::pair< vertex_descriptor_t, vertex_state_t > v_up( v, graph::detail::V_EVEN); std::pair< vertex_descriptor_t, vertex_state_t > w_up( w, graph::detail::V_EVEN); vertex_descriptor_t nca; nca = w_free_ancestor = v_free_ancestor = graph_traits< Graph >::null_vertex(); std::vector< bool > ancestor_of_w_vector(num_vertices(g), false); std::vector< bool > ancestor_of_v_vector(num_vertices(g), false); vertex_to_bool_map_t ancestor_of_w(ancestor_of_w_vector.begin(), vm); vertex_to_bool_map_t ancestor_of_v(ancestor_of_v_vector.begin(), vm); while (nca == graph_traits< Graph >::null_vertex() && (v_free_ancestor == graph_traits< Graph >::null_vertex() || w_free_ancestor == graph_traits< Graph >::null_vertex())) { ancestor_of_w[w_up.first] = true; ancestor_of_v[v_up.first] = true; if (w_free_ancestor == graph_traits< Graph >::null_vertex()) w_up = parent(w_up); if (v_free_ancestor == graph_traits< Graph >::null_vertex()) v_up = parent(v_up); if (mate[v_up.first] == graph_traits< Graph >::null_vertex()) v_free_ancestor = v_up.first; if (mate[w_up.first] == graph_traits< Graph >::null_vertex()) w_free_ancestor = w_up.first; if (ancestor_of_w[v_up.first] == true || v_up.first == w_up.first) nca = v_up.first; else if (ancestor_of_v[w_up.first] == true) nca = w_up.first; else if (v_free_ancestor == w_free_ancestor && v_free_ancestor != graph_traits< Graph >::null_vertex()) nca = v_up.first; } return nca; } // when a new top blossom b is created by connecting (v, w), we add // sub-blossoms into b along backtracing from v_prime and w_prime to // stop_vertex (the base vertex); also, we set labels and outlet for each // base vertex we pass by void make_blossom(blossom_ptr_t b, vertex_descriptor_t w_prime, vertex_descriptor_t v_prime, vertex_descriptor_t stop_vertex) { std::pair< vertex_descriptor_t, vertex_state_t > u( v_prime, graph::detail::V_ODD); std::pair< vertex_descriptor_t, vertex_state_t > u_up( w_prime, graph::detail::V_EVEN); for (; u_up.first != stop_vertex; u = u_up, u_up = parent(u)) { if (u_up.second == graph::detail::V_EVEN) { if (!in_top_blossom(u_up.first)->sub_blossoms.empty()) outlet[u_up.first] = label_T[u.first]; label_T[u_up.first] = outlet[u.first]; } else if (u_up.second == graph::detail::V_ODD) label_S[u_up.first] = u.first; add_sub_blossom(b, u_up.first); } } // the design of recursively expanding augmenting path in // (reversed_)retrieve_augmenting_path functions is inspired by same // functions in max_cardinality_matching.hpp; except that in weighted // matching, we use "outlet" vertices instead of "bridge" vertex pairs: if // blossom b is the smallest non-trivial blossom that contains its base // vertex v, then v and outlet[v] are where augmenting path enters and // leaves b void retrieve_augmenting_path( vertex_descriptor_t v, vertex_descriptor_t w, vertex_state_t v_state) { if (v == w) aug_path.push_back(v); else if (v_state == graph::detail::V_EVEN) { aug_path.push_back(v); retrieve_augmenting_path(label_S[v], w, graph::detail::V_ODD); } else if (v_state == graph::detail::V_ODD) { if (outlet[v] == v) aug_path.push_back(v); else reversed_retrieve_augmenting_path( outlet[v], v, graph::detail::V_EVEN); retrieve_augmenting_path(label_T[v], w, graph::detail::V_EVEN); } } void reversed_retrieve_augmenting_path( vertex_descriptor_t v, vertex_descriptor_t w, vertex_state_t v_state) { if (v == w) aug_path.push_back(v); else if (v_state == graph::detail::V_EVEN) { reversed_retrieve_augmenting_path( label_S[v], w, graph::detail::V_ODD); aug_path.push_back(v); } else if (v_state == graph::detail::V_ODD) { reversed_retrieve_augmenting_path( label_T[v], w, graph::detail::V_EVEN); if (outlet[v] != v) retrieve_augmenting_path(outlet[v], v, graph::detail::V_EVEN); else aug_path.push_back(v); } } // correct labels for vertices in the augmenting path void relabel(vertex_descriptor_t v) { blossom_ptr_t b = in_blossom[v]->father; if (!is_in_blossom(b, mate[v])) { // if v is a new base vertex std::pair< vertex_descriptor_t, vertex_state_t > u( v, graph::detail::V_EVEN); while (label_S[u.first] != u.first && is_in_blossom(b, label_S[u.first])) u = parent(u, true); vertex_descriptor_t old_base = u.first; if (label_S[old_base] != old_base) { // if old base is not exposed label_T[v] = label_S[old_base]; outlet[v] = old_base; } else { // if old base is exposed then new label_T[v] is not in b, // we must (i) make b2 the smallest blossom containing v but not // as base vertex (ii) backtrace from b2's new base vertex to b label_T[v] = graph_traits< Graph >::null_vertex(); for (b = b->father; b != blossom_ptr_t() && b->get_base() == v; b = b->father) ; if (b != blossom_ptr_t()) { u = std::make_pair(b->get_base(), graph::detail::V_ODD); while (!is_in_blossom( in_blossom[v]->father, old_label[u.first].first)) u = parent(u, true); label_T[v] = u.first; outlet[v] = old_label[u.first].first; } } } else if (label_S[v] == v || !is_in_blossom(b, label_S[v])) { // if v is an old base vertex // let u be the new base vertex; backtrace from u's old T-label std::pair< vertex_descriptor_t, vertex_state_t > u( b->get_base(), graph::detail::V_ODD); while ( old_label[u.first].first != graph_traits< Graph >::null_vertex() && old_label[u.first].first != v) u = parent(u, true); label_T[v] = old_label[u.first].second; outlet[v] = v; } else // if v is neither a new nor an old base vertex label_T[v] = label_S[v]; } void augmenting(vertex_descriptor_t v, vertex_descriptor_t v_free_ancestor, vertex_descriptor_t w, vertex_descriptor_t w_free_ancestor) { vertex_iterator_t vi, vi_end; // retrieve the augmenting path and put it in aug_path reversed_retrieve_augmenting_path( v, v_free_ancestor, graph::detail::V_EVEN); retrieve_augmenting_path(w, w_free_ancestor, graph::detail::V_EVEN); // augment the matching along aug_path vertex_descriptor_t a, b; vertex_list_t reversed_aug_path; while (!aug_path.empty()) { a = aug_path.front(); aug_path.pop_front(); reversed_aug_path.push_back(a); b = aug_path.front(); aug_path.pop_front(); reversed_aug_path.push_back(b); mate[a] = b; mate[b] = a; // reset base vertex for every blossom in augment path adjust_blossom(a, b); } for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) old_label[*vi] = std::make_pair(label_T[*vi], outlet[*vi]); // correct labels for in-blossom vertices along aug_path while (!reversed_aug_path.empty()) { a = reversed_aug_path.front(); reversed_aug_path.pop_front(); if (in_blossom[a]->father != blossom_ptr_t()) relabel(a); } for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { vertex_descriptor_t u = *vi; if (mate[u] != graph_traits< Graph >::null_vertex()) label_S[u] = mate[u]; } // expand blossoms with zero dual variables std::vector< blossom_ptr_t > new_top_blossoms; for (blossom_iterator_t bi = top_blossoms.begin(); bi != top_blossoms.end();) { if ((*bi)->dual_var <= 0) bi = expand_blossom(bi, new_top_blossoms); else ++bi; } top_blossoms.insert(top_blossoms.end(), new_top_blossoms.begin(), new_top_blossoms.end()); init(); } // create a new blossom and set labels for vertices inside void blossoming(vertex_descriptor_t v, vertex_descriptor_t v_prime, vertex_descriptor_t w, vertex_descriptor_t w_prime, vertex_descriptor_t nca) { vertex_iterator_t vi, vi_end; std::vector< bool > is_old_base_vector(num_vertices(g)); vertex_to_bool_map_t is_old_base(is_old_base_vector.begin(), vm); for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { if (*vi == base_vertex(*vi)) is_old_base[*vi] = true; } blossom_ptr_t b = boost::make_shared< blossom >(); add_sub_blossom(b, nca); label_T[w_prime] = v; label_T[v_prime] = w; outlet[w_prime] = w; outlet[v_prime] = v; make_blossom(b, w_prime, v_prime, nca); make_blossom(b, v_prime, w_prime, nca); label_T[nca] = graph_traits< Graph >::null_vertex(); outlet[nca] = nca; top_blossoms.push_back(b); bloom(b); // set gamma[b_base] = min_slack{critical_edge(b_base, other_base)} // where each critical edge is updated before, by // argmin{slack(old_bases_in_b, other_base)}; vertex_vec_iter_t i, j; std::vector< vertex_descriptor_t > b_vertices = b->vertices(), old_base_in_b, other_base; vertex_descriptor_t b_base = b->get_base(); for (i = b_vertices.begin(); i != b_vertices.end(); ++i) { if (is_old_base[*i]) old_base_in_b.push_back(*i); } for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { if (*vi != b_base && *vi == base_vertex(*vi)) other_base.push_back(*vi); } for (i = other_base.begin(); i != other_base.end(); ++i) { edge_property_t min_slack = std::numeric_limits< edge_property_t >::max(); std::pair< edge_descriptor_t, bool > b_vi = null_edge; for (j = old_base_in_b.begin(); j != old_base_in_b.end(); ++j) { if (critical_edge[*j][*i] != null_edge && min_slack > slack(critical_edge[*j][*i].first)) { min_slack = slack(critical_edge[*j][*i].first); b_vi = critical_edge[*j][*i]; } } critical_edge[b_base][*i] = critical_edge[*i][b_base] = b_vi; } gamma[b_base] = std::numeric_limits< edge_property_t >::max(); for (i = other_base.begin(); i != other_base.end(); ++i) { if (critical_edge[b_base][*i] != null_edge) gamma[b_base] = std::min( gamma[b_base], slack(critical_edge[b_base][*i].first)); } } void init() { even_edges.clear(); vertex_iterator_t vi, vi_end; typename std::vector< std::vector< std::pair< edge_descriptor_t, bool > > >::iterator vei; for (boost::tie(vi, vi_end) = vertices(g), vei = critical_edge_vectors.begin(); vi != vi_end; ++vi, ++vei) { vertex_descriptor_t u = *vi; out_edge_iterator_t ei, ei_end; gamma[u] = tau[u] = pi[u] = std::numeric_limits< edge_property_t >::max(); std::fill(vei->begin(), vei->end(), null_edge); if (base_vertex(u) != u) continue; label_S[u] = label_T[u] = graph_traits< Graph >::null_vertex(); outlet[u] = u; if (mate[u] == graph_traits< Graph >::null_vertex()) { label_S[u] = u; bloom(in_top_blossom(u)); } } } bool augment_matching() { vertex_descriptor_t v, w, w_free_ancestor, v_free_ancestor; v = w = w_free_ancestor = v_free_ancestor = graph_traits< Graph >::null_vertex(); bool found_alternating_path = false; // note that we only use edges of zero slack value for augmenting while (!even_edges.empty() && !found_alternating_path) { // search for augmenting paths depth-first edge_descriptor_t current_edge = even_edges.back(); even_edges.pop_back(); v = source(current_edge, g); w = target(current_edge, g); vertex_descriptor_t v_prime = base_vertex(v); vertex_descriptor_t w_prime = base_vertex(w); // w_prime == v_prime implies that we get an edge that has been // shrunk into a blossom if (v_prime == w_prime) continue; // a paranoid check if (label_S[v_prime] == graph_traits< Graph >::null_vertex()) { std::swap(v_prime, w_prime); std::swap(v, w); } // w_prime may be unlabeled or have a T-label; replace the existed // T-label if the edge slack is smaller than current pi[w_prime] and // update it. Note that a T-label is "deserved" only when pi equals // zero. also update tau and tau_idx so that tau_idx becomes T-label // when a T-blossom is expanded if (label_S[w_prime] == graph_traits< Graph >::null_vertex()) { if (slack(current_edge) < pi[w_prime]) put_T_label(w_prime, v, w, slack(current_edge)); if (slack(current_edge) < tau[w]) { if (in_blossom[w]->father == blossom_ptr_t() || label_T[w_prime] == v || label_T[w_prime] == graph_traits< Graph >::null_vertex() || nearest_common_ancestor(v_prime, label_T[w_prime], v_free_ancestor, w_free_ancestor) == graph_traits< Graph >::null_vertex()) { tau[w] = slack(current_edge); tau_idx[w] = v; } } } else { if (slack(current_edge) > 0) { // update gamma and critical_edges when we have a smaller // edge slack gamma[v_prime] = std::min(gamma[v_prime], slack(current_edge)); gamma[w_prime] = std::min(gamma[w_prime], slack(current_edge)); if (critical_edge[v_prime][w_prime] == null_edge || slack(critical_edge[v_prime][w_prime].first) > slack(current_edge)) { critical_edge[v_prime][w_prime] = std::pair< edge_descriptor_t, bool >( current_edge, true); critical_edge[w_prime][v_prime] = std::pair< edge_descriptor_t, bool >( current_edge, true); } continue; } else if (slack(current_edge) == 0) { // if nca is null_vertex then we have an augmenting path; // otherwise we have a new top blossom with nca as its base // vertex vertex_descriptor_t nca = nearest_common_ancestor( v_prime, w_prime, v_free_ancestor, w_free_ancestor); if (nca == graph_traits< Graph >::null_vertex()) found_alternating_path = true; // to break out of the loop else blossoming(v, v_prime, w, w_prime, nca); } } } if (!found_alternating_path) return false; augmenting(v, v_free_ancestor, w, w_free_ancestor); return true; } // slack the vertex and blossom dual variables when there is no augmenting // path found according to the primal-dual method bool adjust_dual() { edge_property_t delta1, delta2, delta3, delta4, delta; delta1 = delta2 = delta3 = delta4 = std::numeric_limits< edge_property_t >::max(); vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { delta1 = std::min(delta1, dual_var[*vi]); delta4 = pi[*vi] > 0 ? std::min(delta4, pi[*vi]) : delta4; if (*vi == base_vertex(*vi)) delta3 = std::min(delta3, gamma[*vi] / 2); } for (blossom_iterator_t bi = top_blossoms.begin(); bi != top_blossoms.end(); ++bi) { vertex_descriptor_t b_base = (*bi)->get_base(); if (label_T[b_base] != graph_traits< Graph >::null_vertex() && pi[b_base] == 0) delta2 = std::min(delta2, (*bi)->dual_var / 2); } delta = std::min(std::min(delta1, delta2), std::min(delta3, delta4)); // start updating dual variables, note that the order is important for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { vertex_descriptor_t v = *vi, v_prime = base_vertex(v); if (label_S[v_prime] != graph_traits< Graph >::null_vertex()) dual_var[v] -= delta; else if (label_T[v_prime] != graph_traits< Graph >::null_vertex() && pi[v_prime] == 0) dual_var[v] += delta; if (v == v_prime) gamma[v] -= 2 * delta; } for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { vertex_descriptor_t v_prime = base_vertex(*vi); if (pi[v_prime] > 0) tau[*vi] -= delta; } for (blossom_iterator_t bi = top_blossoms.begin(); bi != top_blossoms.end(); ++bi) { vertex_descriptor_t b_base = (*bi)->get_base(); if (label_T[b_base] != graph_traits< Graph >::null_vertex() && pi[b_base] == 0) (*bi)->dual_var -= 2 * delta; if (label_S[b_base] != graph_traits< Graph >::null_vertex()) (*bi)->dual_var += 2 * delta; } for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { vertex_descriptor_t v = *vi; if (pi[v] > 0) pi[v] -= delta; // when some T-vertices have zero pi value, bloom their mates so // that matching can be further augmented if (label_T[v] != graph_traits< Graph >::null_vertex() && pi[v] == 0) put_T_label(v, label_T[v], outlet[v], pi[v]); } // optimal solution reached, halt if (delta == delta1) return false; // expand odd blossoms with zero dual variables and zero pi value of // their base vertices if (delta == delta2 && delta != delta3) { std::vector< blossom_ptr_t > new_top_blossoms; for (blossom_iterator_t bi = top_blossoms.begin(); bi != top_blossoms.end();) { const blossom_ptr_t b = *bi; vertex_descriptor_t b_base = b->get_base(); if (b->dual_var == 0 && label_T[b_base] != graph_traits< Graph >::null_vertex() && pi[b_base] == 0) bi = expand_T_blossom(bi, new_top_blossoms); else ++bi; } top_blossoms.insert(top_blossoms.end(), new_top_blossoms.begin(), new_top_blossoms.end()); } while (true) { // find a zero-slack critical edge (v, w) of zero gamma values std::pair< edge_descriptor_t, bool > best_edge = null_edge; std::vector< vertex_descriptor_t > base_nodes; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { if (*vi == base_vertex(*vi)) base_nodes.push_back(*vi); } for (vertex_vec_iter_t i = base_nodes.begin(); i != base_nodes.end(); ++i) { if (gamma[*i] == 0) { for (vertex_vec_iter_t j = base_nodes.begin(); j != base_nodes.end(); ++j) { if (critical_edge[*i][*j] != null_edge && slack(critical_edge[*i][*j].first) == 0) best_edge = critical_edge[*i][*j]; } } } // if not found, continue finding other augment matching if (best_edge == null_edge) { bool augmented = augment_matching(); return augmented || delta != delta1; } // if found, determine either augmenting or blossoming vertex_descriptor_t v = source(best_edge.first, g), w = target(best_edge.first, g); vertex_descriptor_t v_prime = base_vertex(v), w_prime = base_vertex(w), v_free_ancestor, w_free_ancestor; vertex_descriptor_t nca = nearest_common_ancestor( v_prime, w_prime, v_free_ancestor, w_free_ancestor); if (nca == graph_traits< Graph >::null_vertex()) { augmenting(v, v_free_ancestor, w, w_free_ancestor); return true; } else blossoming(v, v_prime, w, w_prime, nca); } return false; } template < typename PropertyMap > void get_current_matching(PropertyMap pm) { vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) put(pm, *vi, mate[*vi]); } private: const Graph& g; VertexIndexMap vm; const std::pair< edge_descriptor_t, bool > null_edge; // storage for the property maps below std::vector< vertex_descriptor_t > mate_vector; std::vector< vertex_descriptor_t > label_S_vector, label_T_vector; std::vector< vertex_descriptor_t > outlet_vector; std::vector< vertex_descriptor_t > tau_idx_vector; std::vector< edge_property_t > dual_var_vector; std::vector< edge_property_t > pi_vector, gamma_vector, tau_vector; std::vector< blossom_ptr_t > in_blossom_vector; std::vector< std::pair< vertex_descriptor_t, vertex_descriptor_t > > old_label_vector; std::vector< vertex_to_edge_map_t > critical_edge_vector; std::vector< std::vector< std::pair< edge_descriptor_t, bool > > > critical_edge_vectors; // iterator property maps vertex_to_vertex_map_t mate; vertex_to_vertex_map_t label_S; // v has an S-label -> v can be an even // vertex, label_S[v] is its mate vertex_to_vertex_map_t label_T; // v has a T-label -> v can be an odd vertex, label_T[v] is its // predecessor in aug_path vertex_to_vertex_map_t outlet; vertex_to_vertex_map_t tau_idx; vertex_to_weight_map_t dual_var; vertex_to_weight_map_t pi, gamma, tau; vertex_to_blossom_map_t in_blossom; // map any vertex v to the trivial blossom containing v vertex_to_pair_map_t old_label; // <old T-label, old outlet> before // relabeling or expanding T-blossoms vertex_pair_to_edge_map_t critical_edge; // an not matched edge (v, w) is critical if v and w // belongs to different S-blossoms vertex_list_t aug_path; edge_list_t even_edges; std::vector< blossom_ptr_t > top_blossoms; }; template < typename Graph, typename MateMap, typename VertexIndexMap > void maximum_weighted_matching(const Graph& g, MateMap mate, VertexIndexMap vm) { empty_matching< Graph, MateMap >::find_matching(g, mate); weighted_augmenting_path_finder< Graph, MateMap, VertexIndexMap > augmentor( g, mate, vm); // can have |V| times augmenting at most for (std::size_t t = 0; t < num_vertices(g); ++t) { bool augmented = false; while (!augmented) { augmented = augmentor.augment_matching(); if (!augmented) { // halt if adjusting dual variables can't bring potential // augment if (!augmentor.adjust_dual()) break; } } if (!augmented) break; } augmentor.get_current_matching(mate); } template < typename Graph, typename MateMap > inline void maximum_weighted_matching(const Graph& g, MateMap mate) { maximum_weighted_matching(g, mate, get(vertex_index, g)); } // brute-force matcher searches all possible combinations of matched edges to // get the maximum weighted matching which can be used for testing on small // graphs (within dozens vertices) template < typename Graph, typename MateMap, typename VertexIndexMap > class brute_force_matching { public: typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; typedef typename std::vector< vertex_descriptor_t >::iterator vertex_vec_iter_t; typedef typename graph_traits< Graph >::edge_iterator edge_iterator_t; typedef boost::iterator_property_map< vertex_vec_iter_t, VertexIndexMap > vertex_to_vertex_map_t; brute_force_matching( const Graph& arg_g, MateMap arg_mate, VertexIndexMap arg_vm) : g(arg_g) , vm(arg_vm) , mate_vector(num_vertices(g)) , best_mate_vector(num_vertices(g)) , mate(mate_vector.begin(), vm) , best_mate(best_mate_vector.begin(), vm) { vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) best_mate[*vi] = mate[*vi] = get(arg_mate, *vi); } template < typename PropertyMap > void find_matching(PropertyMap pm) { edge_iterator_t ei; boost::tie(ei, ei_end) = edges(g); select_edge(ei); vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) put(pm, *vi, best_mate[*vi]); } private: const Graph& g; VertexIndexMap vm; std::vector< vertex_descriptor_t > mate_vector, best_mate_vector; vertex_to_vertex_map_t mate, best_mate; edge_iterator_t ei_end; void select_edge(edge_iterator_t ei) { if (ei == ei_end) { if (matching_weight_sum(g, mate) > matching_weight_sum(g, best_mate)) { vertex_iterator_t vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) best_mate[*vi] = mate[*vi]; } return; } vertex_descriptor_t v, w; v = source(*ei, g); w = target(*ei, g); select_edge(++ei); if (mate[v] == graph_traits< Graph >::null_vertex() && mate[w] == graph_traits< Graph >::null_vertex()) { mate[v] = w; mate[w] = v; select_edge(ei); mate[v] = mate[w] = graph_traits< Graph >::null_vertex(); } } }; template < typename Graph, typename MateMap, typename VertexIndexMap > void brute_force_maximum_weighted_matching( const Graph& g, MateMap mate, VertexIndexMap vm) { empty_matching< Graph, MateMap >::find_matching(g, mate); brute_force_matching< Graph, MateMap, VertexIndexMap > brute_force_matcher( g, mate, vm); brute_force_matcher.find_matching(mate); } template < typename Graph, typename MateMap > inline void brute_force_maximum_weighted_matching(const Graph& g, MateMap mate) { brute_force_maximum_weighted_matching(g, mate, get(vertex_index, g)); } } #endif named_function_params.hpp 0000644 00000115327 15125521275 0011627 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_NAMED_FUNCTION_PARAMS_HPP #define BOOST_GRAPH_NAMED_FUNCTION_PARAMS_HPP #include <functional> #include <vector> #include <boost/limits.hpp> #include <boost/core/enable_if.hpp> #include <boost/core/ref.hpp> #include <boost/utility/result_of.hpp> #include <boost/preprocessor.hpp> #include <boost/parameter/is_argument_pack.hpp> #include <boost/parameter/name.hpp> #include <boost/parameter/binding.hpp> #include <boost/type_traits.hpp> #include <boost/mpl/bool.hpp> #include <boost/mpl/has_key.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/detail/d_ary_heap.hpp> #include <boost/property_map/property_map.hpp> #include <boost/property_map/shared_array_property_map.hpp> namespace boost { struct parity_map_t { }; struct vertex_assignment_map_t { }; struct distance_compare_t { }; struct distance_combine_t { }; struct distance_inf_t { }; struct distance_zero_t { }; struct buffer_param_t { }; struct edge_copy_t { }; struct vertex_copy_t { }; struct vertex_isomorphism_t { }; struct vertex_invariant_t { }; struct vertex_invariant1_t { }; struct vertex_invariant2_t { }; struct edge_compare_t { }; struct vertex_max_invariant_t { }; struct orig_to_copy_t { }; struct root_vertex_t { }; struct polling_t { }; struct lookahead_t { }; struct in_parallel_t { }; struct attractive_force_t { }; struct repulsive_force_t { }; struct force_pairs_t { }; struct cooling_t { }; struct vertex_displacement_t { }; struct iterations_t { }; struct diameter_range_t { }; struct learning_constant_range_t { }; struct vertices_equivalent_t { }; struct edges_equivalent_t { }; struct index_in_heap_map_t { }; struct max_priority_queue_t { }; #define BOOST_BGL_DECLARE_NAMED_PARAMS \ BOOST_BGL_ONE_PARAM_CREF(weight_map, edge_weight) \ BOOST_BGL_ONE_PARAM_CREF(weight_map2, edge_weight2) \ BOOST_BGL_ONE_PARAM_CREF(distance_map, vertex_distance) \ BOOST_BGL_ONE_PARAM_CREF(distance_map2, vertex_distance2) \ BOOST_BGL_ONE_PARAM_CREF(predecessor_map, vertex_predecessor) \ BOOST_BGL_ONE_PARAM_CREF(rank_map, vertex_rank) \ BOOST_BGL_ONE_PARAM_CREF(root_map, vertex_root) \ BOOST_BGL_ONE_PARAM_CREF(root_vertex, root_vertex) \ BOOST_BGL_ONE_PARAM_CREF(edge_centrality_map, edge_centrality) \ BOOST_BGL_ONE_PARAM_CREF(centrality_map, vertex_centrality) \ BOOST_BGL_ONE_PARAM_CREF(parity_map, parity_map) \ BOOST_BGL_ONE_PARAM_CREF(color_map, vertex_color) \ BOOST_BGL_ONE_PARAM_CREF(edge_color_map, edge_color) \ BOOST_BGL_ONE_PARAM_CREF(capacity_map, edge_capacity) \ BOOST_BGL_ONE_PARAM_CREF(residual_capacity_map, edge_residual_capacity) \ BOOST_BGL_ONE_PARAM_CREF(reverse_edge_map, edge_reverse) \ BOOST_BGL_ONE_PARAM_CREF(discover_time_map, vertex_discover_time) \ BOOST_BGL_ONE_PARAM_CREF(lowpoint_map, vertex_lowpoint) \ BOOST_BGL_ONE_PARAM_CREF(vertex_index_map, vertex_index) \ BOOST_BGL_ONE_PARAM_CREF(vertex_index1_map, vertex_index1) \ BOOST_BGL_ONE_PARAM_CREF(vertex_index2_map, vertex_index2) \ BOOST_BGL_ONE_PARAM_CREF(vertex_assignment_map, vertex_assignment_map) \ BOOST_BGL_ONE_PARAM_CREF(visitor, graph_visitor) \ BOOST_BGL_ONE_PARAM_CREF(distance_compare, distance_compare) \ BOOST_BGL_ONE_PARAM_CREF(distance_combine, distance_combine) \ BOOST_BGL_ONE_PARAM_CREF(distance_inf, distance_inf) \ BOOST_BGL_ONE_PARAM_CREF(distance_zero, distance_zero) \ BOOST_BGL_ONE_PARAM_CREF(edge_copy, edge_copy) \ BOOST_BGL_ONE_PARAM_CREF(vertex_copy, vertex_copy) \ BOOST_BGL_ONE_PARAM_REF(buffer, buffer_param) \ BOOST_BGL_ONE_PARAM_CREF(orig_to_copy, orig_to_copy) \ BOOST_BGL_ONE_PARAM_CREF(isomorphism_map, vertex_isomorphism) \ BOOST_BGL_ONE_PARAM_CREF(vertex_invariant, vertex_invariant) \ BOOST_BGL_ONE_PARAM_CREF(vertex_invariant1, vertex_invariant1) \ BOOST_BGL_ONE_PARAM_CREF(vertex_invariant2, vertex_invariant2) \ BOOST_BGL_ONE_PARAM_CREF(vertex_max_invariant, vertex_max_invariant) \ BOOST_BGL_ONE_PARAM_CREF(polling, polling) \ BOOST_BGL_ONE_PARAM_CREF(lookahead, lookahead) \ BOOST_BGL_ONE_PARAM_CREF(in_parallel, in_parallel) \ BOOST_BGL_ONE_PARAM_CREF(displacement_map, vertex_displacement) \ BOOST_BGL_ONE_PARAM_CREF(attractive_force, attractive_force) \ BOOST_BGL_ONE_PARAM_CREF(repulsive_force, repulsive_force) \ BOOST_BGL_ONE_PARAM_CREF(force_pairs, force_pairs) \ BOOST_BGL_ONE_PARAM_CREF(cooling, cooling) \ BOOST_BGL_ONE_PARAM_CREF(iterations, iterations) \ BOOST_BGL_ONE_PARAM_CREF(diameter_range, diameter_range) \ BOOST_BGL_ONE_PARAM_CREF(learning_constant_range, learning_constant_range) \ BOOST_BGL_ONE_PARAM_CREF(vertices_equivalent, vertices_equivalent) \ BOOST_BGL_ONE_PARAM_CREF(edges_equivalent, edges_equivalent) \ BOOST_BGL_ONE_PARAM_CREF(index_in_heap_map, index_in_heap_map) \ BOOST_BGL_ONE_PARAM_REF(max_priority_queue, max_priority_queue) template < typename T, typename Tag, typename Base = no_property > struct bgl_named_params { typedef bgl_named_params self; typedef Base next_type; typedef Tag tag_type; typedef T value_type; bgl_named_params(T v = T()) : m_value(v) {} bgl_named_params(T v, const Base& b) : m_value(v), m_base(b) {} T m_value; Base m_base; #define BOOST_BGL_ONE_PARAM_REF(name, key) \ template < typename PType > \ bgl_named_params< boost::reference_wrapper< PType >, \ BOOST_PP_CAT(key, _t), self > \ name(PType& p) const \ { \ typedef bgl_named_params< boost::reference_wrapper< PType >, \ BOOST_PP_CAT(key, _t), self > \ Params; \ return Params(boost::ref(p), *this); \ } #define BOOST_BGL_ONE_PARAM_CREF(name, key) \ template < typename PType > \ bgl_named_params< PType, BOOST_PP_CAT(key, _t), self > name( \ const PType& p) const \ { \ typedef bgl_named_params< PType, BOOST_PP_CAT(key, _t), self > Params; \ return Params(p, *this); \ } BOOST_BGL_DECLARE_NAMED_PARAMS #undef BOOST_BGL_ONE_PARAM_REF #undef BOOST_BGL_ONE_PARAM_CREF // Duplicate template < typename PType > bgl_named_params< PType, vertex_color_t, self > vertex_color_map( const PType& p) const { return this->color_map(p); } }; #define BOOST_BGL_ONE_PARAM_REF(name, key) \ template < typename PType > \ bgl_named_params< boost::reference_wrapper< PType >, \ BOOST_PP_CAT(key, _t) > \ name(PType& p) \ { \ typedef bgl_named_params< boost::reference_wrapper< PType >, \ BOOST_PP_CAT(key, _t) > \ Params; \ return Params(boost::ref(p)); \ } #define BOOST_BGL_ONE_PARAM_CREF(name, key) \ template < typename PType > \ bgl_named_params< PType, BOOST_PP_CAT(key, _t) > name(const PType& p) \ { \ typedef bgl_named_params< PType, BOOST_PP_CAT(key, _t) > Params; \ return Params(p); \ } BOOST_BGL_DECLARE_NAMED_PARAMS #undef BOOST_BGL_ONE_PARAM_REF #undef BOOST_BGL_ONE_PARAM_CREF // Duplicate template < typename PType > bgl_named_params< PType, vertex_color_t > vertex_color_map(const PType& p) { return color_map(p); } namespace detail { struct unused_tag_type { }; } typedef bgl_named_params< char, detail::unused_tag_type > no_named_parameters; //=========================================================================== // Functions for extracting parameters from bgl_named_params template < typename Tag, typename Args > struct lookup_named_param { }; template < typename T, typename Tag, typename Base > struct lookup_named_param< Tag, bgl_named_params< T, Tag, Base > > { typedef T type; static const T& get(const bgl_named_params< T, Tag, Base >& p) { return p.m_value; } }; template < typename Tag1, typename T, typename Tag, typename Base > struct lookup_named_param< Tag1, bgl_named_params< T, Tag, Base > > { typedef typename lookup_named_param< Tag1, Base >::type type; static const type& get(const bgl_named_params< T, Tag, Base >& p) { return lookup_named_param< Tag1, Base >::get(p.m_base); } }; template < typename Tag, typename Args, typename Def > struct lookup_named_param_def { typedef Def type; static const Def& get(const Args&, const Def& def) { return def; } }; template < typename T, typename Tag, typename Base, typename Def > struct lookup_named_param_def< Tag, bgl_named_params< T, Tag, Base >, Def > { typedef T type; static const type& get( const bgl_named_params< T, Tag, Base >& p, const Def&) { return p.m_value; } }; template < typename Tag1, typename T, typename Tag, typename Base, typename Def > struct lookup_named_param_def< Tag1, bgl_named_params< T, Tag, Base >, Def > { typedef typename lookup_named_param_def< Tag1, Base, Def >::type type; static const type& get( const bgl_named_params< T, Tag, Base >& p, const Def& def) { return lookup_named_param_def< Tag1, Base, Def >::get(p.m_base, def); } }; struct param_not_found { }; static param_not_found g_param_not_found; template < typename Tag, typename Args > struct get_param_type : lookup_named_param_def< Tag, Args, param_not_found > { }; template < class Tag, typename Args > inline const typename lookup_named_param_def< Tag, Args, param_not_found >::type& get_param(const Args& p, Tag) { return lookup_named_param_def< Tag, Args, param_not_found >::get( p, g_param_not_found); } template < class P, class Default > const P& choose_param(const P& param, const Default&) { return param; } template < class Default > Default choose_param(const param_not_found&, const Default& d) { return d; } template < typename T > inline bool is_default_param(const T&) { return false; } inline bool is_default_param(const param_not_found&) { return true; } namespace detail { template < typename T > struct const_type_as_type { typedef typename T::const_type type; }; } // namespace detail // Use this function instead of choose_param() when you want // to avoid requiring get(tag, g) when it is not used. namespace detail { template < typename GraphIsConst, typename Graph, typename Param, typename Tag > struct choose_impl_result : boost::mpl::eval_if< boost::is_same< Param, param_not_found >, boost::mpl::eval_if< GraphIsConst, detail::const_type_as_type< property_map< Graph, Tag > >, property_map< Graph, Tag > >, boost::mpl::identity< Param > > { }; // Parameters of f are (GraphIsConst, Graph, Param, Tag) template < bool Found > struct choose_impl_helper; template <> struct choose_impl_helper< false > { template < typename Param, typename Graph, typename PropertyTag > static typename property_map< typename boost::remove_const< Graph >::type, PropertyTag >::const_type f(boost::mpl::true_, const Graph& g, const Param&, PropertyTag tag) { return get(tag, g); } template < typename Param, typename Graph, typename PropertyTag > static typename property_map< typename boost::remove_const< Graph >::type, PropertyTag >::type f(boost::mpl::false_, Graph& g, const Param&, PropertyTag tag) { return get(tag, g); } }; template <> struct choose_impl_helper< true > { template < typename GraphIsConst, typename Param, typename Graph, typename PropertyTag > static Param f(GraphIsConst, const Graph&, const Param& p, PropertyTag) { return p; } }; } template < typename Param, typename Graph, typename PropertyTag > typename detail::choose_impl_result< boost::mpl::true_, Graph, Param, PropertyTag >::type choose_const_pmap(const Param& p, const Graph& g, PropertyTag tag) { return detail::choose_impl_helper< !boost::is_same< Param, param_not_found >::value >::f(boost::mpl::true_(), g, p, tag); } template < typename Param, typename Graph, typename PropertyTag > typename detail::choose_impl_result< boost::mpl::false_, Graph, Param, PropertyTag >::type choose_pmap(const Param& p, Graph& g, PropertyTag tag) { return detail::choose_impl_helper< !boost::is_same< Param, param_not_found >::value >::f(boost::mpl::false_(), g, p, tag); } namespace detail { // used in the max-flow algorithms template < class Graph, class P, class T, class R > struct edge_capacity_value { typedef bgl_named_params< P, T, R > Params; typedef typename detail::choose_impl_result< boost::mpl::true_, Graph, typename get_param_type< edge_capacity_t, Params >::type, edge_capacity_t >::type CapacityEdgeMap; typedef typename property_traits< CapacityEdgeMap >::value_type type; }; // used in the max-flow algorithms template < class Graph, class P, class T, class R > struct edge_weight_value { typedef bgl_named_params< P, T, R > Params; typedef typename detail::choose_impl_result< boost::mpl::true_, Graph, typename get_param_type< edge_weight_t, Params >::type, edge_weight_t >::type WeightMap; typedef typename property_traits< WeightMap >::value_type type; }; } // Declare all new tags namespace graph { namespace keywords { #define BOOST_BGL_ONE_PARAM_REF(name, key) BOOST_PARAMETER_NAME(name) #define BOOST_BGL_ONE_PARAM_CREF(name, key) BOOST_PARAMETER_NAME(name) BOOST_BGL_DECLARE_NAMED_PARAMS #undef BOOST_BGL_ONE_PARAM_REF #undef BOOST_BGL_ONE_PARAM_CREF } } namespace detail { template < typename Tag > struct convert_one_keyword { }; #define BOOST_BGL_ONE_PARAM_REF(name, key) \ template <> struct convert_one_keyword< BOOST_PP_CAT(key, _t) > \ { \ typedef boost::graph::keywords::tag::name type; \ }; #define BOOST_BGL_ONE_PARAM_CREF(name, key) BOOST_BGL_ONE_PARAM_REF(name, key) BOOST_BGL_DECLARE_NAMED_PARAMS #undef BOOST_BGL_ONE_PARAM_REF #undef BOOST_BGL_ONE_PARAM_CREF template < typename T > struct convert_bgl_params_to_boost_parameter { typedef typename convert_one_keyword< typename T::tag_type >::type new_kw; typedef boost::parameter::aux::tagged_argument< new_kw, const typename T::value_type > tagged_arg_type; typedef convert_bgl_params_to_boost_parameter< typename T::next_type > rest_conv; typedef boost::parameter::aux::arg_list< tagged_arg_type, typename rest_conv::type > type; static type conv(const T& x) { return type(tagged_arg_type(x.m_value), rest_conv::conv(x.m_base)); } }; template < typename P, typename R > struct convert_bgl_params_to_boost_parameter< bgl_named_params< P, int, R > > { typedef convert_bgl_params_to_boost_parameter< R > rest_conv; typedef typename rest_conv::type type; static type conv(const bgl_named_params< P, int, R >& x) { return rest_conv::conv(x.m_base); } }; template <> struct convert_bgl_params_to_boost_parameter< boost::no_property > { typedef boost::parameter::aux::empty_arg_list type; static type conv(const boost::no_property&) { return type(); } }; template <> struct convert_bgl_params_to_boost_parameter< boost::no_named_parameters > { typedef boost::parameter::aux::empty_arg_list type; static type conv(const boost::no_named_parameters&) { return type(); } }; struct bgl_parameter_not_found_type { }; } #define BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(old_type, old_var) \ typedef typename boost::detail::convert_bgl_params_to_boost_parameter< \ old_type >::type arg_pack_type; \ arg_pack_type arg_pack \ = boost::detail::convert_bgl_params_to_boost_parameter< \ old_type >::conv(old_var); namespace detail { template < typename ArgType, typename Prop, typename Graph, bool Exists > struct override_const_property_t { typedef typename boost::remove_const< ArgType >::type result_type; result_type operator()(const Graph&, const ArgType& a) const { return a; } }; template < typename ArgType, typename Prop, typename Graph > struct override_const_property_t< ArgType, Prop, Graph, false > { typedef typename boost::property_map< Graph, Prop >::const_type result_type; result_type operator()(const Graph& g, const ArgType&) const { return get(Prop(), g); } }; template < typename ArgPack, typename Tag, typename Prop, typename Graph > struct override_const_property_result { typedef typename boost::mpl::has_key< ArgPack, Tag >::type _parameter_exists; typedef typename override_const_property_t< typename boost::parameter::value_type< ArgPack, Tag, int >::type, Prop, Graph, _parameter_exists::value >::result_type type; }; template < typename ArgPack, typename Tag, typename Prop, typename Graph > typename override_const_property_result< ArgPack, Tag, Prop, Graph >::type override_const_property(const ArgPack& ap, const boost::parameter::keyword< Tag >& t, const Graph& g, Prop) { typedef typename boost::mpl::has_key< ArgPack, Tag >::type _parameter_exists; return override_const_property_t< typename boost::parameter::value_type< ArgPack, Tag, int >::type, Prop, Graph, _parameter_exists::value >()(g, ap[t | 0]); } template < typename ArgType, typename Prop, typename Graph, bool Exists > struct override_property_t { typedef ArgType result_type; result_type operator()(const Graph&, typename boost::add_lvalue_reference< ArgType >::type a) const { return a; } }; template < typename ArgType, typename Prop, typename Graph > struct override_property_t< ArgType, Prop, Graph, false > { typedef typename boost::property_map< Graph, Prop >::type result_type; result_type operator()(const Graph& g, const ArgType&) const { return get(Prop(), g); } }; template < typename ArgPack, typename Tag, typename Prop, typename Graph > struct override_property_result { typedef typename boost::mpl::has_key< ArgPack, Tag >::type _parameter_exists; typedef typename override_property_t< typename boost::parameter::value_type< ArgPack, Tag, int >::type, Prop, Graph, _parameter_exists::value >::result_type type; }; template < typename ArgPack, typename Tag, typename Prop, typename Graph > typename override_property_result< ArgPack, Tag, Prop, Graph >::type override_property(const ArgPack& ap, const boost::parameter::keyword< Tag >& t, const Graph& g, Prop) { typedef typename boost::mpl::has_key< ArgPack, Tag >::type _parameter_exists; return override_property_t< typename boost::parameter::value_type< ArgPack, Tag, int >::type, Prop, Graph, _parameter_exists::value >()(g, ap[t | 0]); } template < typename F > struct make_arg_pack_type; template <> struct make_arg_pack_type< void() > { typedef boost::parameter::aux::empty_arg_list type; }; template < typename K, typename A > struct make_arg_pack_type< void(K, A) > { typedef boost::parameter::aux::tagged_argument< K, A > type; }; #define BOOST_GRAPH_OPENING_PART_OF_PAIR(z, i, n) \ boost::parameter::aux::arg_list \ < boost::parameter::aux::tagged_argument< BOOST_PP_CAT(Keyword, \ BOOST_PP_SUB(n, i)), \ BOOST_PP_CAT(Arg, BOOST_PP_SUB(n, i)) >, #define BOOST_GRAPH_MAKE_PAIR_PARAM(z, i, _) \ const boost::parameter::aux::tagged_argument< BOOST_PP_CAT(Keyword, i), \ BOOST_PP_CAT(Arg, i) >& BOOST_PP_CAT(kw, i) #define BOOST_GRAPH_MAKE_AP_TYPE_SPECIALIZATION(z, i, _) \ template < BOOST_PP_ENUM_PARAMS(i, typename Keyword), \ BOOST_PP_ENUM_PARAMS(i, typename Arg) > \ struct make_arg_pack_type< void( \ BOOST_PP_ENUM_PARAMS(i, Keyword), BOOST_PP_ENUM_PARAMS(i, Arg)) > \ { \ typedef BOOST_PP_REPEAT(i, BOOST_GRAPH_OPENING_PART_OF_PAIR, \ BOOST_PP_DEC(i)) boost::parameter::aux::empty_arg_list \ BOOST_PP_REPEAT(i, > BOOST_PP_TUPLE_EAT(3), ~) type; \ }; BOOST_PP_REPEAT_FROM_TO(2, 11, BOOST_GRAPH_MAKE_AP_TYPE_SPECIALIZATION, ~) #undef BOOST_GRAPH_MAKE_AP_TYPE_SPECIALIZATION #define BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(name, nfixed, nnamed_max) \ /* Entry point for conversion from BGL-style named parameters */ \ template < BOOST_PP_ENUM_PARAMS(nfixed, typename Param) \ BOOST_PP_COMMA_IF(nfixed) typename ArgPack > \ typename boost::result_of< detail::BOOST_PP_CAT(name, _impl) \ < BOOST_PP_ENUM_PARAMS(nfixed, Param) >(BOOST_PP_ENUM_PARAMS( \ nfixed, Param) BOOST_PP_COMMA_IF(nfixed) const ArgPack&) \ > ::type BOOST_PP_CAT(name, _with_named_params)( \ BOOST_PP_ENUM_BINARY_PARAMS(nfixed, const Param, ¶m) \ BOOST_PP_COMMA_IF(nfixed) const ArgPack& arg_pack) \ { \ return detail::BOOST_PP_CAT( \ name, _impl)< BOOST_PP_ENUM_PARAMS(nfixed, Param) >()( \ BOOST_PP_ENUM_PARAMS(nfixed, param) BOOST_PP_COMMA_IF(nfixed) \ arg_pack); \ } \ /* Individual functions taking Boost.Parameter-style keyword arguments */ \ BOOST_PP_REPEAT(BOOST_PP_INC(nnamed_max), \ BOOST_GRAPH_MAKE_FORWARDING_FUNCTION_ONE, (name)(nfixed)) #define BOOST_GRAPH_MAKE_FORWARDING_FUNCTION_ONE(z, nnamed, seq) \ BOOST_GRAPH_MAKE_FORWARDING_FUNCTION_ONEX( \ z, nnamed, BOOST_PP_SEQ_ELEM(0, seq), BOOST_PP_SEQ_ELEM(1, seq)) #define BOOST_GRAPH_MAKE_FORWARDING_FUNCTION_ONEX(z, nnamed, name, nfixed) \ template < BOOST_PP_ENUM_PARAMS_Z(z, nfixed, typename Param) \ BOOST_PP_ENUM_TRAILING_PARAMS_Z( \ z, nnamed, typename ArgumentPack) > \ typename BOOST_PP_EXPR_IF(nnamed, \ boost::lazy_enable_if \ < boost::parameter::is_argument_pack< ArgumentPack0 >) \ BOOST_PP_COMMA_IF(nnamed)::boost::graph::detail::BOOST_PP_CAT( \ name, _impl)< BOOST_PP_ENUM_PARAMS_Z(z, nfixed, Param) > \ BOOST_PP_EXPR_IF(nnamed, >)::type name( \ BOOST_PP_ENUM_BINARY_PARAMS_Z(z, nfixed, Param, const& param) \ BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z( \ z, nnamed, ArgumentPack, const& tagged_arg)) \ { \ return ::boost::graph::BOOST_PP_CAT(name, _with_named_params)( \ BOOST_PP_ENUM_PARAMS_Z(z, nfixed, param) BOOST_PP_COMMA_IF(nnamed) \ BOOST_PP_LPAREN_IF(nnamed) BOOST_PP_ENUM_PARAMS_Z( \ z, nnamed, tagged_arg) BOOST_PP_RPAREN_IF(nnamed)); \ } #define BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(name, nfixed) \ template < BOOST_PP_ENUM_PARAMS(nfixed, typename Param) \ BOOST_PP_COMMA_IF(nfixed) class P, \ class T, class R > \ typename boost::result_of< ::boost::graph::detail::BOOST_PP_CAT( \ name, _impl) BOOST_PP_EXPR_IF(nfixed, <) BOOST_PP_ENUM_PARAMS(nfixed, \ Param) BOOST_PP_EXPR_IF(nfixed, >)(BOOST_PP_ENUM_PARAMS(nfixed, Param) \ BOOST_PP_COMMA_IF(nfixed) const typename boost::detail:: \ convert_bgl_params_to_boost_parameter< \ boost::bgl_named_params< P, T, R > >::type&) >::type \ name(BOOST_PP_ENUM_BINARY_PARAMS(nfixed, const Param, ¶m) \ BOOST_PP_COMMA_IF(nfixed) \ const boost::bgl_named_params< P, T, R >& old_style_params) \ { \ typedef boost::bgl_named_params< P, T, R > old_style_params_type; \ BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS( \ old_style_params_type, old_style_params) \ return ::boost::graph::BOOST_PP_CAT(name, _with_named_params)( \ BOOST_PP_ENUM_PARAMS(nfixed, param) BOOST_PP_COMMA_IF(nfixed) \ arg_pack); \ } \ BOOST_PP_EXPR_IF(nfixed, template < ) \ BOOST_PP_ENUM_PARAMS(nfixed, typename Param) \ BOOST_PP_EXPR_IF(nfixed, >) \ BOOST_PP_EXPR_IF(nfixed, typename) \ boost::result_of< ::boost::graph::detail::BOOST_PP_CAT( \ name, _impl) BOOST_PP_EXPR_IF(nfixed, \ <) BOOST_PP_ENUM_PARAMS(nfixed, Param) BOOST_PP_EXPR_IF(nfixed, \ >)(BOOST_PP_ENUM_PARAMS(nfixed, Param) BOOST_PP_COMMA_IF(nfixed) \ const boost::parameter::aux::empty_arg_list&) >::type \ name(BOOST_PP_ENUM_BINARY_PARAMS(nfixed, const Param, ¶m)) \ { \ BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS( \ boost::no_named_parameters, boost::no_named_parameters()) \ return ::boost::graph::BOOST_PP_CAT(name, _with_named_params)( \ BOOST_PP_ENUM_PARAMS(nfixed, param) BOOST_PP_COMMA_IF(nfixed) \ arg_pack); \ } } namespace detail { template < bool Exists, typename Graph, typename ArgPack, typename Value, typename PM > struct map_maker_helper { typedef PM map_type; static PM make_map(const Graph&, Value, const PM& pm, const ArgPack&) { return pm; } }; template < typename Graph, typename ArgPack, typename Value, typename PM > struct map_maker_helper< false, Graph, ArgPack, Value, PM > { typedef typename boost::mpl::has_key< ArgPack, boost::graph::keywords::tag::vertex_index_map >::type _parameter_exists; typedef typename boost::remove_const< typename override_const_property_t< typename boost::parameter::value_type< ArgPack, boost::graph::keywords::tag::vertex_index_map, int >::type, boost::vertex_index_t, Graph, _parameter_exists::value >::result_type >::type vi_map_type; typedef boost::shared_array_property_map< Value, vi_map_type > map_type; static map_type make_map( const Graph& g, Value v, const PM&, const ArgPack& ap) { return make_shared_array_property_map(num_vertices(g), v, override_const_property(ap, boost::graph::keywords::_vertex_index_map, g, vertex_index)); } }; template < typename Graph, typename ArgPack, typename MapTag, typename ValueType > struct map_maker { typedef typename boost::mpl::has_key< ArgPack, MapTag >::type _parameter_exists; BOOST_STATIC_CONSTANT(bool, has_map = (_parameter_exists::value)); typedef map_maker_helper< has_map, Graph, ArgPack, ValueType, typename boost::remove_const< typename boost::parameter::value_type< ArgPack, MapTag, int >::type >::type > helper; typedef typename helper::map_type map_type; static map_type make_map( const Graph& g, const ArgPack& ap, ValueType default_value) { return helper::make_map(g, default_value, ap[::boost::parameter::keyword< MapTag >::instance | 0], ap); } }; template < typename MapTag, typename ValueType = void > class make_property_map_from_arg_pack_gen { ValueType default_value; public: make_property_map_from_arg_pack_gen(ValueType default_value) : default_value(default_value) { } template < typename Graph, typename ArgPack > typename map_maker< Graph, ArgPack, MapTag, ValueType >::map_type operator()(const Graph& g, const ArgPack& ap) const { return map_maker< Graph, ArgPack, MapTag, ValueType >::make_map( g, ap, default_value); } }; template < typename MapTag > class make_property_map_from_arg_pack_gen< MapTag, void > { public: template < typename ValueType, typename Graph, typename ArgPack > typename map_maker< Graph, ArgPack, MapTag, ValueType >::map_type operator()( const Graph& g, const ArgPack& ap, ValueType default_value) const { return map_maker< Graph, ArgPack, MapTag, ValueType >::make_map( g, ap, default_value); } }; static const make_property_map_from_arg_pack_gen< boost::graph::keywords::tag::color_map, default_color_type > make_color_map_from_arg_pack(white_color); template < bool Exists, class Graph, class ArgPack, class KeyT, class ValueT, class KeyMapTag, class IndexInHeapMapTag, class Compare, class Q > struct priority_queue_maker_helper { typedef Q priority_queue_type; static priority_queue_type make_queue( const Graph&, const ArgPack&, KeyT, const Q& q) { return q; } }; template < class Graph, class ArgPack, class KeyT, class ValueT, class KeyMapTag, class IndexInHeapMapTag, class Compare, class Q > struct priority_queue_maker_helper< false, Graph, ArgPack, KeyT, ValueT, KeyMapTag, IndexInHeapMapTag, Compare, Q > { typedef typename std::vector< ValueT >::size_type default_index_in_heap_type; typedef typename map_maker< Graph, ArgPack, IndexInHeapMapTag, default_index_in_heap_type >::helper::map_type index_in_heap_map; typedef boost::d_ary_heap_indirect< ValueT, 4, index_in_heap_map, typename map_maker< Graph, ArgPack, KeyMapTag, KeyT >::helper::map_type, Compare > priority_queue_type; static priority_queue_type make_queue( const Graph& g, const ArgPack& ap, KeyT defaultKey, const Q&) { return priority_queue_type( map_maker< Graph, ArgPack, KeyMapTag, KeyT >::make_map( g, ap, defaultKey), map_maker< Graph, ArgPack, IndexInHeapMapTag, default_index_in_heap_type >::make_map(g, ap, typename boost::property_traits< index_in_heap_map >::value_type(-1))); } }; template < class Graph, class ArgPack, class KeyT, class ValueT, class PriorityQueueTag, class KeyMapTag, class IndexInHeapMapTag, class Compare > struct priority_queue_maker { typedef typename boost::mpl::has_key< ArgPack, PriorityQueueTag >::type _parameter_exists; BOOST_STATIC_CONSTANT(bool, g_hasQ = (_parameter_exists::value)); typedef boost::reference_wrapper< int > int_refw; typedef typename boost::parameter::value_type< ArgPack, PriorityQueueTag, int_refw >::type param_value_type_wrapper; typedef typename param_value_type_wrapper::type param_value_type; typedef typename boost::remove_const< param_value_type >::type param_value_type_no_const; typedef priority_queue_maker_helper< g_hasQ, Graph, ArgPack, KeyT, ValueT, KeyMapTag, IndexInHeapMapTag, Compare, param_value_type_no_const > helper; typedef typename helper::priority_queue_type priority_queue_type; static priority_queue_type make_queue( const Graph& g, const ArgPack& ap, KeyT defaultKey) { return helper::make_queue(g, ap, defaultKey, ap[::boost::parameter::keyword< PriorityQueueTag >::instance | 0]); } }; template < class PriorityQueueTag, class KeyT, class ValueT, class Compare = std::less< KeyT >, class KeyMapTag = boost::graph::keywords::tag::distance_map, class IndexInHeapMapTag = boost::graph::keywords::tag::index_in_heap_map > struct make_priority_queue_from_arg_pack_gen { KeyT defaultKey; make_priority_queue_from_arg_pack_gen(KeyT defaultKey_) : defaultKey(defaultKey_) { } template < class F > struct result { typedef typename remove_const< typename remove_reference< typename function_traits< F >::arg1_type >::type >::type graph_type; typedef typename remove_const< typename remove_reference< typename function_traits< F >::arg2_type >::type >::type arg_pack_type; typedef typename priority_queue_maker< graph_type, arg_pack_type, KeyT, ValueT, PriorityQueueTag, KeyMapTag, IndexInHeapMapTag, Compare >::priority_queue_type type; }; template < class Graph, class ArgPack > typename priority_queue_maker< Graph, ArgPack, KeyT, ValueT, PriorityQueueTag, KeyMapTag, IndexInHeapMapTag, Compare >::priority_queue_type operator()(const Graph& g, const ArgPack& ap) const { return priority_queue_maker< Graph, ArgPack, KeyT, ValueT, PriorityQueueTag, KeyMapTag, IndexInHeapMapTag, Compare >::make_queue(g, ap, defaultKey); } }; template < typename G > typename boost::graph_traits< G >::vertex_descriptor get_null_vertex( const G&) { return boost::graph_traits< G >::null_vertex(); } template < typename G > typename boost::graph_traits< G >::vertex_descriptor get_default_starting_vertex(const G& g) { std::pair< typename boost::graph_traits< G >::vertex_iterator, typename boost::graph_traits< G >::vertex_iterator > iters = vertices(g); return (iters.first == iters.second) ? boost::graph_traits< G >::null_vertex() : *iters.first; } template < typename G > struct get_default_starting_vertex_t { typedef typename boost::graph_traits< G >::vertex_descriptor result_type; const G& g; get_default_starting_vertex_t(const G& g) : g(g) {} result_type operator()() const { return get_default_starting_vertex(g); } }; // Wrapper to avoid instantiating numeric_limits when users provide // distance_inf value manually template < typename T > struct get_max { T operator()() const { return (std::numeric_limits< T >::max)(); } typedef T result_type; }; } // namespace detail } // namespace boost #undef BOOST_BGL_DECLARE_NAMED_PARAMS #endif // BOOST_GRAPH_NAMED_FUNCTION_PARAMS_HPP core_numbers.hpp 0000644 00000032537 15125521275 0007757 0 ustar 00 // //======================================================================= // Copyright 2007 Stanford University // Authors: David Gleich // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_CORE_NUMBERS_HPP #define BOOST_GRAPH_CORE_NUMBERS_HPP #include <boost/graph/detail/d_ary_heap.hpp> #include <boost/graph/breadth_first_search.hpp> #include <boost/iterator/reverse_iterator.hpp> #include <boost/concept/assert.hpp> /* * core_numbers * * Requirement: IncidenceGraph */ // History // // 30 July 2007 // Added visitors to the implementation // // 8 February 2008 // Fixed headers and missing typename namespace boost { // A linear time O(m) algorithm to compute the indegree core number // of a graph for unweighted graphs. // // and a O((n+m) log n) algorithm to compute the in-edge-weight core // numbers of a weighted graph. // // The linear algorithm comes from: // Vladimir Batagelj and Matjaz Zaversnik, "An O(m) Algorithm for Cores // Decomposition of Networks." Sept. 1 2002. template < typename Visitor, typename Graph > struct CoreNumbersVisitorConcept { void constraints() { BOOST_CONCEPT_ASSERT((CopyConstructibleConcept< Visitor >)); vis.examine_vertex(u, g); vis.finish_vertex(u, g); vis.examine_edge(e, g); } Visitor vis; Graph g; typename graph_traits< Graph >::vertex_descriptor u; typename graph_traits< Graph >::edge_descriptor e; }; template < class Visitors = null_visitor > class core_numbers_visitor : public bfs_visitor< Visitors > { public: core_numbers_visitor() {} core_numbers_visitor(Visitors vis) : bfs_visitor< Visitors >(vis) {} private: template < class Vertex, class Graph > void initialize_vertex(Vertex, Graph&) { } template < class Vertex, class Graph > void discover_vertex(Vertex, Graph&) { } template < class Vertex, class Graph > void gray_target(Vertex, Graph&) {} template < class Vertex, class Graph > void black_target(Vertex, Graph&) {} template < class Edge, class Graph > void tree_edge(Edge, Graph&) {} template < class Edge, class Graph > void non_tree_edge(Edge, Graph&) {} }; template < class Visitors > core_numbers_visitor< Visitors > make_core_numbers_visitor(Visitors vis) { return core_numbers_visitor< Visitors >(vis); } typedef core_numbers_visitor<> default_core_numbers_visitor; namespace detail { // implement a constant_property_map to simplify compute_in_degree // for the weighted and unweighted case // this is based on dummy property map template < typename ValueType > class constant_value_property_map : public boost::put_get_helper< ValueType, constant_value_property_map< ValueType > > { public: typedef void key_type; typedef ValueType value_type; typedef const ValueType& reference; typedef boost::readable_property_map_tag category; inline constant_value_property_map(ValueType cc) : c(cc) {} inline constant_value_property_map( const constant_value_property_map< ValueType >& x) : c(x.c) { } template < class Vertex > inline reference operator[](Vertex) const { return c; } protected: ValueType c; }; // the core numbers start as the indegree or inweight. This function // will initialize these values template < typename Graph, typename CoreMap, typename EdgeWeightMap > void compute_in_degree_map(Graph& g, CoreMap d, EdgeWeightMap wm) { typename graph_traits< Graph >::vertex_iterator vi, vi_end; typename graph_traits< Graph >::out_edge_iterator ei, ei_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { put(d, *vi, 0); } for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { for (boost::tie(ei, ei_end) = out_edges(*vi, g); ei != ei_end; ++ei) { put(d, target(*ei, g), get(d, target(*ei, g)) + get(wm, *ei)); } } } // the version for weighted graphs is a little different template < typename Graph, typename CoreMap, typename EdgeWeightMap, typename MutableQueue, typename Visitor > typename property_traits< CoreMap >::value_type core_numbers_impl( Graph& g, CoreMap c, EdgeWeightMap wm, MutableQueue& Q, Visitor vis) { typename property_traits< CoreMap >::value_type v_cn = 0; typedef typename graph_traits< Graph >::vertex_descriptor vertex; while (!Q.empty()) { // remove v from the Q, and then decrease the core numbers // of its successors vertex v = Q.top(); vis.examine_vertex(v, g); Q.pop(); v_cn = get(c, v); typename graph_traits< Graph >::out_edge_iterator oi, oi_end; for (boost::tie(oi, oi_end) = out_edges(v, g); oi != oi_end; ++oi) { vis.examine_edge(*oi, g); vertex u = target(*oi, g); // if c[u] > c[v], then u is still in the graph, if (get(c, u) > v_cn) { // remove the edge put(c, u, get(c, u) - get(wm, *oi)); if (Q.contains(u)) Q.update(u); } } vis.finish_vertex(v, g); } return (v_cn); } template < typename Graph, typename CoreMap, typename EdgeWeightMap, typename IndexMap, typename CoreNumVisitor > typename property_traits< CoreMap >::value_type core_numbers_dispatch( Graph& g, CoreMap c, EdgeWeightMap wm, IndexMap im, CoreNumVisitor vis) { typedef typename property_traits< CoreMap >::value_type D; typedef std::less< D > Cmp; // build the mutable queue typedef typename graph_traits< Graph >::vertex_descriptor vertex; std::vector< std::size_t > index_in_heap_data(num_vertices(g)); typedef iterator_property_map< std::vector< std::size_t >::iterator, IndexMap > index_in_heap_map_type; index_in_heap_map_type index_in_heap_map( index_in_heap_data.begin(), im); typedef d_ary_heap_indirect< vertex, 4, index_in_heap_map_type, CoreMap, Cmp > MutableQueue; MutableQueue Q(c, index_in_heap_map, Cmp()); typename graph_traits< Graph >::vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { Q.push(*vi); } return core_numbers_impl(g, c, wm, Q, vis); } // the version for the unweighted case // for this functions CoreMap must be initialized // with the in degree of each vertex template < typename Graph, typename CoreMap, typename PositionMap, typename Visitor > typename property_traits< CoreMap >::value_type core_numbers_impl( Graph& g, CoreMap c, PositionMap pos, Visitor vis) { typedef typename graph_traits< Graph >::vertices_size_type size_type; typedef typename graph_traits< Graph >::degree_size_type degree_type; typedef typename graph_traits< Graph >::vertex_descriptor vertex; typename graph_traits< Graph >::vertex_iterator vi, vi_end; // store the vertex core numbers typename property_traits< CoreMap >::value_type v_cn = 0; // compute the maximum degree (degrees are in the coremap) typename graph_traits< Graph >::degree_size_type max_deg = 0; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { max_deg = (std::max< typename graph_traits< Graph >::degree_size_type >)(max_deg, get(c, *vi)); } // store the vertices in bins by their degree // allocate two extra locations to ease boundary cases std::vector< size_type > bin(max_deg + 2); for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { ++bin[get(c, *vi)]; } // this loop sets bin[d] to the starting position of vertices // with degree d in the vert array for the bucket sort size_type cur_pos = 0; for (degree_type cur_deg = 0; cur_deg < max_deg + 2; ++cur_deg) { degree_type tmp = bin[cur_deg]; bin[cur_deg] = cur_pos; cur_pos += tmp; } // perform the bucket sort with pos and vert so that // pos[0] is the vertex of smallest degree std::vector< vertex > vert(num_vertices(g)); for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { vertex v = *vi; size_type p = bin[get(c, v)]; put(pos, v, p); vert[p] = v; ++bin[get(c, v)]; } // we ``abused'' bin while placing the vertices, now, // we need to restore it std::copy(boost::make_reverse_iterator(bin.end() - 2), boost::make_reverse_iterator(bin.begin()), boost::make_reverse_iterator(bin.end() - 1)); // now simulate removing the vertices for (size_type i = 0; i < num_vertices(g); ++i) { vertex v = vert[i]; vis.examine_vertex(v, g); v_cn = get(c, v); typename graph_traits< Graph >::out_edge_iterator oi, oi_end; for (boost::tie(oi, oi_end) = out_edges(v, g); oi != oi_end; ++oi) { vis.examine_edge(*oi, g); vertex u = target(*oi, g); // if c[u] > c[v], then u is still in the graph, if (get(c, u) > v_cn) { degree_type deg_u = get(c, u); degree_type pos_u = get(pos, u); // w is the first vertex with the same degree as u // (this is the resort operation!) degree_type pos_w = bin[deg_u]; vertex w = vert[pos_w]; if (u != v) { // swap u and w put(pos, u, pos_w); put(pos, w, pos_u); vert[pos_w] = u; vert[pos_u] = w; } // now, the vertices array is sorted assuming // we perform the following step // start the set of vertices with degree of u // one into the future (this now points at vertex // w which we swapped with u). ++bin[deg_u]; // we are removing v from the graph, so u's degree // decreases put(c, u, get(c, u) - 1); } } vis.finish_vertex(v, g); } return v_cn; } } // namespace detail // non-named parameter version for the unweighted case template < typename Graph, typename CoreMap, typename CoreNumVisitor > typename property_traits< CoreMap >::value_type core_numbers( Graph& g, CoreMap c, CoreNumVisitor vis) { typedef typename graph_traits< Graph >::vertices_size_type size_type; detail::compute_in_degree_map(g, c, detail::constant_value_property_map< typename property_traits< CoreMap >::value_type >(1)); return detail::core_numbers_impl(g, c, make_iterator_property_map( std::vector< size_type >(num_vertices(g)).begin(), get(vertex_index, g)), vis); } // non-named paramter version for the unweighted case template < typename Graph, typename CoreMap > typename property_traits< CoreMap >::value_type core_numbers( Graph& g, CoreMap c) { return core_numbers(g, c, make_core_numbers_visitor(null_visitor())); } // non-named parameter version for the weighted case template < typename Graph, typename CoreMap, typename EdgeWeightMap, typename VertexIndexMap, typename CoreNumVisitor > typename property_traits< CoreMap >::value_type core_numbers(Graph& g, CoreMap c, EdgeWeightMap wm, VertexIndexMap vim, CoreNumVisitor vis) { detail::compute_in_degree_map(g, c, wm); return detail::core_numbers_dispatch(g, c, wm, vim, vis); } // non-named parameter version for the weighted case // template <typename Graph, typename CoreMap, typename EdgeWeightMap> // typename property_traits<CoreMap>::value_type // core_numbers(Graph& g, CoreMap c, EdgeWeightMap wm) // { // typedef typename graph_traits<Graph>::vertices_size_type size_type; // detail::compute_in_degree_map(g,c,wm); // return detail::core_numbers_dispatch(g,c,wm,get(vertex_index,g), // make_core_numbers_visitor(null_visitor())); // } template < typename Graph, typename CoreMap > typename property_traits< CoreMap >::value_type weighted_core_numbers( Graph& g, CoreMap c) { return weighted_core_numbers( g, c, make_core_numbers_visitor(null_visitor())); } template < typename Graph, typename CoreMap, typename CoreNumVisitor > typename property_traits< CoreMap >::value_type weighted_core_numbers( Graph& g, CoreMap c, CoreNumVisitor vis) { return core_numbers(g, c, get(edge_weight, g), get(vertex_index, g), vis); } } // namespace boost #endif // BOOST_GRAPH_CORE_NUMBERS_HPP topological_sort.hpp 0000644 00000005063 15125521275 0010651 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_TOPOLOGICAL_SORT_HPP #define BOOST_GRAPH_TOPOLOGICAL_SORT_HPP #include <boost/config.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/depth_first_search.hpp> #include <boost/graph/visitors.hpp> #include <boost/graph/exception.hpp> #include <boost/throw_exception.hpp> namespace boost { // Topological sort visitor // // This visitor merely writes the linear ordering into an // OutputIterator. The OutputIterator could be something like an // ostream_iterator, or it could be a back/front_insert_iterator. // Note that if it is a back_insert_iterator, the recorded order is // the reverse topological order. On the other hand, if it is a // front_insert_iterator, the recorded order is the topological // order. // template < typename OutputIterator > struct topo_sort_visitor : public dfs_visitor<> { topo_sort_visitor(OutputIterator _iter) : m_iter(_iter) {} template < typename Edge, typename Graph > void back_edge(const Edge&, Graph&) { BOOST_THROW_EXCEPTION(not_a_dag()); } template < typename Vertex, typename Graph > void finish_vertex(const Vertex& u, Graph&) { *m_iter++ = u; } OutputIterator m_iter; }; // Topological Sort // // The topological sort algorithm creates a linear ordering // of the vertices such that if edge (u,v) appears in the graph, // then u comes before v in the ordering. The graph must // be a directed acyclic graph (DAG). The implementation // consists mainly of a call to depth-first search. // template < typename VertexListGraph, typename OutputIterator, typename P, typename T, typename R > void topological_sort(VertexListGraph& g, OutputIterator result, const bgl_named_params< P, T, R >& params) { typedef topo_sort_visitor< OutputIterator > TopoVisitor; depth_first_search(g, params.visitor(TopoVisitor(result))); } template < typename VertexListGraph, typename OutputIterator > void topological_sort(VertexListGraph& g, OutputIterator result) { topological_sort( g, result, bgl_named_params< int, buffer_param_t >(0)); // bogus } } // namespace boost #endif /*BOOST_GRAPH_TOPOLOGICAL_SORT_H*/ graph_selectors.hpp 0000644 00000002372 15125521275 0010452 0 ustar 00 //======================================================================= // Copyright 2002 Indiana University. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_SELECTORS_HPP #define BOOST_GRAPH_SELECTORS_HPP #include <boost/mpl/bool.hpp> namespace boost { //=========================================================================== // Selectors for the Directed template parameter of adjacency_list // and adjacency_matrix. struct directedS { enum { is_directed = true, is_bidir = false }; typedef mpl::true_ is_directed_t; typedef mpl::false_ is_bidir_t; }; struct undirectedS { enum { is_directed = false, is_bidir = false }; typedef mpl::false_ is_directed_t; typedef mpl::false_ is_bidir_t; }; struct bidirectionalS { enum { is_directed = true, is_bidir = true }; typedef mpl::true_ is_directed_t; typedef mpl::true_ is_bidir_t; }; } // namespace boost #endif // BOOST_GRAPH_SELECTORS_HPP smallest_last_ordering.hpp 0000644 00000012522 15125521275 0012024 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // Revision History: // 17 March 2006: Fixed a bug: when updating the degree a vertex // could be moved to a wrong bucket. (Roman Dementiev) // #ifndef BOOST_SMALLEST_LAST_VERTEX_ORDERING_HPP #define BOOST_SMALLEST_LAST_VERTEX_ORDERING_HPP /* The smallest-last ordering is defined for the loopless graph G with vertices a(j), j = 1,2,...,n where a(j) is the j-th column of A and with edge (a(i),a(j)) if and only if columns i and j have a non-zero in the same row position. The smallest-last ordering is determined recursively by letting list(k), k = n,...,1 be a column with least degree in the subgraph spanned by the un-ordered columns. */ #include <vector> #include <algorithm> #include <boost/config.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/pending/bucket_sorter.hpp> namespace boost { template < class VertexListGraph, class Order, class Degree, class Marker > void smallest_last_vertex_ordering( const VertexListGraph& G, Order order, Degree degree, Marker marker) { typedef typename boost::graph_traits< VertexListGraph > GraphTraits; typedef typename GraphTraits::vertex_descriptor Vertex; // typedef typename GraphTraits::size_type size_type; typedef std::size_t size_type; const size_type num = num_vertices(G); typedef typename boost::property_map< VertexListGraph, vertex_index_t >::type ID; typedef bucket_sorter< size_type, Vertex, Degree, ID > BucketSorter; BucketSorter degree_bucket_sorter(num, num, degree, get(vertex_index, G)); smallest_last_vertex_ordering( G, order, degree, marker, degree_bucket_sorter); } template < class VertexListGraph, class Order, class Degree, class Marker, class BucketSorter > void smallest_last_vertex_ordering(const VertexListGraph& G, Order order, Degree degree, Marker marker, BucketSorter& degree_buckets) { typedef typename boost::graph_traits< VertexListGraph > GraphTraits; typedef typename GraphTraits::vertex_descriptor Vertex; // typedef typename GraphTraits::size_type size_type; typedef std::size_t size_type; const size_type num = num_vertices(G); typename GraphTraits::vertex_iterator v, vend; for (boost::tie(v, vend) = vertices(G); v != vend; ++v) { put(marker, *v, num); put(degree, *v, out_degree(*v, G)); degree_buckets.push(*v); } size_type minimum_degree = 0; size_type current_order = num - 1; while (1) { typedef typename BucketSorter::stack MDStack; MDStack minimum_degree_stack = degree_buckets[minimum_degree]; while (minimum_degree_stack.empty()) minimum_degree_stack = degree_buckets[++minimum_degree]; Vertex node = minimum_degree_stack.top(); put(order, current_order, node); if (current_order == 0) // find all vertices break; minimum_degree_stack.pop(); put(marker, node, 0); // node has been ordered. typename GraphTraits::adjacency_iterator v, vend; for (boost::tie(v, vend) = adjacent_vertices(node, G); v != vend; ++v) if (get(marker, *v) > current_order) { //*v is unordered vertex put(marker, *v, current_order); // mark the columns adjacent to node // delete *v from the bucket sorter degree_buckets.remove(*v); // It is possible minimum degree goes down // Here we keep tracking it. put(degree, *v, get(degree, *v) - 1); BOOST_USING_STD_MIN(); minimum_degree = min BOOST_PREVENT_MACRO_SUBSTITUTION( minimum_degree, get(degree, *v)); // reinsert *v in the bucket sorter with the new degree degree_buckets.push(*v); } current_order--; } // at this point, order[i] = v_i; } template < class VertexListGraph, class Order > void smallest_last_vertex_ordering(const VertexListGraph& G, Order order) { typedef typename graph_traits< VertexListGraph >::vertex_descriptor vertex_descriptor; typedef typename graph_traits< VertexListGraph >::degree_size_type degree_size_type; smallest_last_vertex_ordering(G, order, make_shared_array_property_map( num_vertices(G), degree_size_type(0), get(vertex_index, G)), make_shared_array_property_map( num_vertices(G), (std::size_t)(0), get(vertex_index, G))); } template < class VertexListGraph > std::vector< typename graph_traits< VertexListGraph >::vertex_descriptor > smallest_last_vertex_ordering(const VertexListGraph& G) { std::vector< typename graph_traits< VertexListGraph >::vertex_descriptor > o(num_vertices(G)); smallest_last_vertex_ordering(G, make_iterator_property_map( o.begin(), typed_identity_property_map< std::size_t >())); return o; } } #endif two_graphs_common_spanning_trees.hpp 0000644 00000104264 15125521275 0014115 0 ustar 00 // Copyright (C) 2012, Michele Caini. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Two Graphs Common Spanning Trees Algorithm // Based on academic article of Mint, Read and Tarjan // Efficient Algorithm for Common Spanning Tree Problem // Electron. Lett., 28 April 1983, Volume 19, Issue 9, p.346-347 #ifndef BOOST_GRAPH_TWO_GRAPHS_COMMON_SPANNING_TREES_HPP #define BOOST_GRAPH_TWO_GRAPHS_COMMON_SPANNING_TREES_HPP #include <boost/config.hpp> #include <boost/bimap.hpp> #include <boost/type_traits.hpp> #include <boost/concept/requires.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/undirected_dfs.hpp> #include <boost/graph/connected_components.hpp> #include <boost/graph/filtered_graph.hpp> #include <vector> #include <stack> #include <map> namespace boost { namespace detail { template < typename TreeMap, typename PredMap, typename DistMap, typename LowMap, typename Buffer > struct bridges_visitor : public default_dfs_visitor { bridges_visitor(TreeMap tree, PredMap pred, DistMap dist, LowMap low, Buffer& buffer) : mTree(tree), mPred(pred), mDist(dist), mLow(low), mBuffer(buffer) { mNum = -1; } template < typename Vertex, typename Graph > void initialize_vertex(const Vertex& u, const Graph& g) { put(mPred, u, u); put(mDist, u, -1); } template < typename Vertex, typename Graph > void discover_vertex(const Vertex& u, const Graph& g) { put(mDist, u, ++mNum); put(mLow, u, get(mDist, u)); } template < typename Edge, typename Graph > void tree_edge(const Edge& e, const Graph& g) { put(mPred, target(e, g), source(e, g)); put(mTree, target(e, g), e); } template < typename Edge, typename Graph > void back_edge(const Edge& e, const Graph& g) { put(mLow, source(e, g), (std::min)(get(mLow, source(e, g)), get(mDist, target(e, g)))); } template < typename Vertex, typename Graph > void finish_vertex(const Vertex& u, const Graph& g) { Vertex parent = get(mPred, u); if (get(mLow, u) > get(mDist, parent)) mBuffer.push(get(mTree, u)); put(mLow, parent, (std::min)(get(mLow, parent), get(mLow, u))); } TreeMap mTree; PredMap mPred; DistMap mDist; LowMap mLow; Buffer& mBuffer; int mNum; }; template < typename Buffer > struct cycle_finder : public base_visitor< cycle_finder< Buffer > > { typedef on_back_edge event_filter; cycle_finder() : mBuffer(0) {} cycle_finder(Buffer* buffer) : mBuffer(buffer) {} template < typename Edge, typename Graph > void operator()(const Edge& e, const Graph& g) { if (mBuffer) mBuffer->push(e); } Buffer* mBuffer; }; template < typename DeletedMap > struct deleted_edge_status { deleted_edge_status() {} deleted_edge_status(DeletedMap map) : mMap(map) {} template < typename Edge > bool operator()(const Edge& e) const { return (!get(mMap, e)); } DeletedMap mMap; }; template < typename InLMap > struct inL_edge_status { inL_edge_status() {} inL_edge_status(InLMap map) : mMap(map) {} template < typename Edge > bool operator()(const Edge& e) const { return get(mMap, e); } InLMap mMap; }; template < typename Graph, typename Func, typename Seq, typename Map > void rec_two_graphs_common_spanning_trees(const Graph& iG, bimap< bimaps::set_of< int >, bimaps::set_of< typename graph_traits< Graph >::edge_descriptor > > iG_bimap, Map aiG_inL, Map diG, const Graph& vG, bimap< bimaps::set_of< int >, bimaps::set_of< typename graph_traits< Graph >::edge_descriptor > > vG_bimap, Map avG_inL, Map dvG, Func func, Seq inL) { typedef graph_traits< Graph > GraphTraits; typedef typename GraphTraits::vertex_descriptor vertex_descriptor; typedef typename GraphTraits::edge_descriptor edge_descriptor; typedef typename Seq::size_type seq_size_type; int edges = num_vertices(iG) - 1; // // [ Michele Caini ] // // Using the condition (edges != 0) leads to the accidental submission // of // sub-graphs ((V-1+1)-fake-tree, named here fat-tree). // Remove this condition is a workaround for the problem of fat-trees. // Please do not add that condition, even if it improves performance. // // Here is proposed the previous guard (that was wrong): // for(seq_size_type i = 0; (i < inL.size()) && (edges != 0); ++i) // { for (seq_size_type i = 0; i < inL.size(); ++i) if (inL[i]) --edges; if (edges < 0) return; } bool is_tree = (edges == 0); if (is_tree) { func(inL); } else { std::map< vertex_descriptor, default_color_type > vertex_color; std::map< edge_descriptor, default_color_type > edge_color; std::stack< edge_descriptor > iG_buf, vG_buf; bool found = false; seq_size_type m; for (seq_size_type j = 0; j < inL.size() && !found; ++j) { if (!inL[j] && !get(diG, iG_bimap.left.at(j)) && !get(dvG, vG_bimap.left.at(j))) { put(aiG_inL, iG_bimap.left.at(j), true); put(avG_inL, vG_bimap.left.at(j), true); undirected_dfs( make_filtered_graph(iG, detail::inL_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >(aiG_inL)), make_dfs_visitor(detail::cycle_finder< std::stack< edge_descriptor > >(&iG_buf)), associative_property_map< std::map< vertex_descriptor, default_color_type > >( vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >( edge_color)); undirected_dfs( make_filtered_graph(vG, detail::inL_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >(avG_inL)), make_dfs_visitor(detail::cycle_finder< std::stack< edge_descriptor > >(&vG_buf)), associative_property_map< std::map< vertex_descriptor, default_color_type > >( vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >( edge_color)); if (iG_buf.empty() && vG_buf.empty()) { inL[j] = true; found = true; m = j; } else { while (!iG_buf.empty()) iG_buf.pop(); while (!vG_buf.empty()) vG_buf.pop(); put(aiG_inL, iG_bimap.left.at(j), false); put(avG_inL, vG_bimap.left.at(j), false); } } } if (found) { std::stack< edge_descriptor > iG_buf_copy, vG_buf_copy; for (seq_size_type j = 0; j < inL.size(); ++j) { if (!inL[j] && !get(diG, iG_bimap.left.at(j)) && !get(dvG, vG_bimap.left.at(j))) { put(aiG_inL, iG_bimap.left.at(j), true); put(avG_inL, vG_bimap.left.at(j), true); undirected_dfs( make_filtered_graph(iG, detail::inL_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >( aiG_inL)), make_dfs_visitor(detail::cycle_finder< std::stack< edge_descriptor > >(&iG_buf)), associative_property_map< std::map< vertex_descriptor, default_color_type > >( vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >(edge_color)); undirected_dfs( make_filtered_graph(vG, detail::inL_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >( avG_inL)), make_dfs_visitor(detail::cycle_finder< std::stack< edge_descriptor > >(&vG_buf)), associative_property_map< std::map< vertex_descriptor, default_color_type > >( vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >(edge_color)); if (!iG_buf.empty() || !vG_buf.empty()) { while (!iG_buf.empty()) iG_buf.pop(); while (!vG_buf.empty()) vG_buf.pop(); put(diG, iG_bimap.left.at(j), true); put(dvG, vG_bimap.left.at(j), true); iG_buf_copy.push(iG_bimap.left.at(j)); vG_buf_copy.push(vG_bimap.left.at(j)); } put(aiG_inL, iG_bimap.left.at(j), false); put(avG_inL, vG_bimap.left.at(j), false); } } // REC detail::rec_two_graphs_common_spanning_trees< Graph, Func, Seq, Map >(iG, iG_bimap, aiG_inL, diG, vG, vG_bimap, aiG_inL, dvG, func, inL); while (!iG_buf_copy.empty()) { put(diG, iG_buf_copy.top(), false); put(dvG, vG_bimap.left.at(iG_bimap.right.at(iG_buf_copy.top())), false); iG_buf_copy.pop(); } while (!vG_buf_copy.empty()) { put(dvG, vG_buf_copy.top(), false); put(diG, iG_bimap.left.at(vG_bimap.right.at(vG_buf_copy.top())), false); vG_buf_copy.pop(); } inL[m] = false; put(aiG_inL, iG_bimap.left.at(m), false); put(avG_inL, vG_bimap.left.at(m), false); put(diG, iG_bimap.left.at(m), true); put(dvG, vG_bimap.left.at(m), true); std::map< vertex_descriptor, edge_descriptor > tree_map; std::map< vertex_descriptor, vertex_descriptor > pred_map; std::map< vertex_descriptor, int > dist_map, low_map; detail::bridges_visitor< associative_property_map< std::map< vertex_descriptor, edge_descriptor > >, associative_property_map< std::map< vertex_descriptor, vertex_descriptor > >, associative_property_map< std::map< vertex_descriptor, int > >, associative_property_map< std::map< vertex_descriptor, int > >, std::stack< edge_descriptor > > iG_vis(associative_property_map< std::map< vertex_descriptor, edge_descriptor > >( tree_map), associative_property_map< std::map< vertex_descriptor, vertex_descriptor > >( pred_map), associative_property_map< std::map< vertex_descriptor, int > >(dist_map), associative_property_map< std::map< vertex_descriptor, int > >(low_map), iG_buf), vG_vis(associative_property_map< std::map< vertex_descriptor, edge_descriptor > >( tree_map), associative_property_map< std::map< vertex_descriptor, vertex_descriptor > >( pred_map), associative_property_map< std::map< vertex_descriptor, int > >(dist_map), associative_property_map< std::map< vertex_descriptor, int > >(low_map), vG_buf); undirected_dfs( make_filtered_graph(iG, detail::deleted_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >(diG)), iG_vis, associative_property_map< std::map< vertex_descriptor, default_color_type > >( vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >( edge_color)); undirected_dfs( make_filtered_graph(vG, detail::deleted_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >(dvG)), vG_vis, associative_property_map< std::map< vertex_descriptor, default_color_type > >( vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >( edge_color)); found = false; std::stack< edge_descriptor > iG_buf_tmp, vG_buf_tmp; while (!iG_buf.empty() && !found) { if (!inL[iG_bimap.right.at(iG_buf.top())]) { put(aiG_inL, iG_buf.top(), true); put(avG_inL, vG_bimap.left.at(iG_bimap.right.at(iG_buf.top())), true); undirected_dfs( make_filtered_graph(iG, detail::inL_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >( aiG_inL)), make_dfs_visitor(detail::cycle_finder< std::stack< edge_descriptor > >(&iG_buf_tmp)), associative_property_map< std::map< vertex_descriptor, default_color_type > >( vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >(edge_color)); undirected_dfs( make_filtered_graph(vG, detail::inL_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >( avG_inL)), make_dfs_visitor(detail::cycle_finder< std::stack< edge_descriptor > >(&vG_buf_tmp)), associative_property_map< std::map< vertex_descriptor, default_color_type > >( vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >(edge_color)); if (!iG_buf_tmp.empty() || !vG_buf_tmp.empty()) { found = true; } else { while (!iG_buf_tmp.empty()) iG_buf_tmp.pop(); while (!vG_buf_tmp.empty()) vG_buf_tmp.pop(); iG_buf_copy.push(iG_buf.top()); } put(aiG_inL, iG_buf.top(), false); put(avG_inL, vG_bimap.left.at(iG_bimap.right.at(iG_buf.top())), false); } iG_buf.pop(); } while (!vG_buf.empty() && !found) { if (!inL[vG_bimap.right.at(vG_buf.top())]) { put(avG_inL, vG_buf.top(), true); put(aiG_inL, iG_bimap.left.at(vG_bimap.right.at(vG_buf.top())), true); undirected_dfs( make_filtered_graph(iG, detail::inL_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >( aiG_inL)), make_dfs_visitor(detail::cycle_finder< std::stack< edge_descriptor > >(&iG_buf_tmp)), associative_property_map< std::map< vertex_descriptor, default_color_type > >( vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >(edge_color)); undirected_dfs( make_filtered_graph(vG, detail::inL_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >( avG_inL)), make_dfs_visitor(detail::cycle_finder< std::stack< edge_descriptor > >(&vG_buf_tmp)), associative_property_map< std::map< vertex_descriptor, default_color_type > >( vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >(edge_color)); if (!iG_buf_tmp.empty() || !vG_buf_tmp.empty()) { found = true; } else { while (!iG_buf_tmp.empty()) iG_buf_tmp.pop(); while (!vG_buf_tmp.empty()) vG_buf_tmp.pop(); vG_buf_copy.push(vG_buf.top()); } put(avG_inL, vG_buf.top(), false); put(aiG_inL, iG_bimap.left.at(vG_bimap.right.at(vG_buf.top())), false); } vG_buf.pop(); } if (!found) { while (!iG_buf_copy.empty()) { inL[iG_bimap.right.at(iG_buf_copy.top())] = true; put(aiG_inL, iG_buf_copy.top(), true); put(avG_inL, vG_bimap.left.at( iG_bimap.right.at(iG_buf_copy.top())), true); iG_buf.push(iG_buf_copy.top()); iG_buf_copy.pop(); } while (!vG_buf_copy.empty()) { inL[vG_bimap.right.at(vG_buf_copy.top())] = true; put(avG_inL, vG_buf_copy.top(), true); put(aiG_inL, iG_bimap.left.at( vG_bimap.right.at(vG_buf_copy.top())), true); vG_buf.push(vG_buf_copy.top()); vG_buf_copy.pop(); } // REC detail::rec_two_graphs_common_spanning_trees< Graph, Func, Seq, Map >(iG, iG_bimap, aiG_inL, diG, vG, vG_bimap, aiG_inL, dvG, func, inL); while (!iG_buf.empty()) { inL[iG_bimap.right.at(iG_buf.top())] = false; put(aiG_inL, iG_buf.top(), false); put(avG_inL, vG_bimap.left.at(iG_bimap.right.at(iG_buf.top())), false); iG_buf.pop(); } while (!vG_buf.empty()) { inL[vG_bimap.right.at(vG_buf.top())] = false; put(avG_inL, vG_buf.top(), false); put(aiG_inL, iG_bimap.left.at(vG_bimap.right.at(vG_buf.top())), false); vG_buf.pop(); } } put(diG, iG_bimap.left.at(m), false); put(dvG, vG_bimap.left.at(m), false); } } } } // namespace detail template < typename Coll, typename Seq > struct tree_collector { public: BOOST_CONCEPT_ASSERT((BackInsertionSequence< Coll >)); BOOST_CONCEPT_ASSERT((RandomAccessContainer< Seq >)); BOOST_CONCEPT_ASSERT((CopyConstructible< Seq >)); typedef typename Coll::value_type coll_value_type; typedef typename Seq::value_type seq_value_type; BOOST_STATIC_ASSERT((is_same< coll_value_type, Seq >::value)); BOOST_STATIC_ASSERT((is_same< seq_value_type, bool >::value)); tree_collector(Coll& seqs) : mSeqs(seqs) {} inline void operator()(Seq seq) { mSeqs.push_back(seq); } private: Coll& mSeqs; }; template < typename Graph, typename Order, typename Func, typename Seq > BOOST_CONCEPT_REQUIRES( ((RandomAccessContainer< Order >))((IncidenceGraphConcept< Graph >))( (UnaryFunction< Func, void, Seq >))( (Mutable_RandomAccessContainer< Seq >))( (VertexAndEdgeListGraphConcept< Graph >)), (void)) two_graphs_common_spanning_trees(const Graph& iG, Order iG_map, const Graph& vG, Order vG_map, Func func, Seq inL) { typedef graph_traits< Graph > GraphTraits; typedef typename GraphTraits::directed_category directed_category; typedef typename GraphTraits::vertex_descriptor vertex_descriptor; typedef typename GraphTraits::edge_descriptor edge_descriptor; typedef typename GraphTraits::edges_size_type edges_size_type; typedef typename GraphTraits::edge_iterator edge_iterator; typedef typename Seq::value_type seq_value_type; typedef typename Seq::size_type seq_size_type; typedef typename Order::value_type order_value_type; typedef typename Order::size_type order_size_type; BOOST_STATIC_ASSERT((is_same< order_value_type, edge_descriptor >::value)); BOOST_CONCEPT_ASSERT((Convertible< order_size_type, edges_size_type >)); BOOST_CONCEPT_ASSERT((Convertible< seq_size_type, edges_size_type >)); BOOST_STATIC_ASSERT((is_same< seq_value_type, bool >::value)); BOOST_STATIC_ASSERT((is_same< directed_category, undirected_tag >::value)); if (num_vertices(iG) != num_vertices(vG)) return; if (inL.size() != num_edges(iG) || inL.size() != num_edges(vG)) return; if (iG_map.size() != num_edges(iG) || vG_map.size() != num_edges(vG)) return; typedef bimaps::bimap< bimaps::set_of< int >, bimaps::set_of< order_value_type > > bimap_type; typedef typename bimap_type::value_type bimap_value; bimap_type iG_bimap, vG_bimap; for (order_size_type i = 0; i < iG_map.size(); ++i) iG_bimap.insert(bimap_value(i, iG_map[i])); for (order_size_type i = 0; i < vG_map.size(); ++i) vG_bimap.insert(bimap_value(i, vG_map[i])); edge_iterator current, last; boost::tuples::tie(current, last) = edges(iG); for (; current != last; ++current) if (iG_bimap.right.find(*current) == iG_bimap.right.end()) return; boost::tuples::tie(current, last) = edges(vG); for (; current != last; ++current) if (vG_bimap.right.find(*current) == vG_bimap.right.end()) return; std::stack< edge_descriptor > iG_buf, vG_buf; std::map< vertex_descriptor, edge_descriptor > tree_map; std::map< vertex_descriptor, vertex_descriptor > pred_map; std::map< vertex_descriptor, int > dist_map, low_map; detail::bridges_visitor< associative_property_map< std::map< vertex_descriptor, edge_descriptor > >, associative_property_map< std::map< vertex_descriptor, vertex_descriptor > >, associative_property_map< std::map< vertex_descriptor, int > >, associative_property_map< std::map< vertex_descriptor, int > >, std::stack< edge_descriptor > > iG_vis(associative_property_map< std::map< vertex_descriptor, edge_descriptor > >(tree_map), associative_property_map< std::map< vertex_descriptor, vertex_descriptor > >(pred_map), associative_property_map< std::map< vertex_descriptor, int > >( dist_map), associative_property_map< std::map< vertex_descriptor, int > >(low_map), iG_buf), vG_vis(associative_property_map< std::map< vertex_descriptor, edge_descriptor > >(tree_map), associative_property_map< std::map< vertex_descriptor, vertex_descriptor > >(pred_map), associative_property_map< std::map< vertex_descriptor, int > >( dist_map), associative_property_map< std::map< vertex_descriptor, int > >( low_map), vG_buf); std::map< vertex_descriptor, default_color_type > vertex_color; std::map< edge_descriptor, default_color_type > edge_color; undirected_dfs(iG, iG_vis, associative_property_map< std::map< vertex_descriptor, default_color_type > >(vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >(edge_color)); undirected_dfs(vG, vG_vis, associative_property_map< std::map< vertex_descriptor, default_color_type > >(vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >(edge_color)); while (!iG_buf.empty()) { inL[iG_bimap.right.at(iG_buf.top())] = true; iG_buf.pop(); } while (!vG_buf.empty()) { inL[vG_bimap.right.at(vG_buf.top())] = true; vG_buf.pop(); } std::map< edge_descriptor, bool > iG_inL, vG_inL; associative_property_map< std::map< edge_descriptor, bool > > aiG_inL( iG_inL), avG_inL(vG_inL); for (seq_size_type i = 0; i < inL.size(); ++i) { if (inL[i]) { put(aiG_inL, iG_bimap.left.at(i), true); put(avG_inL, vG_bimap.left.at(i), true); } else { put(aiG_inL, iG_bimap.left.at(i), false); put(avG_inL, vG_bimap.left.at(i), false); } } undirected_dfs( make_filtered_graph(iG, detail::inL_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >( aiG_inL)), make_dfs_visitor( detail::cycle_finder< std::stack< edge_descriptor > >(&iG_buf)), associative_property_map< std::map< vertex_descriptor, default_color_type > >(vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >(edge_color)); undirected_dfs( make_filtered_graph(vG, detail::inL_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >( avG_inL)), make_dfs_visitor( detail::cycle_finder< std::stack< edge_descriptor > >(&vG_buf)), associative_property_map< std::map< vertex_descriptor, default_color_type > >(vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >(edge_color)); if (iG_buf.empty() && vG_buf.empty()) { std::map< edge_descriptor, bool > iG_deleted, vG_deleted; associative_property_map< std::map< edge_descriptor, bool > > diG( iG_deleted); associative_property_map< std::map< edge_descriptor, bool > > dvG( vG_deleted); boost::tuples::tie(current, last) = edges(iG); for (; current != last; ++current) put(diG, *current, false); boost::tuples::tie(current, last) = edges(vG); for (; current != last; ++current) put(dvG, *current, false); for (seq_size_type j = 0; j < inL.size(); ++j) { if (!inL[j]) { put(aiG_inL, iG_bimap.left.at(j), true); put(avG_inL, vG_bimap.left.at(j), true); undirected_dfs( make_filtered_graph(iG, detail::inL_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >(aiG_inL)), make_dfs_visitor( detail::cycle_finder< std::stack< edge_descriptor > >( &iG_buf)), associative_property_map< std::map< vertex_descriptor, default_color_type > >( vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >( edge_color)); undirected_dfs( make_filtered_graph(vG, detail::inL_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >(avG_inL)), make_dfs_visitor( detail::cycle_finder< std::stack< edge_descriptor > >( &vG_buf)), associative_property_map< std::map< vertex_descriptor, default_color_type > >( vertex_color), associative_property_map< std::map< edge_descriptor, default_color_type > >( edge_color)); if (!iG_buf.empty() || !vG_buf.empty()) { while (!iG_buf.empty()) iG_buf.pop(); while (!vG_buf.empty()) vG_buf.pop(); put(diG, iG_bimap.left.at(j), true); put(dvG, vG_bimap.left.at(j), true); } put(aiG_inL, iG_bimap.left.at(j), false); put(avG_inL, vG_bimap.left.at(j), false); } } int cc = 0; std::map< vertex_descriptor, int > com_map; cc += connected_components( make_filtered_graph(iG, detail::deleted_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >(diG)), associative_property_map< std::map< vertex_descriptor, int > >( com_map)); cc += connected_components( make_filtered_graph(vG, detail::deleted_edge_status< associative_property_map< std::map< edge_descriptor, bool > > >(dvG)), associative_property_map< std::map< vertex_descriptor, int > >( com_map)); if (cc != 2) return; // REC detail::rec_two_graphs_common_spanning_trees< Graph, Func, Seq, associative_property_map< std::map< edge_descriptor, bool > > >( iG, iG_bimap, aiG_inL, diG, vG, vG_bimap, aiG_inL, dvG, func, inL); } } template < typename Graph, typename Func, typename Seq > BOOST_CONCEPT_REQUIRES( ((IncidenceGraphConcept< Graph >))((EdgeListGraphConcept< Graph >)), (void)) two_graphs_common_spanning_trees( const Graph& iG, const Graph& vG, Func func, Seq inL) { typedef graph_traits< Graph > GraphTraits; typedef typename GraphTraits::edge_descriptor edge_descriptor; typedef typename GraphTraits::edge_iterator edge_iterator; std::vector< edge_descriptor > iGO, vGO; edge_iterator curr, last; boost::tuples::tie(curr, last) = edges(iG); for (; curr != last; ++curr) iGO.push_back(*curr); boost::tuples::tie(curr, last) = edges(vG); for (; curr != last; ++curr) vGO.push_back(*curr); two_graphs_common_spanning_trees(iG, iGO, vG, vGO, func, inL); } } // namespace boost #endif // BOOST_GRAPH_TWO_GRAPHS_COMMON_SPANNING_TREES_HPP iteration_macros_undef.hpp 0000644 00000001241 15125521275 0012003 0 ustar 00 //======================================================================= // Copyright 2002 Indiana University. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifdef BOOST_GRAPH_ITERATION_MACROS_HPP #undef BOOST_GRAPH_ITERATION_MACROS_HPP #undef BGL_CAT #undef BGL_FIRST #undef BGL_LAST #undef BGL_FORALL_VERTICES #undef BGL_FORALL_EDGES #undef BGL_FORALL_ADJACENT #undef BGL_FORALL_OUTEDGES #undef BGL_FORALL_INEDGES #endif parallel/simple_trigger.hpp 0000644 00000001023 15125521275 0012066 0 ustar 00 // Copyright (C) 2007 Douglas Gregor // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // This file contains a simplification of the "trigger" method for // process groups. The simple trigger handles the common case where // the handler associated with a trigger is a member function bound to // a particular pointer. // File moved #include <boost/property_map/parallel/simple_trigger.hpp> parallel/properties.hpp 0000644 00000006535 15125521275 0011263 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_PARALLEL_PROPERTIES_HPP #define BOOST_GRAPH_PARALLEL_PROPERTIES_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/properties.hpp> #include <boost/property_map/parallel/distributed_property_map.hpp> namespace boost { /*************************************************************************** * Property map reduction operations ***************************************************************************/ /** * Metafunction that produces a reduction operation for the given * property. The default behavior merely forwards to @ref * basic_reduce, but it is expected that this class template will be * specified for important properties. */ template<typename Property> struct property_reduce { template<typename Value> class apply : public parallel::basic_reduce<Value> {}; }; /** * Reduction of vertex colors can only darken, not lighten, the * color. Black cannot turn black, grey can only turn black, and * white can be changed to either color. The default color is white. */ template<> struct property_reduce<vertex_color_t> { template<typename Color> class apply { typedef color_traits<Color> traits; public: BOOST_STATIC_CONSTANT(bool, non_default_resolver = true); template<typename Key> Color operator()(const Key&) const { return traits::white(); } template<typename Key> Color operator()(const Key&, Color local, Color remote) const { if (local == traits::white()) return remote; else if (remote == traits::black()) return remote; else return local; } }; }; /** * Reduction of a distance always takes the shorter distance. The * default distance value is the maximum value for the data type. */ template<> struct property_reduce<vertex_distance_t> { template<typename T> class apply { public: BOOST_STATIC_CONSTANT(bool, non_default_resolver = true); template<typename Key> T operator()(const Key&) const { return (std::numeric_limits<T>::max)(); } template<typename Key> T operator()(const Key&, T x, T y) const { return x < y? x : y; } }; }; template<> struct property_reduce<vertex_predecessor_t> { template<typename T> class apply { public: BOOST_STATIC_CONSTANT(bool, non_default_resolver = true); template<typename Key> T operator()(Key key) const { return key; } template<typename Key> T operator()(Key key, T, T y) const { return y; } }; }; template<typename Property, typename PropertyMap> inline void set_property_map_role(Property p, PropertyMap pm) { typedef typename property_traits<PropertyMap>::value_type value_type; typedef property_reduce<Property> property_red; typedef typename property_red::template apply<value_type> reduce; pm.set_reduce(reduce()); } } // end namespace boost #endif // BOOST_GRAPH_PARALLEL_PROPERTIES_HPP parallel/distribution.hpp 0000644 00000047034 15125521275 0011605 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Peter Gottschling // Andrew Lumsdaine #ifndef BOOST_PARALLEL_DISTRIBUTION_HPP #define BOOST_PARALLEL_DISTRIBUTION_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <cstddef> #include <vector> #include <algorithm> #include <numeric> #include <boost/assert.hpp> #include <boost/iterator/counting_iterator.hpp> #include <boost/random/uniform_int.hpp> #include <boost/shared_ptr.hpp> #include <boost/config.hpp> #include <typeinfo> namespace boost { namespace parallel { template<typename ProcessGroup, typename SizeType = std::size_t> class variant_distribution { public: typedef typename ProcessGroup::process_id_type process_id_type; typedef typename ProcessGroup::process_size_type process_size_type; typedef SizeType size_type; private: struct basic_distribution { virtual ~basic_distribution() {} virtual size_type block_size(process_id_type, size_type) const = 0; virtual process_id_type in_process(size_type) const = 0; virtual size_type local(size_type) const = 0; virtual size_type global(size_type) const = 0; virtual size_type global(process_id_type, size_type) const = 0; virtual void* address() = 0; virtual const void* address() const = 0; virtual const std::type_info& type() const = 0; }; template<typename Distribution> struct poly_distribution : public basic_distribution { explicit poly_distribution(const Distribution& distribution) : distribution_(distribution) { } virtual size_type block_size(process_id_type id, size_type n) const { return distribution_.block_size(id, n); } virtual process_id_type in_process(size_type i) const { return distribution_(i); } virtual size_type local(size_type i) const { return distribution_.local(i); } virtual size_type global(size_type n) const { return distribution_.global(n); } virtual size_type global(process_id_type id, size_type n) const { return distribution_.global(id, n); } virtual void* address() { return &distribution_; } virtual const void* address() const { return &distribution_; } virtual const std::type_info& type() const { return typeid(Distribution); } private: Distribution distribution_; }; public: variant_distribution() { } template<typename Distribution> variant_distribution(const Distribution& distribution) : distribution_(new poly_distribution<Distribution>(distribution)) { } size_type block_size(process_id_type id, size_type n) const { return distribution_->block_size(id, n); } process_id_type operator()(size_type i) const { return distribution_->in_process(i); } size_type local(size_type i) const { return distribution_->local(i); } size_type global(size_type n) const { return distribution_->global(n); } size_type global(process_id_type id, size_type n) const { return distribution_->global(id, n); } operator bool() const { return distribution_; } void clear() { distribution_.reset(); } template<typename T> T* as() { if (distribution_->type() == typeid(T)) return static_cast<T*>(distribution_->address()); else return 0; } template<typename T> const T* as() const { if (distribution_->type() == typeid(T)) return static_cast<T*>(distribution_->address()); else return 0; } private: shared_ptr<basic_distribution> distribution_; }; struct block { template<typename LinearProcessGroup> explicit block(const LinearProcessGroup& pg, std::size_t n) : id(process_id(pg)), p(num_processes(pg)), n(n) { } // If there are n elements in the distributed data structure, returns the number of elements stored locally. template<typename SizeType> SizeType block_size(SizeType n) const { return (n / p) + ((std::size_t)(n % p) > id? 1 : 0); } // If there are n elements in the distributed data structure, returns the number of elements stored on processor ID template<typename SizeType, typename ProcessID> SizeType block_size(ProcessID id, SizeType n) const { return (n / p) + ((ProcessID)(n % p) > id? 1 : 0); } // Returns the processor on which element with global index i is stored template<typename SizeType> SizeType operator()(SizeType i) const { SizeType cutoff_processor = n % p; SizeType cutoff = cutoff_processor * (n / p + 1); if (i < cutoff) return i / (n / p + 1); else return cutoff_processor + (i - cutoff) / (n / p); } // Find the starting index for processor with the given id template<typename ID> std::size_t start(ID id) const { std::size_t estimate = id * (n / p + 1); ID cutoff_processor = n % p; if (id < cutoff_processor) return estimate; else return estimate - (id - cutoff_processor); } // Find the local index for the ith global element template<typename SizeType> SizeType local(SizeType i) const { SizeType owner = (*this)(i); return i - start(owner); } // Returns the global index of local element i template<typename SizeType> SizeType global(SizeType i) const { return global(id, i); } // Returns the global index of the ith local element on processor id template<typename ProcessID, typename SizeType> SizeType global(ProcessID id, SizeType i) const { return i + start(id); } private: std::size_t id; //< The ID number of this processor std::size_t p; //< The number of processors std::size_t n; //< The size of the problem space }; // Block distribution with arbitrary block sizes struct uneven_block { typedef std::vector<std::size_t> size_vector; template<typename LinearProcessGroup> explicit uneven_block(const LinearProcessGroup& pg, const std::vector<std::size_t>& local_sizes) : id(process_id(pg)), p(num_processes(pg)), local_sizes(local_sizes) { BOOST_ASSERT(local_sizes.size() == p); local_starts.resize(p + 1); local_starts[0] = 0; std::partial_sum(local_sizes.begin(), local_sizes.end(), &local_starts[1]); n = local_starts[p]; } // To do maybe: enter local size in each process and gather in constructor (much handier) // template<typename LinearProcessGroup> // explicit uneven_block(const LinearProcessGroup& pg, std::size_t my_local_size) // If there are n elements in the distributed data structure, returns the number of elements stored locally. template<typename SizeType> SizeType block_size(SizeType) const { return local_sizes[id]; } // If there are n elements in the distributed data structure, returns the number of elements stored on processor ID template<typename SizeType, typename ProcessID> SizeType block_size(ProcessID id, SizeType) const { return local_sizes[id]; } // Returns the processor on which element with global index i is stored template<typename SizeType> SizeType operator()(SizeType i) const { BOOST_ASSERT (i >= (SizeType) 0 && i < (SizeType) n); // check for valid range size_vector::const_iterator lb = std::lower_bound(local_starts.begin(), local_starts.end(), (std::size_t) i); return ((SizeType)(*lb) == i ? lb : --lb) - local_starts.begin(); } // Find the starting index for processor with the given id template<typename ID> std::size_t start(ID id) const { return local_starts[id]; } // Find the local index for the ith global element template<typename SizeType> SizeType local(SizeType i) const { SizeType owner = (*this)(i); return i - start(owner); } // Returns the global index of local element i template<typename SizeType> SizeType global(SizeType i) const { return global(id, i); } // Returns the global index of the ith local element on processor id template<typename ProcessID, typename SizeType> SizeType global(ProcessID id, SizeType i) const { return i + start(id); } private: std::size_t id; //< The ID number of this processor std::size_t p; //< The number of processors std::size_t n; //< The size of the problem space std::vector<std::size_t> local_sizes; //< The sizes of all blocks std::vector<std::size_t> local_starts; //< Lowest global index of each block }; struct oned_block_cyclic { template<typename LinearProcessGroup> explicit oned_block_cyclic(const LinearProcessGroup& pg, std::size_t size) : id(process_id(pg)), p(num_processes(pg)), size(size) { } template<typename SizeType> SizeType block_size(SizeType n) const { return block_size(id, n); } template<typename SizeType, typename ProcessID> SizeType block_size(ProcessID id, SizeType n) const { SizeType all_blocks = n / size; SizeType extra_elements = n % size; SizeType everyone_gets = all_blocks / p; SizeType extra_blocks = all_blocks % p; SizeType my_blocks = everyone_gets + (p < extra_blocks? 1 : 0); SizeType my_elements = my_blocks * size + (p == extra_blocks? extra_elements : 0); return my_elements; } template<typename SizeType> SizeType operator()(SizeType i) const { return (i / size) % p; } template<typename SizeType> SizeType local(SizeType i) const { return ((i / size) / p) * size + i % size; } template<typename SizeType> SizeType global(SizeType i) const { return global(id, i); } template<typename ProcessID, typename SizeType> SizeType global(ProcessID id, SizeType i) const { return ((i / size) * p + id) * size + i % size; } private: std::size_t id; //< The ID number of this processor std::size_t p; //< The number of processors std::size_t size; //< Block size }; struct twod_block_cyclic { template<typename LinearProcessGroup> explicit twod_block_cyclic(const LinearProcessGroup& pg, std::size_t block_rows, std::size_t block_columns, std::size_t data_columns_per_row) : id(process_id(pg)), p(num_processes(pg)), block_rows(block_rows), block_columns(block_columns), data_columns_per_row(data_columns_per_row) { } template<typename SizeType> SizeType block_size(SizeType n) const { return block_size(id, n); } template<typename SizeType, typename ProcessID> SizeType block_size(ProcessID id, SizeType n) const { // TBD: This is really lame :) int result = -1; while (n > 0) { --n; if ((*this)(n) == id && (int)local(n) > result) result = local(n); } ++result; // std::cerr << "Block size of id " << id << " is " << result << std::endl; return result; } template<typename SizeType> SizeType operator()(SizeType i) const { SizeType result = get_block_num(i) % p; // std::cerr << "Item " << i << " goes on processor " << result << std::endl; return result; } template<typename SizeType> SizeType local(SizeType i) const { // Compute the start of the block std::size_t block_num = get_block_num(i); // std::cerr << "Item " << i << " is in block #" << block_num << std::endl; std::size_t local_block_num = block_num / p; std::size_t block_start = local_block_num * block_rows * block_columns; // Compute the offset into the block std::size_t data_row = i / data_columns_per_row; std::size_t data_col = i % data_columns_per_row; std::size_t block_offset = (data_row % block_rows) * block_columns + (data_col % block_columns); // std::cerr << "Item " << i << " maps to local index " << block_start+block_offset << std::endl; return block_start + block_offset; } template<typename SizeType> SizeType global(SizeType i) const { // Compute the (global) block in which this element resides SizeType local_block_num = i / (block_rows * block_columns); SizeType block_offset = i % (block_rows * block_columns); SizeType block_num = local_block_num * p + id; // Compute the position of the start of the block (globally) SizeType block_start = block_num * block_rows * block_columns; std::cerr << "Block " << block_num << " starts at index " << block_start << std::endl; // Compute the row and column of this block SizeType block_row = block_num / (data_columns_per_row / block_columns); SizeType block_col = block_num % (data_columns_per_row / block_columns); SizeType row_in_block = block_offset / block_columns; SizeType col_in_block = block_offset % block_columns; std::cerr << "Local index " << i << " is in block at row " << block_row << ", column " << block_col << ", in-block row " << row_in_block << ", in-block col " << col_in_block << std::endl; SizeType result = block_row * block_rows + block_col * block_columns + row_in_block * block_rows + col_in_block; std::cerr << "global(" << i << "@" << id << ") = " << result << " =? " << local(result) << std::endl; BOOST_ASSERT(i == local(result)); return result; } private: template<typename SizeType> std::size_t get_block_num(SizeType i) const { std::size_t data_row = i / data_columns_per_row; std::size_t data_col = i % data_columns_per_row; std::size_t block_row = data_row / block_rows; std::size_t block_col = data_col / block_columns; std::size_t blocks_in_row = data_columns_per_row / block_columns; std::size_t block_num = block_col * blocks_in_row + block_row; return block_num; } std::size_t id; //< The ID number of this processor std::size_t p; //< The number of processors std::size_t block_rows; //< The # of rows in each block std::size_t block_columns; //< The # of columns in each block std::size_t data_columns_per_row; //< The # of columns per row of data }; class twod_random { template<typename RandomNumberGen> struct random_int { explicit random_int(RandomNumberGen& gen) : gen(gen) { } template<typename T> T operator()(T n) const { uniform_int<T> distrib(0, n-1); return distrib(gen); } private: RandomNumberGen& gen; }; public: template<typename LinearProcessGroup, typename RandomNumberGen> explicit twod_random(const LinearProcessGroup& pg, std::size_t block_rows, std::size_t block_columns, std::size_t data_columns_per_row, std::size_t n, RandomNumberGen& gen) : id(process_id(pg)), p(num_processes(pg)), block_rows(block_rows), block_columns(block_columns), data_columns_per_row(data_columns_per_row), global_to_local(n / (block_rows * block_columns)) { std::copy(make_counting_iterator(std::size_t(0)), make_counting_iterator(global_to_local.size()), global_to_local.begin()); #if defined(BOOST_NO_CXX98_RANDOM_SHUFFLE) std::shuffle(global_to_local.begin(), global_to_local.end(), gen); #else random_int<RandomNumberGen> rand(gen); std::random_shuffle(global_to_local.begin(), global_to_local.end(), rand); #endif } template<typename SizeType> SizeType block_size(SizeType n) const { return block_size(id, n); } template<typename SizeType, typename ProcessID> SizeType block_size(ProcessID id, SizeType n) const { // TBD: This is really lame :) int result = -1; while (n > 0) { --n; if ((*this)(n) == id && (int)local(n) > result) result = local(n); } ++result; // std::cerr << "Block size of id " << id << " is " << result << std::endl; return result; } template<typename SizeType> SizeType operator()(SizeType i) const { SizeType result = get_block_num(i) % p; // std::cerr << "Item " << i << " goes on processor " << result << std::endl; return result; } template<typename SizeType> SizeType local(SizeType i) const { // Compute the start of the block std::size_t block_num = get_block_num(i); // std::cerr << "Item " << i << " is in block #" << block_num << std::endl; std::size_t local_block_num = block_num / p; std::size_t block_start = local_block_num * block_rows * block_columns; // Compute the offset into the block std::size_t data_row = i / data_columns_per_row; std::size_t data_col = i % data_columns_per_row; std::size_t block_offset = (data_row % block_rows) * block_columns + (data_col % block_columns); // std::cerr << "Item " << i << " maps to local index " << block_start+block_offset << std::endl; return block_start + block_offset; } private: template<typename SizeType> std::size_t get_block_num(SizeType i) const { std::size_t data_row = i / data_columns_per_row; std::size_t data_col = i % data_columns_per_row; std::size_t block_row = data_row / block_rows; std::size_t block_col = data_col / block_columns; std::size_t blocks_in_row = data_columns_per_row / block_columns; std::size_t block_num = block_col * blocks_in_row + block_row; return global_to_local[block_num]; } std::size_t id; //< The ID number of this processor std::size_t p; //< The number of processors std::size_t block_rows; //< The # of rows in each block std::size_t block_columns; //< The # of columns in each block std::size_t data_columns_per_row; //< The # of columns per row of data std::vector<std::size_t> global_to_local; }; class random_distribution { template<typename RandomNumberGen> struct random_int { explicit random_int(RandomNumberGen& gen) : gen(gen) { } template<typename T> T operator()(T n) const { uniform_int<T> distrib(0, n-1); return distrib(gen); } private: RandomNumberGen& gen; }; public: template<typename LinearProcessGroup, typename RandomNumberGen> random_distribution(const LinearProcessGroup& pg, RandomNumberGen& gen, std::size_t n) : base(pg, n), local_to_global(n), global_to_local(n) { std::copy(make_counting_iterator(std::size_t(0)), make_counting_iterator(n), local_to_global.begin()); #if defined(BOOST_NO_CXX98_RANDOM_SHUFFLE) std::shuffle(local_to_global.begin(), local_to_global.end(), gen); #else random_int<RandomNumberGen> rand(gen); std::random_shuffle(local_to_global.begin(), local_to_global.end(), rand); #endif for (std::vector<std::size_t>::size_type i = 0; i < n; ++i) global_to_local[local_to_global[i]] = i; } template<typename SizeType> SizeType block_size(SizeType n) const { return base.block_size(n); } template<typename SizeType, typename ProcessID> SizeType block_size(ProcessID id, SizeType n) const { return base.block_size(id, n); } template<typename SizeType> SizeType operator()(SizeType i) const { return base(global_to_local[i]); } template<typename SizeType> SizeType local(SizeType i) const { return base.local(global_to_local[i]); } template<typename ProcessID, typename SizeType> SizeType global(ProcessID p, SizeType i) const { return local_to_global[base.global(p, i)]; } template<typename SizeType> SizeType global(SizeType i) const { return local_to_global[base.global(i)]; } private: block base; std::vector<std::size_t> local_to_global; std::vector<std::size_t> global_to_local; }; } } // end namespace boost::parallel #endif // BOOST_PARALLEL_DISTRIBUTION_HPP parallel/container_traits.hpp 0000644 00000002332 15125521275 0012426 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine // // This file contains traits that describe // #ifndef BOOST_GRAPH_PARALLEL_CONTAINER_TRAITS_HPP #define BOOST_GRAPH_PARALLEL_CONTAINER_TRAITS_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif namespace boost { namespace graph { namespace parallel { template<typename T> struct process_group_type { typedef typename T::process_group_type type; }; template<typename T> inline typename process_group_type<T>::type process_group(const T& x) { return x.process_group(); } // Helper function that algorithms should use to get the process group // out of a container. template<typename Container> inline typename process_group_type<Container>::type process_group_adl(const Container& container) { return process_group(container); } } } } // end namespace boost::graph::parallel #endif // BOOST_GRAPH_PARALLEL_CONTAINER_TRAITS_HPP parallel/algorithm.hpp 0000644 00000004705 15125521275 0011052 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_PARALLEL_ALGORITHM_HPP #define BOOST_PARALLEL_ALGORITHM_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/optional.hpp> #include <boost/config.hpp> // for BOOST_STATIC_CONSTANT #include <vector> #include <functional> namespace boost { namespace parallel { template<typename BinaryOp> struct is_commutative { BOOST_STATIC_CONSTANT(bool, value = false); }; template<typename T> struct minimum : std::binary_function<T, T, T> { const T& operator()(const T& x, const T& y) const { return x < y? x : y; } }; template<typename T> struct maximum : std::binary_function<T, T, T> { const T& operator()(const T& x, const T& y) const { return x < y? y : x; } }; template<typename T> struct sum : std::binary_function<T, T, T> { const T operator()(const T& x, const T& y) const { return x + y; } }; template<typename ProcessGroup, typename InputIterator, typename OutputIterator, typename BinaryOperation> OutputIterator reduce(ProcessGroup pg, typename ProcessGroup::process_id_type root, InputIterator first, InputIterator last, OutputIterator out, BinaryOperation bin_op); template<typename ProcessGroup, typename T, typename BinaryOperation> inline T all_reduce(ProcessGroup pg, const T& value, BinaryOperation bin_op) { T result; all_reduce(pg, const_cast<T*>(&value), const_cast<T*>(&value+1), &result, bin_op); return result; } template<typename ProcessGroup, typename T, typename BinaryOperation> inline T scan(ProcessGroup pg, const T& value, BinaryOperation bin_op) { T result; scan(pg, const_cast<T*>(&value), const_cast<T*>(&value+1), &result, bin_op); return result; } template<typename ProcessGroup, typename InputIterator, typename T> void all_gather(ProcessGroup pg, InputIterator first, InputIterator last, std::vector<T>& out); } } // end namespace boost::parallel #include <boost/graph/parallel/detail/inplace_all_to_all.hpp> #endif // BOOST_PARALLEL_ALGORITHM_HPP parallel/detail/inplace_all_to_all.hpp 0000644 00000004566 15125521275 0014130 0 ustar 00 // Copyright 2005 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_PARALLEL_INPLACE_ALL_TO_ALL_HPP #define BOOST_GRAPH_PARALLEL_INPLACE_ALL_TO_ALL_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif // // Implements the inplace all-to-all communication algorithm. // #include <vector> #include <iterator> namespace boost { namespace parallel { template<typename ProcessGroup, typename T> // where {LinearProcessGroup<ProcessGroup>, MessagingProcessGroup<ProcessGroup>} void inplace_all_to_all(ProcessGroup pg, const std::vector<std::vector<T> >& outgoing, std::vector<std::vector<T> >& incoming) { typedef typename std::vector<T>::size_type size_type; typedef typename ProcessGroup::process_size_type process_size_type; typedef typename ProcessGroup::process_id_type process_id_type; process_size_type p = num_processes(pg); // Make sure there are no straggling messages synchronize(pg); // Send along the count (always) and the data (if count > 0) for (process_id_type dest = 0; dest < p; ++dest) { if (dest != process_id(pg)) { send(pg, dest, 0, outgoing[dest].size()); if (!outgoing[dest].empty()) send(pg, dest, 1, &outgoing[dest].front(), outgoing[dest].size()); } } // Make sure all of the data gets transferred synchronize(pg); // Receive the sizes and data for (process_id_type source = 0; source < p; ++source) { if (source != process_id(pg)) { size_type size; receive(pg, source, 0, size); incoming[source].resize(size); if (size > 0) receive(pg, source, 1, &incoming[source].front(), size); } else if (&incoming != &outgoing) { incoming[source] = outgoing[source]; } } } template<typename ProcessGroup, typename T> // where {LinearProcessGroup<ProcessGroup>, MessagingProcessGroup<ProcessGroup>} void inplace_all_to_all(ProcessGroup pg, std::vector<std::vector<T> >& data) { inplace_all_to_all(pg, data, data); } } } // end namespace boost::parallel #endif // BOOST_GRAPH_PARALLEL_INPLACE_ALL_TO_ALL_HPP parallel/detail/untracked_pair.hpp 0000644 00000000711 15125521275 0013312 0 ustar 00 // Copyright (C) 2007 Matthias Troyer // // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // // This file contains helper data structures for use in transmitting // properties. The basic idea is to optimize away any storage for the // properties when no properties are specified. // File moved #include <boost/property_map/parallel/detail/untracked_pair.hpp> parallel/detail/property_holders.hpp 0000644 00000011562 15125521275 0013731 0 ustar 00 // Copyright (C) 2007 Douglas Gregor and Matthias Troyer // // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // // This file contains helper data structures for use in transmitting // properties. The basic idea is to optimize away any storage for the // properties when no properties are specified. #ifndef BOOST_PARALLEL_DETAIL_PROPERTY_HOLDERS_HPP #define BOOST_PARALLEL_DETAIL_PROPERTY_HOLDERS_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/mpi/datatype.hpp> #include <boost/property_map/property_map.hpp> #include <boost/serialization/base_object.hpp> #include <boost/mpl/and.hpp> #include <boost/graph/parallel/detail/untracked_pair.hpp> namespace boost { namespace detail { namespace parallel { /** * This structure contains an instance of @c Property, unless @c * Property is a placeholder for "no property". Always access the * property through @c get_property. Typically used as a base class. */ template<typename Property> struct maybe_store_property { maybe_store_property() {} maybe_store_property(const Property& p) : p(p) {} Property& get_property() { return p; } const Property& get_property() const { return p; } private: Property p; friend class boost::serialization::access; template<typename Archiver> void serialize(Archiver& ar, const unsigned int /*version*/) { ar & p; } }; template<> struct maybe_store_property<no_property> { maybe_store_property() {} maybe_store_property(no_property) {} no_property get_property() const { return no_property(); } private: friend class boost::serialization::access; template<typename Archiver> void serialize(Archiver&, const unsigned int /*version*/) { } }; /** * This structure is a simple pair that also contains a property. */ template<typename T, typename U, typename Property> class pair_with_property : public boost::parallel::detail::untracked_pair<T, U> , public maybe_store_property<Property> { public: typedef boost::parallel::detail::untracked_pair<T, U> pair_base; typedef maybe_store_property<Property> property_base; pair_with_property() { } pair_with_property(const T& t, const U& u, const Property& property) : pair_base(t, u), property_base(property) { } private: friend class boost::serialization::access; template<typename Archiver> void serialize(Archiver& ar, const unsigned int /*version*/) { ar & boost::serialization::base_object<pair_base>(*this) & boost::serialization::base_object<property_base>(*this); } }; template<typename T, typename U, typename Property> inline pair_with_property<T, U, Property> make_pair_with_property(const T& t, const U& u, const Property& property) { return pair_with_property<T, U, Property>(t, u, property); } } } } // end namespace boost::parallel::detail namespace boost { namespace mpi { template<> struct is_mpi_datatype<boost::detail::parallel::maybe_store_property<no_property> > : mpl::true_ { }; template<typename Property> struct is_mpi_datatype<boost::detail::parallel::maybe_store_property<Property> > : is_mpi_datatype<Property> { }; template<typename T, typename U, typename Property> struct is_mpi_datatype<boost::detail::parallel::pair_with_property<T, U, Property> > : boost::mpl::and_<is_mpi_datatype<boost::parallel::detail::untracked_pair<T, U> >, is_mpi_datatype<Property> > { }; } } // end namespace boost::mpi BOOST_IS_BITWISE_SERIALIZABLE(boost::detail::parallel::maybe_store_property<no_property>) namespace boost { namespace serialization { template<typename Property> struct is_bitwise_serializable<boost::detail::parallel::maybe_store_property<Property> > : is_bitwise_serializable<Property> { }; template<typename Property> struct implementation_level<boost::detail::parallel::maybe_store_property<Property> > : mpl::int_<object_serializable> {} ; template<typename Property> struct tracking_level<boost::detail::parallel::maybe_store_property<Property> > : mpl::int_<track_never> {} ; template<typename T, typename U, typename Property> struct is_bitwise_serializable< boost::detail::parallel::pair_with_property<T, U, Property> > : boost::mpl::and_<is_bitwise_serializable<boost::parallel::detail::untracked_pair<T, U> >, is_bitwise_serializable<Property> > { }; template<typename T, typename U, typename Property> struct implementation_level< boost::detail::parallel::pair_with_property<T, U, Property> > : mpl::int_<object_serializable> {} ; template<typename T, typename U, typename Property> struct tracking_level< boost::detail::parallel::pair_with_property<T, U, Property> > : mpl::int_<track_never> {} ; } } // end namespace boost::serialization #endif // BOOST_PARALLEL_DETAIL_PROPERTY_HOLDERS_HPP parallel/process_group.hpp 0000644 00000000565 15125521275 0011756 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine // File moved #include <boost/property_map/parallel/process_group.hpp> parallel/basic_reduce.hpp 0000644 00000000564 15125521275 0011473 0 ustar 00 // Copyright 2005 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine // File moved #include <boost/property_map/parallel/basic_reduce.hpp> edmonds_karp_max_flow.hpp 0000644 00000023701 15125521275 0011627 0 ustar 00 //======================================================================= // Copyright 2000 University of Notre Dame. // Authors: Jeremy G. Siek, Andrew Lumsdaine, Lie-Quan Lee // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_EDMONDS_KARP_MAX_FLOW_HPP #define BOOST_GRAPH_EDMONDS_KARP_MAX_FLOW_HPP #include <boost/config.hpp> #include <vector> #include <algorithm> // for std::min and std::max #include <boost/config.hpp> #include <boost/pending/queue.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/filtered_graph.hpp> #include <boost/graph/breadth_first_search.hpp> namespace boost { // The "labeling" algorithm from "Network Flows" by Ahuja, Magnanti, // Orlin. I think this is the same as or very similar to the original // Edmonds-Karp algorithm. This solves the maximum flow problem. namespace detail { template < class Graph, class ResCapMap > filtered_graph< Graph, is_residual_edge< ResCapMap > > residual_graph( Graph& g, ResCapMap residual_capacity) { return filtered_graph< Graph, is_residual_edge< ResCapMap > >( g, is_residual_edge< ResCapMap >(residual_capacity)); } template < class Graph, class PredEdgeMap, class ResCapMap, class RevEdgeMap > inline void augment(Graph& g, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink, PredEdgeMap p, ResCapMap residual_capacity, RevEdgeMap reverse_edge) { typename graph_traits< Graph >::edge_descriptor e; typename graph_traits< Graph >::vertex_descriptor u; typedef typename property_traits< ResCapMap >::value_type FlowValue; // find minimum residual capacity along the augmenting path FlowValue delta = (std::numeric_limits< FlowValue >::max)(); e = get(p, sink); do { BOOST_USING_STD_MIN(); delta = min BOOST_PREVENT_MACRO_SUBSTITUTION( delta, get(residual_capacity, e)); u = source(e, g); e = get(p, u); } while (u != src); // push delta units of flow along the augmenting path e = get(p, sink); do { put(residual_capacity, e, get(residual_capacity, e) - delta); put(residual_capacity, get(reverse_edge, e), get(residual_capacity, get(reverse_edge, e)) + delta); u = source(e, g); e = get(p, u); } while (u != src); } } // namespace detail template < class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap, class ReverseEdgeMap, class ColorMap, class PredEdgeMap > typename property_traits< CapacityEdgeMap >::value_type edmonds_karp_max_flow( Graph& g, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink, CapacityEdgeMap cap, ResidualCapacityEdgeMap res, ReverseEdgeMap rev, ColorMap color, PredEdgeMap pred) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; typename graph_traits< Graph >::vertex_iterator u_iter, u_end; typename graph_traits< Graph >::out_edge_iterator ei, e_end; for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) for (boost::tie(ei, e_end) = out_edges(*u_iter, g); ei != e_end; ++ei) put(res, *ei, get(cap, *ei)); put(color, sink, Color::gray()); while (get(color, sink) != Color::white()) { boost::queue< vertex_t > Q; breadth_first_search(detail::residual_graph(g, res), src, Q, make_bfs_visitor(record_edge_predecessors(pred, on_tree_edge())), color); if (get(color, sink) != Color::white()) detail::augment(g, src, sink, pred, res, rev); } // while typename property_traits< CapacityEdgeMap >::value_type flow = 0; for (boost::tie(ei, e_end) = out_edges(src, g); ei != e_end; ++ei) flow += (get(cap, *ei) - get(res, *ei)); return flow; } // edmonds_karp_max_flow() namespace detail { //------------------------------------------------------------------------- // Handle default for color property map // use of class here is a VC++ workaround template < class ColorMap > struct edmonds_karp_dispatch2 { template < class Graph, class PredMap, class P, class T, class R > static typename edge_capacity_value< Graph, P, T, R >::type apply( Graph& g, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink, PredMap pred, const bgl_named_params< P, T, R >& params, ColorMap color) { return edmonds_karp_max_flow(g, src, sink, choose_const_pmap( get_param(params, edge_capacity), g, edge_capacity), choose_pmap(get_param(params, edge_residual_capacity), g, edge_residual_capacity), choose_const_pmap( get_param(params, edge_reverse), g, edge_reverse), color, pred); } }; template <> struct edmonds_karp_dispatch2< param_not_found > { template < class Graph, class PredMap, class P, class T, class R > static typename edge_capacity_value< Graph, P, T, R >::type apply( Graph& g, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink, PredMap pred, const bgl_named_params< P, T, R >& params, param_not_found) { typedef typename graph_traits< Graph >::vertices_size_type size_type; size_type n = is_default_param(get_param(params, vertex_color)) ? num_vertices(g) : 1; std::vector< default_color_type > color_vec(n); return edmonds_karp_max_flow(g, src, sink, choose_const_pmap( get_param(params, edge_capacity), g, edge_capacity), choose_pmap(get_param(params, edge_residual_capacity), g, edge_residual_capacity), choose_const_pmap( get_param(params, edge_reverse), g, edge_reverse), make_iterator_property_map(color_vec.begin(), choose_const_pmap( get_param(params, vertex_index), g, vertex_index), color_vec[0]), pred); } }; //------------------------------------------------------------------------- // Handle default for predecessor property map // use of class here is a VC++ workaround template < class PredMap > struct edmonds_karp_dispatch1 { template < class Graph, class P, class T, class R > static typename edge_capacity_value< Graph, P, T, R >::type apply( Graph& g, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink, const bgl_named_params< P, T, R >& params, PredMap pred) { typedef typename get_param_type< vertex_color_t, bgl_named_params< P, T, R > >::type C; return edmonds_karp_dispatch2< C >::apply( g, src, sink, pred, params, get_param(params, vertex_color)); } }; template <> struct edmonds_karp_dispatch1< param_not_found > { template < class Graph, class P, class T, class R > static typename edge_capacity_value< Graph, P, T, R >::type apply( Graph& g, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink, const bgl_named_params< P, T, R >& params, param_not_found) { typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor; typedef typename graph_traits< Graph >::vertices_size_type size_type; size_type n = is_default_param(get_param(params, vertex_predecessor)) ? num_vertices(g) : 1; std::vector< edge_descriptor > pred_vec(n); typedef typename get_param_type< vertex_color_t, bgl_named_params< P, T, R > >::type C; return edmonds_karp_dispatch2< C >::apply(g, src, sink, make_iterator_property_map(pred_vec.begin(), choose_const_pmap( get_param(params, vertex_index), g, vertex_index), pred_vec[0]), params, get_param(params, vertex_color)); } }; } // namespace detail template < class Graph, class P, class T, class R > typename detail::edge_capacity_value< Graph, P, T, R >::type edmonds_karp_max_flow(Graph& g, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink, const bgl_named_params< P, T, R >& params) { typedef typename get_param_type< vertex_predecessor_t, bgl_named_params< P, T, R > >::type Pred; return detail::edmonds_karp_dispatch1< Pred >::apply( g, src, sink, params, get_param(params, vertex_predecessor)); } template < class Graph > typename property_traits< typename property_map< Graph, edge_capacity_t >::const_type >::value_type edmonds_karp_max_flow(Graph& g, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink) { bgl_named_params< int, buffer_param_t > params(0); return edmonds_karp_max_flow(g, src, sink, params); } } // namespace boost #endif // BOOST_GRAPH_EDMONDS_KARP_MAX_FLOW_HPP eccentricity.hpp 0000644 00000011003 15125521275 0007742 0 ustar 00 // (C) Copyright 2007-2009 Andrew Sutton // // 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_ECCENTRICITY_HPP #define BOOST_GRAPH_ECCENTRICITY_HPP #include <boost/next_prior.hpp> #include <boost/config.hpp> #include <boost/graph/detail/geodesic.hpp> #include <boost/concept/assert.hpp> namespace boost { template < typename Graph, typename DistanceMap, typename Combinator > inline typename property_traits< DistanceMap >::value_type eccentricity( const Graph& g, DistanceMap dist, Combinator combine) { BOOST_CONCEPT_ASSERT((GraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< DistanceMap, Vertex >)); typedef typename property_traits< DistanceMap >::value_type Distance; return detail::combine_distances(g, dist, combine, Distance(0)); } template < typename Graph, typename DistanceMap > inline typename property_traits< DistanceMap >::value_type eccentricity( const Graph& g, DistanceMap dist) { BOOST_CONCEPT_ASSERT((GraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< DistanceMap, Vertex >)); typedef typename property_traits< DistanceMap >::value_type Distance; return eccentricity(g, dist, detail::maximize< Distance >()); } template < typename Graph, typename DistanceMatrix, typename EccentricityMap > inline std::pair< typename property_traits< EccentricityMap >::value_type, typename property_traits< EccentricityMap >::value_type > all_eccentricities( const Graph& g, const DistanceMatrix& dist, EccentricityMap ecc) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::vertex_iterator VertexIterator; BOOST_CONCEPT_ASSERT( (ReadablePropertyMapConcept< DistanceMatrix, Vertex >)); typedef typename property_traits< DistanceMatrix >::value_type DistanceMap; BOOST_CONCEPT_ASSERT( (WritablePropertyMapConcept< EccentricityMap, Vertex >)); typedef typename property_traits< EccentricityMap >::value_type Eccentricity; BOOST_USING_STD_MIN(); BOOST_USING_STD_MAX(); Eccentricity r = numeric_values< Eccentricity >::infinity(), d = numeric_values< Eccentricity >::zero(); VertexIterator i, end; boost::tie(i, end) = vertices(g); for (boost::tie(i, end) = vertices(g); i != end; ++i) { DistanceMap dm = get(dist, *i); Eccentricity e = eccentricity(g, dm); put(ecc, *i, e); // track the radius and diameter at the same time r = min BOOST_PREVENT_MACRO_SUBSTITUTION(r, e); d = max BOOST_PREVENT_MACRO_SUBSTITUTION(d, e); } return std::make_pair(r, d); } template < typename Graph, typename EccentricityMap > inline std::pair< typename property_traits< EccentricityMap >::value_type, typename property_traits< EccentricityMap >::value_type > radius_and_diameter(const Graph& g, EccentricityMap ecc) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::vertex_iterator VertexIterator; BOOST_CONCEPT_ASSERT( (ReadablePropertyMapConcept< EccentricityMap, Vertex >)); typedef typename property_traits< EccentricityMap >::value_type Eccentricity; BOOST_USING_STD_MIN(); BOOST_USING_STD_MAX(); VertexIterator i, end; boost::tie(i, end) = vertices(g); Eccentricity radius = get(ecc, *i); Eccentricity diameter = get(ecc, *i); for (i = boost::next(i); i != end; ++i) { Eccentricity cur = get(ecc, *i); radius = min BOOST_PREVENT_MACRO_SUBSTITUTION(radius, cur); diameter = max BOOST_PREVENT_MACRO_SUBSTITUTION(diameter, cur); } return std::make_pair(radius, diameter); } template < typename Graph, typename EccentricityMap > inline typename property_traits< EccentricityMap >::value_type radius( const Graph& g, EccentricityMap ecc) { return radius_and_diameter(g, ecc).first; } template < typename Graph, typename EccentricityMap > inline typename property_traits< EccentricityMap >::value_type diameter( const Graph& g, EccentricityMap ecc) { return radius_and_diameter(g, ecc).second; } } /* namespace boost */ #endif edge_connectivity.hpp 0000644 00000015214 15125521275 0010767 0 ustar 00 //======================================================================= // Copyright 2000 University of Notre Dame. // Authors: Jeremy G. Siek, Andrew Lumsdaine, Lie-Quan Lee // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_EDGE_CONNECTIVITY #define BOOST_EDGE_CONNECTIVITY // WARNING: not-yet fully tested! #include <boost/config.hpp> #include <vector> #include <set> #include <algorithm> #include <boost/graph/edmonds_karp_max_flow.hpp> namespace boost { namespace detail { template < class Graph > inline std::pair< typename graph_traits< Graph >::vertex_descriptor, typename graph_traits< Graph >::degree_size_type > min_degree_vertex(Graph& g) { typedef graph_traits< Graph > Traits; typename Traits::vertex_descriptor p; typedef typename Traits::degree_size_type size_type; size_type delta = (std::numeric_limits< size_type >::max)(); typename Traits::vertex_iterator i, iend; for (boost::tie(i, iend) = vertices(g); i != iend; ++i) if (degree(*i, g) < delta) { delta = degree(*i, g); p = *i; } return std::make_pair(p, delta); } template < class Graph, class OutputIterator > void neighbors(const Graph& g, typename graph_traits< Graph >::vertex_descriptor u, OutputIterator result) { typename graph_traits< Graph >::adjacency_iterator ai, aend; for (boost::tie(ai, aend) = adjacent_vertices(u, g); ai != aend; ++ai) *result++ = *ai; } template < class Graph, class VertexIterator, class OutputIterator > void neighbors(const Graph& g, VertexIterator first, VertexIterator last, OutputIterator result) { for (; first != last; ++first) neighbors(g, *first, result); } } // namespace detail // O(m n) template < class VertexListGraph, class OutputIterator > typename graph_traits< VertexListGraph >::degree_size_type edge_connectivity( VertexListGraph& g, OutputIterator disconnecting_set) { //------------------------------------------------------------------------- // Type Definitions typedef graph_traits< VertexListGraph > Traits; typedef typename Traits::vertex_iterator vertex_iterator; typedef typename Traits::edge_iterator edge_iterator; typedef typename Traits::out_edge_iterator out_edge_iterator; typedef typename Traits::vertex_descriptor vertex_descriptor; typedef typename Traits::degree_size_type degree_size_type; typedef color_traits< default_color_type > Color; typedef adjacency_list_traits< vecS, vecS, directedS > Tr; typedef typename Tr::edge_descriptor Tr_edge_desc; typedef adjacency_list< vecS, vecS, directedS, no_property, property< edge_capacity_t, degree_size_type, property< edge_residual_capacity_t, degree_size_type, property< edge_reverse_t, Tr_edge_desc > > > > FlowGraph; typedef typename graph_traits< FlowGraph >::edge_descriptor edge_descriptor; //------------------------------------------------------------------------- // Variable Declarations vertex_descriptor u, v, p, k; edge_descriptor e1, e2; bool inserted; vertex_iterator vi, vi_end; edge_iterator ei, ei_end; degree_size_type delta, alpha_star, alpha_S_k; std::set< vertex_descriptor > S, neighbor_S; std::vector< vertex_descriptor > S_star, non_neighbor_S; std::vector< default_color_type > color(num_vertices(g)); std::vector< edge_descriptor > pred(num_vertices(g)); //------------------------------------------------------------------------- // Create a network flow graph out of the undirected graph FlowGraph flow_g(num_vertices(g)); typename property_map< FlowGraph, edge_capacity_t >::type cap = get(edge_capacity, flow_g); typename property_map< FlowGraph, edge_residual_capacity_t >::type res_cap = get(edge_residual_capacity, flow_g); typename property_map< FlowGraph, edge_reverse_t >::type rev_edge = get(edge_reverse, flow_g); for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) { u = source(*ei, g), v = target(*ei, g); boost::tie(e1, inserted) = add_edge(u, v, flow_g); cap[e1] = 1; boost::tie(e2, inserted) = add_edge(v, u, flow_g); cap[e2] = 1; // not sure about this rev_edge[e1] = e2; rev_edge[e2] = e1; } //------------------------------------------------------------------------- // The Algorithm boost::tie(p, delta) = detail::min_degree_vertex(g); S_star.push_back(p); alpha_star = delta; S.insert(p); neighbor_S.insert(p); detail::neighbors( g, S.begin(), S.end(), std::inserter(neighbor_S, neighbor_S.begin())); boost::tie(vi, vi_end) = vertices(g); std::set_difference(vi, vi_end, neighbor_S.begin(), neighbor_S.end(), std::back_inserter(non_neighbor_S)); while (!non_neighbor_S.empty()) { // at most n - 1 times k = non_neighbor_S.front(); alpha_S_k = edmonds_karp_max_flow( flow_g, p, k, cap, res_cap, rev_edge, &color[0], &pred[0]); if (alpha_S_k < alpha_star) { alpha_star = alpha_S_k; S_star.clear(); for (boost::tie(vi, vi_end) = vertices(flow_g); vi != vi_end; ++vi) if (color[*vi] != Color::white()) S_star.push_back(*vi); } S.insert(k); neighbor_S.insert(k); detail::neighbors(g, k, std::inserter(neighbor_S, neighbor_S.begin())); non_neighbor_S.clear(); boost::tie(vi, vi_end) = vertices(g); std::set_difference(vi, vi_end, neighbor_S.begin(), neighbor_S.end(), std::back_inserter(non_neighbor_S)); } //------------------------------------------------------------------------- // Compute edges of the cut [S*, ~S*] std::vector< bool > in_S_star(num_vertices(g), false); typename std::vector< vertex_descriptor >::iterator si; for (si = S_star.begin(); si != S_star.end(); ++si) in_S_star[*si] = true; degree_size_type c = 0; for (si = S_star.begin(); si != S_star.end(); ++si) { out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(*si, g); ei != ei_end; ++ei) if (!in_S_star[target(*ei, g)]) { *disconnecting_set++ = *ei; ++c; } } return c; } } // namespace boost #endif // BOOST_EDGE_CONNECTIVITY graph_traits.hpp 0000644 00000031411 15125521275 0007751 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_TRAITS_HPP #define BOOST_GRAPH_TRAITS_HPP #include <boost/config.hpp> #include <iterator> #include <utility> /* Primarily for std::pair */ #include <boost/tuple/tuple.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/eval_if.hpp> #include <boost/mpl/bool.hpp> #include <boost/mpl/not.hpp> #include <boost/mpl/has_xxx.hpp> #include <boost/mpl/void.hpp> #include <boost/mpl/identity.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/iterator/iterator_categories.hpp> #include <boost/iterator/iterator_adaptor.hpp> #include <boost/pending/property.hpp> #include <boost/detail/workaround.hpp> namespace boost { namespace detail { #define BOOST_GRAPH_MEMBER_OR_VOID(name) \ BOOST_MPL_HAS_XXX_TRAIT_DEF(name) \ template < typename T > struct BOOST_JOIN(get_member_, name) \ { \ typedef typename T::name type; \ }; \ template < typename T > \ struct BOOST_JOIN(get_opt_member_, name) \ : boost::mpl::eval_if_c< BOOST_JOIN(has_, name) < T >::value, BOOST_JOIN(get_member_, name)< T >, boost::mpl::identity< void > >\ { \ }; BOOST_GRAPH_MEMBER_OR_VOID(adjacency_iterator) BOOST_GRAPH_MEMBER_OR_VOID(out_edge_iterator) BOOST_GRAPH_MEMBER_OR_VOID(in_edge_iterator) BOOST_GRAPH_MEMBER_OR_VOID(vertex_iterator) BOOST_GRAPH_MEMBER_OR_VOID(edge_iterator) BOOST_GRAPH_MEMBER_OR_VOID(vertices_size_type) BOOST_GRAPH_MEMBER_OR_VOID(edges_size_type) BOOST_GRAPH_MEMBER_OR_VOID(degree_size_type) } template < typename G > struct graph_traits { #define BOOST_GRAPH_PULL_OPT_MEMBER(name) \ typedef typename detail::BOOST_JOIN(get_opt_member_, name)< G >::type name; typedef typename G::vertex_descriptor vertex_descriptor; typedef typename G::edge_descriptor edge_descriptor; BOOST_GRAPH_PULL_OPT_MEMBER(adjacency_iterator) BOOST_GRAPH_PULL_OPT_MEMBER(out_edge_iterator) BOOST_GRAPH_PULL_OPT_MEMBER(in_edge_iterator) BOOST_GRAPH_PULL_OPT_MEMBER(vertex_iterator) BOOST_GRAPH_PULL_OPT_MEMBER(edge_iterator) typedef typename G::directed_category directed_category; typedef typename G::edge_parallel_category edge_parallel_category; typedef typename G::traversal_category traversal_category; BOOST_GRAPH_PULL_OPT_MEMBER(vertices_size_type) BOOST_GRAPH_PULL_OPT_MEMBER(edges_size_type) BOOST_GRAPH_PULL_OPT_MEMBER(degree_size_type) #undef BOOST_GRAPH_PULL_OPT_MEMBER static inline vertex_descriptor null_vertex(); }; template < typename G > inline typename graph_traits< G >::vertex_descriptor graph_traits< G >::null_vertex() { return G::null_vertex(); } // directed_category tags struct directed_tag { }; struct undirected_tag { }; struct bidirectional_tag : public directed_tag { }; namespace detail { inline bool is_directed(directed_tag) { return true; } inline bool is_directed(undirected_tag) { return false; } } /** Return true if the given graph is directed. */ template < typename Graph > bool is_directed(const Graph&) { typedef typename graph_traits< Graph >::directed_category Cat; return detail::is_directed(Cat()); } /** Return true if the given graph is undirected. */ template < typename Graph > bool is_undirected(const Graph& g) { return !is_directed(g); } /** @name Directed/Undirected Graph Traits */ //@{ namespace graph_detail { template < typename Tag > struct is_directed_tag : mpl::bool_< is_convertible< Tag, directed_tag >::value > { }; } // namespace graph_detail template < typename Graph > struct is_directed_graph : graph_detail::is_directed_tag< typename graph_traits< Graph >::directed_category > { }; template < typename Graph > struct is_undirected_graph : mpl::not_< is_directed_graph< Graph > > { }; //@} // edge_parallel_category tags struct allow_parallel_edge_tag { }; struct disallow_parallel_edge_tag { }; namespace detail { inline bool allows_parallel(allow_parallel_edge_tag) { return true; } inline bool allows_parallel(disallow_parallel_edge_tag) { return false; } } template < typename Graph > bool allows_parallel_edges(const Graph&) { typedef typename graph_traits< Graph >::edge_parallel_category Cat; return detail::allows_parallel(Cat()); } /** @name Parallel Edges Traits */ //@{ /** * The is_multigraph metafunction returns true if the graph allows * parallel edges. Technically, a multigraph is a simple graph that * allows parallel edges, but since there are no traits for the allowance * or disallowance of loops, this is a moot point. */ template < typename Graph > struct is_multigraph : mpl::bool_< is_same< typename graph_traits< Graph >::edge_parallel_category, allow_parallel_edge_tag >::value > { }; //@} // traversal_category tags struct incidence_graph_tag { }; struct adjacency_graph_tag { }; struct bidirectional_graph_tag : virtual incidence_graph_tag { }; struct vertex_list_graph_tag { }; struct edge_list_graph_tag { }; struct adjacency_matrix_tag { }; // Parallel traversal_category tags struct distributed_graph_tag { }; struct distributed_vertex_list_graph_tag { }; struct distributed_edge_list_graph_tag { }; #define BOOST_GRAPH_SEQUENTIAL_TRAITS_DEFINES_DISTRIBUTED_TAGS // Disable these // from external // versions of // PBGL /** @name Traversal Category Traits * These traits classify graph types by their supported methods of * vertex and edge traversal. */ //@{ template < typename Graph > struct is_incidence_graph : mpl::bool_< is_convertible< typename graph_traits< Graph >::traversal_category, incidence_graph_tag >::value > { }; template < typename Graph > struct is_bidirectional_graph : mpl::bool_< is_convertible< typename graph_traits< Graph >::traversal_category, bidirectional_graph_tag >::value > { }; template < typename Graph > struct is_vertex_list_graph : mpl::bool_< is_convertible< typename graph_traits< Graph >::traversal_category, vertex_list_graph_tag >::value > { }; template < typename Graph > struct is_edge_list_graph : mpl::bool_< is_convertible< typename graph_traits< Graph >::traversal_category, edge_list_graph_tag >::value > { }; template < typename Graph > struct is_adjacency_matrix : mpl::bool_< is_convertible< typename graph_traits< Graph >::traversal_category, adjacency_matrix_tag >::value > { }; //@} /** @name Directed Graph Traits * These metafunctions are used to fully classify directed vs. undirected * graphs. Recall that an undirected graph is also bidirectional, but it * cannot be both undirected and directed at the same time. */ //@{ template < typename Graph > struct is_directed_unidirectional_graph : mpl::and_< is_directed_graph< Graph >, mpl::not_< is_bidirectional_graph< Graph > > > { }; template < typename Graph > struct is_directed_bidirectional_graph : mpl::and_< is_directed_graph< Graph >, is_bidirectional_graph< Graph > > { }; //@} //?? not the right place ?? Lee typedef boost::forward_traversal_tag multi_pass_input_iterator_tag; namespace detail { BOOST_MPL_HAS_XXX_TRAIT_DEF(graph_property_type) BOOST_MPL_HAS_XXX_TRAIT_DEF(edge_property_type) BOOST_MPL_HAS_XXX_TRAIT_DEF(vertex_property_type) template < typename G > struct get_graph_property_type { typedef typename G::graph_property_type type; }; template < typename G > struct get_edge_property_type { typedef typename G::edge_property_type type; }; template < typename G > struct get_vertex_property_type { typedef typename G::vertex_property_type type; }; } template < typename G > struct graph_property_type : boost::mpl::eval_if< detail::has_graph_property_type< G >, detail::get_graph_property_type< G >, no_property > { }; template < typename G > struct edge_property_type : boost::mpl::eval_if< detail::has_edge_property_type< G >, detail::get_edge_property_type< G >, no_property > { }; template < typename G > struct vertex_property_type : boost::mpl::eval_if< detail::has_vertex_property_type< G >, detail::get_vertex_property_type< G >, no_property > { }; template < typename G > struct graph_bundle_type { typedef typename G::graph_bundled type; }; template < typename G > struct vertex_bundle_type { typedef typename G::vertex_bundled type; }; template < typename G > struct edge_bundle_type { typedef typename G::edge_bundled type; }; namespace graph { namespace detail { template < typename Graph, typename Descriptor > class bundled_result { typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename mpl::if_c< (is_same< Descriptor, Vertex >::value), vertex_bundle_type< Graph >, edge_bundle_type< Graph > >::type bundler; public: typedef typename bundler::type type; }; template < typename Graph > class bundled_result< Graph, graph_bundle_t > { typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef graph_bundle_type< Graph > bundler; public: typedef typename bundler::type type; }; } } // namespace graph::detail namespace graph_detail { // A helper metafunction for determining whether or not a type is // bundled. template < typename T > struct is_no_bundle : mpl::bool_< is_same< T, no_property >::value > { }; } // namespace graph_detail /** @name Graph Property Traits * These metafunctions (along with those above), can be used to access the * vertex and edge properties (bundled or otherwise) of vertices and * edges. */ //@{ template < typename Graph > struct has_graph_property : mpl::not_< typename detail::is_no_property< typename graph_property_type< Graph >::type >::type >::type { }; template < typename Graph > struct has_bundled_graph_property : mpl::not_< graph_detail::is_no_bundle< typename graph_bundle_type< Graph >::type > > { }; template < typename Graph > struct has_vertex_property : mpl::not_< typename detail::is_no_property< typename vertex_property_type< Graph >::type > >::type { }; template < typename Graph > struct has_bundled_vertex_property : mpl::not_< graph_detail::is_no_bundle< typename vertex_bundle_type< Graph >::type > > { }; template < typename Graph > struct has_edge_property : mpl::not_< typename detail::is_no_property< typename edge_property_type< Graph >::type > >::type { }; template < typename Graph > struct has_bundled_edge_property : mpl::not_< graph_detail::is_no_bundle< typename edge_bundle_type< Graph >::type > > { }; //@} } // namespace boost // Since pair is in namespace std, Koenig lookup will find source and // target if they are also defined in namespace std. This is illegal, // but the alternative is to put source and target in the global // namespace which causes name conflicts with other libraries (like // SUIF). namespace std { /* Some helper functions for dealing with pairs as edges */ template < class T, class G > T source(pair< T, T > p, const G&) { return p.first; } template < class T, class G > T target(pair< T, T > p, const G&) { return p.second; } } #if defined(__GNUC__) && defined(__SGI_STL_PORT) // For some reason g++ with STLport does not see the above definition // of source() and target() unless we bring them into the boost // namespace. namespace boost { using std::source; using std::target; } #endif #endif // BOOST_GRAPH_TRAITS_HPP incremental_components.hpp 0000644 00000020044 15125521275 0012030 0 ustar 00 // //======================================================================= // Copyright 1997-2001 University of Notre Dame. // Copyright 2009 Trustees of Indiana University. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Michael Hansen // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_INCREMENTAL_COMPONENTS_HPP #define BOOST_INCREMENTAL_COMPONENTS_HPP #include <boost/detail/iterator.hpp> #include <boost/graph/detail/incremental_components.hpp> #include <boost/iterator/counting_iterator.hpp> #include <boost/make_shared.hpp> #include <boost/pending/disjoint_sets.hpp> #include <iterator> namespace boost { // A connected component algorithm for the case when dynamically // adding (but not removing) edges is common. The // incremental_components() function is a preparing operation. Call // same_component to check whether two vertices are in the same // component, or use disjoint_set::find_set to determine the // representative for a vertex. // This version of connected components does not require a full // Graph. Instead, it just needs an edge list, where the vertices of // each edge need to be of integer type. The edges are assumed to // be undirected. The other difference is that the result is stored in // a container, instead of just a decorator. The container should be // empty before the algorithm is called. It will grow during the // course of the algorithm. The container must be a model of // BackInsertionSequence and RandomAccessContainer // (std::vector is a good choice). After running the algorithm the // index container will map each vertex to the representative // vertex of the component to which it belongs. // // Adapted from an implementation by Alex Stepanov. The disjoint // sets data structure is from Tarjan's "Data Structures and Network // Algorithms", and the application to connected components is // similar to the algorithm described in Ch. 22 of "Intro to // Algorithms" by Cormen, et. all. // // An implementation of disjoint sets can be found in // boost/pending/disjoint_sets.hpp template < class EdgeListGraph, class DisjointSets > void incremental_components(EdgeListGraph& g, DisjointSets& ds) { typename graph_traits< EdgeListGraph >::edge_iterator e, end; for (boost::tie(e, end) = edges(g); e != end; ++e) ds.union_set(source(*e, g), target(*e, g)); } template < class ParentIterator > void compress_components(ParentIterator first, ParentIterator last) { for (ParentIterator current = first; current != last; ++current) detail::find_representative_with_full_compression( first, current - first); } template < class ParentIterator > typename boost::detail::iterator_traits< ParentIterator >::difference_type component_count(ParentIterator first, ParentIterator last) { std::ptrdiff_t count = 0; for (ParentIterator current = first; current != last; ++current) if (*current == current - first) ++count; return count; } // This algorithm can be applied to the result container of the // connected_components algorithm to normalize // the components. template < class ParentIterator > void normalize_components(ParentIterator first, ParentIterator last) { for (ParentIterator current = first; current != last; ++current) detail::normalize_node(first, current - first); } template < class VertexListGraph, class DisjointSets > void initialize_incremental_components(VertexListGraph& G, DisjointSets& ds) { typename graph_traits< VertexListGraph >::vertex_iterator v, vend; for (boost::tie(v, vend) = vertices(G); v != vend; ++v) ds.make_set(*v); } template < class Vertex, class DisjointSet > inline bool same_component(Vertex u, Vertex v, DisjointSet& ds) { return ds.find_set(u) == ds.find_set(v); } // Class that builds a quick-access indexed linked list that allows // for fast iterating through a parent component's children. template < typename IndexType > class component_index { private: typedef std::vector< IndexType > IndexContainer; public: typedef counting_iterator< IndexType > iterator; typedef iterator const_iterator; typedef IndexType value_type; typedef IndexType size_type; typedef detail::component_index_iterator< typename IndexContainer::iterator > component_iterator; public: template < typename ParentIterator, typename ElementIndexMap > component_index(ParentIterator parent_start, ParentIterator parent_end, const ElementIndexMap& index_map) : m_num_elements(std::distance(parent_start, parent_end)) , m_components(make_shared< IndexContainer >()) , m_index_list(make_shared< IndexContainer >(m_num_elements)) { build_index_lists(parent_start, index_map); } // component_index template < typename ParentIterator > component_index(ParentIterator parent_start, ParentIterator parent_end) : m_num_elements(std::distance(parent_start, parent_end)) , m_components(make_shared< IndexContainer >()) , m_index_list(make_shared< IndexContainer >(m_num_elements)) { build_index_lists(parent_start, boost::identity_property_map()); } // component_index // Returns the number of components inline std::size_t size() const { return (m_components->size()); } // Beginning iterator for component indices iterator begin() const { return (iterator(0)); } // End iterator for component indices iterator end() const { return (iterator(this->size())); } // Returns a pair of begin and end iterators for the child // elements of component [component_index]. std::pair< component_iterator, component_iterator > operator[]( IndexType component_index) const { IndexType first_index = (*m_components)[component_index]; return (std::make_pair( component_iterator(m_index_list->begin(), first_index), component_iterator(m_num_elements))); } private: template < typename ParentIterator, typename ElementIndexMap > void build_index_lists( ParentIterator parent_start, const ElementIndexMap& index_map) { typedef typename std::iterator_traits< ParentIterator >::value_type Element; typename IndexContainer::iterator index_list = m_index_list->begin(); // First pass - find root elements, construct index list for (IndexType element_index = 0; element_index < m_num_elements; ++element_index) { Element parent_element = parent_start[element_index]; IndexType parent_index = get(index_map, parent_element); if (element_index != parent_index) { index_list[element_index] = parent_index; } else { m_components->push_back(element_index); // m_num_elements is the linked list terminator index_list[element_index] = m_num_elements; } } // Second pass - build linked list for (IndexType element_index = 0; element_index < m_num_elements; ++element_index) { Element parent_element = parent_start[element_index]; IndexType parent_index = get(index_map, parent_element); if (element_index != parent_index) { // Follow list until a component parent is found while (index_list[parent_index] != m_num_elements) { parent_index = index_list[parent_index]; } // Push element to the front of the linked list index_list[element_index] = index_list[parent_index]; index_list[parent_index] = element_index; } } } // build_index_lists protected: IndexType m_num_elements; shared_ptr< IndexContainer > m_components, m_index_list; }; // class component_index } // namespace boost #endif // BOOST_INCREMENTAL_COMPONENTS_HPP make_connected.hpp 0000644 00000005125 15125521275 0010224 0 ustar 00 //======================================================================= // Copyright 2007 Aaron Windsor // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef __MAKE_CONNECTED_HPP__ #define __MAKE_CONNECTED_HPP__ #include <boost/config.hpp> #include <boost/next_prior.hpp> #include <boost/tuple/tuple.hpp> //for tie #include <boost/graph/connected_components.hpp> #include <boost/property_map/property_map.hpp> #include <vector> #include <boost/graph/planar_detail/add_edge_visitors.hpp> #include <boost/graph/planar_detail/bucket_sort.hpp> namespace boost { template < typename Graph, typename VertexIndexMap, typename AddEdgeVisitor > void make_connected(Graph& g, VertexIndexMap vm, AddEdgeVisitor& vis) { typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t; typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::vertices_size_type v_size_t; typedef iterator_property_map< typename std::vector< v_size_t >::iterator, VertexIndexMap > vertex_to_v_size_map_t; std::vector< v_size_t > component_vector(num_vertices(g)); vertex_to_v_size_map_t component(component_vector.begin(), vm); std::vector< vertex_t > vertices_by_component(num_vertices(g)); v_size_t num_components = connected_components(g, component); if (num_components < 2) return; vertex_iterator_t vi, vi_end; boost::tie(vi, vi_end) = vertices(g); std::copy(vi, vi_end, vertices_by_component.begin()); bucket_sort(vertices_by_component.begin(), vertices_by_component.end(), component, num_components); typedef typename std::vector< vertex_t >::iterator vec_of_vertices_itr_t; vec_of_vertices_itr_t ci_end = vertices_by_component.end(); vec_of_vertices_itr_t ci_prev = vertices_by_component.begin(); if (ci_prev == ci_end) return; for (vec_of_vertices_itr_t ci = boost::next(ci_prev); ci != ci_end; ci_prev = ci, ++ci) { if (component[*ci_prev] != component[*ci]) vis.visit_vertex_pair(*ci_prev, *ci, g); } } template < typename Graph, typename VertexIndexMap > inline void make_connected(Graph& g, VertexIndexMap vm) { default_add_edge_visitor vis; make_connected(g, vm, vis); } template < typename Graph > inline void make_connected(Graph& g) { make_connected(g, get(vertex_index, g)); } } // namespace boost #endif //__MAKE_CONNECTED_HPP__ read_dimacs.hpp 0000644 00000027460 15125521275 0007526 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Jeremy G. Siek, Andrew Lumsdaine, Lie-Quan Lee // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= /* Reads maximal flow problem in extended DIMACS format. This works, but could use some polishing. */ /* ----------------------------------------------------------------- */ #ifndef BOOST_GRAPH_READ_DIMACS_HPP #define BOOST_GRAPH_READ_DIMACS_HPP #include <vector> #include <iostream> #include <string> #include <cstdio> #include <cstring> #include <cstdlib> #include <boost/graph/graph_traits.hpp> namespace boost { namespace detail { template < class Graph, class CapacityMap, class ReverseEdgeMap > int read_dimacs_max_flow_internal(Graph& g, CapacityMap capacity, ReverseEdgeMap reverse_edge, typename graph_traits< Graph >::vertex_descriptor& src, typename graph_traits< Graph >::vertex_descriptor& sink, std::istream& in, bool require_source_and_sink, const std::string& problem_type) { // const int MAXLINE = 100; /* max line length in the input file // */ const int ARC_FIELDS = 3; /* no of fields in arc line */ const int NODE_FIELDS = 2; /* no of fields in node line */ const int P_FIELDS = 3; /* no of fields in problem line */ typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor; std::vector< vertex_descriptor > verts; long m, n, /* number of edges and nodes */ i, head, tail, cap; long no_lines = 0, /* no of current input line */ no_plines = 0, /* no of problem-lines */ no_nslines = 0, /* no of node-source-lines */ no_nklines = 0, /* no of node-source-lines */ no_alines = 0; /* no of arc-lines */ std::string in_line; /* for reading input line */ char pr_type[4]; /* for reading type of the problem */ char nd; /* source (s) or sink (t) */ int k, /* temporary */ err_no; /* no of detected error */ /* -------------- error numbers & error messages ---------------- */ const int EN1 = 0; const int EN2 = 1; const int EN3 = 2; const int EN4 = 3; // const int EN6 = 4; // const int EN10 = 5; // const int EN7 = 6; const int EN8 = 7; const int EN9 = 8; const int EN11 = 9; const int EN12 = 10; // const int EN13 = 11; const int EN14 = 12; const int EN16 = 13; const int EN15 = 14; const int EN17 = 15; const int EN18 = 16; const int EN21 = 17; const int EN19 = 18; const int EN20 = 19; const int EN22 = 20; static const char* err_message[] = { /* 0*/ "more than one problem line.", /* 1*/ "wrong number of parameters in the problem line.", /* 2*/ "it is not a Max Flow problem line.", /* 3*/ "bad value of a parameter in the problem line.", /* 4*/ "can't obtain enough memory to solve this problem.", /* 5*/ "more than one line with the problem name.", /* 6*/ "can't read problem name.", /* 7*/ "problem description must be before node description.", /* 8*/ "this parser doesn't support multiply sources and sinks.", /* 9*/ "wrong number of parameters in the node line.", /*10*/ "wrong value of parameters in the node line.", /*11*/ " ", /*12*/ "source and sink descriptions must be before arc descriptions.", /*13*/ "too many arcs in the input.", /*14*/ "wrong number of parameters in the arc line.", /*15*/ "wrong value of parameters in the arc line.", /*16*/ "unknown line type in the input.", /*17*/ "reading error.", /*18*/ "not enough arcs in the input.", /*19*/ "source or sink doesn't have incident arcs.", /*20*/ "can't read anything from the input file." }; /* --------------------------------------------------------------- */ /* The main loop: - reads the line of the input, - analyses its type, - checks correctness of parameters, - puts data to the arrays, - does service functions */ while (std::getline(in, in_line)) { ++no_lines; switch (in_line[0]) { case 'c': /* skip lines with comments */ case '\n': /* skip empty lines */ case '\0': /* skip empty lines at the end of file */ break; case 'p': /* problem description */ if (no_plines > 0) /* more than one problem line */ { err_no = EN1; goto error; } no_plines = 1; if ( /* reading problem line: type of problem, no of nodes, no of arcs */ std::sscanf( in_line.c_str(), "%*c %3s %ld %ld", pr_type, &n, &m) != P_FIELDS) /*wrong number of parameters in the problem line*/ { err_no = EN2; goto error; } if (pr_type != problem_type) /*wrong problem type*/ { err_no = EN3; goto error; } if (n <= 0 || m <= 0) /*wrong value of no of arcs or nodes*/ { err_no = EN4; goto error; } { for (long vi = 0; vi < n; ++vi) verts.push_back(add_vertex(g)); } break; case 'n': /* source(s) description */ if (no_plines == 0) /* there was not problem line above */ { err_no = EN8; goto error; } /* reading source or sink */ k = std::sscanf(in_line.c_str(), "%*c %ld %c", &i, &nd); --i; // index from 0 if (k < NODE_FIELDS) /* node line is incorrect */ { err_no = EN11; goto error; } if (i < 0 || i > n) /* wrong value of node */ { err_no = EN12; goto error; } switch (nd) { case 's': /* source line */ if (no_nslines != 0) /* more than one source line */ { err_no = EN9; goto error; } no_nslines = 1; src = verts[i]; break; case 't': /* sink line */ if (no_nklines != 0) /* more than one sink line */ { err_no = EN9; goto error; } no_nklines = 1; sink = verts[i]; break; default: /* wrong type of node-line */ err_no = EN12; goto error; } break; case 'a': /* arc description */ if (require_source_and_sink && (no_nslines == 0 || no_nklines == 0)) /* there was not source and sink description above */ { err_no = EN14; goto error; } if (no_alines >= m) /*too many arcs on input*/ { err_no = EN16; goto error; } if ( /* reading an arc description */ std::sscanf( in_line.c_str(), "%*c %ld %ld %ld", &tail, &head, &cap) != ARC_FIELDS) /* arc description is not correct */ { err_no = EN15; goto error; } --tail; // index from 0, not 1 --head; if (tail < 0 || tail > n || head < 0 || head > n) /* wrong value of nodes */ { err_no = EN17; goto error; } { edge_descriptor e1, e2; bool in1, in2; boost::tie(e1, in1) = add_edge(verts[tail], verts[head], g); boost::tie(e2, in2) = add_edge(verts[head], verts[tail], g); if (!in1 || !in2) { std::cerr << "unable to add edge (" << head << "," << tail << ")" << std::endl; return -1; } capacity[e1] = cap; capacity[e2] = 0; reverse_edge[e1] = e2; reverse_edge[e2] = e1; } ++no_alines; break; default: /* unknown type of line */ err_no = EN18; goto error; } /* end of switch */ } /* end of input loop */ /* ----- all is red or error while reading ----- */ if (in.eof() == 0) /* reading error */ { err_no = EN21; goto error; } if (no_lines == 0) /* empty input */ { err_no = EN22; goto error; } if (no_alines < m) /* not enough arcs */ { err_no = EN19; goto error; } if (require_source_and_sink && (out_degree(src, g) == 0 || out_degree(sink, g) == 0)) /* no arc goes out of the source */ { err_no = EN20; goto error; } /* Thanks God! all is done */ return (0); /* ---------------------------------- */ error: /* error found reading input */ std::printf( "\nline %ld of input - %s\n", no_lines, err_message[err_no]); return -1; } /* -------------------- end of parser -------------------*/ } // namespace detail template < class Graph, class CapacityMap, class ReverseEdgeMap > int read_dimacs_max_flow(Graph& g, CapacityMap capacity, ReverseEdgeMap reverse_edge, typename graph_traits< Graph >::vertex_descriptor& src, typename graph_traits< Graph >::vertex_descriptor& sink, std::istream& in = std::cin) { return detail::read_dimacs_max_flow_internal( g, capacity, reverse_edge, src, sink, in, true, "max"); } template < class Graph, class CapacityMap, class ReverseEdgeMap > int read_dimacs_min_cut(Graph& g, CapacityMap capacity, ReverseEdgeMap reverse_edge, std::istream& in = std::cin) { typename graph_traits< Graph >::vertex_descriptor dummy_src, dummy_sink; // Not filled in return detail::read_dimacs_max_flow_internal( g, capacity, reverse_edge, dummy_src, dummy_sink, in, false, "cut"); } } // namespace boost #endif // BOOST_GRAPH_READ_DIMACS_HPP lookup_edge.hpp 0000644 00000003546 15125521275 0007567 0 ustar 00 //======================================================================= // Copyright 2009 Trustees of Indiana University // Author: Jeremiah Willcock // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_LOOKUP_EDGE_HPP #define BOOST_GRAPH_LOOKUP_EDGE_HPP #include <utility> #include <boost/config.hpp> #include <boost/utility/enable_if.hpp> #include <boost/graph/graph_traits.hpp> // lookup_edge: a function that acts like edge() but falls back to out_edges() // and a search when edge() is not provided. namespace boost { template < typename Graph > std::pair< typename boost::graph_traits< Graph >::edge_descriptor, bool > lookup_edge(typename boost::graph_traits< Graph >::vertex_descriptor src, typename boost::graph_traits< Graph >::vertex_descriptor tgt, const Graph& g, typename boost::enable_if< is_adjacency_matrix< Graph >, int >::type = 0) { return edge(src, tgt, g); } template < typename Graph > std::pair< typename boost::graph_traits< Graph >::edge_descriptor, bool > lookup_edge(typename boost::graph_traits< Graph >::vertex_descriptor src, typename boost::graph_traits< Graph >::vertex_descriptor tgt, const Graph& g, typename boost::disable_if< is_adjacency_matrix< Graph >, int >::type = 0) { typedef typename boost::graph_traits< Graph >::out_edge_iterator it; typedef typename boost::graph_traits< Graph >::edge_descriptor edesc; std::pair< it, it > oe = out_edges(src, g); for (; oe.first != oe.second; ++oe.first) { edesc e = *oe.first; if (target(e, g) == tgt) return std::make_pair(e, true); } return std::make_pair(edesc(), false); } } #endif // BOOST_GRAPH_LOOKUP_EDGE_HPP boykov_kolmogorov_max_flow.hpp 0000644 00000134356 15125521275 0012761 0 ustar 00 // Copyright (c) 2006, Stephan Diederich // // This code may be used under either of the following two licences: // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE. // // Or: // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP #define BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP #include <boost/config.hpp> #include <boost/assert.hpp> #include <vector> #include <list> #include <utility> #include <iosfwd> #include <algorithm> // for std::min and std::max #include <boost/pending/queue.hpp> #include <boost/limits.hpp> #include <boost/property_map/property_map.hpp> #include <boost/none_t.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/graph/lookup_edge.hpp> #include <boost/concept/assert.hpp> // The algorithm impelemented here is described in: // // Boykov, Y., Kolmogorov, V. "An Experimental Comparison of Min-Cut/Max-Flow // Algorithms for Energy Minimization in Vision", In IEEE Transactions on // Pattern Analysis and Machine Intelligence, vol. 26, no. 9, pp. 1124-1137, // Sep 2004. // // For further reading, also see: // // Kolmogorov, V. "Graph Based Algorithms for Scene Reconstruction from Two or // More Views". PhD thesis, Cornell University, Sep 2003. namespace boost { namespace detail { template < class Graph, class EdgeCapacityMap, class ResidualCapacityEdgeMap, class ReverseEdgeMap, class PredecessorMap, class ColorMap, class DistanceMap, class IndexMap > class bk_max_flow { typedef typename property_traits< EdgeCapacityMap >::value_type tEdgeVal; typedef graph_traits< Graph > tGraphTraits; typedef typename tGraphTraits::vertex_iterator vertex_iterator; typedef typename tGraphTraits::vertex_descriptor vertex_descriptor; typedef typename tGraphTraits::edge_descriptor edge_descriptor; typedef typename tGraphTraits::edge_iterator edge_iterator; typedef typename tGraphTraits::out_edge_iterator out_edge_iterator; typedef boost::queue< vertex_descriptor > tQueue; // queue of vertices, used in adoption-stage typedef typename property_traits< ColorMap >::value_type tColorValue; typedef color_traits< tColorValue > tColorTraits; typedef typename property_traits< DistanceMap >::value_type tDistanceVal; public: bk_max_flow(Graph& g, EdgeCapacityMap cap, ResidualCapacityEdgeMap res, ReverseEdgeMap rev, PredecessorMap pre, ColorMap color, DistanceMap dist, IndexMap idx, vertex_descriptor src, vertex_descriptor sink) : m_g(g) , m_index_map(idx) , m_cap_map(cap) , m_res_cap_map(res) , m_rev_edge_map(rev) , m_pre_map(pre) , m_tree_map(color) , m_dist_map(dist) , m_source(src) , m_sink(sink) , m_active_nodes() , m_in_active_list_vec(num_vertices(g), false) , m_in_active_list_map(make_iterator_property_map( m_in_active_list_vec.begin(), m_index_map)) , m_has_parent_vec(num_vertices(g), false) , m_has_parent_map( make_iterator_property_map(m_has_parent_vec.begin(), m_index_map)) , m_time_vec(num_vertices(g), 0) , m_time_map( make_iterator_property_map(m_time_vec.begin(), m_index_map)) , m_flow(0) , m_time(1) , m_last_grow_vertex(graph_traits< Graph >::null_vertex()) { // initialize the color-map with gray-values vertex_iterator vi, v_end; for (boost::tie(vi, v_end) = vertices(m_g); vi != v_end; ++vi) { set_tree(*vi, tColorTraits::gray()); } // Initialize flow to zero which means initializing // the residual capacity equal to the capacity edge_iterator ei, e_end; for (boost::tie(ei, e_end) = edges(m_g); ei != e_end; ++ei) { put(m_res_cap_map, *ei, get(m_cap_map, *ei)); BOOST_ASSERT(get(m_rev_edge_map, get(m_rev_edge_map, *ei)) == *ei); // check if the reverse edge map is build up // properly } // init the search trees with the two terminals set_tree(m_source, tColorTraits::black()); set_tree(m_sink, tColorTraits::white()); put(m_time_map, m_source, 1); put(m_time_map, m_sink, 1); } tEdgeVal max_flow() { // augment direct paths from SOURCE->SINK and SOURCE->VERTEX->SINK augment_direct_paths(); // start the main-loop while (true) { bool path_found; edge_descriptor connecting_edge; boost::tie(connecting_edge, path_found) = grow(); // find a path from source to sink if (!path_found) { // we're finished, no more paths were found break; } ++m_time; augment(connecting_edge); // augment that path adopt(); // rebuild search tree structure } return m_flow; } // the complete class is protected, as we want access to members in // derived test-class (see test/boykov_kolmogorov_max_flow_test.cpp) protected: void augment_direct_paths() { // in a first step, we augment all direct paths from // source->NODE->sink and additionally paths from source->sink. This // improves especially graphcuts for segmentation, as most of the // nodes have source/sink connects but shouldn't have an impact on // other maxflow problems (this is done in grow() anyway) out_edge_iterator ei, e_end; for (boost::tie(ei, e_end) = out_edges(m_source, m_g); ei != e_end; ++ei) { edge_descriptor from_source = *ei; vertex_descriptor current_node = target(from_source, m_g); if (current_node == m_sink) { tEdgeVal cap = get(m_res_cap_map, from_source); put(m_res_cap_map, from_source, 0); m_flow += cap; continue; } edge_descriptor to_sink; bool is_there; boost::tie(to_sink, is_there) = lookup_edge(current_node, m_sink, m_g); if (is_there) { tEdgeVal cap_from_source = get(m_res_cap_map, from_source); tEdgeVal cap_to_sink = get(m_res_cap_map, to_sink); if (cap_from_source > cap_to_sink) { set_tree(current_node, tColorTraits::black()); add_active_node(current_node); set_edge_to_parent(current_node, from_source); put(m_dist_map, current_node, 1); put(m_time_map, current_node, 1); // add stuff to flow and update residuals. we dont need // to update reverse_edges, as incoming/outgoing edges // to/from source/sink don't count for max-flow put(m_res_cap_map, from_source, get(m_res_cap_map, from_source) - cap_to_sink); put(m_res_cap_map, to_sink, 0); m_flow += cap_to_sink; } else if (cap_to_sink > 0) { set_tree(current_node, tColorTraits::white()); add_active_node(current_node); set_edge_to_parent(current_node, to_sink); put(m_dist_map, current_node, 1); put(m_time_map, current_node, 1); // add stuff to flow and update residuals. we dont need // to update reverse_edges, as incoming/outgoing edges // to/from source/sink don't count for max-flow put(m_res_cap_map, to_sink, get(m_res_cap_map, to_sink) - cap_from_source); put(m_res_cap_map, from_source, 0); m_flow += cap_from_source; } } else if (get(m_res_cap_map, from_source)) { // there is no sink connect, so we can't augment this path, // but to avoid adding m_source to the active nodes, we just // activate this node and set the approciate things set_tree(current_node, tColorTraits::black()); set_edge_to_parent(current_node, from_source); put(m_dist_map, current_node, 1); put(m_time_map, current_node, 1); add_active_node(current_node); } } for (boost::tie(ei, e_end) = out_edges(m_sink, m_g); ei != e_end; ++ei) { edge_descriptor to_sink = get(m_rev_edge_map, *ei); vertex_descriptor current_node = source(to_sink, m_g); if (get(m_res_cap_map, to_sink)) { set_tree(current_node, tColorTraits::white()); set_edge_to_parent(current_node, to_sink); put(m_dist_map, current_node, 1); put(m_time_map, current_node, 1); add_active_node(current_node); } } } /** * Returns a pair of an edge and a boolean. if the bool is true, the * edge is a connection of a found path from s->t , read "the link" and * source(returnVal, m_g) is the end of the path found in the * source-tree target(returnVal, m_g) is the beginning of the path found * in the sink-tree */ std::pair< edge_descriptor, bool > grow() { BOOST_ASSERT(m_orphans.empty()); vertex_descriptor current_node; while ((current_node = get_next_active_node()) != graph_traits< Graph >::null_vertex()) { // if there is one BOOST_ASSERT(get_tree(current_node) != tColorTraits::gray() && (has_parent(current_node) || current_node == m_source || current_node == m_sink)); if (get_tree(current_node) == tColorTraits::black()) { // source tree growing out_edge_iterator ei, e_end; if (current_node != m_last_grow_vertex) { m_last_grow_vertex = current_node; boost::tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g); } for (; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it) { edge_descriptor out_edge = *m_last_grow_edge_it; if (get(m_res_cap_map, out_edge) > 0) { // check if we have capacity left on this edge vertex_descriptor other_node = target(out_edge, m_g); if (get_tree(other_node) == tColorTraits::gray()) { // it's a free node set_tree(other_node, tColorTraits::black()); // aquire other node // to our search // tree set_edge_to_parent( other_node, out_edge); // set us as parent put(m_dist_map, other_node, get(m_dist_map, current_node) + 1); // and update the // distance-heuristic put(m_time_map, other_node, get(m_time_map, current_node)); add_active_node(other_node); } else if (get_tree(other_node) == tColorTraits::black()) { // we do this to get shorter paths. check if we // are nearer to the source as its parent is if (is_closer_to_terminal( current_node, other_node)) { set_edge_to_parent(other_node, out_edge); put(m_dist_map, other_node, get(m_dist_map, current_node) + 1); put(m_time_map, other_node, get(m_time_map, current_node)); } } else { BOOST_ASSERT(get_tree(other_node) == tColorTraits::white()); // kewl, found a path from one to the other // search tree, return // the connecting edge in src->sink dir return std::make_pair(out_edge, true); } } } // for all out-edges } // source-tree-growing else { BOOST_ASSERT( get_tree(current_node) == tColorTraits::white()); out_edge_iterator ei, e_end; if (current_node != m_last_grow_vertex) { m_last_grow_vertex = current_node; boost::tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g); } for (; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it) { edge_descriptor in_edge = get(m_rev_edge_map, *m_last_grow_edge_it); if (get(m_res_cap_map, in_edge) > 0) { // check if there is capacity left vertex_descriptor other_node = source(in_edge, m_g); if (get_tree(other_node) == tColorTraits::gray()) { // it's a free node set_tree(other_node, tColorTraits::white()); // aquire that node // to our search // tree set_edge_to_parent( other_node, in_edge); // set us as parent add_active_node( other_node); // activate that node put(m_dist_map, other_node, get(m_dist_map, current_node) + 1); // set its distance put(m_time_map, other_node, get(m_time_map, current_node)); // and time } else if (get_tree(other_node) == tColorTraits::white()) { if (is_closer_to_terminal( current_node, other_node)) { // we are closer to the sink than its parent // is, so we "adopt" him set_edge_to_parent(other_node, in_edge); put(m_dist_map, other_node, get(m_dist_map, current_node) + 1); put(m_time_map, other_node, get(m_time_map, current_node)); } } else { BOOST_ASSERT(get_tree(other_node) == tColorTraits::black()); // kewl, found a path from one to the other // search tree, // return the connecting edge in src->sink dir return std::make_pair(in_edge, true); } } } // for all out-edges } // sink-tree growing // all edges of that node are processed, and no more paths were // found. // remove if from the front of the active queue finish_node(current_node); } // while active_nodes not empty // no active nodes anymore and no path found, we're done return std::make_pair(edge_descriptor(), false); } /** * augments path from s->t and updates residual graph * source(e, m_g) is the end of the path found in the source-tree * target(e, m_g) is the beginning of the path found in the sink-tree * this phase generates orphans on satured edges, if the attached verts * are from different search-trees orphans are ordered in distance to * sink/source. first the farest from the source are front_inserted into * the orphans list, and after that the sink-tree-orphans are * front_inserted. when going to adoption stage the orphans are * popped_front, and so we process the nearest verts to the terminals * first */ void augment(edge_descriptor e) { BOOST_ASSERT(get_tree(target(e, m_g)) == tColorTraits::white()); BOOST_ASSERT(get_tree(source(e, m_g)) == tColorTraits::black()); BOOST_ASSERT(m_orphans.empty()); const tEdgeVal bottleneck = find_bottleneck(e); // now we push the found flow through the path // for each edge we saturate we have to look for the verts that // belong to that edge, one of them becomes an orphans now process // the connecting edge put(m_res_cap_map, e, get(m_res_cap_map, e) - bottleneck); BOOST_ASSERT(get(m_res_cap_map, e) >= 0); put(m_res_cap_map, get(m_rev_edge_map, e), get(m_res_cap_map, get(m_rev_edge_map, e)) + bottleneck); // now we follow the path back to the source vertex_descriptor current_node = source(e, m_g); while (current_node != m_source) { edge_descriptor pred = get_edge_to_parent(current_node); put(m_res_cap_map, pred, get(m_res_cap_map, pred) - bottleneck); BOOST_ASSERT(get(m_res_cap_map, pred) >= 0); put(m_res_cap_map, get(m_rev_edge_map, pred), get(m_res_cap_map, get(m_rev_edge_map, pred)) + bottleneck); if (get(m_res_cap_map, pred) == 0) { set_no_parent(current_node); m_orphans.push_front(current_node); } current_node = source(pred, m_g); } // then go forward in the sink-tree current_node = target(e, m_g); while (current_node != m_sink) { edge_descriptor pred = get_edge_to_parent(current_node); put(m_res_cap_map, pred, get(m_res_cap_map, pred) - bottleneck); BOOST_ASSERT(get(m_res_cap_map, pred) >= 0); put(m_res_cap_map, get(m_rev_edge_map, pred), get(m_res_cap_map, get(m_rev_edge_map, pred)) + bottleneck); if (get(m_res_cap_map, pred) == 0) { set_no_parent(current_node); m_orphans.push_front(current_node); } current_node = target(pred, m_g); } // and add it to the max-flow m_flow += bottleneck; } /** * returns the bottleneck of a s->t path (end_of_path is last vertex in * source-tree, begin_of_path is first vertex in sink-tree) */ inline tEdgeVal find_bottleneck(edge_descriptor e) { BOOST_USING_STD_MIN(); tEdgeVal minimum_cap = get(m_res_cap_map, e); vertex_descriptor current_node = source(e, m_g); // first go back in the source tree while (current_node != m_source) { edge_descriptor pred = get_edge_to_parent(current_node); minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION( minimum_cap, get(m_res_cap_map, pred)); current_node = source(pred, m_g); } // then go forward in the sink-tree current_node = target(e, m_g); while (current_node != m_sink) { edge_descriptor pred = get_edge_to_parent(current_node); minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION( minimum_cap, get(m_res_cap_map, pred)); current_node = target(pred, m_g); } return minimum_cap; } /** * rebuild search trees * empty the queue of orphans, and find new parents for them or just * drop them from the search trees */ void adopt() { while (!m_orphans.empty() || !m_child_orphans.empty()) { vertex_descriptor current_node; if (m_child_orphans.empty()) { // get the next orphan from the main-queue and remove it current_node = m_orphans.front(); m_orphans.pop_front(); } else { current_node = m_child_orphans.front(); m_child_orphans.pop(); } if (get_tree(current_node) == tColorTraits::black()) { // we're in the source-tree tDistanceVal min_distance = (std::numeric_limits< tDistanceVal >::max)(); edge_descriptor new_parent_edge; out_edge_iterator ei, e_end; for (boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei) { const edge_descriptor in_edge = get(m_rev_edge_map, *ei); BOOST_ASSERT(target(in_edge, m_g) == current_node); // we should be the target of this // edge if (get(m_res_cap_map, in_edge) > 0) { vertex_descriptor other_node = source(in_edge, m_g); if (get_tree(other_node) == tColorTraits::black() && has_source_connect(other_node)) { if (get(m_dist_map, other_node) < min_distance) { min_distance = get(m_dist_map, other_node); new_parent_edge = in_edge; } } } } if (min_distance != (std::numeric_limits< tDistanceVal >::max)()) { set_edge_to_parent(current_node, new_parent_edge); put(m_dist_map, current_node, min_distance + 1); put(m_time_map, current_node, m_time); } else { put(m_time_map, current_node, 0); for (boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei) { edge_descriptor in_edge = get(m_rev_edge_map, *ei); vertex_descriptor other_node = source(in_edge, m_g); if (get_tree(other_node) == tColorTraits::black() && other_node != m_source) { if (get(m_res_cap_map, in_edge) > 0) { add_active_node(other_node); } if (has_parent(other_node) && source( get_edge_to_parent(other_node), m_g) == current_node) { // we are the parent of that node // it has to find a new parent, too set_no_parent(other_node); m_child_orphans.push(other_node); } } } set_tree(current_node, tColorTraits::gray()); } // no parent found } // source-tree-adoption else { // now we should be in the sink-tree, check that... BOOST_ASSERT( get_tree(current_node) == tColorTraits::white()); out_edge_iterator ei, e_end; edge_descriptor new_parent_edge; tDistanceVal min_distance = (std::numeric_limits< tDistanceVal >::max)(); for (boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei) { const edge_descriptor out_edge = *ei; if (get(m_res_cap_map, out_edge) > 0) { const vertex_descriptor other_node = target(out_edge, m_g); if (get_tree(other_node) == tColorTraits::white() && has_sink_connect(other_node)) if (get(m_dist_map, other_node) < min_distance) { min_distance = get(m_dist_map, other_node); new_parent_edge = out_edge; } } } if (min_distance != (std::numeric_limits< tDistanceVal >::max)()) { set_edge_to_parent(current_node, new_parent_edge); put(m_dist_map, current_node, min_distance + 1); put(m_time_map, current_node, m_time); } else { put(m_time_map, current_node, 0); for (boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei) { const edge_descriptor out_edge = *ei; const vertex_descriptor other_node = target(out_edge, m_g); if (get_tree(other_node) == tColorTraits::white() && other_node != m_sink) { if (get(m_res_cap_map, out_edge) > 0) { add_active_node(other_node); } if (has_parent(other_node) && target( get_edge_to_parent(other_node), m_g) == current_node) { // we were it's parent, so it has to find a // new one, too set_no_parent(other_node); m_child_orphans.push(other_node); } } } set_tree(current_node, tColorTraits::gray()); } // no parent found } // sink-tree adoption } // while !orphans.empty() } // adopt /** * return next active vertex if there is one, otherwise a null_vertex */ inline vertex_descriptor get_next_active_node() { while (true) { if (m_active_nodes.empty()) return graph_traits< Graph >::null_vertex(); vertex_descriptor v = m_active_nodes.front(); // if it has no parent, this node can't be active (if its not // source or sink) if (!has_parent(v) && v != m_source && v != m_sink) { m_active_nodes.pop(); put(m_in_active_list_map, v, false); } else { BOOST_ASSERT(get_tree(v) == tColorTraits::black() || get_tree(v) == tColorTraits::white()); return v; } } } /** * adds v as an active vertex, but only if its not in the list already */ inline void add_active_node(vertex_descriptor v) { BOOST_ASSERT(get_tree(v) != tColorTraits::gray()); if (get(m_in_active_list_map, v)) { if (m_last_grow_vertex == v) { m_last_grow_vertex = graph_traits< Graph >::null_vertex(); } return; } else { put(m_in_active_list_map, v, true); m_active_nodes.push(v); } } /** * finish_node removes a node from the front of the active queue (its * called in grow phase, if no more paths can be found using this node) */ inline void finish_node(vertex_descriptor v) { BOOST_ASSERT(m_active_nodes.front() == v); m_active_nodes.pop(); put(m_in_active_list_map, v, false); m_last_grow_vertex = graph_traits< Graph >::null_vertex(); } /** * removes a vertex from the queue of active nodes (actually this does * nothing, but checks if this node has no parent edge, as this is the * criteria for being no more active) */ inline void remove_active_node(vertex_descriptor v) { BOOST_ASSERT(!has_parent(v)); } /** * returns the search tree of v; tColorValue::black() for source tree, * white() for sink tree, gray() for no tree */ inline tColorValue get_tree(vertex_descriptor v) const { return get(m_tree_map, v); } /** * sets search tree of v; tColorValue::black() for source tree, white() * for sink tree, gray() for no tree */ inline void set_tree(vertex_descriptor v, tColorValue t) { put(m_tree_map, v, t); } /** * returns edge to parent vertex of v; */ inline edge_descriptor get_edge_to_parent(vertex_descriptor v) const { return get(m_pre_map, v); } /** * returns true if the edge stored in m_pre_map[v] is a valid entry */ inline bool has_parent(vertex_descriptor v) const { return get(m_has_parent_map, v); } /** * sets edge to parent vertex of v; */ inline void set_edge_to_parent( vertex_descriptor v, edge_descriptor f_edge_to_parent) { BOOST_ASSERT(get(m_res_cap_map, f_edge_to_parent) > 0); put(m_pre_map, v, f_edge_to_parent); put(m_has_parent_map, v, true); } /** * removes the edge to parent of v (this is done by invalidating the * entry an additional map) */ inline void set_no_parent(vertex_descriptor v) { put(m_has_parent_map, v, false); } /** * checks if vertex v has a connect to the sink-vertex (@var m_sink) * @param v the vertex which is checked * @return true if a path to the sink was found, false if not */ inline bool has_sink_connect(vertex_descriptor v) { tDistanceVal current_distance = 0; vertex_descriptor current_vertex = v; while (true) { if (get(m_time_map, current_vertex) == m_time) { // we found a node which was already checked this round. use // it for distance calculations current_distance += get(m_dist_map, current_vertex); break; } if (current_vertex == m_sink) { put(m_time_map, m_sink, m_time); break; } if (has_parent(current_vertex)) { // it has a parent, so get it current_vertex = target(get_edge_to_parent(current_vertex), m_g); ++current_distance; } else { // no path found return false; } } current_vertex = v; while (get(m_time_map, current_vertex) != m_time) { put(m_dist_map, current_vertex, current_distance); --current_distance; put(m_time_map, current_vertex, m_time); current_vertex = target(get_edge_to_parent(current_vertex), m_g); } return true; } /** * checks if vertex v has a connect to the source-vertex (@var m_source) * @param v the vertex which is checked * @return true if a path to the source was found, false if not */ inline bool has_source_connect(vertex_descriptor v) { tDistanceVal current_distance = 0; vertex_descriptor current_vertex = v; while (true) { if (get(m_time_map, current_vertex) == m_time) { // we found a node which was already checked this round. use // it for distance calculations current_distance += get(m_dist_map, current_vertex); break; } if (current_vertex == m_source) { put(m_time_map, m_source, m_time); break; } if (has_parent(current_vertex)) { // it has a parent, so get it current_vertex = source(get_edge_to_parent(current_vertex), m_g); ++current_distance; } else { // no path found return false; } } current_vertex = v; while (get(m_time_map, current_vertex) != m_time) { put(m_dist_map, current_vertex, current_distance); --current_distance; put(m_time_map, current_vertex, m_time); current_vertex = source(get_edge_to_parent(current_vertex), m_g); } return true; } /** * returns true, if p is closer to a terminal than q */ inline bool is_closer_to_terminal( vertex_descriptor p, vertex_descriptor q) { // checks the timestamps first, to build no cycles, and after that // the real distance return (get(m_time_map, q) <= get(m_time_map, p) && get(m_dist_map, q) > get(m_dist_map, p) + 1); } //////// // member vars //////// Graph& m_g; IndexMap m_index_map; EdgeCapacityMap m_cap_map; ResidualCapacityEdgeMap m_res_cap_map; ReverseEdgeMap m_rev_edge_map; PredecessorMap m_pre_map; // stores paths found in the growth stage ColorMap m_tree_map; // maps each vertex into one of the two search tree // or none (gray()) DistanceMap m_dist_map; // stores distance to source/sink nodes vertex_descriptor m_source; vertex_descriptor m_sink; tQueue m_active_nodes; std::vector< bool > m_in_active_list_vec; iterator_property_map< std::vector< bool >::iterator, IndexMap > m_in_active_list_map; std::list< vertex_descriptor > m_orphans; tQueue m_child_orphans; // we use a second queuqe for child orphans, as // they are FIFO processed std::vector< bool > m_has_parent_vec; iterator_property_map< std::vector< bool >::iterator, IndexMap > m_has_parent_map; std::vector< long > m_time_vec; // timestamp of each node, used for // sink/source-path calculations iterator_property_map< std::vector< long >::iterator, IndexMap > m_time_map; tEdgeVal m_flow; long m_time; vertex_descriptor m_last_grow_vertex; out_edge_iterator m_last_grow_edge_it; out_edge_iterator m_last_grow_edge_end; }; } // namespace boost::detail /** * non-named-parameter version, given everything * this is the catch all version */ template < class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap, class ReverseEdgeMap, class PredecessorMap, class ColorMap, class DistanceMap, class IndexMap > typename property_traits< CapacityEdgeMap >::value_type boykov_kolmogorov_max_flow(Graph& g, CapacityEdgeMap cap, ResidualCapacityEdgeMap res_cap, ReverseEdgeMap rev_map, PredecessorMap pre_map, ColorMap color, DistanceMap dist, IndexMap idx, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink) { typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor; // as this method is the last one before we instantiate the solver, we do // the concept checks here BOOST_CONCEPT_ASSERT( (VertexListGraphConcept< Graph >)); // to have vertices(), // num_vertices(), BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph >)); // to have edges() BOOST_CONCEPT_ASSERT( (IncidenceGraphConcept< Graph >)); // to have source(), target() and // out_edges() BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< CapacityEdgeMap, edge_descriptor >)); // read flow-values from edges BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< ResidualCapacityEdgeMap, edge_descriptor >)); // write flow-values to residuals BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< ReverseEdgeMap, edge_descriptor >)); // read out reverse edges BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< PredecessorMap, vertex_descriptor >)); // store predecessor there BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< ColorMap, vertex_descriptor >)); // write corresponding tree BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< DistanceMap, vertex_descriptor >)); // write distance to source/sink BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< IndexMap, vertex_descriptor >)); // get index 0...|V|-1 BOOST_ASSERT(num_vertices(g) >= 2 && src != sink); detail::bk_max_flow< Graph, CapacityEdgeMap, ResidualCapacityEdgeMap, ReverseEdgeMap, PredecessorMap, ColorMap, DistanceMap, IndexMap > algo(g, cap, res_cap, rev_map, pre_map, color, dist, idx, src, sink); return algo.max_flow(); } /** * non-named-parameter version, given capacity, residucal_capacity, * reverse_edges, and an index map. */ template < class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap, class ReverseEdgeMap, class IndexMap > typename property_traits< CapacityEdgeMap >::value_type boykov_kolmogorov_max_flow(Graph& g, CapacityEdgeMap cap, ResidualCapacityEdgeMap res_cap, ReverseEdgeMap rev, IndexMap idx, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink) { typename graph_traits< Graph >::vertices_size_type n_verts = num_vertices(g); std::vector< typename graph_traits< Graph >::edge_descriptor > predecessor_vec(n_verts); std::vector< default_color_type > color_vec(n_verts); std::vector< typename graph_traits< Graph >::vertices_size_type > distance_vec(n_verts); return boykov_kolmogorov_max_flow(g, cap, res_cap, rev, make_iterator_property_map(predecessor_vec.begin(), idx), make_iterator_property_map(color_vec.begin(), idx), make_iterator_property_map(distance_vec.begin(), idx), idx, src, sink); } /** * non-named-parameter version, some given: capacity, residual_capacity, * reverse_edges, color_map and an index map. Use this if you are interested in * the minimum cut, as the color map provides that info. */ template < class Graph, class CapacityEdgeMap, class ResidualCapacityEdgeMap, class ReverseEdgeMap, class ColorMap, class IndexMap > typename property_traits< CapacityEdgeMap >::value_type boykov_kolmogorov_max_flow(Graph& g, CapacityEdgeMap cap, ResidualCapacityEdgeMap res_cap, ReverseEdgeMap rev, ColorMap color, IndexMap idx, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink) { typename graph_traits< Graph >::vertices_size_type n_verts = num_vertices(g); std::vector< typename graph_traits< Graph >::edge_descriptor > predecessor_vec(n_verts); std::vector< typename graph_traits< Graph >::vertices_size_type > distance_vec(n_verts); return boykov_kolmogorov_max_flow(g, cap, res_cap, rev, make_iterator_property_map(predecessor_vec.begin(), idx), color, make_iterator_property_map(distance_vec.begin(), idx), idx, src, sink); } /** * named-parameter version, some given */ template < class Graph, class P, class T, class R > typename property_traits< typename property_map< Graph, edge_capacity_t >::const_type >::value_type boykov_kolmogorov_max_flow(Graph& g, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink, const bgl_named_params< P, T, R >& params) { return boykov_kolmogorov_max_flow(g, choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity), choose_pmap(get_param(params, edge_residual_capacity), g, edge_residual_capacity), choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse), choose_pmap( get_param(params, vertex_predecessor), g, vertex_predecessor), choose_pmap(get_param(params, vertex_color), g, vertex_color), choose_pmap(get_param(params, vertex_distance), g, vertex_distance), choose_const_pmap(get_param(params, vertex_index), g, vertex_index), src, sink); } /** * named-parameter version, none given */ template < class Graph > typename property_traits< typename property_map< Graph, edge_capacity_t >::const_type >::value_type boykov_kolmogorov_max_flow(Graph& g, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink) { bgl_named_params< int, buffer_param_t > params(0); // bogus empty param return boykov_kolmogorov_max_flow(g, src, sink, params); } } // namespace boost #endif // BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP write_dimacs.hpp 0000644 00000005511 15125521275 0007736 0 ustar 00 // Copyright (c) 2006, Stephan Diederich // // This code may be used under either of the following two licences: // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE. // // Or: // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) /* Writes maximal flow problem in extended DIMACS format to an OutputIterator Vertex indices are read from an IndexMap and shiftet by 1. so their new range is [1..num_vertices(g)] */ /* ----------------------------------------------------------------- */ #include <vector> #include <string> #include <ostream> namespace boost { template < class Graph, class CapacityMap, class IndexMap > void write_dimacs_max_flow(const Graph& g, CapacityMap capacity, IndexMap idx, typename graph_traits< Graph >::vertex_descriptor src, typename graph_traits< Graph >::vertex_descriptor sink, std::ostream& out) { typedef typename graph_traits< Graph >::edge_iterator edge_iterator; out << "c DIMACS max-flow file generated from boost::write_dimacs_max_flow" << std::endl; out << "p max " << num_vertices(g) << " " << num_edges(g) << std::endl; // print problem description "max" and number of verts and // edges out << "n " << get(idx, src) + 1 << " s" << std::endl; ; // say which one is source out << "n " << get(idx, sink) + 1 << " t" << std::endl; // say which one is sink // output the edges edge_iterator ei, e_end; for (boost::tie(ei, e_end) = edges(g); ei != e_end; ++ei) { out << "a " << idx[source(*ei, g)] + 1 << " " << idx[target(*ei, g)] + 1 << " " << get(capacity, *ei) << std::endl; } } } // namespace boost reverse_graph.hpp 0000644 00000053602 15125521275 0010124 0 ustar 00 // (C) Copyright David Abrahams 2000. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef REVERSE_GRAPH_DWA092300_H_ #define REVERSE_GRAPH_DWA092300_H_ #include <boost/graph/adjacency_iterator.hpp> #include <boost/graph/properties.hpp> #include <boost/iterator/transform_iterator.hpp> #include <boost/tuple/tuple.hpp> #include <boost/type_traits.hpp> #include <boost/mpl/if.hpp> namespace boost { struct reverse_graph_tag { }; namespace detail { template < typename EdgeDesc > class reverse_graph_edge_descriptor { public: EdgeDesc underlying_descx; // Odd name is because this needs to be public but // shouldn't be exposed to users anymore private: typedef EdgeDesc base_descriptor_type; public: explicit reverse_graph_edge_descriptor( const EdgeDesc& underlying_descx = EdgeDesc()) : underlying_descx(underlying_descx) { } friend bool operator==(const reverse_graph_edge_descriptor& a, const reverse_graph_edge_descriptor& b) { return a.underlying_descx == b.underlying_descx; } friend bool operator!=(const reverse_graph_edge_descriptor& a, const reverse_graph_edge_descriptor& b) { return a.underlying_descx != b.underlying_descx; } friend bool operator<(const reverse_graph_edge_descriptor& a, const reverse_graph_edge_descriptor& b) { return a.underlying_descx < b.underlying_descx; } friend bool operator>(const reverse_graph_edge_descriptor& a, const reverse_graph_edge_descriptor& b) { return a.underlying_descx > b.underlying_descx; } friend bool operator<=(const reverse_graph_edge_descriptor& a, const reverse_graph_edge_descriptor& b) { return a.underlying_descx <= b.underlying_descx; } friend bool operator>=(const reverse_graph_edge_descriptor& a, const reverse_graph_edge_descriptor& b) { return a.underlying_descx >= b.underlying_descx; } }; template < typename EdgeDesc > struct reverse_graph_edge_descriptor_maker { typedef reverse_graph_edge_descriptor< EdgeDesc > result_type; reverse_graph_edge_descriptor< EdgeDesc > operator()( const EdgeDesc& ed) const { return reverse_graph_edge_descriptor< EdgeDesc >(ed); } }; template < typename EdgeDesc, typename Iter > std::pair< transform_iterator< reverse_graph_edge_descriptor_maker< EdgeDesc >, Iter >, transform_iterator< reverse_graph_edge_descriptor_maker< EdgeDesc >, Iter > > reverse_edge_iter_pair(const std::pair< Iter, Iter >& ip) { return std::make_pair( make_transform_iterator( ip.first, reverse_graph_edge_descriptor_maker< EdgeDesc >()), make_transform_iterator( ip.second, reverse_graph_edge_descriptor_maker< EdgeDesc >())); } // Get the underlying descriptor from a vertex or edge descriptor template < typename Desc > struct get_underlying_descriptor_from_reverse_descriptor { typedef Desc type; static Desc convert(const Desc& d) { return d; } }; template < typename Desc > struct get_underlying_descriptor_from_reverse_descriptor< reverse_graph_edge_descriptor< Desc > > { typedef Desc type; static Desc convert(const reverse_graph_edge_descriptor< Desc >& d) { return d.underlying_descx; } }; template < bool isEdgeList > struct choose_rev_edge_iter { }; template <> struct choose_rev_edge_iter< true > { template < class G > struct bind_ { typedef transform_iterator< reverse_graph_edge_descriptor_maker< typename graph_traits< G >::edge_descriptor >, typename graph_traits< G >::edge_iterator > type; }; }; template <> struct choose_rev_edge_iter< false > { template < class G > struct bind_ { typedef void type; }; }; } // namespace detail template < class BidirectionalGraph, class GraphRef = const BidirectionalGraph& > class reverse_graph { typedef reverse_graph< BidirectionalGraph, GraphRef > Self; typedef graph_traits< BidirectionalGraph > Traits; public: typedef BidirectionalGraph base_type; typedef GraphRef base_ref_type; // Constructor reverse_graph(GraphRef g) : m_g(g) {} // Conversion from reverse_graph on non-const reference to one on const // reference reverse_graph( const reverse_graph< BidirectionalGraph, BidirectionalGraph& >& o) : m_g(o.m_g) { } // Graph requirements typedef typename Traits::vertex_descriptor vertex_descriptor; typedef detail::reverse_graph_edge_descriptor< typename Traits::edge_descriptor > edge_descriptor; typedef typename Traits::directed_category directed_category; typedef typename Traits::edge_parallel_category edge_parallel_category; typedef typename Traits::traversal_category traversal_category; // IncidenceGraph requirements typedef transform_iterator< detail::reverse_graph_edge_descriptor_maker< typename Traits::edge_descriptor >, typename Traits::in_edge_iterator > out_edge_iterator; typedef typename Traits::degree_size_type degree_size_type; // BidirectionalGraph requirements typedef transform_iterator< detail::reverse_graph_edge_descriptor_maker< typename Traits::edge_descriptor >, typename Traits::out_edge_iterator > in_edge_iterator; // AdjacencyGraph requirements typedef typename adjacency_iterator_generator< Self, vertex_descriptor, out_edge_iterator >::type adjacency_iterator; // VertexListGraph requirements typedef typename Traits::vertex_iterator vertex_iterator; // EdgeListGraph requirements enum { is_edge_list = is_convertible< traversal_category, edge_list_graph_tag >::value }; typedef detail::choose_rev_edge_iter< is_edge_list > ChooseEdgeIter; typedef typename ChooseEdgeIter::template bind_< BidirectionalGraph >::type edge_iterator; typedef typename Traits::vertices_size_type vertices_size_type; typedef typename Traits::edges_size_type edges_size_type; typedef reverse_graph_tag graph_tag; #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES // Bundled properties support template < typename Descriptor > typename graph::detail::bundled_result< BidirectionalGraph, typename detail::get_underlying_descriptor_from_reverse_descriptor< Descriptor >::type >::type& operator[](Descriptor x) { return m_g[detail::get_underlying_descriptor_from_reverse_descriptor< Descriptor >::convert(x)]; } template < typename Descriptor > typename graph::detail::bundled_result< BidirectionalGraph, typename detail::get_underlying_descriptor_from_reverse_descriptor< Descriptor >::type >::type const& operator[](Descriptor x) const { return m_g[detail::get_underlying_descriptor_from_reverse_descriptor< Descriptor >::convert(x)]; } #endif // BOOST_GRAPH_NO_BUNDLED_PROPERTIES static vertex_descriptor null_vertex() { return Traits::null_vertex(); } // would be private, but template friends aren't portable enough. // private: GraphRef m_g; }; // These are separate so they are not instantiated unless used (see bug 1021) template < class BidirectionalGraph, class GraphRef > struct vertex_property_type< reverse_graph< BidirectionalGraph, GraphRef > > { typedef typename boost::vertex_property_type< BidirectionalGraph >::type type; }; template < class BidirectionalGraph, class GraphRef > struct edge_property_type< reverse_graph< BidirectionalGraph, GraphRef > > { typedef typename boost::edge_property_type< BidirectionalGraph >::type type; }; template < class BidirectionalGraph, class GraphRef > struct graph_property_type< reverse_graph< BidirectionalGraph, GraphRef > > { typedef typename boost::graph_property_type< BidirectionalGraph >::type type; }; #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES template < typename Graph, typename GraphRef > struct vertex_bundle_type< reverse_graph< Graph, GraphRef > > : vertex_bundle_type< Graph > { }; template < typename Graph, typename GraphRef > struct edge_bundle_type< reverse_graph< Graph, GraphRef > > : edge_bundle_type< Graph > { }; template < typename Graph, typename GraphRef > struct graph_bundle_type< reverse_graph< Graph, GraphRef > > : graph_bundle_type< Graph > { }; #endif // BOOST_GRAPH_NO_BUNDLED_PROPERTIES template < class BidirectionalGraph > inline reverse_graph< BidirectionalGraph > make_reverse_graph( const BidirectionalGraph& g) { return reverse_graph< BidirectionalGraph >(g); } template < class BidirectionalGraph > inline reverse_graph< BidirectionalGraph, BidirectionalGraph& > make_reverse_graph(BidirectionalGraph& g) { return reverse_graph< BidirectionalGraph, BidirectionalGraph& >(g); } template < class BidirectionalGraph, class GRef > std::pair< typename reverse_graph< BidirectionalGraph >::vertex_iterator, typename reverse_graph< BidirectionalGraph >::vertex_iterator > vertices(const reverse_graph< BidirectionalGraph, GRef >& g) { return vertices(g.m_g); } template < class BidirectionalGraph, class GRef > std::pair< typename reverse_graph< BidirectionalGraph >::edge_iterator, typename reverse_graph< BidirectionalGraph >::edge_iterator > edges(const reverse_graph< BidirectionalGraph, GRef >& g) { return detail::reverse_edge_iter_pair< typename graph_traits< BidirectionalGraph >::edge_descriptor >( edges(g.m_g)); } template < class BidirectionalGraph, class GRef > inline std::pair< typename reverse_graph< BidirectionalGraph >::out_edge_iterator, typename reverse_graph< BidirectionalGraph >::out_edge_iterator > out_edges( const typename graph_traits< BidirectionalGraph >::vertex_descriptor u, const reverse_graph< BidirectionalGraph, GRef >& g) { return detail::reverse_edge_iter_pair< typename graph_traits< BidirectionalGraph >::edge_descriptor >( in_edges(u, g.m_g)); } template < class BidirectionalGraph, class GRef > inline typename graph_traits< BidirectionalGraph >::vertices_size_type num_vertices(const reverse_graph< BidirectionalGraph, GRef >& g) { return num_vertices(g.m_g); } template < class BidirectionalGraph, class GRef > inline typename reverse_graph< BidirectionalGraph >::edges_size_type num_edges( const reverse_graph< BidirectionalGraph, GRef >& g) { return num_edges(g.m_g); } template < class BidirectionalGraph, class GRef > inline typename graph_traits< BidirectionalGraph >::degree_size_type out_degree( const typename graph_traits< BidirectionalGraph >::vertex_descriptor u, const reverse_graph< BidirectionalGraph, GRef >& g) { return in_degree(u, g.m_g); } template < class BidirectionalGraph, class GRef > inline typename graph_traits< BidirectionalGraph >::vertex_descriptor vertex( const typename graph_traits< BidirectionalGraph >::vertices_size_type v, const reverse_graph< BidirectionalGraph, GRef >& g) { return vertex(v, g.m_g); } template < class BidirectionalGraph, class GRef > inline std::pair< typename graph_traits< reverse_graph< BidirectionalGraph, GRef > >::edge_descriptor, bool > edge(const typename graph_traits< BidirectionalGraph >::vertex_descriptor u, const typename graph_traits< BidirectionalGraph >::vertex_descriptor v, const reverse_graph< BidirectionalGraph, GRef >& g) { typedef typename graph_traits< BidirectionalGraph >::edge_descriptor underlying_edge_descriptor; std::pair< underlying_edge_descriptor, bool > e = edge(v, u, g.m_g); return std::make_pair( detail::reverse_graph_edge_descriptor< underlying_edge_descriptor >( e.first), e.second); } template < class BidirectionalGraph, class GRef > inline std::pair< typename reverse_graph< BidirectionalGraph >::in_edge_iterator, typename reverse_graph< BidirectionalGraph >::in_edge_iterator > in_edges(const typename graph_traits< BidirectionalGraph >::vertex_descriptor u, const reverse_graph< BidirectionalGraph, GRef >& g) { return detail::reverse_edge_iter_pair< typename graph_traits< BidirectionalGraph >::edge_descriptor >( out_edges(u, g.m_g)); } template < class BidirectionalGraph, class GRef > inline std::pair< typename reverse_graph< BidirectionalGraph, GRef >::adjacency_iterator, typename reverse_graph< BidirectionalGraph, GRef >::adjacency_iterator > adjacent_vertices( typename graph_traits< BidirectionalGraph >::vertex_descriptor u, const reverse_graph< BidirectionalGraph, GRef >& g) { typedef reverse_graph< BidirectionalGraph, GRef > Graph; typename graph_traits< Graph >::out_edge_iterator first, last; boost::tie(first, last) = out_edges(u, g); typedef typename graph_traits< Graph >::adjacency_iterator adjacency_iterator; return std::make_pair(adjacency_iterator(first, const_cast< Graph* >(&g)), adjacency_iterator(last, const_cast< Graph* >(&g))); } template < class BidirectionalGraph, class GRef > inline typename graph_traits< BidirectionalGraph >::degree_size_type in_degree( const typename graph_traits< BidirectionalGraph >::vertex_descriptor u, const reverse_graph< BidirectionalGraph, GRef >& g) { return out_degree(u, g.m_g); } template < class Edge, class BidirectionalGraph, class GRef > inline typename graph_traits< BidirectionalGraph >::vertex_descriptor source( const detail::reverse_graph_edge_descriptor< Edge >& e, const reverse_graph< BidirectionalGraph, GRef >& g) { return target(e.underlying_descx, g.m_g); } template < class Edge, class BidirectionalGraph, class GRef > inline typename graph_traits< BidirectionalGraph >::vertex_descriptor target( const detail::reverse_graph_edge_descriptor< Edge >& e, const reverse_graph< BidirectionalGraph, GRef >& g) { return source(e.underlying_descx, g.m_g); } template < class BidirectionalGraph, class GRef > inline typename graph_traits< BidirectionalGraph >::degree_size_type degree( const typename graph_traits< BidirectionalGraph >::vertex_descriptor u, const reverse_graph< BidirectionalGraph, GRef >& g) { return degree(u, g.m_g); } namespace detail { template < typename PM > struct reverse_graph_edge_property_map { private: PM underlying_pm; public: typedef reverse_graph_edge_descriptor< typename property_traits< PM >::key_type > key_type; typedef typename property_traits< PM >::value_type value_type; typedef typename property_traits< PM >::reference reference; typedef typename property_traits< PM >::category category; explicit reverse_graph_edge_property_map(const PM& pm) : underlying_pm(pm) { } friend reference get( const reverse_graph_edge_property_map& m, const key_type& e) { return get(m.underlying_pm, e.underlying_descx); } friend void put(const reverse_graph_edge_property_map& m, const key_type& e, const value_type& v) { put(m.underlying_pm, e.underlying_descx, v); } reference operator[](const key_type& k) const { return (this->underlying_pm)[k.underlying_descx]; } }; } // namespace detail template < class BidirGraph, class GRef, class Property > struct property_map< reverse_graph< BidirGraph, GRef >, Property > { typedef boost::is_same< typename detail::property_kind_from_graph< BidirGraph, Property >::type, edge_property_tag > is_edge_prop; typedef boost::is_const< typename boost::remove_reference< GRef >::type > is_ref_const; typedef typename boost::mpl::if_< is_ref_const, typename property_map< BidirGraph, Property >::const_type, typename property_map< BidirGraph, Property >::type >::type orig_type; typedef typename property_map< BidirGraph, Property >::const_type orig_const_type; typedef typename boost::mpl::if_< is_edge_prop, detail::reverse_graph_edge_property_map< orig_type >, orig_type >::type type; typedef typename boost::mpl::if_< is_edge_prop, detail::reverse_graph_edge_property_map< orig_const_type >, orig_const_type >::type const_type; }; template < class BidirGraph, class GRef, class Property > struct property_map< const reverse_graph< BidirGraph, GRef >, Property > { typedef boost::is_same< typename detail::property_kind_from_graph< BidirGraph, Property >::type, edge_property_tag > is_edge_prop; typedef typename property_map< BidirGraph, Property >::const_type orig_const_type; typedef typename boost::mpl::if_< is_edge_prop, detail::reverse_graph_edge_property_map< orig_const_type >, orig_const_type >::type const_type; typedef const_type type; }; template < class BidirGraph, class GRef, class Property > typename disable_if< is_same< Property, edge_underlying_t >, typename property_map< reverse_graph< BidirGraph, GRef >, Property >::type >::type get(Property p, reverse_graph< BidirGraph, GRef >& g) { return typename property_map< reverse_graph< BidirGraph, GRef >, Property >::type(get(p, g.m_g)); } template < class BidirGraph, class GRef, class Property > typename disable_if< is_same< Property, edge_underlying_t >, typename property_map< reverse_graph< BidirGraph, GRef >, Property >::const_type >::type get(Property p, const reverse_graph< BidirGraph, GRef >& g) { const BidirGraph& gref = g.m_g; // in case GRef is non-const return typename property_map< reverse_graph< BidirGraph, GRef >, Property >::const_type(get(p, gref)); } template < class BidirectionalGraph, class GRef, class Property, class Key > typename disable_if< is_same< Property, edge_underlying_t >, typename property_traits< typename property_map< reverse_graph< BidirectionalGraph, GRef >, Property >::const_type >::value_type >::type get(Property p, const reverse_graph< BidirectionalGraph, GRef >& g, const Key& k) { return get(get(p, g), k); } template < class BidirectionalGraph, class GRef, class Property, class Key, class Value > void put(Property p, reverse_graph< BidirectionalGraph, GRef >& g, const Key& k, const Value& val) { put(get(p, g), k, val); } // Get the underlying descriptor from a reverse_graph's wrapped edge descriptor namespace detail { template < class E > struct underlying_edge_desc_map_type { E operator[](const reverse_graph_edge_descriptor< E >& k) const { return k.underlying_descx; } }; template < class E > E get(underlying_edge_desc_map_type< E > m, const reverse_graph_edge_descriptor< E >& k) { return m[k]; } } template < class E > struct property_traits< detail::underlying_edge_desc_map_type< E > > { typedef detail::reverse_graph_edge_descriptor< E > key_type; typedef E value_type; typedef const E& reference; typedef readable_property_map_tag category; }; template < class Graph, class GRef > struct property_map< reverse_graph< Graph, GRef >, edge_underlying_t > { private: typedef typename graph_traits< Graph >::edge_descriptor ed; public: typedef detail::underlying_edge_desc_map_type< ed > type; typedef detail::underlying_edge_desc_map_type< ed > const_type; }; template < typename T > struct is_reverse_graph : boost::mpl::false_ { }; template < typename G, typename R > struct is_reverse_graph< reverse_graph< G, R > > : boost::mpl::true_ { }; template < class G > typename enable_if< is_reverse_graph< G >, detail::underlying_edge_desc_map_type< typename graph_traits< typename G::base_type >::edge_descriptor > >::type get(edge_underlying_t, G&) { return detail::underlying_edge_desc_map_type< typename graph_traits< typename G::base_type >::edge_descriptor >(); } template < class G > typename enable_if< is_reverse_graph< G >, typename graph_traits< typename G::base_type >::edge_descriptor >::type get(edge_underlying_t, G&, const typename graph_traits< G >::edge_descriptor& k) { return k.underlying_descx; } template < class G > typename enable_if< is_reverse_graph< G >, detail::underlying_edge_desc_map_type< typename graph_traits< typename G::base_type >::edge_descriptor > >::type get(edge_underlying_t, const G&) { return detail::underlying_edge_desc_map_type< typename graph_traits< typename G::base_type >::edge_descriptor >(); } template < class G > typename enable_if< is_reverse_graph< G >, typename graph_traits< typename G::base_type >::edge_descriptor >::type get(edge_underlying_t, const G&, const typename graph_traits< G >::edge_descriptor& k) { return k.underlying_descx; } // Access to wrapped graph's graph properties template < typename BidirectionalGraph, typename GRef, typename Tag, typename Value > inline void set_property(const reverse_graph< BidirectionalGraph, GRef >& g, Tag tag, const Value& value) { set_property(g.m_g, tag, value); } template < typename BidirectionalGraph, typename GRef, typename Tag > inline typename boost::mpl::if_< boost::is_const< typename boost::remove_reference< GRef >::type >, const typename graph_property< BidirectionalGraph, Tag >::type&, typename graph_property< BidirectionalGraph, Tag >::type& >::type get_property(const reverse_graph< BidirectionalGraph, GRef >& g, Tag tag) { return get_property(g.m_g, tag); } } // namespace boost #endif cycle_canceling.hpp 0000644 00000014765 15125521275 0010401 0 ustar 00 //======================================================================= // Copyright 2013 University of Warsaw. // Authors: Piotr Wygocki // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // // // This algorithm is described in "Network Flows: Theory, Algorithms, and // Applications" // by Ahuja, Magnanti, Orlin. #ifndef BOOST_GRAPH_CYCLE_CANCELING_HPP #define BOOST_GRAPH_CYCLE_CANCELING_HPP #include <numeric> #include <boost/property_map/property_map.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/pending/indirect_cmp.hpp> #include <boost/graph/bellman_ford_shortest_paths.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/graph/detail/augment.hpp> #include <boost/graph/find_flow_cost.hpp> namespace boost { namespace detail { template < typename PredEdgeMap, typename Vertex > class RecordEdgeMapAndCycleVertex : public bellman_visitor< edge_predecessor_recorder< PredEdgeMap, on_edge_relaxed > > { typedef edge_predecessor_recorder< PredEdgeMap, on_edge_relaxed > PredRec; public: RecordEdgeMapAndCycleVertex(PredEdgeMap pred, Vertex& v) : bellman_visitor< PredRec >(PredRec(pred)), m_v(v), m_pred(pred) { } template < typename Graph, typename Edge > void edge_not_minimized(Edge e, const Graph& g) const { typename graph_traits< Graph >::vertices_size_type n = num_vertices(g) + 1; // edge e is not minimized but does not have to be on the negative // weight cycle to find vertex on negative wieight cycle we move n+1 // times backword in the PredEdgeMap graph. while (n > 0) { e = get(m_pred, source(e, g)); --n; } m_v = source(e, g); } private: Vertex& m_v; PredEdgeMap m_pred; }; } // detail template < class Graph, class Pred, class Distance, class Reversed, class ResidualCapacity, class Weight > void cycle_canceling(const Graph& g, Weight weight, Reversed rev, ResidualCapacity residual_capacity, Pred pred, Distance distance) { typedef filtered_graph< const Graph, is_residual_edge< ResidualCapacity > > ResGraph; ResGraph gres = detail::residual_graph(g, residual_capacity); typedef graph_traits< ResGraph > ResGTraits; typedef graph_traits< Graph > GTraits; typedef typename ResGTraits::edge_descriptor edge_descriptor; typedef typename ResGTraits::vertex_descriptor vertex_descriptor; typename GTraits::vertices_size_type N = num_vertices(g); BGL_FORALL_VERTICES_T(v, g, Graph) { put(pred, v, edge_descriptor()); put(distance, v, 0); } vertex_descriptor cycleStart; while (!bellman_ford_shortest_paths(gres, N, weight_map(weight).distance_map(distance).visitor( detail::RecordEdgeMapAndCycleVertex< Pred, vertex_descriptor >( pred, cycleStart)))) { detail::augment( g, cycleStart, cycleStart, pred, residual_capacity, rev); BGL_FORALL_VERTICES_T(v, g, Graph) { put(pred, v, edge_descriptor()); put(distance, v, 0); } } } // in this namespace argument dispatching takes place namespace detail { template < class Graph, class P, class T, class R, class ResidualCapacity, class Weight, class Reversed, class Pred, class Distance > void cycle_canceling_dispatch2(const Graph& g, Weight weight, Reversed rev, ResidualCapacity residual_capacity, Pred pred, Distance dist, const bgl_named_params< P, T, R >& params) { cycle_canceling(g, weight, rev, residual_capacity, pred, dist); } // setting default distance map template < class Graph, class P, class T, class R, class Pred, class ResidualCapacity, class Weight, class Reversed > void cycle_canceling_dispatch2(Graph& g, Weight weight, Reversed rev, ResidualCapacity residual_capacity, Pred pred, param_not_found, const bgl_named_params< P, T, R >& params) { typedef typename property_traits< Weight >::value_type D; std::vector< D > d_map(num_vertices(g)); cycle_canceling(g, weight, rev, residual_capacity, pred, make_iterator_property_map(d_map.begin(), choose_const_pmap( get_param(params, vertex_index), g, vertex_index))); } template < class Graph, class P, class T, class R, class ResidualCapacity, class Weight, class Reversed, class Pred > void cycle_canceling_dispatch1(Graph& g, Weight weight, Reversed rev, ResidualCapacity residual_capacity, Pred pred, const bgl_named_params< P, T, R >& params) { cycle_canceling_dispatch2(g, weight, rev, residual_capacity, pred, get_param(params, vertex_distance), params); } // setting default predecessors map template < class Graph, class P, class T, class R, class ResidualCapacity, class Weight, class Reversed > void cycle_canceling_dispatch1(Graph& g, Weight weight, Reversed rev, ResidualCapacity residual_capacity, param_not_found, const bgl_named_params< P, T, R >& params) { typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor; std::vector< edge_descriptor > p_map(num_vertices(g)); cycle_canceling_dispatch2(g, weight, rev, residual_capacity, make_iterator_property_map(p_map.begin(), choose_const_pmap( get_param(params, vertex_index), g, vertex_index)), get_param(params, vertex_distance), params); } } // detail template < class Graph, class P, class T, class R > void cycle_canceling(Graph& g, const bgl_named_params< P, T, R >& params) { cycle_canceling_dispatch1(g, choose_const_pmap(get_param(params, edge_weight), g, edge_weight), choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse), choose_pmap(get_param(params, edge_residual_capacity), g, edge_residual_capacity), get_param(params, vertex_predecessor), params); } template < class Graph > void cycle_canceling(Graph& g) { bgl_named_params< int, buffer_param_t > params(0); cycle_canceling(g, params); } } #endif /* BOOST_GRAPH_CYCLE_CANCELING_HPP */ tiernan_all_cycles.hpp 0000644 00000030403 15125521275 0011114 0 ustar 00 // (C) Copyright 2007-2009 Andrew Sutton // // 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_CYCLE_HPP #define BOOST_GRAPH_CYCLE_HPP #include <vector> #include <boost/config.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/properties.hpp> #include <boost/concept/assert.hpp> #include <boost/concept/detail/concept_def.hpp> namespace boost { namespace concepts { BOOST_concept(CycleVisitor, (Visitor)(Path)(Graph)) { BOOST_CONCEPT_USAGE(CycleVisitor) { vis.cycle(p, g); } private: Visitor vis; Graph g; Path p; }; } /* namespace concepts */ using concepts::CycleVisitorConcept; } /* namespace boost */ #include <boost/concept/detail/concept_undef.hpp> namespace boost { // The implementation of this algorithm is a reproduction of the Teirnan // approach for directed graphs: bibtex follows // // @article{362819, // author = {James C. Tiernan}, // title = {An efficient search algorithm to find the elementary // circuits of a graph}, journal = {Commun. ACM}, volume = {13}, number // = {12}, year = {1970}, issn = {0001-0782}, pages = {722--726}, doi = // {http://doi.acm.org/10.1145/362814.362819}, // publisher = {ACM Press}, // address = {New York, NY, USA}, // } // // It should be pointed out that the author does not provide a complete analysis // for either time or space. This is in part, due to the fact that it's a fairly // input sensitive problem related to the density and construction of the graph, // not just its size. // // I've also taken some liberties with the interpretation of the algorithm - // I've basically modernized it to use real data structures (no more arrays and // matrices). Oh... and there's explicit control structures - not just gotos. // // The problem is definitely NP-complete, an unbounded implementation of this // will probably run for quite a while on a large graph. The conclusions // of this paper also reference a Paton algorithm for undirected graphs as being // much more efficient (apparently based on spanning trees). Although not // implemented, it can be found here: // // @article{363232, // author = {Keith Paton}, // title = {An algorithm for finding a fundamental set of cycles of a // graph}, journal = {Commun. ACM}, volume = {12}, number = {9}, year = // {1969}, issn = {0001-0782}, pages = {514--518}, doi = // {http://doi.acm.org/10.1145/363219.363232}, // publisher = {ACM Press}, // address = {New York, NY, USA}, // } /** * The default cycle visitor provides an empty visit function for cycle * visitors. */ struct cycle_visitor { template < typename Path, typename Graph > inline void cycle(const Path& p, const Graph& g) { } }; /** * The min_max_cycle_visitor simultaneously records the minimum and maximum * cycles in a graph. */ struct min_max_cycle_visitor { min_max_cycle_visitor(std::size_t& min_, std::size_t& max_) : minimum(min_), maximum(max_) { } template < typename Path, typename Graph > inline void cycle(const Path& p, const Graph& g) { BOOST_USING_STD_MIN(); BOOST_USING_STD_MAX(); std::size_t len = p.size(); minimum = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum, len); maximum = max BOOST_PREVENT_MACRO_SUBSTITUTION(maximum, len); } std::size_t& minimum; std::size_t& maximum; }; inline min_max_cycle_visitor find_min_max_cycle( std::size_t& min_, std::size_t& max_) { return min_max_cycle_visitor(min_, max_); } namespace detail { template < typename Graph, typename Path > inline bool is_vertex_in_path(const Graph&, typename graph_traits< Graph >::vertex_descriptor v, const Path& p) { return (std::find(p.begin(), p.end(), v) != p.end()); } template < typename Graph, typename ClosedMatrix > inline bool is_path_closed(const Graph& g, typename graph_traits< Graph >::vertex_descriptor u, typename graph_traits< Graph >::vertex_descriptor v, const ClosedMatrix& closed) { // the path from u to v is closed if v can be found in the list // of closed vertices associated with u. typedef typename ClosedMatrix::const_reference Row; Row r = closed[get(vertex_index, g, u)]; if (find(r.begin(), r.end(), v) != r.end()) { return true; } return false; } template < typename Graph, typename Path, typename ClosedMatrix > inline bool can_extend_path(const Graph& g, typename graph_traits< Graph >::edge_descriptor e, const Path& p, const ClosedMatrix& m) { BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >)); BOOST_CONCEPT_ASSERT((VertexIndexGraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; // get the vertices in question Vertex u = source(e, g), v = target(e, g); // conditions for allowing a traversal along this edge are: // 1. the index of v must be greater than that at which the // path is rooted (p.front()). // 2. the vertex v cannot already be in the path // 3. the vertex v cannot be closed to the vertex u bool indices = get(vertex_index, g, p.front()) < get(vertex_index, g, v); bool path = !is_vertex_in_path(g, v, p); bool closed = !is_path_closed(g, u, v, m); return indices && path && closed; } template < typename Graph, typename Path > inline bool can_wrap_path(const Graph& g, const Path& p) { BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::out_edge_iterator OutIterator; // iterate over the out-edges of the back, looking for the // front of the path. also, we can't travel along the same // edge that we did on the way here, but we don't quite have the // stringent requirements that we do in can_extend_path(). Vertex u = p.back(), v = p.front(); OutIterator i, end; for (boost::tie(i, end) = out_edges(u, g); i != end; ++i) { if ((target(*i, g) == v)) { return true; } } return false; } template < typename Graph, typename Path, typename ClosedMatrix > inline typename graph_traits< Graph >::vertex_descriptor extend_path( const Graph& g, Path& p, ClosedMatrix& closed) { BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::out_edge_iterator OutIterator; // get the current vertex Vertex u = p.back(); Vertex ret = graph_traits< Graph >::null_vertex(); // AdjacencyIterator i, end; OutIterator i, end; for (boost::tie(i, end) = out_edges(u, g); i != end; ++i) { Vertex v = target(*i, g); // if we can actually extend along this edge, // then that's what we want to do if (can_extend_path(g, *i, p, closed)) { p.push_back(v); // add the vertex to the path ret = v; break; } } return ret; } template < typename Graph, typename Path, typename ClosedMatrix > inline bool exhaust_paths(const Graph& g, Path& p, ClosedMatrix& closed) { BOOST_CONCEPT_ASSERT((GraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; // if there's more than one vertex in the path, this closes // of some possible routes and returns true. otherwise, if there's // only one vertex left, the vertex has been used up if (p.size() > 1) { // get the last and second to last vertices, popping the last // vertex off the path Vertex last, prev; last = p.back(); p.pop_back(); prev = p.back(); // reset the closure for the last vertex of the path and // indicate that the last vertex in p is now closed to // the next-to-last vertex in p closed[get(vertex_index, g, last)].clear(); closed[get(vertex_index, g, prev)].push_back(last); return true; } else { return false; } } template < typename Graph, typename Visitor > inline void all_cycles_from_vertex(const Graph& g, typename graph_traits< Graph >::vertex_descriptor v, Visitor vis, std::size_t minlen, std::size_t maxlen) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef std::vector< Vertex > Path; BOOST_CONCEPT_ASSERT((CycleVisitorConcept< Visitor, Path, Graph >)); typedef std::vector< Vertex > VertexList; typedef std::vector< VertexList > ClosedMatrix; Path p; ClosedMatrix closed(num_vertices(g), VertexList()); Vertex null = graph_traits< Graph >::null_vertex(); // each path investigation starts at the ith vertex p.push_back(v); while (1) { // extend the path until we've reached the end or the // maxlen-sized cycle Vertex j = null; while (((j = detail::extend_path(g, p, closed)) != null) && (p.size() < maxlen)) ; // empty loop // if we're done extending the path and there's an edge // connecting the back to the front, then we should have // a cycle. if (detail::can_wrap_path(g, p) && p.size() >= minlen) { vis.cycle(p, g); } if (!detail::exhaust_paths(g, p, closed)) { break; } } } // Select the minimum allowable length of a cycle based on the directedness // of the graph - 2 for directed, 3 for undirected. template < typename D > struct min_cycles { enum { value = 2 }; }; template <> struct min_cycles< undirected_tag > { enum { value = 3 }; }; } /* namespace detail */ template < typename Graph, typename Visitor > inline void tiernan_all_cycles( const Graph& g, Visitor vis, std::size_t minlen, std::size_t maxlen) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_iterator VertexIterator; VertexIterator i, end; for (boost::tie(i, end) = vertices(g); i != end; ++i) { detail::all_cycles_from_vertex(g, *i, vis, minlen, maxlen); } } template < typename Graph, typename Visitor > inline void tiernan_all_cycles(const Graph& g, Visitor vis, std::size_t maxlen) { typedef typename graph_traits< Graph >::directed_category Dir; tiernan_all_cycles(g, vis, detail::min_cycles< Dir >::value, maxlen); } template < typename Graph, typename Visitor > inline void tiernan_all_cycles(const Graph& g, Visitor vis) { typedef typename graph_traits< Graph >::directed_category Dir; tiernan_all_cycles(g, vis, detail::min_cycles< Dir >::value, (std::numeric_limits< std::size_t >::max)()); } template < typename Graph > inline std::pair< std::size_t, std::size_t > tiernan_girth_and_circumference( const Graph& g) { std::size_t min_ = (std::numeric_limits< std::size_t >::max)(), max_ = 0; tiernan_all_cycles(g, find_min_max_cycle(min_, max_)); // if this is the case, the graph is acyclic... if (max_ == 0) max_ = min_; return std::make_pair(min_, max_); } template < typename Graph > inline std::size_t tiernan_girth(const Graph& g) { return tiernan_girth_and_circumference(g).first; } template < typename Graph > inline std::size_t tiernan_circumference(const Graph& g) { return tiernan_girth_and_circumference(g).second; } } /* namespace boost */ #endif minimum_degree_ordering.hpp 0000644 00000064717 15125521275 0012160 0 ustar 00 //-*-c++-*- //======================================================================= // Copyright 1997-2001 University of Notre Dame. // Authors: Lie-Quan Lee, Jeremy Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_MINIMUM_DEGREE_ORDERING_HPP #define BOOST_GRAPH_MINIMUM_DEGREE_ORDERING_HPP #include <vector> #include <boost/assert.hpp> #include <boost/config.hpp> #include <boost/pending/bucket_sorter.hpp> #include <boost/detail/numeric_traits.hpp> // for integer_traits #include <boost/graph/graph_traits.hpp> #include <boost/property_map/property_map.hpp> namespace boost { namespace detail { // // Given a set of n integers (where the integer values range from // zero to n-1), we want to keep track of a collection of stacks // of integers. It so happens that an integer will appear in at // most one stack at a time, so the stacks form disjoint sets. // Because of these restrictions, we can use one big array to // store all the stacks, intertwined with one another. // No allocation/deallocation happens in the push()/pop() methods // so this is faster than using std::stack's. // template < class SignedInteger > class Stacks { typedef SignedInteger value_type; typedef typename std::vector< value_type >::size_type size_type; public: Stacks(size_type n) : data(n) {} //: stack class stack { typedef typename std::vector< value_type >::iterator Iterator; public: stack(Iterator _data, const value_type& head) : data(_data), current(head) { } // did not use default argument here to avoid internal compiler // error in g++. stack(Iterator _data) : data(_data), current(-(std::numeric_limits< value_type >::max)()) { } void pop() { BOOST_ASSERT(!empty()); current = data[current]; } void push(value_type v) { data[v] = current; current = v; } bool empty() { return current == -(std::numeric_limits< value_type >::max)(); } value_type& top() { return current; } private: Iterator data; value_type current; }; // To return a stack object stack make_stack() { return stack(data.begin()); } protected: std::vector< value_type > data; }; // marker class, a generalization of coloring. // // This class is to provide a generalization of coloring which has // complexity of amortized constant time to set all vertices' color // back to be untagged. It implemented by increasing a tag. // // The colors are: // not tagged // tagged // multiple_tagged // done // template < class SignedInteger, class Vertex, class VertexIndexMap > class Marker { typedef SignedInteger value_type; typedef typename std::vector< value_type >::size_type size_type; static value_type done() { return (std::numeric_limits< value_type >::max)() / 2; } public: Marker(size_type _num, VertexIndexMap index_map) : tag(1 - (std::numeric_limits< value_type >::max)()) , data(_num, -(std::numeric_limits< value_type >::max)()) , id(index_map) { } void mark_done(Vertex node) { data[get(id, node)] = done(); } bool is_done(Vertex node) { return data[get(id, node)] == done(); } void mark_tagged(Vertex node) { data[get(id, node)] = tag; } void mark_multiple_tagged(Vertex node) { data[get(id, node)] = multiple_tag; } bool is_tagged(Vertex node) const { return data[get(id, node)] >= tag; } bool is_not_tagged(Vertex node) const { return data[get(id, node)] < tag; } bool is_multiple_tagged(Vertex node) const { return data[get(id, node)] >= multiple_tag; } void increment_tag() { const size_type num = data.size(); ++tag; if (tag >= done()) { tag = 1 - (std::numeric_limits< value_type >::max)(); for (size_type i = 0; i < num; ++i) if (data[i] < done()) data[i] = -(std::numeric_limits< value_type >::max)(); } } void set_multiple_tag(value_type mdeg0) { const size_type num = data.size(); multiple_tag = tag + mdeg0; if (multiple_tag >= done()) { tag = 1 - (std::numeric_limits< value_type >::max)(); for (size_type i = 0; i < num; i++) if (data[i] < done()) data[i] = -(std::numeric_limits< value_type >::max)(); multiple_tag = tag + mdeg0; } } void set_tag_as_multiple_tag() { tag = multiple_tag; } protected: value_type tag; value_type multiple_tag; std::vector< value_type > data; VertexIndexMap id; }; template < class Iterator, class SignedInteger, class Vertex, class VertexIndexMap, int offset = 1 > class Numbering { typedef SignedInteger number_type; number_type num; // start from 1 instead of zero Iterator data; number_type max_num; VertexIndexMap id; public: Numbering(Iterator _data, number_type _max_num, VertexIndexMap id) : num(1), data(_data), max_num(_max_num), id(id) { } void operator()(Vertex node) { data[get(id, node)] = -num; } bool all_done(number_type i = 0) const { return num + i > max_num; } void increment(number_type i = 1) { num += i; } bool is_numbered(Vertex node) const { return data[get(id, node)] < 0; } void indistinguishable(Vertex i, Vertex j) { data[get(id, i)] = -(get(id, j) + offset); } }; template < class SignedInteger, class Vertex, class VertexIndexMap > class degreelists_marker { public: typedef SignedInteger value_type; typedef typename std::vector< value_type >::size_type size_type; degreelists_marker(size_type n, VertexIndexMap id) : marks(n, 0), id(id) { } void mark_need_update(Vertex i) { marks[get(id, i)] = 1; } bool need_update(Vertex i) { return marks[get(id, i)] == 1; } bool outmatched_or_done(Vertex i) { return marks[get(id, i)] == -1; } void mark(Vertex i) { marks[get(id, i)] = -1; } void unmark(Vertex i) { marks[get(id, i)] = 0; } private: std::vector< value_type > marks; VertexIndexMap id; }; // Helper function object for edge removal template < class Graph, class MarkerP, class NumberD, class Stack, class VertexIndexMap > class predicateRemoveEdge1 { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::edge_descriptor edge_t; public: predicateRemoveEdge1(Graph& _g, MarkerP& _marker, NumberD _numbering, Stack& n_e, VertexIndexMap id) : g(&_g) , marker(&_marker) , numbering(_numbering) , neighbor_elements(&n_e) , id(id) { } bool operator()(edge_t e) { vertex_t dist = target(e, *g); if (marker->is_tagged(dist)) return true; marker->mark_tagged(dist); if (numbering.is_numbered(dist)) { neighbor_elements->push(get(id, dist)); return true; } return false; } private: Graph* g; MarkerP* marker; NumberD numbering; Stack* neighbor_elements; VertexIndexMap id; }; // Helper function object for edge removal template < class Graph, class MarkerP > class predicate_remove_tagged_edges { typedef typename graph_traits< Graph >::vertex_descriptor vertex_t; typedef typename graph_traits< Graph >::edge_descriptor edge_t; public: predicate_remove_tagged_edges(Graph& _g, MarkerP& _marker) : g(&_g), marker(&_marker) { } bool operator()(edge_t e) { vertex_t dist = target(e, *g); if (marker->is_tagged(dist)) return true; return false; } private: Graph* g; MarkerP* marker; }; template < class Graph, class DegreeMap, class InversePermutationMap, class PermutationMap, class SuperNodeMap, class VertexIndexMap > class mmd_impl { // Typedefs typedef graph_traits< Graph > Traits; typedef typename Traits::vertices_size_type size_type; typedef typename detail::integer_traits< size_type >::difference_type diff_t; typedef typename Traits::vertex_descriptor vertex_t; typedef typename Traits::adjacency_iterator adj_iter; typedef iterator_property_map< vertex_t*, identity_property_map, vertex_t, vertex_t& > IndexVertexMap; typedef detail::Stacks< diff_t > Workspace; typedef bucket_sorter< size_type, vertex_t, DegreeMap, VertexIndexMap > DegreeLists; typedef Numbering< InversePermutationMap, diff_t, vertex_t, VertexIndexMap > NumberingD; typedef degreelists_marker< diff_t, vertex_t, VertexIndexMap > DegreeListsMarker; typedef Marker< diff_t, vertex_t, VertexIndexMap > MarkerP; // Data Members bool has_no_edges; // input parameters Graph& G; int delta; DegreeMap degree; InversePermutationMap inverse_perm; PermutationMap perm; SuperNodeMap supernode_size; VertexIndexMap vertex_index_map; // internal data-structures std::vector< vertex_t > index_vertex_vec; size_type n; IndexVertexMap index_vertex_map; DegreeLists degreelists; NumberingD numbering; DegreeListsMarker degree_lists_marker; MarkerP marker; Workspace work_space; public: mmd_impl(Graph& g, size_type n_, int delta, DegreeMap degree, InversePermutationMap inverse_perm, PermutationMap perm, SuperNodeMap supernode_size, VertexIndexMap id) : has_no_edges(true) , G(g) , delta(delta) , degree(degree) , inverse_perm(inverse_perm) , perm(perm) , supernode_size(supernode_size) , vertex_index_map(id) , index_vertex_vec(n_) , n(n_) , degreelists(n_ + 1, n_, degree, id) , numbering(inverse_perm, n_, vertex_index_map) , degree_lists_marker(n_, vertex_index_map) , marker(n_, vertex_index_map) , work_space(n_) { typename graph_traits< Graph >::vertex_iterator v, vend; size_type vid = 0; for (boost::tie(v, vend) = vertices(G); v != vend; ++v, ++vid) index_vertex_vec[vid] = *v; index_vertex_map = IndexVertexMap(&index_vertex_vec[0]); // Initialize degreelists. Degreelists organizes the nodes // according to their degree. for (boost::tie(v, vend) = vertices(G); v != vend; ++v) { typename Traits::degree_size_type d = out_degree(*v, G); put(degree, *v, d); if (0 < d) has_no_edges = false; degreelists.push(*v); } } void do_mmd() { // Eliminate the isolated nodes -- these are simply the nodes // with no neighbors, which are accessible as a list (really, a // stack) at location 0. Since these don't affect any other // nodes, we can eliminate them without doing degree updates. typename DegreeLists::stack list_isolated = degreelists[0]; while (!list_isolated.empty()) { vertex_t node = list_isolated.top(); marker.mark_done(node); numbering(node); numbering.increment(); list_isolated.pop(); } if (has_no_edges) { return; } size_type min_degree = 1; typename DegreeLists::stack list_min_degree = degreelists[min_degree]; while (list_min_degree.empty()) { ++min_degree; list_min_degree = degreelists[min_degree]; } // check if the whole eliminating process is done while (!numbering.all_done()) { size_type min_degree_limit = min_degree + delta; // WARNING typename Workspace::stack llist = work_space.make_stack(); // multiple elimination while (delta >= 0) { // Find the next non-empty degree for (list_min_degree = degreelists[min_degree]; list_min_degree.empty() && min_degree <= min_degree_limit; ++min_degree, list_min_degree = degreelists[min_degree]) ; if (min_degree > min_degree_limit) break; const vertex_t node = list_min_degree.top(); const size_type node_id = get(vertex_index_map, node); list_min_degree.pop(); numbering(node); // check if node is the last one if (numbering.all_done(supernode_size[node])) { numbering.increment(supernode_size[node]); break; } marker.increment_tag(); marker.mark_tagged(node); this->eliminate(node); numbering.increment(supernode_size[node]); llist.push(node_id); } // multiple elimination if (numbering.all_done()) break; this->update(llist, min_degree); } } // do_mmd() void eliminate(vertex_t node) { typename Workspace::stack element_neighbor = work_space.make_stack(); // Create two function objects for edge removal typedef typename Workspace::stack WorkStack; predicateRemoveEdge1< Graph, MarkerP, NumberingD, WorkStack, VertexIndexMap > p(G, marker, numbering, element_neighbor, vertex_index_map); predicate_remove_tagged_edges< Graph, MarkerP > p2(G, marker); // Reconstruct the adjacent node list, push element neighbor in a // List. remove_out_edge_if(node, p, G); // during removal element neighbors are collected. while (!element_neighbor.empty()) { // element absorb size_type e_id = element_neighbor.top(); vertex_t element = get(index_vertex_map, e_id); adj_iter i, i_end; for (boost::tie(i, i_end) = adjacent_vertices(element, G); i != i_end; ++i) { vertex_t i_node = *i; if (!marker.is_tagged(i_node) && !numbering.is_numbered(i_node)) { marker.mark_tagged(i_node); add_edge(node, i_node, G); } } element_neighbor.pop(); } adj_iter v, ve; for (boost::tie(v, ve) = adjacent_vertices(node, G); v != ve; ++v) { vertex_t v_node = *v; if (!degree_lists_marker.need_update(v_node) && !degree_lists_marker.outmatched_or_done(v_node)) { degreelists.remove(v_node); } // update out edges of v_node remove_out_edge_if(v_node, p2, G); if (out_degree(v_node, G) == 0) { // indistinguishable nodes supernode_size[node] += supernode_size[v_node]; supernode_size[v_node] = 0; numbering.indistinguishable(v_node, node); marker.mark_done(v_node); degree_lists_marker.mark(v_node); } else { // not indistinguishable nodes add_edge(v_node, node, G); degree_lists_marker.mark_need_update(v_node); } } } // eliminate() template < class Stack > void update(Stack llist, size_type& min_degree) { size_type min_degree0 = min_degree + delta + 1; while (!llist.empty()) { size_type deg, deg0 = 0; marker.set_multiple_tag(min_degree0); typename Workspace::stack q2list = work_space.make_stack(); typename Workspace::stack qxlist = work_space.make_stack(); vertex_t current = get(index_vertex_map, llist.top()); adj_iter i, ie; for (boost::tie(i, ie) = adjacent_vertices(current, G); i != ie; ++i) { vertex_t i_node = *i; const size_type i_id = get(vertex_index_map, i_node); if (supernode_size[i_node] != 0) { deg0 += supernode_size[i_node]; marker.mark_multiple_tagged(i_node); if (degree_lists_marker.need_update(i_node)) { if (out_degree(i_node, G) == 2) q2list.push(i_id); else qxlist.push(i_id); } } } while (!q2list.empty()) { const size_type u_id = q2list.top(); vertex_t u_node = get(index_vertex_map, u_id); // if u_id is outmatched by others, no need to update degree if (degree_lists_marker.outmatched_or_done(u_node)) { q2list.pop(); continue; } marker.increment_tag(); deg = deg0; adj_iter nu = adjacent_vertices(u_node, G).first; vertex_t neighbor = *nu; if (neighbor == u_node) { ++nu; neighbor = *nu; } if (numbering.is_numbered(neighbor)) { adj_iter i, ie; for (boost::tie(i, ie) = adjacent_vertices(neighbor, G); i != ie; ++i) { const vertex_t i_node = *i; if (i_node == u_node || supernode_size[i_node] == 0) continue; if (marker.is_tagged(i_node)) { if (degree_lists_marker.need_update(i_node)) { if (out_degree(i_node, G) == 2) { // is indistinguishable supernode_size[u_node] += supernode_size[i_node]; supernode_size[i_node] = 0; numbering.indistinguishable( i_node, u_node); marker.mark_done(i_node); degree_lists_marker.mark(i_node); } else // is outmatched degree_lists_marker.mark(i_node); } } else { marker.mark_tagged(i_node); deg += supernode_size[i_node]; } } } else deg += supernode_size[neighbor]; deg -= supernode_size[u_node]; degree[u_node] = deg; // update degree degreelists[deg].push(u_node); // u_id has been pushed back into degreelists degree_lists_marker.unmark(u_node); if (min_degree > deg) min_degree = deg; q2list.pop(); } // while (!q2list.empty()) while (!qxlist.empty()) { const size_type u_id = qxlist.top(); const vertex_t u_node = get(index_vertex_map, u_id); // if u_id is outmatched by others, no need to update degree if (degree_lists_marker.outmatched_or_done(u_node)) { qxlist.pop(); continue; } marker.increment_tag(); deg = deg0; adj_iter i, ie; for (boost::tie(i, ie) = adjacent_vertices(u_node, G); i != ie; ++i) { vertex_t i_node = *i; if (marker.is_tagged(i_node)) continue; marker.mark_tagged(i_node); if (numbering.is_numbered(i_node)) { adj_iter j, je; for (boost::tie(j, je) = adjacent_vertices(i_node, G); j != je; ++j) { const vertex_t j_node = *j; if (marker.is_not_tagged(j_node)) { marker.mark_tagged(j_node); deg += supernode_size[j_node]; } } } else deg += supernode_size[i_node]; } // for adjacent vertices of u_node deg -= supernode_size[u_node]; degree[u_node] = deg; degreelists[deg].push(u_node); // u_id has been pushed back into degreelists degree_lists_marker.unmark(u_node); if (min_degree > deg) min_degree = deg; qxlist.pop(); } // while (!qxlist.empty()) { marker.set_tag_as_multiple_tag(); llist.pop(); } // while (! llist.empty()) } // update() void build_permutation(InversePermutationMap next, PermutationMap prev) { // collect the permutation info size_type i; for (i = 0; i < n; ++i) { diff_t size = supernode_size[get(index_vertex_map, i)]; if (size <= 0) { prev[i] = next[i]; supernode_size[get(index_vertex_map, i)] = next[i] + 1; // record the supernode info } else prev[i] = -next[i]; } for (i = 1; i < n + 1; ++i) { if (prev[i - 1] > 0) continue; diff_t parent = i; while (prev[parent - 1] < 0) { parent = -prev[parent - 1]; } diff_t root = parent; diff_t num = prev[root - 1] + 1; next[i - 1] = -num; prev[root - 1] = num; parent = i; diff_t next_node = -prev[parent - 1]; while (next_node > 0) { prev[parent - 1] = -root; parent = next_node; next_node = -prev[parent - 1]; } } for (i = 0; i < n; i++) { diff_t num = -next[i] - 1; next[i] = num; prev[num] = i; } } // build_permutation() }; } // namespace detail // MMD algorithm // // The implementation presently includes the enhancements for mass // elimination, incomplete degree update, multiple elimination, and // external degree. // // Important Note: This implementation requires the BGL graph to be // directed. Therefore, nonzero entry (i, j) in a symmetrical matrix // A coresponds to two directed edges (i->j and j->i). // // see Alan George and Joseph W. H. Liu, The Evolution of the Minimum // Degree Ordering Algorithm, SIAM Review, 31, 1989, Page 1-19 template < class Graph, class DegreeMap, class InversePermutationMap, class PermutationMap, class SuperNodeMap, class VertexIndexMap > void minimum_degree_ordering(Graph& G, DegreeMap degree, InversePermutationMap inverse_perm, PermutationMap perm, SuperNodeMap supernode_size, int delta, VertexIndexMap vertex_index_map) { detail::mmd_impl< Graph, DegreeMap, InversePermutationMap, PermutationMap, SuperNodeMap, VertexIndexMap > impl(G, num_vertices(G), delta, degree, inverse_perm, perm, supernode_size, vertex_index_map); impl.do_mmd(); impl.build_permutation(inverse_perm, perm); } } // namespace boost #endif // BOOST_GRAPH_MINIMUM_DEGREE_ORDERING_HPP sloan_ordering.hpp 0000644 00000036264 15125521275 0010302 0 ustar 00 // //======================================================================= // Copyright 2002 Marc Wintermantel (wintermantel@even-ag.ch) // ETH Zurich, Center of Structure Technologies // (https://web.archive.org/web/20050307090307/http://www.structures.ethz.ch/) // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_SLOAN_HPP #define BOOST_GRAPH_SLOAN_HPP #define WEIGHT1 1 // default weight for the distance in the Sloan algorithm #define WEIGHT2 2 // default weight for the degree in the Sloan algorithm #include <boost/config.hpp> #include <vector> #include <queue> #include <algorithm> #include <limits> #include <boost/pending/queue.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/properties.hpp> #include <boost/pending/indirect_cmp.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/visitors.hpp> #include <boost/graph/adjacency_list.hpp> #include <boost/graph/cuthill_mckee_ordering.hpp> //////////////////////////////////////////////////////////// // // Sloan-Algorithm for graph reordering //(optimzes profile and wavefront, not primiraly bandwidth // //////////////////////////////////////////////////////////// namespace boost { ///////////////////////////////////////////////////////////////////////// // Function that returns the maximum depth of // a rooted level strucutre (RLS) // ///////////////////////////////////////////////////////////////////////// template < class Distance > typename Distance::value_type RLS_depth(Distance& d) { typename Distance::value_type h_s = 0; typename Distance::iterator iter; for (iter = d.begin(); iter != d.end(); ++iter) { if (*iter > h_s) { h_s = *iter; } } return h_s; } ///////////////////////////////////////////////////////////////////////// // Function that returns the width of the largest level of // a rooted level strucutre (RLS) // ///////////////////////////////////////////////////////////////////////// template < class Distance, class my_int > typename Distance::value_type RLS_max_width(Distance& d, my_int depth) { typedef typename Distance::value_type Degree; // Searching for the maximum width of a level std::vector< Degree > dummy_width(depth + 1, 0); typename std::vector< Degree >::iterator my_it; typename Distance::iterator iter; Degree w_max = 0; for (iter = d.begin(); iter != d.end(); ++iter) { dummy_width[*iter]++; } for (my_it = dummy_width.begin(); my_it != dummy_width.end(); ++my_it) { if (*my_it > w_max) w_max = *my_it; } return w_max; } ///////////////////////////////////////////////////////////////////////// // Function for finding a good starting node for Sloan algorithm // // This is to find a good starting node. "good" is in the sense // of the ordering generated. ///////////////////////////////////////////////////////////////////////// template < class Graph, class ColorMap, class DegreeMap > typename graph_traits< Graph >::vertex_descriptor sloan_start_end_vertices( Graph& G, typename graph_traits< Graph >::vertex_descriptor& s, ColorMap color, DegreeMap degree) { typedef typename property_traits< DegreeMap >::value_type Degree; typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename std::vector< typename graph_traits< Graph >::vertices_size_type >::iterator vec_iter; typedef typename graph_traits< Graph >::vertices_size_type size_type; typedef typename property_map< Graph, vertex_index_t >::const_type VertexID; s = *(vertices(G).first); Vertex e = s; Vertex i; Degree my_degree = get(degree, s); Degree dummy, h_i, h_s, w_i, w_e; bool new_start = true; Degree maximum_degree = 0; // Creating a std-vector for storing the distance from the start vertex in // dist std::vector< typename graph_traits< Graph >::vertices_size_type > dist( num_vertices(G), 0); // Wrap a property_map_iterator around the std::iterator boost::iterator_property_map< vec_iter, VertexID, size_type, size_type& > dist_pmap(dist.begin(), get(vertex_index, G)); // Creating a property_map for the indices of a vertex typename property_map< Graph, vertex_index_t >::type index_map = get(vertex_index, G); // Creating a priority queue typedef indirect_cmp< DegreeMap, std::greater< Degree > > Compare; Compare comp(degree); std::priority_queue< Vertex, std::vector< Vertex >, Compare > degree_queue( comp); // step 1 // Scan for the vertex with the smallest degree and the maximum degree typename graph_traits< Graph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(G); ui != ui_end; ++ui) { dummy = get(degree, *ui); if (dummy < my_degree) { my_degree = dummy; s = *ui; } if (dummy > maximum_degree) { maximum_degree = dummy; } } // end 1 do { new_start = false; // Setting the loop repetition status to false // step 2 // initialize the the disance std-vector with 0 for (typename std::vector< typename graph_traits< Graph >::vertices_size_type >::iterator iter = dist.begin(); iter != dist.end(); ++iter) *iter = 0; // generating the RLS (rooted level structure) breadth_first_search(G, s, visitor( make_bfs_visitor(record_distances(dist_pmap, on_tree_edge())))); // end 2 // step 3 // calculating the depth of the RLS h_s = RLS_depth(dist); // step 4 // pushing one node of each degree in an ascending manner into // degree_queue std::vector< bool > shrink_trace(maximum_degree, false); for (boost::tie(ui, ui_end) = vertices(G); ui != ui_end; ++ui) { dummy = get(degree, *ui); if ((dist[index_map[*ui]] == h_s) && (!shrink_trace[dummy])) { degree_queue.push(*ui); shrink_trace[dummy] = true; } } // end 3 & 4 // step 5 // Initializing w w_e = (std::numeric_limits< Degree >::max)(); // end 5 // step 6 // Testing for termination while (!degree_queue.empty()) { i = degree_queue.top(); // getting the node with the lowest degree // from the degree queue degree_queue.pop(); // ereasing the node with the lowest degree from // the degree queue // generating a RLS for (typename std::vector< typename graph_traits< Graph >::vertices_size_type >::iterator iter = dist.begin(); iter != dist.end(); ++iter) *iter = 0; breadth_first_search(G, i, boost::visitor(make_bfs_visitor( record_distances(dist_pmap, on_tree_edge())))); // Calculating depth and width of the rooted level h_i = RLS_depth(dist); w_i = RLS_max_width(dist, h_i); // Testing for termination if ((h_i > h_s) && (w_i < w_e)) { h_s = h_i; s = i; while (!degree_queue.empty()) degree_queue.pop(); new_start = true; } else if (w_i < w_e) { w_e = w_i; e = i; } } // end 6 } while (new_start); return e; } ////////////////////////////////////////////////////////////////////////// // Sloan algorithm with a given starting Vertex. // // This algorithm requires user to provide a starting vertex to // compute Sloan ordering. ////////////////////////////////////////////////////////////////////////// template < class Graph, class OutputIterator, class ColorMap, class DegreeMap, class PriorityMap, class Weight > OutputIterator sloan_ordering(Graph& g, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor e, OutputIterator permutation, ColorMap color, DegreeMap degree, PriorityMap priority, Weight W1, Weight W2) { // typedef typename property_traits<DegreeMap>::value_type Degree; typedef typename property_traits< PriorityMap >::value_type Degree; typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename std::vector< typename graph_traits< Graph >::vertices_size_type >::iterator vec_iter; typedef typename graph_traits< Graph >::vertices_size_type size_type; typedef typename property_map< Graph, vertex_index_t >::const_type VertexID; // Creating a std-vector for storing the distance from the end vertex in it typename std::vector< typename graph_traits< Graph >::vertices_size_type > dist(num_vertices(g), 0); // Wrap a property_map_iterator around the std::iterator boost::iterator_property_map< vec_iter, VertexID, size_type, size_type& > dist_pmap(dist.begin(), get(vertex_index, g)); breadth_first_search(g, e, visitor(make_bfs_visitor(record_distances(dist_pmap, on_tree_edge())))); // Creating a property_map for the indices of a vertex typename property_map< Graph, vertex_index_t >::type index_map = get(vertex_index, g); // Sets the color and priority to their initial status Degree cdeg; typename graph_traits< Graph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { put(color, *ui, Color::white()); cdeg = get(degree, *ui) + 1; put(priority, *ui, W1 * dist[index_map[*ui]] - W2 * cdeg); } // Priority list typedef indirect_cmp< PriorityMap, std::greater< Degree > > Compare; Compare comp(priority); std::list< Vertex > priority_list; // Some more declarations typename graph_traits< Graph >::out_edge_iterator ei, ei_end, ei2, ei2_end; Vertex u, v, w; put(color, s, Color::green()); // Sets the color of the starting vertex to gray priority_list.push_front(s); // Puts s into the priority_list while (!priority_list.empty()) { priority_list.sort(comp); // Orders the elements in the priority list in // an ascending manner u = priority_list .front(); // Accesses the last element in the priority list priority_list .pop_front(); // Removes the last element in the priority list if (get(color, u) == Color::green()) { // for-loop over all out-edges of vertex u for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) { v = target(*ei, g); put(priority, v, get(priority, v) + W2); // updates the priority if (get(color, v) == Color::white()) // test if the vertex is inactive { put(color, v, Color::green()); // giving the vertex a preactive status priority_list.push_front( v); // writing the vertex in the priority_queue } } } // Here starts step 8 *permutation++ = u; // Puts u to the first position in the permutation-vector put(color, u, Color::black()); // Gives u an inactive status // for loop over all the adjacent vertices of u for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) { v = target(*ei, g); if (get(color, v) == Color::green()) { // tests if the vertex is inactive put(color, v, Color::red()); // giving the vertex an active status put(priority, v, get(priority, v) + W2); // updates the priority // for loop over alll adjacent vertices of v for (boost::tie(ei2, ei2_end) = out_edges(v, g); ei2 != ei2_end; ++ei2) { w = target(*ei2, g); if (get(color, w) != Color::black()) { // tests if vertex is postactive put(priority, w, get(priority, w) + W2); // updates the priority if (get(color, w) == Color::white()) { put(color, w, Color::green()); // gives the vertex a // preactive status priority_list.push_front( w); // puts the vertex into the priority queue } // end if } // end if } // end for } // end if } // end for } // end while return permutation; } ///////////////////////////////////////////////////////////////////////////////////////// // Same algorithm as before, but without the weights given (taking default // weights template < class Graph, class OutputIterator, class ColorMap, class DegreeMap, class PriorityMap > OutputIterator sloan_ordering(Graph& g, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor e, OutputIterator permutation, ColorMap color, DegreeMap degree, PriorityMap priority) { return sloan_ordering( g, s, e, permutation, color, degree, priority, WEIGHT1, WEIGHT2); } ////////////////////////////////////////////////////////////////////////// // Sloan algorithm without a given starting Vertex. // // This algorithm finds a good starting vertex itself to // compute Sloan-ordering. ////////////////////////////////////////////////////////////////////////// template < class Graph, class OutputIterator, class Color, class Degree, class Priority, class Weight > inline OutputIterator sloan_ordering(Graph& G, OutputIterator permutation, Color color, Degree degree, Priority priority, Weight W1, Weight W2) { typedef typename boost::graph_traits< Graph >::vertex_descriptor Vertex; Vertex s, e; e = sloan_start_end_vertices(G, s, color, degree); return sloan_ordering( G, s, e, permutation, color, degree, priority, W1, W2); } ///////////////////////////////////////////////////////////////////////////////////////// // Same as before, but without given weights (default weights are taken instead) template < class Graph, class OutputIterator, class Color, class Degree, class Priority > inline OutputIterator sloan_ordering(Graph& G, OutputIterator permutation, Color color, Degree degree, Priority priority) { return sloan_ordering( G, permutation, color, degree, priority, WEIGHT1, WEIGHT2); } } // namespace boost #endif // BOOST_GRAPH_SLOAN_HPP simple_point.hpp 0000644 00000001164 15125521275 0007766 0 ustar 00 //======================================================================= // Copyright 2005 Trustees of Indiana University // Authors: Andrew Lumsdaine, Douglas Gregor // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_SIMPLE_POINT_HPP #define BOOST_GRAPH_SIMPLE_POINT_HPP namespace boost { template < typename T > struct simple_point { T x; T y; }; } // end namespace boost #endif // BOOST_GRAPH_SIMPLE_POINT_HPP plod_generator.hpp 0000644 00000017034 15125521275 0010273 0 ustar 00 // Copyright 2004-2006 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_PLOD_GENERATOR_HPP #define BOOST_GRAPH_PLOD_GENERATOR_HPP #include <iterator> #include <utility> #include <boost/random/uniform_int.hpp> #include <boost/shared_ptr.hpp> #include <boost/graph/graph_traits.hpp> #include <vector> #include <map> #include <boost/config/no_tr1/cmath.hpp> #include <boost/mpl/if.hpp> namespace boost { template < typename RandomGenerator > class out_directed_plod_iterator { public: typedef std::forward_iterator_tag iterator_category; typedef std::pair< std::size_t, std::size_t > value_type; typedef const value_type& reference; typedef const value_type* pointer; typedef std::ptrdiff_t difference_type; out_directed_plod_iterator() : gen(0), at_end(true) {} out_directed_plod_iterator(RandomGenerator& gen, std::size_t n, double alpha, double beta, bool allow_self_loops) : gen(&gen) , n(n) , alpha(alpha) , beta(beta) , allow_self_loops(allow_self_loops) , at_end(false) , degree(0) , current(0, 0) { using std::pow; uniform_int< std::size_t > x(0, n - 1); std::size_t xv = x(gen); degree = (xv == 0 ? 0 : std::size_t(beta * pow(xv, -alpha))); } reference operator*() const { return current; } pointer operator->() const { return ¤t; } out_directed_plod_iterator& operator++() { using std::pow; uniform_int< std::size_t > x(0, n - 1); // Continue stepping through source nodes until the // (out)degree is > 0 while (degree == 0) { // Step to the next source node. If we've gone past the // number of nodes we're responsible for, we're done. if (++current.first >= n) { at_end = true; return *this; } std::size_t xv = x(*gen); degree = (xv == 0 ? 0 : std::size_t(beta * pow(xv, -alpha))); } do { current.second = x(*gen); } while (current.first == current.second && !allow_self_loops); --degree; return *this; } out_directed_plod_iterator operator++(int) { out_directed_plod_iterator temp(*this); ++(*this); return temp; } bool operator==(const out_directed_plod_iterator& other) const { return at_end == other.at_end; } bool operator!=(const out_directed_plod_iterator& other) const { return !(*this == other); } private: RandomGenerator* gen; std::size_t n; double alpha; double beta; bool allow_self_loops; bool at_end; std::size_t degree; value_type current; }; template < typename RandomGenerator > class undirected_plod_iterator { typedef std::vector< std::pair< std::size_t, std::size_t > > out_degrees_t; public: typedef std::input_iterator_tag iterator_category; typedef std::pair< std::size_t, std::size_t > value_type; typedef const value_type& reference; typedef const value_type* pointer; typedef std::ptrdiff_t difference_type; undirected_plod_iterator() : gen(0), out_degrees(), degrees_left(0), allow_self_loops(false) { } undirected_plod_iterator(RandomGenerator& gen, std::size_t n, double alpha, double beta, bool allow_self_loops = false) : gen(&gen) , n(n) , out_degrees(new out_degrees_t) , degrees_left(0) , allow_self_loops(allow_self_loops) { using std::pow; uniform_int< std::size_t > x(0, n - 1); for (std::size_t i = 0; i != n; ++i) { std::size_t xv = x(gen); std::size_t degree = (xv == 0 ? 0 : std::size_t(beta * pow(xv, -alpha))); if (degree == 0) degree = 1; else if (degree >= n) degree = n - 1; out_degrees->push_back(std::make_pair(i, degree)); degrees_left += degree; } next(); } reference operator*() const { return current; } pointer operator->() const { return ¤t; } undirected_plod_iterator& operator++() { next(); return *this; } undirected_plod_iterator operator++(int) { undirected_plod_iterator temp(*this); ++(*this); return temp; } bool operator==(const undirected_plod_iterator& other) const { return degrees_left == other.degrees_left; } bool operator!=(const undirected_plod_iterator& other) const { return !(*this == other); } private: void next() { std::size_t source, target; while (true) { /* We may get to the point where we can't actually find any new edges, so we just add some random edge and set the degrees left = 0 to signal termination. */ if (out_degrees->size() < 2) { uniform_int< std::size_t > x(0, n - 1); current.first = x(*gen); do { current.second = x(*gen); } while (current.first == current.second && !allow_self_loops); degrees_left = 0; out_degrees->clear(); return; } uniform_int< std::size_t > x(0, out_degrees->size() - 1); // Select source vertex source = x(*gen); if ((*out_degrees)[source].second == 0) { (*out_degrees)[source] = out_degrees->back(); out_degrees->pop_back(); continue; } // Select target vertex target = x(*gen); if ((*out_degrees)[target].second == 0) { (*out_degrees)[target] = out_degrees->back(); out_degrees->pop_back(); continue; } else if (source != target || (allow_self_loops && (*out_degrees)[source].second > 2)) { break; } } // Update degree counts --(*out_degrees)[source].second; --degrees_left; --(*out_degrees)[target].second; --degrees_left; current.first = (*out_degrees)[source].first; current.second = (*out_degrees)[target].first; } RandomGenerator* gen; std::size_t n; shared_ptr< out_degrees_t > out_degrees; std::size_t degrees_left; bool allow_self_loops; value_type current; }; template < typename RandomGenerator, typename Graph > class plod_iterator : public mpl::if_< is_convertible< typename graph_traits< Graph >::directed_category, directed_tag >, out_directed_plod_iterator< RandomGenerator >, undirected_plod_iterator< RandomGenerator > >::type { typedef typename mpl::if_< is_convertible< typename graph_traits< Graph >::directed_category, directed_tag >, out_directed_plod_iterator< RandomGenerator >, undirected_plod_iterator< RandomGenerator > >::type inherited; public: plod_iterator() : inherited() {} plod_iterator(RandomGenerator& gen, std::size_t n, double alpha, double beta, bool allow_self_loops = false) : inherited(gen, n, alpha, beta, allow_self_loops) { } }; } // end namespace boost #endif // BOOST_GRAPH_PLOD_GENERATOR_HPP kamada_kawai_spring_layout.hpp 0000644 00000066620 15125521275 0012645 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_KAMADA_KAWAI_SPRING_LAYOUT_HPP #define BOOST_GRAPH_KAMADA_KAWAI_SPRING_LAYOUT_HPP #include <boost/graph/graph_traits.hpp> #include <boost/graph/topology.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/graph/johnson_all_pairs_shortest.hpp> #include <boost/type_traits/is_convertible.hpp> #include <utility> #include <iterator> #include <vector> #include <iostream> #include <boost/limits.hpp> #include <boost/config/no_tr1/cmath.hpp> namespace boost { namespace detail { namespace graph { /** * Denotes an edge or display area side length used to scale a * Kamada-Kawai drawing. */ template < bool Edge, typename T > struct edge_or_side { explicit edge_or_side(T value) : value(value) {} T value; }; /** * Compute the edge length from an edge length. This is trivial. */ template < typename Graph, typename DistanceMap, typename IndexMap, typename T > T compute_edge_length( const Graph&, DistanceMap, IndexMap, edge_or_side< true, T > length) { return length.value; } /** * Compute the edge length based on the display area side length. We do this by dividing the side length by the largest shortest distance between any two vertices in the graph. */ template < typename Graph, typename DistanceMap, typename IndexMap, typename T > T compute_edge_length(const Graph& g, DistanceMap distance, IndexMap index, edge_or_side< false, T > length) { T result(0); typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator; for (vertex_iterator ui = vertices(g).first, end = vertices(g).second; ui != end; ++ui) { vertex_iterator vi = ui; for (++vi; vi != end; ++vi) { T dij = distance[get(index, *ui)][get(index, *vi)]; if (dij > result) result = dij; } } return length.value / result; } /** * Dense linear solver for fixed-size matrices. */ template < std::size_t Size > struct linear_solver { // Indices in mat are (row, column) // template <typename Vec> // static Vec solve(double mat[Size][Size], Vec rhs); }; template <> struct linear_solver< 1 > { template < typename Vec > static Vec solve(double mat[1][1], Vec rhs) { return rhs / mat[0][0]; } }; // These are from http://en.wikipedia.org/wiki/Cramer%27s_rule template <> struct linear_solver< 2 > { template < typename Vec > static Vec solve(double mat[2][2], Vec rhs) { double denom = mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1]; double x_num = rhs[0] * mat[1][1] - rhs[1] * mat[0][1]; double y_num = mat[0][0] * rhs[1] - mat[1][0] * rhs[0]; Vec result; result[0] = x_num / denom; result[1] = y_num / denom; return result; } }; template <> struct linear_solver< 3 > { template < typename Vec > static Vec solve(double mat[3][3], Vec rhs) { double denom = mat[0][0] * (mat[1][1] * mat[2][2] - mat[2][1] * mat[1][2]) - mat[1][0] * (mat[0][1] * mat[2][2] - mat[2][1] * mat[0][2]) + mat[2][0] * (mat[0][1] * mat[1][2] - mat[1][1] * mat[0][2]); double x_num = rhs[0] * (mat[1][1] * mat[2][2] - mat[2][1] * mat[1][2]) - rhs[1] * (mat[0][1] * mat[2][2] - mat[2][1] * mat[0][2]) + rhs[2] * (mat[0][1] * mat[1][2] - mat[1][1] * mat[0][2]); double y_num = mat[0][0] * (rhs[1] * mat[2][2] - rhs[2] * mat[1][2]) - mat[1][0] * (rhs[0] * mat[2][2] - rhs[2] * mat[0][2]) + mat[2][0] * (rhs[0] * mat[1][2] - rhs[1] * mat[0][2]); double z_num = mat[0][0] * (mat[1][1] * rhs[2] - mat[2][1] * rhs[1]) - mat[1][0] * (mat[0][1] * rhs[2] - mat[2][1] * rhs[0]) + mat[2][0] * (mat[0][1] * rhs[1] - mat[1][1] * rhs[0]); Vec result; result[0] = x_num / denom; result[1] = y_num / denom; result[2] = z_num / denom; return result; } }; /** * Implementation of the Kamada-Kawai spring layout algorithm. */ template < typename Topology, typename Graph, typename PositionMap, typename WeightMap, typename EdgeOrSideLength, typename Done, typename VertexIndexMap, typename DistanceMatrix, typename SpringStrengthMatrix, typename PartialDerivativeMap > struct kamada_kawai_spring_layout_impl { typedef typename property_traits< WeightMap >::value_type weight_type; typedef typename Topology::point_type Point; typedef typename Topology::point_difference_type point_difference_type; typedef point_difference_type deriv_type; typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; kamada_kawai_spring_layout_impl(const Topology& topology, const Graph& g, PositionMap position, WeightMap weight, EdgeOrSideLength edge_or_side_length, Done done, weight_type spring_constant, VertexIndexMap index, DistanceMatrix distance, SpringStrengthMatrix spring_strength, PartialDerivativeMap partial_derivatives) : topology(topology) , g(g) , position(position) , weight(weight) , edge_or_side_length(edge_or_side_length) , done(done) , spring_constant(spring_constant) , index(index) , distance(distance) , spring_strength(spring_strength) , partial_derivatives(partial_derivatives) { } // Compute contribution of vertex i to the first partial // derivatives (dE/dx_m, dE/dy_m) (for vertex m) deriv_type compute_partial_derivative( vertex_descriptor m, vertex_descriptor i) { #ifndef BOOST_NO_STDC_NAMESPACE using std::sqrt; #endif // BOOST_NO_STDC_NAMESPACE deriv_type result; if (i != m) { point_difference_type diff = topology.difference(position[m], position[i]); weight_type dist = topology.norm(diff); result = spring_strength[get(index, m)][get(index, i)] * (diff - distance[get(index, m)][get(index, i)] / dist * diff); } return result; } // Compute partial derivatives dE/dx_m and dE/dy_m deriv_type compute_partial_derivatives(vertex_descriptor m) { #ifndef BOOST_NO_STDC_NAMESPACE using std::sqrt; #endif // BOOST_NO_STDC_NAMESPACE deriv_type result; // TBD: looks like an accumulate to me BGL_FORALL_VERTICES_T(i, g, Graph) { deriv_type deriv = compute_partial_derivative(m, i); result += deriv; } return result; } // The actual Kamada-Kawai spring layout algorithm implementation bool run() { #ifndef BOOST_NO_STDC_NAMESPACE using std::sqrt; #endif // BOOST_NO_STDC_NAMESPACE // Compute d_{ij} and place it in the distance matrix if (!johnson_all_pairs_shortest_paths( g, distance, index, weight, weight_type(0))) return false; // Compute L based on side length (if needed), or retrieve L weight_type edge_length = detail::graph::compute_edge_length( g, distance, index, edge_or_side_length); // std::cerr << "edge_length = " << edge_length << std::endl; // Compute l_{ij} and k_{ij} const weight_type K = spring_constant; vertex_iterator ui, end; for (ui = vertices(g).first, end = vertices(g).second; ui != end; ++ui) { vertex_iterator vi = ui; for (++vi; vi != end; ++vi) { weight_type dij = distance[get(index, *ui)][get(index, *vi)]; if (dij == (std::numeric_limits< weight_type >::max)()) return false; distance[get(index, *ui)][get(index, *vi)] = edge_length * dij; distance[get(index, *vi)][get(index, *ui)] = edge_length * dij; spring_strength[get(index, *ui)][get(index, *vi)] = K / (dij * dij); spring_strength[get(index, *vi)][get(index, *ui)] = K / (dij * dij); } } // Compute Delta_i and find max vertex_descriptor p = *vertices(g).first; weight_type delta_p(0); for (ui = vertices(g).first, end = vertices(g).second; ui != end; ++ui) { deriv_type deriv = compute_partial_derivatives(*ui); put(partial_derivatives, *ui, deriv); weight_type delta = topology.norm(deriv); if (delta > delta_p) { p = *ui; delta_p = delta; } } while (!done(delta_p, p, g, true)) { // The contribution p makes to the partial derivatives of // each vertex. Computing this (at O(n) cost) allows us to // update the delta_i values in O(n) time instead of O(n^2) // time. std::vector< deriv_type > p_partials(num_vertices(g)); for (ui = vertices(g).first, end = vertices(g).second; ui != end; ++ui) { vertex_descriptor i = *ui; p_partials[get(index, i)] = compute_partial_derivative(i, p); } do { // For debugging, compute the energy value E double E = 0.; for (ui = vertices(g).first, end = vertices(g).second; ui != end; ++ui) { vertex_iterator vi = ui; for (++vi; vi != end; ++vi) { double dist = topology.distance( position[*ui], position[*vi]); weight_type k_ij = spring_strength[get( index, *ui)][get(index, *vi)]; weight_type l_ij = distance[get(index, *ui)] [get(index, *vi)]; E += .5 * k_ij * (dist - l_ij) * (dist - l_ij); } } // std::cerr << "E = " << E << std::endl; // Compute the elements of the Jacobian // From // http://www.cs.panam.edu/~rfowler/papers/1994_kumar_fowler_A_Spring_UTPACSTR.pdf // with the bugs fixed in the off-diagonal case weight_type dE_d_d[Point::dimensions] [Point::dimensions]; for (std::size_t i = 0; i < Point::dimensions; ++i) for (std::size_t j = 0; j < Point::dimensions; ++j) dE_d_d[i][j] = 0.; for (ui = vertices(g).first, end = vertices(g).second; ui != end; ++ui) { vertex_descriptor i = *ui; if (i != p) { point_difference_type diff = topology.difference( position[p], position[i]); weight_type dist = topology.norm(diff); weight_type dist_squared = dist * dist; weight_type inv_dist_cubed = 1. / (dist_squared * dist); weight_type k_mi = spring_strength[get( index, p)][get(index, i)]; weight_type l_mi = distance[get(index, p)][get(index, i)]; for (std::size_t i = 0; i < Point::dimensions; ++i) { for (std::size_t j = 0; j < Point::dimensions; ++j) { if (i == j) { dE_d_d[i][i] += k_mi * (1 + (l_mi * (diff[i] * diff[i] - dist_squared) * inv_dist_cubed)); } else { dE_d_d[i][j] += k_mi * l_mi * diff[i] * diff[j] * inv_dist_cubed; // dE_d_d[i][j] += k_mi * l_mi * // sqrt(hypot(diff[i], diff[j])) * // inv_dist_cubed; } } } } } deriv_type dE_d = get(partial_derivatives, p); // Solve dE_d_d * delta = -dE_d to get delta point_difference_type delta = -linear_solver< Point::dimensions >::solve( dE_d_d, dE_d); // Move p by delta position[p] = topology.adjust(position[p], delta); // Recompute partial derivatives and delta_p deriv_type deriv = compute_partial_derivatives(p); put(partial_derivatives, p, deriv); delta_p = topology.norm(deriv); } while (!done(delta_p, p, g, false)); // Select new p by updating each partial derivative and // delta vertex_descriptor old_p = p; for (ui = vertices(g).first, end = vertices(g).second; ui != end; ++ui) { deriv_type old_deriv_p = p_partials[get(index, *ui)]; deriv_type old_p_partial = compute_partial_derivative(*ui, old_p); deriv_type deriv = get(partial_derivatives, *ui); deriv += old_p_partial - old_deriv_p; put(partial_derivatives, *ui, deriv); weight_type delta = topology.norm(deriv); if (delta > delta_p) { p = *ui; delta_p = delta; } } } return true; } const Topology& topology; const Graph& g; PositionMap position; WeightMap weight; EdgeOrSideLength edge_or_side_length; Done done; weight_type spring_constant; VertexIndexMap index; DistanceMatrix distance; SpringStrengthMatrix spring_strength; PartialDerivativeMap partial_derivatives; }; } } // end namespace detail::graph /// States that the given quantity is an edge length. template < typename T > inline detail::graph::edge_or_side< true, T > edge_length(T x) { return detail::graph::edge_or_side< true, T >(x); } /// States that the given quantity is a display area side length. template < typename T > inline detail::graph::edge_or_side< false, T > side_length(T x) { return detail::graph::edge_or_side< false, T >(x); } /** * \brief Determines when to terminate layout of a particular graph based * on a given relative tolerance. */ template < typename T = double > struct layout_tolerance { layout_tolerance(const T& tolerance = T(0.001)) : tolerance(tolerance) , last_energy((std::numeric_limits< T >::max)()) , last_local_energy((std::numeric_limits< T >::max)()) { } template < typename Graph > bool operator()(T delta_p, typename boost::graph_traits< Graph >::vertex_descriptor p, const Graph& g, bool global) { if (global) { if (last_energy == (std::numeric_limits< T >::max)()) { last_energy = delta_p; return false; } T diff = last_energy - delta_p; if (diff < T(0)) diff = -diff; bool done = (delta_p == T(0) || diff / last_energy < tolerance); last_energy = delta_p; return done; } else { if (last_local_energy == (std::numeric_limits< T >::max)()) { last_local_energy = delta_p; return delta_p == T(0); } T diff = last_local_energy - delta_p; bool done = (delta_p == T(0) || (diff / last_local_energy) < tolerance); last_local_energy = delta_p; return done; } } private: T tolerance; T last_energy; T last_local_energy; }; /** \brief Kamada-Kawai spring layout for undirected graphs. * * This algorithm performs graph layout (in two dimensions) for * connected, undirected graphs. It operates by relating the layout * of graphs to a dynamic spring system and minimizing the energy * within that system. The strength of a spring between two vertices * is inversely proportional to the square of the shortest distance * (in graph terms) between those two vertices. Essentially, * vertices that are closer in the graph-theoretic sense (i.e., by * following edges) will have stronger springs and will therefore be * placed closer together. * * Prior to invoking this algorithm, it is recommended that the * vertices be placed along the vertices of a regular n-sided * polygon. * * \param g (IN) must be a model of Vertex List Graph, Edge List * Graph, and Incidence Graph and must be undirected. * * \param position (OUT) must be a model of Lvalue Property Map, * where the value type is a class containing fields @c x and @c y * that will be set to the @c x and @c y coordinates of each vertex. * * \param weight (IN) must be a model of Readable Property Map, * which provides the weight of each edge in the graph @p g. * * \param topology (IN) must be a topology object (see topology.hpp), * which provides operations on points and differences between them. * * \param edge_or_side_length (IN) provides either the unit length * @c e of an edge in the layout or the length of a side @c s of the * display area, and must be either @c boost::edge_length(e) or @c * boost::side_length(s), respectively. * * \param done (IN) is a 4-argument function object that is passed * the current value of delta_p (i.e., the energy of vertex @p p), * the vertex @p p, the graph @p g, and a boolean flag indicating * whether @p delta_p is the maximum energy in the system (when @c * true) or the energy of the vertex being moved. Defaults to @c * layout_tolerance instantiated over the value type of the weight * map. * * \param spring_constant (IN) is the constant multiplied by each * spring's strength. Larger values create systems with more energy * that can take longer to stabilize; smaller values create systems * with less energy that stabilize quickly but do not necessarily * result in pleasing layouts. The default value is 1. * * \param index (IN) is a mapping from vertices to index values * between 0 and @c num_vertices(g). The default is @c * get(vertex_index,g). * * \param distance (UTIL/OUT) will be used to store the distance * from every vertex to every other vertex, which is computed in the * first stages of the algorithm. This value's type must be a model * of BasicMatrix with value type equal to the value type of the * weight map. The default is a vector of vectors. * * \param spring_strength (UTIL/OUT) will be used to store the * strength of the spring between every pair of vertices. This * value's type must be a model of BasicMatrix with value type equal * to the value type of the weight map. The default is a vector of * vectors. * * \param partial_derivatives (UTIL) will be used to store the * partial derivates of each vertex with respect to the @c x and @c * y coordinates. This must be a Read/Write Property Map whose value * type is a pair with both types equivalent to the value type of * the weight map. The default is an iterator property map. * * \returns @c true if layout was successful or @c false if a * negative weight cycle was detected. */ template < typename Topology, typename Graph, typename PositionMap, typename WeightMap, typename T, bool EdgeOrSideLength, typename Done, typename VertexIndexMap, typename DistanceMatrix, typename SpringStrengthMatrix, typename PartialDerivativeMap > bool kamada_kawai_spring_layout(const Graph& g, PositionMap position, WeightMap weight, const Topology& topology, detail::graph::edge_or_side< EdgeOrSideLength, T > edge_or_side_length, Done done, typename property_traits< WeightMap >::value_type spring_constant, VertexIndexMap index, DistanceMatrix distance, SpringStrengthMatrix spring_strength, PartialDerivativeMap partial_derivatives) { BOOST_STATIC_ASSERT( (is_convertible< typename graph_traits< Graph >::directed_category*, undirected_tag* >::value)); detail::graph::kamada_kawai_spring_layout_impl< Topology, Graph, PositionMap, WeightMap, detail::graph::edge_or_side< EdgeOrSideLength, T >, Done, VertexIndexMap, DistanceMatrix, SpringStrengthMatrix, PartialDerivativeMap > alg(topology, g, position, weight, edge_or_side_length, done, spring_constant, index, distance, spring_strength, partial_derivatives); return alg.run(); } /** * \overload */ template < typename Topology, typename Graph, typename PositionMap, typename WeightMap, typename T, bool EdgeOrSideLength, typename Done, typename VertexIndexMap > bool kamada_kawai_spring_layout(const Graph& g, PositionMap position, WeightMap weight, const Topology& topology, detail::graph::edge_or_side< EdgeOrSideLength, T > edge_or_side_length, Done done, typename property_traits< WeightMap >::value_type spring_constant, VertexIndexMap index) { typedef typename property_traits< WeightMap >::value_type weight_type; typename graph_traits< Graph >::vertices_size_type n = num_vertices(g); typedef std::vector< weight_type > weight_vec; std::vector< weight_vec > distance(n, weight_vec(n)); std::vector< weight_vec > spring_strength(n, weight_vec(n)); std::vector< typename Topology::point_difference_type > partial_derivatives( n); return kamada_kawai_spring_layout(g, position, weight, topology, edge_or_side_length, done, spring_constant, index, distance.begin(), spring_strength.begin(), make_iterator_property_map(partial_derivatives.begin(), index, typename Topology::point_difference_type())); } /** * \overload */ template < typename Topology, typename Graph, typename PositionMap, typename WeightMap, typename T, bool EdgeOrSideLength, typename Done > bool kamada_kawai_spring_layout(const Graph& g, PositionMap position, WeightMap weight, const Topology& topology, detail::graph::edge_or_side< EdgeOrSideLength, T > edge_or_side_length, Done done, typename property_traits< WeightMap >::value_type spring_constant) { return kamada_kawai_spring_layout(g, position, weight, topology, edge_or_side_length, done, spring_constant, get(vertex_index, g)); } /** * \overload */ template < typename Topology, typename Graph, typename PositionMap, typename WeightMap, typename T, bool EdgeOrSideLength, typename Done > bool kamada_kawai_spring_layout(const Graph& g, PositionMap position, WeightMap weight, const Topology& topology, detail::graph::edge_or_side< EdgeOrSideLength, T > edge_or_side_length, Done done) { typedef typename property_traits< WeightMap >::value_type weight_type; return kamada_kawai_spring_layout(g, position, weight, topology, edge_or_side_length, done, weight_type(1)); } /** * \overload */ template < typename Topology, typename Graph, typename PositionMap, typename WeightMap, typename T, bool EdgeOrSideLength > bool kamada_kawai_spring_layout(const Graph& g, PositionMap position, WeightMap weight, const Topology& topology, detail::graph::edge_or_side< EdgeOrSideLength, T > edge_or_side_length) { typedef typename property_traits< WeightMap >::value_type weight_type; return kamada_kawai_spring_layout(g, position, weight, topology, edge_or_side_length, layout_tolerance< weight_type >(), weight_type(1.0), get(vertex_index, g)); } } // end namespace boost #endif // BOOST_GRAPH_KAMADA_KAWAI_SPRING_LAYOUT_HPP hawick_circuits.hpp 0000644 00000034401 15125521275 0010437 0 ustar 00 // Copyright Louis Dionne 2013 // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy // at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GRAPH_HAWICK_CIRCUITS_HPP #define BOOST_GRAPH_HAWICK_CIRCUITS_HPP #include <algorithm> #include <boost/assert.hpp> #include <boost/foreach.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/one_bit_color_map.hpp> #include <boost/graph/properties.hpp> #include <boost/move/utility.hpp> #include <boost/property_map/property_map.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/iterator.hpp> #include <boost/tuple/tuple.hpp> // for boost::tie #include <boost/type_traits/remove_reference.hpp> #include <boost/utility/result_of.hpp> #include <set> #include <utility> // for std::pair #include <vector> namespace boost { namespace hawick_circuits_detail { //! @internal Functor returning all the vertices adjacent to a vertex. struct get_all_adjacent_vertices { template < typename Sig > struct result; template < typename This, typename Vertex, typename Graph > struct result< This(Vertex, Graph) > { private: typedef typename remove_reference< Graph >::type RawGraph; typedef graph_traits< RawGraph > Traits; typedef typename Traits::adjacency_iterator AdjacencyIterator; public: typedef std::pair< AdjacencyIterator, AdjacencyIterator > type; }; template < typename Vertex, typename Graph > typename result< get_all_adjacent_vertices( BOOST_FWD_REF(Vertex), BOOST_FWD_REF(Graph)) >::type operator()(BOOST_FWD_REF(Vertex) v, BOOST_FWD_REF(Graph) g) const { return adjacent_vertices( boost::forward< Vertex >(v), boost::forward< Graph >(g)); } }; //! @internal Functor returning a set of the vertices adjacent to a vertex. struct get_unique_adjacent_vertices { template < typename Sig > struct result; template < typename This, typename Vertex, typename Graph > struct result< This(Vertex, Graph) > { typedef std::set< typename remove_reference< Vertex >::type > type; }; template < typename Vertex, typename Graph > typename result< get_unique_adjacent_vertices( Vertex, Graph const&) >::type operator()(Vertex v, Graph const& g) const { typedef typename result< get_unique_adjacent_vertices( Vertex, Graph const&) >::type Set; return Set( adjacent_vertices(v, g).first, adjacent_vertices(v, g).second); } }; //! @internal //! Return whether a container contains a given value. //! This is not meant as a general purpose membership testing function; it //! would have to be more clever about possible optimizations. template < typename Container, typename Value > bool contains(Container const& c, Value const& v) { return std::find(boost::begin(c), boost::end(c), v) != boost::end(c); } /*! * @internal * Algorithm finding all the cycles starting from a given vertex. * * The search is only done in the subgraph induced by the starting vertex * and the vertices with an index higher than the starting vertex. */ template < typename Graph, typename Visitor, typename VertexIndexMap, typename Stack, typename ClosedMatrix, typename GetAdjacentVertices > struct hawick_circuits_from { private: typedef graph_traits< Graph > Traits; typedef typename Traits::vertex_descriptor Vertex; typedef typename Traits::edge_descriptor Edge; typedef typename Traits::vertices_size_type VerticesSize; typedef typename property_traits< VertexIndexMap >::value_type VertexIndex; typedef typename result_of< GetAdjacentVertices( Vertex, Graph const&) >::type AdjacentVertices; typedef typename range_iterator< AdjacentVertices const >::type AdjacencyIterator; // The one_bit_color_map starts all white, i.e. not blocked. // Since we make that assumption (I looked at the implementation, but // I can't find anything that documents this behavior), we're gonna // assert it in the constructor. typedef one_bit_color_map< VertexIndexMap > BlockedMap; typedef typename property_traits< BlockedMap >::value_type BlockedColor; static BlockedColor blocked_false_color() { return color_traits< BlockedColor >::white(); } static BlockedColor blocked_true_color() { return color_traits< BlockedColor >::black(); } // This is used by the constructor to secure the assumption // documented above. bool blocked_map_starts_all_unblocked() const { BOOST_FOREACH (Vertex v, vertices(graph_)) if (is_blocked(v)) return false; return true; } // This is only used in the constructor to make sure the optimization of // sharing data structures between iterations does not break the code. bool all_closed_rows_are_empty() const { BOOST_FOREACH (typename ClosedMatrix::reference row, closed_) if (!row.empty()) return false; return true; } public: hawick_circuits_from(Graph const& graph, Visitor& visitor, VertexIndexMap const& vim, Stack& stack, ClosedMatrix& closed, VerticesSize n_vertices) : graph_(graph) , visitor_(visitor) , vim_(vim) , stack_(stack) , closed_(closed) , blocked_(n_vertices, vim_) { BOOST_ASSERT(blocked_map_starts_all_unblocked()); // Since sharing the data structures between iterations is // just an optimization, it must always be equivalent to // constructing new ones in this constructor. BOOST_ASSERT(stack_.empty()); BOOST_ASSERT(closed_.size() == n_vertices); BOOST_ASSERT(all_closed_rows_are_empty()); } private: //! @internal Return the index of a given vertex. VertexIndex index_of(Vertex v) const { return get(vim_, v); } //! @internal Return whether a vertex `v` is closed to a vertex `u`. bool is_closed_to(Vertex u, Vertex v) const { typedef typename ClosedMatrix::const_reference VertexList; VertexList closed_to_u = closed_[index_of(u)]; return contains(closed_to_u, v); } //! @internal Close a vertex `v` to a vertex `u`. void close_to(Vertex u, Vertex v) { BOOST_ASSERT(!is_closed_to(u, v)); closed_[index_of(u)].push_back(v); } //! @internal Return whether a given vertex is blocked. bool is_blocked(Vertex v) const { return get(blocked_, v) == blocked_true_color(); } //! @internal Block a given vertex. void block(Vertex v) { put(blocked_, v, blocked_true_color()); } //! @internal Unblock a given vertex. void unblock(Vertex u) { typedef typename ClosedMatrix::reference VertexList; put(blocked_, u, blocked_false_color()); VertexList closed_to_u = closed_[index_of(u)]; while (!closed_to_u.empty()) { Vertex const w = closed_to_u.back(); closed_to_u.pop_back(); if (is_blocked(w)) unblock(w); } BOOST_ASSERT(closed_to_u.empty()); } //! @internal Main procedure as described in the paper. bool circuit(Vertex start, Vertex v) { bool found_circuit = false; stack_.push_back(v); block(v); // Cache some values that are used more than once in the function. VertexIndex const index_of_start = index_of(start); AdjacentVertices const adj_vertices = GetAdjacentVertices()(v, graph_); AdjacencyIterator const w_end = boost::end(adj_vertices); for (AdjacencyIterator w_it = boost::begin(adj_vertices); w_it != w_end; ++w_it) { Vertex const w = *w_it; // Since we're only looking in the subgraph induced by `start` // and the vertices with an index higher than `start`, we skip // any vertex that does not satisfy that. if (index_of(w) < index_of_start) continue; // If the last vertex is equal to `start`, we have a circuit. else if (w == start) { // const_cast to ensure the visitor does not modify the // stack visitor_.cycle(const_cast< Stack const& >(stack_), graph_); found_circuit = true; } // If `w` is not blocked, we continue searching further down the // same path for a cycle with `w` in it. else if (!is_blocked(w) && circuit(start, w)) found_circuit = true; } if (found_circuit) unblock(v); else for (AdjacencyIterator w_it = boost::begin(adj_vertices); w_it != w_end; ++w_it) { Vertex const w = *w_it; // Like above, we skip vertices that are not in the subgraph // we're considering. if (index_of(w) < index_of_start) continue; // If `v` is not closed to `w`, we make it so. if (!is_closed_to(w, v)) close_to(w, v); } BOOST_ASSERT(v == stack_.back()); stack_.pop_back(); return found_circuit; } public: void operator()(Vertex start) { circuit(start, start); } private: Graph const& graph_; Visitor& visitor_; VertexIndexMap const& vim_; Stack& stack_; ClosedMatrix& closed_; BlockedMap blocked_; }; template < typename GetAdjacentVertices, typename Graph, typename Visitor, typename VertexIndexMap > void call_hawick_circuits(Graph const& graph, Visitor /* by value */ visitor, VertexIndexMap const& vertex_index_map) { typedef graph_traits< Graph > Traits; typedef typename Traits::vertex_descriptor Vertex; typedef typename Traits::vertices_size_type VerticesSize; typedef typename Traits::vertex_iterator VertexIterator; typedef std::vector< Vertex > Stack; typedef std::vector< std::vector< Vertex > > ClosedMatrix; typedef hawick_circuits_from< Graph, Visitor, VertexIndexMap, Stack, ClosedMatrix, GetAdjacentVertices > SubAlgorithm; VerticesSize const n_vertices = num_vertices(graph); Stack stack; stack.reserve(n_vertices); ClosedMatrix closed(n_vertices); VertexIterator start, last; for (boost::tie(start, last) = vertices(graph); start != last; ++start) { // Note1: The sub algorithm may NOT be reused once it has been // called. // Note2: We reuse the Stack and the ClosedMatrix (after clearing // them) in each iteration to avoid redundant destruction and // construction. It would be strictly equivalent to have these as // member variables of the sub algorithm. SubAlgorithm sub_algo( graph, visitor, vertex_index_map, stack, closed, n_vertices); sub_algo(*start); stack.clear(); typename ClosedMatrix::iterator row, last_row = closed.end(); for (row = closed.begin(); row != last_row; ++row) row->clear(); } } template < typename GetAdjacentVertices, typename Graph, typename Visitor > void call_hawick_circuits( Graph const& graph, BOOST_FWD_REF(Visitor) visitor) { call_hawick_circuits< GetAdjacentVertices >(graph, boost::forward< Visitor >(visitor), get(vertex_index, graph)); } } // end namespace hawick_circuits_detail //! Enumerate all the elementary circuits in a directed multigraph. template < typename Graph, typename Visitor, typename VertexIndexMap > void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor, BOOST_FWD_REF(VertexIndexMap) vertex_index_map) { hawick_circuits_detail::call_hawick_circuits< hawick_circuits_detail::get_all_adjacent_vertices >( boost::forward< Graph >(graph), boost::forward< Visitor >(visitor), boost::forward< VertexIndexMap >(vertex_index_map)); } template < typename Graph, typename Visitor > void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor) { hawick_circuits_detail::call_hawick_circuits< hawick_circuits_detail::get_all_adjacent_vertices >( boost::forward< Graph >(graph), boost::forward< Visitor >(visitor)); } /*! * Same as `boost::hawick_circuits`, but duplicate circuits caused by parallel * edges will not be considered. Each circuit will be considered only once. */ template < typename Graph, typename Visitor, typename VertexIndexMap > void hawick_unique_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor, BOOST_FWD_REF(VertexIndexMap) vertex_index_map) { hawick_circuits_detail::call_hawick_circuits< hawick_circuits_detail::get_unique_adjacent_vertices >( boost::forward< Graph >(graph), boost::forward< Visitor >(visitor), boost::forward< VertexIndexMap >(vertex_index_map)); } template < typename Graph, typename Visitor > void hawick_unique_circuits( BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor) { hawick_circuits_detail::call_hawick_circuits< hawick_circuits_detail::get_unique_adjacent_vertices >( boost::forward< Graph >(graph), boost::forward< Visitor >(visitor)); } } // end namespace boost #endif // !BOOST_GRAPH_HAWICK_CIRCUITS_HPP distributed/mpi_process_group.hpp 0000644 00000063740 15125521275 0013355 0 ustar 00 // Copyright (C) 2004-2008 The Trustees of Indiana University. // Copyright (C) 2007 Douglas Gregor // Copyright (C) 2007 Matthias Troyer <troyer@boost-consulting.com> // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Matthias Troyer // Andrew Lumsdaine #ifndef BOOST_GRAPH_DISTRIBUTED_MPI_PROCESS_GROUP #define BOOST_GRAPH_DISTRIBUTED_MPI_PROCESS_GROUP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif //#define NO_SPLIT_BATCHES #define SEND_OOB_BSEND #include <boost/optional.hpp> #include <boost/shared_ptr.hpp> #include <boost/weak_ptr.hpp> #include <utility> #include <memory> #include <boost/function/function1.hpp> #include <boost/function/function2.hpp> #include <boost/function/function0.hpp> #include <boost/mpi.hpp> #include <boost/property_map/parallel/process_group.hpp> #include <boost/serialization/vector.hpp> #include <boost/utility/enable_if.hpp> namespace boost { namespace graph { namespace distributed { // Process group tags struct mpi_process_group_tag : virtual boost::parallel::linear_process_group_tag { }; class mpi_process_group { struct impl; public: /// Number of tags available to each data structure. static const int max_tags = 256; /** * The type of a "receive" handler, that will be provided with * (source, tag) pairs when a message is received. Users can provide a * receive handler for a distributed data structure, for example, to * automatically pick up and respond to messages as needed. */ typedef function<void(int source, int tag)> receiver_type; /** * The type of a handler for the on-synchronize event, which will be * executed at the beginning of synchronize(). */ typedef function0<void> on_synchronize_event_type; /// Used as a tag to help create an "empty" process group. struct create_empty {}; /// The type used to buffer message data typedef boost::mpi::packed_oprimitive::buffer_type buffer_type; /// The type used to identify a process typedef int process_id_type; /// The type used to count the number of processes typedef int process_size_type; /// The type of communicator used to transmit data via MPI typedef boost::mpi::communicator communicator_type; /// Classification of the capabilities of this process group struct communication_category : virtual boost::parallel::bsp_process_group_tag, virtual mpi_process_group_tag { }; // TBD: We can eliminate the "source" field and possibly the // "offset" field. struct message_header { /// The process that sent the message process_id_type source; /// The message tag int tag; /// The offset of the message into the buffer std::size_t offset; /// The length of the message in the buffer, in bytes std::size_t bytes; template <class Archive> void serialize(Archive& ar, int) { ar & source & tag & offset & bytes; } }; /** * Stores the outgoing messages for a particular processor. * * @todo Evaluate whether we should use a deque instance, which * would reduce could reduce the cost of "sending" messages but * increases the time spent in the synchronization step. */ struct outgoing_messages { outgoing_messages() {} ~outgoing_messages() {} std::vector<message_header> headers; buffer_type buffer; template <class Archive> void serialize(Archive& ar, int) { ar & headers & buffer; } void swap(outgoing_messages& x) { headers.swap(x.headers); buffer.swap(x.buffer); } }; private: /** * Virtual base from which every trigger will be launched. See @c * trigger_launcher for more information. */ class trigger_base : boost::noncopyable { public: explicit trigger_base(int tag) : tag_(tag) { } /// Retrieve the tag associated with this trigger int tag() const { return tag_; } virtual ~trigger_base() { } /** * Invoked to receive a message that matches a particular trigger. * * @param source the source of the message * @param tag the (local) tag of the message * @param context the context under which the trigger is being * invoked */ virtual void receive(mpi_process_group const& pg, int source, int tag, trigger_receive_context context, int block=-1) const = 0; protected: // The message tag associated with this trigger int tag_; }; /** * Launches a specific handler in response to a trigger. This * function object wraps up the handler function object and a buffer * for incoming data. */ template<typename Type, typename Handler> class trigger_launcher : public trigger_base { public: explicit trigger_launcher(mpi_process_group& self, int tag, const Handler& handler) : trigger_base(tag), self(self), handler(handler) {} void receive(mpi_process_group const& pg, int source, int tag, trigger_receive_context context, int block=-1) const; private: mpi_process_group& self; mutable Handler handler; }; /** * Launches a specific handler with a message reply in response to a * trigger. This function object wraps up the handler function * object and a buffer for incoming data. */ template<typename Type, typename Handler> class reply_trigger_launcher : public trigger_base { public: explicit reply_trigger_launcher(mpi_process_group& self, int tag, const Handler& handler) : trigger_base(tag), self(self), handler(handler) {} void receive(mpi_process_group const& pg, int source, int tag, trigger_receive_context context, int block=-1) const; private: mpi_process_group& self; mutable Handler handler; }; template<typename Type, typename Handler> class global_trigger_launcher : public trigger_base { public: explicit global_trigger_launcher(mpi_process_group& self, int tag, const Handler& handler) : trigger_base(tag), handler(handler) { } void receive(mpi_process_group const& pg, int source, int tag, trigger_receive_context context, int block=-1) const; private: mutable Handler handler; // TBD: do not forget to cancel any outstanding Irecv when deleted, // if we decide to use Irecv }; template<typename Type, typename Handler> class global_irecv_trigger_launcher : public trigger_base { public: explicit global_irecv_trigger_launcher(mpi_process_group& self, int tag, const Handler& handler, int sz) : trigger_base(tag), handler(handler), buffer_size(sz) { prepare_receive(self,tag); } void receive(mpi_process_group const& pg, int source, int tag, trigger_receive_context context, int block=-1) const; private: void prepare_receive(mpi_process_group const& pg, int tag, bool force=false) const; Handler handler; int buffer_size; // TBD: do not forget to cancel any outstanding Irecv when deleted, // if we decide to use Irecv }; public: /** * Construct a new BSP process group from an MPI communicator. The * MPI communicator will be duplicated to create a new communicator * for this process group to use. */ mpi_process_group(communicator_type parent_comm = communicator_type()); /** * Construct a new BSP process group from an MPI communicator. The * MPI communicator will be duplicated to create a new communicator * for this process group to use. This constructor allows to tune the * size of message batches. * * @param num_headers The maximum number of headers in a message batch * * @param buffer_size The maximum size of the message buffer in a batch. * */ mpi_process_group( std::size_t num_headers, std::size_t buffer_size, communicator_type parent_comm = communicator_type()); /** * Construct a copy of the BSP process group for a new distributed * data structure. This data structure will synchronize with all * other members of the process group's equivalence class (including * @p other), but will have its own set of tags. * * @param other The process group that this new process group will * be based on, using a different set of tags within the same * communication and synchronization space. * * @param handler A message handler that will be passed (source, * tag) pairs for each message received by this data * structure. The handler is expected to receive the messages * immediately. The handler can be changed after-the-fact by * calling @c replace_handler. * * @param out_of_band_receive An anachronism. TODO: remove this. */ mpi_process_group(const mpi_process_group& other, const receiver_type& handler, bool out_of_band_receive = false); /** * Construct a copy of the BSP process group for a new distributed * data structure. This data structure will synchronize with all * other members of the process group's equivalence class (including * @p other), but will have its own set of tags. */ mpi_process_group(const mpi_process_group& other, attach_distributed_object, bool out_of_band_receive = false); /** * Create an "empty" process group, with no information. This is an * internal routine that users should never need. */ explicit mpi_process_group(create_empty) {} /** * Destroys this copy of the process group. */ ~mpi_process_group(); /** * Replace the current message handler with a new message handler. * * @param handle The new message handler. * @param out_of_band_receive An anachronism: remove this */ void replace_handler(const receiver_type& handler, bool out_of_band_receive = false); /** * Turns this process group into the process group for a new * distributed data structure or object, allocating its own tag * block. */ void make_distributed_object(); /** * Replace the handler to be invoked at the beginning of synchronize. */ void replace_on_synchronize_handler(const on_synchronize_event_type& handler = 0); /** * Return the block number of the current data structure. A value of * 0 indicates that this particular instance of the process group is * not associated with any distributed data structure. */ int my_block_number() const { return block_num? *block_num : 0; } /** * Encode a block number/tag pair into a single encoded tag for * transmission. */ int encode_tag(int block_num, int tag) const { return block_num * max_tags + tag; } /** * Decode an encoded tag into a block number/tag pair. */ std::pair<int, int> decode_tag(int encoded_tag) const { return std::make_pair(encoded_tag / max_tags, encoded_tag % max_tags); } // @todo Actually write up the friend declarations so these could be // private. // private: /** Allocate a block of tags for this instance. The block should not * have been allocated already, e.g., my_block_number() == * 0. Returns the newly-allocated block number. */ int allocate_block(bool out_of_band_receive = false); /** Potentially emit a receive event out of band. Returns true if an event * was actually sent, false otherwise. */ bool maybe_emit_receive(int process, int encoded_tag) const; /** Emit a receive event. Returns true if an event was actually * sent, false otherwise. */ bool emit_receive(int process, int encoded_tag) const; /** Emit an on-synchronize event to all block handlers. */ void emit_on_synchronize() const; /** Retrieve a reference to the stored receiver in this block. */ template<typename Receiver> Receiver* get_receiver(); template<typename T> void send_impl(int dest, int tag, const T& value, mpl::true_ /*is_mpi_datatype*/) const; template<typename T> void send_impl(int dest, int tag, const T& value, mpl::false_ /*is_mpi_datatype*/) const; template<typename T> typename disable_if<boost::mpi::is_mpi_datatype<T>, void>::type array_send_impl(int dest, int tag, const T values[], std::size_t n) const; template<typename T> bool receive_impl(int source, int tag, T& value, mpl::true_ /*is_mpi_datatype*/) const; template<typename T> bool receive_impl(int source, int tag, T& value, mpl::false_ /*is_mpi_datatype*/) const; // Receive an array of values template<typename T> typename disable_if<boost::mpi::is_mpi_datatype<T>, bool>::type array_receive_impl(int source, int tag, T* values, std::size_t& n) const; optional<std::pair<mpi_process_group::process_id_type, int> > probe() const; void synchronize() const; operator bool() { return bool(impl_); } mpi_process_group base() const; /** * Create a new trigger for a specific message tag. Triggers handle * out-of-band messaging, and the handler itself will be called * whenever a message is available. The handler itself accepts four * arguments: the source of the message, the message tag (which will * be the same as @p tag), the message data (of type @c Type), and a * boolean flag that states whether the message was received * out-of-band. The last will be @c true for out-of-band receives, * or @c false for receives at the end of a synchronization step. */ template<typename Type, typename Handler> void trigger(int tag, const Handler& handler); /** * Create a new trigger for a specific message tag, along with a way * to send a reply with data back to the sender. Triggers handle * out-of-band messaging, and the handler itself will be called * whenever a message is available. The handler itself accepts four * arguments: the source of the message, the message tag (which will * be the same as @p tag), the message data (of type @c Type), and a * boolean flag that states whether the message was received * out-of-band. The last will be @c true for out-of-band receives, * or @c false for receives at the end of a synchronization * step. The handler also returns a value, which will be routed back * to the sender. */ template<typename Type, typename Handler> void trigger_with_reply(int tag, const Handler& handler); template<typename Type, typename Handler> void global_trigger(int tag, const Handler& handler, std::size_t buffer_size=0); /** * Poll for any out-of-band messages. This routine will check if any * out-of-band messages are available. Those that are available will * be handled immediately, if possible. * * @returns if an out-of-band message has been received, but we are * unable to actually receive the message, a (source, tag) pair will * be returned. Otherwise, returns an empty optional. * * @param wait When true, we should block until a message comes in. * * @param synchronizing whether we are currently synchronizing the * process group */ optional<std::pair<int, int> > poll(bool wait = false, int block = -1, bool synchronizing = false) const; /** * Determines the context of the trigger currently executing. If * multiple triggers are executing (recursively), then the context * for the most deeply nested trigger will be returned. If no * triggers are executing, returns @c trc_none. This might be used, * for example, to determine whether a reply to a message should * itself be sent out-of-band or whether it can go via the normal, * slower communication route. */ trigger_receive_context trigger_context() const; /// INTERNAL ONLY void receive_batch(process_id_type source, outgoing_messages& batch) const; /// INTERNAL ONLY /// /// Determine the actual communicator and tag will be used for a /// transmission with the given tag. std::pair<boost::mpi::communicator, int> actual_communicator_and_tag(int tag, int block) const; /// set the size of the message buffer used for buffered oob sends static void set_message_buffer_size(std::size_t s); /// get the size of the message buffer used for buffered oob sends static std::size_t message_buffer_size(); static int old_buffer_size; static void* old_buffer; private: void install_trigger(int tag, int block, shared_ptr<trigger_base> const& launcher); void poll_requests(int block=-1) const; // send a batch if the buffer is full now or would get full void maybe_send_batch(process_id_type dest) const; // actually send a batch void send_batch(process_id_type dest, outgoing_messages& batch) const; void send_batch(process_id_type dest) const; void pack_headers() const; /** * Process a batch of incoming messages immediately. * * @param source the source of these messages */ void process_batch(process_id_type source) const; void receive_batch(boost::mpi::status& status) const; //void free_finished_sends() const; /// Status messages used internally by the process group enum status_messages { /// the first of the reserved message tags msg_reserved_first = 126, /// Sent from a processor when sending batched messages msg_batch = 126, /// Sent from a processor when sending large batched messages, larger than /// the maximum buffer size for messages to be received by MPI_Irecv msg_large_batch = 127, /// Sent from a source processor to everyone else when that /// processor has entered the synchronize() function. msg_synchronizing = 128, /// the last of the reserved message tags msg_reserved_last = 128 }; /** * Description of a block of tags associated to a particular * distributed data structure. This structure will live as long as * the distributed data structure is around, and will be used to * help send messages to the data structure. */ struct block_type { block_type() { } /// Handler for receive events receiver_type on_receive; /// Handler executed at the start of synchronization on_synchronize_event_type on_synchronize; /// Individual message triggers. Note: at present, this vector is /// indexed by the (local) tag of the trigger. Any tags that /// don't have triggers will have NULL pointers in that spot. std::vector<shared_ptr<trigger_base> > triggers; }; /** * Data structure containing all of the blocks for the distributed * data structures attached to a process group. */ typedef std::vector<block_type*> blocks_type; /// Iterator into @c blocks_type. typedef blocks_type::iterator block_iterator; /** * Deleter used to deallocate a block when its distributed data * structure is destroyed. This type will be used as the deleter for * @c block_num. */ struct deallocate_block; static std::vector<char> message_buffer; public: /** * Data associated with the process group and all of its attached * distributed data structures. */ shared_ptr<impl> impl_; /** * When non-null, indicates that this copy of the process group is * associated with a particular distributed data structure. The * integer value contains the block number (a value > 0) associated * with that data structure. The deleter for this @c shared_ptr is a * @c deallocate_block object that will deallocate the associated * block in @c impl_->blocks. */ shared_ptr<int> block_num; /** * Rank of this process, to avoid having to call rank() repeatedly. */ int rank; /** * Number of processes in this process group, to avoid having to * call communicator::size() repeatedly. */ int size; }; inline mpi_process_group::process_id_type process_id(const mpi_process_group& pg) { return pg.rank; } inline mpi_process_group::process_size_type num_processes(const mpi_process_group& pg) { return pg.size; } mpi_process_group::communicator_type communicator(const mpi_process_group& pg); template<typename T> void send(const mpi_process_group& pg, mpi_process_group::process_id_type dest, int tag, const T& value); template<typename InputIterator> void send(const mpi_process_group& pg, mpi_process_group::process_id_type dest, int tag, InputIterator first, InputIterator last); template<typename T> inline void send(const mpi_process_group& pg, mpi_process_group::process_id_type dest, int tag, T* first, T* last) { send(pg, dest, tag, first, last - first); } template<typename T> inline void send(const mpi_process_group& pg, mpi_process_group::process_id_type dest, int tag, const T* first, const T* last) { send(pg, dest, tag, first, last - first); } template<typename T> mpi_process_group::process_id_type receive(const mpi_process_group& pg, int tag, T& value); template<typename T> mpi_process_group::process_id_type receive(const mpi_process_group& pg, mpi_process_group::process_id_type source, int tag, T& value); optional<std::pair<mpi_process_group::process_id_type, int> > probe(const mpi_process_group& pg); void synchronize(const mpi_process_group& pg); template<typename T, typename BinaryOperation> T* all_reduce(const mpi_process_group& pg, T* first, T* last, T* out, BinaryOperation bin_op); template<typename T, typename BinaryOperation> T* scan(const mpi_process_group& pg, T* first, T* last, T* out, BinaryOperation bin_op); template<typename InputIterator, typename T> void all_gather(const mpi_process_group& pg, InputIterator first, InputIterator last, std::vector<T>& out); template<typename InputIterator> mpi_process_group process_subgroup(const mpi_process_group& pg, InputIterator first, InputIterator last); template<typename T> void broadcast(const mpi_process_group& pg, T& val, mpi_process_group::process_id_type root); /******************************************************************* * Out-of-band communication * *******************************************************************/ template<typename T> typename enable_if<boost::mpi::is_mpi_datatype<T> >::type send_oob(const mpi_process_group& pg, mpi_process_group::process_id_type dest, int tag, const T& value, int block=-1) { using boost::mpi::get_mpi_datatype; // Determine the actual message tag we will use for the send, and which // communicator we will use. std::pair<boost::mpi::communicator, int> actual = pg.actual_communicator_and_tag(tag, block); #ifdef SEND_OOB_BSEND if (mpi_process_group::message_buffer_size()) { MPI_Bsend(const_cast<T*>(&value), 1, get_mpi_datatype<T>(value), dest, actual.second, actual.first); return; } #endif MPI_Request request; MPI_Isend(const_cast<T*>(&value), 1, get_mpi_datatype<T>(value), dest, actual.second, actual.first, &request); int done=0; do { pg.poll(); MPI_Test(&request,&done,MPI_STATUS_IGNORE); } while (!done); } template<typename T> typename disable_if<boost::mpi::is_mpi_datatype<T> >::type send_oob(const mpi_process_group& pg, mpi_process_group::process_id_type dest, int tag, const T& value, int block=-1) { using boost::mpi::packed_oarchive; // Determine the actual message tag we will use for the send, and which // communicator we will use. std::pair<boost::mpi::communicator, int> actual = pg.actual_communicator_and_tag(tag, block); // Serialize the data into a buffer packed_oarchive out(actual.first); out << value; std::size_t size = out.size(); // Send the actual message data #ifdef SEND_OOB_BSEND if (mpi_process_group::message_buffer_size()) { MPI_Bsend(const_cast<void*>(out.address()), size, MPI_PACKED, dest, actual.second, actual.first); return; } #endif MPI_Request request; MPI_Isend(const_cast<void*>(out.address()), size, MPI_PACKED, dest, actual.second, actual.first, &request); int done=0; do { pg.poll(); MPI_Test(&request,&done,MPI_STATUS_IGNORE); } while (!done); } template<typename T> typename enable_if<boost::mpi::is_mpi_datatype<T> >::type receive_oob(const mpi_process_group& pg, mpi_process_group::process_id_type source, int tag, T& value, int block=-1); template<typename T> typename disable_if<boost::mpi::is_mpi_datatype<T> >::type receive_oob(const mpi_process_group& pg, mpi_process_group::process_id_type source, int tag, T& value, int block=-1); template<typename SendT, typename ReplyT> typename enable_if<boost::mpi::is_mpi_datatype<ReplyT> >::type send_oob_with_reply(const mpi_process_group& pg, mpi_process_group::process_id_type dest, int tag, const SendT& send_value, ReplyT& reply_value, int block = -1); template<typename SendT, typename ReplyT> typename disable_if<boost::mpi::is_mpi_datatype<ReplyT> >::type send_oob_with_reply(const mpi_process_group& pg, mpi_process_group::process_id_type dest, int tag, const SendT& send_value, ReplyT& reply_value, int block = -1); } } } // end namespace boost::graph::distributed BOOST_IS_BITWISE_SERIALIZABLE(boost::graph::distributed::mpi_process_group::message_header) namespace boost { namespace mpi { template<> struct is_mpi_datatype<boost::graph::distributed::mpi_process_group::message_header> : mpl::true_ { }; } } // end namespace boost::mpi namespace std { /// optimized swap for outgoing messages inline void swap(boost::graph::distributed::mpi_process_group::outgoing_messages& x, boost::graph::distributed::mpi_process_group::outgoing_messages& y) { x.swap(y); } } BOOST_CLASS_IMPLEMENTATION(boost::graph::distributed::mpi_process_group::outgoing_messages,object_serializable) BOOST_CLASS_TRACKING(boost::graph::distributed::mpi_process_group::outgoing_messages,track_never) #include <boost/graph/distributed/detail/mpi_process_group.ipp> #endif // BOOST_PARALLEL_MPI_MPI_PROCESS_GROUP_HPP distributed/fruchterman_reingold.hpp 0000644 00000031243 15125521275 0014010 0 ustar 00 // Copyright (C) 2005-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_DISTRIBUTED_FRUCHTERMAN_REINGOLD_HPP #define BOOST_GRAPH_DISTRIBUTED_FRUCHTERMAN_REINGOLD_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/fruchterman_reingold.hpp> namespace boost { namespace graph { namespace distributed { class simple_tiling { public: simple_tiling(int columns, int rows, bool flip = true) : columns(columns), rows(rows), flip(flip) { } // Convert from a position (x, y) in the tiled display into a // processor ID number int operator()(int x, int y) const { return flip? (rows - y - 1) * columns + x : y * columns + x; } // Convert from a process ID to a position (x, y) in the tiled // display std::pair<int, int> operator()(int id) { int my_col = id % columns; int my_row = flip? rows - (id / columns) - 1 : id / columns; return std::make_pair(my_col, my_row); } int columns, rows; private: bool flip; }; // Force pairs function object that does nothing struct no_force_pairs { template<typename Graph, typename ApplyForce> void operator()(const Graph&, const ApplyForce&) { } }; // Computes force pairs in the distributed case. template<typename PositionMap, typename DisplacementMap, typename LocalForces, typename NonLocalForces = no_force_pairs> class distributed_force_pairs_proxy { public: distributed_force_pairs_proxy(const PositionMap& position, const DisplacementMap& displacement, const LocalForces& local_forces, const NonLocalForces& nonlocal_forces = NonLocalForces()) : position(position), displacement(displacement), local_forces(local_forces), nonlocal_forces(nonlocal_forces) { } template<typename Graph, typename ApplyForce> void operator()(const Graph& g, ApplyForce apply_force) { // Flush remote displacements displacement.flush(); // Receive updated positions for all of our neighbors synchronize(position); // Reset remote displacements displacement.reset(); // Compute local repulsive forces local_forces(g, apply_force); // Compute neighbor repulsive forces nonlocal_forces(g, apply_force); } protected: PositionMap position; DisplacementMap displacement; LocalForces local_forces; NonLocalForces nonlocal_forces; }; template<typename PositionMap, typename DisplacementMap, typename LocalForces> inline distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces> make_distributed_force_pairs(const PositionMap& position, const DisplacementMap& displacement, const LocalForces& local_forces) { typedef distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces> result_type; return result_type(position, displacement, local_forces); } template<typename PositionMap, typename DisplacementMap, typename LocalForces, typename NonLocalForces> inline distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces, NonLocalForces> make_distributed_force_pairs(const PositionMap& position, const DisplacementMap& displacement, const LocalForces& local_forces, const NonLocalForces& nonlocal_forces) { typedef distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces, NonLocalForces> result_type; return result_type(position, displacement, local_forces, nonlocal_forces); } // Compute nonlocal force pairs based on the shared borders with // adjacent tiles. template<typename PositionMap> class neighboring_tiles_force_pairs { public: typedef typename property_traits<PositionMap>::value_type Point; typedef typename point_traits<Point>::component_type Dim; enum bucket_position { left, top, right, bottom, end_position }; neighboring_tiles_force_pairs(PositionMap position, Point origin, Point extent, simple_tiling tiling) : position(position), origin(origin), extent(extent), tiling(tiling) { } template<typename Graph, typename ApplyForce> void operator()(const Graph& g, ApplyForce apply_force) { // TBD: Do this some smarter way if (tiling.columns == 1 && tiling.rows == 1) return; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; #ifndef BOOST_NO_STDC_NAMESPACE using std::sqrt; #endif // BOOST_NO_STDC_NAMESPACE // TBD: num_vertices(g) should be the global number of vertices? Dim two_k = Dim(2) * sqrt(extent[0] * extent[1] / num_vertices(g)); std::vector<vertex_descriptor> my_vertices[4]; std::vector<vertex_descriptor> neighbor_vertices[4]; // Compute cutoff positions Dim cutoffs[4]; cutoffs[left] = origin[0] + two_k; cutoffs[top] = origin[1] + two_k; cutoffs[right] = origin[0] + extent[0] - two_k; cutoffs[bottom] = origin[1] + extent[1] - two_k; // Compute neighbors typename PositionMap::process_group_type pg = position.process_group(); std::pair<int, int> my_tile = tiling(process_id(pg)); int neighbors[4] = { -1, -1, -1, -1 } ; if (my_tile.first > 0) neighbors[left] = tiling(my_tile.first - 1, my_tile.second); if (my_tile.second > 0) neighbors[top] = tiling(my_tile.first, my_tile.second - 1); if (my_tile.first < tiling.columns - 1) neighbors[right] = tiling(my_tile.first + 1, my_tile.second); if (my_tile.second < tiling.rows - 1) neighbors[bottom] = tiling(my_tile.first, my_tile.second + 1); // Sort vertices along the edges into buckets BGL_FORALL_VERTICES_T(v, g, Graph) { if (position[v][0] <= cutoffs[left]) my_vertices[left].push_back(v); if (position[v][1] <= cutoffs[top]) my_vertices[top].push_back(v); if (position[v][0] >= cutoffs[right]) my_vertices[right].push_back(v); if (position[v][1] >= cutoffs[bottom]) my_vertices[bottom].push_back(v); } // Send vertices to neighbors, and gather our neighbors' vertices bucket_position pos; for (pos = left; pos < end_position; pos = bucket_position(pos + 1)) { if (neighbors[pos] != -1) { send(pg, neighbors[pos], 0, my_vertices[pos].size()); if (!my_vertices[pos].empty()) send(pg, neighbors[pos], 1, &my_vertices[pos].front(), my_vertices[pos].size()); } } // Pass messages around synchronize(pg); // Receive neighboring vertices for (pos = left; pos < end_position; pos = bucket_position(pos + 1)) { if (neighbors[pos] != -1) { std::size_t incoming_vertices; receive(pg, neighbors[pos], 0, incoming_vertices); if (incoming_vertices) { neighbor_vertices[pos].resize(incoming_vertices); receive(pg, neighbors[pos], 1, &neighbor_vertices[pos].front(), incoming_vertices); } } } // For each neighboring vertex, we need to get its current position for (pos = left; pos < end_position; pos = bucket_position(pos + 1)) for (typename std::vector<vertex_descriptor>::iterator i = neighbor_vertices[pos].begin(); i != neighbor_vertices[pos].end(); ++i) request(position, *i); synchronize(position); // Apply forces in adjacent bins. This is O(n^2) in the worst // case. Oh well. for (pos = left; pos < end_position; pos = bucket_position(pos + 1)) { for (typename std::vector<vertex_descriptor>::iterator i = my_vertices[pos].begin(); i != my_vertices[pos].end(); ++i) for (typename std::vector<vertex_descriptor>::iterator j = neighbor_vertices[pos].begin(); j != neighbor_vertices[pos].end(); ++j) apply_force(*i, *j); } } protected: PositionMap position; Point origin; Point extent; simple_tiling tiling; }; template<typename PositionMap> inline neighboring_tiles_force_pairs<PositionMap> make_neighboring_tiles_force_pairs (PositionMap position, typename property_traits<PositionMap>::value_type origin, typename property_traits<PositionMap>::value_type extent, simple_tiling tiling) { return neighboring_tiles_force_pairs<PositionMap>(position, origin, extent, tiling); } template<typename DisplacementMap, typename Cooling> class distributed_cooling_proxy { public: typedef typename Cooling::result_type result_type; distributed_cooling_proxy(const DisplacementMap& displacement, const Cooling& cooling) : displacement(displacement), cooling(cooling) { } result_type operator()() { // Accumulate displacements computed on each processor synchronize(displacement.data->process_group); // Allow the underlying cooling to occur return cooling(); } protected: DisplacementMap displacement; Cooling cooling; }; template<typename DisplacementMap, typename Cooling> inline distributed_cooling_proxy<DisplacementMap, Cooling> make_distributed_cooling(const DisplacementMap& displacement, const Cooling& cooling) { typedef distributed_cooling_proxy<DisplacementMap, Cooling> result_type; return result_type(displacement, cooling); } template<typename Point> struct point_accumulating_reducer { BOOST_STATIC_CONSTANT(bool, non_default_resolver = true); template<typename K> Point operator()(const K&) const { return Point(); } template<typename K> Point operator()(const K&, const Point& p1, const Point& p2) const { return Point(p1[0] + p2[0], p1[1] + p2[1]); } }; template<typename Graph, typename PositionMap, typename AttractiveForce, typename RepulsiveForce, typename ForcePairs, typename Cooling, typename DisplacementMap> void fruchterman_reingold_force_directed_layout (const Graph& g, PositionMap position, typename property_traits<PositionMap>::value_type const& origin, typename property_traits<PositionMap>::value_type const& extent, AttractiveForce attractive_force, RepulsiveForce repulsive_force, ForcePairs force_pairs, Cooling cool, DisplacementMap displacement) { typedef typename property_traits<PositionMap>::value_type Point; // Reduction in the displacement map involves summing the forces displacement.set_reduce(point_accumulating_reducer<Point>()); // We need to track the positions of all of our neighbors BGL_FORALL_VERTICES_T(u, g, Graph) BGL_FORALL_ADJ_T(u, v, g, Graph) request(position, v); // Invoke the "sequential" Fruchterman-Reingold implementation boost::fruchterman_reingold_force_directed_layout (g, position, origin, extent, attractive_force, repulsive_force, make_distributed_force_pairs(position, displacement, force_pairs), make_distributed_cooling(displacement, cool), displacement); } template<typename Graph, typename PositionMap, typename AttractiveForce, typename RepulsiveForce, typename ForcePairs, typename Cooling, typename DisplacementMap> void fruchterman_reingold_force_directed_layout (const Graph& g, PositionMap position, typename property_traits<PositionMap>::value_type const& origin, typename property_traits<PositionMap>::value_type const& extent, AttractiveForce attractive_force, RepulsiveForce repulsive_force, ForcePairs force_pairs, Cooling cool, DisplacementMap displacement, simple_tiling tiling) { typedef typename property_traits<PositionMap>::value_type Point; // Reduction in the displacement map involves summing the forces displacement.set_reduce(point_accumulating_reducer<Point>()); // We need to track the positions of all of our neighbors BGL_FORALL_VERTICES_T(u, g, Graph) BGL_FORALL_ADJ_T(u, v, g, Graph) request(position, v); // Invoke the "sequential" Fruchterman-Reingold implementation boost::fruchterman_reingold_force_directed_layout (g, position, origin, extent, attractive_force, repulsive_force, make_distributed_force_pairs (position, displacement, force_pairs, make_neighboring_tiles_force_pairs(position, origin, extent, tiling)), make_distributed_cooling(displacement, cool), displacement); } } } } // end namespace boost::graph::distributed #endif // BOOST_GRAPH_DISTRIBUTED_FRUCHTERMAN_REINGOLD_HPP distributed/concepts.hpp 0000644 00000015564 15125521275 0011435 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine // // Distributed graph concepts and helpers // #ifndef BOOST_GRAPH_DISTRIBUTED_CONCEPTS_HPP #define BOOST_GRAPH_DISTRIBUTED_CONCEPTS_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/version.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/concept/assert.hpp> #if BOOST_VERSION >= 103500 # include <boost/concept/detail/concept_def.hpp> #endif namespace boost { #if BOOST_VERSION >= 103500 namespace concepts { #endif #if BOOST_VERSION < 103500 template <class G> struct DistributedVertexListGraphConcept { typedef typename graph_traits<G>::vertex_iterator vertex_iterator; typedef typename graph_traits<G>::vertices_size_type vertices_size_type; typedef typename graph_traits<G>::traversal_category traversal_category; void constraints() { BOOST_CONCEPT_ASSERT(( GraphConcept<G> )); BOOST_CONCEPT_ASSERT(( MultiPassInputIteratorConcept<vertex_iterator> )); BOOST_CONCEPT_ASSERT(( ConvertibleConcept<traversal_category, distributed_vertex_list_graph_tag> )); #ifdef BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK // dwa 2003/7/11 -- This clearly shouldn't be necessary, but if // you want to use vector_as_graph, it is! I'm sure the graph // library leaves these out all over the place. Probably a // redesign involving specializing a template with a static // member function is in order :( using boost::vertices; #endif p = vertices(g); v = *p.first; const_constraints(g); } void const_constraints(const G& cg) { #ifdef BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK // dwa 2003/7/11 -- This clearly shouldn't be necessary, but if // you want to use vector_as_graph, it is! I'm sure the graph // library leaves these out all over the place. Probably a // redesign involving specializing a template with a static // member function is in order :( using boost::vertices; #endif p = vertices(cg); v = *p.first; V = num_vertices(cg); } std::pair<vertex_iterator,vertex_iterator> p; typename graph_traits<G>::vertex_descriptor v; G g; vertices_size_type V; }; template <class G> struct DistributedEdgeListGraphConcept { typedef typename graph_traits<G>::edge_descriptor edge_descriptor; typedef typename graph_traits<G>::edge_iterator edge_iterator; typedef typename graph_traits<G>::edges_size_type edges_size_type; typedef typename graph_traits<G>::traversal_category traversal_category; void constraints() { BOOST_CONCEPT_ASSERT(( GraphConcept<G> )); BOOST_CONCEPT_ASSERT(( MultiPassInputIteratorConcept<edge_iterator> )); BOOST_CONCEPT_ASSERT(( DefaultConstructibleConcept<edge_descriptor> )); BOOST_CONCEPT_ASSERT(( EqualityComparableConcept<edge_descriptor> )); BOOST_CONCEPT_ASSERT(( AssignableConcept<edge_descriptor> )); BOOST_CONCEPT_ASSERT(( ConvertibleConcept<traversal_category, distributed_edge_list_graph_tag> )); p = edges(g); e = *p.first; u = source(e, g); v = target(e, g); const_constraints(g); } void const_constraints(const G& cg) { p = edges(cg); E = num_edges(cg); e = *p.first; u = source(e, cg); v = target(e, cg); } std::pair<edge_iterator,edge_iterator> p; typename graph_traits<G>::vertex_descriptor u, v; typename graph_traits<G>::edge_descriptor e; edges_size_type E; G g; }; #else BOOST_concept(DistributedVertexListGraph,(G)) : Graph<G> { typedef typename graph_traits<G>::vertex_iterator vertex_iterator; typedef typename graph_traits<G>::vertices_size_type vertices_size_type; typedef typename graph_traits<G>::traversal_category traversal_category; ~DistributedVertexListGraph() { BOOST_CONCEPT_ASSERT((MultiPassInputIterator<vertex_iterator>)); BOOST_CONCEPT_ASSERT((Convertible<traversal_category, distributed_vertex_list_graph_tag>)); #ifdef BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK // dwa 2003/7/11 -- This clearly shouldn't be necessary, but if // you want to use vector_as_graph, it is! I'm sure the graph // library leaves these out all over the place. Probably a // redesign involving specializing a template with a static // member function is in order :( using boost::vertices; #endif p = vertices(g); v = *p.first; const_constraints(g); } void const_constraints(const G& cg) { #ifdef BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK // dwa 2003/7/11 -- This clearly shouldn't be necessary, but if // you want to use vector_as_graph, it is! I'm sure the graph // library leaves these out all over the place. Probably a // redesign involving specializing a template with a static // member function is in order :( using boost::vertices; #endif p = vertices(cg); v = *p.first; V = num_vertices(cg); } std::pair<vertex_iterator,vertex_iterator> p; typename graph_traits<G>::vertex_descriptor v; G g; vertices_size_type V; }; BOOST_concept(DistributedEdgeListGraph,(G)) : Graph<G> { typedef typename graph_traits<G>::edge_descriptor edge_descriptor; typedef typename graph_traits<G>::edge_iterator edge_iterator; typedef typename graph_traits<G>::edges_size_type edges_size_type; typedef typename graph_traits<G>::traversal_category traversal_category; ~DistributedEdgeListGraph() { BOOST_CONCEPT_ASSERT((MultiPassInputIterator<edge_iterator>)); BOOST_CONCEPT_ASSERT((DefaultConstructible<edge_descriptor>)); BOOST_CONCEPT_ASSERT((EqualityComparable<edge_descriptor>)); BOOST_CONCEPT_ASSERT((Assignable<edge_descriptor>)); BOOST_CONCEPT_ASSERT((Convertible<traversal_category, distributed_edge_list_graph_tag>)); p = edges(g); e = *p.first; u = source(e, g); v = target(e, g); const_constraints(g); } void const_constraints(const G& cg) { p = edges(cg); E = num_edges(cg); e = *p.first; u = source(e, cg); v = target(e, cg); } std::pair<edge_iterator,edge_iterator> p; typename graph_traits<G>::vertex_descriptor u, v; typename graph_traits<G>::edge_descriptor e; edges_size_type E; G g; }; #endif #if BOOST_VERSION >= 103500 } // end namespace concepts using concepts::DistributedVertexListGraphConcept; using concepts::DistributedEdgeListGraphConcept; #endif } // end namespace boost #if BOOST_VERSION >= 103500 # include <boost/concept/detail/concept_undef.hpp> #endif #endif // BOOST_GRAPH_DISTRIBUTED_CONCEPTS_HPP distributed/adjlist/handlers.hpp 0000644 00000012246 15125521275 0013043 0 ustar 00 // Copyright (C) 2007 Douglas Gregor // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // This file contains code for the distributed adjacency list's // message handlers. It should not be included directly by users. #ifndef BOOST_GRAPH_DISTRIBUTED_ADJLIST_HANDLERS_HPP #define BOOST_GRAPH_DISTRIBUTED_ADJLIST_HANDLERS_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/parallel/simple_trigger.hpp> #include <boost/graph/parallel/detail/untracked_pair.hpp> namespace boost { template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> void PBGL_DISTRIB_ADJLIST_TYPE:: setup_triggers() { using boost::graph::parallel::simple_trigger; simple_trigger(process_group_, msg_add_vertex_with_property, this, &adjacency_list::handle_add_vertex_with_property); simple_trigger(process_group_, msg_add_vertex_with_property_and_reply, this, &adjacency_list::handle_add_vertex_with_property_and_reply); simple_trigger(process_group_, msg_add_edge, this, &adjacency_list::handle_add_edge); simple_trigger(process_group_, msg_add_edge_with_reply, this, &adjacency_list::handle_add_edge_with_reply); simple_trigger(process_group_, msg_add_edge_with_property, this, &adjacency_list::handle_add_edge_with_property); simple_trigger(process_group_, msg_add_edge_with_property_and_reply, this, &adjacency_list::handle_add_edge_with_property_and_reply); simple_trigger(process_group_, msg_nonlocal_edge, this, &adjacency_list::handle_nonlocal_edge); simple_trigger(process_group_, msg_remove_edge, this, &adjacency_list::handle_remove_edge); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> void PBGL_DISTRIB_ADJLIST_TYPE:: handle_add_vertex_with_property(int source, int tag, const vertex_property_type& data, trigger_receive_context) { vertex_descriptor v(this->processor(), add_vertex(this->build_vertex_property(data), this->base())); if (on_add_vertex) on_add_vertex(v, *this); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename PBGL_DISTRIB_ADJLIST_TYPE::local_vertex_descriptor PBGL_DISTRIB_ADJLIST_TYPE:: handle_add_vertex_with_property_and_reply(int source, int tag, const vertex_property_type& data, trigger_receive_context) { // Try to find a vertex with this name local_vertex_descriptor local_v = add_vertex(this->build_vertex_property(data), this->base()); vertex_descriptor v(processor(), local_v); if (on_add_vertex) on_add_vertex(v, *this); return local_v; } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> void PBGL_DISTRIB_ADJLIST_TYPE:: handle_add_edge(int source, int tag, const msg_add_edge_data& data, trigger_receive_context) { add_edge(vertex_descriptor(processor(), data.source), data.target, *this); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> boost::parallel::detail::untracked_pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool> PBGL_DISTRIB_ADJLIST_TYPE:: handle_add_edge_with_reply(int source, int tag, const msg_add_edge_data& data, trigger_receive_context) { std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool> p = add_edge(vertex_descriptor(processor(), data.source),data.target, *this); return p; } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> void PBGL_DISTRIB_ADJLIST_TYPE:: handle_add_edge_with_property(int source, int tag, const msg_add_edge_with_property_data& data, trigger_receive_context) { add_edge(vertex_descriptor(processor(), data.source), data.target, data.get_property(), *this); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> boost::parallel::detail::untracked_pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool> PBGL_DISTRIB_ADJLIST_TYPE:: handle_add_edge_with_property_and_reply (int source, int tag, const msg_add_edge_with_property_data& data, trigger_receive_context) { std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool> p = add_edge(vertex_descriptor(processor(), data.source), data.target, data.get_property(), *this); return p; } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> void PBGL_DISTRIB_ADJLIST_TYPE:: handle_nonlocal_edge(int source, int tag, const msg_nonlocal_edge_data& data, trigger_receive_context) { add_remote_edge(data, source, directed_selector()); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> void PBGL_DISTRIB_ADJLIST_TYPE:: handle_remove_edge(int source, int tag, const msg_remove_edge_data& data, trigger_receive_context) { remove_local_edge(data, source, directed_selector()); } } #endif // BOOST_GRAPH_DISTRIBUTED_ADJLIST_HANDLERS_HPP distributed/adjlist/initialize.hpp 0000644 00000026440 15125521275 0013405 0 ustar 00 // Copyright (C) 2007 Douglas Gregor // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // This file contains code for the distributed adjacency list's // initializations. It should not be included directly by users. #ifndef BOOST_GRAPH_DISTRIBUTED_ADJLIST_INITIALIZE_HPP #define BOOST_GRAPH_DISTRIBUTED_ADJLIST_INITIALIZE_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif namespace boost { template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> template<typename EdgeIterator> void PBGL_DISTRIB_ADJLIST_TYPE:: initialize(EdgeIterator first, EdgeIterator last, vertices_size_type, const base_distribution_type& distribution, vecS) { process_id_type id = process_id(process_group_); while (first != last) { if ((process_id_type)distribution(first->first) == id) { vertex_descriptor source(id, distribution.local(first->first)); vertex_descriptor target(distribution(first->second), distribution.local(first->second)); add_edge(source, target, *this); } ++first; } synchronize(process_group_); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> template<typename EdgeIterator, typename EdgePropertyIterator> void PBGL_DISTRIB_ADJLIST_TYPE:: initialize(EdgeIterator first, EdgeIterator last, EdgePropertyIterator ep_iter, vertices_size_type, const base_distribution_type& distribution, vecS) { process_id_type id = process_id(process_group_); while (first != last) { if (static_cast<process_id_type>(distribution(first->first)) == id) { vertex_descriptor source(id, distribution.local(first->first)); vertex_descriptor target(distribution(first->second), distribution.local(first->second)); add_edge(source, target, *ep_iter, *this); } ++first; ++ep_iter; } synchronize(process_group_); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> template<typename EdgeIterator, typename EdgePropertyIterator, typename VertexListS> void PBGL_DISTRIB_ADJLIST_TYPE:: initialize(EdgeIterator first, EdgeIterator last, EdgePropertyIterator ep_iter, vertices_size_type n, const base_distribution_type& distribution, VertexListS) { using boost::parallel::inplace_all_to_all; typedef vertices_size_type vertex_number_t; typedef typename std::iterator_traits<EdgePropertyIterator>::value_type edge_property_init_t; typedef std::pair<vertex_descriptor, vertex_number_t> st_pair; typedef std::pair<st_pair, edge_property_init_t> delayed_edge_t; process_group_type pg = process_group(); process_id_type id = process_id(pg); // Vertex indices std::vector<local_vertex_descriptor> index_to_vertex; index_to_vertex.reserve(num_vertices(*this)); BGL_FORALL_VERTICES_T(v, base(), inherited) index_to_vertex.push_back(v); // The list of edges we can't add immediately. std::vector<delayed_edge_t> delayed_edges; std::vector<std::vector<vertex_number_t> > descriptor_requests; descriptor_requests.resize(num_processes(pg)); // Add all of the edges we can, up to the point where we run // into a descriptor we don't know. while (first != last) { if (distribution(first->first) == id) { if (distribution(first->second) != id) break; vertex_descriptor source (id, index_to_vertex[distribution.local(first->first)]); vertex_descriptor target (distribution(first->second), index_to_vertex[distribution.local(first->second)]); add_edge(source, target, *ep_iter, *this); } ++first; ++ep_iter; } // Queue all of the remaining edges and determine the set of // descriptors we need to know about. while (first != last) { if (distribution(first->first) == id) { vertex_descriptor source (id, index_to_vertex[distribution.local(first->first)]); process_id_type dest = distribution(first->second); if (dest != id) { descriptor_requests[dest] .push_back(distribution.local(first->second)); // Compact request list if we need to if (descriptor_requests[dest].size() > distribution.block_size(dest, n)) { std::sort(descriptor_requests[dest].begin(), descriptor_requests[dest].end()); descriptor_requests[dest].erase( std::unique(descriptor_requests[dest].begin(), descriptor_requests[dest].end()), descriptor_requests[dest].end()); } } // Save the edge for later delayed_edges.push_back (delayed_edge_t(st_pair(source, first->second), *ep_iter)); } ++first; ++ep_iter; } // Compact descriptor requests for (process_id_type dest = 0; dest < num_processes(pg); ++dest) { std::sort(descriptor_requests[dest].begin(), descriptor_requests[dest].end()); descriptor_requests[dest].erase( std::unique(descriptor_requests[dest].begin(), descriptor_requests[dest].end()), descriptor_requests[dest].end()); } // Send out all of the descriptor requests std::vector<std::vector<vertex_number_t> > in_descriptor_requests; in_descriptor_requests.resize(num_processes(pg)); inplace_all_to_all(pg, descriptor_requests, in_descriptor_requests); // Reply to all of the descriptor requests std::vector<std::vector<local_vertex_descriptor> > descriptor_responses; descriptor_responses.resize(num_processes(pg)); for (process_id_type dest = 0; dest < num_processes(pg); ++dest) { for (std::size_t i = 0; i < in_descriptor_requests[dest].size(); ++i) { local_vertex_descriptor v = index_to_vertex[in_descriptor_requests[dest][i]]; descriptor_responses[dest].push_back(v); } in_descriptor_requests[dest].clear(); } in_descriptor_requests.clear(); inplace_all_to_all(pg, descriptor_responses); // Add the queued edges for(typename std::vector<delayed_edge_t>::iterator i = delayed_edges.begin(); i != delayed_edges.end(); ++i) { process_id_type dest = distribution(i->first.second); local_vertex_descriptor tgt_local; if (dest == id) { tgt_local = index_to_vertex[distribution.local(i->first.second)]; } else { std::vector<vertex_number_t>& requests = descriptor_requests[dest]; typename std::vector<vertex_number_t>::iterator pos = std::lower_bound(requests.begin(), requests.end(), distribution.local(i->first.second)); tgt_local = descriptor_responses[dest][pos - requests.begin()]; } add_edge(i->first.first, vertex_descriptor(dest, tgt_local), i->second, *this); } synchronize(process_group_); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> template<typename EdgeIterator, typename VertexListS> void PBGL_DISTRIB_ADJLIST_TYPE:: initialize(EdgeIterator first, EdgeIterator last, vertices_size_type n, const base_distribution_type& distribution, VertexListS) { using boost::parallel::inplace_all_to_all; typedef vertices_size_type vertex_number_t; typedef std::pair<vertex_descriptor, vertex_number_t> delayed_edge_t; process_group_type pg = process_group(); process_id_type id = process_id(pg); // Vertex indices std::vector<local_vertex_descriptor> index_to_vertex; index_to_vertex.reserve(num_vertices(*this)); BGL_FORALL_VERTICES_T(v, base(), inherited) index_to_vertex.push_back(v); // The list of edges we can't add immediately. std::vector<delayed_edge_t> delayed_edges; std::vector<std::vector<vertex_number_t> > descriptor_requests; descriptor_requests.resize(num_processes(pg)); // Add all of the edges we can, up to the point where we run // into a descriptor we don't know. while (first != last) { if (distribution(first->first) == id) { if (distribution(first->second) != id) break; vertex_descriptor source (id, index_to_vertex[distribution.local(first->first)]); vertex_descriptor target (distribution(first->second), index_to_vertex[distribution.local(first->second)]); add_edge(source, target, *this); } ++first; } // Queue all of the remaining edges and determine the set of // descriptors we need to know about. while (first != last) { if (distribution(first->first) == id) { vertex_descriptor source (id, index_to_vertex[distribution.local(first->first)]); process_id_type dest = distribution(first->second); if (dest != id) { descriptor_requests[dest] .push_back(distribution.local(first->second)); // Compact request list if we need to if (descriptor_requests[dest].size() > distribution.block_size(dest, n)) { std::sort(descriptor_requests[dest].begin(), descriptor_requests[dest].end()); descriptor_requests[dest].erase( std::unique(descriptor_requests[dest].begin(), descriptor_requests[dest].end()), descriptor_requests[dest].end()); } } // Save the edge for later delayed_edges.push_back(delayed_edge_t(source, first->second)); } ++first; } // Compact descriptor requests for (process_id_type dest = 0; dest < num_processes(pg); ++dest) { std::sort(descriptor_requests[dest].begin(), descriptor_requests[dest].end()); descriptor_requests[dest].erase( std::unique(descriptor_requests[dest].begin(), descriptor_requests[dest].end()), descriptor_requests[dest].end()); } // Send out all of the descriptor requests std::vector<std::vector<vertex_number_t> > in_descriptor_requests; in_descriptor_requests.resize(num_processes(pg)); inplace_all_to_all(pg, descriptor_requests, in_descriptor_requests); // Reply to all of the descriptor requests std::vector<std::vector<local_vertex_descriptor> > descriptor_responses; descriptor_responses.resize(num_processes(pg)); for (process_id_type dest = 0; dest < num_processes(pg); ++dest) { for (std::size_t i = 0; i < in_descriptor_requests[dest].size(); ++i) { local_vertex_descriptor v = index_to_vertex[in_descriptor_requests[dest][i]]; descriptor_responses[dest].push_back(v); } in_descriptor_requests[dest].clear(); } in_descriptor_requests.clear(); inplace_all_to_all(pg, descriptor_responses); // Add the queued edges for(typename std::vector<delayed_edge_t>::iterator i = delayed_edges.begin(); i != delayed_edges.end(); ++i) { process_id_type dest = distribution(i->second); local_vertex_descriptor tgt_local; if (dest == id) { tgt_local = index_to_vertex[distribution.local(i->second)]; } else { std::vector<vertex_number_t>& requests = descriptor_requests[dest]; typename std::vector<vertex_number_t>::iterator pos = std::lower_bound(requests.begin(), requests.end(), distribution.local(i->second)); tgt_local = descriptor_responses[dest][pos - requests.begin()]; } add_edge(i->first, vertex_descriptor(dest, tgt_local), *this); } synchronize(process_group_); } } // end namespace boost #endif // BOOST_GRAPH_DISTRIBUTED_ADJLIST_INITIALIZE_HPP distributed/adjlist/redistribute.hpp 0000644 00000034721 15125521275 0013752 0 ustar 00 // Copyright (C) 2005-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine // // Implements redistribution of vertices for a distributed adjacency // list. This file should not be included by users. It will be // included by the distributed adjacency list header. // #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/pending/container_traits.hpp> namespace boost { namespace detail { namespace parallel { /* This structure contains a (vertex or edge) descriptor that is being moved from one processor to another. It contains the properties for that descriptor (if any). */ template<typename Descriptor, typename DescriptorProperty> struct redistributed_descriptor : maybe_store_property<DescriptorProperty> { typedef maybe_store_property<DescriptorProperty> inherited; redistributed_descriptor() { } redistributed_descriptor(const Descriptor& v, const DescriptorProperty& p) : inherited(p), descriptor(v) { } Descriptor descriptor; private: friend class boost::serialization::access; template<typename Archiver> void serialize(Archiver& ar, unsigned int /*version*/) { ar & boost::serialization::base_object<inherited>(*this) & unsafe_serialize(descriptor); } }; /* Predicate that returns true if the target has migrated. */ template<typename VertexProcessorMap, typename Graph> struct target_migrated_t { typedef typename graph_traits<Graph>::vertex_descriptor Vertex; typedef typename graph_traits<Graph>::edge_descriptor Edge; target_migrated_t(VertexProcessorMap vertex_to_processor, const Graph& g) : vertex_to_processor(vertex_to_processor), g(g) { } bool operator()(Edge e) const { typedef global_descriptor<Vertex> DVertex; processor_id_type owner = get(edge_target_processor_id, g, e); return get(vertex_to_processor, DVertex(owner, target(e, g))) != owner; } private: VertexProcessorMap vertex_to_processor; const Graph& g; }; template<typename VertexProcessorMap, typename Graph> inline target_migrated_t<VertexProcessorMap, Graph> target_migrated(VertexProcessorMap vertex_to_processor, const Graph& g) { return target_migrated_t<VertexProcessorMap, Graph>(vertex_to_processor, g); } /* Predicate that returns true if the source of an in-edge has migrated. */ template<typename VertexProcessorMap, typename Graph> struct source_migrated_t { typedef typename graph_traits<Graph>::vertex_descriptor Vertex; typedef typename graph_traits<Graph>::edge_descriptor Edge; source_migrated_t(VertexProcessorMap vertex_to_processor, const Graph& g) : vertex_to_processor(vertex_to_processor), g(g) { } bool operator()(stored_in_edge<Edge> e) const { return get(vertex_to_processor, DVertex(e.source_processor, source(e.e, g))) != e.source_processor; } private: VertexProcessorMap vertex_to_processor; const Graph& g; }; template<typename VertexProcessorMap, typename Graph> inline source_migrated_t<VertexProcessorMap, Graph> source_migrated(VertexProcessorMap vertex_to_processor, const Graph& g) { return source_migrated_t<VertexProcessorMap, Graph>(vertex_to_processor, g); } /* Predicate that returns true if the target has migrated. */ template<typename VertexProcessorMap, typename Graph> struct source_or_target_migrated_t { typedef typename graph_traits<Graph>::edge_descriptor Edge; source_or_target_migrated_t(VertexProcessorMap vertex_to_processor, const Graph& g) : vertex_to_processor(vertex_to_processor), g(g) { } bool operator()(Edge e) const { return get(vertex_to_processor, source(e, g)) != source(e, g).owner || get(vertex_to_processor, target(e, g)) != target(e, g).owner; } private: VertexProcessorMap vertex_to_processor; const Graph& g; }; template<typename VertexProcessorMap, typename Graph> inline source_or_target_migrated_t<VertexProcessorMap, Graph> source_or_target_migrated(VertexProcessorMap vertex_to_processor, const Graph& g) { typedef source_or_target_migrated_t<VertexProcessorMap, Graph> result_type; return result_type(vertex_to_processor, g); } } } // end of namespace detail::parallel template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> template<typename VertexProcessorMap> void PBGL_DISTRIB_ADJLIST_TYPE ::request_in_neighbors(vertex_descriptor v, VertexProcessorMap vertex_to_processor, bidirectionalS) { BGL_FORALL_INEDGES_T(v, e, *this, graph_type) request(vertex_to_processor, source(e, *this)); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> template<typename VertexProcessorMap> void PBGL_DISTRIB_ADJLIST_TYPE ::remove_migrated_in_edges(vertex_descriptor v, VertexProcessorMap vertex_to_processor, bidirectionalS) { graph_detail::erase_if(get(vertex_in_edges, base())[v.local], source_migrated(vertex_to_processor, base())); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> template<typename VertexProcessorMap> void PBGL_DISTRIB_ADJLIST_TYPE ::redistribute(VertexProcessorMap vertex_to_processor) { using boost::parallel::inplace_all_to_all; // When we have stable descriptors, we only move those descriptors // that actually need to be moved. Otherwise, we essentially have to // regenerate the entire graph. const bool has_stable_descriptors = is_same<typename config_type::vertex_list_selector, listS>::value || is_same<typename config_type::vertex_list_selector, setS>::value || is_same<typename config_type::vertex_list_selector, multisetS>::value; typedef detail::parallel::redistributed_descriptor<vertex_descriptor, vertex_property_type> redistributed_vertex; typedef detail::parallel::redistributed_descriptor<edge_descriptor, edge_property_type> redistributed_edge; vertex_iterator vi, vi_end; edge_iterator ei, ei_end; process_group_type pg = process_group(); // Initial synchronization makes sure that we have all of our ducks // in a row. We don't want any outstanding add/remove messages // coming in mid-redistribution! synchronize(process_group_); // We cannot cope with eviction of ghost cells vertex_to_processor.set_max_ghost_cells(0); process_id_type p = num_processes(pg); // Send vertices and edges to the processor where they will // actually reside. This requires O(|V| + |E|) communication std::vector<std::vector<redistributed_vertex> > redistributed_vertices(p); std::vector<std::vector<redistributed_edge> > redistributed_edges(p); // Build the sets of relocated vertices for each process and then do // an all-to-all transfer. for (boost::tie(vi, vi_end) = vertices(*this); vi != vi_end; ++vi) { if (!has_stable_descriptors || get(vertex_to_processor, *vi) != vi->owner) { redistributed_vertices[get(vertex_to_processor, *vi)] .push_back(redistributed_vertex(*vi, get(vertex_all_t(), base(), vi->local))); } // When our descriptors are stable, we need to determine which // adjacent descriptors are stable to determine which edges will // be removed. if (has_stable_descriptors) { BGL_FORALL_OUTEDGES_T(*vi, e, *this, graph_type) request(vertex_to_processor, target(e, *this)); request_in_neighbors(*vi, vertex_to_processor, directed_selector()); } } inplace_all_to_all(pg, redistributed_vertices); // If we have stable descriptors, we need to know where our neighbor // vertices are moving. if (has_stable_descriptors) synchronize(vertex_to_processor); // Build the sets of relocated edges for each process and then do // an all-to-all transfer. for (boost::tie(ei, ei_end) = edges(*this); ei != ei_end; ++ei) { vertex_descriptor src = source(*ei, *this); vertex_descriptor tgt = target(*ei, *this); if (!has_stable_descriptors || get(vertex_to_processor, src) != src.owner || get(vertex_to_processor, tgt) != tgt.owner) redistributed_edges[get(vertex_to_processor, source(*ei, *this))] .push_back(redistributed_edge(*ei, split_edge_property(get(edge_all_t(), base(), ei->local)))); } inplace_all_to_all(pg, redistributed_edges); // A mapping from old vertex descriptors to new vertex // descriptors. This is an STL map partly because I'm too lazy to // build a real property map (which is hard in the general case) but // also because it won't try to look in the graph itself, because // the keys are all vertex descriptors that have been invalidated. std::map<vertex_descriptor, vertex_descriptor> old_to_new_vertex_map; if (has_stable_descriptors) { // Clear out all vertices and edges that will have moved. There // are several stages to this. // First, eliminate all outgoing edges from the (local) vertices // that have been moved or whose targets have been moved. BGL_FORALL_VERTICES_T(v, *this, graph_type) { if (get(vertex_to_processor, v) != v.owner) { clear_out_edges(v.local, base()); clear_in_edges_local(v, directed_selector()); } else { remove_out_edge_if(v.local, target_migrated(vertex_to_processor, base()), base()); remove_migrated_in_edges(v, vertex_to_processor, directed_selector()); } } // Next, eliminate locally-stored edges that have migrated (for // undirected graphs). graph_detail::erase_if(local_edges_, source_or_target_migrated(vertex_to_processor, *this)); // Eliminate vertices that have migrated for (boost::tie(vi, vi_end) = vertices(*this); vi != vi_end; /* in loop */) { if (get(vertex_to_processor, *vi) != vi->owner) remove_vertex((*vi++).local, base()); else { // Add the identity relation for vertices that have not migrated old_to_new_vertex_map[*vi] = *vi; ++vi; } } } else { // Clear out the local graph: the entire graph is in transit clear(); } // Add the new vertices to the graph. When we do so, update the old // -> new vertex mapping both locally and for the owner of the "old" // vertex. { typedef std::pair<vertex_descriptor, vertex_descriptor> mapping_pair; std::vector<std::vector<mapping_pair> > mappings(p); for (process_id_type src = 0; src < p; ++src) { for (typename std::vector<redistributed_vertex>::iterator vi = redistributed_vertices[src].begin(); vi != redistributed_vertices[src].end(); ++vi) { vertex_descriptor new_vertex = add_vertex(vi->get_property(), *this); old_to_new_vertex_map[vi->descriptor] = new_vertex; mappings[vi->descriptor.owner].push_back(mapping_pair(vi->descriptor, new_vertex)); } redistributed_vertices[src].clear(); } inplace_all_to_all(pg, mappings); // Add the mappings we were sent into the old->new map. for (process_id_type src = 0; src < p; ++src) old_to_new_vertex_map.insert(mappings[src].begin(), mappings[src].end()); } // Get old->new vertex mappings for all of the vertices we need to // know about. // TBD: An optimization here might involve sending the // request-response pairs without an explicit request step (for // bidirectional and undirected graphs). However, it may not matter // all that much given the cost of redistribution. { std::vector<std::vector<vertex_descriptor> > vertex_map_requests(p); std::vector<std::vector<vertex_descriptor> > vertex_map_responses(p); // We need to know about all of the vertices incident on edges // that have been relocated to this processor. Tell each processor // what each other processor needs to know. for (process_id_type src = 0; src < p; ++src) for (typename std::vector<redistributed_edge>::iterator ei = redistributed_edges[src].begin(); ei != redistributed_edges[src].end(); ++ei) { vertex_descriptor need_vertex = target(ei->descriptor, *this); if (old_to_new_vertex_map.find(need_vertex) == old_to_new_vertex_map.end()) { old_to_new_vertex_map[need_vertex] = need_vertex; vertex_map_requests[need_vertex.owner].push_back(need_vertex); } } inplace_all_to_all(pg, vertex_map_requests, vertex_map_responses); // Process the requests made for vertices we own. Then perform yet // another all-to-all swap. This one matches the requests we've // made to the responses we were given. for (process_id_type src = 0; src < p; ++src) for (typename std::vector<vertex_descriptor>::iterator vi = vertex_map_responses[src].begin(); vi != vertex_map_responses[src].end(); ++vi) *vi = old_to_new_vertex_map[*vi]; inplace_all_to_all(pg, vertex_map_responses); // Matching the requests to the responses, update the old->new // vertex map for all of the vertices we will need to know. for (process_id_type src = 0; src < p; ++src) { typedef typename std::vector<vertex_descriptor>::size_type size_type; for (size_type i = 0; i < vertex_map_requests[src].size(); ++i) { old_to_new_vertex_map[vertex_map_requests[src][i]] = vertex_map_responses[src][i]; } } } // Add edges to the graph by mapping the source and target. for (process_id_type src = 0; src < p; ++src) { for (typename std::vector<redistributed_edge>::iterator ei = redistributed_edges[src].begin(); ei != redistributed_edges[src].end(); ++ei) { add_edge(old_to_new_vertex_map[source(ei->descriptor, *this)], old_to_new_vertex_map[target(ei->descriptor, *this)], ei->get_property(), *this); } redistributed_edges[src].clear(); } // Be sure that edge-addition messages are received now, completing // the graph. synchronize(process_group_); this->distribution().clear(); detail::parallel::maybe_initialize_vertex_indices(vertices(base()), get(vertex_index, base())); } } // end namespace boost distributed/adjlist/serialization.hpp 0000644 00000100146 15125521275 0014115 0 ustar 00 // Copyright Daniel Wallin 2007. Use, modification and distribution is // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GRAPH_DISTRIBUTED_ADJLIST_SERIALIZATION_070925_HPP #define BOOST_GRAPH_DISTRIBUTED_ADJLIST_SERIALIZATION_070925_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif # include <boost/assert.hpp> # include <boost/lexical_cast.hpp> # include <boost/foreach.hpp> # include <boost/filesystem/path.hpp> # include <boost/filesystem/operations.hpp> # include <cctype> # include <fstream> namespace boost { namespace detail { namespace parallel { // Wraps a local descriptor, making it serializable. template <class Local> struct serializable_local_descriptor { serializable_local_descriptor() {} serializable_local_descriptor(Local local) : local(local) {} operator Local const&() const { return local; } bool operator==(serializable_local_descriptor const& other) const { return local == other.local; } bool operator<(serializable_local_descriptor const& other) const { return local < other.local; } template <class Archive> void serialize(Archive& ar, const unsigned int /*version*/) { ar & unsafe_serialize(local); } Local local; }; template <class Vertex, class Properties> struct pending_edge { pending_edge( Vertex source, Vertex target , Properties properties, void* property_ptr ) : source(source) , target(target) , properties(properties) , property_ptr(property_ptr) {} Vertex source; Vertex target; Properties properties; void* property_ptr; }; inline bool is_digit(char c) { return std::isdigit(c) != 0; } inline std::vector<int> available_process_files(std::string const& filename) { if (!filesystem::exists(filename)) return std::vector<int>(); std::vector<int> result; for (filesystem::directory_iterator i(filename), end; i != end; ++i) { if (!filesystem::is_regular(*i)) boost::throw_exception(std::runtime_error("directory contains non-regular entries")); std::string process_name = i->path().filename().string(); for (std::string::size_type i = 0; i < process_name.size(); ++i) if (!is_digit(process_name[i])) boost::throw_exception(std::runtime_error("directory contains files with invalid names")); result.push_back(boost::lexical_cast<int>(process_name)); } return result; } template <class Archive, class Tag, class T, class Base> void maybe_load_properties( Archive& ar, char const* name, property<Tag, T, Base>& properties) { ar >> serialization::make_nvp(name, get_property_value(properties, Tag())); maybe_load_properties(ar, name, static_cast<Base&>(properties)); } template <class Archive> void maybe_load_properties( Archive&, char const*, no_property&) {} template <class Archive, typename Bundle> void maybe_load_properties( Archive& ar, char const* name, Bundle& bundle) { ar >> serialization::make_nvp(name, bundle); no_property prop; maybe_load_properties(ar, name, prop); } template <class Graph, class Archive, class VertexListS> struct graph_loader { typedef typename Graph::vertex_descriptor vertex_descriptor; typedef typename Graph::local_vertex_descriptor local_vertex_descriptor; typedef typename Graph::vertex_property_type vertex_property_type; typedef typename Graph::edge_descriptor edge_descriptor; typedef typename Graph::local_edge_descriptor local_edge_descriptor; typedef typename Graph::edge_property_type edge_property_type; typedef typename Graph::process_group_type process_group_type; typedef typename process_group_type::process_id_type process_id_type; typedef typename Graph::directed_selector directed_selector; typedef typename mpl::if_< is_same<VertexListS, defaultS>, vecS, VertexListS >::type vertex_list_selector; typedef pending_edge<vertex_descriptor, edge_property_type> pending_edge_type; typedef serializable_local_descriptor<local_vertex_descriptor> serializable_vertex_descriptor; graph_loader(Graph& g, Archive& ar) : m_g(g) , m_ar(ar) , m_pg(g.process_group()) , m_requested_vertices(num_processes(m_pg)) , m_remote_vertices(num_processes(m_pg)) , m_property_ptrs(num_processes(m_pg)) { g.clear(); load_prefix(); load_vertices(); load_edges(); ar >> make_nvp("distribution", m_g.distribution()); } private: struct pending_in_edge { pending_in_edge( vertex_descriptor u, vertex_descriptor v, void* property_ptr ) : u(u) , v(v) , property_ptr(property_ptr) {} vertex_descriptor u; vertex_descriptor v; void* property_ptr; }; bool is_root() const { return process_id(m_pg) == 0; } template <class T> serialization::nvp<T> const make_nvp(char const* name, T& value) const { return serialization::nvp<T>(name, value); } void load_prefix(); void load_vertices(); template <class Anything> void maybe_load_and_store_local_vertex(Anything); void maybe_load_and_store_local_vertex(vecS); void load_edges(); void load_in_edges(bidirectionalS); void load_in_edges(directedS); void add_pending_in_edge( vertex_descriptor u, vertex_descriptor v, void* property_ptr, vecS); template <class Anything> void add_pending_in_edge( vertex_descriptor u, vertex_descriptor v, void* property_ptr, Anything); template <class Anything> void add_edge( vertex_descriptor u, vertex_descriptor v , edge_property_type const& property, void* property_ptr, Anything); void add_edge( vertex_descriptor u, vertex_descriptor v , edge_property_type const& property, void* property_ptr, vecS); void add_remote_vertex_request( vertex_descriptor u, vertex_descriptor v, directedS); void add_remote_vertex_request( vertex_descriptor u, vertex_descriptor v, bidirectionalS); void add_in_edge( edge_descriptor const&, void*, directedS); void add_in_edge( edge_descriptor const& edge, void* old_property_ptr, bidirectionalS); void resolve_remote_vertices(directedS); void resolve_remote_vertices(bidirectionalS); vertex_descriptor resolve_remote_vertex(vertex_descriptor u) const; vertex_descriptor resolve_remote_vertex(vertex_descriptor u, vecS) const; template <class Anything> vertex_descriptor resolve_remote_vertex(vertex_descriptor u, Anything) const; void resolve_property_ptrs(); void commit_pending_edges(vecS); template <class Anything> void commit_pending_edges(Anything); void commit_pending_in_edges(directedS); void commit_pending_in_edges(bidirectionalS); void* maybe_load_property_ptr(directedS) { return 0; } void* maybe_load_property_ptr(bidirectionalS); Graph& m_g; Archive& m_ar; process_group_type m_pg; std::vector<process_id_type> m_id_mapping; // Maps local vertices as loaded from the archive to // the ones actually added to the graph. Only used // when !vecS. std::map<local_vertex_descriptor, local_vertex_descriptor> m_local_vertices; // This is the list of remote vertex descriptors that we // are going to receive from other processes. This is // kept sorted so that we can determine the position of // the matching vertex descriptor in m_remote_vertices. std::vector<std::vector<serializable_vertex_descriptor> > m_requested_vertices; // This is the list of remote vertex descriptors that // we send and receive from other processes. std::vector<std::vector<serializable_vertex_descriptor> > m_remote_vertices; // ... std::vector<pending_edge_type> m_pending_edges; // The pending in-edges that will be added in the commit step, after // the remote vertex descriptors has been resolved. Only used // when bidirectionalS and !vecS. std::vector<pending_in_edge> m_pending_in_edges; std::vector<std::vector<unsafe_pair<void*,void*> > > m_property_ptrs; }; template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::load_prefix() { typename process_group_type::process_size_type num_processes_; m_ar >> make_nvp("num_processes", num_processes_); if (num_processes_ != num_processes(m_pg)) boost::throw_exception(std::runtime_error("number of processes mismatch")); process_id_type old_id; m_ar >> make_nvp("id", old_id); std::vector<typename Graph::distribution_type::size_type> mapping; m_ar >> make_nvp("mapping", mapping); // Fetch all the old id's from the other processes. std::vector<process_id_type> old_ids; all_gather(m_pg, &old_id, &old_id+1, old_ids); m_id_mapping.resize(num_processes(m_pg), -1); for (process_id_type i = 0; i < num_processes(m_pg); ++i) { # ifdef PBGL_SERIALIZE_DEBUG if (is_root()) std::cout << i << " used to be " << old_ids[i] << "\n"; # endif BOOST_ASSERT(m_id_mapping[old_ids[i]] == -1); m_id_mapping[old_ids[i]] = i; } std::vector<typename Graph::distribution_type::size_type> new_mapping( mapping.size()); for (int i = 0; i < num_processes(m_pg); ++i) { new_mapping[mapping[old_ids[i]]] = i; } m_g.distribution().assign_mapping( new_mapping.begin(), new_mapping.end()); } template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::load_vertices() { int V; m_ar >> BOOST_SERIALIZATION_NVP(V); # ifdef PBGL_SERIALIZE_DEBUG if (is_root()) std::cout << "Loading vertices\n"; # endif for (int i = 0; i < V; ++i) { maybe_load_and_store_local_vertex(vertex_list_selector()); } } template <class Graph, class Archive, class VertexListS> template <class Anything> void graph_loader<Graph, Archive, VertexListS>::maybe_load_and_store_local_vertex(Anything) { // Load the original vertex descriptor local_vertex_descriptor local; m_ar >> make_nvp("local", unsafe_serialize(local)); // Load the properties vertex_property_type property; detail::parallel::maybe_load_properties(m_ar, "vertex_property", property); // Add the vertex vertex_descriptor v(process_id(m_pg), add_vertex(property, m_g.base())); if (m_g.on_add_vertex) m_g.on_add_vertex(v, m_g); // Create the mapping from the "old" local descriptor to the new // local descriptor. m_local_vertices[local] = v.local; } template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::maybe_load_and_store_local_vertex(vecS) { // Load the properties vertex_property_type property; detail::parallel::maybe_load_properties(m_ar, "vertex_property", property); // Add the vertex vertex_descriptor v(process_id(m_pg), add_vertex(m_g.build_vertex_property(property), m_g.base())); if (m_g.on_add_vertex) m_g.on_add_vertex(v, m_g); } template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::load_edges() { int E; m_ar >> BOOST_SERIALIZATION_NVP(E); # ifdef PBGL_SERIALIZE_DEBUG if (is_root()) std::cout << "Loading edges\n"; # endif for (int i = 0; i < E; ++i) { local_vertex_descriptor local_src; process_id_type target_owner; local_vertex_descriptor local_tgt; m_ar >> make_nvp("source", unsafe_serialize(local_src)); m_ar >> make_nvp("target_owner", target_owner); m_ar >> make_nvp("target", unsafe_serialize(local_tgt)); process_id_type new_src_owner = process_id(m_pg); process_id_type new_tgt_owner = m_id_mapping[target_owner]; vertex_descriptor source(new_src_owner, local_src); vertex_descriptor target(new_tgt_owner, local_tgt); edge_property_type properties; detail::parallel::maybe_load_properties(m_ar, "edge_property", properties); void* property_ptr = maybe_load_property_ptr(directed_selector()); add_edge(source, target, properties, property_ptr, vertex_list_selector()); } load_in_edges(directed_selector()); commit_pending_edges(vertex_list_selector()); } template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::load_in_edges(bidirectionalS) { std::size_t I; m_ar >> BOOST_SERIALIZATION_NVP(I); # ifdef PBGL_SERIALIZE_DEBUG if (is_root()) std::cout << "Loading in-edges\n"; # endif for (int i = 0; i < I; ++i) { process_id_type src_owner; local_vertex_descriptor local_src; local_vertex_descriptor local_target; void* property_ptr; m_ar >> make_nvp("src_owner", src_owner); m_ar >> make_nvp("source", unsafe_serialize(local_src)); m_ar >> make_nvp("target", unsafe_serialize(local_target)); m_ar >> make_nvp("property_ptr", unsafe_serialize(property_ptr)); src_owner = m_id_mapping[src_owner]; vertex_descriptor u(src_owner, local_src); vertex_descriptor v(process_id(m_pg), local_target); add_pending_in_edge(u, v, property_ptr, vertex_list_selector()); } } template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::load_in_edges(directedS) {} template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::add_pending_in_edge( vertex_descriptor u, vertex_descriptor v, void* property_ptr, vecS) { m_pending_in_edges.push_back(pending_in_edge(u,v,property_ptr)); } template <class Graph, class Archive, class VertexListS> template <class Anything> void graph_loader<Graph, Archive, VertexListS>::add_pending_in_edge( vertex_descriptor u, vertex_descriptor v, void* property_ptr, Anything) { // u and v represent the out-edge here, meaning v is local // to us, and u is always remote. m_pending_in_edges.push_back(pending_in_edge(u,v,property_ptr)); add_remote_vertex_request(v, u, bidirectionalS()); } template <class Graph, class Archive, class VertexListS> template <class Anything> void graph_loader<Graph, Archive, VertexListS>::add_edge( vertex_descriptor u, vertex_descriptor v , edge_property_type const& property, void* property_ptr, Anything) { m_pending_edges.push_back(pending_edge_type(u, v, property, property_ptr)); add_remote_vertex_request(u, v, directed_selector()); } template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::add_remote_vertex_request( vertex_descriptor u, vertex_descriptor v, directedS) { // We have to request the remote vertex. m_requested_vertices[owner(v)].push_back(local(v)); } template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::add_remote_vertex_request( vertex_descriptor u, vertex_descriptor v, bidirectionalS) { // If the edge spans to another process, we know // that that process has a matching in-edge, so // we can just send our vertex. No requests // necessary. if (owner(v) != m_g.processor()) { m_remote_vertices[owner(v)].push_back(local(u)); m_requested_vertices[owner(v)].push_back(local(v)); } } template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::add_edge( vertex_descriptor u, vertex_descriptor v , edge_property_type const& property, void* property_ptr, vecS) { std::pair<local_edge_descriptor, bool> inserted = detail::parallel::add_local_edge( local(u), local(v) , m_g.build_edge_property(property), m_g.base()); BOOST_ASSERT(inserted.second); put(edge_target_processor_id, m_g.base(), inserted.first, owner(v)); edge_descriptor e(owner(u), owner(v), true, inserted.first); if (inserted.second && m_g.on_add_edge) m_g.on_add_edge(e, m_g); add_in_edge(e, property_ptr, directed_selector()); } template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::add_in_edge( edge_descriptor const&, void*, directedS) {} template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::add_in_edge( edge_descriptor const& edge, void* old_property_ptr, bidirectionalS) { if (owner(target(edge, m_g)) == m_g.processor()) { detail::parallel::stored_in_edge<local_edge_descriptor> e(m_g.processor(), local(edge)); boost::graph_detail::push(get( vertex_in_edges, m_g.base())[local(target(edge, m_g))], e); } else { // We send the (old,new) property pointer pair to // the remote process. This could be optimized to // only send the new one -- the ordering can be // made implicit because the old pointer value is // stored on the remote process. // // Doing that is a little bit more complicated, but // in case it turns out it's important we can do it. void* property_ptr = local(edge).get_property(); m_property_ptrs[owner(target(edge, m_g))].push_back( unsafe_pair<void*,void*>(old_property_ptr, property_ptr)); } } template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::resolve_property_ptrs() { # ifdef PBGL_SERIALIZE_DEBUG if (is_root()) std::cout << "Resolving property pointers\n"; # endif for (int i = 0; i < num_processes(m_pg); ++i) { std::sort( m_property_ptrs[i].begin(), m_property_ptrs[i].end()); } boost::parallel::inplace_all_to_all(m_pg, m_property_ptrs); } template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertices(directedS) { for (int i = 0; i < num_processes(m_pg); ++i) { std::sort(m_requested_vertices[i].begin(), m_requested_vertices[i].end()); } boost::parallel::inplace_all_to_all( m_pg, m_requested_vertices, m_remote_vertices); for (int i = 0; i < num_processes(m_pg); ++i) { BOOST_FOREACH(serializable_vertex_descriptor& u, m_remote_vertices[i]) { u = m_local_vertices[u]; } } boost::parallel::inplace_all_to_all(m_pg, m_remote_vertices); } template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertices(bidirectionalS) { # ifdef PBGL_SERIALIZE_DEBUG if (is_root()) std::cout << "Resolving remote vertices\n"; # endif for (int i = 0; i < num_processes(m_pg); ++i) { std::sort(m_requested_vertices[i].begin(), m_requested_vertices[i].end()); std::sort(m_remote_vertices[i].begin(), m_remote_vertices[i].end()); BOOST_FOREACH(serializable_vertex_descriptor& u, m_remote_vertices[i]) { u = m_local_vertices[u]; } } boost::parallel::inplace_all_to_all(m_pg, m_remote_vertices); for (int i = 0; i < num_processes(m_pg); ++i) BOOST_ASSERT(m_remote_vertices[i].size() == m_requested_vertices[i].size()); } template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::commit_pending_edges(vecS) { commit_pending_in_edges(directed_selector()); } template <class Graph, class Archive, class VertexListS> template <class Anything> void graph_loader<Graph, Archive, VertexListS>::commit_pending_edges(Anything) { resolve_remote_vertices(directed_selector()); BOOST_FOREACH(pending_edge_type const& e, m_pending_edges) { vertex_descriptor u = resolve_remote_vertex(e.source); vertex_descriptor v = resolve_remote_vertex(e.target); add_edge(u, v, e.properties, e.property_ptr, vecS()); } commit_pending_in_edges(directed_selector()); } template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::commit_pending_in_edges(directedS) {} template <class Graph, class Archive, class VertexListS> void graph_loader<Graph, Archive, VertexListS>::commit_pending_in_edges(bidirectionalS) { resolve_property_ptrs(); BOOST_FOREACH(pending_in_edge const& e, m_pending_in_edges) { vertex_descriptor u = resolve_remote_vertex(e.u, vertex_list_selector()); vertex_descriptor v = resolve_remote_vertex(e.v, vertex_list_selector()); typedef detail::parallel::stored_in_edge<local_edge_descriptor> stored_edge; std::vector<unsafe_pair<void*,void*> >::iterator i = std::lower_bound( m_property_ptrs[owner(u)].begin() , m_property_ptrs[owner(u)].end() , unsafe_pair<void*,void*>(e.property_ptr, 0) ); if (i == m_property_ptrs[owner(u)].end() || i->first != e.property_ptr) { BOOST_ASSERT(false); } local_edge_descriptor local_edge(local(u), local(v), i->second); stored_edge edge(owner(u), local_edge); boost::graph_detail::push( get(vertex_in_edges, m_g.base())[local(v)], edge); } } template <class Graph, class Archive, class VertexListS> typename graph_loader<Graph, Archive, VertexListS>::vertex_descriptor graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertex( vertex_descriptor u) const { if (owner(u) == process_id(m_pg)) { return vertex_descriptor( process_id(m_pg), m_local_vertices.find(local(u))->second); } typename std::vector<serializable_vertex_descriptor>::const_iterator i = std::lower_bound( m_requested_vertices[owner(u)].begin() , m_requested_vertices[owner(u)].end() , serializable_vertex_descriptor(local(u)) ); if (i == m_requested_vertices[owner(u)].end() || *i != local(u)) { BOOST_ASSERT(false); } local_vertex_descriptor local = m_remote_vertices[owner(u)][m_requested_vertices[owner(u)].end() - i]; return vertex_descriptor(owner(u), local); } template <class Graph, class Archive, class VertexListS> typename graph_loader<Graph, Archive, VertexListS>::vertex_descriptor graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertex( vertex_descriptor u, vecS) const { return u; } template <class Graph, class Archive, class VertexListS> template <class Anything> typename graph_loader<Graph, Archive, VertexListS>::vertex_descriptor graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertex( vertex_descriptor u, Anything) const { return resolve_remote_vertex(u); } template <class Graph, class Archive, class VertexListS> void* graph_loader<Graph, Archive, VertexListS>::maybe_load_property_ptr(bidirectionalS) { void* ptr; m_ar >> make_nvp("property_ptr", unsafe_serialize(ptr)); return ptr; } template <class Archive, class D> void maybe_save_local_descriptor(Archive& ar, D const&, vecS) {} template <class Archive, class D, class NotVecS> void maybe_save_local_descriptor(Archive& ar, D const& d, NotVecS) { ar << serialization::make_nvp( "local", unsafe_serialize(const_cast<D&>(d))); } template <class Archive> void maybe_save_properties( Archive&, char const*, no_property const&) {} template <class Archive, class Tag, class T, class Base> void maybe_save_properties( Archive& ar, char const* name, property<Tag, T, Base> const& properties) { ar & serialization::make_nvp(name, get_property_value(properties, Tag())); maybe_save_properties(ar, name, static_cast<Base const&>(properties)); } template <class Archive, class Graph> void save_in_edges(Archive& ar, Graph const& g, directedS) {} // We need to save the edges in the base edge // list, and the in_edges that are stored in the // vertex_in_edges vertex property. template <class Archive, class Graph> void save_in_edges(Archive& ar, Graph const& g, bidirectionalS) { typedef typename Graph::process_group_type process_group_type; typedef typename process_group_type::process_id_type process_id_type; typedef typename graph_traits< Graph>::vertex_descriptor vertex_descriptor; typedef typename vertex_descriptor::local_descriptor_type local_vertex_descriptor; typedef typename graph_traits< Graph>::edge_descriptor edge_descriptor; process_id_type id = g.processor(); std::vector<edge_descriptor> saved_in_edges; BGL_FORALL_VERTICES_T(v, g, Graph) { BOOST_FOREACH(edge_descriptor const& e, in_edges(v, g)) { // Only save the in_edges that isn't owned by this process. if (owner(e) == id) continue; saved_in_edges.push_back(e); } } std::size_t I = saved_in_edges.size(); ar << BOOST_SERIALIZATION_NVP(I); BOOST_FOREACH(edge_descriptor const& e, saved_in_edges) { process_id_type src_owner = owner(source(e,g)); local_vertex_descriptor local_src = local(source(e,g)); local_vertex_descriptor local_target = local(target(e,g)); void* property_ptr = local(e).get_property(); using serialization::make_nvp; ar << make_nvp("src_owner", src_owner); ar << make_nvp("source", unsafe_serialize(local_src)); ar << make_nvp("target", unsafe_serialize(local_target)); ar << make_nvp("property_ptr", unsafe_serialize(property_ptr)); } } template <class Archive, class Edge> void maybe_save_property_ptr(Archive&, Edge const&, directedS) {} template <class Archive, class Edge> void maybe_save_property_ptr(Archive& ar, Edge const& e, bidirectionalS) { void* ptr = local(e).get_property(); ar << serialization::make_nvp("property_ptr", unsafe_serialize(ptr)); } template <class Archive, class Graph, class DirectedS> void save_edges(Archive& ar, Graph const& g, DirectedS) { typedef typename Graph::process_group_type process_group_type; typedef typename process_group_type::process_id_type process_id_type; typedef typename graph_traits< Graph>::vertex_descriptor vertex_descriptor; typedef typename Graph::edge_property_type edge_property_type; int E = num_edges(g); ar << BOOST_SERIALIZATION_NVP(E); // For *directed* graphs, we can just save // the edge list and be done. // // For *bidirectional* graphs, we need to also // save the "vertex_in_edges" property map, // because it might contain in-edges that // are not locally owned. BGL_FORALL_EDGES_T(e, g, Graph) { vertex_descriptor src(source(e, g)); vertex_descriptor tgt(target(e, g)); typename vertex_descriptor::local_descriptor_type local_u(local(src)); typename vertex_descriptor::local_descriptor_type local_v(local(tgt)); process_id_type target_owner = owner(tgt); using serialization::make_nvp; ar << make_nvp("source", unsafe_serialize(local_u)); ar << make_nvp("target_owner", target_owner); ar << make_nvp("target", unsafe_serialize(local_v)); maybe_save_properties( ar, "edge_property" , static_cast<edge_property_type const&>(get(edge_all_t(), g, e)) ); maybe_save_property_ptr(ar, e, DirectedS()); } save_in_edges(ar, g, DirectedS()); } }} // namespace detail::parallel template <PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> template <class IStreamConstructibleArchive> void PBGL_DISTRIB_ADJLIST_TYPE::load(std::string const& filename) { process_group_type pg = process_group(); process_id_type id = process_id(pg); synchronize(pg); std::vector<int> disk_files = detail::parallel::available_process_files(filename); std::sort(disk_files.begin(), disk_files.end()); // Negotiate which process gets which file. Serialized. std::vector<int> consumed_files; int picked_file = -1; if (id > 0) receive_oob(pg, id-1, 0, consumed_files); std::sort(consumed_files.begin(), consumed_files.end()); std::vector<int> available_files; std::set_difference( disk_files.begin(), disk_files.end() , consumed_files.begin(), consumed_files.end() , std::back_inserter(available_files) ); if (available_files.empty()) boost::throw_exception(std::runtime_error("no file available")); // back() used for debug purposes. Making sure the // ranks are shuffled. picked_file = available_files.back(); # ifdef PBGL_SERIALIZE_DEBUG std::cout << id << " picked " << picked_file << "\n"; # endif consumed_files.push_back(picked_file); if (id < num_processes(pg) - 1) send_oob(pg, id+1, 0, consumed_files); std::string local_filename = filename + "/" + lexical_cast<std::string>(picked_file); std::ifstream in(local_filename.c_str(), std::ios_base::binary); IStreamConstructibleArchive ar(in); detail::parallel::graph_loader< graph_type, IStreamConstructibleArchive, InVertexListS > loader(*this, ar); # ifdef PBGL_SERIALIZE_DEBUG std::cout << "Process " << id << " done loading.\n"; # endif synchronize(pg); } template <PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> template <class OStreamConstructibleArchive> void PBGL_DISTRIB_ADJLIST_TYPE::save(std::string const& filename) const { typedef typename config_type::VertexListS vertex_list_selector; process_group_type pg = process_group(); process_id_type id = process_id(pg); if (filesystem::exists(filename) && !filesystem::is_directory(filename)) boost::throw_exception(std::runtime_error("entry exists, but is not a directory")); filesystem::remove_all(filename); filesystem::create_directory(filename); synchronize(pg); std::string local_filename = filename + "/" + lexical_cast<std::string>(id); std::ofstream out(local_filename.c_str(), std::ios_base::binary); OStreamConstructibleArchive ar(out); using serialization::make_nvp; typename process_group_type::process_size_type num_processes_ = num_processes(pg); ar << make_nvp("num_processes", num_processes_); ar << BOOST_SERIALIZATION_NVP(id); ar << make_nvp("mapping", this->distribution().mapping()); int V = num_vertices(*this); ar << BOOST_SERIALIZATION_NVP(V); BGL_FORALL_VERTICES_T(v, *this, graph_type) { local_vertex_descriptor local_descriptor(local(v)); detail::parallel::maybe_save_local_descriptor( ar, local_descriptor, vertex_list_selector()); detail::parallel::maybe_save_properties( ar, "vertex_property" , static_cast<vertex_property_type const&>(get(vertex_all_t(), *this, v)) ); } detail::parallel::save_edges(ar, *this, directed_selector()); ar << make_nvp("distribution", this->distribution()); } } // namespace boost #endif // BOOST_GRAPH_DISTRIBUTED_ADJLIST_SERIALIZATION_070925_HPP distributed/vertex_list_adaptor.hpp 0000644 00000037574 15125521275 0013706 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_VERTEX_LIST_ADAPTOR_HPP #define BOOST_VERTEX_LIST_ADAPTOR_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/graph_traits.hpp> #include <vector> #include <boost/shared_ptr.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/parallel/algorithm.hpp> #include <boost/graph/parallel/container_traits.hpp> #include <boost/property_map/vector_property_map.hpp> namespace boost { namespace graph { // -------------------------------------------------------------------------- // Global index map built from a distribution // -------------------------------------------------------------------------- template<typename Distribution, typename OwnerPropertyMap, typename LocalPropertyMap> class distribution_global_index_map { public: typedef std::size_t value_type; typedef value_type reference; typedef typename property_traits<OwnerPropertyMap>::key_type key_type; typedef readable_property_map_tag category; distribution_global_index_map(const Distribution& distribution, const OwnerPropertyMap& owner, const LocalPropertyMap& local) : distribution_(distribution), owner(owner), local(local) { } Distribution distribution_; OwnerPropertyMap owner; LocalPropertyMap local; }; template<typename Distribution, typename OwnerPropertyMap, typename LocalPropertyMap> inline typename distribution_global_index_map<Distribution, OwnerPropertyMap, LocalPropertyMap>::value_type get(const distribution_global_index_map<Distribution, OwnerPropertyMap, LocalPropertyMap>& p, typename distribution_global_index_map<Distribution, OwnerPropertyMap, LocalPropertyMap>::key_type x) { using boost::get; return p.distribution_.global(get(p.owner, x), get(p.local, x)); } template<typename Graph, typename Distribution> inline distribution_global_index_map< Distribution, typename property_map<Graph, vertex_owner_t>::const_type, typename property_map<Graph, vertex_local_t>::const_type> make_distribution_global_index_map(const Graph& g, const Distribution& d) { typedef distribution_global_index_map< Distribution, typename property_map<Graph, vertex_owner_t>::const_type, typename property_map<Graph, vertex_local_t>::const_type> result_type; return result_type(d, get(vertex_owner, g), get(vertex_local, g)); } // -------------------------------------------------------------------------- // Global index map built from a distributed index map and list of vertices // -------------------------------------------------------------------------- template<typename IndexMap> class stored_global_index_map : public IndexMap { public: typedef readable_property_map_tag category; stored_global_index_map(const IndexMap& index_map) : IndexMap(index_map) { // When we have a global index, we need to always have the indices // of every key we've seen this->set_max_ghost_cells(0); } }; // -------------------------------------------------------------------------- // Global index map support code // -------------------------------------------------------------------------- namespace detail { template<typename PropertyMap, typename ForwardIterator> inline void initialize_global_index_map(const PropertyMap&, ForwardIterator, ForwardIterator) { } template<typename IndexMap, typename ForwardIterator> void initialize_global_index_map(stored_global_index_map<IndexMap>& p, ForwardIterator first, ForwardIterator last) { using std::distance; typedef typename property_traits<IndexMap>::value_type size_t; size_t n = distance(first, last); for (size_t i = 0; i < n; ++i, ++first) local_put(p, *first, i); } } // -------------------------------------------------------------------------- // Adapts a Distributed Vertex List Graph to a Vertex List Graph // -------------------------------------------------------------------------- template<typename Graph, typename GlobalIndexMap> class vertex_list_adaptor : public graph_traits<Graph> { typedef graph_traits<Graph> inherited; typedef typename inherited::traversal_category base_traversal_category; public: typedef typename inherited::vertex_descriptor vertex_descriptor; typedef typename std::vector<vertex_descriptor>::iterator vertex_iterator; typedef typename std::vector<vertex_descriptor>::size_type vertices_size_type; struct traversal_category : public virtual base_traversal_category, public virtual vertex_list_graph_tag {}; vertex_list_adaptor(const Graph& g, const GlobalIndexMap& index_map = GlobalIndexMap()) : g(&g), index_map(index_map) { using boost::vertices; all_vertices_.reset(new std::vector<vertex_descriptor>()); all_gather(process_group(), vertices(g).first, vertices(g).second, *all_vertices_); detail::initialize_global_index_map(this->index_map, all_vertices_->begin(), all_vertices_->end()); } const Graph& base() const { return *g; } // -------------------------------------------------------------------------- // Distributed Container // -------------------------------------------------------------------------- typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type; process_group_type process_group() const { using boost::graph::parallel::process_group; return process_group(*g); } std::pair<vertex_iterator, vertex_iterator> vertices() const { return std::make_pair(all_vertices_->begin(), all_vertices_->end()); } vertices_size_type num_vertices() const { return all_vertices_->size(); } GlobalIndexMap get_index_map() const { return index_map; } private: const Graph* g; GlobalIndexMap index_map; shared_ptr<std::vector<vertex_descriptor> > all_vertices_; }; template<typename Graph, typename GlobalIndexMap> inline vertex_list_adaptor<Graph, GlobalIndexMap> make_vertex_list_adaptor(const Graph& g, const GlobalIndexMap& index_map) { return vertex_list_adaptor<Graph, GlobalIndexMap>(g, index_map); } namespace detail { template<typename Graph> class default_global_index_map { typedef typename graph_traits<Graph>::vertices_size_type value_type; typedef typename property_map<Graph, vertex_index_t>::const_type local_map; public: typedef vector_property_map<value_type, local_map> distributed_map; typedef stored_global_index_map<distributed_map> type; }; } template<typename Graph> inline vertex_list_adaptor<Graph, typename detail::default_global_index_map<Graph>::type> make_vertex_list_adaptor(const Graph& g) { typedef typename detail::default_global_index_map<Graph>::type GlobalIndexMap; typedef typename detail::default_global_index_map<Graph>::distributed_map DistributedMap; typedef vertex_list_adaptor<Graph, GlobalIndexMap> result_type; return result_type(g, GlobalIndexMap(DistributedMap(num_vertices(g), get(vertex_index, g)))); } // -------------------------------------------------------------------------- // Incidence Graph // -------------------------------------------------------------------------- template<typename Graph, typename GlobalIndexMap> inline typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor source(typename vertex_list_adaptor<Graph, GlobalIndexMap>::edge_descriptor e, const vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return source(e, g.base()); } template<typename Graph, typename GlobalIndexMap> inline typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor target(typename vertex_list_adaptor<Graph, GlobalIndexMap>::edge_descriptor e, const vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return target(e, g.base()); } template<typename Graph, typename GlobalIndexMap> inline std::pair<typename vertex_list_adaptor<Graph, GlobalIndexMap>::out_edge_iterator, typename vertex_list_adaptor<Graph, GlobalIndexMap>::out_edge_iterator> out_edges(typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor v, const vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return out_edges(v, g.base()); } template<typename Graph, typename GlobalIndexMap> inline typename vertex_list_adaptor<Graph, GlobalIndexMap>::degree_size_type out_degree(typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor v, const vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return out_degree(v, g.base()); } // -------------------------------------------------------------------------- // Bidirectional Graph // -------------------------------------------------------------------------- template<typename Graph, typename GlobalIndexMap> inline std::pair<typename vertex_list_adaptor<Graph, GlobalIndexMap>::in_edge_iterator, typename vertex_list_adaptor<Graph, GlobalIndexMap>::in_edge_iterator> in_edges(typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor v, const vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return in_edges(v, g.base()); } template<typename Graph, typename GlobalIndexMap> inline typename vertex_list_adaptor<Graph, GlobalIndexMap>::degree_size_type in_degree(typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor v, const vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return in_degree(v, g.base()); } template<typename Graph, typename GlobalIndexMap> inline typename vertex_list_adaptor<Graph, GlobalIndexMap>::degree_size_type degree(typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor v, const vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return degree(v, g.base()); } // -------------------------------------------------------------------------- // Adjacency Graph // -------------------------------------------------------------------------- template<typename Graph, typename GlobalIndexMap> inline std::pair<typename vertex_list_adaptor<Graph, GlobalIndexMap>::adjacency_iterator, typename vertex_list_adaptor<Graph, GlobalIndexMap>::adjacency_iterator> adjacent_vertices(typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor v, const vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return adjacent_vertices(v, g.base()); } // -------------------------------------------------------------------------- // Vertex List Graph // -------------------------------------------------------------------------- template<typename Graph, typename GlobalIndexMap> inline std::pair<typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_iterator, typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_iterator> vertices(const vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return g.vertices(); } template<typename Graph, typename GlobalIndexMap> inline typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertices_size_type num_vertices(const vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return g.num_vertices(); } // -------------------------------------------------------------------------- // Edge List Graph // -------------------------------------------------------------------------- template<typename Graph, typename GlobalIndexMap> inline std::pair<typename vertex_list_adaptor<Graph, GlobalIndexMap>::edge_iterator, typename vertex_list_adaptor<Graph, GlobalIndexMap>::edge_iterator> edges(const vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return edges(g.base()); } template<typename Graph, typename GlobalIndexMap> inline typename vertex_list_adaptor<Graph, GlobalIndexMap>::edges_size_type num_edges(const vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return num_edges(g.base()); } // -------------------------------------------------------------------------- // Property Graph // -------------------------------------------------------------------------- template<typename PropertyTag, typename Graph, typename GlobalIndexMap> inline typename property_map<Graph, PropertyTag>::type get(PropertyTag p, vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return get(p, g.base()); } template<typename PropertyTag, typename Graph, typename GlobalIndexMap> inline typename property_map<Graph, PropertyTag>::const_type get(PropertyTag p, const vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return get(p, g.base()); } template<typename PropertyTag, typename Graph, typename GlobalIndexMap> inline typename property_traits< typename property_map<Graph, PropertyTag>::type >::value_type get(PropertyTag p, const vertex_list_adaptor<Graph, GlobalIndexMap>& g, typename property_traits< typename property_map<Graph, PropertyTag>::type >::key_type const& x) { return get(p, g.base(), x); } template<typename PropertyTag, typename Graph, typename GlobalIndexMap> inline void put(PropertyTag p, vertex_list_adaptor<Graph, GlobalIndexMap>& g, typename property_traits< typename property_map<Graph, PropertyTag>::type >::key_type const& x, typename property_traits< typename property_map<Graph, PropertyTag>::type >::value_type const& v) { return put(p, g.base(), x, v); } // -------------------------------------------------------------------------- // Property Graph: vertex_index property // -------------------------------------------------------------------------- template<typename Graph, typename GlobalIndexMap> inline GlobalIndexMap get(vertex_index_t, const vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return g.get_index_map(); } template<typename Graph, typename GlobalIndexMap> inline typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertices_size_type get(vertex_index_t, const vertex_list_adaptor<Graph, GlobalIndexMap>& g, typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor x) { return get(g.get_index_map(), x); } // -------------------------------------------------------------------------- // Adjacency Matrix Graph // -------------------------------------------------------------------------- template<typename Graph, typename GlobalIndexMap> std::pair<typename vertex_list_adaptor<Graph, GlobalIndexMap>::edge_descriptor, bool> edge(typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor u, typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor v, vertex_list_adaptor<Graph, GlobalIndexMap>& g) { return edge(u, v, g.base()); } } } // end namespace boost::graph namespace boost { // -------------------------------------------------------------------------- // Property Graph: vertex_index property // -------------------------------------------------------------------------- template<typename Graph, typename GlobalIndexMap> class property_map<vertex_index_t, graph::vertex_list_adaptor<Graph, GlobalIndexMap> > { public: typedef GlobalIndexMap type; typedef type const_type; }; template<typename Graph, typename GlobalIndexMap> class property_map<vertex_index_t, const graph::vertex_list_adaptor<Graph, GlobalIndexMap> > { public: typedef GlobalIndexMap type; typedef type const_type; }; using graph::distribution_global_index_map; using graph::make_distribution_global_index_map; using graph::stored_global_index_map; using graph::make_vertex_list_adaptor; using graph::vertex_list_adaptor; } // end namespace boost #endif // BOOST_VERTEX_LIST_ADAPTOR_HPP distributed/page_rank.hpp 0000644 00000017503 15125521275 0011541 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Copyright (C) 2002 Brad King and Douglas Gregor // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine // Brian Barrett #ifndef BOOST_PARALLEL_GRAPH_PAGE_RANK_HPP #define BOOST_PARALLEL_GRAPH_PAGE_RANK_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/assert.hpp> #include <boost/graph/overloading.hpp> #include <boost/graph/page_rank.hpp> #include <boost/graph/distributed/concepts.hpp> #include <boost/property_map/parallel/distributed_property_map.hpp> #include <boost/property_map/parallel/caching_property_map.hpp> #include <boost/graph/parallel/algorithm.hpp> #include <boost/graph/parallel/container_traits.hpp> // #define WANT_MPI_ONESIDED 1 namespace boost { namespace graph { namespace distributed { namespace detail { #ifdef WANT_MPI_ONESIDED template<typename Graph, typename RankMap, typename owner_map_t> void page_rank_step(const Graph& g, RankMap from_rank, MPI_Win to_win, typename property_traits<RankMap>::value_type damping, owner_map_t owner) { typedef typename property_traits<RankMap>::value_type rank_type; int me, ret; MPI_Comm_rank(MPI_COMM_WORLD, &me); // MPI_Accumulate is not required to store the value of the data // being sent, only the address. The value of the memory location // must not change until the end of the access epoch, meaning the // call to MPI_Fence. We therefore store the updated value back // into the from_rank map before the accumulate rather than using // a temporary. We're going to reset the values in the from_rank // before the end of page_rank_step() anyway, so this isn't a huge // deal. But MPI-2 One-sided is an abomination. BGL_FORALL_VERTICES_T(u, g, Graph) { put(from_rank, u, (damping * get(from_rank, u) / out_degree(u, g))); BGL_FORALL_ADJ_T(u, v, g, Graph) { ret = MPI_Accumulate(&(from_rank[u]), 1, MPI_DOUBLE, get(owner, v), local(v), 1, MPI_DOUBLE, MPI_SUM, to_win); BOOST_ASSERT(MPI_SUCCESS == ret); } } MPI_Win_fence(0, to_win); // Set new rank maps for the other map. Do this now to get around // the stupid synchronization rules of MPI-2 One-sided BGL_FORALL_VERTICES_T(v, g, Graph) put(from_rank, v, rank_type(1 - damping)); } #endif template<typename T> struct rank_accumulate_reducer { BOOST_STATIC_CONSTANT(bool, non_default_resolver = true); template<typename K> T operator()(const K&) const { return T(0); } template<typename K> T operator()(const K&, const T& x, const T& y) const { return x + y; } }; } // end namespace detail template<typename Graph, typename RankMap, typename Done, typename RankMap2> void page_rank_impl(const Graph& g, RankMap rank_map, Done done, typename property_traits<RankMap>::value_type damping, typename graph_traits<Graph>::vertices_size_type n, RankMap2 rank_map2) { typedef typename property_traits<RankMap>::value_type rank_type; int me; MPI_Comm_rank(MPI_COMM_WORLD, &me); typename property_map<Graph, vertex_owner_t>::const_type owner = get(vertex_owner, g); (void)owner; typedef typename boost::graph::parallel::process_group_type<Graph> ::type process_group_type; typedef typename process_group_type::process_id_type process_id_type; process_group_type pg = process_group(g); process_id_type id = process_id(pg); BOOST_ASSERT(me == id); rank_type initial_rank = rank_type(rank_type(1) / n); BGL_FORALL_VERTICES_T(v, g, Graph) put(rank_map, v, initial_rank); #ifdef WANT_MPI_ONESIDED BOOST_ASSERT(sizeof(rank_type) == sizeof(double)); bool to_map_2 = true; MPI_Win win, win2; MPI_Win_create(&(rank_map[*(vertices(g).first)]), sizeof(double) * num_vertices(g), sizeof(double), MPI_INFO_NULL, MPI_COMM_WORLD, &win); MPI_Win_set_name(win, "rank_map_win"); MPI_Win_create(&(rank_map2[*(vertices(g).first)]), sizeof(double) * num_vertices(g), sizeof(double), MPI_INFO_NULL, MPI_COMM_WORLD, &win2); MPI_Win_set_name(win, "rank_map2_win"); // set initial rank maps for the first iteration... BGL_FORALL_VERTICES_T(v, g, Graph) put(rank_map2, v, rank_type(1 - damping)); MPI_Win_fence(0, win); MPI_Win_fence(0, win2); while ((to_map_2 && !done(rank_map, g)) || (!to_map_2 && !done(rank_map2, g))) { if (to_map_2) { graph::distributed::detail::page_rank_step(g, rank_map, win2, damping, owner); to_map_2 = false; } else { graph::distributed::detail::page_rank_step(g, rank_map2, win, damping, owner); to_map_2 = true; } } synchronize(boost::graph::parallel::process_group(g)); MPI_Win_free(&win); MPI_Win_free(&win2); #else // The ranks accumulate after each step. rank_map.set_reduce(detail::rank_accumulate_reducer<rank_type>()); rank_map2.set_reduce(detail::rank_accumulate_reducer<rank_type>()); rank_map.set_consistency_model(boost::parallel::cm_flush | boost::parallel::cm_reset); rank_map2.set_consistency_model(boost::parallel::cm_flush | boost::parallel::cm_reset); bool to_map_2 = true; while ((to_map_2 && !done(rank_map, g)) || (!to_map_2 && !done(rank_map2, g))) { /** * PageRank can implemented slightly more efficiently on a * bidirectional graph than on an incidence graph. However, * distributed PageRank requires that we have the rank of the * source vertex available locally, so we force the incidence * graph implementation, which pushes rank from source to * target. */ typedef incidence_graph_tag category; if (to_map_2) { graph::detail::page_rank_step(g, rank_map, rank_map2, damping, category()); to_map_2 = false; } else { graph::detail::page_rank_step(g, rank_map2, rank_map, damping, category()); to_map_2 = true; } using boost::graph::parallel::process_group; synchronize(process_group(g)); } rank_map.reset(); #endif if (!to_map_2) BGL_FORALL_VERTICES_T(v, g, Graph) put(rank_map, v, get(rank_map2, v)); } template<typename Graph, typename RankMap, typename Done, typename RankMap2> void page_rank(const Graph& g, RankMap rank_map, Done done, typename property_traits<RankMap>::value_type damping, typename graph_traits<Graph>::vertices_size_type n, RankMap2 rank_map2 BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag)) { (page_rank_impl)(g, rank_map, done, damping, n, rank_map2); } template<typename MutableGraph> void remove_dangling_links(MutableGraph& g BOOST_GRAPH_ENABLE_IF_MODELS_PARM(MutableGraph, distributed_graph_tag)) { typename graph_traits<MutableGraph>::vertices_size_type old_n; do { old_n = num_vertices(g); typename graph_traits<MutableGraph>::vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; /* in loop */) { typename graph_traits<MutableGraph>::vertex_descriptor v = *vi++; if (out_degree(v, g) == 0) { clear_vertex(v, g); remove_vertex(v, g); } } } while (num_vertices(g) < old_n); } } // end namespace distributed using distributed::page_rank; using distributed::remove_dangling_links; } } // end namespace boost::graph #endif // BOOST_PARALLEL_GRAPH_PAGE_RANK_HPP distributed/connected_components.hpp 0000644 00000067361 15125521275 0014030 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Nick Edmonds // Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_PARALLEL_CC_HPP #define BOOST_GRAPH_PARALLEL_CC_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/detail/is_sorted.hpp> #include <boost/assert.hpp> #include <boost/property_map/property_map.hpp> #include <boost/property_map/parallel/caching_property_map.hpp> #include <boost/graph/parallel/algorithm.hpp> #include <boost/pending/indirect_cmp.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/overloading.hpp> #include <boost/graph/distributed/concepts.hpp> #include <boost/graph/parallel/properties.hpp> #include <boost/graph/distributed/local_subgraph.hpp> #include <boost/graph/connected_components.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/graph/parallel/process_group.hpp> #include <boost/optional.hpp> #include <functional> #include <algorithm> #include <vector> #include <list> #include <boost/graph/parallel/container_traits.hpp> #include <boost/graph/iteration_macros.hpp> #define PBGL_IN_PLACE_MERGE /* In place merge instead of sorting */ //#define PBGL_SORT_ASSERT /* Assert sorted for in place merge */ /* Explicit sychronization in pointer doubling step? */ #define PBGL_EXPLICIT_SYNCH //#define PBGL_CONSTRUCT_METAGRAPH #ifdef PBGL_CONSTRUCT_METAGRAPH # define MAX_VERTICES_IN_METAGRAPH 10000 #endif namespace boost { namespace graph { namespace distributed { namespace cc_detail { enum connected_components_message { edges_msg, req_parents_msg, parents_msg, root_adj_msg }; template <typename Vertex> struct metaVertex { metaVertex() {} metaVertex(const Vertex& v) : name(v) {} template<typename Archiver> void serialize(Archiver& ar, const unsigned int /*version*/) { ar & name; } Vertex name; }; #ifdef PBGL_CONSTRUCT_METAGRAPH // Build meta-graph on result of local connected components template <typename Graph, typename ParentMap, typename RootIterator, typename AdjacencyMap> void build_local_metagraph(const Graph& g, ParentMap p, RootIterator r, RootIterator r_end, AdjacencyMap& adj) { // TODO: Static assert that AdjacencyMap::value_type is std::vector<vertex_descriptor> typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type; typedef typename process_group_type::process_id_type process_id_type; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; BOOST_STATIC_ASSERT((is_same<typename AdjacencyMap::mapped_type, std::vector<vertex_descriptor> >::value)); using boost::graph::parallel::process_group; process_group_type pg = process_group(g); process_id_type id = process_id(pg); if (id != 0) { // Send component roots and their associated edges to P0 for ( ; r != r_end; ++r ) { std::vector<vertex_descriptor> adjs(1, *r); // Root adjs.reserve(adjs.size() + adj[*r].size()); for (typename std::vector<vertex_descriptor>::iterator iter = adj[*r].begin(); iter != adj[*r].end(); ++iter) adjs.push_back(get(p, *iter)); // Adjacencies send(pg, 0, root_adj_msg, adjs); } } synchronize(pg); if (id == 0) { typedef metaVertex<vertex_descriptor> VertexProperties; typedef boost::adjacency_list<vecS, vecS, undirectedS, VertexProperties> metaGraph; typedef typename graph_traits<metaGraph>::vertex_descriptor meta_vertex_descriptor; std::map<vertex_descriptor, meta_vertex_descriptor> vertex_map; std::vector<std::pair<vertex_descriptor, vertex_descriptor> > edges; // Receive remote roots and edges while (optional<std::pair<process_id_type, int> > m = probe(pg)) { BOOST_ASSERT(m->second == root_adj_msg); std::vector<vertex_descriptor> adjs; receive(pg, m->first, m->second, adjs); vertex_map[adjs[0]] = graph_traits<metaGraph>::null_vertex(); for (typename std::vector<vertex_descriptor>::iterator iter = ++adjs.begin(); iter != adjs.end(); ++iter) edges.push_back(std::make_pair(adjs[0], *iter)); } // Add local roots and edges for ( ; r != r_end; ++r ) { vertex_map[*r] = graph_traits<metaGraph>::null_vertex(); edges.reserve(edges.size() + adj[*r].size()); for (typename std::vector<vertex_descriptor>::iterator iter = adj[*r].begin(); iter != adj[*r].end(); ++iter) edges.push_back(std::make_pair(*r, get(p, *iter))); } // Build local meta-graph metaGraph mg; // Add vertices with property to map back to distributed graph vertex for (typename std::map<vertex_descriptor, meta_vertex_descriptor>::iterator iter = vertex_map.begin(); iter != vertex_map.end(); ++iter) vertex_map[iter->first] = add_vertex(metaVertex<vertex_descriptor>(iter->first), mg); // Build meta-vertex map typename property_map<metaGraph, vertex_descriptor VertexProperties::*>::type metaVertexMap = get(&VertexProperties::name, mg); typename std::vector<std::pair<vertex_descriptor, vertex_descriptor> > ::iterator edge_iter = edges.begin(); for ( ; edge_iter != edges.end(); ++edge_iter) add_edge(vertex_map[edge_iter->first], vertex_map[edge_iter->second], mg); edges.clear(); // Call connected_components on it typedef typename property_map<metaGraph, vertex_index_t>::type meta_index_map_type; meta_index_map_type meta_index = get(vertex_index, mg); std::vector<std::size_t> mg_component_vec(num_vertices(mg)); typedef iterator_property_map<std::vector<std::size_t>::iterator, meta_index_map_type> meta_components_map_type; meta_components_map_type mg_component(mg_component_vec.begin(), meta_index); std::size_t num_comp = connected_components(mg, mg_component); // Update Parent pointers std::vector<meta_vertex_descriptor> roots(num_comp, graph_traits<metaGraph>::null_vertex()); BGL_FORALL_VERTICES_T(v, mg, metaGraph) { size_t component = get(mg_component, v); if (roots[component] == graph_traits<metaGraph>::null_vertex() || get(meta_index, v) < get(meta_index, roots[component])) roots[component] = v; } // Set all the local parent pointers BGL_FORALL_VERTICES_T(v, mg, metaGraph) { // Problem in value being put (3rd parameter) put(p, get(metaVertexMap, v), get(metaVertexMap, roots[get(mg_component, v)])); } } synchronize(p); } #endif /* Function object used to remove internal vertices and vertices > the current vertex from the adjacent vertex lists at each root */ template <typename Vertex, typename ParentMap> class cull_adjacency_list { public: cull_adjacency_list(const Vertex v, const ParentMap p) : v(v), p(p) {} bool operator() (const Vertex x) { return (get(p, x) == v || x == v); } private: const Vertex v; const ParentMap p; }; /* Comparison operator used to choose targets for hooking s.t. vertices that are hooked to are evenly distributed across processors */ template <typename OwnerMap, typename LocalMap> class hashed_vertex_compare { public: hashed_vertex_compare (const OwnerMap& o, const LocalMap& l) : owner(o), local(l) { } template <typename Vertex> bool operator() (const Vertex x, const Vertex y) { if (get(local, x) < get(local, y)) return true; else if (get(local, x) == get(local, y)) return (get(owner, x) < get(owner, y)); return false; } private: OwnerMap owner; LocalMap local; }; #ifdef PBGL_EXPLICIT_SYNCH template <typename Graph, typename ParentMap, typename VertexList> void request_parent_map_entries(const Graph& g, ParentMap p, std::vector<VertexList>& parent_requests) { typedef typename boost::graph::parallel::process_group_type<Graph> ::type process_group_type; typedef typename process_group_type::process_id_type process_id_type; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; process_group_type pg = process_group(g); /* This should probably be send_oob_with_reply, especially when Dave finishes prefetch-batching */ // Send root requests for (process_id_type i = 0; i < num_processes(pg); ++i) { if (!parent_requests[i].empty()) { std::vector<vertex_descriptor> reqs(parent_requests[i].begin(), parent_requests[i].end()); send(pg, i, req_parents_msg, reqs); } } synchronize(pg); // Receive root requests and reply to them while (optional<std::pair<process_id_type, int> > m = probe(pg)) { std::vector<vertex_descriptor> requests; receive(pg, m->first, m->second, requests); for (std::size_t i = 0; i < requests.size(); ++i) requests[i] = get(p, requests[i]); send(pg, m->first, parents_msg, requests); } synchronize(pg); // Receive requested parents std::vector<vertex_descriptor> responses; for (process_id_type i = 0; i < num_processes(pg); ++i) { if (!parent_requests[i].empty()) { receive(pg, i, parents_msg, responses); std::size_t parent_idx = 0; for (typename VertexList::iterator v = parent_requests[i].begin(); v != parent_requests[i].end(); ++v, ++parent_idx) put(p, *v, responses[parent_idx]); } } } #endif template<typename DistributedGraph, typename ParentMap> void parallel_connected_components(DistributedGraph& g, ParentMap p) { using boost::connected_components; typedef typename graph_traits<DistributedGraph>::adjacency_iterator adjacency_iterator; typedef typename graph_traits<DistributedGraph>::vertex_descriptor vertex_descriptor; typedef typename boost::graph::parallel::process_group_type<DistributedGraph> ::type process_group_type; typedef typename process_group_type::process_id_type process_id_type; using boost::graph::parallel::process_group; process_group_type pg = process_group(g); process_id_type id = process_id(pg); // TODO (NGE): Should old_roots, roots, and completed_roots be std::list adjacency_iterator av1, av2; std::vector<vertex_descriptor> old_roots; typename std::vector<vertex_descriptor>::iterator liter; typename std::vector<vertex_descriptor>::iterator aliter; typename std::map<vertex_descriptor, std::vector<vertex_descriptor> > adj; typedef typename property_map<DistributedGraph, vertex_owner_t>::const_type OwnerMap; OwnerMap owner = get(vertex_owner, g); typedef typename property_map<DistributedGraph, vertex_local_t>::const_type LocalMap; LocalMap local = get(vertex_local, g); // We need to hold on to all of the parent pointers p.set_max_ghost_cells(0); // // STAGE 1 : Compute local components // local_subgraph<const DistributedGraph> ls(g); typedef typename property_map<local_subgraph<const DistributedGraph>, vertex_index_t>::type local_index_map_type; local_index_map_type local_index = get(vertex_index, ls); // Compute local connected components std::vector<std::size_t> ls_components_vec(num_vertices(ls)); typedef iterator_property_map<std::vector<std::size_t>::iterator, local_index_map_type> ls_components_map_type; ls_components_map_type ls_component(ls_components_vec.begin(), local_index); std::size_t num_comp = connected_components(ls, ls_component); std::vector<vertex_descriptor> roots(num_comp, graph_traits<DistributedGraph>::null_vertex()); BGL_FORALL_VERTICES_T(v, g, DistributedGraph) { size_t component = get(ls_component, v); if (roots[component] == graph_traits<DistributedGraph>::null_vertex() || get(local_index, v) < get(local_index, roots[component])) roots[component] = v; } // Set all the local parent pointers BGL_FORALL_VERTICES_T(v, g, DistributedGraph) { put(p, v, roots[get(ls_component, v)]); } if (num_processes(pg) == 1) return; // Build adjacency list for all roots BGL_FORALL_VERTICES_T(v, g, DistributedGraph) { std::vector<vertex_descriptor>& my_adj = adj[get(p, v)]; for (boost::tie(av1, av2) = adjacent_vertices(v, g); av1 != av2; ++av1) { if (get(owner, *av1) != id) my_adj.push_back(*av1); } } // For all vertices adjacent to a local vertex get p(v) for ( liter = roots.begin(); liter != roots.end(); ++liter ) { std::vector<vertex_descriptor>& my_adj = adj[*liter]; for ( aliter = my_adj.begin(); aliter != my_adj.end(); ++aliter ) request(p, *aliter); } synchronize(p); // Update adjacency list at root to make sure all adjacent // vertices are roots of remote components for ( liter = roots.begin(); liter != roots.end(); ++liter ) { std::vector<vertex_descriptor>& my_adj = adj[*liter]; for ( aliter = my_adj.begin(); aliter != my_adj.end(); ++aliter ) *aliter = get(p, *aliter); my_adj.erase (std::remove_if(my_adj.begin(), my_adj.end(), cull_adjacency_list<vertex_descriptor, ParentMap>(*liter, p) ), my_adj.end()); // This sort needs to be here to make sure the initial // adjacency list is sorted std::sort(my_adj.begin(), my_adj.end(), std::less<vertex_descriptor>()); my_adj.erase(std::unique(my_adj.begin(), my_adj.end()), my_adj.end()); } // Get p(v) for the new adjacent roots p.clear(); for ( liter = roots.begin(); liter != roots.end(); ++liter ) { std::vector<vertex_descriptor>& my_adj = adj[*liter]; for ( aliter = my_adj.begin(); aliter != my_adj.end(); ++aliter ) request(p, *aliter); } #ifdef PBGL_EXPLICIT_SYNCH synchronize(p); #endif // Lastly, remove roots with no adjacent vertices, this is // unnecessary but will speed up sparse graphs for ( liter = roots.begin(); liter != roots.end(); /*in loop*/) { if ( adj[*liter].empty() ) liter = roots.erase(liter); else ++liter; } #ifdef PBGL_CONSTRUCT_METAGRAPH /* TODO: If the number of roots is sufficiently small, we can use a 'problem folding' approach like we do in MST to gather all the roots and their adjacencies on one proc and solve for the connected components of the meta-graph */ using boost::parallel::all_reduce; std::size_t num_roots = all_reduce(pg, roots.size(), std::plus<std::size_t>()); if (num_roots < MAX_VERTICES_IN_METAGRAPH) { build_local_metagraph(g, p, roots.begin(), roots.end(), adj); // For each vertex in g, p(v) = p(p(v)), assign parent of leaf // vertices from first step to final parent BGL_FORALL_VERTICES_T(v, g, DistributedGraph) { put(p, v, get(p, get(p, v))); } synchronize(p); return; } #endif // // Parallel Phase // std::vector<vertex_descriptor> completed_roots; hashed_vertex_compare<OwnerMap, LocalMap> v_compare(owner, local); bool any_hooked; vertex_descriptor new_root; std::size_t steps = 0; do { ++steps; // Pull in new parents for hooking phase synchronize(p); // // Hooking // bool hooked = false; completed_roots.clear(); for ( liter = roots.begin(); liter != roots.end(); ) { new_root = graph_traits<DistributedGraph>::null_vertex(); std::vector<vertex_descriptor>& my_adj = adj[*liter]; for ( aliter = my_adj.begin(); aliter != my_adj.end(); ++aliter ) // try to hook to better adjacent vertex if ( v_compare( get(p, *aliter), *liter ) ) new_root = get(p, *aliter); if ( new_root != graph_traits<DistributedGraph>::null_vertex() ) { hooked = true; put(p, *liter, new_root); old_roots.push_back(*liter); completed_roots.push_back(*liter); liter = roots.erase(liter); } else ++liter; } // // Pointer jumping, perform until new roots determined // // TODO: Implement cycle reduction rules to reduce this from // O(n) to O(log n) [n = cycle length] bool all_done; std::size_t parent_root_count; std::size_t double_steps = 0; do { ++double_steps; #ifndef PBGL_EXPLICIT_SYNCH // Get p(p(v)) for all old roots, and p(v) for all current roots for ( liter = old_roots.begin(); liter != old_roots.end(); ++liter ) request(p, get(p, *liter)); synchronize(p); #else // Build root requests typedef std::set<vertex_descriptor> VertexSet; std::vector<VertexSet> parent_requests(num_processes(pg)); for ( liter = old_roots.begin(); liter != old_roots.end(); ++liter ) { vertex_descriptor p1 = *liter; if (get(owner, p1) != id) parent_requests[get(owner, p1)].insert(p1); vertex_descriptor p2 = get(p, p1); if (get(owner, p2) != id) parent_requests[get(owner, p2)].insert(p2); } request_parent_map_entries(g, p, parent_requests); #endif // Perform a pointer jumping step on all old roots for ( liter = old_roots.begin(); liter != old_roots.end(); ++liter ) put(p, *liter, get(p, get(p, *liter))); // make sure the parent of all old roots is itself a root parent_root_count = 0; for ( liter = old_roots.begin(); liter != old_roots.end(); ++liter ) if ( get(p, *liter) == get(p, get(p, *liter)) ) parent_root_count++; bool done = parent_root_count == old_roots.size(); all_reduce(pg, &done, &done+1, &all_done, std::logical_and<bool>()); } while ( !all_done ); #ifdef PARALLEL_BGL_DEBUG if (id == 0) std::cerr << double_steps << " doubling steps.\n"; #endif // // Add adjacent vertices of just completed roots to adjacent // vertex list at new parent // typename std::vector<vertex_descriptor> outgoing_edges; for ( liter = completed_roots.begin(); liter != completed_roots.end(); ++liter ) { vertex_descriptor new_parent = get(p, *liter); if ( get(owner, new_parent) == id ) { std::vector<vertex_descriptor>& my_adj = adj[new_parent]; my_adj.reserve(my_adj.size() + adj[*liter].size()); my_adj.insert( my_adj.end(), adj[*liter].begin(), adj[*liter].end() ); #ifdef PBGL_IN_PLACE_MERGE #ifdef PBGL_SORT_ASSERT BOOST_ASSERT(::boost::detail::is_sorted(my_adj.begin(), my_adj.end() - adj[*liter].size(), std::less<vertex_descriptor>())); BOOST_ASSERT(::boost::detail::is_sorted(my_adj.end() - adj[*liter].size(), my_adj.end(), std::less<vertex_descriptor>())); #endif std::inplace_merge(my_adj.begin(), my_adj.end() - adj[*liter].size(), my_adj.end(), std::less<vertex_descriptor>()); #endif } else if ( adj[*liter].begin() != adj[*liter].end() ) { outgoing_edges.clear(); outgoing_edges.reserve(adj[*liter].size() + 1); // First element is the destination of the adjacency list outgoing_edges.push_back(new_parent); outgoing_edges.insert(outgoing_edges.end(), adj[*liter].begin(), adj[*liter].end() ); send(pg, get(owner, new_parent), edges_msg, outgoing_edges); adj[*liter].clear(); } } synchronize(pg); // Receive edges sent by remote nodes and add them to the // indicated vertex's adjacency list while (optional<std::pair<process_id_type, int> > m = probe(pg)) { std::vector<vertex_descriptor> incoming_edges; receive(pg, m->first, edges_msg, incoming_edges); typename std::vector<vertex_descriptor>::iterator aviter = incoming_edges.begin(); ++aviter; std::vector<vertex_descriptor>& my_adj = adj[incoming_edges[0]]; my_adj.reserve(my_adj.size() + incoming_edges.size() - 1); my_adj.insert( my_adj.end(), aviter, incoming_edges.end() ); #ifdef PBGL_IN_PLACE_MERGE std::size_t num_incoming_edges = incoming_edges.size(); #ifdef PBGL_SORT_ASSERT BOOST_ASSERT(::boost::detail::is_sorted(my_adj.begin(), my_adj.end() - (num_incoming_edges-1), std::less<vertex_descriptor>())); BOOST_ASSERT(::boost::detail::is_sorted(my_adj.end() - (num_incoming_edges-1), my_adj.end(), std::less<vertex_descriptor>())); #endif std::inplace_merge(my_adj.begin(), my_adj.end() - (num_incoming_edges - 1), my_adj.end(), std::less<vertex_descriptor>()); #endif } // Remove any adjacent vertices that are in the same component // as a root from that root's list for ( liter = roots.begin(); liter != roots.end(); ++liter ) { // We can probably get away without sorting and removing // duplicates Though sorting *may* cause root // determination to occur faster by choosing the root with // the most potential to hook to at each step std::vector<vertex_descriptor>& my_adj = adj[*liter]; my_adj.erase (std::remove_if(my_adj.begin(), my_adj.end(), cull_adjacency_list<vertex_descriptor, ParentMap>(*liter, p) ), my_adj.end()); #ifndef PBGL_IN_PLACE_MERGE std::sort(my_adj.begin(), my_adj.end(), std::less<vertex_descriptor>() ); #endif my_adj.erase(std::unique(my_adj.begin(), my_adj.end()), my_adj.end()); } // Reduce result of empty root list test all_reduce(pg, &hooked, &hooked+1, &any_hooked, std::logical_or<bool>()); } while ( any_hooked ); #ifdef PARALLEL_BGL_DEBUG if (id == 0) std::cerr << steps << " iterations.\n"; #endif // // Finalize // // For each vertex in g, p(v) = p(p(v)), assign parent of leaf // vertices from first step to final parent BGL_FORALL_VERTICES_T(v, g, DistributedGraph) { put(p, v, get(p, get(p, v))); } synchronize(p); } } // end namespace cc_detail template<typename Graph, typename ParentMap, typename ComponentMap> typename property_traits<ComponentMap>::value_type number_components_from_parents(const Graph& g, ParentMap p, ComponentMap c) { typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type; typedef typename property_traits<ComponentMap>::value_type ComponentMapType; process_group_type pg = process_group(g); /* Build list of roots */ std::vector<vertex_descriptor> my_roots, all_roots; BGL_FORALL_VERTICES_T(v, g, Graph) { if( std::find( my_roots.begin(), my_roots.end(), get(p, v) ) == my_roots.end() ) my_roots.push_back( get(p, v) ); } all_gather(pg, my_roots.begin(), my_roots.end(), all_roots); /* Number components */ std::map<vertex_descriptor, ComponentMapType> comp_numbers; ComponentMapType c_num = 0; // Compute component numbers for (std::size_t i = 0; i < all_roots.size(); i++ ) if ( comp_numbers.count(all_roots[i]) == 0 ) comp_numbers[all_roots[i]] = c_num++; // Broadcast component numbers BGL_FORALL_VERTICES_T(v, g, Graph) { put( c, v, comp_numbers[get(p, v)] ); } // Broadcast number of components if (process_id(pg) == 0) { typedef typename process_group_type::process_size_type process_size_type; for (process_size_type dest = 1, n = num_processes(pg); dest != n; ++dest) send(pg, dest, 0, c_num); } synchronize(pg); if (process_id(pg) != 0) receive(pg, 0, 0, c_num); synchronize(c); return c_num; } template<typename Graph, typename ParentMap> int number_components_from_parents(const Graph& g, ParentMap p, dummy_property_map) { using boost::parallel::all_reduce; // Count local roots. int num_roots = 0; BGL_FORALL_VERTICES_T(v, g, Graph) if (get(p, v) == v) ++num_roots; return all_reduce(g.process_group(), num_roots, std::plus<int>()); } template<typename Graph, typename ComponentMap, typename ParentMap> typename property_traits<ComponentMap>::value_type connected_components (const Graph& g, ComponentMap c, ParentMap p BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag)) { cc_detail::parallel_connected_components(g, p); return number_components_from_parents(g, p, c); } /* Construct ParentMap by default */ template<typename Graph, typename ComponentMap> typename property_traits<ComponentMap>::value_type connected_components ( const Graph& g, ComponentMap c BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag) ) { typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; std::vector<vertex_descriptor> x(num_vertices(g)); return connected_components (g, c, make_iterator_property_map(x.begin(), get(vertex_index, g))); } } // end namespace distributed using distributed::connected_components; } // end namespace graph using graph::distributed::connected_components; } // end namespace boost #endif // BOOST_GRAPH_PARALLEL_CC_HPP distributed/adjacency_list.hpp 0000644 00000444400 15125521275 0012566 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Copyright (C) 2007 Douglas Gregor // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_DISTRIBUTED_ADJACENCY_LIST_HPP #define BOOST_GRAPH_DISTRIBUTED_ADJACENCY_LIST_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/adjacency_list.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/graph/distributed/concepts.hpp> #include <boost/iterator/transform_iterator.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/adjacency_iterator.hpp> #include <boost/property_map/parallel/distributed_property_map.hpp> #include <boost/property_map/parallel/local_property_map.hpp> #include <boost/graph/parallel/detail/property_holders.hpp> #include <boost/mpl/if.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/assert.hpp> #include <list> #include <algorithm> #include <boost/limits.hpp> #include <boost/graph/parallel/properties.hpp> #include <boost/graph/parallel/distribution.hpp> #include <boost/graph/parallel/algorithm.hpp> #include <boost/graph/distributed/selector.hpp> #include <boost/graph/parallel/process_group.hpp> #include <boost/pending/container_traits.hpp> // Callbacks #include <boost/function/function2.hpp> // Serialization #include <boost/serialization/base_object.hpp> #include <boost/mpi/datatype.hpp> #include <boost/pending/property_serialize.hpp> #include <boost/graph/distributed/unsafe_serialize.hpp> // Named vertices #include <boost/graph/distributed/named_graph.hpp> #include <boost/graph/distributed/shuffled_distribution.hpp> namespace boost { /// The type used to store an identifier that uniquely names a processor. // NGE: I doubt we'll be running on more than 32768 procs for the time being typedef /*int*/ short processor_id_type; // Tell which processor the target of an edge resides on (for // directed graphs) or which processor the other end point of the // edge resides on (for undirected graphs). enum edge_target_processor_id_t { edge_target_processor_id }; BOOST_INSTALL_PROPERTY(edge, target_processor_id); // For undirected graphs, tells whether the edge is locally owned. enum edge_locally_owned_t { edge_locally_owned }; BOOST_INSTALL_PROPERTY(edge, locally_owned); // For bidirectional graphs, stores the incoming edges. enum vertex_in_edges_t { vertex_in_edges }; BOOST_INSTALL_PROPERTY(vertex, in_edges); /// Tag class for directed, distributed adjacency list struct directed_distributed_adj_list_tag : public virtual distributed_graph_tag, public virtual distributed_vertex_list_graph_tag, public virtual distributed_edge_list_graph_tag, public virtual incidence_graph_tag, public virtual adjacency_graph_tag {}; /// Tag class for bidirectional, distributed adjacency list struct bidirectional_distributed_adj_list_tag : public virtual distributed_graph_tag, public virtual distributed_vertex_list_graph_tag, public virtual distributed_edge_list_graph_tag, public virtual incidence_graph_tag, public virtual adjacency_graph_tag, public virtual bidirectional_graph_tag {}; /// Tag class for undirected, distributed adjacency list struct undirected_distributed_adj_list_tag : public virtual distributed_graph_tag, public virtual distributed_vertex_list_graph_tag, public virtual distributed_edge_list_graph_tag, public virtual incidence_graph_tag, public virtual adjacency_graph_tag, public virtual bidirectional_graph_tag {}; namespace detail { template<typename Archiver, typename Directed, typename Vertex> void serialize(Archiver& ar, edge_base<Directed, Vertex>& e, const unsigned int /*version*/) { ar & unsafe_serialize(e.m_source) & unsafe_serialize(e.m_target); } template<typename Archiver, typename Directed, typename Vertex> void serialize(Archiver& ar, edge_desc_impl<Directed, Vertex>& e, const unsigned int /*version*/) { ar & boost::serialization::base_object<edge_base<Directed, Vertex> >(e) & unsafe_serialize(e.m_eproperty); } } namespace detail { namespace parallel { /** * A distributed vertex descriptor. These descriptors contain both * the ID of the processor that owns the vertex and a local vertex * descriptor that identifies the particular vertex for that * processor. */ template<typename LocalDescriptor> struct global_descriptor { typedef LocalDescriptor local_descriptor_type; global_descriptor() : owner(), local() { } global_descriptor(processor_id_type owner, LocalDescriptor local) : owner(owner), local(local) { } processor_id_type owner; LocalDescriptor local; /** * A function object that, given a processor ID, generates * distributed vertex descriptors from local vertex * descriptors. This function object is used by the * vertex_iterator of the distributed adjacency list. */ struct generator { typedef global_descriptor<LocalDescriptor> result_type; typedef LocalDescriptor argument_type; generator() {} generator(processor_id_type owner) : owner(owner) {} result_type operator()(argument_type v) const { return result_type(owner, v); } private: processor_id_type owner; }; template<typename Archiver> void serialize(Archiver& ar, const unsigned int /*version*/) { ar & owner & unsafe_serialize(local); } }; /// Determine the process that owns the given descriptor template<typename LocalDescriptor> inline processor_id_type owner(const global_descriptor<LocalDescriptor>& v) { return v.owner; } /// Determine the local portion of the given descriptor template<typename LocalDescriptor> inline LocalDescriptor local(const global_descriptor<LocalDescriptor>& v) { return v.local; } /// Compare distributed vertex descriptors for equality template<typename LocalDescriptor> inline bool operator==(const global_descriptor<LocalDescriptor>& u, const global_descriptor<LocalDescriptor>& v) { return u.owner == v.owner && u.local == v.local; } /// Compare distributed vertex descriptors for inequality template<typename LocalDescriptor> inline bool operator!=(const global_descriptor<LocalDescriptor>& u, const global_descriptor<LocalDescriptor>& v) { return !(u == v); } template<typename LocalDescriptor> inline bool operator<(const global_descriptor<LocalDescriptor>& u, const global_descriptor<LocalDescriptor>& v) { return (u.owner) < v.owner || (u.owner == v.owner && (u.local) < v.local); } template<typename LocalDescriptor> inline bool operator<=(const global_descriptor<LocalDescriptor>& u, const global_descriptor<LocalDescriptor>& v) { return u.owner <= v.owner || (u.owner == v.owner && u.local <= v.local); } template<typename LocalDescriptor> inline bool operator>(const global_descriptor<LocalDescriptor>& u, const global_descriptor<LocalDescriptor>& v) { return v < u; } template<typename LocalDescriptor> inline bool operator>=(const global_descriptor<LocalDescriptor>& u, const global_descriptor<LocalDescriptor>& v) { return v <= u; } // DPG TBD: Add <, <=, >=, > for global descriptors /** * A Readable Property Map that extracts a global descriptor pair * from a global_descriptor. */ template<typename LocalDescriptor> struct global_descriptor_property_map { typedef std::pair<processor_id_type, LocalDescriptor> value_type; typedef value_type reference; typedef global_descriptor<LocalDescriptor> key_type; typedef readable_property_map_tag category; }; template<typename LocalDescriptor> inline std::pair<processor_id_type, LocalDescriptor> get(global_descriptor_property_map<LocalDescriptor>, global_descriptor<LocalDescriptor> x) { return std::pair<processor_id_type, LocalDescriptor>(x.owner, x.local); } /** * A Readable Property Map that extracts the owner of a global * descriptor. */ template<typename LocalDescriptor> struct owner_property_map { typedef processor_id_type value_type; typedef value_type reference; typedef global_descriptor<LocalDescriptor> key_type; typedef readable_property_map_tag category; }; template<typename LocalDescriptor> inline processor_id_type get(owner_property_map<LocalDescriptor>, global_descriptor<LocalDescriptor> x) { return x.owner; } /** * A Readable Property Map that extracts the local descriptor from * a global descriptor. */ template<typename LocalDescriptor> struct local_descriptor_property_map { typedef LocalDescriptor value_type; typedef value_type reference; typedef global_descriptor<LocalDescriptor> key_type; typedef readable_property_map_tag category; }; template<typename LocalDescriptor> inline LocalDescriptor get(local_descriptor_property_map<LocalDescriptor>, global_descriptor<LocalDescriptor> x) { return x.local; } /** * Stores an incoming edge for a bidirectional distributed * adjacency list. The user does not see this type directly, * because it is just an implementation detail. */ template<typename Edge> struct stored_in_edge { stored_in_edge(processor_id_type sp, Edge e) : source_processor(sp), e(e) {} processor_id_type source_processor; Edge e; }; /** * A distributed edge descriptor. These descriptors contain the * underlying edge descriptor, the processor IDs for both the * source and the target of the edge, and a boolean flag that * indicates which of the processors actually owns the edge. */ template<typename Edge> struct edge_descriptor { edge_descriptor(processor_id_type sp = processor_id_type(), processor_id_type tp = processor_id_type(), bool owns = false, Edge ld = Edge()) : source_processor(sp), target_processor(tp), source_owns_edge(owns), local(ld) {} processor_id_type owner() const { return source_owns_edge? source_processor : target_processor; } /// The processor that the source vertex resides on processor_id_type source_processor; /// The processor that the target vertex resides on processor_id_type target_processor; /// True when the source processor owns the edge, false when the /// target processor owns the edge. bool source_owns_edge; /// The local edge descriptor. Edge local; /** * Function object that generates edge descriptors for the * out_edge_iterator of the given distributed adjacency list * from the edge descriptors of the underlying adjacency list. */ template<typename Graph> class out_generator { typedef typename Graph::directed_selector directed_selector; public: typedef edge_descriptor<Edge> result_type; typedef Edge argument_type; out_generator() : g(0) {} explicit out_generator(const Graph& g) : g(&g) {} result_type operator()(argument_type e) const { return map(e, directed_selector()); } private: result_type map(argument_type e, directedS) const { return result_type(g->processor(), get(edge_target_processor_id, g->base(), e), true, e); } result_type map(argument_type e, bidirectionalS) const { return result_type(g->processor(), get(edge_target_processor_id, g->base(), e), true, e); } result_type map(argument_type e, undirectedS) const { return result_type(g->processor(), get(edge_target_processor_id, g->base(), e), get(edge_locally_owned, g->base(), e), e); } const Graph* g; }; /** * Function object that generates edge descriptors for the * in_edge_iterator of the given distributed adjacency list * from the edge descriptors of the underlying adjacency list. */ template<typename Graph> class in_generator { typedef typename Graph::directed_selector DirectedS; public: typedef typename boost::mpl::if_<is_same<DirectedS, bidirectionalS>, stored_in_edge<Edge>, Edge>::type argument_type; typedef edge_descriptor<Edge> result_type; in_generator() : g(0) {} explicit in_generator(const Graph& g) : g(&g) {} result_type operator()(argument_type e) const { return map(e, DirectedS()); } private: /** * For a bidirectional graph, we just generate the appropriate * edge. No tricks. */ result_type map(argument_type e, bidirectionalS) const { return result_type(e.source_processor, g->processor(), true, e.e); } /** * For an undirected graph, we generate descriptors for the * incoming edges by swapping the source/target of the * underlying edge descriptor (a hack). The target processor * ID on the edge is actually the source processor for this * edge, and our processor is the target processor. If the * edge is locally owned, then it is owned by the target (us); * otherwise it is owned by the source. */ result_type map(argument_type e, undirectedS) const { typename Graph::local_edge_descriptor local_edge(e); // TBD: This is a very, VERY lame hack that takes advantage // of our knowledge of the internals of the BGL // adjacency_list. There should be a cleaner way to handle // this... using std::swap; swap(local_edge.m_source, local_edge.m_target); return result_type(get(edge_target_processor_id, g->base(), e), g->processor(), !get(edge_locally_owned, g->base(), e), local_edge); } const Graph* g; }; private: friend class boost::serialization::access; template<typename Archiver> void serialize(Archiver& ar, const unsigned int /*version*/) { ar & source_processor & target_processor & source_owns_edge & local; } }; /// Determine the process that owns this edge template<typename Edge> inline processor_id_type owner(const edge_descriptor<Edge>& e) { return e.source_owns_edge? e.source_processor : e.target_processor; } /// Determine the local descriptor for this edge. template<typename Edge> inline Edge local(const edge_descriptor<Edge>& e) { return e.local; } /** * A Readable Property Map that extracts the owner and local * descriptor of an edge descriptor. */ template<typename Edge> struct edge_global_property_map { typedef std::pair<processor_id_type, Edge> value_type; typedef value_type reference; typedef edge_descriptor<Edge> key_type; typedef readable_property_map_tag category; }; template<typename Edge> inline std::pair<processor_id_type, Edge> get(edge_global_property_map<Edge>, const edge_descriptor<Edge>& e) { typedef std::pair<processor_id_type, Edge> result_type; return result_type(e.source_owns_edge? e.source_processor /* target owns edge*/: e.target_processor, e.local); } /** * A Readable Property Map that extracts the owner of an edge * descriptor. */ template<typename Edge> struct edge_owner_property_map { typedef processor_id_type value_type; typedef value_type reference; typedef edge_descriptor<Edge> key_type; typedef readable_property_map_tag category; }; template<typename Edge> inline processor_id_type get(edge_owner_property_map<Edge>, const edge_descriptor<Edge>& e) { return e.source_owns_edge? e.source_processor : e.target_processor; } /** * A Readable Property Map that extracts the local descriptor from * an edge descriptor. */ template<typename Edge> struct edge_local_property_map { typedef Edge value_type; typedef value_type reference; typedef edge_descriptor<Edge> key_type; typedef readable_property_map_tag category; }; template<typename Edge> inline Edge get(edge_local_property_map<Edge>, const edge_descriptor<Edge>& e) { return e.local; } /** Compare distributed edge descriptors for equality. * * \todo need edge_descriptor to know if it is undirected so we * can compare both ways. */ template<typename Edge> inline bool operator==(const edge_descriptor<Edge>& e1, const edge_descriptor<Edge>& e2) { return (e1.source_processor == e2.source_processor && e1.target_processor == e2.target_processor && e1.local == e2.local); } /// Compare distributed edge descriptors for inequality. template<typename Edge> inline bool operator!=(const edge_descriptor<Edge>& e1, const edge_descriptor<Edge>& e2) { return !(e1 == e2); } /** * Configuration for the distributed adjacency list. We use this * parameter to store all of the configuration details for the * implementation of the distributed adjacency list, which allows us to * get at the distribution type in the maybe_named_graph. */ template<typename OutEdgeListS, typename ProcessGroup, typename InVertexListS, typename InDistribution, typename DirectedS, typename VertexProperty, typename EdgeProperty, typename GraphProperty, typename EdgeListS> struct adjacency_list_config { typedef typename mpl::if_<is_same<InVertexListS, defaultS>, vecS, InVertexListS>::type VertexListS; /// Introduce the target processor ID property for each edge typedef property<edge_target_processor_id_t, processor_id_type, EdgeProperty> edge_property_with_id; /// For undirected graphs, introduce the locally-owned property for edges typedef typename boost::mpl::if_<is_same<DirectedS, undirectedS>, property<edge_locally_owned_t, bool, edge_property_with_id>, edge_property_with_id>::type base_edge_property_type; /// The edge descriptor type for the local subgraph typedef typename adjacency_list_traits<OutEdgeListS, VertexListS, directedS>::edge_descriptor local_edge_descriptor; /// For bidirectional graphs, the type of an incoming stored edge typedef stored_in_edge<local_edge_descriptor> bidir_stored_edge; /// The container type that will store incoming edges for a /// bidirectional graph. typedef typename container_gen<EdgeListS, bidir_stored_edge>::type in_edge_list_type; // Bidirectional graphs have an extra vertex property to store // the incoming edges. typedef typename boost::mpl::if_<is_same<DirectedS, bidirectionalS>, property<vertex_in_edges_t, in_edge_list_type, VertexProperty>, VertexProperty>::type base_vertex_property_type; // The type of the distributed adjacency list typedef adjacency_list<OutEdgeListS, distributedS<ProcessGroup, VertexListS, InDistribution>, DirectedS, VertexProperty, EdgeProperty, GraphProperty, EdgeListS> graph_type; // The type of the underlying adjacency list implementation typedef adjacency_list<OutEdgeListS, VertexListS, directedS, base_vertex_property_type, base_edge_property_type, GraphProperty, EdgeListS> inherited; typedef InDistribution in_distribution_type; typedef typename inherited::vertices_size_type vertices_size_type; typedef typename ::boost::graph::distributed::select_distribution< in_distribution_type, VertexProperty, vertices_size_type, ProcessGroup>::type base_distribution_type; typedef ::boost::graph::distributed::shuffled_distribution< base_distribution_type> distribution_type; typedef VertexProperty vertex_property_type; typedef EdgeProperty edge_property_type; typedef ProcessGroup process_group_type; typedef VertexListS vertex_list_selector; typedef OutEdgeListS out_edge_list_selector; typedef DirectedS directed_selector; typedef GraphProperty graph_property_type; typedef EdgeListS edge_list_selector; }; // Maybe initialize the indices of each vertex template<typename IteratorPair, typename VertexIndexMap> void maybe_initialize_vertex_indices(IteratorPair p, VertexIndexMap to_index, read_write_property_map_tag) { typedef typename property_traits<VertexIndexMap>::value_type index_t; index_t next_index = 0; while (p.first != p.second) put(to_index, *p.first++, next_index++); } template<typename IteratorPair, typename VertexIndexMap> inline void maybe_initialize_vertex_indices(IteratorPair p, VertexIndexMap to_index, readable_property_map_tag) { // Do nothing } template<typename IteratorPair, typename VertexIndexMap> inline void maybe_initialize_vertex_indices(IteratorPair p, VertexIndexMap to_index) { typedef typename property_traits<VertexIndexMap>::category category; maybe_initialize_vertex_indices(p, to_index, category()); } template<typename IteratorPair> inline void maybe_initialize_vertex_indices(IteratorPair p, ::boost::detail::error_property_not_found) { } /*********************************************************************** * Message Payloads * ***********************************************************************/ /** * Data stored with a msg_add_edge message, which requests the * remote addition of an edge. */ template<typename Vertex, typename LocalVertex> struct msg_add_edge_data { msg_add_edge_data() { } msg_add_edge_data(Vertex source, Vertex target) : source(source.local), target(target) { } /// The source of the edge; the processor will be the /// receiving processor. LocalVertex source; /// The target of the edge. Vertex target; template<typename Archiver> void serialize(Archiver& ar, const unsigned int /*version*/) { ar & unsafe_serialize(source) & target; } }; /** * Like @c msg_add_edge_data, but also includes a user-specified * property value to be attached to the edge. */ template<typename Vertex, typename LocalVertex, typename EdgeProperty> struct msg_add_edge_with_property_data : msg_add_edge_data<Vertex, LocalVertex>, maybe_store_property<EdgeProperty> { private: typedef msg_add_edge_data<Vertex, LocalVertex> inherited_data; typedef maybe_store_property<EdgeProperty> inherited_property; public: msg_add_edge_with_property_data() { } msg_add_edge_with_property_data(Vertex source, Vertex target, const EdgeProperty& property) : inherited_data(source, target), inherited_property(property) { } template<typename Archiver> void serialize(Archiver& ar, const unsigned int /*version*/) { ar & boost::serialization::base_object<inherited_data>(*this) & boost::serialization::base_object<inherited_property>(*this); } }; //------------------------------------------------------------------------ // Distributed adjacency list property map details /** * Metafunction that extracts the given property from the given * distributed adjacency list type. This could be implemented much * more cleanly, but even newer versions of GCC (e.g., 3.2.3) * cannot properly handle partial specializations involving * enumerator types. */ template<typename Property> struct get_adj_list_pmap { template<typename Graph> struct apply { typedef Graph graph_type; typedef typename graph_type::process_group_type process_group_type; typedef typename graph_type::inherited base_graph_type; typedef typename property_map<base_graph_type, Property>::type local_pmap; typedef typename property_map<base_graph_type, Property>::const_type local_const_pmap; typedef graph_traits<graph_type> traits; typedef typename graph_type::local_vertex_descriptor local_vertex; typedef typename property_traits<local_pmap>::key_type local_key_type; typedef typename property_traits<local_pmap>::value_type value_type; typedef typename property_map<Graph, vertex_global_t>::const_type vertex_global_map; typedef typename property_map<Graph, edge_global_t>::const_type edge_global_map; typedef typename mpl::if_c<(is_same<local_key_type, local_vertex>::value), vertex_global_map, edge_global_map>::type global_map; public: typedef ::boost::parallel::distributed_property_map< process_group_type, global_map, local_pmap> type; typedef ::boost::parallel::distributed_property_map< process_group_type, global_map, local_const_pmap> const_type; }; }; /** * The local vertex index property map is actually a mapping from * the local vertex descriptors to vertex indices. */ template<> struct get_adj_list_pmap<vertex_local_index_t> { template<typename Graph> struct apply : ::boost::property_map<typename Graph::inherited, vertex_index_t> { }; }; /** * The vertex index property map maps from global descriptors * (e.g., the vertex descriptor of a distributed adjacency list) * to the underlying local index. It is not valid to use this * property map with nonlocal descriptors. */ template<> struct get_adj_list_pmap<vertex_index_t> { template<typename Graph> struct apply { private: typedef typename property_map<Graph, vertex_global_t>::const_type global_map; typedef property_map<typename Graph::inherited, vertex_index_t> local; public: typedef local_property_map<typename Graph::process_group_type, global_map, typename local::type> type; typedef local_property_map<typename Graph::process_group_type, global_map, typename local::const_type> const_type; }; }; /** * The vertex owner property map maps from vertex descriptors to * the processor that owns the vertex. */ template<> struct get_adj_list_pmap<vertex_global_t> { template<typename Graph> struct apply { private: typedef typename Graph::local_vertex_descriptor local_vertex_descriptor; public: typedef global_descriptor_property_map<local_vertex_descriptor> type; typedef type const_type; }; }; /** * The vertex owner property map maps from vertex descriptors to * the processor that owns the vertex. */ template<> struct get_adj_list_pmap<vertex_owner_t> { template<typename Graph> struct apply { private: typedef typename Graph::local_vertex_descriptor local_vertex_descriptor; public: typedef owner_property_map<local_vertex_descriptor> type; typedef type const_type; }; }; /** * The vertex local property map maps from vertex descriptors to * the local descriptor for that vertex. */ template<> struct get_adj_list_pmap<vertex_local_t> { template<typename Graph> struct apply { private: typedef typename Graph::local_vertex_descriptor local_vertex_descriptor; public: typedef local_descriptor_property_map<local_vertex_descriptor> type; typedef type const_type; }; }; /** * The edge global property map maps from edge descriptors to * a pair of the owning processor and local descriptor. */ template<> struct get_adj_list_pmap<edge_global_t> { template<typename Graph> struct apply { private: typedef typename Graph::local_edge_descriptor local_edge_descriptor; public: typedef edge_global_property_map<local_edge_descriptor> type; typedef type const_type; }; }; /** * The edge owner property map maps from edge descriptors to * the processor that owns the edge. */ template<> struct get_adj_list_pmap<edge_owner_t> { template<typename Graph> struct apply { private: typedef typename Graph::local_edge_descriptor local_edge_descriptor; public: typedef edge_owner_property_map<local_edge_descriptor> type; typedef type const_type; }; }; /** * The edge local property map maps from edge descriptors to * the local descriptor for that edge. */ template<> struct get_adj_list_pmap<edge_local_t> { template<typename Graph> struct apply { private: typedef typename Graph::local_edge_descriptor local_edge_descriptor; public: typedef edge_local_property_map<local_edge_descriptor> type; typedef type const_type; }; }; //------------------------------------------------------------------------ // Directed graphs do not have in edges, so this is a no-op template<typename Graph> inline void remove_in_edge(typename Graph::edge_descriptor, Graph&, directedS) { } // Bidirectional graphs have in edges stored in the // vertex_in_edges property. template<typename Graph> inline void remove_in_edge(typename Graph::edge_descriptor e, Graph& g, bidirectionalS) { typedef typename Graph::in_edge_list_type in_edge_list_type; in_edge_list_type& in_edges = get(vertex_in_edges, g.base())[target(e, g).local]; typename in_edge_list_type::iterator i = in_edges.begin(); while (i != in_edges.end() && !(i->source_processor == source(e, g).owner) && i->e == e.local) ++i; BOOST_ASSERT(i != in_edges.end()); in_edges.erase(i); } // Undirected graphs have in edges stored as normal edges. template<typename Graph> inline void remove_in_edge(typename Graph::edge_descriptor e, Graph& g, undirectedS) { typedef typename Graph::inherited base_type; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; // TBD: can we make this more efficient? // Removing edge (v, u). v is local base_type& bg = g.base(); vertex_descriptor u = source(e, g); vertex_descriptor v = target(e, g); if (v.owner != process_id(g.process_group())) { using std::swap; swap(u, v); } typename graph_traits<base_type>::out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(v.local, bg); ei != ei_end; ++ei) { if (target(*ei, g.base()) == u.local // TBD: deal with parallel edges properly && *ei == e && get(edge_target_processor_id, bg, *ei) == u.owner) { remove_edge(ei, bg); return; } } if (v.owner == process_id(g.process_group())) { } } //------------------------------------------------------------------------ // Lazy addition of edges // Work around the fact that an adjacency_list with vecS vertex // storage automatically adds edges when the descriptor is // out-of-range. template <class Graph, class Config, class Base> inline std::pair<typename Config::edge_descriptor, bool> add_local_edge(typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, const typename Config::edge_property_type& p, vec_adj_list_impl<Graph, Config, Base>& g_) { adj_list_helper<Config, Base>& g = g_; return add_edge(u, v, p, g); } template <class Graph, class Config, class Base> inline std::pair<typename Config::edge_descriptor, bool> add_local_edge(typename Config::vertex_descriptor u, typename Config::vertex_descriptor v, const typename Config::edge_property_type& p, boost::adj_list_impl<Graph, Config, Base>& g) { return add_edge(u, v, p, g); } template <class EdgeProperty,class EdgeDescriptor> struct msg_nonlocal_edge_data : public detail::parallel::maybe_store_property<EdgeProperty> { typedef EdgeProperty edge_property_type; typedef EdgeDescriptor local_edge_descriptor; typedef detail::parallel::maybe_store_property<edge_property_type> inherited; msg_nonlocal_edge_data() {} msg_nonlocal_edge_data(local_edge_descriptor e, const edge_property_type& p) : inherited(p), e(e) { } local_edge_descriptor e; template<typename Archiver> void serialize(Archiver& ar, const unsigned int /*version*/) { ar & boost::serialization::base_object<inherited>(*this) & e; } }; template <class EdgeDescriptor> struct msg_remove_edge_data { typedef EdgeDescriptor edge_descriptor; msg_remove_edge_data() {} explicit msg_remove_edge_data(edge_descriptor e) : e(e) {} edge_descriptor e; template<typename Archiver> void serialize(Archiver& ar, const unsigned int /*version*/) { ar & e; } }; } } // end namespace detail::parallel /** * Adjacency list traits for a distributed adjacency list. Contains * the vertex and edge descriptors, the directed-ness, and the * parallel edges typedefs. */ template<typename OutEdgeListS, typename ProcessGroup, typename InVertexListS, typename InDistribution, typename DirectedS> struct adjacency_list_traits<OutEdgeListS, distributedS<ProcessGroup, InVertexListS, InDistribution>, DirectedS> { private: typedef typename mpl::if_<is_same<InVertexListS, defaultS>, vecS, InVertexListS>::type VertexListS; typedef adjacency_list_traits<OutEdgeListS, VertexListS, directedS> base_type; public: typedef typename base_type::vertex_descriptor local_vertex_descriptor; typedef typename base_type::edge_descriptor local_edge_descriptor; typedef typename boost::mpl::if_<typename DirectedS::is_bidir_t, bidirectional_tag, typename boost::mpl::if_<typename DirectedS::is_directed_t, directed_tag, undirected_tag >::type >::type directed_category; typedef typename parallel_edge_traits<OutEdgeListS>::type edge_parallel_category; typedef detail::parallel::global_descriptor<local_vertex_descriptor> vertex_descriptor; typedef detail::parallel::edge_descriptor<local_edge_descriptor> edge_descriptor; }; #define PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS \ typename OutEdgeListS, typename ProcessGroup, typename InVertexListS, \ typename InDistribution, typename DirectedS, typename VertexProperty, \ typename EdgeProperty, typename GraphProperty, typename EdgeListS #define PBGL_DISTRIB_ADJLIST_TYPE \ adjacency_list<OutEdgeListS, \ distributedS<ProcessGroup, InVertexListS, InDistribution>, \ DirectedS, VertexProperty, EdgeProperty, GraphProperty, \ EdgeListS> #define PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG \ typename OutEdgeListS, typename ProcessGroup, typename InVertexListS, \ typename InDistribution, typename VertexProperty, \ typename EdgeProperty, typename GraphProperty, typename EdgeListS #define PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directed) \ adjacency_list<OutEdgeListS, \ distributedS<ProcessGroup, InVertexListS, InDistribution>, \ directed, VertexProperty, EdgeProperty, GraphProperty, \ EdgeListS> /** A distributed adjacency list. * * This class template partial specialization defines a distributed * (or "partitioned") adjacency list graph. The distributed * adjacency list is similar to the standard Boost Graph Library * adjacency list, which stores a list of vertices and for each * verted the list of edges outgoing from the vertex (and, in some * cases, also the edges incoming to the vertex). The distributed * adjacency list differs in that it partitions the graph into * several subgraphs that are then divided among different * processors (or nodes within a cluster). The distributed adjacency * list attempts to maintain a high degree of compatibility with the * standard, non-distributed adjacency list. * * The graph is partitioned by vertex, with each processor storing * all of the required information for a particular subset of the * vertices, including vertex properties, outgoing edges, and (for * bidirectional graphs) incoming edges. This information is * accessible only on the processor that owns the vertex: for * instance, if processor 0 owns vertex @c v, no other processor can * directly access the properties of @c v or enumerate its outgoing * edges. * * Edges in a graph may be entirely local (connecting two local * vertices), but more often it is the case that edges are * non-local, meaning that the two vertices they connect reside in * different processes. Edge properties are stored with the * originating vertex for directed and bidirectional graphs, and are * therefore only accessible from the processor that owns the * originating vertex. Other processors may query the source and * target of the edge, but cannot access its properties. This is * particularly interesting when accessing the incoming edges of a * bidirectional graph, which are not guaranteed to be stored on the * processor that is able to perform the iteration. For undirected * graphs the situation is more complicated, since no vertex clearly * owns the edges: the list of edges incident to a vertex may * contain a mix of local and non-local edges. * * The distributed adjacency list is able to model several of the * existing Graph concepts. It models the Graph concept because it * exposes vertex and edge descriptors in the normal way; these * descriptors model the GlobalDescriptor concept (because they have * an owner and a local descriptor), and as such the distributed * adjacency list models the DistributedGraph concept. The adjacency * list also models the IncidenceGraph and AdjacencyGraph concepts, * although this is only true so long as the domain of the valid * expression arguments are restricted to vertices and edges stored * locally. Likewise, bidirectional and undirected distributed * adjacency lists model the BidirectionalGraph concept (vertex and * edge domains must be respectived) and the distributed adjacency * list models the MutableGraph concept (vertices and edges can only * be added or removed locally). T he distributed adjacency list * does not, however, model the VertexListGraph or EdgeListGraph * concepts, because we can not efficiently enumerate all vertices * or edges in the graph. Instead, the local subsets of vertices and * edges can be enumerated (with the same syntax): the distributed * adjacency list therefore models the DistributedVertexListGraph * and DistributedEdgeListGraph concepts, because concurrent * iteration over all of the vertices or edges stored on each * processor will visit each vertex or edge. * * The distributed adjacency list is distinguished from the * non-distributed version by the vertex list descriptor, which will * be @c distributedS<ProcessGroup,VertexListS>. Here, * the VertexListS type plays the same role as the VertexListS type * in the non-distributed adjacency list: it allows one to select * the data structure that will be used to store the local * vertices. The ProcessGroup type, on the other hand, is unique to * distributed data structures: it is the type that abstracts a * group of cooperating processes, and it used for process * identification, communication, and synchronization, among other * things. Different process group types represent different * communication mediums (e.g., MPI, PVM, TCP) or different models * of communication (LogP, CGM, BSP, synchronous, etc.). This * distributed adjacency list assumes a model based on non-blocking * sends. * * Distribution of vertices across different processors is * accomplished in two different ways. When initially constructing * the graph, the user may provide a distribution object (that * models the Distribution concept), which will determine the * distribution of vertices to each process. Additionally, the @c * add_vertex and @c add_edge operations add vertices or edges * stored on the local processor. For @c add_edge, this is * accomplished by requiring that the source vertex of the new edge * be local to the process executing @c add_edge. * * Internal properties of a distributed adjacency list are * accessible in the same manner as internal properties for a * non-distributed adjacency list for local vertices or * edges. Access to properties for remote vertices or edges occurs * with the same syntax, but involve communication with the owner of * the information: for more information, refer to class template * @ref distributed_property_map, which manages distributed * property maps. Note that the distributed property maps created * for internal properties determine their reduction operation via * the metafunction @ref property_reduce, which for the vast * majority of uses is correct behavior. * * Communication among the processes coordinating on a particular * distributed graph relies on non-blocking message passing along * with synchronization. Local portions of the distributed graph may * be modified concurrently, including the introduction of non-local * edges, but prior to accessing the graph it is recommended that * the @c synchronize free function be invoked on the graph to clear * up any pending interprocess communication and modifications. All * processes will then be released from the synchronization barrier * concurrently. * * \todo Determine precisely what we should do with nonlocal edges * in undirected graphs. Our parallelization of certain algorithms * relies on the ability to access edge property maps immediately * (e.g., edge_weight_t), so it may be necessary to duplicate the * edge properties in both processes (but then we need some form of * coherence protocol). * * \todo What does the user do if @c property_reduce doesn't do the * right thing? */ template<typename OutEdgeListS, typename ProcessGroup, typename InVertexListS, typename InDistribution, typename DirectedS, typename VertexProperty, typename EdgeProperty, typename GraphProperty, typename EdgeListS> class adjacency_list<OutEdgeListS, distributedS<ProcessGroup, InVertexListS, InDistribution>, DirectedS, VertexProperty, EdgeProperty, GraphProperty, EdgeListS> : // Support for named vertices public graph::distributed::maybe_named_graph< adjacency_list<OutEdgeListS, distributedS<ProcessGroup, InVertexListS, InDistribution>, DirectedS, VertexProperty, EdgeProperty, GraphProperty, EdgeListS>, typename adjacency_list_traits<OutEdgeListS, distributedS<ProcessGroup, InVertexListS, InDistribution>, DirectedS>::vertex_descriptor, typename adjacency_list_traits<OutEdgeListS, distributedS<ProcessGroup, InVertexListS, InDistribution>, DirectedS>::edge_descriptor, detail::parallel::adjacency_list_config<OutEdgeListS, ProcessGroup, InVertexListS, InDistribution, DirectedS, VertexProperty, EdgeProperty, GraphProperty, EdgeListS> > { typedef detail::parallel::adjacency_list_config<OutEdgeListS, ProcessGroup, InVertexListS, InDistribution, DirectedS, VertexProperty, EdgeProperty, GraphProperty, EdgeListS> config_type; typedef adjacency_list_traits<OutEdgeListS, distributedS<ProcessGroup, InVertexListS, InDistribution>, DirectedS> traits_type; typedef typename DirectedS::is_directed_t is_directed; typedef EdgeListS edge_list_selector; public: /// The container type that will store incoming edges for a /// bidirectional graph. typedef typename config_type::in_edge_list_type in_edge_list_type; // typedef typename inherited::edge_descriptor edge_descriptor; /// The type of the underlying adjacency list implementation typedef typename config_type::inherited inherited; /// The type of properties stored in the local subgraph /// Bidirectional graphs have an extra vertex property to store /// the incoming edges. typedef typename inherited::vertex_property_type base_vertex_property_type; /// The type of the distributed adjacency list (this type) typedef typename config_type::graph_type graph_type; /// Expose graph components and graph category typedef typename traits_type::local_vertex_descriptor local_vertex_descriptor; typedef typename traits_type::local_edge_descriptor local_edge_descriptor; typedef typename traits_type::vertex_descriptor vertex_descriptor; typedef typename traits_type::edge_descriptor edge_descriptor; typedef typename traits_type::directed_category directed_category; typedef typename inherited::edge_parallel_category edge_parallel_category; typedef typename inherited::graph_tag graph_tag; // Current implementation requires the ability to have parallel // edges in the underlying adjacency_list. Which processor each // edge refers to is attached as an internal property. TBD: // remove this restriction, which may require some rewriting. BOOST_STATIC_ASSERT((is_same<edge_parallel_category, allow_parallel_edge_tag>::value)); /** Determine the graph traversal category. * * A directed distributed adjacency list models the Distributed * Graph, Incidence Graph, and Adjacency Graph * concepts. Bidirectional and undirected graphs also model the * Bidirectional Graph concept. Note that when modeling these * concepts the domains of certain operations (e.g., in_edges) * are restricted; see the distributed adjacency_list * documentation. */ typedef typename boost::mpl::if_< is_same<DirectedS, directedS>, directed_distributed_adj_list_tag, typename boost::mpl::if_<is_same<DirectedS, bidirectionalS>, bidirectional_distributed_adj_list_tag, undirected_distributed_adj_list_tag>::type> ::type traversal_category; typedef typename inherited::degree_size_type degree_size_type; typedef typename inherited::vertices_size_type vertices_size_type; typedef typename inherited::edges_size_type edges_size_type; typedef VertexProperty vertex_property_type; typedef EdgeProperty edge_property_type; typedef typename inherited::graph_property_type graph_property_type; typedef typename inherited::vertex_bundled vertex_bundled; typedef typename inherited::edge_bundled edge_bundled; typedef typename inherited::graph_bundled graph_bundled; typedef typename container_gen<edge_list_selector, edge_descriptor>::type local_edge_list_type; private: typedef typename boost::mpl::if_<is_same<DirectedS, bidirectionalS>, typename in_edge_list_type::const_iterator, typename inherited::out_edge_iterator>::type base_in_edge_iterator; typedef typename inherited::out_edge_iterator base_out_edge_iterator; typedef typename graph_traits<inherited>::edge_iterator base_edge_iterator; typedef typename inherited::edge_property_type base_edge_property_type; typedef typename local_edge_list_type::const_iterator undirected_edge_iterator; typedef InDistribution in_distribution_type; typedef parallel::trigger_receive_context trigger_receive_context; public: /// Iterator over the (local) vertices of the graph typedef transform_iterator<typename vertex_descriptor::generator, typename inherited::vertex_iterator> vertex_iterator; /// Helper for out_edge_iterator typedef typename edge_descriptor::template out_generator<adjacency_list> out_edge_generator; /// Iterator over the outgoing edges of a vertex typedef transform_iterator<out_edge_generator, typename inherited::out_edge_iterator> out_edge_iterator; /// Helper for in_edge_iterator typedef typename edge_descriptor::template in_generator<adjacency_list> in_edge_generator; /// Iterator over the incoming edges of a vertex typedef transform_iterator<in_edge_generator, base_in_edge_iterator> in_edge_iterator; /// Iterator over the neighbors of a vertex typedef boost::adjacency_iterator< adjacency_list, vertex_descriptor, out_edge_iterator, typename detail::iterator_traits<base_out_edge_iterator> ::difference_type> adjacency_iterator; /// Iterator over the (local) edges in a graph typedef typename boost::mpl::if_<is_same<DirectedS, undirectedS>, undirected_edge_iterator, transform_iterator<out_edge_generator, base_edge_iterator> >::type edge_iterator; public: /// The type of the mixin for named vertices typedef graph::distributed::maybe_named_graph<graph_type, vertex_descriptor, edge_descriptor, config_type> named_graph_mixin; /// Process group used for communication typedef ProcessGroup process_group_type; /// How to refer to a process typedef typename process_group_type::process_id_type process_id_type; /// Whether this graph is directed, undirected, or bidirectional typedef DirectedS directed_selector; // Structure used for the lazy addition of vertices struct lazy_add_vertex_with_property; friend struct lazy_add_vertex_with_property; // Structure used for the lazy addition of edges struct lazy_add_edge; friend struct lazy_add_edge; // Structure used for the lazy addition of edges with properties struct lazy_add_edge_with_property; friend struct lazy_add_edge_with_property; /// default_distribution_type is the type of the distribution used if the /// user didn't specify an explicit one typedef typename graph::distributed::select_distribution< InDistribution, VertexProperty, vertices_size_type, ProcessGroup>::default_type default_distribution_type; /// distribution_type is the type of the distribution instance stored in /// the maybe_named_graph base class typedef typename graph::distributed::select_distribution< InDistribution, VertexProperty, vertices_size_type, ProcessGroup>::type base_distribution_type; typedef graph::distributed::shuffled_distribution< base_distribution_type> distribution_type; private: // FIXME: the original adjacency_list contained this comment: // Default copy constructor and copy assignment operators OK??? TBD // but the adj_list_impl contained these declarations: adjacency_list(const adjacency_list& other); adjacency_list& operator=(const adjacency_list& other); public: adjacency_list(const ProcessGroup& pg = ProcessGroup()) : named_graph_mixin(pg, default_distribution_type(pg, 0)), m_local_graph(GraphProperty()), process_group_(pg, boost::parallel::attach_distributed_object()) { setup_triggers(); } adjacency_list(const ProcessGroup& pg, const base_distribution_type& distribution) : named_graph_mixin(pg, distribution), m_local_graph(GraphProperty()), process_group_(pg, boost::parallel::attach_distributed_object()) { setup_triggers(); } adjacency_list(const GraphProperty& g, const ProcessGroup& pg = ProcessGroup()) : named_graph_mixin(pg, default_distribution_type(pg, 0)), m_local_graph(g), process_group_(pg, boost::parallel::attach_distributed_object()) { setup_triggers(); } adjacency_list(vertices_size_type n, const GraphProperty& p, const ProcessGroup& pg, const base_distribution_type& distribution) : named_graph_mixin(pg, distribution), m_local_graph(distribution.block_size(process_id(pg), n), p), process_group_(pg, boost::parallel::attach_distributed_object()) { setup_triggers(); detail::parallel::maybe_initialize_vertex_indices(vertices(base()), get(vertex_index, base())); } adjacency_list(vertices_size_type n, const ProcessGroup& pg, const base_distribution_type& distribution) : named_graph_mixin(pg, distribution), m_local_graph(distribution.block_size(process_id(pg), n), GraphProperty()), process_group_(pg, boost::parallel::attach_distributed_object()) { setup_triggers(); detail::parallel::maybe_initialize_vertex_indices(vertices(base()), get(vertex_index, base())); } adjacency_list(vertices_size_type n, const GraphProperty& p, const ProcessGroup& pg = ProcessGroup()) : named_graph_mixin(pg, default_distribution_type(pg, n)), m_local_graph(this->distribution().block_size(process_id(pg), n), p), process_group_(pg, boost::parallel::attach_distributed_object()) { setup_triggers(); detail::parallel::maybe_initialize_vertex_indices(vertices(base()), get(vertex_index, base())); } adjacency_list(vertices_size_type n, const ProcessGroup& pg = ProcessGroup()) : named_graph_mixin(pg, default_distribution_type(pg, n)), m_local_graph(this->distribution().block_size(process_id(pg), n), GraphProperty()), process_group_(pg, boost::parallel::attach_distributed_object()) { setup_triggers(); detail::parallel::maybe_initialize_vertex_indices(vertices(base()), get(vertex_index, base())); } /* * We assume that every processor sees the same list of edges, so * they skip over any that don't originate from themselves. This * means that programs switching between a local and a distributed * graph will keep the same semantics. */ template <class EdgeIterator> adjacency_list(EdgeIterator first, EdgeIterator last, vertices_size_type n, const ProcessGroup& pg = ProcessGroup(), const GraphProperty& p = GraphProperty()) : named_graph_mixin(pg, default_distribution_type(pg, n)), m_local_graph(this->distribution().block_size(process_id(pg), n), p), process_group_(pg, boost::parallel::attach_distributed_object()) { setup_triggers(); typedef typename config_type::VertexListS vertex_list_selector; initialize(first, last, n, this->distribution(), vertex_list_selector()); detail::parallel::maybe_initialize_vertex_indices(vertices(base()), get(vertex_index, base())); } template <class EdgeIterator, class EdgePropertyIterator> adjacency_list(EdgeIterator first, EdgeIterator last, EdgePropertyIterator ep_iter, vertices_size_type n, const ProcessGroup& pg = ProcessGroup(), const GraphProperty& p = GraphProperty()) : named_graph_mixin(pg, default_distribution_type(pg, n)), m_local_graph(this->distribution().block_size(process_id(pg), n), p), process_group_(pg, boost::parallel::attach_distributed_object()) { setup_triggers(); typedef typename config_type::VertexListS vertex_list_selector; initialize(first, last, ep_iter, n, this->distribution(), vertex_list_selector()); detail::parallel::maybe_initialize_vertex_indices(vertices(base()), get(vertex_index, base())); } template <class EdgeIterator> adjacency_list(EdgeIterator first, EdgeIterator last, vertices_size_type n, const ProcessGroup& pg, const base_distribution_type& distribution, const GraphProperty& p = GraphProperty()) : named_graph_mixin(pg, distribution), m_local_graph(distribution.block_size(process_id(pg), n), p), process_group_(pg, boost::parallel::attach_distributed_object()) { setup_triggers(); typedef typename config_type::VertexListS vertex_list_selector; initialize(first, last, n, this->distribution(), vertex_list_selector()); detail::parallel::maybe_initialize_vertex_indices(vertices(base()), get(vertex_index, base())); } template <class EdgeIterator, class EdgePropertyIterator> adjacency_list(EdgeIterator first, EdgeIterator last, EdgePropertyIterator ep_iter, vertices_size_type n, const ProcessGroup& pg, const base_distribution_type& distribution, const GraphProperty& p = GraphProperty()) : named_graph_mixin(pg, distribution), m_local_graph(this->distribution().block_size(process_id(pg), n), p), process_group_(pg, boost::parallel::attach_distributed_object()) { setup_triggers(); typedef typename config_type::VertexListS vertex_list_selector; initialize(first, last, ep_iter, n, distribution, vertex_list_selector()); detail::parallel::maybe_initialize_vertex_indices(vertices(base()), get(vertex_index, base())); } ~adjacency_list() { synchronize(process_group_); } void clear() { base().clear(); local_edges_.clear(); named_graph_mixin::clearing_graph(); } void swap(adjacency_list& other) { using std::swap; base().swap(other); swap(process_group_, other.process_group_); } static vertex_descriptor null_vertex() { return vertex_descriptor(processor_id_type(0), inherited::null_vertex()); } inherited& base() { return m_local_graph; } const inherited& base() const { return m_local_graph; } processor_id_type processor() const { return process_id(process_group_); } process_group_type process_group() const { return process_group_.base(); } local_edge_list_type& local_edges() { return local_edges_; } const local_edge_list_type& local_edges() const { return local_edges_; } // Redistribute the vertices of the graph by placing each vertex // v on the processor get(vertex_to_processor, v). template<typename VertexProcessorMap> void redistribute(VertexProcessorMap vertex_to_processor); // Directly access a vertex or edge bundle vertex_bundled& operator[](vertex_descriptor v) { BOOST_ASSERT(v.owner == processor()); return base()[v.local]; } const vertex_bundled& operator[](vertex_descriptor v) const { BOOST_ASSERT(v.owner == processor()); return base()[v.local]; } edge_bundled& operator[](edge_descriptor e) { BOOST_ASSERT(e.owner() == processor()); return base()[e.local]; } const edge_bundled& operator[](edge_descriptor e) const { BOOST_ASSERT(e.owner() == processor()); return base()[e.local]; } graph_bundled& operator[](graph_bundle_t) { return get_property(*this); } graph_bundled const& operator[](graph_bundle_t) const { return get_property(*this); } template<typename OStreamConstructibleArchive> void save(std::string const& filename) const; template<typename IStreamConstructibleArchive> void load(std::string const& filename); // Callback that will be invoked whenever a new vertex is added locally boost::function<void(vertex_descriptor, adjacency_list&)> on_add_vertex; // Callback that will be invoked whenever a new edge is added locally boost::function<void(edge_descriptor, adjacency_list&)> on_add_edge; private: // Request vertex->processor mapping for neighbors <does nothing> template<typename VertexProcessorMap> void request_in_neighbors(vertex_descriptor, VertexProcessorMap, directedS) { } // Request vertex->processor mapping for neighbors <does nothing> template<typename VertexProcessorMap> void request_in_neighbors(vertex_descriptor, VertexProcessorMap, undirectedS) { } // Request vertex->processor mapping for neighbors template<typename VertexProcessorMap> void request_in_neighbors(vertex_descriptor v, VertexProcessorMap vertex_to_processor, bidirectionalS); // Clear the list of in-edges, but don't tell the remote processor void clear_in_edges_local(vertex_descriptor v, directedS) {} void clear_in_edges_local(vertex_descriptor v, undirectedS) {} void clear_in_edges_local(vertex_descriptor v, bidirectionalS) { get(vertex_in_edges, base())[v.local].clear(); } // Remove in-edges that have migrated <does nothing> template<typename VertexProcessorMap> void remove_migrated_in_edges(vertex_descriptor, VertexProcessorMap, directedS) { } // Remove in-edges that have migrated <does nothing> template<typename VertexProcessorMap> void remove_migrated_in_edges(vertex_descriptor, VertexProcessorMap, undirectedS) { } // Remove in-edges that have migrated template<typename VertexProcessorMap> void remove_migrated_in_edges(vertex_descriptor v, VertexProcessorMap vertex_to_processor, bidirectionalS); // Initialize the graph with the given edge list and vertex // distribution. This variation works only when // VertexListS=vecS, and we know how to create remote vertex // descriptors based solely on the distribution. template<typename EdgeIterator> void initialize(EdgeIterator first, EdgeIterator last, vertices_size_type, const base_distribution_type& distribution, vecS); // Initialize the graph with the given edge list, edge // properties, and vertex distribution. This variation works // only when VertexListS=vecS, and we know how to create remote // vertex descriptors based solely on the distribution. template<typename EdgeIterator, typename EdgePropertyIterator> void initialize(EdgeIterator first, EdgeIterator last, EdgePropertyIterator ep_iter, vertices_size_type, const base_distribution_type& distribution, vecS); // Initialize the graph with the given edge list, edge // properties, and vertex distribution. template<typename EdgeIterator, typename EdgePropertyIterator, typename VertexListS> void initialize(EdgeIterator first, EdgeIterator last, EdgePropertyIterator ep_iter, vertices_size_type n, const base_distribution_type& distribution, VertexListS); // Initialize the graph with the given edge list and vertex // distribution. This is nearly identical to the one below it, // for which I should be flogged. However, this version does use // slightly less memory than the version that accepts an edge // property iterator. template<typename EdgeIterator, typename VertexListS> void initialize(EdgeIterator first, EdgeIterator last, vertices_size_type n, const base_distribution_type& distribution, VertexListS); public: //--------------------------------------------------------------------- // Build a vertex property instance for the underlying adjacency // list from the given property instance of the type exposed to // the user. base_vertex_property_type build_vertex_property(const vertex_property_type& p) { return build_vertex_property(p, directed_selector()); } base_vertex_property_type build_vertex_property(const vertex_property_type& p, directedS) { return base_vertex_property_type(p); } base_vertex_property_type build_vertex_property(const vertex_property_type& p, bidirectionalS) { return base_vertex_property_type(in_edge_list_type(), p); } base_vertex_property_type build_vertex_property(const vertex_property_type& p, undirectedS) { return base_vertex_property_type(p); } //--------------------------------------------------------------------- //--------------------------------------------------------------------- // Build an edge property instance for the underlying adjacency // list from the given property instance of the type exposed to // the user. base_edge_property_type build_edge_property(const edge_property_type& p) { return build_edge_property(p, directed_selector()); } base_edge_property_type build_edge_property(const edge_property_type& p, directedS) { return base_edge_property_type(0, p); } base_edge_property_type build_edge_property(const edge_property_type& p, bidirectionalS) { return base_edge_property_type(0, p); } base_edge_property_type build_edge_property(const edge_property_type& p, undirectedS) { typedef typename base_edge_property_type::next_type edge_property_with_id; return base_edge_property_type(true, edge_property_with_id(0, p)); } //--------------------------------------------------------------------- //--------------------------------------------------------------------- // Opposite of above. edge_property_type split_edge_property(const base_edge_property_type& p) { return split_edge_property(p, directed_selector()); } edge_property_type split_edge_property(const base_edge_property_type& p, directedS) { return p.m_base; } edge_property_type split_edge_property(const base_edge_property_type& p, bidirectionalS) { return p.m_base; } edge_property_type split_edge_property(const base_edge_property_type& p, undirectedS) { return p.m_base.m_base; } //--------------------------------------------------------------------- /** The set of messages that can be transmitted and received by * a distributed adjacency list. This list will eventually be * exhaustive, but is currently quite limited. */ enum { /** * Request to add or find a vertex with the given vertex * property. The data will be a vertex_property_type * structure. */ msg_add_vertex_with_property = 0, /** * Request to add or find a vertex with the given vertex * property, and request that the remote processor return the * descriptor for the added/found edge. The data will be a * vertex_property_type structure. */ msg_add_vertex_with_property_and_reply, /** * Reply to a msg_add_vertex_* message, containing the local * vertex descriptor that was added or found. */ msg_add_vertex_reply, /** * Request to add an edge remotely. The data will be a * msg_add_edge_data structure. */ msg_add_edge, /** * Request to add an edge remotely. The data will be a * msg_add_edge_with_property_data structure. */ msg_add_edge_with_property, /** * Request to add an edge remotely and reply back with the * edge descriptor. The data will be a * msg_add_edge_data structure. */ msg_add_edge_with_reply, /** * Request to add an edge remotely and reply back with the * edge descriptor. The data will be a * msg_add_edge_with_property_data structure. */ msg_add_edge_with_property_and_reply, /** * Reply message responding to an @c msg_add_edge_with_reply * or @c msg_add_edge_with_property_and_reply messages. The * data will be a std::pair<edge_descriptor, bool>. */ msg_add_edge_reply, /** * Indicates that a nonlocal edge has been created that should * be added locally. Only valid for bidirectional and * undirected graphs. The message carries a * msg_nonlocal_edge_data structure. */ msg_nonlocal_edge, /** * Indicates that a remote edge should be removed. This * message does not exist for directedS graphs but may refer * to either in-edges or out-edges for undirectedS graphs. */ msg_remove_edge, /** * Indicates the number of vertices and edges that will be * relocated from the source processor to the target * processor. The data will be a pair<vertices_size_type, * edges_size_type>. */ msg_num_relocated }; typedef detail::parallel::msg_add_edge_data<vertex_descriptor, local_vertex_descriptor> msg_add_edge_data; typedef detail::parallel::msg_add_edge_with_property_data <vertex_descriptor, local_vertex_descriptor, edge_property_type> msg_add_edge_with_property_data; typedef boost::detail::parallel::msg_nonlocal_edge_data< edge_property_type,local_edge_descriptor> msg_nonlocal_edge_data; typedef boost::detail::parallel::msg_remove_edge_data<edge_descriptor> msg_remove_edge_data; void send_remove_edge_request(edge_descriptor e) { process_id_type dest = e.target_processor; if (e.target_processor == process_id(process_group_)) dest = e.source_processor; send(process_group_, dest, msg_remove_edge, msg_remove_edge_data(e)); } /// Process incoming messages. void setup_triggers(); void handle_add_vertex_with_property(int source, int tag, const vertex_property_type&, trigger_receive_context); local_vertex_descriptor handle_add_vertex_with_property_and_reply(int source, int tag, const vertex_property_type&, trigger_receive_context); void handle_add_edge(int source, int tag, const msg_add_edge_data& data, trigger_receive_context); boost::parallel::detail::untracked_pair<edge_descriptor, bool> handle_add_edge_with_reply(int source, int tag, const msg_add_edge_data& data, trigger_receive_context); void handle_add_edge_with_property(int source, int tag, const msg_add_edge_with_property_data&, trigger_receive_context); boost::parallel::detail::untracked_pair<edge_descriptor, bool> handle_add_edge_with_property_and_reply (int source, int tag, const msg_add_edge_with_property_data&, trigger_receive_context); void handle_nonlocal_edge(int source, int tag, const msg_nonlocal_edge_data& data, trigger_receive_context); void handle_remove_edge(int source, int tag, const msg_remove_edge_data& data, trigger_receive_context); protected: /** Add an edge (locally) that was received from another * processor. This operation is a no-op for directed graphs, * because all edges reside on the local processor. For * bidirectional graphs, this routine places the edge onto the * list of incoming edges for the target vertex. For undirected * graphs, the edge is placed along with all of the other edges * for the target vertex, but it is marked as a non-local edge * descriptor. * * \todo There is a potential problem here, where we could * unintentionally allow duplicate edges in undirected graphs * because the same edge is added on two different processors * simultaneously. It's not an issue now, because we require * that the graph allow parallel edges. Once we do support * containers such as setS or hash_setS that disallow parallel * edges we will need to deal with this. */ void add_remote_edge(const msg_nonlocal_edge_data&, processor_id_type, directedS) { } /** * \overload */ void add_remote_edge(const msg_nonlocal_edge_data& data, processor_id_type other_proc, bidirectionalS) { typedef detail::parallel::stored_in_edge<local_edge_descriptor> stored_edge; stored_edge edge(other_proc, data.e); local_vertex_descriptor v = target(data.e, base()); boost::graph_detail::push(get(vertex_in_edges, base())[v], edge); } /** * \overload */ void add_remote_edge(const msg_nonlocal_edge_data& data, processor_id_type other_proc, undirectedS) { std::pair<local_edge_descriptor, bool> edge = detail::parallel::add_local_edge(target(data.e, base()), source(data.e, base()), build_edge_property(data.get_property()), base()); BOOST_ASSERT(edge.second); put(edge_target_processor_id, base(), edge.first, other_proc); if (edge.second && on_add_edge) on_add_edge(edge_descriptor(processor(), other_proc, false, edge.first), *this); } void remove_local_edge(const msg_remove_edge_data&, processor_id_type, directedS) { } void remove_local_edge(const msg_remove_edge_data& data, processor_id_type other_proc, bidirectionalS) { /* When the source is local, we first check if the edge still * exists (it may have been deleted locally) and, if so, * remove it locally. */ vertex_descriptor src = source(data.e, *this); vertex_descriptor tgt = target(data.e, *this); if (src.owner == process_id(process_group_)) { base_out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(src.local, base()); ei != ei_end; ++ei) { // TBD: can't check the descriptor here, because it could // have changed if we're allowing the removal of // edges. Egads! if (tgt.local == target(*ei, base()) && get(edge_target_processor_id, base(), *ei) == other_proc) break; } if (ei != ei_end) boost::remove_edge(ei, base()); remove_local_edge_from_list(src, tgt, undirectedS()); } else { BOOST_ASSERT(tgt.owner == process_id(process_group_)); in_edge_list_type& in_edges = get(vertex_in_edges, base())[tgt.local]; typename in_edge_list_type::iterator ei; for (ei = in_edges.begin(); ei != in_edges.end(); ++ei) { if (src.local == source(ei->e, base()) && src.owner == ei->source_processor) break; } if (ei != in_edges.end()) in_edges.erase(ei); } } void remove_local_edge(const msg_remove_edge_data& data, processor_id_type other_proc, undirectedS) { vertex_descriptor local_vertex = source(data.e, *this); vertex_descriptor remote_vertex = target(data.e, *this); if (remote_vertex.owner == process_id(process_group_)) { using std::swap; swap(local_vertex, remote_vertex); } // Remove the edge from the out-edge list, if it is there { base_out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(local_vertex.local, base()); ei != ei_end; ++ei) { // TBD: can't check the descriptor here, because it could // have changed if we're allowing the removal of // edges. Egads! if (remote_vertex.local == target(*ei, base()) && get(edge_target_processor_id, base(), *ei) == other_proc) break; } if (ei != ei_end) boost::remove_edge(ei, base()); } remove_local_edge_from_list(local_vertex, remote_vertex, undirectedS()); } public: void remove_local_edge_from_list(vertex_descriptor, vertex_descriptor, directedS) { } void remove_local_edge_from_list(vertex_descriptor, vertex_descriptor, bidirectionalS) { } void remove_local_edge_from_list(vertex_descriptor src, vertex_descriptor tgt, undirectedS) { // TBD: At some point we'll be able to improve the speed here // because we'll know when the edge can't be in the local // list. { typename local_edge_list_type::iterator ei; for (ei = local_edges_.begin(); ei != local_edges_.end(); ++ei) { if ((source(*ei, *this) == src && target(*ei, *this) == tgt) || (source(*ei, *this) == tgt && target(*ei, *this) == src)) break; } if (ei != local_edges_.end()) local_edges_.erase(ei); } } private: /// The local subgraph inherited m_local_graph; /// The process group through which this distributed graph /// communicates. process_group_type process_group_; // TBD: should only be available for undirected graphs, but for // now it'll just be empty for directed and bidirectional // graphs. local_edge_list_type local_edges_; }; //------------------------------------------------------------------------ // Lazy addition of vertices template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> struct PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_vertex_with_property { /// Construct a lazy request to add a vertex lazy_add_vertex_with_property(adjacency_list& self, const vertex_property_type& property) : self(self), property(property), committed(false) { } /// Copying a lazy_add_vertex_with_property transfers the /// responsibility for adding the vertex to the newly-constructed /// object. lazy_add_vertex_with_property(const lazy_add_vertex_with_property& other) : self(other.self), property(other.property), committed(other.committed) { other.committed = true; } /// If the vertex has not yet been added, add the vertex but don't /// wait for a reply. ~lazy_add_vertex_with_property(); /// Returns commit(). operator vertex_descriptor() const { return commit(); } // Add the vertex. This operation will block if the vertex is // being added remotely. vertex_descriptor commit() const; protected: adjacency_list& self; vertex_property_type property; mutable bool committed; private: // No copy-assignment semantics void operator=(lazy_add_vertex_with_property&); }; template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_vertex_with_property:: ~lazy_add_vertex_with_property() { /// If this vertex has already been created or will be created by /// someone else, or if someone threw an exception, we will not /// create the vertex now. if (committed || std::uncaught_exception()) return; committed = true; process_id_type owner = static_cast<graph_type&>(self).owner_by_property(property); if (owner == self.processor()) { /// Add the vertex locally. vertex_descriptor v(owner, add_vertex(self.build_vertex_property(property), self.base())); if (self.on_add_vertex) self.on_add_vertex(v, self); } else /// Ask the owner of this new vertex to add the vertex. We /// don't need a reply. send(self.process_group_, owner, msg_add_vertex_with_property, property); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_vertex_with_property:: commit() const { BOOST_ASSERT(!this->committed); this->committed = true; process_id_type owner = static_cast<graph_type&>(self).owner_by_property(property); local_vertex_descriptor local_v; if (owner == self.processor()) /// Add the vertex locally. local_v = add_vertex(self.build_vertex_property(property), self.base()); else { // Request that the remote process add the vertex immediately send_oob_with_reply(self.process_group_, owner, msg_add_vertex_with_property_and_reply, property, local_v); } vertex_descriptor v(owner, local_v); if (self.on_add_vertex) self.on_add_vertex(v, self); // Build the full vertex descriptor to return return v; } /** * Data structure returned from add_edge that will "lazily" add * the edge, either when it is converted to a * @c pair<edge_descriptor, bool> or when the most recent copy has * been destroyed. */ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> struct PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge { /// Construct a lazy request to add an edge lazy_add_edge(adjacency_list& self, vertex_descriptor source, vertex_descriptor target) : self(self), source(source), target(target), committed(false) { } /// Copying a lazy_add_edge transfers the responsibility for /// adding the edge to the newly-constructed object. lazy_add_edge(const lazy_add_edge& other) : self(other.self), source(other.source), target(other.target), committed(other.committed) { other.committed = true; } /// If the edge has not yet been added, add the edge but don't /// wait for a reply. ~lazy_add_edge(); /// Returns commit(). operator std::pair<edge_descriptor, bool>() const { return commit(); } // Add the edge. This operation will block if a remote edge is // being added. std::pair<edge_descriptor, bool> commit() const; protected: std::pair<edge_descriptor, bool> add_local_edge(const edge_property_type& property, directedS) const; std::pair<edge_descriptor, bool> add_local_edge(const edge_property_type& property, bidirectionalS) const; std::pair<edge_descriptor, bool> add_local_edge(const edge_property_type& property, undirectedS) const; adjacency_list& self; vertex_descriptor source; vertex_descriptor target; mutable bool committed; private: // No copy-assignment semantics void operator=(lazy_add_edge&); }; template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge::~lazy_add_edge() { /// If this edge has already been created or will be created by /// someone else, or if someone threw an exception, we will not /// create the edge now. if (committed || std::uncaught_exception()) return; committed = true; if (source.owner == self.processor()) this->add_local_edge(edge_property_type(), DirectedS()); else // Request that the remote processor add an edge and, but // don't wait for a reply. send(self.process_group_, source.owner, msg_add_edge, msg_add_edge_data(source, target)); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool> PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge::commit() const { BOOST_ASSERT(!committed); committed = true; if (source.owner == self.processor()) return this->add_local_edge(edge_property_type(), DirectedS()); else { // Request that the remote processor add an edge boost::parallel::detail::untracked_pair<edge_descriptor, bool> result; send_oob_with_reply(self.process_group_, source.owner, msg_add_edge_with_reply, msg_add_edge_data(source, target), result); return result; } } // Add a local edge into a directed graph template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool> PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge:: add_local_edge(const edge_property_type& property, directedS) const { // Add the edge to the local part of the graph std::pair<local_edge_descriptor, bool> inserted = detail::parallel::add_local_edge(source.local, target.local, self.build_edge_property(property), self.base()); if (inserted.second) // Keep track of the owner of the target put(edge_target_processor_id, self.base(), inserted.first, target.owner); // Compose the edge descriptor and return the result edge_descriptor e(source.owner, target.owner, true, inserted.first); // Trigger the on_add_edge event if (inserted.second && self.on_add_edge) self.on_add_edge(e, self); return std::pair<edge_descriptor, bool>(e, inserted.second); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool> PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge:: add_local_edge(const edge_property_type& property, bidirectionalS) const { // Add the directed edge. std::pair<edge_descriptor, bool> result = this->add_local_edge(property, directedS()); if (result.second) { if (target.owner == self.processor()) { // Edge is local, so add the stored edge to the in_edges list typedef detail::parallel::stored_in_edge<local_edge_descriptor> stored_edge; stored_edge e(self.processor(), result.first.local); boost::graph_detail::push(get(vertex_in_edges, self.base())[target.local], e); } else { // Edge is remote, so notify the target's owner that an edge // has been added. if (self.process_group_.trigger_context() == boost::parallel::trc_out_of_band) send_oob(self.process_group_, target.owner, msg_nonlocal_edge, msg_nonlocal_edge_data(result.first.local, property)); else send(self.process_group_, target.owner, msg_nonlocal_edge, msg_nonlocal_edge_data(result.first.local, property)); } } return result; } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool> PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge:: add_local_edge(const edge_property_type& property, undirectedS) const { // Add the directed edge std::pair<edge_descriptor, bool> result = this->add_local_edge(property, directedS()); if (result.second) { if (target.owner == self.processor()) { // Edge is local, so add the new edge to the list // TODO: This is not what we want to do for an undirected // edge, because we haven't linked the source and target's // representations of those edges. local_edge_descriptor return_edge = detail::parallel::add_local_edge(target.local, source.local, self.build_edge_property(property), self.base()).first; put(edge_target_processor_id, self.base(), return_edge, source.owner); } else { // Edge is remote, so notify the target's owner that an edge // has been added. if (self.process_group_.trigger_context() == boost::parallel::trc_out_of_band) send_oob(self.process_group_, target.owner, msg_nonlocal_edge, msg_nonlocal_edge_data(result.first.local, property)); else send(self.process_group_, target.owner, msg_nonlocal_edge, msg_nonlocal_edge_data(result.first.local, property)); } // Add this edge to the list of local edges graph_detail::push(self.local_edges(), result.first); } return result; } /** * Data structure returned from add_edge that will "lazily" add * the edge with its property, either when it is converted to a * pair<edge_descriptor, bool> or when the most recent copy has * been destroyed. */ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> struct PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge_with_property : lazy_add_edge { /// Construct a lazy request to add an edge lazy_add_edge_with_property(adjacency_list& self, vertex_descriptor source, vertex_descriptor target, const edge_property_type& property) : lazy_add_edge(self, source, target), property(property) { } /// Copying a lazy_add_edge transfers the responsibility for /// adding the edge to the newly-constructed object. lazy_add_edge_with_property(const lazy_add_edge& other) : lazy_add_edge(other), property(other.property) { } /// If the edge has not yet been added, add the edge but don't /// wait for a reply. ~lazy_add_edge_with_property(); /// Returns commit(). operator std::pair<edge_descriptor, bool>() const { return commit(); } // Add the edge. This operation will block if a remote edge is // being added. std::pair<edge_descriptor, bool> commit() const; private: // No copy-assignment semantics void operator=(lazy_add_edge_with_property&); edge_property_type property; }; template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge_with_property:: ~lazy_add_edge_with_property() { /// If this edge has already been created or will be created by /// someone else, or if someone threw an exception, we will not /// create the edge now. if (this->committed || std::uncaught_exception()) return; this->committed = true; if (this->source.owner == this->self.processor()) // Add a local edge this->add_local_edge(property, DirectedS()); else // Request that the remote processor add an edge and, but // don't wait for a reply. send(this->self.process_group_, this->source.owner, msg_add_edge_with_property, msg_add_edge_with_property_data(this->source, this->target, property)); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool> PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge_with_property:: commit() const { BOOST_ASSERT(!this->committed); this->committed = true; if (this->source.owner == this->self.processor()) // Add a local edge return this->add_local_edge(property, DirectedS()); else { // Request that the remote processor add an edge boost::parallel::detail::untracked_pair<edge_descriptor, bool> result; send_oob_with_reply(this->self.process_group_, this->source.owner, msg_add_edge_with_property_and_reply, msg_add_edge_with_property_data(this->source, this->target, property), result); return result; } } /** * Returns the set of vertices local to this processor. Note that * although this routine matches a valid expression of a * VertexListGraph, it does not meet the semantic requirements of * VertexListGraph because it returns only local vertices (not all * vertices). */ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE ::vertex_iterator, typename PBGL_DISTRIB_ADJLIST_TYPE ::vertex_iterator> vertices(const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename PBGL_DISTRIB_ADJLIST_TYPE ::vertex_descriptor Vertex; typedef typename Vertex::generator generator; return std::make_pair(make_transform_iterator(vertices(g.base()).first, generator(g.processor())), make_transform_iterator(vertices(g.base()).second, generator(g.processor()))); } /** * Returns the number of vertices local to this processor. Note that * although this routine matches a valid expression of a * VertexListGraph, it does not meet the semantic requirements of * VertexListGraph because it returns only a count of local vertices * (not all vertices). */ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename PBGL_DISTRIB_ADJLIST_TYPE ::vertices_size_type num_vertices(const PBGL_DISTRIB_ADJLIST_TYPE& g) { return num_vertices(g.base()); } /*************************************************************************** * Implementation of Incidence Graph concept ***************************************************************************/ /** * Returns the source of edge @param e in @param g. */ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Edge> typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor source(const detail::parallel::edge_descriptor<Edge>& e, const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename PBGL_DISTRIB_ADJLIST_TYPE ::vertex_descriptor Vertex; return Vertex(e.source_processor, source(e.local, g.base())); } /** * Returns the target of edge @param e in @param g. */ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Edge> typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor target(const detail::parallel::edge_descriptor<Edge>& e, const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename PBGL_DISTRIB_ADJLIST_TYPE ::vertex_descriptor Vertex; return Vertex(e.target_processor, target(e.local, g.base())); } /** * Return the set of edges outgoing from a particular vertex. The * vertex @param v must be local to the processor executing this * routine. */ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::out_edge_iterator, typename PBGL_DISTRIB_ADJLIST_TYPE::out_edge_iterator> out_edges(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v, const PBGL_DISTRIB_ADJLIST_TYPE& g) { BOOST_ASSERT(v.owner == g.processor()); typedef PBGL_DISTRIB_ADJLIST_TYPE impl; typedef typename impl::out_edge_generator generator; return std::make_pair( make_transform_iterator(out_edges(v.local, g.base()).first, generator(g)), make_transform_iterator(out_edges(v.local, g.base()).second, generator(g))); } /** * Return the number of edges outgoing from a particular vertex. The * vertex @param v must be local to the processor executing this * routine. */ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename PBGL_DISTRIB_ADJLIST_TYPE::degree_size_type out_degree(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v, const PBGL_DISTRIB_ADJLIST_TYPE& g) { BOOST_ASSERT(v.owner == g.processor()); return out_degree(v.local, g.base()); } /*************************************************************************** * Implementation of Bidirectional Graph concept ***************************************************************************/ /** * Returns the set of edges incoming to a particular vertex. The * vertex @param v must be local to the processor executing this * routine. */ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) ::in_edge_iterator, typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) ::in_edge_iterator> in_edges(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) ::vertex_descriptor v, const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g) { BOOST_ASSERT(v.owner == g.processor()); typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) impl; typedef typename impl::inherited base_graph_type; typedef typename impl::in_edge_generator generator; typename property_map<base_graph_type, vertex_in_edges_t>::const_type in_edges = get(vertex_in_edges, g.base()); return std::make_pair(make_transform_iterator(in_edges[v.local].begin(), generator(g)), make_transform_iterator(in_edges[v.local].end(), generator(g))); } /** * \overload */ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS) ::in_edge_iterator, typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS) ::in_edge_iterator> in_edges(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS) ::vertex_descriptor v, const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g) { BOOST_ASSERT(v.owner == g.processor()); typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS) impl; typedef typename impl::in_edge_generator generator; return std::make_pair( make_transform_iterator(out_edges(v.local, g.base()).first, generator(g)), make_transform_iterator(out_edges(v.local, g.base()).second, generator(g))); } /** * Returns the number of edges incoming to a particular vertex. The * vertex @param v must be local to the processor executing this * routine. */ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)::degree_size_type in_degree(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) ::vertex_descriptor v, const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g) { BOOST_ASSERT(v.owner == g.processor()); return get(vertex_in_edges, g.base())[v.local].size(); } /** * \overload */ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)::degree_size_type in_degree(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS) ::vertex_descriptor v, const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g) { BOOST_ASSERT(v.owner == g.processor()); return out_degree(v.local, g.base()); } /** * Returns the number of edges incident on the given vertex. The * vertex @param v must be local to the processor executing this * routine. */ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS) ::degree_size_type degree(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS) ::vertex_descriptor v, const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g) { BOOST_ASSERT(v.owner == g.processor()); return out_degree(v.local, g.base()); } /** * \overload */ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) ::degree_size_type degree(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) ::vertex_descriptor v, const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g) { BOOST_ASSERT(v.owner == g.processor()); return out_degree(v, g) + in_degree(v, g); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename PBGL_DISTRIB_ADJLIST_TYPE::edges_size_type num_edges(const PBGL_DISTRIB_ADJLIST_TYPE& g) { return num_edges(g.base()); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)::edges_size_type num_edges(const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g) { return g.local_edges().size(); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> std::pair< typename PBGL_DISTRIB_ADJLIST_TYPE::edge_iterator, typename PBGL_DISTRIB_ADJLIST_TYPE::edge_iterator> edges(const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef PBGL_DISTRIB_ADJLIST_TYPE impl; typedef typename impl::out_edge_generator generator; return std::make_pair(make_transform_iterator(edges(g.base()).first, generator(g)), make_transform_iterator(edges(g.base()).second, generator(g))); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> std::pair< typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)::edge_iterator, typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)::edge_iterator> edges(const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g) { return std::make_pair(g.local_edges().begin(), g.local_edges().end()); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> inline typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor vertex(typename PBGL_DISTRIB_ADJLIST_TYPE::vertices_size_type n, const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor vertex_descriptor; return vertex_descriptor(g.distribution()(n), g.distribution().local(n)); } /*************************************************************************** * Access to particular edges ***************************************************************************/ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> std::pair< typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)::edge_descriptor, bool > edge(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)::vertex_descriptor u, typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)::vertex_descriptor v, const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)& g) { typedef typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS) ::edge_descriptor edge_descriptor; // For directed graphs, u must be local BOOST_ASSERT(u.owner == process_id(g.process_group())); typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS) ::out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) { if (target(*ei, g) == v) return std::make_pair(*ei, true); } return std::make_pair(edge_descriptor(), false); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> std::pair< typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool > edge(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u, typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v, const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename PBGL_DISTRIB_ADJLIST_TYPE ::edge_descriptor edge_descriptor; // For bidirectional and undirected graphs, u must be local or v // must be local if (u.owner == process_id(g.process_group())) { typename PBGL_DISTRIB_ADJLIST_TYPE::out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) { if (target(*ei, g) == v) return std::make_pair(*ei, true); } return std::make_pair(edge_descriptor(), false); } else if (v.owner == process_id(g.process_group())) { typename PBGL_DISTRIB_ADJLIST_TYPE::in_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = in_edges(v, g); ei != ei_end; ++ei) { if (source(*ei, g) == u) return std::make_pair(*ei, true); } return std::make_pair(edge_descriptor(), false); } else { BOOST_ASSERT(false); abort(); } } #if 0 // TBD: not yet supported std::pair<out_edge_iterator, out_edge_iterator> edge_range(vertex_descriptor u, vertex_descriptor v, const adjacency_list& g); #endif /*************************************************************************** * Implementation of Adjacency Graph concept ***************************************************************************/ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::adjacency_iterator, typename PBGL_DISTRIB_ADJLIST_TYPE::adjacency_iterator> adjacent_vertices(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v, const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename PBGL_DISTRIB_ADJLIST_TYPE::adjacency_iterator iter; return std::make_pair(iter(out_edges(v, g).first, &g), iter(out_edges(v, g).second, &g)); } /*************************************************************************** * Implementation of Mutable Graph concept ***************************************************************************/ /************************************************************************ * add_edge ************************************************************************/ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge add_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u, typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge lazy_add_edge; return lazy_add_edge(g, u, v); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename PBGL_DISTRIB_ADJLIST_TYPE ::lazy_add_edge_with_property add_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u, typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v, typename PBGL_DISTRIB_ADJLIST_TYPE::edge_property_type const& p, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename PBGL_DISTRIB_ADJLIST_TYPE ::lazy_add_edge_with_property lazy_add_edge_with_property; return lazy_add_edge_with_property(g, u, v, p); } /************************************************************************ * * remove_edge * ************************************************************************/ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> void remove_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor e, PBGL_DISTRIB_ADJLIST_TYPE& g) { BOOST_ASSERT(source(e, g).owner == g.processor() || target(e, g).owner == g.processor()); if (target(e, g).owner == g.processor()) detail::parallel::remove_in_edge(e, g, DirectedS()); if (source(e, g).owner == g.processor()) remove_edge(e.local, g.base()); g.remove_local_edge_from_list(source(e, g), target(e, g), DirectedS()); if (source(e, g).owner != g.processor() || (target(e, g).owner != g.processor() && !(is_same<DirectedS, directedS>::value))) { g.send_remove_edge_request(e); } } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> void remove_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u, typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename PBGL_DISTRIB_ADJLIST_TYPE ::edge_descriptor edge_descriptor; std::pair<edge_descriptor, bool> the_edge = edge(u, v, g); if (the_edge.second) remove_edge(the_edge.first, g); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> inline void remove_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::out_edge_iterator ei, PBGL_DISTRIB_ADJLIST_TYPE& g) { remove_edge(*ei, g); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> inline void remove_edge(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS) ::out_edge_iterator ei, PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)& g) { BOOST_ASSERT(source(*ei, g).owner == g.processor()); remove_edge(ei->local, g.base()); } /************************************************************************ * * remove_out_edge_if * ************************************************************************/ namespace parallel { namespace detail { /** * Function object that applies the underlying predicate to * determine if an out-edge should be removed. If so, either * removes the incoming edge (if it is stored locally) or sends a * message to the owner of the target requesting that it remove * the edge. */ template<typename Graph, typename Predicate> struct remove_out_edge_predicate { typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor; typedef typename Graph::local_edge_descriptor argument_type; typedef typename Graph::directed_selector directed_selector; typedef bool result_type; remove_out_edge_predicate(Graph& g, Predicate& predicate) : g(g), predicate(predicate) { } bool operator()(const argument_type& le) { typedef typename edge_descriptor::template out_generator<Graph> generator; edge_descriptor e = generator(g)(le); if (predicate(e)) { if (source(e, g).owner != target(e, g).owner && !(is_same<directed_selector, directedS>::value)) g.send_remove_edge_request(e); else ::boost::detail::parallel::remove_in_edge(e, g, directed_selector()); g.remove_local_edge_from_list(source(e, g), target(e, g), directed_selector()); return true; } else return false; } private: Graph& g; Predicate predicate; }; } } // end namespace parallel::detail template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Predicate> inline void remove_out_edge_if (typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u, Predicate predicate, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef PBGL_DISTRIB_ADJLIST_TYPE Graph; typedef parallel::detail::remove_out_edge_predicate<Graph, Predicate> Pred; BOOST_ASSERT(u.owner == g.processor()); remove_out_edge_if(u.local, Pred(g, predicate), g.base()); } /************************************************************************ * * remove_in_edge_if * ************************************************************************/ namespace parallel { namespace detail { /** * Function object that applies the underlying predicate to * determine if an in-edge should be removed. If so, either * removes the outgoing edge (if it is stored locally) or sends a * message to the owner of the target requesting that it remove * the edge. Only required for bidirectional graphs. */ template<typename Graph, typename Predicate> struct remove_in_edge_predicate { typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor; typedef bool result_type; remove_in_edge_predicate(Graph& g, const Predicate& predicate) : g(g), predicate(predicate) { } template<typename StoredEdge> bool operator()(const StoredEdge& le) { typedef typename edge_descriptor::template in_generator<Graph> generator; edge_descriptor e = generator(g)(le); if (predicate(e)) { if (source(e, g).owner != target(e, g).owner) g.send_remove_edge_request(e); else remove_edge(source(e, g).local, target(e, g).local, g.base()); return true; } else return false; } private: Graph& g; Predicate predicate; }; } } // end namespace parallel::detail template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate> inline void remove_in_edge_if (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) ::vertex_descriptor u, Predicate predicate, PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g) { typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) Graph; typedef parallel::detail::remove_in_edge_predicate<Graph, Predicate> Pred; BOOST_ASSERT(u.owner == g.processor()); graph_detail::erase_if(get(vertex_in_edges, g.base())[u.local], Pred(g, predicate)); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate> inline void remove_in_edge_if (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS) ::vertex_descriptor u, Predicate predicate, PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g) { remove_out_edge_if(u, predicate, g); } /************************************************************************ * * remove_edge_if * ************************************************************************/ namespace parallel { namespace detail { /** * Function object that applies the underlying predicate to * determine if a directed edge can be removed. This only applies * to directed graphs. */ template<typename Graph, typename Predicate> struct remove_directed_edge_predicate { typedef typename Graph::local_edge_descriptor argument_type; typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor; typedef bool result_type; remove_directed_edge_predicate(Graph& g, const Predicate& predicate) : g(g), predicate(predicate) { } bool operator()(const argument_type& le) { typedef typename edge_descriptor::template out_generator<Graph> generator; edge_descriptor e = generator(g)(le); return predicate(e); } private: Graph& g; Predicate predicate; }; } } // end namespace parallel::detail template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate> inline void remove_edge_if(Predicate predicate, PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)& g) { typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS) Graph; typedef parallel::detail::remove_directed_edge_predicate<Graph, Predicate> Pred; remove_edge_if(Pred(g, predicate), g.base()); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate> inline void remove_edge_if(Predicate predicate, PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g) { typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) Graph; typedef parallel::detail::remove_out_edge_predicate<Graph, Predicate> Pred; remove_edge_if(Pred(g, predicate), g.base()); } namespace parallel { namespace detail { /** * Function object that applies the underlying predicate to * determine if an undirected edge should be removed. If so, * removes the local edges associated with the edge and * (potentially) sends a message to the remote processor that also * is removing this edge. */ template<typename Graph, typename Predicate> struct remove_undirected_edge_predicate { typedef typename graph_traits<Graph>::edge_descriptor argument_type; typedef bool result_type; remove_undirected_edge_predicate(Graph& g, Predicate& predicate) : g(g), predicate(predicate) { } bool operator()(const argument_type& e) { if (predicate(e)) { if (source(e, g).owner != target(e, g).owner) g.send_remove_edge_request(e); if (target(e, g).owner == g.processor()) ::boost::detail::parallel::remove_in_edge(e, g, undirectedS()); if (source(e, g).owner == g.processor()) remove_edge(e.local, g.base()); return true; } else return false; } private: Graph& g; Predicate predicate; }; } } // end namespace parallel::detail template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate> inline void remove_edge_if(Predicate predicate, PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g) { typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS) Graph; typedef parallel::detail::remove_undirected_edge_predicate<Graph, Predicate> Pred; graph_detail::erase_if(g.local_edges(), Pred(g, predicate)); } /************************************************************************ * * clear_vertex * ************************************************************************/ namespace parallel { namespace detail { struct always_true { typedef bool result_type; template<typename T> bool operator()(const T&) const { return true; } }; } } // end namespace parallel::detail template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> void clear_vertex (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) ::vertex_descriptor u, PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g) { clear_out_edges(u, g); clear_in_edges(u, g); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> void clear_vertex (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS) ::vertex_descriptor u, PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g) { remove_out_edge_if(u, parallel::detail::always_true(), g); } /************************************************************************ * * clear_out_edges * ************************************************************************/ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> void clear_out_edges (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)::vertex_descriptor u, PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)& g) { BOOST_ASSERT(u.owner == g.processor()); clear_out_edges(u.local, g.base()); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> void clear_out_edges (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) ::vertex_descriptor u, PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g) { remove_out_edge_if(u, parallel::detail::always_true(), g); } /************************************************************************ * * clear_in_edges * ************************************************************************/ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG> void clear_in_edges (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) ::vertex_descriptor u, PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g) { remove_in_edge_if(u, parallel::detail::always_true(), g); } /************************************************************************ * * add_vertex * ************************************************************************/ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor add_vertex(PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef PBGL_DISTRIB_ADJLIST_TYPE graph_type; typename graph_type::vertex_property_type p; return add_vertex(p, g); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_vertex_with_property add_vertex(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_property_type const& p, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename PBGL_DISTRIB_ADJLIST_TYPE ::lazy_add_vertex_with_property lazy_add_vertex; return lazy_add_vertex(g, p); } /************************************************************************ * * remove_vertex * ************************************************************************/ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> void remove_vertex(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename PBGL_DISTRIB_ADJLIST_TYPE::graph_type graph_type; typedef typename graph_type::named_graph_mixin named_graph_mixin; BOOST_ASSERT(u.owner == g.processor()); static_cast<named_graph_mixin&>(static_cast<graph_type&>(g)) .removing_vertex(u, boost::graph_detail::iterator_stability(g.base().m_vertices)); g.distribution().clear(); remove_vertex(u.local, g.base()); } /*************************************************************************** * Implementation of Property Graph concept ***************************************************************************/ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Property> struct property_map<PBGL_DISTRIB_ADJLIST_TYPE, Property> : detail::parallel::get_adj_list_pmap<Property> ::template apply<PBGL_DISTRIB_ADJLIST_TYPE> { }; template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Property> struct property_map<PBGL_DISTRIB_ADJLIST_TYPE const, Property> : boost::detail::parallel::get_adj_list_pmap<Property> // FIXME: in the original code the following was not const ::template apply<PBGL_DISTRIB_ADJLIST_TYPE const> { }; template<typename Property, PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, Property>::type get(Property p, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef PBGL_DISTRIB_ADJLIST_TYPE Graph; typedef typename property_map<Graph, Property>::type result_type; typedef typename property_traits<result_type>::value_type value_type; typedef typename property_reduce<Property>::template apply<value_type> reduce; typedef typename property_traits<result_type>::key_type descriptor; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>, vertex_global_t, edge_global_t>::type global_map_t; return result_type(g.process_group(), get(global_map_t(), g), get(p, g.base()), reduce()); } template<typename Property, PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, Property>::const_type get(Property p, const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef PBGL_DISTRIB_ADJLIST_TYPE Graph; typedef typename property_map<Graph, Property>::const_type result_type; typedef typename property_traits<result_type>::value_type value_type; typedef typename property_reduce<Property>::template apply<value_type> reduce; typedef typename property_traits<result_type>::key_type descriptor; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>, vertex_global_t, edge_global_t>::type global_map_t; return result_type(g.process_group(), get(global_map_t(), g), get(p, g.base()), reduce()); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_local_index_t>::type get(vertex_local_index_t, PBGL_DISTRIB_ADJLIST_TYPE& g) { return get(vertex_local_index, g.base()); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_local_index_t>::const_type get(vertex_local_index_t, const PBGL_DISTRIB_ADJLIST_TYPE& g) { return get(vertex_local_index, g.base()); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_global_t>::const_type get(vertex_global_t, const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename property_map< PBGL_DISTRIB_ADJLIST_TYPE, vertex_global_t>::const_type result_type; return result_type(); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_global_t>::const_type get(vertex_global_t, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename property_map< PBGL_DISTRIB_ADJLIST_TYPE, vertex_global_t>::const_type result_type; return result_type(); } /// Retrieve a property map mapping from a vertex descriptor to its /// owner. template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_owner_t>::type get(vertex_owner_t, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename property_map< PBGL_DISTRIB_ADJLIST_TYPE, vertex_owner_t>::type result_type; return result_type(); } /// Retrieve a property map mapping from a vertex descriptor to its /// owner. template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_owner_t>::const_type get(vertex_owner_t, const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename property_map< PBGL_DISTRIB_ADJLIST_TYPE, vertex_owner_t>::const_type result_type; return result_type(); } /// Retrieve the owner of a vertex template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> inline processor_id_type get(vertex_owner_t, PBGL_DISTRIB_ADJLIST_TYPE&, typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v) { return v.owner; } /// Retrieve the owner of a vertex template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> inline processor_id_type get(vertex_owner_t, const PBGL_DISTRIB_ADJLIST_TYPE&, typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v) { return v.owner; } /// Retrieve a property map that maps from a vertex descriptor to /// its local descriptor. template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_local_t>::type get(vertex_local_t, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename property_map< PBGL_DISTRIB_ADJLIST_TYPE, vertex_local_t>::type result_type; return result_type(); } /// Retrieve a property map that maps from a vertex descriptor to /// its local descriptor. template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_local_t>::const_type get(vertex_local_t, const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename property_map< PBGL_DISTRIB_ADJLIST_TYPE, vertex_local_t>::const_type result_type; return result_type(); } /// Retrieve the local descriptor of a vertex template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> inline typename PBGL_DISTRIB_ADJLIST_TYPE::local_vertex_descriptor get(vertex_local_t, PBGL_DISTRIB_ADJLIST_TYPE&, typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v) { return v.local; } /// Retrieve the local descriptor of a vertex template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> inline typename PBGL_DISTRIB_ADJLIST_TYPE::local_vertex_descriptor get(vertex_local_t, const PBGL_DISTRIB_ADJLIST_TYPE&, typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v) { return v.local; } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_global_t>::const_type get(edge_global_t, const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename property_map< PBGL_DISTRIB_ADJLIST_TYPE, edge_global_t>::const_type result_type; return result_type(); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_global_t>::const_type get(edge_global_t, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename property_map< PBGL_DISTRIB_ADJLIST_TYPE, edge_global_t>::const_type result_type; return result_type(); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_owner_t>::type get(edge_owner_t, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename property_map< PBGL_DISTRIB_ADJLIST_TYPE, edge_owner_t>::type result_type; return result_type(); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_owner_t>::const_type get(edge_owner_t, const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename property_map< PBGL_DISTRIB_ADJLIST_TYPE, edge_owner_t>::const_type result_type; return result_type(); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_local_t>::type get(edge_local_t, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename property_map< PBGL_DISTRIB_ADJLIST_TYPE, edge_local_t>::type result_type; return result_type(); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_local_t>::const_type get(edge_local_t, const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef typename property_map< PBGL_DISTRIB_ADJLIST_TYPE, edge_local_t>::const_type result_type; return result_type(); } template<typename Property, PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Key> inline typename property_traits<typename property_map< PBGL_DISTRIB_ADJLIST_TYPE, Property>::const_type >::value_type get(Property p, const PBGL_DISTRIB_ADJLIST_TYPE& g, const Key& key) { if (owner(key) == process_id(g.process_group())) return get(p, g.base(), local(key)); else BOOST_ASSERT(false); } template<typename Property, PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Key, typename Value> void put(Property p, PBGL_DISTRIB_ADJLIST_TYPE& g, const Key& key, const Value& v) { if (owner(key) == process_id(g.process_group())) put(p, g.base(), local(key), v); else BOOST_ASSERT(false); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_index_t>::type get(vertex_index_t vi, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef PBGL_DISTRIB_ADJLIST_TYPE graph_type; typedef typename property_map<graph_type, vertex_index_t>::type result_type; return result_type(g.process_group(), get(vertex_global, g), get(vi, g.base())); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_index_t>::const_type get(vertex_index_t vi, const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef PBGL_DISTRIB_ADJLIST_TYPE graph_type; typedef typename property_map<graph_type, vertex_index_t>::const_type result_type; return result_type(g.process_group(), get(vertex_global, g), get(vi, g.base())); } /*************************************************************************** * Implementation of bundled properties ***************************************************************************/ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename T, typename Bundle> struct property_map<PBGL_DISTRIB_ADJLIST_TYPE, T Bundle::*> : detail::parallel::get_adj_list_pmap<T Bundle::*> ::template apply<PBGL_DISTRIB_ADJLIST_TYPE> { }; template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename T, typename Bundle> struct property_map<PBGL_DISTRIB_ADJLIST_TYPE const, T Bundle::*> : detail::parallel::get_adj_list_pmap<T Bundle::*> ::template apply<PBGL_DISTRIB_ADJLIST_TYPE const> { }; template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename T, typename Bundle> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, T Bundle::*>::type get(T Bundle::* p, PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef PBGL_DISTRIB_ADJLIST_TYPE Graph; typedef typename property_map<Graph, T Bundle::*>::type result_type; typedef typename property_traits<result_type>::value_type value_type; typedef typename property_reduce<T Bundle::*>::template apply<value_type> reduce; typedef typename property_traits<result_type>::key_type descriptor; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>, vertex_global_t, edge_global_t>::type global_map_t; return result_type(g.process_group(), get(global_map_t(), g), get(p, g.base()), reduce()); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename T, typename Bundle> typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, T Bundle::*>::const_type get(T Bundle::* p, const PBGL_DISTRIB_ADJLIST_TYPE& g) { typedef PBGL_DISTRIB_ADJLIST_TYPE Graph; typedef typename property_map<Graph, T Bundle::*>::const_type result_type; typedef typename property_traits<result_type>::value_type value_type; typedef typename property_reduce<T Bundle::*>::template apply<value_type> reduce; typedef typename property_traits<result_type>::key_type descriptor; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>, vertex_global_t, edge_global_t>::type global_map_t; return result_type(g.process_group(), get(global_map_t(), g), get(p, g.base()), reduce()); } /*************************************************************************** * Implementation of DistributedGraph concept ***************************************************************************/ template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> void synchronize(const PBGL_DISTRIB_ADJLIST_TYPE& g) { synchronize(g.process_group()); } template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS> ProcessGroup process_group(const PBGL_DISTRIB_ADJLIST_TYPE& g) { return g.process_group(); } /*************************************************************************** * Specializations of is_mpi_datatype for Serializable entities ***************************************************************************/ namespace mpi { template<typename Directed, typename Vertex> struct is_mpi_datatype<boost::detail::edge_base<Directed, Vertex> > : is_mpi_datatype<Vertex> { }; template<typename Directed, typename Vertex> struct is_mpi_datatype<boost::detail::edge_desc_impl<Directed, Vertex> > : is_mpi_datatype<boost::detail::edge_base<Directed, Vertex> > { }; template<typename LocalDescriptor> struct is_mpi_datatype<boost::detail::parallel::global_descriptor<LocalDescriptor> > : is_mpi_datatype<LocalDescriptor> { }; template<typename Edge> struct is_mpi_datatype<boost::detail::parallel::edge_descriptor<Edge> > : is_mpi_datatype<Edge> { }; template<typename Vertex, typename LocalVertex> struct is_mpi_datatype<boost::detail::parallel:: msg_add_edge_data<Vertex, LocalVertex> > : is_mpi_datatype<Vertex> { }; template<typename Vertex, typename LocalVertex, typename EdgeProperty> struct is_mpi_datatype<boost::detail::parallel:: msg_add_edge_with_property_data<Vertex, LocalVertex, EdgeProperty> > : mpl::and_<is_mpi_datatype<Vertex>, is_mpi_datatype<EdgeProperty> > { }; template<typename EdgeProperty, typename EdgeDescriptor> struct is_mpi_datatype<boost::detail::parallel::msg_nonlocal_edge_data< EdgeProperty,EdgeDescriptor> > : mpl::and_< is_mpi_datatype<boost::detail::parallel::maybe_store_property< EdgeProperty> >, is_mpi_datatype<EdgeDescriptor> > {}; template<typename EdgeDescriptor> struct is_mpi_datatype< boost::detail::parallel::msg_remove_edge_data<EdgeDescriptor> > : is_mpi_datatype<EdgeDescriptor> {}; } /*************************************************************************** * Specializations of is_bitwise_serializable for Serializable entities ***************************************************************************/ namespace serialization { template<typename Directed, typename Vertex> struct is_bitwise_serializable<boost::detail::edge_base<Directed, Vertex> > : is_bitwise_serializable<Vertex> { }; template<typename Directed, typename Vertex> struct is_bitwise_serializable<boost::detail::edge_desc_impl<Directed, Vertex> > : is_bitwise_serializable<boost::detail::edge_base<Directed, Vertex> > { }; template<typename LocalDescriptor> struct is_bitwise_serializable<boost::detail::parallel::global_descriptor<LocalDescriptor> > : is_bitwise_serializable<LocalDescriptor> { }; template<typename Edge> struct is_bitwise_serializable<boost::detail::parallel::edge_descriptor<Edge> > : is_bitwise_serializable<Edge> { }; template<typename Vertex, typename LocalVertex> struct is_bitwise_serializable<boost::detail::parallel:: msg_add_edge_data<Vertex, LocalVertex> > : is_bitwise_serializable<Vertex> { }; template<typename Vertex, typename LocalVertex, typename EdgeProperty> struct is_bitwise_serializable<boost::detail::parallel:: msg_add_edge_with_property_data<Vertex, LocalVertex, EdgeProperty> > : mpl::and_<is_bitwise_serializable<Vertex>, is_bitwise_serializable<EdgeProperty> > { }; template<typename EdgeProperty, typename EdgeDescriptor> struct is_bitwise_serializable<boost::detail::parallel::msg_nonlocal_edge_data< EdgeProperty,EdgeDescriptor> > : mpl::and_< is_bitwise_serializable< boost::detail::parallel::maybe_store_property<EdgeProperty> >, is_bitwise_serializable<EdgeDescriptor> > {}; template<typename EdgeDescriptor> struct is_bitwise_serializable< boost::detail::parallel::msg_remove_edge_data<EdgeDescriptor> > : is_bitwise_serializable<EdgeDescriptor> {}; template<typename Directed, typename Vertex> struct implementation_level<boost::detail::edge_base<Directed, Vertex> > : mpl::int_<object_serializable> {}; template<typename Directed, typename Vertex> struct implementation_level<boost::detail::edge_desc_impl<Directed, Vertex> > : mpl::int_<object_serializable> {}; template<typename LocalDescriptor> struct implementation_level<boost::detail::parallel::global_descriptor<LocalDescriptor> > : mpl::int_<object_serializable> {}; template<typename Edge> struct implementation_level<boost::detail::parallel::edge_descriptor<Edge> > : mpl::int_<object_serializable> {}; template<typename Vertex, typename LocalVertex> struct implementation_level<boost::detail::parallel:: msg_add_edge_data<Vertex, LocalVertex> > : mpl::int_<object_serializable> {}; template<typename Vertex, typename LocalVertex, typename EdgeProperty> struct implementation_level<boost::detail::parallel:: msg_add_edge_with_property_data<Vertex, LocalVertex, EdgeProperty> > : mpl::int_<object_serializable> {}; template<typename EdgeProperty, typename EdgeDescriptor> struct implementation_level<boost::detail::parallel::msg_nonlocal_edge_data< EdgeProperty,EdgeDescriptor> > : mpl::int_<object_serializable> {}; template<typename EdgeDescriptor> struct implementation_level< boost::detail::parallel::msg_remove_edge_data<EdgeDescriptor> > : mpl::int_<object_serializable> {}; template<typename Directed, typename Vertex> struct tracking_level<boost::detail::edge_base<Directed, Vertex> > : mpl::int_<track_never> {}; template<typename Directed, typename Vertex> struct tracking_level<boost::detail::edge_desc_impl<Directed, Vertex> > : mpl::int_<track_never> {}; template<typename LocalDescriptor> struct tracking_level<boost::detail::parallel::global_descriptor<LocalDescriptor> > : mpl::int_<track_never> {}; template<typename Edge> struct tracking_level<boost::detail::parallel::edge_descriptor<Edge> > : mpl::int_<track_never> {}; template<typename Vertex, typename LocalVertex> struct tracking_level<boost::detail::parallel:: msg_add_edge_data<Vertex, LocalVertex> > : mpl::int_<track_never> {}; template<typename Vertex, typename LocalVertex, typename EdgeProperty> struct tracking_level<boost::detail::parallel:: msg_add_edge_with_property_data<Vertex, LocalVertex, EdgeProperty> > : mpl::int_<track_never> {}; template<typename EdgeProperty, typename EdgeDescriptor> struct tracking_level<boost::detail::parallel::msg_nonlocal_edge_data< EdgeProperty,EdgeDescriptor> > : mpl::int_<track_never> {}; template<typename EdgeDescriptor> struct tracking_level< boost::detail::parallel::msg_remove_edge_data<EdgeDescriptor> > : mpl::int_<track_never> {}; } // Hash function for global descriptors template<typename LocalDescriptor> struct hash<detail::parallel::global_descriptor<LocalDescriptor> > { typedef detail::parallel::global_descriptor<LocalDescriptor> argument_type; std::size_t operator()(argument_type const& x) const { std::size_t hash = hash_value(x.owner); hash_combine(hash, x.local); return hash; } }; // Hash function for parallel edge descriptors template<typename Edge> struct hash<detail::parallel::edge_descriptor<Edge> > { typedef detail::parallel::edge_descriptor<Edge> argument_type; std::size_t operator()(argument_type const& x) const { std::size_t hash = hash_value(x.owner()); hash_combine(hash, x.local); return hash; } }; } // end namespace boost #include <boost/graph/distributed/adjlist/handlers.hpp> #include <boost/graph/distributed/adjlist/initialize.hpp> #include <boost/graph/distributed/adjlist/redistribute.hpp> #include <boost/graph/distributed/adjlist/serialization.hpp> #endif // BOOST_GRAPH_DISTRIBUTED_ADJACENCY_LIST_HPP distributed/selector.hpp 0000644 00000002537 15125521275 0011433 0 ustar 00 // Copyright (C) 2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_DISTRIBUTED_SELECTOR_HPP #define BOOST_GRAPH_DISTRIBUTED_SELECTOR_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/detail/is_distributed_selector.hpp> namespace boost { /* The default local selector for a distributedS selector. */ struct defaultS {}; /** * Selector that specifies that the graph should be distributed * among different processes organized based on the given process * group. */ template<typename ProcessGroup, typename LocalS = defaultS, typename DistributionS = defaultS> struct distributedS { typedef ProcessGroup process_group_type; typedef LocalS local_selector; typedef DistributionS distribution; }; namespace detail { template<typename ProcessGroup, typename LocalS, typename DistributionS> struct is_distributed_selector<distributedS<ProcessGroup, LocalS, DistributionS> >: mpl::true_ {}; } } #endif // BOOST_GRAPH_DISTRIBUTED_SELECTOR_HPP distributed/filtered_graph.hpp 0000644 00000003627 15125521275 0012573 0 ustar 00 // Copyright (C) 2004-2008 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Nick Edmonds // Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_DISTRIBUTED_FILTERED_GRAPH_HPP #define BOOST_DISTRIBUTED_FILTERED_GRAPH_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/parallel/process_group.hpp> #include <boost/graph/filtered_graph.hpp> namespace boost { namespace graph { namespace parallel { /// Retrieve the process group from a filtered graph template<typename Graph, typename EdgePredicate, typename VertexPredicate> struct process_group_type<filtered_graph<Graph, EdgePredicate, VertexPredicate> > : process_group_type<Graph> { }; template<typename Graph, typename EdgePredicate, typename VertexPredicate> struct process_group_type<const filtered_graph<Graph, EdgePredicate, VertexPredicate> > : process_group_type<Graph> { }; } } /// Retrieve the process group from a filtered graph template<typename Graph, typename EdgePredicate, typename VertexPredicate> inline typename graph::parallel::process_group_type<Graph>::type process_group(filtered_graph<Graph, EdgePredicate, VertexPredicate> const& g) { return process_group(g.m_g); } /// Forward vertex() to vertex() of the base graph template <typename Graph, typename EdgePredicate, typename VertexPredicate> typename graph_traits<Graph>::vertex_descriptor vertex(typename graph_traits<Graph>::vertices_size_type i, filtered_graph<Graph, EdgePredicate, VertexPredicate> const& g) { return vertex(i, g.m_g); } } #endif // BOOST_DISTRIBUTED_FILTERED_GRAPH_HPP distributed/compressed_sparse_row_graph.hpp 0000644 00000237615 15125521275 0015413 0 ustar 00 // Copyright (C) 2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Jeremiah Willcock // Andrew Lumsdaine // Distributed compressed sparse row graph type #ifndef BOOST_GRAPH_DISTRIBUTED_CSR_HPP #define BOOST_GRAPH_DISTRIBUTED_CSR_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/assert.hpp> #include <boost/graph/compressed_sparse_row_graph.hpp> #include <boost/graph/distributed/selector.hpp> #include <boost/mpl/if.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/graph/distributed/concepts.hpp> #include <boost/graph/parallel/properties.hpp> #include <boost/graph/parallel/distribution.hpp> #include <boost/property_map/parallel/local_property_map.hpp> #include <boost/property_map/parallel/distributed_property_map.hpp> namespace boost { // Distributed and sequential inplace ctors have the same signature so // we need a separate tag for distributed inplace ctors enum distributed_construct_inplace_from_sources_and_targets_t {distributed_construct_inplace_from_sources_and_targets}; // The number of bits we reserve for the processor ID. // DPG TBD: This is a hack. It will eventually be a run-time quantity. static const int processor_bits = 8; // Tag class for a distributed CSR graph struct distributed_csr_tag : public virtual distributed_graph_tag, public virtual distributed_vertex_list_graph_tag, public virtual distributed_edge_list_graph_tag, public virtual incidence_graph_tag, public virtual adjacency_graph_tag {}; template<typename VertexProperty, typename EdgeProperty, typename GraphProperty, typename ProcessGroup, typename InVertex, typename InDistribution, typename InEdgeIndex> class compressed_sparse_row_graph< directedS, VertexProperty, EdgeProperty, GraphProperty, distributedS<ProcessGroup, InVertex, InDistribution>, InEdgeIndex> { typedef compressed_sparse_row_graph self_type; private: /** * Determine the type used to represent vertices in the graph. If * the user has overridden the default, use the user's * parameter. Otherwise, fall back to std::size_t. */ typedef typename mpl::if_<is_same<InVertex, defaultS>, std::size_t, InVertex>::type Vertex; /** * Determine the type used to represent edges in the graph. If * the user has overridden the default (which is to be the same as * the distributed vertex selector type), use the user's * parameter. Otherwise, fall back to the value of @c Vertex. */ typedef typename mpl::if_<is_same<InEdgeIndex, distributedS<ProcessGroup, InVertex, InDistribution> >, Vertex, InEdgeIndex>::type EdgeIndex; public: /** * The type of the CSR graph that will be stored locally. */ typedef compressed_sparse_row_graph<directedS, VertexProperty, EdgeProperty, GraphProperty, Vertex, EdgeIndex> base_type; // ----------------------------------------------------------------- // Graph concept requirements typedef Vertex vertex_descriptor; typedef typename graph_traits<base_type>::edge_descriptor edge_descriptor; typedef directed_tag directed_category; typedef allow_parallel_edge_tag edge_parallel_category; typedef distributed_csr_tag traversal_category; static vertex_descriptor null_vertex(); // ----------------------------------------------------------------- // Distributed Vertex List Graph concept requirements typedef Vertex vertices_size_type; class vertex_iterator; // ----------------------------------------------------------------- // Distributed Edge List Graph concept requirements typedef EdgeIndex edges_size_type; class edge_iterator; // ----------------------------------------------------------------- // Incidence Graph concept requirements typedef typename graph_traits<base_type>::out_edge_iterator out_edge_iterator; typedef typename graph_traits<base_type>::degree_size_type degree_size_type; // ----------------------------------------------------------------- // Adjacency Graph concept requirements typedef typename graph_traits<base_type>::adjacency_iterator adjacency_iterator; // Note: This graph type does not model Bidirectional Graph. // However, this typedef is required to satisfy graph_traits. typedef void in_edge_iterator; // ----------------------------------------------------------------- // Distributed Container concept requirements typedef ProcessGroup process_group_type; typedef boost::parallel::variant_distribution<process_group_type, Vertex> distribution_type; // ----------------------------------------------------------------- // Workarounds // NOTE: This graph type does not have old-style graph properties. It only // accepts bundles. typedef no_property vertex_property_type; typedef no_property edge_property_type; typedef no_property graph_property_type; typedef typename mpl::if_<is_void<VertexProperty>, void****, VertexProperty>::type vertex_bundled; typedef typename mpl::if_<is_void<EdgeProperty>, void****, EdgeProperty>::type edge_bundled; typedef typename mpl::if_<is_void<GraphProperty>, void****, GraphProperty>::type graph_bundled; // ----------------------------------------------------------------- // Useful types typedef typename ProcessGroup::process_id_type process_id_type; // ----------------------------------------------------------------- // Graph constructors compressed_sparse_row_graph(const ProcessGroup& pg = ProcessGroup()) : m_process_group(pg), m_distribution(parallel::block(pg, 0)) {} compressed_sparse_row_graph(const GraphProperty& prop, const ProcessGroup& pg = ProcessGroup()) : m_process_group(pg), m_distribution(parallel::block(pg, 0)) {} compressed_sparse_row_graph(vertices_size_type numverts, const ProcessGroup& pg = ProcessGroup()) : m_process_group(pg), m_distribution(parallel::block(pg, 0)), m_base(numverts) {} compressed_sparse_row_graph(vertices_size_type numverts, const GraphProperty& prop, const ProcessGroup& pg = ProcessGroup()) : m_process_group(pg), m_distribution(parallel::block(pg, 0)), m_base(numverts) {} template <typename Distribution> compressed_sparse_row_graph(vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist) : m_process_group(pg), m_distribution(dist), m_base(numverts) {} template <typename Distribution> compressed_sparse_row_graph(vertices_size_type numverts, const GraphProperty& prop, const ProcessGroup& pg, const Distribution& dist) : m_process_group(pg), m_distribution(dist), m_base(numverts) {} template <typename InputIterator> compressed_sparse_row_graph(edges_are_unsorted_t, InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, const ProcessGroup& pg = ProcessGroup(), const GraphProperty& prop = GraphProperty()); template <typename InputIterator, typename Distribution> compressed_sparse_row_graph(edges_are_unsorted_t, InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop = GraphProperty()); template <typename InputIterator, typename EdgePropertyIterator> compressed_sparse_row_graph(edges_are_unsorted_t, InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const ProcessGroup& pg = ProcessGroup(), const GraphProperty& prop = GraphProperty()); template <typename InputIterator, typename EdgePropertyIterator, typename Distribution> compressed_sparse_row_graph(edges_are_unsorted_t, InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop = GraphProperty()); template <typename InputIterator> compressed_sparse_row_graph(edges_are_sorted_t, InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, edges_size_type numedges = 0, const ProcessGroup& pg = ProcessGroup(), const GraphProperty& prop = GraphProperty()); template <typename InputIterator, typename Distribution> compressed_sparse_row_graph(edges_are_sorted_t, InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop = GraphProperty()); template <typename InputIterator, typename EdgePropertyIterator> compressed_sparse_row_graph(edges_are_sorted_t, InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, edges_size_type numedges = 0, const ProcessGroup& pg = ProcessGroup(), const GraphProperty& prop = GraphProperty()); template <typename InputIterator, typename EdgePropertyIterator, typename Distribution> compressed_sparse_row_graph(edges_are_sorted_t, InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop = GraphProperty()); template <typename MultiPassInputIterator> compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, vertices_size_type numverts, const ProcessGroup& pg = ProcessGroup(), const GraphProperty& prop = GraphProperty()); template <typename MultiPassInputIterator, typename Distribution> compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop = GraphProperty()); template <typename MultiPassInputIterator, typename EdgePropertyIterator> compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const ProcessGroup& pg = ProcessGroup(), const GraphProperty& prop = GraphProperty()); template <typename MultiPassInputIterator, typename EdgePropertyIterator, typename Distribution> compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop = GraphProperty()); template <typename Source> compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, std::vector<Source>& sources, std::vector<vertex_descriptor>& targets, vertices_size_type numverts, const ProcessGroup& pg = ProcessGroup(), const GraphProperty& prop = GraphProperty()); template <typename Distribution, typename Source> compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, std::vector<Source>& sources, std::vector<vertex_descriptor>& targets, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop = GraphProperty()); template <typename Source> compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, std::vector<Source>& sources, std::vector<vertex_descriptor>& targets, std::vector<edge_bundled>& edge_props, vertices_size_type numverts, const ProcessGroup& pg = ProcessGroup(), const GraphProperty& prop = GraphProperty()); template <typename Distribution, typename Source> compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, std::vector<Source>& sources, std::vector<vertex_descriptor>& targets, std::vector<edge_bundled>& edge_props, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop = GraphProperty()); template<typename InputIterator> compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, const ProcessGroup& pg = ProcessGroup(), const GraphProperty& prop = GraphProperty()); template<typename InputIterator, typename EdgePropertyIterator> compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const ProcessGroup& pg = ProcessGroup(), const GraphProperty& prop = GraphProperty()); template<typename InputIterator, typename Distribution> compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop = GraphProperty()); template<typename InputIterator, typename EdgePropertyIterator, typename Distribution> compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop = GraphProperty()); base_type& base() { return m_base; } const base_type& base() const { return m_base; } process_group_type process_group() const { return m_process_group.base(); } distribution_type& distribution() { return m_distribution; } const distribution_type& distribution() const { return m_distribution; } // Directly access a vertex or edge bundle vertex_bundled& operator[](vertex_descriptor v) { return get(vertex_bundle, *this, v); } const vertex_bundled& operator[](vertex_descriptor v) const { return get(vertex_bundle, *this, v); } edge_bundled& operator[](edge_descriptor e) { return get(edge_bundle, *this, e); } const edge_bundled& operator[](edge_descriptor e) const { return get(edge_bundle, *this, e); } // Create a vertex descriptor from a process ID and a local index. vertex_descriptor make_vertex_descriptor(process_id_type p, vertex_descriptor v) const { vertex_descriptor vertex_local_index_bits = sizeof(vertex_descriptor) * CHAR_BIT - processor_bits; return v | ((vertex_descriptor)p << vertex_local_index_bits); } // Convert a local vertex descriptor into a global vertex descriptor vertex_descriptor local_to_global_vertex(vertex_descriptor v) const { return make_vertex_descriptor(process_id(m_process_group), v); } // Structural modification vertex_descriptor add_vertex() { typename graph_traits<base_type>::vertex_descriptor v = boost::add_vertex(m_base); return make_vertex_descriptor(process_id(m_process_group), v); } vertex_descriptor add_vertex(const vertex_bundled& p) { typename graph_traits<base_type>::vertex_descriptor v = boost::add_vertex(m_base, p); return make_vertex_descriptor(process_id(m_process_group), v); } vertex_descriptor add_vertices(vertices_size_type count) { typename graph_traits<base_type>::vertex_descriptor v = boost::add_vertices(count, m_base); return make_vertex_descriptor(process_id(m_process_group), v); } template <typename InputIterator> void add_edges(InputIterator first, InputIterator last) { boost::add_edges_global(first, last, get(vertex_local, *this), m_base); } template <typename InputIterator, typename EdgePropertyIterator> void add_edges(InputIterator first, InputIterator last, EdgePropertyIterator ep_iter, EdgePropertyIterator ep_iter_end) { boost::add_edges_global(first, last, ep_iter, ep_iter_end, get(vertex_local, *this), m_base); } template <typename InputIterator> void add_edges_sorted(InputIterator first, InputIterator last) { boost::add_edges_sorted_global(first, last, get(vertex_local, *this), m_base); } template <typename InputIterator, typename EdgePropertyIterator> void add_edges_sorted(InputIterator first_sorted, InputIterator last_sorted, EdgePropertyIterator ep_iter_sorted) { boost::add_edges_sorted_global(first_sorted, last_sorted, ep_iter_sorted, get(vertex_local, *this), m_base); } protected: ProcessGroup m_process_group; distribution_type m_distribution; base_type m_base; }; /** @brief Helper macro containing the template parameters for the * distributed CSR graph. * * This macro contains all of the template parameters needed for the * distributed compressed_sparse_row graph type. It is used to reduce * the amount of typing required to declare free functions for this * graph type. */ #define BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS \ typename VertexProperty, typename EdgeProperty, \ typename GraphProperty, typename ProcessGroup, typename InVertex, \ typename InDistribution, typename InEdgeIndex /** @brief Helper macro containing the typical instantiation of the * distributed CSR graph. * * This macro contains an instantiation of the distributed CSR graph * type using the typical template parameters names (e.g., those * provided by the macro @c * BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS). It is used to reduce * the amount of typing required to declare free functions for this * graph type. */ #define BOOST_DISTRIB_CSR_GRAPH_TYPE \ compressed_sparse_row_graph< \ directedS, VertexProperty, EdgeProperty, GraphProperty, \ distributedS<ProcessGroup, InVertex, InDistribution>, \ InEdgeIndex> // ----------------------------------------------------------------- // Graph concept operations template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor BOOST_DISTRIB_CSR_GRAPH_TYPE::null_vertex() { return graph_traits<base_type>::null_vertex(); } // ----------------------------------------------------------------- // Incidence Graph concept operations template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor source(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor e, const BOOST_DISTRIB_CSR_GRAPH_TYPE&) { return e.src; } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor target(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor e, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { return target(e, g.base()); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline std::pair<typename BOOST_DISTRIB_CSR_GRAPH_TYPE::out_edge_iterator, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::out_edge_iterator> out_edges(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor u, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type edges_size_type; typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor ed; typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::out_edge_iterator it; edges_size_type u_local = get(vertex_local, g, u); edges_size_type u_row_start = g.base().m_forward.m_rowstart[u_local]; edges_size_type next_row_start = g.base().m_forward.m_rowstart[u_local + 1]; return std::make_pair(it(ed(u, u_row_start)), it(ed(u, (std::max)(u_row_start, next_row_start)))); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::degree_size_type out_degree(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor u, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { return out_degree(get(vertex_local, g, u), g.base()); } // ----------------------------------------------------------------- // DistributedGraph concept requirements template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> void synchronize(const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { synchronize(g.process_group()); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> ProcessGroup process_group(const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { return g.process_group(); } // ----------------------------------------------------------------- // Adjacency Graph concept requirements template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline std::pair<typename BOOST_DISTRIB_CSR_GRAPH_TYPE::adjacency_iterator, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::adjacency_iterator> adjacent_vertices(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor u, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { return adjacent_vertices(get(vertex_local, g, u), g.base()); } // ----------------------------------------------------------------- // Distributed Vertex List Graph concept operations template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> class BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_iterator : public iterator_adaptor<vertex_iterator, counting_iterator<Vertex>, Vertex, random_access_traversal_tag, Vertex> { typedef iterator_adaptor<vertex_iterator, counting_iterator<Vertex>, Vertex, random_access_traversal_tag, Vertex> inherited; public: vertex_iterator() {} explicit vertex_iterator(Vertex v, const self_type* graph) : inherited(counting_iterator<Vertex>(v)), graph(graph) { } Vertex dereference() const { return graph->local_to_global_vertex(*(this->base_reference())); } friend class iterator_core_access; private: const self_type* graph; }; template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::degree_size_type num_vertices(const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { return num_vertices(g.base()); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline std::pair<typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_iterator, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_iterator> vertices(const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_iterator vertex_iterator; return std::make_pair(vertex_iterator(0, &g), vertex_iterator(num_vertices(g), &g)); } // ----------------------------------------------------------------- // Distributed Edge List Graph concept operations template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> class BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_iterator { public: typedef std::forward_iterator_tag iterator_category; typedef edge_descriptor value_type; typedef const edge_descriptor* pointer; typedef edge_descriptor reference; typedef typename int_t<CHAR_BIT * sizeof(EdgeIndex)>::fast difference_type; edge_iterator() : graph(0), current_edge(), end_of_this_vertex(0) {} edge_iterator(const compressed_sparse_row_graph& graph, edge_descriptor current_edge, EdgeIndex end_of_this_vertex) : graph(&graph), local_src(current_edge.src), current_edge(current_edge), end_of_this_vertex(end_of_this_vertex) { // The edge that comes in has a local source vertex. Make it global. current_edge.src = graph.local_to_global_vertex(current_edge.src); } // From InputIterator reference operator*() const { return current_edge; } pointer operator->() const { return ¤t_edge; } bool operator==(const edge_iterator& o) const { return current_edge == o.current_edge; } bool operator!=(const edge_iterator& o) const { return current_edge != o.current_edge; } edge_iterator& operator++() { ++current_edge.idx; while (current_edge.idx == end_of_this_vertex && local_src < num_vertices(*graph)-1) { ++local_src; current_edge.src = graph->local_to_global_vertex(local_src); end_of_this_vertex = graph->base().m_forward.m_rowstart[local_src + 1]; } return *this; } edge_iterator operator++(int) { edge_iterator temp = *this; ++*this; return temp; } private: const compressed_sparse_row_graph* graph; EdgeIndex local_src; edge_descriptor current_edge; EdgeIndex end_of_this_vertex; }; template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type num_edges(const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { return g.base().m_forward.m_column.size(); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> std::pair<typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_iterator, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_iterator> edges(const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor Vertex; typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_iterator ei; typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor edgedesc; if (g.base().m_forward.m_rowstart.size() == 1 || g.base().m_forward.m_column.empty()) { return std::make_pair(ei(), ei()); } else { // Find the first vertex that has outgoing edges Vertex src = 0; while (g.base().m_forward.m_rowstart[src + 1] == 0) ++src; return std::make_pair(ei(g, edgedesc(src, 0), g.base().m_forward.m_rowstart[src + 1]), ei(g, edgedesc(num_vertices(g), g.base().m_forward.m_column.size()), 0)); } } // ----------------------------------------------------------------- // Graph constructors // Returns true if a vertex belongs to a process according to a distribution template <typename OwnerMap, typename ProcessId> struct local_vertex { local_vertex(OwnerMap owner, ProcessId id) : owner(owner), id(id) {} template <typename Vertex> bool operator()(Vertex x) { return get(owner, x) == id; } template <typename Vertex> bool operator()(Vertex x) const { return get(owner, x) == id; } private: OwnerMap owner; ProcessId id; }; // Returns true if a vertex belongs to a process according to a distribution template <typename OwnerMap, typename ProcessId> struct local_edge { local_edge(OwnerMap owner, ProcessId id) : owner(owner), id(id) {} template <typename Vertex> bool operator()(std::pair<Vertex, Vertex>& x) { return get(owner, x.first) == id; } template <typename Vertex> bool operator()(const std::pair<Vertex, Vertex>& x) const { return get(owner, x.first) == id; } private: OwnerMap owner; ProcessId id; }; // Turns an index iterator into a vertex iterator template<typename IndexIterator, typename Graph> class index_to_vertex_iterator { public: typedef std::input_iterator_tag iterator_category; typedef typename graph_traits<Graph>::vertex_descriptor Vertex; typedef std::pair<Vertex, Vertex> value_type; typedef const value_type& reference; typedef const value_type* pointer; typedef void difference_type; index_to_vertex_iterator(IndexIterator index, const Graph& g) : index(index), g(g), current(to_edge(*index)) {} reference operator*() { current = to_edge(*index); return current; } pointer operator->() { current = to_edge(*index); return ¤t; } index_to_vertex_iterator& operator++() { ++index; return *this; } index_to_vertex_iterator operator++(int) { index_to_vertex_iterator temp(*this); ++(*this); return temp; } bool operator==(const index_to_vertex_iterator& other) const { return index == other.index; } bool operator!=(const index_to_vertex_iterator& other) const { return !(*this == other); } private: value_type to_edge(const typename std::iterator_traits<IndexIterator>::value_type& x) { return std::make_pair(vertex(x.first, g), vertex(x.second, g)); } IndexIterator index; const Graph& g; value_type current; }; template <typename Distribution, typename Graph> struct index_to_vertex_func { typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits<Graph>::vertices_size_type vertices_size_type; typedef std::pair<vertex_descriptor, vertex_descriptor> result_type; typedef std::pair<vertices_size_type, vertices_size_type> base_iterator_type; index_to_vertex_func(const Distribution& dist, const Graph& g) : dist(dist), g(g) {} result_type operator()(const base_iterator_type& p) const { return std::make_pair(vertex(p.first, g), vertex(p.second, g)); } private: const Distribution& dist; const Graph& g; }; // NGE: This method only works with iterators that have a difference_type, // the index_to_vertex_iterator class above is retained for compatibility // with BGL generators which have no difference_type template <typename IndexIterator, typename Distribution, typename Graph> boost::transform_iterator<index_to_vertex_func<Distribution, Graph>, IndexIterator> make_index_to_vertex_iterator(IndexIterator it, const Distribution& dist, const Graph& g) { return boost::make_transform_iterator( it, index_to_vertex_func<Distribution, Graph>(dist, g)); } // Forward declaration of csr_vertex_owner_map template<typename ProcessID, typename Key> class csr_vertex_owner_map; template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template<typename InputIterator> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(edges_are_unsorted_t, InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, const ProcessGroup& pg, const GraphProperty& prop) : m_process_group(pg), m_distribution(parallel::block(m_process_group, numverts)), m_base(edges_are_unsorted_global, index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_begin, *this), index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_end, *this), m_distribution.block_size(process_id(m_process_group), numverts), get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template <typename InputIterator, typename Distribution> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(edges_are_unsorted_t, InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop) : m_process_group(pg), m_distribution(dist), m_base(edges_are_unsorted_global, index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_begin, *this), index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_end, *this), m_distribution.block_size(process_id(m_process_group), numverts), get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template<typename InputIterator, typename EdgePropertyIterator> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(edges_are_unsorted_t, InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const ProcessGroup& pg, const GraphProperty& prop) : m_process_group(pg), m_distribution(parallel::block(m_process_group, numverts)), m_base(edges_are_unsorted_global, index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_begin, *this), index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_end, *this), ep_iter, m_distribution.block_size(process_id(m_process_group), numverts), get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template <typename InputIterator, typename EdgePropertyIterator, typename Distribution> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(edges_are_unsorted_t, InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop) : m_process_group(pg), m_distribution(dist), m_base(edges_are_unsorted_global, index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_begin, *this), index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_end, *this), ep_iter, m_distribution.block_size(process_id(m_process_group), numverts), get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template<typename InputIterator> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(edges_are_sorted_t, InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, edges_size_type numedges, // This is not used as there is no appropriate BGL ctor const ProcessGroup& pg, const GraphProperty& prop) : m_process_group(pg), m_distribution(parallel::block(m_process_group, numverts)), m_base(edges_are_sorted_global, index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_begin, *this), index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_end, *this), get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), m_distribution.block_size(process_id(m_process_group), numverts), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template <typename InputIterator, typename Distribution> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(edges_are_sorted_t, InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop) : m_process_group(pg), m_distribution(dist), m_base(edges_are_sorted_global, index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_begin, *this), index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_end, *this), get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), m_distribution.block_size(process_id(m_process_group), numverts), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template<typename InputIterator, typename EdgePropertyIterator> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(edges_are_sorted_t, InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, edges_size_type numedges, // This is not used as there is no appropriate BGL ctor const ProcessGroup& pg, const GraphProperty& prop) : m_process_group(pg), m_distribution(parallel::block(m_process_group, numverts)), m_base(edges_are_sorted_global, index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_begin, *this), index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_end, *this), ep_iter, get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), m_distribution.block_size(process_id(m_process_group), numverts), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template<typename InputIterator, typename EdgePropertyIterator, typename Distribution> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(edges_are_sorted_t, InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop) : m_process_group(pg), m_distribution(dist), m_base(edges_are_sorted_global, index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_begin, *this), index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_end, *this), ep_iter, get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), m_distribution.block_size(process_id(m_process_group), numverts), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template<typename MultiPassInputIterator> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, vertices_size_type numverts, const ProcessGroup& pg, const GraphProperty& prop) : m_process_group(pg), m_distribution(parallel::block(m_process_group, numverts)), m_base(edges_are_unsorted_multi_pass_global, make_index_to_vertex_iterator(edge_begin, parallel::block(m_process_group, numverts), *this), make_index_to_vertex_iterator(edge_end, parallel::block(m_process_group, numverts), *this), m_distribution.block_size(process_id(m_process_group), numverts), get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template <typename MultiPassInputIterator, typename Distribution> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop) : m_process_group(pg), m_distribution(dist), m_base(edges_are_unsorted_multi_pass_global, make_index_to_vertex_iterator(edge_begin, parallel::block(m_process_group, numverts), *this), make_index_to_vertex_iterator(edge_end, parallel::block(m_process_group, numverts), *this), m_distribution.block_size(process_id(m_process_group), numverts), get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template<typename MultiPassInputIterator, typename EdgePropertyIterator> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const ProcessGroup& pg, const GraphProperty& prop) : m_process_group(pg), m_distribution(parallel::block(m_process_group, numverts)), m_base(edges_are_unsorted_multi_pass_global, make_index_to_vertex_iterator(edge_begin, parallel::block(m_process_group, numverts), *this), make_index_to_vertex_iterator(edge_end, parallel::block(m_process_group, numverts), *this), ep_iter, m_distribution.block_size(process_id(m_process_group), numverts), get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template <typename MultiPassInputIterator, typename EdgePropertyIterator, typename Distribution> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, MultiPassInputIterator edge_begin, MultiPassInputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop) : m_process_group(pg), m_distribution(dist), m_base(edges_are_unsorted_multi_pass_global, make_index_to_vertex_iterator(edge_begin, parallel::block(m_process_group, numverts), *this), make_index_to_vertex_iterator(edge_end, parallel::block(m_process_group, numverts), *this), ep_iter, m_distribution.block_size(process_id(m_process_group), numverts), get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template<typename Source> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, std::vector<Source>& sources, std::vector<vertex_descriptor>& targets, vertices_size_type numverts, const ProcessGroup& pg, const GraphProperty& prop) : m_process_group(pg), m_distribution(parallel::block(m_process_group, numverts)), m_base(m_distribution.block_size(process_id(m_process_group), numverts)) { // Convert linear indices to global indices for (edges_size_type i = 0; i < sources.size(); ++i) { sources[i] = m_distribution.local(sources[i]); targets[i] = make_vertex_descriptor(m_distribution(targets[i]), m_distribution.local(targets[i])); } m_base.assign_sources_and_targets_global( sources, targets, m_distribution.block_size(process_id(m_process_group), numverts), identity_property_map()); // TODO: set property on m_base? } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template <typename Distribution, typename Source> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, std::vector<Source>& sources, std::vector<vertex_descriptor>& targets, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop) : m_process_group(pg), m_distribution(dist), m_base(m_distribution.block_size(process_id(m_process_group), numverts)) { // Convert linear indices to global indices for (edges_size_type i = 0; i < sources.size(); ++i) { sources[i] = m_distribution.local(sources[i]); targets[i] = make_vertex_descriptor(m_distribution(targets[i]), m_distribution.local(targets[i])); } m_base.assign_sources_and_targets_global( sources, targets, m_distribution.block_size(process_id(m_process_group), numverts), identity_property_map()); // TODO: set property on m_base? } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template<typename Source> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, std::vector<Source>& sources, std::vector<vertex_descriptor>& targets, std::vector<edge_bundled>& edge_props, vertices_size_type numverts, const ProcessGroup& pg, const GraphProperty& prop) : m_process_group(pg), m_distribution(parallel::block(m_process_group, numverts)), m_base(m_distribution.block_size(process_id(m_process_group), numverts)) { // Convert linear indices to global indices for (edges_size_type i = 0; i < sources.size(); ++i) { sources[i] = m_distribution.local(sources[i]); targets[i] = make_vertex_descriptor(m_distribution(targets[i]), m_distribution.local(targets[i])); } m_base.assign_sources_and_targets_global( sources, targets, edge_props, m_distribution.block_size(process_id(m_process_group), numverts), identity_property_map()); // TODO: set property on m_base? } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template <typename Distribution, typename Source> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, std::vector<Source>& sources, std::vector<vertex_descriptor>& targets, std::vector<edge_bundled>& edge_props, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop) : m_process_group(pg), m_distribution(dist), m_base(m_distribution.block_size(process_id(m_process_group), numverts)) { // Convert linear indices to global indices for (edges_size_type i = 0; i < sources.size(); ++i) { sources[i] = m_distribution.local(sources[i]); targets[i] = make_vertex_descriptor(m_distribution(targets[i]), m_distribution.local(targets[i])); } m_base.assign_sources_and_targets_global( sources, targets, edge_props, m_distribution.block_size(process_id(m_process_group), numverts), identity_property_map()); // TODO: set property on m_base? } // // Old (untagged) ctors, these default to the unsorted sequential ctors // template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template<typename InputIterator> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, const ProcessGroup& pg, const GraphProperty& prop) : m_process_group(pg), m_distribution(parallel::block(m_process_group, numverts)), m_base(edges_are_unsorted_global, index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_begin, *this), index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_end, *this), m_distribution.block_size(process_id(m_process_group), numverts), get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template<typename InputIterator, typename EdgePropertyIterator> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const ProcessGroup& pg, const GraphProperty& prop) : m_process_group(pg), m_distribution(parallel::block(m_process_group, numverts)), m_base(edges_are_unsorted_global, index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_begin, *this), index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_end, *this), ep_iter, m_distribution.block_size(process_id(m_process_group), numverts), get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template<typename InputIterator, typename Distribution> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop) : m_process_group(pg), m_distribution(dist), m_base(edges_are_unsorted_global, index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_begin, *this), index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_end, *this), m_distribution.block_size(process_id(m_process_group), numverts), get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), prop) { } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> template<typename InputIterator, typename EdgePropertyIterator, typename Distribution> BOOST_DISTRIB_CSR_GRAPH_TYPE:: compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, EdgePropertyIterator ep_iter, vertices_size_type numverts, const ProcessGroup& pg, const Distribution& dist, const GraphProperty& prop) : m_process_group(pg), m_distribution(dist), m_base(edges_are_unsorted_global, index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_begin, *this), index_to_vertex_iterator<InputIterator, BOOST_DISTRIB_CSR_GRAPH_TYPE>(edge_end, *this), m_distribution.block_size(process_id(m_process_group), numverts), get(vertex_local, *this), local_vertex<csr_vertex_owner_map<process_id_type, vertex_descriptor>, process_id_type> (get(vertex_owner, *this), process_id(pg)), prop) { } // ----------------------------------------------------------------- // Vertex Global Property Map template<typename ProcessID, typename Key> class csr_vertex_global_map { public: // ----------------------------------------------------------------- // Readable Property Map concept requirements typedef std::pair<ProcessID, Key> value_type; typedef value_type reference; typedef Key key_type; typedef readable_property_map_tag category; }; template<typename ProcessID, typename Key> inline std::pair<ProcessID, Key> get(csr_vertex_global_map<ProcessID, Key>, typename csr_vertex_global_map<ProcessID, Key>::key_type k) { const int local_index_bits = sizeof(Key) * CHAR_BIT - processor_bits; const Key local_index_mask = Key(-1) >> processor_bits; return std::pair<ProcessID, Key>(k >> local_index_bits, k & local_index_mask); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_global_t> { public: typedef csr_vertex_global_map< typename ProcessGroup::process_id_type, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor> type; typedef type const_type; }; template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_global_t>::type get(vertex_global_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_global_t> ::type result_type; return result_type(); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline std::pair<typename ProcessGroup::process_id_type, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor> get(vertex_global_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k) { return get(vertex_global, const_cast<const BOOST_DISTRIB_CSR_GRAPH_TYPE&>(g), k); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_global_t>::const_type get(vertex_global_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_global_t> ::const_type result_type; return result_type(); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline std::pair<typename ProcessGroup::process_id_type, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor> get(vertex_global_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k) { typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor vertex_descriptor; typedef std::pair<typename ProcessGroup::process_id_type, vertex_descriptor> result_type; const int local_index_bits = sizeof(vertex_descriptor) * CHAR_BIT - processor_bits; const vertex_descriptor local_index_mask = vertex_descriptor(-1) >> processor_bits; return result_type(k >> local_index_bits, k & local_index_mask); } // ----------------------------------------------------------------- // Extra, common functions template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor vertex(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertices_size_type i, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { return g.make_vertex_descriptor(g.distribution()(i), g.distribution().local(i)); } // Unlike for an adjacency_matrix, edge_range and edge take lg(out_degree(i)) // time template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline std::pair<typename BOOST_DISTRIB_CSR_GRAPH_TYPE::out_edge_iterator, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::out_edge_iterator> edge_range(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor i, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor j, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor Vertex; typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type EdgeIndex; typedef typename std::vector<Vertex>::const_iterator adj_iter; typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::out_edge_iterator out_edge_iter; typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor edge_desc; std::pair<adj_iter, adj_iter> raw_adjacencies = adjacent_vertices(i, g); std::pair<adj_iter, adj_iter> adjacencies = std::equal_range(raw_adjacencies.first, raw_adjacencies.second, j); EdgeIndex idx_begin = adjacencies.first - g.base().m_forward.m_column.begin(); EdgeIndex idx_end = adjacencies.second - g.base().m_forward.m_column.begin(); return std::make_pair(out_edge_iter(edge_desc(i, idx_begin)), out_edge_iter(edge_desc(i, idx_end))); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline std::pair<typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor, bool> edge(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor i, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor j, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::out_edge_iterator out_edge_iter; std::pair<out_edge_iter, out_edge_iter> range = edge_range(i, j, g); if (range.first == range.second) return std::make_pair(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor(), false); else return std::make_pair(*range.first, true); } // A helper that turns requests for property maps for const graphs // into property maps for non-const graphs. template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS, typename Property> class property_map<const BOOST_DISTRIB_CSR_GRAPH_TYPE, Property> { public: typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, Property> ::const_type type; typedef type const_type; }; // ----------------------------------------------------------------- // Structural modifiers #if 0 template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor add_vertex(BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { return g.add_vertex(); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor add_vertex(const typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_bundled& p, BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { return g.add_vertex(p); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor add_vertices(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertices_size_type count, BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { return g.add_vertices(count); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS, typename InputIterator> void add_edges(InputIterator first, InputIterator last, BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { g.add_edges(first, last); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS, typename InputIterator, typename EdgePropertyIterator> void add_edges(InputIterator first, InputIterator last, EdgePropertyIterator ep_iter, EdgePropertyIterator ep_iter_end, BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { return g.add_edges(first, last, ep_iter, ep_iter_end); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS, typename InputIterator> void add_edges_sorted(InputIterator first, InputIterator last, BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { return g.add_edges_sorted(first, last); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS, typename InputIterator, typename EdgePropertyIterator> void add_edges_sorted(InputIterator first_sorted, InputIterator last_sorted, EdgePropertyIterator ep_iter_sorted, BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { g.add_edges_sorted(first_sorted, last_sorted, ep_iter_sorted); } #endif // ----------------------------------------------------------------- // Vertex Owner Property Map template<typename ProcessID, typename Key> class csr_vertex_owner_map { public: // ----------------------------------------------------------------- // Readable Property Map concept requirements typedef ProcessID value_type; typedef value_type reference; typedef Key key_type; typedef readable_property_map_tag category; }; template<typename ProcessID, typename Key> inline ProcessID get(csr_vertex_owner_map<ProcessID, Key> pm, typename csr_vertex_owner_map<ProcessID, Key>::key_type k) { const int local_index_bits = sizeof(Key) * CHAR_BIT - processor_bits; return k >> local_index_bits; } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_owner_t> { public: typedef csr_vertex_owner_map< typename ProcessGroup::process_id_type, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor> type; typedef type const_type; }; template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_owner_t>::type get(vertex_owner_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_owner_t> ::type result_type; return result_type(); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename ProcessGroup::process_id_type get(vertex_owner_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k) { return get(vertex_owner, const_cast<const BOOST_DISTRIB_CSR_GRAPH_TYPE&>(g), k); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_owner_t>::const_type get(vertex_owner_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_owner_t> ::const_type result_type; return result_type(); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename ProcessGroup::process_id_type get(vertex_owner_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k) { typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor vertex_descriptor; const int local_index_bits = sizeof(vertex_descriptor) * CHAR_BIT - processor_bits; return k >> local_index_bits; } // ----------------------------------------------------------------- // Vertex Local Property Map template<typename Key> class csr_vertex_local_map { public: // ----------------------------------------------------------------- // Readable Property Map concept requirements typedef Key value_type; typedef value_type reference; typedef Key key_type; typedef readable_property_map_tag category; }; template<typename Key> inline Key get(csr_vertex_local_map<Key> pm, typename csr_vertex_local_map<Key>::key_type k) { const Key local_index_mask = Key(-1) >> processor_bits; return k & local_index_mask; } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_t> { public: typedef csr_vertex_local_map< typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor> type; typedef type const_type; }; template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_t>::type get(vertex_local_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_t> ::type result_type; return result_type(); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor get(vertex_local_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k) { return get(vertex_local, const_cast<const BOOST_DISTRIB_CSR_GRAPH_TYPE&>(g), k); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_t>::const_type get(vertex_local_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_t> ::const_type result_type; return result_type(); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor get(vertex_local_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k) { typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor vertex_descriptor; const vertex_descriptor local_index_mask = vertex_descriptor(-1) >> processor_bits; return k & local_index_mask; } // ----------------------------------------------------------------- // Vertex Index Property Map template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_index_t> { typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_global_t>::const_type global_map; typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::process_group_type process_group_type; typedef property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_t> local; public: typedef local_property_map<process_group_type, global_map, typename local::type> type; typedef local_property_map<process_group_type, global_map, typename local::const_type> const_type; }; template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_index_t>::type get(vertex_index_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_index_t> ::type result_type; return result_type(g.process_group(), get(vertex_global, g), get(vertex_local, g)); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertices_size_type get(vertex_index_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k) { return get(vertex_local, g, k); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_index_t>::const_type get(vertex_index_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_index_t> ::const_type result_type; return result_type(g.process_group(), get(vertex_global, g), get(vertex_local, g)); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertices_size_type get(vertex_index_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k) { return get(vertex_local, g, k); } // ----------------------------------------------------------------- // Vertex Local Index Property Map template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_index_t> : public property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_t> { }; template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_index_t>::type get(vertex_local_index_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { return get(vertex_local, g); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertices_size_type get(vertex_local_index_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k) { return get(vertex_local, g, k); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_index_t>::const_type get(vertex_local_index_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { return get(vertex_local, g); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertices_size_type get(vertex_local_index_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k) { return get(vertex_local, g, k); } // ----------------------------------------------------------------- // Edge Global Property Map template<typename ProcessID, typename Vertex, typename EdgeIndex> class csr_edge_global_map { public: // ----------------------------------------------------------------- // Readable Property Map concept requirements typedef detail::csr_edge_descriptor<Vertex, EdgeIndex> key_type; typedef std::pair<ProcessID, detail::csr_edge_descriptor<Vertex, EdgeIndex> > value_type; typedef value_type reference; typedef readable_property_map_tag category; }; template<typename ProcessID, typename Vertex, typename EdgeIndex> inline std::pair<ProcessID, detail::csr_edge_descriptor<Vertex, EdgeIndex> > get(csr_edge_global_map<ProcessID, Vertex, EdgeIndex> pm, typename csr_edge_global_map<ProcessID, Vertex, EdgeIndex>::key_type k) { const int local_index_bits = sizeof(Vertex) * CHAR_BIT - processor_bits; const Vertex local_index_mask = Vertex(-1) >> processor_bits; return std::pair<ProcessID, detail::csr_edge_descriptor<Vertex, EdgeIndex> > ((k.src >> local_index_bits), detail::csr_edge_descriptor<Vertex, EdgeIndex>(k.src & local_index_mask, k.idx)); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_global_t> { public: typedef csr_edge_global_map< typename ProcessGroup::process_id_type, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type> type; typedef type const_type; }; template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_global_t>::type get(edge_global_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_global_t> ::type result_type; return result_type(); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline std::pair<typename ProcessGroup::process_id_type, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::base_type::edge_descriptor> get(edge_global_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor k) { return get(edge_global, const_cast<const BOOST_DISTRIB_CSR_GRAPH_TYPE&>(g), k); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_global_t>::const_type get(edge_global_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_global_t> ::const_type result_type; return result_type(); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline std::pair<typename ProcessGroup::process_id_type, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::base_type::edge_descriptor> get(edge_global_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor k) { typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor vertex_descriptor; const int local_index_bits = sizeof(vertex_descriptor) * CHAR_BIT - processor_bits; const typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type local_index_mask = typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type(-1) >> processor_bits; typedef std::pair<typename ProcessGroup::process_id_type, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::base_type::edge_descriptor> result_type; return result_type(k.src >> local_index_bits, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::base_type::edge_descriptor (k.src & local_index_mask, k.idx)); } // ----------------------------------------------------------------- // Edge Index Property Map template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_index_t> { typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_global_t> ::type global_map; public: typedef local_property_map< typename BOOST_DISTRIB_CSR_GRAPH_TYPE::process_group_type, global_map, typename property_map<typename BOOST_DISTRIB_CSR_GRAPH_TYPE::base_type, edge_index_t>::type > type; typedef type const_type; }; template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_index_t>::type get(edge_index_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_index_t> ::type result_type; return result_type(g.process_group(), get(edge_global, g), get(edge_index, g.base())); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type get(edge_index_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor k) { return k.idx; } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_index_t>::const_type get(edge_index_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_index_t> ::const_type result_type; return result_type(g.process_group(), get(edge_global, g), get(edge_index, g.base())); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type get(edge_index_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g, typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor k) { return k.idx; } template <BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS, typename Tag> class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, Tag> { typedef BOOST_DISTRIB_CSR_GRAPH_TYPE graph_type; typedef typename graph_type::process_group_type process_group_type; typedef typename graph_type::base_type base_graph_type; typedef typename property_map<base_graph_type, Tag>::type local_pmap; typedef typename property_map<base_graph_type, Tag>::const_type local_const_pmap; typedef graph_traits<graph_type> traits; typedef typename graph_traits<base_graph_type>::vertex_descriptor local_vertex; typedef typename property_traits<local_pmap>::key_type local_key_type; typedef typename property_traits<local_pmap>::value_type value_type; typedef typename property_map<graph_type, vertex_global_t>::const_type vertex_global_map; typedef typename property_map<graph_type, edge_global_t>::const_type edge_global_map; typedef typename mpl::if_<is_same<typename detail::property_kind_from_graph<base_graph_type, Tag>::type, vertex_property_tag>, vertex_global_map, edge_global_map>::type global_map; public: typedef ::boost::parallel::distributed_property_map< process_group_type, global_map, local_pmap> type; typedef ::boost::parallel::distributed_property_map< process_group_type, global_map, local_const_pmap> const_type; }; template <BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS, typename Tag> typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, Tag>::type get(Tag tag, BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef BOOST_DISTRIB_CSR_GRAPH_TYPE Graph; typedef typename property_map<Graph, Tag>::type result_type; typedef typename property_traits<result_type>::value_type value_type; typedef typename property_reduce<Tag>::template apply<value_type> reduce; typedef typename mpl::if_<is_same<typename detail::property_kind_from_graph<Graph, Tag>::type, vertex_property_tag>, vertex_global_t, edge_global_t>::type global_map_t; return result_type(g.process_group(), get(global_map_t(), g), get(tag, g.base()), reduce()); } template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS, typename Tag> typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, Tag>::const_type get(Tag tag, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) { typedef BOOST_DISTRIB_CSR_GRAPH_TYPE Graph; typedef typename property_map<Graph, Tag>::const_type result_type; typedef typename property_traits<result_type>::value_type value_type; typedef typename property_reduce<Tag>::template apply<value_type> reduce; typedef typename property_traits<result_type>::key_type descriptor; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>, vertex_global_t, edge_global_t>::type global_map_t; return result_type(g.process_group(), get(global_map_t(), g), get(tag, g.base()), reduce()); } namespace mpi { template<typename Vertex, typename EdgeIndex> struct is_mpi_datatype<boost::detail::csr_edge_descriptor<Vertex, EdgeIndex> > : mpl::true_ { }; } namespace serialization { template<typename Vertex, typename EdgeIndex> struct is_bitwise_serializable<boost::detail::csr_edge_descriptor<Vertex, EdgeIndex> > : mpl::true_ { }; template<typename Vertex, typename EdgeIndex> struct implementation_level<boost::detail::csr_edge_descriptor<Vertex, EdgeIndex> > : mpl::int_<object_serializable> {} ; template<typename Vertex, typename EdgeIndex> struct tracking_level<boost::detail::csr_edge_descriptor<Vertex, EdgeIndex> > : mpl::int_<track_never> {} ; } } // end namespace boost #endif // BOOST_GRAPH_DISTRIBUTED_CSR_HPP distributed/rmat_graph_generator.hpp 0000644 00000013431 15125521275 0014000 0 ustar 00 // Copyright 2004, 2005 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Nick Edmonds // Andrew Lumsdaine #ifndef BOOST_GRAPH_DISTRIBUTED_RMAT_GENERATOR_HPP #define BOOST_GRAPH_DISTRIBUTED_RMAT_GENERATOR_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/assert.hpp> #include <boost/graph/parallel/algorithm.hpp> #include <boost/graph/parallel/process_group.hpp> #include <math.h> namespace boost { // Memory-scalable (amount of memory required will scale down // linearly as the number of processes increases) generator, which // requires an MPI process group. Run-time is slightly worse than // the unique rmat generator. Edge list generated is sorted and // unique. template<typename ProcessGroup, typename Distribution, typename RandomGenerator, typename Graph> class scalable_rmat_iterator { typedef typename graph_traits<Graph>::directed_category directed_category; typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type; typedef typename graph_traits<Graph>::edges_size_type edges_size_type; public: typedef std::input_iterator_tag iterator_category; typedef std::pair<vertices_size_type, vertices_size_type> value_type; typedef const value_type& reference; typedef const value_type* pointer; typedef void difference_type; // No argument constructor, set to terminating condition scalable_rmat_iterator() : gen(), done(true) { } // Initialize for edge generation scalable_rmat_iterator(ProcessGroup pg, Distribution distrib, RandomGenerator& gen, vertices_size_type n, edges_size_type m, double a, double b, double c, double d, bool permute_vertices = true) : gen(), done(false) { BOOST_ASSERT(a + b + c + d == 1); int id = process_id(pg); this->gen.reset(new uniform_01<RandomGenerator>(gen)); std::vector<vertices_size_type> vertexPermutation; if (permute_vertices) generate_permutation_vector(gen, vertexPermutation, n); int SCALE = int(floor(log(double(n))/log(2.))); boost::uniform_01<RandomGenerator> prob(gen); std::map<value_type, bool> edge_map; edges_size_type generated = 0, local_edges = 0; do { edges_size_type tossed = 0; do { vertices_size_type u, v; boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d); if (permute_vertices) { u = vertexPermutation[u]; v = vertexPermutation[v]; } // Lowest vertex number always comes first (this // means we don't have to worry about i->j and j->i // being in the edge list) if (u > v && is_same<directed_category, undirected_tag>::value) std::swap(u, v); if (distrib(u) == id || distrib(v) == id) { if (edge_map.find(std::make_pair(u, v)) == edge_map.end()) { edge_map[std::make_pair(u, v)] = true; local_edges++; } else { tossed++; // special case - if both u and v are on same // proc, ++ twice, since we divide by two (to // cover the two process case) if (distrib(u) == id && distrib(v) == id) tossed++; } } generated++; } while (generated < m); tossed = all_reduce(pg, tossed, boost::parallel::sum<vertices_size_type>()); generated -= (tossed / 2); } while (generated < m); // NGE - Asking for more than n^2 edges will result in an infinite loop here // Asking for a value too close to n^2 edges may as well values.reserve(local_edges); typename std::map<value_type, bool>::reverse_iterator em_end = edge_map.rend(); for (typename std::map<value_type, bool>::reverse_iterator em_i = edge_map.rbegin(); em_i != em_end ; ++em_i) { values.push_back(em_i->first); } current = values.back(); values.pop_back(); } reference operator*() const { return current; } pointer operator->() const { return ¤t; } scalable_rmat_iterator& operator++() { if (!values.empty()) { current = values.back(); values.pop_back(); } else done = true; return *this; } scalable_rmat_iterator operator++(int) { scalable_rmat_iterator temp(*this); ++(*this); return temp; } bool operator==(const scalable_rmat_iterator& other) const { return values.empty() && other.values.empty() && done && other.done; } bool operator!=(const scalable_rmat_iterator& other) const { return !(*this == other); } private: // Parameters shared_ptr<uniform_01<RandomGenerator> > gen; // Internal data structures std::vector<value_type> values; value_type current; bool done; }; } // end namespace boost #endif // BOOST_GRAPH_DISTRIBUTED_RMAT_GENERATOR_HPP distributed/shuffled_distribution.hpp 0000644 00000005421 15125521275 0014205 0 ustar 00 // Copyright Daniel Wallin 2007. Use, modification and distribution is // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_SHUFFLED_DISTRIBUTION_070923_HPP #define BOOST_SHUFFLED_DISTRIBUTION_070923_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif # include <boost/assert.hpp> # include <boost/iterator/counting_iterator.hpp> # include <vector> namespace boost { namespace graph { namespace distributed { template <class BaseDistribution> struct shuffled_distribution : BaseDistribution { typedef std::size_t size_type; template <class ProcessGroup> shuffled_distribution(ProcessGroup const& pg, BaseDistribution const& base) : BaseDistribution(base) , n(num_processes(pg)) , mapping_(make_counting_iterator(size_type(0)), make_counting_iterator(n)) , reverse_mapping(mapping_) {} std::vector<size_type> const& mapping() const { return mapping_; } template <class InputIterator> void assign_mapping(InputIterator first, InputIterator last) { mapping_.assign(first, last); BOOST_ASSERT(mapping_.size() == n); reverse_mapping.resize(mapping_.size()); for (std::vector<size_t>::iterator i(mapping_.begin()); i != mapping_.end(); ++i) { reverse_mapping[*i] = i - mapping_.begin(); } } BaseDistribution& base() { return *this; } BaseDistribution const& base() const { return *this; } template <class ProcessID> size_type block_size(ProcessID id, size_type n) const { return base().block_size(reverse_mapping[id], n); } template <class T> size_type operator()(T const& value) const { return mapping_[base()(value)]; } template <class ProcessID> size_type start(ProcessID id) const { return base().start(reverse_mapping[id]); } size_type local(size_type i) const { return base().local(i); } size_type global(size_type i) const { return base().global(i); } template <class ProcessID> size_type global(ProcessID id, size_type n) const { return base().global(reverse_mapping[id], n); } template <class Archive> void serialize(Archive& ar, unsigned long /*version*/) { ar & serialization::make_nvp("base", base()); } void clear() { base().clear(); } private: size_type n; std::vector<size_type> mapping_; std::vector<size_type> reverse_mapping; }; }}} // namespace boost::graph::distributed #endif // BOOST_SHUFFLED_DISTRIBUTION_070923_HPP distributed/connected_components_parallel_search.hpp 0000644 00000035323 15125521275 0017222 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Brian Barrett // Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_PARALLEL_CC_PS_HPP #define BOOST_GRAPH_PARALLEL_CC_PS_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/assert.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/parallel/algorithm.hpp> #include <boost/pending/indirect_cmp.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/overloading.hpp> #include <boost/graph/distributed/concepts.hpp> #include <boost/graph/parallel/properties.hpp> #include <boost/graph/parallel/process_group.hpp> #include <boost/optional.hpp> #include <algorithm> #include <vector> #include <queue> #include <limits> #include <map> #include <boost/graph/parallel/container_traits.hpp> #include <boost/graph/iteration_macros.hpp> // Connected components algorithm based on a parallel search. // // Every N nodes starts a parallel search from the first vertex in // their local vertex list during the first superstep (the other nodes // remain idle during the first superstep to reduce the number of // conflicts in numbering the components). At each superstep, all new // component mappings from remote nodes are handled. If there is no // work from remote updates, a new vertex is removed from the local // list and added to the work queue. // // Components are allocated from the component_value_allocator object, // which ensures that a given component number is unique in the // system, currently by using the rank and number of processes to // stride allocations. // // When two components are discovered to actually be the same // component, a mapping is created in the collisions object. The // lower component number is prefered in the resolution, so component // numbering resolution is consistent. After the search has exhausted // all vertices in the graph, the mapping is shared with all // processes, and they independently resolve the comonent mapping (so // O((N * NP) + (V * NP)) work, in O(N + V) time, where N is the // number of mappings and V is the number of local vertices). This // phase can likely be significantly sped up if a clever algorithm for // the reduction can be found. namespace boost { namespace graph { namespace distributed { namespace cc_ps_detail { // Local object for allocating component numbers. There are two // places this happens in the code, and I was getting sick of them // getting out of sync. Components are not tightly packed in // numbering, but are numbered to ensure each rank has its own // independent sets of numberings. template<typename component_value_type> class component_value_allocator { public: component_value_allocator(int num, int size) : last(0), num(num), size(size) { } component_value_type allocate(void) { component_value_type ret = num + (last * size); last++; return ret; } private: component_value_type last; int num; int size; }; // Map of the "collisions" between component names in the global // component mapping. TO make cleanup easier, component numbers // are added, pointing to themselves, when a new component is // found. In order to make the results deterministic, the lower // component number is always taken. The resolver will drill // through the map until it finds a component entry that points to // itself as the next value, allowing some cleanup to happen at // update() time. Attempts are also made to update the mapping // when new entries are created. // // Note that there's an assumption that the entire mapping is // shared during the end of the algorithm, but before component // name resolution. template<typename component_value_type> class collision_map { public: collision_map() : num_unique(0) { } // add new component mapping first time component is used. Own // function only so that we can sanity check there isn't already // a mapping for that component number (which would be bad) void add(const component_value_type &a) { BOOST_ASSERT(collisions.count(a) == 0); collisions[a] = a; } // add a mapping between component values saying they're the // same component void add(const component_value_type &a, const component_value_type &b) { component_value_type high, low, tmp; if (a > b) { high = a; low = b; } else { high = b; low = a; } if (collisions.count(high) != 0 && collisions[high] != low) { tmp = collisions[high]; if (tmp > low) { collisions[tmp] = low; collisions[high] = low; } else { collisions[low] = tmp; collisions[high] = tmp; } } else { collisions[high] = low; } } // get the "real" component number for the given component. // Used to resolve mapping at end of run. component_value_type update(component_value_type a) { BOOST_ASSERT(num_unique > 0); BOOST_ASSERT(collisions.count(a) != 0); return collisions[a]; } // collapse the collisions tree, so that update is a one lookup // operation. Count unique components at the same time. void uniqify(void) { typename std::map<component_value_type, component_value_type>::iterator i, end; end = collisions.end(); for (i = collisions.begin() ; i != end ; ++i) { if (i->first == i->second) { num_unique++; } else { i->second = collisions[i->second]; } } } // get the number of component entries that have an associated // component number of themselves, which are the real components // used in the final mapping. This is the number of unique // components in the graph. int unique(void) { BOOST_ASSERT(num_unique > 0); return num_unique; } // "serialize" into a vector for communication. std::vector<component_value_type> serialize(void) { std::vector<component_value_type> ret; typename std::map<component_value_type, component_value_type>::iterator i, end; end = collisions.end(); for (i = collisions.begin() ; i != end ; ++i) { ret.push_back(i->first); ret.push_back(i->second); } return ret; } private: std::map<component_value_type, component_value_type> collisions; int num_unique; }; // resolver to handle remote updates. The resolver will add // entries into the collisions map if required, and if it is the // first time the vertex has been touched, it will add the vertex // to the remote queue. Note that local updates are handled // differently, in the main loop (below). // BWB - FIX ME - don't need graph anymore - can pull from key value of Component Map. template<typename ComponentMap, typename work_queue> struct update_reducer { BOOST_STATIC_CONSTANT(bool, non_default_resolver = false); typedef typename property_traits<ComponentMap>::value_type component_value_type; typedef typename property_traits<ComponentMap>::key_type vertex_descriptor; update_reducer(work_queue *q, cc_ps_detail::collision_map<component_value_type> *collisions, processor_id_type pg_id) : q(q), collisions(collisions), pg_id(pg_id) { } // ghost cell initialization routine. This should never be // called in this imlementation. template<typename K> component_value_type operator()(const K&) const { return component_value_type(0); } // resolver for remote updates. I'm not entirely sure why, but // I decided to not change the value of the vertex if it's // already non-infinite. It doesn't matter in the end, as we'll // touch every vertex in the cleanup phase anyway. If the // component is currently infinite, set to the new component // number and add the vertex to the work queue. If it's not // infinite, we've touched it already so don't add it to the // work queue. Do add a collision entry so that we know the two // components are the same. component_value_type operator()(const vertex_descriptor &v, const component_value_type& current, const component_value_type& update) const { const component_value_type max = (std::numeric_limits<component_value_type>::max)(); component_value_type ret = current; if (max == current) { q->push(v); ret = update; } else if (current != update) { collisions->add(current, update); } return ret; } // So for whatever reason, the property map can in theory call // the resolver with a local descriptor in addition to the // standard global descriptor. As far as I can tell, this code // path is never taken in this implementation, but I need to // have this code here to make it compile. We just make a // global descriptor and call the "real" operator(). template<typename K> component_value_type operator()(const K& v, const component_value_type& current, const component_value_type& update) const { return (*this)(vertex_descriptor(pg_id, v), current, update); } private: work_queue *q; collision_map<component_value_type> *collisions; boost::processor_id_type pg_id; }; } // namespace cc_ps_detail template<typename Graph, typename ComponentMap> typename property_traits<ComponentMap>::value_type connected_components_ps(const Graph& g, ComponentMap c) { using boost::graph::parallel::process_group; typedef typename property_traits<ComponentMap>::value_type component_value_type; typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename boost::graph::parallel::process_group_type<Graph> ::type process_group_type; typedef typename process_group_type::process_id_type process_id_type; typedef std::queue<vertex_descriptor> work_queue; static const component_value_type max_component = (std::numeric_limits<component_value_type>::max)(); typename property_map<Graph, vertex_owner_t>::const_type owner = get(vertex_owner, g); // standard who am i? stuff process_group_type pg = process_group(g); process_id_type id = process_id(pg); // Initialize every vertex to have infinite component number BGL_FORALL_VERTICES_T(v, g, Graph) put(c, v, max_component); vertex_iterator current, end; boost::tie(current, end) = vertices(g); cc_ps_detail::component_value_allocator<component_value_type> cva(process_id(pg), num_processes(pg)); cc_ps_detail::collision_map<component_value_type> collisions; work_queue q; // this is intentionally a local data structure c.set_reduce(cc_ps_detail::update_reducer<ComponentMap, work_queue>(&q, &collisions, id)); // add starting work while (true) { bool useful_found = false; component_value_type val = cva.allocate(); put(c, *current, val); collisions.add(val); q.push(*current); if (0 != out_degree(*current, g)) useful_found = true; ++current; if (useful_found) break; } // Run the loop until everyone in the system is done bool global_done = false; while (!global_done) { // drain queue of work for this superstep while (!q.empty()) { vertex_descriptor v = q.front(); q.pop(); // iterate through outedges of the vertex currently being // examined, setting their component to our component. There // is no way to end up in the queue without having a component // number already. BGL_FORALL_ADJ_T(v, peer, g, Graph) { component_value_type my_component = get(c, v); // update other vertex with our component information. // Resolver will handle remote collisions as well as whether // to put the vertex on the work queue or not. We have to // handle local collisions and work queue management if (id == get(owner, peer)) { if (max_component == get(c, peer)) { put(c, peer, my_component); q.push(peer); } else if (my_component != get(c, peer)) { collisions.add(my_component, get(c, peer)); } } else { put(c, peer, my_component); } } } // synchronize / start a new superstep. synchronize(pg); global_done = all_reduce(pg, (q.empty() && (current == end)), boost::parallel::minimum<bool>()); // If the queue is currently empty, add something to do to start // the current superstep (supersteps start at the sync, not at // the top of the while loop as one might expect). Down at the // bottom of the while loop so that not everyone starts the // algorithm with something to do, to try to reduce component // name conflicts if (q.empty()) { bool useful_found = false; for ( ; current != end && !useful_found ; ++current) { if (max_component == get(c, *current)) { component_value_type val = cva.allocate(); put(c, *current, val); collisions.add(val); q.push(*current); if (0 != out_degree(*current, g)) useful_found = true; } } } } // share component mappings std::vector<component_value_type> global; std::vector<component_value_type> mine = collisions.serialize(); all_gather(pg, mine.begin(), mine.end(), global); for (size_t i = 0 ; i < global.size() ; i += 2) { collisions.add(global[i], global[i + 1]); } collisions.uniqify(); // update the component mappings BGL_FORALL_VERTICES_T(v, g, Graph) { put(c, v, collisions.update(get(c, v))); } return collisions.unique(); } } // end namespace distributed } // end namespace graph } // end namespace boost #endif // BOOST_GRAPH_PARALLEL_CC_HPP distributed/st_connected.hpp 0000644 00000014016 15125521275 0012256 0 ustar 00 // Copyright (C) 2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_DISTRIBUTED_ST_CONNECTED_HPP #define BOOST_GRAPH_DISTRIBUTED_ST_CONNECTED_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/graph_traits.hpp> #include <boost/graph/two_bit_color_map.hpp> #include <boost/graph/distributed/queue.hpp> #include <boost/pending/queue.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/graph/parallel/container_traits.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/parallel/algorithm.hpp> #include <utility> #include <boost/optional.hpp> namespace boost { namespace graph { namespace distributed { namespace detail { struct pair_and_or { std::pair<bool, bool> operator()(std::pair<bool, bool> x, std::pair<bool, bool> y) const { return std::pair<bool, bool>(x.first && y.first, x.second || y.second); } }; } // end namespace detail template<typename DistributedGraph, typename ColorMap, typename OwnerMap> bool st_connected(const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, typename graph_traits<DistributedGraph>::vertex_descriptor t, ColorMap color, OwnerMap owner) { using boost::graph::parallel::process_group; using boost::graph::parallel::process_group_type; using boost::parallel::all_reduce; typedef typename property_traits<ColorMap>::value_type Color; typedef color_traits<Color> ColorTraits; typedef typename process_group_type<DistributedGraph>::type ProcessGroup; typedef typename ProcessGroup::process_id_type ProcessID; typedef typename graph_traits<DistributedGraph>::vertex_descriptor Vertex; // Set all vertices to white (unvisited) BGL_FORALL_VERTICES_T(v, g, DistributedGraph) put(color, v, ColorTraits::white()); // "color" plays the role of a color map, with no synchronization. set_property_map_role(vertex_color, color); color.set_consistency_model(0); // Vertices found from the source are grey put(color, s, ColorTraits::gray()); // Vertices found from the target are green put(color, t, ColorTraits::green()); ProcessGroup pg = process_group(g); ProcessID rank = process_id(pg); // Build a local queue queue<Vertex> Q; if (get(owner, s) == rank) Q.push(s); if (get(owner, t) == rank) Q.push(t); queue<Vertex> other_Q; while (true) { bool found = false; // Process all vertices in the local queue while (!found && !Q.empty()) { Vertex u = Q.top(); Q.pop(); Color u_color = get(color, u); BGL_FORALL_OUTEDGES_T(u, e, g, DistributedGraph) { Vertex v = target(e, g); Color v_color = get(color, v); if (v_color == ColorTraits::white()) { // We have not seen "v" before; mark it with the same color as u Color u_color = get(color, u); put(color, v, u_color); // Either push v into the local queue or send it off to its // owner. ProcessID v_owner = get(owner, v); if (v_owner == rank) other_Q.push(v); else send(pg, v_owner, 0, std::make_pair(v, u_color == ColorTraits::gray())); } else if (v_color != ColorTraits::black() && u_color != v_color) { // Colors have collided. We're done! found = true; break; } } // u is done, so mark it black put(color, u, ColorTraits::black()); } // Ensure that all transmitted messages have been received. synchronize(pg); // Move all of the send-to-self values into the local Q. other_Q.swap(Q); if (!found) { // Receive all messages while (optional<std::pair<ProcessID, int> > msg = probe(pg)) { std::pair<Vertex, bool> data; receive(pg, msg->first, msg->second, data); // Determine the colors of u and v, the source and target // vertices (v is local). Vertex v = data.first; Color v_color = get(color, v); Color u_color = data.second? ColorTraits::gray() : ColorTraits::green(); if (v_color == ColorTraits::white()) { // v had no color before, so give it u's color and push it // into the queue. Q.push(v); put(color, v, u_color); } else if (v_color != ColorTraits::black() && u_color != v_color) { // Colors have collided. We're done! found = true; break; } } } // Check if either all queues are empty or std::pair<bool, bool> results = all_reduce(pg, boost::parallel::detail::make_untracked_pair(Q.empty(), found), detail::pair_and_or()); // If someone found the answer, we're done! if (results.second) return true; // If all queues are empty, we're done. if (results.first) return false; } } template<typename DistributedGraph, typename ColorMap> inline bool st_connected(const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, typename graph_traits<DistributedGraph>::vertex_descriptor t, ColorMap color) { return st_connected(g, s, t, color, get(vertex_owner, g)); } template<typename DistributedGraph> inline bool st_connected(const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, typename graph_traits<DistributedGraph>::vertex_descriptor t) { return st_connected(g, s, t, make_two_bit_color_map(num_vertices(g), get(vertex_index, g))); } } } } // end namespace boost::graph::distributed #endif // BOOST_GRAPH_DISTRIBUTED_ST_CONNECTED_HPP distributed/crauser_et_al_shortest_paths.hpp 0000644 00000061324 15125521275 0015554 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine /************************************************************************** * This source file implements the variation on Dijkstra's algorithm * * presented by Crauser et al. in: * * * * Andreas Crauser, Kurt Mehlhorn, Ulrich Meyer, and Peter * * Sanders. A Parallelization of Dijkstra's Shortest Path * * Algorithm. In Lubos Brim, Jozef Gruska, and Jiri Zlatuska, * * editors, Mathematical Foundations of Computer Science (MFCS), * * volume 1450 of Lecture Notes in Computer Science, pages * * 722--731, 1998. Springer. * * * * This implementation is, however, restricted to the distributed-memory * * case, where the work is distributed by virtue of the vertices being * * distributed. In a shared-memory (single address space) context, we * * would want to add an explicit balancing step. * **************************************************************************/ #ifndef BOOST_GRAPH_CRAUSER_ET_AL_SHORTEST_PATHS_HPP #define BOOST_GRAPH_CRAUSER_ET_AL_SHORTEST_PATHS_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/assert.hpp> #include <boost/graph/distributed/detail/dijkstra_shortest_paths.hpp> #include <boost/graph/parallel/algorithm.hpp> #include <functional> #include <boost/graph/iteration_macros.hpp> #include <boost/property_map/property_map_iterator.hpp> #include <boost/type_traits/is_same.hpp> #include <algorithm> #include <boost/property_map/parallel/caching_property_map.hpp> #include <boost/pending/indirect_cmp.hpp> #include <boost/graph/distributed/detail/remote_update_set.hpp> #include <vector> #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/dijkstra_shortest_paths.hpp> #include <boost/graph/parallel/container_traits.hpp> #ifdef PBGL_ACCOUNTING # include <boost/graph/accounting.hpp> # include <numeric> #endif // PBGL_ACCOUNTING #ifdef MUTABLE_QUEUE # include <boost/pending/mutable_queue.hpp> #endif namespace boost { namespace graph { namespace distributed { #ifdef PBGL_ACCOUNTING struct crauser_et_al_shortest_paths_stats_t { /* Total wall-clock time used by the algorithm.*/ accounting::time_type execution_time; /* The number of vertices deleted in each superstep. */ std::vector<std::size_t> deleted_vertices; template<typename OutputStream> void print(OutputStream& out) { double avg_deletions = std::accumulate(deleted_vertices.begin(), deleted_vertices.end(), 0.0); avg_deletions /= deleted_vertices.size(); out << "Problem = \"Single-Source Shortest Paths\"\n" << "Algorithm = \"Crauser et al\"\n" << "Function = crauser_et_al_shortest_paths\n" << "Wall clock time = " << accounting::print_time(execution_time) << "\nSupersteps = " << deleted_vertices.size() << "\n" << "Avg. deletions per superstep = " << avg_deletions << "\n"; } }; static crauser_et_al_shortest_paths_stats_t crauser_et_al_shortest_paths_stats; #endif namespace detail { /************************************************************************ * Function objects that perform distance comparisons modified by the * * minimum or maximum edge weights. * ************************************************************************/ template<typename Vertex, typename DistanceMap, typename MinInWeightMap, typename Combine, typename Compare> struct min_in_distance_compare : std::binary_function<Vertex, Vertex, bool> { min_in_distance_compare(DistanceMap d, MinInWeightMap m, Combine combine, Compare compare) : distance_map(d), min_in_weight(m), combine(combine), compare(compare) { } bool operator()(const Vertex& x, const Vertex& y) const { return compare(combine(get(distance_map, x), -get(min_in_weight, x)), combine(get(distance_map, y), -get(min_in_weight, y))); } private: DistanceMap distance_map; MinInWeightMap min_in_weight; Combine combine; Compare compare; }; template<typename Vertex, typename DistanceMap, typename MinOutWeightMap, typename Combine, typename Compare> struct min_out_distance_compare : std::binary_function<Vertex, Vertex, bool> { min_out_distance_compare(DistanceMap d, MinOutWeightMap m, Combine combine, Compare compare) : distance_map(d), min_out_weight(m), combine(combine), compare(compare) { } bool operator()(const Vertex& x, const Vertex& y) const { return compare(combine(get(distance_map, x), get(min_out_weight, x)), combine(get(distance_map, y), get(min_out_weight, y))); } private: DistanceMap distance_map; MinOutWeightMap min_out_weight; Combine combine; Compare compare; }; /************************************************************************/ /************************************************************************ * Dijkstra queue that implements Crauser et al.'s criteria. This queue * * actually stores three separate priority queues, to help expose all * * vertices that can be processed in a single phase. * ************************************************************************/ template<typename Graph, typename Combine, typename Compare, typename VertexIndexMap, typename DistanceMap, typename PredecessorMap, typename MinOutWeightMap, typename MinInWeightMap> class crauser_et_al_dijkstra_queue : public graph::detail::remote_update_set< crauser_et_al_dijkstra_queue< Graph, Combine, Compare, VertexIndexMap, DistanceMap, PredecessorMap, MinOutWeightMap, MinInWeightMap>, typename boost::graph::parallel::process_group_type<Graph>::type, typename dijkstra_msg_value<DistanceMap, PredecessorMap>::type, typename property_map<Graph, vertex_owner_t>::const_type> { typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef crauser_et_al_dijkstra_queue self_type; typedef dijkstra_msg_value<DistanceMap, PredecessorMap> msg_value_creator; typedef typename msg_value_creator::type msg_value_type; typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type; typedef typename property_map<Graph, vertex_owner_t>::const_type OwnerPropertyMap; typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type; typedef graph::detail::remote_update_set<self_type, process_group_type, msg_value_type, OwnerPropertyMap> inherited; // Priority queue for tentative distances typedef indirect_cmp<DistanceMap, Compare> dist_queue_compare_type; typedef typename property_traits<DistanceMap>::value_type distance_type; #ifdef MUTABLE_QUEUE typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>, dist_queue_compare_type, VertexIndexMap> dist_queue_type; #else typedef relaxed_heap<vertex_descriptor, dist_queue_compare_type, VertexIndexMap> dist_queue_type; #endif // MUTABLE_QUEUE // Priority queue for OUT criteria typedef min_out_distance_compare<vertex_descriptor, DistanceMap, MinOutWeightMap, Combine, Compare> out_queue_compare_type; #ifdef MUTABLE_QUEUE typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>, out_queue_compare_type, VertexIndexMap> out_queue_type; #else typedef relaxed_heap<vertex_descriptor, out_queue_compare_type, VertexIndexMap> out_queue_type; #endif // MUTABLE_QUEUE // Priority queue for IN criteria typedef min_in_distance_compare<vertex_descriptor, DistanceMap, MinInWeightMap, Combine, Compare> in_queue_compare_type; #ifdef MUTABLE_QUEUE typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>, in_queue_compare_type, VertexIndexMap> in_queue_type; #else typedef relaxed_heap<vertex_descriptor, in_queue_compare_type, VertexIndexMap> in_queue_type; #endif // MUTABLE_QUEUE typedef typename process_group_type::process_id_type process_id_type; public: typedef typename dist_queue_type::size_type size_type; typedef typename dist_queue_type::value_type value_type; crauser_et_al_dijkstra_queue(const Graph& g, const Combine& combine, const Compare& compare, const VertexIndexMap& id, const DistanceMap& distance_map, const PredecessorMap& predecessor_map, const MinOutWeightMap& min_out_weight, const MinInWeightMap& min_in_weight) : inherited(boost::graph::parallel::process_group(g), get(vertex_owner, g)), dist_queue(num_vertices(g), dist_queue_compare_type(distance_map, compare), id), out_queue(num_vertices(g), out_queue_compare_type(distance_map, min_out_weight, combine, compare), id), in_queue(num_vertices(g), in_queue_compare_type(distance_map, min_in_weight, combine, compare), id), g(g), distance_map(distance_map), predecessor_map(predecessor_map), min_out_weight(min_out_weight), min_in_weight(min_in_weight), min_distance(0), min_out_distance(0) #ifdef PBGL_ACCOUNTING , local_deletions(0) #endif { } void push(const value_type& x) { msg_value_type msg_value = msg_value_creator::create(get(distance_map, x), predecessor_value(get(predecessor_map, x))); inherited::update(x, msg_value); } void update(const value_type& x) { push(x); } void pop() { // Remove from distance queue dist_queue.remove(top_vertex); // Remove from OUT queue out_queue.remove(top_vertex); // Remove from IN queue in_queue.remove(top_vertex); #ifdef PBGL_ACCOUNTING ++local_deletions; #endif } vertex_descriptor& top() { return top_vertex; } const vertex_descriptor& top() const { return top_vertex; } bool empty() { inherited::collect(); // If there are no suitable messages, wait until we get something while (!has_suitable_vertex()) { if (do_synchronize()) return true; } // Return true only if nobody has any messages; false if we // have suitable messages return false; } bool do_synchronize() { using boost::parallel::all_reduce; using boost::parallel::minimum; inherited::synchronize(); // TBD: could use combine here, but then we need to stop using // minimum<distance_type>() as the function object. distance_type local_distances[2]; local_distances[0] = dist_queue.empty()? (std::numeric_limits<distance_type>::max)() : get(distance_map, dist_queue.top()); local_distances[1] = out_queue.empty()? (std::numeric_limits<distance_type>::max)() : (get(distance_map, out_queue.top()) + get(min_out_weight, out_queue.top())); distance_type distances[2]; all_reduce(this->process_group, local_distances, local_distances + 2, distances, minimum<distance_type>()); min_distance = distances[0]; min_out_distance = distances[1]; #ifdef PBGL_ACCOUNTING std::size_t deletions = 0; all_reduce(this->process_group, &local_deletions, &local_deletions + 1, &deletions, std::plus<std::size_t>()); if (process_id(this->process_group) == 0) { crauser_et_al_shortest_paths_stats.deleted_vertices.push_back(deletions); } local_deletions = 0; BOOST_ASSERT(deletions > 0); #endif return min_distance == (std::numeric_limits<distance_type>::max)(); } private: vertex_descriptor predecessor_value(vertex_descriptor v) const { return v; } vertex_descriptor predecessor_value(property_traits<dummy_property_map>::reference) const { return graph_traits<Graph>::null_vertex(); } bool has_suitable_vertex() const { if (!dist_queue.empty()) { top_vertex = dist_queue.top(); if (get(distance_map, dist_queue.top()) <= min_out_distance) return true; } if (!in_queue.empty()) { top_vertex = in_queue.top(); return (get(distance_map, top_vertex) - get(min_in_weight, top_vertex)) <= min_distance; } return false; } public: void receive_update(process_id_type source, vertex_descriptor vertex, distance_type distance) { // Update the queue if the received distance is better than // the distance we know locally if (distance < get(distance_map, vertex) || (distance == get(distance_map, vertex) && source == process_id(this->process_group))) { // Update the local distance map put(distance_map, vertex, distance); bool is_in_queue = dist_queue.contains(vertex); if (!is_in_queue) { dist_queue.push(vertex); out_queue.push(vertex); in_queue.push(vertex); } else { dist_queue.update(vertex); out_queue.update(vertex); in_queue.update(vertex); } } } void receive_update(process_id_type source, vertex_descriptor vertex, std::pair<distance_type, vertex_descriptor> p) { if (p.first <= get(distance_map, vertex)) { put(predecessor_map, vertex, p.second); receive_update(source, vertex, p.first); } } private: dist_queue_type dist_queue; out_queue_type out_queue; in_queue_type in_queue; mutable value_type top_vertex; const Graph& g; DistanceMap distance_map; PredecessorMap predecessor_map; MinOutWeightMap min_out_weight; MinInWeightMap min_in_weight; distance_type min_distance; distance_type min_out_distance; #ifdef PBGL_ACCOUNTING std::size_t local_deletions; #endif }; /************************************************************************/ /************************************************************************ * Initialize the property map that contains the minimum incoming edge * * weight for each vertex. There are separate implementations for * * directed, bidirectional, and undirected graph. * ************************************************************************/ template<typename Graph, typename MinInWeightMap, typename WeightMap, typename Inf, typename Compare> void initialize_min_in_weights(const Graph& g, MinInWeightMap min_in_weight, WeightMap weight, Inf inf, Compare compare, directed_tag, incidence_graph_tag) { // Send minimum weights off to the owners set_property_map_role(vertex_distance, min_in_weight); BGL_FORALL_VERTICES_T(v, g, Graph) { BGL_FORALL_OUTEDGES_T(v, e, g, Graph) { if (get(weight, e) < get(min_in_weight, target(e, g))) put(min_in_weight, target(e, g), get(weight, e)); } } using boost::graph::parallel::process_group; synchronize(process_group(g)); // Replace any infinities with zeros BGL_FORALL_VERTICES_T(v, g, Graph) { if (get(min_in_weight, v) == inf) put(min_in_weight, v, 0); } } template<typename Graph, typename MinInWeightMap, typename WeightMap, typename Inf, typename Compare> void initialize_min_in_weights(const Graph& g, MinInWeightMap min_in_weight, WeightMap weight, Inf inf, Compare compare, directed_tag, bidirectional_graph_tag) { #if 0 typename property_map<Graph, vertex_local_t>::const_type local = get(vertex_local, g); // This code assumes that the properties of the in-edges are // available locally. This is not necessarily the case, so don't // do this yet. set_property_map_role(vertex_distance, min_in_weight); BGL_FORALL_VERTICES_T(v, g, Graph) { if (in_edges(v, g).first != in_edges(v, g).second) { std::cerr << "weights(" << g.distribution().global(get(local, v)) << ") = "; BGL_FORALL_INEDGES_T(v, e, g, Graph) { std::cerr << get(weight, e) << ' '; } std::cerr << std::endl; put(min_in_weight, v, *std::min_element (make_property_map_iterator(weight, in_edges(v, g).first), make_property_map_iterator(weight, in_edges(v, g).second), compare)); } else { put(min_in_weight, v, 0); } std::cerr << "miw(" << g.distribution().global(get(local, v)) << ") = " << get(min_in_weight, v) << std::endl; } #else initialize_min_in_weights(g, min_in_weight, weight, inf, compare, directed_tag(), incidence_graph_tag()); #endif } template<typename Graph, typename MinInWeightMap, typename WeightMap, typename Inf, typename Compare> inline void initialize_min_in_weights(const Graph&, MinInWeightMap, WeightMap, Inf, Compare, undirected_tag, bidirectional_graph_tag) { // In weights are the same as out weights, so do nothing } /************************************************************************/ /************************************************************************ * Initialize the property map that contains the minimum outgoing edge * * weight for each vertex. * ************************************************************************/ template<typename Graph, typename MinOutWeightMap, typename WeightMap, typename Compare> void initialize_min_out_weights(const Graph& g, MinOutWeightMap min_out_weight, WeightMap weight, Compare compare) { typedef typename property_traits<WeightMap>::value_type weight_type; BGL_FORALL_VERTICES_T(v, g, Graph) { if (out_edges(v, g).first != out_edges(v, g).second) { put(min_out_weight, v, *std::min_element (make_property_map_iterator(weight, out_edges(v, g).first), make_property_map_iterator(weight, out_edges(v, g).second), compare)); if (get(min_out_weight, v) < weight_type(0)) boost::throw_exception(negative_edge()); } } } /************************************************************************/ } // end namespace detail template<typename DistributedGraph, typename DijkstraVisitor, typename PredecessorMap, typename DistanceMap, typename WeightMap, typename IndexMap, typename ColorMap, typename Compare, typename Combine, typename DistInf, typename DistZero> void crauser_et_al_shortest_paths (const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, WeightMap weight, IndexMap index_map, ColorMap color_map, Compare compare, Combine combine, DistInf inf, DistZero zero, DijkstraVisitor vis) { #ifdef PBGL_ACCOUNTING crauser_et_al_shortest_paths_stats.deleted_vertices.clear(); crauser_et_al_shortest_paths_stats.execution_time = accounting::get_time(); #endif // Property map that stores the lowest edge weight outgoing from // each vertex. If a vertex has no out-edges, the stored weight // is zero. typedef typename property_traits<WeightMap>::value_type weight_type; typedef iterator_property_map<weight_type*, IndexMap> MinOutWeightMap; std::vector<weight_type> min_out_weights_vec(num_vertices(g), inf); MinOutWeightMap min_out_weight(&min_out_weights_vec.front(), index_map); detail::initialize_min_out_weights(g, min_out_weight, weight, compare); // Property map that stores the lowest edge weight incoming to // each vertex. For undirected graphs, this will just be a // shallow copy of the version for outgoing edges. typedef typename graph_traits<DistributedGraph>::directed_category directed_category; const bool is_undirected = is_same<directed_category, undirected_tag>::value; typedef MinOutWeightMap MinInWeightMap; std::vector<weight_type> min_in_weights_vec(is_undirected? 1 : num_vertices(g), inf); MinInWeightMap min_in_weight(&min_in_weights_vec.front(), index_map); typedef typename graph_traits<DistributedGraph>::traversal_category category; detail::initialize_min_in_weights(g, min_in_weight, weight, inf, compare, directed_category(), category()); // Initialize local portion of property maps typename graph_traits<DistributedGraph>::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { put(distance, *ui, inf); put(predecessor, *ui, *ui); } put(distance, s, zero); // Dijkstra Queue typedef detail::crauser_et_al_dijkstra_queue <DistributedGraph, Combine, Compare, IndexMap, DistanceMap, PredecessorMap, MinOutWeightMap, MinInWeightMap> Queue; Queue Q(g, combine, compare, index_map, distance, predecessor, min_out_weight, is_undirected? min_out_weight : min_in_weight); // Parallel Dijkstra visitor ::boost::detail::dijkstra_bfs_visitor< DijkstraVisitor, Queue, WeightMap, boost::parallel::caching_property_map<PredecessorMap>, boost::parallel::caching_property_map<DistanceMap>, Combine, Compare > bfs_vis(vis, Q, weight, boost::parallel::make_caching_property_map(predecessor), boost::parallel::make_caching_property_map(distance), combine, compare, zero); set_property_map_role(vertex_color, color_map); set_property_map_role(vertex_distance, distance); breadth_first_search(g, s, Q, bfs_vis, color_map); #ifdef PBGL_ACCOUNTING crauser_et_al_shortest_paths_stats.execution_time = accounting::get_time() - crauser_et_al_shortest_paths_stats.execution_time; #endif } template<typename DistributedGraph, typename PredecessorMap, typename DistanceMap, typename WeightMap> void crauser_et_al_shortest_paths (const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, WeightMap weight) { typedef typename property_traits<DistanceMap>::value_type distance_type; std::vector<default_color_type> colors(num_vertices(g), white_color); crauser_et_al_shortest_paths(g, s, predecessor, distance, weight, get(vertex_index, g), make_iterator_property_map(&colors[0], get(vertex_index, g)), std::less<distance_type>(), closed_plus<distance_type>(), (std::numeric_limits<distance_type>::max)(), distance_type(), dijkstra_visitor<>()); } template<typename DistributedGraph, typename PredecessorMap, typename DistanceMap> void crauser_et_al_shortest_paths (const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance) { crauser_et_al_shortest_paths(g, s, predecessor, distance, get(edge_weight, g)); } } // end namespace distributed #ifdef PBGL_ACCOUNTING using distributed::crauser_et_al_shortest_paths_stats; #endif using distributed::crauser_et_al_shortest_paths; } } // end namespace boost::graph #endif // BOOST_GRAPH_CRAUSER_ET_AL_SHORTEST_PATHS_HPP distributed/delta_stepping_shortest_paths.hpp 0000644 00000045727 15125521275 0015757 0 ustar 00 // Copyright (C) 2007 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine /************************************************************************** * This source file implements the Delta-stepping algorithm: * * * * Ulrich Meyer and Peter Sanders. Parallel Shortest Path for Arbitrary * * Graphs. In Proceedings from the 6th International Euro-Par * * Conference on Parallel Processing, pages 461--470, 2000. * * * * Ulrich Meyer, Peter Sanders: [Delta]-stepping: A Parallelizable * * Shortest Path Algorithm. J. Algorithms 49(1): 114-152, 2003. * * * * There are several potential optimizations we could still perform for * * this algorithm implementation: * * * * - Implement "shortcuts", which bound the number of reinsertions * * in a single bucket (to one). The computation of shortcuts looks * * expensive in a distributed-memory setting, but it could be * * ammortized over many queries. * * * * - The size of the "buckets" data structure can be bounded to * * max_edge_weight/delta buckets, if we treat the buckets as a * * circular array. * * * * - If we partition light/heavy edges ahead of time, we could improve * * relaxation performance by only iterating over the right portion * * of the out-edge list each time. * * * * - Implement a more sophisticated algorithm for guessing "delta", * * based on the shortcut-finding algorithm. * **************************************************************************/ #ifndef BOOST_GRAPH_DELTA_STEPPING_SHORTEST_PATHS_HPP #define BOOST_GRAPH_DELTA_STEPPING_SHORTEST_PATHS_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/config.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/iteration_macros.hpp> #include <limits> #include <list> #include <vector> #include <boost/graph/parallel/container_traits.hpp> #include <boost/graph/parallel/properties.hpp> #include <boost/graph/distributed/detail/dijkstra_shortest_paths.hpp> #include <utility> // for std::pair #include <functional> // for std::logical_or #include <boost/graph/parallel/algorithm.hpp> // for all_reduce #include <cassert> #include <algorithm> // for std::min, std::max #include <boost/graph/parallel/simple_trigger.hpp> #ifdef PBGL_DELTA_STEPPING_DEBUG # include <iostream> // for std::cerr #endif namespace boost { namespace graph { namespace distributed { template<typename Graph, typename PredecessorMap, typename DistanceMap, typename EdgeWeightMap> class delta_stepping_impl { typedef typename graph_traits<Graph>::vertex_descriptor Vertex; typedef typename graph_traits<Graph>::degree_size_type Degree; typedef typename property_traits<EdgeWeightMap>::value_type Dist; typedef typename boost::graph::parallel::process_group_type<Graph>::type ProcessGroup; typedef std::list<Vertex> Bucket; typedef typename Bucket::iterator BucketIterator; typedef typename std::vector<Bucket*>::size_type BucketIndex; typedef detail::dijkstra_msg_value<DistanceMap, PredecessorMap> MessageValue; enum { // Relax a remote vertex. The message contains a pair<Vertex, // MessageValue>, the first part of which is the vertex whose // tentative distance is being relaxed and the second part // contains either the new distance (if there is no predecessor // map) or a pair with the distance and predecessor. msg_relax }; public: delta_stepping_impl(const Graph& g, PredecessorMap predecessor, DistanceMap distance, EdgeWeightMap weight, Dist delta); delta_stepping_impl(const Graph& g, PredecessorMap predecessor, DistanceMap distance, EdgeWeightMap weight); void run(Vertex s); private: // Relax the edge (u, v), creating a new best path of distance x. void relax(Vertex u, Vertex v, Dist x); // Synchronize all of the processes, by receiving all messages that // have not yet been received. void synchronize(); // Handle a relax message that contains only the target and // distance. This kind of message will be received when the // predecessor map is a dummy_property_map. void handle_relax_message(Vertex v, Dist x) { relax(v, v, x); } // Handle a relax message that contains the source (predecessor), // target, and distance. This kind of message will be received when // the predecessor map is not a dummy_property_map. void handle_relax_message(Vertex v, const std::pair<Dist, Vertex>& p) { relax(p.second, v, p.first); } // Setup triggers for msg_relax messages void setup_triggers(); void handle_msg_relax(int /*source*/, int /*tag*/, const std::pair<Vertex, typename MessageValue::type>& data, trigger_receive_context) { handle_relax_message(data.first, data.second); } const Graph& g; PredecessorMap predecessor; DistanceMap distance; EdgeWeightMap weight; Dist delta; ProcessGroup pg; typename property_map<Graph, vertex_owner_t>::const_type owner; typename property_map<Graph, vertex_local_t>::const_type local; // A "property map" that contains the position of each vertex in // whatever bucket it resides in. std::vector<BucketIterator> position_in_bucket; // Bucket data structure. The ith bucket contains all local vertices // with (tentative) distance in the range [i*delta, // (i+1)*delta). std::vector<Bucket*> buckets; // This "dummy" list is used only so that we can initialize the // position_in_bucket property map with non-singular iterators. This // won't matter for most implementations of the C++ Standard // Library, but it avoids undefined behavior and allows us to run // with library "debug modes". std::list<Vertex> dummy_list; // A "property map" that states which vertices have been deleted // from the bucket in this iteration. std::vector<bool> vertex_was_deleted; }; template<typename Graph, typename PredecessorMap, typename DistanceMap, typename EdgeWeightMap> delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap>:: delta_stepping_impl(const Graph& g, PredecessorMap predecessor, DistanceMap distance, EdgeWeightMap weight, Dist delta) : g(g), predecessor(predecessor), distance(distance), weight(weight), delta(delta), pg(boost::graph::parallel::process_group_adl(g), attach_distributed_object()), owner(get(vertex_owner, g)), local(get(vertex_local, g)) { setup_triggers(); } template<typename Graph, typename PredecessorMap, typename DistanceMap, typename EdgeWeightMap> delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap>:: delta_stepping_impl(const Graph& g, PredecessorMap predecessor, DistanceMap distance, EdgeWeightMap weight) : g(g), predecessor(predecessor), distance(distance), weight(weight), pg(boost::graph::parallel::process_group_adl(g), attach_distributed_object()), owner(get(vertex_owner, g)), local(get(vertex_local, g)) { using boost::parallel::all_reduce; using boost::parallel::maximum; using std::max; // Compute the maximum edge weight and degree Dist max_edge_weight = 0; Degree max_degree = 0; BGL_FORALL_VERTICES_T(u, g, Graph) { max_degree = max BOOST_PREVENT_MACRO_SUBSTITUTION (max_degree, out_degree(u, g)); BGL_FORALL_OUTEDGES_T(u, e, g, Graph) max_edge_weight = max BOOST_PREVENT_MACRO_SUBSTITUTION (max_edge_weight, get(weight, e)); } max_edge_weight = all_reduce(pg, max_edge_weight, maximum<Dist>()); max_degree = all_reduce(pg, max_degree, maximum<Degree>()); // Take a guess at delta, based on what works well for random // graphs. delta = max_edge_weight / max_degree; if (delta == 0) delta = 1; setup_triggers(); } template<typename Graph, typename PredecessorMap, typename DistanceMap, typename EdgeWeightMap> void delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap>:: run(Vertex s) { Dist inf = (std::numeric_limits<Dist>::max)(); // None of the vertices are stored in the bucket. position_in_bucket.clear(); position_in_bucket.resize(num_vertices(g), dummy_list.end()); // None of the vertices have been deleted vertex_was_deleted.clear(); vertex_was_deleted.resize(num_vertices(g), false); // No path from s to any other vertex, yet BGL_FORALL_VERTICES_T(v, g, Graph) put(distance, v, inf); // The distance to the starting node is zero if (get(owner, s) == process_id(pg)) // Put "s" into its bucket (bucket 0) relax(s, s, 0); else // Note that we know the distance to s is zero cache(distance, s, 0); BucketIndex max_bucket = (std::numeric_limits<BucketIndex>::max)(); BucketIndex current_bucket = 0; do { // Synchronize with all of the other processes. synchronize(); // Find the next bucket that has something in it. while (current_bucket < buckets.size() && (!buckets[current_bucket] || buckets[current_bucket]->empty())) ++current_bucket; if (current_bucket >= buckets.size()) current_bucket = max_bucket; #ifdef PBGL_DELTA_STEPPING_DEBUG std::cerr << "#" << process_id(pg) << ": lowest bucket is #" << current_bucket << std::endl; #endif // Find the smallest bucket (over all processes) that has vertices // that need to be processed. using boost::parallel::all_reduce; using boost::parallel::minimum; current_bucket = all_reduce(pg, current_bucket, minimum<BucketIndex>()); if (current_bucket == max_bucket) // There are no non-empty buckets in any process; exit. break; #ifdef PBGL_DELTA_STEPPING_DEBUG if (process_id(pg) == 0) std::cerr << "Processing bucket #" << current_bucket << std::endl; #endif // Contains the set of vertices that have been deleted in the // relaxation of "light" edges. Note that we keep track of which // vertices were deleted with the property map // "vertex_was_deleted". std::vector<Vertex> deleted_vertices; // Repeatedly relax light edges bool nonempty_bucket; do { // Someone has work to do in this bucket. if (current_bucket < buckets.size() && buckets[current_bucket]) { Bucket& bucket = *buckets[current_bucket]; // For each element in the bucket while (!bucket.empty()) { Vertex u = bucket.front(); #ifdef PBGL_DELTA_STEPPING_DEBUG std::cerr << "#" << process_id(pg) << ": processing vertex " << get(vertex_global, g, u).second << "@" << get(vertex_global, g, u).first << std::endl; #endif // Remove u from the front of the bucket bucket.pop_front(); // Insert u into the set of deleted vertices, if it hasn't // been done already. if (!vertex_was_deleted[get(local, u)]) { vertex_was_deleted[get(local, u)] = true; deleted_vertices.push_back(u); } // Relax each light edge. Dist u_dist = get(distance, u); BGL_FORALL_OUTEDGES_T(u, e, g, Graph) if (get(weight, e) <= delta) // light edge relax(u, target(e, g), u_dist + get(weight, e)); } } // Synchronize with all of the other processes. synchronize(); // Is the bucket empty now? nonempty_bucket = (current_bucket < buckets.size() && buckets[current_bucket] && !buckets[current_bucket]->empty()); } while (all_reduce(pg, nonempty_bucket, std::logical_or<bool>())); // Relax heavy edges for each of the vertices that we previously // deleted. for (typename std::vector<Vertex>::iterator iter = deleted_vertices.begin(); iter != deleted_vertices.end(); ++iter) { // Relax each heavy edge. Vertex u = *iter; Dist u_dist = get(distance, u); BGL_FORALL_OUTEDGES_T(u, e, g, Graph) if (get(weight, e) > delta) // heavy edge relax(u, target(e, g), u_dist + get(weight, e)); } // Go to the next bucket: the current bucket must already be empty. ++current_bucket; } while (true); // Delete all of the buckets. for (typename std::vector<Bucket*>::iterator iter = buckets.begin(); iter != buckets.end(); ++iter) { if (*iter) { delete *iter; *iter = 0; } } } template<typename Graph, typename PredecessorMap, typename DistanceMap, typename EdgeWeightMap> void delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap>:: relax(Vertex u, Vertex v, Dist x) { #ifdef PBGL_DELTA_STEPPING_DEBUG std::cerr << "#" << process_id(pg) << ": relax(" << get(vertex_global, g, u).second << "@" << get(vertex_global, g, u).first << ", " << get(vertex_global, g, v).second << "@" << get(vertex_global, g, v).first << ", " << x << ")" << std::endl; #endif if (x < get(distance, v)) { // We're relaxing the edge to vertex v. if (get(owner, v) == process_id(pg)) { // Compute the new bucket index for v BucketIndex new_index = static_cast<BucketIndex>(x / delta); // Make sure there is enough room in the buckets data structure. if (new_index >= buckets.size()) buckets.resize(new_index + 1, 0); // Make sure that we have allocated the bucket itself. if (!buckets[new_index]) buckets[new_index] = new Bucket; if (get(distance, v) != (std::numeric_limits<Dist>::max)() && !vertex_was_deleted[get(local, v)]) { // We're moving v from an old bucket into a new one. Compute // the old index, then splice it in. BucketIndex old_index = static_cast<BucketIndex>(get(distance, v) / delta); buckets[new_index]->splice(buckets[new_index]->end(), *buckets[old_index], position_in_bucket[get(local, v)]); } else { // We're inserting v into a bucket for the first time. Put it // at the end. buckets[new_index]->push_back(v); } // v is now at the last position in the new bucket position_in_bucket[get(local, v)] = buckets[new_index]->end(); --position_in_bucket[get(local, v)]; // Update predecessor and tentative distance information put(predecessor, v, u); put(distance, v, x); } else { #ifdef PBGL_DELTA_STEPPING_DEBUG std::cerr << "#" << process_id(pg) << ": sending relax(" << get(vertex_global, g, u).second << "@" << get(vertex_global, g, u).first << ", " << get(vertex_global, g, v).second << "@" << get(vertex_global, g, v).first << ", " << x << ") to " << get(owner, v) << std::endl; #endif // The vertex is remote: send a request to the vertex's owner send(pg, get(owner, v), msg_relax, std::make_pair(v, MessageValue::create(x, u))); // Cache tentative distance information cache(distance, v, x); } } } template<typename Graph, typename PredecessorMap, typename DistanceMap, typename EdgeWeightMap> void delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap>:: synchronize() { using boost::parallel::synchronize; // Synchronize at the process group level. synchronize(pg); // Receive any relaxation request messages. // typedef typename ProcessGroup::process_id_type process_id_type; // while (optional<std::pair<process_id_type, int> > stp = probe(pg)) { // // Receive the relaxation message // assert(stp->second == msg_relax); // std::pair<Vertex, typename MessageValue::type> data; // receive(pg, stp->first, stp->second, data); // // Turn it into a "relax" call // handle_relax_message(data.first, data.second); // } } template<typename Graph, typename PredecessorMap, typename DistanceMap, typename EdgeWeightMap> void delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap>:: setup_triggers() { using boost::graph::parallel::simple_trigger; simple_trigger(pg, msg_relax, this, &delta_stepping_impl::handle_msg_relax); } template<typename Graph, typename PredecessorMap, typename DistanceMap, typename EdgeWeightMap> void delta_stepping_shortest_paths (const Graph& g, typename graph_traits<Graph>::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, EdgeWeightMap weight, typename property_traits<EdgeWeightMap>::value_type delta) { // The "distance" map needs to act like one, retrieving the default // value of infinity. set_property_map_role(vertex_distance, distance); // Construct the implementation object, which will perform all of // the actual work. delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap> impl(g, predecessor, distance, weight, delta); // Run the delta-stepping algorithm. The results will show up in // "predecessor" and "weight". impl.run(s); } template<typename Graph, typename PredecessorMap, typename DistanceMap, typename EdgeWeightMap> void delta_stepping_shortest_paths (const Graph& g, typename graph_traits<Graph>::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, EdgeWeightMap weight) { // The "distance" map needs to act like one, retrieving the default // value of infinity. set_property_map_role(vertex_distance, distance); // Construct the implementation object, which will perform all of // the actual work. delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap> impl(g, predecessor, distance, weight); // Run the delta-stepping algorithm. The results will show up in // "predecessor" and "weight". impl.run(s); } } } } // end namespace boost::graph::distributed #endif // BOOST_GRAPH_DELTA_STEPPING_SHORTEST_PATHS_HPP distributed/named_graph.hpp 0000644 00000136042 15125521275 0012057 0 ustar 00 // Copyright (C) 2007 Douglas Gregor // Copyright (C) 2007 Hartmut Kaiser // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // TODO: // - Cache (some) remote vertex names? #ifndef BOOST_GRAPH_DISTRIBUTED_NAMED_GRAPH_HPP #define BOOST_GRAPH_DISTRIBUTED_NAMED_GRAPH_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/assert.hpp> #include <boost/graph/named_graph.hpp> #include <boost/functional/hash.hpp> #include <boost/variant.hpp> #include <boost/graph/parallel/simple_trigger.hpp> #include <boost/graph/parallel/process_group.hpp> #include <boost/graph/parallel/detail/property_holders.hpp> namespace boost { namespace graph { namespace distributed { using boost::parallel::trigger_receive_context; using boost::detail::parallel::pair_with_property; /******************************************************************* * Hashed distribution of named entities * *******************************************************************/ template<typename T> struct hashed_distribution { template<typename ProcessGroup> hashed_distribution(const ProcessGroup& pg, std::size_t /*num_vertices*/ = 0) : n(num_processes(pg)) { } int operator()(const T& value) const { return hasher(value) % n; } std::size_t n; hash<T> hasher; }; /// Specialization for named graphs template <typename InDistribution, typename VertexProperty, typename VertexSize, typename ProcessGroup, typename ExtractName = typename internal_vertex_name<VertexProperty>::type> struct select_distribution { private: /// The type used to name vertices in the graph typedef typename remove_cv< typename remove_reference< typename ExtractName::result_type>::type>::type vertex_name_type; public: /** * The @c type field provides a distribution object that maps * vertex names to processors. The distribution object will be * constructed with the process group over which communication will * occur. The distribution object shall also be a function * object mapping from the type of the name to a processor number * in @c [0, @c p) (for @c p processors). By default, the mapping * function uses the @c boost::hash value of the name, modulo @c p. */ typedef typename mpl::if_<is_same<InDistribution, defaultS>, hashed_distribution<vertex_name_type>, InDistribution>::type type; /// for named graphs the default type is the same as the stored distribution /// type typedef type default_type; }; /// Specialization for non-named graphs template <typename InDistribution, typename VertexProperty, typename VertexSize, typename ProcessGroup> struct select_distribution<InDistribution, VertexProperty, VertexSize, ProcessGroup, void> { /// the distribution type stored in the graph for non-named graphs should be /// the variant_distribution type typedef typename mpl::if_<is_same<InDistribution, defaultS>, boost::parallel::variant_distribution<ProcessGroup, VertexSize>, InDistribution>::type type; /// default_type is used as the distribution functor for the /// adjacency_list, it should be parallel::block by default typedef typename mpl::if_<is_same<InDistribution, defaultS>, boost::parallel::block, type>::type default_type; }; /******************************************************************* * Named graph mixin * *******************************************************************/ /** * named_graph is a mixin that provides names for the vertices of a * graph, including a mapping from names to vertices. Graph types that * may or may not be have vertex names (depending on the properties * supplied by the user) should use maybe_named_graph. * * Template parameters: * * Graph: the graph type that derives from named_graph * * Vertex: the type of a vertex descriptor in Graph. Note: we cannot * use graph_traits here, because the Graph is not yet defined. * * VertexProperty: the type of the property stored along with the * vertex. * * ProcessGroup: the process group over which the distributed name * graph mixin will communicate. */ template<typename Graph, typename Vertex, typename Edge, typename Config> class named_graph { public: /// Messages passed within the distributed named graph enum message_kind { /** * Requests the addition of a vertex on a remote processor. The * message data is a @c vertex_name_type. */ msg_add_vertex_name, /** * Requests the addition of a vertex on a remote processor. The * message data is a @c vertex_name_type. The remote processor * will send back a @c msg_add_vertex_name_reply message * containing the vertex descriptor. */ msg_add_vertex_name_with_reply, /** * Requests the vertex descriptor corresponding to the given * vertex name. The remote process will reply with a * @c msg_find_vertex_reply message containing the answer. */ msg_find_vertex, /** * Requests the addition of an edge on a remote processor. The * data stored in these messages is a @c pair<source, target>@, * where @c source and @c target may be either names (of type @c * vertex_name_type) or vertex descriptors, depending on what * information we have locally. */ msg_add_edge_name_name, msg_add_edge_vertex_name, msg_add_edge_name_vertex, /** * These messages are identical to msg_add_edge_*_*, except that * the process actually adding the edge will send back a @c * pair<edge_descriptor,bool> */ msg_add_edge_name_name_with_reply, msg_add_edge_vertex_name_with_reply, msg_add_edge_name_vertex_with_reply, /** * Requests the addition of an edge with a property on a remote * processor. The data stored in these messages is a @c * pair<vertex_property_type, pair<source, target>>@, where @c * source and @c target may be either names (of type @c * vertex_name_type) or vertex descriptors, depending on what * information we have locally. */ msg_add_edge_name_name_with_property, msg_add_edge_vertex_name_with_property, msg_add_edge_name_vertex_with_property, /** * These messages are identical to msg_add_edge_*_*_with_property, * except that the process actually adding the edge will send back * a @c pair<edge_descriptor,bool>. */ msg_add_edge_name_name_with_reply_and_property, msg_add_edge_vertex_name_with_reply_and_property, msg_add_edge_name_vertex_with_reply_and_property }; /// The vertex descriptor type typedef Vertex vertex_descriptor; /// The edge descriptor type typedef Edge edge_descriptor; /// The vertex property type typedef typename Config::vertex_property_type vertex_property_type; /// The vertex property type typedef typename Config::edge_property_type edge_property_type; /// The type used to extract names from the property structure typedef typename internal_vertex_name<vertex_property_type>::type extract_name_type; /// The type used to name vertices in the graph typedef typename remove_cv< typename remove_reference< typename extract_name_type::result_type>::type>::type vertex_name_type; /// The type used to distribute named vertices in the graph typedef typename Config::distribution_type distribution_type; typedef typename Config::base_distribution_type base_distribution_type; /// The type used for communication in the distributed structure typedef typename Config::process_group_type process_group_type; /// Type used to identify processes typedef typename process_group_type::process_id_type process_id_type; /// a reference to this class, which is used for disambiguation of the // add_vertex function typedef named_graph named_graph_type; /// Structure returned when adding a vertex by vertex name struct lazy_add_vertex; friend struct lazy_add_vertex; /// Structure returned when adding an edge by vertex name struct lazy_add_edge; friend struct lazy_add_edge; /// Structure returned when adding an edge by vertex name with a property struct lazy_add_edge_with_property; friend struct lazy_add_edge_with_property; explicit named_graph(const process_group_type& pg); named_graph(const process_group_type& pg, const base_distribution_type& distribution); /// Set up triggers, but only for the BSP process group void setup_triggers(); /// Retrieve the derived instance Graph& derived() { return static_cast<Graph&>(*this); } const Graph& derived() const { return static_cast<const Graph&>(*this); } /// Retrieve the process group process_group_type& process_group() { return process_group_; } const process_group_type& process_group() const { return process_group_; } // Retrieve the named distribution distribution_type& named_distribution() { return distribution_; } const distribution_type& named_distribution() const { return distribution_; } /// Notify the named_graph that we have added the given vertex. This /// is a no-op. void added_vertex(Vertex) { } /// Notify the named_graph that we are removing the given /// vertex. This is a no-op. template <typename VertexIterStability> void removing_vertex(Vertex, VertexIterStability) { } /// Notify the named_graph that we are clearing the graph void clearing_graph() { } /// Retrieve the owner of a given vertex based on the properties /// associated with that vertex. This operation just returns the /// number of the local processor, adding all vertices locally. process_id_type owner_by_property(const vertex_property_type&); protected: void handle_add_vertex_name(int source, int tag, const vertex_name_type& msg, trigger_receive_context); vertex_descriptor handle_add_vertex_name_with_reply(int source, int tag, const vertex_name_type& msg, trigger_receive_context); boost::parallel::detail::untracked_pair<vertex_descriptor, bool> handle_find_vertex(int source, int tag, const vertex_name_type& msg, trigger_receive_context); template<typename U, typename V> void handle_add_edge(int source, int tag, const boost::parallel::detail::untracked_pair<U, V>& msg, trigger_receive_context); template<typename U, typename V> boost::parallel::detail::untracked_pair<edge_descriptor, bool> handle_add_edge_with_reply(int source, int tag, const boost::parallel::detail::untracked_pair<U, V>& msg, trigger_receive_context); template<typename U, typename V> void handle_add_edge_with_property (int source, int tag, const pair_with_property<U, V, edge_property_type>& msg, trigger_receive_context); template<typename U, typename V> boost::parallel::detail::untracked_pair<edge_descriptor, bool> handle_add_edge_with_reply_and_property (int source, int tag, const pair_with_property<U, V, edge_property_type>& msg, trigger_receive_context); /// The process group for this distributed data structure process_group_type process_group_; /// The distribution we will use to map names to processors distribution_type distribution_; }; /// Helper macro containing the template parameters of named_graph #define BGL_NAMED_GRAPH_PARAMS \ typename Graph, typename Vertex, typename Edge, typename Config /// Helper macro containing the named_graph<...> instantiation #define BGL_NAMED_GRAPH \ named_graph<Graph, Vertex, Edge, Config> /** * Data structure returned from add_vertex that will "lazily" add the * vertex, either when it is converted to a @c vertex_descriptor or * when the most recent copy has been destroyed. */ template<BGL_NAMED_GRAPH_PARAMS> struct BGL_NAMED_GRAPH::lazy_add_vertex { /// Construct a new lazyily-added vertex lazy_add_vertex(named_graph& self, const vertex_name_type& name) : self(self), name(name), committed(false) { } /// Transfer responsibility for adding the vertex from the source of /// the copy to the newly-constructed opbject. lazy_add_vertex(const lazy_add_vertex& other) : self(other.self), name(other.name), committed(other.committed) { other.committed = true; } /// If the vertex has not been added yet, add it ~lazy_add_vertex(); /// Add the vertex and return its descriptor. This conversion can /// only occur once, and only when this object is responsible for /// creating the vertex. operator vertex_descriptor() const { return commit(); } /// Add the vertex and return its descriptor. This can only be /// called once, and only when this object is responsible for /// creating the vertex. vertex_descriptor commit() const; protected: named_graph& self; vertex_name_type name; mutable bool committed; }; template<BGL_NAMED_GRAPH_PARAMS> BGL_NAMED_GRAPH::lazy_add_vertex::~lazy_add_vertex() { typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type; /// If this vertex has already been created or will be created by /// someone else, or if someone threw an exception, we will not /// create the vertex now. if (committed || std::uncaught_exception()) return; committed = true; process_id_type owner = self.named_distribution()(name); if (owner == process_id(self.process_group())) /// Add the vertex locally add_vertex(self.derived().base().vertex_constructor(name), self.derived()); else /// Ask the owner of the vertex to add a vertex with this name send(self.process_group(), owner, msg_add_vertex_name, name); } template<BGL_NAMED_GRAPH_PARAMS> typename BGL_NAMED_GRAPH::vertex_descriptor BGL_NAMED_GRAPH::lazy_add_vertex::commit() const { typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type; BOOST_ASSERT (!committed); committed = true; process_id_type owner = self.named_distribution()(name); if (owner == process_id(self.process_group())) /// Add the vertex locally return add_vertex(self.derived().base().vertex_constructor(name), self.derived()); else { /// Ask the owner of the vertex to add a vertex with this name vertex_descriptor result; send_oob_with_reply(self.process_group(), owner, msg_add_vertex_name_with_reply, name, result); return result; } } /** * Data structure returned from add_edge that will "lazily" add the * edge, either when it is converted to a @c * pair<edge_descriptor,bool> or when the most recent copy has been * destroyed. */ template<BGL_NAMED_GRAPH_PARAMS> struct BGL_NAMED_GRAPH::lazy_add_edge { /// The graph's edge descriptor typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor; /// Add an edge for the edge (u, v) based on vertex names lazy_add_edge(BGL_NAMED_GRAPH& self, const vertex_name_type& u_name, const vertex_name_type& v_name) : self(self), u(u_name), v(v_name), committed(false) { } /// Add an edge for the edge (u, v) based on a vertex descriptor and name lazy_add_edge(BGL_NAMED_GRAPH& self, vertex_descriptor u, const vertex_name_type& v_name) : self(self), u(u), v(v_name), committed(false) { } /// Add an edge for the edge (u, v) based on a vertex name and descriptor lazy_add_edge(BGL_NAMED_GRAPH& self, const vertex_name_type& u_name, vertex_descriptor v) : self(self), u(u_name), v(v), committed(false) { } /// Add an edge for the edge (u, v) based on vertex descriptors lazy_add_edge(BGL_NAMED_GRAPH& self, vertex_descriptor u, vertex_descriptor v) : self(self), u(u), v(v), committed(false) { } /// Copy a lazy_add_edge structure, which transfers responsibility /// for adding the edge to the newly-constructed object. lazy_add_edge(const lazy_add_edge& other) : self(other.self), u(other.u), v(other.v), committed(other.committed) { other.committed = true; } /// If the edge has not yet been added, add the edge but don't wait /// for a reply. ~lazy_add_edge(); /// Returns commit(). operator std::pair<edge_descriptor, bool>() const { return commit(); } // Add the edge. This operation will block if a remote edge is // being added. std::pair<edge_descriptor, bool> commit() const; protected: BGL_NAMED_GRAPH& self; mutable variant<vertex_descriptor, vertex_name_type> u; mutable variant<vertex_descriptor, vertex_name_type> v; mutable bool committed; private: // No copy-assignment semantics void operator=(lazy_add_edge&); }; template<BGL_NAMED_GRAPH_PARAMS> BGL_NAMED_GRAPH::lazy_add_edge::~lazy_add_edge() { using boost::parallel::detail::make_untracked_pair; /// If this edge has already been created or will be created by /// someone else, or if someone threw an exception, we will not /// create the edge now. if (committed || std::uncaught_exception()) return; committed = true; if (vertex_name_type* v_name = boost::get<vertex_name_type>(&v)) { // We haven't resolved the target vertex to a descriptor yet, so // it must not be local. Send a message to the owner of the target // of the edge. If the owner of the target does not happen to own // the source, it will resolve the target to a vertex descriptor // and pass the message along to the owner of the source. if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u)) send(self.process_group(), self.distribution_(*v_name), BGL_NAMED_GRAPH::msg_add_edge_name_name, make_untracked_pair(*u_name, *v_name)); else send(self.process_group(), self.distribution_(*v_name), BGL_NAMED_GRAPH::msg_add_edge_vertex_name, make_untracked_pair(boost::get<vertex_descriptor>(u), *v_name)); } else { if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u)) // We haven't resolved the source vertex to a descriptor yet, so // it must not be local. Send a message to the owner of the // source vertex requesting the edge addition. send(self.process_group(), self.distribution_(*u_name), BGL_NAMED_GRAPH::msg_add_edge_name_vertex, make_untracked_pair(*u_name, boost::get<vertex_descriptor>(v))); else // We have descriptors for both of the vertices, either of which // may be remote or local. Tell the owner of the source vertex // to add the edge (it may be us!). add_edge(boost::get<vertex_descriptor>(u), boost::get<vertex_descriptor>(v), self.derived()); } } template<BGL_NAMED_GRAPH_PARAMS> std::pair<typename graph_traits<Graph>::edge_descriptor, bool> BGL_NAMED_GRAPH::lazy_add_edge::commit() const { typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type; using boost::parallel::detail::make_untracked_pair; BOOST_ASSERT(!committed); committed = true; /// The result we will return, if we are sending a message to /// request that someone else add the edge. boost::parallel::detail::untracked_pair<edge_descriptor, bool> result; /// The owner of the vertex "u" process_id_type u_owner; process_id_type rank = process_id(self.process_group()); if (const vertex_name_type* u_name = boost::get<vertex_name_type>(&u)) { /// We haven't resolved the source vertex to a descriptor yet, so /// it must not be local. u_owner = self.named_distribution()(*u_name); /// Send a message to the remote vertex requesting that it add the /// edge. The message differs depending on whether we have a /// vertex name or a vertex descriptor for the target. if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v)) send_oob_with_reply(self.process_group(), u_owner, BGL_NAMED_GRAPH::msg_add_edge_name_name_with_reply, make_untracked_pair(*u_name, *v_name), result); else send_oob_with_reply(self.process_group(), u_owner, BGL_NAMED_GRAPH::msg_add_edge_name_vertex_with_reply, make_untracked_pair(*u_name, boost::get<vertex_descriptor>(v)), result); } else { /// We have resolved the source vertex to a descriptor, which may /// either be local or remote. u_owner = get(vertex_owner, self.derived(), boost::get<vertex_descriptor>(u)); if (u_owner == rank) { /// The source is local. If we need to, resolve the target vertex. if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v)) v = add_vertex(*v_name, self.derived()); /// Add the edge using vertex descriptors return add_edge(boost::get<vertex_descriptor>(u), boost::get<vertex_descriptor>(v), self.derived()); } else { /// The source is remote. Just send a message to its owner /// requesting that the owner add the new edge, either directly /// or via the derived class's add_edge function. if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v)) send_oob_with_reply (self.process_group(), u_owner, BGL_NAMED_GRAPH::msg_add_edge_vertex_name_with_reply, make_untracked_pair(boost::get<vertex_descriptor>(u), *v_name), result); else return add_edge(boost::get<vertex_descriptor>(u), boost::get<vertex_descriptor>(v), self.derived()); } } // If we get here, the edge has been added remotely and "result" // contains the result of that edge addition. return result; } /** * Data structure returned from add_edge that will "lazily" add the * edge with a property, either when it is converted to a @c * pair<edge_descriptor,bool> or when the most recent copy has been * destroyed. */ template<BGL_NAMED_GRAPH_PARAMS> struct BGL_NAMED_GRAPH::lazy_add_edge_with_property { /// The graph's edge descriptor typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor; /// The Edge property type for our graph typedef typename Config::edge_property_type edge_property_type; /// Add an edge for the edge (u, v) based on vertex names lazy_add_edge_with_property(BGL_NAMED_GRAPH& self, const vertex_name_type& u_name, const vertex_name_type& v_name, const edge_property_type& property) : self(self), u(u_name), v(v_name), property(property), committed(false) { } /// Add an edge for the edge (u, v) based on a vertex descriptor and name lazy_add_edge_with_property(BGL_NAMED_GRAPH& self, vertex_descriptor u, const vertex_name_type& v_name, const edge_property_type& property) : self(self), u(u), v(v_name), property(property), committed(false) { } /// Add an edge for the edge (u, v) based on a vertex name and descriptor lazy_add_edge_with_property(BGL_NAMED_GRAPH& self, const vertex_name_type& u_name, vertex_descriptor v, const edge_property_type& property) : self(self), u(u_name), v(v), property(property), committed(false) { } /// Add an edge for the edge (u, v) based on vertex descriptors lazy_add_edge_with_property(BGL_NAMED_GRAPH& self, vertex_descriptor u, vertex_descriptor v, const edge_property_type& property) : self(self), u(u), v(v), property(property), committed(false) { } /// Copy a lazy_add_edge_with_property structure, which transfers /// responsibility for adding the edge to the newly-constructed /// object. lazy_add_edge_with_property(const lazy_add_edge_with_property& other) : self(other.self), u(other.u), v(other.v), property(other.property), committed(other.committed) { other.committed = true; } /// If the edge has not yet been added, add the edge but don't wait /// for a reply. ~lazy_add_edge_with_property(); /// Returns commit(). operator std::pair<edge_descriptor, bool>() const { return commit(); } // Add the edge. This operation will block if a remote edge is // being added. std::pair<edge_descriptor, bool> commit() const; protected: BGL_NAMED_GRAPH& self; mutable variant<vertex_descriptor, vertex_name_type> u; mutable variant<vertex_descriptor, vertex_name_type> v; edge_property_type property; mutable bool committed; private: // No copy-assignment semantics void operator=(lazy_add_edge_with_property&); }; template<BGL_NAMED_GRAPH_PARAMS> BGL_NAMED_GRAPH::lazy_add_edge_with_property::~lazy_add_edge_with_property() { using boost::detail::parallel::make_pair_with_property; /// If this edge has already been created or will be created by /// someone else, or if someone threw an exception, we will not /// create the edge now. if (committed || std::uncaught_exception()) return; committed = true; if (vertex_name_type* v_name = boost::get<vertex_name_type>(&v)) { // We haven't resolved the target vertex to a descriptor yet, so // it must not be local. Send a message to the owner of the target // of the edge. If the owner of the target does not happen to own // the source, it will resolve the target to a vertex descriptor // and pass the message along to the owner of the source. if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u)) send(self.process_group(), self.distribution_(*v_name), BGL_NAMED_GRAPH::msg_add_edge_name_name_with_property, make_pair_with_property(*u_name, *v_name, property)); else send(self.process_group(), self.distribution_(*v_name), BGL_NAMED_GRAPH::msg_add_edge_vertex_name_with_property, make_pair_with_property(boost::get<vertex_descriptor>(u), *v_name, property)); } else { if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u)) // We haven't resolved the source vertex to a descriptor yet, so // it must not be local. Send a message to the owner of the // source vertex requesting the edge addition. send(self.process_group(), self.distribution_(*u_name), BGL_NAMED_GRAPH::msg_add_edge_name_vertex_with_property, make_pair_with_property(*u_name, boost::get<vertex_descriptor>(v), property)); else // We have descriptors for both of the vertices, either of which // may be remote or local. Tell the owner of the source vertex // to add the edge (it may be us!). add_edge(boost::get<vertex_descriptor>(u), boost::get<vertex_descriptor>(v), property, self.derived()); } } template<BGL_NAMED_GRAPH_PARAMS> std::pair<typename graph_traits<Graph>::edge_descriptor, bool> BGL_NAMED_GRAPH::lazy_add_edge_with_property::commit() const { using boost::detail::parallel::make_pair_with_property; typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type; BOOST_ASSERT(!committed); committed = true; /// The result we will return, if we are sending a message to /// request that someone else add the edge. boost::parallel::detail::untracked_pair<edge_descriptor, bool> result; /// The owner of the vertex "u" process_id_type u_owner; process_id_type rank = process_id(self.process_group()); if (const vertex_name_type* u_name = boost::get<vertex_name_type>(&u)) { /// We haven't resolved the source vertex to a descriptor yet, so /// it must not be local. u_owner = self.named_distribution()(*u_name); /// Send a message to the remote vertex requesting that it add the /// edge. The message differs depending on whether we have a /// vertex name or a vertex descriptor for the target. if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v)) send_oob_with_reply (self.process_group(), u_owner, BGL_NAMED_GRAPH::msg_add_edge_name_name_with_reply_and_property, make_pair_with_property(*u_name, *v_name, property), result); else send_oob_with_reply (self.process_group(), u_owner, BGL_NAMED_GRAPH::msg_add_edge_name_vertex_with_reply_and_property, make_pair_with_property(*u_name, boost::get<vertex_descriptor>(v), property), result); } else { /// We have resolved the source vertex to a descriptor, which may /// either be local or remote. u_owner = get(vertex_owner, self.derived(), boost::get<vertex_descriptor>(u)); if (u_owner == rank) { /// The source is local. If we need to, resolve the target vertex. if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v)) v = add_vertex(*v_name, self.derived()); /// Add the edge using vertex descriptors return add_edge(boost::get<vertex_descriptor>(u), boost::get<vertex_descriptor>(v), property, self.derived()); } else { /// The source is remote. Just send a message to its owner /// requesting that the owner add the new edge, either directly /// or via the derived class's add_edge function. if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v)) send_oob_with_reply (self.process_group(), u_owner, BGL_NAMED_GRAPH::msg_add_edge_vertex_name_with_reply_and_property, make_pair_with_property(boost::get<vertex_descriptor>(u), *v_name, property), result); else return add_edge(boost::get<vertex_descriptor>(u), boost::get<vertex_descriptor>(v), property, self.derived()); } } // If we get here, the edge has been added remotely and "result" // contains the result of that edge addition. return result; } /// Construct the named_graph with a particular process group template<BGL_NAMED_GRAPH_PARAMS> BGL_NAMED_GRAPH::named_graph(const process_group_type& pg) : process_group_(pg, boost::parallel::attach_distributed_object()), distribution_(pg) { setup_triggers(); } /// Construct the named_graph mixin with a particular process group /// and distribution function template<BGL_NAMED_GRAPH_PARAMS> BGL_NAMED_GRAPH::named_graph(const process_group_type& pg, const base_distribution_type& distribution) : process_group_(pg, boost::parallel::attach_distributed_object()), distribution_(pg, distribution) { setup_triggers(); } template<BGL_NAMED_GRAPH_PARAMS> void BGL_NAMED_GRAPH::setup_triggers() { using boost::graph::parallel::simple_trigger; simple_trigger(process_group_, msg_add_vertex_name, this, &named_graph::handle_add_vertex_name); simple_trigger(process_group_, msg_add_vertex_name_with_reply, this, &named_graph::handle_add_vertex_name_with_reply); simple_trigger(process_group_, msg_find_vertex, this, &named_graph::handle_find_vertex); simple_trigger(process_group_, msg_add_edge_name_name, this, &named_graph::template handle_add_edge<vertex_name_type, vertex_name_type>); simple_trigger(process_group_, msg_add_edge_name_name_with_reply, this, &named_graph::template handle_add_edge_with_reply <vertex_name_type, vertex_name_type>); simple_trigger(process_group_, msg_add_edge_name_vertex, this, &named_graph::template handle_add_edge<vertex_name_type, vertex_descriptor>); simple_trigger(process_group_, msg_add_edge_name_vertex_with_reply, this, &named_graph::template handle_add_edge_with_reply <vertex_name_type, vertex_descriptor>); simple_trigger(process_group_, msg_add_edge_vertex_name, this, &named_graph::template handle_add_edge<vertex_descriptor, vertex_name_type>); simple_trigger(process_group_, msg_add_edge_vertex_name_with_reply, this, &named_graph::template handle_add_edge_with_reply <vertex_descriptor, vertex_name_type>); simple_trigger(process_group_, msg_add_edge_name_name_with_property, this, &named_graph:: template handle_add_edge_with_property<vertex_name_type, vertex_name_type>); simple_trigger(process_group_, msg_add_edge_name_name_with_reply_and_property, this, &named_graph::template handle_add_edge_with_reply_and_property <vertex_name_type, vertex_name_type>); simple_trigger(process_group_, msg_add_edge_name_vertex_with_property, this, &named_graph:: template handle_add_edge_with_property<vertex_name_type, vertex_descriptor>); simple_trigger(process_group_, msg_add_edge_name_vertex_with_reply_and_property, this, &named_graph::template handle_add_edge_with_reply_and_property <vertex_name_type, vertex_descriptor>); simple_trigger(process_group_, msg_add_edge_vertex_name_with_property, this, &named_graph:: template handle_add_edge_with_property<vertex_descriptor, vertex_name_type>); simple_trigger(process_group_, msg_add_edge_vertex_name_with_reply_and_property, this, &named_graph::template handle_add_edge_with_reply_and_property <vertex_descriptor, vertex_name_type>); } /// Retrieve the vertex associated with the given name template<BGL_NAMED_GRAPH_PARAMS> optional<Vertex> find_vertex(typename BGL_NAMED_GRAPH::vertex_name_type const& name, const BGL_NAMED_GRAPH& g) { typedef typename Graph::local_vertex_descriptor local_vertex_descriptor; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; // Determine the owner of this name typename BGL_NAMED_GRAPH::process_id_type owner = g.named_distribution()(name); if (owner == process_id(g.process_group())) { // The vertex is local, so search for a mapping here optional<local_vertex_descriptor> result = find_vertex(name, g.derived().base()); if (result) return Vertex(owner, *result); else return optional<Vertex>(); } else { // Ask the ownering process for the name of this vertex boost::parallel::detail::untracked_pair<vertex_descriptor, bool> result; send_oob_with_reply(g.process_group(), owner, BGL_NAMED_GRAPH::msg_find_vertex, name, result); if (result.second) return result.first; else return optional<Vertex>(); } } /// meta-function helping in figuring out if the given VertextProerty belongs to /// a named graph template<typename VertexProperty> struct not_is_named_graph : is_same<typename internal_vertex_name<VertexProperty>::type, void> {}; /// Retrieve the vertex associated with the given name template<typename Graph> typename Graph::named_graph_type::lazy_add_vertex add_vertex(typename Graph::vertex_name_type const& name, Graph& g, typename disable_if< not_is_named_graph<typename Graph::vertex_property_type>, void*>::type = 0) { return typename Graph::named_graph_type::lazy_add_vertex(g, name); } /// Add an edge using vertex names to refer to the vertices template<BGL_NAMED_GRAPH_PARAMS> typename BGL_NAMED_GRAPH::lazy_add_edge add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name, typename BGL_NAMED_GRAPH::vertex_name_type const& v_name, BGL_NAMED_GRAPH& g) { typedef typename BGL_NAMED_GRAPH::lazy_add_edge lazy_add_edge; typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type; process_id_type rank = process_id(g.process_group()); process_id_type u_owner = g.named_distribution()(u_name); process_id_type v_owner = g.named_distribution()(v_name); // Resolve local vertex names before building the "lazy" edge // addition structure. if (u_owner == rank && v_owner == rank) return lazy_add_edge(g, add_vertex(u_name, g), add_vertex(v_name, g)); else if (u_owner == rank && v_owner != rank) return lazy_add_edge(g, add_vertex(u_name, g), v_name); else if (u_owner != rank && v_owner == rank) return lazy_add_edge(g, u_name, add_vertex(v_name, g)); else return lazy_add_edge(g, u_name, v_name); } template<BGL_NAMED_GRAPH_PARAMS> typename BGL_NAMED_GRAPH::lazy_add_edge add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name, typename BGL_NAMED_GRAPH::vertex_descriptor const& v, BGL_NAMED_GRAPH& g) { // Resolve local vertex names before building the "lazy" edge // addition structure. typedef typename BGL_NAMED_GRAPH::lazy_add_edge lazy_add_edge; if (g.named_distribution()(u_name) == process_id(g.process_group())) return lazy_add_edge(g, add_vertex(u_name, g), v); else return lazy_add_edge(g, u_name, v); } template<BGL_NAMED_GRAPH_PARAMS> typename BGL_NAMED_GRAPH::lazy_add_edge add_edge(typename BGL_NAMED_GRAPH::vertex_descriptor const& u, typename BGL_NAMED_GRAPH::vertex_name_type const& v_name, BGL_NAMED_GRAPH& g) { // Resolve local vertex names before building the "lazy" edge // addition structure. typedef typename BGL_NAMED_GRAPH::lazy_add_edge lazy_add_edge; if (g.named_distribution()(v_name) == process_id(g.process_group())) return lazy_add_edge(g, u, add_vertex(v_name, g)); else return lazy_add_edge(g, u, v_name); } /// Add an edge using vertex names to refer to the vertices template<BGL_NAMED_GRAPH_PARAMS> typename BGL_NAMED_GRAPH::lazy_add_edge_with_property add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name, typename BGL_NAMED_GRAPH::vertex_name_type const& v_name, typename Graph::edge_property_type const& property, BGL_NAMED_GRAPH& g) { typedef typename BGL_NAMED_GRAPH::lazy_add_edge_with_property lazy_add_edge; typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type; process_id_type rank = process_id(g.process_group()); process_id_type u_owner = g.named_distribution()(u_name); process_id_type v_owner = g.named_distribution()(v_name); // Resolve local vertex names before building the "lazy" edge // addition structure. if (u_owner == rank && v_owner == rank) return lazy_add_edge(g, add_vertex(u_name, g), add_vertex(v_name, g), property); else if (u_owner == rank && v_owner != rank) return lazy_add_edge(g, add_vertex(u_name, g), v_name, property); else if (u_owner != rank && v_owner == rank) return lazy_add_edge(g, u_name, add_vertex(v_name, g), property); else return lazy_add_edge(g, u_name, v_name, property); } template<BGL_NAMED_GRAPH_PARAMS> typename BGL_NAMED_GRAPH::lazy_add_edge_with_property add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name, typename BGL_NAMED_GRAPH::vertex_descriptor const& v, typename Graph::edge_property_type const& property, BGL_NAMED_GRAPH& g) { // Resolve local vertex names before building the "lazy" edge // addition structure. typedef typename BGL_NAMED_GRAPH::lazy_add_edge_with_property lazy_add_edge; if (g.named_distribution()(u_name) == process_id(g.process_group())) return lazy_add_edge(g, add_vertex(u_name, g), v, property); else return lazy_add_edge(g, u_name, v, property); } template<BGL_NAMED_GRAPH_PARAMS> typename BGL_NAMED_GRAPH::lazy_add_edge_with_property add_edge(typename BGL_NAMED_GRAPH::vertex_descriptor const& u, typename BGL_NAMED_GRAPH::vertex_name_type const& v_name, typename Graph::edge_property_type const& property, BGL_NAMED_GRAPH& g) { // Resolve local vertex names before building the "lazy" edge // addition structure. typedef typename BGL_NAMED_GRAPH::lazy_add_edge_with_property lazy_add_edge; if (g.named_distribution()(v_name) == process_id(g.process_group())) return lazy_add_edge(g, u, add_vertex(v_name, g), property); else return lazy_add_edge(g, u, v_name, property); } template<BGL_NAMED_GRAPH_PARAMS> typename BGL_NAMED_GRAPH::process_id_type BGL_NAMED_GRAPH::owner_by_property(const vertex_property_type& property) { return distribution_(derived().base().extract_name(property)); } /******************************************************************* * Message handlers * *******************************************************************/ template<BGL_NAMED_GRAPH_PARAMS> void BGL_NAMED_GRAPH:: handle_add_vertex_name(int /*source*/, int /*tag*/, const vertex_name_type& msg, trigger_receive_context) { add_vertex(msg, derived()); } template<BGL_NAMED_GRAPH_PARAMS> typename BGL_NAMED_GRAPH::vertex_descriptor BGL_NAMED_GRAPH:: handle_add_vertex_name_with_reply(int source, int /*tag*/, const vertex_name_type& msg, trigger_receive_context) { return add_vertex(msg, derived()); } template<BGL_NAMED_GRAPH_PARAMS> boost::parallel::detail::untracked_pair<typename BGL_NAMED_GRAPH::vertex_descriptor, bool> BGL_NAMED_GRAPH:: handle_find_vertex(int source, int /*tag*/, const vertex_name_type& msg, trigger_receive_context) { using boost::parallel::detail::make_untracked_pair; optional<vertex_descriptor> v = find_vertex(msg, derived()); if (v) return make_untracked_pair(*v, true); else return make_untracked_pair(graph_traits<Graph>::null_vertex(), false); } template<BGL_NAMED_GRAPH_PARAMS> template<typename U, typename V> void BGL_NAMED_GRAPH:: handle_add_edge(int source, int /*tag*/, const boost::parallel::detail::untracked_pair<U, V>& msg, trigger_receive_context) { add_edge(msg.first, msg.second, derived()); } template<BGL_NAMED_GRAPH_PARAMS> template<typename U, typename V> boost::parallel::detail::untracked_pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool> BGL_NAMED_GRAPH:: handle_add_edge_with_reply(int source, int /*tag*/, const boost::parallel::detail::untracked_pair<U, V>& msg, trigger_receive_context) { std::pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool> p = add_edge(msg.first, msg.second, derived()); return p; } template<BGL_NAMED_GRAPH_PARAMS> template<typename U, typename V> void BGL_NAMED_GRAPH:: handle_add_edge_with_property (int source, int tag, const pair_with_property<U, V, edge_property_type>& msg, trigger_receive_context) { add_edge(msg.first, msg.second, msg.get_property(), derived()); } template<BGL_NAMED_GRAPH_PARAMS> template<typename U, typename V> boost::parallel::detail::untracked_pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool> BGL_NAMED_GRAPH:: handle_add_edge_with_reply_and_property (int source, int tag, const pair_with_property<U, V, edge_property_type>& msg, trigger_receive_context) { std:: pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool> p = add_edge(msg.first, msg.second, msg.get_property(), derived()); return p; } #undef BGL_NAMED_GRAPH #undef BGL_NAMED_GRAPH_PARAMS /******************************************************************* * Maybe named graph mixin * *******************************************************************/ /** * A graph mixin that can provide a mapping from names to vertices, * and use that mapping to simplify creation and manipulation of * graphs. */ template<typename Graph, typename Vertex, typename Edge, typename Config, typename ExtractName = typename internal_vertex_name<typename Config::vertex_property_type>::type> struct maybe_named_graph : public named_graph<Graph, Vertex, Edge, Config> { private: typedef named_graph<Graph, Vertex, Edge, Config> inherited; typedef typename Config::process_group_type process_group_type; public: /// The type used to distribute named vertices in the graph typedef typename Config::distribution_type distribution_type; typedef typename Config::base_distribution_type base_distribution_type; explicit maybe_named_graph(const process_group_type& pg) : inherited(pg) { } maybe_named_graph(const process_group_type& pg, const base_distribution_type& distribution) : inherited(pg, distribution) { } distribution_type& distribution() { return this->distribution_; } const distribution_type& distribution() const { return this->distribution_; } }; /** * A graph mixin that can provide a mapping from names to vertices, * and use that mapping to simplify creation and manipulation of * graphs. This partial specialization turns off this functionality * when the @c VertexProperty does not have an internal vertex name. */ template<typename Graph, typename Vertex, typename Edge, typename Config> struct maybe_named_graph<Graph, Vertex, Edge, Config, void> { private: typedef typename Config::process_group_type process_group_type; typedef typename Config::vertex_property_type vertex_property_type; public: typedef typename process_group_type::process_id_type process_id_type; /// The type used to distribute named vertices in the graph typedef typename Config::distribution_type distribution_type; typedef typename Config::base_distribution_type base_distribution_type; explicit maybe_named_graph(const process_group_type&) { } maybe_named_graph(const process_group_type& pg, const base_distribution_type& distribution) : distribution_(pg, distribution) { } /// Notify the named_graph that we have added the given vertex. This /// is a no-op. void added_vertex(Vertex) { } /// Notify the named_graph that we are removing the given /// vertex. This is a no-op. template <typename VertexIterStability> void removing_vertex(Vertex, VertexIterStability) { } /// Notify the named_graph that we are clearing the graph void clearing_graph() { } /// Retrieve the owner of a given vertex based on the properties /// associated with that vertex. This operation just returns the /// number of the local processor, adding all vertices locally. process_id_type owner_by_property(const vertex_property_type&) { return process_id(pg); } distribution_type& distribution() { return distribution_; } const distribution_type& distribution() const { return distribution_; } protected: /// The process group of the graph process_group_type pg; /// The distribution used for the graph distribution_type distribution_; }; } } } // end namespace boost::graph::distributed #endif // BOOST_GRAPH_DISTRIBUTED_NAMED_GRAPH_HPP distributed/dijkstra_shortest_paths.hpp 0000644 00000021017 15125521275 0014552 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_PARALLEL_DIJKSTRA_HPP #define BOOST_GRAPH_PARALLEL_DIJKSTRA_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/dijkstra_shortest_paths.hpp> #include <boost/graph/overloading.hpp> #include <boost/graph/distributed/concepts.hpp> #include <boost/graph/parallel/properties.hpp> #include <boost/graph/distributed/crauser_et_al_shortest_paths.hpp> #include <boost/graph/distributed/eager_dijkstra_shortest_paths.hpp> namespace boost { namespace graph { namespace detail { template<typename Lookahead> struct parallel_dijkstra_impl2 { template<typename DistributedGraph, typename DijkstraVisitor, typename PredecessorMap, typename DistanceMap, typename WeightMap, typename IndexMap, typename ColorMap, typename Compare, typename Combine, typename DistInf, typename DistZero> static void run(const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, typename property_traits<DistanceMap>::value_type lookahead, WeightMap weight, IndexMap index_map, ColorMap color_map, Compare compare, Combine combine, DistInf inf, DistZero zero, DijkstraVisitor vis) { eager_dijkstra_shortest_paths(g, s, predecessor, distance, lookahead, weight, index_map, color_map, compare, combine, inf, zero, vis); } }; template<> struct parallel_dijkstra_impl2< ::boost::param_not_found > { template<typename DistributedGraph, typename DijkstraVisitor, typename PredecessorMap, typename DistanceMap, typename WeightMap, typename IndexMap, typename ColorMap, typename Compare, typename Combine, typename DistInf, typename DistZero> static void run(const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, ::boost::param_not_found, WeightMap weight, IndexMap index_map, ColorMap color_map, Compare compare, Combine combine, DistInf inf, DistZero zero, DijkstraVisitor vis) { crauser_et_al_shortest_paths(g, s, predecessor, distance, weight, index_map, color_map, compare, combine, inf, zero, vis); } }; template<typename ColorMap> struct parallel_dijkstra_impl { template<typename DistributedGraph, typename DijkstraVisitor, typename PredecessorMap, typename DistanceMap, typename Lookahead, typename WeightMap, typename IndexMap, typename Compare, typename Combine, typename DistInf, typename DistZero> static void run(const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, Lookahead lookahead, WeightMap weight, IndexMap index_map, ColorMap color_map, Compare compare, Combine combine, DistInf inf, DistZero zero, DijkstraVisitor vis) { graph::detail::parallel_dijkstra_impl2<Lookahead> ::run(g, s, predecessor, distance, lookahead, weight, index_map, color_map, compare, combine, inf, zero, vis); } }; template<> struct parallel_dijkstra_impl< ::boost::param_not_found > { private: template<typename DistributedGraph, typename DijkstraVisitor, typename PredecessorMap, typename DistanceMap, typename Lookahead, typename WeightMap, typename IndexMap, typename ColorMap, typename Compare, typename Combine, typename DistInf, typename DistZero> static void run_impl(const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, Lookahead lookahead, WeightMap weight, IndexMap index_map, ColorMap color_map, Compare compare, Combine combine, DistInf inf, DistZero zero, DijkstraVisitor vis) { BGL_FORALL_VERTICES_T(u, g, DistributedGraph) BGL_FORALL_OUTEDGES_T(u, e, g, DistributedGraph) local_put(color_map, target(e, g), white_color); graph::detail::parallel_dijkstra_impl2<Lookahead> ::run(g, s, predecessor, distance, lookahead, weight, index_map, color_map, compare, combine, inf, zero, vis); } public: template<typename DistributedGraph, typename DijkstraVisitor, typename PredecessorMap, typename DistanceMap, typename Lookahead, typename WeightMap, typename IndexMap, typename Compare, typename Combine, typename DistInf, typename DistZero> static void run(const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, Lookahead lookahead, WeightMap weight, IndexMap index_map, ::boost::param_not_found, Compare compare, Combine combine, DistInf inf, DistZero zero, DijkstraVisitor vis) { typedef typename graph_traits<DistributedGraph>::vertices_size_type vertices_size_type; vertices_size_type n = num_vertices(g); std::vector<default_color_type> colors(n, white_color); run_impl(g, s, predecessor, distance, lookahead, weight, index_map, make_iterator_property_map(colors.begin(), index_map), compare, combine, inf, zero, vis); } }; } } // end namespace graph::detail /** Dijkstra's single-source shortest paths algorithm for distributed * graphs. * * Also implements the heuristics of: * * Andreas Crauser, Kurt Mehlhorn, Ulrich Meyer, and Peter * Sanders. A Parallelization of Dijkstra's Shortest Path * Algorithm. In Lubos Brim, Jozef Gruska, and Jiri Zlatuska, * editors, Mathematical Foundations of Computer Science (MFCS), * volume 1450 of Lecture Notes in Computer Science, pages * 722--731, 1998. Springer. */ template<typename DistributedGraph, typename DijkstraVisitor, typename PredecessorMap, typename DistanceMap, typename WeightMap, typename IndexMap, typename Compare, typename Combine, typename DistInf, typename DistZero, typename T, typename Tag, typename Base> inline void dijkstra_shortest_paths (const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, WeightMap weight, IndexMap index_map, Compare compare, Combine combine, DistInf inf, DistZero zero, DijkstraVisitor vis, const bgl_named_params<T, Tag, Base>& params BOOST_GRAPH_ENABLE_IF_MODELS_PARM(DistributedGraph,distributed_graph_tag)) { typedef typename graph_traits<DistributedGraph>::vertices_size_type vertices_size_type; // Build a distributed property map for vertex colors, if we need it bool use_default_color_map = is_default_param(get_param(params, vertex_color)); vertices_size_type n = use_default_color_map? num_vertices(g) : 1; std::vector<default_color_type> color(n, white_color); typedef iterator_property_map<std::vector<default_color_type>::iterator, IndexMap> DefColorMap; DefColorMap color_map(color.begin(), index_map); typedef typename get_param_type< vertex_color_t, bgl_named_params<T, Tag, Base> >::type color_map_type; graph::detail::parallel_dijkstra_impl<color_map_type> ::run(g, s, predecessor, distance, get_param(params, lookahead_t()), weight, index_map, get_param(params, vertex_color), compare, combine, inf, zero, vis); } } // end namespace boost #endif // BOOST_GRAPH_PARALLEL_DIJKSTRA_HPP distributed/queue.hpp 0000644 00000024011 15125521275 0010726 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_DISTRIBUTED_QUEUE_HPP #define BOOST_GRAPH_DISTRIBUTED_QUEUE_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/parallel/process_group.hpp> #include <boost/optional.hpp> #include <boost/shared_ptr.hpp> #include <vector> namespace boost { namespace graph { namespace distributed { /// A unary predicate that always returns "true". struct always_push { template<typename T> bool operator()(const T&) const { return true; } }; /** A distributed queue adaptor. * * Class template @c distributed_queue implements a distributed queue * across a process group. The distributed queue is an adaptor over an * existing (local) queue, which must model the @ref Buffer * concept. Each process stores a distinct copy of the local queue, * from which it draws or removes elements via the @ref pop and @ref * top members. * * The value type of the local queue must be a model of the @ref * GlobalDescriptor concept. The @ref push operation of the * distributed queue passes (via a message) the value to its owning * processor. Thus, the elements within a particular local queue are * guaranteed to have the process owning that local queue as an owner. * * Synchronization of distributed queues occurs in the @ref empty and * @ref size functions, which will only return "empty" values (true or * 0, respectively) when the entire distributed queue is empty. If the * local queue is empty but the distributed queue is not, the * operation will block until either condition changes. When the @ref * size function of a nonempty queue returns, it returns the size of * the local queue. These semantics were selected so that sequential * code that processes elements in the queue via the following idiom * can be parallelized via introduction of a distributed queue: * * distributed_queue<...> Q; * Q.push(x); * while (!Q.empty()) { * // do something, that may push a value onto Q * } * * In the parallel version, the initial @ref push operation will place * the value @c x onto its owner's queue. All processes will * synchronize at the call to empty, and only the process owning @c x * will be allowed to execute the loop (@ref Q.empty() returns * false). This iteration may in turn push values onto other remote * queues, so when that process finishes execution of the loop body * and all processes synchronize again in @ref empty, more processes * may have nonempty local queues to execute. Once all local queues * are empty, @ref Q.empty() returns @c false for all processes. * * The distributed queue can receive messages at two different times: * during synchronization and when polling @ref empty. Messages are * always received during synchronization, to ensure that accurate * local queue sizes can be determines. However, whether @ref empty * should poll for messages is specified as an option to the * constructor. Polling may be desired when the order in which * elements in the queue are processed is not important, because it * permits fewer synchronization steps and less communication * overhead. However, when more strict ordering guarantees are * required, polling may be semantically incorrect. By disabling * polling, one ensures that parallel execution using the idiom above * will not process an element at a later "level" before an earlier * "level". * * The distributed queue nearly models the @ref Buffer * concept. However, the @ref push routine does not necessarily * increase the result of @c size() by one (although the size of the * global queue does increase by one). */ template<typename ProcessGroup, typename OwnerMap, typename Buffer, typename UnaryPredicate = always_push> class distributed_queue { typedef distributed_queue self_type; enum { /** Message indicating a remote push. The message contains a * single value x of type value_type that is to be pushed on the * receiver's queue. */ msg_push, /** Push many elements at once. */ msg_multipush }; public: typedef ProcessGroup process_group_type; typedef Buffer buffer_type; typedef typename buffer_type::value_type value_type; typedef typename buffer_type::size_type size_type; /** Construct a new distributed queue. * * Build a new distributed queue that communicates over the given @p * process_group, whose local queue is initialized via @p buffer and * which may or may not poll for messages. */ explicit distributed_queue(const ProcessGroup& process_group, const OwnerMap& owner, const Buffer& buffer, bool polling = false); /** Construct a new distributed queue. * * Build a new distributed queue that communicates over the given @p * process_group, whose local queue is initialized via @p buffer and * which may or may not poll for messages. */ explicit distributed_queue(const ProcessGroup& process_group = ProcessGroup(), const OwnerMap& owner = OwnerMap(), const Buffer& buffer = Buffer(), const UnaryPredicate& pred = UnaryPredicate(), bool polling = false); /** Construct a new distributed queue. * * Build a new distributed queue that communicates over the given @p * process_group, whose local queue is default-initalized and which * may or may not poll for messages. */ distributed_queue(const ProcessGroup& process_group, const OwnerMap& owner, const UnaryPredicate& pred, bool polling = false); /** Virtual destructor required with virtual functions. * */ virtual ~distributed_queue() {} /** Push an element onto the distributed queue. * * The element will be sent to its owner process to be added to that * process's local queue. If polling is enabled for this queue and * the owner process is the current process, the value will be * immediately pushed onto the local queue. * * Complexity: O(1) messages of size O(sizeof(value_type)) will be * transmitted. */ void push(const value_type& x); /** Pop an element off the local queue. * * @p @c !empty() */ void pop() { buffer.pop(); } /** * Return the element at the top of the local queue. * * @p @c !empty() */ value_type& top() { return buffer.top(); } /** * \overload */ const value_type& top() const { return buffer.top(); } /** Determine if the queue is empty. * * When the local queue is nonempty, returns @c true. If the local * queue is empty, synchronizes with all other processes in the * process group until either (1) the local queue is nonempty * (returns @c true) (2) the entire distributed queue is empty * (returns @c false). */ bool empty() const; /** Determine the size of the local queue. * * The behavior of this routine is equivalent to the behavior of * @ref empty, except that when @ref empty returns true this * function returns the size of the local queue and when @ref empty * returns false this function returns zero. */ size_type size() const; // private: /** Synchronize the distributed queue and determine if all queues * are empty. * * \returns \c true when all local queues are empty, or false if at least * one of the local queues is nonempty. * Defined as virtual for derived classes like depth_limited_distributed_queue. */ virtual bool do_synchronize() const; private: // Setup triggers void setup_triggers(); // Message handlers void handle_push(int source, int tag, const value_type& value, trigger_receive_context); void handle_multipush(int source, int tag, const std::vector<value_type>& values, trigger_receive_context); mutable ProcessGroup process_group; OwnerMap owner; mutable Buffer buffer; UnaryPredicate pred; bool polling; typedef std::vector<value_type> outgoing_buffer_t; typedef std::vector<outgoing_buffer_t> outgoing_buffers_t; shared_ptr<outgoing_buffers_t> outgoing_buffers; }; /// Helper macro containing the normal names for the template /// parameters to distributed_queue. #define BOOST_DISTRIBUTED_QUEUE_PARMS \ typename ProcessGroup, typename OwnerMap, typename Buffer, \ typename UnaryPredicate /// Helper macro containing the normal template-id for /// distributed_queue. #define BOOST_DISTRIBUTED_QUEUE_TYPE \ distributed_queue<ProcessGroup, OwnerMap, Buffer, UnaryPredicate> /** Synchronize all processes involved with the given distributed queue. * * This function will synchronize all of the local queues for a given * distributed queue, by ensuring that no additional messages are in * transit. It is rarely required by the user, because most * synchronization of distributed queues occurs via the @c empty or @c * size methods. */ template<BOOST_DISTRIBUTED_QUEUE_PARMS> inline void synchronize(const BOOST_DISTRIBUTED_QUEUE_TYPE& Q) { Q.do_synchronize(); } /// Construct a new distributed queue. template<typename ProcessGroup, typename OwnerMap, typename Buffer> inline distributed_queue<ProcessGroup, OwnerMap, Buffer> make_distributed_queue(const ProcessGroup& process_group, const OwnerMap& owner, const Buffer& buffer, bool polling = false) { typedef distributed_queue<ProcessGroup, OwnerMap, Buffer> result_type; return result_type(process_group, owner, buffer, polling); } } } } // end namespace boost::graph::distributed #include <boost/graph/distributed/detail/queue.ipp> #undef BOOST_DISTRIBUTED_QUEUE_TYPE #undef BOOST_DISTRIBUTED_QUEUE_PARMS #endif // BOOST_GRAPH_DISTRIBUTED_QUEUE_HPP distributed/detail/queue.ipp 0000644 00000011765 15125521275 0012205 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #include <boost/optional.hpp> #include <cassert> #include <boost/graph/parallel/algorithm.hpp> #include <boost/graph/parallel/process_group.hpp> #include <functional> #include <algorithm> #include <boost/graph/parallel/simple_trigger.hpp> #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif namespace boost { namespace graph { namespace distributed { template<BOOST_DISTRIBUTED_QUEUE_PARMS> BOOST_DISTRIBUTED_QUEUE_TYPE:: distributed_queue(const ProcessGroup& process_group, const OwnerMap& owner, const Buffer& buffer, bool polling) : process_group(process_group, attach_distributed_object()), owner(owner), buffer(buffer), polling(polling) { if (!polling) outgoing_buffers.reset( new outgoing_buffers_t(num_processes(process_group))); setup_triggers(); } template<BOOST_DISTRIBUTED_QUEUE_PARMS> BOOST_DISTRIBUTED_QUEUE_TYPE:: distributed_queue(const ProcessGroup& process_group, const OwnerMap& owner, const Buffer& buffer, const UnaryPredicate& pred, bool polling) : process_group(process_group, attach_distributed_object()), owner(owner), buffer(buffer), pred(pred), polling(polling) { if (!polling) outgoing_buffers.reset( new outgoing_buffers_t(num_processes(process_group))); setup_triggers(); } template<BOOST_DISTRIBUTED_QUEUE_PARMS> BOOST_DISTRIBUTED_QUEUE_TYPE:: distributed_queue(const ProcessGroup& process_group, const OwnerMap& owner, const UnaryPredicate& pred, bool polling) : process_group(process_group, attach_distributed_object()), owner(owner), pred(pred), polling(polling) { if (!polling) outgoing_buffers.reset( new outgoing_buffers_t(num_processes(process_group))); setup_triggers(); } template<BOOST_DISTRIBUTED_QUEUE_PARMS> void BOOST_DISTRIBUTED_QUEUE_TYPE::push(const value_type& x) { typename ProcessGroup::process_id_type dest = get(owner, x); if (outgoing_buffers) outgoing_buffers->at(dest).push_back(x); else if (dest == process_id(process_group)) buffer.push(x); else send(process_group, get(owner, x), msg_push, x); } template<BOOST_DISTRIBUTED_QUEUE_PARMS> bool BOOST_DISTRIBUTED_QUEUE_TYPE::empty() const { /* Processes will stay here until the buffer is nonempty or synchronization with the other processes indicates that all local buffers are empty (and no messages are in transit). */ while (buffer.empty() && !do_synchronize()) ; return buffer.empty(); } template<BOOST_DISTRIBUTED_QUEUE_PARMS> typename BOOST_DISTRIBUTED_QUEUE_TYPE::size_type BOOST_DISTRIBUTED_QUEUE_TYPE::size() const { empty(); return buffer.size(); } template<BOOST_DISTRIBUTED_QUEUE_PARMS> void BOOST_DISTRIBUTED_QUEUE_TYPE::setup_triggers() { using boost::graph::parallel::simple_trigger; simple_trigger(process_group, msg_push, this, &distributed_queue::handle_push); simple_trigger(process_group, msg_multipush, this, &distributed_queue::handle_multipush); } template<BOOST_DISTRIBUTED_QUEUE_PARMS> void BOOST_DISTRIBUTED_QUEUE_TYPE:: handle_push(int /*source*/, int /*tag*/, const value_type& value, trigger_receive_context) { if (pred(value)) buffer.push(value); } template<BOOST_DISTRIBUTED_QUEUE_PARMS> void BOOST_DISTRIBUTED_QUEUE_TYPE:: handle_multipush(int /*source*/, int /*tag*/, const std::vector<value_type>& values, trigger_receive_context) { for (std::size_t i = 0; i < values.size(); ++i) if (pred(values[i])) buffer.push(values[i]); } template<BOOST_DISTRIBUTED_QUEUE_PARMS> bool BOOST_DISTRIBUTED_QUEUE_TYPE::do_synchronize() const { #ifdef PBGL_ACCOUNTING ++num_synchronizations; #endif using boost::parallel::all_reduce; using std::swap; typedef typename ProcessGroup::process_id_type process_id_type; if (outgoing_buffers) { // Transfer all of the push requests process_id_type id = process_id(process_group); process_id_type np = num_processes(process_group); for (process_id_type dest = 0; dest < np; ++dest) { outgoing_buffer_t& outgoing = outgoing_buffers->at(dest); std::size_t size = outgoing.size(); if (size != 0) { if (dest != id) { send(process_group, dest, msg_multipush, outgoing); } else { for (std::size_t i = 0; i < size; ++i) buffer.push(outgoing[i]); } outgoing.clear(); } } } synchronize(process_group); unsigned local_size = buffer.size(); unsigned global_size = all_reduce(process_group, local_size, std::plus<unsigned>()); return global_size == 0; } } } } // end namespace boost::graph::distributed distributed/detail/tag_allocator.hpp 0000644 00000004607 15125521275 0013670 0 ustar 00 // -*- C++ -*- // Copyright (C) 2007 Douglas Gregor <doug.gregor@gmail.com> // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GRAPH_DISTRIBUTED_TAG_ALLOCATOR_HPP #define BOOST_GRAPH_DISTRIBUTED_TAG_ALLOCATOR_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <vector> namespace boost { namespace graph { namespace distributed { namespace detail { /** * \brief The tag allocator allows clients to request unique tags that * can be used for one-time communications. * * The tag allocator hands out tag values from a predefined maximum * (given in the constructor) moving downward. Tags are provided one * at a time via a @c token. When the @c token goes out of scope, the * tag is returned and may be reallocated. These tags should be used, * for example, for one-time communication of values. */ class tag_allocator { public: class token; friend class token; /** * Construct a new tag allocator that provides unique tags starting * with the value @p top_tag and moving lower, as necessary. */ explicit tag_allocator(int top_tag) : bottom(top_tag) { } /** * Retrieve a new tag. The token itself holds onto the tag, which * will be released when the token is destroyed. */ token get_tag(); private: int bottom; std::vector<int> freed; }; /** * A token used to represent an allocated tag. */ class tag_allocator::token { public: /// Transfer ownership of the tag from @p other. token(const token& other); /// De-allocate the tag, if this token still owns it. ~token(); /// Retrieve the tag allocated for this task. operator int() const { return tag_; } private: /// Create a token with a specific tag from the given tag_allocator token(tag_allocator* allocator, int tag) : allocator(allocator), tag_(tag) { } /// Undefined: tokens are not copy-assignable token& operator=(const token&); /// The allocator from which this tag was allocated. tag_allocator* allocator; /// The stored tag flag. If -1, this token does not own the tag. mutable int tag_; friend class tag_allocator; }; } } } } // end namespace boost::graph::distributed::detail #endif // BOOST_GRAPH_DISTRIBUTED_TAG_ALLOCATOR_HPP distributed/detail/dijkstra_shortest_paths.hpp 0000644 00000003424 15125521275 0016016 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_PARALLEL_DIJKSTRA_DETAIL_HPP #define BOOST_GRAPH_PARALLEL_DIJKSTRA_DETAIL_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/property_map/property_map.hpp> namespace boost { namespace graph { namespace distributed { namespace detail { /********************************************************************** * Dijkstra queue message data * **********************************************************************/ template<typename DistanceMap, typename PredecessorMap> class dijkstra_msg_value { typedef typename property_traits<DistanceMap>::value_type distance_type; typedef typename property_traits<PredecessorMap>::value_type predecessor_type; public: typedef std::pair<distance_type, predecessor_type> type; static type create(distance_type dist, predecessor_type pred) { return std::make_pair(dist, pred); } }; template<typename DistanceMap> class dijkstra_msg_value<DistanceMap, dummy_property_map> { typedef typename property_traits<DistanceMap>::key_type vertex_descriptor; public: typedef typename property_traits<DistanceMap>::value_type type; static type create(type dist, vertex_descriptor) { return dist; } }; /**********************************************************************/ } } } } // end namespace boost::graph::distributed::detail #endif // BOOST_GRAPH_PARALLEL_DIJKSTRA_DETAIL_HPP distributed/detail/remote_update_set.hpp 0000644 00000017207 15125521275 0014565 0 ustar 00 // Copyright (C) 2005-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_DETAIL_REMOTE_UPDATE_SET_HPP #define BOOST_GRAPH_DETAIL_REMOTE_UPDATE_SET_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/parallel/process_group.hpp> #include <boost/type_traits/is_convertible.hpp> #include <vector> #include <boost/assert.hpp> #include <boost/optional.hpp> #include <queue> namespace boost { namespace graph { namespace detail { template<typename ProcessGroup> void do_synchronize(ProcessGroup& pg) { using boost::parallel::synchronize; synchronize(pg); } struct remote_set_queued {}; struct remote_set_immediate {}; template<typename ProcessGroup> class remote_set_semantics { BOOST_STATIC_CONSTANT (bool, queued = (is_convertible< typename ProcessGroup::communication_category, boost::parallel::bsp_process_group_tag>::value)); public: typedef typename mpl::if_c<queued, remote_set_queued, remote_set_immediate>::type type; }; template<typename Derived, typename ProcessGroup, typename Value, typename OwnerMap, typename Semantics = typename remote_set_semantics<ProcessGroup>::type> class remote_update_set; /********************************************************************** * Remote updating set that queues messages until synchronization * **********************************************************************/ template<typename Derived, typename ProcessGroup, typename Value, typename OwnerMap> class remote_update_set<Derived, ProcessGroup, Value, OwnerMap, remote_set_queued> { typedef typename property_traits<OwnerMap>::key_type Key; typedef std::vector<std::pair<Key, Value> > Updates; typedef typename Updates::size_type updates_size_type; typedef typename Updates::value_type updates_pair_type; public: private: typedef typename ProcessGroup::process_id_type process_id_type; enum message_kind { /** Message containing the number of updates that will be sent in * a msg_updates message that will immediately follow. This * message will contain a single value of type * updates_size_type. */ msg_num_updates, /** Contains (key, value) pairs with all of the updates from a * particular source. The number of updates is variable, but will * be provided in a msg_num_updates message that immediately * preceeds this message. * */ msg_updates }; struct handle_messages { explicit handle_messages(remote_update_set* self, const ProcessGroup& pg) : self(self), update_sizes(num_processes(pg), 0) { } void operator()(process_id_type source, int tag) { switch(tag) { case msg_num_updates: { // Receive the # of updates updates_size_type num_updates; receive(self->process_group, source, tag, num_updates); update_sizes[source] = num_updates; } break; case msg_updates: { updates_size_type num_updates = update_sizes[source]; BOOST_ASSERT(num_updates); // Receive the actual updates std::vector<updates_pair_type> updates(num_updates); receive(self->process_group, source, msg_updates, &updates[0], num_updates); // Send updates to derived "receive_update" member Derived* derived = static_cast<Derived*>(self); for (updates_size_type u = 0; u < num_updates; ++u) derived->receive_update(source, updates[u].first, updates[u].second); update_sizes[source] = 0; } break; }; } private: remote_update_set* self; std::vector<updates_size_type> update_sizes; }; friend struct handle_messages; protected: remote_update_set(const ProcessGroup& pg, const OwnerMap& owner) : process_group(pg, handle_messages(this, pg)), updates(num_processes(pg)), owner(owner) { } void update(const Key& key, const Value& value) { if (get(owner, key) == process_id(process_group)) { Derived* derived = static_cast<Derived*>(this); derived->receive_update(get(owner, key), key, value); } else { updates[get(owner, key)].push_back(std::make_pair(key, value)); } } void collect() { } void synchronize() { // Emit all updates and then remove them process_id_type num_processes = updates.size(); for (process_id_type p = 0; p < num_processes; ++p) { if (!updates[p].empty()) { send(process_group, p, msg_num_updates, updates[p].size()); send(process_group, p, msg_updates, &updates[p].front(), updates[p].size()); updates[p].clear(); } } do_synchronize(process_group); } ProcessGroup process_group; private: std::vector<Updates> updates; OwnerMap owner; }; /********************************************************************** * Remote updating set that sends messages immediately * **********************************************************************/ template<typename Derived, typename ProcessGroup, typename Value, typename OwnerMap> class remote_update_set<Derived, ProcessGroup, Value, OwnerMap, remote_set_immediate> { typedef typename property_traits<OwnerMap>::key_type Key; typedef std::pair<Key, Value> update_pair_type; typedef typename std::vector<update_pair_type>::size_type updates_size_type; public: typedef typename ProcessGroup::process_id_type process_id_type; private: enum message_kind { /** Contains a (key, value) pair that will be updated. */ msg_update }; struct handle_messages { explicit handle_messages(remote_update_set* self, const ProcessGroup& pg) : self(self) { update_sizes.resize(num_processes(pg), 0); } void operator()(process_id_type source, int tag) { // Receive the # of updates BOOST_ASSERT(tag == msg_update); update_pair_type update; receive(self->process_group, source, tag, update); // Send update to derived "receive_update" member Derived* derived = static_cast<Derived*>(self); derived->receive_update(source, update.first, update.second); } private: std::vector<updates_size_type> update_sizes; remote_update_set* self; }; friend struct handle_messages; protected: remote_update_set(const ProcessGroup& pg, const OwnerMap& owner) : process_group(pg, handle_messages(this, pg)), owner(owner) { } void update(const Key& key, const Value& value) { if (get(owner, key) == process_id(process_group)) { Derived* derived = static_cast<Derived*>(this); derived->receive_update(get(owner, key), key, value); } else send(process_group, get(owner, key), msg_update, update_pair_type(key, value)); } void collect() { typedef std::pair<process_id_type, int> probe_type; handle_messages handler(this, process_group); while (optional<probe_type> stp = probe(process_group)) if (stp->second == msg_update) handler(stp->first, stp->second); } void synchronize() { do_synchronize(process_group); } ProcessGroup process_group; OwnerMap owner; }; } } } // end namespace boost::graph::detail #endif // BOOST_GRAPH_DETAIL_REMOTE_UPDATE_SET_HPP distributed/detail/filtered_queue.hpp 0000644 00000005610 15125521275 0014052 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_FILTERED_QUEUE_HPP #define BOOST_FILTERED_QUEUE_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <algorithm> namespace boost { /** Queue adaptor that filters elements pushed into the queue * according to some predicate. */ template<typename Buffer, typename Predicate> class filtered_queue { public: typedef Buffer buffer_type; typedef Predicate predicate_type; typedef typename Buffer::value_type value_type; typedef typename Buffer::size_type size_type; /** * Constructs a new filtered queue with an initial buffer and a * predicate. * * @param buffer the initial buffer * @param pred the predicate */ explicit filtered_queue(const buffer_type& buffer = buffer_type(), const predicate_type& pred = predicate_type()) : buffer(buffer), pred(pred) {} /** Push a value into the queue. * * If the predicate returns @c true for @p x, pushes @p x into the * buffer. */ void push(const value_type& x) { if (pred(x)) buffer.push(x); } /** Pop the front element off the buffer. * * @pre @c !empty() */ void pop() { buffer.pop(); } /** Retrieve the front (top) element in the buffer. * * @pre @c !empty() */ value_type& top() { return buffer.top(); } /** * \overload */ const value_type& top() const { return buffer.top(); } /** Determine the number of elements in the buffer. */ size_type size() const { return buffer.size(); } /** Determine if the buffer is empty. */ bool empty() const { return buffer.empty(); } /** Get a reference to the underlying buffer. */ buffer_type& base() { return buffer; } const buffer_type& base() const { return buffer; } /** Swap the contents of this with @p other. */ void swap(filtered_queue& other) { using std::swap; swap(buffer, other.buffer); swap(pred, other.pred); } private: buffer_type buffer; predicate_type pred; }; /** Create a filtered queue. */ template<typename Buffer, typename Predicate> inline filtered_queue<Buffer, Predicate> make_filtered_queue(const Buffer& buffer, const Predicate& pred) { return filtered_queue<Buffer, Predicate>(buffer, pred); } /** Swap a filtered_queue. */ template<typename Buffer, typename Predicate> inline void swap(filtered_queue<Buffer, Predicate>& x, filtered_queue<Buffer, Predicate>& y) { x.swap(y); } } // end namespace boost #endif // BOOST_FILTERED_QUEUE_HPP distributed/detail/mpi_process_group.ipp 0000644 00000077151 15125521275 0014621 0 ustar 00 // -*- C++ -*- // Copyright (C) 2004-2008 The Trustees of Indiana University. // Copyright (C) 2007 Douglas Gregor <doug.gregor@gmail.com> // Copyright (C) 2007 Matthias Troyer <troyer@boost-consulting.com> // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine // Matthias Troyer //#define PBGL_PROCESS_GROUP_DEBUG #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/assert.hpp> #include <algorithm> #include <boost/graph/parallel/detail/untracked_pair.hpp> #include <numeric> #include <iterator> #include <functional> #include <vector> #include <queue> #include <stack> #include <list> #include <boost/graph/distributed/detail/tag_allocator.hpp> #include <stdio.h> // #define PBGL_PROCESS_GROUP_DEBUG #ifdef PBGL_PROCESS_GROUP_DEBUG # include <iostream> #endif namespace boost { namespace graph { namespace distributed { struct mpi_process_group::impl { typedef mpi_process_group::message_header message_header; typedef mpi_process_group::outgoing_messages outgoing_messages; /** * Stores the incoming messages from a particular processor. * * @todo Evaluate whether we should use a deque instance, which * would reduce could reduce the cost of "receiving" messages and allow us to deallocate memory earlier, but increases the time spent in the synchronization step. */ struct incoming_messages { incoming_messages(); ~incoming_messages() {} std::vector<message_header> headers; buffer_type buffer; std::vector<std::vector<message_header>::iterator> next_header; }; struct batch_request { MPI_Request request; buffer_type buffer; }; // send once we have a certain number of messages or bytes in the buffer // these numbers need to be tuned, we keep them small at first for testing std::size_t batch_header_number; std::size_t batch_buffer_size; std::size_t batch_message_size; /** * The actual MPI communicator used to transmit data. */ boost::mpi::communicator comm; /** * The MPI communicator used to transmit out-of-band replies. */ boost::mpi::communicator oob_reply_comm; /// Outgoing message information, indexed by destination processor. std::vector<outgoing_messages> outgoing; /// Incoming message information, indexed by source processor. std::vector<incoming_messages> incoming; /// The numbers of processors that have entered a synchronization stage std::vector<int> processors_synchronizing_stage; /// The synchronization stage of a processor std::vector<int> synchronizing_stage; /// Number of processors still sending messages std::vector<int> synchronizing_unfinished; /// Number of batches sent since last synchronization stage std::vector<int> number_sent_batches; /// Number of batches received minus number of expected batches std::vector<int> number_received_batches; /// The context of the currently-executing trigger, or @c trc_none /// if no trigger is executing. trigger_receive_context trigger_context; /// Non-zero indicates that we're processing batches /// Increment this when processing patches, /// decrement it when you're done. int processing_batches; /** * Contains all of the active blocks corresponding to attached * distributed data structures. */ blocks_type blocks; /// Whether we are currently synchronizing bool synchronizing; /// The MPI requests for posted sends of oob messages std::vector<MPI_Request> requests; /// The MPI buffers for posted irecvs of oob messages std::map<int,buffer_type> buffers; /// Queue for message batches received while already processing messages std::queue<std::pair<int,outgoing_messages> > new_batches; /// Maximum encountered size of the new_batches queue std::size_t max_received; /// The MPI requests and buffers for batchess being sent std::list<batch_request> sent_batches; /// Maximum encountered size of the sent_batches list std::size_t max_sent; /// Pre-allocated requests in a pool std::vector<batch_request> batch_pool; /// A stack controlling which batches are available std::stack<std::size_t> free_batches; void free_sent_batches(); // Tag allocator detail::tag_allocator allocated_tags; impl(std::size_t num_headers, std::size_t buffers_size, communicator_type parent_comm); ~impl(); private: void set_batch_size(std::size_t header_num, std::size_t buffer_sz); }; inline trigger_receive_context mpi_process_group::trigger_context() const { return impl_->trigger_context; } template<typename T> void mpi_process_group::send_impl(int dest, int tag, const T& value, mpl::true_ /*is_mpi_datatype*/) const { BOOST_ASSERT(tag < msg_reserved_first || tag > msg_reserved_last); impl::outgoing_messages& outgoing = impl_->outgoing[dest]; // Start constructing the message header impl::message_header header; header.source = process_id(*this); header.tag = tag; header.offset = outgoing.buffer.size(); boost::mpi::packed_oarchive oa(impl_->comm, outgoing.buffer); oa << value; #ifdef PBGL_PROCESS_GROUP_DEBUG std::cerr << "SEND: " << process_id(*this) << " -> " << dest << ", tag = " << tag << ", bytes = " << packed_size << std::endl; #endif // Store the header header.bytes = outgoing.buffer.size() - header.offset; outgoing.headers.push_back(header); maybe_send_batch(dest); } template<typename T> void mpi_process_group::send_impl(int dest, int tag, const T& value, mpl::false_ /*is_mpi_datatype*/) const { BOOST_ASSERT(tag < msg_reserved_first || tag > msg_reserved_last); impl::outgoing_messages& outgoing = impl_->outgoing[dest]; // Start constructing the message header impl::message_header header; header.source = process_id(*this); header.tag = tag; header.offset = outgoing.buffer.size(); // Serialize into the buffer boost::mpi::packed_oarchive out(impl_->comm, outgoing.buffer); out << value; // Store the header header.bytes = outgoing.buffer.size() - header.offset; outgoing.headers.push_back(header); maybe_send_batch(dest); #ifdef PBGL_PROCESS_GROUP_DEBUG std::cerr << "SEND: " << process_id(*this) << " -> " << dest << ", tag = " << tag << ", bytes = " << header.bytes << std::endl; #endif } template<typename T> inline void send(const mpi_process_group& pg, mpi_process_group::process_id_type dest, int tag, const T& value) { pg.send_impl(dest, pg.encode_tag(pg.my_block_number(), tag), value, boost::mpi::is_mpi_datatype<T>()); } template<typename T> typename enable_if<boost::mpi::is_mpi_datatype<T>, void>::type send(const mpi_process_group& pg, mpi_process_group::process_id_type dest, int tag, const T values[], std::size_t n) { pg.send_impl(dest, pg.encode_tag(pg.my_block_number(), tag), boost::serialization::make_array(values,n), boost::mpl::true_()); } template<typename T> typename disable_if<boost::mpi::is_mpi_datatype<T>, void>::type mpi_process_group:: array_send_impl(int dest, int tag, const T values[], std::size_t n) const { BOOST_ASSERT(tag < msg_reserved_first || tag > msg_reserved_last); impl::outgoing_messages& outgoing = impl_->outgoing[dest]; // Start constructing the message header impl::message_header header; header.source = process_id(*this); header.tag = tag; header.offset = outgoing.buffer.size(); // Serialize into the buffer boost::mpi::packed_oarchive out(impl_->comm, outgoing.buffer); out << n; for (std::size_t i = 0; i < n; ++i) out << values[i]; // Store the header header.bytes = outgoing.buffer.size() - header.offset; outgoing.headers.push_back(header); maybe_send_batch(dest); #ifdef PBGL_PROCESS_GROUP_DEBUG std::cerr << "SEND: " << process_id(*this) << " -> " << dest << ", tag = " << tag << ", bytes = " << header.bytes << std::endl; #endif } template<typename T> typename disable_if<boost::mpi::is_mpi_datatype<T>, void>::type send(const mpi_process_group& pg, mpi_process_group::process_id_type dest, int tag, const T values[], std::size_t n) { pg.array_send_impl(dest, pg.encode_tag(pg.my_block_number(), tag), values, n); } template<typename InputIterator> void send(const mpi_process_group& pg, mpi_process_group::process_id_type dest, int tag, InputIterator first, InputIterator last) { typedef typename std::iterator_traits<InputIterator>::value_type value_type; std::vector<value_type> values(first, last); if (values.empty()) send(pg, dest, tag, static_cast<value_type*>(0), 0); else send(pg, dest, tag, &values[0], values.size()); } template<typename T> bool mpi_process_group::receive_impl(int source, int tag, T& value, mpl::true_ /*is_mpi_datatype*/) const { #ifdef PBGL_PROCESS_GROUP_DEBUG std::cerr << "RECV: " << process_id(*this) << " <- " << source << ", tag = " << tag << std::endl; #endif impl::incoming_messages& incoming = impl_->incoming[source]; // Find the next header with the right tag std::vector<impl::message_header>::iterator header = incoming.next_header[my_block_number()]; while (header != incoming.headers.end() && header->tag != tag) ++header; // If no header is found, notify the caller if (header == incoming.headers.end()) return false; // Unpack the data if (header->bytes > 0) { boost::mpi::packed_iarchive ia(impl_->comm, incoming.buffer, archive::no_header, header->offset); ia >> value; } // Mark this message as received header->tag = -1; // Move the "next header" indicator to the next unreceived message while (incoming.next_header[my_block_number()] != incoming.headers.end() && incoming.next_header[my_block_number()]->tag == -1) ++incoming.next_header[my_block_number()]; if (incoming.next_header[my_block_number()] == incoming.headers.end()) { bool finished = true; for (std::size_t i = 0; i < incoming.next_header.size() && finished; ++i) { if (incoming.next_header[i] != incoming.headers.end()) finished = false; } if (finished) { std::vector<impl::message_header> no_headers; incoming.headers.swap(no_headers); buffer_type empty_buffer; incoming.buffer.swap(empty_buffer); for (std::size_t i = 0; i < incoming.next_header.size(); ++i) incoming.next_header[i] = incoming.headers.end(); } } return true; } template<typename T> bool mpi_process_group::receive_impl(int source, int tag, T& value, mpl::false_ /*is_mpi_datatype*/) const { impl::incoming_messages& incoming = impl_->incoming[source]; // Find the next header with the right tag std::vector<impl::message_header>::iterator header = incoming.next_header[my_block_number()]; while (header != incoming.headers.end() && header->tag != tag) ++header; // If no header is found, notify the caller if (header == incoming.headers.end()) return false; // Deserialize the data boost::mpi::packed_iarchive in(impl_->comm, incoming.buffer, archive::no_header, header->offset); in >> value; // Mark this message as received header->tag = -1; // Move the "next header" indicator to the next unreceived message while (incoming.next_header[my_block_number()] != incoming.headers.end() && incoming.next_header[my_block_number()]->tag == -1) ++incoming.next_header[my_block_number()]; if (incoming.next_header[my_block_number()] == incoming.headers.end()) { bool finished = true; for (std::size_t i = 0; i < incoming.next_header.size() && finished; ++i) { if (incoming.next_header[i] != incoming.headers.end()) finished = false; } if (finished) { std::vector<impl::message_header> no_headers; incoming.headers.swap(no_headers); buffer_type empty_buffer; incoming.buffer.swap(empty_buffer); for (std::size_t i = 0; i < incoming.next_header.size(); ++i) incoming.next_header[i] = incoming.headers.end(); } } return true; } template<typename T> typename disable_if<boost::mpi::is_mpi_datatype<T>, bool>::type mpi_process_group:: array_receive_impl(int source, int tag, T* values, std::size_t& n) const { impl::incoming_messages& incoming = impl_->incoming[source]; // Find the next header with the right tag std::vector<impl::message_header>::iterator header = incoming.next_header[my_block_number()]; while (header != incoming.headers.end() && header->tag != tag) ++header; // If no header is found, notify the caller if (header == incoming.headers.end()) return false; // Deserialize the data boost::mpi::packed_iarchive in(impl_->comm, incoming.buffer, archive::no_header, header->offset); std::size_t num_sent; in >> num_sent; if (num_sent > n) std::cerr << "ERROR: Have " << num_sent << " items but only space for " << n << " items\n"; for (std::size_t i = 0; i < num_sent; ++i) in >> values[i]; n = num_sent; // Mark this message as received header->tag = -1; // Move the "next header" indicator to the next unreceived message while (incoming.next_header[my_block_number()] != incoming.headers.end() && incoming.next_header[my_block_number()]->tag == -1) ++incoming.next_header[my_block_number()]; if (incoming.next_header[my_block_number()] == incoming.headers.end()) { bool finished = true; for (std::size_t i = 0; i < incoming.next_header.size() && finished; ++i) { if (incoming.next_header[i] != incoming.headers.end()) finished = false; } if (finished) { std::vector<impl::message_header> no_headers; incoming.headers.swap(no_headers); buffer_type empty_buffer; incoming.buffer.swap(empty_buffer); for (std::size_t i = 0; i < incoming.next_header.size(); ++i) incoming.next_header[i] = incoming.headers.end(); } } return true; } // Construct triggers template<typename Type, typename Handler> void mpi_process_group::trigger(int tag, const Handler& handler) { BOOST_ASSERT(block_num); install_trigger(tag,my_block_number(),shared_ptr<trigger_base>( new trigger_launcher<Type, Handler>(*this, tag, handler))); } template<typename Type, typename Handler> void mpi_process_group::trigger_with_reply(int tag, const Handler& handler) { BOOST_ASSERT(block_num); install_trigger(tag,my_block_number(),shared_ptr<trigger_base>( new reply_trigger_launcher<Type, Handler>(*this, tag, handler))); } template<typename Type, typename Handler> void mpi_process_group::global_trigger(int tag, const Handler& handler, std::size_t sz) { if (sz==0) // normal trigger install_trigger(tag,0,shared_ptr<trigger_base>( new global_trigger_launcher<Type, Handler>(*this, tag, handler))); else // trigger with irecv install_trigger(tag,0,shared_ptr<trigger_base>( new global_irecv_trigger_launcher<Type, Handler>(*this, tag, handler,sz))); } namespace detail { template<typename Type> void do_oob_receive(mpi_process_group const& self, int source, int tag, Type& data, mpl::true_ /*is_mpi_datatype*/) { using boost::mpi::get_mpi_datatype; //self.impl_->comm.recv(source,tag,data); MPI_Recv(&data, 1, get_mpi_datatype<Type>(data), source, tag, self.impl_->comm, MPI_STATUS_IGNORE); } template<typename Type> void do_oob_receive(mpi_process_group const& self, int source, int tag, Type& data, mpl::false_ /*is_mpi_datatype*/) { // self.impl_->comm.recv(source,tag,data); // Receive the size of the data packet boost::mpi::status status; status = self.impl_->comm.probe(source, tag); #if BOOST_VERSION >= 103600 int size = status.count<boost::mpi::packed>().get(); #else int size; MPI_Status& mpi_status = status; MPI_Get_count(&mpi_status, MPI_PACKED, &size); #endif // Receive the data packed itself boost::mpi::packed_iarchive in(self.impl_->comm); in.resize(size); MPI_Recv(in.address(), size, MPI_PACKED, source, tag, self.impl_->comm, MPI_STATUS_IGNORE); // Deserialize the data in >> data; } template<typename Type> void do_oob_receive(mpi_process_group const& self, int source, int tag, Type& data) { do_oob_receive(self, source, tag, data, boost::mpi::is_mpi_datatype<Type>()); } } // namespace detail template<typename Type, typename Handler> void mpi_process_group::trigger_launcher<Type, Handler>:: receive(mpi_process_group const&, int source, int tag, trigger_receive_context context, int block) const { #ifdef PBGL_PROCESS_GROUP_DEBUG std::cerr << (out_of_band? "OOB trigger" : "Trigger") << " receive from source " << source << " and tag " << tag << " in block " << (block == -1 ? self.my_block_number() : block) << std::endl; #endif Type data; if (context == trc_out_of_band) { // Receive the message directly off the wire int realtag = self.encode_tag( block == -1 ? self.my_block_number() : block, tag); detail::do_oob_receive(self,source,realtag,data); } else // Receive the message out of the local buffer boost::graph::distributed::receive(self, source, tag, data); // Pass the message off to the handler handler(source, tag, data, context); } template<typename Type, typename Handler> void mpi_process_group::reply_trigger_launcher<Type, Handler>:: receive(mpi_process_group const&, int source, int tag, trigger_receive_context context, int block) const { #ifdef PBGL_PROCESS_GROUP_DEBUG std::cerr << (out_of_band? "OOB reply trigger" : "Reply trigger") << " receive from source " << source << " and tag " << tag << " in block " << (block == -1 ? self.my_block_number() : block) << std::endl; #endif BOOST_ASSERT(context == trc_out_of_band); boost::parallel::detail::untracked_pair<int, Type> data; // Receive the message directly off the wire int realtag = self.encode_tag(block == -1 ? self.my_block_number() : block, tag); detail::do_oob_receive(self, source, realtag, data); // Pass the message off to the handler and send the result back to // the source. send_oob(self, source, data.first, handler(source, tag, data.second, context), -2); } template<typename Type, typename Handler> void mpi_process_group::global_trigger_launcher<Type, Handler>:: receive(mpi_process_group const& self, int source, int tag, trigger_receive_context context, int block) const { #ifdef PBGL_PROCESS_GROUP_DEBUG std::cerr << (out_of_band? "OOB trigger" : "Trigger") << " receive from source " << source << " and tag " << tag << " in block " << (block == -1 ? self.my_block_number() : block) << std::endl; #endif Type data; if (context == trc_out_of_band) { // Receive the message directly off the wire int realtag = self.encode_tag( block == -1 ? self.my_block_number() : block, tag); detail::do_oob_receive(self,source,realtag,data); } else // Receive the message out of the local buffer boost::graph::distributed::receive(self, source, tag, data); // Pass the message off to the handler handler(self, source, tag, data, context); } template<typename Type, typename Handler> void mpi_process_group::global_irecv_trigger_launcher<Type, Handler>:: receive(mpi_process_group const& self, int source, int tag, trigger_receive_context context, int block) const { #ifdef PBGL_PROCESS_GROUP_DEBUG std::cerr << (out_of_band? "OOB trigger" : "Trigger") << " receive from source " << source << " and tag " << tag << " in block " << (block == -1 ? self.my_block_number() : block) << std::endl; #endif Type data; if (context == trc_out_of_band) { return; } BOOST_ASSERT (context == trc_irecv_out_of_band); // force posting of new MPI_Irecv, even though buffer is already allocated boost::mpi::packed_iarchive ia(self.impl_->comm,self.impl_->buffers[tag]); ia >> data; // Start a new receive prepare_receive(self,tag,true); // Pass the message off to the handler handler(self, source, tag, data, context); } template<typename Type, typename Handler> void mpi_process_group::global_irecv_trigger_launcher<Type, Handler>:: prepare_receive(mpi_process_group const& self, int tag, bool force) const { #ifdef PBGL_PROCESS_GROUP_DEBUG std::cerr << ("Posting Irecv for trigger") << " receive with tag " << tag << std::endl; #endif if (self.impl_->buffers.find(tag) == self.impl_->buffers.end()) { self.impl_->buffers[tag].resize(buffer_size); force = true; } BOOST_ASSERT(static_cast<int>(self.impl_->buffers[tag].size()) >= buffer_size); //BOOST_MPL_ASSERT(mpl::not_<is_mpi_datatype<Type> >); if (force) { self.impl_->requests.push_back(MPI_Request()); MPI_Request* request = &self.impl_->requests.back(); MPI_Irecv(&self.impl_->buffers[tag].front(),buffer_size, MPI_PACKED,MPI_ANY_SOURCE,tag,self.impl_->comm,request); } } template<typename T> inline mpi_process_group::process_id_type receive(const mpi_process_group& pg, int tag, T& value) { for (std::size_t source = 0; source < pg.impl_->incoming.size(); ++source) { if (pg.receive_impl(source, pg.encode_tag(pg.my_block_number(), tag), value, boost::mpi::is_mpi_datatype<T>())) return source; } BOOST_ASSERT (false); } template<typename T> typename enable_if<boost::mpi::is_mpi_datatype<T>, std::pair<mpi_process_group::process_id_type, std::size_t> >::type receive(const mpi_process_group& pg, int tag, T values[], std::size_t n) { for (std::size_t source = 0; source < pg.impl_->incoming.size(); ++source) { bool result = pg.receive_impl(source, pg.encode_tag(pg.my_block_number(), tag), boost::serialization::make_array(values,n), boost::mpl::true_()); if (result) return std::make_pair(source, n); } BOOST_ASSERT(false); } template<typename T> typename disable_if<boost::mpi::is_mpi_datatype<T>, std::pair<mpi_process_group::process_id_type, std::size_t> >::type receive(const mpi_process_group& pg, int tag, T values[], std::size_t n) { for (std::size_t source = 0; source < pg.impl_->incoming.size(); ++source) { if (pg.array_receive_impl(source, pg.encode_tag(pg.my_block_number(), tag), values, n)) return std::make_pair(source, n); } BOOST_ASSERT(false); } template<typename T> mpi_process_group::process_id_type receive(const mpi_process_group& pg, mpi_process_group::process_id_type source, int tag, T& value) { if (pg.receive_impl(source, pg.encode_tag(pg.my_block_number(), tag), value, boost::mpi::is_mpi_datatype<T>())) return source; else { fprintf(stderr, "Process %d failed to receive a message from process %d with tag %d in block %d.\n", process_id(pg), source, tag, pg.my_block_number()); BOOST_ASSERT(false); abort(); } } template<typename T> typename enable_if<boost::mpi::is_mpi_datatype<T>, std::pair<mpi_process_group::process_id_type, std::size_t> >::type receive(const mpi_process_group& pg, int source, int tag, T values[], std::size_t n) { if (pg.receive_impl(source, pg.encode_tag(pg.my_block_number(), tag), boost::serialization::make_array(values,n), boost::mpl::true_())) return std::make_pair(source,n); else { fprintf(stderr, "Process %d failed to receive a message from process %d with tag %d in block %d.\n", process_id(pg), source, tag, pg.my_block_number()); BOOST_ASSERT(false); abort(); } } template<typename T> typename disable_if<boost::mpi::is_mpi_datatype<T>, std::pair<mpi_process_group::process_id_type, std::size_t> >::type receive(const mpi_process_group& pg, int source, int tag, T values[], std::size_t n) { pg.array_receive_impl(source, pg.encode_tag(pg.my_block_number(), tag), values, n); return std::make_pair(source, n); } template<typename T, typename BinaryOperation> T* all_reduce(const mpi_process_group& pg, T* first, T* last, T* out, BinaryOperation bin_op) { synchronize(pg); bool inplace = first == out; if (inplace) out = new T [last-first]; boost::mpi::all_reduce(boost::mpi::communicator(communicator(pg), boost::mpi::comm_attach), first, last-first, out, bin_op); if (inplace) { std::copy(out, out + (last-first), first); delete [] out; return last; } return out; } template<typename T> void broadcast(const mpi_process_group& pg, T& val, mpi_process_group::process_id_type root) { // broadcast the seed boost::mpi::communicator comm(communicator(pg),boost::mpi::comm_attach); boost::mpi::broadcast(comm,val,root); } template<typename T, typename BinaryOperation> T* scan(const mpi_process_group& pg, T* first, T* last, T* out, BinaryOperation bin_op) { synchronize(pg); bool inplace = first == out; if (inplace) out = new T [last-first]; boost::mpi::scan(communicator(pg), first, last-first, out, bin_op); if (inplace) { std::copy(out, out + (last-first), first); delete [] out; return last; } return out; } template<typename InputIterator, typename T> void all_gather(const mpi_process_group& pg, InputIterator first, InputIterator last, std::vector<T>& out) { synchronize(pg); // Stick a copy of the local values into a vector, so we can broadcast it std::vector<T> local_values(first, last); // Collect the number of vertices stored in each process int size = local_values.size(); std::vector<int> sizes(num_processes(pg)); int result = MPI_Allgather(&size, 1, MPI_INT, &sizes[0], 1, MPI_INT, communicator(pg)); BOOST_ASSERT(result == MPI_SUCCESS); (void)result; // Adjust sizes based on the number of bytes // // std::transform(sizes.begin(), sizes.end(), sizes.begin(), // std::bind2nd(std::multiplies<int>(), sizeof(T))); // // std::bind2nd has been removed from C++17 for( std::size_t i = 0, n = sizes.size(); i < n; ++i ) { sizes[ i ] *= sizeof( T ); } // Compute displacements std::vector<int> displacements; displacements.reserve(sizes.size() + 1); displacements.push_back(0); std::partial_sum(sizes.begin(), sizes.end(), std::back_inserter(displacements)); // Gather all of the values out.resize(displacements.back() / sizeof(T)); if (!out.empty()) { result = MPI_Allgatherv(local_values.empty()? (void*)&local_values /* local results */: (void*)&local_values[0], local_values.size() * sizeof(T), MPI_BYTE, &out[0], &sizes[0], &displacements[0], MPI_BYTE, communicator(pg)); } BOOST_ASSERT(result == MPI_SUCCESS); } template<typename InputIterator> mpi_process_group process_subgroup(const mpi_process_group& pg, InputIterator first, InputIterator last) { /* boost::mpi::group current_group = communicator(pg).group(); boost::mpi::group new_group = current_group.include(first,last); boost::mpi::communicator new_comm(communicator(pg),new_group); return mpi_process_group(new_comm); */ std::vector<int> ranks(first, last); MPI_Group current_group; int result = MPI_Comm_group(communicator(pg), ¤t_group); BOOST_ASSERT(result == MPI_SUCCESS); (void)result; MPI_Group new_group; result = MPI_Group_incl(current_group, ranks.size(), &ranks[0], &new_group); BOOST_ASSERT(result == MPI_SUCCESS); MPI_Comm new_comm; result = MPI_Comm_create(communicator(pg), new_group, &new_comm); BOOST_ASSERT(result == MPI_SUCCESS); result = MPI_Group_free(&new_group); BOOST_ASSERT(result == MPI_SUCCESS); result = MPI_Group_free(¤t_group); BOOST_ASSERT(result == MPI_SUCCESS); if (new_comm != MPI_COMM_NULL) { mpi_process_group result_pg(boost::mpi::communicator(new_comm,boost::mpi::comm_attach)); result = MPI_Comm_free(&new_comm); BOOST_ASSERT(result == 0); return result_pg; } else { return mpi_process_group(mpi_process_group::create_empty()); } } template<typename Receiver> Receiver* mpi_process_group::get_receiver() { return impl_->blocks[my_block_number()]->on_receive .template target<Receiver>(); } template<typename T> typename enable_if<boost::mpi::is_mpi_datatype<T> >::type receive_oob(const mpi_process_group& pg, mpi_process_group::process_id_type source, int tag, T& value, int block) { using boost::mpi::get_mpi_datatype; // Determine the actual message we expect to receive, and which // communicator it will come by. std::pair<boost::mpi::communicator, int> actual = pg.actual_communicator_and_tag(tag, block); // Post a non-blocking receive that waits until we complete this request. MPI_Request request; MPI_Irecv(&value, 1, get_mpi_datatype<T>(value), source, actual.second, actual.first, &request); int done = 0; do { MPI_Test(&request, &done, MPI_STATUS_IGNORE); if (!done) pg.poll(/*wait=*/false, block); } while (!done); } template<typename T> typename disable_if<boost::mpi::is_mpi_datatype<T> >::type receive_oob(const mpi_process_group& pg, mpi_process_group::process_id_type source, int tag, T& value, int block) { // Determine the actual message we expect to receive, and which // communicator it will come by. std::pair<boost::mpi::communicator, int> actual = pg.actual_communicator_and_tag(tag, block); boost::optional<boost::mpi::status> status; do { status = actual.first.iprobe(source, actual.second); if (!status) pg.poll(); } while (!status); //actual.first.recv(status->source(), status->tag(),value); // Allocate the receive buffer boost::mpi::packed_iarchive in(actual.first); #if BOOST_VERSION >= 103600 in.resize(status->count<boost::mpi::packed>().get()); #else int size; MPI_Status mpi_status = *status; MPI_Get_count(&mpi_status, MPI_PACKED, &size); in.resize(size); #endif // Receive the message data MPI_Recv(in.address(), in.size(), MPI_PACKED, status->source(), status->tag(), actual.first, MPI_STATUS_IGNORE); // Unpack the message data in >> value; } template<typename SendT, typename ReplyT> typename enable_if<boost::mpi::is_mpi_datatype<ReplyT> >::type send_oob_with_reply(const mpi_process_group& pg, mpi_process_group::process_id_type dest, int tag, const SendT& send_value, ReplyT& reply_value, int block) { detail::tag_allocator::token reply_tag = pg.impl_->allocated_tags.get_tag(); send_oob(pg, dest, tag, boost::parallel::detail::make_untracked_pair( (int)reply_tag, send_value), block); receive_oob(pg, dest, reply_tag, reply_value); } template<typename SendT, typename ReplyT> typename disable_if<boost::mpi::is_mpi_datatype<ReplyT> >::type send_oob_with_reply(const mpi_process_group& pg, mpi_process_group::process_id_type dest, int tag, const SendT& send_value, ReplyT& reply_value, int block) { detail::tag_allocator::token reply_tag = pg.impl_->allocated_tags.get_tag(); send_oob(pg, dest, tag, boost::parallel::detail::make_untracked_pair((int)reply_tag, send_value), block); receive_oob(pg, dest, reply_tag, reply_value); } } } } // end namespace boost::graph::distributed distributed/betweenness_centrality.hpp 0000644 00000210764 15125521275 0014376 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_PARALLEL_BRANDES_BETWEENNESS_CENTRALITY_HPP #define BOOST_GRAPH_PARALLEL_BRANDES_BETWEENNESS_CENTRALITY_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif // #define COMPUTE_PATH_COUNTS_INLINE #include <boost/graph/betweenness_centrality.hpp> #include <boost/graph/overloading.hpp> #include <boost/graph/distributed/concepts.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/config.hpp> #include <boost/assert.hpp> // For additive_reducer #include <boost/graph/distributed/distributed_graph_utility.hpp> #include <boost/type_traits/is_convertible.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/property_map/parallel/distributed_property_map.hpp> #include <boost/graph/distributed/detail/dijkstra_shortest_paths.hpp> #include <boost/tuple/tuple.hpp> // NGE - Needed for minstd_rand at L807, should pass vertex list // or generator instead #include <boost/random/linear_congruential.hpp> #include <algorithm> #include <stack> #include <vector> // Appending reducer template <typename T> struct append_reducer { BOOST_STATIC_CONSTANT(bool, non_default_resolver = true); template<typename K> T operator()(const K&) const { return T(); } template<typename K> T operator()(const K&, const T& x, const T& y) const { T z(x.begin(), x.end()); for (typename T::const_iterator iter = y.begin(); iter != y.end(); ++iter) if (std::find(z.begin(), z.end(), *iter) == z.end()) z.push_back(*iter); return z; } }; namespace boost { namespace serialization { // TODO(nge): Write generalized serialization for tuples template<typename Archive, typename T1, typename T2, typename T3, typename T4> void serialize(Archive & ar, boost::tuple<T1,T2,T3, T4>& t, const unsigned int) { ar & boost::tuples::get<0>(t); ar & boost::tuples::get<1>(t); ar & boost::tuples::get<2>(t); ar & boost::tuples::get<3>(t); } } // serialization template <typename OwnerMap, typename Tuple> class get_owner_of_first_tuple_element { public: typedef typename property_traits<OwnerMap>::value_type owner_type; get_owner_of_first_tuple_element(OwnerMap owner) : owner(owner) { } owner_type get_owner(Tuple t) { return get(owner, boost::tuples::get<0>(t)); } private: OwnerMap owner; }; template <typename OwnerMap, typename Tuple> typename get_owner_of_first_tuple_element<OwnerMap, Tuple>::owner_type get(get_owner_of_first_tuple_element<OwnerMap, Tuple> o, Tuple t) { return o.get_owner(t); } template <typename OwnerMap> class get_owner_of_first_pair_element { public: typedef typename property_traits<OwnerMap>::value_type owner_type; get_owner_of_first_pair_element(OwnerMap owner) : owner(owner) { } template <typename Vertex, typename T> owner_type get_owner(std::pair<Vertex, T> p) { return get(owner, p.first); } private: OwnerMap owner; }; template <typename OwnerMap, typename Vertex, typename T> typename get_owner_of_first_pair_element<OwnerMap>::owner_type get(get_owner_of_first_pair_element<OwnerMap> o, std::pair<Vertex, T> p) { return o.get_owner(p); } namespace graph { namespace parallel { namespace detail { template<typename DistanceMap, typename IncomingMap> class betweenness_centrality_msg_value { typedef typename property_traits<DistanceMap>::value_type distance_type; typedef typename property_traits<IncomingMap>::value_type incoming_type; typedef typename incoming_type::value_type incoming_value_type; public: typedef std::pair<distance_type, incoming_value_type> type; static type create(distance_type dist, incoming_value_type source) { return std::make_pair(dist, source); } }; /************************************************************************/ /* Delta-stepping Betweenness Centrality */ /************************************************************************/ template<typename Graph, typename DistanceMap, typename IncomingMap, typename EdgeWeightMap, typename PathCountMap #ifdef COMPUTE_PATH_COUNTS_INLINE , typename IsSettledMap, typename VertexIndexMap #endif > class betweenness_centrality_delta_stepping_impl { // Could inherit from delta_stepping_impl to get run() method // but for the time being it's just reproduced here typedef typename graph_traits<Graph>::vertex_descriptor Vertex; typedef typename graph_traits<Graph>::degree_size_type Degree; typedef typename property_traits<EdgeWeightMap>::value_type Dist; typedef typename property_traits<IncomingMap>::value_type IncomingType; typedef typename boost::graph::parallel::process_group_type<Graph>::type ProcessGroup; typedef std::list<Vertex> Bucket; typedef typename Bucket::iterator BucketIterator; typedef typename std::vector<Bucket*>::size_type BucketIndex; typedef betweenness_centrality_msg_value<DistanceMap, IncomingMap> MessageValue; enum { // Relax a remote vertex. The message contains a pair<Vertex, // MessageValue>, the first part of which is the vertex whose // tentative distance is being relaxed and the second part // contains either the new distance (if there is no predecessor // map) or a pair with the distance and predecessor. msg_relax }; public: // Must supply delta, ctor that guesses delta removed betweenness_centrality_delta_stepping_impl(const Graph& g, DistanceMap distance, IncomingMap incoming, EdgeWeightMap weight, PathCountMap path_count, #ifdef COMPUTE_PATH_COUNTS_INLINE IsSettledMap is_settled, VertexIndexMap vertex_index, #endif Dist delta); void run(Vertex s); private: // Relax the edge (u, v), creating a new best path of distance x. void relax(Vertex u, Vertex v, Dist x); // Synchronize all of the processes, by receiving all messages that // have not yet been received. void synchronize() { using boost::parallel::synchronize; synchronize(pg); } // Setup triggers for msg_relax messages void setup_triggers() { using boost::parallel::simple_trigger; simple_trigger(pg, msg_relax, this, &betweenness_centrality_delta_stepping_impl::handle_msg_relax); } void handle_msg_relax(int /*source*/, int /*tag*/, const std::pair<Vertex, typename MessageValue::type>& data, boost::parallel::trigger_receive_context) { relax(data.second.second, data.first, data.second.first); } const Graph& g; IncomingMap incoming; DistanceMap distance; EdgeWeightMap weight; PathCountMap path_count; #ifdef COMPUTE_PATH_COUNTS_INLINE IsSettledMap is_settled; VertexIndexMap vertex_index; #endif Dist delta; ProcessGroup pg; typename property_map<Graph, vertex_owner_t>::const_type owner; typename property_map<Graph, vertex_local_t>::const_type local; // A "property map" that contains the position of each vertex in // whatever bucket it resides in. std::vector<BucketIterator> position_in_bucket; // Bucket data structure. The ith bucket contains all local vertices // with (tentative) distance in the range [i*delta, // (i+1)*delta). std::vector<Bucket*> buckets; // This "dummy" list is used only so that we can initialize the // position_in_bucket property map with non-singular iterators. This // won't matter for most implementations of the C++ Standard // Library, but it avoids undefined behavior and allows us to run // with library "debug modes". std::list<Vertex> dummy_list; // A "property map" that states which vertices have been deleted // from the bucket in this iteration. std::vector<bool> vertex_was_deleted; }; template<typename Graph, typename DistanceMap, typename IncomingMap, typename EdgeWeightMap, typename PathCountMap #ifdef COMPUTE_PATH_COUNTS_INLINE , typename IsSettledMap, typename VertexIndexMap #endif > betweenness_centrality_delta_stepping_impl< Graph, DistanceMap, IncomingMap, EdgeWeightMap, PathCountMap #ifdef COMPUTE_PATH_COUNTS_INLINE , IsSettledMap, VertexIndexMap #endif >:: betweenness_centrality_delta_stepping_impl(const Graph& g, DistanceMap distance, IncomingMap incoming, EdgeWeightMap weight, PathCountMap path_count, #ifdef COMPUTE_PATH_COUNTS_INLINE IsSettledMap is_settled, VertexIndexMap vertex_index, #endif Dist delta) : g(g), incoming(incoming), distance(distance), weight(weight), path_count(path_count), #ifdef COMPUTE_PATH_COUNTS_INLINE is_settled(is_settled), vertex_index(vertex_index), #endif delta(delta), pg(boost::graph::parallel::process_group_adl(g), boost::parallel::attach_distributed_object()), owner(get(vertex_owner, g)), local(get(vertex_local, g)) { setup_triggers(); } template<typename Graph, typename DistanceMap, typename IncomingMap, typename EdgeWeightMap, typename PathCountMap #ifdef COMPUTE_PATH_COUNTS_INLINE , typename IsSettledMap, typename VertexIndexMap #endif > void betweenness_centrality_delta_stepping_impl< Graph, DistanceMap, IncomingMap, EdgeWeightMap, PathCountMap #ifdef COMPUTE_PATH_COUNTS_INLINE , IsSettledMap, VertexIndexMap #endif >:: run(Vertex s) { typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type; typename process_group_type::process_id_type id = process_id(pg); Dist inf = (std::numeric_limits<Dist>::max)(); // None of the vertices are stored in the bucket. position_in_bucket.clear(); position_in_bucket.resize(num_vertices(g), dummy_list.end()); // None of the vertices have been deleted vertex_was_deleted.clear(); vertex_was_deleted.resize(num_vertices(g), false); // No path from s to any other vertex, yet BGL_FORALL_VERTICES_T(v, g, Graph) put(distance, v, inf); // The distance to the starting node is zero if (get(owner, s) == id) // Put "s" into its bucket (bucket 0) relax(s, s, 0); else // Note that we know the distance to s is zero cache(distance, s, 0); #ifdef COMPUTE_PATH_COUNTS_INLINE // Synchronize here to deliver initial relaxation since we don't // synchronize at the beginning of the inner loop any more synchronize(); // Incoming edge count map is an implementation detail and should // be freed as soon as possible so build it here typedef typename graph_traits<Graph>::edges_size_type edges_size_type; std::vector<edges_size_type> incoming_edge_countS(num_vertices(g)); iterator_property_map<typename std::vector<edges_size_type>::iterator, VertexIndexMap> incoming_edge_count(incoming_edge_countS.begin(), vertex_index); #endif BucketIndex max_bucket = (std::numeric_limits<BucketIndex>::max)(); BucketIndex current_bucket = 0; do { #ifdef COMPUTE_PATH_COUNTS_INLINE // We need to clear the outgoing map after every bucket so just build it here std::vector<IncomingType> outgoingS(num_vertices(g)); IncomingMap outgoing(outgoingS.begin(), vertex_index); outgoing.set_reduce(append_reducer<IncomingType>()); #else // Synchronize with all of the other processes. synchronize(); #endif // Find the next bucket that has something in it. while (current_bucket < buckets.size() && (!buckets[current_bucket] || buckets[current_bucket]->empty())) ++current_bucket; if (current_bucket >= buckets.size()) current_bucket = max_bucket; // Find the smallest bucket (over all processes) that has vertices // that need to be processed. using boost::parallel::all_reduce; using boost::parallel::minimum; current_bucket = all_reduce(pg, current_bucket, minimum<BucketIndex>()); if (current_bucket == max_bucket) // There are no non-empty buckets in any process; exit. break; // Contains the set of vertices that have been deleted in the // relaxation of "light" edges. Note that we keep track of which // vertices were deleted with the property map // "vertex_was_deleted". std::vector<Vertex> deleted_vertices; // Repeatedly relax light edges bool nonempty_bucket; do { // Someone has work to do in this bucket. if (current_bucket < buckets.size() && buckets[current_bucket]) { Bucket& bucket = *buckets[current_bucket]; // For each element in the bucket while (!bucket.empty()) { Vertex u = bucket.front(); // Remove u from the front of the bucket bucket.pop_front(); // Insert u into the set of deleted vertices, if it hasn't // been done already. if (!vertex_was_deleted[get(local, u)]) { vertex_was_deleted[get(local, u)] = true; deleted_vertices.push_back(u); } // Relax each light edge. Dist u_dist = get(distance, u); BGL_FORALL_OUTEDGES_T(u, e, g, Graph) if (get(weight, e) <= delta) // light edge relax(u, target(e, g), u_dist + get(weight, e)); } } // Synchronize with all of the other processes. synchronize(); // Is the bucket empty now? nonempty_bucket = (current_bucket < buckets.size() && buckets[current_bucket] && !buckets[current_bucket]->empty()); } while (all_reduce(pg, nonempty_bucket, std::logical_or<bool>())); // Relax heavy edges for each of the vertices that we previously // deleted. for (typename std::vector<Vertex>::iterator iter = deleted_vertices.begin(); iter != deleted_vertices.end(); ++iter) { // Relax each heavy edge. Vertex u = *iter; Dist u_dist = get(distance, u); BGL_FORALL_OUTEDGES_T(u, e, g, Graph) if (get(weight, e) > delta) // heavy edge relax(u, target(e, g), u_dist + get(weight, e)); #ifdef COMPUTE_PATH_COUNTS_INLINE // Set outgoing paths IncomingType in = get(incoming, u); for (typename IncomingType::iterator pred = in.begin(); pred != in.end(); ++pred) if (get(owner, *pred) == id) { IncomingType x = get(outgoing, *pred); if (std::find(x.begin(), x.end(), u) == x.end()) x.push_back(u); put(outgoing, *pred, x); } else { IncomingType in; in.push_back(u); put(outgoing, *pred, in); } // Set incoming edge counts put(incoming_edge_count, u, in.size()); #endif } #ifdef COMPUTE_PATH_COUNTS_INLINE synchronize(); // Deliver heavy edge relaxations and outgoing paths // Build Queue typedef typename property_traits<PathCountMap>::value_type PathCountType; typedef std::pair<Vertex, PathCountType> queue_value_type; typedef typename property_map<Graph, vertex_owner_t>::const_type OwnerMap; typedef typename get_owner_of_first_pair_element<OwnerMap> IndirectOwnerMap; typedef boost::queue<queue_value_type> local_queue_type; typedef boost::graph::distributed::distributed_queue<process_group_type, IndirectOwnerMap, local_queue_type> dist_queue_type; IndirectOwnerMap indirect_owner(owner); dist_queue_type Q(pg, indirect_owner); // Find sources to initialize queue BGL_FORALL_VERTICES_T(v, g, Graph) { if (get(is_settled, v) && !(get(outgoing, v).empty())) { put(incoming_edge_count, v, 1); Q.push(std::make_pair(v, 0)); // Push this vertex with no additional path count } } // Set path counts for vertices in this bucket while (!Q.empty()) { queue_value_type t = Q.top(); Q.pop(); Vertex v = t.first; PathCountType p = t.second; put(path_count, v, get(path_count, v) + p); put(incoming_edge_count, v, get(incoming_edge_count, v) - 1); if (get(incoming_edge_count, v) == 0) { IncomingType out = get(outgoing, v); for (typename IncomingType::iterator iter = out.begin(); iter != out.end(); ++iter) Q.push(std::make_pair(*iter, get(path_count, v))); } } // Mark the vertices in this bucket settled for (typename std::vector<Vertex>::iterator iter = deleted_vertices.begin(); iter != deleted_vertices.end(); ++iter) put(is_settled, *iter, true); // No need to clear path count map as it is never read/written remotely // No need to clear outgoing map as it is re-alloced every bucket #endif // Go to the next bucket: the current bucket must already be empty. ++current_bucket; } while (true); // Delete all of the buckets. for (typename std::vector<Bucket*>::iterator iter = buckets.begin(); iter != buckets.end(); ++iter) { if (*iter) { delete *iter; *iter = 0; } } } template<typename Graph, typename DistanceMap, typename IncomingMap, typename EdgeWeightMap, typename PathCountMap #ifdef COMPUTE_PATH_COUNTS_INLINE , typename IsSettledMap, typename VertexIndexMap #endif > void betweenness_centrality_delta_stepping_impl< Graph, DistanceMap, IncomingMap, EdgeWeightMap, PathCountMap #ifdef COMPUTE_PATH_COUNTS_INLINE , IsSettledMap, VertexIndexMap #endif >:: relax(Vertex u, Vertex v, Dist x) { if (x <= get(distance, v)) { // We're relaxing the edge to vertex v. if (get(owner, v) == process_id(pg)) { if (x < get(distance, v)) { // Compute the new bucket index for v BucketIndex new_index = static_cast<BucketIndex>(x / delta); // Make sure there is enough room in the buckets data structure. if (new_index >= buckets.size()) buckets.resize(new_index + 1, 0); // Make sure that we have allocated the bucket itself. if (!buckets[new_index]) buckets[new_index] = new Bucket; if (get(distance, v) != (std::numeric_limits<Dist>::max)() && !vertex_was_deleted[get(local, v)]) { // We're moving v from an old bucket into a new one. Compute // the old index, then splice it in. BucketIndex old_index = static_cast<BucketIndex>(get(distance, v) / delta); buckets[new_index]->splice(buckets[new_index]->end(), *buckets[old_index], position_in_bucket[get(local, v)]); } else { // We're inserting v into a bucket for the first time. Put it // at the end. buckets[new_index]->push_back(v); } // v is now at the last position in the new bucket position_in_bucket[get(local, v)] = buckets[new_index]->end(); --position_in_bucket[get(local, v)]; // Update tentative distance information and incoming, path_count if (u != v) put(incoming, v, IncomingType(1, u)); put(distance, v, x); } // u != v covers initial source relaxation and self-loops else if (x == get(distance, v) && u != v) { // Add incoming edge if it's not already in the list IncomingType in = get(incoming, v); if (std::find(in.begin(), in.end(), u) == in.end()) { in.push_back(u); put(incoming, v, in); } } } else { // The vertex is remote: send a request to the vertex's owner send(pg, get(owner, v), msg_relax, std::make_pair(v, MessageValue::create(x, u))); // Cache tentative distance information cache(distance, v, x); } } } /************************************************************************/ /* Shortest Paths function object for betweenness centrality */ /************************************************************************/ template<typename WeightMap> struct brandes_shortest_paths { typedef typename property_traits<WeightMap>::value_type weight_type; brandes_shortest_paths() : weight(1), delta(0) { } brandes_shortest_paths(weight_type delta) : weight(1), delta(delta) { } brandes_shortest_paths(WeightMap w) : weight(w), delta(0) { } brandes_shortest_paths(WeightMap w, weight_type delta) : weight(w), delta(delta) { } template<typename Graph, typename IncomingMap, typename DistanceMap, typename PathCountMap #ifdef COMPUTE_PATH_COUNTS_INLINE , typename IsSettledMap, typename VertexIndexMap #endif > void operator()(Graph& g, typename graph_traits<Graph>::vertex_descriptor s, IncomingMap incoming, DistanceMap distance, PathCountMap path_count #ifdef COMPUTE_PATH_COUNTS_INLINE , IsSettledMap is_settled, VertexIndexMap vertex_index #endif ) { // The "distance" map needs to act like one, retrieving the default // value of infinity. set_property_map_role(vertex_distance, distance); // Only calculate delta the first time operator() is called // This presumes g is the same every time, but so does the fact // that we're reusing the weight map if (delta == 0) set_delta(g); // TODO (NGE): Restructure the code so we don't have to construct // impl every time? betweenness_centrality_delta_stepping_impl< Graph, DistanceMap, IncomingMap, WeightMap, PathCountMap #ifdef COMPUTE_PATH_COUNTS_INLINE , IsSettledMap, VertexIndexMap #endif > impl(g, distance, incoming, weight, path_count, #ifdef COMPUTE_PATH_COUNTS_INLINE is_settled, vertex_index, #endif delta); impl.run(s); } private: template <typename Graph> void set_delta(const Graph& g) { using boost::parallel::all_reduce; using boost::parallel::maximum; using std::max; typedef typename graph_traits<Graph>::degree_size_type Degree; typedef weight_type Dist; // Compute the maximum edge weight and degree Dist max_edge_weight = 0; Degree max_degree = 0; BGL_FORALL_VERTICES_T(u, g, Graph) { max_degree = max BOOST_PREVENT_MACRO_SUBSTITUTION (max_degree, out_degree(u, g)); BGL_FORALL_OUTEDGES_T(u, e, g, Graph) max_edge_weight = max BOOST_PREVENT_MACRO_SUBSTITUTION (max_edge_weight, get(weight, e)); } max_edge_weight = all_reduce(process_group(g), max_edge_weight, maximum<Dist>()); max_degree = all_reduce(process_group(g), max_degree, maximum<Degree>()); // Take a guess at delta, based on what works well for random // graphs. delta = max_edge_weight / max_degree; if (delta == 0) delta = 1; } WeightMap weight; weight_type delta; }; // Perform a single SSSP from the specified vertex and update the centrality map(s) template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename IncomingMap, typename DistanceMap, typename DependencyMap, typename PathCountMap, #ifdef COMPUTE_PATH_COUNTS_INLINE typename IsSettledMap, #endif typename VertexIndexMap, typename ShortestPaths> void do_brandes_sssp(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, IncomingMap incoming, DistanceMap distance, DependencyMap dependency, PathCountMap path_count, #ifdef COMPUTE_PATH_COUNTS_INLINE IsSettledMap is_settled, #endif VertexIndexMap vertex_index, ShortestPaths shortest_paths, typename graph_traits<Graph>::vertex_descriptor s) { using boost::detail::graph::update_centrality; using boost::graph::parallel::process_group; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename graph_traits<Graph>::edges_size_type edges_size_type; typedef typename property_traits<IncomingMap>::value_type incoming_type; typedef typename property_traits<DistanceMap>::value_type distance_type; typedef typename property_traits<DependencyMap>::value_type dependency_type; typedef typename property_traits<PathCountMap>::value_type path_count_type; typedef typename incoming_type::iterator incoming_iterator; typedef typename property_map<Graph, vertex_owner_t>::const_type OwnerMap; OwnerMap owner = get(vertex_owner, g); typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type; process_group_type pg = process_group(g); typename process_group_type::process_id_type id = process_id(pg); // TODO: Is it faster not to clear some of these maps? // Initialize for this iteration distance.clear(); incoming.clear(); path_count.clear(); dependency.clear(); BGL_FORALL_VERTICES_T(v, g, Graph) { put(path_count, v, 0); put(dependency, v, 0); } if (get(owner, s) == id) { put(incoming, s, incoming_type()); #ifdef COMPUTE_PATH_COUNTS_INLINE put(path_count, s, 1); put(is_settled, s, true); #endif } // Execute the shortest paths algorithm. This will be either // a weighted or unweighted customized breadth-first search, shortest_paths(g, s, incoming, distance, path_count #ifdef COMPUTE_PATH_COUNTS_INLINE , is_settled, vertex_index #endif ); #ifndef COMPUTE_PATH_COUNTS_INLINE // // TODO: Optimize case where source has no out-edges // // Count of incoming edges to tell when all incoming edges have been relaxed in // the induced shortest paths DAG std::vector<edges_size_type> incoming_edge_countS(num_vertices(g)); iterator_property_map<typename std::vector<edges_size_type>::iterator, VertexIndexMap> incoming_edge_count(incoming_edge_countS.begin(), vertex_index); BGL_FORALL_VERTICES_T(v, g, Graph) { put(incoming_edge_count, v, get(incoming, v).size()); } if (get(owner, s) == id) { put(incoming_edge_count, s, 1); put(incoming, s, incoming_type()); } std::vector<incoming_type> outgoingS(num_vertices(g)); iterator_property_map<typename std::vector<incoming_type>::iterator, VertexIndexMap> outgoing(outgoingS.begin(), vertex_index); outgoing.set_reduce(append_reducer<incoming_type>()); // Mark forward adjacencies in DAG of shortest paths // TODO: It's possible to do this using edge flags but it's not currently done this way // because during traversal of the DAG we would have to examine all out edges // which would lead to more memory accesses and a larger cache footprint. // // In the bidirectional graph case edge flags would be an excellent way of marking // edges in the DAG of shortest paths BGL_FORALL_VERTICES_T(v, g, Graph) { incoming_type i = get(incoming, v); for (typename incoming_type::iterator iter = i.begin(); iter != i.end(); ++iter) { if (get(owner, *iter) == id) { incoming_type x = get(outgoing, *iter); if (std::find(x.begin(), x.end(), v) == x.end()) x.push_back(v); put(outgoing, *iter, x); } else { incoming_type in; in.push_back(v); put(outgoing, *iter, in); } } } synchronize(pg); // Traverse DAG induced by forward edges in dependency order and compute path counts { typedef std::pair<vertex_descriptor, path_count_type> queue_value_type; typedef get_owner_of_first_pair_element<OwnerMap> IndirectOwnerMap; typedef boost::queue<queue_value_type> local_queue_type; typedef boost::graph::distributed::distributed_queue<process_group_type, IndirectOwnerMap, local_queue_type> dist_queue_type; IndirectOwnerMap indirect_owner(owner); dist_queue_type Q(pg, indirect_owner); if (get(owner, s) == id) Q.push(std::make_pair(s, 1)); while (!Q.empty()) { queue_value_type t = Q.top(); Q.pop(); vertex_descriptor v = t.first; path_count_type p = t.second; put(path_count, v, get(path_count, v) + p); put(incoming_edge_count, v, get(incoming_edge_count, v) - 1); if (get(incoming_edge_count, v) == 0) { incoming_type out = get(outgoing, v); for (typename incoming_type::iterator iter = out.begin(); iter != out.end(); ++iter) Q.push(std::make_pair(*iter, get(path_count, v))); } } } #endif // COMPUTE_PATH_COUNTS_INLINE // // Compute dependencies // // Build the distributed_queue // Value type consists of 1) target of update 2) source of update // 3) dependency of source 4) path count of source typedef boost::tuple<vertex_descriptor, vertex_descriptor, dependency_type, path_count_type> queue_value_type; typedef get_owner_of_first_tuple_element<OwnerMap, queue_value_type> IndirectOwnerMap; typedef boost::queue<queue_value_type> local_queue_type; typedef boost::graph::distributed::distributed_queue<process_group_type, IndirectOwnerMap, local_queue_type> dist_queue_type; IndirectOwnerMap indirect_owner(owner); dist_queue_type Q(pg, indirect_owner); // Calculate number of vertices each vertex depends on, when a vertex has been pushed // that number of times then we will update it // AND Request path counts of sources of incoming edges std::vector<dependency_type> dependency_countS(num_vertices(g), 0); iterator_property_map<typename std::vector<dependency_type>::iterator, VertexIndexMap> dependency_count(dependency_countS.begin(), vertex_index); dependency_count.set_reduce(boost::graph::distributed::additive_reducer<dependency_type>()); path_count.set_max_ghost_cells(0); BGL_FORALL_VERTICES_T(v, g, Graph) { if (get(distance, v) < (std::numeric_limits<distance_type>::max)()) { incoming_type el = get(incoming, v); for (incoming_iterator vw = el.begin(); vw != el.end(); ++vw) { if (get(owner, *vw) == id) put(dependency_count, *vw, get(dependency_count, *vw) + 1); else { put(dependency_count, *vw, 1); // Request path counts get(path_count, *vw); } // request() doesn't work here, perhaps because we don't have a copy of this // ghost cell already? } } } synchronize(pg); // Push vertices with non-zero distance/path count and zero dependency count BGL_FORALL_VERTICES_T(v, g, Graph) { if (get(distance, v) < (std::numeric_limits<distance_type>::max)() && get(dependency_count, v) == 0) Q.push(boost::make_tuple(v, v, get(dependency, v), get(path_count, v))); } dependency.set_max_ghost_cells(0); while(!Q.empty()) { queue_value_type x = Q.top(); Q.pop(); vertex_descriptor w = boost::tuples::get<0>(x); vertex_descriptor source = boost::tuples::get<1>(x); dependency_type dep = boost::tuples::get<2>(x); path_count_type pc = boost::tuples::get<3>(x); cache(dependency, source, dep); cache(path_count, source, pc); if (get(dependency_count, w) != 0) put(dependency_count, w, get(dependency_count, w) - 1); if (get(dependency_count, w) == 0) { // Update dependency and centrality of sources of incoming edges incoming_type el = get(incoming, w); for (incoming_iterator vw = el.begin(); vw != el.end(); ++vw) { vertex_descriptor v = *vw; BOOST_ASSERT(get(path_count, w) != 0); dependency_type factor = dependency_type(get(path_count, v)) / dependency_type(get(path_count, w)); factor *= (dependency_type(1) + get(dependency, w)); if (get(owner, v) == id) put(dependency, v, get(dependency, v) + factor); else put(dependency, v, factor); update_centrality(edge_centrality_map, v, factor); } if (w != s) update_centrality(centrality, w, get(dependency, w)); // Push sources of edges in incoming edge list for (incoming_iterator vw = el.begin(); vw != el.end(); ++vw) Q.push(boost::make_tuple(*vw, w, get(dependency, w), get(path_count, w))); } } } template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename IncomingMap, typename DistanceMap, typename DependencyMap, typename PathCountMap, typename VertexIndexMap, typename ShortestPaths, typename Buffer> void brandes_betweenness_centrality_impl(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, IncomingMap incoming, DistanceMap distance, DependencyMap dependency, PathCountMap path_count, VertexIndexMap vertex_index, ShortestPaths shortest_paths, Buffer sources) { using boost::detail::graph::init_centrality_map; using boost::detail::graph::divide_centrality_by_two; using boost::graph::parallel::process_group; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename property_traits<DistanceMap>::value_type distance_type; typedef typename property_traits<DependencyMap>::value_type dependency_type; // Initialize centrality init_centrality_map(vertices(g), centrality); init_centrality_map(edges(g), edge_centrality_map); // Set the reduction operation on the dependency map to be addition dependency.set_reduce(boost::graph::distributed::additive_reducer<dependency_type>()); distance.set_reduce(boost::graph::distributed::choose_min_reducer<distance_type>()); // Don't allow remote procs to write incoming or path_count maps // updating them is handled inside the betweenness_centrality_queue incoming.set_consistency_model(0); path_count.set_consistency_model(0); typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type; process_group_type pg = process_group(g); #ifdef COMPUTE_PATH_COUNTS_INLINE // Build is_settled maps std::vector<bool> is_settledS(num_vertices(g)); typedef iterator_property_map<std::vector<bool>::iterator, VertexIndexMap> IsSettledMap; IsSettledMap is_settled(is_settledS.begin(), vertex_index); #endif if (!sources.empty()) { // DO SSSPs while (!sources.empty()) { do_brandes_sssp(g, centrality, edge_centrality_map, incoming, distance, dependency, path_count, #ifdef COMPUTE_PATH_COUNTS_INLINE is_settled, #endif vertex_index, shortest_paths, sources.top()); sources.pop(); } } else { // Exact Betweenness Centrality typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type; vertices_size_type n = num_vertices(g); n = boost::parallel::all_reduce(pg, n, std::plus<vertices_size_type>()); for (vertices_size_type i = 0; i < n; ++i) { vertex_descriptor v = vertex(i, g); do_brandes_sssp(g, centrality, edge_centrality_map, incoming, distance, dependency, path_count, #ifdef COMPUTE_PATH_COUNTS_INLINE is_settled, #endif vertex_index, shortest_paths, v); } } typedef typename graph_traits<Graph>::directed_category directed_category; const bool is_undirected = is_convertible<directed_category*, undirected_tag*>::value; if (is_undirected) { divide_centrality_by_two(vertices(g), centrality); divide_centrality_by_two(edges(g), edge_centrality_map); } } template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename IncomingMap, typename DistanceMap, typename DependencyMap, typename PathCountMap, typename VertexIndexMap, typename ShortestPaths, typename Stack> void do_sequential_brandes_sssp(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, IncomingMap incoming, DistanceMap distance, DependencyMap dependency, PathCountMap path_count, VertexIndexMap vertex_index, ShortestPaths shortest_paths, Stack& ordered_vertices, typename graph_traits<Graph>::vertex_descriptor v) { using boost::detail::graph::update_centrality; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; // Initialize for this iteration BGL_FORALL_VERTICES_T(w, g, Graph) { // put(path_count, w, 0); incoming[w].clear(); put(dependency, w, 0); } put(path_count, v, 1); incoming[v].clear(); // Execute the shortest paths algorithm. This will be either // Dijkstra's algorithm or a customized breadth-first search, // depending on whether the graph is weighted or unweighted. shortest_paths(g, v, ordered_vertices, incoming, distance, path_count, vertex_index); while (!ordered_vertices.empty()) { vertex_descriptor w = ordered_vertices.top(); ordered_vertices.pop(); typedef typename property_traits<IncomingMap>::value_type incoming_type; typedef typename incoming_type::iterator incoming_iterator; typedef typename property_traits<DependencyMap>::value_type dependency_type; for (incoming_iterator vw = incoming[w].begin(); vw != incoming[w].end(); ++vw) { vertex_descriptor v = source(*vw, g); dependency_type factor = dependency_type(get(path_count, v)) / dependency_type(get(path_count, w)); factor *= (dependency_type(1) + get(dependency, w)); put(dependency, v, get(dependency, v) + factor); update_centrality(edge_centrality_map, *vw, factor); } if (w != v) { update_centrality(centrality, w, get(dependency, w)); } } } // Betweenness Centrality variant that duplicates graph across processors // and parallizes SSSPs // This function expects a non-distributed graph and property-maps template<typename ProcessGroup, typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename IncomingMap, typename DistanceMap, typename DependencyMap, typename PathCountMap, typename VertexIndexMap, typename ShortestPaths, typename Buffer> void non_distributed_brandes_betweenness_centrality_impl(const ProcessGroup& pg, const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, IncomingMap incoming, // P DistanceMap distance, // d DependencyMap dependency, // delta PathCountMap path_count, // sigma VertexIndexMap vertex_index, ShortestPaths shortest_paths, Buffer sources) { using boost::detail::graph::init_centrality_map; using boost::detail::graph::divide_centrality_by_two; using boost::graph::parallel::process_group; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef ProcessGroup process_group_type; typename process_group_type::process_id_type id = process_id(pg); typename process_group_type::process_size_type p = num_processes(pg); // Initialize centrality init_centrality_map(vertices(g), centrality); init_centrality_map(edges(g), edge_centrality_map); std::stack<vertex_descriptor> ordered_vertices; if (!sources.empty()) { std::vector<vertex_descriptor> local_sources; for (int i = 0; i < id; ++i) if (!sources.empty()) sources.pop(); while (!sources.empty()) { local_sources.push_back(sources.top()); for (int i = 0; i < p; ++i) if (!sources.empty()) sources.pop(); } // DO SSSPs for(size_t i = 0; i < local_sources.size(); ++i) do_sequential_brandes_sssp(g, centrality, edge_centrality_map, incoming, distance, dependency, path_count, vertex_index, shortest_paths, ordered_vertices, local_sources[i]); } else { // Exact Betweenness Centrality typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type; vertices_size_type n = num_vertices(g); for (vertices_size_type i = id; i < n; i += p) { vertex_descriptor v = vertex(i, g); do_sequential_brandes_sssp(g, centrality, edge_centrality_map, incoming, distance, dependency, path_count, vertex_index, shortest_paths, ordered_vertices, v); } } typedef typename graph_traits<Graph>::directed_category directed_category; const bool is_undirected = is_convertible<directed_category*, undirected_tag*>::value; if (is_undirected) { divide_centrality_by_two(vertices(g), centrality); divide_centrality_by_two(edges(g), edge_centrality_map); } // Merge the centrality maps by summing the values at each vertex) // TODO(nge): this copy-out, reduce, copy-in is lame typedef typename property_traits<CentralityMap>::value_type centrality_type; typedef typename property_traits<EdgeCentralityMap>::value_type edge_centrality_type; std::vector<centrality_type> centrality_v(num_vertices(g)); std::vector<edge_centrality_type> edge_centrality_v; edge_centrality_v.reserve(num_edges(g)); BGL_FORALL_VERTICES_T(v, g, Graph) { centrality_v[get(vertex_index, v)] = get(centrality, v); } // Skip when EdgeCentralityMap is a dummy_property_map if (!is_same<EdgeCentralityMap, dummy_property_map>::value) { BGL_FORALL_EDGES_T(e, g, Graph) { edge_centrality_v.push_back(get(edge_centrality_map, e)); } // NGE: If we trust that the order of elements in the vector isn't changed in the // all_reduce below then this method avoids the need for an edge index map } using boost::parallel::all_reduce; all_reduce(pg, ¢rality_v[0], ¢rality_v[centrality_v.size()], ¢rality_v[0], std::plus<centrality_type>()); if (edge_centrality_v.size()) all_reduce(pg, &edge_centrality_v[0], &edge_centrality_v[edge_centrality_v.size()], &edge_centrality_v[0], std::plus<edge_centrality_type>()); BGL_FORALL_VERTICES_T(v, g, Graph) { put(centrality, v, centrality_v[get(vertex_index, v)]); } // Skip when EdgeCentralityMap is a dummy_property_map if (!is_same<EdgeCentralityMap, dummy_property_map>::value) { int i = 0; BGL_FORALL_EDGES_T(e, g, Graph) { put(edge_centrality_map, e, edge_centrality_v[i]); ++i; } } } } } } // end namespace graph::parallel::detail template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename IncomingMap, typename DistanceMap, typename DependencyMap, typename PathCountMap, typename VertexIndexMap, typename Buffer> void brandes_betweenness_centrality(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, IncomingMap incoming, DistanceMap distance, DependencyMap dependency, PathCountMap path_count, VertexIndexMap vertex_index, Buffer sources, typename property_traits<DistanceMap>::value_type delta BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { typedef typename property_traits<DistanceMap>::value_type distance_type; typedef static_property_map<distance_type> WeightMap; graph::parallel::detail::brandes_shortest_paths<WeightMap> shortest_paths(delta); graph::parallel::detail::brandes_betweenness_centrality_impl(g, centrality, edge_centrality_map, incoming, distance, dependency, path_count, vertex_index, shortest_paths, sources); } template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename IncomingMap, typename DistanceMap, typename DependencyMap, typename PathCountMap, typename VertexIndexMap, typename WeightMap, typename Buffer> void brandes_betweenness_centrality(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, IncomingMap incoming, DistanceMap distance, DependencyMap dependency, PathCountMap path_count, VertexIndexMap vertex_index, Buffer sources, typename property_traits<WeightMap>::value_type delta, WeightMap weight_map BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { graph::parallel::detail::brandes_shortest_paths<WeightMap> shortest_paths(weight_map, delta); graph::parallel::detail::brandes_betweenness_centrality_impl(g, centrality, edge_centrality_map, incoming, distance, dependency, path_count, vertex_index, shortest_paths, sources); } namespace graph { namespace parallel { namespace detail { template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename WeightMap, typename VertexIndexMap, typename Buffer> void brandes_betweenness_centrality_dispatch2(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, WeightMap weight_map, VertexIndexMap vertex_index, Buffer sources, typename property_traits<WeightMap>::value_type delta) { typedef typename graph_traits<Graph>::degree_size_type degree_size_type; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename mpl::if_c<(is_same<CentralityMap, dummy_property_map>::value), EdgeCentralityMap, CentralityMap>::type a_centrality_map; typedef typename property_traits<a_centrality_map>::value_type centrality_type; typename graph_traits<Graph>::vertices_size_type V = num_vertices(g); std::vector<std::vector<vertex_descriptor> > incoming(V); std::vector<centrality_type> distance(V); std::vector<centrality_type> dependency(V); std::vector<degree_size_type> path_count(V); brandes_betweenness_centrality( g, centrality, edge_centrality_map, make_iterator_property_map(incoming.begin(), vertex_index), make_iterator_property_map(distance.begin(), vertex_index), make_iterator_property_map(dependency.begin(), vertex_index), make_iterator_property_map(path_count.begin(), vertex_index), vertex_index, unwrap_ref(sources), delta, weight_map); } // TODO: Should the type of the distance and dependency map depend on the // value type of the centrality map? template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename VertexIndexMap, typename Buffer> void brandes_betweenness_centrality_dispatch2(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index, Buffer sources, typename graph_traits<Graph>::edges_size_type delta) { typedef typename graph_traits<Graph>::degree_size_type degree_size_type; typedef typename graph_traits<Graph>::edges_size_type edges_size_type; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typename graph_traits<Graph>::vertices_size_type V = num_vertices(g); std::vector<std::vector<vertex_descriptor> > incoming(V); std::vector<edges_size_type> distance(V); std::vector<edges_size_type> dependency(V); std::vector<degree_size_type> path_count(V); brandes_betweenness_centrality( g, centrality, edge_centrality_map, make_iterator_property_map(incoming.begin(), vertex_index), make_iterator_property_map(distance.begin(), vertex_index), make_iterator_property_map(dependency.begin(), vertex_index), make_iterator_property_map(path_count.begin(), vertex_index), vertex_index, unwrap_ref(sources), delta); } template<typename WeightMap> struct brandes_betweenness_centrality_dispatch1 { template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename VertexIndexMap, typename Buffer> static void run(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index, Buffer sources, typename property_traits<WeightMap>::value_type delta, WeightMap weight_map) { boost::graph::parallel::detail::brandes_betweenness_centrality_dispatch2( g, centrality, edge_centrality_map, weight_map, vertex_index, sources, delta); } }; template<> struct brandes_betweenness_centrality_dispatch1<boost::param_not_found> { template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename VertexIndexMap, typename Buffer> static void run(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index, Buffer sources, typename graph_traits<Graph>::edges_size_type delta, boost::param_not_found) { boost::graph::parallel::detail::brandes_betweenness_centrality_dispatch2( g, centrality, edge_centrality_map, vertex_index, sources, delta); } }; } } } // end namespace graph::parallel::detail template<typename Graph, typename Param, typename Tag, typename Rest> void brandes_betweenness_centrality(const Graph& g, const bgl_named_params<Param,Tag,Rest>& params BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { typedef bgl_named_params<Param,Tag,Rest> named_params; typedef queue<typename graph_traits<Graph>::vertex_descriptor> queue_t; queue_t q; typedef typename get_param_type<edge_weight_t, named_params>::type ew_param; typedef typename detail::choose_impl_result<mpl::true_, Graph, ew_param, edge_weight_t>::type ew; graph::parallel::detail::brandes_betweenness_centrality_dispatch1<ew>::run( g, choose_param(get_param(params, vertex_centrality), dummy_property_map()), choose_param(get_param(params, edge_centrality), dummy_property_map()), choose_const_pmap(get_param(params, vertex_index), g, vertex_index), choose_param(get_param(params, buffer_param_t()), boost::ref(q)), choose_param(get_param(params, lookahead_t()), 0), choose_const_pmap(get_param(params, edge_weight), g, edge_weight)); } template<typename Graph, typename CentralityMap> void brandes_betweenness_centrality(const Graph& g, CentralityMap centrality BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { typedef queue<typename graph_traits<Graph>::vertex_descriptor> queue_t; queue_t q; boost::graph::parallel::detail::brandes_betweenness_centrality_dispatch2( g, centrality, dummy_property_map(), get(vertex_index, g), boost::ref(q), 0); } template<typename Graph, typename CentralityMap, typename EdgeCentralityMap> void brandes_betweenness_centrality(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { typedef queue<int> queue_t; queue_t q; boost::graph::parallel::detail::brandes_betweenness_centrality_dispatch2( g, centrality, edge_centrality_map, get(vertex_index, g), boost::ref(q), 0); } template<typename ProcessGroup, typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename IncomingMap, typename DistanceMap, typename DependencyMap, typename PathCountMap, typename VertexIndexMap, typename Buffer> void non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg, const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, IncomingMap incoming, DistanceMap distance, DependencyMap dependency, PathCountMap path_count, VertexIndexMap vertex_index, Buffer sources) { detail::graph::brandes_unweighted_shortest_paths shortest_paths; graph::parallel::detail::non_distributed_brandes_betweenness_centrality_impl(pg, g, centrality, edge_centrality_map, incoming, distance, dependency, path_count, vertex_index, shortest_paths, sources); } template<typename ProcessGroup, typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename IncomingMap, typename DistanceMap, typename DependencyMap, typename PathCountMap, typename VertexIndexMap, typename WeightMap, typename Buffer> void non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg, const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, IncomingMap incoming, DistanceMap distance, DependencyMap dependency, PathCountMap path_count, VertexIndexMap vertex_index, WeightMap weight_map, Buffer sources) { detail::graph::brandes_dijkstra_shortest_paths<WeightMap> shortest_paths(weight_map); graph::parallel::detail::non_distributed_brandes_betweenness_centrality_impl(pg, g, centrality, edge_centrality_map, incoming, distance, dependency, path_count, vertex_index, shortest_paths, sources); } namespace detail { namespace graph { template<typename ProcessGroup, typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename WeightMap, typename VertexIndexMap, typename Buffer> void non_distributed_brandes_betweenness_centrality_dispatch2(const ProcessGroup& pg, const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, WeightMap weight_map, VertexIndexMap vertex_index, Buffer sources) { typedef typename graph_traits<Graph>::degree_size_type degree_size_type; typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor; typedef typename mpl::if_c<(is_same<CentralityMap, dummy_property_map>::value), EdgeCentralityMap, CentralityMap>::type a_centrality_map; typedef typename property_traits<a_centrality_map>::value_type centrality_type; typename graph_traits<Graph>::vertices_size_type V = num_vertices(g); std::vector<std::vector<edge_descriptor> > incoming(V); std::vector<centrality_type> distance(V); std::vector<centrality_type> dependency(V); std::vector<degree_size_type> path_count(V); non_distributed_brandes_betweenness_centrality( pg, g, centrality, edge_centrality_map, make_iterator_property_map(incoming.begin(), vertex_index), make_iterator_property_map(distance.begin(), vertex_index), make_iterator_property_map(dependency.begin(), vertex_index), make_iterator_property_map(path_count.begin(), vertex_index), vertex_index, weight_map, unwrap_ref(sources)); } template<typename ProcessGroup, typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename VertexIndexMap, typename Buffer> void non_distributed_brandes_betweenness_centrality_dispatch2(const ProcessGroup& pg, const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index, Buffer sources) { typedef typename graph_traits<Graph>::degree_size_type degree_size_type; typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor; typedef typename mpl::if_c<(is_same<CentralityMap, dummy_property_map>::value), EdgeCentralityMap, CentralityMap>::type a_centrality_map; typedef typename property_traits<a_centrality_map>::value_type centrality_type; typename graph_traits<Graph>::vertices_size_type V = num_vertices(g); std::vector<std::vector<edge_descriptor> > incoming(V); std::vector<centrality_type> distance(V); std::vector<centrality_type> dependency(V); std::vector<degree_size_type> path_count(V); non_distributed_brandes_betweenness_centrality( pg, g, centrality, edge_centrality_map, make_iterator_property_map(incoming.begin(), vertex_index), make_iterator_property_map(distance.begin(), vertex_index), make_iterator_property_map(dependency.begin(), vertex_index), make_iterator_property_map(path_count.begin(), vertex_index), vertex_index, unwrap_ref(sources)); } template<typename WeightMap> struct non_distributed_brandes_betweenness_centrality_dispatch1 { template<typename ProcessGroup, typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename VertexIndexMap, typename Buffer> static void run(const ProcessGroup& pg, const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index, Buffer sources, WeightMap weight_map) { non_distributed_brandes_betweenness_centrality_dispatch2(pg, g, centrality, edge_centrality_map, weight_map, vertex_index, sources); } }; template<> struct non_distributed_brandes_betweenness_centrality_dispatch1<param_not_found> { template<typename ProcessGroup, typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename VertexIndexMap, typename Buffer> static void run(const ProcessGroup& pg, const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index, Buffer sources, param_not_found) { non_distributed_brandes_betweenness_centrality_dispatch2(pg, g, centrality, edge_centrality_map, vertex_index, sources); } }; } } // end namespace detail::graph template<typename ProcessGroup, typename Graph, typename Param, typename Tag, typename Rest> void non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg, const Graph& g, const bgl_named_params<Param,Tag,Rest>& params) { typedef bgl_named_params<Param,Tag,Rest> named_params; typedef queue<int> queue_t; queue_t q; typedef typename get_param_type<edge_weight_t, named_params>::type ew_param; typedef typename detail::choose_impl_result<mpl::true_, Graph, ew_param, edge_weight_t>::type ew; detail::graph::non_distributed_brandes_betweenness_centrality_dispatch1<ew>::run( pg, g, choose_param(get_param(params, vertex_centrality), dummy_property_map()), choose_param(get_param(params, edge_centrality), dummy_property_map()), choose_const_pmap(get_param(params, vertex_index), g, vertex_index), choose_param(get_param(params, buffer_param_t()), boost::ref(q)), choose_const_pmap(get_param(params, edge_weight), g, edge_weight)); } template<typename ProcessGroup, typename Graph, typename CentralityMap> void non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg, const Graph& g, CentralityMap centrality) { typedef queue<int> queue_t; queue_t q; detail::graph::non_distributed_brandes_betweenness_centrality_dispatch2( pg, g, centrality, dummy_property_map(), get(vertex_index, g), boost::ref(q)); } template<typename ProcessGroup, typename Graph, typename CentralityMap, typename Buffer> void non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg, const Graph& g, CentralityMap centrality, Buffer sources) { detail::graph::non_distributed_brandes_betweenness_centrality_dispatch2( pg, g, centrality, dummy_property_map(), get(vertex_index, g), sources); } template<typename ProcessGroup, typename Graph, typename CentralityMap, typename EdgeCentralityMap, typename Buffer> void non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg, const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, Buffer sources) { detail::graph::non_distributed_brandes_betweenness_centrality_dispatch2( pg, g, centrality, edge_centrality_map, get(vertex_index, g), sources); } // Compute the central point dominance of a graph. // TODO: Make sure central point dominance works in parallel case template<typename Graph, typename CentralityMap> typename property_traits<CentralityMap>::value_type central_point_dominance(const Graph& g, CentralityMap centrality BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { using std::max; typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator; typedef typename property_traits<CentralityMap>::value_type centrality_type; typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type; typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type; process_group_type pg = boost::graph::parallel::process_group(g); vertices_size_type n = num_vertices(g); using boost::parallel::all_reduce; n = all_reduce(pg, n, std::plus<vertices_size_type>()); // Find max centrality centrality_type max_centrality(0); vertex_iterator v, v_end; for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) { max_centrality = (max)(max_centrality, get(centrality, *v)); } // All reduce to get global max centrality max_centrality = all_reduce(pg, max_centrality, boost::parallel::maximum<centrality_type>()); // Compute central point dominance centrality_type sum(0); for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) { sum += (max_centrality - get(centrality, *v)); } sum = all_reduce(pg, sum, std::plus<centrality_type>()); return sum/(n-1); } } // end namespace boost #endif // BOOST_GRAPH_PARALLEL_BRANDES_BETWEENNESS_CENTRALITY_HPP distributed/local_subgraph.hpp 0000644 00000013651 15125521275 0012577 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_LOCAL_SUBGRAPH_HPP #define BOOST_GRAPH_LOCAL_SUBGRAPH_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/graph_traits.hpp> #include <boost/graph/filtered_graph.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/type_traits/is_base_and_derived.hpp> #include <boost/graph/parallel/container_traits.hpp> namespace boost { namespace graph { namespace detail { // Optionally, virtually derive from a base class template<bool Derive, typename Base> struct derive_from_if; template<typename Base> struct derive_from_if<true, Base> : virtual Base {}; template<typename Base> struct derive_from_if<false, Base> {}; template<typename NewBase, typename Tag, typename OldBase = NewBase> struct derive_from_if_tag_is : derive_from_if<(is_base_and_derived<OldBase, Tag>::value || is_same<OldBase, Tag>::value), NewBase> { }; } } // end namespace graph::detail template<typename DistributedGraph> class is_local_edge { public: typedef bool result_type; typedef typename graph_traits<DistributedGraph>::edge_descriptor argument_type; is_local_edge() : g(0) {} is_local_edge(DistributedGraph& g) : g(&g), owner(get(vertex_owner, g)) {} // Since either the source or target vertex must be local, the // equivalence of their owners indicates a local edge. result_type operator()(const argument_type& e) const { return get(owner, source(e, *g)) == get(owner, target(e, *g)); } private: DistributedGraph* g; typename property_map<DistributedGraph, vertex_owner_t>::const_type owner; }; template<typename DistributedGraph> class is_local_vertex { public: typedef bool result_type; typedef typename graph_traits<DistributedGraph>::vertex_descriptor argument_type; is_local_vertex() : g(0) {} is_local_vertex(DistributedGraph& g) : g(&g), owner(get(vertex_owner, g)) { } // Since either the source or target vertex must be local, the // equivalence of their owners indicates a local edge. result_type operator()(const argument_type& v) const { return get(owner, v) == process_id(process_group(*g)); } private: DistributedGraph* g; typename property_map<DistributedGraph, vertex_owner_t>::const_type owner; }; template<typename DistributedGraph> class local_subgraph : public filtered_graph<DistributedGraph, is_local_edge<DistributedGraph>, is_local_vertex<DistributedGraph> > { typedef filtered_graph<DistributedGraph, is_local_edge<DistributedGraph>, is_local_vertex<DistributedGraph> > inherited; typedef typename graph_traits<DistributedGraph>::traversal_category inherited_category; public: struct traversal_category : graph::detail::derive_from_if_tag_is<incidence_graph_tag, inherited_category>, graph::detail::derive_from_if_tag_is<adjacency_graph_tag, inherited_category>, graph::detail::derive_from_if_tag_is<vertex_list_graph_tag, inherited_category>, graph::detail::derive_from_if_tag_is<edge_list_graph_tag, inherited_category>, graph::detail::derive_from_if_tag_is<vertex_list_graph_tag, inherited_category, distributed_vertex_list_graph_tag>, graph::detail::derive_from_if_tag_is<edge_list_graph_tag, inherited_category, distributed_edge_list_graph_tag> { }; local_subgraph(DistributedGraph& g) : inherited(g, is_local_edge<DistributedGraph>(g), is_local_vertex<DistributedGraph>(g)), g(g) { } // Distributed Container typedef typename boost::graph::parallel::process_group_type<DistributedGraph>::type process_group_type; process_group_type& process_group() { using boost::graph::parallel::process_group; return process_group(g); } const process_group_type& process_group() const { using boost::graph::parallel::process_group; return boost::graph::parallel::process_group(g); } DistributedGraph& base() { return g; } const DistributedGraph& base() const { return g; } private: DistributedGraph& g; }; template<typename DistributedGraph, typename PropertyTag> class property_map<local_subgraph<DistributedGraph>, PropertyTag> : public property_map<DistributedGraph, PropertyTag> { }; template<typename DistributedGraph, typename PropertyTag> class property_map<local_subgraph<const DistributedGraph>, PropertyTag> { public: typedef typename property_map<DistributedGraph, PropertyTag>::const_type type; typedef type const_type; }; template<typename PropertyTag, typename DistributedGraph> inline typename property_map<local_subgraph<DistributedGraph>, PropertyTag>::type get(PropertyTag p, local_subgraph<DistributedGraph>& g) { return get(p, g.base()); } template<typename PropertyTag, typename DistributedGraph> inline typename property_map<local_subgraph<DistributedGraph>, PropertyTag> ::const_type get(PropertyTag p, const local_subgraph<DistributedGraph>& g) { return get(p, g.base()); } template<typename DistributedGraph> inline local_subgraph<DistributedGraph> make_local_subgraph(DistributedGraph& g) { return local_subgraph<DistributedGraph>(g); } } // end namespace boost #endif // BOOST_GRAPH_LOCAL_SUBGRAPH_HPP distributed/one_bit_color_map.hpp 0000644 00000007716 15125521275 0013271 0 ustar 00 // Copyright (C) 2006-2010 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Jeremiah Willcock // Andrew Lumsdaine // Distributed version of the one-bit color map #ifndef BOOST_DISTRIBUTED_ONE_BIT_COLOR_MAP_HPP #define BOOST_DISTRIBUTED_ONE_BIT_COLOR_MAP_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/one_bit_color_map.hpp> #include <boost/property_map/parallel/distributed_property_map.hpp> #include <boost/property_map/parallel/local_property_map.hpp> namespace boost { template<typename ProcessGroup, typename GlobalMap, typename StorageMap> class one_bit_color_map<local_property_map<ProcessGroup,GlobalMap,StorageMap> > : public parallel::distributed_property_map<ProcessGroup, GlobalMap, one_bit_color_map<StorageMap> > { typedef one_bit_color_map<StorageMap> local_map; typedef parallel::distributed_property_map<ProcessGroup, GlobalMap, local_map > inherited; typedef local_property_map<ProcessGroup, GlobalMap, StorageMap> index_map_type; public: one_bit_color_map(std::size_t inital_size, const index_map_type& index = index_map_type()) : inherited(index.process_group(), index.global(), local_map(inital_size, index.base())) { } inherited& base() { return *this; } const inherited& base() const { return *this; } }; template<typename ProcessGroup, typename GlobalMap, typename StorageMap> inline one_bit_color_type get(one_bit_color_map<local_property_map<ProcessGroup,GlobalMap,StorageMap> > const& pm, typename property_traits<GlobalMap>::key_type key) { return get(pm.base(), key); } template<typename ProcessGroup, typename GlobalMap, typename StorageMap> inline void put(one_bit_color_map<local_property_map<ProcessGroup,GlobalMap,StorageMap> > const& pm, typename property_traits<GlobalMap>::key_type key, one_bit_color_type value) { put(pm.base(), key, value); } template<typename ProcessGroup, typename GlobalMap, typename StorageMap> class one_bit_color_map<parallel::distributed_property_map< ProcessGroup, GlobalMap, StorageMap> > : public parallel::distributed_property_map< ProcessGroup, GlobalMap, one_bit_color_map<StorageMap> > { typedef one_bit_color_map<StorageMap> local_map; typedef parallel::distributed_property_map<ProcessGroup,GlobalMap,local_map> inherited; typedef parallel::distributed_property_map<ProcessGroup, GlobalMap, StorageMap> index_map_type; public: one_bit_color_map(std::size_t inital_size, const index_map_type& index = index_map_type()) : inherited(index.process_group(), index.global(), local_map(inital_size, index.base())) { } inherited& base() { return *this; } const inherited& base() const { return *this; } }; template<typename ProcessGroup, typename GlobalMap, typename StorageMap> inline one_bit_color_type get(one_bit_color_map< parallel::distributed_property_map< ProcessGroup, GlobalMap, one_bit_color_map<StorageMap> > > const& pm, typename property_traits<GlobalMap>::key_type key) { return get(pm.base(), key); } template<typename ProcessGroup, typename GlobalMap, typename StorageMap> inline void put(one_bit_color_map< parallel::distributed_property_map< ProcessGroup, GlobalMap, one_bit_color_map<StorageMap> > > const& pm, typename property_traits<GlobalMap>::key_type key, one_bit_color_type value) { put(pm.base(), key, value); } } // end namespace boost #endif // BOOST_DISTRIBUTED_ONE_BIT_COLOR_MAP_HPP distributed/two_bit_color_map.hpp 0000644 00000007711 15125521275 0013314 0 ustar 00 // Copyright (C) 2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Jeremiah Willcock // Andrew Lumsdaine // Distributed version of the two-bit color map #ifndef BOOST_DISTRIBUTED_TWO_BIT_COLOR_MAP_HPP #define BOOST_DISTRIBUTED_TWO_BIT_COLOR_MAP_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/two_bit_color_map.hpp> #include <boost/property_map/parallel/distributed_property_map.hpp> #include <boost/property_map/parallel/local_property_map.hpp> namespace boost { template<typename ProcessGroup, typename GlobalMap, typename StorageMap> class two_bit_color_map<local_property_map<ProcessGroup,GlobalMap,StorageMap> > : public parallel::distributed_property_map<ProcessGroup, GlobalMap, two_bit_color_map<StorageMap> > { typedef two_bit_color_map<StorageMap> local_map; typedef parallel::distributed_property_map<ProcessGroup, GlobalMap, local_map > inherited; typedef local_property_map<ProcessGroup, GlobalMap, StorageMap> index_map_type; public: two_bit_color_map(std::size_t inital_size, const index_map_type& index = index_map_type()) : inherited(index.process_group(), index.global(), local_map(inital_size, index.base())) { } inherited& base() { return *this; } const inherited& base() const { return *this; } }; template<typename ProcessGroup, typename GlobalMap, typename StorageMap> inline two_bit_color_type get(two_bit_color_map<local_property_map<ProcessGroup,GlobalMap,StorageMap> > const& pm, typename property_traits<GlobalMap>::key_type key) { return get(pm.base(), key); } template<typename ProcessGroup, typename GlobalMap, typename StorageMap> inline void put(two_bit_color_map<local_property_map<ProcessGroup,GlobalMap,StorageMap> > const& pm, typename property_traits<GlobalMap>::key_type key, two_bit_color_type value) { put(pm.base(), key, value); } template<typename ProcessGroup, typename GlobalMap, typename StorageMap> class two_bit_color_map<parallel::distributed_property_map< ProcessGroup, GlobalMap, StorageMap> > : public parallel::distributed_property_map< ProcessGroup, GlobalMap, two_bit_color_map<StorageMap> > { typedef two_bit_color_map<StorageMap> local_map; typedef parallel::distributed_property_map<ProcessGroup,GlobalMap,local_map> inherited; typedef parallel::distributed_property_map<ProcessGroup, GlobalMap, StorageMap> index_map_type; public: two_bit_color_map(std::size_t inital_size, const index_map_type& index = index_map_type()) : inherited(index.process_group(), index.global(), local_map(inital_size, index.base())) { } inherited& base() { return *this; } const inherited& base() const { return *this; } }; template<typename ProcessGroup, typename GlobalMap, typename StorageMap> inline two_bit_color_type get(two_bit_color_map< parallel::distributed_property_map< ProcessGroup, GlobalMap, two_bit_color_map<StorageMap> > > const& pm, typename property_traits<GlobalMap>::key_type key) { return get(pm.base(), key); } template<typename ProcessGroup, typename GlobalMap, typename StorageMap> inline void put(two_bit_color_map< parallel::distributed_property_map< ProcessGroup, GlobalMap, two_bit_color_map<StorageMap> > > const& pm, typename property_traits<GlobalMap>::key_type key, two_bit_color_type value) { put(pm.base(), key, value); } } // end namespace boost #endif // BOOST_DISTRIBUTED_TWO_BIT_COLOR_MAP_HPP distributed/eager_dijkstra_shortest_paths.hpp 0000644 00000037574 15125521275 0015734 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine /************************************************************************** * This source file implements a variation on distributed Dijkstra's * * algorithm that can expose additional parallelism by permitting * * vertices within a certain distance from the minimum to be processed, * * even though they may not be at their final distance. This can * * introduce looping, but the algorithm will still terminate so long as * * there are no negative loops. * **************************************************************************/ #ifndef BOOST_GRAPH_EAGER_DIJKSTRA_SHORTEST_PATHS_HPP #define BOOST_GRAPH_EAGER_DIJKSTRA_SHORTEST_PATHS_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/assert.hpp> #include <boost/graph/distributed/detail/dijkstra_shortest_paths.hpp> #include <boost/property_map/parallel/caching_property_map.hpp> #include <boost/pending/indirect_cmp.hpp> #include <boost/graph/distributed/detail/remote_update_set.hpp> #include <vector> #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/dijkstra_shortest_paths.hpp> #include <boost/graph/parallel/container_traits.hpp> #ifdef PBGL_ACCOUNTING # include <boost/graph/accounting.hpp> # include <numeric> #endif // PBGL_ACCOUNTING #ifdef MUTABLE_QUEUE # include <boost/pending/mutable_queue.hpp> #endif namespace boost { namespace graph { namespace distributed { #ifdef PBGL_ACCOUNTING struct eager_dijkstra_shortest_paths_stats_t { /* The value of the lookahead parameter. */ double lookahead; /* Total wall-clock time used by the algorithm.*/ accounting::time_type execution_time; /* The number of vertices deleted in each superstep. */ std::vector<std::size_t> deleted_vertices; template<typename OutputStream> void print(OutputStream& out) { double avg_deletions = std::accumulate(deleted_vertices.begin(), deleted_vertices.end(), 0.0); avg_deletions /= deleted_vertices.size(); out << "Problem = \"Single-Source Shortest Paths\"\n" << "Algorithm = \"Eager Dijkstra\"\n" << "Function = eager_dijkstra_shortest_paths\n" << "(P) Lookahead = " << lookahead << "\n" << "Wall clock time = " << accounting::print_time(execution_time) << "\nSupersteps = " << deleted_vertices.size() << "\n" << "Avg. deletions per superstep = " << avg_deletions << "\n"; } }; static eager_dijkstra_shortest_paths_stats_t eager_dijkstra_shortest_paths_stats; #endif namespace detail { // Borrowed from BGL's dijkstra_shortest_paths template <class UniformCostVisitor, class Queue, class WeightMap, class PredecessorMap, class DistanceMap, class BinaryFunction, class BinaryPredicate> struct parallel_dijkstra_bfs_visitor : bfs_visitor<> { typedef typename property_traits<DistanceMap>::value_type distance_type; parallel_dijkstra_bfs_visitor(UniformCostVisitor vis, Queue& Q, WeightMap w, PredecessorMap p, DistanceMap d, BinaryFunction combine, BinaryPredicate compare, distance_type zero) : m_vis(vis), m_Q(Q), m_weight(w), m_predecessor(p), m_distance(d), m_combine(combine), m_compare(compare), m_zero(zero) { } template <class Vertex, class Graph> void initialize_vertex(Vertex u, Graph& g) { m_vis.initialize_vertex(u, g); } template <class Vertex, class Graph> void discover_vertex(Vertex u, Graph& g) { m_vis.discover_vertex(u, g); } template <class Vertex, class Graph> void examine_vertex(Vertex u, Graph& g) { m_vis.examine_vertex(u, g); } /* Since the eager formulation of Parallel Dijkstra's algorithm can loop, we may relax on *any* edge, not just those associated with white and gray targets. */ template <class Edge, class Graph> void examine_edge(Edge e, Graph& g) { if (m_compare(get(m_weight, e), m_zero)) boost::throw_exception(negative_edge()); m_vis.examine_edge(e, g); boost::parallel::caching_property_map<PredecessorMap> c_pred(m_predecessor); boost::parallel::caching_property_map<DistanceMap> c_dist(m_distance); distance_type old_distance = get(c_dist, target(e, g)); bool m_decreased = relax(e, g, m_weight, c_pred, c_dist, m_combine, m_compare); /* On x86 Linux with optimization, we sometimes get into a horrible case where m_decreased is true but the distance hasn't actually changed. This occurs when the comparison inside relax() occurs with the 80-bit precision of the x87 floating point unit, but the difference is lost when the resulting values are written back to lower-precision memory (e.g., a double). With the eager Dijkstra's implementation, this results in looping. */ if (m_decreased && old_distance != get(c_dist, target(e, g))) { m_Q.update(target(e, g)); m_vis.edge_relaxed(e, g); } else m_vis.edge_not_relaxed(e, g); } template <class Vertex, class Graph> void finish_vertex(Vertex u, Graph& g) { m_vis.finish_vertex(u, g); } UniformCostVisitor m_vis; Queue& m_Q; WeightMap m_weight; PredecessorMap m_predecessor; DistanceMap m_distance; BinaryFunction m_combine; BinaryPredicate m_compare; distance_type m_zero; }; /********************************************************************** * Dijkstra queue that implements arbitrary "lookahead" * **********************************************************************/ template<typename Graph, typename Combine, typename Compare, typename VertexIndexMap, typename DistanceMap, typename PredecessorMap> class lookahead_dijkstra_queue : public graph::detail::remote_update_set< lookahead_dijkstra_queue< Graph, Combine, Compare, VertexIndexMap, DistanceMap, PredecessorMap>, typename boost::graph::parallel::process_group_type<Graph>::type, typename dijkstra_msg_value<DistanceMap, PredecessorMap>::type, typename property_map<Graph, vertex_owner_t>::const_type> { typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef lookahead_dijkstra_queue self_type; typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type; typedef dijkstra_msg_value<DistanceMap, PredecessorMap> msg_value_creator; typedef typename msg_value_creator::type msg_value_type; typedef typename property_map<Graph, vertex_owner_t>::const_type OwnerPropertyMap; typedef graph::detail::remote_update_set<self_type, process_group_type, msg_value_type, OwnerPropertyMap> inherited; // Priority queue for tentative distances typedef indirect_cmp<DistanceMap, Compare> queue_compare_type; typedef typename property_traits<DistanceMap>::value_type distance_type; #ifdef MUTABLE_QUEUE typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>, queue_compare_type, VertexIndexMap> queue_type; #else typedef relaxed_heap<vertex_descriptor, queue_compare_type, VertexIndexMap> queue_type; #endif // MUTABLE_QUEUE typedef typename process_group_type::process_id_type process_id_type; public: typedef vertex_descriptor value_type; lookahead_dijkstra_queue(const Graph& g, const Combine& combine, const Compare& compare, const VertexIndexMap& id, const DistanceMap& distance_map, const PredecessorMap& predecessor_map, distance_type lookahead) : inherited(boost::graph::parallel::process_group(g), get(vertex_owner, g)), queue(num_vertices(g), queue_compare_type(distance_map, compare), id), distance_map(distance_map), predecessor_map(predecessor_map), min_distance(0), lookahead(lookahead) #ifdef PBGL_ACCOUNTING , local_deletions(0) #endif { } void push(const value_type& x) { msg_value_type msg_value = msg_value_creator::create(get(distance_map, x), predecessor_value(get(predecessor_map, x))); inherited::update(x, msg_value); } void update(const value_type& x) { push(x); } void pop() { queue.pop(); #ifdef PBGL_ACCOUNTING ++local_deletions; #endif } value_type& top() { return queue.top(); } const value_type& top() const { return queue.top(); } bool empty() { inherited::collect(); // If there are no suitable messages, wait until we get something while (!has_suitable_vertex()) { if (do_synchronize()) return true; } // Return true only if nobody has any messages; false if we // have suitable messages return false; } private: vertex_descriptor predecessor_value(vertex_descriptor v) const { return v; } vertex_descriptor predecessor_value(property_traits<dummy_property_map>::reference) const { return graph_traits<Graph>::null_vertex(); } bool has_suitable_vertex() const { return (!queue.empty() && get(distance_map, queue.top()) <= min_distance + lookahead); } bool do_synchronize() { using boost::parallel::all_reduce; using boost::parallel::minimum; inherited::synchronize(); // TBD: could use combine here, but then we need to stop using // minimum<distance_type>() as the function object. distance_type local_distance = queue.empty()? (std::numeric_limits<distance_type>::max)() : get(distance_map, queue.top()); all_reduce(this->process_group, &local_distance, &local_distance + 1, &min_distance, minimum<distance_type>()); #ifdef PBGL_ACCOUNTING std::size_t deletions = 0; all_reduce(this->process_group, &local_deletions, &local_deletions + 1, &deletions, std::plus<std::size_t>()); if (process_id(this->process_group) == 0) eager_dijkstra_shortest_paths_stats.deleted_vertices .push_back(deletions); local_deletions = 0; BOOST_ASSERT(deletions > 0); #endif return min_distance == (std::numeric_limits<distance_type>::max)(); } public: void receive_update(process_id_type source, vertex_descriptor vertex, distance_type distance) { // Update the queue if the received distance is better than // the distance we know locally if (distance <= get(distance_map, vertex)) { // Update the local distance map put(distance_map, vertex, distance); bool is_in_queue = queue.contains(vertex); if (!is_in_queue) queue.push(vertex); else queue.update(vertex); } } void receive_update(process_id_type source, vertex_descriptor vertex, std::pair<distance_type, vertex_descriptor> p) { if (p.first <= get(distance_map, vertex)) { put(predecessor_map, vertex, p.second); receive_update(source, vertex, p.first); } } private: queue_type queue; DistanceMap distance_map; PredecessorMap predecessor_map; distance_type min_distance; distance_type lookahead; #ifdef PBGL_ACCOUNTING std::size_t local_deletions; #endif }; /**********************************************************************/ } // end namespace detail template<typename DistributedGraph, typename DijkstraVisitor, typename PredecessorMap, typename DistanceMap, typename WeightMap, typename IndexMap, typename ColorMap, typename Compare, typename Combine, typename DistInf, typename DistZero> void eager_dijkstra_shortest_paths (const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, typename property_traits<DistanceMap>::value_type lookahead, WeightMap weight, IndexMap index_map, ColorMap color_map, Compare compare, Combine combine, DistInf inf, DistZero zero, DijkstraVisitor vis) { #ifdef PBGL_ACCOUNTING eager_dijkstra_shortest_paths_stats.deleted_vertices.clear(); eager_dijkstra_shortest_paths_stats.lookahead = lookahead; eager_dijkstra_shortest_paths_stats.execution_time = accounting::get_time(); #endif // Initialize local portion of property maps typename graph_traits<DistributedGraph>::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { put(distance, *ui, inf); put(predecessor, *ui, *ui); } put(distance, s, zero); // Dijkstra Queue typedef detail::lookahead_dijkstra_queue <DistributedGraph, Combine, Compare, IndexMap, DistanceMap, PredecessorMap> Queue; Queue Q(g, combine, compare, index_map, distance, predecessor, lookahead); // Parallel Dijkstra visitor detail::parallel_dijkstra_bfs_visitor <DijkstraVisitor, Queue, WeightMap, PredecessorMap, DistanceMap, Combine, Compare> bfs_vis(vis, Q, weight, predecessor, distance, combine, compare, zero); set_property_map_role(vertex_color, color_map); set_property_map_role(vertex_distance, distance); breadth_first_search(g, s, Q, bfs_vis, color_map); #ifdef PBGL_ACCOUNTING eager_dijkstra_shortest_paths_stats.execution_time = accounting::get_time() - eager_dijkstra_shortest_paths_stats.execution_time; #endif } template<typename DistributedGraph, typename DijkstraVisitor, typename PredecessorMap, typename DistanceMap, typename WeightMap> void eager_dijkstra_shortest_paths (const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, typename property_traits<DistanceMap>::value_type lookahead, WeightMap weight) { typedef typename property_traits<DistanceMap>::value_type distance_type; std::vector<default_color_type> colors(num_vertices(g), white_color); eager_dijkstra_shortest_paths(g, s, predecessor, distance, lookahead, weight, get(vertex_index, g), make_iterator_property_map(&colors[0], get(vertex_index, g)), std::less<distance_type>(), closed_plus<distance_type>(), distance_type(), (std::numeric_limits<distance_type>::max)(), dijkstra_visitor<>()); } template<typename DistributedGraph, typename DijkstraVisitor, typename PredecessorMap, typename DistanceMap> void eager_dijkstra_shortest_paths (const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, PredecessorMap predecessor, DistanceMap distance, typename property_traits<DistanceMap>::value_type lookahead) { eager_dijkstra_shortest_paths(g, s, predecessor, distance, lookahead, get(edge_weight, g)); } } // end namespace distributed #ifdef PBGL_ACCOUNTING using distributed::eager_dijkstra_shortest_paths_stats; #endif using distributed::eager_dijkstra_shortest_paths; } } // end namespace boost::graph #endif // BOOST_GRAPH_EAGER_DIJKSTRA_SHORTEST_PATHS_HPP distributed/boman_et_al_graph_coloring.hpp 0000644 00000031273 15125521275 0015127 0 ustar 00 // Copyright (C) 2005-2008 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_DISTRIBUTED_BOMAN_ET_AL_GRAPH_COLORING_HPP #define BOOST_GRAPH_DISTRIBUTED_BOMAN_ET_AL_GRAPH_COLORING_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/graph_traits.hpp> #include <boost/graph/parallel/algorithm.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/parallel/process_group.hpp> #include <functional> #include <vector> #include <utility> #include <boost/graph/iteration_macros.hpp> #include <boost/optional.hpp> #include <boost/assert.hpp> #include <boost/graph/parallel/container_traits.hpp> #include <boost/graph/properties.hpp> #ifdef PBGL_ACCOUNTING # include <boost/graph/accounting.hpp> #endif // PBGL_ACCOUNTING namespace boost { namespace graph { namespace distributed { /************************************************************************** * This source file implements the distributed graph coloring algorithm * * by Boman et al in: * * * * Erik G. Boman, Doruk Bozdag, Umit Catalyurek, Assefaw H. Gebremedhin,* * and Fredrik Manne. A Scalable Parallel Graph Coloring Algorithm for * * Distributed Memory Computers. [unpublished preprint?] * * * **************************************************************************/ #ifdef PBGL_ACCOUNTING struct boman_et_al_graph_coloring_stats_t { /* The size of the blocks to step through (i.e., the parameter s). */ std::size_t block_size; /* Total wall-clock time used by the algorithm.*/ accounting::time_type execution_time; /* The number of conflicts that occurred during execution. */ std::size_t conflicts; /* The number of supersteps. */ std::size_t supersteps; /* The number of colors used. */ std::size_t num_colors; template<typename OutputStream> void print(OutputStream& out) { out << "Problem = \"Coloring\"\n" << "Algorithm = \"Boman et al\"\n" << "Function = boman_et_al_graph_coloring\n" << "(P) Block size = " << block_size << "\n" << "Wall clock time = " << accounting::print_time(execution_time) << "\nConflicts = " << conflicts << "\n" << "Supersteps = " << supersteps << "\n" << "(R) Colors = " << num_colors << "\n"; } }; static boman_et_al_graph_coloring_stats_t boman_et_al_graph_coloring_stats; #endif namespace detail { template<typename T> struct graph_coloring_reduce { BOOST_STATIC_CONSTANT(bool, non_default_resolver = true); template<typename Key> T operator()(const Key&) const { return (std::numeric_limits<T>::max)(); } template<typename Key> T operator()(const Key&, T, T y) const { return y; } }; } template<typename Color> struct first_fit_color { template<typename T> Color operator()(const std::vector<T>& marked, T marked_true) { Color k = 0; while (k < (Color)marked.size() && marked[k] == marked_true) ++k; return k; } }; template<typename DistributedGraph, typename ColorMap, typename ChooseColor, typename VertexOrdering, typename VertexIndexMap> typename property_traits<ColorMap>::value_type boman_et_al_graph_coloring (const DistributedGraph& g, ColorMap color, typename graph_traits<DistributedGraph>::vertices_size_type s, ChooseColor choose_color, VertexOrdering ordering, VertexIndexMap vertex_index) { using namespace boost::graph::parallel; using boost::parallel::all_reduce; typename property_map<DistributedGraph, vertex_owner_t>::const_type owner = get(vertex_owner, g); typedef typename process_group_type<DistributedGraph>::type process_group_type; typedef typename process_group_type::process_id_type process_id_type; typedef typename graph_traits<DistributedGraph>::vertex_descriptor Vertex; typedef typename graph_traits<DistributedGraph>::vertices_size_type vertices_size_type; typedef typename property_traits<ColorMap>::value_type color_type; typedef unsigned long long iterations_type; typedef typename std::vector<Vertex>::iterator vertex_set_iterator; typedef std::pair<Vertex, color_type> message_type; #ifdef PBGL_ACCOUNTING boman_et_al_graph_coloring_stats.block_size = s; boman_et_al_graph_coloring_stats.execution_time = accounting::get_time(); boman_et_al_graph_coloring_stats.conflicts = 0; boman_et_al_graph_coloring_stats.supersteps = 0; #endif // Initialize color map color_type no_color = (std::numeric_limits<color_type>::max)(); BGL_FORALL_VERTICES_T(v, g, DistributedGraph) put(color, v, no_color); color.set_reduce(detail::graph_coloring_reduce<color_type>()); // Determine if we'll be using synchronous or asynchronous communication. typedef typename process_group_type::communication_category communication_category; static const bool asynchronous = is_convertible<communication_category, boost::parallel::immediate_process_group_tag>::value; process_group_type pg = process_group(g); // U_i <- V_i std::vector<Vertex> vertices_to_color(vertices(g).first, vertices(g).second); iterations_type iter_num = 1, outer_iter_num = 1; std::vector<iterations_type> marked; std::vector<iterations_type> marked_conflicting(num_vertices(g), 0); std::vector<bool> sent_to_processors; std::size_t rounds = vertices_to_color.size() / s + (vertices_to_color.size() % s == 0? 0 : 1); rounds = all_reduce(pg, rounds, boost::parallel::maximum<std::size_t>()); #ifdef PBGL_GRAPH_COLORING_DEBUG std::cerr << "Number of rounds = " << rounds << std::endl; #endif while (rounds > 0) { if (!vertices_to_color.empty()) { // Set of conflicting vertices std::vector<Vertex> conflicting_vertices; vertex_set_iterator first = vertices_to_color.begin(); while (first != vertices_to_color.end()) { // For each subset of size s (or smaller for the last subset) vertex_set_iterator start = first; for (vertices_size_type counter = s; first != vertices_to_color.end() && counter > 0; ++first, --counter) { // This vertex hasn't been sent to anyone yet sent_to_processors.assign(num_processes(pg), false); sent_to_processors[process_id(pg)] = true; // Mark all of the colors that we see BGL_FORALL_OUTEDGES_T(*first, e, g, DistributedGraph) { color_type k = get(color, target(e, g)); if (k != no_color) { if (k >= (color_type)marked.size()) marked.resize(k + 1, 0); marked[k] = iter_num; } } // Find a color for this vertex put(color, *first, choose_color(marked, iter_num)); #ifdef PBGL_GRAPH_COLORING_DEBUG std::cerr << "Chose color " << get(color, *first) << " for vertex " << *first << std::endl; #endif // Send this vertex's color to the owner of the edge target. BGL_FORALL_OUTEDGES_T(*first, e, g, DistributedGraph) { if (!sent_to_processors[get(owner, target(e, g))]) { send(pg, get(owner, target(e, g)), 17, message_type(source(e, g), get(color, source(e, g)))); sent_to_processors[get(owner, target(e, g))] = true; } } ++iter_num; } // Synchronize for non-immediate process groups. if (!asynchronous) { --rounds; synchronize(pg); } // Receive boundary colors from other processors while (optional<std::pair<process_id_type, int> > stp = probe(pg)) { BOOST_ASSERT(stp->second == 17); message_type msg; receive(pg, stp->first, stp->second, msg); cache(color, msg.first, msg.second); #ifdef PBGL_GRAPH_COLORING_DEBUG std::cerr << "Cached color " << msg.second << " for vertex " << msg.first << std::endl; #endif } // Compute the set of conflicting vertices // [start, first) contains all vertices in this subset for (vertex_set_iterator vi = start; vi != first; ++vi) { Vertex v = *vi; BGL_FORALL_OUTEDGES_T(v, e, g, DistributedGraph) { Vertex w = target(e, g); if (get(owner, w) != process_id(pg) // boundary vertex && marked_conflicting[get(vertex_index, v)] != outer_iter_num && get(color, v) == get(color, w) && ordering(v, w)) { conflicting_vertices.push_back(v); marked_conflicting[get(vertex_index, v)] = outer_iter_num; put(color, v, no_color); #ifdef PBGL_GRAPH_COLORING_DEBUG std::cerr << "Vertex " << v << " has a conflict with vertex " << w << std::endl; #endif break; } } } #ifdef PBGL_ACCOUNTING boman_et_al_graph_coloring_stats.conflicts += conflicting_vertices.size(); #endif } if (asynchronous) synchronize(pg); else { while (rounds > 0) { synchronize(pg); --rounds; } } conflicting_vertices.swap(vertices_to_color); ++outer_iter_num; } else { if (asynchronous) synchronize(pg); else { while (rounds > 0) { synchronize(pg); --rounds; } } } // Receive boundary colors from other processors while (optional<std::pair<process_id_type, int> > stp = probe(pg)) { BOOST_ASSERT(stp->second == 17); message_type msg; receive(pg, stp->first, stp->second, msg); cache(color, msg.first, msg.second); } rounds = vertices_to_color.size() / s + (vertices_to_color.size() % s == 0? 0 : 1); rounds = all_reduce(pg, rounds, boost::parallel::maximum<std::size_t>()); #ifdef PBGL_ACCOUNTING ++boman_et_al_graph_coloring_stats.supersteps; #endif } // Determine the number of colors used. color_type num_colors = 0; BGL_FORALL_VERTICES_T(v, g, DistributedGraph) { color_type k = get(color, v); BOOST_ASSERT(k != no_color); if (k != no_color) { if (k >= (color_type)marked.size()) marked.resize(k + 1, 0); // TBD: perf? if (marked[k] != iter_num) { marked[k] = iter_num; ++num_colors; } } } num_colors = all_reduce(pg, num_colors, boost::parallel::maximum<color_type>()); #ifdef PBGL_ACCOUNTING boman_et_al_graph_coloring_stats.execution_time = accounting::get_time() - boman_et_al_graph_coloring_stats.execution_time; boman_et_al_graph_coloring_stats.conflicts = all_reduce(pg, boman_et_al_graph_coloring_stats.conflicts, std::plus<color_type>()); boman_et_al_graph_coloring_stats.num_colors = num_colors; #endif return num_colors; } template<typename DistributedGraph, typename ColorMap, typename ChooseColor, typename VertexOrdering> inline typename property_traits<ColorMap>::value_type boman_et_al_graph_coloring (const DistributedGraph& g, ColorMap color, typename graph_traits<DistributedGraph>::vertices_size_type s, ChooseColor choose_color, VertexOrdering ordering) { return boman_et_al_graph_coloring(g, color, s, choose_color, ordering, get(vertex_index, g)); } template<typename DistributedGraph, typename ColorMap, typename ChooseColor> inline typename property_traits<ColorMap>::value_type boman_et_al_graph_coloring (const DistributedGraph& g, ColorMap color, typename graph_traits<DistributedGraph>::vertices_size_type s, ChooseColor choose_color) { typedef typename graph_traits<DistributedGraph>::vertex_descriptor vertex_descriptor; return boman_et_al_graph_coloring(g, color, s, choose_color, std::less<vertex_descriptor>()); } template<typename DistributedGraph, typename ColorMap> inline typename property_traits<ColorMap>::value_type boman_et_al_graph_coloring (const DistributedGraph& g, ColorMap color, typename graph_traits<DistributedGraph>::vertices_size_type s = 100) { typedef typename property_traits<ColorMap>::value_type Color; return boman_et_al_graph_coloring(g, color, s, first_fit_color<Color>()); } } } } // end namespace boost::graph::distributed namespace boost { namespace graph { using distributed::boman_et_al_graph_coloring; } } // end namespace boost::graph #endif // BOOST_GRAPH_DISTRIBUTED_BOMAN_ET_AL_GRAPH_COLORING_HPP distributed/graphviz.hpp 0000644 00000020740 15125521275 0011441 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_PARALLEL_GRAPHVIZ_HPP #define BOOST_GRAPH_PARALLEL_GRAPHVIZ_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/graph_traits.hpp> #include <boost/graph/distributed/concepts.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/graphviz.hpp> #include <boost/type_traits/is_base_and_derived.hpp> #include <boost/type_traits/is_same.hpp> #include <fstream> #include <sstream> #include <iostream> #include <string> #include <boost/graph/parallel/container_traits.hpp> #include <boost/graph/parallel/process_group.hpp> #include <boost/property_map/parallel/global_index_map.hpp> namespace boost { template<typename Graph> struct graph_id_writer { explicit graph_id_writer(const Graph& g) : g(g) { } void operator()(std::ostream& out) { out << " label=\"p" << process_id(g.process_group()) << "\";\n"; } private: const Graph& g; }; template<typename NumberMap> struct paint_by_number_writer { explicit paint_by_number_writer(NumberMap number) : number(number) { } template<typename Descriptor> void operator()(std::ostream& out, Descriptor k) { static const char* color_names[] = { "blue", "brown", "cyan", "darkgreen", "darkorchid", "darksalmon", "darkviolet", "deeppink", "gold3", "green", "magenta", "navy", "red", "yellow", "palegreen", "gray65", "gray21", "bisque2", "greenyellow", "indianred4", "lightblue2", "mediumspringgreen", "orangered", "orange" }; const int colors = sizeof(color_names) / sizeof(color_names[0]); if (get(number, k) < colors) { out << " [ style=\"filled\", fillcolor=\"" << color_names[get(number, k)] << "\" ]"; } else { out << " [ label=\"(" << get(number, k) << ")\" ]"; } } private: NumberMap number; }; template<typename NumberMap> inline paint_by_number_writer<NumberMap> paint_by_number(NumberMap number) { return paint_by_number_writer<NumberMap>(number); } template<typename Graph, typename VertexPropertiesWriter, typename EdgePropertiesWriter, typename GraphPropertiesWriter> void write_graphviz(std::ostream& out, const Graph& g, VertexPropertiesWriter vpw, EdgePropertiesWriter epw, GraphPropertiesWriter gpw BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { typedef typename graph_traits<Graph>::directed_category directed_category; typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type; typedef typename property_map<Graph, vertex_index_t>::const_type VertexIndexMap; typedef typename property_map<Graph, vertex_global_t>::const_type VertexGlobalMap; static const bool is_undirected = (is_base_and_derived<undirected_tag, directed_category>::value || is_same<undirected_tag, directed_category>::value); static const char* graph_kind = is_undirected? "graph" : "digraph"; static const char* edge_kind = is_undirected? "--" : "->"; using boost::graph::parallel::process_group; process_group_type pg = process_group(g); parallel::global_index_map<VertexIndexMap, VertexGlobalMap> global_index(pg, num_vertices(g), get(vertex_index, g), get(vertex_global, g)); std::ostringstream local_graph_out; local_graph_out << " subgraph cluster_" << process_id(pg) << " {\n"; gpw(local_graph_out); typename graph_traits<Graph>::vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { int global_idx = get(global_index, *vi); local_graph_out << " n" << global_idx; vpw(local_graph_out, *vi); local_graph_out << ";\n"; } local_graph_out << " }\n\n"; typename graph_traits<Graph>::edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) { int source_idx = get(global_index, source(*ei, g)); int target_idx = get(global_index, target(*ei, g)); local_graph_out << " n" << source_idx << " " << edge_kind << " n" << target_idx; epw(local_graph_out, *ei); local_graph_out << ";\n"; } if (process_id(pg) == 0) { out << graph_kind << " g {\n"; out << local_graph_out.str(); synchronize(pg); for (int i = 1; i < num_processes(pg); ++i) { int len; receive(pg, i, 0, len); char* data = new char [len+1]; data[len] = 0; receive(pg, i, 1, data, len); out << std::endl << data; delete [] data; } out << "}\n"; } else { std::string result_str = local_graph_out.str(); const char* data = result_str.c_str(); int len = result_str.length(); send(pg, 0, 0, len); send(pg, 0, 1, data, len); synchronize(pg); } synchronize(pg); synchronize(pg); synchronize(pg); } template<typename Graph, typename VertexPropertiesWriter, typename EdgePropertiesWriter> inline void write_graphviz(std::ostream& out, const Graph& g, VertexPropertiesWriter vpw, EdgePropertiesWriter epw BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { write_graphviz(out, g, vpw, epw, graph_id_writer<Graph>(g)); } template<typename Graph, typename VertexPropertiesWriter> inline void write_graphviz(std::ostream& out, const Graph& g, VertexPropertiesWriter vpw BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { write_graphviz(out, g, vpw, default_writer()); } template<typename Graph> inline void write_graphviz(std::ostream& out, const Graph& g BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { write_graphviz(out, g, default_writer()); } template<typename Graph, typename VertexPropertiesWriter, typename EdgePropertiesWriter, typename GraphPropertiesWriter> void write_graphviz(const std::string& filename, const Graph& g, VertexPropertiesWriter vpw, EdgePropertiesWriter epw, GraphPropertiesWriter gpw BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { if (process_id(g.process_group()) == 0) { std::ofstream out(filename.c_str()); write_graphviz(out, g, vpw, epw, gpw); } else { write_graphviz(std::cout, g, vpw, epw, gpw); } } template<typename Graph, typename VertexPropertiesWriter, typename EdgePropertiesWriter> void write_graphviz(const std::string& filename, const Graph& g, VertexPropertiesWriter vpw, EdgePropertiesWriter epw BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { if (process_id(g.process_group()) == 0) { std::ofstream out(filename.c_str()); write_graphviz(out, g, vpw, epw); } else { write_graphviz(std::cout, g, vpw, epw); } } template<typename Graph, typename VertexPropertiesWriter> void write_graphviz(const std::string& filename, const Graph& g, VertexPropertiesWriter vpw BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { if (process_id(g.process_group()) == 0) { std::ofstream out(filename.c_str()); write_graphviz(out, g, vpw); } else { write_graphviz(std::cout, g, vpw); } } template<typename Graph> void write_graphviz(const std::string& filename, const Graph& g BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { if (process_id(g.process_group()) == 0) { std::ofstream out(filename.c_str()); write_graphviz(out, g); } else { write_graphviz(std::cout, g); } } template<typename Graph> void write_graphviz(std::ostream& out, const Graph& g, const dynamic_properties& dp, const std::string& node_id = "node_id" BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag)) { write_graphviz (out, g, /*vertex_writer=*/dynamic_vertex_properties_writer(dp, node_id), /*edge_writer=*/dynamic_properties_writer(dp)); } } // end namespace boost #endif // BOOST_GRAPH_PARALLEL_GRAPHVIZ_HPP distributed/unsafe_serialize.hpp 0000644 00000000574 15125521275 0013142 0 ustar 00 // Copyright (C) 2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine // File moved #include <boost/property_map/parallel/unsafe_serialize.hpp> distributed/strong_components.hpp 0000644 00000116714 15125521275 0013377 0 ustar 00 // Copyright (C) 2004-2008 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Nick Edmonds // Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_DISTRIBUTED_SCC_HPP #define BOOST_GRAPH_DISTRIBUTED_SCC_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif // #define PBGL_SCC_DEBUG #include <boost/assert.hpp> #include <boost/property_map/property_map.hpp> #include <boost/property_map/parallel/distributed_property_map.hpp> #include <boost/property_map/parallel/caching_property_map.hpp> #include <boost/graph/parallel/algorithm.hpp> #include <boost/graph/parallel/process_group.hpp> #include <boost/graph/distributed/queue.hpp> #include <boost/graph/distributed/filtered_graph.hpp> #include <boost/pending/indirect_cmp.hpp> #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/overloading.hpp> #include <boost/graph/distributed/concepts.hpp> #include <boost/graph/distributed/local_subgraph.hpp> #include <boost/graph/parallel/properties.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/graph/random.hpp> #include <boost/graph/distributed/reverse_graph.hpp> #include <boost/optional.hpp> #include <boost/graph/distributed/detail/filtered_queue.hpp> #include <boost/graph/distributed/adjacency_list.hpp> #ifdef PBGL_SCC_DEBUG #include <iostream> #include <cstdlib> #include <iomanip> #include <sys/time.h> #include <boost/graph/distributed/graphviz.hpp> // for ostringstream #endif #include <vector> #include <map> #include <boost/graph/parallel/container_traits.hpp> #ifdef PBGL_SCC_DEBUG # include <boost/graph/accounting.hpp> #endif /* PBGL_SCC_DEBUG */ // If your graph is likely to have large numbers of small strongly connected // components then running the sequential SCC algorithm on the local subgraph // and filtering components with no remote edges may increase performance // #define FILTER_LOCAL_COMPONENTS namespace boost { namespace graph { namespace distributed { namespace detail { template<typename vertex_descriptor> struct v_sets{ std::vector<vertex_descriptor> pred, succ, intersect, ps_union; }; /* Serialize vertex set */ template<typename Graph> void marshal_set( std::vector<std::vector<typename graph_traits<Graph>::vertex_descriptor> > in, std::vector<typename graph_traits<Graph>::vertex_descriptor>& out ) { for( std::size_t i = 0; i < in.size(); ++i ) { out.insert( out.end(), graph_traits<Graph>::null_vertex() ); out.insert( out.end(), in[i].begin(), in[i].end() ); } } /* Un-serialize vertex set */ template<typename Graph> void unmarshal_set( std::vector<typename graph_traits<Graph>::vertex_descriptor> in, std::vector<std::vector<typename graph_traits<Graph>::vertex_descriptor> >& out ) { typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; while( !in.empty() ) { typename std::vector<vertex_descriptor>::iterator end = std::find( in.begin(), in.end(), graph_traits<Graph>::null_vertex() ); if( end == in.begin() ) in.erase( in.begin() ); else { out.push_back(std::vector<vertex_descriptor>()); out[out.size() - 1].insert( out[out.size() - 1].end(), in.begin(), end ); in.erase( in.begin(), end ); } } } /* Determine if vertex is in subset */ template <typename Set> struct in_subset { in_subset() : m_s(0) { } in_subset(const Set& s) : m_s(&s) { } template <typename Elt> bool operator()(const Elt& x) const { return ((*m_s).find(x) != (*m_s).end()); } private: const Set* m_s; }; template<typename T> struct vertex_identity_property_map : public boost::put_get_helper<T, vertex_identity_property_map<T> > { typedef T key_type; typedef T value_type; typedef T reference; typedef boost::readable_property_map_tag category; inline value_type operator[](const key_type& v) const { return v; } inline void clear() { } }; template <typename T> inline void synchronize( vertex_identity_property_map<T> & ) { } /* BFS visitor for SCC */ template<typename Graph, typename SourceMap> struct scc_discovery_visitor : bfs_visitor<> { scc_discovery_visitor(SourceMap& sourceM) : sourceM(sourceM) {} template<typename Edge> void tree_edge(Edge e, const Graph& g) { put(sourceM, target(e,g), get(sourceM, source(e,g))); } private: SourceMap& sourceM; }; } } } } /* End namespace boost::graph::distributed::detail */ namespace boost { namespace graph { namespace distributed { enum fhp_message_tags { fhp_edges_size_msg, fhp_add_edges_msg, fhp_pred_size_msg, fhp_pred_msg, fhp_succ_size_msg, fhp_succ_msg }; template<typename Graph, typename ReverseGraph, typename VertexComponentMap, typename IsoMapFR, typename IsoMapRF, typename VertexIndexMap> void fleischer_hendrickson_pinar_strong_components(const Graph& g, VertexComponentMap c, const ReverseGraph& gr, IsoMapFR fr, IsoMapRF rf, VertexIndexMap vertex_index_map) { typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename graph_traits<ReverseGraph>::vertex_iterator rev_vertex_iterator; typedef typename graph_traits<ReverseGraph>::vertex_descriptor rev_vertex_descriptor; typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type; typedef typename process_group_type::process_id_type process_id_type; typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator, VertexIndexMap> ParentMap; typedef iterator_property_map<typename std::vector<default_color_type>::iterator, VertexIndexMap> ColorMap; typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator, VertexIndexMap> Rev_ParentMap; typedef std::vector<std::pair<vertex_descriptor, vertex_descriptor> > VertexPairVec; typedef typename property_map<Graph, vertex_owner_t>::const_type OwnerMap; OwnerMap owner = get(vertex_owner, g); using boost::graph::parallel::process_group; process_group_type pg = process_group(g); process_id_type id = process_id(pg); int num_procs = num_processes(pg); int n = 0; int my_n = num_vertices(g); all_reduce(pg, &my_n, &my_n+1, &n, std::plus<int>()); // // Initialization // #ifdef PBGL_SCC_DEBUG accounting::time_type start = accounting::get_time(); #endif vertex_iterator vstart, vend; rev_vertex_iterator rev_vstart, rev_vend; std::vector<std::vector<vertex_descriptor> > vertex_sets, new_vertex_sets; vertex_sets.push_back(std::vector<vertex_descriptor>()); // Remove vertices that do not have at least one in edge and one out edge new_vertex_sets.push_back(std::vector<vertex_descriptor>()); for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ ) if( out_degree( get(fr, *vstart), gr) > 0 && out_degree(*vstart, g) > 0 ) new_vertex_sets[0].push_back( *vstart ); // Perform sequential SCC on local subgraph, filter all components with external // edges, mark remaining components and remove them from vertex_sets #ifdef FILTER_LOCAL_COMPONENTS // This doesn't actually speed up SCC in connected graphs it seems, but it does work // and may help in the case where there are lots of small strong components. { local_subgraph<const Graph> ls(g); typedef typename property_map<local_subgraph<const Graph>, vertex_index_t>::type local_index_map_type; local_index_map_type local_index = get(vertex_index, ls); std::vector<int> ls_components_vec(num_vertices(ls)); typedef iterator_property_map<std::vector<int>::iterator, local_index_map_type> ls_components_map_type; ls_components_map_type ls_component(ls_components_vec.begin(), local_index); int num_comp = boost::strong_components(ls, ls_component); // Create map of components std::map<int, std::vector<vertex_descriptor> > local_comp_map; typedef typename graph_traits<local_subgraph<const Graph> >::vertex_iterator ls_vertex_iterator; ls_vertex_iterator vstart, vend; for( boost::tie(vstart,vend) = vertices(ls); vstart != vend; vstart++ ) local_comp_map[get(ls_component, *vstart)].push_back( *vstart ); // Filter components that have no non-local edges typedef typename graph_traits<Graph>::adjacency_iterator adjacency_iterator; typedef typename graph_traits<ReverseGraph>::adjacency_iterator rev_adjacency_iterator; adjacency_iterator abegin, aend; rev_adjacency_iterator rev_abegin, rev_aend; for( std::size_t i = 0; i < num_comp; ++i ) { bool local = true; for( std::size_t j = 0; j < local_comp_map[i].size(); j++ ) { for( boost::tie(abegin,aend) = adjacent_vertices(local_comp_map[i][j], g); abegin != aend; abegin++ ) if( get(owner, *abegin) != id ) { local = false; break; } if( local ) for( boost::tie(rev_abegin,rev_aend) = adjacent_vertices(get(fr, local_comp_map[i][j]), gr); rev_abegin != rev_aend; rev_abegin++ ) if( get(owner, *rev_abegin) != id ) { local = false; break; } if( !local ) break; } if( local ) // Mark and remove from new_vertex_sets for( std::size_t j = 0; j < local_comp_map[i].size(); j++ ) { put( c, local_comp_map[i][j], local_comp_map[i][0] ); typename std::vector<vertex_descriptor>::iterator pos = std::find(new_vertex_sets[0].begin(), new_vertex_sets[0].end(), local_comp_map[i][j]); if( pos != new_vertex_sets[0].end() ) new_vertex_sets[0].erase(pos); } } } #endif // FILTER_LOCAL_COMPONENTS all_gather( pg, new_vertex_sets[0].begin(), new_vertex_sets[0].end(), vertex_sets[0] ); new_vertex_sets.clear(); #ifdef PBGL_SCC_DEBUG accounting::time_type end = accounting::get_time(); if(id == 0) std::cerr << "Trim local SCCs time = " << accounting::print_time(end - start) << " seconds.\n"; #endif if( vertex_sets[0].empty() ) return; // // Recursively determine SCCs // #ifdef PBGL_SCC_DEBUG int iterations = 0; #endif // Only need to be able to map starting vertices for BFS from now on fr.clear(); do { #ifdef PBGL_SCC_DEBUG if(id == 0) { printf("\n\nIteration %d:\n\n", iterations++); if( iterations > 1 ) { end = accounting::get_time(); std::cerr << "Running main loop destructors time = " << accounting::print_time(end - start) << " seconds.\n"; } start = accounting::get_time(); } #endif // Get forward->reverse mappings for BFS start vertices for (std::size_t i = 0; i < vertex_sets.size(); ++i) get(fr, vertex_sets[i][0]); synchronize(fr); // Determine local vertices to start BFS from std::vector<vertex_descriptor> local_start; for( std::size_t i = id; i < vertex_sets.size(); i += num_procs ) local_start.push_back(vertex_sets[i][0]); if( local_start.empty() ) local_start.push_back(vertex_sets[0][0]); // Make filtered graphs typedef std::set<vertex_descriptor> VertexSet; typedef std::set<rev_vertex_descriptor> Rev_VertexSet; VertexSet filter_set_g; Rev_VertexSet filter_set_gr; typename VertexSet::iterator fs; int active_vertices = 0; for (std::size_t i = 0; i < vertex_sets.size(); i++) active_vertices += vertex_sets[i].size(); // This is a completely random bound if ( active_vertices < 0.05*n ) { // TODO: This set insertion is ridiculously inefficient, make it an in-place-merge? for (std::size_t i = 0; i < vertex_sets.size(); i++) filter_set_g.insert(vertex_sets[i].begin(), vertex_sets[i].end()); for (fs = filter_set_g.begin(); fs != filter_set_g.end(); ++fs ) filter_set_gr.insert(get(fr, *fs)); } filtered_graph<const Graph, keep_all, detail::in_subset<VertexSet> > fg(g, keep_all(), detail::in_subset<VertexSet>(filter_set_g)); filtered_graph<const ReverseGraph, keep_all, detail::in_subset<VertexSet> > fgr(gr, keep_all(), detail::in_subset<VertexSet>(filter_set_gr)); // Add additional starting vertices to BFS queue typedef filtered_queue<queue<vertex_descriptor>, boost::detail::has_not_been_seen<VertexIndexMap> > local_queue_type; typedef boost::graph::distributed::distributed_queue<process_group_type, OwnerMap, local_queue_type> queue_t; typedef typename property_map<ReverseGraph, vertex_owner_t>::const_type RevOwnerMap; typedef filtered_queue<queue<rev_vertex_descriptor>, boost::detail::has_not_been_seen<VertexIndexMap> > rev_local_queue_type; typedef boost::graph::distributed::distributed_queue<process_group_type, RevOwnerMap, rev_local_queue_type> rev_queue_t; queue_t Q(process_group(g), owner, make_filtered_queue(queue<vertex_descriptor>(), boost::detail::has_not_been_seen<VertexIndexMap> (num_vertices(g), vertex_index_map)), false); rev_queue_t Qr(process_group(gr), get(vertex_owner, gr), make_filtered_queue(queue<rev_vertex_descriptor>(), boost::detail::has_not_been_seen<VertexIndexMap> (num_vertices(gr), vertex_index_map)), false); for( std::size_t i = 1; i < local_start.size(); ++i ) { Q.push(local_start[i]); Qr.push(get(fr, local_start[i])); } #ifdef PBGL_SCC_DEBUG end = accounting::get_time(); if(id == 0) std::cerr << " Initialize BFS time = " << accounting::print_time(end - start) << " seconds.\n"; start = accounting::get_time(); #endif #ifdef PBGL_SCC_DEBUG accounting::time_type start2 = accounting::get_time(); #endif // Forward BFS std::vector<default_color_type> color_map_s(num_vertices(g)); ColorMap color_map(color_map_s.begin(), vertex_index_map); std::vector<vertex_descriptor> succ_map_s(num_vertices(g), graph_traits<Graph>::null_vertex()); ParentMap succ_map(succ_map_s.begin(), vertex_index_map); for( std::size_t i = 0; i < vertex_sets.size(); ++i ) put(succ_map, vertex_sets[i][0], vertex_sets[i][0]); #ifdef PBGL_SCC_DEBUG accounting::time_type end2 = accounting::get_time(); if(id == 0) std::cerr << " Initialize forward BFS time = " << accounting::print_time(end2 - start2) << " seconds.\n"; #endif if (active_vertices < 0.05*n) breadth_first_search(fg, local_start[0], Q, detail::scc_discovery_visitor<filtered_graph<const Graph, keep_all, detail::in_subset<VertexSet> >, ParentMap> (succ_map), color_map); else breadth_first_search(g, local_start[0], Q, detail::scc_discovery_visitor<const Graph, ParentMap>(succ_map), color_map); #ifdef PBGL_SCC_DEBUG start2 = accounting::get_time(); #endif // Reverse BFS color_map.clear(); // reuse color map since g and gr have same vertex index std::vector<vertex_descriptor> pred_map_s(num_vertices(gr), graph_traits<Graph>::null_vertex()); Rev_ParentMap pred_map(pred_map_s.begin(), vertex_index_map); for( std::size_t i = 0; i < vertex_sets.size(); ++i ) put(pred_map, get(fr, vertex_sets[i][0]), vertex_sets[i][0]); #ifdef PBGL_SCC_DEBUG end2 = accounting::get_time(); if(id == 0) std::cerr << " Initialize reverse BFS time = " << accounting::print_time(end2 - start2) << " seconds.\n"; #endif if (active_vertices < 0.05*n) breadth_first_search(fgr, get(fr, local_start[0]), Qr, detail::scc_discovery_visitor<filtered_graph<const ReverseGraph, keep_all, detail::in_subset<Rev_VertexSet> >, Rev_ParentMap> (pred_map), color_map); else breadth_first_search(gr, get(fr, local_start[0]), Qr, detail::scc_discovery_visitor<const ReverseGraph, Rev_ParentMap>(pred_map), color_map); #ifdef PBGL_SCC_DEBUG end = accounting::get_time(); if(id == 0) std::cerr << " Perform forward and reverse BFS time = " << accounting::print_time(end - start) << " seconds.\n"; start = accounting::get_time(); #endif // Send predecessors and successors discovered by this proc to the proc responsible for // this BFS tree typedef struct detail::v_sets<vertex_descriptor> Vsets; std::map<vertex_descriptor, Vsets> set_map; std::map<vertex_descriptor, int> dest_map; std::vector<VertexPairVec> successors(num_procs); std::vector<VertexPairVec> predecessors(num_procs); // Calculate destinations for messages for (std::size_t i = 0; i < vertex_sets.size(); ++i) dest_map[vertex_sets[i][0]] = i % num_procs; for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ ) { vertex_descriptor v = get(succ_map, *vstart); if( v != graph_traits<Graph>::null_vertex() ) { if (dest_map[v] == id) set_map[v].succ.push_back(*vstart); else successors[dest_map[v]].push_back( std::make_pair(v, *vstart) ); } } for( boost::tie(rev_vstart, rev_vend) = vertices(gr); rev_vstart != rev_vend; rev_vstart++ ) { vertex_descriptor v = get(pred_map, *rev_vstart); if( v != graph_traits<Graph>::null_vertex() ) { if (dest_map[v] == id) set_map[v].pred.push_back(get(rf, *rev_vstart)); else predecessors[dest_map[v]].push_back( std::make_pair(v, get(rf, *rev_vstart)) ); } } // Send predecessor and successor messages for (process_id_type i = 0; i < num_procs; ++i) { if (!successors[i].empty()) { send(pg, i, fhp_succ_size_msg, successors[i].size()); send(pg, i, fhp_succ_msg, &successors[i][0], successors[i].size()); } if (!predecessors[i].empty()) { send(pg, i, fhp_pred_size_msg, predecessors[i].size()); send(pg, i, fhp_pred_msg, &predecessors[i][0], predecessors[i].size()); } } synchronize(pg); // Receive predecessor and successor messages and handle them while (optional<std::pair<process_id_type, int> > m = probe(pg)) { BOOST_ASSERT(m->second == fhp_succ_size_msg || m->second == fhp_pred_size_msg); std::size_t num_requests; receive(pg, m->first, m->second, num_requests); VertexPairVec requests(num_requests); if (m->second == fhp_succ_size_msg) { receive(pg, m->first, fhp_succ_msg, &requests[0], num_requests); std::map<vertex_descriptor, int> added; for (std::size_t i = 0; i < requests.size(); ++i) { set_map[requests[i].first].succ.push_back(requests[i].second); added[requests[i].first]++; } // If order of vertex traversal in vertices() is std::less<vertex_descriptor>, // then the successor sets will be in order for (std::size_t i = 0; i < local_start.size(); ++i) if (added[local_start[i]] > 0) std::inplace_merge(set_map[local_start[i]].succ.begin(), set_map[local_start[i]].succ.end() - added[local_start[i]], set_map[local_start[i]].succ.end(), std::less<vertex_descriptor>()); } else { receive(pg, m->first, fhp_pred_msg, &requests[0], num_requests); std::map<vertex_descriptor, int> added; for (std::size_t i = 0; i < requests.size(); ++i) { set_map[requests[i].first].pred.push_back(requests[i].second); added[requests[i].first]++; } if (boost::is_same<detail::vertex_identity_property_map<vertex_descriptor>, IsoMapRF>::value) for (std::size_t i = 0; i < local_start.size(); ++i) if (added[local_start[i]] > 0) std::inplace_merge(set_map[local_start[i]].pred.begin(), set_map[local_start[i]].pred.end() - added[local_start[i]], set_map[local_start[i]].pred.end(), std::less<vertex_descriptor>()); } } #ifdef PBGL_SCC_DEBUG end = accounting::get_time(); if(id == 0) std::cerr << " All gather successors and predecessors time = " << accounting::print_time(end - start) << " seconds.\n"; start = accounting::get_time(); #endif // // Filter predecessor and successor sets and perform set arithmetic // new_vertex_sets.clear(); if( std::size_t(id) < vertex_sets.size() ) { //If this proc has one or more unique starting points for( std::size_t i = 0; i < local_start.size(); ++i ) { vertex_descriptor v = local_start[i]; // Replace this sort with an in-place merges during receive step if possible if (!boost::is_same<detail::vertex_identity_property_map<vertex_descriptor>, IsoMapRF>::value) std::sort(set_map[v].pred.begin(), set_map[v].pred.end(), std::less<vertex_descriptor>()); // Limit predecessor and successor sets to members of the original set std::vector<vertex_descriptor> temp; std::set_intersection( vertex_sets[id + i*num_procs].begin(), vertex_sets[id + i*num_procs].end(), set_map[v].pred.begin(), set_map[v].pred.end(), back_inserter(temp), std::less<vertex_descriptor>()); set_map[v].pred.clear(); std::swap(set_map[v].pred, temp); std::set_intersection( vertex_sets[id + i*num_procs].begin(), vertex_sets[id + i*num_procs].end(), set_map[v].succ.begin(), set_map[v].succ.end(), back_inserter(temp), std::less<vertex_descriptor>()); set_map[v].succ.clear(); std::swap(set_map[v].succ, temp); // Intersection(pred, succ) std::set_intersection(set_map[v].pred.begin(), set_map[v].pred.end(), set_map[v].succ.begin(), set_map[v].succ.end(), back_inserter(set_map[v].intersect), std::less<vertex_descriptor>()); // Union(pred, succ) std::set_union(set_map[v].pred.begin(), set_map[v].pred.end(), set_map[v].succ.begin(), set_map[v].succ.end(), back_inserter(set_map[v].ps_union), std::less<vertex_descriptor>()); new_vertex_sets.push_back(std::vector<vertex_descriptor>()); // Original set - Union(pred, succ) std::set_difference(vertex_sets[id + i*num_procs].begin(), vertex_sets[id + i*num_procs].end(), set_map[v].ps_union.begin(), set_map[v].ps_union.end(), back_inserter(new_vertex_sets[new_vertex_sets.size() - 1]), std::less<vertex_descriptor>()); set_map[v].ps_union.clear(); new_vertex_sets.push_back(std::vector<vertex_descriptor>()); // Pred - Intersect(pred, succ) std::set_difference(set_map[v].pred.begin(), set_map[v].pred.end(), set_map[v].intersect.begin(), set_map[v].intersect.end(), back_inserter(new_vertex_sets[new_vertex_sets.size() - 1]), std::less<vertex_descriptor>()); set_map[v].pred.clear(); new_vertex_sets.push_back(std::vector<vertex_descriptor>()); // Succ - Intersect(pred, succ) std::set_difference(set_map[v].succ.begin(), set_map[v].succ.end(), set_map[v].intersect.begin(), set_map[v].intersect.end(), back_inserter(new_vertex_sets[new_vertex_sets.size() - 1]), std::less<vertex_descriptor>()); set_map[v].succ.clear(); // Label SCC just identified with the 'first' vertex in that SCC for( std::size_t j = 0; j < set_map[v].intersect.size(); j++ ) put(c, set_map[v].intersect[j], set_map[v].intersect[0]); set_map[v].intersect.clear(); } } #ifdef PBGL_SCC_DEBUG end = accounting::get_time(); if(id == 0) std::cerr << " Perform set arithemetic time = " << accounting::print_time(end - start) << " seconds.\n"; start = accounting::get_time(); #endif // Remove sets of size 1 from new_vertex_sets typename std::vector<std::vector<vertex_descriptor> >::iterator vviter; for( vviter = new_vertex_sets.begin(); vviter != new_vertex_sets.end(); /*in loop*/ ) if( (*vviter).size() < 2 ) vviter = new_vertex_sets.erase( vviter ); else vviter++; // All gather new sets and recur (gotta marshal and unmarshal sets first) vertex_sets.clear(); std::vector<vertex_descriptor> serial_sets, all_serial_sets; detail::marshal_set<Graph>( new_vertex_sets, serial_sets ); all_gather( pg, serial_sets.begin(), serial_sets.end(), all_serial_sets ); detail::unmarshal_set<Graph>( all_serial_sets, vertex_sets ); #ifdef PBGL_SCC_DEBUG end = accounting::get_time(); if(id == 0) { std::cerr << " Serialize and gather new vertex sets time = " << accounting::print_time(end - start) << " seconds.\n\n\n"; printf("Vertex sets: %d\n", (int)vertex_sets.size() ); for( std::size_t i = 0; i < vertex_sets.size(); ++i ) printf(" %d: %d\n", i, (int)vertex_sets[i].size() ); } start = accounting::get_time(); #endif // HACK!?! -- This would be more properly implemented as a topological sort // Remove vertices without an edge to another vertex in the set and an edge from another // vertex in the set typedef typename graph_traits<Graph>::out_edge_iterator out_edge_iterator; out_edge_iterator estart, eend; typedef typename graph_traits<ReverseGraph>::out_edge_iterator r_out_edge_iterator; r_out_edge_iterator restart, reend; for (std::size_t i = 0; i < vertex_sets.size(); ++i) { std::vector<vertex_descriptor> new_set; for (std::size_t j = 0; j < vertex_sets[i].size(); ++j) { vertex_descriptor v = vertex_sets[i][j]; if (get(owner, v) == id) { boost::tie(estart, eend) = out_edges(v, g); while (estart != eend && find(vertex_sets[i].begin(), vertex_sets[i].end(), target(*estart,g)) == vertex_sets[i].end()) estart++; if (estart != eend) { boost::tie(restart, reend) = out_edges(get(fr, v), gr); while (restart != reend && find(vertex_sets[i].begin(), vertex_sets[i].end(), get(rf, target(*restart,gr))) == vertex_sets[i].end()) restart++; if (restart != reend) new_set.push_back(v); } } } vertex_sets[i].clear(); all_gather(pg, new_set.begin(), new_set.end(), vertex_sets[i]); std::sort(vertex_sets[i].begin(), vertex_sets[i].end(), std::less<vertex_descriptor>()); } #ifdef PBGL_SCC_DEBUG end = accounting::get_time(); if(id == 0) std::cerr << " Trim vertex sets time = " << accounting::print_time(end - start) << " seconds.\n\n\n"; start = accounting::get_time(); #endif } while ( !vertex_sets.empty() ); // Label vertices not in a SCC as their own SCC for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ ) if( get(c, *vstart) == graph_traits<Graph>::null_vertex() ) put(c, *vstart, *vstart); synchronize(c); } template<typename Graph, typename ReverseGraph, typename IsoMap> void build_reverse_graph( const Graph& g, ReverseGraph& gr, IsoMap& fr, IsoMap& rf ) { typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename graph_traits<Graph>::out_edge_iterator out_edge_iterator; typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type; typedef typename process_group_type::process_id_type process_id_type; typedef std::vector<std::pair<vertex_descriptor, vertex_descriptor> > VertexPairVec; typename property_map<Graph, vertex_owner_t>::const_type owner = get(vertex_owner, g); process_group_type pg = process_group(g); process_id_type id = process_id(pg); int n; vertex_iterator vstart, vend; int num_procs = num_processes(pg); vertex_descriptor v; out_edge_iterator oestart, oeend; for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ ) { v = add_vertex(gr); put(fr, *vstart, v); put(rf, v, *vstart); } gr.distribution() = g.distribution(); int my_n = num_vertices(g); all_reduce(pg, &my_n, &my_n+1, &n, std::plus<int>()); for (int i = 0; i < n; ++i) get(fr, vertex(i,g)); synchronize(fr); // Add edges to gr std::vector<std::pair<vertex_descriptor, vertex_descriptor> > new_edges; for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ ) for( boost::tie(oestart, oeend) = out_edges(*vstart, g); oestart != oeend; oestart++ ) new_edges.push_back( std::make_pair(get(fr, target(*oestart,g)), get(fr, source(*oestart, g))) ); std::vector<VertexPairVec> edge_requests(num_procs); typename std::vector<std::pair<vertex_descriptor, vertex_descriptor> >::iterator iter; for( iter = new_edges.begin(); iter != new_edges.end(); iter++ ) { std::pair<vertex_descriptor, vertex_descriptor> p1 = *iter; if( get(owner, p1.first ) == id ) add_edge( p1.first, p1.second, gr ); else edge_requests[get(owner, p1.first)].push_back(p1); } new_edges.clear(); // Send edge addition requests for (process_id_type p = 0; p < num_procs; ++p) { if (!edge_requests[p].empty()) { VertexPairVec reqs(edge_requests[p].begin(), edge_requests[p].end()); send(pg, p, fhp_edges_size_msg, reqs.size()); send(pg, p, fhp_add_edges_msg, &reqs[0], reqs.size()); } } synchronize(pg); // Receive edge addition requests and handle them while (optional<std::pair<process_id_type, int> > m = probe(pg)) { BOOST_ASSERT(m->second == fhp_edges_size_msg); std::size_t num_requests; receive(pg, m->first, m->second, num_requests); VertexPairVec requests(num_requests); receive(pg, m->first, fhp_add_edges_msg, &requests[0], num_requests); for( std::size_t i = 0; i < requests.size(); ++i ) add_edge( requests[i].first, requests[i].second, gr ); } synchronize(gr); } template<typename Graph, typename VertexComponentMap, typename ComponentMap> typename property_traits<ComponentMap>::value_type number_components(const Graph& g, VertexComponentMap r, ComponentMap c) { typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type; typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename property_traits<ComponentMap>::value_type ComponentMapType; std::vector<vertex_descriptor> my_roots, all_roots; vertex_iterator vstart, vend; for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ ) if( find( my_roots.begin(), my_roots.end(), get(r, *vstart) ) == my_roots.end() ) my_roots.push_back( get(r, *vstart) ); all_gather( process_group(g), my_roots.begin(), my_roots.end(), all_roots ); /* Number components */ std::map<vertex_descriptor, ComponentMapType> comp_numbers; ComponentMapType c_num = 0; // Compute component numbers for (std::size_t i = 0; i < all_roots.size(); ++i ) if ( comp_numbers.count(all_roots[i]) == 0 ) comp_numbers[all_roots[i]] = c_num++; // Broadcast component numbers for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ ) put( c, *vstart, comp_numbers[get(r,*vstart)] ); // Broadcast number of components if (process_id(process_group(g)) == 0) { typedef typename process_group_type::process_size_type process_size_type; for (process_size_type dest = 1, n = num_processes(process_group(g)); dest != n; ++dest) send(process_group(g), dest, 0, c_num); } synchronize(process_group(g)); if (process_id(process_group(g)) != 0) receive(process_group(g), 0, 0, c_num); synchronize(c); return c_num; } template<typename Graph, typename ComponentMap, typename VertexComponentMap, typename VertexIndexMap> typename property_traits<ComponentMap>::value_type fleischer_hendrickson_pinar_strong_components_impl (const Graph& g, ComponentMap c, VertexComponentMap r, VertexIndexMap vertex_index_map, incidence_graph_tag) { typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator, VertexIndexMap> IsoMap; typename boost::graph::parallel::process_group_type<Graph>::type pg = process_group(g); #ifdef PBGL_SCC_DEBUG accounting::time_type start = accounting::get_time(); #endif typedef adjacency_list<listS, distributedS<typename boost::graph::parallel::process_group_type<Graph>::type, vecS>, directedS > ReverseGraph; ReverseGraph gr(0, pg); std::vector<vertex_descriptor> fr_s(num_vertices(g)); std::vector<vertex_descriptor> rf_s(num_vertices(g)); IsoMap fr(fr_s.begin(), vertex_index_map); // fr = forward->reverse IsoMap rf(rf_s.begin(), vertex_index_map); // rf = reverse->forward build_reverse_graph(g, gr, fr, rf); #ifdef PBGL_SCC_DEBUG accounting::time_type end = accounting::get_time(); if(process_id(process_group(g)) == 0) std::cerr << "Reverse graph initialization time = " << accounting::print_time(end - start) << " seconds.\n"; #endif fleischer_hendrickson_pinar_strong_components(g, r, gr, fr, rf, vertex_index_map); typename property_traits<ComponentMap>::value_type c_num = number_components(g, r, c); return c_num; } template<typename Graph, typename ComponentMap, typename VertexComponentMap, typename VertexIndexMap> typename property_traits<ComponentMap>::value_type fleischer_hendrickson_pinar_strong_components_impl (const Graph& g, ComponentMap c, VertexComponentMap r, VertexIndexMap vertex_index_map, bidirectional_graph_tag) { typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; reverse_graph<Graph> gr(g); detail::vertex_identity_property_map<vertex_descriptor> fr, rf; fleischer_hendrickson_pinar_strong_components(g, r, gr, fr, rf, vertex_index_map); typename property_traits<ComponentMap>::value_type c_num = number_components(g, r, c); return c_num; } template<typename Graph, typename ComponentMap, typename VertexIndexMap> inline typename property_traits<ComponentMap>::value_type fleischer_hendrickson_pinar_strong_components (const Graph& g, ComponentMap c, VertexIndexMap vertex_index_map) { typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator, VertexIndexMap> VertexComponentMap; typename boost::graph::parallel::process_group_type<Graph>::type pg = process_group(g); if (num_processes(pg) == 1) { local_subgraph<const Graph> ls(g); return boost::strong_components(ls, c); } // Create a VertexComponentMap for intermediate labeling of SCCs std::vector<vertex_descriptor> r_s(num_vertices(g), graph_traits<Graph>::null_vertex()); VertexComponentMap r(r_s.begin(), vertex_index_map); return fleischer_hendrickson_pinar_strong_components_impl (g, c, r, vertex_index_map, typename graph_traits<Graph>::traversal_category()); } template<typename Graph, typename ComponentMap> inline typename property_traits<ComponentMap>::value_type fleischer_hendrickson_pinar_strong_components(const Graph& g, ComponentMap c) { return fleischer_hendrickson_pinar_strong_components(g, c, get(vertex_index, g)); } } // end namespace distributed using distributed::fleischer_hendrickson_pinar_strong_components; } // end namespace graph template<class Graph, class ComponentMap, class P, class T, class R> inline typename property_traits<ComponentMap>::value_type strong_components (const Graph& g, ComponentMap comp, const bgl_named_params<P, T, R>& BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag)) { return graph::fleischer_hendrickson_pinar_strong_components(g, comp); } template<class Graph, class ComponentMap> inline typename property_traits<ComponentMap>::value_type strong_components (const Graph& g, ComponentMap comp BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag)) { return graph::fleischer_hendrickson_pinar_strong_components(g, comp); } } /* end namespace boost */ #endif // BOOST_GRAPH_DISTRIBUTED_SCC_HPP distributed/hohberg_biconnected_components.hpp 0000644 00000112315 15125521275 0016027 0 ustar 00 // Copyright 2005 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine // An implementation of Walter Hohberg's distributed biconnected // components algorithm, from: // // Walter Hohberg. How to Find Biconnected Components in Distributed // Networks. J. Parallel Distrib. Comput., 9(4):374-386, 1990. // #ifndef BOOST_GRAPH_DISTRIBUTED_HOHBERG_BICONNECTED_COMPONENTS_HPP #define BOOST_GRAPH_DISTRIBUTED_HOHBERG_BICONNECTED_COMPONENTS_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif /* You can define PBGL_HOHBERG_DEBUG to an integer value (1, 2, or 3) * to enable debugging information. 1 includes only the phases of the * algorithm and messages as their are received. 2 and 3 add * additional levels of detail about internal data structures related * to the algorithm itself. * * #define PBGL_HOHBERG_DEBUG 1 */ #include <boost/graph/graph_traits.hpp> #include <boost/graph/parallel/container_traits.hpp> #include <boost/graph/parallel/process_group.hpp> #include <boost/static_assert.hpp> #include <boost/mpi/operations.hpp> #include <boost/type_traits/is_convertible.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/optional.hpp> #include <utility> // for std::pair #include <boost/assert.hpp> #include <algorithm> // for std::find, std::mismatch #include <vector> #include <boost/graph/parallel/algorithm.hpp> #include <boost/graph/distributed/connected_components.hpp> #include <boost/concept/assert.hpp> namespace boost { namespace graph { namespace distributed { namespace hohberg_detail { enum message_kind { /* A header for the PATH message, stating which edge the message is coming on and how many vertices will be following. The data structure communicated will be a path_header. */ msg_path_header, /* A message containing the vertices that make up a path. It will always follow a msg_path_header and will contain vertex descriptors, only. */ msg_path_vertices, /* A header for the TREE message, stating the value of gamma and the number of vertices to come in the following msg_tree_vertices. */ msg_tree_header, /* A message containing the vertices that make up the set of vertices in the same bicomponent as the sender. It will always follow a msg_tree_header and will contain vertex descriptors, only. */ msg_tree_vertices, /* Provides a name for the biconnected component of the edge. */ msg_name }; // Payload for a msg_path_header message. template<typename EdgeDescriptor> struct path_header { // The edge over which the path is being communicated EdgeDescriptor edge; // The length of the path, i.e., the number of vertex descriptors // that will be coming in the next msg_path_vertices message. std::size_t path_length; template<typename Archiver> void serialize(Archiver& ar, const unsigned int /*version*/) { ar & edge & path_length; } }; // Payload for a msg_tree_header message. template<typename Vertex, typename Edge> struct tree_header { // The edge over which the tree is being communicated Edge edge; // Gamma, which is the eta of the sender. Vertex gamma; // The length of the list of vertices in the bicomponent, i.e., // the number of vertex descriptors that will be coming in the // next msg_tree_vertices message. std::size_t bicomp_length; template<typename Archiver> void serialize(Archiver& ar, const unsigned int /*version*/) { ar & edge & gamma & bicomp_length; } }; // Payload for the msg_name message. template<typename EdgeDescriptor> struct name_header { // The edge being communicated and named. EdgeDescriptor edge; // The 0-based name of the component std::size_t name; template<typename Archiver> void serialize(Archiver& ar, const unsigned int /*version*/) { ar & edge & name; } }; /* Computes the branch point between two paths. The branch point is the last position at which both paths are equivalent, beyond which the paths diverge. Both paths must have length > 0 and the initial elements of the paths must be equal. This is guaranteed in Hohberg's algorithm because all paths start at the leader. Returns the value at the branch point. */ template<typename T> T branch_point(const std::vector<T>& p1, const std::vector<T>& p2) { BOOST_ASSERT(!p1.empty()); BOOST_ASSERT(!p2.empty()); BOOST_ASSERT(p1.front() == p2.front()); typedef typename std::vector<T>::const_iterator iterator; iterator mismatch_pos; if (p1.size() <= p2.size()) mismatch_pos = std::mismatch(p1.begin(), p1.end(), p2.begin()).first; else mismatch_pos = std::mismatch(p2.begin(), p2.end(), p1.begin()).first; --mismatch_pos; return *mismatch_pos; } /* Computes the infimum of vertices a and b in the given path. The infimum is the largest element that is on the paths from a to the root and from b to the root. */ template<typename T> T infimum(const std::vector<T>& parent_path, T a, T b) { using std::swap; typedef typename std::vector<T>::const_iterator iterator; iterator first = parent_path.begin(), last = parent_path.end(); #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2 std::cerr << "infimum("; for (iterator i = first; i != last; ++i) { if (i != first) std::cerr << ' '; std::cerr << local(*i) << '@' << owner(*i); } std::cerr << ", " << local(a) << '@' << owner(a) << ", " << local(b) << '@' << owner(b) << ") = "; #endif if (a == b) { #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2 std::cerr << local(a) << '@' << owner(a) << std::endl; #endif return a; } // Try to find a or b, whichever is closest to the end --last; while (*last != a) { // If we match b, swap the two so we'll be looking for b later. if (*last == b) { swap(a,b); break; } if (last == first) { #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2 std::cerr << local(*first) << '@' << owner(*first) << std::endl; #endif return *first; } else --last; } // Try to find b (which may originally have been a) while (*last != b) { if (last == first) { #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2 std::cerr << local(*first) << '@' << owner(*first) << std::endl; #endif return *first; } else --last; } #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2 std::cerr << local(*last) << '@' << owner(*last) << std::endl; #endif // We've found b; it's the infimum. return *last; } } // end namespace hohberg_detail /* A message that will be stored for each edge by Hohberg's algorithm. */ template<typename Graph> struct hohberg_message { typedef typename graph_traits<Graph>::vertex_descriptor Vertex; typedef typename graph_traits<Graph>::edge_descriptor Edge; // Assign from a path message void assign(const std::vector<Vertex>& path) { gamma = graph_traits<Graph>::null_vertex(); path_or_bicomp = path; } // Assign from a tree message void assign(Vertex gamma, const std::vector<Vertex>& in_same_bicomponent) { this->gamma = gamma; path_or_bicomp = in_same_bicomponent; } bool is_path() const { return gamma == graph_traits<Graph>::null_vertex(); } bool is_tree() const { return gamma != graph_traits<Graph>::null_vertex(); } /// The "gamma" of a tree message, or null_vertex() for a path message Vertex gamma; // Either the path for a path message or the in_same_bicomponent std::vector<Vertex> path_or_bicomp; }; /* An abstraction of a vertex processor in Hohberg's algorithm. The hohberg_vertex_processor class is responsible for processing messages transmitted to it via its edges. */ template<typename Graph> class hohberg_vertex_processor { typedef typename graph_traits<Graph>::vertex_descriptor Vertex; typedef typename graph_traits<Graph>::edge_descriptor Edge; typedef typename graph_traits<Graph>::degree_size_type degree_size_type; typedef typename graph_traits<Graph>::edges_size_type edges_size_type; typedef typename boost::graph::parallel::process_group_type<Graph>::type ProcessGroup; typedef std::vector<Vertex> path_t; typedef typename path_t::iterator path_iterator; public: hohberg_vertex_processor() : phase(1), parent(graph_traits<Graph>::null_vertex()), eta(graph_traits<Graph>::null_vertex()) { } // Called to initialize a leader in the algorithm, which involves // sending out the initial path messages and being ready to receive // them. void initialize_leader(Vertex alpha, const Graph& g); /// Handle a path message on edge e. The path will be destroyed by /// this operation. void operator()(Edge e, path_t& path, const Graph& g); /// Handle a tree message on edge e. in_same_bicomponent will be /// destroyed by this operation. void operator()(Edge e, Vertex gamma, path_t& in_same_bicomponent, const Graph& g); // Handle a name message. void operator()(Edge e, edges_size_type name, const Graph& g); // Retrieve the phase unsigned char get_phase() const { return phase; } // Start the naming phase. The current phase must be 3 (echo), and // the offset contains the offset at which this processor should // begin when labelling its bicomponents. The offset is just a // parallel prefix sum of the number of bicomponents in each // processor that precedes it (globally). void start_naming_phase(Vertex alpha, const Graph& g, edges_size_type offset); /* Determine the number of bicomponents that we will be naming * ourselves. */ edges_size_type num_starting_bicomponents(Vertex alpha, const Graph& g); // Fill in the edge component map with biconnected component // numbers. template<typename ComponentMap> void fill_edge_map(Vertex alpha, const Graph& g, ComponentMap& component); protected: /* Start the echo phase (phase 3) where we propagate information up the tree. */ void echo_phase(Vertex alpha, const Graph& g); /* Retrieve the index of edge in the out-edges list of target(e, g). */ std::size_t get_edge_index(Edge e, const Graph& g); /* Retrieve the index of the edge incidence on v in the out-edges list of vertex u. */ std::size_t get_incident_edge_index(Vertex u, Vertex v, const Graph& g); /* Keeps track of which phase of the algorithm we are in. There are * four phases plus the "finished" phase: * * 1) Building the spanning tree * 2) Discovering cycles * 3) Echoing back up the spanning tree * 4) Labelling biconnected components * 5) Finished */ unsigned char phase; /* The parent of this vertex in the spanning tree. This value will be graph_traits<Graph>::null_vertex() for the leader. */ Vertex parent; /* The farthest ancestor up the tree that resides in the same biconnected component as we do. This information is approximate: we might not know about the actual farthest ancestor, but this is the farthest one we've seen so far. */ Vertex eta; /* The number of edges that have not yet transmitted any messages to us. This starts at the degree of the vertex and decreases as we receive messages. When this counter hits zero, we're done with the second phase of the algorithm. In Hohberg's paper, the actual remaining edge set E is stored with termination when all edges have been removed from E, but we only need to detect termination so the set E need not be explicitly represented. */ degree_size_type num_edges_not_transmitted; /* The path from the root of the spanning tree to this vertex. This vector will always store only the parts of the path leading up to this vertex, and not the vertex itself. Thus, it will be empty for the leader. */ std::vector<Vertex> path_from_root; /* Structure containing all of the extra data we need to keep around PER EDGE. This information can not be contained within a property map, because it can't be shared among vertices without breaking the algorithm. Decreasing the size of this structure will drastically */ struct per_edge_data { hohberg_message<Graph> msg; std::vector<Vertex> M; bool is_tree_edge; degree_size_type partition; }; /* Data for each edge in the graph. This structure will be indexed by the position of the edge in the out_edges() list. */ std::vector<per_edge_data> edge_data; /* The mapping from local partition numbers (0..n-1) to global partition numbers. */ std::vector<edges_size_type> local_to_global_partitions; friend class boost::serialization::access; // We cannot actually serialize a vertex processor, nor would we // want to. However, the fact that we're putting instances into a // distributed_property_map means that we need to have a serialize() // function available. template<typename Archiver> void serialize(Archiver&, const unsigned int /*version*/) { BOOST_ASSERT(false); } }; template<typename Graph> void hohberg_vertex_processor<Graph>::initialize_leader(Vertex alpha, const Graph& g) { using namespace hohberg_detail; ProcessGroup pg = process_group(g); typename property_map<Graph, vertex_owner_t>::const_type owner = get(vertex_owner, g); path_header<Edge> header; header.path_length = 1; BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) { header.edge = e; send(pg, get(owner, target(e, g)), msg_path_header, header); send(pg, get(owner, target(e, g)), msg_path_vertices, alpha); } num_edges_not_transmitted = degree(alpha, g); edge_data.resize(num_edges_not_transmitted); phase = 2; } template<typename Graph> void hohberg_vertex_processor<Graph>::operator()(Edge e, path_t& path, const Graph& g) { using namespace hohberg_detail; typename property_map<Graph, vertex_owner_t>::const_type owner = get(vertex_owner, g); #ifdef PBGL_HOHBERG_DEBUG // std::cerr << local(source(e, g)) << '@' << owner(source(e, g)) << " -> " // << local(target(e, g)) << '@' << owner(target(e, g)) << ": path("; // for (std::size_t i = 0; i < path.size(); ++i) { // if (i > 0) std::cerr << ' '; // std::cerr << local(path[i]) << '@' << owner(path[i]); // } std::cerr << "), phase = " << (int)phase << std::endl; #endif // Get access to edge-specific data if (edge_data.empty()) edge_data.resize(degree(target(e, g), g)); per_edge_data& edata = edge_data[get_edge_index(e, g)]; // Record the message. We'll need it in phase 3. edata.msg.assign(path); // Note: "alpha" refers to the vertex "processor" receiving the // message. Vertex alpha = target(e, g); switch (phase) { case 1: { num_edges_not_transmitted = degree(alpha, g) - 1; edata.is_tree_edge = true; parent = path.back(); eta = parent; edata.M.clear(); edata.M.push_back(parent); // Broadcast the path from the root to our potential children in // the spanning tree. path.push_back(alpha); path_header<Edge> header; header.path_length = path.size(); ProcessGroup pg = process_group(g); BGL_FORALL_OUTEDGES_T(alpha, oe, g, Graph) { // Skip the tree edge we just received if (target(oe, g) != source(e, g)) { header.edge = oe; send(pg, get(owner, target(oe, g)), msg_path_header, header); send(pg, get(owner, target(oe, g)), msg_path_vertices, &path[0], header.path_length); } } path.pop_back(); // Swap the old path in, to save some extra copying. Nobody path_from_root.swap(path); // Once we have received our place in the spanning tree, move on // to phase 2. phase = 2; // If we only had only edge, skip to phase 3. if (num_edges_not_transmitted == 0) echo_phase(alpha, g); return; } case 2: { --num_edges_not_transmitted; edata.is_tree_edge = false; // Determine if alpha (our vertex) is in the path path_iterator pos = std::find(path.begin(), path.end(), alpha); if (pos != path.end()) { // Case A: There is a cycle alpha beta ... gamma alpha // M(e) <- {beta, gammar} edata.M.clear(); ++pos; // If pos == path.end(), we have a self-loop if (pos != path.end()) { // Add beta edata.M.push_back(*pos); ++pos; } // If pos == path.end(), we have a self-loop or beta == gamma // (parallel edge). Otherwise, add gamma. if (pos != path.end()) edata.M.push_back(path.back()); } else { // Case B: There is a cycle but we haven't seen alpha yet. // M(e) = {parent, path.back()} edata.M.clear(); edata.M.push_back(path.back()); if (parent != path.back()) edata.M.push_back(parent); // eta = inf(eta, bra(pi_t, pi)) eta = infimum(path_from_root, eta, branch_point(path_from_root, path)); } if (num_edges_not_transmitted == 0) echo_phase(alpha, g); break; } default: // std::cerr << "Phase is " << int(phase) << "\n"; BOOST_ASSERT(false); } } template<typename Graph> void hohberg_vertex_processor<Graph>::operator()(Edge e, Vertex gamma, path_t& in_same_bicomponent, const Graph& g) { using namespace hohberg_detail; #ifdef PBGL_HOHBERG_DEBUG std::cerr << local(source(e, g)) << '@' << owner(source(e, g)) << " -> " << local(target(e, g)) << '@' << owner(target(e, g)) << ": tree(" << local(gamma) << '@' << owner(gamma) << ", "; for (std::size_t i = 0; i < in_same_bicomponent.size(); ++i) { if (i > 0) std::cerr << ' '; std::cerr << local(in_same_bicomponent[i]) << '@' << owner(in_same_bicomponent[i]); } std::cerr << ", " << local(source(e, g)) << '@' << owner(source(e, g)) << "), phase = " << (int)phase << std::endl; #endif // Get access to edge-specific data per_edge_data& edata = edge_data[get_edge_index(e, g)]; // Record the message. We'll need it in phase 3. edata.msg.assign(gamma, in_same_bicomponent); // Note: "alpha" refers to the vertex "processor" receiving the // message. Vertex alpha = target(e, g); Vertex beta = source(e, g); switch (phase) { case 2: --num_edges_not_transmitted; edata.is_tree_edge = true; if (gamma == alpha) { // Case C edata.M.swap(in_same_bicomponent); } else { // Case D edata.M.clear(); edata.M.push_back(parent); if (beta != parent) edata.M.push_back(beta); eta = infimum(path_from_root, eta, gamma); } if (num_edges_not_transmitted == 0) echo_phase(alpha, g); break; default: BOOST_ASSERT(false); } } template<typename Graph> void hohberg_vertex_processor<Graph>::operator()(Edge e, edges_size_type name, const Graph& g) { using namespace hohberg_detail; #ifdef PBGL_HOHBERG_DEBUG std::cerr << local(source(e, g)) << '@' << owner(source(e, g)) << " -> " << local(target(e, g)) << '@' << owner(target(e, g)) << ": name(" << name << "), phase = " << (int)phase << std::endl; #endif BOOST_ASSERT(phase == 4); typename property_map<Graph, vertex_owner_t>::const_type owner = get(vertex_owner, g); // Send name messages along the spanning tree edges that are in the // same bicomponent as the edge to our parent. ProcessGroup pg = process_group(g); Vertex alpha = target(e, g); std::size_t idx = 0; BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) { per_edge_data& edata = edge_data[idx++]; if (edata.is_tree_edge && find(edata.M.begin(), edata.M.end(), parent) != edata.M.end() && target(e, g) != parent) { // Notify our children in the spanning tree of this name name_header<Edge> header; header.edge = e; header.name = name; send(pg, get(owner, target(e, g)), msg_name, header); } else if (target(e, g) == parent) { // Map from local partition numbers to global bicomponent numbers local_to_global_partitions[edata.partition] = name; } } // Final stage phase = 5; } template<typename Graph> typename hohberg_vertex_processor<Graph>::edges_size_type hohberg_vertex_processor<Graph>:: num_starting_bicomponents(Vertex alpha, const Graph& g) { edges_size_type not_mapped = (std::numeric_limits<edges_size_type>::max)(); edges_size_type result = 0; std::size_t idx = 0; BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) { per_edge_data& edata = edge_data[idx++]; if (edata.is_tree_edge && find(edata.M.begin(), edata.M.end(), parent) == edata.M.end()) { // Map from local partition numbers to global bicomponent numbers if (local_to_global_partitions[edata.partition] == not_mapped) local_to_global_partitions[edata.partition] = result++; } } #ifdef PBGL_HOHBERG_DEBUG std::cerr << local(alpha) << '@' << owner(alpha) << " has " << result << " bicomponents originating at it." << std::endl; #endif return result; } template<typename Graph> template<typename ComponentMap> void hohberg_vertex_processor<Graph>:: fill_edge_map(Vertex alpha, const Graph& g, ComponentMap& component) { std::size_t idx = 0; BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) { per_edge_data& edata = edge_data[idx++]; local_put(component, e, local_to_global_partitions[edata.partition]); #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2 std::cerr << "component(" << local(source(e, g)) << '@' << owner(source(e, g)) << " -> " << local(target(e, g)) << '@' << owner(target(e, g)) << ") = " << local_to_global_partitions[edata.partition] << " (partition = " << edata.partition << " of " << local_to_global_partitions.size() << ")" << std::endl; #endif } } template<typename Graph> void hohberg_vertex_processor<Graph>:: start_naming_phase(Vertex alpha, const Graph& g, edges_size_type offset) { using namespace hohberg_detail; BOOST_ASSERT(phase == 4); typename property_map<Graph, vertex_owner_t>::const_type owner = get(vertex_owner, g); // Send name messages along the spanning tree edges of the // components that we get to number. ProcessGroup pg = process_group(g); bool has_more_children_to_name = false; // Map from local partition numbers to global bicomponent numbers edges_size_type not_mapped = (std::numeric_limits<edges_size_type>::max)(); for (std::size_t i = 0; i < local_to_global_partitions.size(); ++i) { if (local_to_global_partitions[i] != not_mapped) local_to_global_partitions[i] += offset; } std::size_t idx = 0; BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) { per_edge_data& edata = edge_data[idx++]; if (edata.is_tree_edge && find(edata.M.begin(), edata.M.end(), parent) == edata.M.end()) { // Notify our children in the spanning tree of this new name name_header<Edge> header; header.edge = e; header.name = local_to_global_partitions[edata.partition]; send(pg, get(owner, target(e, g)), msg_name, header); } else if (edata.is_tree_edge) { has_more_children_to_name = true; } #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2 std::cerr << "M[" << local(source(e, g)) << '@' << owner(source(e, g)) << " -> " << local(target(e, g)) << '@' << owner(target(e, g)) << "] = "; for (std::size_t i = 0; i < edata.M.size(); ++i) { std::cerr << local(edata.M[i]) << '@' << owner(edata.M[i]) << ' '; } std::cerr << std::endl; #endif } // See if we're done. if (!has_more_children_to_name) // Final stage phase = 5; } template<typename Graph> void hohberg_vertex_processor<Graph>::echo_phase(Vertex alpha, const Graph& g) { using namespace hohberg_detail; typename property_map<Graph, vertex_owner_t>::const_type owner = get(vertex_owner, g); /* We're entering the echo phase. */ phase = 3; if (parent != graph_traits<Graph>::null_vertex()) { Edge edge_to_parent; #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 1 std::cerr << local(alpha) << '@' << owner(alpha) << " echo: parent = " << local(parent) << '@' << owner(parent) << ", eta = " << local(eta) << '@' << owner(eta) << ", Gamma = "; #endif std::vector<Vertex> bicomp; std::size_t e_index = 0; BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) { if (target(e, g) == parent && parent == eta) { edge_to_parent = e; if (find(bicomp.begin(), bicomp.end(), alpha) == bicomp.end()) { #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 1 std::cerr << local(alpha) << '@' << owner(alpha) << ' '; #endif bicomp.push_back(alpha); } } else { if (target(e, g) == parent) edge_to_parent = e; per_edge_data& edata = edge_data[e_index]; if (edata.msg.is_path()) { path_iterator pos = std::find(edata.msg.path_or_bicomp.begin(), edata.msg.path_or_bicomp.end(), eta); if (pos != edata.msg.path_or_bicomp.end()) { ++pos; if (pos != edata.msg.path_or_bicomp.end() && find(bicomp.begin(), bicomp.end(), *pos) == bicomp.end()) { #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 1 std::cerr << local(*pos) << '@' << owner(*pos) << ' '; #endif bicomp.push_back(*pos); } } } else if (edata.msg.is_tree() && edata.msg.gamma == eta) { for (path_iterator i = edata.msg.path_or_bicomp.begin(); i != edata.msg.path_or_bicomp.end(); ++i) { if (find(bicomp.begin(), bicomp.end(), *i) == bicomp.end()) { #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 1 std::cerr << local(*i) << '@' << owner(*i) << ' '; #endif bicomp.push_back(*i); } } } } ++e_index; } #ifdef PBGL_HOHBERG_DEBUG std::cerr << std::endl; #endif // Send tree(eta, bicomp) to parent tree_header<Vertex, Edge> header; header.edge = edge_to_parent; header.gamma = eta; header.bicomp_length = bicomp.size(); ProcessGroup pg = process_group(g); send(pg, get(owner, parent), msg_tree_header, header); send(pg, get(owner, parent), msg_tree_vertices, &bicomp[0], header.bicomp_length); } // Compute the partition of edges such that iff two edges e1 and e2 // are in different subsets then M(e1) is disjoint from M(e2). // Start by putting each edge in a different partition std::vector<degree_size_type> parent_vec(edge_data.size()); degree_size_type idx = 0; for (idx = 0; idx < edge_data.size(); ++idx) parent_vec[idx] = idx; // Go through each edge e, performing a union() on the edges // incident on all vertices in M[e]. idx = 0; BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) { per_edge_data& edata = edge_data[idx++]; // Compute union of vertices in M if (!edata.M.empty()) { degree_size_type e1 = get_incident_edge_index(alpha, edata.M.front(), g); while (parent_vec[e1] != e1) e1 = parent_vec[e1]; for (std::size_t i = 1; i < edata.M.size(); ++i) { degree_size_type e2 = get_incident_edge_index(alpha, edata.M[i], g); while (parent_vec[e2] != e2) e2 = parent_vec[e2]; parent_vec[e2] = e1; } } } edges_size_type not_mapped = (std::numeric_limits<edges_size_type>::max)(); // Determine the number of partitions for (idx = 0; idx < parent_vec.size(); ++idx) { if (parent_vec[idx] == idx) { edge_data[idx].partition = local_to_global_partitions.size(); local_to_global_partitions.push_back(not_mapped); } } // Assign partition numbers to each edge for (idx = 0; idx < parent_vec.size(); ++idx) { degree_size_type rep = parent_vec[idx]; while (rep != parent_vec[rep]) rep = parent_vec[rep]; edge_data[idx].partition = edge_data[rep].partition; } // Enter the naming phase (but don't send anything yet). phase = 4; } template<typename Graph> std::size_t hohberg_vertex_processor<Graph>::get_edge_index(Edge e, const Graph& g) { std::size_t result = 0; BGL_FORALL_OUTEDGES_T(target(e, g), oe, g, Graph) { if (source(e, g) == target(oe, g)) return result; ++result; } BOOST_ASSERT(false); } template<typename Graph> std::size_t hohberg_vertex_processor<Graph>::get_incident_edge_index(Vertex u, Vertex v, const Graph& g) { std::size_t result = 0; BGL_FORALL_OUTEDGES_T(u, e, g, Graph) { if (target(e, g) == v) return result; ++result; } BOOST_ASSERT(false); } template<typename Graph, typename InputIterator, typename ComponentMap, typename VertexProcessorMap> typename graph_traits<Graph>::edges_size_type hohberg_biconnected_components (const Graph& g, ComponentMap component, InputIterator first, InputIterator last, VertexProcessorMap vertex_processor) { using namespace boost::graph::parallel; using namespace hohberg_detail; using boost::parallel::all_reduce; typename property_map<Graph, vertex_owner_t>::const_type owner = get(vertex_owner, g); // The graph must be undirected BOOST_STATIC_ASSERT( (is_convertible<typename graph_traits<Graph>::directed_category, undirected_tag>::value)); // The graph must model Incidence Graph BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<Graph> )); typedef typename graph_traits<Graph>::edges_size_type edges_size_type; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor; // Retrieve the process group we will use for communication typedef typename process_group_type<Graph>::type process_group_type; process_group_type pg = process_group(g); // Keeps track of the edges that we know to be tree edges. std::vector<edge_descriptor> tree_edges; // The leaders send out a path message to initiate the algorithm while (first != last) { vertex_descriptor leader = *first; if (process_id(pg) == get(owner, leader)) vertex_processor[leader].initialize_leader(leader, g); ++first; } synchronize(pg); // Will hold the number of bicomponents in the graph. edges_size_type num_bicomponents = 0; // Keep track of the path length that we should expect, based on the // level in the breadth-first search tree. At present, this is only // used as a sanity check. TBD: This could be used to decrease the // amount of communication required per-edge (by about 4 bytes). std::size_t path_length = 1; typedef std::vector<vertex_descriptor> path_t; unsigned char minimum_phase = 5; do { while (optional<std::pair<int, int> > msg = probe(pg)) { switch (msg->second) { case msg_path_header: { // Receive the path header path_header<edge_descriptor> header; receive(pg, msg->first, msg->second, header); BOOST_ASSERT(path_length == header.path_length); // Receive the path itself path_t path(path_length); receive(pg, msg->first, msg_path_vertices, &path[0], path_length); edge_descriptor e = header.edge; vertex_processor[target(e, g)](e, path, g); } break; case msg_path_vertices: // Should be handled in msg_path_header case, unless we're going // stateless. BOOST_ASSERT(false); break; case msg_tree_header: { // Receive the tree header tree_header<vertex_descriptor, edge_descriptor> header; receive(pg, msg->first, msg->second, header); // Receive the tree itself path_t in_same_bicomponent(header.bicomp_length); receive(pg, msg->first, msg_tree_vertices, &in_same_bicomponent[0], header.bicomp_length); edge_descriptor e = header.edge; vertex_processor[target(e, g)](e, header.gamma, in_same_bicomponent, g); } break; case msg_tree_vertices: // Should be handled in msg_tree_header case, unless we're // going stateless. BOOST_ASSERT(false); break; case msg_name: { name_header<edge_descriptor> header; receive(pg, msg->first, msg->second, header); edge_descriptor e = header.edge; vertex_processor[target(e, g)](e, header.name, g); } break; default: BOOST_ASSERT(false); } } ++path_length; // Compute minimum phase locally minimum_phase = 5; unsigned char maximum_phase = 1; BGL_FORALL_VERTICES_T(v, g, Graph) { minimum_phase = (std::min)(minimum_phase, vertex_processor[v].get_phase()); maximum_phase = (std::max)(maximum_phase, vertex_processor[v].get_phase()); } #ifdef PBGL_HOHBERG_DEBUG if (process_id(pg) == 0) std::cerr << "<---------End of stage------------->" << std::endl; #endif // Compute minimum phase globally minimum_phase = all_reduce(pg, minimum_phase, boost::mpi::minimum<char>()); #ifdef PBGL_HOHBERG_DEBUG if (process_id(pg) == 0) std::cerr << "Minimum phase = " << (int)minimum_phase << std::endl; #endif if (minimum_phase == 4 && all_reduce(pg, maximum_phase, boost::mpi::maximum<char>()) == 4) { #ifdef PBGL_HOHBERG_DEBUG if (process_id(pg) == 0) std::cerr << "<---------Naming phase------------->" << std::endl; #endif // Compute the biconnected component number offsets for each // vertex. std::vector<edges_size_type> local_offsets; local_offsets.reserve(num_vertices(g)); edges_size_type num_local_bicomponents = 0; BGL_FORALL_VERTICES_T(v, g, Graph) { local_offsets.push_back(num_local_bicomponents); num_local_bicomponents += vertex_processor[v].num_starting_bicomponents(v, g); } synchronize(pg); // Find our the number of bicomponent names that will originate // from each process. This tells us how many bicomponents are in // the entire graph and what our global offset is for computing // our own biconnected component names. std::vector<edges_size_type> all_bicomponents(num_processes(pg)); all_gather(pg, &num_local_bicomponents, &num_local_bicomponents + 1, all_bicomponents); num_bicomponents = 0; edges_size_type my_global_offset = 0; for (std::size_t i = 0; i < all_bicomponents.size(); ++i) { if (i == (std::size_t)process_id(pg)) my_global_offset = num_bicomponents; num_bicomponents += all_bicomponents[i]; } std::size_t index = 0; BGL_FORALL_VERTICES_T(v, g, Graph) { edges_size_type offset = my_global_offset + local_offsets[index++]; vertex_processor[v].start_naming_phase(v, g, offset); } } synchronize(pg); } while (minimum_phase < 5); // Number the edges appropriately. BGL_FORALL_VERTICES_T(v, g, Graph) vertex_processor[v].fill_edge_map(v, g, component); return num_bicomponents; } template<typename Graph, typename ComponentMap, typename InputIterator> typename graph_traits<Graph>::edges_size_type hohberg_biconnected_components (const Graph& g, ComponentMap component, InputIterator first, InputIterator last) { std::vector<hohberg_vertex_processor<Graph> > vertex_processors(num_vertices(g)); return hohberg_biconnected_components (g, component, first, last, make_iterator_property_map(vertex_processors.begin(), get(vertex_index, g))); } template<typename Graph, typename ComponentMap, typename ParentMap> typename graph_traits<Graph>::edges_size_type hohberg_biconnected_components(const Graph& g, ComponentMap component, ParentMap parent) { // We need the connected components of the graph, but we don't care // about component numbers. connected_components(g, dummy_property_map(), parent); // Each root in the parent map is a leader typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; std::vector<vertex_descriptor> leaders; BGL_FORALL_VERTICES_T(v, g, Graph) if (get(parent, v) == v) leaders.push_back(v); return hohberg_biconnected_components(g, component, leaders.begin(), leaders.end()); } template<typename Graph, typename ComponentMap> typename graph_traits<Graph>::edges_size_type hohberg_biconnected_components(const Graph& g, ComponentMap component) { typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; std::vector<vertex_descriptor> parents(num_vertices(g)); return hohberg_biconnected_components (g, component, make_iterator_property_map(parents.begin(), get(vertex_index, g))); } } } } // end namespace boost::graph::distributed #endif // BOOST_GRAPH_DISTRIBUTED_HOHBERG_BICONNECTED_COMPONENTS_HPP distributed/dehne_gotz_min_spanning_tree.hpp 0000644 00000113437 15125521275 0015522 0 ustar 00 // Copyright (C) 2004-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine /** * This header implements four distributed algorithms to compute * the minimum spanning tree (actually, minimum spanning forest) of a * graph. All of the algorithms were implemented as specified in the * paper by Dehne and Gotz: * * Frank Dehne and Silvia Gotz. Practical Parallel Algorithms for Minimum * Spanning Trees. In Symposium on Reliable Distributed Systems, * pages 366--371, 1998. * * There are four algorithm variants implemented. */ #ifndef BOOST_DEHNE_GOTZ_MIN_SPANNING_TREE_HPP #define BOOST_DEHNE_GOTZ_MIN_SPANNING_TREE_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/graph_traits.hpp> #include <boost/property_map/property_map.hpp> #include <vector> #include <boost/graph/parallel/algorithm.hpp> #include <boost/limits.hpp> #include <utility> #include <boost/pending/disjoint_sets.hpp> #include <boost/pending/indirect_cmp.hpp> #include <boost/property_map/parallel/caching_property_map.hpp> #include <boost/graph/vertex_and_edge_range.hpp> #include <boost/graph/kruskal_min_spanning_tree.hpp> #include <boost/iterator/counting_iterator.hpp> #include <boost/iterator/transform_iterator.hpp> #include <boost/graph/parallel/container_traits.hpp> #include <boost/graph/parallel/detail/untracked_pair.hpp> #include <cmath> namespace boost { namespace graph { namespace distributed { namespace detail { /** * Binary function object type that selects the (edge, weight) pair * with the minimum weight. Used within a Boruvka merge step to select * the candidate edges incident to each supervertex. */ struct smaller_weighted_edge { template<typename Edge, typename Weight> std::pair<Edge, Weight> operator()(const std::pair<Edge, Weight>& x, const std::pair<Edge, Weight>& y) const { return x.second < y.second? x : y; } }; /** * Unary predicate that determines if the source and target vertices * of the given edge have the same representative within a disjoint * sets data structure. Used to indicate when an edge is now a * self-loop because of supervertex merging in Boruvka's algorithm. */ template<typename DisjointSets, typename Graph> class do_has_same_supervertex { public: typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor; do_has_same_supervertex(DisjointSets& dset, const Graph& g) : dset(dset), g(g) { } bool operator()(edge_descriptor e) { return dset.find_set(source(e, g)) == dset.find_set(target(e, g)); } private: DisjointSets& dset; const Graph& g; }; /** * Build a @ref do_has_same_supervertex object. */ template<typename DisjointSets, typename Graph> inline do_has_same_supervertex<DisjointSets, Graph> has_same_supervertex(DisjointSets& dset, const Graph& g) { return do_has_same_supervertex<DisjointSets, Graph>(dset, g); } /** \brief A single distributed Boruvka merge step. * * A distributed Boruvka merge step involves computing (globally) * the minimum weight edges incident on each supervertex and then * merging supervertices along these edges. Once supervertices are * merged, self-loops are eliminated. * * The set of parameters passed to this algorithm is large, and * considering this algorithm in isolation there are several * redundancies. However, the more asymptotically efficient * distributed MSF algorithms require mixing Boruvka steps with the * merging of local MSFs (implemented in * merge_local_minimum_spanning_trees_step): the interaction of the * two algorithms mandates the addition of these parameters. * * \param pg The process group over which communication should be * performed. Within the distributed Boruvka algorithm, this will be * equivalent to \code process_group(g); however, in the context of * the mixed MSF algorithms, the process group @p pg will be a * (non-strict) process subgroup of \code process_group(g). * * \param g The underlying graph on which the MSF is being * computed. The type of @p g must model DistributedGraph, but there * are no other requirements because the edge and (super)vertex * lists are passed separately. * * \param weight_map Property map containing the weights of each * edge. The type of this property map must model * ReadablePropertyMap and must support caching. * * \param out An output iterator that will be written with the set * of edges selected to build the MSF. Every process within the * process group @p pg will receive all edges in the MSF. * * \param dset Disjoint sets data structure mapping from vertices in * the graph @p g to their representative supervertex. * * \param supervertex_map Mapping from supervertex descriptors to * indices. * * \param supervertices A vector containing all of the * supervertices. Will be modified to include only the remaining * supervertices after merging occurs. * * \param edge_list The list of edges that remain in the graph. This * list will be pruned to remove self-loops once MSF edges have been * found. */ template<typename ProcessGroup, typename Graph, typename WeightMap, typename OutputIterator, typename RankMap, typename ParentMap, typename SupervertexMap, typename Vertex, typename EdgeList> OutputIterator boruvka_merge_step(ProcessGroup pg, const Graph& g, WeightMap weight_map, OutputIterator out, disjoint_sets<RankMap, ParentMap>& dset, SupervertexMap supervertex_map, std::vector<Vertex>& supervertices, EdgeList& edge_list) { typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type; typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor; typedef typename EdgeList::iterator edge_iterator; typedef typename property_traits<WeightMap>::value_type weight_type; typedef boost::parallel::detail::untracked_pair<edge_descriptor, weight_type> w_edge; typedef typename property_traits<SupervertexMap>::value_type supervertex_index; smaller_weighted_edge min_edge; weight_type inf = (std::numeric_limits<weight_type>::max)(); // Renumber the supervertices for (std::size_t i = 0; i < supervertices.size(); ++i) put(supervertex_map, supervertices[i], i); // BSP-B1: Find local minimum-weight edges for each supervertex std::vector<w_edge> candidate_edges(supervertices.size(), w_edge(edge_descriptor(), inf)); for (edge_iterator ei = edge_list.begin(); ei != edge_list.end(); ++ei) { weight_type w = get(weight_map, *ei); supervertex_index u = get(supervertex_map, dset.find_set(source(*ei, g))); supervertex_index v = get(supervertex_map, dset.find_set(target(*ei, g))); if (u != v) { candidate_edges[u] = min_edge(candidate_edges[u], w_edge(*ei, w)); candidate_edges[v] = min_edge(candidate_edges[v], w_edge(*ei, w)); } } // BSP-B2 (a): Compute global minimum edges for each supervertex all_reduce(pg, &candidate_edges[0], &candidate_edges[0] + candidate_edges.size(), &candidate_edges[0], min_edge); // BSP-B2 (b): Use the edges to compute sequentially the new // connected components and emit the edges. for (vertices_size_type i = 0; i < candidate_edges.size(); ++i) { if (candidate_edges[i].second != inf) { edge_descriptor e = candidate_edges[i].first; vertex_descriptor u = dset.find_set(source(e, g)); vertex_descriptor v = dset.find_set(target(e, g)); if (u != v) { // Emit the edge, but cache the weight so everyone knows it cache(weight_map, e, candidate_edges[i].second); *out++ = e; // Link the two supervertices dset.link(u, v); // Whichever vertex was reparented will be removed from the // list of supervertices. vertex_descriptor victim = u; if (dset.find_set(u) == u) victim = v; supervertices[get(supervertex_map, victim)] = graph_traits<Graph>::null_vertex(); } } } // BSP-B3: Eliminate self-loops edge_list.erase(std::remove_if(edge_list.begin(), edge_list.end(), has_same_supervertex(dset, g)), edge_list.end()); // TBD: might also eliminate multiple edges between supervertices // when the edges do not have the best weight, but this is not // strictly necessary. // Eliminate supervertices that have been absorbed supervertices.erase(std::remove(supervertices.begin(), supervertices.end(), graph_traits<Graph>::null_vertex()), supervertices.end()); return out; } /** * An edge descriptor adaptor that reroutes the source and target * edges to different vertices, but retains the original edge * descriptor for, e.g., property maps. This is used when we want to * turn a set of edges in the overall graph into a set of edges * between supervertices. */ template<typename Graph> struct supervertex_edge_descriptor { typedef supervertex_edge_descriptor self_type; typedef typename graph_traits<Graph>::vertex_descriptor Vertex; typedef typename graph_traits<Graph>::edge_descriptor Edge; Vertex source; Vertex target; Edge e; operator Edge() const { return e; } friend inline bool operator==(const self_type& x, const self_type& y) { return x.e == y.e; } friend inline bool operator!=(const self_type& x, const self_type& y) { return x.e != y.e; } }; template<typename Graph> inline typename supervertex_edge_descriptor<Graph>::Vertex source(supervertex_edge_descriptor<Graph> se, const Graph&) { return se.source; } template<typename Graph> inline typename supervertex_edge_descriptor<Graph>::Vertex target(supervertex_edge_descriptor<Graph> se, const Graph&) { return se.target; } /** * Build a supervertex edge descriptor from a normal edge descriptor * using the given disjoint sets data structure to identify * supervertex representatives. */ template<typename Graph, typename DisjointSets> struct build_supervertex_edge_descriptor { typedef typename graph_traits<Graph>::vertex_descriptor Vertex; typedef typename graph_traits<Graph>::edge_descriptor Edge; typedef Edge argument_type; typedef supervertex_edge_descriptor<Graph> result_type; build_supervertex_edge_descriptor() : g(0), dsets(0) { } build_supervertex_edge_descriptor(const Graph& g, DisjointSets& dsets) : g(&g), dsets(&dsets) { } result_type operator()(argument_type e) const { result_type result; result.source = dsets->find_set(source(e, *g)); result.target = dsets->find_set(target(e, *g)); result.e = e; return result; } private: const Graph* g; DisjointSets* dsets; }; template<typename Graph, typename DisjointSets> inline build_supervertex_edge_descriptor<Graph, DisjointSets> make_supervertex_edge_descriptor(const Graph& g, DisjointSets& dsets) { return build_supervertex_edge_descriptor<Graph, DisjointSets>(g, dsets); } template<typename T> struct identity_function { typedef T argument_type; typedef T result_type; result_type operator()(argument_type x) const { return x; } }; template<typename Graph, typename DisjointSets, typename EdgeMapper> class is_not_msf_edge { typedef typename graph_traits<Graph>::vertex_descriptor Vertex; typedef typename graph_traits<Graph>::edge_descriptor Edge; public: is_not_msf_edge(const Graph& g, DisjointSets dset, EdgeMapper edge_mapper) : g(g), dset(dset), edge_mapper(edge_mapper) { } bool operator()(Edge e) { Vertex u = dset.find_set(source(edge_mapper(e), g)); Vertex v = dset.find_set(target(edge_mapper(e), g)); if (u == v) return true; else { dset.link(u, v); return false; } } private: const Graph& g; DisjointSets dset; EdgeMapper edge_mapper; }; template<typename Graph, typename ForwardIterator, typename EdgeList, typename EdgeMapper, typename RankMap, typename ParentMap> void sorted_mutating_kruskal(const Graph& g, ForwardIterator first_vertex, ForwardIterator last_vertex, EdgeList& edge_list, EdgeMapper edge_mapper, RankMap rank_map, ParentMap parent_map) { typedef disjoint_sets<RankMap, ParentMap> DisjointSets; // Build and initialize disjoint-sets data structure DisjointSets dset(rank_map, parent_map); for (ForwardIterator v = first_vertex; v != last_vertex; ++v) dset.make_set(*v); is_not_msf_edge<Graph, DisjointSets, EdgeMapper> remove_non_msf_edges(g, dset, edge_mapper); edge_list.erase(std::remove_if(edge_list.begin(), edge_list.end(), remove_non_msf_edges), edge_list.end()); } /** * Merge local minimum spanning forests from p processes into * minimum spanning forests on p/D processes (where D is the tree * factor, currently fixed at 3), eliminating unnecessary edges in * the process. * * As with @ref boruvka_merge_step, this routine has many * parameters, not all of which make sense within the limited * context of this routine. The parameters are required for the * Boruvka and local MSF merging steps to interoperate. * * \param pg The process group on which local minimum spanning * forests should be merged. The top (D-1)p/D processes will be * eliminated, and a new process subgroup containing p/D processors * will be returned. The value D is a constant factor that is * currently fixed to 3. * * \param g The underlying graph whose MSF is being computed. It must model * the DistributedGraph concept. * * \param first_vertex Iterator to the first vertex in the graph * that should be considered. While the local MSF merging algorithm * typically operates on the entire vertex set, within the hybrid * distributed MSF algorithms this will refer to the first * supervertex. * * \param last_vertex The past-the-end iterator for the vertex list. * * \param edge_list The list of local edges that will be * considered. For the p/D processes that remain, this list will * contain edges in the MSF known to the vertex after other * processes' edge lists have been merged. The edge list must be * sorted in order of increasing weight. * * \param weight Property map containing the weights of each * edge. The type of this property map must model * ReadablePropertyMap and must support caching. * * \param global_index Mapping from vertex descriptors to a global * index. The type must model ReadablePropertyMap. * * \param edge_mapper A function object that can remap edge descriptors * in the edge list to any alternative edge descriptor. This * function object will be the identity function when a pure merging * of local MSFs is required, but may be a mapping to a supervertex * edge when the local MSF merging occurs on a supervertex * graph. This function object saves us the trouble of having to * build a supervertex graph adaptor. * * \param already_local_msf True when the edge list already * constitutes a local MSF. If false, Kruskal's algorithm will first * be applied to the local edge list to select MSF edges. * * \returns The process subgroup containing the remaining p/D * processes. If the size of this process group is greater than one, * the MSF edges contained in the edge list do not constitute an MSF * for the entire graph. */ template<typename ProcessGroup, typename Graph, typename ForwardIterator, typename EdgeList, typename WeightMap, typename GlobalIndexMap, typename EdgeMapper> ProcessGroup merge_local_minimum_spanning_trees_step(ProcessGroup pg, const Graph& g, ForwardIterator first_vertex, ForwardIterator last_vertex, EdgeList& edge_list, WeightMap weight, GlobalIndexMap global_index, EdgeMapper edge_mapper, bool already_local_msf) { typedef typename ProcessGroup::process_id_type process_id_type; typedef typename EdgeList::value_type edge_descriptor; typedef typename property_traits<WeightMap>::value_type weight_type; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; // The tree factor, often called "D" process_id_type const tree_factor = 3; process_id_type num_procs = num_processes(pg); process_id_type id = process_id(pg); process_id_type procs_left = (num_procs + tree_factor - 1) / tree_factor; std::size_t n = std::size_t(last_vertex - first_vertex); if (!already_local_msf) { // Compute local minimum spanning forest. We only care about the // edges in the MSF, because only edges in the local MSF can be in // the global MSF. std::vector<std::size_t> ranks(n); std::vector<vertex_descriptor> parents(n); detail::sorted_mutating_kruskal (g, first_vertex, last_vertex, edge_list, edge_mapper, make_iterator_property_map(ranks.begin(), global_index), make_iterator_property_map(parents.begin(), global_index)); } typedef std::pair<edge_descriptor, weight_type> w_edge; // Order edges based on their weights. indirect_cmp<WeightMap, std::less<weight_type> > cmp_edge_weight(weight); if (id < procs_left) { // The p/D processes that remain will receive local MSF edges from // D-1 other processes. synchronize(pg); for (process_id_type from_id = procs_left + id; from_id < num_procs; from_id += procs_left) { std::size_t num_incoming_edges; receive(pg, from_id, 0, num_incoming_edges); if (num_incoming_edges > 0) { std::vector<w_edge> incoming_edges(num_incoming_edges); receive(pg, from_id, 1, &incoming_edges[0], num_incoming_edges); edge_list.reserve(edge_list.size() + num_incoming_edges); for (std::size_t i = 0; i < num_incoming_edges; ++i) { cache(weight, incoming_edges[i].first, incoming_edges[i].second); edge_list.push_back(incoming_edges[i].first); } std::inplace_merge(edge_list.begin(), edge_list.end() - num_incoming_edges, edge_list.end(), cmp_edge_weight); } } // Compute the local MSF from union of the edges in the MSFs of // all children. std::vector<std::size_t> ranks(n); std::vector<vertex_descriptor> parents(n); detail::sorted_mutating_kruskal (g, first_vertex, last_vertex, edge_list, edge_mapper, make_iterator_property_map(ranks.begin(), global_index), make_iterator_property_map(parents.begin(), global_index)); } else { // The (D-1)p/D processes that are dropping out of further // computations merely send their MSF edges to their parent // process in the process tree. send(pg, id % procs_left, 0, edge_list.size()); if (edge_list.size() > 0) { std::vector<w_edge> outgoing_edges; outgoing_edges.reserve(edge_list.size()); for (std::size_t i = 0; i < edge_list.size(); ++i) { outgoing_edges.push_back(std::make_pair(edge_list[i], get(weight, edge_list[i]))); } send(pg, id % procs_left, 1, &outgoing_edges[0], outgoing_edges.size()); } synchronize(pg); } // Return a process subgroup containing the p/D parent processes return process_subgroup(pg, make_counting_iterator(process_id_type(0)), make_counting_iterator(procs_left)); } } // end namespace detail // --------------------------------------------------------------------- // Dense Boruvka MSF algorithm // --------------------------------------------------------------------- template<typename Graph, typename WeightMap, typename OutputIterator, typename VertexIndexMap, typename RankMap, typename ParentMap, typename SupervertexMap> OutputIterator dense_boruvka_minimum_spanning_tree(const Graph& g, WeightMap weight_map, OutputIterator out, VertexIndexMap index_map, RankMap rank_map, ParentMap parent_map, SupervertexMap supervertex_map) { using boost::graph::parallel::process_group; typedef typename graph_traits<Graph>::traversal_category traversal_category; BOOST_STATIC_ASSERT((is_convertible<traversal_category*, vertex_list_graph_tag*>::value)); typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator; typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor; // Don't throw away cached edge weights weight_map.set_max_ghost_cells(0); // Initialize the disjoint sets structures disjoint_sets<RankMap, ParentMap> dset(rank_map, parent_map); vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) dset.make_set(*vi); std::vector<vertex_descriptor> supervertices; supervertices.assign(vertices(g).first, vertices(g).second); // Use Kruskal's algorithm to find the minimum spanning forest // considering only the local edges. The resulting edges are not // necessarily going to be in the final minimum spanning // forest. However, any edge not part of the local MSF cannot be a // part of the global MSF, so we should have eliminated some edges // from consideration. std::vector<edge_descriptor> edge_list; kruskal_minimum_spanning_tree (make_vertex_and_edge_range(g, vertices(g).first, vertices(g).second, edges(g).first, edges(g).second), std::back_inserter(edge_list), boost::weight_map(weight_map). vertex_index_map(index_map)); // While the number of supervertices is decreasing, keep executing // Boruvka steps to identify additional MSF edges. This loop will // execute log |V| times. vertices_size_type old_num_supervertices; do { old_num_supervertices = supervertices.size(); out = detail::boruvka_merge_step(process_group(g), g, weight_map, out, dset, supervertex_map, supervertices, edge_list); } while (supervertices.size() < old_num_supervertices); return out; } template<typename Graph, typename WeightMap, typename OutputIterator, typename VertexIndex> OutputIterator dense_boruvka_minimum_spanning_tree(const Graph& g, WeightMap weight_map, OutputIterator out, VertexIndex i_map) { typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; std::vector<std::size_t> ranks(num_vertices(g)); std::vector<vertex_descriptor> parents(num_vertices(g)); std::vector<std::size_t> supervertices(num_vertices(g)); return dense_boruvka_minimum_spanning_tree (g, weight_map, out, i_map, make_iterator_property_map(ranks.begin(), i_map), make_iterator_property_map(parents.begin(), i_map), make_iterator_property_map(supervertices.begin(), i_map)); } template<typename Graph, typename WeightMap, typename OutputIterator> OutputIterator dense_boruvka_minimum_spanning_tree(const Graph& g, WeightMap weight_map, OutputIterator out) { return dense_boruvka_minimum_spanning_tree(g, weight_map, out, get(vertex_index, g)); } // --------------------------------------------------------------------- // Merge local MSFs MSF algorithm // --------------------------------------------------------------------- template<typename Graph, typename WeightMap, typename OutputIterator, typename GlobalIndexMap> OutputIterator merge_local_minimum_spanning_trees(const Graph& g, WeightMap weight, OutputIterator out, GlobalIndexMap global_index) { using boost::graph::parallel::process_group_type; using boost::graph::parallel::process_group; typedef typename graph_traits<Graph>::traversal_category traversal_category; BOOST_STATIC_ASSERT((is_convertible<traversal_category*, vertex_list_graph_tag*>::value)); typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor; // Don't throw away cached edge weights weight.set_max_ghost_cells(0); // Compute the initial local minimum spanning forests std::vector<edge_descriptor> edge_list; kruskal_minimum_spanning_tree (make_vertex_and_edge_range(g, vertices(g).first, vertices(g).second, edges(g).first, edges(g).second), std::back_inserter(edge_list), boost::weight_map(weight).vertex_index_map(global_index)); // Merge the local MSFs from p processes into p/D processes, // reducing the number of processes in each step. Continue looping // until either (a) the current process drops out or (b) only one // process remains in the group. This loop will execute log_D p // times. typename process_group_type<Graph>::type pg = process_group(g); while (pg && num_processes(pg) > 1) { pg = detail::merge_local_minimum_spanning_trees_step (pg, g, vertices(g).first, vertices(g).second, edge_list, weight, global_index, detail::identity_function<edge_descriptor>(), true); } // Only process 0 has the entire edge list, so emit it to the output // iterator. if (pg && process_id(pg) == 0) { out = std::copy(edge_list.begin(), edge_list.end(), out); } synchronize(process_group(g)); return out; } template<typename Graph, typename WeightMap, typename OutputIterator> inline OutputIterator merge_local_minimum_spanning_trees(const Graph& g, WeightMap weight, OutputIterator out) { return merge_local_minimum_spanning_trees(g, weight, out, get(vertex_index, g)); } // --------------------------------------------------------------------- // Boruvka-then-merge MSF algorithm // --------------------------------------------------------------------- template<typename Graph, typename WeightMap, typename OutputIterator, typename GlobalIndexMap, typename RankMap, typename ParentMap, typename SupervertexMap> OutputIterator boruvka_then_merge(const Graph& g, WeightMap weight, OutputIterator out, GlobalIndexMap index, RankMap rank_map, ParentMap parent_map, SupervertexMap supervertex_map) { using std::log; using boost::graph::parallel::process_group_type; using boost::graph::parallel::process_group; typedef typename graph_traits<Graph>::traversal_category traversal_category; BOOST_STATIC_ASSERT((is_convertible<traversal_category*, vertex_list_graph_tag*>::value)); typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator; typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor; // Don't throw away cached edge weights weight.set_max_ghost_cells(0); // Compute the initial local minimum spanning forests std::vector<edge_descriptor> edge_list; kruskal_minimum_spanning_tree (make_vertex_and_edge_range(g, vertices(g).first, vertices(g).second, edges(g).first, edges(g).second), std::back_inserter(edge_list), boost::weight_map(weight). vertex_index_map(index)); // Initialize the disjoint sets structures for Boruvka steps disjoint_sets<RankMap, ParentMap> dset(rank_map, parent_map); vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) dset.make_set(*vi); // Construct the initial set of supervertices (all vertices) std::vector<vertex_descriptor> supervertices; supervertices.assign(vertices(g).first, vertices(g).second); // Continue performing Boruvka merge steps until the number of // supervertices reaches |V| / (log_D p)^2. const std::size_t tree_factor = 3; // TBD: same as above! should be param double log_d_p = log((double)num_processes(process_group(g))) / log((double)tree_factor); vertices_size_type target_supervertices = vertices_size_type(num_vertices(g) / (log_d_p * log_d_p)); vertices_size_type old_num_supervertices; while (supervertices.size() > target_supervertices) { old_num_supervertices = supervertices.size(); out = detail::boruvka_merge_step(process_group(g), g, weight, out, dset, supervertex_map, supervertices, edge_list); if (supervertices.size() == old_num_supervertices) return out; } // Renumber the supervertices for (std::size_t i = 0; i < supervertices.size(); ++i) put(supervertex_map, supervertices[i], i); // Merge local MSFs on the supervertices. (D-1)p/D processors drop // out each iteration, so this loop executes log_D p times. typename process_group_type<Graph>::type pg = process_group(g); bool have_msf = false; while (pg && num_processes(pg) > 1) { pg = detail::merge_local_minimum_spanning_trees_step (pg, g, supervertices.begin(), supervertices.end(), edge_list, weight, supervertex_map, detail::make_supervertex_edge_descriptor(g, dset), have_msf); have_msf = true; } // Only process 0 has the complete list of _supervertex_ MST edges, // so emit those to the output iterator. This is not the complete // list of edges in the MSF, however: the Boruvka steps in the // beginning of the algorithm emitted any edges used to merge // supervertices. if (pg && process_id(pg) == 0) out = std::copy(edge_list.begin(), edge_list.end(), out); synchronize(process_group(g)); return out; } template<typename Graph, typename WeightMap, typename OutputIterator, typename GlobalIndexMap> inline OutputIterator boruvka_then_merge(const Graph& g, WeightMap weight, OutputIterator out, GlobalIndexMap index) { typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type; std::vector<vertices_size_type> ranks(num_vertices(g)); std::vector<vertex_descriptor> parents(num_vertices(g)); std::vector<vertices_size_type> supervertex_indices(num_vertices(g)); return boruvka_then_merge (g, weight, out, index, make_iterator_property_map(ranks.begin(), index), make_iterator_property_map(parents.begin(), index), make_iterator_property_map(supervertex_indices.begin(), index)); } template<typename Graph, typename WeightMap, typename OutputIterator> inline OutputIterator boruvka_then_merge(const Graph& g, WeightMap weight, OutputIterator out) { return boruvka_then_merge(g, weight, out, get(vertex_index, g)); } // --------------------------------------------------------------------- // Boruvka-mixed-merge MSF algorithm // --------------------------------------------------------------------- template<typename Graph, typename WeightMap, typename OutputIterator, typename GlobalIndexMap, typename RankMap, typename ParentMap, typename SupervertexMap> OutputIterator boruvka_mixed_merge(const Graph& g, WeightMap weight, OutputIterator out, GlobalIndexMap index, RankMap rank_map, ParentMap parent_map, SupervertexMap supervertex_map) { using boost::graph::parallel::process_group_type; using boost::graph::parallel::process_group; typedef typename graph_traits<Graph>::traversal_category traversal_category; BOOST_STATIC_ASSERT((is_convertible<traversal_category*, vertex_list_graph_tag*>::value)); typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator; typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor; // Don't throw away cached edge weights weight.set_max_ghost_cells(0); // Initialize the disjoint sets structures for Boruvka steps disjoint_sets<RankMap, ParentMap> dset(rank_map, parent_map); vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) dset.make_set(*vi); // Construct the initial set of supervertices (all vertices) std::vector<vertex_descriptor> supervertices; supervertices.assign(vertices(g).first, vertices(g).second); // Compute the initial local minimum spanning forests std::vector<edge_descriptor> edge_list; kruskal_minimum_spanning_tree (make_vertex_and_edge_range(g, vertices(g).first, vertices(g).second, edges(g).first, edges(g).second), std::back_inserter(edge_list), boost::weight_map(weight). vertex_index_map(index)); if (num_processes(process_group(g)) == 1) { return std::copy(edge_list.begin(), edge_list.end(), out); } // Like the merging local MSFs algorithm and the Boruvka-then-merge // algorithm, each iteration of this loop reduces the number of // processes by a constant factor D, and therefore we require log_D // p iterations. Note also that the number of edges in the edge list // decreases geometrically, giving us an efficient distributed MSF // algorithm. typename process_group_type<Graph>::type pg = process_group(g); vertices_size_type old_num_supervertices; while (pg && num_processes(pg) > 1) { // A single Boruvka step. If this doesn't change anything, we're done old_num_supervertices = supervertices.size(); out = detail::boruvka_merge_step(pg, g, weight, out, dset, supervertex_map, supervertices, edge_list); if (old_num_supervertices == supervertices.size()) { edge_list.clear(); break; } // Renumber the supervertices for (std::size_t i = 0; i < supervertices.size(); ++i) put(supervertex_map, supervertices[i], i); // A single merging of local MSTs, which reduces the number of // processes we're using by a constant factor D. pg = detail::merge_local_minimum_spanning_trees_step (pg, g, supervertices.begin(), supervertices.end(), edge_list, weight, supervertex_map, detail::make_supervertex_edge_descriptor(g, dset), true); } // Only process 0 has the complete edge list, so emit it for the // user. Note that list edge list only contains the MSF edges in the // final supervertex graph: all of the other edges were used to // merge supervertices and have been emitted by the Boruvka steps, // although only process 0 has received the complete set. if (pg && process_id(pg) == 0) out = std::copy(edge_list.begin(), edge_list.end(), out); synchronize(process_group(g)); return out; } template<typename Graph, typename WeightMap, typename OutputIterator, typename GlobalIndexMap> inline OutputIterator boruvka_mixed_merge(const Graph& g, WeightMap weight, OutputIterator out, GlobalIndexMap index) { typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type; std::vector<vertices_size_type> ranks(num_vertices(g)); std::vector<vertex_descriptor> parents(num_vertices(g)); std::vector<vertices_size_type> supervertex_indices(num_vertices(g)); return boruvka_mixed_merge (g, weight, out, index, make_iterator_property_map(ranks.begin(), index), make_iterator_property_map(parents.begin(), index), make_iterator_property_map(supervertex_indices.begin(), index)); } template<typename Graph, typename WeightMap, typename OutputIterator> inline OutputIterator boruvka_mixed_merge(const Graph& g, WeightMap weight, OutputIterator out) { return boruvka_mixed_merge(g, weight, out, get(vertex_index, g)); } } // end namespace distributed using distributed::dense_boruvka_minimum_spanning_tree; using distributed::merge_local_minimum_spanning_trees; using distributed::boruvka_then_merge; using distributed::boruvka_mixed_merge; } } // end namespace boost::graph #endif // BOOST_DEHNE_GOTZ_MIN_SPANNING_TREE_HPP distributed/reverse_graph.hpp 0000644 00000002307 15125521275 0012442 0 ustar 00 // Copyright (C) 2005-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Nick Edmonds // Andrew Lumsdaine #ifndef BOOST_GRAPH_DISTRIBUTED_REVERSE_GRAPH_HPP #define BOOST_GRAPH_DISTRIBUTED_REVERSE_GRAPH_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/reverse_graph.hpp> #include <boost/graph/parallel/container_traits.hpp> namespace boost { namespace graph { namespace parallel { /// Retrieve the process group from a reverse graph template<typename Graph, typename GraphRef> struct process_group_type<reverse_graph<Graph, GraphRef> > : process_group_type<Graph> { }; } } /// Retrieve the process group from a reverse graph template<typename Graph, typename GraphRef> inline typename graph::parallel::process_group_type<Graph>::type process_group(reverse_graph<Graph, GraphRef> const& g) { return process_group(g.m_g); } } // namespace boost #endif distributed/depth_first_search.hpp 0000644 00000024305 15125521275 0013450 0 ustar 00 // Copyright (C) 2004-2008 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_DISTRIBUTED_DFS_HPP #define BOOST_GRAPH_DISTRIBUTED_DFS_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/graph_traits.hpp> #include <boost/property_map/property_map.hpp> #include <boost/graph/overloading.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/distributed/concepts.hpp> #include <boost/static_assert.hpp> #include <boost/assert.hpp> #include <boost/graph/parallel/process_group.hpp> #include <boost/graph/parallel/container_traits.hpp> namespace boost { namespace graph { namespace distributed { namespace detail { template<typename DistributedGraph, typename ColorMap, typename ParentMap, typename ExploreMap, typename VertexIndexMap, typename DFSVisitor> class parallel_dfs { typedef typename graph_traits<DistributedGraph>::vertex_iterator vertex_iterator; typedef typename graph_traits<DistributedGraph>::vertex_descriptor vertex_descriptor; typedef typename graph_traits<DistributedGraph>::out_edge_iterator out_edge_iterator; typedef typename boost::graph::parallel::process_group_type<DistributedGraph> ::type process_group_type; typedef typename process_group_type::process_id_type process_id_type; /** * The first vertex in the pair is the local node (i) and the * second vertex in the pair is the (possibly remote) node (j). */ typedef boost::parallel::detail::untracked_pair<vertex_descriptor, vertex_descriptor> vertex_pair; typedef typename property_traits<ColorMap>::value_type color_type; typedef color_traits<color_type> Color; // Message types enum { discover_msg = 10, return_msg = 50, visited_msg = 100 , done_msg = 150}; public: parallel_dfs(const DistributedGraph& g, ColorMap color, ParentMap parent, ExploreMap explore, VertexIndexMap index_map, DFSVisitor vis) : g(g), color(color), parent(parent), explore(explore), index_map(index_map), vis(vis), pg(process_group(g)), owner(get(vertex_owner, g)), next_out_edge(num_vertices(g)) { } void run(vertex_descriptor s) { vertex_iterator vi, vi_end; for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { put(color, *vi, Color::white()); put(parent, *vi, *vi); put(explore, *vi, *vi); next_out_edge[get(index_map, *vi)] = out_edges(*vi, g).first; vis.initialize_vertex(*vi, g); } vis.start_vertex(s, g); if (get(owner, s) == process_id(pg)) { send_oob(pg, get(owner, s), discover_msg, vertex_pair(s, s)); } bool done = false; while (!done) { std::pair<process_id_type, int> msg = *pg.poll(true); switch (msg.second) { case discover_msg: { vertex_pair p; receive_oob(pg, msg.first, msg.second, p); if (p.first != p.second) { // delete j from nomessage(j) if (get(color, p.second) != Color::black()) local_put(color, p.second, Color::gray()); if (recover(p)) break; } if (get(color, p.first) == Color::white()) { put(color, p.first, Color::gray()); put(parent, p.first, p.second); vis.discover_vertex(p.first, g); if (shift_center_of_activity(p.first)) break; out_edge_iterator ei, ei_end; for (boost::tie(ei,ei_end) = out_edges(p.first, g); ei != ei_end; ++ei) { // Notify everyone who may not know that the source // vertex has been visited. They can then mark the // corresponding color map entry gray. if (get(parent, p.first) != target(*ei, g) && get(explore, p.first) != target(*ei, g)) { vertex_pair visit(target(*ei, g), p.first); send_oob(pg, get(owner, target(*ei, g)), visited_msg, visit); } } } } break; case visited_msg: { vertex_pair p; receive_oob(pg, msg.first, msg.second, p); // delete j from nomessage(j) if (get(color, p.second) != Color::black()) local_put(color, p.second, Color::gray()); recover(p); } break; case return_msg: { vertex_pair p; receive_oob(pg, msg.first, msg.second, p); // delete j from nomessage(i) local_put(color, p.second, Color::black()); shift_center_of_activity(p.first); } break; case done_msg: { receive_oob(pg, msg.first, msg.second, done); // Propagate done message downward in tree done = true; process_id_type id = process_id(pg); process_id_type left = 2*id + 1; process_id_type right = left + 1; if (left < num_processes(pg)) send_oob(pg, left, done_msg, done); if (right < num_processes(pg)) send_oob(pg, right, done_msg, done); } break; default: BOOST_ASSERT(false); } } } private: bool recover(const vertex_pair& p) { if (get(explore, p.first) == p.second) { return shift_center_of_activity(p.first); } else return false; } bool shift_center_of_activity(vertex_descriptor i) { for (out_edge_iterator ei = next_out_edge[get(index_map, i)], ei_end = out_edges(i, g).second; ei != ei_end; ++ei) { vis.examine_edge(*ei, g); vertex_descriptor k = target(*ei, g); color_type target_color = get(color, k); if (target_color == Color::black()) vis.forward_or_cross_edge(*ei, g); else if (target_color == Color::gray()) vis.back_edge(*ei, g); else { put(explore, i, k); vis.tree_edge(*ei, g); vertex_pair p(k, i); send_oob(pg, get(owner, k), discover_msg, p); next_out_edge[get(index_map, i)] = ++ei; return false; } } next_out_edge[get(index_map, i)] = out_edges(i, g).second; put(explore, i, i); put(color, i, Color::black()); vis.finish_vertex(i, g); if (get(parent, i) == i) { send_oob(pg, 0, done_msg, true); return true; } else { vertex_pair ret(get(parent, i), i); send_oob(pg, get(owner, ret.first), return_msg, ret); } return false; } const DistributedGraph& g; ColorMap color; ParentMap parent; ExploreMap explore; VertexIndexMap index_map; DFSVisitor vis; process_group_type pg; typename property_map<DistributedGraph, vertex_owner_t>::const_type owner; std::vector<out_edge_iterator> next_out_edge; }; } // end namespace detail template<typename DistributedGraph, typename ColorMap, typename ParentMap, typename ExploreMap, typename VertexIndexMap, typename DFSVisitor> void tsin_depth_first_visit (const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, DFSVisitor vis, ColorMap color, ParentMap parent, ExploreMap explore, VertexIndexMap index_map) { typedef typename graph_traits<DistributedGraph>::directed_category directed_category; BOOST_STATIC_ASSERT( (is_convertible<directed_category, undirected_tag>::value)); set_property_map_role(vertex_color, color); graph::distributed::detail::parallel_dfs <DistributedGraph, ColorMap, ParentMap, ExploreMap, VertexIndexMap, DFSVisitor> do_dfs(g, color, parent, explore, index_map, vis); do_dfs.run(s); using boost::graph::parallel::process_group; synchronize(process_group(g)); } template<typename DistributedGraph, typename DFSVisitor, typename VertexIndexMap> void tsin_depth_first_visit (const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, DFSVisitor vis, VertexIndexMap index_map) { typedef typename graph_traits<DistributedGraph>::vertex_descriptor vertex_descriptor; std::vector<default_color_type> colors(num_vertices(g)); std::vector<vertex_descriptor> parent(num_vertices(g)); std::vector<vertex_descriptor> explore(num_vertices(g)); tsin_depth_first_visit (g, s, vis, make_iterator_property_map(colors.begin(), index_map), make_iterator_property_map(parent.begin(), index_map), make_iterator_property_map(explore.begin(), index_map), index_map); } template<typename DistributedGraph, typename DFSVisitor, typename VertexIndexMap> void tsin_depth_first_visit (const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, DFSVisitor vis) { tsin_depth_first_visit(g, s, vis, get(vertex_index, g)); } } // end namespace distributed using distributed::tsin_depth_first_visit; } // end namespace graph template<typename DistributedGraph, typename DFSVisitor> void depth_first_visit (const DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, DFSVisitor vis) { graph::tsin_depth_first_visit(g, s, vis, get(vertex_index, g)); } } // end namespace boost #endif // BOOST_GRAPH_DISTRIBUTED_DFS_HPP distributed/distributed_graph_utility.hpp 0000644 00000010720 15125521275 0015072 0 ustar 00 // Copyright (C) 2005-2006 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Peter Gottschling // Douglas Gregor // Andrew Lumsdaine #include <boost/graph/iteration_macros.hpp> #include <boost/property_map/parallel/global_index_map.hpp> #ifndef BOOST_GRAPH_DISTRIBUTED_GRAPH_UTILITY_INCLUDE #define BOOST_GRAPH_DISTRIBUTED_GRAPH_UTILITY_INCLUDE #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif namespace boost { namespace graph { template <class Property, class Graph> void property_on_inedges(Property p, const Graph& g) { BGL_FORALL_VERTICES_T(u, g, Graph) BGL_FORALL_INEDGES_T(u, e, g, Graph) request(p, e); synchronize(p); } // For reverse graphs template <class Property, class Graph> void property_on_outedges(Property p, const Graph& g) { BGL_FORALL_VERTICES_T(u, g, Graph) BGL_FORALL_OUTEDGES_T(u, e, g, Graph) request(p, e); synchronize(p); } template <class Property, class Graph> void property_on_successors(Property p, const Graph& g) { BGL_FORALL_VERTICES_T(u, g, Graph) BGL_FORALL_OUTEDGES_T(u, e, g, Graph) request(p, target(e, g)); synchronize(p); } template <class Property, class Graph> void property_on_predecessors(Property p, const Graph& g) { BGL_FORALL_VERTICES_T(u, g, Graph) BGL_FORALL_INEDGES_T(u, e, g, Graph) request(p, source(e, g)); synchronize(p); } // Like successors and predecessors but saves one synchronize (and a call) template <class Property, class Graph> void property_on_adjacents(Property p, const Graph& g) { BGL_FORALL_VERTICES_T(u, g, Graph) { BGL_FORALL_OUTEDGES_T(u, e, g, Graph) request(p, target(e, g)); BGL_FORALL_INEDGES_T(u, e, g, Graph) request(p, source(e, g)); } synchronize(p); } template <class PropertyIn, class PropertyOut, class Graph> void copy_vertex_property(PropertyIn p_in, PropertyOut p_out, Graph& g) { BGL_FORALL_VERTICES_T(u, g, Graph) put(p_out, u, get(p_in, g)); } template <class PropertyIn, class PropertyOut, class Graph> void copy_edge_property(PropertyIn p_in, PropertyOut p_out, Graph& g) { BGL_FORALL_EDGES_T(e, g, Graph) put(p_out, e, get(p_in, g)); } namespace distributed { // Define global_index<Graph> global(graph); // Then global(v) returns global index of v template <typename Graph> struct global_index { typedef typename property_map<Graph, vertex_index_t>::const_type VertexIndexMap; typedef typename property_map<Graph, vertex_global_t>::const_type VertexGlobalMap; explicit global_index(Graph const& g) : global_index_map(process_group(g), num_vertices(g), get(vertex_index, g), get(vertex_global, g)) {} int operator() (typename graph_traits<Graph>::vertex_descriptor v) { return get(global_index_map, v); } protected: boost::parallel::global_index_map<VertexIndexMap, VertexGlobalMap> global_index_map; }; template<typename T> struct additive_reducer { BOOST_STATIC_CONSTANT(bool, non_default_resolver = true); template<typename K> T operator()(const K&) const { return T(0); } template<typename K> T operator()(const K&, const T& local, const T& remote) const { return local + remote; } }; template <typename T> struct choose_min_reducer { BOOST_STATIC_CONSTANT(bool, non_default_resolver = true); template<typename K> T operator()(const K&) const { return (std::numeric_limits<T>::max)(); } template<typename K> T operator()(const K&, const T& x, const T& y) const { return x < y ? x : y; } }; // To use a property map syntactically like a function template <typename PropertyMap> struct property_map_reader { explicit property_map_reader(PropertyMap pm) : pm(pm) {} template <typename T> typename PropertyMap::value_type operator() (const T& v) { return get(pm, v); } private: PropertyMap pm; }; } // namespace distributed }} // namespace boost::graph #endif // BOOST_GRAPH_DISTRIBUTED_GRAPH_UTILITY_INCLUDE distributed/breadth_first_search.hpp 0000644 00000012131 15125521275 0013747 0 ustar 00 // Copyright 2004 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_PARALLEL_BFS_HPP #define BOOST_GRAPH_PARALLEL_BFS_HPP #ifndef BOOST_GRAPH_USE_MPI #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included" #endif #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/overloading.hpp> #include <boost/graph/distributed/concepts.hpp> #include <boost/graph/distributed/detail/filtered_queue.hpp> #include <boost/graph/distributed/queue.hpp> #include <boost/dynamic_bitset.hpp> #include <boost/pending/queue.hpp> #include <boost/graph/parallel/properties.hpp> #include <boost/graph/parallel/container_traits.hpp> namespace boost { namespace detail { /** @brief A unary predicate that decides when to push into a * breadth-first search queue. * * This predicate stores a color map that is used to determine * when to push. If it is provided with a key for which the color * is white, it darkens the color to gray and returns true (so * that the value will be pushed appropriately); if the color is * not white, it returns false so that the vertex will be * ignored. */ template<typename ColorMap> struct darken_and_push { typedef typename property_traits<ColorMap>::key_type argument_type; typedef bool result_type; explicit darken_and_push(const ColorMap& color) : color(color) { } bool operator()(const argument_type& value) const { typedef color_traits<typename property_traits<ColorMap>::value_type> Color; if (get(color, value) == Color::white()) { put(color, value, Color::gray()); return true; } else { return false; } } ColorMap color; }; template<typename IndexMap> struct has_not_been_seen { typedef bool result_type; has_not_been_seen() { } has_not_been_seen(std::size_t n, IndexMap index_map) : seen(n), index_map(index_map) {} template<typename Key> result_type operator()(Key key) { bool result = seen[get(index_map, key)]; seen[get(index_map, key)] = true; return !result; } void swap(has_not_been_seen& other) { using std::swap; swap(seen, other.seen); swap(index_map, other.index_map); } private: dynamic_bitset<> seen; IndexMap index_map; }; template<typename IndexMap> inline void swap(has_not_been_seen<IndexMap>& x, has_not_been_seen<IndexMap>& y) { x.swap(y); } template <class DistributedGraph, class ColorMap, class BFSVisitor, class BufferRef, class VertexIndexMap> inline void parallel_bfs_helper (DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, ColorMap color, BFSVisitor vis, BufferRef Q, VertexIndexMap) { set_property_map_role(vertex_color, color); color.set_consistency_model(0); breadth_first_search(g, s, Q.ref, vis, color); } template <class DistributedGraph, class ColorMap, class BFSVisitor, class VertexIndexMap> void parallel_bfs_helper (DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, ColorMap color, BFSVisitor vis, boost::param_not_found, VertexIndexMap vertex_index) { using boost::graph::parallel::process_group; typedef graph_traits<DistributedGraph> Traits; typedef typename Traits::vertex_descriptor Vertex; typedef typename boost::graph::parallel::process_group_type<DistributedGraph>::type process_group_type; set_property_map_role(vertex_color, color); color.set_consistency_model(0); // Buffer default typedef typename property_map<DistributedGraph, vertex_owner_t> ::const_type vertex_owner_map; typedef boost::graph::distributed::distributed_queue< process_group_type, vertex_owner_map, queue<Vertex>, detail::darken_and_push<ColorMap> > queue_t; queue_t Q(process_group(g), get(vertex_owner, g), detail::darken_and_push<ColorMap>(color)); breadth_first_search(g, s, Q, vis, color); } template <class DistributedGraph, class ColorMap, class BFSVisitor, class P, class T, class R> void bfs_helper (DistributedGraph& g, typename graph_traits<DistributedGraph>::vertex_descriptor s, ColorMap color, BFSVisitor vis, const bgl_named_params<P, T, R>& params, boost::mpl::true_) { parallel_bfs_helper (g, s, color, vis, get_param(params, buffer_param_t()), choose_const_pmap(get_param(params, vertex_index), g, vertex_index)); } } } #endif // BOOST_GRAPH_PARALLEL_BFS_HPP transitive_reduction.hpp 0000644 00000012316 15125521275 0011531 0 ustar 00 // (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 <vector> #include <algorithm> //std::find #include <boost/concept/requires.hpp> #include <boost/concept_check.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/topological_sort.hpp> // 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< Graph >::vertex_descriptor >))( (Integer< typename property_traits< VertexIndexMap >::value_type >))( (LvaluePropertyMapConcept< G_to_TR_VertexMap, typename graph_traits< Graph >::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< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::vertex_iterator VertexIterator; typedef typename std::vector< Vertex >::size_type size_type; std::vector< Vertex > topo_order; topological_sort(g, std::back_inserter(topo_order)); std::vector< size_type > topo_number_storage(num_vertices(g)); iterator_property_map< size_type*, VertexIndexMap, size_type, size_type& > topo_number(&topo_number_storage[0], g_index_map); { typename std::vector< Vertex >::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< bool >(num_vertices(g), false)); { typename std::vector< Vertex >::reverse_iterator it = topo_order.rbegin(); for (; it != topo_order.rend(); ++it) { g_to_tr_map[*it] = add_vertex(tr); } } typename std::vector< Vertex >::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< Vertex > 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 (boost::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< Vertex >::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<Vertex>::reverse_iterator } // { } // for( typename vector<Vertex>::iterator } // void transitive_reduction } // namespace boost #endif depth_first_search.hpp 0000644 00000036116 15125521275 0011131 0 ustar 00 //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Copyright 2003 Bruce Barr // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // Nonrecursive implementation of depth_first_visit_impl submitted by // Bruce Barr, schmoost <at> yahoo.com, May/June 2003. #ifndef BOOST_GRAPH_RECURSIVE_DFS_HPP #define BOOST_GRAPH_RECURSIVE_DFS_HPP #include <boost/config.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/properties.hpp> #include <boost/graph/visitors.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/graph/detail/mpi_include.hpp> #include <boost/ref.hpp> #include <boost/implicit_cast.hpp> #include <boost/optional.hpp> #include <boost/parameter.hpp> #include <boost/concept/assert.hpp> #include <boost/tti/has_member_function.hpp> #include <vector> #include <utility> namespace boost { template < class Visitor, class Graph > class DFSVisitorConcept { public: void constraints() { BOOST_CONCEPT_ASSERT((CopyConstructibleConcept< Visitor >)); vis.initialize_vertex(u, g); vis.start_vertex(u, g); vis.discover_vertex(u, g); vis.examine_edge(e, g); vis.tree_edge(e, g); vis.back_edge(e, g); vis.forward_or_cross_edge(e, g); // vis.finish_edge(e, g); // Optional for user vis.finish_vertex(u, g); } private: Visitor vis; Graph g; typename graph_traits< Graph >::vertex_descriptor u; typename graph_traits< Graph >::edge_descriptor e; }; namespace detail { struct nontruth2 { template < class T, class T2 > bool operator()(const T&, const T2&) const { return false; } }; BOOST_TTI_HAS_MEMBER_FUNCTION(finish_edge) template < bool IsCallable > struct do_call_finish_edge { template < typename E, typename G, typename Vis > static void call_finish_edge(Vis& vis, E e, const G& g) { vis.finish_edge(e, g); } }; template <> struct do_call_finish_edge< false > { template < typename E, typename G, typename Vis > static void call_finish_edge(Vis&, E, const G&) { } }; template < typename E, typename G, typename Vis > void call_finish_edge(Vis& vis, E e, const G& g) { // Only call if method exists #if ((defined(__GNUC__) && (__GNUC__ > 4) \ || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9))) \ || defined(__clang__) \ || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1200))) do_call_finish_edge< has_member_function_finish_edge< Vis, void, boost::mpl::vector< E, const G& > >::value >::call_finish_edge(vis, e, g); #else do_call_finish_edge< has_member_function_finish_edge< Vis, void >::value >::call_finish_edge(vis, e, g); #endif } // Define BOOST_RECURSIVE_DFS to use older, recursive version. // It is retained for a while in order to perform performance // comparison. #ifndef BOOST_RECURSIVE_DFS // If the vertex u and the iterators ei and ei_end are thought of as the // context of the algorithm, each push and pop from the stack could // be thought of as a context shift. // Each pass through "while (ei != ei_end)" may refer to the out-edges of // an entirely different vertex, because the context of the algorithm // shifts every time a white adjacent vertex is discovered. // The corresponding context shift back from the adjacent vertex occurs // after all of its out-edges have been examined. // // See https://lists.boost.org/Archives/boost/2003/06/49265.php for FAQ. template < class IncidenceGraph, class DFSVisitor, class ColorMap, class TerminatorFunc > void depth_first_visit_impl(const IncidenceGraph& g, typename graph_traits< IncidenceGraph >::vertex_descriptor u, DFSVisitor& vis, ColorMap color, TerminatorFunc func = TerminatorFunc()) { BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< IncidenceGraph >)); BOOST_CONCEPT_ASSERT((DFSVisitorConcept< DFSVisitor, IncidenceGraph >)); typedef typename graph_traits< IncidenceGraph >::vertex_descriptor Vertex; typedef typename graph_traits< IncidenceGraph >::edge_descriptor Edge; BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< ColorMap, Vertex >)); typedef typename property_traits< ColorMap >::value_type ColorValue; BOOST_CONCEPT_ASSERT((ColorValueConcept< ColorValue >)); typedef color_traits< ColorValue > Color; typedef typename graph_traits< IncidenceGraph >::out_edge_iterator Iter; typedef std::pair< Vertex, std::pair< boost::optional< Edge >, std::pair< Iter, Iter > > > VertexInfo; boost::optional< Edge > src_e; Iter ei, ei_end; std::vector< VertexInfo > stack; // Possible optimization for vector // stack.reserve(num_vertices(g)); put(color, u, Color::gray()); vis.discover_vertex(u, g); boost::tie(ei, ei_end) = out_edges(u, g); if (func(u, g)) { // If this vertex terminates the search, we push empty range stack.push_back(std::make_pair(u, std::make_pair(boost::optional< Edge >(), std::make_pair(ei_end, ei_end)))); } else { stack.push_back(std::make_pair(u, std::make_pair( boost::optional< Edge >(), std::make_pair(ei, ei_end)))); } while (!stack.empty()) { VertexInfo& back = stack.back(); u = back.first; src_e = back.second.first; boost::tie(ei, ei_end) = back.second.second; stack.pop_back(); // finish_edge has to be called here, not after the // loop. Think of the pop as the return from a recursive call. if (src_e) { call_finish_edge(vis, src_e.get(), g); } while (ei != ei_end) { Vertex v = target(*ei, g); vis.examine_edge(*ei, g); ColorValue v_color = get(color, v); if (v_color == Color::white()) { vis.tree_edge(*ei, g); src_e = *ei; stack.push_back(std::make_pair(u, std::make_pair(src_e, std::make_pair(++ei, ei_end)))); u = v; put(color, u, Color::gray()); vis.discover_vertex(u, g); boost::tie(ei, ei_end) = out_edges(u, g); if (func(u, g)) { ei = ei_end; } } else { if (v_color == Color::gray()) { vis.back_edge(*ei, g); } else { vis.forward_or_cross_edge(*ei, g); } call_finish_edge(vis, *ei, g); ++ei; } } put(color, u, Color::black()); vis.finish_vertex(u, g); } } #else // BOOST_RECURSIVE_DFS is defined template < class IncidenceGraph, class DFSVisitor, class ColorMap, class TerminatorFunc > void depth_first_visit_impl(const IncidenceGraph& g, typename graph_traits< IncidenceGraph >::vertex_descriptor u, DFSVisitor& vis, // pass-by-reference here, important! ColorMap color, TerminatorFunc func) { BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< IncidenceGraph >)); BOOST_CONCEPT_ASSERT((DFSVisitorConcept< DFSVisitor, IncidenceGraph >)); typedef typename graph_traits< IncidenceGraph >::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< ColorMap, Vertex >)); typedef typename property_traits< ColorMap >::value_type ColorValue; BOOST_CONCEPT_ASSERT((ColorValueConcept< ColorValue >)); typedef color_traits< ColorValue > Color; typename graph_traits< IncidenceGraph >::out_edge_iterator ei, ei_end; put(color, u, Color::gray()); vis.discover_vertex(u, g); if (!func(u, g)) for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) { Vertex v = target(*ei, g); vis.examine_edge(*ei, g); ColorValue v_color = get(color, v); if (v_color == Color::white()) { vis.tree_edge(*ei, g); depth_first_visit_impl(g, v, vis, color, func); } else if (v_color == Color::gray()) vis.back_edge(*ei, g); else vis.forward_or_cross_edge(*ei, g); call_finish_edge(vis, *ei, g); } put(color, u, Color::black()); vis.finish_vertex(u, g); } #endif } // namespace detail template < class VertexListGraph, class DFSVisitor, class ColorMap > void depth_first_search(const VertexListGraph& g, DFSVisitor vis, ColorMap color, typename graph_traits< VertexListGraph >::vertex_descriptor start_vertex) { typedef typename graph_traits< VertexListGraph >::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT((DFSVisitorConcept< DFSVisitor, VertexListGraph >)); typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; typename graph_traits< VertexListGraph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { Vertex u = implicit_cast< Vertex >(*ui); put(color, u, Color::white()); vis.initialize_vertex(u, g); } if (start_vertex != detail::get_default_starting_vertex(g)) { vis.start_vertex(start_vertex, g); detail::depth_first_visit_impl( g, start_vertex, vis, color, detail::nontruth2()); } for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { Vertex u = implicit_cast< Vertex >(*ui); ColorValue u_color = get(color, u); if (u_color == Color::white()) { vis.start_vertex(u, g); detail::depth_first_visit_impl( g, u, vis, color, detail::nontruth2()); } } } template < class VertexListGraph, class DFSVisitor, class ColorMap > void depth_first_search( const VertexListGraph& g, DFSVisitor vis, ColorMap color) { typedef typename boost::graph_traits< VertexListGraph >::vertex_iterator vi; std::pair< vi, vi > verts = vertices(g); if (verts.first == verts.second) return; depth_first_search(g, vis, color, detail::get_default_starting_vertex(g)); } template < class Visitors = null_visitor > class dfs_visitor { public: dfs_visitor() {} dfs_visitor(Visitors vis) : m_vis(vis) {} template < class Vertex, class Graph > void initialize_vertex(Vertex u, const Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex()); } template < class Vertex, class Graph > void start_vertex(Vertex u, const Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_start_vertex()); } template < class Vertex, class Graph > void discover_vertex(Vertex u, const Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_discover_vertex()); } template < class Edge, class Graph > void examine_edge(Edge u, const Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_examine_edge()); } template < class Edge, class Graph > void tree_edge(Edge u, const Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_tree_edge()); } template < class Edge, class Graph > void back_edge(Edge u, const Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_back_edge()); } template < class Edge, class Graph > void forward_or_cross_edge(Edge u, const Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_forward_or_cross_edge()); } template < class Edge, class Graph > void finish_edge(Edge u, const Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_finish_edge()); } template < class Vertex, class Graph > void finish_vertex(Vertex u, const Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex()); } BOOST_GRAPH_EVENT_STUB(on_initialize_vertex, dfs) BOOST_GRAPH_EVENT_STUB(on_start_vertex, dfs) BOOST_GRAPH_EVENT_STUB(on_discover_vertex, dfs) BOOST_GRAPH_EVENT_STUB(on_examine_edge, dfs) BOOST_GRAPH_EVENT_STUB(on_tree_edge, dfs) BOOST_GRAPH_EVENT_STUB(on_back_edge, dfs) BOOST_GRAPH_EVENT_STUB(on_forward_or_cross_edge, dfs) BOOST_GRAPH_EVENT_STUB(on_finish_edge, dfs) BOOST_GRAPH_EVENT_STUB(on_finish_vertex, dfs) protected: Visitors m_vis; }; template < class Visitors > dfs_visitor< Visitors > make_dfs_visitor(Visitors vis) { return dfs_visitor< Visitors >(vis); } typedef dfs_visitor<> default_dfs_visitor; // Boost.Parameter named parameter variant namespace graph { namespace detail { template < typename Graph > struct depth_first_search_impl { typedef void result_type; template < typename ArgPack > void operator()(const Graph& g, const ArgPack& arg_pack) const { using namespace boost::graph::keywords; boost::depth_first_search(g, arg_pack[_visitor | make_dfs_visitor(null_visitor())], boost::detail::make_color_map_from_arg_pack(g, arg_pack), arg_pack[_root_vertex || boost::detail::get_default_starting_vertex_t< Graph >(g)]); } }; } BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(depth_first_search, 1, 4) } BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(depth_first_search, 1) template < class IncidenceGraph, class DFSVisitor, class ColorMap > void depth_first_visit(const IncidenceGraph& g, typename graph_traits< IncidenceGraph >::vertex_descriptor u, DFSVisitor vis, ColorMap color) { vis.start_vertex(u, g); detail::depth_first_visit_impl(g, u, vis, color, detail::nontruth2()); } template < class IncidenceGraph, class DFSVisitor, class ColorMap, class TerminatorFunc > void depth_first_visit(const IncidenceGraph& g, typename graph_traits< IncidenceGraph >::vertex_descriptor u, DFSVisitor vis, ColorMap color, TerminatorFunc func = TerminatorFunc()) { vis.start_vertex(u, g); detail::depth_first_visit_impl(g, u, vis, color, func); } } // namespace boost #include BOOST_GRAPH_MPI_INCLUDE(< boost / graph / distributed / depth_first_search.hpp >) #endif topology.hpp 0000644 00000047645 15125521275 0007156 0 ustar 00 // Copyright 2009 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Jeremiah Willcock // Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_TOPOLOGY_HPP #define BOOST_GRAPH_TOPOLOGY_HPP #include <boost/config/no_tr1/cmath.hpp> #include <cmath> #include <boost/random/uniform_01.hpp> #include <boost/random/linear_congruential.hpp> #include <boost/math/constants/constants.hpp> // For root_two #include <boost/algorithm/minmax.hpp> #include <boost/config.hpp> // For BOOST_STATIC_CONSTANT #include <boost/math/special_functions/hypot.hpp> // Classes and concepts to represent points in a space, with distance and move // operations (used for Gurson-Atun layout), plus other things like bounding // boxes used for other layout algorithms. namespace boost { /*********************************************************** * Topologies * ***********************************************************/ template < std::size_t Dims > class convex_topology { public: // For VisualAge C++ struct point { BOOST_STATIC_CONSTANT(std::size_t, dimensions = Dims); point() {} double& operator[](std::size_t i) { return values[i]; } const double& operator[](std::size_t i) const { return values[i]; } private: double values[Dims]; }; public: // For VisualAge C++ struct point_difference { BOOST_STATIC_CONSTANT(std::size_t, dimensions = Dims); point_difference() { for (std::size_t i = 0; i < Dims; ++i) values[i] = 0.; } double& operator[](std::size_t i) { return values[i]; } const double& operator[](std::size_t i) const { return values[i]; } friend point_difference operator+( const point_difference& a, const point_difference& b) { point_difference result; for (std::size_t i = 0; i < Dims; ++i) result[i] = a[i] + b[i]; return result; } friend point_difference& operator+=( point_difference& a, const point_difference& b) { for (std::size_t i = 0; i < Dims; ++i) a[i] += b[i]; return a; } friend point_difference operator-(const point_difference& a) { point_difference result; for (std::size_t i = 0; i < Dims; ++i) result[i] = -a[i]; return result; } friend point_difference operator-( const point_difference& a, const point_difference& b) { point_difference result; for (std::size_t i = 0; i < Dims; ++i) result[i] = a[i] - b[i]; return result; } friend point_difference& operator-=( point_difference& a, const point_difference& b) { for (std::size_t i = 0; i < Dims; ++i) a[i] -= b[i]; return a; } friend point_difference operator*( const point_difference& a, const point_difference& b) { point_difference result; for (std::size_t i = 0; i < Dims; ++i) result[i] = a[i] * b[i]; return result; } friend point_difference operator*(const point_difference& a, double b) { point_difference result; for (std::size_t i = 0; i < Dims; ++i) result[i] = a[i] * b; return result; } friend point_difference operator*(double a, const point_difference& b) { point_difference result; for (std::size_t i = 0; i < Dims; ++i) result[i] = a * b[i]; return result; } friend point_difference operator/( const point_difference& a, const point_difference& b) { point_difference result; for (std::size_t i = 0; i < Dims; ++i) result[i] = (b[i] == 0.) ? 0. : a[i] / b[i]; return result; } friend double dot(const point_difference& a, const point_difference& b) { double result = 0; for (std::size_t i = 0; i < Dims; ++i) result += a[i] * b[i]; return result; } private: double values[Dims]; }; public: typedef point point_type; typedef point_difference point_difference_type; double distance(point a, point b) const { double dist = 0.; for (std::size_t i = 0; i < Dims; ++i) { double diff = b[i] - a[i]; dist = boost::math::hypot(dist, diff); } // Exact properties of the distance are not important, as long as // < on what this returns matches real distances; l_2 is used because // Fruchterman-Reingold also uses this code and it relies on l_2. return dist; } point move_position_toward(point a, double fraction, point b) const { point result; for (std::size_t i = 0; i < Dims; ++i) result[i] = a[i] + (b[i] - a[i]) * fraction; return result; } point_difference difference(point a, point b) const { point_difference result; for (std::size_t i = 0; i < Dims; ++i) result[i] = a[i] - b[i]; return result; } point adjust(point a, point_difference delta) const { point result; for (std::size_t i = 0; i < Dims; ++i) result[i] = a[i] + delta[i]; return result; } point pointwise_min(point a, point b) const { BOOST_USING_STD_MIN(); point result; for (std::size_t i = 0; i < Dims; ++i) result[i] = min BOOST_PREVENT_MACRO_SUBSTITUTION(a[i], b[i]); return result; } point pointwise_max(point a, point b) const { BOOST_USING_STD_MAX(); point result; for (std::size_t i = 0; i < Dims; ++i) result[i] = max BOOST_PREVENT_MACRO_SUBSTITUTION(a[i], b[i]); return result; } double norm(point_difference delta) const { double n = 0.; for (std::size_t i = 0; i < Dims; ++i) n = boost::math::hypot(n, delta[i]); return n; } double volume(point_difference delta) const { double n = 1.; for (std::size_t i = 0; i < Dims; ++i) n *= delta[i]; return n; } }; template < std::size_t Dims, typename RandomNumberGenerator = minstd_rand > class hypercube_topology : public convex_topology< Dims > { typedef uniform_01< RandomNumberGenerator, double > rand_t; public: typedef typename convex_topology< Dims >::point_type point_type; typedef typename convex_topology< Dims >::point_difference_type point_difference_type; explicit hypercube_topology(double scaling = 1.0) : gen_ptr(new RandomNumberGenerator) , rand(new rand_t(*gen_ptr)) , scaling(scaling) { } hypercube_topology(RandomNumberGenerator& gen, double scaling = 1.0) : gen_ptr(), rand(new rand_t(gen)), scaling(scaling) { } point_type random_point() const { point_type p; for (std::size_t i = 0; i < Dims; ++i) p[i] = (*rand)() * scaling; return p; } point_type bound(point_type a) const { BOOST_USING_STD_MIN(); BOOST_USING_STD_MAX(); point_type p; for (std::size_t i = 0; i < Dims; ++i) p[i] = min BOOST_PREVENT_MACRO_SUBSTITUTION( scaling, max BOOST_PREVENT_MACRO_SUBSTITUTION(-scaling, a[i])); return p; } double distance_from_boundary(point_type a) const { BOOST_USING_STD_MIN(); BOOST_USING_STD_MAX(); #ifndef BOOST_NO_STDC_NAMESPACE using std::abs; #endif BOOST_STATIC_ASSERT(Dims >= 1); double dist = abs(scaling - a[0]); for (std::size_t i = 1; i < Dims; ++i) dist = min BOOST_PREVENT_MACRO_SUBSTITUTION( dist, abs(scaling - a[i])); return dist; } point_type center() const { point_type result; for (std::size_t i = 0; i < Dims; ++i) result[i] = scaling * .5; return result; } point_type origin() const { point_type result; for (std::size_t i = 0; i < Dims; ++i) result[i] = 0; return result; } point_difference_type extent() const { point_difference_type result; for (std::size_t i = 0; i < Dims; ++i) result[i] = scaling; return result; } private: shared_ptr< RandomNumberGenerator > gen_ptr; shared_ptr< rand_t > rand; double scaling; }; template < typename RandomNumberGenerator = minstd_rand > class square_topology : public hypercube_topology< 2, RandomNumberGenerator > { typedef hypercube_topology< 2, RandomNumberGenerator > inherited; public: explicit square_topology(double scaling = 1.0) : inherited(scaling) {} square_topology(RandomNumberGenerator& gen, double scaling = 1.0) : inherited(gen, scaling) { } }; template < typename RandomNumberGenerator = minstd_rand > class rectangle_topology : public convex_topology< 2 > { typedef uniform_01< RandomNumberGenerator, double > rand_t; public: rectangle_topology(double left, double top, double right, double bottom) : gen_ptr(new RandomNumberGenerator) , rand(new rand_t(*gen_ptr)) , left(std::min BOOST_PREVENT_MACRO_SUBSTITUTION(left, right)) , top(std::min BOOST_PREVENT_MACRO_SUBSTITUTION(top, bottom)) , right(std::max BOOST_PREVENT_MACRO_SUBSTITUTION(left, right)) , bottom(std::max BOOST_PREVENT_MACRO_SUBSTITUTION(top, bottom)) { } rectangle_topology(RandomNumberGenerator& gen, double left, double top, double right, double bottom) : gen_ptr() , rand(new rand_t(gen)) , left(std::min BOOST_PREVENT_MACRO_SUBSTITUTION(left, right)) , top(std::min BOOST_PREVENT_MACRO_SUBSTITUTION(top, bottom)) , right(std::max BOOST_PREVENT_MACRO_SUBSTITUTION(left, right)) , bottom(std::max BOOST_PREVENT_MACRO_SUBSTITUTION(top, bottom)) { } typedef typename convex_topology< 2 >::point_type point_type; typedef typename convex_topology< 2 >::point_difference_type point_difference_type; point_type random_point() const { point_type p; p[0] = (*rand)() * (right - left) + left; p[1] = (*rand)() * (bottom - top) + top; return p; } point_type bound(point_type a) const { BOOST_USING_STD_MIN(); BOOST_USING_STD_MAX(); point_type p; p[0] = min BOOST_PREVENT_MACRO_SUBSTITUTION( right, max BOOST_PREVENT_MACRO_SUBSTITUTION(left, a[0])); p[1] = min BOOST_PREVENT_MACRO_SUBSTITUTION( bottom, max BOOST_PREVENT_MACRO_SUBSTITUTION(top, a[1])); return p; } double distance_from_boundary(point_type a) const { BOOST_USING_STD_MIN(); BOOST_USING_STD_MAX(); #ifndef BOOST_NO_STDC_NAMESPACE using std::abs; #endif double dist = abs(left - a[0]); dist = min BOOST_PREVENT_MACRO_SUBSTITUTION(dist, abs(right - a[0])); dist = min BOOST_PREVENT_MACRO_SUBSTITUTION(dist, abs(top - a[1])); dist = min BOOST_PREVENT_MACRO_SUBSTITUTION(dist, abs(bottom - a[1])); return dist; } point_type center() const { point_type result; result[0] = (left + right) / 2.; result[1] = (top + bottom) / 2.; return result; } point_type origin() const { point_type result; result[0] = left; result[1] = top; return result; } point_difference_type extent() const { point_difference_type result; result[0] = right - left; result[1] = bottom - top; return result; } private: shared_ptr< RandomNumberGenerator > gen_ptr; shared_ptr< rand_t > rand; double left, top, right, bottom; }; template < typename RandomNumberGenerator = minstd_rand > class cube_topology : public hypercube_topology< 3, RandomNumberGenerator > { typedef hypercube_topology< 3, RandomNumberGenerator > inherited; public: explicit cube_topology(double scaling = 1.0) : inherited(scaling) {} cube_topology(RandomNumberGenerator& gen, double scaling = 1.0) : inherited(gen, scaling) { } }; template < std::size_t Dims, typename RandomNumberGenerator = minstd_rand > class ball_topology : public convex_topology< Dims > { typedef uniform_01< RandomNumberGenerator, double > rand_t; public: typedef typename convex_topology< Dims >::point_type point_type; typedef typename convex_topology< Dims >::point_difference_type point_difference_type; explicit ball_topology(double radius = 1.0) : gen_ptr(new RandomNumberGenerator) , rand(new rand_t(*gen_ptr)) , radius(radius) { } ball_topology(RandomNumberGenerator& gen, double radius = 1.0) : gen_ptr(), rand(new rand_t(gen)), radius(radius) { } point_type random_point() const { point_type p; double dist_sum; do { dist_sum = 0.0; for (std::size_t i = 0; i < Dims; ++i) { double x = (*rand)() * 2 * radius - radius; p[i] = x; dist_sum += x * x; } } while (dist_sum > radius * radius); return p; } point_type bound(point_type a) const { BOOST_USING_STD_MIN(); BOOST_USING_STD_MAX(); double r = 0.; for (std::size_t i = 0; i < Dims; ++i) r = boost::math::hypot(r, a[i]); if (r <= radius) return a; double scaling_factor = radius / r; point_type p; for (std::size_t i = 0; i < Dims; ++i) p[i] = a[i] * scaling_factor; return p; } double distance_from_boundary(point_type a) const { double r = 0.; for (std::size_t i = 0; i < Dims; ++i) r = boost::math::hypot(r, a[i]); return radius - r; } point_type center() const { point_type result; for (std::size_t i = 0; i < Dims; ++i) result[i] = 0; return result; } point_type origin() const { point_type result; for (std::size_t i = 0; i < Dims; ++i) result[i] = -radius; return result; } point_difference_type extent() const { point_difference_type result; for (std::size_t i = 0; i < Dims; ++i) result[i] = 2. * radius; return result; } private: shared_ptr< RandomNumberGenerator > gen_ptr; shared_ptr< rand_t > rand; double radius; }; template < typename RandomNumberGenerator = minstd_rand > class circle_topology : public ball_topology< 2, RandomNumberGenerator > { typedef ball_topology< 2, RandomNumberGenerator > inherited; public: explicit circle_topology(double radius = 1.0) : inherited(radius) {} circle_topology(RandomNumberGenerator& gen, double radius = 1.0) : inherited(gen, radius) { } }; template < typename RandomNumberGenerator = minstd_rand > class sphere_topology : public ball_topology< 3, RandomNumberGenerator > { typedef ball_topology< 3, RandomNumberGenerator > inherited; public: explicit sphere_topology(double radius = 1.0) : inherited(radius) {} sphere_topology(RandomNumberGenerator& gen, double radius = 1.0) : inherited(gen, radius) { } }; template < typename RandomNumberGenerator = minstd_rand > class heart_topology { // Heart is defined as the union of three shapes: // Square w/ corners (+-1000, -1000), (0, 0), (0, -2000) // Circle centered at (-500, -500) radius 500*sqrt(2) // Circle centered at (500, -500) radius 500*sqrt(2) // Bounding box (-1000, -2000) - (1000, 500*(sqrt(2) - 1)) struct point { point() { values[0] = 0.0; values[1] = 0.0; } point(double x, double y) { values[0] = x; values[1] = y; } double& operator[](std::size_t i) { return values[i]; } double operator[](std::size_t i) const { return values[i]; } private: double values[2]; }; bool in_heart(point p) const { #ifndef BOOST_NO_STDC_NAMESPACE using std::abs; #endif if (p[1] < abs(p[0]) - 2000) return false; // Bottom if (p[1] <= -1000) return true; // Diagonal of square if (boost::math::hypot(p[0] - -500, p[1] - -500) <= 500. * boost::math::constants::root_two< double >()) return true; // Left circle if (boost::math::hypot(p[0] - 500, p[1] - -500) <= 500. * boost::math::constants::root_two< double >()) return true; // Right circle return false; } bool segment_within_heart(point p1, point p2) const { // Assumes that p1 and p2 are within the heart if ((p1[0] < 0) == (p2[0] < 0)) return true; // Same side of symmetry line if (p1[0] == p2[0]) return true; // Vertical double slope = (p2[1] - p1[1]) / (p2[0] - p1[0]); double intercept = p1[1] - p1[0] * slope; if (intercept > 0) return false; // Crosses between circles return true; } typedef uniform_01< RandomNumberGenerator, double > rand_t; public: typedef point point_type; heart_topology() : gen_ptr(new RandomNumberGenerator), rand(new rand_t(*gen_ptr)) { } heart_topology(RandomNumberGenerator& gen) : gen_ptr(), rand(new rand_t(gen)) { } point random_point() const { point result; do { result[0] = (*rand)() * (1000 + 1000 * boost::math::constants::root_two< double >()) - (500 + 500 * boost::math::constants::root_two< double >()); result[1] = (*rand)() * (2000 + 500 * (boost::math::constants::root_two< double >() - 1)) - 2000; } while (!in_heart(result)); return result; } // Not going to provide clipping to bounding region or distance from // boundary double distance(point a, point b) const { if (segment_within_heart(a, b)) { // Straight line return boost::math::hypot(b[0] - a[0], b[1] - a[1]); } else { // Straight line bending around (0, 0) return boost::math::hypot(a[0], a[1]) + boost::math::hypot(b[0], b[1]); } } point move_position_toward(point a, double fraction, point b) const { if (segment_within_heart(a, b)) { // Straight line return point(a[0] + (b[0] - a[0]) * fraction, a[1] + (b[1] - a[1]) * fraction); } else { double distance_to_point_a = boost::math::hypot(a[0], a[1]); double distance_to_point_b = boost::math::hypot(b[0], b[1]); double location_of_point = distance_to_point_a / (distance_to_point_a + distance_to_point_b); if (fraction < location_of_point) return point(a[0] * (1 - fraction / location_of_point), a[1] * (1 - fraction / location_of_point)); else return point(b[0] * ((fraction - location_of_point) / (1 - location_of_point)), b[1] * ((fraction - location_of_point) / (1 - location_of_point))); } } private: shared_ptr< RandomNumberGenerator > gen_ptr; shared_ptr< rand_t > rand; }; } // namespace boost #endif // BOOST_GRAPH_TOPOLOGY_HPP accounting.hpp 0000644 00000001554 15125521275 0007421 0 ustar 00 // Copyright 2005 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Douglas Gregor // Andrew Lumsdaine #ifndef BOOST_GRAPH_ACCOUNTING_HPP #define BOOST_GRAPH_ACCOUNTING_HPP #include <iomanip> #include <iostream> #include <string> #include <sstream> #include <boost/mpi/config.hpp> namespace boost { namespace graph { namespace accounting { typedef double time_type; inline time_type get_time() { return MPI_Wtime(); } inline std::string print_time(time_type t) { std::ostringstream out; out << std::setiosflags(std::ios::fixed) << std::setprecision(2) << t; return out.str(); } } } } // end namespace boost::graph::accounting #endif // BOOST_GRAPH_ACCOUNTING_HPP dimacs.hpp 0000644 00000024320 15125521275 0006523 0 ustar 00 // Copyright 2005 The Trustees of Indiana University. // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Alex Breuer // Andrew Lumsdaine #ifndef BOOST_GRAPH_DIMACS_HPP #define BOOST_GRAPH_DIMACS_HPP #include <string> #include <sstream> #include <iostream> #include <fstream> #include <iterator> #include <exception> #include <vector> #include <queue> #include <boost/assert.hpp> namespace boost { namespace graph { class BOOST_SYMBOL_VISIBLE dimacs_exception : public std::exception { }; class dimacs_basic_reader { public: typedef std::size_t vertices_size_type; typedef std::size_t edges_size_type; typedef double vertex_weight_type; typedef double edge_weight_type; typedef std::pair< vertices_size_type, vertices_size_type > edge_type; enum incr_mode { edge, edge_weight }; dimacs_basic_reader(std::istream& in, bool want_weights = true) : inpt(in), seen_edges(0), want_weights(want_weights) { while (getline(inpt, buf) && !buf.empty() && buf[0] == 'c') ; if (buf[0] != 'p') { boost::throw_exception(dimacs_exception()); } std::stringstream instr(buf); std::string junk; instr >> junk >> junk >> num_vertices >> num_edges; read_edge_weights.push(-1); incr(edge_weight); } // for a past the end iterator dimacs_basic_reader() : inpt(std::cin) , num_vertices(0) , num_edges(0) , seen_edges(0) , want_weights(false) { } edge_type edge_deref() { BOOST_ASSERT(!read_edges.empty()); return read_edges.front(); } inline edge_type* edge_ref() { BOOST_ASSERT(!read_edges.empty()); return &read_edges.front(); } inline edge_weight_type edge_weight_deref() { BOOST_ASSERT(!read_edge_weights.empty()); return read_edge_weights.front(); } inline dimacs_basic_reader incr(incr_mode mode) { if (mode == edge) { BOOST_ASSERT(!read_edges.empty()); read_edges.pop(); } else if (mode == edge_weight) { BOOST_ASSERT(!read_edge_weights.empty()); read_edge_weights.pop(); } if ((mode == edge && read_edges.empty()) || (mode == edge_weight && read_edge_weights.empty())) { if (seen_edges > num_edges) { boost::throw_exception(dimacs_exception()); } while (getline(inpt, buf) && !buf.empty() && buf[0] == 'c') ; if (!inpt.eof()) { int source, dest, weight; read_edge_line((char*)buf.c_str(), source, dest, weight); seen_edges++; source--; dest--; read_edges.push(edge_type(source, dest)); if (want_weights) { read_edge_weights.push(weight); } } BOOST_ASSERT(read_edges.size() < 100); BOOST_ASSERT(read_edge_weights.size() < 100); } // the 1000000 just happens to be about how many edges can be read // in 10s // if( !(seen_edges % 1000000) && !process_id( pg ) && mode == // edge ) { // std::cout << "read " << seen_edges << " edges" << // std::endl; // } return *this; } inline bool done_edges() { return inpt.eof() && read_edges.size() == 0; } inline bool done_edge_weights() { return inpt.eof() && read_edge_weights.size() == 0; } inline vertices_size_type n_vertices() { return num_vertices; } inline vertices_size_type processed_edges() { return seen_edges - read_edges.size(); } inline vertices_size_type processed_edge_weights() { return seen_edges - read_edge_weights.size(); } inline vertices_size_type n_edges() { return num_edges; } protected: bool read_edge_line(char* linebuf, int& from, int& to, int& weight) { char *fs = NULL, *ts = NULL, *ws = NULL; char* tmp = linebuf + 2; fs = tmp; if ('e' == linebuf[0]) { while (*tmp != '\n' && *tmp != '\0') { if (*tmp == ' ') { *tmp = '\0'; ts = ++tmp; break; } tmp++; } *tmp = '\0'; if (NULL == fs || NULL == ts) return false; from = atoi(fs); to = atoi(ts); weight = 0; } else if ('a' == linebuf[0]) { while (*tmp != '\n' && *tmp != '\0') { if (*tmp == ' ') { *tmp = '\0'; ts = ++tmp; break; } tmp++; } while (*tmp != '\n' && *tmp != '\0') { if (*tmp == ' ') { *tmp = '\0'; ws = ++tmp; break; } tmp++; } while (*tmp != '\n' && *tmp != '\0') tmp++; *tmp = '\0'; if (fs == NULL || ts == NULL || ws == NULL) return false; from = atoi(fs); to = atoi(ts); if (want_weights) weight = atoi(ws); else weight = 0; } else { return false; } return true; } std::queue< edge_type > read_edges; std::queue< edge_weight_type > read_edge_weights; std::istream& inpt; std::string buf; vertices_size_type num_vertices, num_edges, seen_edges; bool want_weights; }; template < typename T > class dimacs_edge_iterator { public: typedef dimacs_basic_reader::edge_type edge_type; typedef dimacs_basic_reader::incr_mode incr_mode; typedef std::input_iterator_tag iterator_category; typedef edge_type value_type; typedef value_type reference; typedef edge_type* pointer; typedef std::ptrdiff_t difference_type; dimacs_edge_iterator(T& reader) : reader(reader) {} inline dimacs_edge_iterator& operator++() { reader.incr(dimacs_basic_reader::edge); return *this; } inline edge_type operator*() { return reader.edge_deref(); } inline edge_type* operator->() { return reader.edge_ref(); } // don't expect this to do the right thing if you're not comparing // against a general past-the-end-iterator made with the default // constructor for dimacs_basic_reader inline bool operator==(dimacs_edge_iterator arg) { if (reader.n_vertices() == 0) { return arg.reader.done_edges(); } else if (arg.reader.n_vertices() == 0) { return reader.done_edges(); } else { return false; } return false; } inline bool operator!=(dimacs_edge_iterator arg) { if (reader.n_vertices() == 0) { return !arg.reader.done_edges(); } else if (arg.reader.n_vertices() == 0) { return !reader.done_edges(); } else { return true; } return true; } private: T& reader; }; template < typename T > class dimacs_edge_weight_iterator { public: typedef dimacs_basic_reader::edge_weight_type edge_weight_type; typedef dimacs_basic_reader::incr_mode incr_mode; dimacs_edge_weight_iterator(T& reader) : reader(reader) {} inline dimacs_edge_weight_iterator& operator++() { reader.incr(dimacs_basic_reader::edge_weight); return *this; } inline edge_weight_type operator*() { return reader.edge_weight_deref(); } // don't expect this to do the right thing if you're not comparing // against a general past-the-end-iterator made with the default // constructor for dimacs_basic_reader inline bool operator==(dimacs_edge_weight_iterator arg) { if (reader.n_vertices() == 0) { return arg.reader.done_edge_weights(); } else if (arg.reader.n_vertices() == 0) { return reader.done_edge_weights(); } else { return false; } return false; } inline bool operator!=(dimacs_edge_weight_iterator arg) { if (reader.n_vertices() == 0) { return !arg.reader.done_edge_weights(); } else if (arg.reader.n_vertices() == 0) { return !reader.done_edge_weights(); } else { return true; } return true; } private: T& reader; }; } } // end namespace boost::graph #endif mcgregor_common_subgraphs.hpp 0000644 00000124716 15125521275 0012530 0 ustar 00 //======================================================================= // Copyright 2009 Trustees of Indiana University. // Authors: Michael Hansen, Andrew Lumsdaine // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_GRAPH_MCGREGOR_COMMON_SUBGRAPHS_HPP #define BOOST_GRAPH_MCGREGOR_COMMON_SUBGRAPHS_HPP #include <algorithm> #include <vector> #include <stack> #include <boost/make_shared.hpp> #include <boost/graph/adjacency_list.hpp> #include <boost/graph/filtered_graph.hpp> #include <boost/graph/graph_utility.hpp> #include <boost/graph/iteration_macros.hpp> #include <boost/graph/properties.hpp> #include <boost/property_map/shared_array_property_map.hpp> namespace boost { namespace detail { // Traits associated with common subgraphs, used mainly to keep a // consistent type for the correspondence maps. template < typename GraphFirst, typename GraphSecond, typename VertexIndexMapFirst, typename VertexIndexMapSecond > struct mcgregor_common_subgraph_traits { typedef typename graph_traits< GraphFirst >::vertex_descriptor vertex_first_type; typedef typename graph_traits< GraphSecond >::vertex_descriptor vertex_second_type; typedef shared_array_property_map< vertex_second_type, VertexIndexMapFirst > correspondence_map_first_to_second_type; typedef shared_array_property_map< vertex_first_type, VertexIndexMapSecond > correspondence_map_second_to_first_type; }; } // namespace detail // ========================================================================== // Binary function object that returns true if the values for item1 // in property_map1 and item2 in property_map2 are equivalent. template < typename PropertyMapFirst, typename PropertyMapSecond > struct property_map_equivalent { property_map_equivalent(const PropertyMapFirst property_map1, const PropertyMapSecond property_map2) : m_property_map1(property_map1), m_property_map2(property_map2) { } template < typename ItemFirst, typename ItemSecond > bool operator()(const ItemFirst item1, const ItemSecond item2) { return (get(m_property_map1, item1) == get(m_property_map2, item2)); } private: const PropertyMapFirst m_property_map1; const PropertyMapSecond m_property_map2; }; // Returns a property_map_equivalent object that compares the values // of property_map1 and property_map2. template < typename PropertyMapFirst, typename PropertyMapSecond > property_map_equivalent< PropertyMapFirst, PropertyMapSecond > make_property_map_equivalent( const PropertyMapFirst property_map1, const PropertyMapSecond property_map2) { return (property_map_equivalent< PropertyMapFirst, PropertyMapSecond >( property_map1, property_map2)); } // Binary function object that always returns true. Used when // vertices or edges are always equivalent (i.e. have no labels). struct always_equivalent { template < typename ItemFirst, typename ItemSecond > bool operator()(const ItemFirst&, const ItemSecond&) { return (true); } }; // ========================================================================== namespace detail { // Return true if new_vertex1 and new_vertex2 can extend the // subgraph represented by correspondence_map_1_to_2 and // correspondence_map_2_to_1. The vertices_equivalent and // edges_equivalent predicates are used to test vertex and edge // equivalency between the two graphs. template < typename GraphFirst, typename GraphSecond, typename CorrespondenceMapFirstToSecond, typename CorrespondenceMapSecondToFirst, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate > bool can_extend_graph(const GraphFirst& graph1, const GraphSecond& graph2, CorrespondenceMapFirstToSecond correspondence_map_1_to_2, CorrespondenceMapSecondToFirst /*correspondence_map_2_to_1*/, typename graph_traits< GraphFirst >::vertices_size_type subgraph_size, typename graph_traits< GraphFirst >::vertex_descriptor new_vertex1, typename graph_traits< GraphSecond >::vertex_descriptor new_vertex2, EdgeEquivalencePredicate edges_equivalent, VertexEquivalencePredicate vertices_equivalent, bool only_connected_subgraphs) { typedef typename graph_traits< GraphSecond >::vertex_descriptor VertexSecond; typedef typename graph_traits< GraphFirst >::edge_descriptor EdgeFirst; typedef typename graph_traits< GraphSecond >::edge_descriptor EdgeSecond; // Check vertex equality if (!vertices_equivalent(new_vertex1, new_vertex2)) { return (false); } // Vertices match and graph is empty, so we can extend the subgraph if (subgraph_size == 0) { return (true); } bool has_one_edge = false; // Verify edges with existing sub-graph BGL_FORALL_VERTICES_T(existing_vertex1, graph1, GraphFirst) { VertexSecond existing_vertex2 = get(correspondence_map_1_to_2, existing_vertex1); // Skip unassociated vertices if (existing_vertex2 == graph_traits< GraphSecond >::null_vertex()) { continue; } // NOTE: This will not work with parallel edges, since the // first matching edge is always chosen. EdgeFirst edge_to_new1, edge_from_new1; bool edge_to_new_exists1 = false, edge_from_new_exists1 = false; EdgeSecond edge_to_new2, edge_from_new2; bool edge_to_new_exists2 = false, edge_from_new_exists2 = false; // Search for edge from existing to new vertex (graph1) BGL_FORALL_OUTEDGES_T(existing_vertex1, edge1, graph1, GraphFirst) { if (target(edge1, graph1) == new_vertex1) { edge_to_new1 = edge1; edge_to_new_exists1 = true; break; } } // Search for edge from existing to new vertex (graph2) BGL_FORALL_OUTEDGES_T(existing_vertex2, edge2, graph2, GraphSecond) { if (target(edge2, graph2) == new_vertex2) { edge_to_new2 = edge2; edge_to_new_exists2 = true; break; } } // Make sure edges from existing to new vertices are equivalent if ((edge_to_new_exists1 != edge_to_new_exists2) || ((edge_to_new_exists1 && edge_to_new_exists2) && !edges_equivalent(edge_to_new1, edge_to_new2))) { return (false); } bool is_undirected1 = is_undirected(graph1), is_undirected2 = is_undirected(graph2); if (is_undirected1 && is_undirected2) { // Edge in both graphs exists and both graphs are undirected if (edge_to_new_exists1 && edge_to_new_exists2) { has_one_edge = true; } continue; } else { if (!is_undirected1) { // Search for edge from new to existing vertex (graph1) BGL_FORALL_OUTEDGES_T( new_vertex1, edge1, graph1, GraphFirst) { if (target(edge1, graph1) == existing_vertex1) { edge_from_new1 = edge1; edge_from_new_exists1 = true; break; } } } if (!is_undirected2) { // Search for edge from new to existing vertex (graph2) BGL_FORALL_OUTEDGES_T( new_vertex2, edge2, graph2, GraphSecond) { if (target(edge2, graph2) == existing_vertex2) { edge_from_new2 = edge2; edge_from_new_exists2 = true; break; } } } // Make sure edges from new to existing vertices are equivalent if ((edge_from_new_exists1 != edge_from_new_exists2) || ((edge_from_new_exists1 && edge_from_new_exists2) && !edges_equivalent(edge_from_new1, edge_from_new2))) { return (false); } if ((edge_from_new_exists1 && edge_from_new_exists2) || (edge_to_new_exists1 && edge_to_new_exists2)) { has_one_edge = true; } } // else } // BGL_FORALL_VERTICES_T // Make sure new vertices are connected to the existing subgraph if (only_connected_subgraphs && !has_one_edge) { return (false); } return (true); } // Recursive method that does a depth-first search in the space of // potential subgraphs. At each level, every new vertex pair from // both graphs is tested to see if it can extend the current // subgraph. If so, the subgraph is output to subgraph_callback // in the form of two correspondence maps (one for each graph). // Returning false from subgraph_callback will terminate the // search. Function returns true if the entire search space was // explored. template < typename GraphFirst, typename GraphSecond, typename VertexIndexMapFirst, typename VertexIndexMapSecond, typename CorrespondenceMapFirstToSecond, typename CorrespondenceMapSecondToFirst, typename VertexStackFirst, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate, typename SubGraphInternalCallback > bool mcgregor_common_subgraphs_internal(const GraphFirst& graph1, const GraphSecond& graph2, const VertexIndexMapFirst& vindex_map1, const VertexIndexMapSecond& vindex_map2, CorrespondenceMapFirstToSecond correspondence_map_1_to_2, CorrespondenceMapSecondToFirst correspondence_map_2_to_1, VertexStackFirst& vertex_stack1, EdgeEquivalencePredicate edges_equivalent, VertexEquivalencePredicate vertices_equivalent, bool only_connected_subgraphs, SubGraphInternalCallback subgraph_callback) { typedef typename graph_traits< GraphFirst >::vertex_descriptor VertexFirst; typedef typename graph_traits< GraphSecond >::vertex_descriptor VertexSecond; typedef typename graph_traits< GraphFirst >::vertices_size_type VertexSizeFirst; // Get iterators for vertices from both graphs typename graph_traits< GraphFirst >::vertex_iterator vertex1_iter, vertex1_end; typename graph_traits< GraphSecond >::vertex_iterator vertex2_begin, vertex2_end, vertex2_iter; boost::tie(vertex1_iter, vertex1_end) = vertices(graph1); boost::tie(vertex2_begin, vertex2_end) = vertices(graph2); vertex2_iter = vertex2_begin; // Iterate until all vertices have been visited BGL_FORALL_VERTICES_T(new_vertex1, graph1, GraphFirst) { VertexSecond existing_vertex2 = get(correspondence_map_1_to_2, new_vertex1); // Skip already matched vertices in first graph if (existing_vertex2 != graph_traits< GraphSecond >::null_vertex()) { continue; } BGL_FORALL_VERTICES_T(new_vertex2, graph2, GraphSecond) { VertexFirst existing_vertex1 = get(correspondence_map_2_to_1, new_vertex2); // Skip already matched vertices in second graph if (existing_vertex1 != graph_traits< GraphFirst >::null_vertex()) { continue; } // Check if current sub-graph can be extended with the matched // vertex pair if (can_extend_graph(graph1, graph2, correspondence_map_1_to_2, correspondence_map_2_to_1, (VertexSizeFirst)vertex_stack1.size(), new_vertex1, new_vertex2, edges_equivalent, vertices_equivalent, only_connected_subgraphs)) { // Keep track of old graph size for restoring later VertexSizeFirst old_graph_size = (VertexSizeFirst)vertex_stack1.size(), new_graph_size = old_graph_size + 1; // Extend subgraph put(correspondence_map_1_to_2, new_vertex1, new_vertex2); put(correspondence_map_2_to_1, new_vertex2, new_vertex1); vertex_stack1.push(new_vertex1); // Returning false from the callback will cancel iteration if (!subgraph_callback(correspondence_map_1_to_2, correspondence_map_2_to_1, new_graph_size)) { return (false); } // Depth-first search into the state space of possible // sub-graphs bool continue_iteration = mcgregor_common_subgraphs_internal(graph1, graph2, vindex_map1, vindex_map2, correspondence_map_1_to_2, correspondence_map_2_to_1, vertex_stack1, edges_equivalent, vertices_equivalent, only_connected_subgraphs, subgraph_callback); if (!continue_iteration) { return (false); } // Restore previous state if (vertex_stack1.size() > old_graph_size) { VertexFirst stack_vertex1 = vertex_stack1.top(); VertexSecond stack_vertex2 = get(correspondence_map_1_to_2, stack_vertex1); // Contract subgraph put(correspondence_map_1_to_2, stack_vertex1, graph_traits< GraphSecond >::null_vertex()); put(correspondence_map_2_to_1, stack_vertex2, graph_traits< GraphFirst >::null_vertex()); vertex_stack1.pop(); } } // if can_extend_graph } // BGL_FORALL_VERTICES_T (graph2) } // BGL_FORALL_VERTICES_T (graph1) return (true); } // Internal method that initializes blank correspondence maps and // a vertex stack for use in mcgregor_common_subgraphs_internal. template < typename GraphFirst, typename GraphSecond, typename VertexIndexMapFirst, typename VertexIndexMapSecond, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate, typename SubGraphInternalCallback > inline void mcgregor_common_subgraphs_internal_init( const GraphFirst& graph1, const GraphSecond& graph2, const VertexIndexMapFirst vindex_map1, const VertexIndexMapSecond vindex_map2, EdgeEquivalencePredicate edges_equivalent, VertexEquivalencePredicate vertices_equivalent, bool only_connected_subgraphs, SubGraphInternalCallback subgraph_callback) { typedef mcgregor_common_subgraph_traits< GraphFirst, GraphSecond, VertexIndexMapFirst, VertexIndexMapSecond > SubGraphTraits; typename SubGraphTraits::correspondence_map_first_to_second_type correspondence_map_1_to_2(num_vertices(graph1), vindex_map1); BGL_FORALL_VERTICES_T(vertex1, graph1, GraphFirst) { put(correspondence_map_1_to_2, vertex1, graph_traits< GraphSecond >::null_vertex()); } typename SubGraphTraits::correspondence_map_second_to_first_type correspondence_map_2_to_1(num_vertices(graph2), vindex_map2); BGL_FORALL_VERTICES_T(vertex2, graph2, GraphSecond) { put(correspondence_map_2_to_1, vertex2, graph_traits< GraphFirst >::null_vertex()); } typedef typename graph_traits< GraphFirst >::vertex_descriptor VertexFirst; std::stack< VertexFirst > vertex_stack1; mcgregor_common_subgraphs_internal(graph1, graph2, vindex_map1, vindex_map2, correspondence_map_1_to_2, correspondence_map_2_to_1, vertex_stack1, edges_equivalent, vertices_equivalent, only_connected_subgraphs, subgraph_callback); } } // namespace detail // ========================================================================== // Enumerates all common subgraphs present in graph1 and graph2. // Continues until the search space has been fully explored or false // is returned from user_callback. template < typename GraphFirst, typename GraphSecond, typename VertexIndexMapFirst, typename VertexIndexMapSecond, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate, typename SubGraphCallback > void mcgregor_common_subgraphs(const GraphFirst& graph1, const GraphSecond& graph2, const VertexIndexMapFirst vindex_map1, const VertexIndexMapSecond vindex_map2, EdgeEquivalencePredicate edges_equivalent, VertexEquivalencePredicate vertices_equivalent, bool only_connected_subgraphs, SubGraphCallback user_callback) { detail::mcgregor_common_subgraphs_internal_init(graph1, graph2, vindex_map1, vindex_map2, edges_equivalent, vertices_equivalent, only_connected_subgraphs, user_callback); } // Variant of mcgregor_common_subgraphs with all default parameters template < typename GraphFirst, typename GraphSecond, typename SubGraphCallback > void mcgregor_common_subgraphs(const GraphFirst& graph1, const GraphSecond& graph2, bool only_connected_subgraphs, SubGraphCallback user_callback) { detail::mcgregor_common_subgraphs_internal_init(graph1, graph2, get(vertex_index, graph1), get(vertex_index, graph2), always_equivalent(), always_equivalent(), only_connected_subgraphs, user_callback); } // Named parameter variant of mcgregor_common_subgraphs template < typename GraphFirst, typename GraphSecond, typename SubGraphCallback, typename Param, typename Tag, typename Rest > void mcgregor_common_subgraphs(const GraphFirst& graph1, const GraphSecond& graph2, bool only_connected_subgraphs, SubGraphCallback user_callback, const bgl_named_params< Param, Tag, Rest >& params) { detail::mcgregor_common_subgraphs_internal_init(graph1, graph2, choose_const_pmap( get_param(params, vertex_index1), graph1, vertex_index), choose_const_pmap( get_param(params, vertex_index2), graph2, vertex_index), choose_param( get_param(params, edges_equivalent_t()), always_equivalent()), choose_param( get_param(params, vertices_equivalent_t()), always_equivalent()), only_connected_subgraphs, user_callback); } // ========================================================================== namespace detail { // Binary function object that intercepts subgraphs from // mcgregor_common_subgraphs_internal and maintains a cache of // unique subgraphs. The user callback is invoked for each unique // subgraph. template < typename GraphFirst, typename GraphSecond, typename VertexIndexMapFirst, typename VertexIndexMapSecond, typename SubGraphCallback > struct unique_subgraph_interceptor { typedef typename graph_traits< GraphFirst >::vertices_size_type VertexSizeFirst; typedef mcgregor_common_subgraph_traits< GraphFirst, GraphSecond, VertexIndexMapFirst, VertexIndexMapSecond > SubGraphTraits; typedef typename SubGraphTraits::correspondence_map_first_to_second_type CachedCorrespondenceMapFirstToSecond; typedef typename SubGraphTraits::correspondence_map_second_to_first_type CachedCorrespondenceMapSecondToFirst; typedef std::pair< VertexSizeFirst, std::pair< CachedCorrespondenceMapFirstToSecond, CachedCorrespondenceMapSecondToFirst > > SubGraph; typedef std::vector< SubGraph > SubGraphList; unique_subgraph_interceptor(const GraphFirst& graph1, const GraphSecond& graph2, const VertexIndexMapFirst vindex_map1, const VertexIndexMapSecond vindex_map2, SubGraphCallback user_callback) : m_graph1(graph1) , m_graph2(graph2) , m_vindex_map1(vindex_map1) , m_vindex_map2(vindex_map2) , m_subgraphs(make_shared< SubGraphList >()) , m_user_callback(user_callback) { } template < typename CorrespondenceMapFirstToSecond, typename CorrespondenceMapSecondToFirst > bool operator()( CorrespondenceMapFirstToSecond correspondence_map_1_to_2, CorrespondenceMapSecondToFirst correspondence_map_2_to_1, VertexSizeFirst subgraph_size) { for (typename SubGraphList::const_iterator subgraph_iter = m_subgraphs->begin(); subgraph_iter != m_subgraphs->end(); ++subgraph_iter) { SubGraph subgraph_cached = *subgraph_iter; // Compare subgraph sizes if (subgraph_size != subgraph_cached.first) { continue; } if (!are_property_maps_different(correspondence_map_1_to_2, subgraph_cached.second.first, m_graph1)) { // New subgraph is a duplicate return (true); } } // Subgraph is unique, so make a cached copy CachedCorrespondenceMapFirstToSecond new_subgraph_1_to_2 = CachedCorrespondenceMapFirstToSecond( num_vertices(m_graph1), m_vindex_map1); CachedCorrespondenceMapSecondToFirst new_subgraph_2_to_1 = CorrespondenceMapSecondToFirst( num_vertices(m_graph2), m_vindex_map2); BGL_FORALL_VERTICES_T(vertex1, m_graph1, GraphFirst) { put(new_subgraph_1_to_2, vertex1, get(correspondence_map_1_to_2, vertex1)); } BGL_FORALL_VERTICES_T(vertex2, m_graph2, GraphFirst) { put(new_subgraph_2_to_1, vertex2, get(correspondence_map_2_to_1, vertex2)); } m_subgraphs->push_back(std::make_pair(subgraph_size, std::make_pair(new_subgraph_1_to_2, new_subgraph_2_to_1))); return (m_user_callback(correspondence_map_1_to_2, correspondence_map_2_to_1, subgraph_size)); } private: const GraphFirst& m_graph1; const GraphFirst& m_graph2; const VertexIndexMapFirst m_vindex_map1; const VertexIndexMapSecond m_vindex_map2; shared_ptr< SubGraphList > m_subgraphs; SubGraphCallback m_user_callback; }; } // namespace detail // Enumerates all unique common subgraphs between graph1 and graph2. // The user callback is invoked for each unique subgraph as they are // discovered. template < typename GraphFirst, typename GraphSecond, typename VertexIndexMapFirst, typename VertexIndexMapSecond, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate, typename SubGraphCallback > void mcgregor_common_subgraphs_unique(const GraphFirst& graph1, const GraphSecond& graph2, const VertexIndexMapFirst vindex_map1, const VertexIndexMapSecond vindex_map2, EdgeEquivalencePredicate edges_equivalent, VertexEquivalencePredicate vertices_equivalent, bool only_connected_subgraphs, SubGraphCallback user_callback) { detail::unique_subgraph_interceptor< GraphFirst, GraphSecond, VertexIndexMapFirst, VertexIndexMapSecond, SubGraphCallback > unique_callback( graph1, graph2, vindex_map1, vindex_map2, user_callback); detail::mcgregor_common_subgraphs_internal_init(graph1, graph2, vindex_map1, vindex_map2, edges_equivalent, vertices_equivalent, only_connected_subgraphs, unique_callback); } // Variant of mcgregor_common_subgraphs_unique with all default // parameters. template < typename GraphFirst, typename GraphSecond, typename SubGraphCallback > void mcgregor_common_subgraphs_unique(const GraphFirst& graph1, const GraphSecond& graph2, bool only_connected_subgraphs, SubGraphCallback user_callback) { mcgregor_common_subgraphs_unique(graph1, graph2, get(vertex_index, graph1), get(vertex_index, graph2), always_equivalent(), always_equivalent(), only_connected_subgraphs, user_callback); } // Named parameter variant of mcgregor_common_subgraphs_unique template < typename GraphFirst, typename GraphSecond, typename SubGraphCallback, typename Param, typename Tag, typename Rest > void mcgregor_common_subgraphs_unique(const GraphFirst& graph1, const GraphSecond& graph2, bool only_connected_subgraphs, SubGraphCallback user_callback, const bgl_named_params< Param, Tag, Rest >& params) { mcgregor_common_subgraphs_unique(graph1, graph2, choose_const_pmap( get_param(params, vertex_index1), graph1, vertex_index), choose_const_pmap( get_param(params, vertex_index2), graph2, vertex_index), choose_param( get_param(params, edges_equivalent_t()), always_equivalent()), choose_param( get_param(params, vertices_equivalent_t()), always_equivalent()), only_connected_subgraphs, user_callback); } // ========================================================================== namespace detail { // Binary function object that intercepts subgraphs from // mcgregor_common_subgraphs_internal and maintains a cache of the // largest subgraphs. template < typename GraphFirst, typename GraphSecond, typename VertexIndexMapFirst, typename VertexIndexMapSecond, typename SubGraphCallback > struct maximum_subgraph_interceptor { typedef typename graph_traits< GraphFirst >::vertices_size_type VertexSizeFirst; typedef mcgregor_common_subgraph_traits< GraphFirst, GraphSecond, VertexIndexMapFirst, VertexIndexMapSecond > SubGraphTraits; typedef typename SubGraphTraits::correspondence_map_first_to_second_type CachedCorrespondenceMapFirstToSecond; typedef typename SubGraphTraits::correspondence_map_second_to_first_type CachedCorrespondenceMapSecondToFirst; typedef std::pair< VertexSizeFirst, std::pair< CachedCorrespondenceMapFirstToSecond, CachedCorrespondenceMapSecondToFirst > > SubGraph; typedef std::vector< SubGraph > SubGraphList; maximum_subgraph_interceptor(const GraphFirst& graph1, const GraphSecond& graph2, const VertexIndexMapFirst vindex_map1, const VertexIndexMapSecond vindex_map2, SubGraphCallback user_callback) : m_graph1(graph1) , m_graph2(graph2) , m_vindex_map1(vindex_map1) , m_vindex_map2(vindex_map2) , m_subgraphs(make_shared< SubGraphList >()) , m_largest_size_so_far(make_shared< VertexSizeFirst >(0)) , m_user_callback(user_callback) { } template < typename CorrespondenceMapFirstToSecond, typename CorrespondenceMapSecondToFirst > bool operator()( CorrespondenceMapFirstToSecond correspondence_map_1_to_2, CorrespondenceMapSecondToFirst correspondence_map_2_to_1, VertexSizeFirst subgraph_size) { if (subgraph_size > *m_largest_size_so_far) { m_subgraphs->clear(); *m_largest_size_so_far = subgraph_size; } if (subgraph_size == *m_largest_size_so_far) { // Make a cached copy CachedCorrespondenceMapFirstToSecond new_subgraph_1_to_2 = CachedCorrespondenceMapFirstToSecond( num_vertices(m_graph1), m_vindex_map1); CachedCorrespondenceMapSecondToFirst new_subgraph_2_to_1 = CachedCorrespondenceMapSecondToFirst( num_vertices(m_graph2), m_vindex_map2); BGL_FORALL_VERTICES_T(vertex1, m_graph1, GraphFirst) { put(new_subgraph_1_to_2, vertex1, get(correspondence_map_1_to_2, vertex1)); } BGL_FORALL_VERTICES_T(vertex2, m_graph2, GraphFirst) { put(new_subgraph_2_to_1, vertex2, get(correspondence_map_2_to_1, vertex2)); } m_subgraphs->push_back(std::make_pair(subgraph_size, std::make_pair(new_subgraph_1_to_2, new_subgraph_2_to_1))); } return (true); } void output_subgraphs() { for (typename SubGraphList::const_iterator subgraph_iter = m_subgraphs->begin(); subgraph_iter != m_subgraphs->end(); ++subgraph_iter) { SubGraph subgraph_cached = *subgraph_iter; m_user_callback(subgraph_cached.second.first, subgraph_cached.second.second, subgraph_cached.first); } } private: const GraphFirst& m_graph1; const GraphFirst& m_graph2; const VertexIndexMapFirst m_vindex_map1; const VertexIndexMapSecond m_vindex_map2; shared_ptr< SubGraphList > m_subgraphs; shared_ptr< VertexSizeFirst > m_largest_size_so_far; SubGraphCallback m_user_callback; }; } // namespace detail // Enumerates the largest common subgraphs found between graph1 // and graph2. Note that the ENTIRE search space is explored before // user_callback is actually invoked. template < typename GraphFirst, typename GraphSecond, typename VertexIndexMapFirst, typename VertexIndexMapSecond, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate, typename SubGraphCallback > void mcgregor_common_subgraphs_maximum(const GraphFirst& graph1, const GraphSecond& graph2, const VertexIndexMapFirst vindex_map1, const VertexIndexMapSecond vindex_map2, EdgeEquivalencePredicate edges_equivalent, VertexEquivalencePredicate vertices_equivalent, bool only_connected_subgraphs, SubGraphCallback user_callback) { detail::maximum_subgraph_interceptor< GraphFirst, GraphSecond, VertexIndexMapFirst, VertexIndexMapSecond, SubGraphCallback > max_interceptor( graph1, graph2, vindex_map1, vindex_map2, user_callback); detail::mcgregor_common_subgraphs_internal_init(graph1, graph2, vindex_map1, vindex_map2, edges_equivalent, vertices_equivalent, only_connected_subgraphs, max_interceptor); // Only output the largest subgraphs max_interceptor.output_subgraphs(); } // Variant of mcgregor_common_subgraphs_maximum with all default // parameters. template < typename GraphFirst, typename GraphSecond, typename SubGraphCallback > void mcgregor_common_subgraphs_maximum(const GraphFirst& graph1, const GraphSecond& graph2, bool only_connected_subgraphs, SubGraphCallback user_callback) { mcgregor_common_subgraphs_maximum(graph1, graph2, get(vertex_index, graph1), get(vertex_index, graph2), always_equivalent(), always_equivalent(), only_connected_subgraphs, user_callback); } // Named parameter variant of mcgregor_common_subgraphs_maximum template < typename GraphFirst, typename GraphSecond, typename SubGraphCallback, typename Param, typename Tag, typename Rest > void mcgregor_common_subgraphs_maximum(const GraphFirst& graph1, const GraphSecond& graph2, bool only_connected_subgraphs, SubGraphCallback user_callback, const bgl_named_params< Param, Tag, Rest >& params) { mcgregor_common_subgraphs_maximum(graph1, graph2, choose_const_pmap( get_param(params, vertex_index1), graph1, vertex_index), choose_const_pmap( get_param(params, vertex_index2), graph2, vertex_index), choose_param( get_param(params, edges_equivalent_t()), always_equivalent()), choose_param( get_param(params, vertices_equivalent_t()), always_equivalent()), only_connected_subgraphs, user_callback); } // ========================================================================== namespace detail { // Binary function object that intercepts subgraphs from // mcgregor_common_subgraphs_internal and maintains a cache of the // largest, unique subgraphs. template < typename GraphFirst, typename GraphSecond, typename VertexIndexMapFirst, typename VertexIndexMapSecond, typename SubGraphCallback > struct unique_maximum_subgraph_interceptor { typedef typename graph_traits< GraphFirst >::vertices_size_type VertexSizeFirst; typedef mcgregor_common_subgraph_traits< GraphFirst, GraphSecond, VertexIndexMapFirst, VertexIndexMapSecond > SubGraphTraits; typedef typename SubGraphTraits::correspondence_map_first_to_second_type CachedCorrespondenceMapFirstToSecond; typedef typename SubGraphTraits::correspondence_map_second_to_first_type CachedCorrespondenceMapSecondToFirst; typedef std::pair< VertexSizeFirst, std::pair< CachedCorrespondenceMapFirstToSecond, CachedCorrespondenceMapSecondToFirst > > SubGraph; typedef std::vector< SubGraph > SubGraphList; unique_maximum_subgraph_interceptor(const GraphFirst& graph1, const GraphSecond& graph2, const VertexIndexMapFirst vindex_map1, const VertexIndexMapSecond vindex_map2, SubGraphCallback user_callback) : m_graph1(graph1) , m_graph2(graph2) , m_vindex_map1(vindex_map1) , m_vindex_map2(vindex_map2) , m_subgraphs(make_shared< SubGraphList >()) , m_largest_size_so_far(make_shared< VertexSizeFirst >(0)) , m_user_callback(user_callback) { } template < typename CorrespondenceMapFirstToSecond, typename CorrespondenceMapSecondToFirst > bool operator()( CorrespondenceMapFirstToSecond correspondence_map_1_to_2, CorrespondenceMapSecondToFirst correspondence_map_2_to_1, VertexSizeFirst subgraph_size) { if (subgraph_size > *m_largest_size_so_far) { m_subgraphs->clear(); *m_largest_size_so_far = subgraph_size; } if (subgraph_size == *m_largest_size_so_far) { // Check if subgraph is unique for (typename SubGraphList::const_iterator subgraph_iter = m_subgraphs->begin(); subgraph_iter != m_subgraphs->end(); ++subgraph_iter) { SubGraph subgraph_cached = *subgraph_iter; if (!are_property_maps_different(correspondence_map_1_to_2, subgraph_cached.second.first, m_graph1)) { // New subgraph is a duplicate return (true); } } // Subgraph is unique, so make a cached copy CachedCorrespondenceMapFirstToSecond new_subgraph_1_to_2 = CachedCorrespondenceMapFirstToSecond( num_vertices(m_graph1), m_vindex_map1); CachedCorrespondenceMapSecondToFirst new_subgraph_2_to_1 = CachedCorrespondenceMapSecondToFirst( num_vertices(m_graph2), m_vindex_map2); BGL_FORALL_VERTICES_T(vertex1, m_graph1, GraphFirst) { put(new_subgraph_1_to_2, vertex1, get(correspondence_map_1_to_2, vertex1)); } BGL_FORALL_VERTICES_T(vertex2, m_graph2, GraphFirst) { put(new_subgraph_2_to_1, vertex2, get(correspondence_map_2_to_1, vertex2)); } m_subgraphs->push_back(std::make_pair(subgraph_size, std::make_pair(new_subgraph_1_to_2, new_subgraph_2_to_1))); } return (true); } void output_subgraphs() { for (typename SubGraphList::const_iterator subgraph_iter = m_subgraphs->begin(); subgraph_iter != m_subgraphs->end(); ++subgraph_iter) { SubGraph subgraph_cached = *subgraph_iter; m_user_callback(subgraph_cached.second.first, subgraph_cached.second.second, subgraph_cached.first); } } private: const GraphFirst& m_graph1; const GraphFirst& m_graph2; const VertexIndexMapFirst m_vindex_map1; const VertexIndexMapSecond m_vindex_map2; shared_ptr< SubGraphList > m_subgraphs; shared_ptr< VertexSizeFirst > m_largest_size_so_far; SubGraphCallback m_user_callback; }; } // namespace detail // Enumerates the largest, unique common subgraphs found between // graph1 and graph2. Note that the ENTIRE search space is explored // before user_callback is actually invoked. template < typename GraphFirst, typename GraphSecond, typename VertexIndexMapFirst, typename VertexIndexMapSecond, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate, typename SubGraphCallback > void mcgregor_common_subgraphs_maximum_unique(const GraphFirst& graph1, const GraphSecond& graph2, const VertexIndexMapFirst vindex_map1, const VertexIndexMapSecond vindex_map2, EdgeEquivalencePredicate edges_equivalent, VertexEquivalencePredicate vertices_equivalent, bool only_connected_subgraphs, SubGraphCallback user_callback) { detail::unique_maximum_subgraph_interceptor< GraphFirst, GraphSecond, VertexIndexMapFirst, VertexIndexMapSecond, SubGraphCallback > unique_max_interceptor( graph1, graph2, vindex_map1, vindex_map2, user_callback); detail::mcgregor_common_subgraphs_internal_init(graph1, graph2, vindex_map1, vindex_map2, edges_equivalent, vertices_equivalent, only_connected_subgraphs, unique_max_interceptor); // Only output the largest, unique subgraphs unique_max_interceptor.output_subgraphs(); } // Variant of mcgregor_common_subgraphs_maximum_unique with all default // parameters template < typename GraphFirst, typename GraphSecond, typename SubGraphCallback > void mcgregor_common_subgraphs_maximum_unique(const GraphFirst& graph1, const GraphSecond& graph2, bool only_connected_subgraphs, SubGraphCallback user_callback) { mcgregor_common_subgraphs_maximum_unique(graph1, graph2, get(vertex_index, graph1), get(vertex_index, graph2), always_equivalent(), always_equivalent(), only_connected_subgraphs, user_callback); } // Named parameter variant of // mcgregor_common_subgraphs_maximum_unique template < typename GraphFirst, typename GraphSecond, typename SubGraphCallback, typename Param, typename Tag, typename Rest > void mcgregor_common_subgraphs_maximum_unique(const GraphFirst& graph1, const GraphSecond& graph2, bool only_connected_subgraphs, SubGraphCallback user_callback, const bgl_named_params< Param, Tag, Rest >& params) { mcgregor_common_subgraphs_maximum_unique(graph1, graph2, choose_const_pmap( get_param(params, vertex_index1), graph1, vertex_index), choose_const_pmap( get_param(params, vertex_index2), graph2, vertex_index), choose_param( get_param(params, edges_equivalent_t()), always_equivalent()), choose_param( get_param(params, vertices_equivalent_t()), always_equivalent()), only_connected_subgraphs, user_callback); } // ========================================================================== // Fills a membership map (vertex -> bool) using the information // present in correspondence_map_1_to_2. Every vertex in a // membership map will have a true value only if it is not // associated with a null vertex in the correspondence map. template < typename GraphSecond, typename GraphFirst, typename CorrespondenceMapFirstToSecond, typename MembershipMapFirst > void fill_membership_map(const GraphFirst& graph1, const CorrespondenceMapFirstToSecond correspondence_map_1_to_2, MembershipMapFirst membership_map1) { BGL_FORALL_VERTICES_T(vertex1, graph1, GraphFirst) { put(membership_map1, vertex1, get(correspondence_map_1_to_2, vertex1) != graph_traits< GraphSecond >::null_vertex()); } } // Traits associated with a membership map filtered graph. Provided // for convenience to access graph and vertex filter types. template < typename Graph, typename MembershipMap > struct membership_filtered_graph_traits { typedef property_map_filter< MembershipMap > vertex_filter_type; typedef filtered_graph< Graph, keep_all, vertex_filter_type > graph_type; }; // Returns a filtered sub-graph of graph whose edge and vertex // inclusion is dictated by membership_map. template < typename Graph, typename MembershipMap > typename membership_filtered_graph_traits< Graph, MembershipMap >::graph_type make_membership_filtered_graph( const Graph& graph, MembershipMap& membership_map) { typedef membership_filtered_graph_traits< Graph, MembershipMap > MFGTraits; typedef typename MFGTraits::graph_type MembershipFilteredGraph; typename MFGTraits::vertex_filter_type v_filter(membership_map); return (MembershipFilteredGraph(graph, keep_all(), v_filter)); } } // namespace boost #endif // BOOST_GRAPH_MCGREGOR_COMMON_SUBGRAPHS_HPP clustering_coefficient.hpp 0000644 00000013136 15125521275 0012003 0 ustar 00 // (C) Copyright 2007-2009 Andrew Sutton // // 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_CLUSTERING_COEFFICIENT_HPP #define BOOST_GRAPH_CLUSTERING_COEFFICIENT_HPP #include <boost/next_prior.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/lookup_edge.hpp> #include <boost/concept/assert.hpp> namespace boost { namespace detail { template < class Graph > inline typename graph_traits< Graph >::degree_size_type possible_edges( const Graph& g, std::size_t k, directed_tag) { BOOST_CONCEPT_ASSERT((GraphConcept< Graph >)); typedef typename graph_traits< Graph >::degree_size_type T; return T(k) * (T(k) - 1); } template < class Graph > inline typename graph_traits< Graph >::degree_size_type possible_edges( const Graph& g, size_t k, undirected_tag) { // dirty little trick... return possible_edges(g, k, directed_tag()) / 2; } // This template matches directedS and bidirectionalS. template < class Graph > inline typename graph_traits< Graph >::degree_size_type count_edges( const Graph& g, typename graph_traits< Graph >::vertex_descriptor u, typename graph_traits< Graph >::vertex_descriptor v, directed_tag) { BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< Graph >)); return (lookup_edge(u, v, g).second ? 1 : 0) + (lookup_edge(v, u, g).second ? 1 : 0); } // This template matches undirectedS template < class Graph > inline typename graph_traits< Graph >::degree_size_type count_edges( const Graph& g, typename graph_traits< Graph >::vertex_descriptor u, typename graph_traits< Graph >::vertex_descriptor v, undirected_tag) { BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< Graph >)); return lookup_edge(u, v, g).second ? 1 : 0; } } template < typename Graph, typename Vertex > inline typename graph_traits< Graph >::degree_size_type num_paths_through_vertex(const Graph& g, Vertex v) { BOOST_CONCEPT_ASSERT((AdjacencyGraphConcept< Graph >)); typedef typename graph_traits< Graph >::directed_category Directed; typedef typename graph_traits< Graph >::adjacency_iterator AdjacencyIterator; // TODO: There should actually be a set of neighborhood functions // for things like this (num_neighbors() would be great). AdjacencyIterator i, end; boost::tie(i, end) = adjacent_vertices(v, g); std::size_t k = std::distance(i, end); return detail::possible_edges(g, k, Directed()); } template < typename Graph, typename Vertex > inline typename graph_traits< Graph >::degree_size_type num_triangles_on_vertex( const Graph& g, Vertex v) { BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >)); BOOST_CONCEPT_ASSERT((AdjacencyGraphConcept< Graph >)); typedef typename graph_traits< Graph >::degree_size_type Degree; typedef typename graph_traits< Graph >::directed_category Directed; typedef typename graph_traits< Graph >::adjacency_iterator AdjacencyIterator; // TODO: I might be able to reduce the requirement from adjacency graph // to incidence graph by using out edges. Degree count(0); AdjacencyIterator i, j, end; for (boost::tie(i, end) = adjacent_vertices(v, g); i != end; ++i) { for (j = boost::next(i); j != end; ++j) { count += detail::count_edges(g, *i, *j, Directed()); } } return count; } /* namespace detail */ template < typename T, typename Graph, typename Vertex > inline T clustering_coefficient(const Graph& g, Vertex v) { T zero(0); T routes = T(num_paths_through_vertex(g, v)); return (routes > zero) ? T(num_triangles_on_vertex(g, v)) / routes : zero; } template < typename Graph, typename Vertex > inline double clustering_coefficient(const Graph& g, Vertex v) { return clustering_coefficient< double >(g, v); } template < typename Graph, typename ClusteringMap > inline typename property_traits< ClusteringMap >::value_type all_clustering_coefficients(const Graph& g, ClusteringMap cm) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::vertex_iterator VertexIterator; BOOST_CONCEPT_ASSERT((WritablePropertyMapConcept< ClusteringMap, Vertex >)); typedef typename property_traits< ClusteringMap >::value_type Coefficient; Coefficient sum(0); VertexIterator i, end; for (boost::tie(i, end) = vertices(g); i != end; ++i) { Coefficient cc = clustering_coefficient< Coefficient >(g, *i); put(cm, *i, cc); sum += cc; } return sum / Coefficient(num_vertices(g)); } template < typename Graph, typename ClusteringMap > inline typename property_traits< ClusteringMap >::value_type mean_clustering_coefficient(const Graph& g, ClusteringMap cm) { BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); typedef typename graph_traits< Graph >::vertex_descriptor Vertex; typedef typename graph_traits< Graph >::vertex_iterator VertexIterator; BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< ClusteringMap, Vertex >)); typedef typename property_traits< ClusteringMap >::value_type Coefficient; Coefficient cc(0); VertexIterator i, end; for (boost::tie(i, end) = vertices(g); i != end; ++i) { cc += get(cm, *i); } return cc / Coefficient(num_vertices(g)); } } /* namespace boost */ #endif breadth_first_search.hpp 0000644 00000034657 15125521275 0011446 0 ustar 00 // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #ifndef BOOST_GRAPH_BREADTH_FIRST_SEARCH_HPP #define BOOST_GRAPH_BREADTH_FIRST_SEARCH_HPP /* Breadth First Search Algorithm (Cormen, Leiserson, and Rivest p. 470) */ #include <boost/config.hpp> #include <vector> #include <boost/pending/queue.hpp> #include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/visitors.hpp> #include <boost/graph/named_function_params.hpp> #include <boost/graph/overloading.hpp> #include <boost/graph/graph_concepts.hpp> #include <boost/graph/two_bit_color_map.hpp> #include <boost/graph/detail/mpi_include.hpp> #include <boost/concept/assert.hpp> #include BOOST_GRAPH_MPI_INCLUDE(< boost / graph / distributed / concepts.hpp >) namespace boost { template < class Visitor, class Graph > struct BFSVisitorConcept { void constraints() { BOOST_CONCEPT_ASSERT((CopyConstructibleConcept< Visitor >)); vis.initialize_vertex(u, g); vis.discover_vertex(u, g); vis.examine_vertex(u, g); vis.examine_edge(e, g); vis.tree_edge(e, g); vis.non_tree_edge(e, g); vis.gray_target(e, g); vis.black_target(e, g); vis.finish_vertex(u, g); } Visitor vis; Graph g; typename graph_traits< Graph >::vertex_descriptor u; typename graph_traits< Graph >::edge_descriptor e; }; // Multiple-source version template < class IncidenceGraph, class Buffer, class BFSVisitor, class ColorMap, class SourceIterator > void breadth_first_visit(const IncidenceGraph& g, SourceIterator sources_begin, SourceIterator sources_end, Buffer& Q, BFSVisitor vis, ColorMap color) { BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< IncidenceGraph >)); typedef graph_traits< IncidenceGraph > GTraits; typedef typename GTraits::vertex_descriptor Vertex; BOOST_CONCEPT_ASSERT((BFSVisitorConcept< BFSVisitor, IncidenceGraph >)); BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept< ColorMap, Vertex >)); typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; typename GTraits::out_edge_iterator ei, ei_end; for (; sources_begin != sources_end; ++sources_begin) { Vertex s = *sources_begin; put(color, s, Color::gray()); vis.discover_vertex(s, g); Q.push(s); } while (!Q.empty()) { Vertex u = Q.top(); Q.pop(); vis.examine_vertex(u, g); for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) { Vertex v = target(*ei, g); vis.examine_edge(*ei, g); ColorValue v_color = get(color, v); if (v_color == Color::white()) { vis.tree_edge(*ei, g); put(color, v, Color::gray()); vis.discover_vertex(v, g); Q.push(v); } else { vis.non_tree_edge(*ei, g); if (v_color == Color::gray()) vis.gray_target(*ei, g); else vis.black_target(*ei, g); } } // end for put(color, u, Color::black()); vis.finish_vertex(u, g); } // end while } // breadth_first_visit // Single-source version template < class IncidenceGraph, class Buffer, class BFSVisitor, class ColorMap > void breadth_first_visit(const IncidenceGraph& g, typename graph_traits< IncidenceGraph >::vertex_descriptor s, Buffer& Q, BFSVisitor vis, ColorMap color) { typename graph_traits< IncidenceGraph >::vertex_descriptor sources[1] = { s }; breadth_first_visit(g, sources, sources + 1, Q, vis, color); } template < class VertexListGraph, class SourceIterator, class Buffer, class BFSVisitor, class ColorMap > void breadth_first_search(const VertexListGraph& g, SourceIterator sources_begin, SourceIterator sources_end, Buffer& Q, BFSVisitor vis, ColorMap color) { // Initialization typedef typename property_traits< ColorMap >::value_type ColorValue; typedef color_traits< ColorValue > Color; typename boost::graph_traits< VertexListGraph >::vertex_iterator i, i_end; for (boost::tie(i, i_end) = vertices(g); i != i_end; ++i) { vis.initialize_vertex(*i, g); put(color, *i, Color::white()); } breadth_first_visit(g, sources_begin, sources_end, Q, vis, color); } template < class VertexListGraph, class Buffer, class BFSVisitor, class ColorMap > void breadth_first_search(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, Buffer& Q, BFSVisitor vis, ColorMap color) { typename graph_traits< VertexListGraph >::vertex_descriptor sources[1] = { s }; breadth_first_search(g, sources, sources + 1, Q, vis, color); } namespace graph { struct bfs_visitor_event_not_overridden { }; } template < class Visitors = null_visitor > class bfs_visitor { public: bfs_visitor() {} bfs_visitor(Visitors vis) : m_vis(vis) {} template < class Vertex, class Graph > graph::bfs_visitor_event_not_overridden initialize_vertex( Vertex u, Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex()); return graph::bfs_visitor_event_not_overridden(); } template < class Vertex, class Graph > graph::bfs_visitor_event_not_overridden discover_vertex(Vertex u, Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_discover_vertex()); return graph::bfs_visitor_event_not_overridden(); } template < class Vertex, class Graph > graph::bfs_visitor_event_not_overridden examine_vertex(Vertex u, Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_examine_vertex()); return graph::bfs_visitor_event_not_overridden(); } template < class Edge, class Graph > graph::bfs_visitor_event_not_overridden examine_edge(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, ::boost::on_examine_edge()); return graph::bfs_visitor_event_not_overridden(); } template < class Edge, class Graph > graph::bfs_visitor_event_not_overridden tree_edge(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, ::boost::on_tree_edge()); return graph::bfs_visitor_event_not_overridden(); } template < class Edge, class Graph > graph::bfs_visitor_event_not_overridden non_tree_edge(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, ::boost::on_non_tree_edge()); return graph::bfs_visitor_event_not_overridden(); } template < class Edge, class Graph > graph::bfs_visitor_event_not_overridden gray_target(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, ::boost::on_gray_target()); return graph::bfs_visitor_event_not_overridden(); } template < class Edge, class Graph > graph::bfs_visitor_event_not_overridden black_target(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, ::boost::on_black_target()); return graph::bfs_visitor_event_not_overridden(); } template < class Vertex, class Graph > graph::bfs_visitor_event_not_overridden finish_vertex(Vertex u, Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex()); return graph::bfs_visitor_event_not_overridden(); } BOOST_GRAPH_EVENT_STUB(on_initialize_vertex, bfs) BOOST_GRAPH_EVENT_STUB(on_discover_vertex, bfs) BOOST_GRAPH_EVENT_STUB(on_examine_vertex, bfs) BOOST_GRAPH_EVENT_STUB(on_examine_edge, bfs) BOOST_GRAPH_EVENT_STUB(on_tree_edge, bfs) BOOST_GRAPH_EVENT_STUB(on_non_tree_edge, bfs) BOOST_GRAPH_EVENT_STUB(on_gray_target, bfs) BOOST_GRAPH_EVENT_STUB(on_black_target, bfs) BOOST_GRAPH_EVENT_STUB(on_finish_vertex, bfs) protected: Visitors m_vis; }; template < class Visitors > bfs_visitor< Visitors > make_bfs_visitor(Visitors vis) { return bfs_visitor< Visitors >(vis); } typedef bfs_visitor<> default_bfs_visitor; namespace detail { template < class VertexListGraph, class ColorMap, class BFSVisitor, class P, class T, class R > void bfs_helper(VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, ColorMap color, BFSVisitor vis, const bgl_named_params< P, T, R >& params, boost::mpl::false_) { typedef graph_traits< VertexListGraph > Traits; // Buffer default typedef typename Traits::vertex_descriptor Vertex; typedef boost::queue< Vertex > queue_t; queue_t Q; breadth_first_search(g, s, choose_param(get_param(params, buffer_param_t()), boost::ref(Q)) .get(), vis, color); } #ifdef BOOST_GRAPH_USE_MPI template < class DistributedGraph, class ColorMap, class BFSVisitor, class P, class T, class R > void bfs_helper(DistributedGraph& g, typename graph_traits< DistributedGraph >::vertex_descriptor s, ColorMap color, BFSVisitor vis, const bgl_named_params< P, T, R >& params, boost::mpl::true_); #endif // BOOST_GRAPH_USE_MPI //------------------------------------------------------------------------- // Choose between default color and color parameters. Using // function dispatching so that we don't require vertex index if // the color default is not being used. template < class ColorMap > struct bfs_dispatch { template < class VertexListGraph, class P, class T, class R > static void apply(VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, const bgl_named_params< P, T, R >& params, ColorMap color) { bfs_helper(g, s, color, choose_param(get_param(params, graph_visitor), make_bfs_visitor(null_visitor())), params, boost::mpl::bool_< boost::is_base_and_derived< distributed_graph_tag, typename graph_traits< VertexListGraph >::traversal_category >::value >()); } }; template <> struct bfs_dispatch< param_not_found > { template < class VertexListGraph, class P, class T, class R > static void apply(VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, const bgl_named_params< P, T, R >& params, param_not_found) { null_visitor null_vis; bfs_helper(g, s, make_two_bit_color_map(num_vertices(g), choose_const_pmap( get_param(params, vertex_index), g, vertex_index)), choose_param(get_param(params, graph_visitor), make_bfs_visitor(null_vis)), params, boost::mpl::bool_< boost::is_base_and_derived< distributed_graph_tag, typename graph_traits< VertexListGraph >::traversal_category >::value >()); } }; } // namespace detail #if 1 // Named Parameter Variant template < class VertexListGraph, class P, class T, class R > void breadth_first_search(const VertexListGraph& g, typename graph_traits< VertexListGraph >::vertex_descriptor s, const bgl_named_params< P, T, R >& params) { // The graph is passed by *const* reference so that graph adaptors // (temporaries) can be passed into this function. However, the // graph is not really const since we may write to property maps // of the graph. VertexListGraph& ng = const_cast< VertexListGraph& >(g); typedef typename get_param_type< vertex_color_t, bgl_named_params< P, T, R > >::type C; detail::bfs_dispatch< C >::apply( ng, s, params, get_param(params, vertex_color)); } #endif // This version does not initialize colors, user has to. template < class IncidenceGraph, class P, class T, class R > void breadth_first_visit(const IncidenceGraph& g, typename graph_traits< IncidenceGraph >::vertex_descriptor s, const bgl_named_params< P, T, R >& params) { // The graph is passed by *const* reference so that graph adaptors // (temporaries) can be passed into this function. However, the // graph is not really const since we may write to property maps // of the graph. IncidenceGraph& ng = const_cast< IncidenceGraph& >(g); typedef graph_traits< IncidenceGraph > Traits; // Buffer default typedef typename Traits::vertex_descriptor vertex_descriptor; typedef boost::queue< vertex_descriptor > queue_t; queue_t Q; breadth_first_visit(ng, s, choose_param(get_param(params, buffer_param_t()), boost::ref(Q)).get(), choose_param( get_param(params, graph_visitor), make_bfs_visitor(null_visitor())), choose_pmap(get_param(params, vertex_color), ng, vertex_color)); } namespace graph { namespace detail { template < typename Graph, typename Source > struct breadth_first_search_impl { typedef void result_type; template < typename ArgPack > void operator()( const Graph& g, const Source& source, const ArgPack& arg_pack) { using namespace boost::graph::keywords; typename boost::graph_traits< Graph >::vertex_descriptor sources[1] = { source }; boost::queue< typename boost::graph_traits< Graph >::vertex_descriptor > Q; boost::breadth_first_search(g, &sources[0], &sources[1], boost::unwrap_ref(arg_pack[_buffer | boost::ref(Q)]), arg_pack[_visitor | make_bfs_visitor(null_visitor())], boost::detail::make_color_map_from_arg_pack(g, arg_pack)); } }; } BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(breadth_first_search, 2, 4) } #if 0 // Named Parameter Variant BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(breadth_first_search, 2) #endif } // namespace boost #include BOOST_GRAPH_MPI_INCLUDE(< boost / graph / distributed / breadth_first_search.hpp >) #endif // BOOST_GRAPH_BREADTH_FIRST_SEARCH_HPP
| ver. 1.6 |
Github
|
.
| PHP 8.2.30 | ??????????? ?????????: 0.3 |
proxy
|
phpinfo
|
???????????