dijkstra_example.rst 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. .. Copyright (C) 2004-2008 The Trustees of Indiana University.
  2. Use, modification and distribution is subject to the Boost Software
  3. License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  4. http://www.boost.org/LICENSE_1_0.txt)
  5. =======================
  6. Parallel Shortest Paths
  7. =======================
  8. To illustrate the use of the Parallel Boost Graph Library, we
  9. illustrate the use of both the sequential and parallel BGL to find
  10. the shortest paths from vertex A to every other vertex in the
  11. following simple graph:
  12. .. image:: ../dijkstra_seq_graph.png
  13. With the sequential BGL_, the program to calculate shortest paths has
  14. three stages. Readers familiar with the BGL may wish to skip ahead to
  15. the section `Distributing the graph`_.
  16. - `Define the graph type`_
  17. - `Construct the graph`_
  18. - `Invoke Dijkstra's algorithm`_
  19. Define the graph type
  20. ~~~~~~~~~~~~~~~~~~~~~
  21. For this problem we use an adjacency list representation of the graph,
  22. using the BGL ``adjacency_list``_ class template. It will be a directed
  23. graph (``directedS`` parameter ) whose vertices are stored in an
  24. ``std::vector`` (``vecS`` parameter) where the outgoing edges of each
  25. vertex are stored in an ``std::list`` (``listS`` parameter). To each
  26. of the edges we attach an integral weight.
  27. ::
  28. typedef adjacency_list<listS, vecS, directedS,
  29. no_property, // Vertex properties
  30. property<edge_weight_t, int> // Edge properties
  31. > graph_t;
  32. typedef graph_traits < graph_t >::vertex_descriptor vertex_descriptor;
  33. typedef graph_traits < graph_t >::edge_descriptor edge_descriptor;
  34. Construct the graph
  35. ~~~~~~~~~~~~~~~~~~~
  36. To build the graph, we declare an enumeration containing the node
  37. names (for our own use) and create two arrays: the first,
  38. ``edge_array``, contains the source and target of each edge, whereas
  39. the second, ``weights``, contains the integral weight of each
  40. edge. We pass the contents of the arrays via pointers (used here as
  41. iterators) to the graph constructor to build our graph:
  42. ::
  43. typedef std::pair<int, int> Edge;
  44. const int num_nodes = 5;
  45. enum nodes { A, B, C, D, E };
  46. char name[] = "ABCDE";
  47. Edge edge_array[] = { Edge(A, C), Edge(B, B), Edge(B, D), Edge(B, E),
  48. Edge(C, B), Edge(C, D), Edge(D, E), Edge(E, A), Edge(E, B)
  49. };
  50. int weights[] = { 1, 2, 1, 2, 7, 3, 1, 1, 1 };
  51. int num_arcs = sizeof(edge_array) / sizeof(Edge);
  52. graph_t g(edge_array, edge_array + num_arcs, weights, num_nodes);
  53. Invoke Dijkstra's algorithm
  54. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  55. To invoke Dijkstra's algorithm, we need to first decide how we want
  56. to receive the results of the algorithm, namely the distance to each
  57. vertex and the predecessor of each vertex (allowing reconstruction of
  58. the shortest paths themselves). In our case, we will create two
  59. vectors, ``p`` for predecessors and ``d`` for distances.
  60. Next, we determine our starting vertex ``s`` using the ``vertex``
  61. operation on the ``adjacency_list``_ and call
  62. ``dijkstra_shortest_paths``_ with the graph ``g``, starting vertex
  63. ``s``, and two ``property maps``_ that instruct the algorithm to
  64. store predecessors in the ``p`` vector and distances in the ``d``
  65. vector. The algorithm automatically uses the edge weights stored
  66. within the graph, although this capability can be overridden.
  67. ::
  68. // Keeps track of the predecessor of each vertex
  69. std::vector<vertex_descriptor> p(num_vertices(g));
  70. // Keeps track of the distance to each vertex
  71. std::vector<int> d(num_vertices(g));
  72. vertex_descriptor s = vertex(A, g);
  73. dijkstra_shortest_paths
  74. (g, s,
  75. predecessor_map(
  76. make_iterator_property_map(p.begin(), get(vertex_index, g))).
  77. distance_map(
  78. make_iterator_property_map(d.begin(), get(vertex_index, g)))
  79. );
  80. Distributing the graph
  81. ~~~~~~~~~~~~~~~~~~~~~~
  82. The prior computation is entirely sequential, with the graph stored
  83. within a single address space. To distribute the graph across several
  84. processors without a shared address space, we need to represent the
  85. processors and communication among them and alter the graph type.
  86. Processors and their interactions are abstracted via a *process
  87. group*. In our case, we will use MPI_ for communication with
  88. inter-processor messages sent immediately:
  89. ::
  90. typedef mpi::process_group<mpi::immediateS> process_group_type;
  91. Next, we instruct the ``adjacency_list`` template
  92. to distribute the vertices of the graph across our process group,
  93. storing the local vertices in an ``std::vector``::
  94. typedef adjacency_list<listS,
  95. distributedS<process_group_type, vecS>,
  96. directedS,
  97. no_property, // Vertex properties
  98. property<edge_weight_t, int> // Edge properties
  99. > graph_t;
  100. typedef graph_traits < graph_t >::vertex_descriptor vertex_descriptor;
  101. typedef graph_traits < graph_t >::edge_descriptor edge_descriptor;
  102. Note that the only difference from the sequential BGL is the use of
  103. the ``distributedS`` selector, which identifies a distributed
  104. graph. The vertices of the graph will be distributed among the
  105. various processors, and the processor that owns a vertex also stores
  106. the edges outgoing from that vertex and any properties associated
  107. with that vertex or its edges. With three processors and the default
  108. block distribution, the graph would be distributed in this manner:
  109. .. image:: ../dijkstra_dist3_graph.png
  110. Processor 0 (red) owns vertices A and B, including all edges outoing
  111. from those vertices, processor 1 (green) owns vertices C and D (and
  112. their edges), and processor 2 (blue) owns vertex E. Constructing this
  113. graph uses the same syntax is the sequential graph, as in the section
  114. `Construct the graph`_.
  115. The call to ``dijkstra_shortest_paths`` is syntactically equivalent to
  116. the sequential call, but the mechanisms used are very different. The
  117. property maps passed to ``dijkstra_shortest_paths`` are actually
  118. *distributed* property maps, which store properties for local edges
  119. or vertices and perform implicit communication to access properties
  120. of remote edges or vertices when needed. The formulation of Dijkstra's
  121. algorithm is also slightly different, because each processor can
  122. only attempt to relax edges outgoing from local vertices: as shorter
  123. paths to a vertex are discovered, messages to the processor owning
  124. that vertex indicate that the vertex may require reprocessing.
  125. ----------------------------------------------------------------------
  126. Return to the `Parallel BGL home page`_
  127. .. _Parallel BGL home page: index.html
  128. .. _dijkstra_shortest_paths: http://www.boost.org/libs/graph/doc/dijkstra_shortest_paths.html
  129. .. _property maps: http://www.boost.org/libs/graph/doc/using_property_maps.html
  130. .. _adjacency_list: http://www.boost.org/libs/graph/doc/adjacency_list.html
  131. .. _MPI: http://www-unix.mcs.anl.gov/mpi/
  132. .. _BGL: http://www.boost.org/libs/graph/doc