annotate DEPENDENCIES/generic/include/boost/graph/kamada_kawai_spring_layout.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 2004 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_KAMADA_KAWAI_SPRING_LAYOUT_HPP
Chris@16 10 #define BOOST_GRAPH_KAMADA_KAWAI_SPRING_LAYOUT_HPP
Chris@16 11
Chris@16 12 #include <boost/graph/graph_traits.hpp>
Chris@16 13 #include <boost/graph/topology.hpp>
Chris@16 14 #include <boost/graph/iteration_macros.hpp>
Chris@16 15 #include <boost/graph/johnson_all_pairs_shortest.hpp>
Chris@16 16 #include <boost/type_traits/is_convertible.hpp>
Chris@16 17 #include <utility>
Chris@16 18 #include <iterator>
Chris@16 19 #include <vector>
Chris@16 20 #include <iostream>
Chris@16 21 #include <boost/limits.hpp>
Chris@16 22 #include <boost/config/no_tr1/cmath.hpp>
Chris@16 23
Chris@16 24 namespace boost {
Chris@16 25 namespace detail { namespace graph {
Chris@16 26 /**
Chris@16 27 * Denotes an edge or display area side length used to scale a
Chris@16 28 * Kamada-Kawai drawing.
Chris@16 29 */
Chris@16 30 template<bool Edge, typename T>
Chris@16 31 struct edge_or_side
Chris@16 32 {
Chris@16 33 explicit edge_or_side(T value) : value(value) {}
Chris@16 34
Chris@16 35 T value;
Chris@16 36 };
Chris@16 37
Chris@16 38 /**
Chris@16 39 * Compute the edge length from an edge length. This is trivial.
Chris@16 40 */
Chris@16 41 template<typename Graph, typename DistanceMap, typename IndexMap,
Chris@16 42 typename T>
Chris@16 43 T compute_edge_length(const Graph&, DistanceMap, IndexMap,
Chris@16 44 edge_or_side<true, T> length)
Chris@16 45 { return length.value; }
Chris@16 46
Chris@16 47 /**
Chris@16 48 * Compute the edge length based on the display area side
Chris@16 49 length. We do this by dividing the side length by the largest
Chris@16 50 shortest distance between any two vertices in the graph.
Chris@16 51 */
Chris@16 52 template<typename Graph, typename DistanceMap, typename IndexMap,
Chris@16 53 typename T>
Chris@16 54 T
Chris@16 55 compute_edge_length(const Graph& g, DistanceMap distance, IndexMap index,
Chris@16 56 edge_or_side<false, T> length)
Chris@16 57 {
Chris@16 58 T result(0);
Chris@16 59
Chris@16 60 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
Chris@16 61
Chris@16 62 for (vertex_iterator ui = vertices(g).first, end = vertices(g).second;
Chris@16 63 ui != end; ++ui) {
Chris@16 64 vertex_iterator vi = ui;
Chris@16 65 for (++vi; vi != end; ++vi) {
Chris@16 66 T dij = distance[get(index, *ui)][get(index, *vi)];
Chris@16 67 if (dij > result) result = dij;
Chris@16 68 }
Chris@16 69 }
Chris@16 70 return length.value / result;
Chris@16 71 }
Chris@16 72
Chris@16 73 /**
Chris@16 74 * Dense linear solver for fixed-size matrices.
Chris@16 75 */
Chris@16 76 template <std::size_t Size>
Chris@16 77 struct linear_solver {
Chris@16 78 // Indices in mat are (row, column)
Chris@16 79 // template <typename Vec>
Chris@16 80 // static Vec solve(double mat[Size][Size], Vec rhs);
Chris@16 81 };
Chris@16 82
Chris@16 83 template <>
Chris@16 84 struct linear_solver<1> {
Chris@16 85 template <typename Vec>
Chris@16 86 static Vec solve(double mat[1][1], Vec rhs) {
Chris@16 87 return rhs / mat[0][0];
Chris@16 88 }
Chris@16 89 };
Chris@16 90
Chris@16 91 // These are from http://en.wikipedia.org/wiki/Cramer%27s_rule
Chris@16 92 template <>
Chris@16 93 struct linear_solver<2> {
Chris@16 94 template <typename Vec>
Chris@16 95 static Vec solve(double mat[2][2], Vec rhs) {
Chris@16 96 double denom = mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
Chris@16 97 double x_num = rhs[0] * mat[1][1] - rhs[1] * mat[0][1];
Chris@16 98 double y_num = mat[0][0] * rhs[1] - mat[1][0] * rhs[0] ;
Chris@16 99 Vec result;
Chris@16 100 result[0] = x_num / denom;
Chris@16 101 result[1] = y_num / denom;
Chris@16 102 return result;
Chris@16 103 }
Chris@16 104 };
Chris@16 105
Chris@16 106 template <>
Chris@16 107 struct linear_solver<3> {
Chris@16 108 template <typename Vec>
Chris@16 109 static Vec solve(double mat[2][2], Vec rhs) {
Chris@16 110 double denom = mat[0][0] * (mat[1][1] * mat[2][2] - mat[2][1] * mat[1][2])
Chris@16 111 - mat[1][0] * (mat[0][1] * mat[2][2] - mat[2][1] * mat[0][2])
Chris@16 112 + mat[2][0] * (mat[0][1] * mat[1][2] - mat[1][1] * mat[0][2]);
Chris@16 113 double x_num = rhs[0] * (mat[1][1] * mat[2][2] - mat[2][1] * mat[1][2])
Chris@16 114 - rhs[1] * (mat[0][1] * mat[2][2] - mat[2][1] * mat[0][2])
Chris@16 115 + rhs[2] * (mat[0][1] * mat[1][2] - mat[1][1] * mat[0][2]);
Chris@16 116 double y_num = mat[0][0] * (rhs[1] * mat[2][2] - rhs[2] * mat[1][2])
Chris@16 117 - mat[1][0] * (rhs[0] * mat[2][2] - rhs[2] * mat[0][2])
Chris@16 118 + mat[2][0] * (rhs[0] * mat[1][2] - rhs[1] * mat[0][2]);
Chris@16 119 double z_num = mat[0][0] * (mat[1][1] * rhs[2] - mat[2][1] * rhs[1] )
Chris@16 120 - mat[1][0] * (mat[0][1] * rhs[2] - mat[2][1] * rhs[0] )
Chris@16 121 + mat[2][0] * (mat[0][1] * rhs[1] - mat[1][1] * rhs[0] );
Chris@16 122 Vec result;
Chris@16 123 result[0] = x_num / denom;
Chris@16 124 result[1] = y_num / denom;
Chris@16 125 result[2] = z_num / denom;
Chris@16 126 return result;
Chris@16 127 }
Chris@16 128 };
Chris@16 129
Chris@16 130 /**
Chris@16 131 * Implementation of the Kamada-Kawai spring layout algorithm.
Chris@16 132 */
Chris@16 133 template<typename Topology, typename Graph, typename PositionMap, typename WeightMap,
Chris@16 134 typename EdgeOrSideLength, typename Done,
Chris@16 135 typename VertexIndexMap, typename DistanceMatrix,
Chris@16 136 typename SpringStrengthMatrix, typename PartialDerivativeMap>
Chris@16 137 struct kamada_kawai_spring_layout_impl
Chris@16 138 {
Chris@16 139 typedef typename property_traits<WeightMap>::value_type weight_type;
Chris@16 140 typedef typename Topology::point_type Point;
Chris@16 141 typedef typename Topology::point_difference_type point_difference_type;
Chris@16 142 typedef point_difference_type deriv_type;
Chris@16 143 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
Chris@16 144 typedef typename graph_traits<Graph>::vertex_descriptor
Chris@16 145 vertex_descriptor;
Chris@16 146
Chris@16 147 kamada_kawai_spring_layout_impl(
Chris@16 148 const Topology& topology,
Chris@16 149 const Graph& g,
Chris@16 150 PositionMap position,
Chris@16 151 WeightMap weight,
Chris@16 152 EdgeOrSideLength edge_or_side_length,
Chris@16 153 Done done,
Chris@16 154 weight_type spring_constant,
Chris@16 155 VertexIndexMap index,
Chris@16 156 DistanceMatrix distance,
Chris@16 157 SpringStrengthMatrix spring_strength,
Chris@16 158 PartialDerivativeMap partial_derivatives)
Chris@16 159 : topology(topology), g(g), position(position), weight(weight),
Chris@16 160 edge_or_side_length(edge_or_side_length), done(done),
Chris@16 161 spring_constant(spring_constant), index(index), distance(distance),
Chris@16 162 spring_strength(spring_strength),
Chris@16 163 partial_derivatives(partial_derivatives) {}
Chris@16 164
Chris@16 165 // Compute contribution of vertex i to the first partial
Chris@16 166 // derivatives (dE/dx_m, dE/dy_m) (for vertex m)
Chris@16 167 deriv_type
Chris@16 168 compute_partial_derivative(vertex_descriptor m, vertex_descriptor i)
Chris@16 169 {
Chris@16 170 #ifndef BOOST_NO_STDC_NAMESPACE
Chris@16 171 using std::sqrt;
Chris@16 172 #endif // BOOST_NO_STDC_NAMESPACE
Chris@16 173
Chris@16 174 deriv_type result;
Chris@16 175 if (i != m) {
Chris@16 176 point_difference_type diff = topology.difference(position[m], position[i]);
Chris@16 177 weight_type dist = topology.norm(diff);
Chris@16 178 result = spring_strength[get(index, m)][get(index, i)]
Chris@16 179 * (diff - distance[get(index, m)][get(index, i)]/dist*diff);
Chris@16 180 }
Chris@16 181
Chris@16 182 return result;
Chris@16 183 }
Chris@16 184
Chris@16 185 // Compute partial derivatives dE/dx_m and dE/dy_m
Chris@16 186 deriv_type
Chris@16 187 compute_partial_derivatives(vertex_descriptor m)
Chris@16 188 {
Chris@16 189 #ifndef BOOST_NO_STDC_NAMESPACE
Chris@16 190 using std::sqrt;
Chris@16 191 #endif // BOOST_NO_STDC_NAMESPACE
Chris@16 192
Chris@16 193 deriv_type result;
Chris@16 194
Chris@16 195 // TBD: looks like an accumulate to me
Chris@16 196 BGL_FORALL_VERTICES_T(i, g, Graph) {
Chris@16 197 deriv_type deriv = compute_partial_derivative(m, i);
Chris@16 198 result += deriv;
Chris@16 199 }
Chris@16 200
Chris@16 201 return result;
Chris@16 202 }
Chris@16 203
Chris@16 204 // The actual Kamada-Kawai spring layout algorithm implementation
Chris@16 205 bool run()
Chris@16 206 {
Chris@16 207 #ifndef BOOST_NO_STDC_NAMESPACE
Chris@16 208 using std::sqrt;
Chris@16 209 #endif // BOOST_NO_STDC_NAMESPACE
Chris@16 210
Chris@16 211 // Compute d_{ij} and place it in the distance matrix
Chris@16 212 if (!johnson_all_pairs_shortest_paths(g, distance, index, weight,
Chris@16 213 weight_type(0)))
Chris@16 214 return false;
Chris@16 215
Chris@16 216 // Compute L based on side length (if needed), or retrieve L
Chris@16 217 weight_type edge_length =
Chris@16 218 detail::graph::compute_edge_length(g, distance, index,
Chris@16 219 edge_or_side_length);
Chris@16 220
Chris@16 221 // std::cerr << "edge_length = " << edge_length << std::endl;
Chris@16 222
Chris@16 223 // Compute l_{ij} and k_{ij}
Chris@16 224 const weight_type K = spring_constant;
Chris@16 225 vertex_iterator ui, end;
Chris@16 226 for (ui = vertices(g).first, end = vertices(g).second; ui != end; ++ui) {
Chris@16 227 vertex_iterator vi = ui;
Chris@16 228 for (++vi; vi != end; ++vi) {
Chris@16 229 weight_type dij = distance[get(index, *ui)][get(index, *vi)];
Chris@16 230 if (dij == (std::numeric_limits<weight_type>::max)())
Chris@16 231 return false;
Chris@16 232 distance[get(index, *ui)][get(index, *vi)] = edge_length * dij;
Chris@16 233 distance[get(index, *vi)][get(index, *ui)] = edge_length * dij;
Chris@16 234 spring_strength[get(index, *ui)][get(index, *vi)] = K/(dij*dij);
Chris@16 235 spring_strength[get(index, *vi)][get(index, *ui)] = K/(dij*dij);
Chris@16 236 }
Chris@16 237 }
Chris@16 238
Chris@16 239 // Compute Delta_i and find max
Chris@16 240 vertex_descriptor p = *vertices(g).first;
Chris@16 241 weight_type delta_p(0);
Chris@16 242
Chris@16 243 for (ui = vertices(g).first, end = vertices(g).second; ui != end; ++ui) {
Chris@16 244 deriv_type deriv = compute_partial_derivatives(*ui);
Chris@16 245 put(partial_derivatives, *ui, deriv);
Chris@16 246
Chris@16 247 weight_type delta = topology.norm(deriv);
Chris@16 248
Chris@16 249 if (delta > delta_p) {
Chris@16 250 p = *ui;
Chris@16 251 delta_p = delta;
Chris@16 252 }
Chris@16 253 }
Chris@16 254
Chris@16 255 while (!done(delta_p, p, g, true)) {
Chris@16 256 // The contribution p makes to the partial derivatives of
Chris@16 257 // each vertex. Computing this (at O(n) cost) allows us to
Chris@16 258 // update the delta_i values in O(n) time instead of O(n^2)
Chris@16 259 // time.
Chris@16 260 std::vector<deriv_type> p_partials(num_vertices(g));
Chris@16 261 for (ui = vertices(g).first, end = vertices(g).second; ui != end; ++ui) {
Chris@16 262 vertex_descriptor i = *ui;
Chris@16 263 p_partials[get(index, i)] = compute_partial_derivative(i, p);
Chris@16 264 }
Chris@16 265
Chris@16 266 do {
Chris@16 267 // For debugging, compute the energy value E
Chris@16 268 double E = 0.;
Chris@16 269 for (ui = vertices(g).first, end = vertices(g).second; ui != end; ++ui) {
Chris@16 270 vertex_iterator vi = ui;
Chris@16 271 for (++vi; vi != end; ++vi) {
Chris@16 272 double dist = topology.distance(position[*ui], position[*vi]);
Chris@16 273 weight_type k_ij = spring_strength[get(index,*ui)][get(index,*vi)];
Chris@16 274 weight_type l_ij = distance[get(index, *ui)][get(index, *vi)];
Chris@16 275 E += .5 * k_ij * (dist - l_ij) * (dist - l_ij);
Chris@16 276 }
Chris@16 277 }
Chris@16 278 // std::cerr << "E = " << E << std::endl;
Chris@16 279
Chris@16 280 // Compute the elements of the Jacobian
Chris@16 281 // From
Chris@16 282 // http://www.cs.panam.edu/~rfowler/papers/1994_kumar_fowler_A_Spring_UTPACSTR.pdf
Chris@16 283 // with the bugs fixed in the off-diagonal case
Chris@16 284 weight_type dE_d_d[Point::dimensions][Point::dimensions];
Chris@16 285 for (std::size_t i = 0; i < Point::dimensions; ++i)
Chris@16 286 for (std::size_t j = 0; j < Point::dimensions; ++j)
Chris@16 287 dE_d_d[i][j] = 0.;
Chris@16 288 for (ui = vertices(g).first, end = vertices(g).second; ui != end; ++ui) {
Chris@16 289 vertex_descriptor i = *ui;
Chris@16 290 if (i != p) {
Chris@16 291 point_difference_type diff = topology.difference(position[p], position[i]);
Chris@16 292 weight_type dist = topology.norm(diff);
Chris@16 293 weight_type dist_squared = dist * dist;
Chris@16 294 weight_type inv_dist_cubed = 1. / (dist_squared * dist);
Chris@16 295 weight_type k_mi = spring_strength[get(index,p)][get(index,i)];
Chris@16 296 weight_type l_mi = distance[get(index, p)][get(index, i)];
Chris@16 297 for (std::size_t i = 0; i < Point::dimensions; ++i) {
Chris@16 298 for (std::size_t j = 0; j < Point::dimensions; ++j) {
Chris@16 299 if (i == j) {
Chris@16 300 dE_d_d[i][i] += k_mi * (1 + (l_mi * (diff[i] * diff[i] - dist_squared) * inv_dist_cubed));
Chris@16 301 } else {
Chris@16 302 dE_d_d[i][j] += k_mi * l_mi * diff[i] * diff[j] * inv_dist_cubed;
Chris@16 303 // dE_d_d[i][j] += k_mi * l_mi * sqrt(hypot(diff[i], diff[j])) * inv_dist_cubed;
Chris@16 304 }
Chris@16 305 }
Chris@16 306 }
Chris@16 307 }
Chris@16 308 }
Chris@16 309
Chris@16 310 deriv_type dE_d = get(partial_derivatives, p);
Chris@16 311
Chris@16 312 // Solve dE_d_d * delta = -dE_d to get delta
Chris@16 313 point_difference_type delta = -linear_solver<Point::dimensions>::solve(dE_d_d, dE_d);
Chris@16 314
Chris@16 315 // Move p by delta
Chris@16 316 position[p] = topology.adjust(position[p], delta);
Chris@16 317
Chris@16 318 // Recompute partial derivatives and delta_p
Chris@16 319 deriv_type deriv = compute_partial_derivatives(p);
Chris@16 320 put(partial_derivatives, p, deriv);
Chris@16 321
Chris@16 322 delta_p = topology.norm(deriv);
Chris@16 323 } while (!done(delta_p, p, g, false));
Chris@16 324
Chris@16 325 // Select new p by updating each partial derivative and delta
Chris@16 326 vertex_descriptor old_p = p;
Chris@16 327 for (ui = vertices(g).first, end = vertices(g).second; ui != end; ++ui) {
Chris@16 328 deriv_type old_deriv_p = p_partials[get(index, *ui)];
Chris@16 329 deriv_type old_p_partial =
Chris@16 330 compute_partial_derivative(*ui, old_p);
Chris@16 331 deriv_type deriv = get(partial_derivatives, *ui);
Chris@16 332
Chris@16 333 deriv += old_p_partial - old_deriv_p;
Chris@16 334
Chris@16 335 put(partial_derivatives, *ui, deriv);
Chris@16 336 weight_type delta = topology.norm(deriv);
Chris@16 337
Chris@16 338 if (delta > delta_p) {
Chris@16 339 p = *ui;
Chris@16 340 delta_p = delta;
Chris@16 341 }
Chris@16 342 }
Chris@16 343 }
Chris@16 344
Chris@16 345 return true;
Chris@16 346 }
Chris@16 347
Chris@16 348 const Topology& topology;
Chris@16 349 const Graph& g;
Chris@16 350 PositionMap position;
Chris@16 351 WeightMap weight;
Chris@16 352 EdgeOrSideLength edge_or_side_length;
Chris@16 353 Done done;
Chris@16 354 weight_type spring_constant;
Chris@16 355 VertexIndexMap index;
Chris@16 356 DistanceMatrix distance;
Chris@16 357 SpringStrengthMatrix spring_strength;
Chris@16 358 PartialDerivativeMap partial_derivatives;
Chris@16 359 };
Chris@16 360 } } // end namespace detail::graph
Chris@16 361
Chris@16 362 /// States that the given quantity is an edge length.
Chris@16 363 template<typename T>
Chris@16 364 inline detail::graph::edge_or_side<true, T>
Chris@16 365 edge_length(T x)
Chris@16 366 { return detail::graph::edge_or_side<true, T>(x); }
Chris@16 367
Chris@16 368 /// States that the given quantity is a display area side length.
Chris@16 369 template<typename T>
Chris@16 370 inline detail::graph::edge_or_side<false, T>
Chris@16 371 side_length(T x)
Chris@16 372 { return detail::graph::edge_or_side<false, T>(x); }
Chris@16 373
Chris@16 374 /**
Chris@16 375 * \brief Determines when to terminate layout of a particular graph based
Chris@16 376 * on a given relative tolerance.
Chris@16 377 */
Chris@16 378 template<typename T = double>
Chris@16 379 struct layout_tolerance
Chris@16 380 {
Chris@16 381 layout_tolerance(const T& tolerance = T(0.001))
Chris@16 382 : tolerance(tolerance), last_energy((std::numeric_limits<T>::max)()),
Chris@16 383 last_local_energy((std::numeric_limits<T>::max)()) { }
Chris@16 384
Chris@16 385 template<typename Graph>
Chris@16 386 bool
Chris@16 387 operator()(T delta_p,
Chris@16 388 typename boost::graph_traits<Graph>::vertex_descriptor p,
Chris@16 389 const Graph& g,
Chris@16 390 bool global)
Chris@16 391 {
Chris@16 392 if (global) {
Chris@16 393 if (last_energy == (std::numeric_limits<T>::max)()) {
Chris@16 394 last_energy = delta_p;
Chris@16 395 return false;
Chris@16 396 }
Chris@16 397
Chris@16 398 T diff = last_energy - delta_p;
Chris@16 399 if (diff < T(0)) diff = -diff;
Chris@16 400 bool done = (delta_p == T(0) || diff / last_energy < tolerance);
Chris@16 401 last_energy = delta_p;
Chris@16 402 return done;
Chris@16 403 } else {
Chris@16 404 if (last_local_energy == (std::numeric_limits<T>::max)()) {
Chris@16 405 last_local_energy = delta_p;
Chris@16 406 return delta_p == T(0);
Chris@16 407 }
Chris@16 408
Chris@16 409 T diff = last_local_energy - delta_p;
Chris@16 410 bool done = (delta_p == T(0) || (diff / last_local_energy) < tolerance);
Chris@16 411 last_local_energy = delta_p;
Chris@16 412 return done;
Chris@16 413 }
Chris@16 414 }
Chris@16 415
Chris@16 416 private:
Chris@16 417 T tolerance;
Chris@16 418 T last_energy;
Chris@16 419 T last_local_energy;
Chris@16 420 };
Chris@16 421
Chris@16 422 /** \brief Kamada-Kawai spring layout for undirected graphs.
Chris@16 423 *
Chris@16 424 * This algorithm performs graph layout (in two dimensions) for
Chris@16 425 * connected, undirected graphs. It operates by relating the layout
Chris@16 426 * of graphs to a dynamic spring system and minimizing the energy
Chris@16 427 * within that system. The strength of a spring between two vertices
Chris@16 428 * is inversely proportional to the square of the shortest distance
Chris@16 429 * (in graph terms) between those two vertices. Essentially,
Chris@16 430 * vertices that are closer in the graph-theoretic sense (i.e., by
Chris@16 431 * following edges) will have stronger springs and will therefore be
Chris@16 432 * placed closer together.
Chris@16 433 *
Chris@16 434 * Prior to invoking this algorithm, it is recommended that the
Chris@16 435 * vertices be placed along the vertices of a regular n-sided
Chris@16 436 * polygon.
Chris@16 437 *
Chris@16 438 * \param g (IN) must be a model of Vertex List Graph, Edge List
Chris@16 439 * Graph, and Incidence Graph and must be undirected.
Chris@16 440 *
Chris@16 441 * \param position (OUT) must be a model of Lvalue Property Map,
Chris@16 442 * where the value type is a class containing fields @c x and @c y
Chris@16 443 * that will be set to the @c x and @c y coordinates of each vertex.
Chris@16 444 *
Chris@16 445 * \param weight (IN) must be a model of Readable Property Map,
Chris@16 446 * which provides the weight of each edge in the graph @p g.
Chris@16 447 *
Chris@16 448 * \param topology (IN) must be a topology object (see topology.hpp),
Chris@16 449 * which provides operations on points and differences between them.
Chris@16 450 *
Chris@16 451 * \param edge_or_side_length (IN) provides either the unit length
Chris@16 452 * @c e of an edge in the layout or the length of a side @c s of the
Chris@16 453 * display area, and must be either @c boost::edge_length(e) or @c
Chris@16 454 * boost::side_length(s), respectively.
Chris@16 455 *
Chris@16 456 * \param done (IN) is a 4-argument function object that is passed
Chris@16 457 * the current value of delta_p (i.e., the energy of vertex @p p),
Chris@16 458 * the vertex @p p, the graph @p g, and a boolean flag indicating
Chris@16 459 * whether @p delta_p is the maximum energy in the system (when @c
Chris@16 460 * true) or the energy of the vertex being moved. Defaults to @c
Chris@16 461 * layout_tolerance instantiated over the value type of the weight
Chris@16 462 * map.
Chris@16 463 *
Chris@16 464 * \param spring_constant (IN) is the constant multiplied by each
Chris@16 465 * spring's strength. Larger values create systems with more energy
Chris@16 466 * that can take longer to stabilize; smaller values create systems
Chris@16 467 * with less energy that stabilize quickly but do not necessarily
Chris@16 468 * result in pleasing layouts. The default value is 1.
Chris@16 469 *
Chris@16 470 * \param index (IN) is a mapping from vertices to index values
Chris@16 471 * between 0 and @c num_vertices(g). The default is @c
Chris@16 472 * get(vertex_index,g).
Chris@16 473 *
Chris@16 474 * \param distance (UTIL/OUT) will be used to store the distance
Chris@16 475 * from every vertex to every other vertex, which is computed in the
Chris@16 476 * first stages of the algorithm. This value's type must be a model
Chris@16 477 * of BasicMatrix with value type equal to the value type of the
Chris@16 478 * weight map. The default is a vector of vectors.
Chris@16 479 *
Chris@16 480 * \param spring_strength (UTIL/OUT) will be used to store the
Chris@16 481 * strength of the spring between every pair of vertices. This
Chris@16 482 * value's type must be a model of BasicMatrix with value type equal
Chris@16 483 * to the value type of the weight map. The default is a vector of
Chris@16 484 * vectors.
Chris@16 485 *
Chris@16 486 * \param partial_derivatives (UTIL) will be used to store the
Chris@16 487 * partial derivates of each vertex with respect to the @c x and @c
Chris@16 488 * y coordinates. This must be a Read/Write Property Map whose value
Chris@16 489 * type is a pair with both types equivalent to the value type of
Chris@16 490 * the weight map. The default is an iterator property map.
Chris@16 491 *
Chris@16 492 * \returns @c true if layout was successful or @c false if a
Chris@16 493 * negative weight cycle was detected.
Chris@16 494 */
Chris@16 495 template<typename Topology, typename Graph, typename PositionMap, typename WeightMap,
Chris@16 496 typename T, bool EdgeOrSideLength, typename Done,
Chris@16 497 typename VertexIndexMap, typename DistanceMatrix,
Chris@16 498 typename SpringStrengthMatrix, typename PartialDerivativeMap>
Chris@16 499 bool
Chris@16 500 kamada_kawai_spring_layout(
Chris@16 501 const Graph& g,
Chris@16 502 PositionMap position,
Chris@16 503 WeightMap weight,
Chris@16 504 const Topology& topology,
Chris@16 505 detail::graph::edge_or_side<EdgeOrSideLength, T> edge_or_side_length,
Chris@16 506 Done done,
Chris@16 507 typename property_traits<WeightMap>::value_type spring_constant,
Chris@16 508 VertexIndexMap index,
Chris@16 509 DistanceMatrix distance,
Chris@16 510 SpringStrengthMatrix spring_strength,
Chris@16 511 PartialDerivativeMap partial_derivatives)
Chris@16 512 {
Chris@16 513 BOOST_STATIC_ASSERT((is_convertible<
Chris@16 514 typename graph_traits<Graph>::directed_category*,
Chris@16 515 undirected_tag*
Chris@16 516 >::value));
Chris@16 517
Chris@16 518 detail::graph::kamada_kawai_spring_layout_impl<
Chris@16 519 Topology, Graph, PositionMap, WeightMap,
Chris@16 520 detail::graph::edge_or_side<EdgeOrSideLength, T>, Done, VertexIndexMap,
Chris@16 521 DistanceMatrix, SpringStrengthMatrix, PartialDerivativeMap>
Chris@16 522 alg(topology, g, position, weight, edge_or_side_length, done, spring_constant,
Chris@16 523 index, distance, spring_strength, partial_derivatives);
Chris@16 524 return alg.run();
Chris@16 525 }
Chris@16 526
Chris@16 527 /**
Chris@16 528 * \overload
Chris@16 529 */
Chris@16 530 template<typename Topology, typename Graph, typename PositionMap, typename WeightMap,
Chris@16 531 typename T, bool EdgeOrSideLength, typename Done,
Chris@16 532 typename VertexIndexMap>
Chris@16 533 bool
Chris@16 534 kamada_kawai_spring_layout(
Chris@16 535 const Graph& g,
Chris@16 536 PositionMap position,
Chris@16 537 WeightMap weight,
Chris@16 538 const Topology& topology,
Chris@16 539 detail::graph::edge_or_side<EdgeOrSideLength, T> edge_or_side_length,
Chris@16 540 Done done,
Chris@16 541 typename property_traits<WeightMap>::value_type spring_constant,
Chris@16 542 VertexIndexMap index)
Chris@16 543 {
Chris@16 544 typedef typename property_traits<WeightMap>::value_type weight_type;
Chris@16 545
Chris@16 546 typename graph_traits<Graph>::vertices_size_type n = num_vertices(g);
Chris@16 547 typedef std::vector<weight_type> weight_vec;
Chris@16 548
Chris@16 549 std::vector<weight_vec> distance(n, weight_vec(n));
Chris@16 550 std::vector<weight_vec> spring_strength(n, weight_vec(n));
Chris@16 551 std::vector<typename Topology::point_difference_type> partial_derivatives(n);
Chris@16 552
Chris@16 553 return
Chris@16 554 kamada_kawai_spring_layout(
Chris@16 555 g, position, weight, topology, edge_or_side_length, done, spring_constant, index,
Chris@16 556 distance.begin(),
Chris@16 557 spring_strength.begin(),
Chris@16 558 make_iterator_property_map(partial_derivatives.begin(), index,
Chris@16 559 typename Topology::point_difference_type()));
Chris@16 560 }
Chris@16 561
Chris@16 562 /**
Chris@16 563 * \overload
Chris@16 564 */
Chris@16 565 template<typename Topology, typename Graph, typename PositionMap, typename WeightMap,
Chris@16 566 typename T, bool EdgeOrSideLength, typename Done>
Chris@16 567 bool
Chris@16 568 kamada_kawai_spring_layout(
Chris@16 569 const Graph& g,
Chris@16 570 PositionMap position,
Chris@16 571 WeightMap weight,
Chris@16 572 const Topology& topology,
Chris@16 573 detail::graph::edge_or_side<EdgeOrSideLength, T> edge_or_side_length,
Chris@16 574 Done done,
Chris@16 575 typename property_traits<WeightMap>::value_type spring_constant)
Chris@16 576 {
Chris@16 577 return kamada_kawai_spring_layout(g, position, weight, topology, edge_or_side_length,
Chris@16 578 done, spring_constant,
Chris@16 579 get(vertex_index, g));
Chris@16 580 }
Chris@16 581
Chris@16 582 /**
Chris@16 583 * \overload
Chris@16 584 */
Chris@16 585 template<typename Topology, typename Graph, typename PositionMap, typename WeightMap,
Chris@16 586 typename T, bool EdgeOrSideLength, typename Done>
Chris@16 587 bool
Chris@16 588 kamada_kawai_spring_layout(
Chris@16 589 const Graph& g,
Chris@16 590 PositionMap position,
Chris@16 591 WeightMap weight,
Chris@16 592 const Topology& topology,
Chris@16 593 detail::graph::edge_or_side<EdgeOrSideLength, T> edge_or_side_length,
Chris@16 594 Done done)
Chris@16 595 {
Chris@16 596 typedef typename property_traits<WeightMap>::value_type weight_type;
Chris@16 597 return kamada_kawai_spring_layout(g, position, weight, topology, edge_or_side_length,
Chris@16 598 done, weight_type(1));
Chris@16 599 }
Chris@16 600
Chris@16 601 /**
Chris@16 602 * \overload
Chris@16 603 */
Chris@16 604 template<typename Topology, typename Graph, typename PositionMap, typename WeightMap,
Chris@16 605 typename T, bool EdgeOrSideLength>
Chris@16 606 bool
Chris@16 607 kamada_kawai_spring_layout(
Chris@16 608 const Graph& g,
Chris@16 609 PositionMap position,
Chris@16 610 WeightMap weight,
Chris@16 611 const Topology& topology,
Chris@16 612 detail::graph::edge_or_side<EdgeOrSideLength, T> edge_or_side_length)
Chris@16 613 {
Chris@16 614 typedef typename property_traits<WeightMap>::value_type weight_type;
Chris@16 615 return kamada_kawai_spring_layout(g, position, weight, topology, edge_or_side_length,
Chris@16 616 layout_tolerance<weight_type>(),
Chris@16 617 weight_type(1.0),
Chris@16 618 get(vertex_index, g));
Chris@16 619 }
Chris@16 620 } // end namespace boost
Chris@16 621
Chris@16 622 #endif // BOOST_GRAPH_KAMADA_KAWAI_SPRING_LAYOUT_HPP