PageRenderTime 83ms CodeModel.GetById 10ms app.highlight 68ms RepoModel.GetById 1ms app.codeStats 1ms

/Src/Dependencies/Boost/boost/graph/rmat_graph_generator.hpp

http://hadesmem.googlecode.com/
C++ Header | 595 lines | 419 code | 124 blank | 52 comment | 70 complexity | 75b7a776da11c0eed2fd9174ab2caaf4 MD5 | raw file
  1// Copyright 2004, 2005 The Trustees of Indiana University.
  2
  3// Use, modification and distribution is subject to the Boost Software
  4// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5// http://www.boost.org/LICENSE_1_0.txt)
  6
  7//  Authors: Nick Edmonds
  8//           Andrew Lumsdaine
  9#ifndef BOOST_GRAPH_RMAT_GENERATOR_HPP
 10#define BOOST_GRAPH_RMAT_GENERATOR_HPP
 11
 12#include <math.h>
 13#include <iterator>
 14#include <utility>
 15#include <vector>
 16#include <queue>
 17#include <map>
 18#include <boost/shared_ptr.hpp>
 19#include <boost/assert.hpp>
 20#include <boost/random/uniform_int.hpp>
 21#include <boost/random/uniform_01.hpp>
 22#include <boost/graph/graph_traits.hpp>
 23#include <boost/type_traits/is_base_and_derived.hpp>
 24#include <boost/type_traits/is_same.hpp>
 25#include <boost/test/floating_point_comparison.hpp>
 26
 27using boost::shared_ptr;
 28using boost::uniform_01;
 29
 30// Returns floor(log_2(n)), and -1 when n is 0
 31template <typename IntegerType>
 32inline int int_log2(IntegerType n) {
 33  int l = 0;
 34  while (n > 0) {++l; n >>= 1;}
 35  return l - 1;
 36}
 37
 38struct keep_all_edges {
 39  template <typename T>
 40  bool operator()(const T&, const T&) { return true; }
 41};
 42
 43template <typename Distribution, typename ProcessId>
 44struct keep_local_edges {
 45
 46  keep_local_edges(const Distribution& distrib, const ProcessId& id)
 47    : distrib(distrib), id(id)
 48  { }
 49
 50  template <typename T>
 51  bool operator()(const T& x, const T& y)
 52  { return distrib(x) == id || distrib(y) == id; }
 53
 54private:
 55  const Distribution& distrib;
 56  const ProcessId&    id;
 57};
 58
 59template <typename RandomGenerator, typename T>
 60void
 61generate_permutation_vector(RandomGenerator& gen, std::vector<T>& vertexPermutation, T n)
 62{
 63  using boost::uniform_int;
 64
 65  vertexPermutation.resize(n);
 66
 67  // Generate permutation map of vertex numbers
 68  uniform_int<T> rand_vertex(0, n-1);
 69  for (T i = 0; i < n; ++i)
 70    vertexPermutation[i] = i;
 71
 72  // Can't use std::random_shuffle unless we create another (synchronized) PRNG
 73  for (T i = 0; i < n; ++i)
 74    std::swap(vertexPermutation[i], vertexPermutation[rand_vertex(gen)]);
 75}
 76
 77template <typename RandomGenerator, typename T>
 78std::pair<T,T>
 79generate_edge(shared_ptr<uniform_01<RandomGenerator> > prob, T n,
 80              unsigned int SCALE, double a, double b, double c, double d)
 81{
 82  T u = 0, v = 0;
 83  T step = n/2;
 84  for (unsigned int j = 0; j < SCALE; ++j) {
 85    double p = (*prob)();
 86
 87    if (p < a)
 88      ;
 89    else if (p >= a && p < a + b)
 90      v += step;
 91    else if (p >= a + b && p < a + b + c)
 92      u += step;
 93    else { // p > a + b + c && p < a + b + c + d
 94      u += step;
 95      v += step;
 96    }
 97
 98    step /= 2;
 99
100    // 0.2 and 0.9 are hardcoded in the reference SSCA implementation.
101    // The maximum change in any given value should be less than 10%
102    a *= 0.9 + 0.2 * (*prob)();
103    b *= 0.9 + 0.2 * (*prob)();
104    c *= 0.9 + 0.2 * (*prob)();
105    d *= 0.9 + 0.2 * (*prob)();
106
107    double S = a + b + c + d;
108
109    a /= S; b /= S; c /= S;
110    // d /= S;
111    // Ensure all values add up to 1, regardless of floating point errors
112    d = 1. - a - b - c;
113  }
114
115  return std::make_pair(u, v);
116}
117
118namespace boost {
119
120  /*
121    Chakrabarti's R-MAT scale free generator.
122
123    For all flavors of the R-MAT iterator a+b+c+d must equal 1 and for the
124    unique_rmat_iterator 'm' << 'n^2'.  If 'm' is too close to 'n^2' the
125    generator may be unable to generate sufficient unique edges
126
127    To get a true scale free distribution {a, b, c, d : a > b, a > c, a > d}
128  */
129
130  template<typename RandomGenerator, typename Graph>
131  class rmat_iterator
132  {
133    typedef typename graph_traits<Graph>::directed_category directed_category;
134    typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
135    typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
136
137  public:
138    typedef std::input_iterator_tag iterator_category;
139    typedef std::pair<vertices_size_type, vertices_size_type> value_type;
140    typedef const value_type& reference;
141    typedef const value_type* pointer;
142    typedef void difference_type;
143
144    // No argument constructor, set to terminating condition
145    rmat_iterator()
146      : gen(), edge(0) { }
147
148    // Initialize for edge generation
149    rmat_iterator(RandomGenerator& gen, vertices_size_type n,
150                  edges_size_type m, double a, double b, double c,
151                  double d, bool permute_vertices = true)
152      : gen(), n(n), a(a), b(b), c(c), d(d), edge(m),
153        permute_vertices(permute_vertices),
154        SCALE(int_log2(n))
155
156    {
157      this->gen.reset(new uniform_01<RandomGenerator>(gen));
158
159      BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + d, 1., boost::test_tools::fraction_tolerance(1.e-5)));
160
161      if (permute_vertices)
162        generate_permutation_vector(gen, vertexPermutation, n);
163
164      // TODO: Generate the entire adjacency matrix then "Clip and flip" if undirected graph
165
166      // Generate the first edge
167      vertices_size_type u, v;
168      boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);
169
170      if (permute_vertices)
171        current = std::make_pair(vertexPermutation[u],
172                                 vertexPermutation[v]);
173      else
174        current = std::make_pair(u, v);
175
176      --edge;
177    }
178
179    reference operator*() const { return current; }
180    pointer operator->() const { return &current; }
181
182    rmat_iterator& operator++()
183    {
184      vertices_size_type u, v;
185      boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);
186
187      if (permute_vertices)
188        current = std::make_pair(vertexPermutation[u],
189                                 vertexPermutation[v]);
190      else
191        current = std::make_pair(u, v);
192
193      --edge;
194
195      return *this;
196    }
197
198    rmat_iterator operator++(int)
199    {
200      rmat_iterator temp(*this);
201      ++(*this);
202      return temp;
203    }
204
205    bool operator==(const rmat_iterator& other) const
206    {
207      return edge == other.edge;
208    }
209
210    bool operator!=(const rmat_iterator& other) const
211    { return !(*this == other); }
212
213  private:
214
215    // Parameters
216    shared_ptr<uniform_01<RandomGenerator> > gen;
217    vertices_size_type n;
218    double a, b, c, d;
219    int edge;
220    bool permute_vertices;
221    int SCALE;
222
223    // Internal data structures
224    std::vector<vertices_size_type> vertexPermutation;
225    value_type current;
226  };
227
228  // Sorted version for CSR
229  template <typename T>
230  struct sort_pair {
231    bool operator() (const std::pair<T,T>& x, const std::pair<T,T>& y)
232    {
233      if (x.first == y.first)
234        return x.second > y.second;
235      else
236        return x.first > y.first;
237    }
238  };
239
240  template<typename RandomGenerator, typename Graph,
241           typename EdgePredicate = keep_all_edges>
242  class sorted_rmat_iterator
243  {
244    typedef typename graph_traits<Graph>::directed_category directed_category;
245    typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
246    typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
247
248  public:
249    typedef std::input_iterator_tag iterator_category;
250    typedef std::pair<vertices_size_type, vertices_size_type> value_type;
251    typedef const value_type& reference;
252    typedef const value_type* pointer;
253    typedef void difference_type;
254
255    // No argument constructor, set to terminating condition
256    sorted_rmat_iterator()
257      : gen(), values(sort_pair<vertices_size_type>()), done(true)
258    { }
259
260    // Initialize for edge generation
261    sorted_rmat_iterator(RandomGenerator& gen, vertices_size_type n,
262                         edges_size_type m, double a, double b, double c,
263                         double d, bool permute_vertices = true,
264                         EdgePredicate ep = keep_all_edges())
265      : gen(), permute_vertices(permute_vertices),
266        values(sort_pair<vertices_size_type>()), done(false)
267
268    {
269      BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + d, 1., boost::test_tools::fraction_tolerance(1.e-5)));
270
271      this->gen.reset(new uniform_01<RandomGenerator>(gen));
272
273      std::vector<vertices_size_type> vertexPermutation;
274      if (permute_vertices)
275        generate_permutation_vector(gen, vertexPermutation, n);
276
277      // TODO: "Clip and flip" if undirected graph
278      int SCALE = int_log2(n);
279
280      for (edges_size_type i = 0; i < m; ++i) {
281
282        vertices_size_type u, v;
283        boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);
284
285        if (permute_vertices) {
286          if (ep(vertexPermutation[u], vertexPermutation[v]))
287            values.push(std::make_pair(vertexPermutation[u], vertexPermutation[v]));
288        } else {
289          if (ep(u, v))
290            values.push(std::make_pair(u, v));
291        }
292
293      }
294
295      current = values.top();
296      values.pop();
297    }
298
299    reference operator*() const { return current; }
300    pointer operator->() const { return &current; }
301
302    sorted_rmat_iterator& operator++()
303    {
304      if (!values.empty()) {
305        current = values.top();
306        values.pop();
307      } else
308        done = true;
309
310      return *this;
311    }
312
313    sorted_rmat_iterator operator++(int)
314    {
315      sorted_rmat_iterator temp(*this);
316      ++(*this);
317      return temp;
318    }
319
320    bool operator==(const sorted_rmat_iterator& other) const
321    {
322      return values.empty() && other.values.empty() && done && other.done;
323    }
324
325    bool operator!=(const sorted_rmat_iterator& other) const
326    { return !(*this == other); }
327
328  private:
329
330    // Parameters
331    shared_ptr<uniform_01<RandomGenerator> > gen;
332    bool permute_vertices;
333
334    // Internal data structures
335    std::priority_queue<value_type, std::vector<value_type>, sort_pair<vertices_size_type> > values;
336    value_type current;
337    bool       done;
338  };
339
340
341  // This version is slow but guarantees unique edges
342  template<typename RandomGenerator, typename Graph,
343           typename EdgePredicate = keep_all_edges>
344  class unique_rmat_iterator
345  {
346    typedef typename graph_traits<Graph>::directed_category directed_category;
347    typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
348    typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
349
350  public:
351    typedef std::input_iterator_tag iterator_category;
352    typedef std::pair<vertices_size_type, vertices_size_type> value_type;
353    typedef const value_type& reference;
354    typedef const value_type* pointer;
355    typedef void difference_type;
356
357    // No argument constructor, set to terminating condition
358    unique_rmat_iterator()
359        : gen(), done(true)
360    { }
361
362    // Initialize for edge generation
363    unique_rmat_iterator(RandomGenerator& gen, vertices_size_type n,
364                         edges_size_type m, double a, double b, double c,
365                         double d, bool permute_vertices = true,
366                         EdgePredicate ep = keep_all_edges())
367      : gen(), done(false)
368
369    {
370      BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + d, 1., boost::test_tools::fraction_tolerance(1.e-5)));
371
372      this->gen.reset(new uniform_01<RandomGenerator>(gen));
373
374      std::vector<vertices_size_type> vertexPermutation;
375      if (permute_vertices)
376        generate_permutation_vector(gen, vertexPermutation, n);
377
378      int SCALE = int_log2(n);
379
380      std::map<value_type, bool> edge_map;
381
382      edges_size_type edges = 0;
383      do {
384        vertices_size_type u, v;
385        boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);
386
387        // Lowest vertex number always comes first
388        // (this means we don't have to worry about i->j and j->i being in the edge list)
389        if (u > v && is_same<directed_category, undirected_tag>::value)
390          std::swap(u, v);
391
392        if (edge_map.find(std::make_pair(u, v)) == edge_map.end()) {
393          edge_map[std::make_pair(u, v)] = true;
394
395          if (permute_vertices) {
396            if (ep(vertexPermutation[u], vertexPermutation[v]))
397              values.push_back(std::make_pair(vertexPermutation[u], vertexPermutation[v]));
398          } else {
399            if (ep(u, v))
400              values.push_back(std::make_pair(u, v));
401          }
402
403          edges++;
404        }
405      } while (edges < m);
406      // NGE - Asking for more than n^2 edges will result in an infinite loop here
407      //       Asking for a value too close to n^2 edges may as well
408
409      current = values.back();
410      values.pop_back();
411    }
412
413    reference operator*() const { return current; }
414    pointer operator->() const { return &current; }
415
416    unique_rmat_iterator& operator++()
417    {
418      if (!values.empty()) {
419        current = values.back();
420        values.pop_back();
421      } else
422        done = true;
423
424      return *this;
425    }
426
427    unique_rmat_iterator operator++(int)
428    {
429      unique_rmat_iterator temp(*this);
430      ++(*this);
431      return temp;
432    }
433
434    bool operator==(const unique_rmat_iterator& other) const
435    {
436      return values.empty() && other.values.empty() && done && other.done;
437    }
438
439    bool operator!=(const unique_rmat_iterator& other) const
440    { return !(*this == other); }
441
442  private:
443
444    // Parameters
445    shared_ptr<uniform_01<RandomGenerator> > gen;
446
447    // Internal data structures
448    std::vector<value_type> values;
449    value_type              current;
450    bool                    done;
451  };
452
453  // This version is slow but guarantees unique edges
454  template<typename RandomGenerator, typename Graph,
455           typename EdgePredicate = keep_all_edges>
456  class sorted_unique_rmat_iterator
457  {
458    typedef typename graph_traits<Graph>::directed_category directed_category;
459    typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
460    typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
461
462  public:
463    typedef std::input_iterator_tag iterator_category;
464    typedef std::pair<vertices_size_type, vertices_size_type> value_type;
465    typedef const value_type& reference;
466    typedef const value_type* pointer;
467    typedef void difference_type;
468
469    // No argument constructor, set to terminating condition
470    sorted_unique_rmat_iterator()
471      : gen(), values(sort_pair<vertices_size_type>()), done(true) { }
472
473    // Initialize for edge generation
474    sorted_unique_rmat_iterator(RandomGenerator& gen, vertices_size_type n,
475                                edges_size_type m, double a, double b, double c,
476                                double d, bool bidirectional = false,
477                                bool permute_vertices = true,
478                                EdgePredicate ep = keep_all_edges())
479      : gen(), bidirectional(bidirectional),
480        values(sort_pair<vertices_size_type>()), done(false)
481
482    {
483      BOOST_ASSERT(boost::test_tools::check_is_close(a + b + c + d, 1., boost::test_tools::fraction_tolerance(1.e-5)));
484
485      this->gen.reset(new uniform_01<RandomGenerator>(gen));
486
487      std::vector<vertices_size_type> vertexPermutation;
488      if (permute_vertices)
489        generate_permutation_vector(gen, vertexPermutation, n);
490
491      int SCALE = int_log2(n);
492
493      std::map<value_type, bool> edge_map;
494
495      edges_size_type edges = 0;
496      do {
497
498        vertices_size_type u, v;
499        boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);
500
501        if (bidirectional) {
502          if (edge_map.find(std::make_pair(u, v)) == edge_map.end()) {
503            edge_map[std::make_pair(u, v)] = true;
504            edge_map[std::make_pair(v, u)] = true;
505
506            if (ep(u, v)) {
507              if (permute_vertices) {
508                values.push(std::make_pair(vertexPermutation[u], vertexPermutation[v]));
509                values.push(std::make_pair(vertexPermutation[v], vertexPermutation[u]));
510              } else {
511                values.push(std::make_pair(u, v));
512                values.push(std::make_pair(v, u));
513              }
514           }
515
516            ++edges;
517          }
518        } else {
519          // Lowest vertex number always comes first
520          // (this means we don't have to worry about i->j and j->i being in the edge list)
521          if (u > v && is_same<directed_category, undirected_tag>::value)
522            std::swap(u, v);
523
524          if (edge_map.find(std::make_pair(u, v)) == edge_map.end()) {
525            edge_map[std::make_pair(u, v)] = true;
526
527            if (permute_vertices) {
528              if (ep(vertexPermutation[u], vertexPermutation[v]))
529                values.push(std::make_pair(vertexPermutation[u], vertexPermutation[v]));
530            } else {
531              if (ep(u, v))
532                values.push(std::make_pair(u, v));
533            }
534
535            ++edges;
536          }
537        }
538
539      } while (edges < m);
540      // NGE - Asking for more than n^2 edges will result in an infinite loop here
541      //       Asking for a value too close to n^2 edges may as well
542
543      current = values.top();
544      values.pop();
545    }
546
547    reference operator*() const { return current; }
548    pointer operator->() const { return &current; }
549
550    sorted_unique_rmat_iterator& operator++()
551    {
552      if (!values.empty()) {
553        current = values.top();
554        values.pop();
555      } else
556        done = true;
557
558      return *this;
559    }
560
561    sorted_unique_rmat_iterator operator++(int)
562    {
563      sorted_unique_rmat_iterator temp(*this);
564      ++(*this);
565      return temp;
566    }
567
568    bool operator==(const sorted_unique_rmat_iterator& other) const
569    {
570      return values.empty() && other.values.empty() && done && other.done;
571    }
572
573    bool operator!=(const sorted_unique_rmat_iterator& other) const
574    { return !(*this == other); }
575
576  private:
577
578    // Parameters
579    shared_ptr<uniform_01<RandomGenerator> > gen;
580    bool             bidirectional;
581
582    // Internal data structures
583    std::priority_queue<value_type, std::vector<value_type>,
584                        sort_pair<vertices_size_type> > values;
585    value_type current;
586    bool       done;
587  };
588
589} // end namespace boost
590
591#ifdef BOOST_GRAPH_USE_MPI
592#include <boost/graph/distributed/rmat_graph_generator.hpp>
593#endif // BOOST_GRAPH_USE_MPI
594
595#endif // BOOST_GRAPH_RMAT_GENERATOR_HPP