File indexing completed on 2025-01-18 09:37:16
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 #ifndef BOOST_GRAPH_CRAUSER_ET_AL_SHORTEST_PATHS_HPP
0027 #define BOOST_GRAPH_CRAUSER_ET_AL_SHORTEST_PATHS_HPP
0028
0029 #ifndef BOOST_GRAPH_USE_MPI
0030 #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
0031 #endif
0032
0033 #include <boost/assert.hpp>
0034 #include <boost/graph/distributed/detail/dijkstra_shortest_paths.hpp>
0035 #include <boost/graph/parallel/algorithm.hpp>
0036 #include <functional>
0037 #include <boost/graph/iteration_macros.hpp>
0038 #include <boost/property_map/property_map_iterator.hpp>
0039 #include <boost/type_traits/is_same.hpp>
0040 #include <boost/algorithm/minmax_element.hpp>
0041 #include <boost/property_map/parallel/caching_property_map.hpp>
0042 #include <boost/pending/indirect_cmp.hpp>
0043 #include <boost/graph/distributed/detail/remote_update_set.hpp>
0044 #include <vector>
0045 #include <boost/graph/breadth_first_search.hpp>
0046 #include <boost/graph/dijkstra_shortest_paths.hpp>
0047 #include <boost/graph/parallel/container_traits.hpp>
0048 #include <boost/pending/relaxed_heap.hpp>
0049
0050 #ifdef PBGL_ACCOUNTING
0051 # include <boost/graph/accounting.hpp>
0052 # include <numeric>
0053 #endif
0054
0055 #ifdef MUTABLE_QUEUE
0056 # include <boost/pending/mutable_queue.hpp>
0057 #endif
0058
0059 namespace boost { namespace graph { namespace distributed {
0060
0061 #ifdef PBGL_ACCOUNTING
0062 struct crauser_et_al_shortest_paths_stats_t
0063 {
0064
0065 accounting::time_type execution_time;
0066
0067
0068 std::vector<std::size_t> deleted_vertices;
0069
0070 template<typename OutputStream>
0071 void print(OutputStream& out)
0072 {
0073 double avg_deletions = std::accumulate(deleted_vertices.begin(),
0074 deleted_vertices.end(),
0075 0.0);
0076 avg_deletions /= deleted_vertices.size();
0077
0078 out << "Problem = \"Single-Source Shortest Paths\"\n"
0079 << "Algorithm = \"Crauser et al\"\n"
0080 << "Function = crauser_et_al_shortest_paths\n"
0081 << "Wall clock time = " << accounting::print_time(execution_time)
0082 << "\nSupersteps = " << deleted_vertices.size() << "\n"
0083 << "Avg. deletions per superstep = " << avg_deletions << "\n";
0084 }
0085 };
0086
0087 static crauser_et_al_shortest_paths_stats_t crauser_et_al_shortest_paths_stats;
0088 #endif
0089
0090 namespace detail {
0091
0092
0093
0094
0095
0096 template<typename Vertex, typename DistanceMap, typename MinInWeightMap,
0097 typename Combine, typename Compare>
0098 struct min_in_distance_compare
0099 {
0100 typedef Vertex first_argument_type;
0101 typedef Vertex second_argument_type;
0102 typedef bool result_type;
0103 min_in_distance_compare(DistanceMap d, MinInWeightMap m,
0104 Combine combine, Compare compare)
0105 : distance_map(d), min_in_weight(m), combine(combine),
0106 compare(compare)
0107 {
0108 }
0109
0110 bool operator()(const Vertex& x, const Vertex& y) const
0111 {
0112 return compare(combine(get(distance_map, x), -get(min_in_weight, x)),
0113 combine(get(distance_map, y), -get(min_in_weight, y)));
0114 }
0115
0116 private:
0117 DistanceMap distance_map;
0118 MinInWeightMap min_in_weight;
0119 Combine combine;
0120 Compare compare;
0121 };
0122
0123 template<typename Vertex, typename DistanceMap, typename MinOutWeightMap,
0124 typename Combine, typename Compare>
0125 struct min_out_distance_compare
0126 {
0127 typedef Vertex first_argument_type;
0128 typedef Vertex second_argument_type;
0129 typedef bool result_type;
0130 min_out_distance_compare(DistanceMap d, MinOutWeightMap m,
0131 Combine combine, Compare compare)
0132 : distance_map(d), min_out_weight(m), combine(combine),
0133 compare(compare)
0134 {
0135 }
0136
0137 bool operator()(const Vertex& x, const Vertex& y) const
0138 {
0139 return compare(combine(get(distance_map, x), get(min_out_weight, x)),
0140 combine(get(distance_map, y), get(min_out_weight, y)));
0141 }
0142
0143 private:
0144 DistanceMap distance_map;
0145 MinOutWeightMap min_out_weight;
0146 Combine combine;
0147 Compare compare;
0148 };
0149
0150
0151
0152
0153
0154
0155
0156 template<typename Graph, typename Combine,
0157 typename Compare, typename VertexIndexMap, typename DistanceMap,
0158 typename PredecessorMap, typename MinOutWeightMap,
0159 typename MinInWeightMap>
0160 class crauser_et_al_dijkstra_queue
0161 : public graph::detail::remote_update_set<
0162 crauser_et_al_dijkstra_queue<
0163 Graph, Combine, Compare, VertexIndexMap, DistanceMap,
0164 PredecessorMap, MinOutWeightMap, MinInWeightMap>,
0165 typename boost::graph::parallel::process_group_type<Graph>::type,
0166 typename dijkstra_msg_value<DistanceMap, PredecessorMap>::type,
0167 typename property_map<Graph, vertex_owner_t>::const_type>
0168 {
0169 typedef typename graph_traits<Graph>::vertex_descriptor
0170 vertex_descriptor;
0171 typedef crauser_et_al_dijkstra_queue self_type;
0172 typedef dijkstra_msg_value<DistanceMap, PredecessorMap> msg_value_creator;
0173 typedef typename msg_value_creator::type msg_value_type;
0174 typedef typename graph_traits<Graph>::vertices_size_type
0175 vertices_size_type;
0176 typedef typename property_map<Graph, vertex_owner_t>::const_type
0177 OwnerPropertyMap;
0178 typedef typename boost::graph::parallel::process_group_type<Graph>::type
0179 process_group_type;
0180 typedef graph::detail::remote_update_set<self_type, process_group_type,
0181 msg_value_type, OwnerPropertyMap>
0182 inherited;
0183
0184
0185 typedef indirect_cmp<DistanceMap, Compare> dist_queue_compare_type;
0186
0187 typedef typename property_traits<DistanceMap>::value_type distance_type;
0188
0189 #ifdef MUTABLE_QUEUE
0190 typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>,
0191 dist_queue_compare_type, VertexIndexMap> dist_queue_type;
0192
0193 #else
0194 typedef relaxed_heap<vertex_descriptor, dist_queue_compare_type,
0195 VertexIndexMap> dist_queue_type;
0196 #endif
0197
0198
0199 typedef min_out_distance_compare<vertex_descriptor, DistanceMap,
0200 MinOutWeightMap, Combine, Compare>
0201 out_queue_compare_type;
0202
0203 #ifdef MUTABLE_QUEUE
0204 typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>,
0205 out_queue_compare_type, VertexIndexMap> out_queue_type;
0206
0207 #else
0208 typedef relaxed_heap<vertex_descriptor, out_queue_compare_type,
0209 VertexIndexMap> out_queue_type;
0210 #endif
0211
0212
0213 typedef min_in_distance_compare<vertex_descriptor, DistanceMap,
0214 MinInWeightMap, Combine, Compare>
0215 in_queue_compare_type;
0216
0217 #ifdef MUTABLE_QUEUE
0218 typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>,
0219 in_queue_compare_type, VertexIndexMap> in_queue_type;
0220
0221 #else
0222 typedef relaxed_heap<vertex_descriptor, in_queue_compare_type,
0223 VertexIndexMap> in_queue_type;
0224 #endif
0225
0226 typedef typename process_group_type::process_id_type process_id_type;
0227
0228 public:
0229 typedef typename dist_queue_type::size_type size_type;
0230 typedef typename dist_queue_type::value_type value_type;
0231
0232 crauser_et_al_dijkstra_queue(const Graph& g,
0233 const Combine& combine,
0234 const Compare& compare,
0235 const VertexIndexMap& id,
0236 const DistanceMap& distance_map,
0237 const PredecessorMap& predecessor_map,
0238 const MinOutWeightMap& min_out_weight,
0239 const MinInWeightMap& min_in_weight)
0240 : inherited(boost::graph::parallel::process_group(g), get(vertex_owner, g)),
0241 dist_queue(num_vertices(g),
0242 dist_queue_compare_type(distance_map, compare),
0243 id),
0244 out_queue(num_vertices(g),
0245 out_queue_compare_type(distance_map, min_out_weight,
0246 combine, compare),
0247 id),
0248 in_queue(num_vertices(g),
0249 in_queue_compare_type(distance_map, min_in_weight,
0250 combine, compare),
0251 id),
0252 g(g),
0253 distance_map(distance_map),
0254 predecessor_map(predecessor_map),
0255 min_out_weight(min_out_weight),
0256 min_in_weight(min_in_weight),
0257 min_distance(0),
0258 min_out_distance(0)
0259 #ifdef PBGL_ACCOUNTING
0260 , local_deletions(0)
0261 #endif
0262 { }
0263
0264 void push(const value_type& x)
0265 {
0266 msg_value_type msg_value =
0267 msg_value_creator::create(get(distance_map, x),
0268 predecessor_value(get(predecessor_map, x)));
0269 inherited::update(x, msg_value);
0270 }
0271
0272 void update(const value_type& x) { push(x); }
0273
0274 void pop()
0275 {
0276
0277 dist_queue.remove(top_vertex);
0278
0279
0280 out_queue.remove(top_vertex);
0281
0282
0283 in_queue.remove(top_vertex);
0284
0285 #ifdef PBGL_ACCOUNTING
0286 ++local_deletions;
0287 #endif
0288 }
0289
0290 vertex_descriptor& top() { return top_vertex; }
0291 const vertex_descriptor& top() const { return top_vertex; }
0292
0293 bool empty()
0294 {
0295 inherited::collect();
0296
0297
0298 while (!has_suitable_vertex()) {
0299 if (do_synchronize()) return true;
0300 }
0301
0302
0303 return false;
0304 }
0305
0306 bool do_synchronize()
0307 {
0308 using boost::parallel::all_reduce;
0309 using boost::parallel::minimum;
0310
0311 inherited::synchronize();
0312
0313
0314
0315 distance_type local_distances[2];
0316 local_distances[0] =
0317 dist_queue.empty()? (std::numeric_limits<distance_type>::max)()
0318 : get(distance_map, dist_queue.top());
0319
0320 local_distances[1] =
0321 out_queue.empty()? (std::numeric_limits<distance_type>::max)()
0322 : (get(distance_map, out_queue.top())
0323 + get(min_out_weight, out_queue.top()));
0324
0325 distance_type distances[2];
0326 all_reduce(this->process_group, local_distances, local_distances + 2,
0327 distances, minimum<distance_type>());
0328 min_distance = distances[0];
0329 min_out_distance = distances[1];
0330
0331 #ifdef PBGL_ACCOUNTING
0332 std::size_t deletions = 0;
0333 all_reduce(this->process_group, &local_deletions, &local_deletions + 1,
0334 &deletions, std::plus<std::size_t>());
0335 if (process_id(this->process_group) == 0) {
0336 crauser_et_al_shortest_paths_stats.deleted_vertices.push_back(deletions);
0337 }
0338 local_deletions = 0;
0339 BOOST_ASSERT(deletions > 0);
0340 #endif
0341
0342 return min_distance == (std::numeric_limits<distance_type>::max)();
0343 }
0344
0345 private:
0346 vertex_descriptor predecessor_value(vertex_descriptor v) const
0347 { return v; }
0348
0349 vertex_descriptor
0350 predecessor_value(property_traits<dummy_property_map>::reference) const
0351 { return graph_traits<Graph>::null_vertex(); }
0352
0353 bool has_suitable_vertex() const
0354 {
0355 if (!dist_queue.empty()) {
0356 top_vertex = dist_queue.top();
0357 if (get(distance_map, dist_queue.top()) <= min_out_distance)
0358 return true;
0359 }
0360
0361 if (!in_queue.empty()) {
0362 top_vertex = in_queue.top();
0363 return (get(distance_map, top_vertex)
0364 - get(min_in_weight, top_vertex)) <= min_distance;
0365 }
0366 return false;
0367 }
0368
0369 public:
0370 void
0371 receive_update(process_id_type source, vertex_descriptor vertex,
0372 distance_type distance)
0373 {
0374
0375
0376 if (distance < get(distance_map, vertex)
0377 || (distance == get(distance_map, vertex)
0378 && source == process_id(this->process_group))) {
0379
0380 put(distance_map, vertex, distance);
0381
0382 bool is_in_queue = dist_queue.contains(vertex);
0383
0384 if (!is_in_queue) {
0385 dist_queue.push(vertex);
0386 out_queue.push(vertex);
0387 in_queue.push(vertex);
0388 }
0389 else {
0390 dist_queue.update(vertex);
0391 out_queue.update(vertex);
0392 in_queue.update(vertex);
0393 }
0394 }
0395 }
0396
0397 void
0398 receive_update(process_id_type source, vertex_descriptor vertex,
0399 std::pair<distance_type, vertex_descriptor> p)
0400 {
0401 if (p.first <= get(distance_map, vertex)) {
0402 put(predecessor_map, vertex, p.second);
0403 receive_update(source, vertex, p.first);
0404 }
0405 }
0406
0407 private:
0408 dist_queue_type dist_queue;
0409 out_queue_type out_queue;
0410 in_queue_type in_queue;
0411 mutable value_type top_vertex;
0412 const Graph& g;
0413 DistanceMap distance_map;
0414 PredecessorMap predecessor_map;
0415 MinOutWeightMap min_out_weight;
0416 MinInWeightMap min_in_weight;
0417 distance_type min_distance;
0418 distance_type min_out_distance;
0419 #ifdef PBGL_ACCOUNTING
0420 std::size_t local_deletions;
0421 #endif
0422 };
0423
0424
0425
0426
0427
0428
0429
0430 template<typename Graph, typename MinInWeightMap, typename WeightMap,
0431 typename Inf, typename Compare>
0432 void
0433 initialize_min_in_weights(const Graph& g, MinInWeightMap min_in_weight,
0434 WeightMap weight, Inf inf, Compare compare,
0435 directed_tag, incidence_graph_tag)
0436 {
0437
0438 set_property_map_role(vertex_distance, min_in_weight);
0439 BGL_FORALL_VERTICES_T(v, g, Graph) {
0440 BGL_FORALL_OUTEDGES_T(v, e, g, Graph) {
0441 if (get(weight, e) < get(min_in_weight, target(e, g)))
0442 put(min_in_weight, target(e, g), get(weight, e));
0443 }
0444 }
0445
0446 using boost::graph::parallel::process_group;
0447 synchronize(process_group(g));
0448
0449
0450 BGL_FORALL_VERTICES_T(v, g, Graph) {
0451 if (get(min_in_weight, v) == inf) put(min_in_weight, v, 0);
0452 }
0453 }
0454
0455 template<typename Graph, typename MinInWeightMap, typename WeightMap,
0456 typename Inf, typename Compare>
0457 void
0458 initialize_min_in_weights(const Graph& g, MinInWeightMap min_in_weight,
0459 WeightMap weight, Inf inf, Compare compare,
0460 directed_tag, bidirectional_graph_tag)
0461 {
0462 #if 0
0463 typename property_map<Graph, vertex_local_t>::const_type
0464 local = get(vertex_local, g);
0465
0466
0467
0468
0469 set_property_map_role(vertex_distance, min_in_weight);
0470 BGL_FORALL_VERTICES_T(v, g, Graph) {
0471 if (in_edges(v, g).first != in_edges(v, g).second) {
0472 std::cerr << "weights(" << g.distribution().global(get(local, v))
0473 << ") = ";
0474 BGL_FORALL_INEDGES_T(v, e, g, Graph) {
0475 std::cerr << get(weight, e) << ' ';
0476 }
0477 std::cerr << std::endl;
0478 put(min_in_weight, v,
0479 *boost::first_min_element
0480 (make_property_map_iterator(weight, in_edges(v, g).first),
0481 make_property_map_iterator(weight, in_edges(v, g).second),
0482 compare));
0483 } else {
0484 put(min_in_weight, v, 0);
0485 }
0486 std::cerr << "miw(" << g.distribution().global(get(local, v)) << ") = "
0487 << get(min_in_weight, v) << std::endl;
0488 }
0489 #else
0490 initialize_min_in_weights(g, min_in_weight, weight, inf, compare,
0491 directed_tag(), incidence_graph_tag());
0492 #endif
0493 }
0494
0495 template<typename Graph, typename MinInWeightMap, typename WeightMap,
0496 typename Inf, typename Compare>
0497 inline void
0498 initialize_min_in_weights(const Graph&, MinInWeightMap, WeightMap, Inf,
0499 Compare, undirected_tag, bidirectional_graph_tag)
0500 {
0501
0502 }
0503
0504
0505
0506
0507
0508
0509
0510 template<typename Graph, typename MinOutWeightMap, typename WeightMap,
0511 typename Compare>
0512 void
0513 initialize_min_out_weights(const Graph& g, MinOutWeightMap min_out_weight,
0514 WeightMap weight, Compare compare)
0515 {
0516 typedef typename property_traits<WeightMap>::value_type weight_type;
0517
0518 BGL_FORALL_VERTICES_T(v, g, Graph) {
0519 if (out_edges(v, g).first != out_edges(v, g).second) {
0520 put(min_out_weight, v,
0521 *boost::first_min_element
0522 (make_property_map_iterator(weight, out_edges(v, g).first),
0523 make_property_map_iterator(weight, out_edges(v, g).second),
0524 compare));
0525 if (get(min_out_weight, v) < weight_type(0))
0526 boost::throw_exception(negative_edge());
0527 }
0528 }
0529 }
0530
0531
0532
0533 }
0534
0535 template<typename DistributedGraph, typename DijkstraVisitor,
0536 typename PredecessorMap, typename DistanceMap, typename WeightMap,
0537 typename IndexMap, typename ColorMap, typename Compare,
0538 typename Combine, typename DistInf, typename DistZero>
0539 void
0540 crauser_et_al_shortest_paths
0541 (const DistributedGraph& g,
0542 typename graph_traits<DistributedGraph>::vertex_descriptor s,
0543 PredecessorMap predecessor, DistanceMap distance, WeightMap weight,
0544 IndexMap index_map, ColorMap color_map,
0545 Compare compare, Combine combine, DistInf inf, DistZero zero,
0546 DijkstraVisitor vis)
0547 {
0548
0549 #ifdef PBGL_ACCOUNTING
0550 crauser_et_al_shortest_paths_stats.deleted_vertices.clear();
0551 crauser_et_al_shortest_paths_stats.execution_time = accounting::get_time();
0552 #endif
0553
0554
0555
0556
0557 typedef typename property_traits<WeightMap>::value_type weight_type;
0558 typedef iterator_property_map<weight_type*, IndexMap> MinOutWeightMap;
0559 std::vector<weight_type> min_out_weights_vec(num_vertices(g), inf);
0560 MinOutWeightMap min_out_weight(&min_out_weights_vec.front(), index_map);
0561 detail::initialize_min_out_weights(g, min_out_weight, weight, compare);
0562
0563
0564
0565
0566 typedef typename graph_traits<DistributedGraph>::directed_category
0567 directed_category;
0568 const bool is_undirected =
0569 is_same<directed_category, undirected_tag>::value;
0570 typedef MinOutWeightMap MinInWeightMap;
0571 std::vector<weight_type>
0572 min_in_weights_vec(is_undirected? 1 : num_vertices(g), inf);
0573 MinInWeightMap min_in_weight(&min_in_weights_vec.front(), index_map);
0574 typedef typename graph_traits<DistributedGraph>::traversal_category
0575 category;
0576 detail::initialize_min_in_weights(g, min_in_weight, weight, inf, compare,
0577 directed_category(), category());
0578
0579
0580 typename graph_traits<DistributedGraph>::vertex_iterator ui, ui_end;
0581 for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) {
0582 put(distance, *ui, inf);
0583 put(predecessor, *ui, *ui);
0584 }
0585 put(distance, s, zero);
0586
0587
0588 typedef detail::crauser_et_al_dijkstra_queue
0589 <DistributedGraph, Combine, Compare, IndexMap, DistanceMap,
0590 PredecessorMap, MinOutWeightMap, MinInWeightMap>
0591 Queue;
0592
0593 Queue Q(g, combine, compare, index_map, distance, predecessor,
0594 min_out_weight, is_undirected? min_out_weight : min_in_weight);
0595
0596
0597 ::boost::detail::dijkstra_bfs_visitor<
0598 DijkstraVisitor, Queue, WeightMap,
0599 boost::parallel::caching_property_map<PredecessorMap>,
0600 boost::parallel::caching_property_map<DistanceMap>, Combine, Compare
0601 > bfs_vis(vis, Q, weight,
0602 boost::parallel::make_caching_property_map(predecessor),
0603 boost::parallel::make_caching_property_map(distance),
0604 combine, compare, zero);
0605
0606 set_property_map_role(vertex_color, color_map);
0607 set_property_map_role(vertex_distance, distance);
0608
0609 breadth_first_search(g, s, Q, bfs_vis, color_map);
0610
0611 #ifdef PBGL_ACCOUNTING
0612 crauser_et_al_shortest_paths_stats.execution_time =
0613 accounting::get_time() - crauser_et_al_shortest_paths_stats.execution_time;
0614 #endif
0615 }
0616
0617 template<typename DistributedGraph, typename PredecessorMap,
0618 typename DistanceMap, typename WeightMap>
0619 void
0620 crauser_et_al_shortest_paths
0621 (const DistributedGraph& g,
0622 typename graph_traits<DistributedGraph>::vertex_descriptor s,
0623 PredecessorMap predecessor, DistanceMap distance, WeightMap weight)
0624 {
0625 typedef typename property_traits<DistanceMap>::value_type distance_type;
0626
0627 std::vector<default_color_type> colors(num_vertices(g), white_color);
0628
0629 crauser_et_al_shortest_paths(g, s, predecessor, distance, weight,
0630 get(vertex_index, g),
0631 make_iterator_property_map(&colors[0],
0632 get(vertex_index, g)),
0633 std::less<distance_type>(),
0634 closed_plus<distance_type>(),
0635 (std::numeric_limits<distance_type>::max)(),
0636 distance_type(),
0637 dijkstra_visitor<>());
0638 }
0639
0640 template<typename DistributedGraph, typename PredecessorMap,
0641 typename DistanceMap>
0642 void
0643 crauser_et_al_shortest_paths
0644 (const DistributedGraph& g,
0645 typename graph_traits<DistributedGraph>::vertex_descriptor s,
0646 PredecessorMap predecessor, DistanceMap distance)
0647 {
0648 crauser_et_al_shortest_paths(g, s, predecessor, distance,
0649 get(edge_weight, g));
0650 }
0651
0652 }
0653
0654 #ifdef PBGL_ACCOUNTING
0655 using distributed::crauser_et_al_shortest_paths_stats;
0656 #endif
0657
0658 using distributed::crauser_et_al_shortest_paths;
0659
0660
0661 } }
0662
0663 #endif