erdos_renyi_generator.hpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // Copyright 2004, 2005 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: Jeremiah Willcock
  6. // Douglas Gregor
  7. // Andrew Lumsdaine
  8. #ifndef BOOST_GRAPH_ERDOS_RENYI_GENERATOR_HPP
  9. #define BOOST_GRAPH_ERDOS_RENYI_GENERATOR_HPP
  10. #include <boost/assert.hpp>
  11. #include <iterator>
  12. #include <utility>
  13. #include <boost/shared_ptr.hpp>
  14. #include <boost/random/uniform_int.hpp>
  15. #include <boost/graph/graph_traits.hpp>
  16. #include <boost/random/geometric_distribution.hpp>
  17. #include <boost/type_traits/is_base_of.hpp>
  18. #include <boost/type_traits/is_same.hpp>
  19. #include <boost/config/no_tr1/cmath.hpp>
  20. #include <boost/iterator/iterator_facade.hpp>
  21. namespace boost {
  22. template<typename RandomGenerator, typename Graph>
  23. class erdos_renyi_iterator
  24. : public iterator_facade<
  25. erdos_renyi_iterator<RandomGenerator, Graph>,
  26. std::pair<typename graph_traits<Graph>::vertices_size_type,
  27. typename graph_traits<Graph>::vertices_size_type>,
  28. std::input_iterator_tag,
  29. const
  30. std::pair<typename graph_traits<Graph>::vertices_size_type,
  31. typename graph_traits<Graph>::vertices_size_type>&>
  32. {
  33. typedef typename graph_traits<Graph>::directed_category directed_category;
  34. typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
  35. typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
  36. BOOST_STATIC_CONSTANT
  37. (bool,
  38. is_undirected = (is_base_of<undirected_tag, directed_category>::value));
  39. public:
  40. erdos_renyi_iterator() : gen(), n(0), edges(0), allow_self_loops(false) {}
  41. erdos_renyi_iterator(RandomGenerator& gen, vertices_size_type n,
  42. double fraction = 0.0, bool allow_self_loops = false)
  43. : gen(&gen), n(n), edges(edges_size_type(fraction * n * n)),
  44. allow_self_loops(allow_self_loops)
  45. {
  46. if (is_undirected) edges = edges / 2;
  47. next();
  48. }
  49. erdos_renyi_iterator(RandomGenerator& gen, vertices_size_type n,
  50. edges_size_type m, bool allow_self_loops = false)
  51. : gen(&gen), n(n), edges(m),
  52. allow_self_loops(allow_self_loops)
  53. {
  54. next();
  55. }
  56. const std::pair<vertices_size_type, vertices_size_type>&
  57. dereference() const { return current; }
  58. void increment() {
  59. --edges;
  60. next();
  61. }
  62. bool equal(const erdos_renyi_iterator& other) const
  63. { return edges == other.edges; }
  64. private:
  65. void next()
  66. {
  67. uniform_int<vertices_size_type> rand_vertex(0, n-1);
  68. current.first = rand_vertex(*gen);
  69. do {
  70. current.second = rand_vertex(*gen);
  71. } while (current.first == current.second && !allow_self_loops);
  72. }
  73. RandomGenerator* gen;
  74. vertices_size_type n;
  75. edges_size_type edges;
  76. bool allow_self_loops;
  77. std::pair<vertices_size_type, vertices_size_type> current;
  78. };
  79. template<typename RandomGenerator, typename Graph>
  80. class sorted_erdos_renyi_iterator
  81. : public iterator_facade<
  82. sorted_erdos_renyi_iterator<RandomGenerator, Graph>,
  83. std::pair<typename graph_traits<Graph>::vertices_size_type,
  84. typename graph_traits<Graph>::vertices_size_type>,
  85. std::input_iterator_tag,
  86. const
  87. std::pair<typename graph_traits<Graph>::vertices_size_type,
  88. typename graph_traits<Graph>::vertices_size_type>&>
  89. {
  90. typedef typename graph_traits<Graph>::directed_category directed_category;
  91. typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
  92. typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
  93. BOOST_STATIC_CONSTANT
  94. (bool,
  95. is_undirected = (is_base_of<undirected_tag, directed_category>::value));
  96. public:
  97. sorted_erdos_renyi_iterator()
  98. : gen(), rand_vertex(0.5), n(0), allow_self_loops(false)
  99. , src((std::numeric_limits<vertices_size_type>::max)()),
  100. tgt_index(vertices_size_type(-1)), prob(.5)
  101. { }
  102. // NOTE: The default probability has been changed to be the same as that
  103. // used by the geometic distribution. It was previously 0.0, which would
  104. // cause an assertion.
  105. sorted_erdos_renyi_iterator(RandomGenerator& gen, vertices_size_type n,
  106. double prob = 0.5,
  107. bool loops = false)
  108. : gen(), rand_vertex(1. - prob), n(n), allow_self_loops(loops), src(0)
  109. , tgt_index(vertices_size_type(-1)), prob(prob)
  110. {
  111. this->gen.reset(new uniform_01<RandomGenerator*>(&gen));
  112. if (prob == 0.0) {src = (std::numeric_limits<vertices_size_type>::max)(); return;}
  113. next();
  114. }
  115. const std::pair<vertices_size_type, vertices_size_type>&
  116. dereference() const {
  117. return current;
  118. }
  119. bool equal(const sorted_erdos_renyi_iterator& o) const {
  120. return src == o.src && tgt_index == o.tgt_index;
  121. }
  122. void increment() {
  123. next();
  124. }
  125. private:
  126. void next()
  127. {
  128. // In order to get the edges from the generator in sorted order, one
  129. // effective (but slow) procedure would be to use a
  130. // bernoulli_distribution for each legal (src, tgt_index) pair. Because of
  131. // the O(|V|^2) cost of that, a geometric distribution is used. The
  132. // geometric distribution tells how many times the
  133. // bernoulli_distribution would need to be run until it returns true.
  134. // Thus, this distribution can be used to step through the edges
  135. // which are actually present.
  136. BOOST_ASSERT (src != (std::numeric_limits<vertices_size_type>::max)() &&
  137. src != n);
  138. while (src != n) {
  139. vertices_size_type increment = rand_vertex(*gen);
  140. size_t tgt_index_limit =
  141. (is_undirected ? src + 1 : n) +
  142. (allow_self_loops ? 0 : -1);
  143. if (tgt_index + increment >= tgt_index_limit) {
  144. // Overflowed this source; go to the next one and try again.
  145. ++src;
  146. // This bias is because the geometric distribution always returns
  147. // values >=1, and we want to allow 0 as a valid target.
  148. tgt_index = vertices_size_type(-1);
  149. continue;
  150. } else {
  151. tgt_index += increment;
  152. current.first = src;
  153. current.second =
  154. tgt_index +
  155. (!allow_self_loops && !is_undirected && tgt_index >= src ? 1 : 0);
  156. break;
  157. }
  158. }
  159. if (src == n) src = (std::numeric_limits<vertices_size_type>::max)();
  160. }
  161. shared_ptr<uniform_01<RandomGenerator*> > gen;
  162. geometric_distribution<vertices_size_type> rand_vertex;
  163. vertices_size_type n;
  164. bool allow_self_loops;
  165. vertices_size_type src, tgt_index;
  166. std::pair<vertices_size_type, vertices_size_type> current;
  167. double prob;
  168. };
  169. } // end namespace boost
  170. #endif // BOOST_GRAPH_ERDOS_RENYI_GENERATOR_HPP