compressed_sparse_row_struct.hpp 27 KB

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