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