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