epoc32/include/stdapis/boost/graph/erdos_renyi_generator.hpp
author William Roberts <williamr@symbian.org>
Wed, 31 Mar 2010 12:27:01 +0100 (2010-03-31)
branchSymbian2
changeset 3 e1b950c65cb4
permissions -rw-r--r--
Attempt to represent the S^2->S^3 header reorganisation as a series of "hg rename" operations
williamr@2
     1
// Copyright 2004, 2005 The Trustees of Indiana University.
williamr@2
     2
williamr@2
     3
// Distributed under the Boost Software License, Version 1.0.
williamr@2
     4
// (See accompanying file LICENSE_1_0.txt or copy at
williamr@2
     5
// http://www.boost.org/LICENSE_1_0.txt)
williamr@2
     6
williamr@2
     7
//  Authors: Jeremiah Willcock
williamr@2
     8
//           Douglas Gregor
williamr@2
     9
//           Andrew Lumsdaine
williamr@2
    10
#ifndef BOOST_GRAPH_ERDOS_RENYI_GENERATOR_HPP
williamr@2
    11
#define BOOST_GRAPH_ERDOS_RENYI_GENERATOR_HPP
williamr@2
    12
williamr@2
    13
#include <cassert>
williamr@2
    14
#include <iterator>
williamr@2
    15
#include <utility>
williamr@2
    16
#include <boost/shared_ptr.hpp>
williamr@2
    17
#include <boost/random/uniform_int.hpp>
williamr@2
    18
#include <boost/graph/graph_traits.hpp>
williamr@2
    19
#include <boost/random/geometric_distribution.hpp>
williamr@2
    20
#include <boost/type_traits/is_base_and_derived.hpp>
williamr@2
    21
#include <boost/type_traits/is_same.hpp>
williamr@2
    22
#include <cmath>
williamr@2
    23
williamr@2
    24
namespace boost {
williamr@2
    25
williamr@2
    26
  template<typename RandomGenerator, typename Graph>
williamr@2
    27
  class erdos_renyi_iterator
williamr@2
    28
  {
williamr@2
    29
    typedef typename graph_traits<Graph>::directed_category directed_category;
williamr@2
    30
    typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
williamr@2
    31
    typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
williamr@2
    32
williamr@2
    33
    BOOST_STATIC_CONSTANT
williamr@2
    34
      (bool,
williamr@2
    35
       is_undirected = (is_base_and_derived<undirected_tag,
williamr@2
    36
                                            directed_category>::value
williamr@2
    37
                        || is_same<undirected_tag, directed_category>::value));
williamr@2
    38
williamr@2
    39
  public:
williamr@2
    40
    typedef std::input_iterator_tag iterator_category;
williamr@2
    41
    typedef std::pair<vertices_size_type, vertices_size_type> value_type;
williamr@2
    42
    typedef const value_type& reference;
williamr@2
    43
    typedef const value_type* pointer;
williamr@2
    44
    typedef void difference_type;
williamr@2
    45
williamr@2
    46
    erdos_renyi_iterator() : gen(), n(0), edges(0), allow_self_loops(false) {}
williamr@2
    47
    erdos_renyi_iterator(RandomGenerator& gen, vertices_size_type n, 
williamr@2
    48
                         double fraction = 0.0, bool allow_self_loops = false)
williamr@2
    49
      : gen(&gen), n(n), edges(edges_size_type(fraction * n * n)),
williamr@2
    50
        allow_self_loops(allow_self_loops)
williamr@2
    51
    { 
williamr@2
    52
      if (is_undirected) edges = edges / 2;
williamr@2
    53
      next(); 
williamr@2
    54
    }
williamr@2
    55
williamr@2
    56
    erdos_renyi_iterator(RandomGenerator& gen, vertices_size_type n, 
williamr@2
    57
                         edges_size_type m, bool allow_self_loops = false)
williamr@2
    58
      : gen(&gen), n(n), edges(m),
williamr@2
    59
        allow_self_loops(allow_self_loops)
williamr@2
    60
    { 
williamr@2
    61
      next(); 
williamr@2
    62
    }
williamr@2
    63
williamr@2
    64
    reference operator*() const { return current; }
williamr@2
    65
    pointer operator->() const { return &current; }
williamr@2
    66
    
williamr@2
    67
    erdos_renyi_iterator& operator++()
williamr@2
    68
    { 
williamr@2
    69
      --edges;
williamr@2
    70
      next();
williamr@2
    71
      return *this;
williamr@2
    72
    }
williamr@2
    73
williamr@2
    74
    erdos_renyi_iterator operator++(int)
williamr@2
    75
    {
williamr@2
    76
      erdos_renyi_iterator temp(*this);
williamr@2
    77
      ++(*this);
williamr@2
    78
      return temp;
williamr@2
    79
    }
williamr@2
    80
williamr@2
    81
    bool operator==(const erdos_renyi_iterator& other) const
williamr@2
    82
    { return edges == other.edges; }
williamr@2
    83
williamr@2
    84
    bool operator!=(const erdos_renyi_iterator& other) const
williamr@2
    85
    { return !(*this == other); }
williamr@2
    86
williamr@2
    87
  private:
williamr@2
    88
    void next()
williamr@2
    89
    {
williamr@2
    90
      uniform_int<vertices_size_type> rand_vertex(0, n-1);
williamr@2
    91
      current.first = rand_vertex(*gen);
williamr@2
    92
      do {
williamr@2
    93
        current.second = rand_vertex(*gen);
williamr@2
    94
      } while (current.first == current.second && !allow_self_loops);
williamr@2
    95
    }
williamr@2
    96
williamr@2
    97
    RandomGenerator* gen;
williamr@2
    98
    vertices_size_type n;
williamr@2
    99
    edges_size_type edges;
williamr@2
   100
    bool allow_self_loops;
williamr@2
   101
    value_type current;
williamr@2
   102
  };
williamr@2
   103
williamr@2
   104
  template<typename RandomGenerator, typename Graph>
williamr@2
   105
  class sorted_erdos_renyi_iterator
williamr@2
   106
  {
williamr@2
   107
    typedef typename graph_traits<Graph>::directed_category directed_category;
williamr@2
   108
    typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
williamr@2
   109
    typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
williamr@2
   110
williamr@2
   111
    BOOST_STATIC_CONSTANT
williamr@2
   112
      (bool,
williamr@2
   113
       is_undirected = (is_base_and_derived<undirected_tag,
williamr@2
   114
                                            directed_category>::value
williamr@2
   115
                        || is_same<undirected_tag, directed_category>::value));
williamr@2
   116
williamr@2
   117
  public:
williamr@2
   118
    typedef std::input_iterator_tag iterator_category;
williamr@2
   119
    typedef std::pair<vertices_size_type, vertices_size_type> value_type;
williamr@2
   120
    typedef const value_type& reference;
williamr@2
   121
    typedef const value_type* pointer;
williamr@2
   122
    typedef void difference_type;
williamr@2
   123
williamr@2
   124
    sorted_erdos_renyi_iterator()
williamr@2
   125
      : gen(), rand_vertex(0.5), n(0), allow_self_loops(false),
williamr@2
   126
    src((std::numeric_limits<vertices_size_type>::max)()), tgt(0), prob(0) {}
williamr@2
   127
    sorted_erdos_renyi_iterator(RandomGenerator& gen, vertices_size_type n, 
williamr@2
   128
                    double prob = 0.0, 
williamr@2
   129
                                bool allow_self_loops = false)
williamr@2
   130
      : gen(),
williamr@2
   131
        // The "1.0 - prob" in the next line is to work around a Boost.Random
williamr@2
   132
        // (and TR1) bug in the specification of geometric_distribution.  It
williamr@2
   133
        // should be replaced by "prob" when the issue is fixed.
williamr@2
   134
        rand_vertex(1.0 - prob),
williamr@2
   135
    n(n), allow_self_loops(allow_self_loops), src(0), tgt(0), prob(prob)
williamr@2
   136
    { 
williamr@2
   137
      this->gen.reset(new uniform_01<RandomGenerator>(gen));
williamr@2
   138
williamr@2
   139
      if (prob == 0.0) {src = (std::numeric_limits<vertices_size_type>::max)(); return;}
williamr@2
   140
      next(); 
williamr@2
   141
    }
williamr@2
   142
williamr@2
   143
    reference operator*() const { return current; }
williamr@2
   144
    pointer operator->() const { return &current; }
williamr@2
   145
    
williamr@2
   146
    sorted_erdos_renyi_iterator& operator++()
williamr@2
   147
    { 
williamr@2
   148
      next();
williamr@2
   149
      return *this;
williamr@2
   150
    }
williamr@2
   151
williamr@2
   152
    sorted_erdos_renyi_iterator operator++(int)
williamr@2
   153
    {
williamr@2
   154
      sorted_erdos_renyi_iterator temp(*this);
williamr@2
   155
      ++(*this);
williamr@2
   156
      return temp;
williamr@2
   157
    }
williamr@2
   158
williamr@2
   159
    bool operator==(const sorted_erdos_renyi_iterator& other) const
williamr@2
   160
    { return src == other.src && tgt == other.tgt; }
williamr@2
   161
williamr@2
   162
    bool operator!=(const sorted_erdos_renyi_iterator& other) const
williamr@2
   163
    { return !(*this == other); }
williamr@2
   164
williamr@2
   165
  private:
williamr@2
   166
    void next()
williamr@2
   167
    {
williamr@2
   168
      using std::sqrt;
williamr@2
   169
      using std::floor;
williamr@2
   170
williamr@2
   171
      // In order to get the edges from the generator in sorted order, one
williamr@2
   172
      // effective (but slow) procedure would be to use a
williamr@2
   173
      // bernoulli_distribution for each legal (src, tgt) pair.  Because of the
williamr@2
   174
      // O(n^2) cost of that, a geometric distribution is used.  The geometric
williamr@2
   175
      // distribution tells how many times the bernoulli_distribution would
williamr@2
   176
      // need to be run until it returns true.  Thus, this distribution can be
williamr@2
   177
      // used to step through the edges which are actually present.  Everything
williamr@2
   178
      // beyond "tgt += increment" is done to effectively convert linear
williamr@2
   179
      // indexing (the partial sums of the geometric distribution output) into
williamr@2
   180
      // graph edges.
williamr@2
   181
      assert (src != (std::numeric_limits<vertices_size_type>::max)());
williamr@2
   182
      vertices_size_type increment = rand_vertex(*gen);
williamr@2
   183
      tgt += increment;
williamr@2
   184
      if (is_undirected) {
williamr@2
   185
    // Update src and tgt based on position of tgt
williamr@2
   186
    // Basically, we want the greatest src_increment such that (in \bbQ):
williamr@2
   187
    // src_increment * (src + allow_self_loops + src_increment - 1/2) <= tgt
williamr@2
   188
    // The result of the LHS of this, evaluated with the computed
williamr@2
   189
    // src_increment, is then subtracted from tgt
williamr@2
   190
    double src_minus_half = (src + allow_self_loops) - 0.5;
williamr@2
   191
    double disc = src_minus_half * src_minus_half + 2 * tgt;
williamr@2
   192
    double src_increment_fp = floor(sqrt(disc) - src_minus_half);
williamr@2
   193
    vertices_size_type src_increment = vertices_size_type(src_increment_fp);
williamr@2
   194
    if (src + src_increment >= n) {
williamr@2
   195
      src = n;
williamr@2
   196
    } else {
williamr@2
   197
      tgt -= (src + allow_self_loops) * src_increment + 
williamr@2
   198
         src_increment * (src_increment - 1) / 2;
williamr@2
   199
      src += src_increment;
williamr@2
   200
    }
williamr@2
   201
      } else {
williamr@2
   202
    // Number of out edge positions possible from each vertex in this graph
williamr@2
   203
    vertices_size_type possible_out_edges = n - (allow_self_loops ? 0 : 1);
williamr@2
   204
    src += (std::min)(n - src, tgt / possible_out_edges);
williamr@2
   205
    tgt %= possible_out_edges;
williamr@2
   206
      }
williamr@2
   207
      // Set end of graph code so (src, tgt) will be the same as for the end
williamr@2
   208
      // sorted_erdos_renyi_iterator
williamr@2
   209
      if (src >= n) {src = (std::numeric_limits<vertices_size_type>::max)(); tgt = 0;}
williamr@2
   210
      // Copy (src, tgt) into current
williamr@2
   211
      current.first = src;
williamr@2
   212
      current.second = tgt;
williamr@2
   213
      // Adjust for (src, src) edge being forbidden
williamr@2
   214
      if (!allow_self_loops && tgt >= src) ++current.second;
williamr@2
   215
    }
williamr@2
   216
williamr@2
   217
    shared_ptr<uniform_01<RandomGenerator> > gen;
williamr@2
   218
    geometric_distribution<vertices_size_type> rand_vertex;
williamr@2
   219
    vertices_size_type n;
williamr@2
   220
    bool allow_self_loops;
williamr@2
   221
    vertices_size_type src, tgt;
williamr@2
   222
    value_type current;
williamr@2
   223
    double prob;
williamr@2
   224
  };
williamr@2
   225
williamr@2
   226
} // end namespace boost
williamr@2
   227
williamr@2
   228
#endif // BOOST_GRAPH_ERDOS_RENYI_GENERATOR_HPP