epoc32/include/stdapis/boost/graph/kamada_kawai_spring_layout.hpp
author William Roberts <williamr@symbian.org>
Wed, 31 Mar 2010 12:33:34 +0100
branchSymbian3
changeset 4 837f303aceeb
permissions -rw-r--r--
Current Symbian^3 public API header files (from PDK 3.0.h)
This is the epoc32/include tree with the "platform" subtrees removed, and
all but a selected few mbg and rsg files removed.
williamr@2
     1
// Copyright 2004 The Trustees of Indiana University.
williamr@2
     2
williamr@2
     3
// Distributed under the Boost Software License, Version 1.0.
williamr@2
     4
// (See accompanying file LICENSE_1_0.txt or copy at
williamr@2
     5
// http://www.boost.org/LICENSE_1_0.txt)
williamr@2
     6
williamr@2
     7
//  Authors: Douglas Gregor
williamr@2
     8
//           Andrew Lumsdaine
williamr@2
     9
#ifndef BOOST_GRAPH_KAMADA_KAWAI_SPRING_LAYOUT_HPP
williamr@2
    10
#define BOOST_GRAPH_KAMADA_KAWAI_SPRING_LAYOUT_HPP
williamr@2
    11
williamr@2
    12
#include <boost/graph/graph_traits.hpp>
williamr@2
    13
#include <boost/graph/johnson_all_pairs_shortest.hpp>
williamr@2
    14
#include <boost/type_traits/is_convertible.hpp>
williamr@2
    15
#include <utility>
williamr@2
    16
#include <iterator>
williamr@2
    17
#include <vector>
williamr@2
    18
#include <boost/limits.hpp>
williamr@2
    19
#include <cmath>
williamr@2
    20
williamr@2
    21
namespace boost {
williamr@2
    22
  namespace detail { namespace graph {
williamr@2
    23
    /**
williamr@2
    24
     * Denotes an edge or display area side length used to scale a
williamr@2
    25
     * Kamada-Kawai drawing.
williamr@2
    26
     */
williamr@2
    27
    template<bool Edge, typename T>
williamr@2
    28
    struct edge_or_side
williamr@2
    29
    {
williamr@2
    30
      explicit edge_or_side(T value) : value(value) {}
williamr@2
    31
williamr@2
    32
      T value;
williamr@2
    33
    };
williamr@2
    34
williamr@2
    35
    /**
williamr@2
    36
     * Compute the edge length from an edge length. This is trivial.
williamr@2
    37
     */
williamr@2
    38
    template<typename Graph, typename DistanceMap, typename IndexMap, 
williamr@2
    39
             typename T>
williamr@2
    40
    T compute_edge_length(const Graph&, DistanceMap, IndexMap, 
williamr@2
    41
                          edge_or_side<true, T> length)
williamr@2
    42
    { return length.value; }
williamr@2
    43
williamr@2
    44
    /**
williamr@2
    45
     * Compute the edge length based on the display area side
williamr@2
    46
       length. We do this by dividing the side length by the largest
williamr@2
    47
       shortest distance between any two vertices in the graph.
williamr@2
    48
     */
williamr@2
    49
    template<typename Graph, typename DistanceMap, typename IndexMap, 
williamr@2
    50
             typename T>
williamr@2
    51
    T
williamr@2
    52
    compute_edge_length(const Graph& g, DistanceMap distance, IndexMap index,
williamr@2
    53
                        edge_or_side<false, T> length)
williamr@2
    54
    {
williamr@2
    55
      T result(0);
williamr@2
    56
williamr@2
    57
      typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
williamr@2
    58
williamr@2
    59
      for (vertex_iterator ui = vertices(g).first, end = vertices(g).second;
williamr@2
    60
           ui != end; ++ui) {
williamr@2
    61
        vertex_iterator vi = ui;
williamr@2
    62
        for (++vi; vi != end; ++vi) {
williamr@2
    63
          T dij = distance[get(index, *ui)][get(index, *vi)];
williamr@2
    64
          if (dij > result) result = dij;
williamr@2
    65
        }
williamr@2
    66
      }
williamr@2
    67
      return length.value / result;
williamr@2
    68
    }
williamr@2
    69
williamr@2
    70
    /**
williamr@2
    71
     * Implementation of the Kamada-Kawai spring layout algorithm.
williamr@2
    72
     */
williamr@2
    73
    template<typename Graph, typename PositionMap, typename WeightMap,
williamr@2
    74
             typename EdgeOrSideLength, typename Done,
williamr@2
    75
             typename VertexIndexMap, typename DistanceMatrix,
williamr@2
    76
             typename SpringStrengthMatrix, typename PartialDerivativeMap>
williamr@2
    77
    struct kamada_kawai_spring_layout_impl
williamr@2
    78
    {
williamr@2
    79
      typedef typename property_traits<WeightMap>::value_type weight_type;
williamr@2
    80
      typedef std::pair<weight_type, weight_type> deriv_type;
williamr@2
    81
      typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
williamr@2
    82
      typedef typename graph_traits<Graph>::vertex_descriptor
williamr@2
    83
        vertex_descriptor;
williamr@2
    84
williamr@2
    85
      kamada_kawai_spring_layout_impl(
williamr@2
    86
        const Graph& g, 
williamr@2
    87
        PositionMap position,
williamr@2
    88
        WeightMap weight, 
williamr@2
    89
        EdgeOrSideLength edge_or_side_length,
williamr@2
    90
        Done done,
williamr@2
    91
        weight_type spring_constant,
williamr@2
    92
        VertexIndexMap index,
williamr@2
    93
        DistanceMatrix distance,
williamr@2
    94
        SpringStrengthMatrix spring_strength,
williamr@2
    95
        PartialDerivativeMap partial_derivatives)
williamr@2
    96
        : g(g), position(position), weight(weight), 
williamr@2
    97
          edge_or_side_length(edge_or_side_length), done(done),
williamr@2
    98
          spring_constant(spring_constant), index(index), distance(distance),
williamr@2
    99
          spring_strength(spring_strength), 
williamr@2
   100
          partial_derivatives(partial_derivatives) {}
williamr@2
   101
williamr@2
   102
      // Compute contribution of vertex i to the first partial
williamr@2
   103
      // derivatives (dE/dx_m, dE/dy_m) (for vertex m)
williamr@2
   104
      deriv_type
williamr@2
   105
      compute_partial_derivative(vertex_descriptor m, vertex_descriptor i)
williamr@2
   106
      {
williamr@2
   107
#ifndef BOOST_NO_STDC_NAMESPACE
williamr@2
   108
        using std::sqrt;
williamr@2
   109
#endif // BOOST_NO_STDC_NAMESPACE
williamr@2
   110
williamr@2
   111
        deriv_type result(0, 0);
williamr@2
   112
        if (i != m) {
williamr@2
   113
          weight_type x_diff = position[m].x - position[i].x;
williamr@2
   114
          weight_type y_diff = position[m].y - position[i].y;
williamr@2
   115
          weight_type dist = sqrt(x_diff * x_diff + y_diff * y_diff);
williamr@2
   116
          result.first = spring_strength[get(index, m)][get(index, i)] 
williamr@2
   117
            * (x_diff - distance[get(index, m)][get(index, i)]*x_diff/dist);
williamr@2
   118
          result.second = spring_strength[get(index, m)][get(index, i)] 
williamr@2
   119
            * (y_diff - distance[get(index, m)][get(index, i)]*y_diff/dist);
williamr@2
   120
        }
williamr@2
   121
williamr@2
   122
        return result;
williamr@2
   123
      }
williamr@2
   124
williamr@2
   125
      // Compute partial derivatives dE/dx_m and dE/dy_m
williamr@2
   126
      deriv_type 
williamr@2
   127
      compute_partial_derivatives(vertex_descriptor m)
williamr@2
   128
      {
williamr@2
   129
#ifndef BOOST_NO_STDC_NAMESPACE
williamr@2
   130
        using std::sqrt;
williamr@2
   131
#endif // BOOST_NO_STDC_NAMESPACE
williamr@2
   132
williamr@2
   133
        deriv_type result(0, 0);
williamr@2
   134
williamr@2
   135
        // TBD: looks like an accumulate to me
williamr@2
   136
        std::pair<vertex_iterator, vertex_iterator> verts = vertices(g);
williamr@2
   137
        for (/* no init */; verts.first != verts.second; ++verts.first) {
williamr@2
   138
          vertex_descriptor i = *verts.first;
williamr@2
   139
          deriv_type deriv = compute_partial_derivative(m, i);
williamr@2
   140
          result.first += deriv.first;
williamr@2
   141
          result.second += deriv.second;
williamr@2
   142
        }
williamr@2
   143
williamr@2
   144
        return result;
williamr@2
   145
      }
williamr@2
   146
williamr@2
   147
      // The actual Kamada-Kawai spring layout algorithm implementation
williamr@2
   148
      bool run()
williamr@2
   149
      {
williamr@2
   150
#ifndef BOOST_NO_STDC_NAMESPACE
williamr@2
   151
        using std::sqrt;
williamr@2
   152
#endif // BOOST_NO_STDC_NAMESPACE
williamr@2
   153
williamr@2
   154
        // Compute d_{ij} and place it in the distance matrix
williamr@2
   155
        if (!johnson_all_pairs_shortest_paths(g, distance, index, weight, 
williamr@2
   156
                                              weight_type(0)))
williamr@2
   157
          return false;
williamr@2
   158
williamr@2
   159
        // Compute L based on side length (if needed), or retrieve L
williamr@2
   160
        weight_type edge_length = 
williamr@2
   161
          detail::graph::compute_edge_length(g, distance, index,
williamr@2
   162
                                             edge_or_side_length);
williamr@2
   163
        
williamr@2
   164
        // Compute l_{ij} and k_{ij}
williamr@2
   165
        const weight_type K = spring_constant;
williamr@2
   166
        vertex_iterator ui, end = vertices(g).second;
williamr@2
   167
        for (ui = vertices(g).first; ui != end; ++ui) {
williamr@2
   168
          vertex_iterator vi = ui;
williamr@2
   169
          for (++vi; vi != end; ++vi) {
williamr@2
   170
            weight_type dij = distance[get(index, *ui)][get(index, *vi)];
williamr@2
   171
            if (dij == (std::numeric_limits<weight_type>::max)())
williamr@2
   172
              return false;
williamr@2
   173
            distance[get(index, *ui)][get(index, *vi)] = edge_length * dij;
williamr@2
   174
            distance[get(index, *vi)][get(index, *ui)] = edge_length * dij;
williamr@2
   175
            spring_strength[get(index, *ui)][get(index, *vi)] = K/(dij*dij);
williamr@2
   176
            spring_strength[get(index, *vi)][get(index, *ui)] = K/(dij*dij);
williamr@2
   177
          }
williamr@2
   178
        }
williamr@2
   179
        
williamr@2
   180
        // Compute Delta_i and find max
williamr@2
   181
        vertex_descriptor p = *vertices(g).first;
williamr@2
   182
        weight_type delta_p(0);
williamr@2
   183
williamr@2
   184
        for (ui = vertices(g).first; ui != end; ++ui) {
williamr@2
   185
          deriv_type deriv = compute_partial_derivatives(*ui);
williamr@2
   186
          put(partial_derivatives, *ui, deriv);
williamr@2
   187
williamr@2
   188
          weight_type delta = 
williamr@2
   189
            sqrt(deriv.first*deriv.first + deriv.second*deriv.second);
williamr@2
   190
williamr@2
   191
          if (delta > delta_p) {
williamr@2
   192
            p = *ui;
williamr@2
   193
            delta_p = delta;
williamr@2
   194
          }
williamr@2
   195
        }
williamr@2
   196
williamr@2
   197
        while (!done(delta_p, p, g, true)) {
williamr@2
   198
          // The contribution p makes to the partial derivatives of
williamr@2
   199
          // each vertex. Computing this (at O(n) cost) allows us to
williamr@2
   200
          // update the delta_i values in O(n) time instead of O(n^2)
williamr@2
   201
          // time.
williamr@2
   202
          std::vector<deriv_type> p_partials(num_vertices(g));
williamr@2
   203
          for (ui = vertices(g).first; ui != end; ++ui) {
williamr@2
   204
            vertex_descriptor i = *ui;
williamr@2
   205
            p_partials[get(index, i)] = compute_partial_derivative(i, p);
williamr@2
   206
          }
williamr@2
   207
williamr@2
   208
          do {
williamr@2
   209
            // Compute the 4 elements of the Jacobian
williamr@2
   210
            weight_type dE_dx_dx = 0, dE_dx_dy = 0, dE_dy_dx = 0, dE_dy_dy = 0;
williamr@2
   211
            for (ui = vertices(g).first; ui != end; ++ui) {
williamr@2
   212
              vertex_descriptor i = *ui;
williamr@2
   213
              if (i != p) {
williamr@2
   214
                weight_type x_diff = position[p].x - position[i].x;
williamr@2
   215
                weight_type y_diff = position[p].y - position[i].y;
williamr@2
   216
                weight_type dist = sqrt(x_diff * x_diff + y_diff * y_diff);
williamr@2
   217
                weight_type dist_cubed = dist * dist * dist;
williamr@2
   218
                weight_type k_mi = spring_strength[get(index,p)][get(index,i)];
williamr@2
   219
                weight_type l_mi = distance[get(index, p)][get(index, i)];
williamr@2
   220
                dE_dx_dx += k_mi * (1 - (l_mi * y_diff * y_diff)/dist_cubed);
williamr@2
   221
                dE_dx_dy += k_mi * l_mi * x_diff * y_diff / dist_cubed;
williamr@2
   222
                dE_dy_dx += k_mi * l_mi * x_diff * y_diff / dist_cubed;
williamr@2
   223
                dE_dy_dy += k_mi * (1 - (l_mi * x_diff * x_diff)/dist_cubed);
williamr@2
   224
              }
williamr@2
   225
            }
williamr@2
   226
williamr@2
   227
            // Solve for delta_x and delta_y
williamr@2
   228
            weight_type dE_dx = get(partial_derivatives, p).first;
williamr@2
   229
            weight_type dE_dy = get(partial_derivatives, p).second;
williamr@2
   230
williamr@2
   231
            weight_type delta_x = 
williamr@2
   232
              (dE_dx_dy * dE_dy - dE_dy_dy * dE_dx)
williamr@2
   233
              / (dE_dx_dx * dE_dy_dy - dE_dx_dy * dE_dy_dx);
williamr@2
   234
williamr@2
   235
            weight_type delta_y = 
williamr@2
   236
              (dE_dx_dx * dE_dy - dE_dy_dx * dE_dx)
williamr@2
   237
              / (dE_dy_dx * dE_dx_dy - dE_dx_dx * dE_dy_dy);
williamr@2
   238
williamr@2
   239
williamr@2
   240
            // Move p by (delta_x, delta_y)
williamr@2
   241
            position[p].x += delta_x;
williamr@2
   242
            position[p].y += delta_y;
williamr@2
   243
williamr@2
   244
            // Recompute partial derivatives and delta_p
williamr@2
   245
            deriv_type deriv = compute_partial_derivatives(p);
williamr@2
   246
            put(partial_derivatives, p, deriv);
williamr@2
   247
williamr@2
   248
            delta_p = 
williamr@2
   249
              sqrt(deriv.first*deriv.first + deriv.second*deriv.second);
williamr@2
   250
          } while (!done(delta_p, p, g, false));
williamr@2
   251
williamr@2
   252
          // Select new p by updating each partial derivative and delta
williamr@2
   253
          vertex_descriptor old_p = p;
williamr@2
   254
          for (ui = vertices(g).first; ui != end; ++ui) {
williamr@2
   255
            deriv_type old_deriv_p = p_partials[get(index, *ui)];
williamr@2
   256
            deriv_type old_p_partial = 
williamr@2
   257
              compute_partial_derivative(*ui, old_p);
williamr@2
   258
            deriv_type deriv = get(partial_derivatives, *ui);
williamr@2
   259
williamr@2
   260
            deriv.first += old_p_partial.first - old_deriv_p.first;
williamr@2
   261
            deriv.second += old_p_partial.second - old_deriv_p.second;
williamr@2
   262
williamr@2
   263
            put(partial_derivatives, *ui, deriv);
williamr@2
   264
            weight_type delta = 
williamr@2
   265
              sqrt(deriv.first*deriv.first + deriv.second*deriv.second);
williamr@2
   266
williamr@2
   267
            if (delta > delta_p) {
williamr@2
   268
              p = *ui;
williamr@2
   269
              delta_p = delta;
williamr@2
   270
            }
williamr@2
   271
          }
williamr@2
   272
        }
williamr@2
   273
williamr@2
   274
        return true;
williamr@2
   275
      }
williamr@2
   276
williamr@2
   277
      const Graph& g; 
williamr@2
   278
      PositionMap position;
williamr@2
   279
      WeightMap weight; 
williamr@2
   280
      EdgeOrSideLength edge_or_side_length;
williamr@2
   281
      Done done;
williamr@2
   282
      weight_type spring_constant;
williamr@2
   283
      VertexIndexMap index;
williamr@2
   284
      DistanceMatrix distance;
williamr@2
   285
      SpringStrengthMatrix spring_strength;
williamr@2
   286
      PartialDerivativeMap partial_derivatives;
williamr@2
   287
    };
williamr@2
   288
  } } // end namespace detail::graph
williamr@2
   289
williamr@2
   290
  /// States that the given quantity is an edge length.
williamr@2
   291
  template<typename T> 
williamr@2
   292
  inline detail::graph::edge_or_side<true, T>
williamr@2
   293
  edge_length(T x) 
williamr@2
   294
  { return detail::graph::edge_or_side<true, T>(x); }
williamr@2
   295
williamr@2
   296
  /// States that the given quantity is a display area side length.
williamr@2
   297
  template<typename T> 
williamr@2
   298
  inline detail::graph::edge_or_side<false, T>
williamr@2
   299
  side_length(T x) 
williamr@2
   300
  { return detail::graph::edge_or_side<false, T>(x); }
williamr@2
   301
williamr@2
   302
  /** 
williamr@2
   303
   * \brief Determines when to terminate layout of a particular graph based
williamr@2
   304
   * on a given relative tolerance. 
williamr@2
   305
   */
williamr@2
   306
  template<typename T = double>
williamr@2
   307
  struct layout_tolerance
williamr@2
   308
  {
williamr@2
   309
    layout_tolerance(const T& tolerance = T(0.001))
williamr@2
   310
      : tolerance(tolerance), last_energy((std::numeric_limits<T>::max)()),
williamr@2
   311
        last_local_energy((std::numeric_limits<T>::max)()) { }
williamr@2
   312
williamr@2
   313
    template<typename Graph>
williamr@2
   314
    bool 
williamr@2
   315
    operator()(T delta_p, 
williamr@2
   316
               typename boost::graph_traits<Graph>::vertex_descriptor p,
williamr@2
   317
               const Graph& g,
williamr@2
   318
               bool global)
williamr@2
   319
    {
williamr@2
   320
      if (global) {
williamr@2
   321
        if (last_energy == (std::numeric_limits<T>::max)()) {
williamr@2
   322
          last_energy = delta_p;
williamr@2
   323
          return false;
williamr@2
   324
        }
williamr@2
   325
          
williamr@2
   326
        T diff = last_energy - delta_p;
williamr@2
   327
        if (diff < T(0)) diff = -diff;
williamr@2
   328
        bool done = (delta_p == T(0) || diff / last_energy < tolerance);
williamr@2
   329
        last_energy = delta_p;
williamr@2
   330
        return done;
williamr@2
   331
      } else {
williamr@2
   332
        if (last_local_energy == (std::numeric_limits<T>::max)()) {
williamr@2
   333
          last_local_energy = delta_p;
williamr@2
   334
          return delta_p == T(0);
williamr@2
   335
        }
williamr@2
   336
          
williamr@2
   337
        T diff = last_local_energy - delta_p;
williamr@2
   338
        bool done = (delta_p == T(0) || (diff / last_local_energy) < tolerance);
williamr@2
   339
        last_local_energy = delta_p;
williamr@2
   340
        return done;
williamr@2
   341
      }
williamr@2
   342
    }
williamr@2
   343
williamr@2
   344
  private:
williamr@2
   345
    T tolerance;
williamr@2
   346
    T last_energy;
williamr@2
   347
    T last_local_energy;
williamr@2
   348
  };
williamr@2
   349
williamr@2
   350
  /** \brief Kamada-Kawai spring layout for undirected graphs.
williamr@2
   351
   *
williamr@2
   352
   * This algorithm performs graph layout (in two dimensions) for
williamr@2
   353
   * connected, undirected graphs. It operates by relating the layout
williamr@2
   354
   * of graphs to a dynamic spring system and minimizing the energy
williamr@2
   355
   * within that system. The strength of a spring between two vertices
williamr@2
   356
   * is inversely proportional to the square of the shortest distance
williamr@2
   357
   * (in graph terms) between those two vertices. Essentially,
williamr@2
   358
   * vertices that are closer in the graph-theoretic sense (i.e., by
williamr@2
   359
   * following edges) will have stronger springs and will therefore be
williamr@2
   360
   * placed closer together.
williamr@2
   361
   *
williamr@2
   362
   * Prior to invoking this algorithm, it is recommended that the
williamr@2
   363
   * vertices be placed along the vertices of a regular n-sided
williamr@2
   364
   * polygon.
williamr@2
   365
   *
williamr@2
   366
   * \param g (IN) must be a model of Vertex List Graph, Edge List
williamr@2
   367
   * Graph, and Incidence Graph and must be undirected.
williamr@2
   368
   *
williamr@2
   369
   * \param position (OUT) must be a model of Lvalue Property Map,
williamr@2
   370
   * where the value type is a class containing fields @c x and @c y
williamr@2
   371
   * that will be set to the @c x and @c y coordinates of each vertex.
williamr@2
   372
   *
williamr@2
   373
   * \param weight (IN) must be a model of Readable Property Map,
williamr@2
   374
   * which provides the weight of each edge in the graph @p g.
williamr@2
   375
   *
williamr@2
   376
   * \param edge_or_side_length (IN) provides either the unit length
williamr@2
   377
   * @c e of an edge in the layout or the length of a side @c s of the
williamr@2
   378
   * display area, and must be either @c boost::edge_length(e) or @c
williamr@2
   379
   * boost::side_length(s), respectively.
williamr@2
   380
   *
williamr@2
   381
   * \param done (IN) is a 4-argument function object that is passed
williamr@2
   382
   * the current value of delta_p (i.e., the energy of vertex @p p),
williamr@2
   383
   * the vertex @p p, the graph @p g, and a boolean flag indicating
williamr@2
   384
   * whether @p delta_p is the maximum energy in the system (when @c
williamr@2
   385
   * true) or the energy of the vertex being moved. Defaults to @c
williamr@2
   386
   * layout_tolerance instantiated over the value type of the weight
williamr@2
   387
   * map.
williamr@2
   388
   *
williamr@2
   389
   * \param spring_constant (IN) is the constant multiplied by each
williamr@2
   390
   * spring's strength. Larger values create systems with more energy
williamr@2
   391
   * that can take longer to stabilize; smaller values create systems
williamr@2
   392
   * with less energy that stabilize quickly but do not necessarily
williamr@2
   393
   * result in pleasing layouts. The default value is 1.
williamr@2
   394
   *
williamr@2
   395
   * \param index (IN) is a mapping from vertices to index values
williamr@2
   396
   * between 0 and @c num_vertices(g). The default is @c
williamr@2
   397
   * get(vertex_index,g).
williamr@2
   398
   *
williamr@2
   399
   * \param distance (UTIL/OUT) will be used to store the distance
williamr@2
   400
   * from every vertex to every other vertex, which is computed in the
williamr@2
   401
   * first stages of the algorithm. This value's type must be a model
williamr@2
   402
   * of BasicMatrix with value type equal to the value type of the
williamr@2
   403
   * weight map. The default is a a vector of vectors.
williamr@2
   404
   *
williamr@2
   405
   * \param spring_strength (UTIL/OUT) will be used to store the
williamr@2
   406
   * strength of the spring between every pair of vertices. This
williamr@2
   407
   * value's type must be a model of BasicMatrix with value type equal
williamr@2
   408
   * to the value type of the weight map. The default is a a vector of
williamr@2
   409
   * vectors.
williamr@2
   410
   *
williamr@2
   411
   * \param partial_derivatives (UTIL) will be used to store the
williamr@2
   412
   * partial derivates of each vertex with respect to the @c x and @c
williamr@2
   413
   * y coordinates. This must be a Read/Write Property Map whose value
williamr@2
   414
   * type is a pair with both types equivalent to the value type of
williamr@2
   415
   * the weight map. The default is an iterator property map.
williamr@2
   416
   *
williamr@2
   417
   * \returns @c true if layout was successful or @c false if a
williamr@2
   418
   * negative weight cycle was detected.
williamr@2
   419
   */
williamr@2
   420
  template<typename Graph, typename PositionMap, typename WeightMap,
williamr@2
   421
           typename T, bool EdgeOrSideLength, typename Done,
williamr@2
   422
           typename VertexIndexMap, typename DistanceMatrix,
williamr@2
   423
           typename SpringStrengthMatrix, typename PartialDerivativeMap>
williamr@2
   424
  bool 
williamr@2
   425
  kamada_kawai_spring_layout(
williamr@2
   426
    const Graph& g, 
williamr@2
   427
    PositionMap position,
williamr@2
   428
    WeightMap weight, 
williamr@2
   429
    detail::graph::edge_or_side<EdgeOrSideLength, T> edge_or_side_length,
williamr@2
   430
    Done done,
williamr@2
   431
    typename property_traits<WeightMap>::value_type spring_constant,
williamr@2
   432
    VertexIndexMap index,
williamr@2
   433
    DistanceMatrix distance,
williamr@2
   434
    SpringStrengthMatrix spring_strength,
williamr@2
   435
    PartialDerivativeMap partial_derivatives)
williamr@2
   436
  {
williamr@2
   437
    BOOST_STATIC_ASSERT((is_convertible<
williamr@2
   438
                           typename graph_traits<Graph>::directed_category*,
williamr@2
   439
                           undirected_tag*
williamr@2
   440
                         >::value));
williamr@2
   441
williamr@2
   442
    detail::graph::kamada_kawai_spring_layout_impl<
williamr@2
   443
      Graph, PositionMap, WeightMap, 
williamr@2
   444
      detail::graph::edge_or_side<EdgeOrSideLength, T>, Done, VertexIndexMap, 
williamr@2
   445
      DistanceMatrix, SpringStrengthMatrix, PartialDerivativeMap>
williamr@2
   446
      alg(g, position, weight, edge_or_side_length, done, spring_constant,
williamr@2
   447
          index, distance, spring_strength, partial_derivatives);
williamr@2
   448
    return alg.run();
williamr@2
   449
  }
williamr@2
   450
williamr@2
   451
  /**
williamr@2
   452
   * \overload
williamr@2
   453
   */
williamr@2
   454
  template<typename Graph, typename PositionMap, typename WeightMap,
williamr@2
   455
           typename T, bool EdgeOrSideLength, typename Done, 
williamr@2
   456
           typename VertexIndexMap>
williamr@2
   457
  bool 
williamr@2
   458
  kamada_kawai_spring_layout(
williamr@2
   459
    const Graph& g, 
williamr@2
   460
    PositionMap position,
williamr@2
   461
    WeightMap weight, 
williamr@2
   462
    detail::graph::edge_or_side<EdgeOrSideLength, T> edge_or_side_length,
williamr@2
   463
    Done done,
williamr@2
   464
    typename property_traits<WeightMap>::value_type spring_constant,
williamr@2
   465
    VertexIndexMap index)
williamr@2
   466
  {
williamr@2
   467
    typedef typename property_traits<WeightMap>::value_type weight_type;
williamr@2
   468
williamr@2
   469
    typename graph_traits<Graph>::vertices_size_type n = num_vertices(g);
williamr@2
   470
    typedef std::vector<weight_type> weight_vec;
williamr@2
   471
williamr@2
   472
    std::vector<weight_vec> distance(n, weight_vec(n));
williamr@2
   473
    std::vector<weight_vec> spring_strength(n, weight_vec(n));
williamr@2
   474
    std::vector<std::pair<weight_type, weight_type> > partial_derivatives(n);
williamr@2
   475
williamr@2
   476
    return 
williamr@2
   477
      kamada_kawai_spring_layout(
williamr@2
   478
        g, position, weight, edge_or_side_length, done, spring_constant, index,
williamr@2
   479
        distance.begin(),
williamr@2
   480
        spring_strength.begin(),
williamr@2
   481
        make_iterator_property_map(partial_derivatives.begin(), index,
williamr@2
   482
                                   std::pair<weight_type, weight_type>()));
williamr@2
   483
  }
williamr@2
   484
williamr@2
   485
  /**
williamr@2
   486
   * \overload
williamr@2
   487
   */
williamr@2
   488
  template<typename Graph, typename PositionMap, typename WeightMap,
williamr@2
   489
           typename T, bool EdgeOrSideLength, typename Done>
williamr@2
   490
  bool 
williamr@2
   491
  kamada_kawai_spring_layout(
williamr@2
   492
    const Graph& g, 
williamr@2
   493
    PositionMap position,
williamr@2
   494
    WeightMap weight, 
williamr@2
   495
    detail::graph::edge_or_side<EdgeOrSideLength, T> edge_or_side_length,
williamr@2
   496
    Done done,
williamr@2
   497
    typename property_traits<WeightMap>::value_type spring_constant)
williamr@2
   498
  {
williamr@2
   499
    return kamada_kawai_spring_layout(g, position, weight, edge_or_side_length,
williamr@2
   500
                                      done, spring_constant, 
williamr@2
   501
                                      get(vertex_index, g));
williamr@2
   502
  }
williamr@2
   503
williamr@2
   504
  /**
williamr@2
   505
   * \overload
williamr@2
   506
   */
williamr@2
   507
  template<typename Graph, typename PositionMap, typename WeightMap,
williamr@2
   508
           typename T, bool EdgeOrSideLength, typename Done>
williamr@2
   509
  bool 
williamr@2
   510
  kamada_kawai_spring_layout(
williamr@2
   511
    const Graph& g, 
williamr@2
   512
    PositionMap position,
williamr@2
   513
    WeightMap weight, 
williamr@2
   514
    detail::graph::edge_or_side<EdgeOrSideLength, T> edge_or_side_length,
williamr@2
   515
    Done done)
williamr@2
   516
  {
williamr@2
   517
    typedef typename property_traits<WeightMap>::value_type weight_type;
williamr@2
   518
    return kamada_kawai_spring_layout(g, position, weight, edge_or_side_length,
williamr@2
   519
                                      done, weight_type(1)); 
williamr@2
   520
  }
williamr@2
   521
williamr@2
   522
  /**
williamr@2
   523
   * \overload
williamr@2
   524
   */
williamr@2
   525
  template<typename Graph, typename PositionMap, typename WeightMap,
williamr@2
   526
           typename T, bool EdgeOrSideLength>
williamr@2
   527
  bool 
williamr@2
   528
  kamada_kawai_spring_layout(
williamr@2
   529
    const Graph& g, 
williamr@2
   530
    PositionMap position,
williamr@2
   531
    WeightMap weight, 
williamr@2
   532
    detail::graph::edge_or_side<EdgeOrSideLength, T> edge_or_side_length)
williamr@2
   533
  {
williamr@2
   534
    typedef typename property_traits<WeightMap>::value_type weight_type;
williamr@2
   535
    return kamada_kawai_spring_layout(g, position, weight, edge_or_side_length,
williamr@2
   536
                                      layout_tolerance<weight_type>(),
williamr@2
   537
                                      weight_type(1.0), 
williamr@2
   538
                                      get(vertex_index, g));
williamr@2
   539
  }
williamr@2
   540
} // end namespace boost
williamr@2
   541
williamr@2
   542
#endif // BOOST_GRAPH_KAMADA_KAWAI_SPRING_LAYOUT_HPP