• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 //          Copyright W.P. McNeill 2010.
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 #include <boost/concept/assert.hpp>
8 #include <boost/graph/adjacency_iterator.hpp>
9 #include <boost/graph/dijkstra_shortest_paths.hpp>
10 #include <boost/graph/graph_concepts.hpp>
11 #include <boost/graph/properties.hpp>
12 #include <boost/iterator/counting_iterator.hpp>
13 #include <boost/iterator/iterator_facade.hpp>
14 #include <boost/lexical_cast.hpp>
15 #include <iostream>
16 #include <utility>
17 
18 /*
19 This file defines a simple example of a read-only implicit weighted graph
20 built using the Boost Graph Library. It can be used as a starting point for
21 developers creating their own implicit graphs.
22 
23 The graph models the following concepts:
24   Graph
25   IncidenceGraph
26   BidirectionalGraph
27   AdjacencyGraph
28   VertexListGraph
29   EdgeListGraph
30   AdjacencyMatrix
31   ReadablePropertyGraph
32 
33 The graph defined here is a ring graph, a graph whose vertices are arranged in
34 a ring so that each vertex has exactly two neighbors. For example, here is a
35 ring graph with five nodes.
36 
37                                     0
38                                   /   \
39                                 4      1
40                                 |      |
41                                 3 ---- 2
42 
43 The edges of this graph are undirected and each has a weight that is a
44 function of its position in the graph.
45 
46 The vertices indexed are by integer and arranged sequentially so that each
47 vertex i is adjacent to i-1 for i>0 and i+1 for i<n-1.  Vertex 0 is also
48 adjacent to vertex n-1.  Edges are indexed by pairs of vertex indices.
49 
50 Various aspects of the graph are modeled by the following classes:
51 
52   ring_graph
53     The graph class instantiated by a client. This defines types for the
54     concepts that this graph models and keeps track of the number of vertices
55     in the graph.
56 
57   ring_incident_edge_iterator
58     This is an iterator that ranges over edges incident on a given vertex. The
59     behavior of this iterator defines the ring topology. Other iterators that
60     make reference to the graph structure are defined in terms of this one.
61 
62   edge_weight_map
63     This defines a property map between edges and weights. Here edges have a
64     weight equal to the average of their endpoint vertex indices, i.e. edge
65     (2,3) has weight 2.5, edge (0,4) has weight 2, etc.
66 
67   boost::property_map<graph, boost::edge_weight_t>
68     This tells Boost to associate the edges of the ring graph with the edge
69     weight map.
70 
71 Along with these classes, the graph concepts are modeled by various valid
72 expression functions defined below.  This example also defines a
73 get(boost::vertex_index_t, const ring_graph&) function which isn't part of a
74 graph concept, but is used for Dijkstra search.
75 
76 Apart from graph, client code should not instantiate the model classes
77 directly. Instead it should access them and their properties via
78 graph_traits<...> and property_traits<...> lookups. For convenience,
79 this example defines short names for all these properties that client code can
80 use.
81 */
82 
83 // Forward declarations
84 class ring_graph;
85 class ring_incident_edge_iterator;
86 class ring_adjacency_iterator;
87 class ring_edge_iterator;
88 struct edge_weight_map;
89 
90 // ReadablePropertyGraph associated types
91 namespace boost
92 {
93 template <> struct property_map< ring_graph, edge_weight_t >
94 {
95     typedef edge_weight_map type;
96     typedef edge_weight_map const_type;
97 };
98 
99 template <> struct property_map< const ring_graph, edge_weight_t >
100 {
101     typedef edge_weight_map type;
102     typedef edge_weight_map const_type;
103 };
104 }
105 
106 // Tag values that specify the traversal type in graph::traversal_category.
107 struct ring_traversal_catetory : virtual public boost::bidirectional_graph_tag,
108                                  virtual public boost::adjacency_graph_tag,
109                                  virtual public boost::vertex_list_graph_tag,
110                                  virtual public boost::edge_list_graph_tag
111 {
112 };
113 
114 /*
115 Undirected graph of vertices arranged in a ring shape.
116 
117 Vertices are indexed by integer, and edges connect vertices with consecutive
118 indices.  Vertex 0 is also adjacent to the vertex n-1.
119 */
120 class ring_graph
121 {
122 public:
123     // Graph associated types
124     typedef std::size_t vertex_descriptor;
125     typedef boost::undirected_tag directed_category;
126     typedef boost::disallow_parallel_edge_tag edge_parallel_category;
127     typedef ring_traversal_catetory traversal_category;
128 
129     // IncidenceGraph associated types
130     typedef std::pair< vertex_descriptor, vertex_descriptor > edge_descriptor;
131     typedef ring_incident_edge_iterator out_edge_iterator;
132     typedef std::size_t degree_size_type;
133 
134     // BidirectionalGraph associated types
135     // Note that undirected graphs make no distinction between in- and out-
136     // edges.
137     typedef ring_incident_edge_iterator in_edge_iterator;
138 
139     // AdjacencyGraph associated types
140     typedef ring_adjacency_iterator adjacency_iterator;
141 
142     // VertexListGraph associated types
143     typedef boost::counting_iterator< vertex_descriptor > vertex_iterator;
144     typedef std::size_t vertices_size_type;
145 
146     // EdgeListGraph associated types
147     typedef ring_edge_iterator edge_iterator;
148     typedef std::size_t edges_size_type;
149 
150     // This type is not part of a graph concept, but is used to return the
151     // default vertex index map used by the Dijkstra search algorithm.
152     typedef vertex_descriptor vertex_property_type;
153 
ring_graph(std::size_t n)154     ring_graph(std::size_t n) : m_n(n) {};
n() const155     std::size_t n() const { return m_n; }
156 
157 private:
158     // The number of vertices in the graph.
159     std::size_t m_n;
160 };
161 
162 // Use these graph_traits parameterizations to refer to the associated
163 // graph types.
164 typedef boost::graph_traits< ring_graph >::vertex_descriptor vertex_descriptor;
165 typedef boost::graph_traits< ring_graph >::edge_descriptor edge_descriptor;
166 typedef boost::graph_traits< ring_graph >::out_edge_iterator out_edge_iterator;
167 typedef boost::graph_traits< ring_graph >::in_edge_iterator in_edge_iterator;
168 typedef boost::graph_traits< ring_graph >::adjacency_iterator
169     adjacency_iterator;
170 typedef boost::graph_traits< ring_graph >::degree_size_type degree_size_type;
171 typedef boost::graph_traits< ring_graph >::vertex_iterator vertex_iterator;
172 typedef boost::graph_traits< ring_graph >::vertices_size_type
173     vertices_size_type;
174 typedef boost::graph_traits< ring_graph >::edge_iterator edge_iterator;
175 typedef boost::graph_traits< ring_graph >::edges_size_type edges_size_type;
176 
177 // Tag values passed to an iterator constructor to specify whether it should
178 // be created at the start or the end of its range.
179 struct iterator_position
180 {
181 };
182 struct iterator_start : virtual public iterator_position
183 {
184 };
185 struct iterator_end : virtual public iterator_position
186 {
187 };
188 
189 /*
190 Iterator over edges incident on a vertex in a ring graph.
191 
192 For vertex i, this returns edge (i, i+1) and then edge (i, i-1), wrapping
193 around the end of the ring as needed.
194 
195 It is implemented with the boost::iterator_adaptor class, adapting an
196 offset into the dereference::ring_offset array.
197 */
198 class ring_incident_edge_iterator
199 : public boost::iterator_adaptor< ring_incident_edge_iterator,
200       boost::counting_iterator< std::size_t >, edge_descriptor,
201       boost::use_default, edge_descriptor >
202 {
203 public:
ring_incident_edge_iterator()204     ring_incident_edge_iterator()
205     : ring_incident_edge_iterator::iterator_adaptor_(0), m_n(0), m_u(0) {};
ring_incident_edge_iterator(const ring_graph & g,vertex_descriptor u,iterator_start)206     explicit ring_incident_edge_iterator(
207         const ring_graph& g, vertex_descriptor u, iterator_start)
208     : ring_incident_edge_iterator::iterator_adaptor_(0), m_n(g.n()), m_u(u) {};
ring_incident_edge_iterator(const ring_graph & g,vertex_descriptor u,iterator_end)209     explicit ring_incident_edge_iterator(
210         const ring_graph& g, vertex_descriptor u, iterator_end)
211     : // A graph with one vertex only has a single self-loop.  A graph with
212       // two vertices has a single edge between them.  All other graphs have
213       // two edges per vertex.
214         ring_incident_edge_iterator::iterator_adaptor_(g.n() > 2 ? 2 : 1)
215     , m_n(g.n())
216     , m_u(u) {};
217 
218 private:
219     friend class boost::iterator_core_access;
220 
dereference() const221     edge_descriptor dereference() const
222     {
223         static const int ring_offset[] = { 1, -1 };
224         vertex_descriptor v;
225 
226         std::size_t p = *this->base_reference();
227         if (m_u == 0 && p == 1)
228             v = m_n - 1; // Vertex n-1 precedes vertex 0.
229         else
230             v = (m_u + ring_offset[p]) % m_n;
231         return edge_descriptor(m_u, v);
232     }
233 
234     std::size_t m_n; // Size of the graph
235     vertex_descriptor m_u; // Vertex whose out edges are iterated
236 };
237 
238 // IncidenceGraph valid expressions
source(edge_descriptor e,const ring_graph &)239 vertex_descriptor source(edge_descriptor e, const ring_graph&)
240 {
241     // The first vertex in the edge pair is the source.
242     return e.first;
243 }
244 
target(edge_descriptor e,const ring_graph &)245 vertex_descriptor target(edge_descriptor e, const ring_graph&)
246 {
247     // The second vertex in the edge pair is the target.
248     return e.second;
249 }
250 
out_edges(vertex_descriptor u,const ring_graph & g)251 std::pair< out_edge_iterator, out_edge_iterator > out_edges(
252     vertex_descriptor u, const ring_graph& g)
253 {
254     return std::pair< out_edge_iterator, out_edge_iterator >(
255         out_edge_iterator(g, u, iterator_start()),
256         out_edge_iterator(g, u, iterator_end()));
257 }
258 
out_degree(vertex_descriptor,const ring_graph &)259 degree_size_type out_degree(vertex_descriptor, const ring_graph&)
260 {
261     // All vertices in a ring graph have two neighbors.
262     return 2;
263 }
264 
265 // BidirectionalGraph valid expressions
in_edges(vertex_descriptor u,const ring_graph & g)266 std::pair< in_edge_iterator, in_edge_iterator > in_edges(
267     vertex_descriptor u, const ring_graph& g)
268 {
269     // The in-edges and out-edges are the same in an undirected graph.
270     return out_edges(u, g);
271 }
272 
in_degree(vertex_descriptor u,const ring_graph & g)273 degree_size_type in_degree(vertex_descriptor u, const ring_graph& g)
274 {
275     // The in-degree and out-degree are both equal to the number of incident
276     // edges in an undirected graph.
277     return out_degree(u, g);
278 }
279 
degree(vertex_descriptor u,const ring_graph & g)280 degree_size_type degree(vertex_descriptor u, const ring_graph& g)
281 {
282     // The in-degree and out-degree are both equal to the number of incident
283     // edges in an undirected graph.
284     return out_degree(u, g);
285 }
286 
287 /*
288 Iterator over vertices adjacent to a given vertex.
289 
290 This iterates over the target vertices of all the incident edges.
291 */
292 class ring_adjacency_iterator
293 : public boost::adjacency_iterator_generator< ring_graph, vertex_descriptor,
294       out_edge_iterator >::type
295 {
296     // The parent class is an iterator_adpator that turns an iterator over
297     // out edges into an iterator over adjacent vertices.
298     typedef boost::adjacency_iterator_generator< ring_graph, vertex_descriptor,
299         out_edge_iterator >::type parent_class;
300 
301 public:
ring_adjacency_iterator()302     ring_adjacency_iterator() {};
ring_adjacency_iterator(vertex_descriptor u,const ring_graph & g,iterator_start)303     ring_adjacency_iterator(
304         vertex_descriptor u, const ring_graph& g, iterator_start)
305     : parent_class(out_edge_iterator(g, u, iterator_start()), &g) {};
ring_adjacency_iterator(vertex_descriptor u,const ring_graph & g,iterator_end)306     ring_adjacency_iterator(
307         vertex_descriptor u, const ring_graph& g, iterator_end)
308     : parent_class(out_edge_iterator(g, u, iterator_end()), &g) {};
309 };
310 
311 // AdjacencyGraph valid expressions
adjacent_vertices(vertex_descriptor u,const ring_graph & g)312 std::pair< adjacency_iterator, adjacency_iterator > adjacent_vertices(
313     vertex_descriptor u, const ring_graph& g)
314 {
315     return std::pair< adjacency_iterator, adjacency_iterator >(
316         adjacency_iterator(u, g, iterator_start()),
317         adjacency_iterator(u, g, iterator_end()));
318 }
319 
320 // VertexListGraph valid expressions
num_vertices(const ring_graph & g)321 vertices_size_type num_vertices(const ring_graph& g) { return g.n(); };
322 
vertices(const ring_graph & g)323 std::pair< vertex_iterator, vertex_iterator > vertices(const ring_graph& g)
324 {
325     return std::pair< vertex_iterator, vertex_iterator >(
326         vertex_iterator(0), // The first iterator position
327         vertex_iterator(num_vertices(g))); // The last iterator position
328 }
329 
330 /*
331 Iterator over edges in a ring graph.
332 
333 This object iterates over all the vertices in the graph, then for each
334 vertex returns its first outgoing edge.
335 
336 It is implemented with the boost::iterator_adaptor class, because it is
337 essentially a vertex_iterator with a customized deference operation.
338 */
339 class ring_edge_iterator
340 : public boost::iterator_adaptor< ring_edge_iterator, vertex_iterator,
341       edge_descriptor, boost::use_default, edge_descriptor >
342 {
343 public:
ring_edge_iterator()344     ring_edge_iterator()
345     : ring_edge_iterator::iterator_adaptor_(0), m_g(NULL) {};
ring_edge_iterator(const ring_graph & g,iterator_start)346     explicit ring_edge_iterator(const ring_graph& g, iterator_start)
347     : ring_edge_iterator::iterator_adaptor_(vertices(g).first), m_g(&g) {};
ring_edge_iterator(const ring_graph & g,iterator_end)348     explicit ring_edge_iterator(const ring_graph& g, iterator_end)
349     : ring_edge_iterator::iterator_adaptor_(
350         // Size 2 graphs have a single edge connecting the two vertices.
351         g.n() == 2 ? ++(vertices(g).first) : vertices(g).second)
352     , m_g(&g) {};
353 
354 private:
355     friend class boost::iterator_core_access;
356 
dereference() const357     edge_descriptor dereference() const
358     {
359         // The first element in the incident edge list of the current vertex.
360         return *(out_edges(*this->base_reference(), *m_g).first);
361     }
362 
363     // The graph being iterated over
364     const ring_graph* m_g;
365 };
366 
367 // EdgeListGraph valid expressions
edges(const ring_graph & g)368 std::pair< edge_iterator, edge_iterator > edges(const ring_graph& g)
369 {
370     return std::pair< edge_iterator, edge_iterator >(
371         ring_edge_iterator(g, iterator_start()),
372         ring_edge_iterator(g, iterator_end()));
373 }
374 
num_edges(const ring_graph & g)375 edges_size_type num_edges(const ring_graph& g)
376 {
377     // There are as many edges as there are vertices, except for size 2
378     // graphs, which have a single edge connecting the two vertices.
379     return g.n() == 2 ? 1 : g.n();
380 }
381 
382 // AdjacencyMatrix valid expressions
edge(vertex_descriptor u,vertex_descriptor v,const ring_graph & g)383 std::pair< edge_descriptor, bool > edge(
384     vertex_descriptor u, vertex_descriptor v, const ring_graph& g)
385 {
386     if ((u == v + 1 || v == u + 1) && u > 0 && u < num_vertices(g) && v > 0
387         && v < num_vertices(g))
388         return std::pair< edge_descriptor, bool >(edge_descriptor(u, v), true);
389     else
390         return std::pair< edge_descriptor, bool >(edge_descriptor(), false);
391 }
392 
393 /*
394 Map from edges to weight values
395 */
396 struct edge_weight_map
397 {
398     typedef double value_type;
399     typedef value_type reference;
400     typedef edge_descriptor key_type;
401     typedef boost::readable_property_map_tag category;
402 
403     // Edges have a weight equal to the average of their endpoint indexes.
operator []edge_weight_map404     reference operator[](key_type e) const
405     {
406         return (e.first + e.second) / 2.0;
407     }
408 };
409 
410 // Use these propety_map and property_traits parameterizations to refer to
411 // the associated property map types.
412 typedef boost::property_map< ring_graph, boost::edge_weight_t >::const_type
413     const_edge_weight_map;
414 typedef boost::property_traits< const_edge_weight_map >::reference
415     edge_weight_map_value_type;
416 typedef boost::property_traits< const_edge_weight_map >::key_type
417     edge_weight_map_key;
418 
419 // PropertyMap valid expressions
get(const_edge_weight_map pmap,edge_weight_map_key e)420 edge_weight_map_value_type get(
421     const_edge_weight_map pmap, edge_weight_map_key e)
422 {
423     return pmap[e];
424 }
425 
426 // ReadablePropertyGraph valid expressions
get(boost::edge_weight_t,const ring_graph &)427 const_edge_weight_map get(boost::edge_weight_t, const ring_graph&)
428 {
429     return const_edge_weight_map();
430 }
431 
get(boost::edge_weight_t tag,const ring_graph & g,edge_weight_map_key e)432 edge_weight_map_value_type get(
433     boost::edge_weight_t tag, const ring_graph& g, edge_weight_map_key e)
434 {
435     return get(tag, g)[e];
436 }
437 
438 // This expression is not part of a graph concept, but is used to return the
439 // default vertex index map used by the Dijkstra search algorithm.
get(boost::vertex_index_t,const ring_graph &)440 boost::identity_property_map get(boost::vertex_index_t, const ring_graph&)
441 {
442     // The vertex descriptors are already unsigned integer indices, so just
443     // return an identity map.
444     return boost::identity_property_map();
445 }
446 
447 // Print edges as (x, y)
operator <<(std::ostream & output,const edge_descriptor & e)448 std::ostream& operator<<(std::ostream& output, const edge_descriptor& e)
449 {
450     return output << "(" << e.first << ", " << e.second << ")";
451 }
452 
main(int argc,char const * argv[])453 int main(int argc, char const* argv[])
454 {
455     using namespace boost;
456     // Check the concepts that graph models.  This is included to demonstrate
457     // how concept checking works, but is not required for a working program
458     // since Boost algorithms do their own concept checking.
459     BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< ring_graph >));
460     BOOST_CONCEPT_ASSERT((AdjacencyGraphConcept< ring_graph >));
461     BOOST_CONCEPT_ASSERT((VertexListGraphConcept< ring_graph >));
462     BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< ring_graph >));
463     BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< ring_graph >));
464     BOOST_CONCEPT_ASSERT(
465         (ReadablePropertyMapConcept< const_edge_weight_map, edge_descriptor >));
466     BOOST_CONCEPT_ASSERT((ReadablePropertyGraphConcept< ring_graph,
467         edge_descriptor, edge_weight_t >));
468 
469     // Specify the size of the graph on the command line, or use a default size
470     // of 5.
471     std::size_t n = argc == 2 ? boost::lexical_cast< std::size_t >(argv[1]) : 5;
472 
473     // Create a small ring graph.
474     ring_graph g(n);
475 
476     // Print the outgoing edges of all the vertices.  For n=5 this will print:
477     //
478     // Vertices, outgoing edges, and adjacent vertices
479     // Vertex 0: (0, 1)  (0, 4)   Adjacent vertices 1 4
480     // Vertex 1: (1, 2)  (1, 0)   Adjacent vertices 2 0
481     // Vertex 2: (2, 3)  (2, 1)   Adjacent vertices 3 1
482     // Vertex 3: (3, 4)  (3, 2)   Adjacent vertices 4 2
483     // Vertex 4: (4, 0)  (4, 3)   Adjacent vertices 0 3
484     // 5 vertices
485     std::cout << "Vertices, outgoing edges, and adjacent vertices" << std::endl;
486     vertex_iterator vi, vi_end;
487     for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; vi++)
488     {
489         vertex_descriptor u = *vi;
490         std::cout << "Vertex " << u << ": ";
491         // Adjacenct edges
492         out_edge_iterator ei, ei_end;
493         for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ei++)
494             std::cout << *ei << "  ";
495         std::cout << " Adjacent vertices ";
496         // Adjacent vertices
497         // Here we want our adjacency_iterator and not
498         // boost::adjacency_iterator.
499         ::adjacency_iterator ai, ai_end;
500         for (boost::tie(ai, ai_end) = adjacent_vertices(u, g); ai != ai_end;
501              ai++)
502         {
503             std::cout << *ai << " ";
504         }
505         std::cout << std::endl;
506     }
507     std::cout << num_vertices(g) << " vertices" << std::endl << std::endl;
508 
509     // Print all the edges in the graph along with their weights.  For n=5 this
510     // will print:
511     //
512     // Edges and weights
513     // (0, 1) weight 0.5
514     // (1, 2) weight 1.5
515     // (2, 3) weight 2.5
516     // (3, 4) weight 3.5
517     // (4, 0) weight 2
518     // 5 edges
519     std::cout << "Edges and weights" << std::endl;
520     edge_iterator ei, ei_end;
521     for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ei++)
522     {
523         edge_descriptor e = *ei;
524         std::cout << e << " weight " << get(edge_weight, g, e) << std::endl;
525     }
526     std::cout << num_edges(g) << " edges" << std::endl;
527 
528     if (n > 0)
529     {
530         std::cout << std::endl;
531         // Do a Dijkstra search from vertex 0.  For n=5 this will print:
532         //
533         // Dijkstra search from vertex 0
534         // Vertex 0: parent 0, distance 0
535         // Vertex 1: parent 0, distance 0.5
536         // Vertex 2: parent 1, distance 2
537         // Vertex 3: parent 2, distance 4.5
538         // Vertex 4: parent 0, distance 2
539         vertex_descriptor source = 0;
540         std::vector< vertex_descriptor > pred(num_vertices(g));
541         std::vector< edge_weight_map_value_type > dist(num_vertices(g));
542         iterator_property_map< std::vector< vertex_descriptor >::iterator,
543             property_map< ring_graph, vertex_index_t >::const_type >
544             pred_pm(pred.begin(), get(vertex_index, g));
545         iterator_property_map<
546             std::vector< edge_weight_map_value_type >::iterator,
547             property_map< ring_graph, vertex_index_t >::const_type >
548             dist_pm(dist.begin(), get(vertex_index, g));
549 
550         dijkstra_shortest_paths(
551             g, source, predecessor_map(pred_pm).distance_map(dist_pm));
552 
553         std::cout << "Dijkstra search from vertex " << source << std::endl;
554         for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
555         {
556             vertex_descriptor u = *vi;
557             std::cout << "Vertex " << u << ": "
558                       << "parent " << pred[*vi] << ", "
559                       << "distance " << dist[u] << std::endl;
560         }
561     }
562 
563     return 0;
564 }
565