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