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