erdos_renyi_generator.hpp 7.1 KB

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