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