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