1 // 2 //======================================================================= 3 // Copyright 1997-2001 University of Notre Dame. 4 // Copyright 2009 Trustees of Indiana University. 5 // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Michael Hansen 6 // 7 // Distributed under the Boost Software License, Version 1.0. (See 8 // accompanying file LICENSE_1_0.txt or copy at 9 // http://www.boost.org/LICENSE_1_0.txt) 10 //======================================================================= 11 // 12 13 #ifndef BOOST_INCREMENTAL_COMPONENTS_HPP 14 #define BOOST_INCREMENTAL_COMPONENTS_HPP 15 16 #include <boost/detail/iterator.hpp> 17 #include <boost/graph/detail/incremental_components.hpp> 18 #include <boost/iterator/counting_iterator.hpp> 19 #include <boost/make_shared.hpp> 20 #include <boost/pending/disjoint_sets.hpp> 21 #include <iterator> 22 23 namespace boost { 24 25 // A connected component algorithm for the case when dynamically 26 // adding (but not removing) edges is common. The 27 // incremental_components() function is a preparing operation. Call 28 // same_component to check whether two vertices are in the same 29 // component, or use disjoint_set::find_set to determine the 30 // representative for a vertex. 31 32 // This version of connected components does not require a full 33 // Graph. Instead, it just needs an edge list, where the vertices of 34 // each edge need to be of integer type. The edges are assumed to 35 // be undirected. The other difference is that the result is stored in 36 // a container, instead of just a decorator. The container should be 37 // empty before the algorithm is called. It will grow during the 38 // course of the algorithm. The container must be a model of 39 // BackInsertionSequence and RandomAccessContainer 40 // (std::vector is a good choice). After running the algorithm the 41 // index container will map each vertex to the representative 42 // vertex of the component to which it belongs. 43 // 44 // Adapted from an implementation by Alex Stepanov. The disjoint 45 // sets data structure is from Tarjan's "Data Structures and Network 46 // Algorithms", and the application to connected components is 47 // similar to the algorithm described in Ch. 22 of "Intro to 48 // Algorithms" by Cormen, et. all. 49 // 50 51 // An implementation of disjoint sets can be found in 52 // boost/pending/disjoint_sets.hpp 53 54 template <class EdgeListGraph, class DisjointSets> incremental_components(EdgeListGraph & g,DisjointSets & ds)55 void incremental_components(EdgeListGraph& g, DisjointSets& ds) 56 { 57 typename graph_traits<EdgeListGraph>::edge_iterator e, end; 58 for (boost::tie(e,end) = edges(g); e != end; ++e) 59 ds.union_set(source(*e,g),target(*e,g)); 60 } 61 62 template <class ParentIterator> compress_components(ParentIterator first,ParentIterator last)63 void compress_components(ParentIterator first, ParentIterator last) 64 { 65 for (ParentIterator current = first; current != last; ++current) 66 detail::find_representative_with_full_compression(first, current-first); 67 } 68 69 template <class ParentIterator> 70 typename boost::detail::iterator_traits<ParentIterator>::difference_type component_count(ParentIterator first,ParentIterator last)71 component_count(ParentIterator first, ParentIterator last) 72 { 73 std::ptrdiff_t count = 0; 74 for (ParentIterator current = first; current != last; ++current) 75 if (*current == current - first) ++count; 76 return count; 77 } 78 79 // This algorithm can be applied to the result container of the 80 // connected_components algorithm to normalize 81 // the components. 82 template <class ParentIterator> normalize_components(ParentIterator first,ParentIterator last)83 void normalize_components(ParentIterator first, ParentIterator last) 84 { 85 for (ParentIterator current = first; current != last; ++current) 86 detail::normalize_node(first, current - first); 87 } 88 89 template <class VertexListGraph, class DisjointSets> initialize_incremental_components(VertexListGraph & G,DisjointSets & ds)90 void initialize_incremental_components(VertexListGraph& G, DisjointSets& ds) 91 { 92 typename graph_traits<VertexListGraph> 93 ::vertex_iterator v, vend; 94 for (boost::tie(v, vend) = vertices(G); v != vend; ++v) 95 ds.make_set(*v); 96 } 97 98 template <class Vertex, class DisjointSet> same_component(Vertex u,Vertex v,DisjointSet & ds)99 inline bool same_component(Vertex u, Vertex v, DisjointSet& ds) 100 { 101 return ds.find_set(u) == ds.find_set(v); 102 } 103 104 // Class that builds a quick-access indexed linked list that allows 105 // for fast iterating through a parent component's children. 106 template <typename IndexType> 107 class component_index { 108 109 private: 110 typedef std::vector<IndexType> IndexContainer; 111 112 public: 113 typedef counting_iterator<IndexType> iterator; 114 typedef iterator const_iterator; 115 typedef IndexType value_type; 116 typedef IndexType size_type; 117 118 typedef detail::component_index_iterator<typename IndexContainer::iterator> 119 component_iterator; 120 121 public: 122 template <typename ParentIterator, 123 typename ElementIndexMap> component_index(ParentIterator parent_start,ParentIterator parent_end,const ElementIndexMap & index_map)124 component_index(ParentIterator parent_start, 125 ParentIterator parent_end, 126 const ElementIndexMap& index_map) : 127 m_num_elements(std::distance(parent_start, parent_end)), 128 m_components(make_shared<IndexContainer>()), 129 m_index_list(make_shared<IndexContainer>(m_num_elements)) { 130 131 build_index_lists(parent_start, index_map); 132 133 } // component_index 134 135 template <typename ParentIterator> component_index(ParentIterator parent_start,ParentIterator parent_end)136 component_index(ParentIterator parent_start, 137 ParentIterator parent_end) : 138 m_num_elements(std::distance(parent_start, parent_end)), 139 m_components(make_shared<IndexContainer>()), 140 m_index_list(make_shared<IndexContainer>(m_num_elements)) { 141 142 build_index_lists(parent_start, boost::identity_property_map()); 143 144 } // component_index 145 146 // Returns the number of components size() const147 inline std::size_t size() const { 148 return (m_components->size()); 149 } 150 151 // Beginning iterator for component indices begin() const152 iterator begin() const { 153 return (iterator(0)); 154 } 155 156 // End iterator for component indices end() const157 iterator end() const { 158 return (iterator(this->size())); 159 } 160 161 // Returns a pair of begin and end iterators for the child 162 // elements of component [component_index]. 163 std::pair<component_iterator, component_iterator> operator [](IndexType component_index) const164 operator[](IndexType component_index) const { 165 166 IndexType first_index = (*m_components)[component_index]; 167 168 return (std::make_pair 169 (component_iterator(m_index_list->begin(), first_index), 170 component_iterator(m_num_elements))); 171 } 172 173 private: 174 template <typename ParentIterator, 175 typename ElementIndexMap> build_index_lists(ParentIterator parent_start,const ElementIndexMap & index_map)176 void build_index_lists(ParentIterator parent_start, 177 const ElementIndexMap& index_map) { 178 179 typedef typename std::iterator_traits<ParentIterator>::value_type Element; 180 typename IndexContainer::iterator index_list = 181 m_index_list->begin(); 182 183 // First pass - find root elements, construct index list 184 for (IndexType element_index = 0; element_index < m_num_elements; 185 ++element_index) { 186 187 Element parent_element = parent_start[element_index]; 188 IndexType parent_index = get(index_map, parent_element); 189 190 if (element_index != parent_index) { 191 index_list[element_index] = parent_index; 192 } 193 else { 194 m_components->push_back(element_index); 195 196 // m_num_elements is the linked list terminator 197 index_list[element_index] = m_num_elements; 198 } 199 } 200 201 // Second pass - build linked list 202 for (IndexType element_index = 0; element_index < m_num_elements; 203 ++element_index) { 204 205 Element parent_element = parent_start[element_index]; 206 IndexType parent_index = get(index_map, parent_element); 207 208 if (element_index != parent_index) { 209 210 // Follow list until a component parent is found 211 while (index_list[parent_index] != m_num_elements) { 212 parent_index = index_list[parent_index]; 213 } 214 215 // Push element to the front of the linked list 216 index_list[element_index] = index_list[parent_index]; 217 index_list[parent_index] = element_index; 218 } 219 } 220 221 } // build_index_lists 222 223 protected: 224 IndexType m_num_elements; 225 shared_ptr<IndexContainer> m_components, m_index_list; 226 227 }; // class component_index 228 229 } // namespace boost 230 231 #endif // BOOST_INCREMENTAL_COMPONENTS_HPP 232