| 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
 |