annotate DEPENDENCIES/generic/include/boost/graph/distributed/fruchterman_reingold.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 // Copyright (C) 2005-2006 The Trustees of Indiana University.
Chris@16 2
Chris@16 3 // Use, modification and distribution is subject to the Boost Software
Chris@16 4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 5 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 6
Chris@16 7 // Authors: Douglas Gregor
Chris@16 8 // Andrew Lumsdaine
Chris@16 9 #ifndef BOOST_GRAPH_DISTRIBUTED_FRUCHTERMAN_REINGOLD_HPP
Chris@16 10 #define BOOST_GRAPH_DISTRIBUTED_FRUCHTERMAN_REINGOLD_HPP
Chris@16 11
Chris@16 12 #ifndef BOOST_GRAPH_USE_MPI
Chris@16 13 #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
Chris@16 14 #endif
Chris@16 15
Chris@16 16 #include <boost/graph/fruchterman_reingold.hpp>
Chris@16 17
Chris@16 18 namespace boost { namespace graph { namespace distributed {
Chris@16 19
Chris@16 20 class simple_tiling
Chris@16 21 {
Chris@16 22 public:
Chris@16 23 simple_tiling(int columns, int rows, bool flip = true)
Chris@16 24 : columns(columns), rows(rows), flip(flip)
Chris@16 25 {
Chris@16 26 }
Chris@16 27
Chris@16 28 // Convert from a position (x, y) in the tiled display into a
Chris@16 29 // processor ID number
Chris@16 30 int operator()(int x, int y) const
Chris@16 31 {
Chris@16 32 return flip? (rows - y - 1) * columns + x : y * columns + x;
Chris@16 33 }
Chris@16 34
Chris@16 35 // Convert from a process ID to a position (x, y) in the tiled
Chris@16 36 // display
Chris@16 37 std::pair<int, int> operator()(int id)
Chris@16 38 {
Chris@16 39 int my_col = id % columns;
Chris@16 40 int my_row = flip? rows - (id / columns) - 1 : id / columns;
Chris@16 41 return std::make_pair(my_col, my_row);
Chris@16 42 }
Chris@16 43
Chris@16 44 int columns, rows;
Chris@16 45
Chris@16 46 private:
Chris@16 47 bool flip;
Chris@16 48 };
Chris@16 49
Chris@16 50 // Force pairs function object that does nothing
Chris@16 51 struct no_force_pairs
Chris@16 52 {
Chris@16 53 template<typename Graph, typename ApplyForce>
Chris@16 54 void operator()(const Graph&, const ApplyForce&)
Chris@16 55 {
Chris@16 56 }
Chris@16 57 };
Chris@16 58
Chris@16 59 // Computes force pairs in the distributed case.
Chris@16 60 template<typename PositionMap, typename DisplacementMap, typename LocalForces,
Chris@16 61 typename NonLocalForces = no_force_pairs>
Chris@16 62 class distributed_force_pairs_proxy
Chris@16 63 {
Chris@16 64 public:
Chris@16 65 distributed_force_pairs_proxy(const PositionMap& position,
Chris@16 66 const DisplacementMap& displacement,
Chris@16 67 const LocalForces& local_forces,
Chris@16 68 const NonLocalForces& nonlocal_forces = NonLocalForces())
Chris@16 69 : position(position), displacement(displacement),
Chris@16 70 local_forces(local_forces), nonlocal_forces(nonlocal_forces)
Chris@16 71 {
Chris@16 72 }
Chris@16 73
Chris@16 74 template<typename Graph, typename ApplyForce>
Chris@16 75 void operator()(const Graph& g, ApplyForce apply_force)
Chris@16 76 {
Chris@16 77 // Flush remote displacements
Chris@16 78 displacement.flush();
Chris@16 79
Chris@16 80 // Receive updated positions for all of our neighbors
Chris@16 81 synchronize(position);
Chris@16 82
Chris@16 83 // Reset remote displacements
Chris@16 84 displacement.reset();
Chris@16 85
Chris@16 86 // Compute local repulsive forces
Chris@16 87 local_forces(g, apply_force);
Chris@16 88
Chris@16 89 // Compute neighbor repulsive forces
Chris@16 90 nonlocal_forces(g, apply_force);
Chris@16 91 }
Chris@16 92
Chris@16 93 protected:
Chris@16 94 PositionMap position;
Chris@16 95 DisplacementMap displacement;
Chris@16 96 LocalForces local_forces;
Chris@16 97 NonLocalForces nonlocal_forces;
Chris@16 98 };
Chris@16 99
Chris@16 100 template<typename PositionMap, typename DisplacementMap, typename LocalForces>
Chris@16 101 inline
Chris@16 102 distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces>
Chris@16 103 make_distributed_force_pairs(const PositionMap& position,
Chris@16 104 const DisplacementMap& displacement,
Chris@16 105 const LocalForces& local_forces)
Chris@16 106 {
Chris@16 107 typedef
Chris@16 108 distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces>
Chris@16 109 result_type;
Chris@16 110 return result_type(position, displacement, local_forces);
Chris@16 111 }
Chris@16 112
Chris@16 113 template<typename PositionMap, typename DisplacementMap, typename LocalForces,
Chris@16 114 typename NonLocalForces>
Chris@16 115 inline
Chris@16 116 distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces,
Chris@16 117 NonLocalForces>
Chris@16 118 make_distributed_force_pairs(const PositionMap& position,
Chris@16 119 const DisplacementMap& displacement,
Chris@16 120 const LocalForces& local_forces,
Chris@16 121 const NonLocalForces& nonlocal_forces)
Chris@16 122 {
Chris@16 123 typedef
Chris@16 124 distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces,
Chris@16 125 NonLocalForces>
Chris@16 126 result_type;
Chris@16 127 return result_type(position, displacement, local_forces, nonlocal_forces);
Chris@16 128 }
Chris@16 129
Chris@16 130 // Compute nonlocal force pairs based on the shared borders with
Chris@16 131 // adjacent tiles.
Chris@16 132 template<typename PositionMap>
Chris@16 133 class neighboring_tiles_force_pairs
Chris@16 134 {
Chris@16 135 public:
Chris@16 136 typedef typename property_traits<PositionMap>::value_type Point;
Chris@16 137 typedef typename point_traits<Point>::component_type Dim;
Chris@16 138
Chris@16 139 enum bucket_position { left, top, right, bottom, end_position };
Chris@16 140
Chris@16 141 neighboring_tiles_force_pairs(PositionMap position, Point origin,
Chris@16 142 Point extent, simple_tiling tiling)
Chris@16 143 : position(position), origin(origin), extent(extent), tiling(tiling)
Chris@16 144 {
Chris@16 145 }
Chris@16 146
Chris@16 147 template<typename Graph, typename ApplyForce>
Chris@16 148 void operator()(const Graph& g, ApplyForce apply_force)
Chris@16 149 {
Chris@16 150 // TBD: Do this some smarter way
Chris@16 151 if (tiling.columns == 1 && tiling.rows == 1)
Chris@16 152 return;
Chris@16 153
Chris@16 154 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
Chris@16 155 #ifndef BOOST_NO_STDC_NAMESPACE
Chris@16 156 using std::sqrt;
Chris@16 157 #endif // BOOST_NO_STDC_NAMESPACE
Chris@16 158
Chris@16 159 // TBD: num_vertices(g) should be the global number of vertices?
Chris@16 160 Dim two_k = Dim(2) * sqrt(extent[0] * extent[1] / num_vertices(g));
Chris@16 161
Chris@16 162 std::vector<vertex_descriptor> my_vertices[4];
Chris@16 163 std::vector<vertex_descriptor> neighbor_vertices[4];
Chris@16 164
Chris@16 165 // Compute cutoff positions
Chris@16 166 Dim cutoffs[4];
Chris@16 167 cutoffs[left] = origin[0] + two_k;
Chris@16 168 cutoffs[top] = origin[1] + two_k;
Chris@16 169 cutoffs[right] = origin[0] + extent[0] - two_k;
Chris@16 170 cutoffs[bottom] = origin[1] + extent[1] - two_k;
Chris@16 171
Chris@16 172 // Compute neighbors
Chris@16 173 typename PositionMap::process_group_type pg = position.process_group();
Chris@16 174 std::pair<int, int> my_tile = tiling(process_id(pg));
Chris@16 175 int neighbors[4] = { -1, -1, -1, -1 } ;
Chris@16 176 if (my_tile.first > 0)
Chris@16 177 neighbors[left] = tiling(my_tile.first - 1, my_tile.second);
Chris@16 178 if (my_tile.second > 0)
Chris@16 179 neighbors[top] = tiling(my_tile.first, my_tile.second - 1);
Chris@16 180 if (my_tile.first < tiling.columns - 1)
Chris@16 181 neighbors[right] = tiling(my_tile.first + 1, my_tile.second);
Chris@16 182 if (my_tile.second < tiling.rows - 1)
Chris@16 183 neighbors[bottom] = tiling(my_tile.first, my_tile.second + 1);
Chris@16 184
Chris@16 185 // Sort vertices along the edges into buckets
Chris@16 186 BGL_FORALL_VERTICES_T(v, g, Graph) {
Chris@16 187 if (position[v][0] <= cutoffs[left]) my_vertices[left].push_back(v);
Chris@16 188 if (position[v][1] <= cutoffs[top]) my_vertices[top].push_back(v);
Chris@16 189 if (position[v][0] >= cutoffs[right]) my_vertices[right].push_back(v);
Chris@16 190 if (position[v][1] >= cutoffs[bottom]) my_vertices[bottom].push_back(v);
Chris@16 191 }
Chris@16 192
Chris@16 193 // Send vertices to neighbors, and gather our neighbors' vertices
Chris@16 194 bucket_position pos;
Chris@16 195 for (pos = left; pos < end_position; pos = bucket_position(pos + 1)) {
Chris@16 196 if (neighbors[pos] != -1) {
Chris@16 197 send(pg, neighbors[pos], 0, my_vertices[pos].size());
Chris@16 198 if (!my_vertices[pos].empty())
Chris@16 199 send(pg, neighbors[pos], 1,
Chris@16 200 &my_vertices[pos].front(), my_vertices[pos].size());
Chris@16 201 }
Chris@16 202 }
Chris@16 203
Chris@16 204 // Pass messages around
Chris@16 205 synchronize(pg);
Chris@16 206
Chris@16 207 // Receive neighboring vertices
Chris@16 208 for (pos = left; pos < end_position; pos = bucket_position(pos + 1)) {
Chris@16 209 if (neighbors[pos] != -1) {
Chris@16 210 std::size_t incoming_vertices;
Chris@16 211 receive(pg, neighbors[pos], 0, incoming_vertices);
Chris@16 212
Chris@16 213 if (incoming_vertices) {
Chris@16 214 neighbor_vertices[pos].resize(incoming_vertices);
Chris@16 215 receive(pg, neighbors[pos], 1, &neighbor_vertices[pos].front(),
Chris@16 216 incoming_vertices);
Chris@16 217 }
Chris@16 218 }
Chris@16 219 }
Chris@16 220
Chris@16 221 // For each neighboring vertex, we need to get its current position
Chris@16 222 for (pos = left; pos < end_position; pos = bucket_position(pos + 1))
Chris@16 223 for (typename std::vector<vertex_descriptor>::iterator i =
Chris@16 224 neighbor_vertices[pos].begin();
Chris@16 225 i != neighbor_vertices[pos].end();
Chris@16 226 ++i)
Chris@16 227 request(position, *i);
Chris@16 228 synchronize(position);
Chris@16 229
Chris@16 230 // Apply forces in adjacent bins. This is O(n^2) in the worst
Chris@16 231 // case. Oh well.
Chris@16 232 for (pos = left; pos < end_position; pos = bucket_position(pos + 1)) {
Chris@16 233 for (typename std::vector<vertex_descriptor>::iterator i =
Chris@16 234 my_vertices[pos].begin();
Chris@16 235 i != my_vertices[pos].end();
Chris@16 236 ++i)
Chris@16 237 for (typename std::vector<vertex_descriptor>::iterator j =
Chris@16 238 neighbor_vertices[pos].begin();
Chris@16 239 j != neighbor_vertices[pos].end();
Chris@16 240 ++j)
Chris@16 241 apply_force(*i, *j);
Chris@16 242 }
Chris@16 243 }
Chris@16 244
Chris@16 245 protected:
Chris@16 246 PositionMap position;
Chris@16 247 Point origin;
Chris@16 248 Point extent;
Chris@16 249 simple_tiling tiling;
Chris@16 250 };
Chris@16 251
Chris@16 252 template<typename PositionMap>
Chris@16 253 inline neighboring_tiles_force_pairs<PositionMap>
Chris@16 254 make_neighboring_tiles_force_pairs
Chris@16 255 (PositionMap position,
Chris@16 256 typename property_traits<PositionMap>::value_type origin,
Chris@16 257 typename property_traits<PositionMap>::value_type extent,
Chris@16 258 simple_tiling tiling)
Chris@16 259 {
Chris@16 260 return neighboring_tiles_force_pairs<PositionMap>(position, origin, extent,
Chris@16 261 tiling);
Chris@16 262 }
Chris@16 263
Chris@16 264 template<typename DisplacementMap, typename Cooling>
Chris@16 265 class distributed_cooling_proxy
Chris@16 266 {
Chris@16 267 public:
Chris@16 268 typedef typename Cooling::result_type result_type;
Chris@16 269
Chris@16 270 distributed_cooling_proxy(const DisplacementMap& displacement,
Chris@16 271 const Cooling& cooling)
Chris@16 272 : displacement(displacement), cooling(cooling)
Chris@16 273 {
Chris@16 274 }
Chris@16 275
Chris@16 276 result_type operator()()
Chris@16 277 {
Chris@16 278 // Accumulate displacements computed on each processor
Chris@16 279 synchronize(displacement.data->process_group);
Chris@16 280
Chris@16 281 // Allow the underlying cooling to occur
Chris@16 282 return cooling();
Chris@16 283 }
Chris@16 284
Chris@16 285 protected:
Chris@16 286 DisplacementMap displacement;
Chris@16 287 Cooling cooling;
Chris@16 288 };
Chris@16 289
Chris@16 290 template<typename DisplacementMap, typename Cooling>
Chris@16 291 inline distributed_cooling_proxy<DisplacementMap, Cooling>
Chris@16 292 make_distributed_cooling(const DisplacementMap& displacement,
Chris@16 293 const Cooling& cooling)
Chris@16 294 {
Chris@16 295 typedef distributed_cooling_proxy<DisplacementMap, Cooling> result_type;
Chris@16 296 return result_type(displacement, cooling);
Chris@16 297 }
Chris@16 298
Chris@16 299 template<typename Point>
Chris@16 300 struct point_accumulating_reducer {
Chris@16 301 BOOST_STATIC_CONSTANT(bool, non_default_resolver = true);
Chris@16 302
Chris@16 303 template<typename K>
Chris@16 304 Point operator()(const K&) const { return Point(); }
Chris@16 305
Chris@16 306 template<typename K>
Chris@16 307 Point operator()(const K&, const Point& p1, const Point& p2) const
Chris@16 308 { return Point(p1[0] + p2[0], p1[1] + p2[1]); }
Chris@16 309 };
Chris@16 310
Chris@16 311 template<typename Graph, typename PositionMap,
Chris@16 312 typename AttractiveForce, typename RepulsiveForce,
Chris@16 313 typename ForcePairs, typename Cooling, typename DisplacementMap>
Chris@16 314 void
Chris@16 315 fruchterman_reingold_force_directed_layout
Chris@16 316 (const Graph& g,
Chris@16 317 PositionMap position,
Chris@16 318 typename property_traits<PositionMap>::value_type const& origin,
Chris@16 319 typename property_traits<PositionMap>::value_type const& extent,
Chris@16 320 AttractiveForce attractive_force,
Chris@16 321 RepulsiveForce repulsive_force,
Chris@16 322 ForcePairs force_pairs,
Chris@16 323 Cooling cool,
Chris@16 324 DisplacementMap displacement)
Chris@16 325 {
Chris@16 326 typedef typename property_traits<PositionMap>::value_type Point;
Chris@16 327
Chris@16 328 // Reduction in the displacement map involves summing the forces
Chris@16 329 displacement.set_reduce(point_accumulating_reducer<Point>());
Chris@16 330
Chris@16 331 // We need to track the positions of all of our neighbors
Chris@16 332 BGL_FORALL_VERTICES_T(u, g, Graph)
Chris@16 333 BGL_FORALL_ADJ_T(u, v, g, Graph)
Chris@16 334 request(position, v);
Chris@16 335
Chris@16 336 // Invoke the "sequential" Fruchterman-Reingold implementation
Chris@16 337 boost::fruchterman_reingold_force_directed_layout
Chris@16 338 (g, position, origin, extent,
Chris@16 339 attractive_force, repulsive_force,
Chris@16 340 make_distributed_force_pairs(position, displacement, force_pairs),
Chris@16 341 make_distributed_cooling(displacement, cool),
Chris@16 342 displacement);
Chris@16 343 }
Chris@16 344
Chris@16 345 template<typename Graph, typename PositionMap,
Chris@16 346 typename AttractiveForce, typename RepulsiveForce,
Chris@16 347 typename ForcePairs, typename Cooling, typename DisplacementMap>
Chris@16 348 void
Chris@16 349 fruchterman_reingold_force_directed_layout
Chris@16 350 (const Graph& g,
Chris@16 351 PositionMap position,
Chris@16 352 typename property_traits<PositionMap>::value_type const& origin,
Chris@16 353 typename property_traits<PositionMap>::value_type const& extent,
Chris@16 354 AttractiveForce attractive_force,
Chris@16 355 RepulsiveForce repulsive_force,
Chris@16 356 ForcePairs force_pairs,
Chris@16 357 Cooling cool,
Chris@16 358 DisplacementMap displacement,
Chris@16 359 simple_tiling tiling)
Chris@16 360 {
Chris@16 361 typedef typename property_traits<PositionMap>::value_type Point;
Chris@16 362
Chris@16 363 // Reduction in the displacement map involves summing the forces
Chris@16 364 displacement.set_reduce(point_accumulating_reducer<Point>());
Chris@16 365
Chris@16 366 // We need to track the positions of all of our neighbors
Chris@16 367 BGL_FORALL_VERTICES_T(u, g, Graph)
Chris@16 368 BGL_FORALL_ADJ_T(u, v, g, Graph)
Chris@16 369 request(position, v);
Chris@16 370
Chris@16 371 // Invoke the "sequential" Fruchterman-Reingold implementation
Chris@16 372 boost::fruchterman_reingold_force_directed_layout
Chris@16 373 (g, position, origin, extent,
Chris@16 374 attractive_force, repulsive_force,
Chris@16 375 make_distributed_force_pairs
Chris@16 376 (position, displacement, force_pairs,
Chris@16 377 make_neighboring_tiles_force_pairs(position, origin, extent, tiling)),
Chris@16 378 make_distributed_cooling(displacement, cool),
Chris@16 379 displacement);
Chris@16 380 }
Chris@16 381
Chris@16 382 } } } // end namespace boost::graph::distributed
Chris@16 383
Chris@16 384 #endif // BOOST_GRAPH_DISTRIBUTED_FRUCHTERMAN_REINGOLD_HPP