1 // Copyright (C) 2005, 2006 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/lexical_cast.hpp>
14 #include <boost/serialization/vector.hpp>
15 #include <boost/graph/distributed/adjacency_list.hpp>
16 #include <boost/graph/distributed/mpi_process_group.hpp>
17 #include <boost/random/linear_congruential.hpp>
19 #include <boost/property_map/property_map_iterator.hpp>
20 #include <boost/graph/distributed/dehne_gotz_min_spanning_tree.hpp>
21 #include <boost/graph/distributed/vertex_list_adaptor.hpp>
22 #include <boost/graph/erdos_renyi_generator.hpp>
23 #include <boost/graph/distributed/graphviz.hpp>
26 #include <boost/graph/iteration_macros.hpp>
27 #include <boost/test/minimal.hpp>
29 #ifdef BOOST_NO_EXCEPTIONS
31 boost::throw_exception(std::exception
const& ex
)
33 std::cout
<< ex
.what() << std::endl
;
38 using namespace boost
;
39 using boost::graph::distributed::mpi_process_group
;
41 /****************************************************************************
42 * Edge weight generator iterator *
43 ****************************************************************************/
45 class generator_iterator
48 typedef std::input_iterator_tag iterator_category
;
49 typedef typename
F::result_type value_type
;
50 typedef const value_type
& reference
;
51 typedef const value_type
* pointer
;
52 typedef void difference_type
;
54 explicit generator_iterator(const F
& f
= F()) : f(f
) { value
= this->f(); }
56 reference
operator*() const { return value
; }
57 pointer
operator->() const { return &value
; }
59 generator_iterator
& operator++()
65 generator_iterator
operator++(int)
67 generator_iterator
temp(*this);
72 bool operator==(const generator_iterator
& other
) const
73 { return f
== other
.f
; }
75 bool operator!=(const generator_iterator
& other
) const
76 { return !(*this == other
); }
84 inline generator_iterator
<F
> make_generator_iterator(const F
& f
)
85 { return generator_iterator
<F
>(f
); }
87 typedef minstd_rand RandomGenerator
;
89 template<typename Graph
>
90 double get_mst_weight (const Graph
& g
)
92 typedef typename graph_traits
<Graph
>::edge_descriptor edge_descriptor
;
93 typename property_map
<Graph
, edge_weight_t
>::const_type weight
94 = get(edge_weight
, g
);
96 // Boruvka then merge test
97 std::vector
<edge_descriptor
> results
;
98 graph::boruvka_then_merge(make_vertex_list_adaptor(g
), weight
,
99 std::back_inserter(results
));
100 if (process_id(g
.process_group()) == 0)
101 return accumulate(make_property_map_iterator(weight
, results
.begin()),
102 make_property_map_iterator(weight
, results
.end()),
108 template<typename Graph
>
109 void test_redistribution(int n
, double p
, int iterations
, bool debug_output
)
112 Graph
g(erdos_renyi_iterator
<RandomGenerator
, Graph
>(gen
, n
, p
),
113 erdos_renyi_iterator
<RandomGenerator
, Graph
>(),
114 make_generator_iterator(uniform_01
<RandomGenerator
>(gen
)),
118 mpi_process_group pg
= g
.process_group();
120 // Set the names of the vertices to be the global index in the
121 // initial distribution. Then when we are debugging we'll be able to
122 // see how vertices have moved.
124 typedef typename property_map
<Graph
, vertex_index_t
>::type VertexIndexMap
;
125 typedef typename property_map
<Graph
, vertex_global_t
>::type VertexGlobalMap
;
126 typename property_map
<Graph
, vertex_name_t
>::type name_map
127 = get(vertex_name
, g
);
129 parallel::global_index_map
<VertexIndexMap
, VertexGlobalMap
>
130 global_index(g
.process_group(), num_vertices(g
),
131 get(vertex_index
, g
), get(vertex_global
, g
));
132 BGL_FORALL_VERTICES_T(v
, g
, Graph
)
133 put(name_map
, v
, get(global_index
, v
));
137 write_graphviz("redist-0.dot", g
,
138 make_label_writer(get(vertex_name
, g
)),
139 make_label_writer(get(edge_weight
, g
)));
141 double mst_weight
= get_mst_weight(g
);
142 if (process_id(pg
) == 0)
143 std::cout
<< "MST weight = " << mst_weight
<< std::endl
;
145 RandomGenerator
nonsync_gen(process_id(pg
) + gen());
146 while (++iter
<= iterations
) {
147 typename property_map
<Graph
, vertex_rank_t
>::type to_processor_map
=
150 // Randomly assign a new distribution
151 typename graph_traits
<Graph
>::vertex_iterator vi
, vi_end
;
152 for (boost::tie(vi
, vi_end
) = vertices(g
); vi
!= vi_end
; ++vi
)
153 put(to_processor_map
, *vi
, gen() % num_processes(pg
));
155 if (process_id(pg
) == 0)
156 std::cout
<< "Redistributing...";
157 // Perform the actual redistribution
158 g
.redistribute(to_processor_map
);
160 if (process_id(pg
) == 0)
161 std::cout
<< " done." << std::endl
;
164 std::ostringstream out
;
165 out
<< "redist-" << iter
<< ".dot";
166 write_graphviz(out
.str().c_str(), g
,
167 make_label_writer(get(vertex_name
, g
)),
168 make_label_writer(get(edge_weight
, g
)));
171 // Check that the MST weight is unchanged
172 double new_mst_weight
= get_mst_weight(g
);
173 if (process_id(pg
) == 0) {
174 std::cout
<< "MST weight = " << new_mst_weight
<< std::endl
;
175 if (std::fabs(new_mst_weight
- mst_weight
) > 0.0001)
176 communicator(pg
).abort(-1); }
180 int test_main(int argc
, char** argv
)
185 bool debug_output
= false;
187 boost::mpi::environment
env(argc
, argv
);
189 if (argc
> 1) n
= lexical_cast
<int>(argv
[1]);
190 if (argc
> 2) p
= lexical_cast
<double>(argv
[2]);
191 if (argc
> 3) iterations
= lexical_cast
<int>(argv
[3]);
192 if (argc
> 4) debug_output
= true;
194 typedef adjacency_list
<listS
,
195 distributedS
<mpi_process_group
, vecS
>,
198 property
<vertex_name_t
, std::size_t,
199 property
<vertex_rank_t
, int> >,
201 property
<edge_weight_t
, double> > UnstableUDGraph
;
202 typedef adjacency_list
<listS
,
203 distributedS
<mpi_process_group
, listS
>,
206 property
<vertex_name_t
, std::size_t,
207 property
<vertex_rank_t
, int,
208 property
<vertex_index_t
, std::size_t> > >,
210 property
<edge_weight_t
, double> > StableUDGraph
;
212 test_redistribution
<UnstableUDGraph
>(n
, p
, iterations
, debug_output
);
213 test_redistribution
<StableUDGraph
>(n
, p
, iterations
, debug_output
);