1 // Copyright 2005-2006 The Trustees of Indiana University.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
7 // Authors: Jeremiah Willcock
11 // Compressed sparse row graph type
13 #ifndef BOOST_GRAPH_COMPRESSED_SPARSE_ROW_GRAPH_HPP
14 #define BOOST_GRAPH_COMPRESSED_SPARSE_ROW_GRAPH_HPP
21 #include <boost/graph/graph_traits.hpp>
22 #include <boost/graph/properties.hpp>
23 #include <boost/graph/detail/indexed_properties.hpp>
24 #include <boost/iterator/counting_iterator.hpp>
25 #include <boost/integer.hpp>
26 #include <boost/iterator/iterator_facade.hpp>
27 #include <boost/mpl/if.hpp>
28 #include <boost/graph/graph_selectors.hpp>
29 #include <boost/static_assert.hpp>
31 #ifdef BOOST_GRAPH_NO_BUNDLED_PROPERTIES
32 # error The Compressed Sparse Row graph only supports bundled properties.
33 # error You will need a compiler that conforms better to the C++ standard.
38 // A tag type indicating that the graph in question is a compressed
39 // sparse row graph. This is an internal detail of the BGL.
42 /****************************************************************************
43 * Local helper macros to reduce typing and clutter later on. *
44 ****************************************************************************/
45 #define BOOST_CSR_GRAPH_TEMPLATE_PARMS \
46 typename Directed, typename VertexProperty, typename EdgeProperty, \
47 typename GraphProperty, typename Vertex, typename EdgeIndex
48 #define BOOST_CSR_GRAPH_TYPE \
49 compressed_sparse_row_graph<Directed, VertexProperty, EdgeProperty, \
50 GraphProperty, Vertex, EdgeIndex>
52 // Forward declaration of CSR edge descriptor type, needed to pass to
53 // indexed_edge_properties.
54 template<typename Vertex, typename EdgeIndex>
55 class csr_edge_descriptor;
57 /** Compressed sparse row graph.
59 * Vertex and EdgeIndex should be unsigned integral types and should
60 * specialize numeric_limits.
62 template<typename Directed = directedS,
63 typename VertexProperty = void,
64 typename EdgeProperty = void,
65 typename GraphProperty = no_property,
66 typename Vertex = std::size_t,
67 typename EdgeIndex = Vertex>
68 class compressed_sparse_row_graph
69 : public detail::indexed_vertex_properties<BOOST_CSR_GRAPH_TYPE, VertexProperty,
71 public detail::indexed_edge_properties<BOOST_CSR_GRAPH_TYPE, EdgeProperty,
72 csr_edge_descriptor<Vertex,
76 typedef detail::indexed_vertex_properties<compressed_sparse_row_graph,
77 VertexProperty, Vertex>
78 inherited_vertex_properties;
80 typedef detail::indexed_edge_properties<BOOST_CSR_GRAPH_TYPE, EdgeProperty,
81 csr_edge_descriptor<Vertex, EdgeIndex> >
82 inherited_edge_properties;
86 typedef GraphProperty graph_property_type;
89 template<typename InputIterator>
91 maybe_reserve_edge_list_storage(InputIterator, InputIterator,
92 std::input_iterator_tag)
94 // Do nothing: we have no idea how much storage to reserve.
97 template<typename InputIterator>
99 maybe_reserve_edge_list_storage(InputIterator first, InputIterator last,
100 std::forward_iterator_tag)
103 typename std::iterator_traits<InputIterator>::difference_type n =
104 distance(first, last);
106 inherited_edge_properties::reserve(n);
110 /* At this time, the compressed sparse row graph can only be used to
111 * create a directed graph. In the future, bidirectional and
112 * undirected CSR graphs will also be supported.
114 BOOST_STATIC_ASSERT((is_same<Directed, directedS>::value));
116 // Concept requirements:
118 typedef Vertex vertex_descriptor;
119 typedef csr_edge_descriptor<Vertex, EdgeIndex> edge_descriptor;
120 typedef directed_tag directed_category;
121 typedef allow_parallel_edge_tag edge_parallel_category;
123 class traversal_category: public incidence_graph_tag,
124 public adjacency_graph_tag,
125 public vertex_list_graph_tag,
126 public edge_list_graph_tag {};
128 static vertex_descriptor null_vertex() { return vertex_descriptor(-1); }
130 // For VertexListGraph
131 typedef counting_iterator<Vertex> vertex_iterator;
132 typedef Vertex vertices_size_type;
135 typedef EdgeIndex edges_size_type;
137 // For IncidenceGraph
138 class out_edge_iterator;
139 typedef EdgeIndex degree_size_type;
141 // For AdjacencyGraph
142 typedef typename std::vector<Vertex>::const_iterator adjacency_iterator;
147 // For BidirectionalGraph (not implemented)
148 typedef void in_edge_iterator;
151 typedef csr_graph_tag graph_tag;
155 // Default constructor: an empty graph.
156 compressed_sparse_row_graph()
157 : m_rowstart(1, EdgeIndex(0)), m_column(0), m_property(),
160 // From number of vertices and sorted list of edges
161 template<typename InputIterator>
162 compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end,
163 vertices_size_type numverts,
164 edges_size_type numedges = 0,
165 const GraphProperty& prop = GraphProperty())
166 : inherited_vertex_properties(numverts), m_rowstart(numverts + 1),
167 m_column(0), m_property(prop), m_last_source(numverts)
169 // Reserving storage in advance can save us lots of time and
170 // memory, but it can only be done if we have forward iterators or
171 // the user has supplied the number of edges.
173 typedef typename std::iterator_traits<InputIterator>::iterator_category
175 maybe_reserve_edge_list_storage(edge_begin, edge_end, category());
177 m_column.reserve(numedges);
180 EdgeIndex current_edge = 0;
181 Vertex current_vertex_plus_one = 1;
183 for (InputIterator ei = edge_begin; ei != edge_end; ++ei) {
184 Vertex src = ei->first;
185 Vertex tgt = ei->second;
186 for (; current_vertex_plus_one != src + 1; ++current_vertex_plus_one)
187 m_rowstart[current_vertex_plus_one] = current_edge;
188 m_column.push_back(tgt);
192 // The remaining vertices have no edges
193 for (; current_vertex_plus_one != numverts + 1; ++current_vertex_plus_one)
194 m_rowstart[current_vertex_plus_one] = current_edge;
196 // Default-construct properties for edges
197 inherited_edge_properties::resize(m_column.size());
200 // From number of vertices and sorted list of edges
201 template<typename InputIterator, typename EdgePropertyIterator>
202 compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end,
203 EdgePropertyIterator ep_iter,
204 vertices_size_type numverts,
205 edges_size_type numedges = 0,
206 const GraphProperty& prop = GraphProperty())
207 : inherited_vertex_properties(numverts), m_rowstart(numverts + 1),
208 m_column(0), m_property(prop), m_last_source(numverts)
210 // Reserving storage in advance can save us lots of time and
211 // memory, but it can only be done if we have forward iterators or
212 // the user has supplied the number of edges.
214 typedef typename std::iterator_traits<InputIterator>::iterator_category
216 maybe_reserve_edge_list_storage(edge_begin, edge_end, category());
218 m_column.reserve(numedges);
221 EdgeIndex current_edge = 0;
222 Vertex current_vertex_plus_one = 1;
224 for (InputIterator ei = edge_begin; ei != edge_end; ++ei, ++ep_iter) {
225 Vertex src = ei->first;
226 Vertex tgt = ei->second;
227 for (; current_vertex_plus_one != src + 1; ++current_vertex_plus_one)
228 m_rowstart[current_vertex_plus_one] = current_edge;
229 m_column.push_back(tgt);
230 inherited_edge_properties::push_back(*ep_iter);
234 // The remaining vertices have no edges
235 for (; current_vertex_plus_one != numverts + 1; ++current_vertex_plus_one)
236 m_rowstart[current_vertex_plus_one] = current_edge;
239 // Requires IncidenceGraph, a vertex index map, and a vertex(n, g) function
240 template<typename Graph, typename VertexIndexMap>
241 compressed_sparse_row_graph(const Graph& g, const VertexIndexMap& vi,
242 vertices_size_type numverts,
243 edges_size_type numedges)
244 : m_property(), m_last_source(0)
246 assign(g, vi, numverts, numedges);
249 // Requires VertexListGraph and EdgeListGraph
250 template<typename Graph, typename VertexIndexMap>
251 compressed_sparse_row_graph(const Graph& g, const VertexIndexMap& vi)
252 : m_property(), m_last_source(0)
254 assign(g, vi, num_vertices(g), num_edges(g));
257 // Requires vertex index map plus requirements of previous constructor
258 template<typename Graph>
259 explicit compressed_sparse_row_graph(const Graph& g)
260 : m_property(), m_last_source(0)
262 assign(g, get(vertex_index, g), num_vertices(g), num_edges(g));
265 // From any graph (slow and uses a lot of memory)
266 // Requires IncidenceGraph, a vertex index map, and a vertex(n, g) function
267 // Internal helper function
268 template<typename Graph, typename VertexIndexMap>
270 assign(const Graph& g, const VertexIndexMap& vi,
271 vertices_size_type numverts, edges_size_type numedges)
273 inherited_vertex_properties::resize(numverts);
274 m_rowstart.resize(numverts + 1);
275 m_column.resize(numedges);
276 EdgeIndex current_edge = 0;
277 typedef typename boost::graph_traits<Graph>::vertex_descriptor g_vertex;
278 typedef typename boost::graph_traits<Graph>::edge_descriptor g_edge;
279 typedef typename boost::graph_traits<Graph>::out_edge_iterator
282 for (Vertex i = 0; i != numverts; ++i) {
283 m_rowstart[i] = current_edge;
284 g_vertex v = vertex(i, g);
285 EdgeIndex num_edges_before_this_vertex = current_edge;
286 g_out_edge_iter ei, ei_end;
287 for (tie(ei, ei_end) = out_edges(v, g); ei != ei_end; ++ei) {
288 m_column[current_edge++] = get(vi, target(*ei, g));
290 std::sort(m_column.begin() + num_edges_before_this_vertex,
291 m_column.begin() + current_edge);
293 m_rowstart[numverts] = current_edge;
294 m_last_source = numverts;
297 // Requires the above, plus VertexListGraph and EdgeListGraph
298 template<typename Graph, typename VertexIndexMap>
299 void assign(const Graph& g, const VertexIndexMap& vi)
301 assign(g, vi, num_vertices(g), num_edges(g));
304 // Requires the above, plus a vertex_index map.
305 template<typename Graph>
306 void assign(const Graph& g)
308 assign(g, get(vertex_index, g), num_vertices(g), num_edges(g));
311 using inherited_vertex_properties::operator[];
312 using inherited_edge_properties::operator[];
314 // private: non-portable, requires friend templates
315 inherited_vertex_properties& vertex_properties() {return *this;}
316 const inherited_vertex_properties& vertex_properties() const {return *this;}
317 inherited_edge_properties& edge_properties() { return *this; }
318 const inherited_edge_properties& edge_properties() const { return *this; }
320 std::vector<EdgeIndex> m_rowstart;
321 std::vector<Vertex> m_column;
322 GraphProperty m_property;
323 Vertex m_last_source; // Last source of added edge, plus one
326 template<typename Vertex, typename EdgeIndex>
327 class csr_edge_descriptor
333 csr_edge_descriptor(Vertex src, EdgeIndex idx): src(src), idx(idx) {}
334 csr_edge_descriptor(): src(0), idx(0) {}
336 bool operator==(const csr_edge_descriptor& e) const {return idx == e.idx;}
337 bool operator!=(const csr_edge_descriptor& e) const {return idx != e.idx;}
338 bool operator<(const csr_edge_descriptor& e) const {return idx < e.idx;}
339 bool operator>(const csr_edge_descriptor& e) const {return idx > e.idx;}
340 bool operator<=(const csr_edge_descriptor& e) const {return idx <= e.idx;}
341 bool operator>=(const csr_edge_descriptor& e) const {return idx >= e.idx;}
344 // Construction functions
345 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
347 add_vertex(BOOST_CSR_GRAPH_TYPE& g) {
348 Vertex old_num_verts_plus_one = g.m_rowstart.size();
349 g.m_rowstart.push_back(EdgeIndex(0));
350 return old_num_verts_plus_one - 1;
353 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
355 add_vertices(typename BOOST_CSR_GRAPH_TYPE::vertices_size_type count, BOOST_CSR_GRAPH_TYPE& g) {
356 Vertex old_num_verts_plus_one = g.m_rowstart.size();
357 g.m_rowstart.resize(old_num_verts_plus_one + count, EdgeIndex(0));
358 return old_num_verts_plus_one - 1;
361 // This function requires that (src, tgt) be lexicographically at least as
362 // large as the largest edge in the graph so far
363 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
364 inline typename BOOST_CSR_GRAPH_TYPE::edge_descriptor
365 add_edge(Vertex src, Vertex tgt, BOOST_CSR_GRAPH_TYPE& g) {
366 assert ((g.m_last_source == 0 || src >= g.m_last_source - 1) &&
367 src < num_vertices(g));
368 EdgeIndex num_edges_orig = g.m_column.size();
369 for (; g.m_last_source <= src; ++g.m_last_source)
370 g.m_rowstart[g.m_last_source] = num_edges_orig;
371 g.m_rowstart[src + 1] = num_edges_orig + 1;
372 g.m_column.push_back(tgt);
373 typedef typename BOOST_CSR_GRAPH_TYPE::edge_push_back_type push_back_type;
374 g.edge_properties().push_back(push_back_type());
375 return typename BOOST_CSR_GRAPH_TYPE::edge_descriptor(src, num_edges_orig);
378 // This function requires that (src, tgt) be lexicographically at least as
379 // large as the largest edge in the graph so far
380 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
381 inline typename BOOST_CSR_GRAPH_TYPE::edge_descriptor
382 add_edge(Vertex src, Vertex tgt,
383 typename BOOST_CSR_GRAPH_TYPE::edge_bundled const& p,
384 BOOST_CSR_GRAPH_TYPE& g) {
385 assert ((g.m_last_source == 0 || src >= g.m_last_source - 1) &&
386 src < num_vertices(g));
387 EdgeIndex num_edges_orig = g.m_column.size();
388 for (; g.m_last_source <= src; ++g.m_last_source)
389 g.m_rowstart[g.m_last_source] = num_edges_orig;
390 g.m_rowstart[src + 1] = num_edges_orig + 1;
391 g.m_column.push_back(tgt);
392 g.edge_properties().push_back(p);
393 return typename BOOST_CSR_GRAPH_TYPE::edge_descriptor(src, num_edges_orig);
397 // From VertexListGraph
398 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
400 num_vertices(const BOOST_CSR_GRAPH_TYPE& g) {
401 return g.m_rowstart.size() - 1;
404 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
405 std::pair<counting_iterator<Vertex>, counting_iterator<Vertex> >
406 inline vertices(const BOOST_CSR_GRAPH_TYPE& g) {
407 return std::make_pair(counting_iterator<Vertex>(0),
408 counting_iterator<Vertex>(num_vertices(g)));
411 // From IncidenceGraph
412 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
413 class BOOST_CSR_GRAPH_TYPE::out_edge_iterator
414 : public iterator_facade<typename BOOST_CSR_GRAPH_TYPE::out_edge_iterator,
415 typename BOOST_CSR_GRAPH_TYPE::edge_descriptor,
416 std::random_access_iterator_tag,
417 const typename BOOST_CSR_GRAPH_TYPE::edge_descriptor&,
418 typename int_t<CHAR_BIT * sizeof(EdgeIndex)>::fast>
421 typedef typename int_t<CHAR_BIT * sizeof(EdgeIndex)>::fast difference_type;
423 out_edge_iterator() {}
424 // Implicit copy constructor OK
425 explicit out_edge_iterator(edge_descriptor edge) : m_edge(edge) { }
428 // iterator_facade requirements
429 const edge_descriptor& dereference() const { return m_edge; }
431 bool equal(const out_edge_iterator& other) const
432 { return m_edge == other.m_edge; }
434 void increment() { ++m_edge.idx; }
435 void decrement() { ++m_edge.idx; }
436 void advance(difference_type n) { m_edge.idx += n; }
438 difference_type distance_to(const out_edge_iterator& other) const
439 { return other.m_edge.idx - m_edge.idx; }
441 edge_descriptor m_edge;
443 friend class iterator_core_access;
446 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
448 source(typename BOOST_CSR_GRAPH_TYPE::edge_descriptor e,
449 const BOOST_CSR_GRAPH_TYPE&)
454 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
456 target(typename BOOST_CSR_GRAPH_TYPE::edge_descriptor e,
457 const BOOST_CSR_GRAPH_TYPE& g)
459 return g.m_column[e.idx];
462 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
463 inline std::pair<typename BOOST_CSR_GRAPH_TYPE::out_edge_iterator,
464 typename BOOST_CSR_GRAPH_TYPE::out_edge_iterator>
465 out_edges(Vertex v, const BOOST_CSR_GRAPH_TYPE& g)
467 typedef typename BOOST_CSR_GRAPH_TYPE::edge_descriptor ed;
468 typedef typename BOOST_CSR_GRAPH_TYPE::out_edge_iterator it;
469 EdgeIndex v_row_start = g.m_rowstart[v];
470 EdgeIndex next_row_start = g.m_rowstart[v + 1];
471 return std::make_pair(it(ed(v, v_row_start)),
472 it(ed(v, (std::max)(v_row_start, next_row_start))));
475 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
477 out_degree(Vertex v, const BOOST_CSR_GRAPH_TYPE& g)
479 EdgeIndex v_row_start = g.m_rowstart[v];
480 EdgeIndex next_row_start = g.m_rowstart[v + 1];
481 return (std::max)(v_row_start, next_row_start) - v_row_start;
484 // From AdjacencyGraph
485 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
486 inline std::pair<typename BOOST_CSR_GRAPH_TYPE::adjacency_iterator,
487 typename BOOST_CSR_GRAPH_TYPE::adjacency_iterator>
488 adjacent_vertices(Vertex v, const BOOST_CSR_GRAPH_TYPE& g)
490 EdgeIndex v_row_start = g.m_rowstart[v];
491 EdgeIndex next_row_start = g.m_rowstart[v + 1];
492 return std::make_pair(g.m_column.begin() + v_row_start,
494 (std::max)(v_row_start, next_row_start));
497 // Extra, common functions
498 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
499 inline typename graph_traits<BOOST_CSR_GRAPH_TYPE>::vertex_descriptor
500 vertex(typename graph_traits<BOOST_CSR_GRAPH_TYPE>::vertex_descriptor i,
501 const BOOST_CSR_GRAPH_TYPE&)
506 // Unlike for an adjacency_matrix, edge_range and edge take lg(out_degree(i))
508 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
509 inline std::pair<typename BOOST_CSR_GRAPH_TYPE::out_edge_iterator,
510 typename BOOST_CSR_GRAPH_TYPE::out_edge_iterator>
511 edge_range(Vertex i, Vertex j, const BOOST_CSR_GRAPH_TYPE& g)
513 typedef typename std::vector<Vertex>::const_iterator adj_iter;
514 typedef typename BOOST_CSR_GRAPH_TYPE::out_edge_iterator out_edge_iter;
515 typedef typename BOOST_CSR_GRAPH_TYPE::edge_descriptor edge_desc;
516 std::pair<adj_iter, adj_iter> raw_adjacencies = adjacent_vertices(i, g);
517 std::pair<adj_iter, adj_iter> adjacencies =
518 std::equal_range(raw_adjacencies.first, raw_adjacencies.second, j);
519 EdgeIndex idx_begin = adjacencies.first - g.m_column.begin();
520 EdgeIndex idx_end = adjacencies.second - g.m_column.begin();
521 return std::make_pair(out_edge_iter(edge_desc(i, idx_begin)),
522 out_edge_iter(edge_desc(i, idx_end)));
525 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
526 inline std::pair<typename BOOST_CSR_GRAPH_TYPE::edge_descriptor, bool>
527 edge(Vertex i, Vertex j, const BOOST_CSR_GRAPH_TYPE& g)
529 typedef typename BOOST_CSR_GRAPH_TYPE::out_edge_iterator out_edge_iter;
530 std::pair<out_edge_iter, out_edge_iter> range = edge_range(i, j, g);
531 if (range.first == range.second)
532 return std::make_pair(typename BOOST_CSR_GRAPH_TYPE::edge_descriptor(),
535 return std::make_pair(*range.first, true);
538 // Find an edge given its index in the graph
539 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
540 inline typename BOOST_CSR_GRAPH_TYPE::edge_descriptor
541 edge_from_index(EdgeIndex idx, const BOOST_CSR_GRAPH_TYPE& g)
543 typedef typename std::vector<EdgeIndex>::const_iterator row_start_iter;
544 assert (idx < num_edges(g));
545 row_start_iter src_plus_1 =
546 std::upper_bound(g.m_rowstart.begin(),
547 g.m_rowstart.begin() + g.m_last_source + 1,
549 // Get last source whose rowstart is at most idx
550 // upper_bound returns this position plus 1
551 Vertex src = (src_plus_1 - g.m_rowstart.begin()) - 1;
552 return typename BOOST_CSR_GRAPH_TYPE::edge_descriptor(src, idx);
555 // From EdgeListGraph
556 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
557 class BOOST_CSR_GRAPH_TYPE::edge_iterator
560 typedef std::forward_iterator_tag iterator_category;
561 typedef edge_descriptor value_type;
563 typedef const edge_descriptor* pointer;
565 typedef edge_descriptor reference;
566 typedef typename int_t<CHAR_BIT * sizeof(EdgeIndex)>::fast difference_type;
568 edge_iterator() : rowstart_array(0), current_edge(), end_of_this_vertex(0) {}
570 edge_iterator(const compressed_sparse_row_graph& graph,
571 edge_descriptor current_edge,
572 EdgeIndex end_of_this_vertex)
573 : rowstart_array(&graph.m_rowstart[0]), current_edge(current_edge),
574 end_of_this_vertex(end_of_this_vertex) {}
576 // From InputIterator
577 reference operator*() const { return current_edge; }
578 pointer operator->() const { return ¤t_edge; }
580 bool operator==(const edge_iterator& o) const {
581 return current_edge == o.current_edge;
583 bool operator!=(const edge_iterator& o) const {
584 return current_edge != o.current_edge;
587 edge_iterator& operator++() {
589 while (current_edge.idx == end_of_this_vertex) {
591 end_of_this_vertex = rowstart_array[current_edge.src + 1];
596 edge_iterator operator++(int) {
597 edge_iterator temp = *this;
603 const EdgeIndex* rowstart_array;
604 edge_descriptor current_edge;
605 EdgeIndex end_of_this_vertex;
608 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
610 num_edges(const BOOST_CSR_GRAPH_TYPE& g)
612 return g.m_column.size();
615 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
616 std::pair<typename BOOST_CSR_GRAPH_TYPE::edge_iterator,
617 typename BOOST_CSR_GRAPH_TYPE::edge_iterator>
618 edges(const BOOST_CSR_GRAPH_TYPE& g)
620 typedef typename BOOST_CSR_GRAPH_TYPE::edge_iterator ei;
621 typedef typename BOOST_CSR_GRAPH_TYPE::edge_descriptor edgedesc;
622 if (g.m_rowstart.size() == 1 || g.m_column.empty()) {
623 return std::make_pair(ei(), ei());
625 // Find the first vertex that has outgoing edges
627 while (g.m_rowstart[src + 1] == 0) ++src;
628 return std::make_pair(ei(g, edgedesc(src, 0), g.m_rowstart[src + 1]),
629 ei(g, edgedesc(num_vertices(g), g.m_column.size()), 0));
633 // For Property Graph
636 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, class Tag, class Value>
638 set_property(BOOST_CSR_GRAPH_TYPE& g, Tag, const Value& value)
640 get_property_value(g.m_property, Tag()) = value;
643 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, class Tag>
645 typename graph_property<BOOST_CSR_GRAPH_TYPE, Tag>::type&
646 get_property(BOOST_CSR_GRAPH_TYPE& g, Tag)
648 return get_property_value(g.m_property, Tag());
651 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, class Tag>
654 typename graph_property<BOOST_CSR_GRAPH_TYPE, Tag>::type&
655 get_property(const BOOST_CSR_GRAPH_TYPE& g, Tag)
657 return get_property_value(g.m_property, Tag());
660 // Add edge_index property map
661 template<typename Index, typename Descriptor>
662 struct csr_edge_index_map
664 typedef Index value_type;
665 typedef Index reference;
666 typedef Descriptor key_type;
667 typedef readable_property_map_tag category;
670 template<typename Index, typename Descriptor>
672 get(const csr_edge_index_map<Index, Descriptor>&,
673 const typename csr_edge_index_map<Index, Descriptor>::key_type& key)
678 // Doing the right thing here (by unifying with vertex_index_t and
679 // edge_index_t) breaks GCC.
680 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename Tag>
681 struct property_map<BOOST_CSR_GRAPH_TYPE, Tag>
684 typedef identity_property_map vertex_index_type;
685 typedef typename graph_traits<BOOST_CSR_GRAPH_TYPE>::edge_descriptor
687 typedef csr_edge_index_map<EdgeIndex, edge_descriptor> edge_index_type;
689 typedef typename mpl::if_<is_same<Tag, edge_index_t>,
691 detail::error_property_not_found>::type
695 typedef typename mpl::if_<is_same<Tag, vertex_index_t>,
697 edge_or_none>::type type;
699 typedef type const_type;
702 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
703 inline identity_property_map
704 get(vertex_index_t, const BOOST_CSR_GRAPH_TYPE&)
706 return identity_property_map();
709 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
712 const BOOST_CSR_GRAPH_TYPE&, Vertex v)
717 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
718 inline typename property_map<BOOST_CSR_GRAPH_TYPE, edge_index_t>::const_type
719 get(edge_index_t, const BOOST_CSR_GRAPH_TYPE&)
721 typedef typename property_map<BOOST_CSR_GRAPH_TYPE, edge_index_t>::const_type
723 return result_type();
726 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
728 get(edge_index_t, const BOOST_CSR_GRAPH_TYPE&,
729 typename BOOST_CSR_GRAPH_TYPE::edge_descriptor e)
734 // Support for bundled properties
735 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename T, typename Bundle>
736 struct property_map<BOOST_CSR_GRAPH_TYPE, T Bundle::*>
739 typedef graph_traits<BOOST_CSR_GRAPH_TYPE> traits;
740 typedef VertexProperty vertex_bundled;
741 typedef EdgeProperty edge_bundled;
742 typedef typename ct_if<(detail::is_vertex_bundle<vertex_bundled, edge_bundled, Bundle>::value),
743 typename traits::vertex_descriptor,
744 typename traits::edge_descriptor>::type
748 typedef bundle_property_map<BOOST_CSR_GRAPH_TYPE, descriptor, Bundle, T>
750 typedef bundle_property_map<const BOOST_CSR_GRAPH_TYPE, descriptor, Bundle,
754 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename T, typename Bundle>
756 typename property_map<BOOST_CSR_GRAPH_TYPE, T Bundle::*>::type
757 get(T Bundle::* p, BOOST_CSR_GRAPH_TYPE& g)
759 typedef typename property_map<BOOST_CSR_GRAPH_TYPE,
762 return result_type(&g, p);
765 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename T, typename Bundle>
767 typename property_map<BOOST_CSR_GRAPH_TYPE, T Bundle::*>::const_type
768 get(T Bundle::* p, BOOST_CSR_GRAPH_TYPE const & g)
770 typedef typename property_map<BOOST_CSR_GRAPH_TYPE,
771 T Bundle::*>::const_type
773 return result_type(&g, p);
776 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename T, typename Bundle,
779 get(T Bundle::* p, BOOST_CSR_GRAPH_TYPE const & g,
782 return get(get(p, g), key);
785 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename T, typename Bundle,
788 put(T Bundle::* p, BOOST_CSR_GRAPH_TYPE& g,
789 const Key& key, const T& value)
791 put(get(p, g), key, value);
794 #undef BOOST_CSR_GRAPH_TYPE
795 #undef BOOST_CSR_GRAPH_TEMPLATE_PARMS
797 } // end namespace boost
799 #endif // BOOST_GRAPH_COMPRESSED_SPARSE_ROW_GRAPH_HPP