| 1 | // Copyright 2004 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 <cmath> | 
|---|
| 20 |  | 
|---|
| 21 | namespace boost { | 
|---|
| 22 |  | 
|---|
| 23 |   template<typename RandomGenerator, typename Graph> | 
|---|
| 24 |   class plod_iterator | 
|---|
| 25 |   { | 
|---|
| 26 |     typedef std::vector<std::pair<std::size_t, std::size_t> > out_degrees_t; | 
|---|
| 27 |     typedef typename graph_traits<Graph>::directed_category directed_category; | 
|---|
| 28 |  | 
|---|
| 29 |   public: | 
|---|
| 30 |     typedef std::input_iterator_tag iterator_category; | 
|---|
| 31 |     typedef std::pair<std::size_t, std::size_t> value_type; | 
|---|
| 32 |     typedef const value_type& reference; | 
|---|
| 33 |     typedef const value_type* pointer; | 
|---|
| 34 |     typedef void difference_type; | 
|---|
| 35 |  | 
|---|
| 36 |     plod_iterator()  | 
|---|
| 37 |       : gen(0), out_degrees(), degrees_left(0), allow_self_loops(false) { } | 
|---|
| 38 |  | 
|---|
| 39 |     plod_iterator(RandomGenerator& gen, std::size_t n,   | 
|---|
| 40 |                   double alpha, double beta, bool allow_self_loops = false) | 
|---|
| 41 |       : gen(&gen), n(n), out_degrees(new out_degrees_t), | 
|---|
| 42 |         degrees_left(0), allow_self_loops(allow_self_loops) | 
|---|
| 43 |     { | 
|---|
| 44 |       using std::pow; | 
|---|
| 45 |  | 
|---|
| 46 |       uniform_int<std::size_t> x(0, n-1); | 
|---|
| 47 |       for (std::size_t i = 0; i != n; ++i) { | 
|---|
| 48 |         std::size_t xv = x(gen); | 
|---|
| 49 |     std::size_t degree = (xv == 0? 0 : std::size_t(beta * pow(xv, -alpha))); | 
|---|
| 50 |     if (degree != 0) { | 
|---|
| 51 |       out_degrees->push_back(std::make_pair(i, degree)); | 
|---|
| 52 |     } | 
|---|
| 53 |         degrees_left += degree; | 
|---|
| 54 |       } | 
|---|
| 55 |  | 
|---|
| 56 |       next(directed_category()); | 
|---|
| 57 |     } | 
|---|
| 58 |  | 
|---|
| 59 |     reference operator*() const { return current; } | 
|---|
| 60 |     pointer operator->() const { return ¤t; } | 
|---|
| 61 |      | 
|---|
| 62 |     plod_iterator& operator++() | 
|---|
| 63 |     {  | 
|---|
| 64 |       next(directed_category()); | 
|---|
| 65 |       return *this; | 
|---|
| 66 |     } | 
|---|
| 67 |  | 
|---|
| 68 |     plod_iterator operator++(int) | 
|---|
| 69 |     { | 
|---|
| 70 |       plod_iterator temp(*this); | 
|---|
| 71 |       ++(*this); | 
|---|
| 72 |       return temp; | 
|---|
| 73 |     } | 
|---|
| 74 |  | 
|---|
| 75 |     bool operator==(const plod_iterator& other) const | 
|---|
| 76 |     {  | 
|---|
| 77 |       return degrees_left == other.degrees_left;  | 
|---|
| 78 |     } | 
|---|
| 79 |  | 
|---|
| 80 |     bool operator!=(const plod_iterator& other) const | 
|---|
| 81 |     { return !(*this == other); } | 
|---|
| 82 |  | 
|---|
| 83 |   private: | 
|---|
| 84 |     void next(directed_tag) | 
|---|
| 85 |     { | 
|---|
| 86 |       uniform_int<std::size_t> x(0, out_degrees->size()-1); | 
|---|
| 87 |       std::size_t source; | 
|---|
| 88 |       do { | 
|---|
| 89 |         source = x(*gen); | 
|---|
| 90 |       } while ((*out_degrees)[source].second == 0); | 
|---|
| 91 |       current.first = (*out_degrees)[source].first; | 
|---|
| 92 |       do { | 
|---|
| 93 |         current.second = x(*gen); | 
|---|
| 94 |       } while (current.first == current.second && !allow_self_loops); | 
|---|
| 95 |       --degrees_left; | 
|---|
| 96 |       if (--(*out_degrees)[source].second == 0) { | 
|---|
| 97 |         (*out_degrees)[source] = out_degrees->back(); | 
|---|
| 98 |         out_degrees->pop_back(); | 
|---|
| 99 |       } | 
|---|
| 100 |     } | 
|---|
| 101 |  | 
|---|
| 102 |     void next(undirected_tag) | 
|---|
| 103 |     { | 
|---|
| 104 |       std::size_t source, target; | 
|---|
| 105 |       while (true) { | 
|---|
| 106 |         /* We may get to the point where we can't actually find any | 
|---|
| 107 |            new edges, so we just add some random edge and set the | 
|---|
| 108 |            degrees left = 0 to signal termination. */ | 
|---|
| 109 |         if (out_degrees->size() < 2) { | 
|---|
| 110 |           uniform_int<std::size_t> x(0, n); | 
|---|
| 111 |           current.first  = x(*gen); | 
|---|
| 112 |           do { | 
|---|
| 113 |             current.second = x(*gen); | 
|---|
| 114 |           } while (current.first == current.second && !allow_self_loops); | 
|---|
| 115 |           degrees_left = 0; | 
|---|
| 116 |           out_degrees->clear(); | 
|---|
| 117 |           return; | 
|---|
| 118 |         } | 
|---|
| 119 |  | 
|---|
| 120 |         uniform_int<std::size_t> x(0, out_degrees->size()-1); | 
|---|
| 121 |  | 
|---|
| 122 |         // Select source vertex | 
|---|
| 123 |         source = x(*gen); | 
|---|
| 124 |         if ((*out_degrees)[source].second == 0) { | 
|---|
| 125 |           (*out_degrees)[source] = out_degrees->back(); | 
|---|
| 126 |           out_degrees->pop_back(); | 
|---|
| 127 |           continue; | 
|---|
| 128 |         }  | 
|---|
| 129 |  | 
|---|
| 130 |         // Select target vertex | 
|---|
| 131 |         target = x(*gen); | 
|---|
| 132 |         if ((*out_degrees)[target].second == 0) { | 
|---|
| 133 |           (*out_degrees)[target] = out_degrees->back(); | 
|---|
| 134 |           out_degrees->pop_back(); | 
|---|
| 135 |           continue; | 
|---|
| 136 |         } else if (source != target  | 
|---|
| 137 |                    || (allow_self_loops && (*out_degrees)[source].second > 2)) { | 
|---|
| 138 |           break; | 
|---|
| 139 |         } | 
|---|
| 140 |       } | 
|---|
| 141 |  | 
|---|
| 142 |       // Update degree counts | 
|---|
| 143 |       --(*out_degrees)[source].second; | 
|---|
| 144 |       --degrees_left; | 
|---|
| 145 |       --(*out_degrees)[target].second; | 
|---|
| 146 |       --degrees_left; | 
|---|
| 147 |       current.first  = (*out_degrees)[source].first; | 
|---|
| 148 |       current.second = (*out_degrees)[target].first; | 
|---|
| 149 |     } | 
|---|
| 150 |  | 
|---|
| 151 |     RandomGenerator* gen; | 
|---|
| 152 |     std::size_t n; | 
|---|
| 153 |     shared_ptr<out_degrees_t> out_degrees; | 
|---|
| 154 |     std::size_t degrees_left; | 
|---|
| 155 |     bool allow_self_loops; | 
|---|
| 156 |     value_type current; | 
|---|
| 157 |   }; | 
|---|
| 158 |  | 
|---|
| 159 | } // end namespace boost | 
|---|
| 160 |  | 
|---|
| 161 | #endif // BOOST_GRAPH_PLOD_GENERATOR_HPP | 
|---|