123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- // Copyright 2004-2006 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: Douglas Gregor
- // Andrew Lumsdaine
- #ifndef BOOST_GRAPH_PLOD_GENERATOR_HPP
- #define BOOST_GRAPH_PLOD_GENERATOR_HPP
- #include <iterator>
- #include <utility>
- #include <boost/random/uniform_int.hpp>
- #include <boost/shared_ptr.hpp>
- #include <boost/graph/graph_traits.hpp>
- #include <vector>
- #include <map>
- #include <boost/config/no_tr1/cmath.hpp>
- #include <boost/mpl/if.hpp>
- namespace boost
- {
- template < typename RandomGenerator > class out_directed_plod_iterator
- {
- public:
- typedef std::forward_iterator_tag iterator_category;
- typedef std::pair< std::size_t, std::size_t > value_type;
- typedef const value_type& reference;
- typedef const value_type* pointer;
- typedef std::ptrdiff_t difference_type;
- out_directed_plod_iterator() : gen(0), at_end(true) {}
- out_directed_plod_iterator(RandomGenerator& gen, std::size_t n,
- double alpha, double beta, bool allow_self_loops)
- : gen(&gen)
- , n(n)
- , alpha(alpha)
- , beta(beta)
- , allow_self_loops(allow_self_loops)
- , at_end(false)
- , degree(0)
- , current(0, 0)
- {
- using std::pow;
- uniform_int< std::size_t > x(0, n - 1);
- std::size_t xv = x(gen);
- degree = (xv == 0 ? 0 : std::size_t(beta * pow(xv, -alpha)));
- }
- reference operator*() const { return current; }
- pointer operator->() const { return ¤t; }
- out_directed_plod_iterator& operator++()
- {
- using std::pow;
- uniform_int< std::size_t > x(0, n - 1);
- // Continue stepping through source nodes until the
- // (out)degree is > 0
- while (degree == 0)
- {
- // Step to the next source node. If we've gone past the
- // number of nodes we're responsible for, we're done.
- if (++current.first >= n)
- {
- at_end = true;
- return *this;
- }
- std::size_t xv = x(*gen);
- degree = (xv == 0 ? 0 : std::size_t(beta * pow(xv, -alpha)));
- }
- do
- {
- current.second = x(*gen);
- } while (current.first == current.second && !allow_self_loops);
- --degree;
- return *this;
- }
- out_directed_plod_iterator operator++(int)
- {
- out_directed_plod_iterator temp(*this);
- ++(*this);
- return temp;
- }
- bool operator==(const out_directed_plod_iterator& other) const
- {
- return at_end == other.at_end;
- }
- bool operator!=(const out_directed_plod_iterator& other) const
- {
- return !(*this == other);
- }
- private:
- RandomGenerator* gen;
- std::size_t n;
- double alpha;
- double beta;
- bool allow_self_loops;
- bool at_end;
- std::size_t degree;
- value_type current;
- };
- template < typename RandomGenerator > class undirected_plod_iterator
- {
- typedef std::vector< std::pair< std::size_t, std::size_t > > out_degrees_t;
- public:
- typedef std::input_iterator_tag iterator_category;
- typedef std::pair< std::size_t, std::size_t > value_type;
- typedef const value_type& reference;
- typedef const value_type* pointer;
- typedef std::ptrdiff_t difference_type;
- undirected_plod_iterator()
- : gen(0), out_degrees(), degrees_left(0), allow_self_loops(false)
- {
- }
- undirected_plod_iterator(RandomGenerator& gen, std::size_t n, double alpha,
- double beta, bool allow_self_loops = false)
- : gen(&gen)
- , n(n)
- , out_degrees(new out_degrees_t)
- , degrees_left(0)
- , allow_self_loops(allow_self_loops)
- {
- using std::pow;
- uniform_int< std::size_t > x(0, n - 1);
- for (std::size_t i = 0; i != n; ++i)
- {
- std::size_t xv = x(gen);
- std::size_t degree
- = (xv == 0 ? 0 : std::size_t(beta * pow(xv, -alpha)));
- if (degree == 0)
- degree = 1;
- else if (degree >= n)
- degree = n - 1;
- out_degrees->push_back(std::make_pair(i, degree));
- degrees_left += degree;
- }
- next();
- }
- reference operator*() const { return current; }
- pointer operator->() const { return ¤t; }
- undirected_plod_iterator& operator++()
- {
- next();
- return *this;
- }
- undirected_plod_iterator operator++(int)
- {
- undirected_plod_iterator temp(*this);
- ++(*this);
- return temp;
- }
- bool operator==(const undirected_plod_iterator& other) const
- {
- return degrees_left == other.degrees_left;
- }
- bool operator!=(const undirected_plod_iterator& other) const
- {
- return !(*this == other);
- }
- private:
- void next()
- {
- std::size_t source, target;
- while (true)
- {
- /* We may get to the point where we can't actually find any
- new edges, so we just add some random edge and set the
- degrees left = 0 to signal termination. */
- if (out_degrees->size() < 2)
- {
- uniform_int< std::size_t > x(0, n - 1);
- current.first = x(*gen);
- do
- {
- current.second = x(*gen);
- } while (current.first == current.second && !allow_self_loops);
- degrees_left = 0;
- out_degrees->clear();
- return;
- }
- uniform_int< std::size_t > x(0, out_degrees->size() - 1);
- // Select source vertex
- source = x(*gen);
- if ((*out_degrees)[source].second == 0)
- {
- (*out_degrees)[source] = out_degrees->back();
- out_degrees->pop_back();
- continue;
- }
- // Select target vertex
- target = x(*gen);
- if ((*out_degrees)[target].second == 0)
- {
- (*out_degrees)[target] = out_degrees->back();
- out_degrees->pop_back();
- continue;
- }
- else if (source != target
- || (allow_self_loops && (*out_degrees)[source].second > 2))
- {
- break;
- }
- }
- // Update degree counts
- --(*out_degrees)[source].second;
- --degrees_left;
- --(*out_degrees)[target].second;
- --degrees_left;
- current.first = (*out_degrees)[source].first;
- current.second = (*out_degrees)[target].first;
- }
- RandomGenerator* gen;
- std::size_t n;
- shared_ptr< out_degrees_t > out_degrees;
- std::size_t degrees_left;
- bool allow_self_loops;
- value_type current;
- };
- template < typename RandomGenerator, typename Graph >
- class plod_iterator
- : public mpl::if_<
- is_convertible< typename graph_traits< Graph >::directed_category,
- directed_tag >,
- out_directed_plod_iterator< RandomGenerator >,
- undirected_plod_iterator< RandomGenerator > >::type
- {
- typedef typename mpl::if_<
- is_convertible< typename graph_traits< Graph >::directed_category,
- directed_tag >,
- out_directed_plod_iterator< RandomGenerator >,
- undirected_plod_iterator< RandomGenerator > >::type inherited;
- public:
- plod_iterator() : inherited() {}
- plod_iterator(RandomGenerator& gen, std::size_t n, double alpha,
- double beta, bool allow_self_loops = false)
- : inherited(gen, n, alpha, beta, allow_self_loops)
- {
- }
- };
- } // end namespace boost
- #endif // BOOST_GRAPH_PLOD_GENERATOR_HPP
|