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