Chris@16
|
1 // Copyright 2005-2009 The Trustees of Indiana University.
|
Chris@16
|
2
|
Chris@16
|
3 // Distributed under the Boost Software License, Version 1.0.
|
Chris@16
|
4 // (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
5 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6
|
Chris@16
|
7 // Authors: Jeremiah Willcock
|
Chris@16
|
8 // Douglas Gregor
|
Chris@16
|
9 // Andrew Lumsdaine
|
Chris@16
|
10
|
Chris@16
|
11 // Compressed sparse row graph type internal structure
|
Chris@16
|
12
|
Chris@16
|
13 #ifndef BOOST_GRAPH_COMPRESSED_SPARSE_ROW_STRUCT_HPP
|
Chris@16
|
14 #define BOOST_GRAPH_COMPRESSED_SPARSE_ROW_STRUCT_HPP
|
Chris@16
|
15
|
Chris@16
|
16 #ifndef BOOST_GRAPH_COMPRESSED_SPARSE_ROW_GRAPH_HPP
|
Chris@16
|
17 #error This file should only be included from boost/graph/compressed_sparse_row_graph.hpp
|
Chris@16
|
18 #endif
|
Chris@16
|
19
|
Chris@16
|
20 #include <vector>
|
Chris@16
|
21 #include <utility>
|
Chris@16
|
22 #include <algorithm>
|
Chris@16
|
23 #include <climits>
|
Chris@16
|
24 #include <boost/assert.hpp>
|
Chris@16
|
25 #include <iterator>
|
Chris@16
|
26 #if 0
|
Chris@16
|
27 #include <iostream> // For some debugging code below
|
Chris@16
|
28 #endif
|
Chris@16
|
29 #include <boost/graph/graph_traits.hpp>
|
Chris@16
|
30 #include <boost/graph/properties.hpp>
|
Chris@16
|
31 #include <boost/graph/filtered_graph.hpp> // For keep_all
|
Chris@16
|
32 #include <boost/graph/detail/indexed_properties.hpp>
|
Chris@16
|
33 #include <boost/graph/detail/histogram_sort.hpp>
|
Chris@16
|
34 #include <boost/graph/iteration_macros.hpp>
|
Chris@16
|
35 #include <boost/iterator/counting_iterator.hpp>
|
Chris@16
|
36 #include <boost/iterator/reverse_iterator.hpp>
|
Chris@16
|
37 #include <boost/iterator/zip_iterator.hpp>
|
Chris@16
|
38 #include <boost/iterator/transform_iterator.hpp>
|
Chris@16
|
39 #include <boost/tuple/tuple.hpp>
|
Chris@16
|
40 #include <boost/property_map/property_map.hpp>
|
Chris@16
|
41 #include <boost/integer.hpp>
|
Chris@16
|
42 #include <boost/iterator/iterator_facade.hpp>
|
Chris@16
|
43 #include <boost/mpl/if.hpp>
|
Chris@16
|
44 #include <boost/graph/graph_selectors.hpp>
|
Chris@16
|
45 #include <boost/static_assert.hpp>
|
Chris@16
|
46 #include <boost/functional/hash.hpp>
|
Chris@16
|
47
|
Chris@16
|
48 namespace boost {
|
Chris@16
|
49
|
Chris@16
|
50 namespace detail {
|
Chris@16
|
51 // Forward declaration of CSR edge descriptor type, needed to pass to
|
Chris@16
|
52 // indexed_edge_properties.
|
Chris@16
|
53 template<typename Vertex, typename EdgeIndex>
|
Chris@16
|
54 class csr_edge_descriptor;
|
Chris@16
|
55
|
Chris@16
|
56 // Add edge_index property map
|
Chris@16
|
57 template<typename Vertex, typename EdgeIndex>
|
Chris@16
|
58 struct csr_edge_index_map
|
Chris@16
|
59 {
|
Chris@16
|
60 typedef EdgeIndex value_type;
|
Chris@16
|
61 typedef EdgeIndex reference;
|
Chris@16
|
62 typedef csr_edge_descriptor<Vertex, EdgeIndex> key_type;
|
Chris@16
|
63 typedef readable_property_map_tag category;
|
Chris@16
|
64 };
|
Chris@16
|
65
|
Chris@16
|
66 template<typename Vertex, typename EdgeIndex>
|
Chris@16
|
67 inline EdgeIndex
|
Chris@16
|
68 get(const csr_edge_index_map<Vertex, EdgeIndex>&,
|
Chris@16
|
69 const csr_edge_descriptor<Vertex, EdgeIndex>& key)
|
Chris@16
|
70 {
|
Chris@16
|
71 return key.idx;
|
Chris@16
|
72 }
|
Chris@16
|
73
|
Chris@16
|
74 /** Compressed sparse row graph internal structure.
|
Chris@16
|
75 *
|
Chris@16
|
76 * Vertex and EdgeIndex should be unsigned integral types and should
|
Chris@16
|
77 * specialize numeric_limits.
|
Chris@16
|
78 */
|
Chris@16
|
79 template <typename EdgeProperty,
|
Chris@16
|
80 typename Vertex = std::size_t, typename EdgeIndex = Vertex>
|
Chris@16
|
81 class compressed_sparse_row_structure :
|
Chris@16
|
82 public detail::indexed_edge_properties<
|
Chris@16
|
83 compressed_sparse_row_structure<EdgeProperty, Vertex, EdgeIndex>,
|
Chris@16
|
84 EdgeProperty,
|
Chris@16
|
85 csr_edge_descriptor<Vertex, EdgeIndex>,
|
Chris@16
|
86 csr_edge_index_map<Vertex, EdgeIndex> > {
|
Chris@16
|
87 public:
|
Chris@16
|
88 typedef detail::indexed_edge_properties<
|
Chris@16
|
89 compressed_sparse_row_structure<EdgeProperty, Vertex, EdgeIndex>,
|
Chris@16
|
90 EdgeProperty,
|
Chris@16
|
91 csr_edge_descriptor<Vertex, EdgeIndex>,
|
Chris@16
|
92 csr_edge_index_map<Vertex, EdgeIndex> >
|
Chris@16
|
93 inherited_edge_properties;
|
Chris@16
|
94
|
Chris@16
|
95 typedef Vertex vertices_size_type;
|
Chris@16
|
96 typedef Vertex vertex_descriptor;
|
Chris@16
|
97 typedef EdgeIndex edges_size_type;
|
Chris@16
|
98
|
Chris@16
|
99 static vertex_descriptor null_vertex() { return vertex_descriptor(-1); }
|
Chris@16
|
100
|
Chris@16
|
101 std::vector<EdgeIndex> m_rowstart;
|
Chris@16
|
102 std::vector<Vertex> m_column;
|
Chris@16
|
103
|
Chris@16
|
104 compressed_sparse_row_structure(Vertex numverts = 0)
|
Chris@16
|
105 : m_rowstart(numverts + 1, EdgeIndex(0)), m_column()
|
Chris@16
|
106 {}
|
Chris@16
|
107
|
Chris@16
|
108 // Rebuild graph from number of vertices and multi-pass unsorted list of
|
Chris@16
|
109 // edges (filtered using source_pred and mapped using global_to_local)
|
Chris@16
|
110 template <typename MultiPassInputIterator, typename GlobalToLocal, typename SourcePred>
|
Chris@16
|
111 void
|
Chris@16
|
112 assign_unsorted_multi_pass_edges(MultiPassInputIterator edge_begin,
|
Chris@16
|
113 MultiPassInputIterator edge_end,
|
Chris@16
|
114 vertices_size_type numlocalverts,
|
Chris@16
|
115 const GlobalToLocal& global_to_local,
|
Chris@16
|
116 const SourcePred& source_pred) {
|
Chris@16
|
117 m_rowstart.clear();
|
Chris@16
|
118 m_rowstart.resize(numlocalverts + 1, 0);
|
Chris@16
|
119 typedef std::pair<vertices_size_type, vertices_size_type> edge_type;
|
Chris@16
|
120 typedef boost::transform_iterator<boost::graph::detail::project1st<edge_type>, MultiPassInputIterator> source_iterator;
|
Chris@16
|
121 typedef boost::transform_iterator<boost::graph::detail::project2nd<edge_type>, MultiPassInputIterator> target_iterator;
|
Chris@16
|
122 source_iterator sources_begin(edge_begin, boost::graph::detail::project1st<edge_type>());
|
Chris@16
|
123 source_iterator sources_end(edge_end, boost::graph::detail::project1st<edge_type>());
|
Chris@16
|
124 target_iterator targets_begin(edge_begin, boost::graph::detail::project2nd<edge_type>());
|
Chris@16
|
125 target_iterator targets_end(edge_end, boost::graph::detail::project2nd<edge_type>());
|
Chris@16
|
126
|
Chris@16
|
127 boost::graph::detail::count_starts
|
Chris@16
|
128 (sources_begin, sources_end, m_rowstart.begin(), numlocalverts,
|
Chris@16
|
129 source_pred, boost::make_property_map_function(global_to_local));
|
Chris@16
|
130
|
Chris@16
|
131 m_column.resize(m_rowstart.back());
|
Chris@16
|
132 inherited_edge_properties::resize(m_rowstart.back());
|
Chris@16
|
133
|
Chris@16
|
134 boost::graph::detail::histogram_sort
|
Chris@16
|
135 (sources_begin, sources_end, m_rowstart.begin(), numlocalverts,
|
Chris@16
|
136 targets_begin, m_column.begin(),
|
Chris@16
|
137 source_pred, boost::make_property_map_function(global_to_local));
|
Chris@16
|
138 }
|
Chris@16
|
139
|
Chris@16
|
140 // Rebuild graph from number of vertices and multi-pass unsorted list of
|
Chris@16
|
141 // edges and their properties (filtered using source_pred and mapped using
|
Chris@16
|
142 // global_to_local)
|
Chris@16
|
143 template <typename MultiPassInputIterator, typename EdgePropertyIterator, typename GlobalToLocal, typename SourcePred>
|
Chris@16
|
144 void
|
Chris@16
|
145 assign_unsorted_multi_pass_edges(MultiPassInputIterator edge_begin,
|
Chris@16
|
146 MultiPassInputIterator edge_end,
|
Chris@16
|
147 EdgePropertyIterator ep_iter,
|
Chris@16
|
148 vertices_size_type numlocalverts,
|
Chris@16
|
149 const GlobalToLocal& global_to_local,
|
Chris@16
|
150 const SourcePred& source_pred) {
|
Chris@16
|
151 m_rowstart.clear();
|
Chris@16
|
152 m_rowstart.resize(numlocalverts + 1, 0);
|
Chris@16
|
153 typedef std::pair<vertices_size_type, vertices_size_type> edge_type;
|
Chris@16
|
154 typedef boost::transform_iterator<boost::graph::detail::project1st<edge_type>, MultiPassInputIterator> source_iterator;
|
Chris@16
|
155 typedef boost::transform_iterator<boost::graph::detail::project2nd<edge_type>, MultiPassInputIterator> target_iterator;
|
Chris@16
|
156 source_iterator sources_begin(edge_begin, boost::graph::detail::project1st<edge_type>());
|
Chris@16
|
157 source_iterator sources_end(edge_end, boost::graph::detail::project1st<edge_type>());
|
Chris@16
|
158 target_iterator targets_begin(edge_begin, boost::graph::detail::project2nd<edge_type>());
|
Chris@16
|
159 target_iterator targets_end(edge_end, boost::graph::detail::project2nd<edge_type>());
|
Chris@16
|
160
|
Chris@16
|
161 boost::graph::detail::count_starts
|
Chris@16
|
162 (sources_begin, sources_end, m_rowstart.begin(), numlocalverts,
|
Chris@16
|
163 source_pred, boost::make_property_map_function(global_to_local));
|
Chris@16
|
164
|
Chris@16
|
165 m_column.resize(m_rowstart.back());
|
Chris@16
|
166 inherited_edge_properties::resize(m_rowstart.back());
|
Chris@16
|
167
|
Chris@16
|
168 boost::graph::detail::histogram_sort
|
Chris@16
|
169 (sources_begin, sources_end, m_rowstart.begin(), numlocalverts,
|
Chris@16
|
170 targets_begin, m_column.begin(),
|
Chris@16
|
171 ep_iter, inherited_edge_properties::begin(),
|
Chris@16
|
172 source_pred, boost::make_property_map_function(global_to_local));
|
Chris@16
|
173 }
|
Chris@16
|
174
|
Chris@16
|
175 // Assign from number of vertices and sorted list of edges
|
Chris@16
|
176 template<typename InputIterator, typename GlobalToLocal, typename SourcePred>
|
Chris@16
|
177 void assign_from_sorted_edges(
|
Chris@16
|
178 InputIterator edge_begin, InputIterator edge_end,
|
Chris@16
|
179 const GlobalToLocal& global_to_local,
|
Chris@16
|
180 const SourcePred& source_pred,
|
Chris@16
|
181 vertices_size_type numlocalverts,
|
Chris@16
|
182 edges_size_type numedges_or_zero) {
|
Chris@16
|
183 m_column.clear();
|
Chris@16
|
184 m_column.reserve(numedges_or_zero);
|
Chris@16
|
185 m_rowstart.resize(numlocalverts + 1);
|
Chris@16
|
186 EdgeIndex current_edge = 0;
|
Chris@16
|
187 Vertex current_vertex_plus_one = 1;
|
Chris@16
|
188 m_rowstart[0] = 0;
|
Chris@16
|
189 for (InputIterator ei = edge_begin; ei != edge_end; ++ei) {
|
Chris@16
|
190 if (!source_pred(ei->first)) continue;
|
Chris@16
|
191 Vertex src = get(global_to_local, ei->first);
|
Chris@16
|
192 Vertex tgt = ei->second;
|
Chris@16
|
193 for (; current_vertex_plus_one != src + 1; ++current_vertex_plus_one)
|
Chris@16
|
194 m_rowstart[current_vertex_plus_one] = current_edge;
|
Chris@16
|
195 m_column.push_back(tgt);
|
Chris@16
|
196 ++current_edge;
|
Chris@16
|
197 }
|
Chris@16
|
198
|
Chris@16
|
199 // The remaining vertices have no edges
|
Chris@16
|
200 for (; current_vertex_plus_one != numlocalverts + 1; ++current_vertex_plus_one)
|
Chris@16
|
201 m_rowstart[current_vertex_plus_one] = current_edge;
|
Chris@16
|
202
|
Chris@16
|
203 // Default-construct properties for edges
|
Chris@16
|
204 inherited_edge_properties::resize(m_column.size());
|
Chris@16
|
205 }
|
Chris@16
|
206
|
Chris@16
|
207 // Assign from number of vertices and sorted list of edges
|
Chris@16
|
208 template<typename InputIterator, typename EdgePropertyIterator, typename GlobalToLocal, typename SourcePred>
|
Chris@16
|
209 void assign_from_sorted_edges(
|
Chris@16
|
210 InputIterator edge_begin, InputIterator edge_end,
|
Chris@16
|
211 EdgePropertyIterator ep_iter,
|
Chris@16
|
212 const GlobalToLocal& global_to_local,
|
Chris@16
|
213 const SourcePred& source_pred,
|
Chris@16
|
214 vertices_size_type numlocalverts,
|
Chris@16
|
215 edges_size_type numedges_or_zero) {
|
Chris@16
|
216 // Reserving storage in advance can save us lots of time and
|
Chris@16
|
217 // memory, but it can only be done if we have forward iterators or
|
Chris@16
|
218 // the user has supplied the number of edges.
|
Chris@16
|
219 edges_size_type numedges = numedges_or_zero;
|
Chris@16
|
220 if (numedges == 0) {
|
Chris@16
|
221 numedges = boost::graph::detail::reserve_count_for_single_pass(edge_begin, edge_end);
|
Chris@16
|
222 }
|
Chris@16
|
223 m_column.clear();
|
Chris@16
|
224 m_column.reserve(numedges_or_zero);
|
Chris@16
|
225 inherited_edge_properties::clear();
|
Chris@16
|
226 inherited_edge_properties::reserve(numedges_or_zero);
|
Chris@16
|
227 m_rowstart.resize(numlocalverts + 1);
|
Chris@16
|
228 EdgeIndex current_edge = 0;
|
Chris@16
|
229 Vertex current_vertex_plus_one = 1;
|
Chris@16
|
230 m_rowstart[0] = 0;
|
Chris@16
|
231 for (InputIterator ei = edge_begin; ei != edge_end; ++ei, ++ep_iter) {
|
Chris@16
|
232 if (!source_pred(ei->first)) continue;
|
Chris@16
|
233 Vertex src = get(global_to_local, ei->first);
|
Chris@16
|
234 Vertex tgt = ei->second;
|
Chris@16
|
235 for (; current_vertex_plus_one != src + 1; ++current_vertex_plus_one)
|
Chris@16
|
236 m_rowstart[current_vertex_plus_one] = current_edge;
|
Chris@16
|
237 m_column.push_back(tgt);
|
Chris@16
|
238 inherited_edge_properties::push_back(*ep_iter);
|
Chris@16
|
239 ++current_edge;
|
Chris@16
|
240 }
|
Chris@16
|
241
|
Chris@16
|
242 // The remaining vertices have no edges
|
Chris@16
|
243 for (; current_vertex_plus_one != numlocalverts + 1; ++current_vertex_plus_one)
|
Chris@16
|
244 m_rowstart[current_vertex_plus_one] = current_edge;
|
Chris@16
|
245 }
|
Chris@16
|
246
|
Chris@16
|
247 // Replace graph with sources and targets given, sorting them in-place, and
|
Chris@16
|
248 // using the given global-to-local property map to get local indices from
|
Chris@16
|
249 // global ones in the two arrays.
|
Chris@16
|
250 template <typename GlobalToLocal>
|
Chris@16
|
251 void assign_sources_and_targets_global(std::vector<vertex_descriptor>& sources,
|
Chris@16
|
252 std::vector<vertex_descriptor>& targets,
|
Chris@16
|
253 vertices_size_type numverts,
|
Chris@16
|
254 GlobalToLocal global_to_local) {
|
Chris@16
|
255 BOOST_ASSERT (sources.size() == targets.size());
|
Chris@16
|
256 // Do an in-place histogram sort (at least that's what I think it is) to
|
Chris@16
|
257 // sort sources and targets
|
Chris@16
|
258 m_rowstart.clear();
|
Chris@16
|
259 m_rowstart.resize(numverts + 1);
|
Chris@16
|
260 boost::graph::detail::count_starts
|
Chris@16
|
261 (sources.begin(), sources.end(), m_rowstart.begin(), numverts,
|
Chris@16
|
262 keep_all(), boost::make_property_map_function(global_to_local));
|
Chris@16
|
263 boost::graph::detail::histogram_sort_inplace
|
Chris@16
|
264 (sources.begin(), m_rowstart.begin(), numverts,
|
Chris@16
|
265 targets.begin(), boost::make_property_map_function(global_to_local));
|
Chris@16
|
266 // Now targets is the correct vector (properly sorted by source) for
|
Chris@16
|
267 // m_column
|
Chris@16
|
268 m_column.swap(targets);
|
Chris@16
|
269 inherited_edge_properties::resize(m_rowstart.back());
|
Chris@16
|
270 }
|
Chris@16
|
271
|
Chris@16
|
272 // Replace graph with sources and targets and edge properties given, sorting
|
Chris@16
|
273 // them in-place, and using the given global-to-local property map to get
|
Chris@16
|
274 // local indices from global ones in the two arrays.
|
Chris@16
|
275 template <typename GlobalToLocal>
|
Chris@16
|
276 void assign_sources_and_targets_global(std::vector<vertex_descriptor>& sources,
|
Chris@16
|
277 std::vector<vertex_descriptor>& targets,
|
Chris@16
|
278 std::vector<typename inherited_edge_properties::edge_bundled>& edge_props,
|
Chris@16
|
279 vertices_size_type numverts,
|
Chris@16
|
280 GlobalToLocal global_to_local) {
|
Chris@16
|
281 BOOST_ASSERT (sources.size() == targets.size());
|
Chris@16
|
282 BOOST_ASSERT (sources.size() == edge_props.size());
|
Chris@16
|
283 // Do an in-place histogram sort (at least that's what I think it is) to
|
Chris@16
|
284 // sort sources and targets
|
Chris@16
|
285 m_rowstart.clear();
|
Chris@16
|
286 m_rowstart.resize(numverts + 1);
|
Chris@16
|
287 boost::graph::detail::count_starts
|
Chris@16
|
288 (sources.begin(), sources.end(), m_rowstart.begin(), numverts,
|
Chris@16
|
289 keep_all(), boost::make_property_map_function(global_to_local));
|
Chris@16
|
290 boost::graph::detail::histogram_sort_inplace
|
Chris@16
|
291 (sources.begin(), m_rowstart.begin(), numverts,
|
Chris@16
|
292 targets.begin(), edge_props.begin(),
|
Chris@16
|
293 boost::make_property_map_function(global_to_local));
|
Chris@16
|
294 // Now targets is the correct vector (properly sorted by source) for
|
Chris@16
|
295 // m_column, and edge_props for m_edge_properties
|
Chris@16
|
296 m_column.swap(targets);
|
Chris@16
|
297 this->m_edge_properties.swap(edge_props);
|
Chris@16
|
298 }
|
Chris@16
|
299
|
Chris@16
|
300 // From any graph (slow and uses a lot of memory)
|
Chris@16
|
301 // Requires IncidenceGraph and a vertex index map
|
Chris@16
|
302 // Internal helper function
|
Chris@16
|
303 // Note that numedges must be doubled for undirected source graphs
|
Chris@16
|
304 template<typename Graph, typename VertexIndexMap>
|
Chris@16
|
305 void
|
Chris@16
|
306 assign(const Graph& g, const VertexIndexMap& vi,
|
Chris@16
|
307 vertices_size_type numverts, edges_size_type numedges)
|
Chris@16
|
308 {
|
Chris@16
|
309 m_rowstart.resize(numverts + 1);
|
Chris@16
|
310 m_column.resize(numedges);
|
Chris@16
|
311 inherited_edge_properties::resize(numedges);
|
Chris@16
|
312 EdgeIndex current_edge = 0;
|
Chris@16
|
313 typedef typename boost::graph_traits<Graph>::vertex_descriptor g_vertex;
|
Chris@16
|
314 typedef typename boost::graph_traits<Graph>::out_edge_iterator
|
Chris@16
|
315 g_out_edge_iter;
|
Chris@16
|
316
|
Chris@16
|
317 std::vector<g_vertex> ordered_verts_of_g(numverts);
|
Chris@16
|
318 BGL_FORALL_VERTICES_T(v, g, Graph) {
|
Chris@16
|
319 ordered_verts_of_g[get(vertex_index, g, v)] = v;
|
Chris@16
|
320 }
|
Chris@16
|
321 for (Vertex i = 0; i != numverts; ++i) {
|
Chris@16
|
322 m_rowstart[i] = current_edge;
|
Chris@16
|
323 g_vertex v = ordered_verts_of_g[i];
|
Chris@16
|
324 g_out_edge_iter ei, ei_end;
|
Chris@16
|
325 for (boost::tie(ei, ei_end) = out_edges(v, g); ei != ei_end; ++ei) {
|
Chris@16
|
326 m_column[current_edge++] = get(vi, target(*ei, g));
|
Chris@16
|
327 }
|
Chris@16
|
328 }
|
Chris@16
|
329 m_rowstart[numverts] = current_edge;
|
Chris@16
|
330 }
|
Chris@16
|
331
|
Chris@16
|
332 // Add edges from a sorted (smallest sources first) range of pairs and edge
|
Chris@16
|
333 // properties
|
Chris@16
|
334 template <typename BidirectionalIteratorOrig, typename EPIterOrig,
|
Chris@16
|
335 typename GlobalToLocal>
|
Chris@16
|
336 void
|
Chris@16
|
337 add_edges_sorted_internal(
|
Chris@16
|
338 BidirectionalIteratorOrig first_sorted,
|
Chris@16
|
339 BidirectionalIteratorOrig last_sorted,
|
Chris@16
|
340 EPIterOrig ep_iter_sorted,
|
Chris@16
|
341 const GlobalToLocal& global_to_local) {
|
Chris@16
|
342 typedef boost::reverse_iterator<BidirectionalIteratorOrig> BidirectionalIterator;
|
Chris@16
|
343 typedef boost::reverse_iterator<EPIterOrig> EPIter;
|
Chris@16
|
344 // Flip sequence
|
Chris@16
|
345 BidirectionalIterator first(last_sorted);
|
Chris@16
|
346 BidirectionalIterator last(first_sorted);
|
Chris@16
|
347 typedef Vertex vertex_num;
|
Chris@16
|
348 typedef EdgeIndex edge_num;
|
Chris@16
|
349 edge_num new_edge_count = std::distance(first, last);
|
Chris@16
|
350
|
Chris@16
|
351 EPIter ep_iter(ep_iter_sorted);
|
Chris@16
|
352 std::advance(ep_iter, -(std::ptrdiff_t)new_edge_count);
|
Chris@16
|
353 edge_num edges_added_before_i = new_edge_count; // Count increment to add to rowstarts
|
Chris@16
|
354 m_column.resize(m_column.size() + new_edge_count);
|
Chris@16
|
355 inherited_edge_properties::resize(inherited_edge_properties::size() + new_edge_count);
|
Chris@16
|
356 BidirectionalIterator current_new_edge = first, prev_new_edge = first;
|
Chris@16
|
357 EPIter current_new_edge_prop = ep_iter;
|
Chris@16
|
358 for (vertex_num i_plus_1 = m_rowstart.size() - 1; i_plus_1 > 0; --i_plus_1) {
|
Chris@16
|
359 vertex_num i = i_plus_1 - 1;
|
Chris@16
|
360 prev_new_edge = current_new_edge;
|
Chris@16
|
361 // edges_added_to_this_vertex = #mbrs of new_edges with first == i
|
Chris@16
|
362 edge_num edges_added_to_this_vertex = 0;
|
Chris@16
|
363 while (current_new_edge != last) {
|
Chris@16
|
364 if (get(global_to_local, current_new_edge->first) != i) break;
|
Chris@16
|
365 ++current_new_edge;
|
Chris@16
|
366 ++current_new_edge_prop;
|
Chris@16
|
367 ++edges_added_to_this_vertex;
|
Chris@16
|
368 }
|
Chris@16
|
369 edges_added_before_i -= edges_added_to_this_vertex;
|
Chris@16
|
370 // Invariant: edges_added_before_i = #mbrs of new_edges with first < i
|
Chris@16
|
371 edge_num old_rowstart = m_rowstart[i];
|
Chris@16
|
372 edge_num new_rowstart = m_rowstart[i] + edges_added_before_i;
|
Chris@16
|
373 edge_num old_degree = m_rowstart[i + 1] - m_rowstart[i];
|
Chris@16
|
374 edge_num new_degree = old_degree + edges_added_to_this_vertex;
|
Chris@16
|
375 // Move old edges forward (by #new_edges before this i) to make room
|
Chris@16
|
376 // new_rowstart > old_rowstart, so use copy_backwards
|
Chris@16
|
377 if (old_rowstart != new_rowstart) {
|
Chris@16
|
378 std::copy_backward(m_column.begin() + old_rowstart,
|
Chris@16
|
379 m_column.begin() + old_rowstart + old_degree,
|
Chris@16
|
380 m_column.begin() + new_rowstart + old_degree);
|
Chris@16
|
381 inherited_edge_properties::move_range(old_rowstart, old_rowstart + old_degree, new_rowstart);
|
Chris@16
|
382 }
|
Chris@16
|
383 // Add new edges (reversed because current_new_edge is a
|
Chris@16
|
384 // const_reverse_iterator)
|
Chris@16
|
385 BidirectionalIterator temp = current_new_edge;
|
Chris@16
|
386 EPIter temp_prop = current_new_edge_prop;
|
Chris@16
|
387 for (; temp != prev_new_edge; ++old_degree) {
|
Chris@16
|
388 --temp;
|
Chris@16
|
389 --temp_prop;
|
Chris@16
|
390 m_column[new_rowstart + old_degree] = temp->second;
|
Chris@16
|
391 inherited_edge_properties::write_by_index(new_rowstart + old_degree, *temp_prop);
|
Chris@16
|
392 }
|
Chris@16
|
393 m_rowstart[i + 1] = new_rowstart + new_degree;
|
Chris@16
|
394 if (edges_added_before_i == 0) break; // No more edges inserted before this point
|
Chris@16
|
395 // m_rowstart[i] will be fixed up on the next iteration (to avoid
|
Chris@16
|
396 // changing the degree of vertex i - 1); the last iteration never changes
|
Chris@16
|
397 // it (either because of the condition of the break or because
|
Chris@16
|
398 // m_rowstart[0] is always 0)
|
Chris@16
|
399 }
|
Chris@16
|
400 }
|
Chris@16
|
401
|
Chris@16
|
402 };
|
Chris@16
|
403
|
Chris@16
|
404 template<typename Vertex, typename EdgeIndex>
|
Chris@16
|
405 class csr_edge_descriptor
|
Chris@16
|
406 {
|
Chris@16
|
407 public:
|
Chris@16
|
408 Vertex src;
|
Chris@16
|
409 EdgeIndex idx;
|
Chris@16
|
410
|
Chris@16
|
411 csr_edge_descriptor(Vertex src, EdgeIndex idx): src(src), idx(idx) {}
|
Chris@16
|
412 csr_edge_descriptor(): src(0), idx(0) {}
|
Chris@16
|
413
|
Chris@16
|
414 bool operator==(const csr_edge_descriptor& e) const {return idx == e.idx;}
|
Chris@16
|
415 bool operator!=(const csr_edge_descriptor& e) const {return idx != e.idx;}
|
Chris@16
|
416 bool operator<(const csr_edge_descriptor& e) const {return idx < e.idx;}
|
Chris@16
|
417 bool operator>(const csr_edge_descriptor& e) const {return idx > e.idx;}
|
Chris@16
|
418 bool operator<=(const csr_edge_descriptor& e) const {return idx <= e.idx;}
|
Chris@16
|
419 bool operator>=(const csr_edge_descriptor& e) const {return idx >= e.idx;}
|
Chris@16
|
420
|
Chris@16
|
421 template<typename Archiver>
|
Chris@16
|
422 void serialize(Archiver& ar, const unsigned int /*version*/)
|
Chris@16
|
423 {
|
Chris@16
|
424 ar & src & idx;
|
Chris@16
|
425 }
|
Chris@16
|
426 };
|
Chris@16
|
427
|
Chris@16
|
428 // Common out edge and edge iterators
|
Chris@16
|
429 template<typename CSRGraph>
|
Chris@16
|
430 class csr_out_edge_iterator
|
Chris@16
|
431 : public iterator_facade<csr_out_edge_iterator<CSRGraph>,
|
Chris@16
|
432 typename CSRGraph::edge_descriptor,
|
Chris@16
|
433 std::random_access_iterator_tag,
|
Chris@16
|
434 const typename CSRGraph::edge_descriptor&,
|
Chris@16
|
435 typename int_t<CHAR_BIT * sizeof(typename CSRGraph::edges_size_type)>::fast>
|
Chris@16
|
436 {
|
Chris@16
|
437 public:
|
Chris@16
|
438 typedef typename CSRGraph::edges_size_type EdgeIndex;
|
Chris@16
|
439 typedef typename CSRGraph::edge_descriptor edge_descriptor;
|
Chris@16
|
440 typedef typename int_t<CHAR_BIT * sizeof(EdgeIndex)>::fast difference_type;
|
Chris@16
|
441
|
Chris@16
|
442 csr_out_edge_iterator() {}
|
Chris@16
|
443 // Implicit copy constructor OK
|
Chris@16
|
444 explicit csr_out_edge_iterator(edge_descriptor edge) : m_edge(edge) { }
|
Chris@16
|
445
|
Chris@16
|
446 public: // GCC 4.2.1 doesn't like the private-and-friend thing
|
Chris@16
|
447 // iterator_facade requirements
|
Chris@16
|
448 const edge_descriptor& dereference() const { return m_edge; }
|
Chris@16
|
449
|
Chris@16
|
450 bool equal(const csr_out_edge_iterator& other) const
|
Chris@16
|
451 { return m_edge == other.m_edge; }
|
Chris@16
|
452
|
Chris@16
|
453 void increment() { ++m_edge.idx; }
|
Chris@16
|
454 void decrement() { --m_edge.idx; }
|
Chris@16
|
455 void advance(difference_type n) { m_edge.idx += n; }
|
Chris@16
|
456
|
Chris@16
|
457 difference_type distance_to(const csr_out_edge_iterator& other) const
|
Chris@16
|
458 { return other.m_edge.idx - m_edge.idx; }
|
Chris@16
|
459
|
Chris@16
|
460 edge_descriptor m_edge;
|
Chris@16
|
461
|
Chris@16
|
462 friend class iterator_core_access;
|
Chris@16
|
463 };
|
Chris@16
|
464
|
Chris@16
|
465 template<typename CSRGraph>
|
Chris@16
|
466 class csr_edge_iterator
|
Chris@16
|
467 : public iterator_facade<csr_edge_iterator<CSRGraph>,
|
Chris@16
|
468 typename CSRGraph::edge_descriptor,
|
Chris@16
|
469 boost::forward_traversal_tag,
|
Chris@16
|
470 typename CSRGraph::edge_descriptor>
|
Chris@16
|
471 {
|
Chris@16
|
472 private:
|
Chris@16
|
473 typedef typename CSRGraph::edge_descriptor edge_descriptor;
|
Chris@16
|
474 typedef typename CSRGraph::edges_size_type EdgeIndex;
|
Chris@16
|
475
|
Chris@16
|
476 public:
|
Chris@16
|
477 csr_edge_iterator() : rowstart_array(0), current_edge(), end_of_this_vertex(0), total_num_edges(0) {}
|
Chris@16
|
478
|
Chris@16
|
479 csr_edge_iterator(const CSRGraph& graph,
|
Chris@16
|
480 edge_descriptor current_edge,
|
Chris@16
|
481 EdgeIndex end_of_this_vertex)
|
Chris@16
|
482 : rowstart_array(&graph.m_forward.m_rowstart[0]),
|
Chris@16
|
483 current_edge(current_edge),
|
Chris@16
|
484 end_of_this_vertex(end_of_this_vertex),
|
Chris@16
|
485 total_num_edges(num_edges(graph)) {}
|
Chris@16
|
486
|
Chris@16
|
487 public: // See above
|
Chris@16
|
488 friend class boost::iterator_core_access;
|
Chris@16
|
489
|
Chris@16
|
490 edge_descriptor dereference() const {return current_edge;}
|
Chris@16
|
491
|
Chris@16
|
492 bool equal(const csr_edge_iterator& o) const {
|
Chris@16
|
493 return current_edge == o.current_edge;
|
Chris@16
|
494 }
|
Chris@16
|
495
|
Chris@16
|
496 void increment() {
|
Chris@16
|
497 ++current_edge.idx;
|
Chris@16
|
498 if (current_edge.idx == total_num_edges) return;
|
Chris@16
|
499 while (current_edge.idx == end_of_this_vertex) {
|
Chris@16
|
500 ++current_edge.src;
|
Chris@16
|
501 end_of_this_vertex = rowstart_array[current_edge.src + 1];
|
Chris@16
|
502 }
|
Chris@16
|
503 }
|
Chris@16
|
504
|
Chris@16
|
505 const EdgeIndex* rowstart_array;
|
Chris@16
|
506 edge_descriptor current_edge;
|
Chris@16
|
507 EdgeIndex end_of_this_vertex;
|
Chris@16
|
508 EdgeIndex total_num_edges;
|
Chris@16
|
509 };
|
Chris@16
|
510
|
Chris@16
|
511 // Only for bidirectional graphs
|
Chris@16
|
512 template<typename CSRGraph>
|
Chris@16
|
513 class csr_in_edge_iterator
|
Chris@16
|
514 : public iterator_facade<csr_in_edge_iterator<CSRGraph>,
|
Chris@16
|
515 typename CSRGraph::edge_descriptor,
|
Chris@16
|
516 boost::forward_traversal_tag,
|
Chris@16
|
517 typename CSRGraph::edge_descriptor>
|
Chris@16
|
518 {
|
Chris@16
|
519 public:
|
Chris@16
|
520 typedef typename CSRGraph::edges_size_type EdgeIndex;
|
Chris@16
|
521 typedef typename CSRGraph::edge_descriptor edge_descriptor;
|
Chris@16
|
522
|
Chris@16
|
523 csr_in_edge_iterator(): m_graph(0) {}
|
Chris@16
|
524 // Implicit copy constructor OK
|
Chris@16
|
525 csr_in_edge_iterator(const CSRGraph& graph,
|
Chris@16
|
526 EdgeIndex index_in_backward_graph)
|
Chris@16
|
527 : m_index_in_backward_graph(index_in_backward_graph), m_graph(&graph) {}
|
Chris@16
|
528
|
Chris@16
|
529 public: // See above
|
Chris@16
|
530 // iterator_facade requirements
|
Chris@16
|
531 edge_descriptor dereference() const {
|
Chris@16
|
532 return edge_descriptor(
|
Chris@16
|
533 m_graph->m_backward.m_column[m_index_in_backward_graph],
|
Chris@16
|
534 m_graph->m_backward.m_edge_properties[m_index_in_backward_graph]);
|
Chris@16
|
535 }
|
Chris@16
|
536
|
Chris@16
|
537 bool equal(const csr_in_edge_iterator& other) const
|
Chris@16
|
538 { return m_index_in_backward_graph == other.m_index_in_backward_graph; }
|
Chris@16
|
539
|
Chris@16
|
540 void increment() { ++m_index_in_backward_graph; }
|
Chris@16
|
541 void decrement() { --m_index_in_backward_graph; }
|
Chris@16
|
542 void advance(std::ptrdiff_t n) { m_index_in_backward_graph += n; }
|
Chris@16
|
543
|
Chris@16
|
544 std::ptrdiff_t distance_to(const csr_in_edge_iterator& other) const
|
Chris@16
|
545 { return other.m_index_in_backward_graph - m_index_in_backward_graph; }
|
Chris@16
|
546
|
Chris@16
|
547 EdgeIndex m_index_in_backward_graph;
|
Chris@16
|
548 const CSRGraph* m_graph;
|
Chris@16
|
549
|
Chris@16
|
550 friend class iterator_core_access;
|
Chris@16
|
551 };
|
Chris@16
|
552
|
Chris@16
|
553 template <typename A, typename B>
|
Chris@16
|
554 struct transpose_pair {
|
Chris@16
|
555 typedef std::pair<B, A> result_type;
|
Chris@16
|
556 result_type operator()(const std::pair<A, B>& p) const {
|
Chris@16
|
557 return result_type(p.second, p.first);
|
Chris@16
|
558 }
|
Chris@16
|
559 };
|
Chris@16
|
560
|
Chris@16
|
561 template <typename Iter>
|
Chris@16
|
562 struct transpose_iterator_gen {
|
Chris@16
|
563 typedef typename std::iterator_traits<Iter>::value_type vt;
|
Chris@16
|
564 typedef typename vt::first_type first_type;
|
Chris@16
|
565 typedef typename vt::second_type second_type;
|
Chris@16
|
566 typedef transpose_pair<first_type, second_type> transpose;
|
Chris@16
|
567 typedef boost::transform_iterator<transpose, Iter> type;
|
Chris@16
|
568 static type make(Iter it) {
|
Chris@16
|
569 return type(it, transpose());
|
Chris@16
|
570 }
|
Chris@16
|
571 };
|
Chris@16
|
572
|
Chris@16
|
573 template <typename Iter>
|
Chris@16
|
574 typename transpose_iterator_gen<Iter>::type transpose_edges(Iter i) {
|
Chris@16
|
575 return transpose_iterator_gen<Iter>::make(i);
|
Chris@16
|
576 }
|
Chris@16
|
577
|
Chris@16
|
578 template<typename GraphT, typename VertexIndexMap>
|
Chris@16
|
579 class edge_to_index_pair
|
Chris@16
|
580 {
|
Chris@16
|
581 typedef typename boost::graph_traits<GraphT>::vertices_size_type
|
Chris@16
|
582 vertices_size_type;
|
Chris@16
|
583 typedef typename boost::graph_traits<GraphT>::edge_descriptor edge_descriptor;
|
Chris@16
|
584
|
Chris@16
|
585 public:
|
Chris@16
|
586 typedef std::pair<vertices_size_type, vertices_size_type> result_type;
|
Chris@16
|
587
|
Chris@16
|
588 edge_to_index_pair() : g(0), index() { }
|
Chris@16
|
589 edge_to_index_pair(const GraphT& g, const VertexIndexMap& index)
|
Chris@16
|
590 : g(&g), index(index)
|
Chris@16
|
591 { }
|
Chris@16
|
592
|
Chris@16
|
593 result_type operator()(edge_descriptor e) const
|
Chris@16
|
594 {
|
Chris@16
|
595 return result_type(get(index, source(e, *g)), get(index, target(e, *g)));
|
Chris@16
|
596 }
|
Chris@16
|
597
|
Chris@16
|
598 private:
|
Chris@16
|
599 const GraphT* g;
|
Chris@16
|
600 VertexIndexMap index;
|
Chris@16
|
601 };
|
Chris@16
|
602
|
Chris@16
|
603 template<typename GraphT, typename VertexIndexMap>
|
Chris@16
|
604 edge_to_index_pair<GraphT, VertexIndexMap>
|
Chris@16
|
605 make_edge_to_index_pair(const GraphT& g, const VertexIndexMap& index)
|
Chris@16
|
606 {
|
Chris@16
|
607 return edge_to_index_pair<GraphT, VertexIndexMap>(g, index);
|
Chris@16
|
608 }
|
Chris@16
|
609
|
Chris@16
|
610 template<typename GraphT>
|
Chris@16
|
611 edge_to_index_pair
|
Chris@16
|
612 <GraphT,
|
Chris@16
|
613 typename boost::property_map<GraphT,boost::vertex_index_t>::const_type>
|
Chris@16
|
614 make_edge_to_index_pair(const GraphT& g)
|
Chris@16
|
615 {
|
Chris@16
|
616 typedef typename boost::property_map<GraphT,
|
Chris@16
|
617 boost::vertex_index_t>::const_type
|
Chris@16
|
618 VertexIndexMap;
|
Chris@16
|
619 return edge_to_index_pair<GraphT, VertexIndexMap>(g,
|
Chris@16
|
620 get(boost::vertex_index,
|
Chris@16
|
621 g));
|
Chris@16
|
622 }
|
Chris@16
|
623
|
Chris@16
|
624 template<typename GraphT, typename VertexIndexMap, typename Iter>
|
Chris@16
|
625 boost::transform_iterator<edge_to_index_pair<GraphT, VertexIndexMap>, Iter>
|
Chris@16
|
626 make_edge_to_index_pair_iter(const GraphT& g, const VertexIndexMap& index,
|
Chris@16
|
627 Iter it) {
|
Chris@16
|
628 return boost::transform_iterator<edge_to_index_pair<GraphT, VertexIndexMap>, Iter>(it, edge_to_index_pair<GraphT, VertexIndexMap>(g, index));
|
Chris@16
|
629 }
|
Chris@16
|
630
|
Chris@16
|
631 } // namespace detail
|
Chris@16
|
632
|
Chris@16
|
633 template<typename Vertex, typename EdgeIndex>
|
Chris@16
|
634 struct hash<detail::csr_edge_descriptor<Vertex, EdgeIndex> >
|
Chris@16
|
635 {
|
Chris@16
|
636 std::size_t operator()
|
Chris@16
|
637 (detail::csr_edge_descriptor<Vertex, EdgeIndex> const& x) const
|
Chris@16
|
638 {
|
Chris@16
|
639 std::size_t hash = hash_value(x.src);
|
Chris@16
|
640 hash_combine(hash, x.idx);
|
Chris@16
|
641 return hash;
|
Chris@16
|
642 }
|
Chris@16
|
643 };
|
Chris@16
|
644
|
Chris@16
|
645 } // namespace boost
|
Chris@16
|
646
|
Chris@16
|
647 #endif // BOOST_GRAPH_COMPRESSED_SPARSE_ROW_STRUCT_HPP
|