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
9 #include <boost/graph/use_mpi.hpp>
10 #include <boost/config.hpp>
11 #include <boost/throw_exception.hpp>
12 #include <boost/graph/distributed/mpi_process_group.hpp>
13 #include <boost/property_map/property_map.hpp>
14 #include <boost/core/lightweight_test.hpp>
17 #include <boost/serialization/vector.hpp>
18 #include <boost/serialization/string.hpp>
19 #include <boost/serialization/utility.hpp>
20 #include <boost/lexical_cast.hpp>
21 #include <boost/graph/parallel/basic_reduce.hpp>
23 #ifdef BOOST_NO_EXCEPTIONS
25 boost::throw_exception(std::exception
const& ex
)
27 std::cout
<< ex
.what() << std::endl
;
32 using namespace boost
;
33 using boost::graph::distributed::mpi_process_group
;
35 enum color_t
{ red
, blue
};
39 remote_key(int p
= -1, std::size_t l
= 0) : processor(p
), local_key(l
) {}
42 std::size_t local_key
;
44 template<typename Archiver
>
45 void serialize(Archiver
& ar
, const unsigned int /*version*/)
47 ar
& processor
& local_key
;
51 namespace boost
{ namespace mpi
{
52 template<> struct is_mpi_datatype
<remote_key
> : mpl::true_
{ };
54 BOOST_IS_BITWISE_SERIALIZABLE(remote_key
)
55 BOOST_CLASS_IMPLEMENTATION(remote_key
,object_serializable
)
56 BOOST_CLASS_TRACKING(remote_key
,track_never
)
61 struct hash
<remote_key
>
63 std::size_t operator()(const remote_key
& key
) const
65 std::size_t hash
= hash_value(key
.processor
);
66 hash_combine(hash
, key
.local_key
);
72 inline bool operator==(const remote_key
& x
, const remote_key
& y
)
73 { return x
.processor
== y
.processor
&& x
.local_key
== y
.local_key
; }
75 struct remote_key_to_global
77 typedef readable_property_map_tag category
;
78 typedef remote_key key_type
;
79 typedef std::pair
<int, std::size_t> value_type
;
80 typedef value_type reference
;
83 inline std::pair
<int, std::size_t>
84 get(remote_key_to_global
, const remote_key
& key
)
86 return std::make_pair(key
.processor
, key
.local_key
);
90 struct my_reduce
: boost::parallel::basic_reduce
<T
> {
91 BOOST_STATIC_CONSTANT(bool, non_default_resolver
= true);
99 color_t my_start_color
= process_id(pg
) % 2 == 0? ::red
: ::blue
;
100 int next_processor
= (process_id(pg
) + 1) % num_processes(pg
);
101 color_t next_start_color
= next_processor
% 2 == 0? ::red
: ::blue
;
103 // Initial color map: even-numbered processes are all red,
104 // odd-numbered processes are all blue.
105 std::vector
<color_t
> color_vec(n
, my_start_color
);
107 typedef iterator_property_map
<std::vector
<color_t
>::iterator
,
108 identity_property_map
> LocalPropertyMap
;
109 LocalPropertyMap
local_colors(color_vec
.begin(), identity_property_map());
113 // Create the distributed property map
114 typedef boost::parallel::distributed_property_map
<mpi_process_group
,
115 remote_key_to_global
,
116 LocalPropertyMap
> ColorMap
;
117 ColorMap
colors(pg
, remote_key_to_global(), local_colors
);
118 colors
.set_reduce(my_reduce
<color_t
>());
120 if (process_id(pg
) == 0) std::cerr
<< "Checking local colors...";
121 // check local processor colors
122 for (int i
= 0; i
< n
; ++i
) {
123 remote_key
k(process_id(pg
), i
);
124 BOOST_TEST(get(colors
, k
) == my_start_color
);
127 colors
.set_consistency_model(boost::parallel::cm_bidirectional
);
128 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChecking next processor's default colors...";
129 // check next processor's colors
130 for (int i
= 0; i
< n
; ++i
) {
131 remote_key
k(next_processor
, i
);
132 BOOST_TEST(get(colors
, k
) == color_t());
135 if (process_id(pg
) == 0) std::cerr
<< "OK.\nSynchronizing...";
138 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChecking next processor's colors...";
139 // check next processor's colors
140 for (int i
= 0; i
< n
; ++i
) {
141 remote_key
k(next_processor
, i
);
142 BOOST_TEST(get(colors
, k
) == next_start_color
);
145 if (process_id(pg
) == 0) std::cerr
<< "OK.\nSynchronizing...";
148 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChanging next processor's colors...";
149 // change the next processor's colors
150 color_t next_finish_color
= next_processor
% 2 == 0? ::blue
: ::red
;
151 for (int i
= 0; i
< n
; ++i
) {
152 remote_key
k(next_processor
, i
);
153 put(colors
, k
, next_finish_color
);
156 if (process_id(pg
) == 0) std::cerr
<< "OK.\nSynchronizing...";
159 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChecking changed colors...";
160 // check our own colors
161 color_t my_finish_color
= process_id(pg
) % 2 == 0? ::blue
: ::red
;
162 for (int i
= 0; i
< n
; ++i
) {
163 remote_key
k(process_id(pg
), i
);
164 BOOST_TEST(get(colors
, k
) == my_finish_color
);
167 // check our neighbor's colors
168 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChecking changed colors on neighbor...";
169 for (int i
= 0; i
< n
; ++i
) {
170 remote_key
k(next_processor
, i
);
171 BOOST_TEST(get(colors
, k
) == next_finish_color
);
176 if (process_id(pg
) == 0) std::cerr
<< "OK.\n";
181 mpi_process_group pg
;
184 bool my_start_value
= process_id(pg
) % 2;
185 int next_processor
= (process_id(pg
) + 1) % num_processes(pg
);
186 bool next_start_value
= ((process_id(pg
) + 1) % num_processes(pg
)) % 2;
188 // Initial color map: even-numbered processes are false,
189 // odd-numbered processes are true
190 std::vector
<bool> bool_vec(n
, my_start_value
);
192 typedef iterator_property_map
<std::vector
<bool>::iterator
,
193 identity_property_map
> LocalPropertyMap
;
194 LocalPropertyMap
local_values(bool_vec
.begin(), identity_property_map());
198 // Create the distributed property map
199 typedef boost::parallel::distributed_property_map
<mpi_process_group
,
200 remote_key_to_global
,
201 LocalPropertyMap
> ValueMap
;
202 ValueMap
values(pg
, remote_key_to_global(), local_values
);
203 values
.set_reduce(my_reduce
<bool>());
205 if (process_id(pg
) == 0) std::cerr
<< "Checking local values...";
206 // check local processor values
207 for (int i
= 0; i
< n
; ++i
) {
208 remote_key
k(process_id(pg
), i
);
209 BOOST_TEST(get(values
, k
) == my_start_value
);
212 values
.set_consistency_model(boost::parallel::cm_bidirectional
);
213 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChecking next processor's default values...";
214 // check next processor's values
215 for (int i
= 0; i
< n
; ++i
) {
216 remote_key
k(next_processor
, i
);
217 BOOST_TEST(get(values
, k
) == false);
220 if (process_id(pg
) == 0) std::cerr
<< "OK.\nSynchronizing...";
223 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChecking next processor's values...";
224 // check next processor's values
225 for (int i
= 0; i
< n
; ++i
) {
226 remote_key
k(next_processor
, i
);
227 BOOST_TEST(get(values
, k
) == next_start_value
);
230 if (process_id(pg
) == 0) std::cerr
<< "OK.\nSynchronizing...";
233 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChanging next processor's values...";
234 // change the next processor's values
235 bool next_finish_value
= next_processor
% 2 == 0;
236 for (int i
= 0; i
< n
; ++i
) {
237 remote_key
k(next_processor
, i
);
238 put(values
, k
, next_finish_value
);
241 if (process_id(pg
) == 0) std::cerr
<< "OK.\nSynchronizing...";
244 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChecking changed values...";
245 // check our own values
246 bool my_finish_value
= process_id(pg
) % 2 == 0;
247 for (int i
= 0; i
< n
; ++i
) {
248 remote_key
k(process_id(pg
), i
);
249 BOOST_TEST(get(values
, k
) == my_finish_value
);
252 // check our neighbor's values
253 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChecking changed values on neighbor...";
254 for (int i
= 0; i
< n
; ++i
) {
255 remote_key
k(next_processor
, i
);
256 BOOST_TEST(get(values
, k
) == next_finish_value
);
261 if (process_id(pg
) == 0) std::cerr
<< "OK.\n";
266 mpi_process_group pg
;
269 std::string my_start_string
= lexical_cast
<std::string
>(process_id(pg
));
270 int next_processor
= (process_id(pg
) + 1) % num_processes(pg
);
271 std::string next_start_string
= lexical_cast
<std::string
>(next_processor
);
273 // Initial color map: even-numbered processes are false,
274 // odd-numbered processes are true
275 std::vector
<std::string
> string_vec(n
, my_start_string
);
277 typedef iterator_property_map
<std::vector
<std::string
>::iterator
,
278 identity_property_map
> LocalPropertyMap
;
279 LocalPropertyMap
local_strings(string_vec
.begin(), identity_property_map());
283 // Create the distributed property map
284 typedef boost::parallel::distributed_property_map
<mpi_process_group
,
285 remote_key_to_global
,
286 LocalPropertyMap
> StringMap
;
287 StringMap
strings(pg
, remote_key_to_global(), local_strings
);
288 strings
.set_reduce(my_reduce
<std::string
>());
290 if (process_id(pg
) == 0) std::cerr
<< "Checking local strings...";
291 // check local processor strings
292 for (int i
= 0; i
< n
; ++i
) {
293 remote_key
k(process_id(pg
), i
);
294 BOOST_TEST(get(strings
, k
) == my_start_string
);
297 strings
.set_consistency_model(boost::parallel::cm_bidirectional
);
298 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChecking next processor's default strings...";
299 // check next processor's strings
300 for (int i
= 0; i
< n
; ++i
) {
301 remote_key
k(next_processor
, i
);
302 BOOST_TEST(get(strings
, k
) == (num_processes(pg
) == 1 ? my_start_string
: std::string()));
305 if (process_id(pg
) == 0) std::cerr
<< "OK.\nSynchronizing...";
308 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChecking next processor's strings...";
309 // check next processor's strings
310 for (int i
= 0; i
< n
; ++i
) {
311 remote_key
k(next_processor
, i
);
312 BOOST_TEST(get(strings
, k
) == next_start_string
);
315 if (process_id(pg
) == 0) std::cerr
<< "OK.\nSynchronizing...";
318 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChanging next processor's strings...";
319 // change the next processor's strings
320 std::string next_finish_string
= next_start_string
+ next_start_string
;
321 for (int i
= 0; i
< n
; ++i
) {
322 remote_key
k(next_processor
, i
);
323 put(strings
, k
, next_finish_string
);
326 if (process_id(pg
) == 0) std::cerr
<< "OK.\nSynchronizing...";
329 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChecking changed strings...";
330 // check our own strings
331 std::string my_finish_string
= my_start_string
+ my_start_string
;
332 for (int i
= 0; i
< n
; ++i
) {
333 remote_key
k(process_id(pg
), i
);
334 BOOST_TEST(get(strings
, k
) == my_finish_string
);
337 // check our neighbor's strings
338 if (process_id(pg
) == 0) std::cerr
<< "OK.\nChecking changed strings on neighbor...";
339 for (int i
= 0; i
< n
; ++i
) {
340 remote_key
k(next_processor
, i
);
341 BOOST_TEST(get(strings
, k
) == next_finish_string
);
346 if (process_id(pg
) == 0) std::cerr
<< "OK.\n";
349 int main(int argc
, char** argv
)
351 boost::mpi::environment
env(argc
, argv
);
355 return boost::report_errors();