ossrv_pub/boost_apis/boost/graph/plod_generator.hpp
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     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 &current; }
       
    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