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