File: erdos_renyi_generator.hpp

package info (click to toggle)
boost1.62 1.62.0+dfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 686,420 kB
  • sloc: cpp: 2,609,004; xml: 972,558; ansic: 53,674; python: 32,437; sh: 8,829; asm: 3,071; cs: 2,121; makefile: 964; perl: 859; yacc: 472; php: 132; ruby: 94; f90: 55; sql: 13; csh: 6
file content (195 lines) | stat: -rw-r--r-- 7,122 bytes parent folder | download | duplicates (14)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// Copyright 2004, 2005 The Trustees of Indiana University.

// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  Authors: Jeremiah Willcock
//           Douglas Gregor
//           Andrew Lumsdaine
#ifndef BOOST_GRAPH_ERDOS_RENYI_GENERATOR_HPP
#define BOOST_GRAPH_ERDOS_RENYI_GENERATOR_HPP

#include <boost/assert.hpp>
#include <iterator>
#include <utility>
#include <boost/shared_ptr.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/random/geometric_distribution.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/iterator/iterator_facade.hpp>

namespace boost {

  template<typename RandomGenerator, typename Graph>
  class erdos_renyi_iterator
    : public iterator_facade<
               erdos_renyi_iterator<RandomGenerator, Graph>,
               std::pair<typename graph_traits<Graph>::vertices_size_type,
                         typename graph_traits<Graph>::vertices_size_type>,
               std::input_iterator_tag,
               const 
                 std::pair<typename graph_traits<Graph>::vertices_size_type,
                           typename graph_traits<Graph>::vertices_size_type>&>
  {
    typedef typename graph_traits<Graph>::directed_category directed_category;
    typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
    typedef typename graph_traits<Graph>::edges_size_type edges_size_type;

    BOOST_STATIC_CONSTANT
      (bool,
       is_undirected = (is_base_of<undirected_tag, directed_category>::value));

  public:
    erdos_renyi_iterator() : gen(), n(0), edges(0), allow_self_loops(false) {}
    erdos_renyi_iterator(RandomGenerator& gen, vertices_size_type n,
                         double fraction = 0.0, bool allow_self_loops = false)
      : gen(&gen), n(n), edges(edges_size_type(fraction * n * n)),
        allow_self_loops(allow_self_loops)
    {
      if (is_undirected) edges = edges / 2;
      next();
    }

    erdos_renyi_iterator(RandomGenerator& gen, vertices_size_type n,
                         edges_size_type m, bool allow_self_loops = false)
      : gen(&gen), n(n), edges(m),
        allow_self_loops(allow_self_loops)
    {
      next();
    }

    const std::pair<vertices_size_type, vertices_size_type>&
    dereference() const { return current; }

    void increment() {
      --edges;
      next();
    }

    bool equal(const erdos_renyi_iterator& other) const
    { return edges == other.edges; }

  private:
    void next()
    {
      uniform_int<vertices_size_type> rand_vertex(0, n-1);
      current.first = rand_vertex(*gen);
      do {
        current.second = rand_vertex(*gen);
      } while (current.first == current.second && !allow_self_loops);
    }

    RandomGenerator* gen;
    vertices_size_type n;
    edges_size_type edges;
    bool allow_self_loops;
    std::pair<vertices_size_type, vertices_size_type> current;
  };

  template<typename RandomGenerator, typename Graph>
  class sorted_erdos_renyi_iterator
    : public iterator_facade<
               sorted_erdos_renyi_iterator<RandomGenerator, Graph>,
               std::pair<typename graph_traits<Graph>::vertices_size_type,
                         typename graph_traits<Graph>::vertices_size_type>,
               std::input_iterator_tag,
               const 
                 std::pair<typename graph_traits<Graph>::vertices_size_type,
                           typename graph_traits<Graph>::vertices_size_type>&>
  {
    typedef typename graph_traits<Graph>::directed_category directed_category;
    typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
    typedef typename graph_traits<Graph>::edges_size_type edges_size_type;

    BOOST_STATIC_CONSTANT
      (bool,
       is_undirected = (is_base_of<undirected_tag, directed_category>::value));

  public:
    sorted_erdos_renyi_iterator()
      : gen(), rand_vertex(0.5), n(0), allow_self_loops(false)
      , src((std::numeric_limits<vertices_size_type>::max)()),
        tgt_index(vertices_size_type(-1)), prob(.5)
    { }

    // NOTE: The default probability has been changed to be the same as that
    // used by the geometic distribution. It was previously 0.0, which would
    // cause an assertion.
    sorted_erdos_renyi_iterator(RandomGenerator& gen, vertices_size_type n,
                                double prob = 0.5,
                                bool loops = false)
      : gen(), rand_vertex(1. - prob), n(n), allow_self_loops(loops), src(0)
      , tgt_index(vertices_size_type(-1)), prob(prob)
    {
      this->gen.reset(new uniform_01<RandomGenerator*>(&gen));

      if (prob == 0.0) {src = (std::numeric_limits<vertices_size_type>::max)(); return;}
      next();
    }

    const std::pair<vertices_size_type, vertices_size_type>&
    dereference() const {
      return current;
    }

    bool equal(const sorted_erdos_renyi_iterator& o) const {
      return src == o.src && tgt_index == o.tgt_index;
    }

    void increment() {
      next();
    }

  private:
    void next()
    {
      // In order to get the edges from the generator in sorted order, one
      // effective (but slow) procedure would be to use a
      // bernoulli_distribution for each legal (src, tgt_index) pair.  Because of
      // the O(|V|^2) cost of that, a geometric distribution is used.  The
      // geometric distribution tells how many times the
      // bernoulli_distribution would need to be run until it returns true.
      // Thus, this distribution can be used to step through the edges
      // which are actually present.
      BOOST_ASSERT (src != (std::numeric_limits<vertices_size_type>::max)() &&
                    src != n);
      while (src != n) {
        vertices_size_type increment = rand_vertex(*gen);
        size_t tgt_index_limit =
                 (is_undirected ? src + 1 : n) +
                 (allow_self_loops ? 0 : -1);
        if (tgt_index + increment >= tgt_index_limit) {
          // Overflowed this source; go to the next one and try again.
          ++src;
          // This bias is because the geometric distribution always returns
          // values >=1, and we want to allow 0 as a valid target.
          tgt_index = vertices_size_type(-1);
          continue;
        } else {
          tgt_index += increment;
          current.first = src;
          current.second =
            tgt_index +
            (!allow_self_loops && !is_undirected && tgt_index >= src ? 1 : 0);
          break;
        }
      }
      if (src == n) src = (std::numeric_limits<vertices_size_type>::max)();
    }

    shared_ptr<uniform_01<RandomGenerator*> > gen;
    geometric_distribution<vertices_size_type> rand_vertex;
    vertices_size_type n;
    bool allow_self_loops;
    vertices_size_type src, tgt_index;
    std::pair<vertices_size_type, vertices_size_type> current;
    double prob;
  };

} // end namespace boost

#endif // BOOST_GRAPH_ERDOS_RENYI_GENERATOR_HPP