epoc32/include/stdapis/boost/graph/compressed_sparse_row_graph.hpp
author William Roberts <williamr@symbian.org>
Tue, 16 Mar 2010 16:12:26 +0000
branchSymbian2
changeset 2 2fe1408b6811
permissions -rw-r--r--
Final list of Symbian^2 public API header files
     1 // Copyright 2005-2006 The Trustees of Indiana University.
     2 
     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)
     6 
     7 //  Authors: Jeremiah Willcock
     8 //           Douglas Gregor
     9 //           Andrew Lumsdaine
    10 
    11 // Compressed sparse row graph type
    12 
    13 #ifndef BOOST_GRAPH_COMPRESSED_SPARSE_ROW_GRAPH_HPP
    14 #define BOOST_GRAPH_COMPRESSED_SPARSE_ROW_GRAPH_HPP
    15 
    16 #include <vector>
    17 #include <utility>
    18 #include <algorithm>
    19 #include <climits>
    20 #include <iterator>
    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>
    30 
    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.
    34 #endif
    35 
    36 namespace boost {
    37 
    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.
    40 struct csr_graph_tag;
    41 
    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>
    51 
    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;
    56 
    57 /** Compressed sparse row graph.
    58  *
    59  * Vertex and EdgeIndex should be unsigned integral types and should
    60  * specialize numeric_limits.
    61  */
    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,
    70                                               Vertex>,
    71      public detail::indexed_edge_properties<BOOST_CSR_GRAPH_TYPE, EdgeProperty,
    72                                             csr_edge_descriptor<Vertex,
    73                                                                 EdgeIndex> >
    74 
    75 {
    76   typedef detail::indexed_vertex_properties<compressed_sparse_row_graph,
    77                                             VertexProperty, Vertex>
    78     inherited_vertex_properties;
    79 
    80   typedef detail::indexed_edge_properties<BOOST_CSR_GRAPH_TYPE, EdgeProperty,
    81                                           csr_edge_descriptor<Vertex, EdgeIndex> >
    82     inherited_edge_properties;
    83 
    84  public:
    85   // For Property Graph
    86   typedef GraphProperty graph_property_type;
    87 
    88  protected:
    89   template<typename InputIterator>
    90   void
    91   maybe_reserve_edge_list_storage(InputIterator, InputIterator,
    92                                   std::input_iterator_tag)
    93   {
    94     // Do nothing: we have no idea how much storage to reserve.
    95   }
    96 
    97   template<typename InputIterator>
    98   void
    99   maybe_reserve_edge_list_storage(InputIterator first, InputIterator last,
   100                                   std::forward_iterator_tag)
   101   {
   102     using std::distance;
   103     typename std::iterator_traits<InputIterator>::difference_type n =
   104       distance(first, last);
   105     m_column.reserve(n);
   106     inherited_edge_properties::reserve(n);
   107   }
   108 
   109  public:
   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.
   113    */
   114   BOOST_STATIC_ASSERT((is_same<Directed, directedS>::value));
   115 
   116   // Concept requirements:
   117   // For Graph
   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;
   122 
   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 {};
   127 
   128   static vertex_descriptor null_vertex() { return vertex_descriptor(-1); }
   129 
   130   // For VertexListGraph
   131   typedef counting_iterator<Vertex> vertex_iterator;
   132   typedef Vertex vertices_size_type;
   133 
   134   // For EdgeListGraph
   135   typedef EdgeIndex edges_size_type;
   136 
   137   // For IncidenceGraph
   138   class out_edge_iterator;
   139   typedef EdgeIndex degree_size_type;
   140 
   141   // For AdjacencyGraph
   142   typedef typename std::vector<Vertex>::const_iterator adjacency_iterator;
   143 
   144   // For EdgeListGraph
   145   class edge_iterator;
   146 
   147   // For BidirectionalGraph (not implemented)
   148   typedef void in_edge_iterator;
   149 
   150   // For internal use
   151   typedef csr_graph_tag graph_tag;
   152 
   153   // Constructors
   154 
   155   // Default constructor: an empty graph.
   156   compressed_sparse_row_graph()
   157     : m_rowstart(1, EdgeIndex(0)), m_column(0), m_property(),
   158       m_last_source(0) {}
   159 
   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)
   168   {
   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.
   172     if (numedges == 0) {
   173       typedef typename std::iterator_traits<InputIterator>::iterator_category
   174         category;
   175       maybe_reserve_edge_list_storage(edge_begin, edge_end, category());
   176     } else {
   177       m_column.reserve(numedges);
   178     }
   179 
   180     EdgeIndex current_edge = 0;
   181     Vertex current_vertex_plus_one = 1;
   182     m_rowstart[0] = 0;
   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);
   189       ++current_edge;
   190     }
   191 
   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;
   195 
   196     // Default-construct properties for edges
   197     inherited_edge_properties::resize(m_column.size());
   198   }
   199 
   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)
   209   {
   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.
   213     if (numedges == 0) {
   214       typedef typename std::iterator_traits<InputIterator>::iterator_category
   215         category;
   216       maybe_reserve_edge_list_storage(edge_begin, edge_end, category());
   217     } else {
   218       m_column.reserve(numedges);
   219     }
   220 
   221     EdgeIndex current_edge = 0;
   222     Vertex current_vertex_plus_one = 1;
   223     m_rowstart[0] = 0;
   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);
   231       ++current_edge;
   232     }
   233 
   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;
   237   }
   238 
   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)
   245   {
   246     assign(g, vi, numverts, numedges);
   247   }
   248 
   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)
   253   {
   254     assign(g, vi, num_vertices(g), num_edges(g));
   255   }
   256 
   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)
   261   {
   262     assign(g, get(vertex_index, g), num_vertices(g), num_edges(g));
   263   }
   264 
   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>
   269   void
   270   assign(const Graph& g, const VertexIndexMap& vi,
   271          vertices_size_type numverts, edges_size_type numedges)
   272   {
   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
   280       g_out_edge_iter;
   281 
   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));
   289       }
   290       std::sort(m_column.begin() + num_edges_before_this_vertex,
   291                 m_column.begin() + current_edge);
   292     }
   293     m_rowstart[numverts] = current_edge;
   294     m_last_source = numverts;
   295   }
   296 
   297   // Requires the above, plus VertexListGraph and EdgeListGraph
   298   template<typename Graph, typename VertexIndexMap>
   299   void assign(const Graph& g, const VertexIndexMap& vi)
   300   {
   301     assign(g, vi, num_vertices(g), num_edges(g));
   302   }
   303 
   304   // Requires the above, plus a vertex_index map.
   305   template<typename Graph>
   306   void assign(const Graph& g)
   307   {
   308     assign(g, get(vertex_index, g), num_vertices(g), num_edges(g));
   309   }
   310 
   311   using inherited_vertex_properties::operator[];
   312   using inherited_edge_properties::operator[];
   313 
   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; }
   319 
   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
   324 };
   325 
   326 template<typename Vertex, typename EdgeIndex>
   327 class csr_edge_descriptor
   328 {
   329  public:
   330   Vertex src;
   331   EdgeIndex idx;
   332 
   333   csr_edge_descriptor(Vertex src, EdgeIndex idx): src(src), idx(idx) {}
   334   csr_edge_descriptor(): src(0), idx(0) {}
   335 
   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;}
   342 };
   343 
   344 // Construction functions
   345 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
   346 inline Vertex
   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;
   351 }
   352 
   353 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
   354 inline Vertex
   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;
   359 }
   360 
   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);
   376 }
   377 
   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);
   394 }
   395 
   396 
   397 // From VertexListGraph
   398 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
   399 inline Vertex
   400 num_vertices(const BOOST_CSR_GRAPH_TYPE& g) {
   401   return g.m_rowstart.size() - 1;
   402 }
   403 
   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)));
   409 }
   410 
   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>
   419 {
   420  public:
   421   typedef typename int_t<CHAR_BIT * sizeof(EdgeIndex)>::fast difference_type;
   422 
   423   out_edge_iterator() {}
   424   // Implicit copy constructor OK
   425   explicit out_edge_iterator(edge_descriptor edge) : m_edge(edge) { }
   426 
   427  private:
   428   // iterator_facade requirements
   429   const edge_descriptor& dereference() const { return m_edge; }
   430 
   431   bool equal(const out_edge_iterator& other) const
   432   { return m_edge == other.m_edge; }
   433 
   434   void increment() { ++m_edge.idx; }
   435   void decrement() { ++m_edge.idx; }
   436   void advance(difference_type n) { m_edge.idx += n; }
   437 
   438   difference_type distance_to(const out_edge_iterator& other) const
   439   { return other.m_edge.idx - m_edge.idx; }
   440 
   441   edge_descriptor m_edge;
   442 
   443   friend class iterator_core_access;
   444 };
   445 
   446 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
   447 inline Vertex
   448 source(typename BOOST_CSR_GRAPH_TYPE::edge_descriptor e,
   449        const BOOST_CSR_GRAPH_TYPE&)
   450 {
   451   return e.src;
   452 }
   453 
   454 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
   455 inline Vertex
   456 target(typename BOOST_CSR_GRAPH_TYPE::edge_descriptor e,
   457        const BOOST_CSR_GRAPH_TYPE& g)
   458 {
   459   return g.m_column[e.idx];
   460 }
   461 
   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)
   466 {
   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))));
   473 }
   474 
   475 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
   476 inline EdgeIndex
   477 out_degree(Vertex v, const BOOST_CSR_GRAPH_TYPE& g)
   478 {
   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;
   482 }
   483 
   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)
   489 {
   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,
   493                         g.m_column.begin() +
   494                                 (std::max)(v_row_start, next_row_start));
   495 }
   496 
   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&)
   502 {
   503   return i;
   504 }
   505 
   506 // Unlike for an adjacency_matrix, edge_range and edge take lg(out_degree(i))
   507 // time
   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)
   512 {
   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)));
   523 }
   524 
   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)
   528 {
   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(),
   533                           false);
   534   else
   535     return std::make_pair(*range.first, true);
   536 }
   537 
   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)
   542 {
   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,
   548                      idx);
   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);
   553 }
   554 
   555 // From EdgeListGraph
   556 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
   557 class BOOST_CSR_GRAPH_TYPE::edge_iterator
   558 {
   559  public:
   560   typedef std::forward_iterator_tag iterator_category;
   561   typedef edge_descriptor value_type;
   562 
   563   typedef const edge_descriptor* pointer;
   564 
   565   typedef edge_descriptor reference;
   566   typedef typename int_t<CHAR_BIT * sizeof(EdgeIndex)>::fast difference_type;
   567 
   568   edge_iterator() : rowstart_array(0), current_edge(), end_of_this_vertex(0) {}
   569 
   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) {}
   575 
   576   // From InputIterator
   577   reference operator*() const { return current_edge; }
   578   pointer operator->() const { return &current_edge; }
   579 
   580   bool operator==(const edge_iterator& o) const {
   581     return current_edge == o.current_edge;
   582   }
   583   bool operator!=(const edge_iterator& o) const {
   584     return current_edge != o.current_edge;
   585   }
   586 
   587   edge_iterator& operator++() {
   588     ++current_edge.idx;
   589     while (current_edge.idx == end_of_this_vertex) {
   590       ++current_edge.src;
   591       end_of_this_vertex = rowstart_array[current_edge.src + 1];
   592     }
   593     return *this;
   594   }
   595 
   596   edge_iterator operator++(int) {
   597     edge_iterator temp = *this;
   598     ++*this;
   599     return temp;
   600   }
   601 
   602  private:
   603   const EdgeIndex* rowstart_array;
   604   edge_descriptor current_edge;
   605   EdgeIndex end_of_this_vertex;
   606 };
   607 
   608 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
   609 inline EdgeIndex
   610 num_edges(const BOOST_CSR_GRAPH_TYPE& g)
   611 {
   612   return g.m_column.size();
   613 }
   614 
   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)
   619 {
   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());
   624   } else {
   625     // Find the first vertex that has outgoing edges
   626     Vertex src = 0;
   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));
   630   }
   631 }
   632 
   633 // For Property Graph
   634 
   635 // Graph properties
   636 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, class Tag, class Value>
   637 inline void
   638 set_property(BOOST_CSR_GRAPH_TYPE& g, Tag, const Value& value)
   639 {
   640   get_property_value(g.m_property, Tag()) = value;
   641 }
   642 
   643 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, class Tag>
   644 inline
   645 typename graph_property<BOOST_CSR_GRAPH_TYPE, Tag>::type&
   646 get_property(BOOST_CSR_GRAPH_TYPE& g, Tag)
   647 {
   648   return get_property_value(g.m_property, Tag());
   649 }
   650 
   651 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, class Tag>
   652 inline
   653 const
   654 typename graph_property<BOOST_CSR_GRAPH_TYPE, Tag>::type&
   655 get_property(const BOOST_CSR_GRAPH_TYPE& g, Tag)
   656 {
   657   return get_property_value(g.m_property, Tag());
   658 }
   659 
   660 // Add edge_index property map
   661 template<typename Index, typename Descriptor>
   662 struct csr_edge_index_map
   663 {
   664   typedef Index                     value_type;
   665   typedef Index                     reference;
   666   typedef Descriptor                key_type;
   667   typedef readable_property_map_tag category;
   668 };
   669 
   670 template<typename Index, typename Descriptor>
   671 inline Index
   672 get(const csr_edge_index_map<Index, Descriptor>&,
   673     const typename csr_edge_index_map<Index, Descriptor>::key_type& key)
   674 {
   675   return key.idx;
   676 }
   677 
   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>
   682 {
   683 private:
   684   typedef identity_property_map vertex_index_type;
   685   typedef typename graph_traits<BOOST_CSR_GRAPH_TYPE>::edge_descriptor
   686     edge_descriptor;
   687   typedef csr_edge_index_map<EdgeIndex, edge_descriptor> edge_index_type;
   688 
   689   typedef typename mpl::if_<is_same<Tag, edge_index_t>,
   690                             edge_index_type,
   691                             detail::error_property_not_found>::type
   692     edge_or_none;
   693 
   694 public:
   695   typedef typename mpl::if_<is_same<Tag, vertex_index_t>,
   696                             vertex_index_type,
   697                             edge_or_none>::type type;
   698 
   699   typedef type const_type;
   700 };
   701 
   702 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
   703 inline identity_property_map
   704 get(vertex_index_t, const BOOST_CSR_GRAPH_TYPE&)
   705 {
   706   return identity_property_map();
   707 }
   708 
   709 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
   710 inline Vertex
   711 get(vertex_index_t,
   712     const BOOST_CSR_GRAPH_TYPE&, Vertex v)
   713 {
   714   return v;
   715 }
   716 
   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&)
   720 {
   721   typedef typename property_map<BOOST_CSR_GRAPH_TYPE, edge_index_t>::const_type
   722     result_type;
   723   return result_type();
   724 }
   725 
   726 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS>
   727 inline EdgeIndex
   728 get(edge_index_t, const BOOST_CSR_GRAPH_TYPE&,
   729     typename BOOST_CSR_GRAPH_TYPE::edge_descriptor e)
   730 {
   731   return e.idx;
   732 }
   733 
   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::*>
   737 {
   738 private:
   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
   745     descriptor;
   746 
   747 public:
   748   typedef bundle_property_map<BOOST_CSR_GRAPH_TYPE, descriptor, Bundle, T>
   749     type;
   750   typedef bundle_property_map<const BOOST_CSR_GRAPH_TYPE, descriptor, Bundle,
   751                               const T> const_type;
   752 };
   753 
   754 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename T, typename Bundle>
   755 inline
   756 typename property_map<BOOST_CSR_GRAPH_TYPE, T Bundle::*>::type
   757 get(T Bundle::* p, BOOST_CSR_GRAPH_TYPE& g)
   758 {
   759   typedef typename property_map<BOOST_CSR_GRAPH_TYPE,
   760                                 T Bundle::*>::type
   761     result_type;
   762   return result_type(&g, p);
   763 }
   764 
   765 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename T, typename Bundle>
   766 inline
   767 typename property_map<BOOST_CSR_GRAPH_TYPE, T Bundle::*>::const_type
   768 get(T Bundle::* p, BOOST_CSR_GRAPH_TYPE const & g)
   769 {
   770   typedef typename property_map<BOOST_CSR_GRAPH_TYPE,
   771                                 T Bundle::*>::const_type
   772     result_type;
   773   return result_type(&g, p);
   774 }
   775 
   776 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename T, typename Bundle,
   777          typename Key>
   778 inline T
   779 get(T Bundle::* p, BOOST_CSR_GRAPH_TYPE const & g,
   780     const Key& key)
   781 {
   782   return get(get(p, g), key);
   783 }
   784 
   785 template<BOOST_CSR_GRAPH_TEMPLATE_PARMS, typename T, typename Bundle,
   786          typename Key>
   787 inline void
   788 put(T Bundle::* p, BOOST_CSR_GRAPH_TYPE& g,
   789     const Key& key, const T& value)
   790 {
   791   put(get(p, g), key, value);
   792 }
   793 
   794 #undef BOOST_CSR_GRAPH_TYPE
   795 #undef BOOST_CSR_GRAPH_TEMPLATE_PARMS
   796 
   797 } // end namespace boost
   798 
   799 #endif // BOOST_GRAPH_COMPRESSED_SPARSE_ROW_GRAPH_HPP