os/ossrv/ossrv_pub/boost_apis/boost/graph/fruchterman_reingold.hpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright 2004 The Trustees of Indiana University.
sl@0
     2
sl@0
     3
// Distributed under the Boost Software License, Version 1.0.
sl@0
     4
// (See accompanying file LICENSE_1_0.txt or copy at
sl@0
     5
// http://www.boost.org/LICENSE_1_0.txt)
sl@0
     6
sl@0
     7
//  Authors: Douglas Gregor
sl@0
     8
//           Andrew Lumsdaine
sl@0
     9
#ifndef BOOST_GRAPH_FRUCHTERMAN_REINGOLD_FORCE_DIRECTED_LAYOUT_HPP
sl@0
    10
#define BOOST_GRAPH_FRUCHTERMAN_REINGOLD_FORCE_DIRECTED_LAYOUT_HPP
sl@0
    11
sl@0
    12
#include <cmath>
sl@0
    13
#include <boost/graph/graph_traits.hpp>
sl@0
    14
#include <boost/graph/named_function_params.hpp>
sl@0
    15
#include <boost/graph/simple_point.hpp>
sl@0
    16
#include <vector>
sl@0
    17
#include <list>
sl@0
    18
#include <algorithm> // for std::min and std::max
sl@0
    19
sl@0
    20
namespace boost {
sl@0
    21
sl@0
    22
struct square_distance_attractive_force {
sl@0
    23
  template<typename Graph, typename T>
sl@0
    24
  T
sl@0
    25
  operator()(typename graph_traits<Graph>::edge_descriptor,
sl@0
    26
             T k,
sl@0
    27
             T d,
sl@0
    28
             const Graph&) const
sl@0
    29
  {
sl@0
    30
    return d * d / k;
sl@0
    31
  }
sl@0
    32
};
sl@0
    33
sl@0
    34
struct square_distance_repulsive_force {
sl@0
    35
  template<typename Graph, typename T>
sl@0
    36
  T
sl@0
    37
  operator()(typename graph_traits<Graph>::vertex_descriptor,
sl@0
    38
             typename graph_traits<Graph>::vertex_descriptor,
sl@0
    39
             T k,
sl@0
    40
             T d,
sl@0
    41
             const Graph&) const
sl@0
    42
  {
sl@0
    43
    return k * k / d;
sl@0
    44
  }
sl@0
    45
};
sl@0
    46
sl@0
    47
template<typename T>
sl@0
    48
struct linear_cooling {
sl@0
    49
  typedef T result_type;
sl@0
    50
sl@0
    51
  linear_cooling(std::size_t iterations)
sl@0
    52
    : temp(T(iterations) / T(10)), step(0.1) { }
sl@0
    53
sl@0
    54
  linear_cooling(std::size_t iterations, T temp)
sl@0
    55
    : temp(temp), step(temp / T(iterations)) { }
sl@0
    56
sl@0
    57
  T operator()()
sl@0
    58
  {
sl@0
    59
    T old_temp = temp;
sl@0
    60
    temp -= step;
sl@0
    61
    if (temp < T(0)) temp = T(0);
sl@0
    62
    return old_temp;
sl@0
    63
  }
sl@0
    64
sl@0
    65
 private:
sl@0
    66
  T temp;
sl@0
    67
  T step;
sl@0
    68
};
sl@0
    69
sl@0
    70
struct all_force_pairs
sl@0
    71
{
sl@0
    72
  template<typename Graph, typename ApplyForce >
sl@0
    73
  void operator()(const Graph& g, ApplyForce apply_force)
sl@0
    74
  {
sl@0
    75
    typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
sl@0
    76
    vertex_iterator v, end;
sl@0
    77
    for (tie(v, end) = vertices(g); v != end; ++v) {
sl@0
    78
      vertex_iterator u = v;
sl@0
    79
      for (++u; u != end; ++u) {
sl@0
    80
        apply_force(*u, *v);
sl@0
    81
        apply_force(*v, *u);
sl@0
    82
      }
sl@0
    83
    }
sl@0
    84
  }
sl@0
    85
};
sl@0
    86
sl@0
    87
template<typename Dim, typename PositionMap>
sl@0
    88
struct grid_force_pairs
sl@0
    89
{
sl@0
    90
  template<typename Graph>
sl@0
    91
  explicit
sl@0
    92
  grid_force_pairs(Dim width, Dim height, PositionMap position, const Graph& g)
sl@0
    93
    : width(width), height(height), position(position)
sl@0
    94
  {
sl@0
    95
#ifndef BOOST_NO_STDC_NAMESPACE
sl@0
    96
    using std::sqrt;
sl@0
    97
#endif // BOOST_NO_STDC_NAMESPACE
sl@0
    98
    two_k = Dim(2) * sqrt(width*height / num_vertices(g));
sl@0
    99
  }
sl@0
   100
sl@0
   101
  template<typename Graph, typename ApplyForce >
sl@0
   102
  void operator()(const Graph& g, ApplyForce apply_force)
sl@0
   103
  {
sl@0
   104
    typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
sl@0
   105
    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
sl@0
   106
    typedef std::list<vertex_descriptor> bucket_t;
sl@0
   107
    typedef std::vector<bucket_t> buckets_t;
sl@0
   108
sl@0
   109
    std::size_t columns = std::size_t(width / two_k + Dim(1));
sl@0
   110
    std::size_t rows = std::size_t(height / two_k + Dim(1));
sl@0
   111
    buckets_t buckets(rows * columns);
sl@0
   112
    vertex_iterator v, v_end;
sl@0
   113
    for (tie(v, v_end) = vertices(g); v != v_end; ++v) {
sl@0
   114
      std::size_t column = std::size_t((position[*v].x + width  / 2) / two_k);
sl@0
   115
      std::size_t row    = std::size_t((position[*v].y + height / 2) / two_k);
sl@0
   116
sl@0
   117
      if (column >= columns) column = columns - 1;
sl@0
   118
      if (row >= rows) row = rows - 1;
sl@0
   119
      buckets[row * columns + column].push_back(*v);
sl@0
   120
    }
sl@0
   121
sl@0
   122
    for (std::size_t row = 0; row < rows; ++row)
sl@0
   123
      for (std::size_t column = 0; column < columns; ++column) {
sl@0
   124
        bucket_t& bucket = buckets[row * columns + column];
sl@0
   125
        typedef typename bucket_t::iterator bucket_iterator;
sl@0
   126
        for (bucket_iterator u = bucket.begin(); u != bucket.end(); ++u) {
sl@0
   127
          // Repulse vertices in this bucket
sl@0
   128
          bucket_iterator v = u;
sl@0
   129
          for (++v; v != bucket.end(); ++v) {
sl@0
   130
            apply_force(*u, *v);
sl@0
   131
            apply_force(*v, *u);
sl@0
   132
          }
sl@0
   133
sl@0
   134
          std::size_t adj_start_row = row == 0? 0 : row - 1;
sl@0
   135
          std::size_t adj_end_row = row == rows - 1? row : row + 1;
sl@0
   136
          std::size_t adj_start_column = column == 0? 0 : column - 1;
sl@0
   137
          std::size_t adj_end_column = column == columns - 1? column : column + 1;
sl@0
   138
          for (std::size_t other_row = adj_start_row; other_row <= adj_end_row;
sl@0
   139
               ++other_row)
sl@0
   140
            for (std::size_t other_column = adj_start_column; 
sl@0
   141
                 other_column <= adj_end_column; ++other_column)
sl@0
   142
              if (other_row != row || other_column != column) {
sl@0
   143
                // Repulse vertices in this bucket
sl@0
   144
                bucket_t& other_bucket 
sl@0
   145
                  = buckets[other_row * columns + other_column];
sl@0
   146
                for (v = other_bucket.begin(); v != other_bucket.end(); ++v)
sl@0
   147
                  apply_force(*u, *v);
sl@0
   148
              }
sl@0
   149
        }
sl@0
   150
      }
sl@0
   151
  }
sl@0
   152
sl@0
   153
 private:
sl@0
   154
  Dim width;
sl@0
   155
  Dim height;
sl@0
   156
  PositionMap position;
sl@0
   157
  Dim two_k;
sl@0
   158
};
sl@0
   159
sl@0
   160
template<typename Dim, typename PositionMap, typename Graph>
sl@0
   161
inline grid_force_pairs<Dim, PositionMap>
sl@0
   162
make_grid_force_pairs(Dim width, Dim height, const PositionMap& position,
sl@0
   163
                      const Graph& g)
sl@0
   164
{ return grid_force_pairs<Dim, PositionMap>(width, height, position, g); }
sl@0
   165
sl@0
   166
template<typename Graph, typename PositionMap, typename Dim>
sl@0
   167
void
sl@0
   168
scale_graph(const Graph& g, PositionMap position,
sl@0
   169
            Dim left, Dim top, Dim right, Dim bottom)
sl@0
   170
{
sl@0
   171
  if (num_vertices(g) == 0) return;
sl@0
   172
sl@0
   173
  if (bottom > top) {
sl@0
   174
    using std::swap;
sl@0
   175
    swap(bottom, top);
sl@0
   176
  }
sl@0
   177
sl@0
   178
  typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
sl@0
   179
sl@0
   180
  // Find min/max ranges
sl@0
   181
  Dim minX = position[*vertices(g).first].x, maxX = minX;
sl@0
   182
  Dim minY = position[*vertices(g).first].y, maxY = minY;
sl@0
   183
  vertex_iterator vi, vi_end;
sl@0
   184
  for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
sl@0
   185
    BOOST_USING_STD_MIN();
sl@0
   186
    BOOST_USING_STD_MAX();
sl@0
   187
    minX = min BOOST_PREVENT_MACRO_SUBSTITUTION (minX, position[*vi].x);
sl@0
   188
    maxX = max BOOST_PREVENT_MACRO_SUBSTITUTION (maxX, position[*vi].x);
sl@0
   189
    minY = min BOOST_PREVENT_MACRO_SUBSTITUTION (minY, position[*vi].y);
sl@0
   190
    maxY = max BOOST_PREVENT_MACRO_SUBSTITUTION (maxY, position[*vi].y);
sl@0
   191
  }
sl@0
   192
sl@0
   193
  // Scale to bounding box provided
sl@0
   194
  for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
sl@0
   195
    position[*vi].x = ((position[*vi].x - minX) / (maxX - minX))
sl@0
   196
                    * (right - left) + left;
sl@0
   197
    position[*vi].y = ((position[*vi].y - minY) / (maxY - minY))
sl@0
   198
                    * (top - bottom) + bottom;
sl@0
   199
  }
sl@0
   200
}
sl@0
   201
sl@0
   202
namespace detail {
sl@0
   203
  template<typename PositionMap, typename DisplacementMap,
sl@0
   204
           typename RepulsiveForce, typename Dim, typename Graph>
sl@0
   205
  struct fr_apply_force
sl@0
   206
  {
sl@0
   207
    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
sl@0
   208
sl@0
   209
    fr_apply_force(const PositionMap& position,
sl@0
   210
                   const DisplacementMap& displacement,
sl@0
   211
                   RepulsiveForce repulsive_force, Dim k, const Graph& g)
sl@0
   212
      : position(position), displacement(displacement),
sl@0
   213
        repulsive_force(repulsive_force), k(k), g(g)
sl@0
   214
    { }
sl@0
   215
sl@0
   216
    void operator()(vertex_descriptor u, vertex_descriptor v)
sl@0
   217
    {
sl@0
   218
#ifndef BOOST_NO_STDC_NAMESPACE
sl@0
   219
      using std::sqrt;
sl@0
   220
#endif // BOOST_NO_STDC_NAMESPACE
sl@0
   221
      if (u != v) {
sl@0
   222
        Dim delta_x = position[v].x - position[u].x;
sl@0
   223
        Dim delta_y = position[v].y - position[u].y;
sl@0
   224
        Dim dist = sqrt(delta_x * delta_x + delta_y * delta_y);
sl@0
   225
        Dim fr = repulsive_force(u, v, k, dist, g);
sl@0
   226
        displacement[v].x += delta_x / dist * fr;
sl@0
   227
        displacement[v].y += delta_y / dist * fr;
sl@0
   228
      }
sl@0
   229
    }
sl@0
   230
sl@0
   231
  private:
sl@0
   232
    PositionMap position;
sl@0
   233
    DisplacementMap displacement;
sl@0
   234
    RepulsiveForce repulsive_force;
sl@0
   235
    Dim k;
sl@0
   236
    const Graph& g;
sl@0
   237
  };
sl@0
   238
sl@0
   239
} // end namespace detail
sl@0
   240
sl@0
   241
template<typename Graph, typename PositionMap, typename Dim,
sl@0
   242
         typename AttractiveForce, typename RepulsiveForce,
sl@0
   243
         typename ForcePairs, typename Cooling, typename DisplacementMap>
sl@0
   244
void
sl@0
   245
fruchterman_reingold_force_directed_layout
sl@0
   246
 (const Graph&    g,
sl@0
   247
  PositionMap     position,
sl@0
   248
  Dim             width,
sl@0
   249
  Dim             height,
sl@0
   250
  AttractiveForce attractive_force,
sl@0
   251
  RepulsiveForce  repulsive_force,
sl@0
   252
  ForcePairs      force_pairs,
sl@0
   253
  Cooling         cool,
sl@0
   254
  DisplacementMap displacement)
sl@0
   255
{
sl@0
   256
  typedef typename graph_traits<Graph>::vertex_iterator   vertex_iterator;
sl@0
   257
  typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
sl@0
   258
  typedef typename graph_traits<Graph>::edge_iterator     edge_iterator;
sl@0
   259
sl@0
   260
#ifndef BOOST_NO_STDC_NAMESPACE
sl@0
   261
  using std::sqrt;
sl@0
   262
#endif // BOOST_NO_STDC_NAMESPACE
sl@0
   263
sl@0
   264
  Dim area = width * height;
sl@0
   265
  // assume positions are initialized randomly
sl@0
   266
  Dim k = sqrt(area / num_vertices(g));
sl@0
   267
sl@0
   268
  detail::fr_apply_force<PositionMap, DisplacementMap,
sl@0
   269
                         RepulsiveForce, Dim, Graph>
sl@0
   270
    apply_force(position, displacement, repulsive_force, k, g);
sl@0
   271
sl@0
   272
  Dim temp = cool();
sl@0
   273
  if (temp) do {
sl@0
   274
    // Calculate repulsive forces
sl@0
   275
    vertex_iterator v, v_end;
sl@0
   276
    for (tie(v, v_end) = vertices(g); v != v_end; ++v) {
sl@0
   277
      displacement[*v].x = 0;
sl@0
   278
      displacement[*v].y = 0;
sl@0
   279
    }
sl@0
   280
    force_pairs(g, apply_force);
sl@0
   281
sl@0
   282
    // Calculate attractive forces
sl@0
   283
    edge_iterator e, e_end;
sl@0
   284
    for (tie(e, e_end) = edges(g); e != e_end; ++e) {
sl@0
   285
      vertex_descriptor v = source(*e, g);
sl@0
   286
      vertex_descriptor u = target(*e, g);
sl@0
   287
      Dim delta_x = position[v].x - position[u].x;
sl@0
   288
      Dim delta_y = position[v].y - position[u].y;
sl@0
   289
      Dim dist = sqrt(delta_x * delta_x + delta_y * delta_y);
sl@0
   290
      Dim fa = attractive_force(*e, k, dist, g);
sl@0
   291
sl@0
   292
      displacement[v].x -= delta_x / dist * fa;
sl@0
   293
      displacement[v].y -= delta_y / dist * fa;
sl@0
   294
      displacement[u].x += delta_x / dist * fa;
sl@0
   295
      displacement[u].y += delta_y / dist * fa;
sl@0
   296
    }
sl@0
   297
sl@0
   298
    // Update positions
sl@0
   299
    for (tie(v, v_end) = vertices(g); v != v_end; ++v) {
sl@0
   300
      BOOST_USING_STD_MIN();
sl@0
   301
      BOOST_USING_STD_MAX();
sl@0
   302
      Dim disp_size = sqrt(displacement[*v].x * displacement[*v].x
sl@0
   303
                           + displacement[*v].y * displacement[*v].y);
sl@0
   304
      position[*v].x += displacement[*v].x / disp_size 
sl@0
   305
                     * min BOOST_PREVENT_MACRO_SUBSTITUTION (disp_size, temp);
sl@0
   306
      position[*v].y += displacement[*v].y / disp_size 
sl@0
   307
                     * min BOOST_PREVENT_MACRO_SUBSTITUTION (disp_size, temp);
sl@0
   308
      position[*v].x = min BOOST_PREVENT_MACRO_SUBSTITUTION 
sl@0
   309
                         (width / 2, 
sl@0
   310
                          max BOOST_PREVENT_MACRO_SUBSTITUTION(-width / 2, 
sl@0
   311
                                                               position[*v].x));
sl@0
   312
      position[*v].y = min BOOST_PREVENT_MACRO_SUBSTITUTION
sl@0
   313
                         (height / 2, 
sl@0
   314
                          max BOOST_PREVENT_MACRO_SUBSTITUTION(-height / 2, 
sl@0
   315
                                                               position[*v].y));
sl@0
   316
    }
sl@0
   317
  } while (temp = cool());
sl@0
   318
}
sl@0
   319
sl@0
   320
namespace detail {
sl@0
   321
  template<typename DisplacementMap>
sl@0
   322
  struct fr_force_directed_layout
sl@0
   323
  {
sl@0
   324
    template<typename Graph, typename PositionMap, typename Dim,
sl@0
   325
             typename AttractiveForce, typename RepulsiveForce,
sl@0
   326
             typename ForcePairs, typename Cooling,
sl@0
   327
             typename Param, typename Tag, typename Rest>
sl@0
   328
    static void
sl@0
   329
    run(const Graph&    g,
sl@0
   330
        PositionMap     position,
sl@0
   331
        Dim             width,
sl@0
   332
        Dim             height,
sl@0
   333
        AttractiveForce attractive_force,
sl@0
   334
        RepulsiveForce  repulsive_force,
sl@0
   335
        ForcePairs      force_pairs,
sl@0
   336
        Cooling         cool,
sl@0
   337
        DisplacementMap displacement,
sl@0
   338
        const bgl_named_params<Param, Tag, Rest>&)
sl@0
   339
    {
sl@0
   340
      fruchterman_reingold_force_directed_layout
sl@0
   341
        (g, position, width, height, attractive_force, repulsive_force,
sl@0
   342
         force_pairs, cool, displacement);
sl@0
   343
    }
sl@0
   344
  };
sl@0
   345
sl@0
   346
  template<>
sl@0
   347
  struct fr_force_directed_layout<error_property_not_found>
sl@0
   348
  {
sl@0
   349
    template<typename Graph, typename PositionMap, typename Dim,
sl@0
   350
             typename AttractiveForce, typename RepulsiveForce,
sl@0
   351
             typename ForcePairs, typename Cooling,
sl@0
   352
             typename Param, typename Tag, typename Rest>
sl@0
   353
    static void
sl@0
   354
    run(const Graph&    g,
sl@0
   355
        PositionMap     position,
sl@0
   356
        Dim             width,
sl@0
   357
        Dim             height,
sl@0
   358
        AttractiveForce attractive_force,
sl@0
   359
        RepulsiveForce  repulsive_force,
sl@0
   360
        ForcePairs      force_pairs,
sl@0
   361
        Cooling         cool,
sl@0
   362
        error_property_not_found,
sl@0
   363
        const bgl_named_params<Param, Tag, Rest>& params)
sl@0
   364
    {
sl@0
   365
      std::vector<simple_point<Dim> > displacements(num_vertices(g));
sl@0
   366
      fruchterman_reingold_force_directed_layout
sl@0
   367
        (g, position, width, height, attractive_force, repulsive_force,
sl@0
   368
         force_pairs, cool,
sl@0
   369
         make_iterator_property_map
sl@0
   370
         (displacements.begin(),
sl@0
   371
          choose_const_pmap(get_param(params, vertex_index), g,
sl@0
   372
                            vertex_index),
sl@0
   373
          simple_point<Dim>()));
sl@0
   374
    }
sl@0
   375
  };
sl@0
   376
sl@0
   377
} // end namespace detail
sl@0
   378
sl@0
   379
template<typename Graph, typename PositionMap, typename Dim, typename Param,
sl@0
   380
         typename Tag, typename Rest>
sl@0
   381
void
sl@0
   382
fruchterman_reingold_force_directed_layout
sl@0
   383
  (const Graph&    g,
sl@0
   384
   PositionMap     position,
sl@0
   385
   Dim             width,
sl@0
   386
   Dim             height,
sl@0
   387
   const bgl_named_params<Param, Tag, Rest>& params)
sl@0
   388
{
sl@0
   389
  typedef typename property_value<bgl_named_params<Param,Tag,Rest>,
sl@0
   390
                                  vertex_displacement_t>::type D;
sl@0
   391
sl@0
   392
  detail::fr_force_directed_layout<D>::run
sl@0
   393
    (g, position, width, height,
sl@0
   394
     choose_param(get_param(params, attractive_force_t()),
sl@0
   395
                  square_distance_attractive_force()),
sl@0
   396
     choose_param(get_param(params, repulsive_force_t()),
sl@0
   397
                  square_distance_repulsive_force()),
sl@0
   398
     choose_param(get_param(params, force_pairs_t()),
sl@0
   399
                  make_grid_force_pairs(width, height, position, g)),
sl@0
   400
     choose_param(get_param(params, cooling_t()),
sl@0
   401
                  linear_cooling<Dim>(100)),
sl@0
   402
     get_param(params, vertex_displacement_t()),
sl@0
   403
     params);
sl@0
   404
}
sl@0
   405
sl@0
   406
template<typename Graph, typename PositionMap, typename Dim>
sl@0
   407
void
sl@0
   408
fruchterman_reingold_force_directed_layout(const Graph&    g,
sl@0
   409
                                           PositionMap     position,
sl@0
   410
                                           Dim             width,
sl@0
   411
                                           Dim             height)
sl@0
   412
{
sl@0
   413
  fruchterman_reingold_force_directed_layout
sl@0
   414
    (g, position, width, height,
sl@0
   415
     attractive_force(square_distance_attractive_force()));
sl@0
   416
}
sl@0
   417
sl@0
   418
} // end namespace boost
sl@0
   419
sl@0
   420
#endif // BOOST_GRAPH_FRUCHTERMAN_REINGOLD_FORCE_DIRECTED_LAYOUT_HPP