1 // Copyright 2004-2006 The Trustees of Indiana University.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
7 // Authors: Douglas Gregor
9 #ifndef BOOST_GRAPH_PLOD_GENERATOR_HPP
10 #define BOOST_GRAPH_PLOD_GENERATOR_HPP
14 #include <boost/random/uniform_int.hpp>
15 #include <boost/shared_ptr.hpp>
16 #include <boost/graph/graph_traits.hpp>
19 #include <boost/config/no_tr1/cmath.hpp>
20 #include <boost/mpl/if.hpp>
23 template<typename RandomGenerator>
24 class out_directed_plod_iterator
27 typedef std::forward_iterator_tag iterator_category;
28 typedef std::pair<std::size_t, std::size_t> value_type;
29 typedef const value_type& reference;
30 typedef const value_type* pointer;
31 typedef std::ptrdiff_t difference_type;
33 out_directed_plod_iterator() : gen(0), at_end(true) { }
35 out_directed_plod_iterator(RandomGenerator& gen, std::size_t n,
36 double alpha, double beta,
37 bool allow_self_loops)
38 : gen(&gen), n(n), alpha(alpha), beta(beta),
39 allow_self_loops(allow_self_loops), at_end(false), degree(0),
44 uniform_int<std::size_t> x(0, n-1);
45 std::size_t xv = x(gen);
46 degree = (xv == 0? 0 : std::size_t(beta * pow(xv, -alpha)));
49 reference operator*() const { return current; }
50 pointer operator->() const { return ¤t; }
52 out_directed_plod_iterator& operator++()
56 uniform_int<std::size_t> x(0, n-1);
58 // Continue stepping through source nodes until the
61 // Step to the next source node. If we've gone past the
62 // number of nodes we're responsible for, we're done.
63 if (++current.first >= n) {
68 std::size_t xv = x(*gen);
69 degree = (xv == 0? 0 : std::size_t(beta * pow(xv, -alpha)));
73 current.second = x(*gen);
74 } while (current.first == current.second && !allow_self_loops);
80 out_directed_plod_iterator operator++(int)
82 out_directed_plod_iterator temp(*this);
87 bool operator==(const out_directed_plod_iterator& other) const
89 return at_end == other.at_end;
92 bool operator!=(const out_directed_plod_iterator& other) const
94 return !(*this == other);
102 bool allow_self_loops;
108 template<typename RandomGenerator>
109 class undirected_plod_iterator
111 typedef std::vector<std::pair<std::size_t, std::size_t> > out_degrees_t;
114 typedef std::input_iterator_tag iterator_category;
115 typedef std::pair<std::size_t, std::size_t> value_type;
116 typedef const value_type& reference;
117 typedef const value_type* pointer;
118 typedef std::ptrdiff_t difference_type;
120 undirected_plod_iterator()
121 : gen(0), out_degrees(), degrees_left(0), allow_self_loops(false) { }
123 undirected_plod_iterator(RandomGenerator& gen, std::size_t n,
124 double alpha, double beta,
125 bool allow_self_loops = false)
126 : gen(&gen), n(n), out_degrees(new out_degrees_t),
127 degrees_left(0), allow_self_loops(allow_self_loops)
131 uniform_int<std::size_t> x(0, n-1);
132 for (std::size_t i = 0; i != n; ++i) {
133 std::size_t xv = x(gen);
134 std::size_t degree = (xv == 0? 0 : std::size_t(beta * pow(xv, -alpha)));
135 if (degree == 0) degree = 1;
136 else if (degree >= n) degree = n-1;
137 out_degrees->push_back(std::make_pair(i, degree));
138 degrees_left += degree;
144 reference operator*() const { return current; }
145 pointer operator->() const { return ¤t; }
147 undirected_plod_iterator& operator++()
153 undirected_plod_iterator operator++(int)
155 undirected_plod_iterator temp(*this);
160 bool operator==(const undirected_plod_iterator& other) const
162 return degrees_left == other.degrees_left;
165 bool operator!=(const undirected_plod_iterator& other) const
166 { return !(*this == other); }
171 std::size_t source, target;
173 /* We may get to the point where we can't actually find any
174 new edges, so we just add some random edge and set the
175 degrees left = 0 to signal termination. */
176 if (out_degrees->size() < 2) {
177 uniform_int<std::size_t> x(0, n-1);
178 current.first = x(*gen);
180 current.second = x(*gen);
181 } while (current.first == current.second && !allow_self_loops);
183 out_degrees->clear();
187 uniform_int<std::size_t> x(0, out_degrees->size()-1);
189 // Select source vertex
191 if ((*out_degrees)[source].second == 0) {
192 (*out_degrees)[source] = out_degrees->back();
193 out_degrees->pop_back();
197 // Select target vertex
199 if ((*out_degrees)[target].second == 0) {
200 (*out_degrees)[target] = out_degrees->back();
201 out_degrees->pop_back();
203 } else if (source != target
204 || (allow_self_loops && (*out_degrees)[source].second > 2)) {
209 // Update degree counts
210 --(*out_degrees)[source].second;
212 --(*out_degrees)[target].second;
214 current.first = (*out_degrees)[source].first;
215 current.second = (*out_degrees)[target].first;
218 RandomGenerator* gen;
220 shared_ptr<out_degrees_t> out_degrees;
221 std::size_t degrees_left;
222 bool allow_self_loops;
227 template<typename RandomGenerator, typename Graph>
229 : public mpl::if_<is_convertible<
230 typename graph_traits<Graph>::directed_category,
232 out_directed_plod_iterator<RandomGenerator>,
233 undirected_plod_iterator<RandomGenerator> >::type
235 typedef typename mpl::if_<
237 typename graph_traits<Graph>::directed_category,
239 out_directed_plod_iterator<RandomGenerator>,
240 undirected_plod_iterator<RandomGenerator> >::type
244 plod_iterator() : inherited() { }
246 plod_iterator(RandomGenerator& gen, std::size_t n,
247 double alpha, double beta, bool allow_self_loops = false)
248 : inherited(gen, n, alpha, beta, allow_self_loops) { }
251 } // end namespace boost
253 #endif // BOOST_GRAPH_PLOD_GENERATOR_HPP