plod_generator.hpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. // Copyright 2004-2006 The Trustees of Indiana University.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. // Authors: Douglas Gregor
  6. // Andrew Lumsdaine
  7. #ifndef BOOST_GRAPH_PLOD_GENERATOR_HPP
  8. #define BOOST_GRAPH_PLOD_GENERATOR_HPP
  9. #include <iterator>
  10. #include <utility>
  11. #include <boost/random/uniform_int.hpp>
  12. #include <boost/shared_ptr.hpp>
  13. #include <boost/graph/graph_traits.hpp>
  14. #include <vector>
  15. #include <map>
  16. #include <boost/config/no_tr1/cmath.hpp>
  17. #include <boost/mpl/if.hpp>
  18. namespace boost {
  19. template<typename RandomGenerator>
  20. class out_directed_plod_iterator
  21. {
  22. public:
  23. typedef std::forward_iterator_tag iterator_category;
  24. typedef std::pair<std::size_t, std::size_t> value_type;
  25. typedef const value_type& reference;
  26. typedef const value_type* pointer;
  27. typedef std::ptrdiff_t difference_type;
  28. out_directed_plod_iterator() : gen(0), at_end(true) { }
  29. out_directed_plod_iterator(RandomGenerator& gen, std::size_t n,
  30. double alpha, double beta,
  31. bool allow_self_loops)
  32. : gen(&gen), n(n), alpha(alpha), beta(beta),
  33. allow_self_loops(allow_self_loops), at_end(false), degree(0),
  34. current(0, 0)
  35. {
  36. using std::pow;
  37. uniform_int<std::size_t> x(0, n-1);
  38. std::size_t xv = x(gen);
  39. degree = (xv == 0? 0 : std::size_t(beta * pow(xv, -alpha)));
  40. }
  41. reference operator*() const { return current; }
  42. pointer operator->() const { return &current; }
  43. out_directed_plod_iterator& operator++()
  44. {
  45. using std::pow;
  46. uniform_int<std::size_t> x(0, n-1);
  47. // Continue stepping through source nodes until the
  48. // (out)degree is > 0
  49. while (degree == 0) {
  50. // Step to the next source node. If we've gone past the
  51. // number of nodes we're responsible for, we're done.
  52. if (++current.first >= n) {
  53. at_end = true;
  54. return *this;
  55. }
  56. std::size_t xv = x(*gen);
  57. degree = (xv == 0? 0 : std::size_t(beta * pow(xv, -alpha)));
  58. }
  59. do {
  60. current.second = x(*gen);
  61. } while (current.first == current.second && !allow_self_loops);
  62. --degree;
  63. return *this;
  64. }
  65. out_directed_plod_iterator operator++(int)
  66. {
  67. out_directed_plod_iterator temp(*this);
  68. ++(*this);
  69. return temp;
  70. }
  71. bool operator==(const out_directed_plod_iterator& other) const
  72. {
  73. return at_end == other.at_end;
  74. }
  75. bool operator!=(const out_directed_plod_iterator& other) const
  76. {
  77. return !(*this == other);
  78. }
  79. private:
  80. RandomGenerator* gen;
  81. std::size_t n;
  82. double alpha;
  83. double beta;
  84. bool allow_self_loops;
  85. bool at_end;
  86. std::size_t degree;
  87. value_type current;
  88. };
  89. template<typename RandomGenerator>
  90. class undirected_plod_iterator
  91. {
  92. typedef std::vector<std::pair<std::size_t, std::size_t> > out_degrees_t;
  93. public:
  94. typedef std::input_iterator_tag iterator_category;
  95. typedef std::pair<std::size_t, std::size_t> value_type;
  96. typedef const value_type& reference;
  97. typedef const value_type* pointer;
  98. typedef std::ptrdiff_t difference_type;
  99. undirected_plod_iterator()
  100. : gen(0), out_degrees(), degrees_left(0), allow_self_loops(false) { }
  101. undirected_plod_iterator(RandomGenerator& gen, std::size_t n,
  102. double alpha, double beta,
  103. bool allow_self_loops = false)
  104. : gen(&gen), n(n), out_degrees(new out_degrees_t),
  105. degrees_left(0), allow_self_loops(allow_self_loops)
  106. {
  107. using std::pow;
  108. uniform_int<std::size_t> x(0, n-1);
  109. for (std::size_t i = 0; i != n; ++i) {
  110. std::size_t xv = x(gen);
  111. std::size_t degree = (xv == 0? 0 : std::size_t(beta * pow(xv, -alpha)));
  112. if (degree == 0) degree = 1;
  113. else if (degree >= n) degree = n-1;
  114. out_degrees->push_back(std::make_pair(i, degree));
  115. degrees_left += degree;
  116. }
  117. next();
  118. }
  119. reference operator*() const { return current; }
  120. pointer operator->() const { return &current; }
  121. undirected_plod_iterator& operator++()
  122. {
  123. next();
  124. return *this;
  125. }
  126. undirected_plod_iterator operator++(int)
  127. {
  128. undirected_plod_iterator temp(*this);
  129. ++(*this);
  130. return temp;
  131. }
  132. bool operator==(const undirected_plod_iterator& other) const
  133. {
  134. return degrees_left == other.degrees_left;
  135. }
  136. bool operator!=(const undirected_plod_iterator& other) const
  137. { return !(*this == other); }
  138. private:
  139. void next()
  140. {
  141. std::size_t source, target;
  142. while (true) {
  143. /* We may get to the point where we can't actually find any
  144. new edges, so we just add some random edge and set the
  145. degrees left = 0 to signal termination. */
  146. if (out_degrees->size() < 2) {
  147. uniform_int<std::size_t> x(0, n-1);
  148. current.first = x(*gen);
  149. do {
  150. current.second = x(*gen);
  151. } while (current.first == current.second && !allow_self_loops);
  152. degrees_left = 0;
  153. out_degrees->clear();
  154. return;
  155. }
  156. uniform_int<std::size_t> x(0, out_degrees->size()-1);
  157. // Select source vertex
  158. source = x(*gen);
  159. if ((*out_degrees)[source].second == 0) {
  160. (*out_degrees)[source] = out_degrees->back();
  161. out_degrees->pop_back();
  162. continue;
  163. }
  164. // Select target vertex
  165. target = x(*gen);
  166. if ((*out_degrees)[target].second == 0) {
  167. (*out_degrees)[target] = out_degrees->back();
  168. out_degrees->pop_back();
  169. continue;
  170. } else if (source != target
  171. || (allow_self_loops && (*out_degrees)[source].second > 2)) {
  172. break;
  173. }
  174. }
  175. // Update degree counts
  176. --(*out_degrees)[source].second;
  177. --degrees_left;
  178. --(*out_degrees)[target].second;
  179. --degrees_left;
  180. current.first = (*out_degrees)[source].first;
  181. current.second = (*out_degrees)[target].first;
  182. }
  183. RandomGenerator* gen;
  184. std::size_t n;
  185. shared_ptr<out_degrees_t> out_degrees;
  186. std::size_t degrees_left;
  187. bool allow_self_loops;
  188. value_type current;
  189. };
  190. template<typename RandomGenerator, typename Graph>
  191. class plod_iterator
  192. : public mpl::if_<is_convertible<
  193. typename graph_traits<Graph>::directed_category,
  194. directed_tag>,
  195. out_directed_plod_iterator<RandomGenerator>,
  196. undirected_plod_iterator<RandomGenerator> >::type
  197. {
  198. typedef typename mpl::if_<
  199. is_convertible<
  200. typename graph_traits<Graph>::directed_category,
  201. directed_tag>,
  202. out_directed_plod_iterator<RandomGenerator>,
  203. undirected_plod_iterator<RandomGenerator> >::type
  204. inherited;
  205. public:
  206. plod_iterator() : inherited() { }
  207. plod_iterator(RandomGenerator& gen, std::size_t n,
  208. double alpha, double beta, bool allow_self_loops = false)
  209. : inherited(gen, n, alpha, beta, allow_self_loops) { }
  210. };
  211. } // end namespace boost
  212. #endif // BOOST_GRAPH_PLOD_GENERATOR_HPP