123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663 |
- // Copyright (C) 2004-2006 The Trustees of Indiana University.
- // Use, modification and distribution is subject to the Boost Software
- // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- // Authors: Douglas Gregor
- // Andrew Lumsdaine
- /**************************************************************************
- * This source file implements the variation on Dijkstra's algorithm *
- * presented by Crauser et al. in: *
- * *
- * Andreas Crauser, Kurt Mehlhorn, Ulrich Meyer, and Peter *
- * Sanders. A Parallelization of Dijkstra's Shortest Path *
- * Algorithm. In Lubos Brim, Jozef Gruska, and Jiri Zlatuska, *
- * editors, Mathematical Foundations of Computer Science (MFCS), *
- * volume 1450 of Lecture Notes in Computer Science, pages *
- * 722--731, 1998. Springer. *
- * *
- * This implementation is, however, restricted to the distributed-memory *
- * case, where the work is distributed by virtue of the vertices being *
- * distributed. In a shared-memory (single address space) context, we *
- * would want to add an explicit balancing step. *
- **************************************************************************/
- #ifndef BOOST_GRAPH_CRAUSER_ET_AL_SHORTEST_PATHS_HPP
- #define BOOST_GRAPH_CRAUSER_ET_AL_SHORTEST_PATHS_HPP
- #ifndef BOOST_GRAPH_USE_MPI
- #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
- #endif
- #include <boost/assert.hpp>
- #include <boost/graph/distributed/detail/dijkstra_shortest_paths.hpp>
- #include <boost/graph/parallel/algorithm.hpp>
- #include <functional>
- #include <boost/graph/iteration_macros.hpp>
- #include <boost/property_map/property_map_iterator.hpp>
- #include <boost/type_traits/is_same.hpp>
- #include <boost/algorithm/minmax_element.hpp>
- #include <boost/property_map/parallel/caching_property_map.hpp>
- #include <boost/pending/indirect_cmp.hpp>
- #include <boost/graph/distributed/detail/remote_update_set.hpp>
- #include <vector>
- #include <boost/graph/breadth_first_search.hpp>
- #include <boost/graph/dijkstra_shortest_paths.hpp>
- #include <boost/graph/parallel/container_traits.hpp>
- #include <boost/pending/relaxed_heap.hpp>
- #ifdef PBGL_ACCOUNTING
- # include <boost/graph/accounting.hpp>
- # include <numeric>
- #endif // PBGL_ACCOUNTING
- #ifdef MUTABLE_QUEUE
- # include <boost/pending/mutable_queue.hpp>
- #endif
- namespace boost { namespace graph { namespace distributed {
- #ifdef PBGL_ACCOUNTING
- struct crauser_et_al_shortest_paths_stats_t
- {
- /* Total wall-clock time used by the algorithm.*/
- accounting::time_type execution_time;
- /* The number of vertices deleted in each superstep. */
- std::vector<std::size_t> deleted_vertices;
- template<typename OutputStream>
- void print(OutputStream& out)
- {
- double avg_deletions = std::accumulate(deleted_vertices.begin(),
- deleted_vertices.end(),
- 0.0);
- avg_deletions /= deleted_vertices.size();
- out << "Problem = \"Single-Source Shortest Paths\"\n"
- << "Algorithm = \"Crauser et al\"\n"
- << "Function = crauser_et_al_shortest_paths\n"
- << "Wall clock time = " << accounting::print_time(execution_time)
- << "\nSupersteps = " << deleted_vertices.size() << "\n"
- << "Avg. deletions per superstep = " << avg_deletions << "\n";
- }
- };
- static crauser_et_al_shortest_paths_stats_t crauser_et_al_shortest_paths_stats;
- #endif
- namespace detail {
- /************************************************************************
- * Function objects that perform distance comparisons modified by the *
- * minimum or maximum edge weights. *
- ************************************************************************/
- template<typename Vertex, typename DistanceMap, typename MinInWeightMap,
- typename Combine, typename Compare>
- struct min_in_distance_compare
- {
- typedef Vertex first_argument_type;
- typedef Vertex second_argument_type;
- typedef bool result_type;
- min_in_distance_compare(DistanceMap d, MinInWeightMap m,
- Combine combine, Compare compare)
- : distance_map(d), min_in_weight(m), combine(combine),
- compare(compare)
- {
- }
- bool operator()(const Vertex& x, const Vertex& y) const
- {
- return compare(combine(get(distance_map, x), -get(min_in_weight, x)),
- combine(get(distance_map, y), -get(min_in_weight, y)));
- }
- private:
- DistanceMap distance_map;
- MinInWeightMap min_in_weight;
- Combine combine;
- Compare compare;
- };
- template<typename Vertex, typename DistanceMap, typename MinOutWeightMap,
- typename Combine, typename Compare>
- struct min_out_distance_compare
- {
- typedef Vertex first_argument_type;
- typedef Vertex second_argument_type;
- typedef bool result_type;
- min_out_distance_compare(DistanceMap d, MinOutWeightMap m,
- Combine combine, Compare compare)
- : distance_map(d), min_out_weight(m), combine(combine),
- compare(compare)
- {
- }
- bool operator()(const Vertex& x, const Vertex& y) const
- {
- return compare(combine(get(distance_map, x), get(min_out_weight, x)),
- combine(get(distance_map, y), get(min_out_weight, y)));
- }
- private:
- DistanceMap distance_map;
- MinOutWeightMap min_out_weight;
- Combine combine;
- Compare compare;
- };
- /************************************************************************/
- /************************************************************************
- * Dijkstra queue that implements Crauser et al.'s criteria. This queue *
- * actually stores three separate priority queues, to help expose all *
- * vertices that can be processed in a single phase. *
- ************************************************************************/
- template<typename Graph, typename Combine,
- typename Compare, typename VertexIndexMap, typename DistanceMap,
- typename PredecessorMap, typename MinOutWeightMap,
- typename MinInWeightMap>
- class crauser_et_al_dijkstra_queue
- : public graph::detail::remote_update_set<
- crauser_et_al_dijkstra_queue<
- Graph, Combine, Compare, VertexIndexMap, DistanceMap,
- PredecessorMap, MinOutWeightMap, MinInWeightMap>,
- typename boost::graph::parallel::process_group_type<Graph>::type,
- typename dijkstra_msg_value<DistanceMap, PredecessorMap>::type,
- typename property_map<Graph, vertex_owner_t>::const_type>
- {
- typedef typename graph_traits<Graph>::vertex_descriptor
- vertex_descriptor;
- typedef crauser_et_al_dijkstra_queue self_type;
- typedef dijkstra_msg_value<DistanceMap, PredecessorMap> msg_value_creator;
- typedef typename msg_value_creator::type msg_value_type;
- typedef typename graph_traits<Graph>::vertices_size_type
- vertices_size_type;
- typedef typename property_map<Graph, vertex_owner_t>::const_type
- OwnerPropertyMap;
- typedef typename boost::graph::parallel::process_group_type<Graph>::type
- process_group_type;
- typedef graph::detail::remote_update_set<self_type, process_group_type,
- msg_value_type, OwnerPropertyMap>
- inherited;
- // Priority queue for tentative distances
- typedef indirect_cmp<DistanceMap, Compare> dist_queue_compare_type;
- typedef typename property_traits<DistanceMap>::value_type distance_type;
- #ifdef MUTABLE_QUEUE
- typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>,
- dist_queue_compare_type, VertexIndexMap> dist_queue_type;
- #else
- typedef relaxed_heap<vertex_descriptor, dist_queue_compare_type,
- VertexIndexMap> dist_queue_type;
- #endif // MUTABLE_QUEUE
- // Priority queue for OUT criteria
- typedef min_out_distance_compare<vertex_descriptor, DistanceMap,
- MinOutWeightMap, Combine, Compare>
- out_queue_compare_type;
- #ifdef MUTABLE_QUEUE
- typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>,
- out_queue_compare_type, VertexIndexMap> out_queue_type;
- #else
- typedef relaxed_heap<vertex_descriptor, out_queue_compare_type,
- VertexIndexMap> out_queue_type;
- #endif // MUTABLE_QUEUE
- // Priority queue for IN criteria
- typedef min_in_distance_compare<vertex_descriptor, DistanceMap,
- MinInWeightMap, Combine, Compare>
- in_queue_compare_type;
- #ifdef MUTABLE_QUEUE
- typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>,
- in_queue_compare_type, VertexIndexMap> in_queue_type;
- #else
- typedef relaxed_heap<vertex_descriptor, in_queue_compare_type,
- VertexIndexMap> in_queue_type;
- #endif // MUTABLE_QUEUE
- typedef typename process_group_type::process_id_type process_id_type;
- public:
- typedef typename dist_queue_type::size_type size_type;
- typedef typename dist_queue_type::value_type value_type;
- crauser_et_al_dijkstra_queue(const Graph& g,
- const Combine& combine,
- const Compare& compare,
- const VertexIndexMap& id,
- const DistanceMap& distance_map,
- const PredecessorMap& predecessor_map,
- const MinOutWeightMap& min_out_weight,
- const MinInWeightMap& min_in_weight)
- : inherited(boost::graph::parallel::process_group(g), get(vertex_owner, g)),
- dist_queue(num_vertices(g),
- dist_queue_compare_type(distance_map, compare),
- id),
- out_queue(num_vertices(g),
- out_queue_compare_type(distance_map, min_out_weight,
- combine, compare),
- id),
- in_queue(num_vertices(g),
- in_queue_compare_type(distance_map, min_in_weight,
- combine, compare),
- id),
- g(g),
- distance_map(distance_map),
- predecessor_map(predecessor_map),
- min_out_weight(min_out_weight),
- min_in_weight(min_in_weight),
- min_distance(0),
- min_out_distance(0)
- #ifdef PBGL_ACCOUNTING
- , local_deletions(0)
- #endif
- { }
- void push(const value_type& x)
- {
- msg_value_type msg_value =
- msg_value_creator::create(get(distance_map, x),
- predecessor_value(get(predecessor_map, x)));
- inherited::update(x, msg_value);
- }
- void update(const value_type& x) { push(x); }
- void pop()
- {
- // Remove from distance queue
- dist_queue.remove(top_vertex);
- // Remove from OUT queue
- out_queue.remove(top_vertex);
- // Remove from IN queue
- in_queue.remove(top_vertex);
- #ifdef PBGL_ACCOUNTING
- ++local_deletions;
- #endif
- }
- vertex_descriptor& top() { return top_vertex; }
- const vertex_descriptor& top() const { return top_vertex; }
- bool empty()
- {
- inherited::collect();
- // If there are no suitable messages, wait until we get something
- while (!has_suitable_vertex()) {
- if (do_synchronize()) return true;
- }
- // Return true only if nobody has any messages; false if we
- // have suitable messages
- return false;
- }
- bool do_synchronize()
- {
- using boost::parallel::all_reduce;
- using boost::parallel::minimum;
- inherited::synchronize();
- // TBD: could use combine here, but then we need to stop using
- // minimum<distance_type>() as the function object.
- distance_type local_distances[2];
- local_distances[0] =
- dist_queue.empty()? (std::numeric_limits<distance_type>::max)()
- : get(distance_map, dist_queue.top());
- local_distances[1] =
- out_queue.empty()? (std::numeric_limits<distance_type>::max)()
- : (get(distance_map, out_queue.top())
- + get(min_out_weight, out_queue.top()));
- distance_type distances[2];
- all_reduce(this->process_group, local_distances, local_distances + 2,
- distances, minimum<distance_type>());
- min_distance = distances[0];
- min_out_distance = distances[1];
- #ifdef PBGL_ACCOUNTING
- std::size_t deletions = 0;
- all_reduce(this->process_group, &local_deletions, &local_deletions + 1,
- &deletions, std::plus<std::size_t>());
- if (process_id(this->process_group) == 0) {
- crauser_et_al_shortest_paths_stats.deleted_vertices.push_back(deletions);
- }
- local_deletions = 0;
- BOOST_ASSERT(deletions > 0);
- #endif
- return min_distance == (std::numeric_limits<distance_type>::max)();
- }
- private:
- vertex_descriptor predecessor_value(vertex_descriptor v) const
- { return v; }
- vertex_descriptor
- predecessor_value(property_traits<dummy_property_map>::reference) const
- { return graph_traits<Graph>::null_vertex(); }
- bool has_suitable_vertex() const
- {
- if (!dist_queue.empty()) {
- top_vertex = dist_queue.top();
- if (get(distance_map, dist_queue.top()) <= min_out_distance)
- return true;
- }
- if (!in_queue.empty()) {
- top_vertex = in_queue.top();
- return (get(distance_map, top_vertex)
- - get(min_in_weight, top_vertex)) <= min_distance;
- }
- return false;
- }
- public:
- void
- receive_update(process_id_type source, vertex_descriptor vertex,
- distance_type distance)
- {
- // Update the queue if the received distance is better than
- // the distance we know locally
- if (distance < get(distance_map, vertex)
- || (distance == get(distance_map, vertex)
- && source == process_id(this->process_group))) {
- // Update the local distance map
- put(distance_map, vertex, distance);
- bool is_in_queue = dist_queue.contains(vertex);
- if (!is_in_queue) {
- dist_queue.push(vertex);
- out_queue.push(vertex);
- in_queue.push(vertex);
- }
- else {
- dist_queue.update(vertex);
- out_queue.update(vertex);
- in_queue.update(vertex);
- }
- }
- }
- void
- receive_update(process_id_type source, vertex_descriptor vertex,
- std::pair<distance_type, vertex_descriptor> p)
- {
- if (p.first <= get(distance_map, vertex)) {
- put(predecessor_map, vertex, p.second);
- receive_update(source, vertex, p.first);
- }
- }
- private:
- dist_queue_type dist_queue;
- out_queue_type out_queue;
- in_queue_type in_queue;
- mutable value_type top_vertex;
- const Graph& g;
- DistanceMap distance_map;
- PredecessorMap predecessor_map;
- MinOutWeightMap min_out_weight;
- MinInWeightMap min_in_weight;
- distance_type min_distance;
- distance_type min_out_distance;
- #ifdef PBGL_ACCOUNTING
- std::size_t local_deletions;
- #endif
- };
- /************************************************************************/
- /************************************************************************
- * Initialize the property map that contains the minimum incoming edge *
- * weight for each vertex. There are separate implementations for *
- * directed, bidirectional, and undirected graph. *
- ************************************************************************/
- template<typename Graph, typename MinInWeightMap, typename WeightMap,
- typename Inf, typename Compare>
- void
- initialize_min_in_weights(const Graph& g, MinInWeightMap min_in_weight,
- WeightMap weight, Inf inf, Compare compare,
- directed_tag, incidence_graph_tag)
- {
- // Send minimum weights off to the owners
- set_property_map_role(vertex_distance, min_in_weight);
- BGL_FORALL_VERTICES_T(v, g, Graph) {
- BGL_FORALL_OUTEDGES_T(v, e, g, Graph) {
- if (get(weight, e) < get(min_in_weight, target(e, g)))
- put(min_in_weight, target(e, g), get(weight, e));
- }
- }
- using boost::graph::parallel::process_group;
- synchronize(process_group(g));
- // Replace any infinities with zeros
- BGL_FORALL_VERTICES_T(v, g, Graph) {
- if (get(min_in_weight, v) == inf) put(min_in_weight, v, 0);
- }
- }
- template<typename Graph, typename MinInWeightMap, typename WeightMap,
- typename Inf, typename Compare>
- void
- initialize_min_in_weights(const Graph& g, MinInWeightMap min_in_weight,
- WeightMap weight, Inf inf, Compare compare,
- directed_tag, bidirectional_graph_tag)
- {
- #if 0
- typename property_map<Graph, vertex_local_t>::const_type
- local = get(vertex_local, g);
- // This code assumes that the properties of the in-edges are
- // available locally. This is not necessarily the case, so don't
- // do this yet.
- set_property_map_role(vertex_distance, min_in_weight);
- BGL_FORALL_VERTICES_T(v, g, Graph) {
- if (in_edges(v, g).first != in_edges(v, g).second) {
- std::cerr << "weights(" << g.distribution().global(get(local, v))
- << ") = ";
- BGL_FORALL_INEDGES_T(v, e, g, Graph) {
- std::cerr << get(weight, e) << ' ';
- }
- std::cerr << std::endl;
- put(min_in_weight, v,
- *boost::first_min_element
- (make_property_map_iterator(weight, in_edges(v, g).first),
- make_property_map_iterator(weight, in_edges(v, g).second),
- compare));
- } else {
- put(min_in_weight, v, 0);
- }
- std::cerr << "miw(" << g.distribution().global(get(local, v)) << ") = "
- << get(min_in_weight, v) << std::endl;
- }
- #else
- initialize_min_in_weights(g, min_in_weight, weight, inf, compare,
- directed_tag(), incidence_graph_tag());
- #endif
- }
- template<typename Graph, typename MinInWeightMap, typename WeightMap,
- typename Inf, typename Compare>
- inline void
- initialize_min_in_weights(const Graph&, MinInWeightMap, WeightMap, Inf,
- Compare, undirected_tag, bidirectional_graph_tag)
- {
- // In weights are the same as out weights, so do nothing
- }
- /************************************************************************/
- /************************************************************************
- * Initialize the property map that contains the minimum outgoing edge *
- * weight for each vertex. *
- ************************************************************************/
- template<typename Graph, typename MinOutWeightMap, typename WeightMap,
- typename Compare>
- void
- initialize_min_out_weights(const Graph& g, MinOutWeightMap min_out_weight,
- WeightMap weight, Compare compare)
- {
- typedef typename property_traits<WeightMap>::value_type weight_type;
- BGL_FORALL_VERTICES_T(v, g, Graph) {
- if (out_edges(v, g).first != out_edges(v, g).second) {
- put(min_out_weight, v,
- *boost::first_min_element
- (make_property_map_iterator(weight, out_edges(v, g).first),
- make_property_map_iterator(weight, out_edges(v, g).second),
- compare));
- if (get(min_out_weight, v) < weight_type(0))
- boost::throw_exception(negative_edge());
- }
- }
- }
- /************************************************************************/
- } // end namespace detail
- template<typename DistributedGraph, typename DijkstraVisitor,
- typename PredecessorMap, typename DistanceMap, typename WeightMap,
- typename IndexMap, typename ColorMap, typename Compare,
- typename Combine, typename DistInf, typename DistZero>
- void
- crauser_et_al_shortest_paths
- (const DistributedGraph& g,
- typename graph_traits<DistributedGraph>::vertex_descriptor s,
- PredecessorMap predecessor, DistanceMap distance, WeightMap weight,
- IndexMap index_map, ColorMap color_map,
- Compare compare, Combine combine, DistInf inf, DistZero zero,
- DijkstraVisitor vis)
- {
- #ifdef PBGL_ACCOUNTING
- crauser_et_al_shortest_paths_stats.deleted_vertices.clear();
- crauser_et_al_shortest_paths_stats.execution_time = accounting::get_time();
- #endif
- // Property map that stores the lowest edge weight outgoing from
- // each vertex. If a vertex has no out-edges, the stored weight
- // is zero.
- typedef typename property_traits<WeightMap>::value_type weight_type;
- typedef iterator_property_map<weight_type*, IndexMap> MinOutWeightMap;
- std::vector<weight_type> min_out_weights_vec(num_vertices(g), inf);
- MinOutWeightMap min_out_weight(&min_out_weights_vec.front(), index_map);
- detail::initialize_min_out_weights(g, min_out_weight, weight, compare);
- // Property map that stores the lowest edge weight incoming to
- // each vertex. For undirected graphs, this will just be a
- // shallow copy of the version for outgoing edges.
- typedef typename graph_traits<DistributedGraph>::directed_category
- directed_category;
- const bool is_undirected =
- is_same<directed_category, undirected_tag>::value;
- typedef MinOutWeightMap MinInWeightMap;
- std::vector<weight_type>
- min_in_weights_vec(is_undirected? 1 : num_vertices(g), inf);
- MinInWeightMap min_in_weight(&min_in_weights_vec.front(), index_map);
- typedef typename graph_traits<DistributedGraph>::traversal_category
- category;
- detail::initialize_min_in_weights(g, min_in_weight, weight, inf, compare,
- directed_category(), category());
- // Initialize local portion of property maps
- typename graph_traits<DistributedGraph>::vertex_iterator ui, ui_end;
- for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) {
- put(distance, *ui, inf);
- put(predecessor, *ui, *ui);
- }
- put(distance, s, zero);
- // Dijkstra Queue
- typedef detail::crauser_et_al_dijkstra_queue
- <DistributedGraph, Combine, Compare, IndexMap, DistanceMap,
- PredecessorMap, MinOutWeightMap, MinInWeightMap>
- Queue;
- Queue Q(g, combine, compare, index_map, distance, predecessor,
- min_out_weight, is_undirected? min_out_weight : min_in_weight);
- // Parallel Dijkstra visitor
- ::boost::detail::dijkstra_bfs_visitor<
- DijkstraVisitor, Queue, WeightMap,
- boost::parallel::caching_property_map<PredecessorMap>,
- boost::parallel::caching_property_map<DistanceMap>, Combine, Compare
- > bfs_vis(vis, Q, weight,
- boost::parallel::make_caching_property_map(predecessor),
- boost::parallel::make_caching_property_map(distance),
- combine, compare, zero);
- set_property_map_role(vertex_color, color_map);
- set_property_map_role(vertex_distance, distance);
- breadth_first_search(g, s, Q, bfs_vis, color_map);
- #ifdef PBGL_ACCOUNTING
- crauser_et_al_shortest_paths_stats.execution_time =
- accounting::get_time() - crauser_et_al_shortest_paths_stats.execution_time;
- #endif
- }
- template<typename DistributedGraph, typename PredecessorMap,
- typename DistanceMap, typename WeightMap>
- void
- crauser_et_al_shortest_paths
- (const DistributedGraph& g,
- typename graph_traits<DistributedGraph>::vertex_descriptor s,
- PredecessorMap predecessor, DistanceMap distance, WeightMap weight)
- {
- typedef typename property_traits<DistanceMap>::value_type distance_type;
- std::vector<default_color_type> colors(num_vertices(g), white_color);
- crauser_et_al_shortest_paths(g, s, predecessor, distance, weight,
- get(vertex_index, g),
- make_iterator_property_map(&colors[0],
- get(vertex_index, g)),
- std::less<distance_type>(),
- closed_plus<distance_type>(),
- (std::numeric_limits<distance_type>::max)(),
- distance_type(),
- dijkstra_visitor<>());
- }
- template<typename DistributedGraph, typename PredecessorMap,
- typename DistanceMap>
- void
- crauser_et_al_shortest_paths
- (const DistributedGraph& g,
- typename graph_traits<DistributedGraph>::vertex_descriptor s,
- PredecessorMap predecessor, DistanceMap distance)
- {
- crauser_et_al_shortest_paths(g, s, predecessor, distance,
- get(edge_weight, g));
- }
- } // end namespace distributed
- #ifdef PBGL_ACCOUNTING
- using distributed::crauser_et_al_shortest_paths_stats;
- #endif
- using distributed::crauser_et_al_shortest_paths;
- } } // end namespace boost::graph
- #endif // BOOST_GRAPH_CRAUSER_ET_AL_SHORTEST_PATHS_HPP
|