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