1 // Copyright (C) 2004-2008 The Trustees of Indiana University.
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 // Authors: Douglas Gregor
10 #include <boost/graph/use_mpi.hpp>
11 #include <boost/config.hpp>
12 #include <boost/throw_exception.hpp>
13 #include <boost/graph/distributed/adjacency_list.hpp>
14 #include <boost/graph/distributed/mpi_process_group.hpp>
15 #include <boost/graph/distributed/local_subgraph.hpp>
16 #include <boost/graph/parallel/distribution.hpp>
19 #include <boost/test/minimal.hpp>
21 #ifdef BOOST_NO_EXCEPTIONS
23 boost::throw_exception(std::exception
const& ex
)
25 std::cout
<< ex
.what() << std::endl
;
30 using namespace boost
;
31 using boost::graph::distributed::mpi_process_group
;
33 template<typename Graph
>
36 typedef typename graph_traits
<Graph
>::edge_descriptor argument_type
;
37 typedef bool result_type
;
39 result_type
operator()(argument_type
) { return false; }
42 int test_main(int argc
, char** argv
)
44 boost::mpi::environment
env(argc
, argv
);
47 parallel::block
dist(pg
, 20);
49 typedef adjacency_list
<listS
, distributedS
<mpi_process_group
, vecS
>,
50 bidirectionalS
> Graph1
;
51 typedef adjacency_list
<listS
, distributedS
<mpi_process_group
, vecS
>,
53 typedef adjacency_list
<listS
, distributedS
<mpi_process_group
, vecS
>,
56 if (num_processes(pg
) > 20) return -1;
58 if (process_id(pg
) == 0) std::cout
<< "Graph 1------------------\n";
60 std::cout
<< "Processor #" << process_id(pg
) << ": "
61 << dist
.block_size(20) << " vertices." << std::endl
;
65 // if (process_id(pg) == num_processes(pg)() - 1)
68 graph_traits
<Graph1
>::vertex_iterator v
, v_end
;
70 for (boost::tie(v
, v_end
) = vertices(g1
); v
!= v_end
; ++v
) {
71 std::cout
<< "Processor #" << process_id(pg
) << ": vertex " << ++counter
79 graph_traits
<Graph1
>::vertex_descriptor other
= *v
;
80 other
.owner
= (other
.owner
+ 1) % num_processes(pg
);
82 add_edge(*v
, other
, g1
);
84 std::cout
<< "Adding edge from processor " << process_id(pg
)
85 << " to processor " << other
.owner
<< std::endl
;
89 assert((std::size_t)std::distance(edges(g1
).first
, edges(g1
).second
) == num_vertices(g1
));
91 if (num_vertices(g1
) >= 2) {
92 graph_traits
<Graph1
>::vertex_iterator vi
= vertices(g1
).first
;
93 graph_traits
<Graph1
>::vertex_descriptor u
= *vi
++;
94 graph_traits
<Graph1
>::vertex_descriptor v
= *vi
++;
96 assert(out_degree(u
, g1
) == 2);
97 assert(in_degree(v
, g1
) == 1);
100 int prior_processor
= (process_id(pg
) + num_processes(pg
) - 1)
103 std::size_t vertices_in_prior
= (n
/ num_processes(pg
))
104 + (n
% num_processes(pg
) > prior_processor
? 1 : 0);
106 graph_traits
<Graph1
>::vertex_descriptor u
= *vertices(g1
).first
;
107 if (in_degree(u
, g1
) != vertices_in_prior
) {
108 std::cout
<< "Processor #" << process_id(pg
) << ": " << in_degree(u
, g1
)
109 << " vs. " << vertices_in_prior
<< std::endl
;
111 assert(in_degree(u
, g1
) == vertices_in_prior
);
112 std::cout
<< "Processor #" << process_id(pg
) << ": " << num_edges(g1
)
115 local_subgraph
<Graph1
> local_g1(g1
);
118 if (num_vertices(local_g1
) > 0) {
119 out_edges(*vertices(local_g1
).first
, local_g1
);
120 in_edges(*vertices(local_g1
).first
, local_g1
);
121 adjacent_vertices(*vertices(local_g1
).first
, local_g1
);
123 remove_out_edge_if(*vertices(g1
).first
, never
<Graph1
>(), g1
);
124 remove_in_edge_if(*vertices(g1
).first
, never
<Graph1
>(), g1
);
125 clear_out_edges(*vertices(g1
).first
, g1
);
126 clear_in_edges(*vertices(g1
).first
, g1
);
127 clear_vertex(*vertices(g1
).first
, g1
);
128 remove_vertex(*vertices(g1
).first
, g1
);
131 remove_edge_if(never
<Graph1
>(), g1
);
135 if (process_id(pg
) == 0) std::cout
<< "Graph 2------------------\n";
140 if (process_id(pg
) == num_processes(pg
) - 1)
143 graph_traits
<Graph2
>::vertex_iterator v
, v_end
;
145 for (boost::tie(v
, v_end
) = vertices(g2
); v
!= v_end
; ++v
) {
146 std::cout
<< "Processor #" << process_id(pg
) << ": vertex " << ++counter
154 if (num_vertices(g2
) >= 2) {
155 graph_traits
<Graph2
>::vertex_iterator vi
= vertices(g2
).first
;
156 graph_traits
<Graph2
>::vertex_descriptor u
= *vi
++;
157 graph_traits
<Graph2
>::vertex_descriptor v
= *vi
++;
159 assert(out_degree(u
, g2
) == 1);
160 assert(*adjacent_vertices(u
, g2
).first
== v
);
161 std::cout
<< "Processor #" << process_id(pg
) << ": " << num_edges(g2
)
163 assert(std::distance(edges(g2
).first
, edges(g2
).second
) == 1);
168 local_subgraph
<Graph2
> local_g2(g2
);
171 if (num_vertices(local_g2
) > 0) {
172 out_edges(*vertices(local_g2
).first
, local_g2
);
173 adjacent_vertices(*vertices(local_g2
).first
, local_g2
);
174 remove_out_edge_if(*vertices(g2
).first
, never
<Graph2
>(), g2
);
175 clear_out_edges(*vertices(g2
).first
, g2
);
176 remove_vertex(*vertices(g2
).first
, g2
);
178 remove_edge_if(never
<Graph2
>(), g2
);
181 if (process_id(pg
) == 0) std::cout
<< "Graph 3------------------\n";
186 // if (process_id(pg) == num_processes(pg) - 1)
189 graph_traits
<Graph3
>::vertex_iterator v
, v_end
;
191 for (boost::tie(v
, v_end
) = vertices(g3
); v
!= v_end
; ++v
) {
192 std::cout
<< "Processor #" << process_id(pg
) << ": vertex " << ++counter
201 graph_traits
<Graph3
>::vertices_size_type added_edges
= 0;
202 if (num_vertices(g3
) >= 2) {
203 graph_traits
<Graph3
>::vertex_iterator vi
= vertices(g3
).first
;
204 graph_traits
<Graph3
>::vertex_descriptor u
= *vi
++;
205 graph_traits
<Graph3
>::vertex_descriptor v
= *vi
++;
206 add_edge(u
, v
, g3
); ++added_edges
;
207 assert(out_degree(u
, g3
) == 1);
208 assert(in_degree(u
, g3
) == 1);
209 graph_traits
<Graph3
>::edge_descriptor e
= *out_edges(u
, g3
).first
;
210 assert(source(e
, g3
) == u
);
211 assert(target(e
, g3
) == v
);
212 e
= *in_edges(u
, g3
).first
;
213 assert(source(e
, g3
) == v
);
214 assert(target(e
, g3
) == u
);
215 assert(out_degree(v
, g3
) == 1);
216 assert(in_degree(v
, g3
) == 1);
217 e
= *out_edges(v
, g3
).first
;
218 assert(source(e
, g3
) == v
);
219 assert(target(e
, g3
) == u
);
220 e
= *in_edges(v
, g3
).first
;
221 assert(source(e
, g3
) == u
);
222 assert(target(e
, g3
) == v
);
224 assert(*adjacent_vertices(u
, g3
).first
== v
);
225 assert(*adjacent_vertices(v
, g3
).first
== u
);
226 std::cout
<< "Processor #" << process_id(pg
) << ": " << num_edges(g3
)
230 // Add some remote edges
231 for (boost::tie(v
, v_end
) = vertices(g3
); v
!= v_end
; ++v
) {
232 graph_traits
<Graph1
>::vertex_descriptor other
= *v
;
233 other
.owner
= (other
.owner
+ 1) % num_processes(pg
);
235 add_edge(*v
, other
, g3
); ++added_edges
;
237 std::cout
<< "Adding edge from processor " << process_id(pg
)
238 << " to processor " << other
.owner
<< std::endl
;
242 assert(std::distance(edges(g3
).first
, edges(g3
).second
) == (ptrdiff_t)added_edges
);
243 assert(num_edges(g3
) == added_edges
);
245 // Verify the remote edges
246 if (num_vertices(g3
) >= 2) {
247 graph_traits
<Graph3
>::vertex_iterator vi
= vertices(g3
).first
;
248 graph_traits
<Graph3
>::vertex_descriptor u
= *vi
++;
250 int prior_processor
= (process_id(pg
) + num_processes(pg
) - 1)
253 graph_traits
<Graph3
>::vertices_size_type vertices_in_prior
= (n
/ num_processes(pg
))
254 + (n
% num_processes(pg
) > prior_processor
? 1 : 0);
255 if (in_degree(u
, g3
) != vertices_in_prior
+ 2) {
256 std::cerr
<< "#" << process_id(pg
) << ": " << in_degree(u
, g3
)
257 << " != " << vertices_in_prior
+ 2 << std::endl
;
260 assert(in_degree(u
, g3
) == vertices_in_prior
+ 2);
261 assert(out_degree(u
, g3
) == vertices_in_prior
+ 2);
264 local_subgraph
<Graph3
> local_g3(g3
);
267 if (num_vertices(local_g3
) > 0) {
268 out_edges(*vertices(local_g3
).first
, local_g3
);
269 in_edges(*vertices(local_g3
).first
, local_g3
);
270 adjacent_vertices(*vertices(local_g3
).first
, local_g3
);
271 remove_out_edge_if(*vertices(g3
).first
, never
<Graph3
>(), g3
);
272 remove_in_edge_if(*vertices(g3
).first
, never
<Graph3
>(), g3
);
274 // Removing an edge from two processes concurrently is not yet
276 clear_vertex(*vertices(g3
).first
, g3
);
277 remove_vertex(*vertices(g3
).first
, g3
);
280 remove_edge_if(never
<Graph3
>(), g3
);