123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- // Copyright (C) 2005-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
- #ifndef BOOST_GRAPH_DISTRIBUTED_FRUCHTERMAN_REINGOLD_HPP
- #define BOOST_GRAPH_DISTRIBUTED_FRUCHTERMAN_REINGOLD_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/graph/fruchterman_reingold.hpp>
- namespace boost { namespace graph { namespace distributed {
- class simple_tiling
- {
- public:
- simple_tiling(int columns, int rows, bool flip = true)
- : columns(columns), rows(rows), flip(flip)
- {
- }
- // Convert from a position (x, y) in the tiled display into a
- // processor ID number
- int operator()(int x, int y) const
- {
- return flip? (rows - y - 1) * columns + x : y * columns + x;
- }
- // Convert from a process ID to a position (x, y) in the tiled
- // display
- std::pair<int, int> operator()(int id)
- {
- int my_col = id % columns;
- int my_row = flip? rows - (id / columns) - 1 : id / columns;
- return std::make_pair(my_col, my_row);
- }
- int columns, rows;
- private:
- bool flip;
- };
- // Force pairs function object that does nothing
- struct no_force_pairs
- {
- template<typename Graph, typename ApplyForce>
- void operator()(const Graph&, const ApplyForce&)
- {
- }
- };
- // Computes force pairs in the distributed case.
- template<typename PositionMap, typename DisplacementMap, typename LocalForces,
- typename NonLocalForces = no_force_pairs>
- class distributed_force_pairs_proxy
- {
- public:
- distributed_force_pairs_proxy(const PositionMap& position,
- const DisplacementMap& displacement,
- const LocalForces& local_forces,
- const NonLocalForces& nonlocal_forces = NonLocalForces())
- : position(position), displacement(displacement),
- local_forces(local_forces), nonlocal_forces(nonlocal_forces)
- {
- }
- template<typename Graph, typename ApplyForce>
- void operator()(const Graph& g, ApplyForce apply_force)
- {
- // Flush remote displacements
- displacement.flush();
- // Receive updated positions for all of our neighbors
- synchronize(position);
- // Reset remote displacements
- displacement.reset();
- // Compute local repulsive forces
- local_forces(g, apply_force);
- // Compute neighbor repulsive forces
- nonlocal_forces(g, apply_force);
- }
- protected:
- PositionMap position;
- DisplacementMap displacement;
- LocalForces local_forces;
- NonLocalForces nonlocal_forces;
- };
- template<typename PositionMap, typename DisplacementMap, typename LocalForces>
- inline
- distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces>
- make_distributed_force_pairs(const PositionMap& position,
- const DisplacementMap& displacement,
- const LocalForces& local_forces)
- {
- typedef
- distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces>
- result_type;
- return result_type(position, displacement, local_forces);
- }
- template<typename PositionMap, typename DisplacementMap, typename LocalForces,
- typename NonLocalForces>
- inline
- distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces,
- NonLocalForces>
- make_distributed_force_pairs(const PositionMap& position,
- const DisplacementMap& displacement,
- const LocalForces& local_forces,
- const NonLocalForces& nonlocal_forces)
- {
- typedef
- distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces,
- NonLocalForces>
- result_type;
- return result_type(position, displacement, local_forces, nonlocal_forces);
- }
- // Compute nonlocal force pairs based on the shared borders with
- // adjacent tiles.
- template<typename PositionMap>
- class neighboring_tiles_force_pairs
- {
- public:
- typedef typename property_traits<PositionMap>::value_type Point;
- typedef typename point_traits<Point>::component_type Dim;
- enum bucket_position { left, top, right, bottom, end_position };
-
- neighboring_tiles_force_pairs(PositionMap position, Point origin,
- Point extent, simple_tiling tiling)
- : position(position), origin(origin), extent(extent), tiling(tiling)
- {
- }
- template<typename Graph, typename ApplyForce>
- void operator()(const Graph& g, ApplyForce apply_force)
- {
- // TBD: Do this some smarter way
- if (tiling.columns == 1 && tiling.rows == 1)
- return;
- typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
- #ifndef BOOST_NO_STDC_NAMESPACE
- using std::sqrt;
- #endif // BOOST_NO_STDC_NAMESPACE
- // TBD: num_vertices(g) should be the global number of vertices?
- Dim two_k = Dim(2) * sqrt(extent[0] * extent[1] / num_vertices(g));
- std::vector<vertex_descriptor> my_vertices[4];
- std::vector<vertex_descriptor> neighbor_vertices[4];
-
- // Compute cutoff positions
- Dim cutoffs[4];
- cutoffs[left] = origin[0] + two_k;
- cutoffs[top] = origin[1] + two_k;
- cutoffs[right] = origin[0] + extent[0] - two_k;
- cutoffs[bottom] = origin[1] + extent[1] - two_k;
- // Compute neighbors
- typename PositionMap::process_group_type pg = position.process_group();
- std::pair<int, int> my_tile = tiling(process_id(pg));
- int neighbors[4] = { -1, -1, -1, -1 } ;
- if (my_tile.first > 0)
- neighbors[left] = tiling(my_tile.first - 1, my_tile.second);
- if (my_tile.second > 0)
- neighbors[top] = tiling(my_tile.first, my_tile.second - 1);
- if (my_tile.first < tiling.columns - 1)
- neighbors[right] = tiling(my_tile.first + 1, my_tile.second);
- if (my_tile.second < tiling.rows - 1)
- neighbors[bottom] = tiling(my_tile.first, my_tile.second + 1);
- // Sort vertices along the edges into buckets
- BGL_FORALL_VERTICES_T(v, g, Graph) {
- if (position[v][0] <= cutoffs[left]) my_vertices[left].push_back(v);
- if (position[v][1] <= cutoffs[top]) my_vertices[top].push_back(v);
- if (position[v][0] >= cutoffs[right]) my_vertices[right].push_back(v);
- if (position[v][1] >= cutoffs[bottom]) my_vertices[bottom].push_back(v);
- }
- // Send vertices to neighbors, and gather our neighbors' vertices
- bucket_position pos;
- for (pos = left; pos < end_position; pos = bucket_position(pos + 1)) {
- if (neighbors[pos] != -1) {
- send(pg, neighbors[pos], 0, my_vertices[pos].size());
- if (!my_vertices[pos].empty())
- send(pg, neighbors[pos], 1,
- &my_vertices[pos].front(), my_vertices[pos].size());
- }
- }
- // Pass messages around
- synchronize(pg);
-
- // Receive neighboring vertices
- for (pos = left; pos < end_position; pos = bucket_position(pos + 1)) {
- if (neighbors[pos] != -1) {
- std::size_t incoming_vertices;
- receive(pg, neighbors[pos], 0, incoming_vertices);
- if (incoming_vertices) {
- neighbor_vertices[pos].resize(incoming_vertices);
- receive(pg, neighbors[pos], 1, &neighbor_vertices[pos].front(),
- incoming_vertices);
- }
- }
- }
- // For each neighboring vertex, we need to get its current position
- for (pos = left; pos < end_position; pos = bucket_position(pos + 1))
- for (typename std::vector<vertex_descriptor>::iterator i =
- neighbor_vertices[pos].begin();
- i != neighbor_vertices[pos].end();
- ++i)
- request(position, *i);
- synchronize(position);
- // Apply forces in adjacent bins. This is O(n^2) in the worst
- // case. Oh well.
- for (pos = left; pos < end_position; pos = bucket_position(pos + 1)) {
- for (typename std::vector<vertex_descriptor>::iterator i =
- my_vertices[pos].begin();
- i != my_vertices[pos].end();
- ++i)
- for (typename std::vector<vertex_descriptor>::iterator j =
- neighbor_vertices[pos].begin();
- j != neighbor_vertices[pos].end();
- ++j)
- apply_force(*i, *j);
- }
- }
- protected:
- PositionMap position;
- Point origin;
- Point extent;
- simple_tiling tiling;
- };
- template<typename PositionMap>
- inline neighboring_tiles_force_pairs<PositionMap>
- make_neighboring_tiles_force_pairs
- (PositionMap position,
- typename property_traits<PositionMap>::value_type origin,
- typename property_traits<PositionMap>::value_type extent,
- simple_tiling tiling)
- {
- return neighboring_tiles_force_pairs<PositionMap>(position, origin, extent,
- tiling);
- }
- template<typename DisplacementMap, typename Cooling>
- class distributed_cooling_proxy
- {
- public:
- typedef typename Cooling::result_type result_type;
- distributed_cooling_proxy(const DisplacementMap& displacement,
- const Cooling& cooling)
- : displacement(displacement), cooling(cooling)
- {
- }
- result_type operator()()
- {
- // Accumulate displacements computed on each processor
- synchronize(displacement.data->process_group);
- // Allow the underlying cooling to occur
- return cooling();
- }
- protected:
- DisplacementMap displacement;
- Cooling cooling;
- };
- template<typename DisplacementMap, typename Cooling>
- inline distributed_cooling_proxy<DisplacementMap, Cooling>
- make_distributed_cooling(const DisplacementMap& displacement,
- const Cooling& cooling)
- {
- typedef distributed_cooling_proxy<DisplacementMap, Cooling> result_type;
- return result_type(displacement, cooling);
- }
- template<typename Point>
- struct point_accumulating_reducer {
- BOOST_STATIC_CONSTANT(bool, non_default_resolver = true);
- template<typename K>
- Point operator()(const K&) const { return Point(); }
- template<typename K>
- Point operator()(const K&, const Point& p1, const Point& p2) const
- { return Point(p1[0] + p2[0], p1[1] + p2[1]); }
- };
- template<typename Graph, typename PositionMap,
- typename AttractiveForce, typename RepulsiveForce,
- typename ForcePairs, typename Cooling, typename DisplacementMap>
- void
- fruchterman_reingold_force_directed_layout
- (const Graph& g,
- PositionMap position,
- typename property_traits<PositionMap>::value_type const& origin,
- typename property_traits<PositionMap>::value_type const& extent,
- AttractiveForce attractive_force,
- RepulsiveForce repulsive_force,
- ForcePairs force_pairs,
- Cooling cool,
- DisplacementMap displacement)
- {
- typedef typename property_traits<PositionMap>::value_type Point;
- // Reduction in the displacement map involves summing the forces
- displacement.set_reduce(point_accumulating_reducer<Point>());
- // We need to track the positions of all of our neighbors
- BGL_FORALL_VERTICES_T(u, g, Graph)
- BGL_FORALL_ADJ_T(u, v, g, Graph)
- request(position, v);
- // Invoke the "sequential" Fruchterman-Reingold implementation
- boost::fruchterman_reingold_force_directed_layout
- (g, position, origin, extent,
- attractive_force, repulsive_force,
- make_distributed_force_pairs(position, displacement, force_pairs),
- make_distributed_cooling(displacement, cool),
- displacement);
- }
- template<typename Graph, typename PositionMap,
- typename AttractiveForce, typename RepulsiveForce,
- typename ForcePairs, typename Cooling, typename DisplacementMap>
- void
- fruchterman_reingold_force_directed_layout
- (const Graph& g,
- PositionMap position,
- typename property_traits<PositionMap>::value_type const& origin,
- typename property_traits<PositionMap>::value_type const& extent,
- AttractiveForce attractive_force,
- RepulsiveForce repulsive_force,
- ForcePairs force_pairs,
- Cooling cool,
- DisplacementMap displacement,
- simple_tiling tiling)
- {
- typedef typename property_traits<PositionMap>::value_type Point;
- // Reduction in the displacement map involves summing the forces
- displacement.set_reduce(point_accumulating_reducer<Point>());
- // We need to track the positions of all of our neighbors
- BGL_FORALL_VERTICES_T(u, g, Graph)
- BGL_FORALL_ADJ_T(u, v, g, Graph)
- request(position, v);
- // Invoke the "sequential" Fruchterman-Reingold implementation
- boost::fruchterman_reingold_force_directed_layout
- (g, position, origin, extent,
- attractive_force, repulsive_force,
- make_distributed_force_pairs
- (position, displacement, force_pairs,
- make_neighboring_tiles_force_pairs(position, origin, extent, tiling)),
- make_distributed_cooling(displacement, cool),
- displacement);
- }
- } } } // end namespace boost::graph::distributed
- #endif // BOOST_GRAPH_DISTRIBUTED_FRUCHTERMAN_REINGOLD_HPP
|