Back to home page

EIC code displayed by LXR

 
 

    


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

0001 // Copyright 2009 The Trustees of Indiana University.
0002 
0003 // Distributed under the Boost Software License, Version 1.0.
0004 // (See accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 //  Authors: Jeremiah Willcock
0008 //           Douglas Gregor
0009 //           Andrew Lumsdaine
0010 #ifndef BOOST_GRAPH_TOPOLOGY_HPP
0011 #define BOOST_GRAPH_TOPOLOGY_HPP
0012 
0013 #include <boost/config/no_tr1/cmath.hpp>
0014 #include <cmath>
0015 #include <boost/random/uniform_01.hpp>
0016 #include <boost/random/linear_congruential.hpp>
0017 #include <boost/math/constants/constants.hpp> // For root_two
0018 #include <boost/algorithm/minmax.hpp>
0019 #include <boost/config.hpp> // For BOOST_STATIC_CONSTANT
0020 #include <boost/math/special_functions/hypot.hpp>
0021 
0022 // Classes and concepts to represent points in a space, with distance and move
0023 // operations (used for Gurson-Atun layout), plus other things like bounding
0024 // boxes used for other layout algorithms.
0025 
0026 namespace boost
0027 {
0028 
0029 /***********************************************************
0030  * Topologies                                              *
0031  ***********************************************************/
0032 template < std::size_t Dims > class convex_topology
0033 {
0034 public: // For VisualAge C++
0035     struct point
0036     {
0037         BOOST_STATIC_CONSTANT(std::size_t, dimensions = Dims);
0038         point() {}
0039         double& operator[](std::size_t i) { return values[i]; }
0040         const double& operator[](std::size_t i) const { return values[i]; }
0041 
0042     private:
0043         double values[Dims];
0044     };
0045 
0046 public: // For VisualAge C++
0047     struct point_difference
0048     {
0049         BOOST_STATIC_CONSTANT(std::size_t, dimensions = Dims);
0050         point_difference()
0051         {
0052             for (std::size_t i = 0; i < Dims; ++i)
0053                 values[i] = 0.;
0054         }
0055         double& operator[](std::size_t i) { return values[i]; }
0056         const double& operator[](std::size_t i) const { return values[i]; }
0057 
0058         friend point_difference operator+(
0059             const point_difference& a, const point_difference& b)
0060         {
0061             point_difference result;
0062             for (std::size_t i = 0; i < Dims; ++i)
0063                 result[i] = a[i] + b[i];
0064             return result;
0065         }
0066 
0067         friend point_difference& operator+=(
0068             point_difference& a, const point_difference& b)
0069         {
0070             for (std::size_t i = 0; i < Dims; ++i)
0071                 a[i] += b[i];
0072             return a;
0073         }
0074 
0075         friend point_difference operator-(const point_difference& a)
0076         {
0077             point_difference result;
0078             for (std::size_t i = 0; i < Dims; ++i)
0079                 result[i] = -a[i];
0080             return result;
0081         }
0082 
0083         friend point_difference operator-(
0084             const point_difference& a, const point_difference& b)
0085         {
0086             point_difference result;
0087             for (std::size_t i = 0; i < Dims; ++i)
0088                 result[i] = a[i] - b[i];
0089             return result;
0090         }
0091 
0092         friend point_difference& operator-=(
0093             point_difference& a, const point_difference& b)
0094         {
0095             for (std::size_t i = 0; i < Dims; ++i)
0096                 a[i] -= b[i];
0097             return a;
0098         }
0099 
0100         friend point_difference operator*(
0101             const point_difference& a, const point_difference& b)
0102         {
0103             point_difference result;
0104             for (std::size_t i = 0; i < Dims; ++i)
0105                 result[i] = a[i] * b[i];
0106             return result;
0107         }
0108 
0109         friend point_difference operator*(const point_difference& a, double b)
0110         {
0111             point_difference result;
0112             for (std::size_t i = 0; i < Dims; ++i)
0113                 result[i] = a[i] * b;
0114             return result;
0115         }
0116 
0117         friend point_difference operator*(double a, const point_difference& b)
0118         {
0119             point_difference result;
0120             for (std::size_t i = 0; i < Dims; ++i)
0121                 result[i] = a * b[i];
0122             return result;
0123         }
0124 
0125         friend point_difference operator/(
0126             const point_difference& a, const point_difference& b)
0127         {
0128             point_difference result;
0129             for (std::size_t i = 0; i < Dims; ++i)
0130                 result[i] = (b[i] == 0.) ? 0. : a[i] / b[i];
0131             return result;
0132         }
0133 
0134         friend double dot(const point_difference& a, const point_difference& b)
0135         {
0136             double result = 0;
0137             for (std::size_t i = 0; i < Dims; ++i)
0138                 result += a[i] * b[i];
0139             return result;
0140         }
0141 
0142     private:
0143         double values[Dims];
0144     };
0145 
0146 public:
0147     typedef point point_type;
0148     typedef point_difference point_difference_type;
0149 
0150     double distance(point a, point b) const
0151     {
0152         double dist = 0.;
0153         for (std::size_t i = 0; i < Dims; ++i)
0154         {
0155             double diff = b[i] - a[i];
0156             dist = boost::math::hypot(dist, diff);
0157         }
0158         // Exact properties of the distance are not important, as long as
0159         // < on what this returns matches real distances; l_2 is used because
0160         // Fruchterman-Reingold also uses this code and it relies on l_2.
0161         return dist;
0162     }
0163 
0164     point move_position_toward(point a, double fraction, point b) const
0165     {
0166         point result;
0167         for (std::size_t i = 0; i < Dims; ++i)
0168             result[i] = a[i] + (b[i] - a[i]) * fraction;
0169         return result;
0170     }
0171 
0172     point_difference difference(point a, point b) const
0173     {
0174         point_difference result;
0175         for (std::size_t i = 0; i < Dims; ++i)
0176             result[i] = a[i] - b[i];
0177         return result;
0178     }
0179 
0180     point adjust(point a, point_difference delta) const
0181     {
0182         point result;
0183         for (std::size_t i = 0; i < Dims; ++i)
0184             result[i] = a[i] + delta[i];
0185         return result;
0186     }
0187 
0188     point pointwise_min(point a, point b) const
0189     {
0190         BOOST_USING_STD_MIN();
0191         point result;
0192         for (std::size_t i = 0; i < Dims; ++i)
0193             result[i] = min BOOST_PREVENT_MACRO_SUBSTITUTION(a[i], b[i]);
0194         return result;
0195     }
0196 
0197     point pointwise_max(point a, point b) const
0198     {
0199         BOOST_USING_STD_MAX();
0200         point result;
0201         for (std::size_t i = 0; i < Dims; ++i)
0202             result[i] = max BOOST_PREVENT_MACRO_SUBSTITUTION(a[i], b[i]);
0203         return result;
0204     }
0205 
0206     double norm(point_difference delta) const
0207     {
0208         double n = 0.;
0209         for (std::size_t i = 0; i < Dims; ++i)
0210             n = boost::math::hypot(n, delta[i]);
0211         return n;
0212     }
0213 
0214     double volume(point_difference delta) const
0215     {
0216         double n = 1.;
0217         for (std::size_t i = 0; i < Dims; ++i)
0218             n *= delta[i];
0219         return n;
0220     }
0221 };
0222 
0223 template < std::size_t Dims, typename RandomNumberGenerator = minstd_rand >
0224 class hypercube_topology : public convex_topology< Dims >
0225 {
0226     typedef uniform_01< RandomNumberGenerator, double > rand_t;
0227 
0228 public:
0229     typedef typename convex_topology< Dims >::point_type point_type;
0230     typedef typename convex_topology< Dims >::point_difference_type
0231         point_difference_type;
0232 
0233     explicit hypercube_topology(double scaling = 1.0)
0234     : gen_ptr(new RandomNumberGenerator)
0235     , rand(new rand_t(*gen_ptr))
0236     , scaling(scaling)
0237     {
0238     }
0239 
0240     hypercube_topology(RandomNumberGenerator& gen, double scaling = 1.0)
0241     : gen_ptr(), rand(new rand_t(gen)), scaling(scaling)
0242     {
0243     }
0244 
0245     point_type random_point() const
0246     {
0247         point_type p;
0248         for (std::size_t i = 0; i < Dims; ++i)
0249             p[i] = (*rand)() * scaling;
0250         return p;
0251     }
0252 
0253     point_type bound(point_type a) const
0254     {
0255         BOOST_USING_STD_MIN();
0256         BOOST_USING_STD_MAX();
0257         point_type p;
0258         for (std::size_t i = 0; i < Dims; ++i)
0259             p[i] = min BOOST_PREVENT_MACRO_SUBSTITUTION(
0260                 scaling, max BOOST_PREVENT_MACRO_SUBSTITUTION(-scaling, a[i]));
0261         return p;
0262     }
0263 
0264     double distance_from_boundary(point_type a) const
0265     {
0266         BOOST_USING_STD_MIN();
0267         BOOST_USING_STD_MAX();
0268 #ifndef BOOST_NO_STDC_NAMESPACE
0269         using std::abs;
0270 #endif
0271         BOOST_STATIC_ASSERT(Dims >= 1);
0272         double dist = abs(scaling - a[0]);
0273         for (std::size_t i = 1; i < Dims; ++i)
0274             dist = min BOOST_PREVENT_MACRO_SUBSTITUTION(
0275                 dist, abs(scaling - a[i]));
0276         return dist;
0277     }
0278 
0279     point_type center() const
0280     {
0281         point_type result;
0282         for (std::size_t i = 0; i < Dims; ++i)
0283             result[i] = scaling * .5;
0284         return result;
0285     }
0286 
0287     point_type origin() const
0288     {
0289         point_type result;
0290         for (std::size_t i = 0; i < Dims; ++i)
0291             result[i] = 0;
0292         return result;
0293     }
0294 
0295     point_difference_type extent() const
0296     {
0297         point_difference_type result;
0298         for (std::size_t i = 0; i < Dims; ++i)
0299             result[i] = scaling;
0300         return result;
0301     }
0302 
0303 private:
0304     shared_ptr< RandomNumberGenerator > gen_ptr;
0305     shared_ptr< rand_t > rand;
0306     double scaling;
0307 };
0308 
0309 template < typename RandomNumberGenerator = minstd_rand >
0310 class square_topology : public hypercube_topology< 2, RandomNumberGenerator >
0311 {
0312     typedef hypercube_topology< 2, RandomNumberGenerator > inherited;
0313 
0314 public:
0315     explicit square_topology(double scaling = 1.0) : inherited(scaling) {}
0316 
0317     square_topology(RandomNumberGenerator& gen, double scaling = 1.0)
0318     : inherited(gen, scaling)
0319     {
0320     }
0321 };
0322 
0323 template < typename RandomNumberGenerator = minstd_rand >
0324 class rectangle_topology : public convex_topology< 2 >
0325 {
0326     typedef uniform_01< RandomNumberGenerator, double > rand_t;
0327 
0328 public:
0329     rectangle_topology(double left, double top, double right, double bottom)
0330     : gen_ptr(new RandomNumberGenerator)
0331     , rand(new rand_t(*gen_ptr))
0332     , left(std::min BOOST_PREVENT_MACRO_SUBSTITUTION(left, right))
0333     , top(std::min BOOST_PREVENT_MACRO_SUBSTITUTION(top, bottom))
0334     , right(std::max BOOST_PREVENT_MACRO_SUBSTITUTION(left, right))
0335     , bottom(std::max BOOST_PREVENT_MACRO_SUBSTITUTION(top, bottom))
0336     {
0337     }
0338 
0339     rectangle_topology(RandomNumberGenerator& gen, double left, double top,
0340         double right, double bottom)
0341     : gen_ptr()
0342     , rand(new rand_t(gen))
0343     , left(std::min BOOST_PREVENT_MACRO_SUBSTITUTION(left, right))
0344     , top(std::min BOOST_PREVENT_MACRO_SUBSTITUTION(top, bottom))
0345     , right(std::max BOOST_PREVENT_MACRO_SUBSTITUTION(left, right))
0346     , bottom(std::max BOOST_PREVENT_MACRO_SUBSTITUTION(top, bottom))
0347     {
0348     }
0349 
0350     typedef typename convex_topology< 2 >::point_type point_type;
0351     typedef typename convex_topology< 2 >::point_difference_type
0352         point_difference_type;
0353 
0354     point_type random_point() const
0355     {
0356         point_type p;
0357         p[0] = (*rand)() * (right - left) + left;
0358         p[1] = (*rand)() * (bottom - top) + top;
0359         return p;
0360     }
0361 
0362     point_type bound(point_type a) const
0363     {
0364         BOOST_USING_STD_MIN();
0365         BOOST_USING_STD_MAX();
0366         point_type p;
0367         p[0] = min BOOST_PREVENT_MACRO_SUBSTITUTION(
0368             right, max BOOST_PREVENT_MACRO_SUBSTITUTION(left, a[0]));
0369         p[1] = min BOOST_PREVENT_MACRO_SUBSTITUTION(
0370             bottom, max BOOST_PREVENT_MACRO_SUBSTITUTION(top, a[1]));
0371         return p;
0372     }
0373 
0374     double distance_from_boundary(point_type a) const
0375     {
0376         BOOST_USING_STD_MIN();
0377         BOOST_USING_STD_MAX();
0378 #ifndef BOOST_NO_STDC_NAMESPACE
0379         using std::abs;
0380 #endif
0381         double dist = abs(left - a[0]);
0382         dist = min BOOST_PREVENT_MACRO_SUBSTITUTION(dist, abs(right - a[0]));
0383         dist = min BOOST_PREVENT_MACRO_SUBSTITUTION(dist, abs(top - a[1]));
0384         dist = min BOOST_PREVENT_MACRO_SUBSTITUTION(dist, abs(bottom - a[1]));
0385         return dist;
0386     }
0387 
0388     point_type center() const
0389     {
0390         point_type result;
0391         result[0] = (left + right) / 2.;
0392         result[1] = (top + bottom) / 2.;
0393         return result;
0394     }
0395 
0396     point_type origin() const
0397     {
0398         point_type result;
0399         result[0] = left;
0400         result[1] = top;
0401         return result;
0402     }
0403 
0404     point_difference_type extent() const
0405     {
0406         point_difference_type result;
0407         result[0] = right - left;
0408         result[1] = bottom - top;
0409         return result;
0410     }
0411 
0412 private:
0413     shared_ptr< RandomNumberGenerator > gen_ptr;
0414     shared_ptr< rand_t > rand;
0415     double left, top, right, bottom;
0416 };
0417 
0418 template < typename RandomNumberGenerator = minstd_rand >
0419 class cube_topology : public hypercube_topology< 3, RandomNumberGenerator >
0420 {
0421     typedef hypercube_topology< 3, RandomNumberGenerator > inherited;
0422 
0423 public:
0424     explicit cube_topology(double scaling = 1.0) : inherited(scaling) {}
0425 
0426     cube_topology(RandomNumberGenerator& gen, double scaling = 1.0)
0427     : inherited(gen, scaling)
0428     {
0429     }
0430 };
0431 
0432 template < std::size_t Dims, typename RandomNumberGenerator = minstd_rand >
0433 class ball_topology : public convex_topology< Dims >
0434 {
0435     typedef uniform_01< RandomNumberGenerator, double > rand_t;
0436 
0437 public:
0438     typedef typename convex_topology< Dims >::point_type point_type;
0439     typedef typename convex_topology< Dims >::point_difference_type
0440         point_difference_type;
0441 
0442     explicit ball_topology(double radius = 1.0)
0443     : gen_ptr(new RandomNumberGenerator)
0444     , rand(new rand_t(*gen_ptr))
0445     , radius(radius)
0446     {
0447     }
0448 
0449     ball_topology(RandomNumberGenerator& gen, double radius = 1.0)
0450     : gen_ptr(), rand(new rand_t(gen)), radius(radius)
0451     {
0452     }
0453 
0454     point_type random_point() const
0455     {
0456         point_type p;
0457         double dist_sum;
0458         do
0459         {
0460             dist_sum = 0.0;
0461             for (std::size_t i = 0; i < Dims; ++i)
0462             {
0463                 double x = (*rand)() * 2 * radius - radius;
0464                 p[i] = x;
0465                 dist_sum += x * x;
0466             }
0467         } while (dist_sum > radius * radius);
0468         return p;
0469     }
0470 
0471     point_type bound(point_type a) const
0472     {
0473         BOOST_USING_STD_MIN();
0474         BOOST_USING_STD_MAX();
0475         double r = 0.;
0476         for (std::size_t i = 0; i < Dims; ++i)
0477             r = boost::math::hypot(r, a[i]);
0478         if (r <= radius)
0479             return a;
0480         double scaling_factor = radius / r;
0481         point_type p;
0482         for (std::size_t i = 0; i < Dims; ++i)
0483             p[i] = a[i] * scaling_factor;
0484         return p;
0485     }
0486 
0487     double distance_from_boundary(point_type a) const
0488     {
0489         double r = 0.;
0490         for (std::size_t i = 0; i < Dims; ++i)
0491             r = boost::math::hypot(r, a[i]);
0492         return radius - r;
0493     }
0494 
0495     point_type center() const
0496     {
0497         point_type result;
0498         for (std::size_t i = 0; i < Dims; ++i)
0499             result[i] = 0;
0500         return result;
0501     }
0502 
0503     point_type origin() const
0504     {
0505         point_type result;
0506         for (std::size_t i = 0; i < Dims; ++i)
0507             result[i] = -radius;
0508         return result;
0509     }
0510 
0511     point_difference_type extent() const
0512     {
0513         point_difference_type result;
0514         for (std::size_t i = 0; i < Dims; ++i)
0515             result[i] = 2. * radius;
0516         return result;
0517     }
0518 
0519 private:
0520     shared_ptr< RandomNumberGenerator > gen_ptr;
0521     shared_ptr< rand_t > rand;
0522     double radius;
0523 };
0524 
0525 template < typename RandomNumberGenerator = minstd_rand >
0526 class circle_topology : public ball_topology< 2, RandomNumberGenerator >
0527 {
0528     typedef ball_topology< 2, RandomNumberGenerator > inherited;
0529 
0530 public:
0531     explicit circle_topology(double radius = 1.0) : inherited(radius) {}
0532 
0533     circle_topology(RandomNumberGenerator& gen, double radius = 1.0)
0534     : inherited(gen, radius)
0535     {
0536     }
0537 };
0538 
0539 template < typename RandomNumberGenerator = minstd_rand >
0540 class sphere_topology : public ball_topology< 3, RandomNumberGenerator >
0541 {
0542     typedef ball_topology< 3, RandomNumberGenerator > inherited;
0543 
0544 public:
0545     explicit sphere_topology(double radius = 1.0) : inherited(radius) {}
0546 
0547     sphere_topology(RandomNumberGenerator& gen, double radius = 1.0)
0548     : inherited(gen, radius)
0549     {
0550     }
0551 };
0552 
0553 template < typename RandomNumberGenerator = minstd_rand > class heart_topology
0554 {
0555     // Heart is defined as the union of three shapes:
0556     // Square w/ corners (+-1000, -1000), (0, 0), (0, -2000)
0557     // Circle centered at (-500, -500) radius 500*sqrt(2)
0558     // Circle centered at (500, -500) radius 500*sqrt(2)
0559     // Bounding box (-1000, -2000) - (1000, 500*(sqrt(2) - 1))
0560 
0561     struct point
0562     {
0563         point()
0564         {
0565             values[0] = 0.0;
0566             values[1] = 0.0;
0567         }
0568         point(double x, double y)
0569         {
0570             values[0] = x;
0571             values[1] = y;
0572         }
0573 
0574         double& operator[](std::size_t i) { return values[i]; }
0575         double operator[](std::size_t i) const { return values[i]; }
0576 
0577     private:
0578         double values[2];
0579     };
0580 
0581     bool in_heart(point p) const
0582     {
0583 #ifndef BOOST_NO_STDC_NAMESPACE
0584         using std::abs;
0585 #endif
0586 
0587         if (p[1] < abs(p[0]) - 2000)
0588             return false; // Bottom
0589         if (p[1] <= -1000)
0590             return true; // Diagonal of square
0591         if (boost::math::hypot(p[0] - -500, p[1] - -500)
0592             <= 500. * boost::math::constants::root_two< double >())
0593             return true; // Left circle
0594         if (boost::math::hypot(p[0] - 500, p[1] - -500)
0595             <= 500. * boost::math::constants::root_two< double >())
0596             return true; // Right circle
0597         return false;
0598     }
0599 
0600     bool segment_within_heart(point p1, point p2) const
0601     {
0602         // Assumes that p1 and p2 are within the heart
0603         if ((p1[0] < 0) == (p2[0] < 0))
0604             return true; // Same side of symmetry line
0605         if (p1[0] == p2[0])
0606             return true; // Vertical
0607         double slope = (p2[1] - p1[1]) / (p2[0] - p1[0]);
0608         double intercept = p1[1] - p1[0] * slope;
0609         if (intercept > 0)
0610             return false; // Crosses between circles
0611         return true;
0612     }
0613 
0614     typedef uniform_01< RandomNumberGenerator, double > rand_t;
0615 
0616 public:
0617     typedef point point_type;
0618 
0619     heart_topology()
0620     : gen_ptr(new RandomNumberGenerator), rand(new rand_t(*gen_ptr))
0621     {
0622     }
0623 
0624     heart_topology(RandomNumberGenerator& gen)
0625     : gen_ptr(), rand(new rand_t(gen))
0626     {
0627     }
0628 
0629     point random_point() const
0630     {
0631         point result;
0632         do
0633         {
0634             result[0] = (*rand)()
0635                     * (1000
0636                         + 1000 * boost::math::constants::root_two< double >())
0637                 - (500 + 500 * boost::math::constants::root_two< double >());
0638             result[1] = (*rand)()
0639                     * (2000
0640                         + 500
0641                             * (boost::math::constants::root_two< double >()
0642                                 - 1))
0643                 - 2000;
0644         } while (!in_heart(result));
0645         return result;
0646     }
0647 
0648     // Not going to provide clipping to bounding region or distance from
0649     // boundary
0650 
0651     double distance(point a, point b) const
0652     {
0653         if (segment_within_heart(a, b))
0654         {
0655             // Straight line
0656             return boost::math::hypot(b[0] - a[0], b[1] - a[1]);
0657         }
0658         else
0659         {
0660             // Straight line bending around (0, 0)
0661             return boost::math::hypot(a[0], a[1])
0662                 + boost::math::hypot(b[0], b[1]);
0663         }
0664     }
0665 
0666     point move_position_toward(point a, double fraction, point b) const
0667     {
0668         if (segment_within_heart(a, b))
0669         {
0670             // Straight line
0671             return point(a[0] + (b[0] - a[0]) * fraction,
0672                 a[1] + (b[1] - a[1]) * fraction);
0673         }
0674         else
0675         {
0676             double distance_to_point_a = boost::math::hypot(a[0], a[1]);
0677             double distance_to_point_b = boost::math::hypot(b[0], b[1]);
0678             double location_of_point = distance_to_point_a
0679                 / (distance_to_point_a + distance_to_point_b);
0680             if (fraction < location_of_point)
0681                 return point(a[0] * (1 - fraction / location_of_point),
0682                     a[1] * (1 - fraction / location_of_point));
0683             else
0684                 return point(b[0]
0685                         * ((fraction - location_of_point)
0686                             / (1 - location_of_point)),
0687                     b[1]
0688                         * ((fraction - location_of_point)
0689                             / (1 - location_of_point)));
0690         }
0691     }
0692 
0693 private:
0694     shared_ptr< RandomNumberGenerator > gen_ptr;
0695     shared_ptr< rand_t > rand;
0696 };
0697 
0698 } // namespace boost
0699 
0700 #endif // BOOST_GRAPH_TOPOLOGY_HPP