1 // Copyright (C) 2005, 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
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 // A test of the reduce() collective.
8 #include <boost/mpi/collectives/reduce.hpp>
9 #include <boost/mpi/communicator.hpp>
10 #include <boost/mpi/environment.hpp>
12 #include <boost/serialization/string.hpp>
13 #include <boost/iterator/counting_iterator.hpp>
14 #include <boost/lexical_cast.hpp>
17 #define BOOST_TEST_MODULE mpi_reduce_test
18 #include <boost/test/included/unit_test.hpp>
20 using boost::mpi::communicator;
22 // A simple point class that we can build, add, compare, and
26 point() : x(0), y(0), z(0) { }
27 point(int x, int y, int z) : x(x), y(y), z(z) { }
34 template<typename Archiver>
35 void serialize(Archiver& ar, unsigned int /*version*/)
40 friend class boost::serialization::access;
43 std::ostream& operator<<(std::ostream& out, const point& p)
45 return out << p.x << ' ' << p.y << ' ' << p.z;
48 bool operator==(const point& p1, const point& p2)
50 return p1.x == p2.x && p1.y == p2.y && p1.z == p2.z;
53 bool operator!=(const point& p1, const point& p2)
58 point operator+(const point& p1, const point& p2)
60 return point(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z);
63 namespace boost { namespace mpi {
66 struct is_mpi_datatype<point> : public mpl::true_ { };
68 } } // end namespace boost::mpi
70 template<typename Generator, typename Op>
72 reduce_test(const communicator& comm, Generator generator,
73 const char* type_kind, Op op, const char* op_kind,
74 typename Generator::result_type init,
77 typedef typename Generator::result_type value_type;
78 value_type value = generator(comm.rank());
81 for (root = 0; root < comm.size(); ++root)
82 reduce_test(comm, generator, type_kind, op, op_kind, init, root);
84 using boost::mpi::reduce;
86 if (comm.rank() == root) {
87 std::cout << "Reducing to " << op_kind << " of " << type_kind
88 << " at root " << root << "...";
91 value_type result_value;
92 reduce(comm, value, result_value, op, root);
94 // Compute expected result
95 std::vector<value_type> generated_values;
96 for (int p = 0; p < comm.size(); ++p)
97 generated_values.push_back(generator(p));
98 value_type expected_result = std::accumulate(generated_values.begin(),
99 generated_values.end(),
101 BOOST_CHECK(result_value == expected_result);
102 if (result_value == expected_result)
103 std::cout << "OK." << std::endl;
105 reduce(comm, value, op, root);
112 // Generates integers to test with reduce()
115 typedef int result_type;
117 int_generator(int base = 1) : base(base) { }
119 int operator()(int p) const { return base + p; }
125 // Generate points to test with reduce()
126 struct point_generator
128 typedef point result_type;
130 point_generator(point origin) : origin(origin) { }
132 point operator()(int p) const
134 return point(origin.x + 1, origin.y + 1, origin.z + 1);
141 struct string_generator
143 typedef std::string result_type;
145 std::string operator()(int p) const
147 std::string result = boost::lexical_cast<std::string>(p);
148 result += " rosebud";
149 if (p != 1) result += 's';
154 struct secret_int_bit_and
156 int operator()(int x, int y) const { return x & y; }
161 wrapped_int() : value(0) { }
162 explicit wrapped_int(int value) : value(value) { }
164 template<typename Archive>
165 void serialize(Archive& ar, unsigned int /* version */)
173 wrapped_int operator+(const wrapped_int& x, const wrapped_int& y)
175 return wrapped_int(x.value + y.value);
178 bool operator==(const wrapped_int& x, const wrapped_int& y)
180 return x.value == y.value;
183 // Generates wrapped_its to test with reduce()
184 struct wrapped_int_generator
186 typedef wrapped_int result_type;
188 wrapped_int_generator(int base = 1) : base(base) { }
190 wrapped_int operator()(int p) const { return wrapped_int(base + p); }
196 namespace boost { namespace mpi {
198 // Make std::plus<wrapped_int> commutative.
200 struct is_commutative<std::plus<wrapped_int>, wrapped_int>
203 } } // end namespace boost::mpi
205 BOOST_AUTO_TEST_CASE(reduce_check)
207 using namespace boost::mpi;
212 // Built-in MPI datatypes with built-in MPI operations
213 reduce_test(comm, int_generator(), "integers", std::plus<int>(), "sum", 0);
214 reduce_test(comm, int_generator(), "integers", std::multiplies<int>(),
216 reduce_test(comm, int_generator(), "integers", maximum<int>(),
218 reduce_test(comm, int_generator(), "integers", minimum<int>(),
221 // User-defined MPI datatypes with operations that have the
222 // same name as built-in operations.
223 reduce_test(comm, point_generator(point(0,0,0)), "points",
224 std::plus<point>(), "sum", point());
226 // Built-in MPI datatypes with user-defined operations
227 reduce_test(comm, int_generator(17), "integers", secret_int_bit_and(),
230 // Arbitrary types with user-defined, commutative operations.
231 reduce_test(comm, wrapped_int_generator(17), "wrapped integers",
232 std::plus<wrapped_int>(), "sum", wrapped_int(0));
234 // Arbitrary types with (non-commutative) user-defined operations
235 reduce_test(comm, string_generator(), "strings",
236 std::plus<std::string>(), "concatenation", std::string());