annotate DEPENDENCIES/generic/include/boost/graph/detail/compressed_sparse_row_struct.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents 2665513ce2d3
children
rev   line source
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