Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:37:31

0001 // Copyright 2004 The Trustees of Indiana University.
0002 
0003 // Distributed under the Boost Software License, Version 1.0.
0004 // (See accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 //  Authors: Douglas Gregor
0008 //           Andrew Lumsdaine
0009 #ifndef BOOST_GRAPH_KAMADA_KAWAI_SPRING_LAYOUT_HPP
0010 #define BOOST_GRAPH_KAMADA_KAWAI_SPRING_LAYOUT_HPP
0011 
0012 #include <boost/graph/graph_traits.hpp>
0013 #include <boost/graph/topology.hpp>
0014 #include <boost/graph/iteration_macros.hpp>
0015 #include <boost/graph/johnson_all_pairs_shortest.hpp>
0016 #include <boost/type_traits/is_convertible.hpp>
0017 #include <utility>
0018 #include <iterator>
0019 #include <vector>
0020 #include <iostream>
0021 #include <boost/limits.hpp>
0022 #include <boost/config/no_tr1/cmath.hpp>
0023 
0024 namespace boost
0025 {
0026 namespace detail
0027 {
0028     namespace graph
0029     {
0030         /**
0031          * Denotes an edge or display area side length used to scale a
0032          * Kamada-Kawai drawing.
0033          */
0034         template < bool Edge, typename T > struct edge_or_side
0035         {
0036             explicit edge_or_side(T value) : value(value) {}
0037 
0038             T value;
0039         };
0040 
0041         /**
0042          * Compute the edge length from an edge length. This is trivial.
0043          */
0044         template < typename Graph, typename DistanceMap, typename IndexMap,
0045             typename T >
0046         T compute_edge_length(
0047             const Graph&, DistanceMap, IndexMap, edge_or_side< true, T > length)
0048         {
0049             return length.value;
0050         }
0051 
0052         /**
0053          * Compute the edge length based on the display area side
0054            length. We do this by dividing the side length by the largest
0055            shortest distance between any two vertices in the graph.
0056          */
0057         template < typename Graph, typename DistanceMap, typename IndexMap,
0058             typename T >
0059         T compute_edge_length(const Graph& g, DistanceMap distance,
0060             IndexMap index, edge_or_side< false, T > length)
0061         {
0062             T result(0);
0063 
0064             typedef
0065                 typename graph_traits< Graph >::vertex_iterator vertex_iterator;
0066 
0067             for (vertex_iterator ui = vertices(g).first,
0068                                  end = vertices(g).second;
0069                  ui != end; ++ui)
0070             {
0071                 vertex_iterator vi = ui;
0072                 for (++vi; vi != end; ++vi)
0073                 {
0074                     T dij = distance[get(index, *ui)][get(index, *vi)];
0075                     if (dij > result)
0076                         result = dij;
0077                 }
0078             }
0079             return length.value / result;
0080         }
0081 
0082         /**
0083          * Dense linear solver for fixed-size matrices.
0084          */
0085         template < std::size_t Size > struct linear_solver
0086         {
0087             // Indices in mat are (row, column)
0088             // template <typename Vec>
0089             // static Vec solve(double mat[Size][Size], Vec rhs);
0090         };
0091 
0092         template <> struct linear_solver< 1 >
0093         {
0094             template < typename Vec >
0095             static Vec solve(double mat[1][1], Vec rhs)
0096             {
0097                 return rhs / mat[0][0];
0098             }
0099         };
0100 
0101         // These are from http://en.wikipedia.org/wiki/Cramer%27s_rule
0102         template <> struct linear_solver< 2 >
0103         {
0104             template < typename Vec >
0105             static Vec solve(double mat[2][2], Vec rhs)
0106             {
0107                 double denom = mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
0108                 double x_num = rhs[0] * mat[1][1] - rhs[1] * mat[0][1];
0109                 double y_num = mat[0][0] * rhs[1] - mat[1][0] * rhs[0];
0110                 Vec result;
0111                 result[0] = x_num / denom;
0112                 result[1] = y_num / denom;
0113                 return result;
0114             }
0115         };
0116 
0117         template <> struct linear_solver< 3 >
0118         {
0119             template < typename Vec >
0120             static Vec solve(double mat[3][3], Vec rhs)
0121             {
0122                 double denom = mat[0][0]
0123                         * (mat[1][1] * mat[2][2] - mat[2][1] * mat[1][2])
0124                     - mat[1][0]
0125                         * (mat[0][1] * mat[2][2] - mat[2][1] * mat[0][2])
0126                     + mat[2][0]
0127                         * (mat[0][1] * mat[1][2] - mat[1][1] * mat[0][2]);
0128                 double x_num
0129                     = rhs[0] * (mat[1][1] * mat[2][2] - mat[2][1] * mat[1][2])
0130                     - rhs[1] * (mat[0][1] * mat[2][2] - mat[2][1] * mat[0][2])
0131                     + rhs[2] * (mat[0][1] * mat[1][2] - mat[1][1] * mat[0][2]);
0132                 double y_num
0133                     = mat[0][0] * (rhs[1] * mat[2][2] - rhs[2] * mat[1][2])
0134                     - mat[1][0] * (rhs[0] * mat[2][2] - rhs[2] * mat[0][2])
0135                     + mat[2][0] * (rhs[0] * mat[1][2] - rhs[1] * mat[0][2]);
0136                 double z_num
0137                     = mat[0][0] * (mat[1][1] * rhs[2] - mat[2][1] * rhs[1])
0138                     - mat[1][0] * (mat[0][1] * rhs[2] - mat[2][1] * rhs[0])
0139                     + mat[2][0] * (mat[0][1] * rhs[1] - mat[1][1] * rhs[0]);
0140                 Vec result;
0141                 result[0] = x_num / denom;
0142                 result[1] = y_num / denom;
0143                 result[2] = z_num / denom;
0144                 return result;
0145             }
0146         };
0147 
0148         /**
0149          * Implementation of the Kamada-Kawai spring layout algorithm.
0150          */
0151         template < typename Topology, typename Graph, typename PositionMap,
0152             typename WeightMap, typename EdgeOrSideLength, typename Done,
0153             typename VertexIndexMap, typename DistanceMatrix,
0154             typename SpringStrengthMatrix, typename PartialDerivativeMap >
0155         struct kamada_kawai_spring_layout_impl
0156         {
0157             typedef
0158                 typename property_traits< WeightMap >::value_type weight_type;
0159             typedef typename Topology::point_type Point;
0160             typedef
0161                 typename Topology::point_difference_type point_difference_type;
0162             typedef point_difference_type deriv_type;
0163             typedef
0164                 typename graph_traits< Graph >::vertex_iterator vertex_iterator;
0165             typedef typename graph_traits< Graph >::vertex_descriptor
0166                 vertex_descriptor;
0167 
0168             kamada_kawai_spring_layout_impl(const Topology& topology,
0169                 const Graph& g, PositionMap position, WeightMap weight,
0170                 EdgeOrSideLength edge_or_side_length, Done done,
0171                 weight_type spring_constant, VertexIndexMap index,
0172                 DistanceMatrix distance, SpringStrengthMatrix spring_strength,
0173                 PartialDerivativeMap partial_derivatives)
0174             : topology(topology)
0175             , g(g)
0176             , position(position)
0177             , weight(weight)
0178             , edge_or_side_length(edge_or_side_length)
0179             , done(done)
0180             , spring_constant(spring_constant)
0181             , index(index)
0182             , distance(distance)
0183             , spring_strength(spring_strength)
0184             , partial_derivatives(partial_derivatives)
0185             {
0186             }
0187 
0188             // Compute contribution of vertex i to the first partial
0189             // derivatives (dE/dx_m, dE/dy_m) (for vertex m)
0190             deriv_type compute_partial_derivative(
0191                 vertex_descriptor m, vertex_descriptor i)
0192             {
0193 #ifndef BOOST_NO_STDC_NAMESPACE
0194                 using std::sqrt;
0195 #endif // BOOST_NO_STDC_NAMESPACE
0196 
0197                 deriv_type result;
0198                 if (i != m)
0199                 {
0200                     point_difference_type diff
0201                         = topology.difference(position[m], position[i]);
0202                     weight_type dist = topology.norm(diff);
0203                     result = spring_strength[get(index, m)][get(index, i)]
0204                         * (diff
0205                             - distance[get(index, m)][get(index, i)] / dist
0206                                 * diff);
0207                 }
0208 
0209                 return result;
0210             }
0211 
0212             // Compute partial derivatives dE/dx_m and dE/dy_m
0213             deriv_type compute_partial_derivatives(vertex_descriptor m)
0214             {
0215 #ifndef BOOST_NO_STDC_NAMESPACE
0216                 using std::sqrt;
0217 #endif // BOOST_NO_STDC_NAMESPACE
0218 
0219                 deriv_type result;
0220 
0221                 // TBD: looks like an accumulate to me
0222                 BGL_FORALL_VERTICES_T(i, g, Graph)
0223                 {
0224                     deriv_type deriv = compute_partial_derivative(m, i);
0225                     result += deriv;
0226                 }
0227 
0228                 return result;
0229             }
0230 
0231             // The actual Kamada-Kawai spring layout algorithm implementation
0232             bool run()
0233             {
0234 #ifndef BOOST_NO_STDC_NAMESPACE
0235                 using std::sqrt;
0236 #endif // BOOST_NO_STDC_NAMESPACE
0237 
0238                 // Compute d_{ij} and place it in the distance matrix
0239                 if (!johnson_all_pairs_shortest_paths(
0240                         g, distance, index, weight, weight_type(0)))
0241                     return false;
0242 
0243                 // Compute L based on side length (if needed), or retrieve L
0244                 weight_type edge_length = detail::graph::compute_edge_length(
0245                     g, distance, index, edge_or_side_length);
0246 
0247                 // std::cerr << "edge_length = " << edge_length << std::endl;
0248 
0249                 // Compute l_{ij} and k_{ij}
0250                 const weight_type K = spring_constant;
0251                 vertex_iterator ui, end;
0252                 for (ui = vertices(g).first, end = vertices(g).second;
0253                      ui != end; ++ui)
0254                 {
0255                     vertex_iterator vi = ui;
0256                     for (++vi; vi != end; ++vi)
0257                     {
0258                         weight_type dij
0259                             = distance[get(index, *ui)][get(index, *vi)];
0260                         if (dij == (std::numeric_limits< weight_type >::max)())
0261                             return false;
0262                         distance[get(index, *ui)][get(index, *vi)]
0263                             = edge_length * dij;
0264                         distance[get(index, *vi)][get(index, *ui)]
0265                             = edge_length * dij;
0266                         spring_strength[get(index, *ui)][get(index, *vi)]
0267                             = K / (dij * dij);
0268                         spring_strength[get(index, *vi)][get(index, *ui)]
0269                             = K / (dij * dij);
0270                     }
0271                 }
0272 
0273                 // Compute Delta_i and find max
0274                 vertex_descriptor p = *vertices(g).first;
0275                 weight_type delta_p(0);
0276 
0277                 for (ui = vertices(g).first, end = vertices(g).second;
0278                      ui != end; ++ui)
0279                 {
0280                     deriv_type deriv = compute_partial_derivatives(*ui);
0281                     put(partial_derivatives, *ui, deriv);
0282 
0283                     weight_type delta = topology.norm(deriv);
0284 
0285                     if (delta > delta_p)
0286                     {
0287                         p = *ui;
0288                         delta_p = delta;
0289                     }
0290                 }
0291 
0292                 while (!done(delta_p, p, g, true))
0293                 {
0294                     // The contribution p makes to the partial derivatives of
0295                     // each vertex. Computing this (at O(n) cost) allows us to
0296                     // update the delta_i values in O(n) time instead of O(n^2)
0297                     // time.
0298                     std::vector< deriv_type > p_partials(num_vertices(g));
0299                     for (ui = vertices(g).first, end = vertices(g).second;
0300                          ui != end; ++ui)
0301                     {
0302                         vertex_descriptor i = *ui;
0303                         p_partials[get(index, i)]
0304                             = compute_partial_derivative(i, p);
0305                     }
0306 
0307                     do
0308                     {
0309                         // For debugging, compute the energy value E
0310                         double E = 0.;
0311                         for (ui = vertices(g).first, end = vertices(g).second;
0312                              ui != end; ++ui)
0313                         {
0314                             vertex_iterator vi = ui;
0315                             for (++vi; vi != end; ++vi)
0316                             {
0317                                 double dist = topology.distance(
0318                                     position[*ui], position[*vi]);
0319                                 weight_type k_ij = spring_strength[get(
0320                                     index, *ui)][get(index, *vi)];
0321                                 weight_type l_ij = distance[get(index, *ui)]
0322                                                            [get(index, *vi)];
0323                                 E += .5 * k_ij * (dist - l_ij) * (dist - l_ij);
0324                             }
0325                         }
0326                         // std::cerr << "E = " << E << std::endl;
0327 
0328                         // Compute the elements of the Jacobian
0329                         // From
0330                         // http://www.cs.panam.edu/~rfowler/papers/1994_kumar_fowler_A_Spring_UTPACSTR.pdf
0331                         // with the bugs fixed in the off-diagonal case
0332                         weight_type dE_d_d[Point::dimensions]
0333                                           [Point::dimensions];
0334                         for (std::size_t i = 0; i < Point::dimensions; ++i)
0335                             for (std::size_t j = 0; j < Point::dimensions; ++j)
0336                                 dE_d_d[i][j] = 0.;
0337                         for (ui = vertices(g).first, end = vertices(g).second;
0338                              ui != end; ++ui)
0339                         {
0340                             vertex_descriptor i = *ui;
0341                             if (i != p)
0342                             {
0343                                 point_difference_type diff
0344                                     = topology.difference(
0345                                         position[p], position[i]);
0346                                 weight_type dist = topology.norm(diff);
0347                                 weight_type dist_squared = dist * dist;
0348                                 weight_type inv_dist_cubed
0349                                     = 1. / (dist_squared * dist);
0350                                 weight_type k_mi = spring_strength[get(
0351                                     index, p)][get(index, i)];
0352                                 weight_type l_mi
0353                                     = distance[get(index, p)][get(index, i)];
0354                                 for (std::size_t i = 0; i < Point::dimensions;
0355                                      ++i)
0356                                 {
0357                                     for (std::size_t j = 0;
0358                                          j < Point::dimensions; ++j)
0359                                     {
0360                                         if (i == j)
0361                                         {
0362                                             dE_d_d[i][i] += k_mi
0363                                                 * (1
0364                                                     + (l_mi
0365                                                         * (diff[i] * diff[i]
0366                                                             - dist_squared)
0367                                                         * inv_dist_cubed));
0368                                         }
0369                                         else
0370                                         {
0371                                             dE_d_d[i][j] += k_mi * l_mi
0372                                                 * diff[i] * diff[j]
0373                                                 * inv_dist_cubed;
0374                                             // dE_d_d[i][j] += k_mi * l_mi *
0375                                             // sqrt(hypot(diff[i], diff[j])) *
0376                                             // inv_dist_cubed;
0377                                         }
0378                                     }
0379                                 }
0380                             }
0381                         }
0382 
0383                         deriv_type dE_d = get(partial_derivatives, p);
0384 
0385                         // Solve dE_d_d * delta = -dE_d to get delta
0386                         point_difference_type delta
0387                             = -linear_solver< Point::dimensions >::solve(
0388                                 dE_d_d, dE_d);
0389 
0390                         // Move p by delta
0391                         position[p] = topology.adjust(position[p], delta);
0392 
0393                         // Recompute partial derivatives and delta_p
0394                         deriv_type deriv = compute_partial_derivatives(p);
0395                         put(partial_derivatives, p, deriv);
0396 
0397                         delta_p = topology.norm(deriv);
0398                     } while (!done(delta_p, p, g, false));
0399 
0400                     // Select new p by updating each partial derivative and
0401                     // delta
0402                     vertex_descriptor old_p = p;
0403                     for (ui = vertices(g).first, end = vertices(g).second;
0404                          ui != end; ++ui)
0405                     {
0406                         deriv_type old_deriv_p = p_partials[get(index, *ui)];
0407                         deriv_type old_p_partial
0408                             = compute_partial_derivative(*ui, old_p);
0409                         deriv_type deriv = get(partial_derivatives, *ui);
0410 
0411                         deriv += old_p_partial - old_deriv_p;
0412 
0413                         put(partial_derivatives, *ui, deriv);
0414                         weight_type delta = topology.norm(deriv);
0415 
0416                         if (delta > delta_p)
0417                         {
0418                             p = *ui;
0419                             delta_p = delta;
0420                         }
0421                     }
0422                 }
0423 
0424                 return true;
0425             }
0426 
0427             const Topology& topology;
0428             const Graph& g;
0429             PositionMap position;
0430             WeightMap weight;
0431             EdgeOrSideLength edge_or_side_length;
0432             Done done;
0433             weight_type spring_constant;
0434             VertexIndexMap index;
0435             DistanceMatrix distance;
0436             SpringStrengthMatrix spring_strength;
0437             PartialDerivativeMap partial_derivatives;
0438         };
0439     }
0440 } // end namespace detail::graph
0441 
0442 /// States that the given quantity is an edge length.
0443 template < typename T >
0444 inline detail::graph::edge_or_side< true, T > edge_length(T x)
0445 {
0446     return detail::graph::edge_or_side< true, T >(x);
0447 }
0448 
0449 /// States that the given quantity is a display area side length.
0450 template < typename T >
0451 inline detail::graph::edge_or_side< false, T > side_length(T x)
0452 {
0453     return detail::graph::edge_or_side< false, T >(x);
0454 }
0455 
0456 /**
0457  * \brief Determines when to terminate layout of a particular graph based
0458  * on a given relative tolerance.
0459  */
0460 template < typename T = double > struct layout_tolerance
0461 {
0462     layout_tolerance(const T& tolerance = T(0.001))
0463     : tolerance(tolerance)
0464     , last_energy((std::numeric_limits< T >::max)())
0465     , last_local_energy((std::numeric_limits< T >::max)())
0466     {
0467     }
0468 
0469     template < typename Graph >
0470     bool operator()(T delta_p,
0471         typename boost::graph_traits< Graph >::vertex_descriptor p,
0472         const Graph& g, bool global)
0473     {
0474         if (global)
0475         {
0476             if (last_energy == (std::numeric_limits< T >::max)())
0477             {
0478                 last_energy = delta_p;
0479                 return false;
0480             }
0481 
0482             T diff = last_energy - delta_p;
0483             if (diff < T(0))
0484                 diff = -diff;
0485             bool done = (delta_p == T(0) || diff / last_energy < tolerance);
0486             last_energy = delta_p;
0487             return done;
0488         }
0489         else
0490         {
0491             if (last_local_energy == (std::numeric_limits< T >::max)())
0492             {
0493                 last_local_energy = delta_p;
0494                 return delta_p == T(0);
0495             }
0496 
0497             T diff = last_local_energy - delta_p;
0498             bool done
0499                 = (delta_p == T(0) || (diff / last_local_energy) < tolerance);
0500             last_local_energy = delta_p;
0501             return done;
0502         }
0503     }
0504 
0505 private:
0506     T tolerance;
0507     T last_energy;
0508     T last_local_energy;
0509 };
0510 
0511 /** \brief Kamada-Kawai spring layout for undirected graphs.
0512  *
0513  * This algorithm performs graph layout (in two dimensions) for
0514  * connected, undirected graphs. It operates by relating the layout
0515  * of graphs to a dynamic spring system and minimizing the energy
0516  * within that system. The strength of a spring between two vertices
0517  * is inversely proportional to the square of the shortest distance
0518  * (in graph terms) between those two vertices. Essentially,
0519  * vertices that are closer in the graph-theoretic sense (i.e., by
0520  * following edges) will have stronger springs and will therefore be
0521  * placed closer together.
0522  *
0523  * Prior to invoking this algorithm, it is recommended that the
0524  * vertices be placed along the vertices of a regular n-sided
0525  * polygon.
0526  *
0527  * \param g (IN) must be a model of Vertex List Graph, Edge List
0528  * Graph, and Incidence Graph and must be undirected.
0529  *
0530  * \param position (OUT) must be a model of Lvalue Property Map,
0531  * where the value type is a class containing fields @c x and @c y
0532  * that will be set to the @c x and @c y coordinates of each vertex.
0533  *
0534  * \param weight (IN) must be a model of Readable Property Map,
0535  * which provides the weight of each edge in the graph @p g.
0536  *
0537  * \param topology (IN) must be a topology object (see topology.hpp),
0538  * which provides operations on points and differences between them.
0539  *
0540  * \param edge_or_side_length (IN) provides either the unit length
0541  * @c e of an edge in the layout or the length of a side @c s of the
0542  * display area, and must be either @c boost::edge_length(e) or @c
0543  * boost::side_length(s), respectively.
0544  *
0545  * \param done (IN) is a 4-argument function object that is passed
0546  * the current value of delta_p (i.e., the energy of vertex @p p),
0547  * the vertex @p p, the graph @p g, and a boolean flag indicating
0548  * whether @p delta_p is the maximum energy in the system (when @c
0549  * true) or the energy of the vertex being moved. Defaults to @c
0550  * layout_tolerance instantiated over the value type of the weight
0551  * map.
0552  *
0553  * \param spring_constant (IN) is the constant multiplied by each
0554  * spring's strength. Larger values create systems with more energy
0555  * that can take longer to stabilize; smaller values create systems
0556  * with less energy that stabilize quickly but do not necessarily
0557  * result in pleasing layouts. The default value is 1.
0558  *
0559  * \param index (IN) is a mapping from vertices to index values
0560  * between 0 and @c num_vertices(g). The default is @c
0561  * get(vertex_index,g).
0562  *
0563  * \param distance (UTIL/OUT) will be used to store the distance
0564  * from every vertex to every other vertex, which is computed in the
0565  * first stages of the algorithm. This value's type must be a model
0566  * of BasicMatrix with value type equal to the value type of the
0567  * weight map. The default is a vector of vectors.
0568  *
0569  * \param spring_strength (UTIL/OUT) will be used to store the
0570  * strength of the spring between every pair of vertices. This
0571  * value's type must be a model of BasicMatrix with value type equal
0572  * to the value type of the weight map. The default is a vector of
0573  * vectors.
0574  *
0575  * \param partial_derivatives (UTIL) will be used to store the
0576  * partial derivates of each vertex with respect to the @c x and @c
0577  * y coordinates. This must be a Read/Write Property Map whose value
0578  * type is a pair with both types equivalent to the value type of
0579  * the weight map. The default is an iterator property map.
0580  *
0581  * \returns @c true if layout was successful or @c false if a
0582  * negative weight cycle was detected.
0583  */
0584 template < typename Topology, typename Graph, typename PositionMap,
0585     typename WeightMap, typename T, bool EdgeOrSideLength, typename Done,
0586     typename VertexIndexMap, typename DistanceMatrix,
0587     typename SpringStrengthMatrix, typename PartialDerivativeMap >
0588 bool kamada_kawai_spring_layout(const Graph& g, PositionMap position,
0589     WeightMap weight, const Topology& topology,
0590     detail::graph::edge_or_side< EdgeOrSideLength, T > edge_or_side_length,
0591     Done done,
0592     typename property_traits< WeightMap >::value_type spring_constant,
0593     VertexIndexMap index, DistanceMatrix distance,
0594     SpringStrengthMatrix spring_strength,
0595     PartialDerivativeMap partial_derivatives)
0596 {
0597     BOOST_STATIC_ASSERT(
0598         (is_convertible< typename graph_traits< Graph >::directed_category*,
0599             undirected_tag* >::value));
0600 
0601     detail::graph::kamada_kawai_spring_layout_impl< Topology, Graph,
0602         PositionMap, WeightMap,
0603         detail::graph::edge_or_side< EdgeOrSideLength, T >, Done,
0604         VertexIndexMap, DistanceMatrix, SpringStrengthMatrix,
0605         PartialDerivativeMap >
0606         alg(topology, g, position, weight, edge_or_side_length, done,
0607             spring_constant, index, distance, spring_strength,
0608             partial_derivatives);
0609     return alg.run();
0610 }
0611 
0612 /**
0613  * \overload
0614  */
0615 template < typename Topology, typename Graph, typename PositionMap,
0616     typename WeightMap, typename T, bool EdgeOrSideLength, typename Done,
0617     typename VertexIndexMap >
0618 bool kamada_kawai_spring_layout(const Graph& g, PositionMap position,
0619     WeightMap weight, const Topology& topology,
0620     detail::graph::edge_or_side< EdgeOrSideLength, T > edge_or_side_length,
0621     Done done,
0622     typename property_traits< WeightMap >::value_type spring_constant,
0623     VertexIndexMap index)
0624 {
0625     typedef typename property_traits< WeightMap >::value_type weight_type;
0626 
0627     typename graph_traits< Graph >::vertices_size_type n = num_vertices(g);
0628     typedef std::vector< weight_type > weight_vec;
0629 
0630     std::vector< weight_vec > distance(n, weight_vec(n));
0631     std::vector< weight_vec > spring_strength(n, weight_vec(n));
0632     std::vector< typename Topology::point_difference_type > partial_derivatives(
0633         n);
0634 
0635     return kamada_kawai_spring_layout(g, position, weight, topology,
0636         edge_or_side_length, done, spring_constant, index, distance.begin(),
0637         spring_strength.begin(),
0638         make_iterator_property_map(partial_derivatives.begin(), index,
0639             typename Topology::point_difference_type()));
0640 }
0641 
0642 /**
0643  * \overload
0644  */
0645 template < typename Topology, typename Graph, typename PositionMap,
0646     typename WeightMap, typename T, bool EdgeOrSideLength, typename Done >
0647 bool kamada_kawai_spring_layout(const Graph& g, PositionMap position,
0648     WeightMap weight, const Topology& topology,
0649     detail::graph::edge_or_side< EdgeOrSideLength, T > edge_or_side_length,
0650     Done done,
0651     typename property_traits< WeightMap >::value_type spring_constant)
0652 {
0653     return kamada_kawai_spring_layout(g, position, weight, topology,
0654         edge_or_side_length, done, spring_constant, get(vertex_index, g));
0655 }
0656 
0657 /**
0658  * \overload
0659  */
0660 template < typename Topology, typename Graph, typename PositionMap,
0661     typename WeightMap, typename T, bool EdgeOrSideLength, typename Done >
0662 bool kamada_kawai_spring_layout(const Graph& g, PositionMap position,
0663     WeightMap weight, const Topology& topology,
0664     detail::graph::edge_or_side< EdgeOrSideLength, T > edge_or_side_length,
0665     Done done)
0666 {
0667     typedef typename property_traits< WeightMap >::value_type weight_type;
0668     return kamada_kawai_spring_layout(g, position, weight, topology,
0669         edge_or_side_length, done, weight_type(1));
0670 }
0671 
0672 /**
0673  * \overload
0674  */
0675 template < typename Topology, typename Graph, typename PositionMap,
0676     typename WeightMap, typename T, bool EdgeOrSideLength >
0677 bool kamada_kawai_spring_layout(const Graph& g, PositionMap position,
0678     WeightMap weight, const Topology& topology,
0679     detail::graph::edge_or_side< EdgeOrSideLength, T > edge_or_side_length)
0680 {
0681     typedef typename property_traits< WeightMap >::value_type weight_type;
0682     return kamada_kawai_spring_layout(g, position, weight, topology,
0683         edge_or_side_length, layout_tolerance< weight_type >(),
0684         weight_type(1.0), get(vertex_index, g));
0685 }
0686 } // end namespace boost
0687 
0688 #endif // BOOST_GRAPH_KAMADA_KAWAI_SPRING_LAYOUT_HPP