annotate DEPENDENCIES/generic/include/boost/graph/fruchterman_reingold.hpp @ 125:34e428693f5d vext

Vext -> Repoint
author Chris Cannam
date Thu, 14 Jun 2018 11:15:39 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 // Copyright 2004, 2005 The Trustees of Indiana University.
Chris@16 2
Chris@16 3 // Distributed under the Boost Software License, Version 1.0.
Chris@16 4 // (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_FRUCHTERMAN_REINGOLD_FORCE_DIRECTED_LAYOUT_HPP
Chris@16 10 #define BOOST_GRAPH_FRUCHTERMAN_REINGOLD_FORCE_DIRECTED_LAYOUT_HPP
Chris@16 11
Chris@16 12 #include <boost/config/no_tr1/cmath.hpp>
Chris@16 13 #include <boost/graph/graph_traits.hpp>
Chris@16 14 #include <boost/graph/named_function_params.hpp>
Chris@16 15 #include <boost/graph/iteration_macros.hpp>
Chris@16 16 #include <boost/graph/topology.hpp> // For topology concepts
Chris@16 17 #include <vector>
Chris@16 18 #include <list>
Chris@16 19 #include <algorithm> // for std::min and std::max
Chris@16 20 #include <numeric> // for std::accumulate
Chris@16 21 #include <cmath> // for std::sqrt and std::fabs
Chris@16 22 #include <functional>
Chris@16 23
Chris@16 24 namespace boost {
Chris@16 25
Chris@16 26 struct square_distance_attractive_force {
Chris@16 27 template<typename Graph, typename T>
Chris@16 28 T
Chris@16 29 operator()(typename graph_traits<Graph>::edge_descriptor,
Chris@16 30 T k,
Chris@16 31 T d,
Chris@16 32 const Graph&) const
Chris@16 33 {
Chris@16 34 return d * d / k;
Chris@16 35 }
Chris@16 36 };
Chris@16 37
Chris@16 38 struct square_distance_repulsive_force {
Chris@16 39 template<typename Graph, typename T>
Chris@16 40 T
Chris@16 41 operator()(typename graph_traits<Graph>::vertex_descriptor,
Chris@16 42 typename graph_traits<Graph>::vertex_descriptor,
Chris@16 43 T k,
Chris@16 44 T d,
Chris@16 45 const Graph&) const
Chris@16 46 {
Chris@16 47 return k * k / d;
Chris@16 48 }
Chris@16 49 };
Chris@16 50
Chris@16 51 template<typename T>
Chris@16 52 struct linear_cooling {
Chris@16 53 typedef T result_type;
Chris@16 54
Chris@16 55 linear_cooling(std::size_t iterations)
Chris@16 56 : temp(T(iterations) / T(10)), step(0.1) { }
Chris@16 57
Chris@16 58 linear_cooling(std::size_t iterations, T temp)
Chris@16 59 : temp(temp), step(temp / T(iterations)) { }
Chris@16 60
Chris@16 61 T operator()()
Chris@16 62 {
Chris@16 63 T old_temp = temp;
Chris@16 64 temp -= step;
Chris@16 65 if (temp < T(0)) temp = T(0);
Chris@16 66 return old_temp;
Chris@16 67 }
Chris@16 68
Chris@16 69 private:
Chris@16 70 T temp;
Chris@16 71 T step;
Chris@16 72 };
Chris@16 73
Chris@16 74 struct all_force_pairs
Chris@16 75 {
Chris@16 76 template<typename Graph, typename ApplyForce >
Chris@16 77 void operator()(const Graph& g, ApplyForce apply_force)
Chris@16 78 {
Chris@16 79 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
Chris@16 80 vertex_iterator v, end;
Chris@16 81 for (boost::tie(v, end) = vertices(g); v != end; ++v) {
Chris@16 82 vertex_iterator u = v;
Chris@16 83 for (++u; u != end; ++u) {
Chris@16 84 apply_force(*u, *v);
Chris@16 85 apply_force(*v, *u);
Chris@16 86 }
Chris@16 87 }
Chris@16 88 }
Chris@16 89 };
Chris@16 90
Chris@16 91 template<typename Topology, typename PositionMap>
Chris@16 92 struct grid_force_pairs
Chris@16 93 {
Chris@16 94 typedef typename property_traits<PositionMap>::value_type Point;
Chris@16 95 BOOST_STATIC_ASSERT (Point::dimensions == 2);
Chris@16 96 typedef typename Topology::point_difference_type point_difference_type;
Chris@16 97
Chris@16 98 template<typename Graph>
Chris@16 99 explicit
Chris@16 100 grid_force_pairs(const Topology& topology,
Chris@16 101 PositionMap position, const Graph& g)
Chris@16 102 : topology(topology), position(position)
Chris@16 103 {
Chris@16 104 two_k = 2. * this->topology.volume(this->topology.extent()) / std::sqrt((double)num_vertices(g));
Chris@16 105 }
Chris@16 106
Chris@16 107 template<typename Graph, typename ApplyForce >
Chris@16 108 void operator()(const Graph& g, ApplyForce apply_force)
Chris@16 109 {
Chris@16 110 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
Chris@16 111 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
Chris@16 112 typedef std::list<vertex_descriptor> bucket_t;
Chris@16 113 typedef std::vector<bucket_t> buckets_t;
Chris@16 114
Chris@16 115 std::size_t columns = std::size_t(topology.extent()[0] / two_k + 1.);
Chris@16 116 std::size_t rows = std::size_t(topology.extent()[1] / two_k + 1.);
Chris@16 117 buckets_t buckets(rows * columns);
Chris@16 118 vertex_iterator v, v_end;
Chris@16 119 for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) {
Chris@16 120 std::size_t column =
Chris@16 121 std::size_t((get(position, *v)[0] + topology.extent()[0] / 2) / two_k);
Chris@16 122 std::size_t row =
Chris@16 123 std::size_t((get(position, *v)[1] + topology.extent()[1] / 2) / two_k);
Chris@16 124
Chris@16 125 if (column >= columns) column = columns - 1;
Chris@16 126 if (row >= rows) row = rows - 1;
Chris@16 127 buckets[row * columns + column].push_back(*v);
Chris@16 128 }
Chris@16 129
Chris@16 130 for (std::size_t row = 0; row < rows; ++row)
Chris@16 131 for (std::size_t column = 0; column < columns; ++column) {
Chris@16 132 bucket_t& bucket = buckets[row * columns + column];
Chris@16 133 typedef typename bucket_t::iterator bucket_iterator;
Chris@16 134 for (bucket_iterator u = bucket.begin(); u != bucket.end(); ++u) {
Chris@16 135 // Repulse vertices in this bucket
Chris@16 136 bucket_iterator v = u;
Chris@16 137 for (++v; v != bucket.end(); ++v) {
Chris@16 138 apply_force(*u, *v);
Chris@16 139 apply_force(*v, *u);
Chris@16 140 }
Chris@16 141
Chris@16 142 std::size_t adj_start_row = row == 0? 0 : row - 1;
Chris@16 143 std::size_t adj_end_row = row == rows - 1? row : row + 1;
Chris@16 144 std::size_t adj_start_column = column == 0? 0 : column - 1;
Chris@16 145 std::size_t adj_end_column = column == columns - 1? column : column + 1;
Chris@16 146 for (std::size_t other_row = adj_start_row; other_row <= adj_end_row;
Chris@16 147 ++other_row)
Chris@16 148 for (std::size_t other_column = adj_start_column;
Chris@16 149 other_column <= adj_end_column; ++other_column)
Chris@16 150 if (other_row != row || other_column != column) {
Chris@16 151 // Repulse vertices in this bucket
Chris@16 152 bucket_t& other_bucket
Chris@16 153 = buckets[other_row * columns + other_column];
Chris@16 154 for (v = other_bucket.begin(); v != other_bucket.end(); ++v) {
Chris@16 155 double dist =
Chris@16 156 topology.distance(get(position, *u), get(position, *v));
Chris@16 157 if (dist < two_k) apply_force(*u, *v);
Chris@16 158 }
Chris@16 159 }
Chris@16 160 }
Chris@16 161 }
Chris@16 162 }
Chris@16 163
Chris@16 164 private:
Chris@16 165 const Topology& topology;
Chris@16 166 PositionMap position;
Chris@16 167 double two_k;
Chris@16 168 };
Chris@16 169
Chris@16 170 template<typename PositionMap, typename Topology, typename Graph>
Chris@16 171 inline grid_force_pairs<Topology, PositionMap>
Chris@16 172 make_grid_force_pairs
Chris@16 173 (const Topology& topology,
Chris@16 174 const PositionMap& position, const Graph& g)
Chris@16 175 { return grid_force_pairs<Topology, PositionMap>(topology, position, g); }
Chris@16 176
Chris@16 177 template<typename Graph, typename PositionMap, typename Topology>
Chris@16 178 void
Chris@16 179 scale_graph(const Graph& g, PositionMap position, const Topology& topology,
Chris@16 180 typename Topology::point_type upper_left, typename Topology::point_type lower_right)
Chris@16 181 {
Chris@16 182 if (num_vertices(g) == 0) return;
Chris@16 183
Chris@16 184 typedef typename Topology::point_type Point;
Chris@16 185 typedef typename Topology::point_difference_type point_difference_type;
Chris@16 186
Chris@16 187 // Find min/max ranges
Chris@16 188 Point min_point = get(position, *vertices(g).first), max_point = min_point;
Chris@16 189 BGL_FORALL_VERTICES_T(v, g, Graph) {
Chris@16 190 min_point = topology.pointwise_min(min_point, get(position, v));
Chris@16 191 max_point = topology.pointwise_max(max_point, get(position, v));
Chris@16 192 }
Chris@16 193
Chris@16 194 Point old_origin = topology.move_position_toward(min_point, 0.5, max_point);
Chris@16 195 Point new_origin = topology.move_position_toward(upper_left, 0.5, lower_right);
Chris@16 196 point_difference_type old_size = topology.difference(max_point, min_point);
Chris@16 197 point_difference_type new_size = topology.difference(lower_right, upper_left);
Chris@16 198
Chris@16 199 // Scale to bounding box provided
Chris@16 200 BGL_FORALL_VERTICES_T(v, g, Graph) {
Chris@16 201 point_difference_type relative_loc = topology.difference(get(position, v), old_origin);
Chris@16 202 relative_loc = (relative_loc / old_size) * new_size;
Chris@16 203 put(position, v, topology.adjust(new_origin, relative_loc));
Chris@16 204 }
Chris@16 205 }
Chris@16 206
Chris@16 207 namespace detail {
Chris@16 208 template<typename Topology, typename PropMap, typename Vertex>
Chris@16 209 void
Chris@16 210 maybe_jitter_point(const Topology& topology,
Chris@16 211 const PropMap& pm, Vertex v,
Chris@16 212 const typename Topology::point_type& p2)
Chris@16 213 {
Chris@16 214 double too_close = topology.norm(topology.extent()) / 10000.;
Chris@16 215 if (topology.distance(get(pm, v), p2) < too_close) {
Chris@16 216 put(pm, v,
Chris@16 217 topology.move_position_toward(get(pm, v), 1./200,
Chris@16 218 topology.random_point()));
Chris@16 219 }
Chris@16 220 }
Chris@16 221
Chris@16 222 template<typename Topology, typename PositionMap, typename DisplacementMap,
Chris@16 223 typename RepulsiveForce, typename Graph>
Chris@16 224 struct fr_apply_force
Chris@16 225 {
Chris@16 226 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
Chris@16 227 typedef typename Topology::point_type Point;
Chris@16 228 typedef typename Topology::point_difference_type PointDiff;
Chris@16 229
Chris@16 230 fr_apply_force(const Topology& topology,
Chris@16 231 const PositionMap& position,
Chris@16 232 const DisplacementMap& displacement,
Chris@16 233 RepulsiveForce repulsive_force, double k, const Graph& g)
Chris@16 234 : topology(topology), position(position), displacement(displacement),
Chris@16 235 repulsive_force(repulsive_force), k(k), g(g)
Chris@16 236 { }
Chris@16 237
Chris@16 238 void operator()(vertex_descriptor u, vertex_descriptor v)
Chris@16 239 {
Chris@16 240 if (u != v) {
Chris@16 241 // When the vertices land on top of each other, move the
Chris@16 242 // first vertex away from the boundaries.
Chris@16 243 maybe_jitter_point(topology, position, u, get(position, v));
Chris@16 244
Chris@16 245 double dist = topology.distance(get(position, u), get(position, v));
Chris@16 246 typename Topology::point_difference_type dispv = get(displacement, v);
Chris@16 247 if (dist == 0.) {
Chris@16 248 for (std::size_t i = 0; i < Point::dimensions; ++i) {
Chris@16 249 dispv[i] += 0.01;
Chris@16 250 }
Chris@16 251 } else {
Chris@16 252 double fr = repulsive_force(u, v, k, dist, g);
Chris@16 253 dispv += (fr / dist) *
Chris@16 254 topology.difference(get(position, v), get(position, u));
Chris@16 255 }
Chris@16 256 put(displacement, v, dispv);
Chris@16 257 }
Chris@16 258 }
Chris@16 259
Chris@16 260 private:
Chris@16 261 const Topology& topology;
Chris@16 262 PositionMap position;
Chris@16 263 DisplacementMap displacement;
Chris@16 264 RepulsiveForce repulsive_force;
Chris@16 265 double k;
Chris@16 266 const Graph& g;
Chris@16 267 };
Chris@16 268
Chris@16 269 } // end namespace detail
Chris@16 270
Chris@16 271 template<typename Topology, typename Graph, typename PositionMap,
Chris@16 272 typename AttractiveForce, typename RepulsiveForce,
Chris@16 273 typename ForcePairs, typename Cooling, typename DisplacementMap>
Chris@16 274 void
Chris@16 275 fruchterman_reingold_force_directed_layout
Chris@16 276 (const Graph& g,
Chris@16 277 PositionMap position,
Chris@16 278 const Topology& topology,
Chris@16 279 AttractiveForce attractive_force,
Chris@16 280 RepulsiveForce repulsive_force,
Chris@16 281 ForcePairs force_pairs,
Chris@16 282 Cooling cool,
Chris@16 283 DisplacementMap displacement)
Chris@16 284 {
Chris@16 285 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
Chris@16 286 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
Chris@16 287 typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
Chris@16 288
Chris@16 289 double volume = topology.volume(topology.extent());
Chris@16 290
Chris@16 291 // assume positions are initialized randomly
Chris@16 292 double k = pow(volume / num_vertices(g), 1. / (double)(Topology::point_difference_type::dimensions));
Chris@16 293
Chris@16 294 detail::fr_apply_force<Topology, PositionMap, DisplacementMap,
Chris@16 295 RepulsiveForce, Graph>
Chris@16 296 apply_force(topology, position, displacement, repulsive_force, k, g);
Chris@16 297
Chris@16 298 do {
Chris@16 299 // Calculate repulsive forces
Chris@16 300 vertex_iterator v, v_end;
Chris@16 301 for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v)
Chris@16 302 put(displacement, *v, typename Topology::point_difference_type());
Chris@16 303 force_pairs(g, apply_force);
Chris@16 304
Chris@16 305 // Calculate attractive forces
Chris@16 306 edge_iterator e, e_end;
Chris@16 307 for (boost::tie(e, e_end) = edges(g); e != e_end; ++e) {
Chris@16 308 vertex_descriptor v = source(*e, g);
Chris@16 309 vertex_descriptor u = target(*e, g);
Chris@16 310
Chris@16 311 // When the vertices land on top of each other, move the
Chris@16 312 // first vertex away from the boundaries.
Chris@16 313 ::boost::detail::maybe_jitter_point(topology, position, u, get(position, v));
Chris@16 314
Chris@16 315 typename Topology::point_difference_type delta =
Chris@16 316 topology.difference(get(position, v), get(position, u));
Chris@16 317 double dist = topology.distance(get(position, u), get(position, v));
Chris@16 318 double fa = attractive_force(*e, k, dist, g);
Chris@16 319
Chris@16 320 put(displacement, v, get(displacement, v) - (fa / dist) * delta);
Chris@16 321 put(displacement, u, get(displacement, u) + (fa / dist) * delta);
Chris@16 322 }
Chris@16 323
Chris@16 324 if (double temp = cool()) {
Chris@16 325 // Update positions
Chris@16 326 BGL_FORALL_VERTICES_T (v, g, Graph) {
Chris@16 327 BOOST_USING_STD_MIN();
Chris@16 328 BOOST_USING_STD_MAX();
Chris@16 329 double disp_size = topology.norm(get(displacement, v));
Chris@16 330 put(position, v, topology.adjust(get(position, v), get(displacement, v) * (min BOOST_PREVENT_MACRO_SUBSTITUTION (disp_size, temp) / disp_size)));
Chris@16 331 put(position, v, topology.bound(get(position, v)));
Chris@16 332 }
Chris@16 333 } else {
Chris@16 334 break;
Chris@16 335 }
Chris@16 336 } while (true);
Chris@16 337 }
Chris@16 338
Chris@16 339 namespace detail {
Chris@16 340 template<typename DisplacementMap>
Chris@16 341 struct fr_force_directed_layout
Chris@16 342 {
Chris@16 343 template<typename Topology, typename Graph, typename PositionMap,
Chris@16 344 typename AttractiveForce, typename RepulsiveForce,
Chris@16 345 typename ForcePairs, typename Cooling,
Chris@16 346 typename Param, typename Tag, typename Rest>
Chris@16 347 static void
Chris@16 348 run(const Graph& g,
Chris@16 349 PositionMap position,
Chris@16 350 const Topology& topology,
Chris@16 351 AttractiveForce attractive_force,
Chris@16 352 RepulsiveForce repulsive_force,
Chris@16 353 ForcePairs force_pairs,
Chris@16 354 Cooling cool,
Chris@16 355 DisplacementMap displacement,
Chris@16 356 const bgl_named_params<Param, Tag, Rest>&)
Chris@16 357 {
Chris@16 358 fruchterman_reingold_force_directed_layout
Chris@16 359 (g, position, topology, attractive_force, repulsive_force,
Chris@16 360 force_pairs, cool, displacement);
Chris@16 361 }
Chris@16 362 };
Chris@16 363
Chris@16 364 template<>
Chris@16 365 struct fr_force_directed_layout<param_not_found>
Chris@16 366 {
Chris@16 367 template<typename Topology, typename Graph, typename PositionMap,
Chris@16 368 typename AttractiveForce, typename RepulsiveForce,
Chris@16 369 typename ForcePairs, typename Cooling,
Chris@16 370 typename Param, typename Tag, typename Rest>
Chris@16 371 static void
Chris@16 372 run(const Graph& g,
Chris@16 373 PositionMap position,
Chris@16 374 const Topology& topology,
Chris@16 375 AttractiveForce attractive_force,
Chris@16 376 RepulsiveForce repulsive_force,
Chris@16 377 ForcePairs force_pairs,
Chris@16 378 Cooling cool,
Chris@16 379 param_not_found,
Chris@16 380 const bgl_named_params<Param, Tag, Rest>& params)
Chris@16 381 {
Chris@16 382 typedef typename Topology::point_difference_type PointDiff;
Chris@16 383 std::vector<PointDiff> displacements(num_vertices(g));
Chris@16 384 fruchterman_reingold_force_directed_layout
Chris@16 385 (g, position, topology, attractive_force, repulsive_force,
Chris@16 386 force_pairs, cool,
Chris@16 387 make_iterator_property_map
Chris@16 388 (displacements.begin(),
Chris@16 389 choose_const_pmap(get_param(params, vertex_index), g,
Chris@16 390 vertex_index),
Chris@16 391 PointDiff()));
Chris@16 392 }
Chris@16 393 };
Chris@16 394
Chris@16 395 } // end namespace detail
Chris@16 396
Chris@16 397 template<typename Topology, typename Graph, typename PositionMap, typename Param,
Chris@16 398 typename Tag, typename Rest>
Chris@16 399 void
Chris@16 400 fruchterman_reingold_force_directed_layout
Chris@16 401 (const Graph& g,
Chris@16 402 PositionMap position,
Chris@16 403 const Topology& topology,
Chris@16 404 const bgl_named_params<Param, Tag, Rest>& params)
Chris@16 405 {
Chris@16 406 typedef typename get_param_type<vertex_displacement_t, bgl_named_params<Param,Tag,Rest> >::type D;
Chris@16 407
Chris@16 408 detail::fr_force_directed_layout<D>::run
Chris@16 409 (g, position, topology,
Chris@16 410 choose_param(get_param(params, attractive_force_t()),
Chris@16 411 square_distance_attractive_force()),
Chris@16 412 choose_param(get_param(params, repulsive_force_t()),
Chris@16 413 square_distance_repulsive_force()),
Chris@16 414 choose_param(get_param(params, force_pairs_t()),
Chris@16 415 make_grid_force_pairs(topology, position, g)),
Chris@16 416 choose_param(get_param(params, cooling_t()),
Chris@16 417 linear_cooling<double>(100)),
Chris@16 418 get_param(params, vertex_displacement_t()),
Chris@16 419 params);
Chris@16 420 }
Chris@16 421
Chris@16 422 template<typename Topology, typename Graph, typename PositionMap>
Chris@16 423 void
Chris@16 424 fruchterman_reingold_force_directed_layout
Chris@16 425 (const Graph& g,
Chris@16 426 PositionMap position,
Chris@16 427 const Topology& topology)
Chris@16 428 {
Chris@16 429 fruchterman_reingold_force_directed_layout
Chris@16 430 (g, position, topology,
Chris@16 431 attractive_force(square_distance_attractive_force()));
Chris@16 432 }
Chris@16 433
Chris@16 434 } // end namespace boost
Chris@16 435
Chris@16 436 #ifdef BOOST_GRAPH_USE_MPI
Chris@16 437 # include <boost/graph/distributed/fruchterman_reingold.hpp>
Chris@16 438 #endif
Chris@16 439
Chris@16 440 #endif // BOOST_GRAPH_FRUCHTERMAN_REINGOLD_FORCE_DIRECTED_LAYOUT_HPP