1 // Copyright (C) 2007 Douglas Gregor
3 // Use, modification and distribution is subject to the Boost Software
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
7 #include <boost/graph/use_mpi.hpp>
8 #include <boost/config.hpp>
9 #include <boost/throw_exception.hpp>
10 #include <boost/graph/distributed/adjacency_list.hpp>
11 #include <boost/graph/distributed/mpi_process_group.hpp>
12 #include <boost/core/lightweight_test.hpp>
13 #include <boost/random/linear_congruential.hpp>
14 #include <boost/graph/erdos_renyi_generator.hpp>
15 #include <boost/lexical_cast.hpp>
18 using namespace boost
;
19 using boost::graph::distributed::mpi_process_group
;
21 #ifdef BOOST_NO_EXCEPTIONS
23 boost::throw_exception(std::exception
const& ex
)
25 std::cout
<< ex
.what() << std::endl
;
31 int main(int argc
, char** argv
)
33 boost::mpi::environment
env(argc
, argv
);
37 int seed
= std::time(0);
38 int immediate_response_percent
= 10;
40 if (argc
> 1) n
= lexical_cast
<int>(argv
[1]);
41 if (argc
> 2) p
= lexical_cast
<double>(argv
[2]);
42 if (argc
> 3) seed
= lexical_cast
<int>(argv
[3]);
44 typedef adjacency_list
<listS
,
45 distributedS
<mpi_process_group
, vecS
>,
46 bidirectionalS
> Graph
;
49 int rank
= process_id(pg
);
50 int numprocs
= num_processes(pg
);
51 bool i_am_root
= rank
== 0;
54 broadcast(pg
, seed
, 0);
56 // Random number generator
58 minstd_rand require_response_gen
;
61 std::cout
<< "n = " << n
<< ", p = " << p
<< ", seed = " << seed
62 << "\nBuilding graph with the iterator constructor... ";
66 // Build a graph using the iterator constructor, where each of the
67 // processors has exactly the same information.
69 Graph
g1(erdos_renyi_iterator
<minstd_rand
, Graph
>(gen
, n
, p
),
70 erdos_renyi_iterator
<minstd_rand
, Graph
>(),
71 n
, pg
, Graph::graph_property_type());
72 // NGE: Grrr, the default graph property is needed to resolve an
73 // ambiguous overload in the adjaceny list constructor
75 // Build another, identical graph using add_edge
77 std::cout
<< "done.\nBuilding graph with add_edge from the root...";
82 require_response_gen
.seed(1);
85 // The root will add all of the edges, some percentage of which
86 // will require an immediate response from the owner of the edge.
87 for (erdos_renyi_iterator
<minstd_rand
, Graph
> first(gen
, n
, p
), last
;
88 first
!= last
; ++first
) {
89 Graph::lazy_add_edge lazy
90 = add_edge(vertex(first
->first
, g2
), vertex(first
->second
, g2
), g2
);
92 if ((int)require_response_gen() % 100 < immediate_response_percent
) {
93 // Send out-of-band to require a response
94 std::pair
<graph_traits
<Graph
>::edge_descriptor
, bool> result(lazy
);
95 BOOST_TEST(source(result
.first
, g2
) == vertex(first
->first
, g2
));
96 BOOST_TEST(target(result
.first
, g2
) == vertex(first
->second
, g2
));
102 std::cout
<< "synchronizing...";
108 // Verify that the two graphs are indeed identical.
110 std::cout
<< "done.\nVerifying graphs...";
114 // Check the number of vertices
115 if (num_vertices(g1
) != num_vertices(g2
)) {
116 std::cerr
<< g1
.processor() << ": g1 has " << num_vertices(g1
)
117 << " vertices, g2 has " << num_vertices(g2
) << " vertices.\n";
118 communicator(pg
).abort(-1);
121 // Check the number of edges
122 if (num_edges(g1
) != num_edges(g2
)) {
123 std::cerr
<< g1
.processor() << ": g1 has " << num_edges(g1
)
124 << " edges, g2 has " << num_edges(g2
) << " edges.\n";
125 communicator(pg
).abort(-1);
128 // Check the in-degree and out-degree of each vertex
129 graph_traits
<Graph
>::vertex_iterator vfirst1
, vlast1
, vfirst2
, vlast2
;
130 boost::tie(vfirst1
, vlast1
) = vertices(g1
);
131 boost::tie(vfirst2
, vlast2
) = vertices(g2
);
132 for(; vfirst1
!= vlast1
&& vfirst2
!= vlast2
; ++vfirst1
, ++vfirst2
) {
133 if (out_degree(*vfirst1
, g1
) != out_degree(*vfirst2
, g2
)) {
134 std::cerr
<< g1
.processor() << ": out-degree mismatch ("
135 << out_degree(*vfirst1
, g1
) << " vs. "
136 << out_degree(*vfirst2
, g2
) << ").\n";
137 communicator(pg
).abort(-1);
140 if (in_degree(*vfirst1
, g1
) != in_degree(*vfirst2
, g2
)) {
141 std::cerr
<< g1
.processor() << ": in-degree mismatch ("
142 << in_degree(*vfirst1
, g1
) << " vs. "
143 << in_degree(*vfirst2
, g2
) << ").\n";
144 communicator(pg
).abort(-1);
148 // TODO: Check the actual edge targets
150 // Build another, identical graph using add_edge
152 std::cout
<< "done.\nBuilding graph with add_edge from everywhere...";
157 require_response_gen
.seed(1);
161 // Each processor will take a chunk of incoming edges and add
162 // them. Some percentage of the edge additions will require an
163 // immediate response from the owner of the edge. This should
164 // create a lot of traffic when building the graph, but should
165 // produce a graph identical to the other graphs.
166 typedef graph_traits
<Graph
>::edges_size_type edges_size_type
;
168 erdos_renyi_iterator
<minstd_rand
, Graph
> first(gen
, n
, p
);
169 edges_size_type chunk_size
= edges_size_type(p
*n
*n
)/numprocs
;
170 edges_size_type start
= chunk_size
* rank
;
171 edges_size_type remaining_edges
=
172 (rank
< numprocs
- 1? chunk_size
173 : edges_size_type(p
*n
*n
) - start
);
175 // Spin the generator to the first edge we're responsible for
176 for (; start
; ++first
, --start
) ;
178 for (; remaining_edges
; --remaining_edges
, ++first
) {
179 Graph::lazy_add_edge lazy
180 = add_edge(vertex(first
->first
, g3
), vertex(first
->second
, g3
), g3
);
182 if ((int)require_response_gen() % 100 < immediate_response_percent
) {
183 // Send out-of-band to require a response
184 std::pair
<graph_traits
<Graph
>::edge_descriptor
, bool> result(lazy
);
185 BOOST_TEST(source(result
.first
, g3
) == vertex(first
->first
, g3
));
186 BOOST_TEST(target(result
.first
, g3
) == vertex(first
->second
, g3
));
192 std::cout
<< "synchronizing...";
198 // Verify that the two graphs are indeed identical.
200 std::cout
<< "done.\nVerifying graphs...";
204 // Check the number of vertices
205 if (num_vertices(g1
) != num_vertices(g3
)) {
206 std::cerr
<< g1
.processor() << ": g1 has " << num_vertices(g1
)
207 << " vertices, g3 has " << num_vertices(g3
) << " vertices.\n";
208 communicator(pg
).abort(-1);
211 // Check the number of edges
212 if (num_edges(g1
) != num_edges(g3
)) {
213 std::cerr
<< g1
.processor() << ": g1 has " << num_edges(g1
)
214 << " edges, g3 has " << num_edges(g3
) << " edges.\n";
215 communicator(pg
).abort(-1);
218 // Check the in-degree and out-degree of each vertex
219 boost::tie(vfirst1
, vlast1
) = vertices(g1
);
220 boost::tie(vfirst2
, vlast2
) = vertices(g3
);
221 for(; vfirst1
!= vlast1
&& vfirst2
!= vlast2
; ++vfirst1
, ++vfirst2
) {
222 if (out_degree(*vfirst1
, g1
) != out_degree(*vfirst2
, g3
)) {
223 std::cerr
<< g1
.processor() << ": out-degree mismatch ("
224 << out_degree(*vfirst1
, g1
) << " vs. "
225 << out_degree(*vfirst2
, g3
) << ").\n";
226 communicator(pg
).abort(-1);
229 if (in_degree(*vfirst1
, g1
) != in_degree(*vfirst2
, g3
)) {
230 std::cerr
<< g1
.processor() << ": in-degree mismatch ("
231 << in_degree(*vfirst1
, g1
) << " vs. "
232 << in_degree(*vfirst2
, g3
) << ").\n";
233 communicator(pg
).abort(-1);
237 // TODO: Check the actual edge targets
240 std::cout
<< "done.\n";
244 return boost::report_errors();