Chris@16
|
1 // Copyright 2004, 2005 The Trustees of Indiana University.
|
Chris@16
|
2
|
Chris@16
|
3 // Use, modification and distribution is subject to the Boost Software
|
Chris@16
|
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
5 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6
|
Chris@16
|
7 // Authors: Nick Edmonds
|
Chris@16
|
8 // Andrew Lumsdaine
|
Chris@16
|
9 #ifndef BOOST_GRAPH_DISTRIBUTED_RMAT_GENERATOR_HPP
|
Chris@16
|
10 #define BOOST_GRAPH_DISTRIBUTED_RMAT_GENERATOR_HPP
|
Chris@16
|
11
|
Chris@16
|
12 #ifndef BOOST_GRAPH_USE_MPI
|
Chris@16
|
13 #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
|
Chris@16
|
14 #endif
|
Chris@16
|
15
|
Chris@16
|
16 #include <boost/assert.hpp>
|
Chris@16
|
17 #include <boost/graph/parallel/algorithm.hpp>
|
Chris@16
|
18 #include <boost/graph/parallel/process_group.hpp>
|
Chris@16
|
19 #include <math.h>
|
Chris@16
|
20
|
Chris@16
|
21 namespace boost {
|
Chris@16
|
22
|
Chris@16
|
23 // Memory-scalable (amount of memory required will scale down
|
Chris@16
|
24 // linearly as the number of processes increases) generator, which
|
Chris@16
|
25 // requires an MPI process group. Run-time is slightly worse than
|
Chris@16
|
26 // the unique rmat generator. Edge list generated is sorted and
|
Chris@16
|
27 // unique.
|
Chris@16
|
28 template<typename ProcessGroup, typename Distribution,
|
Chris@16
|
29 typename RandomGenerator, typename Graph>
|
Chris@16
|
30 class scalable_rmat_iterator
|
Chris@16
|
31 {
|
Chris@16
|
32 typedef typename graph_traits<Graph>::directed_category directed_category;
|
Chris@16
|
33 typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
|
Chris@16
|
34 typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
|
Chris@16
|
35
|
Chris@16
|
36 public:
|
Chris@16
|
37 typedef std::input_iterator_tag iterator_category;
|
Chris@16
|
38 typedef std::pair<vertices_size_type, vertices_size_type> value_type;
|
Chris@16
|
39 typedef const value_type& reference;
|
Chris@16
|
40 typedef const value_type* pointer;
|
Chris@16
|
41 typedef void difference_type;
|
Chris@16
|
42
|
Chris@16
|
43 // No argument constructor, set to terminating condition
|
Chris@16
|
44 scalable_rmat_iterator()
|
Chris@16
|
45 : gen(), done(true)
|
Chris@16
|
46 { }
|
Chris@16
|
47
|
Chris@16
|
48 // Initialize for edge generation
|
Chris@16
|
49 scalable_rmat_iterator(ProcessGroup pg, Distribution distrib,
|
Chris@16
|
50 RandomGenerator& gen, vertices_size_type n,
|
Chris@16
|
51 edges_size_type m, double a, double b, double c,
|
Chris@16
|
52 double d, bool permute_vertices = true)
|
Chris@16
|
53 : gen(), done(false)
|
Chris@16
|
54 {
|
Chris@16
|
55 BOOST_ASSERT(a + b + c + d == 1);
|
Chris@16
|
56 int id = process_id(pg);
|
Chris@16
|
57
|
Chris@16
|
58 this->gen.reset(new uniform_01<RandomGenerator>(gen));
|
Chris@16
|
59
|
Chris@16
|
60 std::vector<vertices_size_type> vertexPermutation;
|
Chris@16
|
61 if (permute_vertices)
|
Chris@16
|
62 generate_permutation_vector(gen, vertexPermutation, n);
|
Chris@16
|
63
|
Chris@16
|
64 int SCALE = int(floor(log(double(n))/log(2.)));
|
Chris@16
|
65 boost::uniform_01<RandomGenerator> prob(gen);
|
Chris@16
|
66
|
Chris@16
|
67 std::map<value_type, bool> edge_map;
|
Chris@16
|
68
|
Chris@16
|
69 edges_size_type generated = 0, local_edges = 0;
|
Chris@16
|
70 do {
|
Chris@16
|
71 edges_size_type tossed = 0;
|
Chris@16
|
72 do {
|
Chris@16
|
73 vertices_size_type u, v;
|
Chris@16
|
74 boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);
|
Chris@16
|
75
|
Chris@16
|
76 if (permute_vertices) {
|
Chris@16
|
77 u = vertexPermutation[u];
|
Chris@16
|
78 v = vertexPermutation[v];
|
Chris@16
|
79 }
|
Chris@16
|
80
|
Chris@16
|
81 // Lowest vertex number always comes first (this
|
Chris@16
|
82 // means we don't have to worry about i->j and j->i
|
Chris@16
|
83 // being in the edge list)
|
Chris@16
|
84 if (u > v && is_same<directed_category, undirected_tag>::value)
|
Chris@16
|
85 std::swap(u, v);
|
Chris@16
|
86
|
Chris@16
|
87 if (distrib(u) == id || distrib(v) == id) {
|
Chris@16
|
88 if (edge_map.find(std::make_pair(u, v)) == edge_map.end()) {
|
Chris@16
|
89 edge_map[std::make_pair(u, v)] = true;
|
Chris@16
|
90 local_edges++;
|
Chris@16
|
91 } else {
|
Chris@16
|
92 tossed++;
|
Chris@16
|
93
|
Chris@16
|
94 // special case - if both u and v are on same
|
Chris@16
|
95 // proc, ++ twice, since we divide by two (to
|
Chris@16
|
96 // cover the two process case)
|
Chris@16
|
97 if (distrib(u) == id && distrib(v) == id)
|
Chris@16
|
98 tossed++;
|
Chris@16
|
99 }
|
Chris@16
|
100 }
|
Chris@16
|
101 generated++;
|
Chris@16
|
102
|
Chris@16
|
103 } while (generated < m);
|
Chris@16
|
104 tossed = all_reduce(pg, tossed, boost::parallel::sum<vertices_size_type>());
|
Chris@16
|
105 generated -= (tossed / 2);
|
Chris@16
|
106 } while (generated < m);
|
Chris@16
|
107 // NGE - Asking for more than n^2 edges will result in an infinite loop here
|
Chris@16
|
108 // Asking for a value too close to n^2 edges may as well
|
Chris@16
|
109
|
Chris@16
|
110 values.reserve(local_edges);
|
Chris@16
|
111 typename std::map<value_type, bool>::reverse_iterator em_end = edge_map.rend();
|
Chris@16
|
112 for (typename std::map<value_type, bool>::reverse_iterator em_i = edge_map.rbegin();
|
Chris@16
|
113 em_i != em_end ;
|
Chris@16
|
114 ++em_i) {
|
Chris@16
|
115 values.push_back(em_i->first);
|
Chris@16
|
116 }
|
Chris@16
|
117
|
Chris@16
|
118 current = values.back();
|
Chris@16
|
119 values.pop_back();
|
Chris@16
|
120 }
|
Chris@16
|
121
|
Chris@16
|
122 reference operator*() const { return current; }
|
Chris@16
|
123 pointer operator->() const { return ¤t; }
|
Chris@16
|
124
|
Chris@16
|
125 scalable_rmat_iterator& operator++()
|
Chris@16
|
126 {
|
Chris@16
|
127 if (!values.empty()) {
|
Chris@16
|
128 current = values.back();
|
Chris@16
|
129 values.pop_back();
|
Chris@16
|
130 } else
|
Chris@16
|
131 done = true;
|
Chris@16
|
132
|
Chris@16
|
133 return *this;
|
Chris@16
|
134 }
|
Chris@16
|
135
|
Chris@16
|
136 scalable_rmat_iterator operator++(int)
|
Chris@16
|
137 {
|
Chris@16
|
138 scalable_rmat_iterator temp(*this);
|
Chris@16
|
139 ++(*this);
|
Chris@16
|
140 return temp;
|
Chris@16
|
141 }
|
Chris@16
|
142
|
Chris@16
|
143 bool operator==(const scalable_rmat_iterator& other) const
|
Chris@16
|
144 {
|
Chris@16
|
145 return values.empty() && other.values.empty() && done && other.done;
|
Chris@16
|
146 }
|
Chris@16
|
147
|
Chris@16
|
148 bool operator!=(const scalable_rmat_iterator& other) const
|
Chris@16
|
149 { return !(*this == other); }
|
Chris@16
|
150
|
Chris@16
|
151 private:
|
Chris@16
|
152
|
Chris@16
|
153 // Parameters
|
Chris@16
|
154 shared_ptr<uniform_01<RandomGenerator> > gen;
|
Chris@16
|
155
|
Chris@16
|
156 // Internal data structures
|
Chris@16
|
157 std::vector<value_type> values;
|
Chris@16
|
158 value_type current;
|
Chris@16
|
159 bool done;
|
Chris@16
|
160 };
|
Chris@16
|
161
|
Chris@16
|
162 } // end namespace boost
|
Chris@16
|
163
|
Chris@16
|
164 #endif // BOOST_GRAPH_DISTRIBUTED_RMAT_GENERATOR_HPP
|