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