mirror of
https://github.com/boostorg/mpi.git
synced 2026-02-25 16:32:22 +00:00
Full merge from trunk at revision 41356 of entire boost-root tree.
[SVN r41370]
This commit is contained in:
228
test/all_reduce_test.cpp
Normal file
228
test/all_reduce_test.cpp
Normal file
@@ -0,0 +1,228 @@
|
||||
// Copyright (C) 2005, 2006 Douglas Gregor.
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// A test of the all_reduce() collective.
|
||||
#include <boost/mpi/collectives/all_reduce.hpp>
|
||||
#include <boost/mpi/communicator.hpp>
|
||||
#include <boost/mpi/environment.hpp>
|
||||
#include <boost/test/minimal.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include <boost/iterator/counting_iterator.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <numeric>
|
||||
|
||||
using boost::mpi::communicator;
|
||||
|
||||
// A simple point class that we can build, add, compare, and
|
||||
// serialize.
|
||||
struct point
|
||||
{
|
||||
point() : x(0), y(0), z(0) { }
|
||||
point(int x, int y, int z) : x(x), y(y), z(z) { }
|
||||
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
|
||||
private:
|
||||
template<typename Archiver>
|
||||
void serialize(Archiver& ar, unsigned int /*version*/)
|
||||
{
|
||||
ar & x & y & z;
|
||||
}
|
||||
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const point& p)
|
||||
{
|
||||
return out << p.x << ' ' << p.y << ' ' << p.z;
|
||||
}
|
||||
|
||||
bool operator==(const point& p1, const point& p2)
|
||||
{
|
||||
return p1.x == p2.x && p1.y == p2.y && p1.z == p2.z;
|
||||
}
|
||||
|
||||
bool operator!=(const point& p1, const point& p2)
|
||||
{
|
||||
return !(p1 == p2);
|
||||
}
|
||||
|
||||
point operator+(const point& p1, const point& p2)
|
||||
{
|
||||
return point(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z);
|
||||
}
|
||||
|
||||
namespace boost { namespace mpi {
|
||||
|
||||
template <>
|
||||
struct is_mpi_datatype<point> : public mpl::true_ { };
|
||||
|
||||
} } // end namespace boost::mpi
|
||||
|
||||
template<typename Generator, typename Op>
|
||||
void
|
||||
all_reduce_test(const communicator& comm, Generator generator,
|
||||
const char* type_kind, Op op, const char* op_kind,
|
||||
typename Generator::result_type init)
|
||||
{
|
||||
typedef typename Generator::result_type value_type;
|
||||
value_type value = generator(comm.rank());
|
||||
|
||||
using boost::mpi::all_reduce;
|
||||
|
||||
if (comm.rank() == 0) {
|
||||
std::cout << "Reducing to " << op_kind << " of " << type_kind << "...";
|
||||
std::cout.flush();
|
||||
}
|
||||
|
||||
value_type result_value = all_reduce(comm, value, op);
|
||||
|
||||
// Compute expected result
|
||||
std::vector<value_type> generated_values;
|
||||
for (int p = 0; p < comm.size(); ++p)
|
||||
generated_values.push_back(generator(p));
|
||||
value_type expected_result = std::accumulate(generated_values.begin(),
|
||||
generated_values.end(),
|
||||
init, op);
|
||||
BOOST_CHECK(result_value == expected_result);
|
||||
if (result_value == expected_result && comm.rank() == 0)
|
||||
std::cout << "OK." << std::endl;
|
||||
|
||||
(comm.barrier)();
|
||||
}
|
||||
|
||||
// Generates integers to test with all_reduce()
|
||||
struct int_generator
|
||||
{
|
||||
typedef int result_type;
|
||||
|
||||
int_generator(int base = 1) : base(base) { }
|
||||
|
||||
int operator()(int p) const { return base + p; }
|
||||
|
||||
private:
|
||||
int base;
|
||||
};
|
||||
|
||||
// Generate points to test with all_reduce()
|
||||
struct point_generator
|
||||
{
|
||||
typedef point result_type;
|
||||
|
||||
point_generator(point origin) : origin(origin) { }
|
||||
|
||||
point operator()(int p) const
|
||||
{
|
||||
return point(origin.x + 1, origin.y + 1, origin.z + 1);
|
||||
}
|
||||
|
||||
private:
|
||||
point origin;
|
||||
};
|
||||
|
||||
struct string_generator
|
||||
{
|
||||
typedef std::string result_type;
|
||||
|
||||
std::string operator()(int p) const
|
||||
{
|
||||
std::string result = boost::lexical_cast<std::string>(p);
|
||||
result += " rosebud";
|
||||
if (p != 1) result += 's';
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct secret_int_bit_and
|
||||
{
|
||||
int operator()(int x, int y) const { return x & y; }
|
||||
};
|
||||
|
||||
struct wrapped_int
|
||||
{
|
||||
wrapped_int() : value(0) { }
|
||||
explicit wrapped_int(int value) : value(value) { }
|
||||
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, unsigned int /* version */)
|
||||
{
|
||||
ar & value;
|
||||
}
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
wrapped_int operator+(const wrapped_int& x, const wrapped_int& y)
|
||||
{
|
||||
return wrapped_int(x.value + y.value);
|
||||
}
|
||||
|
||||
bool operator==(const wrapped_int& x, const wrapped_int& y)
|
||||
{
|
||||
return x.value == y.value;
|
||||
}
|
||||
|
||||
// Generates wrapped_its to test with all_reduce()
|
||||
struct wrapped_int_generator
|
||||
{
|
||||
typedef wrapped_int result_type;
|
||||
|
||||
wrapped_int_generator(int base = 1) : base(base) { }
|
||||
|
||||
wrapped_int operator()(int p) const { return wrapped_int(base + p); }
|
||||
|
||||
private:
|
||||
int base;
|
||||
};
|
||||
|
||||
namespace boost { namespace mpi {
|
||||
|
||||
// Make std::plus<wrapped_int> commutative.
|
||||
template<>
|
||||
struct is_commutative<std::plus<wrapped_int>, wrapped_int>
|
||||
: mpl::true_ { };
|
||||
|
||||
} } // end namespace boost::mpi
|
||||
|
||||
int test_main(int argc, char* argv[])
|
||||
{
|
||||
using namespace boost::mpi;
|
||||
environment env(argc, argv);
|
||||
|
||||
communicator comm;
|
||||
|
||||
// Built-in MPI datatypes with built-in MPI operations
|
||||
all_reduce_test(comm, int_generator(), "integers", std::plus<int>(), "sum",
|
||||
0);
|
||||
all_reduce_test(comm, int_generator(), "integers", std::multiplies<int>(),
|
||||
"product", 1);
|
||||
all_reduce_test(comm, int_generator(), "integers", maximum<int>(),
|
||||
"maximum", 0);
|
||||
all_reduce_test(comm, int_generator(), "integers", minimum<int>(),
|
||||
"minimum", 2);
|
||||
|
||||
// User-defined MPI datatypes with operations that have the
|
||||
// same name as built-in operations.
|
||||
all_reduce_test(comm, point_generator(point(0,0,0)), "points",
|
||||
std::plus<point>(), "sum", point());
|
||||
|
||||
// Built-in MPI datatypes with user-defined operations
|
||||
all_reduce_test(comm, int_generator(17), "integers", secret_int_bit_and(),
|
||||
"bitwise and", -1);
|
||||
|
||||
// Arbitrary types with user-defined, commutative operations.
|
||||
all_reduce_test(comm, wrapped_int_generator(17), "wrapped integers",
|
||||
std::plus<wrapped_int>(), "sum", wrapped_int(0));
|
||||
|
||||
// Arbitrary types with (non-commutative) user-defined operations
|
||||
all_reduce_test(comm, string_generator(), "strings",
|
||||
std::plus<std::string>(), "concatenation", std::string());
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user