| 1 | <html> |
|---|
| 2 | |
|---|
| 3 | <!-- |
|---|
| 4 | -- Copyright (c) Jeremy Siek 2000 |
|---|
| 5 | -- |
|---|
| 6 | -- Distributed under the Boost Software License, Version 1.0. |
|---|
| 7 | -- (See accompanying file LICENSE_1_0.txt or copy at |
|---|
| 8 | -- http://www.boost.org/LICENSE_1_0.txt) |
|---|
| 9 | --> |
|---|
| 10 | |
|---|
| 11 | <head> |
|---|
| 12 | <title>Quick Tour of Boost Graph Library</title> |
|---|
| 13 | <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> |
|---|
| 14 | <meta name="ProgId" content="FrontPage.Editor.Document"> |
|---|
| 15 | </head> |
|---|
| 16 | |
|---|
| 17 | <body bgcolor="#ffffff" link="#0000ee" text="#000000" vlink="#551a8b" alink="#ff0000"> |
|---|
| 18 | |
|---|
| 19 | <img src="../../../boost.png" alt="C++ Boost" width="277" height="86"><br clear> |
|---|
| 20 | <h1>A Quick Tour of the Boost Graph Library</h1> |
|---|
| 21 | <p>The domain of graph data structures and algorithms is in some respects more |
|---|
| 22 | complicated than that of containers. The abstract iterator interface used by STL |
|---|
| 23 | is not sufficiently rich to encompass the numerous ways that graph algorithms |
|---|
| 24 | may traverse a graph. Instead, we formulate an abstract interface that serves |
|---|
| 25 | the same purpose for graphs that iterators do for basic containers (though |
|---|
| 26 | iterators still play a large role). <a href="#fig:analogy">Figure 1</a> depicts |
|---|
| 27 | the analogy between the STL and the BGL. |
|---|
| 28 | <p> </p> |
|---|
| 29 | <div align="CENTER"> |
|---|
| 30 | <a name="fig:analogy"></a><a name="752"></a> |
|---|
| 31 | <table> |
|---|
| 32 | <caption valign="bottom"><strong>Figure 1:</strong> The analogy between the |
|---|
| 33 | STL and the BGL.</caption> |
|---|
| 34 | <tr> |
|---|
| 35 | <td><img src="figs/analogy.gif" width="518" height="335"></td> |
|---|
| 36 | </tr> |
|---|
| 37 | </table> |
|---|
| 38 | </div> |
|---|
| 39 | <p> </p> |
|---|
| 40 | The graph abstraction consists of a set of vertices (or nodes), and a set of |
|---|
| 41 | edges (or arcs) that connect the vertices. <a href="#fig:quick-start">Figure 2</a> |
|---|
| 42 | depicts a directed graph with five vertices (labeled 0 through 4) and 11 edges. |
|---|
| 43 | The edges leaving a vertex are called the <i>out-edges</i> of the vertex. The |
|---|
| 44 | edges <tt>{(0,1),(0,2),(0,3),(0,4)}</tt> are all out-edges of vertex 0. The |
|---|
| 45 | edges entering a vertex are called the <i>in-edges</i> of the vertex. The edges <tt>{(0,4),(2,4),(3,4)}</tt> |
|---|
| 46 | are all in-edges of vertex 4. |
|---|
| 47 | <p> </p> |
|---|
| 48 | <div align="CENTER"> |
|---|
| 49 | <a name="fig:quick-start"></a> |
|---|
| 50 | <table> |
|---|
| 51 | <caption valign="bottom"><strong>Figure 2:</strong> An example of a directed |
|---|
| 52 | graph.</caption> |
|---|
| 53 | <tr> |
|---|
| 54 | <td><img src="figs/quick_start.gif" width="103" height="124"></td> |
|---|
| 55 | </tr> |
|---|
| 56 | </table> |
|---|
| 57 | </div> |
|---|
| 58 | <p> </p> |
|---|
| 59 | <p>In the following sections we will use the BGL to construct this example graph |
|---|
| 60 | and manipulate it in various ways. The complete source code for this example can |
|---|
| 61 | be found in <a href="../example/quick_tour.cpp"><tt>examples/quick_tour.cpp</tt></a>. |
|---|
| 62 | Each of the following sections discusses a "slice" of this example |
|---|
| 63 | file. Excerpts from the output of the example program will also be listed. |
|---|
| 64 | <p> |
|---|
| 65 | <h2>Constructing a Graph</h2> |
|---|
| 66 | <p>In this example we will use the BGL <a href="adjacency_list.html"><tt>adjacency_list</tt></a> |
|---|
| 67 | class to demonstrate the main ideas in the BGL interface. The <tt>adjacency_list</tt> |
|---|
| 68 | class provides a generalized version of the classic "adjacency list" |
|---|
| 69 | data structure. The <tt>adjacency_list</tt> is a template class with six |
|---|
| 70 | template parameters, though here we only fill in the first three parameters and |
|---|
| 71 | use the defaults for the remaining three. The first two template arguments (<tt>vecS, |
|---|
| 72 | vecS</tt>) determine the data structure used to represent the out-edges for each |
|---|
| 73 | vertex in the graph and the data structure used to represent the graph's vertex |
|---|
| 74 | set (see section <a href="using_adjacency_list.html#sec:choosing-graph-type">Choosing |
|---|
| 75 | the <tt>Edgelist</tt> and <tt>VertexList</tt></a> for information about the |
|---|
| 76 | tradeoffs of the different data structures). The third argument, <tt>bidirectionalS</tt>, |
|---|
| 77 | selects a directed graph that provides access to both out and in-edges. The |
|---|
| 78 | other options for the third argument are <tt>directedS</tt> which selects a |
|---|
| 79 | directed graph with only out-edges, and <tt>undirectedS</tt> which selects an |
|---|
| 80 | undirected graph. |
|---|
| 81 | <p>Once we have the graph type selected, we can create the graph in <a href="#fig:quick-start">Figure |
|---|
| 82 | 2</a> by declaring a graph object and filling in edges using the <a href="MutableGraph.html#sec:add-edge"><tt>add_edge()</tt></a> |
|---|
| 83 | function of the <a href="MutableGraph.html">MutableGraph</a> interface (which <tt>adjacency_list</tt> |
|---|
| 84 | implements). We use the array of pairs <tt>edge_array</tt> merely as a |
|---|
| 85 | convenient way to explicitly create the edges for this example. |
|---|
| 86 | <p> |
|---|
| 87 | <pre> |
|---|
| 88 | #include <iostream> // for std::cout |
|---|
| 89 | #include <utility> // for std::pair |
|---|
| 90 | #include <algorithm> // for std::for_each |
|---|
| 91 | #include <boost/graph/graph_traits.hpp> |
|---|
| 92 | #include <boost/graph/adjacency_list.hpp> |
|---|
| 93 | #include <boost/graph/dijkstra_shortest_paths.hpp> |
|---|
| 94 | |
|---|
| 95 | using namespace boost; |
|---|
| 96 | |
|---|
| 97 | int main(int,char*[]) |
|---|
| 98 | { |
|---|
| 99 | // create a typedef for the Graph type |
|---|
| 100 | typedef adjacency_list<vecS, vecS, bidirectionalS> Graph; |
|---|
| 101 | |
|---|
| 102 | // Make convenient labels for the vertices |
|---|
| 103 | enum { A, B, C, D, E, N }; |
|---|
| 104 | const int num_vertices = N; |
|---|
| 105 | const char* name = "ABCDE"; |
|---|
| 106 | |
|---|
| 107 | // writing out the edges in the graph |
|---|
| 108 | typedef std::pair<int, int> Edge; |
|---|
| 109 | Edge edge_array[] = |
|---|
| 110 | { Edge(A,B), Edge(A,D), Edge(C,A), Edge(D,C), |
|---|
| 111 | Edge(C,E), Edge(B,D), Edge(D,E) }; |
|---|
| 112 | const int num_edges = sizeof(edge_array)/sizeof(edge_array[0]); |
|---|
| 113 | |
|---|
| 114 | // declare a graph object |
|---|
| 115 | Graph g(num_vertices); |
|---|
| 116 | |
|---|
| 117 | // add the edges to the graph object |
|---|
| 118 | for (int i = 0; i < num_edges; ++i) |
|---|
| 119 | add_edge(edge_array[i].first, edge_array[i].second, g); |
|---|
| 120 | ... |
|---|
| 121 | return 0; |
|---|
| 122 | } |
|---|
| 123 | </pre> |
|---|
| 124 | <p>Instead of calling the <tt>add_edge()</tt> function for each edge, we could |
|---|
| 125 | use the <a href="adjacency_list.html#sec:iterator-constructor">edge iterator |
|---|
| 126 | constructor</a> of the graph. This is typically more efficient than using <tt>add_edge()</tt>. |
|---|
| 127 | Pointers to the <tt>edge_array</tt> can be viewed as iterators, so we can call |
|---|
| 128 | the iterator constructor by passing pointers to the beginning and end of the |
|---|
| 129 | array. |
|---|
| 130 | <pre> |
|---|
| 131 | Graph g(edge_array, edge_array + sizeof(edge_array) / sizeof(Edge), num_vertices); |
|---|
| 132 | </pre> |
|---|
| 133 | <p>Instead of creating a graph with a certain number of vertices to begin with, |
|---|
| 134 | it is also possible to add and remove vertices with the <a href="MutableGraph.html#sec:add-vertex"><tt>add_vertex()</tt></a> |
|---|
| 135 | and <a href="MutableGraph.html#sec:remove-vertex"><tt>remove_vertex()</tt></a> |
|---|
| 136 | functions, also of the <a href="MutableGraph.html">MutableGraph</a> interface. |
|---|
| 137 | <h2>Accessing the Vertex Set</h2> |
|---|
| 138 | <p>Now that we have created a graph, we can use the graph interface to access |
|---|
| 139 | the graph data in different ways. First we can access all of the vertices in the |
|---|
| 140 | graph using the <a href="VertexListGraph.html#sec:vertices"><tt>vertices()</tt></a> |
|---|
| 141 | function of the <a href="VertexListGraph.html">VertexListGraph</a> interface. |
|---|
| 142 | This function returns a <tt>std::pair</tt> of <i>vertex iterators</i> (the <tt>first</tt> |
|---|
| 143 | iterator points to the "beginning" of the vertices and the <tt>second</tt> |
|---|
| 144 | iterator points "past the end"). Dereferencing a vertex iterator gives |
|---|
| 145 | a vertex object. The type of the vertex iterator is given by the <a href="graph_traits.html"><tt>graph_traits</tt></a> |
|---|
| 146 | class. Note that different graph classes can have different associated vertex |
|---|
| 147 | iterator types, which is why we need the <tt>graph_traits</tt> class. Given some |
|---|
| 148 | graph type, the <tt>graph_traits</tt> class will provide access to the <tt>vertex_iterator</tt> |
|---|
| 149 | type. |
|---|
| 150 | <p>The following example prints out the index for each of the vertices in the |
|---|
| 151 | graph. All vertex and edge properties, including index, are accessed via |
|---|
| 152 | property map objects. The <a href="property_map.html"><tt>property_map</tt></a> |
|---|
| 153 | class is used to obtain the property map type for a specific property (specified |
|---|
| 154 | by <tt>vertex_index_t</tt>, one of the BGL predefined properties) and function |
|---|
| 155 | call <tt>get(vertex_index, g)</tt> returns the actual property map object. |
|---|
| 156 | <p> |
|---|
| 157 | <pre> |
|---|
| 158 | // ... |
|---|
| 159 | int main(int,char*[]) |
|---|
| 160 | { |
|---|
| 161 | // ... |
|---|
| 162 | |
|---|
| 163 | // get the property map for vertex indices |
|---|
| 164 | typedef property_map<Graph, vertex_index_t>::type IndexMap; |
|---|
| 165 | IndexMap index = get(vertex_index, g); |
|---|
| 166 | |
|---|
| 167 | std::cout << "vertices(g) = "; |
|---|
| 168 | typedef graph_traits<Graph>::vertex_iterator vertex_iter; |
|---|
| 169 | std::pair<vertex_iter, vertex_iter> vp; |
|---|
| 170 | for (vp = vertices(g); vp.first != vp.second; ++vp.first) |
|---|
| 171 | std::cout << index[*vp.first] << " "; |
|---|
| 172 | std::cout << std::endl; |
|---|
| 173 | // ... |
|---|
| 174 | return 0; |
|---|
| 175 | } |
|---|
| 176 | </pre> |
|---|
| 177 | The output is: |
|---|
| 178 | <pre> |
|---|
| 179 | vertices(g) = 0 1 2 3 4 |
|---|
| 180 | </pre> |
|---|
| 181 | <p> |
|---|
| 182 | <h2>Accessing the Edge Set</h2> |
|---|
| 183 | <p>The set of edges for a graph can be accessed with the <a href="EdgeListGraph.html#sec:edges"><tt>edges()</tt></a> |
|---|
| 184 | function of the <a href="EdgeListGraph.html">EdgeListGraph</a> interface. |
|---|
| 185 | Similar to the <tt>vertices()</tt> function, this returns a pair of iterators, |
|---|
| 186 | but in this case the iterators are <i>edge iterators</i>. Dereferencing an edge |
|---|
| 187 | iterator gives an edge object. The <tt>source()</tt> and <tt>target()</tt> |
|---|
| 188 | functions return the two vertices that are connected by the edge. Instead of |
|---|
| 189 | explicitly creating a <tt>std::pair</tt> for the iterators, this time we will |
|---|
| 190 | use the <a href="../../tuple/doc/tuple_users_guide.html#tiers"><tt>tie()</tt></a> helper function. |
|---|
| 191 | This handy function can be used to assign the parts of a <tt>std::pair</tt> into |
|---|
| 192 | two separate variables, in this case <tt>ei</tt> and <tt>ei_end</tt>. This is |
|---|
| 193 | usually more convenient than creating a <tt>std::pair</tt> and is our method of |
|---|
| 194 | choice for the BGL. |
|---|
| 195 | <p> |
|---|
| 196 | <pre> |
|---|
| 197 | // ... |
|---|
| 198 | int main(int,char*[]) |
|---|
| 199 | { |
|---|
| 200 | // ... |
|---|
| 201 | std::cout << "edges(g) = "; |
|---|
| 202 | graph_traits<Graph>::edge_iterator ei, ei_end; |
|---|
| 203 | for (tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) |
|---|
| 204 | std::cout << "(" << index[source(*ei, g)] |
|---|
| 205 | << "," << index[target(*ei, g)] << ") "; |
|---|
| 206 | std::cout << std::endl; |
|---|
| 207 | // ... |
|---|
| 208 | return 0; |
|---|
| 209 | } |
|---|
| 210 | </pre> |
|---|
| 211 | The output is: |
|---|
| 212 | <pre> |
|---|
| 213 | edges(g) = (0,1) (0,2) (0,3) (0,4) (2,0) (2,4) (3,0) |
|---|
| 214 | (3,1) (3,4) (4,0) (4,1) |
|---|
| 215 | </pre> |
|---|
| 216 | <p> |
|---|
| 217 | <h2>The Adjacency Structure</h2> |
|---|
| 218 | <p>In the next few examples we will explore the adjacency structure of the graph |
|---|
| 219 | from the point of view of a particular vertex. We will look at the vertices' |
|---|
| 220 | in-edges, out-edges, and its adjacent vertices. We will encapsulate this in an |
|---|
| 221 | "exercise vertex" function, and apply it to each vertex in the graph. |
|---|
| 222 | To demonstrate the STL-interoperability of BGL, we will use the STL <tt>for_each()</tt> |
|---|
| 223 | function to iterate through the vertices and apply the function. |
|---|
| 224 | <p> |
|---|
| 225 | <pre> |
|---|
| 226 | //... |
|---|
| 227 | int main(int,char*[]) |
|---|
| 228 | { |
|---|
| 229 | //... |
|---|
| 230 | std::for_each(vertices(g).first, vertices(g).second, |
|---|
| 231 | exercise_vertex<Graph>(g)); |
|---|
| 232 | return 0; |
|---|
| 233 | } |
|---|
| 234 | </pre> |
|---|
| 235 | <p>We use a functor for <tt>exercise_vertex</tt> instead of just a function |
|---|
| 236 | because the graph object will be needed when we access information about each |
|---|
| 237 | vertex; using a functor gives us a place to keep a reference to the graph object |
|---|
| 238 | during the execution of the <tt>std::for_each()</tt>. Also we template the |
|---|
| 239 | functor on the graph type so that it is reusable with different graph classes. |
|---|
| 240 | Here is the start of the <tt>exercise_vertex</tt> functor: |
|---|
| 241 | <p> |
|---|
| 242 | <pre> |
|---|
| 243 | template <class Graph> struct exercise_vertex { |
|---|
| 244 | exercise_vertex(Graph& g_) : g(g_) {} |
|---|
| 245 | //... |
|---|
| 246 | Graph& g; |
|---|
| 247 | }; |
|---|
| 248 | </pre> |
|---|
| 249 | <p> |
|---|
| 250 | <h3>Vertex Descriptors</h3> |
|---|
| 251 | <p>The first thing we need to know in order to write the <tt>operator()</tt> |
|---|
| 252 | method of the functor is the type for the vertex objects of the graph. The |
|---|
| 253 | vertex type will be the parameter to the <tt>operator()</tt> method. To be |
|---|
| 254 | precise, we do not deal with actual vertex objects, but rather with <i>vertex |
|---|
| 255 | descriptors</i>. Many graph representations (such as adjacency lists) do not |
|---|
| 256 | store actual vertex objects, while others do (e.g., pointer-linked graphs). This |
|---|
| 257 | difference is hidden underneath the "black-box" of the vertex |
|---|
| 258 | descriptor object. The vertex descriptor is something provided by each graph |
|---|
| 259 | type that can be used to access information about the graph via the <tt>out_edges()</tt>, |
|---|
| 260 | <tt>in_edges()</tt>, <tt>adjacent_vertices()</tt>, and property map functions |
|---|
| 261 | that are described in the following sections. The <tt>vertex_descriptor</tt> |
|---|
| 262 | type is obtained through the <tt>graph_traits</tt> class. The <tt>typename</tt> |
|---|
| 263 | keyword used below is necessary because the type on the left hand side of the |
|---|
| 264 | scope <tt>::</tt> operator (the <tt>graph_traits<Graph></tt> type) is |
|---|
| 265 | dependent on a template parameter (the <tt>Graph</tt> type). Here is how we |
|---|
| 266 | define the functor's apply method: |
|---|
| 267 | <p> |
|---|
| 268 | <pre> |
|---|
| 269 | template <class Graph> struct exercise_vertex { |
|---|
| 270 | //... |
|---|
| 271 | typedef typename graph_traits<Graph> |
|---|
| 272 | ::vertex_descriptor Vertex; |
|---|
| 273 | |
|---|
| 274 | void operator()(const Vertex& v) const |
|---|
| 275 | { |
|---|
| 276 | //... |
|---|
| 277 | } |
|---|
| 278 | //... |
|---|
| 279 | }; |
|---|
| 280 | </pre> |
|---|
| 281 | <p> |
|---|
| 282 | <h3>Out-Edges, In-Edges, and Edge Descriptors</h3> |
|---|
| 283 | <p>The out-edges of a vertex are accessed with the <a href="IncidenceGraph.html#sec:out-edges"><tt>out_edges()</tt></a> |
|---|
| 284 | function of the <a href="IncidenceGraph.html">IncidenceGraph</a> interface. The <tt>out_edges()</tt> |
|---|
| 285 | function takes two arguments: the first argument is the vertex and the second is |
|---|
| 286 | the graph object. The function returns a pair of iterators which provide access |
|---|
| 287 | to all of the out-edges of a vertex (similar to how the <tt>vertices()</tt> |
|---|
| 288 | function returned a pair of iterators). The iterators are called <i>out-edge |
|---|
| 289 | iterators</i> and dereferencing one of these iterators gives an <i>edge |
|---|
| 290 | descriptor</i> object. An edge descriptor plays the same kind of role as the |
|---|
| 291 | vertex descriptor object, it is a "black box" provided by the graph |
|---|
| 292 | type. The following code snippet prints the source-target pairs for each |
|---|
| 293 | out-edge of vertex <tt>v</tt>. |
|---|
| 294 | <p> |
|---|
| 295 | <pre> |
|---|
| 296 | template <class Graph> struct exercise_vertex { |
|---|
| 297 | //... |
|---|
| 298 | void operator()(const Vertex& v) const |
|---|
| 299 | { |
|---|
| 300 | typedef graph_traits<Graph> GraphTraits; |
|---|
| 301 | typename property_map<Graph, vertex_index_t>::type |
|---|
| 302 | index = get(vertex_index, g); |
|---|
| 303 | |
|---|
| 304 | std::cout << "out-edges: "; |
|---|
| 305 | typename GraphTraits::out_edge_iterator out_i, out_end; |
|---|
| 306 | typename GraphTraits::edge_descriptor e; |
|---|
| 307 | for (tie(out_i, out_end) = out_edges(v, g); |
|---|
| 308 | out_i != out_end; ++out_i) { |
|---|
| 309 | e = *out_i; |
|---|
| 310 | Vertex src = source(e, g), targ = target(e, g); |
|---|
| 311 | std::cout << "(" << index[src] << "," |
|---|
| 312 | << index[targ] << ") "; |
|---|
| 313 | } |
|---|
| 314 | std::cout << std::endl; |
|---|
| 315 | //... |
|---|
| 316 | } |
|---|
| 317 | //... |
|---|
| 318 | }; |
|---|
| 319 | </pre> |
|---|
| 320 | For vertex 0 the output is: |
|---|
| 321 | <pre> |
|---|
| 322 | out-edges: (0,1) (0,2) (0,3) (0,4) |
|---|
| 323 | </pre> |
|---|
| 324 | <p>The <a href="BidirectionalGraph.html#sec:in-edges"><tt>in_edges()</tt></a> |
|---|
| 325 | function of the <a href="BidirectionalGraph.html">BidirectionalGraph</a> |
|---|
| 326 | interface provides access to all the in-edges of a vertex through <i>in-edge |
|---|
| 327 | iterators</i>. The <tt>in_edges()</tt> function is only available for the <tt>adjacency_list</tt> |
|---|
| 328 | if <tt>bidirectionalS</tt> is supplied for the <tt>Directed</tt> template |
|---|
| 329 | parameter. There is an extra cost in space when <tt>bidirectionalS</tt> is |
|---|
| 330 | specified instead of <tt>directedS</tt>. |
|---|
| 331 | <p> |
|---|
| 332 | <pre> |
|---|
| 333 | template <class Graph> struct exercise_vertex { |
|---|
| 334 | //... |
|---|
| 335 | void operator()(const Vertex& v) const |
|---|
| 336 | { |
|---|
| 337 | //... |
|---|
| 338 | std::cout << "in-edges: "; |
|---|
| 339 | typedef typename graph_traits<Graph> GraphTraits; |
|---|
| 340 | typename GraphTraits::in_edge_iterator in_i, in_end; |
|---|
| 341 | for (tie(in_i, in_end) = in_edges(v,g); |
|---|
| 342 | in_i != in_end; ++in_i) { |
|---|
| 343 | e = *in_i; |
|---|
| 344 | Vertex src = source(e, g), targ = target(e, g); |
|---|
| 345 | std::cout << "(" << index[src] << "," << index[targ] << ") "; |
|---|
| 346 | } |
|---|
| 347 | std::cout << std::endl; |
|---|
| 348 | //... |
|---|
| 349 | } |
|---|
| 350 | //... |
|---|
| 351 | }; |
|---|
| 352 | </pre> |
|---|
| 353 | For vertex 0 the output is: |
|---|
| 354 | <pre> |
|---|
| 355 | in-edges: (2,0) (3,0) (4,0) |
|---|
| 356 | </pre> |
|---|
| 357 | <p> |
|---|
| 358 | <h3>Adjacent Vertices</h3> |
|---|
| 359 | <p>Given the out-edges of a vertex, the target vertices of these edges are <i>adjacent</i> |
|---|
| 360 | to the source vertex. Sometimes an algorithm does not need to look at the edges |
|---|
| 361 | of the graph and only cares about the vertices. Therefore the graph interface |
|---|
| 362 | also includes the <a href="AdjacencyGraph.html#sec:adjacent-vertices"><tt>adjacent_vertices()</tt></a> |
|---|
| 363 | function of the <a href="AdjacencyGraph.html">AdjacencyGraph</a> interface which |
|---|
| 364 | provides direct access to the adjacent vertices. This function returns a pair of |
|---|
| 365 | <i>adjacency iterators</i>. Dereferencing an adjacency iterator gives a vertex |
|---|
| 366 | descriptor for an adjacent vertex. |
|---|
| 367 | <p> |
|---|
| 368 | <pre> |
|---|
| 369 | template <class Graph> struct exercise_vertex { |
|---|
| 370 | //... |
|---|
| 371 | void operator()(Vertex v) const |
|---|
| 372 | { |
|---|
| 373 | //... |
|---|
| 374 | std::cout << "adjacent vertices: "; |
|---|
| 375 | typename graph_traits<Graph>::adjacency_iterator ai; |
|---|
| 376 | typename graph_traits<Graph>::adjacency_iterator ai_end; |
|---|
| 377 | for (tie(ai, ai_end) = adjacent_vertices(v, g); |
|---|
| 378 | ai != ai_end; ++ai) |
|---|
| 379 | std::cout << index[*ai] << " "; |
|---|
| 380 | std::cout << std::endl; |
|---|
| 381 | } |
|---|
| 382 | //... |
|---|
| 383 | }; |
|---|
| 384 | </pre> |
|---|
| 385 | For vertex 4 the output is: |
|---|
| 386 | <pre> |
|---|
| 387 | adjacent vertices: 0 1 |
|---|
| 388 | </pre> |
|---|
| 389 | <p> |
|---|
| 390 | <h2>Adding Some Color to your Graph</h2> |
|---|
| 391 | <p>BGL attempts to be as flexible as possible in terms of accommodating how |
|---|
| 392 | properties are attached to a graph. For instance, a property such as edge weight |
|---|
| 393 | may need to be used throughout a graph object's lifespan and therefore it would |
|---|
| 394 | be convenient to have the graph object also manage the property storage. On the |
|---|
| 395 | other hand, a property like vertex color may only be needed for the duration of |
|---|
| 396 | a single algorithm, and it would be better to have the property stored |
|---|
| 397 | separately from the graph object. The first kind of property is called an <i>internally |
|---|
| 398 | stored property</i> while the second kind is called an <i>externally stored |
|---|
| 399 | property</i>. BGL uses a uniform mechanism to access both kinds of properties |
|---|
| 400 | inside its graph algorithms called the <i>property map</i> interface, described |
|---|
| 401 | in Section <a href="property_map.html">Property Map Concepts</a>. In addition, |
|---|
| 402 | the <a href="PropertyGraph.html">PropertyGraph</a> concept defines the interface |
|---|
| 403 | for obtaining a property map object for an internally stored property. |
|---|
| 404 | <p>The BGL <tt>adjacency_list</tt> class allows users to specify internally |
|---|
| 405 | stored properties through plug-in template parameters of the graph class. How to |
|---|
| 406 | do this is discussed in detail in Section <a href="using_adjacency_list.html#sec:adjacency-list-properties">Internal |
|---|
| 407 | Properties</a>. Externally stored properties can be created in many different |
|---|
| 408 | ways, although they are ultimately passed as separate arguments to the graph |
|---|
| 409 | algorithms. One straightforward way to store properties is to create an array |
|---|
| 410 | indexed by vertex or edge index. In the <tt>adjacency_list</tt> with <tt>vecS</tt> |
|---|
| 411 | specified for the <tt>VertexList</tt> template parameter, vertices are |
|---|
| 412 | automatically assigned indices, which can be accessed via the property map for |
|---|
| 413 | the <tt>vertex_index_t</tt>. Edges are not automatically assigned indices. |
|---|
| 414 | However the property mechanism can be used to attach indices to the edges which |
|---|
| 415 | can be used to index into other externally stored properties. |
|---|
| 416 | <p>In the following example, we construct a graph and apply <a href="dijkstra_shortest_paths.html"><tt>dijkstra_shortest_paths()</tt></a>. |
|---|
| 417 | The complete source code for the example is in <a href="../example/dijkstra-example.cpp"><tt>examples/dijkstra-example.cpp</tt></a>. |
|---|
| 418 | Dijkstra's algorithm computes the shortest distance from the starting vertex to |
|---|
| 419 | every other vertex in the graph. |
|---|
| 420 | <p>Dijkstra's algorithm requires that a weight property is associated with each |
|---|
| 421 | edge and a distance property with each vertex. Here we use an internal property |
|---|
| 422 | for the weight and an external property for the distance. For the weight |
|---|
| 423 | property we use the <tt>property</tt> class and specify <tt>int</tt> as the type |
|---|
| 424 | used to represent weight values and <tt>edge_weight_t</tt> for the property tag |
|---|
| 425 | (which is one of the BGL predefined property tags). The weight property is then |
|---|
| 426 | used as a template argument for <tt>adjacency_list</tt>. |
|---|
| 427 | <p>The <tt>listS</tt> and <tt>vecS</tt> types are selectors that determine the |
|---|
| 428 | data structure used inside the <tt>adjacency_list</tt> (see Section <a href="using_adjacency_list.html#sec:choosing-graph-type">Choosing |
|---|
| 429 | the <tt>Edgelist</tt> and <tt>VertexList</tt></a>). The <tt>directedS</tt> type |
|---|
| 430 | specifies that the graph should be directed (versus undirected). The following |
|---|
| 431 | code shows the specification of the graph type and then the initialization of |
|---|
| 432 | the graph. The edges and weights are passed to the graph constructor in the form |
|---|
| 433 | of iterators (a pointer qualifies as a <a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">RandomAccessIterator</a>). |
|---|
| 434 | <p> |
|---|
| 435 | <pre> |
|---|
| 436 | typedef adjacency_list<listS, vecS, directedS, |
|---|
| 437 | no_property, property<edge_weight_t, int> > Graph; |
|---|
| 438 | typedef graph_traits<Graph>::vertex_descriptor Vertex; |
|---|
| 439 | typedef std::pair<int,int> E; |
|---|
| 440 | |
|---|
| 441 | const int num_nodes = 5; |
|---|
| 442 | E edges[] = { E(0,2), |
|---|
| 443 | E(1,1), E(1,3), E(1,4), |
|---|
| 444 | E(2,1), E(2,3), |
|---|
| 445 | E(3,4), |
|---|
| 446 | E(4,0), E(4,1) }; |
|---|
| 447 | int weights[] = { 1, 2, 1, 2, 7, 3, 1, 1, 1}; |
|---|
| 448 | |
|---|
| 449 | Graph G(edges + sizeof(edges) / sizeof(E), weights, num_nodes); |
|---|
| 450 | </pre> |
|---|
| 451 | <p>For the external distance property we will use a <tt>std::vector</tt> for |
|---|
| 452 | storage. BGL algorithms treat random access iterators as property maps, so we |
|---|
| 453 | can just pass the beginning iterator of the distance vector to Dijkstra's |
|---|
| 454 | algorithm. Continuing the above example, the following code shows the creation |
|---|
| 455 | of the distance vector, the call to Dijkstra's algorithm (implicitly using the |
|---|
| 456 | internal edge weight property), and then the output of the results. |
|---|
| 457 | <p> |
|---|
| 458 | <pre> |
|---|
| 459 | // vector for storing distance property |
|---|
| 460 | std::vector<int> d(num_vertices(G)); |
|---|
| 461 | |
|---|
| 462 | // get the first vertex |
|---|
| 463 | Vertex s = *(vertices(G).first); |
|---|
| 464 | // invoke variant 2 of Dijkstra's algorithm |
|---|
| 465 | dijkstra_shortest_paths(G, s, distance_map(&d[0])); |
|---|
| 466 | |
|---|
| 467 | std::cout << "distances from start vertex:" << std::endl; |
|---|
| 468 | graph_traits<Graph>::vertex_iterator vi; |
|---|
| 469 | for(vi = vertices(G).first; vi != vertices(G).second; ++vi) |
|---|
| 470 | std::cout << "distance(" << index(*vi) << ") = " |
|---|
| 471 | << d[*vi] << std::endl; |
|---|
| 472 | std::cout << std::endl; |
|---|
| 473 | </pre> |
|---|
| 474 | The output is: |
|---|
| 475 | <pre> |
|---|
| 476 | distances from start vertex: |
|---|
| 477 | distance(0) = 0 |
|---|
| 478 | distance(1) = 6 |
|---|
| 479 | distance(2) = 1 |
|---|
| 480 | distance(3) = 4 |
|---|
| 481 | distance(4) = 5 |
|---|
| 482 | </pre> |
|---|
| 483 | <p> |
|---|
| 484 | <h2>Extending Algorithms with Visitors</h2> |
|---|
| 485 | <p>Often times an algorithm in a library <i>almost</i> does what you need, but |
|---|
| 486 | not quite. For example, in the previous section we used Dijkstra's algorithm to |
|---|
| 487 | calculate the shortest distances to each vertex, but perhaps we also wanted to |
|---|
| 488 | record the tree of shortest paths. One way to do this is to record the |
|---|
| 489 | predecessor (parent) for each node in the shortest-paths tree. |
|---|
| 490 | <p>It would be nice if we could avoid rewriting Dijkstra's algorithm, and just |
|---|
| 491 | add that little bit extra needed to record the predecessors <a href="#1">[1]</a>. In the STL, this |
|---|
| 492 | kind of extensibility is provided by functors, which are optional parameters to |
|---|
| 493 | each algorithm. In the BGL this role is fulfilled by <i>visitors</i>. |
|---|
| 494 | <p>A visitor is like a functor, but instead of having just one "apply" |
|---|
| 495 | method, it has several. Each of these methods get invoked at certain |
|---|
| 496 | well-defined points within the algorithm. The visitor methods are explained in |
|---|
| 497 | detail in Section <a href="visitor_concepts.html">Visitor Concepts</a>. The BGL |
|---|
| 498 | provides a number of visitors for some common tasks including a predecessor |
|---|
| 499 | recording visitor. The user is encouraged to write his or her own visitors as a |
|---|
| 500 | way of extending the BGL. Here we will take a quick look at the implementation |
|---|
| 501 | and use of the predecessor recorder. Since we will be using the <a href="dijkstra_shortest_paths.html">dijkstra_shortest_paths()</a> |
|---|
| 502 | algorithm, the visitor we create must be a <a href="DijkstraVisitor.html">Dijkstra Visitor</a>. |
|---|
| 503 | <p>The functionality of the <tt>record_predecessors</tt> visitor is separated |
|---|
| 504 | into two parts. For the storage and access of the predecessor property, we will |
|---|
| 505 | use a <a href="../../property_map/property_map.html">property map</a>. The |
|---|
| 506 | predecessor visitor will then only be responsible for what parent to record. To |
|---|
| 507 | implement this, we create a <tt>record_predecessors</tt> class and template it |
|---|
| 508 | on the predecessor property map <tt>PredecessorMap</tt>. Since this visitor will |
|---|
| 509 | only be filling in one of the visitor methods, we will inherit from <a href="dijkstra_visitor.html"><tt>dijkstra_visitor</tt></a> |
|---|
| 510 | which will provide empty methods for the rest. The constructor of the <tt>predecessor_recorder</tt> |
|---|
| 511 | will take the property map object and save it away in a data member. |
|---|
| 512 | <p> |
|---|
| 513 | <pre> |
|---|
| 514 | template <class PredecessorMap> |
|---|
| 515 | class record_predecessors : public dijkstra_visitor<> |
|---|
| 516 | { |
|---|
| 517 | public: |
|---|
| 518 | record_predecessors(PredecessorMap p) |
|---|
| 519 | : m_predecessor(p) { } |
|---|
| 520 | |
|---|
| 521 | template <class Edge, class Graph> |
|---|
| 522 | void edge_relaxed(Edge e, Graph& g) { |
|---|
| 523 | // set the parent of the target(e) to source(e) |
|---|
| 524 | put(m_predecessor, target(e, g), source(e, g)); |
|---|
| 525 | } |
|---|
| 526 | protected: |
|---|
| 527 | PredecessorMap m_predecessor; |
|---|
| 528 | }; |
|---|
| 529 | </pre> |
|---|
| 530 | <p>The job of recording the predecessors is quite simple. When Dijkstra's |
|---|
| 531 | algorithm relaxes an edge (potentially adding it to the shortest-paths tree) we |
|---|
| 532 | record the source vertex as the predecessor of the target vertex. Later, if the |
|---|
| 533 | edge is relaxed again the predecessor property will be overwritten by the new |
|---|
| 534 | predecessor. Here we use the <tt>put()</tt> function associated with the |
|---|
| 535 | property map to record the predecessor. The <tt>edge_filter</tt> of the visitor |
|---|
| 536 | tells the algorithm when to invoke the <tt>explore()</tt> method. In this case |
|---|
| 537 | we only want to be notified about edges in the shortest-paths tree so we specify |
|---|
| 538 | <tt>tree_edge_tag</tt>. |
|---|
| 539 | <p>As a finishing touch, we create a helper function to make it more convenient |
|---|
| 540 | to create predecessor visitors. All BGL visitors have a helper function like |
|---|
| 541 | this. |
|---|
| 542 | <p> |
|---|
| 543 | <pre> |
|---|
| 544 | template <class PredecessorMap> |
|---|
| 545 | record_predecessors<PredecessorMap> |
|---|
| 546 | make_predecessor_recorder(PredecessorMap p) { |
|---|
| 547 | return record_predecessors<PredecessorMap>(p); |
|---|
| 548 | } |
|---|
| 549 | </pre> |
|---|
| 550 | <p>We are now ready to use the <tt>record_predecessors</tt> in |
|---|
| 551 | Dijkstra's algorithm. Luckily, BGL's Dijkstra's algorithm is already |
|---|
| 552 | equipped to handle visitors, so we just pass in our new visitor. In |
|---|
| 553 | this example we only need to use one visitor, but the BGL is also |
|---|
| 554 | equipped to handle the use of multiple visitors in the same algorithm |
|---|
| 555 | (see Section <a href="visitor_concepts.html">Visitor Concepts</a>). |
|---|
| 556 | <p> |
|---|
| 557 | <pre> |
|---|
| 558 | using std::vector; |
|---|
| 559 | using std::cout; |
|---|
| 560 | using std::endl; |
|---|
| 561 | vector<Vertex> p(num_vertices(G)); //the predecessor array |
|---|
| 562 | dijkstra_shortest_paths(G, s, distance_map(&d[0]). |
|---|
| 563 | visitor(make_predecessor_recorder(&p[0]))); |
|---|
| 564 | |
|---|
| 565 | cout << "parents in the tree of shortest paths:" << endl; |
|---|
| 566 | for(vi = vertices(G).first; vi != vertices(G).second; ++vi) { |
|---|
| 567 | cout << "parent(" << *vi; |
|---|
| 568 | if (p[*vi] == Vertex()) |
|---|
| 569 | cout << ") = no parent" << endl; |
|---|
| 570 | else |
|---|
| 571 | cout << ") = " << p[*vi] << endl; |
|---|
| 572 | } |
|---|
| 573 | </pre> |
|---|
| 574 | The output is: |
|---|
| 575 | <pre> |
|---|
| 576 | parents in the tree of shortest paths: |
|---|
| 577 | parent(0) = no parent |
|---|
| 578 | parent(1) = 4 |
|---|
| 579 | parent(2) = 0 |
|---|
| 580 | parent(3) = 2 |
|---|
| 581 | parent(4) = 3 |
|---|
| 582 | </pre> |
|---|
| 583 | |
|---|
| 584 | <br> |
|---|
| 585 | |
|---|
| 586 | <h3>Notes</h3> |
|---|
| 587 | |
|---|
| 588 | <a name="1">[1]</a> The new version of Dijkstra's algorithm now includes |
|---|
| 589 | a named parameter for recording predecessors, so a predecessor visitor |
|---|
| 590 | is no long necessary, though this still makes for a good example. |
|---|
| 591 | |
|---|
| 592 | <br> |
|---|
| 593 | <hr> |
|---|
| 594 | <table> |
|---|
| 595 | <tr valign="top"> |
|---|
| 596 | <td nowrap>Copyright © 2000</td> |
|---|
| 597 | <td><a href="../../../people/jeremy_siek.htm">Jeremy Siek</a>, |
|---|
| 598 | Indiana University (<a href="mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</a>)</td> |
|---|
| 599 | </tr> |
|---|
| 600 | </table> |
|---|
| 601 | |
|---|
| 602 | </body> |
|---|
| 603 | |
|---|
| 604 | </html> |
|---|
| 605 | <!-- LocalWords: STL BGL cpp vecS bidirectionalS directedS undirectedS hpp vp |
|---|
| 606 | --> |
|---|
| 607 | <!-- LocalWords: iostream namespace int const num sizeof map ID's gif typedef |
|---|
| 608 | --> |
|---|
| 609 | <!-- LocalWords: iter ei interoperability struct typename GraphTraits src ai |
|---|
| 610 | --> |
|---|
| 611 | <!-- LocalWords: targ PropertyGraph Properties property iterator iterators |
|---|
| 612 | --> |
|---|
| 613 | <!-- LocalWords: VertexList dijkstra listS Edgelist RandomAccessIterator cout |
|---|
| 614 | --> |
|---|
| 615 | <!-- LocalWords: weightp adjacency tradeoffs undirected MutableGraph indices |
|---|
| 616 | --> |
|---|
| 617 | <!-- LocalWords: VertexListGraph Dereferencing IndexMap EdgeListGraph functor |
|---|
| 618 | --> |
|---|
| 619 | <!-- LocalWords: functor's IncidenceGraph dereferencing BidirectionalGraph |
|---|
| 620 | --> |
|---|
| 621 | <!-- LocalWords: AdjacencyGraph Dijkstra's extensibility functors BGL's endl |
|---|
| 622 | --> |
|---|
| 623 | <!-- LocalWords: DijkstraVisitor PredecessorMap siek htm Univ Notre |
|---|
| 624 | --> |
|---|