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 ¤t; } 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 ¤t; } 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