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