Back to home page

EIC code displayed by LXR

 
 

    


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

0001 // Copyright 2004, 2005 The Trustees of Indiana University.
0002 
0003 // Use, modification and distribution is subject to the Boost Software
0004 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 //  Authors: Nick Edmonds
0008 //           Andrew Lumsdaine
0009 #ifndef BOOST_GRAPH_RMAT_GENERATOR_HPP
0010 #define BOOST_GRAPH_RMAT_GENERATOR_HPP
0011 
0012 #include <math.h>
0013 #include <iterator>
0014 #include <utility>
0015 #include <vector>
0016 #include <queue>
0017 #include <map>
0018 #include <boost/shared_ptr.hpp>
0019 #include <boost/assert.hpp>
0020 #include <boost/random/uniform_int.hpp>
0021 #include <boost/random/uniform_01.hpp>
0022 #include <boost/graph/graph_traits.hpp>
0023 #include <boost/graph/detail/mpi_include.hpp>
0024 #include <boost/type_traits/is_base_and_derived.hpp>
0025 #include <boost/type_traits/is_same.hpp>
0026 // #include <boost/test/floating_point_comparison.hpp>
0027 
0028 using boost::shared_ptr;
0029 using boost::uniform_01;
0030 
0031 // Returns floor(log_2(n)), and -1 when n is 0
0032 template < typename IntegerType > inline int int_log2(IntegerType n)
0033 {
0034     int l = 0;
0035     while (n > 0)
0036     {
0037         ++l;
0038         n >>= 1;
0039     }
0040     return l - 1;
0041 }
0042 
0043 struct keep_all_edges
0044 {
0045     template < typename T > bool operator()(const T&, const T&) { return true; }
0046 };
0047 
0048 template < typename Distribution, typename ProcessId > struct keep_local_edges
0049 {
0050 
0051     keep_local_edges(const Distribution& distrib, const ProcessId& id)
0052     : distrib(distrib), id(id)
0053     {
0054     }
0055 
0056     template < typename T > bool operator()(const T& x, const T& y)
0057     {
0058         return distrib(x) == id || distrib(y) == id;
0059     }
0060 
0061 private:
0062     const Distribution& distrib;
0063     const ProcessId& id;
0064 };
0065 
0066 template < typename RandomGenerator, typename T >
0067 void generate_permutation_vector(
0068     RandomGenerator& gen, std::vector< T >& vertexPermutation, T n)
0069 {
0070     using boost::uniform_int;
0071 
0072     vertexPermutation.resize(n);
0073 
0074     // Generate permutation map of vertex numbers
0075     uniform_int< T > rand_vertex(0, n - 1);
0076     for (T i = 0; i < n; ++i)
0077         vertexPermutation[i] = i;
0078 
0079     // Can't use std::random_shuffle unless we create another (synchronized)
0080     // PRNG
0081     for (T i = 0; i < n; ++i)
0082         std::swap(vertexPermutation[i], vertexPermutation[rand_vertex(gen)]);
0083 }
0084 
0085 template < typename RandomGenerator, typename T >
0086 std::pair< T, T > generate_edge(
0087     shared_ptr< uniform_01< RandomGenerator > > prob, T n, unsigned int SCALE,
0088     double a, double b, double c, double d)
0089 {
0090     T u = 0, v = 0;
0091     T step = n / 2;
0092     for (unsigned int j = 0; j < SCALE; ++j)
0093     {
0094         double p = (*prob)();
0095 
0096         if (p < a)
0097             ;
0098         else if (p >= a && p < a + b)
0099             v += step;
0100         else if (p >= a + b && p < a + b + c)
0101             u += step;
0102         else
0103         { // p > a + b + c && p < a + b + c + d
0104             u += step;
0105             v += step;
0106         }
0107 
0108         step /= 2;
0109 
0110         // 0.2 and 0.9 are hardcoded in the reference SSCA implementation.
0111         // The maximum change in any given value should be less than 10%
0112         a *= 0.9 + 0.2 * (*prob)();
0113         b *= 0.9 + 0.2 * (*prob)();
0114         c *= 0.9 + 0.2 * (*prob)();
0115         d *= 0.9 + 0.2 * (*prob)();
0116 
0117         double S = a + b + c + d;
0118 
0119         a /= S;
0120         b /= S;
0121         c /= S;
0122         // d /= S;
0123         // Ensure all values add up to 1, regardless of floating point errors
0124         d = 1. - a - b - c;
0125     }
0126 
0127     return std::make_pair(u, v);
0128 }
0129 
0130 namespace boost
0131 {
0132 
0133 /*
0134   Chakrabarti's R-MAT scale free generator.
0135 
0136   For all flavors of the R-MAT iterator a+b+c+d must equal 1 and for the
0137   unique_rmat_iterator 'm' << 'n^2'.  If 'm' is too close to 'n^2' the
0138   generator may be unable to generate sufficient unique edges
0139 
0140   To get a true scale free distribution {a, b, c, d : a > b, a > c, a > d}
0141 */
0142 
0143 template < typename RandomGenerator, typename Graph > class rmat_iterator
0144 {
0145     typedef typename graph_traits< Graph >::directed_category directed_category;
0146     typedef
0147         typename graph_traits< Graph >::vertices_size_type vertices_size_type;
0148     typedef typename graph_traits< Graph >::edges_size_type edges_size_type;
0149 
0150 public:
0151     typedef std::input_iterator_tag iterator_category;
0152     typedef std::pair< vertices_size_type, vertices_size_type > value_type;
0153     typedef const value_type& reference;
0154     typedef const value_type* pointer;
0155     typedef std::ptrdiff_t difference_type; // Not used
0156 
0157     // No argument constructor, set to terminating condition
0158     rmat_iterator() : gen(), edge(0) {}
0159 
0160     // Initialize for edge generation
0161     rmat_iterator(RandomGenerator& gen, vertices_size_type n, edges_size_type m,
0162         double a, double b, double c, double d, bool permute_vertices = true)
0163     : gen()
0164     , n(n)
0165     , a(a)
0166     , b(b)
0167     , c(c)
0168     , d(d)
0169     , edge(m)
0170     , permute_vertices(permute_vertices)
0171     , SCALE(int_log2(n))
0172 
0173     {
0174         this->gen.reset(new uniform_01< RandomGenerator >(gen));
0175 
0176         // BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c +
0177         // d, 1., 1.e-5));
0178 
0179         if (permute_vertices)
0180             generate_permutation_vector(gen, vertexPermutation, n);
0181 
0182         // TODO: Generate the entire adjacency matrix then "Clip and flip" if
0183         // undirected graph
0184 
0185         // Generate the first edge
0186         vertices_size_type u, v;
0187         boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);
0188 
0189         if (permute_vertices)
0190             current
0191                 = std::make_pair(vertexPermutation[u], vertexPermutation[v]);
0192         else
0193             current = std::make_pair(u, v);
0194 
0195         --edge;
0196     }
0197 
0198     reference operator*() const { return current; }
0199     pointer operator->() const { return &current; }
0200 
0201     rmat_iterator& operator++()
0202     {
0203         vertices_size_type u, v;
0204         boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);
0205 
0206         if (permute_vertices)
0207             current
0208                 = std::make_pair(vertexPermutation[u], vertexPermutation[v]);
0209         else
0210             current = std::make_pair(u, v);
0211 
0212         --edge;
0213 
0214         return *this;
0215     }
0216 
0217     rmat_iterator operator++(int)
0218     {
0219         rmat_iterator temp(*this);
0220         ++(*this);
0221         return temp;
0222     }
0223 
0224     bool operator==(const rmat_iterator& other) const
0225     {
0226         return edge == other.edge;
0227     }
0228 
0229     bool operator!=(const rmat_iterator& other) const
0230     {
0231         return !(*this == other);
0232     }
0233 
0234 private:
0235     // Parameters
0236     shared_ptr< uniform_01< RandomGenerator > > gen;
0237     vertices_size_type n;
0238     double a, b, c, d;
0239     int edge;
0240     bool permute_vertices;
0241     int SCALE;
0242 
0243     // Internal data structures
0244     std::vector< vertices_size_type > vertexPermutation;
0245     value_type current;
0246 };
0247 
0248 // Sorted version for CSR
0249 template < typename T > struct sort_pair
0250 {
0251     bool operator()(const std::pair< T, T >& x, const std::pair< T, T >& y)
0252     {
0253         if (x.first == y.first)
0254             return x.second > y.second;
0255         else
0256             return x.first > y.first;
0257     }
0258 };
0259 
0260 template < typename RandomGenerator, typename Graph,
0261     typename EdgePredicate = keep_all_edges >
0262 class sorted_rmat_iterator
0263 {
0264     typedef typename graph_traits< Graph >::directed_category directed_category;
0265     typedef
0266         typename graph_traits< Graph >::vertices_size_type vertices_size_type;
0267     typedef typename graph_traits< Graph >::edges_size_type edges_size_type;
0268 
0269 public:
0270     typedef std::input_iterator_tag iterator_category;
0271     typedef std::pair< vertices_size_type, vertices_size_type > value_type;
0272     typedef const value_type& reference;
0273     typedef const value_type* pointer;
0274     typedef std::ptrdiff_t difference_type; // Not used
0275 
0276     // No argument constructor, set to terminating condition
0277     sorted_rmat_iterator()
0278     : gen(), values(sort_pair< vertices_size_type >()), done(true)
0279     {
0280     }
0281 
0282     // Initialize for edge generation
0283     sorted_rmat_iterator(RandomGenerator& gen, vertices_size_type n,
0284         edges_size_type m, double a, double b, double c, double d,
0285         bool permute_vertices = true, EdgePredicate ep = keep_all_edges())
0286     : gen()
0287     , permute_vertices(permute_vertices)
0288     , values(sort_pair< vertices_size_type >())
0289     , done(false)
0290 
0291     {
0292         // BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c +
0293         // d, 1., 1.e-5));
0294 
0295         this->gen.reset(new uniform_01< RandomGenerator >(gen));
0296 
0297         std::vector< vertices_size_type > vertexPermutation;
0298         if (permute_vertices)
0299             generate_permutation_vector(gen, vertexPermutation, n);
0300 
0301         // TODO: "Clip and flip" if undirected graph
0302         int SCALE = int_log2(n);
0303 
0304         for (edges_size_type i = 0; i < m; ++i)
0305         {
0306 
0307             vertices_size_type u, v;
0308             boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);
0309 
0310             if (permute_vertices)
0311             {
0312                 if (ep(vertexPermutation[u], vertexPermutation[v]))
0313                     values.push(std::make_pair(
0314                         vertexPermutation[u], vertexPermutation[v]));
0315             }
0316             else
0317             {
0318                 if (ep(u, v))
0319                     values.push(std::make_pair(u, v));
0320             }
0321         }
0322 
0323         current = values.top();
0324         values.pop();
0325     }
0326 
0327     reference operator*() const { return current; }
0328     pointer operator->() const { return &current; }
0329 
0330     sorted_rmat_iterator& operator++()
0331     {
0332         if (!values.empty())
0333         {
0334             current = values.top();
0335             values.pop();
0336         }
0337         else
0338             done = true;
0339 
0340         return *this;
0341     }
0342 
0343     sorted_rmat_iterator operator++(int)
0344     {
0345         sorted_rmat_iterator temp(*this);
0346         ++(*this);
0347         return temp;
0348     }
0349 
0350     bool operator==(const sorted_rmat_iterator& other) const
0351     {
0352         return values.empty() && other.values.empty() && done && other.done;
0353     }
0354 
0355     bool operator!=(const sorted_rmat_iterator& other) const
0356     {
0357         return !(*this == other);
0358     }
0359 
0360 private:
0361     // Parameters
0362     shared_ptr< uniform_01< RandomGenerator > > gen;
0363     bool permute_vertices;
0364 
0365     // Internal data structures
0366     std::priority_queue< value_type, std::vector< value_type >,
0367         sort_pair< vertices_size_type > >
0368         values;
0369     value_type current;
0370     bool done;
0371 };
0372 
0373 // This version is slow but guarantees unique edges
0374 template < typename RandomGenerator, typename Graph,
0375     typename EdgePredicate = keep_all_edges >
0376 class unique_rmat_iterator
0377 {
0378     typedef typename graph_traits< Graph >::directed_category directed_category;
0379     typedef
0380         typename graph_traits< Graph >::vertices_size_type vertices_size_type;
0381     typedef typename graph_traits< Graph >::edges_size_type edges_size_type;
0382 
0383 public:
0384     typedef std::input_iterator_tag iterator_category;
0385     typedef std::pair< vertices_size_type, vertices_size_type > value_type;
0386     typedef const value_type& reference;
0387     typedef const value_type* pointer;
0388     typedef std::ptrdiff_t difference_type; // Not used
0389 
0390     // No argument constructor, set to terminating condition
0391     unique_rmat_iterator() : gen(), done(true) {}
0392 
0393     // Initialize for edge generation
0394     unique_rmat_iterator(RandomGenerator& gen, vertices_size_type n,
0395         edges_size_type m, double a, double b, double c, double d,
0396         bool permute_vertices = true, EdgePredicate ep = keep_all_edges())
0397     : gen(), done(false)
0398 
0399     {
0400         // BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c +
0401         // d, 1., 1.e-5));
0402 
0403         this->gen.reset(new uniform_01< RandomGenerator >(gen));
0404 
0405         std::vector< vertices_size_type > vertexPermutation;
0406         if (permute_vertices)
0407             generate_permutation_vector(gen, vertexPermutation, n);
0408 
0409         int SCALE = int_log2(n);
0410 
0411         std::map< value_type, bool > edge_map;
0412 
0413         edges_size_type edges = 0;
0414         do
0415         {
0416             vertices_size_type u, v;
0417             boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);
0418 
0419             // Lowest vertex number always comes first
0420             // (this means we don't have to worry about i->j and j->i being in
0421             // the edge list)
0422             if (u > v && is_same< directed_category, undirected_tag >::value)
0423                 std::swap(u, v);
0424 
0425             if (edge_map.find(std::make_pair(u, v)) == edge_map.end())
0426             {
0427                 edge_map[std::make_pair(u, v)] = true;
0428 
0429                 if (permute_vertices)
0430                 {
0431                     if (ep(vertexPermutation[u], vertexPermutation[v]))
0432                         values.push_back(std::make_pair(
0433                             vertexPermutation[u], vertexPermutation[v]));
0434                 }
0435                 else
0436                 {
0437                     if (ep(u, v))
0438                         values.push_back(std::make_pair(u, v));
0439                 }
0440 
0441                 edges++;
0442             }
0443         } while (edges < m);
0444         // NGE - Asking for more than n^2 edges will result in an infinite loop
0445         // here
0446         //       Asking for a value too close to n^2 edges may as well
0447 
0448         current = values.back();
0449         values.pop_back();
0450     }
0451 
0452     reference operator*() const { return current; }
0453     pointer operator->() const { return &current; }
0454 
0455     unique_rmat_iterator& operator++()
0456     {
0457         if (!values.empty())
0458         {
0459             current = values.back();
0460             values.pop_back();
0461         }
0462         else
0463             done = true;
0464 
0465         return *this;
0466     }
0467 
0468     unique_rmat_iterator operator++(int)
0469     {
0470         unique_rmat_iterator temp(*this);
0471         ++(*this);
0472         return temp;
0473     }
0474 
0475     bool operator==(const unique_rmat_iterator& other) const
0476     {
0477         return values.empty() && other.values.empty() && done && other.done;
0478     }
0479 
0480     bool operator!=(const unique_rmat_iterator& other) const
0481     {
0482         return !(*this == other);
0483     }
0484 
0485 private:
0486     // Parameters
0487     shared_ptr< uniform_01< RandomGenerator > > gen;
0488 
0489     // Internal data structures
0490     std::vector< value_type > values;
0491     value_type current;
0492     bool done;
0493 };
0494 
0495 // This version is slow but guarantees unique edges
0496 template < typename RandomGenerator, typename Graph,
0497     typename EdgePredicate = keep_all_edges >
0498 class sorted_unique_rmat_iterator
0499 {
0500     typedef typename graph_traits< Graph >::directed_category directed_category;
0501     typedef
0502         typename graph_traits< Graph >::vertices_size_type vertices_size_type;
0503     typedef typename graph_traits< Graph >::edges_size_type edges_size_type;
0504 
0505 public:
0506     typedef std::input_iterator_tag iterator_category;
0507     typedef std::pair< vertices_size_type, vertices_size_type > value_type;
0508     typedef const value_type& reference;
0509     typedef const value_type* pointer;
0510     typedef std::ptrdiff_t difference_type; // Not used
0511 
0512     // No argument constructor, set to terminating condition
0513     sorted_unique_rmat_iterator()
0514     : gen(), values(sort_pair< vertices_size_type >()), done(true)
0515     {
0516     }
0517 
0518     // Initialize for edge generation
0519     sorted_unique_rmat_iterator(RandomGenerator& gen, vertices_size_type n,
0520         edges_size_type m, double a, double b, double c, double d,
0521         bool bidirectional = false, bool permute_vertices = true,
0522         EdgePredicate ep = keep_all_edges())
0523     : gen()
0524     , bidirectional(bidirectional)
0525     , values(sort_pair< vertices_size_type >())
0526     , done(false)
0527 
0528     {
0529         // BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c +
0530         // d, 1., 1.e-5));
0531 
0532         this->gen.reset(new uniform_01< RandomGenerator >(gen));
0533 
0534         std::vector< vertices_size_type > vertexPermutation;
0535         if (permute_vertices)
0536             generate_permutation_vector(gen, vertexPermutation, n);
0537 
0538         int SCALE = int_log2(n);
0539 
0540         std::map< value_type, bool > edge_map;
0541 
0542         edges_size_type edges = 0;
0543         do
0544         {
0545 
0546             vertices_size_type u, v;
0547             boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);
0548 
0549             if (bidirectional)
0550             {
0551                 if (edge_map.find(std::make_pair(u, v)) == edge_map.end())
0552                 {
0553                     edge_map[std::make_pair(u, v)] = true;
0554                     edge_map[std::make_pair(v, u)] = true;
0555 
0556                     if (ep(u, v))
0557                     {
0558                         if (permute_vertices)
0559                         {
0560                             values.push(std::make_pair(
0561                                 vertexPermutation[u], vertexPermutation[v]));
0562                             values.push(std::make_pair(
0563                                 vertexPermutation[v], vertexPermutation[u]));
0564                         }
0565                         else
0566                         {
0567                             values.push(std::make_pair(u, v));
0568                             values.push(std::make_pair(v, u));
0569                         }
0570                     }
0571 
0572                     ++edges;
0573                 }
0574             }
0575             else
0576             {
0577                 // Lowest vertex number always comes first
0578                 // (this means we don't have to worry about i->j and j->i being
0579                 // in the edge list)
0580                 if (u > v
0581                     && is_same< directed_category, undirected_tag >::value)
0582                     std::swap(u, v);
0583 
0584                 if (edge_map.find(std::make_pair(u, v)) == edge_map.end())
0585                 {
0586                     edge_map[std::make_pair(u, v)] = true;
0587 
0588                     if (permute_vertices)
0589                     {
0590                         if (ep(vertexPermutation[u], vertexPermutation[v]))
0591                             values.push(std::make_pair(
0592                                 vertexPermutation[u], vertexPermutation[v]));
0593                     }
0594                     else
0595                     {
0596                         if (ep(u, v))
0597                             values.push(std::make_pair(u, v));
0598                     }
0599 
0600                     ++edges;
0601                 }
0602             }
0603 
0604         } while (edges < m);
0605         // NGE - Asking for more than n^2 edges will result in an infinite loop
0606         // here
0607         //       Asking for a value too close to n^2 edges may as well
0608 
0609         current = values.top();
0610         values.pop();
0611     }
0612 
0613     reference operator*() const { return current; }
0614     pointer operator->() const { return &current; }
0615 
0616     sorted_unique_rmat_iterator& operator++()
0617     {
0618         if (!values.empty())
0619         {
0620             current = values.top();
0621             values.pop();
0622         }
0623         else
0624             done = true;
0625 
0626         return *this;
0627     }
0628 
0629     sorted_unique_rmat_iterator operator++(int)
0630     {
0631         sorted_unique_rmat_iterator temp(*this);
0632         ++(*this);
0633         return temp;
0634     }
0635 
0636     bool operator==(const sorted_unique_rmat_iterator& other) const
0637     {
0638         return values.empty() && other.values.empty() && done && other.done;
0639     }
0640 
0641     bool operator!=(const sorted_unique_rmat_iterator& other) const
0642     {
0643         return !(*this == other);
0644     }
0645 
0646 private:
0647     // Parameters
0648     shared_ptr< uniform_01< RandomGenerator > > gen;
0649     bool bidirectional;
0650 
0651     // Internal data structures
0652     std::priority_queue< value_type, std::vector< value_type >,
0653         sort_pair< vertices_size_type > >
0654         values;
0655     value_type current;
0656     bool done;
0657 };
0658 
0659 } // end namespace boost
0660 
0661 #include BOOST_GRAPH_MPI_INCLUDE(<boost/graph/distributed/rmat_graph_generator.hpp>)
0662 
0663 #endif // BOOST_GRAPH_RMAT_GENERATOR_HPP