PageRenderTime 93ms CodeModel.GetById 14ms app.highlight 71ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/graph/distributed/eager_dijkstra_shortest_paths.hpp

http://hadesmem.googlecode.com/
C++ Header | 447 lines | 329 code | 73 blank | 45 comment | 16 complexity | 4ccd8e570af5f62a6bf1d6ceff809c16 MD5 | raw file
  1// Copyright (C) 2004-2006 The Trustees of Indiana University.
  2
  3// Use, modification and distribution is subject to the Boost Software
  4// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5// http://www.boost.org/LICENSE_1_0.txt)
  6
  7//  Authors: Douglas Gregor
  8//           Andrew Lumsdaine
  9
 10/**************************************************************************
 11 * This source file implements a variation on distributed Dijkstra's      *
 12 * algorithm that can expose additional parallelism by permitting         *
 13 * vertices within a certain distance from the minimum to be processed,   *
 14 * even though they may not be at their final distance. This can          *
 15 * introduce looping, but the algorithm will still terminate so long as   *
 16 * there are no negative loops.                                           *
 17 **************************************************************************/
 18#ifndef BOOST_GRAPH_EAGER_DIJKSTRA_SHORTEST_PATHS_HPP
 19#define BOOST_GRAPH_EAGER_DIJKSTRA_SHORTEST_PATHS_HPP
 20
 21#ifndef BOOST_GRAPH_USE_MPI
 22#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
 23#endif
 24
 25#include <boost/assert.hpp>
 26#include <boost/graph/distributed/detail/dijkstra_shortest_paths.hpp>
 27#include <boost/property_map/parallel/caching_property_map.hpp>
 28#include <boost/pending/indirect_cmp.hpp>
 29#include <boost/graph/distributed/detail/remote_update_set.hpp>
 30#include <vector>
 31#include <boost/graph/breadth_first_search.hpp>
 32#include <boost/graph/dijkstra_shortest_paths.hpp>
 33#include <boost/graph/parallel/container_traits.hpp>
 34
 35#ifdef PBGL_ACCOUNTING
 36#  include <boost/graph/accounting.hpp>
 37#  include <numeric>
 38#endif // PBGL_ACCOUNTING
 39
 40#ifdef MUTABLE_QUEUE
 41#  include <boost/pending/mutable_queue.hpp>
 42#endif
 43
 44namespace boost { namespace graph { namespace distributed {
 45
 46#ifdef PBGL_ACCOUNTING
 47struct eager_dijkstra_shortest_paths_stats_t
 48{
 49  /* The value of the lookahead parameter. */
 50  double lookahead;
 51
 52  /* Total wall-clock time used by the algorithm.*/
 53  accounting::time_type execution_time;
 54
 55  /* The number of vertices deleted in each superstep. */
 56  std::vector<std::size_t> deleted_vertices;
 57
 58  template<typename OutputStream>
 59  void print(OutputStream& out)
 60  {
 61    double avg_deletions = std::accumulate(deleted_vertices.begin(),
 62                                           deleted_vertices.end(),
 63                                           0.0);
 64    avg_deletions /= deleted_vertices.size();
 65
 66    out << "Problem = \"Single-Source Shortest Paths\"\n"
 67        << "Algorithm = \"Eager Dijkstra\"\n"
 68        << "Function = eager_dijkstra_shortest_paths\n"
 69        << "(P) Lookahead = " << lookahead << "\n"
 70        << "Wall clock time = " << accounting::print_time(execution_time) 
 71        << "\nSupersteps = " << deleted_vertices.size() << "\n"
 72        << "Avg. deletions per superstep = " << avg_deletions << "\n";
 73  }
 74};
 75
 76static eager_dijkstra_shortest_paths_stats_t eager_dijkstra_shortest_paths_stats;
 77#endif
 78
 79namespace detail {
 80
 81// Borrowed from BGL's dijkstra_shortest_paths
 82template <class UniformCostVisitor, class Queue,
 83          class WeightMap, class PredecessorMap, class DistanceMap,
 84          class BinaryFunction, class BinaryPredicate>
 85 struct parallel_dijkstra_bfs_visitor : bfs_visitor<>
 86{
 87  typedef typename property_traits<DistanceMap>::value_type distance_type;
 88
 89  parallel_dijkstra_bfs_visitor(UniformCostVisitor vis, Queue& Q,
 90                                WeightMap w, PredecessorMap p, DistanceMap d,
 91                                BinaryFunction combine, BinaryPredicate compare,
 92                                distance_type zero)
 93    : m_vis(vis), m_Q(Q), m_weight(w), m_predecessor(p), m_distance(d),
 94      m_combine(combine), m_compare(compare), m_zero(zero)  { }
 95
 96  template <class Vertex, class Graph>
 97  void initialize_vertex(Vertex u, Graph& g)
 98    { m_vis.initialize_vertex(u, g); }
 99  template <class Vertex, class Graph>
100  void discover_vertex(Vertex u, Graph& g) { m_vis.discover_vertex(u, g); }
101  template <class Vertex, class Graph>
102  void examine_vertex(Vertex u, Graph& g) { m_vis.examine_vertex(u, g); }
103
104  /* Since the eager formulation of Parallel Dijkstra's algorithm can
105     loop, we may relax on *any* edge, not just those associated with
106     white and gray targets. */
107  template <class Edge, class Graph>
108  void examine_edge(Edge e, Graph& g) {
109    if (m_compare(get(m_weight, e), m_zero))
110        boost::throw_exception(negative_edge());
111
112    m_vis.examine_edge(e, g);
113
114    boost::parallel::caching_property_map<PredecessorMap> c_pred(m_predecessor);
115    boost::parallel::caching_property_map<DistanceMap> c_dist(m_distance);
116
117    distance_type old_distance = get(c_dist, target(e, g));
118
119    bool m_decreased = relax(e, g, m_weight, c_pred, c_dist,
120                             m_combine, m_compare);
121
122    /* On x86 Linux with optimization, we sometimes get into a
123       horrible case where m_decreased is true but the distance hasn't
124       actually changed. This occurs when the comparison inside
125       relax() occurs with the 80-bit precision of the x87 floating
126       point unit, but the difference is lost when the resulting
127       values are written back to lower-precision memory (e.g., a
128       double). With the eager Dijkstra's implementation, this results
129       in looping. */
130    if (m_decreased && old_distance != get(c_dist, target(e, g))) {
131      m_Q.update(target(e, g));
132      m_vis.edge_relaxed(e, g);
133    } else
134      m_vis.edge_not_relaxed(e, g);
135  }
136  template <class Vertex, class Graph>
137  void finish_vertex(Vertex u, Graph& g) { m_vis.finish_vertex(u, g); }
138
139  UniformCostVisitor m_vis;
140  Queue& m_Q;
141  WeightMap m_weight;
142  PredecessorMap m_predecessor;
143  DistanceMap m_distance;
144  BinaryFunction m_combine;
145  BinaryPredicate m_compare;
146  distance_type m_zero;
147};
148
149  /**********************************************************************
150   * Dijkstra queue that implements arbitrary "lookahead"               *
151   **********************************************************************/
152  template<typename Graph, typename Combine, typename Compare,
153           typename VertexIndexMap, typename DistanceMap,
154           typename PredecessorMap>
155  class lookahead_dijkstra_queue
156    : public graph::detail::remote_update_set<
157               lookahead_dijkstra_queue<
158                 Graph, Combine, Compare, VertexIndexMap, DistanceMap,
159                 PredecessorMap>,
160               typename boost::graph::parallel::process_group_type<Graph>::type,
161               typename dijkstra_msg_value<DistanceMap, PredecessorMap>::type,
162               typename property_map<Graph, vertex_owner_t>::const_type>
163  {
164    typedef typename graph_traits<Graph>::vertex_descriptor
165      vertex_descriptor;
166    typedef lookahead_dijkstra_queue self_type;
167    typedef typename boost::graph::parallel::process_group_type<Graph>::type
168      process_group_type;
169    typedef dijkstra_msg_value<DistanceMap, PredecessorMap> msg_value_creator;
170    typedef typename msg_value_creator::type msg_value_type;
171    typedef typename property_map<Graph, vertex_owner_t>::const_type
172      OwnerPropertyMap;
173
174    typedef graph::detail::remote_update_set<self_type, process_group_type,
175                                             msg_value_type, OwnerPropertyMap>
176      inherited;
177
178    // Priority queue for tentative distances
179    typedef indirect_cmp<DistanceMap, Compare> queue_compare_type;
180
181    typedef typename property_traits<DistanceMap>::value_type distance_type;
182
183#ifdef MUTABLE_QUEUE
184    typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>, 
185                          queue_compare_type, VertexIndexMap> queue_type;
186
187#else
188    typedef relaxed_heap<vertex_descriptor, queue_compare_type, 
189                         VertexIndexMap> queue_type;
190#endif // MUTABLE_QUEUE
191
192    typedef typename process_group_type::process_id_type process_id_type;
193
194  public:
195    typedef vertex_descriptor value_type;
196
197    lookahead_dijkstra_queue(const Graph& g,
198                             const Combine& combine,
199                             const Compare& compare,
200                             const VertexIndexMap& id,
201                             const DistanceMap& distance_map,
202                             const PredecessorMap& predecessor_map,
203                             distance_type lookahead)
204      : inherited(boost::graph::parallel::process_group(g), get(vertex_owner, g)),
205        queue(num_vertices(g), queue_compare_type(distance_map, compare), id),
206        distance_map(distance_map),
207        predecessor_map(predecessor_map),
208        min_distance(0),
209        lookahead(lookahead)
210#ifdef PBGL_ACCOUNTING
211        , local_deletions(0)
212#endif
213    { }
214
215    void push(const value_type& x)
216    {
217      msg_value_type msg_value = 
218        msg_value_creator::create(get(distance_map, x),
219                                  predecessor_value(get(predecessor_map, x)));
220      inherited::update(x, msg_value);
221    }
222    
223    void update(const value_type& x) { push(x); }
224
225    void pop() 
226    { 
227      queue.pop(); 
228#ifdef PBGL_ACCOUNTING
229      ++local_deletions;
230#endif
231    }
232
233    value_type&       top()       { return queue.top(); }
234    const value_type& top() const { return queue.top(); }
235
236    bool empty()
237    {
238      inherited::collect();
239
240      // If there are no suitable messages, wait until we get something
241      while (!has_suitable_vertex()) {
242        if (do_synchronize()) return true;
243      }
244
245      // Return true only if nobody has any messages; false if we
246      // have suitable messages
247      return false;
248    }
249
250  private:
251    vertex_descriptor predecessor_value(vertex_descriptor v) const
252    { return v; }
253
254    vertex_descriptor
255    predecessor_value(property_traits<dummy_property_map>::reference) const
256    { return graph_traits<Graph>::null_vertex(); }
257
258    bool has_suitable_vertex() const
259    {
260      return (!queue.empty() 
261              && get(distance_map, queue.top()) <= min_distance + lookahead);
262    }
263
264    bool do_synchronize()
265    {
266      using boost::parallel::all_reduce;
267      using boost::parallel::minimum;
268
269      inherited::synchronize();
270
271      // TBD: could use combine here, but then we need to stop using
272      // minimum<distance_type>() as the function object.
273      distance_type local_distance = 
274        queue.empty()? (std::numeric_limits<distance_type>::max)()
275        : get(distance_map, queue.top());
276
277      all_reduce(this->process_group, &local_distance, &local_distance + 1,
278                 &min_distance, minimum<distance_type>());
279
280#ifdef PBGL_ACCOUNTING
281      std::size_t deletions = 0;
282      all_reduce(this->process_group, &local_deletions, &local_deletions + 1,
283                 &deletions, std::plus<std::size_t>());
284      if (process_id(this->process_group) == 0)
285        eager_dijkstra_shortest_paths_stats.deleted_vertices
286          .push_back(deletions);
287      local_deletions = 0;
288      BOOST_ASSERT(deletions > 0);
289#endif
290
291      return min_distance == (std::numeric_limits<distance_type>::max)();
292    }
293    
294  public:
295    void 
296    receive_update(process_id_type source, vertex_descriptor vertex,
297                   distance_type distance)
298    {
299      // Update the queue if the received distance is better than
300      // the distance we know locally
301      if (distance <= get(distance_map, vertex)) {
302
303        // Update the local distance map
304        put(distance_map, vertex, distance);
305
306        bool is_in_queue = queue.contains(vertex);
307
308        if (!is_in_queue) 
309          queue.push(vertex);
310        else 
311          queue.update(vertex);
312      }
313    }
314
315    void 
316    receive_update(process_id_type source, vertex_descriptor vertex,
317                   std::pair<distance_type, vertex_descriptor> p)
318    {
319      if (p.first <= get(distance_map, vertex)) {
320        put(predecessor_map, vertex, p.second);
321        receive_update(source, vertex, p.first);
322      }
323    }
324
325  private:
326    queue_type     queue;
327    DistanceMap    distance_map;
328    PredecessorMap predecessor_map;
329    distance_type  min_distance;
330    distance_type  lookahead;
331#ifdef PBGL_ACCOUNTING
332    std::size_t    local_deletions;
333#endif
334  };
335  /**********************************************************************/
336} // end namespace detail
337
338template<typename DistributedGraph, typename DijkstraVisitor,
339         typename PredecessorMap, typename DistanceMap, typename WeightMap,
340         typename IndexMap, typename ColorMap, typename Compare,
341         typename Combine, typename DistInf, typename DistZero>
342void
343eager_dijkstra_shortest_paths
344  (const DistributedGraph& g,
345   typename graph_traits<DistributedGraph>::vertex_descriptor s,
346   PredecessorMap predecessor, DistanceMap distance, 
347   typename property_traits<DistanceMap>::value_type lookahead,
348   WeightMap weight, IndexMap index_map, ColorMap color_map,
349   Compare compare, Combine combine, DistInf inf, DistZero zero,
350   DijkstraVisitor vis)
351{
352  typedef typename boost::graph::parallel::process_group_type<DistributedGraph>::type
353    process_group_type;
354  typedef typename graph_traits<DistributedGraph>::vertex_descriptor
355    Vertex;
356  typedef typename graph_traits<DistributedGraph>::vertices_size_type
357    vertices_size_type;
358
359#ifdef PBGL_ACCOUNTING
360  eager_dijkstra_shortest_paths_stats.deleted_vertices.clear();
361  eager_dijkstra_shortest_paths_stats.lookahead = lookahead;
362  eager_dijkstra_shortest_paths_stats.execution_time = accounting::get_time();
363#endif
364
365  // Initialize local portion of property maps
366  typename graph_traits<DistributedGraph>::vertex_iterator ui, ui_end;
367  for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) {
368    put(distance, *ui, inf);
369    put(predecessor, *ui, *ui);
370  }
371  put(distance, s, zero);
372
373  // Dijkstra Queue
374  typedef detail::lookahead_dijkstra_queue
375            <DistributedGraph, Combine, Compare, IndexMap, DistanceMap,
376             PredecessorMap> Queue;
377
378  Queue Q(g, combine, compare, index_map, distance, 
379          predecessor, lookahead);
380
381  // Parallel Dijkstra visitor
382  detail::parallel_dijkstra_bfs_visitor
383    <DijkstraVisitor, Queue, WeightMap, PredecessorMap, DistanceMap, Combine, 
384     Compare> bfs_vis(vis, Q, weight, predecessor, distance, combine, compare,
385                      zero);
386
387  set_property_map_role(vertex_color, color_map);
388  set_property_map_role(vertex_distance, distance);
389
390  breadth_first_search(g, s, Q, bfs_vis, color_map);
391
392#ifdef PBGL_ACCOUNTING
393  eager_dijkstra_shortest_paths_stats.execution_time = 
394    accounting::get_time() 
395    - eager_dijkstra_shortest_paths_stats.execution_time;
396#endif
397}
398
399template<typename DistributedGraph, typename DijkstraVisitor,
400         typename PredecessorMap, typename DistanceMap, typename WeightMap>
401void
402eager_dijkstra_shortest_paths
403  (const DistributedGraph& g,
404   typename graph_traits<DistributedGraph>::vertex_descriptor s,
405   PredecessorMap predecessor, DistanceMap distance, 
406   typename property_traits<DistanceMap>::value_type lookahead,
407   WeightMap weight)
408{
409  typedef typename property_traits<DistanceMap>::value_type distance_type;
410
411  std::vector<default_color_type> colors(num_vertices(g), white_color);
412
413  eager_dijkstra_shortest_paths(g, s, predecessor, distance, lookahead, weight,
414                                get(vertex_index, g),
415                                make_iterator_property_map(&colors[0],
416                                                           get(vertex_index, 
417                                                               g)),
418                                std::less<distance_type>(),
419                                closed_plus<distance_type>(),
420                                distance_type(),
421                                (std::numeric_limits<distance_type>::max)(),
422                                dijkstra_visitor<>());
423}
424
425template<typename DistributedGraph, typename DijkstraVisitor,
426         typename PredecessorMap, typename DistanceMap>
427void
428eager_dijkstra_shortest_paths
429  (const DistributedGraph& g,
430   typename graph_traits<DistributedGraph>::vertex_descriptor s,
431   PredecessorMap predecessor, DistanceMap distance,
432   typename property_traits<DistanceMap>::value_type lookahead)
433{
434  eager_dijkstra_shortest_paths(g, s, predecessor, distance, lookahead,
435                               get(edge_weight, g));
436}
437} // end namespace distributed
438
439#ifdef PBGL_ACCOUNTING
440using distributed::eager_dijkstra_shortest_paths_stats;
441#endif
442
443using distributed::eager_dijkstra_shortest_paths;
444
445} } // end namespace boost::graph
446
447#endif // BOOST_GRAPH_EAGER_DIJKSTRA_SHORTEST_PATHS_HPP