summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/mpi/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/mpi/test')
-rw-r--r--src/boost/libs/mpi/test/Jamfile.v255
-rw-r--r--src/boost/libs/mpi/test/all_gather_test.cpp148
-rw-r--r--src/boost/libs/mpi/test/all_reduce_test.cpp309
-rw-r--r--src/boost/libs/mpi/test/all_to_all_test.cpp113
-rw-r--r--src/boost/libs/mpi/test/block_nonblock_test.cpp95
-rw-r--r--src/boost/libs/mpi/test/broadcast_stl_test.cpp75
-rw-r--r--src/boost/libs/mpi/test/broadcast_test.cpp159
-rw-r--r--src/boost/libs/mpi/test/cartesian_topology_init_test.cpp88
-rw-r--r--src/boost/libs/mpi/test/cartesian_topology_test.cpp193
-rw-r--r--src/boost/libs/mpi/test/debugger.cpp48
-rw-r--r--src/boost/libs/mpi/test/debugger.hpp26
-rw-r--r--src/boost/libs/mpi/test/gather_test.cpp165
-rw-r--r--src/boost/libs/mpi/test/gps_position.hpp69
-rw-r--r--src/boost/libs/mpi/test/graph_topology_test.cpp141
-rw-r--r--src/boost/libs/mpi/test/groups_test.cpp59
-rw-r--r--src/boost/libs/mpi/test/is_mpi_op_test.cpp33
-rw-r--r--src/boost/libs/mpi/test/mt_init_test.cpp37
-rw-r--r--src/boost/libs/mpi/test/mt_level_test.cpp108
-rw-r--r--src/boost/libs/mpi/test/non_blocking_any_source.cpp63
-rw-r--r--src/boost/libs/mpi/test/nonblocking_test.cpp247
-rw-r--r--src/boost/libs/mpi/test/pointer_test.cpp42
-rw-r--r--src/boost/libs/mpi/test/python/all_gather_test.py25
-rw-r--r--src/boost/libs/mpi/test/python/all_reduce_test.py29
-rw-r--r--src/boost/libs/mpi/test/python/all_to_all_test.py30
-rw-r--r--src/boost/libs/mpi/test/python/broadcast_test.py29
-rw-r--r--src/boost/libs/mpi/test/python/gather_test.py32
-rw-r--r--src/boost/libs/mpi/test/python/generators.py23
-rw-r--r--src/boost/libs/mpi/test/python/nonblocking_test.py131
-rw-r--r--src/boost/libs/mpi/test/python/reduce_test.py31
-rw-r--r--src/boost/libs/mpi/test/python/ring_test.py42
-rw-r--r--src/boost/libs/mpi/test/python/scan_test.py29
-rw-r--r--src/boost/libs/mpi/test/python/scatter_test.py36
-rw-r--r--src/boost/libs/mpi/test/python/skeleton_content_test.cpp37
-rw-r--r--src/boost/libs/mpi/test/python/skeleton_content_test.py75
-rw-r--r--src/boost/libs/mpi/test/reduce_test.cpp237
-rw-r--r--src/boost/libs/mpi/test/ring_test.cpp124
-rw-r--r--src/boost/libs/mpi/test/scan_test.cpp228
-rw-r--r--src/boost/libs/mpi/test/scatter_test.cpp233
-rw-r--r--src/boost/libs/mpi/test/sendrecv_test.cpp62
-rw-r--r--src/boost/libs/mpi/test/sendrecv_vector.cpp95
-rw-r--r--src/boost/libs/mpi/test/skeleton_content_test.cpp200
-rw-r--r--src/boost/libs/mpi/test/version_test.cpp60
-rw-r--r--src/boost/libs/mpi/test/wait_all_vector_test.cpp46
-rw-r--r--src/boost/libs/mpi/test/wait_any_test.cpp64
44 files changed, 4171 insertions, 0 deletions
diff --git a/src/boost/libs/mpi/test/Jamfile.v2 b/src/boost/libs/mpi/test/Jamfile.v2
new file mode 100644
index 000000000..ac9ac2539
--- /dev/null
+++ b/src/boost/libs/mpi/test/Jamfile.v2
@@ -0,0 +1,55 @@
+# Support for the Message Passing Interface (MPI)
+#
+# (C) Copyright 2005, 2006 Trustees of Indiana University
+# (C) Copyright 2005 Douglas Gregor
+#
+# Distributed under 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.)
+#
+# Authors: Douglas Gregor
+# Andrew Lumsdaine
+
+project : requirements <library>/boost//mpi ;
+import mpi : mpi-test ;
+
+if [ mpi.configured ]
+{
+test-suite mpi
+ :
+ [ mpi-test version_test : : : 1 ]
+ [ mpi-test block_nonblock_test-b2nb : block_nonblock_test.cpp : : 2 ]
+ [ mpi-test block_nonblock_test-nb2b : block_nonblock_test.cpp : : 2 ]
+ [ mpi-test random_gather : ../example/random_gather.cpp : : 2 ]
+ [ mpi-test random_scatter : ../example/random_scatter.cpp : : 2 ]
+ [ mpi-test cartesian_communicator : ../example/cartesian_communicator.cpp : : 24 ]
+ [ mpi-test cartesian_topology_init_test : : : 1 ]
+ [ mpi-test broadcast_stl_test : : : 2 ]
+ [ mpi-test all_gather_test : : : 1 2 11 ]
+ [ mpi-test all_reduce_test : : : 1 2 11 ]
+ [ mpi-test all_to_all_test : : : 1 2 11 ]
+ [ mpi-test broadcast_test : : : 2 17 ]
+ [ mpi-test gather_test : : : 1 2 11 ]
+ [ mpi-test is_mpi_op_test : : : 1 ]
+ [ mpi-test mt_level_test : : : 1 ]
+ [ mpi-test mt_init_test : : : 1 4 ]
+ # Note: Microsoft MPI fails nonblocking_test on 1 processor
+ [ mpi-test nonblocking_test : : : 2 11 24 ]
+ [ mpi-test reduce_test ]
+ [ mpi-test ring_test : : : 2 3 4 7 8 13 17 ]
+ [ mpi-test sendrecv_test : : : 1 4 7 48 ]
+ [ mpi-test wait_any_test : : : 1 4 7 20 ]
+ [ mpi-test wait_all_vector_test : : : 2 ]
+ [ mpi-test scan_test ]
+ [ mpi-test scatter_test ]
+ # Note: Microsoft MPI fails all skeleton-content tests
+ [ mpi-test skeleton_content_test : : : 2 3 4 7 8 13 17 ]
+ [ mpi-test graph_topology_test : : : 2 7 13 ]
+ [ mpi-test cartesian_topology_test : : : 24 ]
+ [ mpi-test pointer_test : : : 2 ]
+ [ mpi-test groups_test ]
+ # tests that require -std=c++11
+ [ mpi-test sendrecv_vector : : : 2 ]
+ # Intel MPI 2018 and older are axtected to fail:
+ [ mpi-test non_blocking_any_source : : : 2 17 ]
+ ;
+}
diff --git a/src/boost/libs/mpi/test/all_gather_test.cpp b/src/boost/libs/mpi/test/all_gather_test.cpp
new file mode 100644
index 000000000..c2385f61e
--- /dev/null
+++ b/src/boost/libs/mpi/test/all_gather_test.cpp
@@ -0,0 +1,148 @@
+// Copyright (C) 2005-2006 Douglas Gregor <doug.gregor@gmail.com>
+
+// 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_gather() collective.
+
+#include <algorithm>
+
+#include <boost/mpi/collectives/all_gather.hpp>
+#include <boost/mpi/collectives/all_gatherv.hpp>
+#include <boost/mpi/environment.hpp>
+#include <boost/mpi/communicator.hpp>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/list.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/lexical_cast.hpp>
+
+#define BOOST_TEST_MODULE mpi_all_gather
+#include <boost/test/included/unit_test.hpp>
+
+#include "gps_position.hpp"
+
+namespace mpi = boost::mpi;
+
+template<typename Generator>
+void
+all_gather_test(const mpi::communicator& comm, Generator generator,
+ std::string kind)
+{
+ typedef typename Generator::result_type value_type;
+ value_type value = generator(comm.rank());
+
+ std::vector<value_type> values;
+ if (comm.rank() == 0) {
+ std::cout << "Gathering " << kind << "...";
+ std::cout.flush();
+ }
+
+ mpi::all_gather(comm, value, values);
+
+ std::vector<value_type> expected_values;
+ for (int p = 0; p < comm.size(); ++p)
+ expected_values.push_back(generator(p));
+ BOOST_CHECK(values == expected_values);
+ if (comm.rank() == 0 && values == expected_values)
+ std::cout << "OK." << std::endl;
+
+ (comm.barrier)();
+}
+
+template<typename Generator>
+void
+all_gatherv_test(const mpi::communicator& comm, Generator generator,
+ std::string kind)
+{
+ typedef typename Generator::result_type value_type;
+ using boost::mpi::all_gatherv;
+
+ std::vector<value_type> myvalues, expected, values;
+ std::vector<int> sizes;
+ for(int r = 0; r < comm.size(); ++r) {
+ value_type value = generator(r);
+ sizes.push_back(r+1);
+ for (int k=0; k < r+1; ++k) {
+ expected.push_back(value);
+ if(comm.rank() == r) {
+ myvalues.push_back(value);
+ }
+ }
+ }
+ if (comm.rank() == 0) {
+ std::cout << "Gathering " << kind << "...";
+ std::cout.flush();
+ }
+
+ mpi::all_gatherv(comm, myvalues, values, sizes);
+
+ BOOST_CHECK(values == expected);
+
+ if (comm.rank() == 0 && values == expected)
+ std::cout << "OK." << std::endl;
+
+ (comm.barrier)();
+}
+
+// Generates integers to test with gather()
+struct int_generator
+{
+ typedef int result_type;
+
+ int operator()(int p) const { return 17 + p; }
+};
+
+// Generates GPS positions to test with gather()
+struct gps_generator
+{
+ typedef gps_position result_type;
+
+ gps_position operator()(int p) const
+ {
+ return gps_position(39 + p, 16, 20.2799);
+ }
+};
+
+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 string_list_generator
+{
+ typedef std::list<std::string> result_type;
+
+ std::list<std::string> operator()(int p) const
+ {
+ std::list<std::string> result;
+ for (int i = 0; i <= p; ++i) {
+ std::string value = boost::lexical_cast<std::string>(i);
+ result.push_back(value);
+ }
+ return result;
+ }
+};
+
+BOOST_AUTO_TEST_CASE(all_gather)
+{
+ boost::mpi::environment env;
+ mpi::communicator comm;
+ all_gather_test(comm, int_generator(), "integers");
+ all_gather_test(comm, gps_generator(), "GPS positions");
+ all_gather_test(comm, string_generator(), "string");
+ all_gather_test(comm, string_list_generator(), "list of strings");
+
+ all_gatherv_test(comm, int_generator(), "integers");
+ all_gatherv_test(comm, gps_generator(), "GPS positions");
+ all_gatherv_test(comm, string_generator(), "string");
+ all_gatherv_test(comm, string_list_generator(), "list of strings");
+}
diff --git a/src/boost/libs/mpi/test/all_reduce_test.cpp b/src/boost/libs/mpi/test/all_reduce_test.cpp
new file mode 100644
index 000000000..99fee9b8a
--- /dev/null
+++ b/src/boost/libs/mpi/test/all_reduce_test.cpp
@@ -0,0 +1,309 @@
+// 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 <vector>
+#include <algorithm>
+#include <boost/serialization/string.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/lexical_cast.hpp>
+#include <numeric>
+
+#define BOOST_TEST_MODULE mpi_all_reduce
+#include <boost/test/included/unit_test.hpp>
+
+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);
+}
+
+// test lexical order
+bool operator<(const point& p1, const point& p2)
+{
+ return (p1.x < p2.x
+ ? true
+ : (p1.x > p2.x
+ ? false
+ : p1.y < p2.y ));
+}
+
+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_one_test(const communicator& comm, Generator generator,
+ const char* type_kind, Op op, const char* op_kind,
+ typename Generator::result_type init, bool in_place)
+{
+ typedef typename Generator::result_type value_type;
+ value_type value = generator(comm.rank());
+
+ using boost::mpi::all_reduce;
+ using boost::mpi::inplace;
+
+ if (comm.rank() == 0) {
+ std::cout << "Reducing to " << op_kind << " of " << type_kind << "...";
+ std::cout.flush();
+ }
+
+ value_type result_value;
+ if (in_place) {
+ all_reduce(comm, inplace(value), op);
+ result_value = value;
+ } else {
+ 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)();
+}
+
+template<typename Generator, typename Op>
+void
+all_reduce_array_test(const communicator& comm, Generator generator,
+ const char* type_kind, Op op, const char* op_kind,
+ typename Generator::result_type init, bool in_place)
+{
+ typedef typename Generator::result_type value_type;
+ value_type value = generator(comm.rank());
+ std::vector<value_type> send(10, value);
+
+ using boost::mpi::all_reduce;
+ using boost::mpi::inplace;
+
+ if (comm.rank() == 0) {
+ char const* place = in_place ? "in place" : "out of place";
+ std::cout << "Reducing (" << place << ") array to " << op_kind << " of " << type_kind << "...";
+ std::cout.flush();
+ }
+ std::vector<value_type> result;
+ if (in_place) {
+ all_reduce(comm, inplace(&(send[0])), send.size(), op);
+ result.swap(send);
+ } else {
+ std::vector<value_type> recv(10, value_type());
+ all_reduce(comm, &(send[0]), send.size(), &(recv[0]), op);
+ result.swap(recv);
+ }
+
+ // 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);
+
+ bool got_expected_result = (std::equal_range(result.begin(), result.end(),
+ expected_result)
+ == std::make_pair(result.begin(), result.end()));
+ BOOST_CHECK(got_expected_result);
+ if (got_expected_result && comm.rank() == 0)
+ std::cout << "OK." << std::endl;
+
+ (comm.barrier)();
+}
+
+// Test the 4 families of all reduce: (value, array) X (in place, out of place)
+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)
+{
+ const bool in_place = true;
+ const bool out_of_place = false;
+ all_reduce_one_test(comm, generator, type_kind, op, op_kind, init, in_place);
+ all_reduce_one_test(comm, generator, type_kind, op, op_kind, init, out_of_place);
+ all_reduce_array_test(comm, generator, type_kind, op, op_kind,
+ init, in_place);
+ all_reduce_array_test(comm, generator, type_kind, op, op_kind,
+ init, out_of_place);
+}
+
+// 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;
+}
+
+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
+
+BOOST_AUTO_TEST_CASE(test_all_reduce)
+{
+ using namespace boost::mpi;
+ environment env;
+ 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());
+}
diff --git a/src/boost/libs/mpi/test/all_to_all_test.cpp b/src/boost/libs/mpi/test/all_to_all_test.cpp
new file mode 100644
index 000000000..0e27dcf05
--- /dev/null
+++ b/src/boost/libs/mpi/test/all_to_all_test.cpp
@@ -0,0 +1,113 @@
+// 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_to_all() collective.
+#include <boost/mpi/collectives/all_to_all.hpp>
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/environment.hpp>
+#include <algorithm>
+#include "gps_position.hpp"
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/list.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/lexical_cast.hpp>
+
+#define BOOST_TEST_MODULE mpi_all_to_all
+#include <boost/test/included/unit_test.hpp>
+
+using boost::mpi::communicator;
+
+using boost::mpi::packed_skeleton_iarchive;
+using boost::mpi::packed_skeleton_oarchive;
+
+template<typename Generator>
+void
+all_to_all_test(const communicator& comm, Generator generator,
+ const char* kind)
+{
+ typedef typename Generator::result_type value_type;
+
+ using boost::mpi::all_to_all;
+
+ std::vector<value_type> in_values;
+ for (int p = 0; p < comm.size(); ++p)
+ in_values.push_back(generator((p + 1) * (comm.rank() + 1)));
+
+ if (comm.rank() == 0) {
+ std::cout << "Performing all-to-all operation on " << kind << "...";
+ std::cout.flush();
+ }
+ std::vector<value_type> out_values;
+ all_to_all(comm, in_values, out_values);
+
+ for (int p = 0; p < comm.size(); ++p) {
+ BOOST_CHECK(out_values[p] == generator((p + 1) * (comm.rank() + 1)));
+ }
+
+ if (comm.rank() == 0) {
+ std::cout << " done." << std::endl;
+ }
+
+ (comm.barrier)();
+}
+
+// Generates integers to test with all_to_all()
+struct int_generator
+{
+ typedef int result_type;
+
+ int operator()(int p) const { return 17 + p; }
+};
+
+// Generates GPS positions to test with all_to_all()
+struct gps_generator
+{
+ typedef gps_position result_type;
+
+ gps_position operator()(int p) const
+ {
+ return gps_position(39 + p, 16, 20.2799);
+ }
+};
+
+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 string_list_generator
+{
+ typedef std::list<std::string> result_type;
+
+ std::list<std::string> operator()(int p) const
+ {
+ std::list<std::string> result;
+ for (int i = 0; i <= p; ++i) {
+ std::string value = boost::lexical_cast<std::string>(i);
+ result.push_back(value);
+ }
+ return result;
+ }
+};
+
+BOOST_AUTO_TEST_CASE(all_to_all_check)
+{
+ boost::mpi::environment env;
+ communicator comm;
+
+ all_to_all_test(comm, int_generator(), "integers");
+ all_to_all_test(comm, gps_generator(), "GPS positions");
+ all_to_all_test(comm, string_generator(), "string");
+ all_to_all_test(comm, string_list_generator(), "list of strings");
+}
diff --git a/src/boost/libs/mpi/test/block_nonblock_test.cpp b/src/boost/libs/mpi/test/block_nonblock_test.cpp
new file mode 100644
index 000000000..3088b6559
--- /dev/null
+++ b/src/boost/libs/mpi/test/block_nonblock_test.cpp
@@ -0,0 +1,95 @@
+#include <vector>
+#include <iostream>
+#include <iterator>
+#include <typeinfo>
+
+#include <boost/mpi.hpp>
+#include <boost/serialization/vector.hpp>
+#include <boost/core/demangle.hpp>
+
+//#include "debugger.cpp"
+
+#define BOOST_TEST_MODULE mpi_nonblocking
+#include <boost/test/included/unit_test.hpp>
+
+namespace mpi = boost::mpi;
+
+template<typename T>
+bool test(mpi::communicator const& comm, std::vector<T> const& ref, bool iswap, bool alloc)
+{
+
+ int rank = comm.rank();
+ if (rank == 0) {
+ std::cout << "Testing with type " << boost::core::demangle(typeid(T).name()) << '\n';
+ if (iswap) {
+ std::cout << "Blockin send, non blocking receive.\n";
+ } else {
+ std::cout << "Non blockin send, blocking receive.\n";
+ }
+ if (alloc) {
+ std::cout << "Explicitly allocate space for the receiver.\n";
+ } else {
+ std::cout << "Do not explicitly allocate space for the receiver.\n";
+ }
+ }
+ if (rank == 0) {
+ std::vector<T> data;
+ if (alloc) {
+ data.resize(ref.size());
+ }
+ if (iswap) {
+ mpi::request req = comm.irecv(1, 0, data);
+ req.wait();
+ } else {
+ comm.recv(1, 0, data);
+ }
+ std::cout << "Process 0 received " << data.size() << " elements :" << std::endl;
+ std::copy(data.begin(), data.end(), std::ostream_iterator<T>(std::cout, " "));
+ std::cout << std::endl;
+ std::cout << "While expecting " << ref.size() << " elements :" << std::endl;
+ std::copy(ref.begin(), ref.end(), std::ostream_iterator<T>(std::cout, " "));
+ std::cout << std::endl;
+ return (data == ref);
+ } else {
+ if (rank == 1) {
+ std::vector<T> vec = ref;
+ if (iswap) {
+ comm.send(0, 0, vec);
+ } else {
+ mpi::request req = comm.isend(0, 0, vec);
+ req.wait();
+ }
+ }
+ return true;
+ }
+}
+
+BOOST_AUTO_TEST_CASE(non_blocking)
+{
+ mpi::environment env;
+ mpi::communicator world;
+
+ BOOST_TEST_REQUIRE(world.size() > 1);
+
+ std::vector<int> integers(13); // don't assume we're lucky
+ for(int i = 0; i < int(integers.size()); ++i) {
+ integers[i] = i;
+ }
+
+ std::vector<std::string> strings(13); // don't assume we're lucky
+ for(int i = 0; i < int(strings.size()); ++i) {
+ std::ostringstream fmt;
+ fmt << "S" << i;
+ strings[i] = fmt.str();
+ }
+
+ BOOST_CHECK(test(world, integers, true, true));
+ BOOST_CHECK(test(world, integers, true, false));
+ BOOST_CHECK(test(world, strings, true, true));
+ BOOST_CHECK(test(world, strings, true, false));
+
+ BOOST_CHECK(test(world, integers, false, true));
+ BOOST_CHECK(test(world, integers, false, false));
+ BOOST_CHECK(test(world, strings, false, true));
+ BOOST_CHECK(test(world, strings, false, false));
+}
diff --git a/src/boost/libs/mpi/test/broadcast_stl_test.cpp b/src/boost/libs/mpi/test/broadcast_stl_test.cpp
new file mode 100644
index 000000000..705d6ccb9
--- /dev/null
+++ b/src/boost/libs/mpi/test/broadcast_stl_test.cpp
@@ -0,0 +1,75 @@
+// 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 broadcast() collective.
+#include <algorithm>
+#include <vector>
+#include <map>
+
+#include <boost/mpi/collectives/broadcast.hpp>
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/environment.hpp>
+
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/vector.hpp>
+#include <boost/serialization/map.hpp>
+
+#define BOOST_TEST_MODULE mpi_broadcast_stl
+#include <boost/test/included/unit_test.hpp>
+
+namespace mpi = boost::mpi;
+
+typedef std::vector<std::map<int, double> > sparse;
+
+template<typename T>
+void
+broadcast_test(const mpi::communicator& comm, const T& bc_value,
+ std::string const& kind, int root) {
+ using boost::mpi::broadcast;
+
+ T value;
+ if (comm.rank() == root) {
+ value = bc_value;
+ std::cout << "Broadcasting " << kind << " from root " << root << "...";
+ std::cout.flush();
+ }
+
+
+ broadcast(comm, value, root);
+ BOOST_CHECK(value == bc_value);
+ if (comm.rank() == root) {
+ if (value == bc_value) {
+ std::cout << "OK." << std::endl;
+ } else {
+ std::cout << "FAIL." << std::endl;
+ }
+ }
+ comm.barrier();
+}
+
+template<typename T>
+void
+broadcast_test(const mpi::communicator& comm, const T& bc_value,
+ std::string const& kind)
+{
+ for (int root = 0; root < comm.size(); ++root) {
+ broadcast_test(comm, bc_value, kind, root);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(broadcast_stl)
+{
+ boost::mpi::environment env;
+
+ mpi::communicator comm;
+ BOOST_TEST_REQUIRE(comm.size() > 1);
+
+ sparse s;
+ s.resize(2);
+ s[0][12] = 0.12;
+ s[1][13] = 1.13;
+ broadcast_test(comm, s, "sparse");
+}
diff --git a/src/boost/libs/mpi/test/broadcast_test.cpp b/src/boost/libs/mpi/test/broadcast_test.cpp
new file mode 100644
index 000000000..50081aad9
--- /dev/null
+++ b/src/boost/libs/mpi/test/broadcast_test.cpp
@@ -0,0 +1,159 @@
+// 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 broadcast() collective.
+#include <boost/mpi/collectives/broadcast.hpp>
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/environment.hpp>
+#include <algorithm>
+#include "gps_position.hpp"
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/list.hpp>
+#include <boost/mpi/skeleton_and_content.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+//#include "debugger.hpp"
+
+#define BOOST_TEST_MODULE mpi_broadcast
+#include <boost/test/included/unit_test.hpp>
+
+using boost::mpi::communicator;
+
+using boost::mpi::packed_skeleton_iarchive;
+using boost::mpi::packed_skeleton_oarchive;
+
+template<typename T>
+void
+broadcast_test(const communicator& comm, const T& bc_value,
+ const char* kind, int root = -1)
+{
+ if (root == -1) {
+ for (root = 0; root < comm.size(); ++root)
+ broadcast_test(comm, bc_value, kind, root);
+ } else {
+ using boost::mpi::broadcast;
+
+ T value;
+ if (comm.rank() == root) {
+ value = bc_value;
+ std::cout << "Broadcasting " << kind << " from root " << root << "...";
+ std::cout.flush();
+ }
+
+ broadcast(comm, value, root);
+ BOOST_CHECK(value == bc_value);
+ if (comm.rank() == root && value == bc_value)
+ std::cout << "OK." << std::endl;
+ }
+
+ (comm.barrier)();
+}
+
+void
+test_skeleton_and_content(const communicator& comm, int root = 0)
+{
+ using boost::mpi::content;
+ using boost::mpi::get_content;
+ using boost::make_counting_iterator;
+ using boost::mpi::broadcast;
+
+ int list_size = comm.size() + 7;
+ if (comm.rank() == root) {
+ // Fill in the seed data
+ std::list<int> original_list;
+ for (int i = 0; i < list_size; ++i)
+ original_list.push_back(i);
+
+ // Build up the skeleton
+ packed_skeleton_oarchive oa(comm);
+ oa << original_list;
+
+ // Broadcast the skeleton
+ std::cout << "Broadcasting integer list skeleton from root " << root
+ << "..." << std::flush;
+ broadcast(comm, oa, root);
+ std::cout << "OK." << std::endl;
+
+ // Broadcast the content
+ std::cout << "Broadcasting integer list content from root " << root
+ << "..." << std::flush;
+ {
+ content c = get_content(original_list);
+ broadcast(comm, c, root);
+ }
+ std::cout << "OK." << std::endl;
+
+ // Reverse the list, broadcast the content again
+ std::reverse(original_list.begin(), original_list.end());
+ std::cout << "Broadcasting reversed integer list content from root "
+ << root << "..." << std::flush;
+ {
+ content c = get_content(original_list);
+ broadcast(comm, c, root);
+ }
+ std::cout << "OK." << std::endl;
+
+ } else {
+ // Allocate some useless data, to try to get the addresses of the
+ // list<int>'s used later to be different across processes.
+ std::list<int> junk_list(comm.rank() * 3 + 1, 17);
+
+ // Receive the skeleton
+ packed_skeleton_iarchive ia(comm);
+ broadcast(comm, ia, root);
+
+ // Build up a list to match the skeleton, and make sure it has the
+ // right structure (we have no idea what the data will be).
+ std::list<int> transferred_list;
+ ia >> transferred_list;
+ BOOST_CHECK((int)transferred_list.size() == list_size);
+
+ // Receive the content and check it
+ broadcast(comm, get_content(transferred_list), root);
+ bool list_content_ok = std::equal(make_counting_iterator(0),
+ make_counting_iterator(list_size),
+ transferred_list.begin());
+ BOOST_CHECK(list_content_ok);
+
+ // Receive the reversed content and check it
+ broadcast(comm, get_content(transferred_list), root);
+ bool rlist_content_ok = std::equal(make_counting_iterator(0),
+ make_counting_iterator(list_size),
+ transferred_list.rbegin());
+ BOOST_CHECK(rlist_content_ok);
+ if (!(list_content_ok && rlist_content_ok)) {
+ if (comm.rank() == 1) {
+ std::cout
+ << "\n##### You might want to check for BOOST_MPI_BCAST_BOTTOM_WORKS_FINE "
+ << "in boost/mpi/config.hpp.\n\n";
+ }
+ }
+ }
+
+ (comm.barrier)();
+}
+
+BOOST_AUTO_TEST_CASE(broadcast_check)
+{
+ boost::mpi::environment env;
+ communicator comm;
+
+ BOOST_TEST_REQUIRE(comm.size() > 1);
+
+ // Check transfer of individual objects
+ broadcast_test(comm, 17, "integers");
+ broadcast_test(comm, gps_position(39,16,20.2799), "GPS positions");
+ broadcast_test(comm, gps_position(26,25,30.0), "GPS positions");
+ broadcast_test(comm, std::string("Rosie"), "string");
+
+ std::list<std::string> strings;
+ strings.push_back("Hello");
+ strings.push_back("MPI");
+ strings.push_back("World");
+ broadcast_test(comm, strings, "list of strings");
+
+ test_skeleton_and_content(comm, 0);
+ test_skeleton_and_content(comm, 1);
+}
diff --git a/src/boost/libs/mpi/test/cartesian_topology_init_test.cpp b/src/boost/libs/mpi/test/cartesian_topology_init_test.cpp
new file mode 100644
index 000000000..6138a2e6c
--- /dev/null
+++ b/src/boost/libs/mpi/test/cartesian_topology_init_test.cpp
@@ -0,0 +1,88 @@
+
+// Copyright Alain Miniussi 2014.
+// Distributed under 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)
+
+// Authors: Alain Miniussi
+
+#include <vector>
+#include <list>
+#include <iostream>
+#include <sstream>
+#include <iterator>
+#include <algorithm>
+#include <functional>
+
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/collectives.hpp>
+#include <boost/array.hpp>
+#include <boost/mpi/environment.hpp>
+#include <boost/mpi/cartesian_communicator.hpp>
+
+#define BOOST_TEST_MODULE mpi_cartesian_topology_init
+#include <boost/test/included/unit_test.hpp>
+
+namespace mpi = boost::mpi;
+
+BOOST_AUTO_TEST_CASE(cartesian_dimension_init)
+{
+ // Curly brace initialization syntax not supported on (very) old gnu
+ // This typedef keeps things shorter
+ typedef mpi::cartesian_dimension cd;
+
+ {
+ // Check the basic ctor
+ mpi::cartesian_dimension def;
+ mpi::cartesian_topology t1(10);
+ BOOST_CHECK(t1.stl() == std::vector<mpi::cartesian_dimension>(10, def));
+ }
+#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
+ {
+ // Intializer list ctor vs range based
+ int dims[] = {2,3,4};
+ bool per[] = {true, false, true};
+ mpi::cartesian_topology t1(dims, per);
+ mpi::cartesian_topology t2({{2,true},{3, false},{4, true}});
+ BOOST_CHECK(t1.size() == 3);
+ BOOST_CHECK(t1 == t2);
+ }
+#endif
+ // Container based ctor only available as a replacement for initializer list ctor
+ {
+ // seq ctor vs C array ctor
+ mpi::cartesian_dimension d[] = {cd(2,true),cd(3, false),cd(4, true)};
+ std::list<mpi::cartesian_dimension> seq;
+ std::copy(d, d+3, std::back_inserter(seq));
+ mpi::cartesian_topology t1(seq);
+ mpi::cartesian_topology t2(d);
+ BOOST_CHECK(t1 == t2);
+ }
+ {
+ // Check range based with array based ctor.
+ boost::array<mpi::cartesian_dimension, 3> d = {{cd(2,true),cd(3, false),cd(4, true)}};
+ int dims[] = {2,3,4};
+ bool per[] = {true, false, true};
+ mpi::cartesian_topology t1(dims, per);
+ mpi::cartesian_topology t2(d);
+ BOOST_CHECK(t1.size() == 3);
+ BOOST_CHECK(t1 == t2);
+ }
+ {
+ // Iterator based ctor vs C array based ctor
+ mpi::cartesian_dimension d[] = {cd(2,true),cd(3, false),cd(4, true)};
+ std::vector<mpi::cartesian_dimension> vdims(d, d+3);
+ mpi::cartesian_topology t1(vdims);
+ mpi::cartesian_topology t2(d);
+ BOOST_CHECK(t1.size() == 3);
+ BOOST_CHECK(t1 == t2);
+ BOOST_CHECK(!(t1 != t2));
+ t1[1].periodic = true;
+ BOOST_CHECK(t1 != t2);
+ t1[2].periodic = false;
+ t1[2].size = 0;
+ vdims.push_back(mpi::cartesian_dimension(3, false));
+ mpi::cartesian_topology t3(vdims);
+ BOOST_CHECK(t1 != t3);
+ }
+}
diff --git a/src/boost/libs/mpi/test/cartesian_topology_test.cpp b/src/boost/libs/mpi/test/cartesian_topology_test.cpp
new file mode 100644
index 000000000..d63fc5003
--- /dev/null
+++ b/src/boost/libs/mpi/test/cartesian_topology_test.cpp
@@ -0,0 +1,193 @@
+// Copyright Alain Miniussi 2014.
+// Distributed under 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)
+
+// Authors: Alain Miniussi
+
+#include <vector>
+#include <iostream>
+#include <sstream>
+#include <iterator>
+#include <algorithm>
+#include <functional>
+
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/collectives.hpp>
+#include <boost/mpi/environment.hpp>
+#include <boost/mpi/cartesian_communicator.hpp>
+
+#define BOOST_TEST_MODULE mpi_cartesian_topolohy
+#include <boost/test/included/unit_test.hpp>
+
+namespace mpi = boost::mpi;
+
+struct topo_minimum {
+ mpi::cartesian_dimension
+ operator()(mpi::cartesian_dimension const& d1,
+ mpi::cartesian_dimension const& d2 ) const {
+ return mpi::cartesian_dimension(std::min(d1.size, d2.size),
+ d1.periodic && d2.periodic);
+ }
+};
+
+std::string topology_description( mpi::cartesian_topology const& topo ) {
+ std::ostringstream out;
+ std::copy(topo.begin(), topo.end(), std::ostream_iterator<mpi::cartesian_dimension>(out, " "));
+ out << std::flush;
+ return out.str();
+}
+
+// Check that everyone agrees on the coordinates
+void test_coordinates_consistency( mpi::cartesian_communicator const& cc,
+ std::vector<int> const& coords )
+{
+ cc.barrier(); // flush IOs for nice printing
+ bool master = cc.rank() == 0;
+ if (master) {
+ std::cout << "Test coordinates consistency.\n";
+ }
+ for(int p = 0; p < cc.size(); ++p) {
+ std::vector<int> min(cc.ndims());
+ std::vector<int> local(cc.coordinates(p));
+ mpi::reduce(cc, &local.front(), local.size(),
+ &(min[0]), mpi::minimum<int>(), p);
+ cc.barrier();
+ if (p == cc.rank()) {
+ BOOST_CHECK(std::equal(coords.begin(), coords.end(), min.begin()));
+ std::ostringstream out;
+ out << "proc " << p << " at (";
+ std::copy(min.begin(), min.end(), std::ostream_iterator<int>(out, " "));
+ out << ")\n";
+ std::cout << out.str();
+ }
+ }
+}
+
+void test_shifted_coords( mpi::cartesian_communicator const& cc, int pos, mpi::cartesian_dimension desc, int dim )
+{
+ if (desc.periodic) {
+ for (int i = -(desc.size); i < desc.size; ++i) {
+ std::pair<int,int> rks = cc.shifted_ranks(dim, i);
+ int src = cc.coordinates(rks.first)[dim];
+ int dst = cc.coordinates(rks.second)[dim];
+ if (pos == (dim/2)) {
+ std::ostringstream out;
+ out << "Rank " << cc.rank() << ", dim. " << dim << ", pos " << pos << ", in " << desc << ' ';
+ out << "shifted pos: " << src << ", " << dst << '\n';
+ std::cout << out.str();
+ }
+ }
+ }
+}
+
+void test_shifted_coords( mpi::cartesian_communicator const& cc)
+{
+ cc.barrier(); // flush IOs for nice printing
+ std::vector<int> coords;
+ mpi::cartesian_topology topo(cc.ndims());
+ cc.topology(topo, coords);
+ bool master = cc.rank() == 0;
+ if (master) {
+ std::cout << "Testing shifts with topology " << topo << '\n';
+ }
+ for(int i = 0; i < cc.ndims(); ++i) {
+ if (master) {
+ std::cout << " for dimension " << i << ": " << topo[i] << '\n';
+ }
+ test_shifted_coords( cc, coords[i], topo[i], i );
+ }
+}
+
+void test_topology_consistency( mpi::cartesian_communicator const& cc)
+{
+ cc.barrier(); // flush IOs for nice printing
+ mpi::cartesian_topology itopo(cc.ndims());
+ mpi::cartesian_topology otopo(cc.ndims());
+ std::vector<int> coords(cc.ndims());
+ cc.topology(itopo, coords);
+ bool master = cc.rank() == 0;
+ if (master) {
+ std::cout << "Test topology consistency of" << itopo << "(on master)\n";
+ std::cout << "Check that everyone agrees on the dimensions.\n";
+ }
+ mpi::all_reduce(cc,
+ &(itopo[0]), itopo.size(), &(otopo[0]),
+ topo_minimum());
+ BOOST_CHECK(std::equal(itopo.begin(), itopo.end(), otopo.begin()));
+ if (master) {
+ std::cout << "We agree on " << topology_description(otopo) << '\n';
+ }
+ test_coordinates_consistency( cc, coords );
+}
+
+void test_cartesian_topology( mpi::cartesian_communicator const& cc)
+{
+ BOOST_CHECK(cc.has_cartesian_topology());
+ for( int r = 0; r < cc.size(); ++r) {
+ cc.barrier();
+ if (r == cc.rank()) {
+ std::vector<int> coords = cc.coordinates(r);
+ std::cout << "Process of cartesian rank " << cc.rank()
+ << " has coordinates (";
+ std::copy(coords.begin(), coords.end(), std::ostream_iterator<int>(std::cout," "));
+ std::cout << ")\n";
+ }
+ }
+ test_topology_consistency(cc);
+ test_shifted_coords(cc);
+ std::vector<int> even;
+ for(int i = 0; i < cc.ndims(); i += 2) {
+ even.push_back(i);
+ }
+ cc.barrier();
+ mpi::cartesian_communicator cce(cc, even);
+}
+
+void test_cartesian_topology( mpi::communicator const& world, mpi::cartesian_topology const& topo)
+{
+ mpi::cartesian_communicator cc(world, topo, true);
+ if (cc) {
+ BOOST_CHECK(cc.has_cartesian_topology());
+ BOOST_CHECK(cc.ndims() == int(topo.size()));
+ if (cc.rank() == 0) {
+ std::cout << "Asked topology " << topo << ", got " << cc.topology() << '\n';
+ }
+ test_cartesian_topology(cc);
+ } else {
+ std::ostringstream out;
+ out << world.rank() << " was left outside the cartesian grid\n";
+ std::cout << out.str();
+ }
+}
+
+BOOST_AUTO_TEST_CASE(cartesian_topology)
+{
+ mpi::environment env;
+ mpi::communicator world;
+
+ int const ndim = world.size() >= 24 ? 3 : 2;
+ mpi::cartesian_topology topo(ndim);
+ typedef mpi::cartesian_dimension cd;
+ if (topo.size() == 3) {
+ topo[0] = cd(2,true);
+ topo[1] = cd(3,false);
+ topo[2] = cd(4, true);
+ } else {
+ if (world.size() >= 6) {
+ topo[0] = cd(2,true);
+ topo[1] = cd(3, false);
+ } else {
+ topo[0] = cd(1,true);
+ topo[1] = cd(1, false);
+ }
+ }
+ test_cartesian_topology( world, topo);
+#if !defined(BOOST_NO_CXX11_DEFAULTED_MOVES)
+ world.barrier();
+ if (world.rank()==0) {
+ std::cout << "Testing move constructor.\n";
+ }
+ test_cartesian_topology( world, std::move(topo));
+#endif
+}
diff --git a/src/boost/libs/mpi/test/debugger.cpp b/src/boost/libs/mpi/test/debugger.cpp
new file mode 100644
index 000000000..90093e79f
--- /dev/null
+++ b/src/boost/libs/mpi/test/debugger.cpp
@@ -0,0 +1,48 @@
+// Copyright AlainMiniussi 20014 - 20015.
+// Distributed under 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)
+
+#include <cstdlib>
+
+#include "debugger.hpp"
+
+std::vector<int> extract_paused_ranks(int argc, char** argv) {
+ std::vector<int> paused;
+ for (int i=1; i < argc; ++i) {
+ paused.push_back(std::atoi(argv[i]));
+ }
+ return paused;
+}
+
+void wait_for_debugger(std::vector<int> const& processes, boost::mpi::communicator const& comm)
+{
+ int i = 1;
+ bool waiting = std::find(processes.begin(), processes.end(), comm.rank()) != processes.end();
+ for (int r = 0; r < comm.size(); ++r) {
+ if (comm.rank() == r) {
+ std::cout << "Rank " << comm.rank() << " has PID " << getpid();
+ if (waiting) {
+ std::cout << " and is waiting.";
+ }
+ std::cout << std::endl;
+ }
+ comm.barrier();
+ }
+ if (std::find(processes.begin(), processes.end(), comm.rank()) != processes.end()) {
+ while (i != 0) {
+ sleep(5);
+ }
+ }
+ std::cout << "Rank " << comm.rank() << " will proceed.\n";
+}
+
+void wait_for_debugger(boost::mpi::communicator const& comm)
+{
+ std::vector<int> all;
+ for (int r = 0; r < comm.size(); ++r) {
+ all.push_back(r);
+ }
+ wait_for_debugger(all, comm);
+}
+
diff --git a/src/boost/libs/mpi/test/debugger.hpp b/src/boost/libs/mpi/test/debugger.hpp
new file mode 100644
index 000000000..71abf51d0
--- /dev/null
+++ b/src/boost/libs/mpi/test/debugger.hpp
@@ -0,0 +1,26 @@
+// Copyright AlainMiniussi 20014 - 20015.
+// Distributed under 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)
+
+#include <vector>
+#include "boost/mpi/communicator.hpp"
+
+/**
+ * @brief Extract the MPI rank to pause.
+ *
+ * Right now, just atois alla the parameters in argv....
+ */
+std::vector<int> extract_paused_ranks(int argc, char** argv);
+
+/**
+ * @print Print rank pid map and wait if requested.
+ * @param processes Wait if our rank is in there.
+ * @param comm The communicator to consider.
+ *
+ * Once the debugger has attached to the process, it is expected to
+ * set the local variable 'i' to 0 to let the process restarts.
+ */
+void wait_for_debugger(std::vector<int> const& processes, boost::mpi::communicator const& comm);
+/** @override */
+void wait_for_debugger(boost::mpi::communicator const& comm);
diff --git a/src/boost/libs/mpi/test/gather_test.cpp b/src/boost/libs/mpi/test/gather_test.cpp
new file mode 100644
index 000000000..9bef7acd2
--- /dev/null
+++ b/src/boost/libs/mpi/test/gather_test.cpp
@@ -0,0 +1,165 @@
+// 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 gather() and gatherv() collectives.
+#include <boost/mpi/collectives/gather.hpp>
+#include <boost/mpi/collectives/gatherv.hpp>
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/environment.hpp>
+#include "gps_position.hpp"
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/list.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/lexical_cast.hpp>
+
+#define BOOST_TEST_MODULE mpi_gather
+#include <boost/test/included/unit_test.hpp>
+
+using boost::mpi::communicator;
+
+template<typename Generator>
+void
+gather_test(const communicator& comm, Generator generator,
+ const char* kind, int root = -1)
+{
+ typedef typename Generator::result_type value_type;
+ value_type value = generator(comm.rank());
+
+ if (root == -1) {
+ for (root = 0; root < comm.size(); ++root)
+ gather_test(comm, generator, kind, root);
+ } else {
+ using boost::mpi::gather;
+
+ std::vector<value_type> values;
+ if (comm.rank() == root) {
+ std::cout << "Gathering " << kind << " from root "
+ << root << "..." << std::endl;
+ }
+
+ gather(comm, value, values, root);
+
+ if (comm.rank() == root) {
+ std::vector<value_type> expected_values;
+ for (int p = 0; p < comm.size(); ++p)
+ expected_values.push_back(generator(p));
+ BOOST_CHECK(values == expected_values);
+ } else {
+ BOOST_CHECK(values.empty());
+ }
+ }
+
+ (comm.barrier)();
+}
+
+
+template<typename Generator>
+void
+gatherv_test(const communicator& comm, Generator generator,
+ const char* kind, int root = -1)
+{
+ typedef typename Generator::result_type value_type;
+
+ if (root == -1) {
+ for (root = 0; root < comm.size(); ++root)
+ gatherv_test(comm, generator, kind, root);
+ } else {
+ using boost::mpi::gatherv;
+
+ int mysize = comm.rank() + 1;
+ int nprocs = comm.size();
+
+ // process p will send p+1 identical generator(p) elements
+ std::vector<value_type> myvalues(mysize, generator(comm.rank()));
+
+ if (comm.rank() == root) {
+ std::vector<value_type> values((nprocs*(nprocs+1))/2);
+ std::vector<int> sizes(comm.size());
+ for (int p = 0; p < comm.size(); ++p)
+ sizes[p] = p + 1;
+
+ std::cout << "Gatheringv " << kind << " from root "
+ << root << "..." << std::endl;
+
+ gatherv(comm, myvalues, &values[0], sizes, root);
+
+ std::vector<value_type> expected_values;
+ for (int p = 0; p < comm.size(); ++p)
+ for (int i = 0; i < p+1; ++i)
+ expected_values.push_back(generator(p));
+
+ BOOST_CHECK(values == expected_values);
+ } else {
+ gatherv(comm, myvalues, root);
+ }
+ }
+
+ (comm.barrier)();
+}
+
+//
+// Generators to test with gather/gatherv
+//
+struct int_generator
+{
+ typedef int result_type;
+
+ int operator()(int p) const { return 17 + p; }
+};
+
+struct gps_generator
+{
+ typedef gps_position result_type;
+
+ gps_position operator()(int p) const
+ {
+ return gps_position(39 + p, 16, 20.2799);
+ }
+};
+
+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 string_list_generator
+{
+ typedef std::list<std::string> result_type;
+
+ std::list<std::string> operator()(int p) const
+ {
+ std::list<std::string> result;
+ for (int i = 0; i <= p; ++i) {
+ std::string value = boost::lexical_cast<std::string>(i);
+ result.push_back(value);
+ }
+ return result;
+ }
+};
+
+BOOST_AUTO_TEST_CASE(gather_check)
+{
+ boost::mpi::environment env;
+ communicator comm;
+
+ gather_test(comm, int_generator(), "integers");
+ gather_test(comm, gps_generator(), "GPS positions");
+ gather_test(comm, string_generator(), "string");
+ gather_test(comm, string_list_generator(), "list of strings");
+
+ gatherv_test(comm, int_generator(), "integers");
+ gatherv_test(comm, gps_generator(), "GPS positions");
+ gatherv_test(comm, string_generator(), "string");
+ gatherv_test(comm, string_list_generator(), "list of strings");
+}
diff --git a/src/boost/libs/mpi/test/gps_position.hpp b/src/boost/libs/mpi/test/gps_position.hpp
new file mode 100644
index 000000000..e6910c444
--- /dev/null
+++ b/src/boost/libs/mpi/test/gps_position.hpp
@@ -0,0 +1,69 @@
+#ifndef GPS_POSITION_HPP
+#define GPS_POSITION_HPP
+
+// Copyright Matthias Troyer
+// 2005. Distributed under 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)
+
+#include <boost/mpi/datatype_fwd.hpp>
+#include <boost/mpl/and.hpp>
+#include <boost/serialization/export.hpp>
+#include <boost/shared_ptr.hpp>
+#include <iostream>
+
+class gps_position
+{
+private:
+ friend class boost::serialization::access;
+ // When the class Archive corresponds to an output archive, the
+ // & operator is defined similar to <<. Likewise, when the class Archive
+ // is a type of input archive the & operator is defined similar to >>.
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int version)
+ {
+ ar & degrees & minutes & seconds;
+ }
+ int degrees;
+ int minutes;
+ float seconds;
+public:
+ gps_position(){};
+ gps_position(int d, int m, float s) :
+ degrees(d), minutes(m), seconds(s)
+ {}
+
+ friend std::ostream& operator<<(std::ostream& out, const gps_position& g);
+
+ friend bool operator==(const gps_position& x, const gps_position& y)
+ {
+ return (x.degrees == y.degrees
+ && x.minutes == y.minutes
+ && x.seconds == y.seconds);
+ }
+
+ inline friend bool operator!=(const gps_position& x, const gps_position& y)
+ {
+ return !(x == y);
+ }
+};
+
+inline
+std::ostream& operator<<(std::ostream& out, const gps_position& g) {
+ out << "gps{" << g.degrees << 'd' << g.minutes << 'm' << g.seconds << "s}";
+ return out;
+}
+
+namespace boost { namespace mpi {
+
+ template <>
+ struct is_mpi_datatype<gps_position>
+ : public mpl::and_
+ <
+ is_mpi_datatype<int>,
+ is_mpi_datatype<float>
+ >
+ {};
+
+} }
+#endif
diff --git a/src/boost/libs/mpi/test/graph_topology_test.cpp b/src/boost/libs/mpi/test/graph_topology_test.cpp
new file mode 100644
index 000000000..4d781265c
--- /dev/null
+++ b/src/boost/libs/mpi/test/graph_topology_test.cpp
@@ -0,0 +1,141 @@
+// Copyright (C) 2007 Trustees of Indiana University
+
+// Authors: Douglas Gregor
+// Andrew Lumsdaine
+
+// 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 communicator that passes data around a ring and
+// verifies that the same data makes it all the way. Should test all
+// of the various kinds of data that can be sent (primitive types, POD
+// types, serializable objects, etc.)
+#include <boost/mpi/graph_communicator.hpp>
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/environment.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/graph/erdos_renyi_generator.hpp>
+#include <boost/random/linear_congruential.hpp>
+#include <boost/graph/iteration_macros.hpp>
+#include <boost/graph/isomorphism.hpp>
+#include <algorithm> // for random_shuffle
+#include <boost/serialization/vector.hpp>
+#include <boost/mpi/collectives/broadcast.hpp>
+#include <boost/config.hpp>
+
+#define BOOST_TEST_MODULE mpi_graph_topology
+#include <boost/test/included/unit_test.hpp>
+
+#if defined(BOOST_NO_CXX98_RANDOM_SHUFFLE)
+
+#include <random>
+
+std::default_random_engine gen;
+
+template<typename RandomIt> void random_shuffle( RandomIt first, RandomIt last )
+{
+ std::shuffle( first, last, gen );
+}
+
+#else
+
+using std::random_shuffle;
+
+#endif // #if defined(BOOST_NO_CXX98_RANDOM_SHUFFLE)
+
+
+using boost::mpi::communicator;
+using boost::mpi::graph_communicator;
+using namespace boost;
+
+BOOST_AUTO_TEST_CASE(graph_topology)
+{
+ boost::function_requires< IncidenceGraphConcept<graph_communicator> >();
+ boost::function_requires< AdjacencyGraphConcept<graph_communicator> >();
+ boost::function_requires< VertexListGraphConcept<graph_communicator> >();
+ boost::function_requires< EdgeListGraphConcept<graph_communicator> >();
+
+ double prob = 0.1;
+
+ boost::mpi::environment env;
+ communicator world;
+
+ // Random number generator
+ minstd_rand gen;
+
+ // Build a random graph with as many vertices as there are processes
+ typedef adjacency_list<listS, vecS, bidirectionalS> Graph;
+ sorted_erdos_renyi_iterator<minstd_rand, Graph>
+ first(gen, world.size(), prob), last;
+ Graph graph(first, last, world.size());
+
+ // Display the original graph
+ if (world.rank() == 0) {
+ std::cout << "Original, random graph:\n";
+ BGL_FORALL_VERTICES(v, graph, Graph) {
+ BGL_FORALL_OUTEDGES(v, e, graph, Graph) {
+ std::cout << source(e, graph) << " -> " << target(e, graph)
+ << std::endl;
+ }
+ }
+ }
+
+ // Create an arbitrary mapping from vertices to integers
+ typedef property_map<Graph, vertex_index_t>::type GraphVertexIndexMap;
+ std::vector<int> graph_alt_index_vec(num_vertices(graph));
+ iterator_property_map<int*, GraphVertexIndexMap>
+ graph_alt_index(&graph_alt_index_vec[0], get(vertex_index, graph));
+
+ // Rank 0 will populate the alternative index vector
+ if (world.rank() == 0) {
+ int index = 0;
+ BGL_FORALL_VERTICES(v, graph, Graph)
+ put(graph_alt_index, v, index++);
+
+ ::random_shuffle(graph_alt_index_vec.begin(), graph_alt_index_vec.end());
+ }
+ broadcast(world, graph_alt_index_vec, 0);
+
+ // Display the original graph with the remapping
+ if (world.rank() == 0) {
+ std::cout << "Original, random graph with remapped vertex numbers:\n";
+ BGL_FORALL_VERTICES(v, graph, Graph) {
+ BGL_FORALL_OUTEDGES(v, e, graph, Graph) {
+ std::cout << get(graph_alt_index, source(e, graph)) << " -> "
+ << get(graph_alt_index, target(e, graph)) << std::endl;
+ }
+ }
+ }
+
+ // Create a communicator with a topology equivalent to the graph
+ graph_communicator graph_comm(world, graph, graph_alt_index, false);
+
+ // The communicator's topology should have the same number of
+ // vertices and edges and the original graph
+ BOOST_CHECK((int)num_vertices(graph) == num_vertices(graph_comm));
+ BOOST_CHECK((int)num_edges(graph) == num_edges(graph_comm));
+
+ // Display the communicator graph
+ if (graph_comm.rank() == 0) {
+ std::cout << "Communicator graph:\n";
+ BGL_FORALL_VERTICES(v, graph_comm, graph_communicator) {
+ BGL_FORALL_OUTEDGES(v, e, graph_comm, graph_communicator) {
+ std::cout << source(e, graph_comm) << " -> " << target(e, graph_comm)
+ << std::endl;
+ }
+ }
+
+ std::cout << "Communicator graph via edges():\n";
+ BGL_FORALL_EDGES(e, graph_comm, graph_communicator)
+ std::cout << source(e, graph_comm) << " -> " << target(e, graph_comm)
+ << std::endl;
+ }
+ (graph_comm.barrier)();
+
+ // Verify the isomorphism
+ if (graph_comm.rank() == 0)
+ std::cout << "Verifying isomorphism..." << std::endl;
+ BOOST_CHECK(verify_isomorphism(graph, graph_comm, graph_alt_index));
+}
diff --git a/src/boost/libs/mpi/test/groups_test.cpp b/src/boost/libs/mpi/test/groups_test.cpp
new file mode 100644
index 000000000..ce81d182d
--- /dev/null
+++ b/src/boost/libs/mpi/test/groups_test.cpp
@@ -0,0 +1,59 @@
+// Copyright (C) 2013 Andreas Hehn <hehn@phys.ethz.ch>, ETH Zurich
+
+// 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 communicators created from groups.
+
+#include <boost/mpi/environment.hpp>
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/group.hpp>
+#include <vector>
+#include <algorithm>
+
+#define BOOST_TEST_MODULE mpi_group_test
+#include <boost/test/included/unit_test.hpp>
+
+namespace mpi = boost::mpi;
+
+template <typename T>
+struct iota
+{
+ iota() : state(0){};
+ T operator()()
+ {
+ return state++;
+ }
+ T state;
+};
+
+void group_test(const mpi::communicator& comm)
+{
+ std::vector<int> grp_a_ranks(comm.size() / 2);
+ std::generate(grp_a_ranks.begin(),grp_a_ranks.end(),iota<int>());
+
+ mpi::group grp_a = comm.group().include(grp_a_ranks.begin(),grp_a_ranks.end());
+ mpi::group grp_b = comm.group().exclude(grp_a_ranks.begin(),grp_a_ranks.end());
+
+ mpi::communicator part_a(comm,grp_a);
+ mpi::communicator part_b(comm,grp_b);
+
+ if(part_a)
+ {
+ std::cout << "comm rank: " << comm.rank() << " -> part_a rank:" << part_a.rank() << std::endl;
+ BOOST_CHECK(part_a.rank() == comm.rank());
+ }
+ if(part_b)
+ {
+ std::cout << "comm rank: " << comm.rank() << " -> part_b rank:" << part_b.rank() << std::endl;
+ BOOST_CHECK(part_b.rank() == comm.rank() - comm.size()/2);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(group)
+{
+ mpi::environment env;
+ mpi::communicator comm;
+ group_test(comm);
+}
diff --git a/src/boost/libs/mpi/test/is_mpi_op_test.cpp b/src/boost/libs/mpi/test/is_mpi_op_test.cpp
new file mode 100644
index 000000000..d023c3f76
--- /dev/null
+++ b/src/boost/libs/mpi/test/is_mpi_op_test.cpp
@@ -0,0 +1,33 @@
+// Copyright (C) 2005-2006 Douglas Gregor <doug.gregor@gmail.com>
+
+// 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 is_mpi_op functionality.
+#include <boost/mpi/operations.hpp>
+#include <boost/mpi/environment.hpp>
+#include <boost/type_traits/is_base_and_derived.hpp>
+
+#define BOOST_TEST_MODULE mpi_is_mpi_op_test
+#include <boost/test/included/unit_test.hpp>
+
+using namespace boost::mpi;
+using namespace std;
+using boost::is_base_and_derived;
+
+BOOST_AUTO_TEST_CASE(mpi_basic_op)
+{
+ boost::mpi::environment env;
+
+ // Check each predefined MPI_Op type that we support directly.
+ BOOST_TEST((is_mpi_op<minimum<float>, float>::op() == MPI_MIN));
+ BOOST_TEST((is_mpi_op<plus<double>, double>::op() == MPI_SUM));
+ BOOST_TEST((is_mpi_op<multiplies<long>, long>::op() == MPI_PROD));
+ BOOST_TEST((is_mpi_op<logical_and<int>, int>::op() == MPI_LAND));
+ BOOST_TEST((is_mpi_op<bitwise_and<int>, int>::op() == MPI_BAND));
+ BOOST_TEST((is_mpi_op<logical_or<int>, int>::op() == MPI_LOR));
+ BOOST_TEST((is_mpi_op<bitwise_or<int>, int>::op() == MPI_BOR));
+ BOOST_TEST((is_mpi_op<logical_xor<int>, int>::op() == MPI_LXOR));
+ BOOST_TEST((is_mpi_op<bitwise_xor<int>, int>::op() == MPI_BXOR));
+}
diff --git a/src/boost/libs/mpi/test/mt_init_test.cpp b/src/boost/libs/mpi/test/mt_init_test.cpp
new file mode 100644
index 000000000..cfd0f57b4
--- /dev/null
+++ b/src/boost/libs/mpi/test/mt_init_test.cpp
@@ -0,0 +1,37 @@
+// Copyright (C) 2013 Alain Miniussi <alain.miniussi@oca.eu>
+
+// 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)
+
+// test threading::level operations
+
+#include <boost/mpi.hpp>
+#include <iostream>
+#include <sstream>
+
+#define BOOST_TEST_MODULE mpi_mt_init
+#include <boost/test/included/unit_test.hpp>
+
+namespace mpi = boost::mpi;
+
+void
+test_mt_init(std::string s)
+{
+ mpi::threading::level required = mpi::threading::level(-1);
+ std::istringstream in(s);
+ in >> required;
+ BOOST_CHECK(!in.bad());
+ BOOST_CHECK(mpi::environment::thread_level() >= mpi::threading::single);
+ BOOST_CHECK(mpi::environment::thread_level() <= mpi::threading::multiple);
+}
+
+BOOST_AUTO_TEST_CASE(mt_init)
+{
+ mpi::environment env;
+ mpi::communicator comm;
+ test_mt_init("single");
+ test_mt_init("funneled");
+ test_mt_init("serialized");
+ test_mt_init("multiple");
+}
diff --git a/src/boost/libs/mpi/test/mt_level_test.cpp b/src/boost/libs/mpi/test/mt_level_test.cpp
new file mode 100644
index 000000000..a72e9a8a5
--- /dev/null
+++ b/src/boost/libs/mpi/test/mt_level_test.cpp
@@ -0,0 +1,108 @@
+// Copyright (C) 2013 Alain Miniussi <alain.miniussi@oca.eu>
+
+// 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)
+
+// test threading::level operations
+
+#include <boost/mpi/environment.hpp>
+#include <iostream>
+#include <sstream>
+
+#define BOOST_TEST_MODULE mpi_level_test
+#include <boost/test/included/unit_test.hpp>
+
+namespace mpi = boost::mpi;
+
+void
+test_threading_level_io(mpi::threading::level orig) {
+ std::ostringstream out;
+ namespace mt = boost::mpi::threading;
+ mt::level printed = mt::level(-1);
+
+ out << orig;
+ BOOST_CHECK(out.good());
+ std::string orig_str(out.str());
+ std::cout << "orig string:" << orig_str << '\n';
+ std::istringstream in(orig_str);
+ in >> printed;
+ BOOST_CHECK(!in.bad());
+ std::cout << "orig: " << orig << ", printed: " << printed << std::endl;
+ BOOST_CHECK(orig == printed);
+}
+
+void
+test_threading_levels_io() {
+ namespace mt = boost::mpi::threading;
+ test_threading_level_io(mt::single);
+ test_threading_level_io(mt::funneled);
+ test_threading_level_io(mt::serialized);
+ test_threading_level_io(mt::multiple);
+}
+
+void
+test_threading_level_cmp() {
+ namespace mt = boost::mpi::threading;
+ BOOST_CHECK(mt::single == mt::single);
+ BOOST_CHECK(mt::funneled == mt::funneled);
+ BOOST_CHECK(mt::serialized == mt::serialized);
+ BOOST_CHECK(mt::multiple == mt::multiple);
+
+ BOOST_CHECK(mt::single != mt::funneled);
+ BOOST_CHECK(mt::single != mt::serialized);
+ BOOST_CHECK(mt::single != mt::multiple);
+
+ BOOST_CHECK(mt::funneled != mt::single);
+ BOOST_CHECK(mt::funneled != mt::serialized);
+ BOOST_CHECK(mt::funneled != mt::multiple);
+
+ BOOST_CHECK(mt::serialized != mt::single);
+ BOOST_CHECK(mt::serialized != mt::funneled);
+ BOOST_CHECK(mt::serialized != mt::multiple);
+
+ BOOST_CHECK(mt::multiple != mt::single);
+ BOOST_CHECK(mt::multiple != mt::funneled);
+ BOOST_CHECK(mt::multiple != mt::serialized);
+
+ BOOST_CHECK(mt::single < mt::funneled);
+ BOOST_CHECK(mt::funneled > mt::single);
+ BOOST_CHECK(mt::single < mt::serialized);
+ BOOST_CHECK(mt::serialized > mt::single);
+ BOOST_CHECK(mt::single < mt::multiple);
+ BOOST_CHECK(mt::multiple > mt::single);
+
+ BOOST_CHECK(mt::funneled < mt::serialized);
+ BOOST_CHECK(mt::serialized > mt::funneled);
+ BOOST_CHECK(mt::funneled < mt::multiple);
+ BOOST_CHECK(mt::multiple > mt::funneled);
+
+ BOOST_CHECK(mt::serialized < mt::multiple);
+ BOOST_CHECK(mt::multiple > mt::serialized);
+
+ BOOST_CHECK(mt::single <= mt::single);
+ BOOST_CHECK(mt::single <= mt::funneled);
+ BOOST_CHECK(mt::funneled >= mt::single);
+ BOOST_CHECK(mt::single <= mt::serialized);
+ BOOST_CHECK(mt::serialized >= mt::single);
+ BOOST_CHECK(mt::single <= mt::multiple);
+ BOOST_CHECK(mt::multiple >= mt::single);
+
+ BOOST_CHECK(mt::funneled <= mt::funneled);
+ BOOST_CHECK(mt::funneled <= mt::serialized);
+ BOOST_CHECK(mt::serialized >= mt::funneled);
+ BOOST_CHECK(mt::funneled <= mt::multiple);
+ BOOST_CHECK(mt::multiple >= mt::funneled);
+
+ BOOST_CHECK(mt::serialized <= mt::serialized);
+ BOOST_CHECK(mt::serialized <= mt::multiple);
+ BOOST_CHECK(mt::multiple >= mt::serialized);
+
+ BOOST_CHECK(mt::multiple <= mt::multiple);
+}
+
+BOOST_AUTO_TEST_CASE(mt_level)
+{
+ test_threading_levels_io();
+ test_threading_level_cmp();
+}
diff --git a/src/boost/libs/mpi/test/non_blocking_any_source.cpp b/src/boost/libs/mpi/test/non_blocking_any_source.cpp
new file mode 100644
index 000000000..dde8f92c6
--- /dev/null
+++ b/src/boost/libs/mpi/test/non_blocking_any_source.cpp
@@ -0,0 +1,63 @@
+// Copyright (C) 2018 Steffen Hirschmann
+
+// 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)
+
+// Test any_source on serialized data
+#include <vector>
+#include <iostream>
+#include <iterator>
+#include <boost/mpi.hpp>
+#include <boost/serialization/vector.hpp>
+
+#define BOOST_TEST_MODULE mpi_non_blockin_any_source
+#include <boost/test/included/unit_test.hpp>
+
+namespace mpi = boost::mpi;
+
+std::string ok(bool b) {
+ return b ? "ok" : "ko";
+}
+
+BOOST_AUTO_TEST_CASE(non_blocking_any)
+{
+ mpi::environment env;
+ mpi::communicator world;
+ int rank = world.rank();
+#if BOOST_MPI_VERSION < 3
+ if (rank == 0) {
+ std::cout << "\nExpected failure with MPI standard < 3 ("
+ << BOOST_MPI_VERSION << "." << BOOST_MPI_SUBVERSION
+ << " detected)\n\n";
+ }
+ return;
+#endif
+ if (rank == 0) {
+ std::vector<boost::mpi::request> req;
+ std::vector<std::vector<int> > data(world.size() - 1);
+ for (int i = 1; i < world.size(); ++i) {
+ req.push_back(world.irecv(mpi::any_source, 0, data[i - 1]));
+ }
+ boost::mpi::wait_all(req.begin(), req.end());
+ std::vector<bool> check(world.size()-1, false);
+ for (int i = 0; i < world.size() - 1; ++i) {
+ std::cout << "Process 0 received:" << std::endl;
+ std::copy(data[i].begin(), data[i].end(), std::ostream_iterator<int>(std::cout, " "));
+ std::cout << std::endl;
+ int idx = data[i].size();
+ BOOST_CHECK(std::equal_range(data[i].begin(), data[i].end(), idx)
+ == std::make_pair(data[i].begin(), data[i].end()));
+ check[idx-1] = true;
+ }
+ for(int i = 0; i < world.size() - 1; ++i) {
+ std::cout << "Received from " << i+1 << " is " << ok(check[i]) << '\n';
+ }
+ BOOST_CHECK(std::equal_range(check.begin(), check.end(), true)
+ == std::make_pair(check.begin(), check.end()));
+ } else {
+ std::vector<int> vec(rank, rank);
+ mpi::request req = world.isend(0, 0, vec);
+ req.wait();
+ }
+}
diff --git a/src/boost/libs/mpi/test/nonblocking_test.cpp b/src/boost/libs/mpi/test/nonblocking_test.cpp
new file mode 100644
index 000000000..8e3eb099f
--- /dev/null
+++ b/src/boost/libs/mpi/test/nonblocking_test.cpp
@@ -0,0 +1,247 @@
+// Copyright (C) 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 nonblocking point-to-point operations.
+#include <boost/mpi/nonblocking.hpp>
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/environment.hpp>
+#include "gps_position.hpp"
+#include <boost/lexical_cast.hpp>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/list.hpp>
+#include <iterator>
+#include <algorithm>
+//#include "debugger.cpp"
+
+#define BOOST_TEST_MODULE mpi_non_blockin_test
+#include <boost/test/included/unit_test.hpp>
+
+using boost::mpi::communicator;
+using boost::mpi::request;
+using boost::mpi::status;
+
+enum method_kind {
+ mk_wait_any, mk_test_any, mk_wait_all, mk_wait_all_keep,
+ mk_test_all, mk_test_all_keep, mk_wait_some, mk_wait_some_keep,
+ mk_test_some, mk_test_some_keep,
+ mk_test_size
+};
+
+static const char* method_kind_names[mk_test_size] = {
+ "wait_any",
+ "test_any",
+ "wait_all",
+ "wait_all (keep results)",
+ "test_all",
+ "test_all (keep results)",
+ "wait_some",
+ "wait_some (keep results)",
+ "test_some",
+ "test_some (keep results)"
+};
+
+
+template<typename T>
+void
+nonblocking_tests( const communicator& comm, const T* values, int num_values,
+ const char* kind, bool composite)
+{
+ nonblocking_test(comm, values, num_values, kind, mk_wait_any);
+ nonblocking_test(comm, values, num_values, kind, mk_test_any);
+ //wait_for_debugger(comm);
+ nonblocking_test(comm, values, num_values, kind, mk_wait_all);
+ nonblocking_test(comm, values, num_values, kind, mk_wait_all_keep);
+ if (!composite) {
+ nonblocking_test(comm, values, num_values, kind, mk_test_all);
+ nonblocking_test(comm, values, num_values, kind, mk_test_all_keep);
+ }
+ nonblocking_test(comm, values, num_values, kind, mk_wait_some);
+ nonblocking_test(comm, values, num_values, kind, mk_wait_some_keep);
+ nonblocking_test(comm, values, num_values, kind, mk_test_some);
+ nonblocking_test(comm, values, num_values, kind, mk_test_some_keep);
+}
+
+template<typename T>
+void
+nonblocking_test(const communicator& comm, const T* values, int num_values,
+ const char* kind, method_kind method)
+{
+ using boost::mpi::wait_any;
+ using boost::mpi::test_any;
+ using boost::mpi::wait_all;
+ using boost::mpi::test_all;
+ using boost::mpi::wait_some;
+ using boost::mpi::test_some;
+
+ int next = (comm.rank() + 1) % comm.size();
+ int prev = (comm.rank() + comm.size() - 1) % comm.size();
+
+ if (comm.rank() == 0) {
+ std::cout << "Testing " << method_kind_names[method]
+ << " with " << kind << "...";
+ std::cout.flush();
+ }
+
+ typedef std::pair<status, std::vector<request>::iterator>
+ status_iterator_pair;
+
+ T incoming_value;
+ std::vector<T> incoming_values(num_values);
+ std::vector<request> reqs;
+ // Send/receive the first value
+ reqs.push_back(comm.isend(next, 0, values[0]));
+ reqs.push_back(comm.irecv(prev, 0, incoming_value));
+
+ if (method != mk_wait_any && method != mk_test_any) {
+#ifndef LAM_MPI
+ // We've run into problems here (with 0-length messages) with
+ // LAM/MPI on Mac OS X and x86-86 Linux. Will investigate
+ // further at a later time, but the problem only seems to occur
+ // when using shared memory, not TCP.
+
+ // Send/receive an empty message
+ reqs.push_back(comm.isend(next, 1));
+ reqs.push_back(comm.irecv(prev, 1));
+#endif
+
+ // Send/receive an array
+ reqs.push_back(comm.isend(next, 2, values, num_values));
+ reqs.push_back(comm.irecv(prev, 2, &incoming_values.front(), num_values));
+ }
+
+ switch (method) {
+ case mk_wait_any:
+ if (wait_any(reqs.begin(), reqs.end()).second == reqs.begin())
+ reqs[1].wait();
+ else
+ reqs[0].wait();
+ break;
+
+ case mk_test_any:
+ {
+ boost::optional<status_iterator_pair> result;
+ do {
+ result = test_any(reqs.begin(), reqs.end());
+ } while (!result);
+ if (result->second == reqs.begin())
+ reqs[1].wait();
+ else
+ reqs[0].wait();
+ break;
+ }
+
+ case mk_wait_all:
+ wait_all(reqs.begin(), reqs.end());
+ break;
+
+ case mk_wait_all_keep:
+ {
+ std::vector<status> stats;
+ wait_all(reqs.begin(), reqs.end(), std::back_inserter(stats));
+ }
+ break;
+
+ case mk_test_all:
+ while (!test_all(reqs.begin(), reqs.end())) { /* Busy wait */ }
+ break;
+
+ case mk_test_all_keep:
+ {
+ std::vector<status> stats;
+ while (!test_all(reqs.begin(), reqs.end(), std::back_inserter(stats)))
+ /* Busy wait */;
+ }
+ break;
+
+ case mk_wait_some:
+ {
+ std::vector<request>::iterator pos = reqs.end();
+ do {
+ pos = wait_some(reqs.begin(), pos);
+ } while (pos != reqs.begin());
+ }
+ break;
+
+ case mk_wait_some_keep:
+ {
+ std::vector<status> stats;
+ std::vector<request>::iterator pos = reqs.end();
+ do {
+ pos = wait_some(reqs.begin(), pos, std::back_inserter(stats)).second;
+ } while (pos != reqs.begin());
+ }
+ break;
+
+ case mk_test_some:
+ {
+ std::vector<request>::iterator pos = reqs.end();
+ do {
+ pos = test_some(reqs.begin(), pos);
+ } while (pos != reqs.begin());
+ }
+ break;
+
+ case mk_test_some_keep:
+ {
+ std::vector<status> stats;
+ std::vector<request>::iterator pos = reqs.end();
+ do {
+ pos = test_some(reqs.begin(), pos, std::back_inserter(stats)).second;
+ } while (pos != reqs.begin());
+ }
+ break;
+
+ default:
+ BOOST_CHECK(false);
+ }
+
+ if (comm.rank() == 0) {
+ bool okay = true;
+
+ if (!((incoming_value == values[0])))
+ okay = false;
+
+ if (method != mk_wait_any && method != mk_test_any
+ && !std::equal(incoming_values.begin(), incoming_values.end(),
+ values))
+ okay = false;
+
+ if (okay)
+ std::cout << "OK." << std::endl;
+ else
+ std::cerr << "ERROR!" << std::endl;
+ }
+
+ BOOST_CHECK(incoming_value == values[0]);
+
+ if (method != mk_wait_any && method != mk_test_any)
+ BOOST_CHECK(std::equal(incoming_values.begin(), incoming_values.end(),
+ values));
+}
+
+BOOST_AUTO_TEST_CASE(nonblocking)
+{
+ boost::mpi::environment env;
+ communicator comm;
+
+ int int_array[3] = {17, 42, 256};
+ nonblocking_tests(comm, int_array, 3, "integers", false);
+
+ gps_position gps_array[2] = {
+ gps_position(17, 42, .06),
+ gps_position(42, 17, .06)
+ };
+ nonblocking_tests(comm, gps_array, 2, "gps positions", false);
+
+ std::string string_array[2] = { "Hello", "World" };
+ nonblocking_tests(comm, string_array, 2, "strings", true);
+
+ std::list<std::string> lst_of_strings;
+ for (int i = 0; i < comm.size(); ++i)
+ lst_of_strings.push_back(boost::lexical_cast<std::string>(i));
+
+ nonblocking_tests(comm, &lst_of_strings, 1, "list of strings", true);
+}
diff --git a/src/boost/libs/mpi/test/pointer_test.cpp b/src/boost/libs/mpi/test/pointer_test.cpp
new file mode 100644
index 000000000..65428e752
--- /dev/null
+++ b/src/boost/libs/mpi/test/pointer_test.cpp
@@ -0,0 +1,42 @@
+// 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 pointer serialization
+#include <boost/mpi.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+
+#define BOOST_TEST_MODULE mpi_pointer
+#include <boost/test/included/unit_test.hpp>
+
+class A
+{
+ public:
+ int i;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int version)
+ {
+ ar & i;
+ }
+};
+
+BOOST_AUTO_TEST_CASE(pointer)
+{
+ boost::mpi::environment env;
+ boost::mpi::communicator world;
+
+ if (world.rank() == 0) {
+ boost::shared_ptr<A> p(new A);
+ p->i = 42;
+ world.send(1, 0, p);
+ } else if (world.rank() == 1) {
+ boost::shared_ptr<A> p;
+ world.recv(0, 0, p);
+ std::cout << p->i << std::endl;
+ BOOST_CHECK(p->i==42);
+ }
+}
+
diff --git a/src/boost/libs/mpi/test/python/all_gather_test.py b/src/boost/libs/mpi/test/python/all_gather_test.py
new file mode 100644
index 000000000..824dc892f
--- /dev/null
+++ b/src/boost/libs/mpi/test/python/all_gather_test.py
@@ -0,0 +1,25 @@
+# Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
+
+# 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)
+
+# Test all_gather() collective.
+
+import boost.parallel.mpi as mpi
+from generators import *
+
+def all_gather_test(comm, generator, kind):
+ if comm.rank == 0: print ("Gathering %s..." % (kind,)),
+ my_value = generator(comm.rank)
+ result = mpi.all_gather(comm, my_value)
+ for p in range(0, comm.size):
+ assert result[p] == generator(p)
+ if comm.rank == 0: print "OK."
+
+ return
+
+all_gather_test(mpi.world, int_generator, "integers")
+all_gather_test(mpi.world, gps_generator, "GPS positions")
+all_gather_test(mpi.world, string_generator, "strings")
+all_gather_test(mpi.world, string_list_generator, "list of strings")
diff --git a/src/boost/libs/mpi/test/python/all_reduce_test.py b/src/boost/libs/mpi/test/python/all_reduce_test.py
new file mode 100644
index 000000000..c3285e65b
--- /dev/null
+++ b/src/boost/libs/mpi/test/python/all_reduce_test.py
@@ -0,0 +1,29 @@
+# Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
+
+# 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)
+
+# Test all_reduce() collective.
+
+import boost.parallel.mpi as mpi
+from generators import *
+
+def all_reduce_test(comm, generator, kind, op, op_kind):
+ if comm.rank == 0:
+ print ("Reducing to %s of %s..." % (op_kind, kind)),
+ my_value = generator(comm.rank)
+ result = mpi.all_reduce(comm, my_value, op)
+ expected_result = generator(0);
+ for p in range(1, comm.size):
+ expected_result = op(expected_result, generator(p))
+
+ assert result == expected_result
+ if comm.rank == 0:
+ print "OK."
+ return
+
+all_reduce_test(mpi.world, int_generator, "integers", lambda x,y:x + y, "sum")
+all_reduce_test(mpi.world, int_generator, "integers", lambda x,y:x * y, "product")
+all_reduce_test(mpi.world, string_generator, "strings", lambda x,y:x + y, "concatenation")
+all_reduce_test(mpi.world, string_list_generator, "list of strings", lambda x,y:x + y, "concatenation")
diff --git a/src/boost/libs/mpi/test/python/all_to_all_test.py b/src/boost/libs/mpi/test/python/all_to_all_test.py
new file mode 100644
index 000000000..b149bf0d3
--- /dev/null
+++ b/src/boost/libs/mpi/test/python/all_to_all_test.py
@@ -0,0 +1,30 @@
+# Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
+
+# 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)
+
+# Test all_to_all() collective.
+
+import boost.parallel.mpi as mpi
+from generators import *
+
+def all_to_all_test(comm, generator, kind):
+ if comm.rank == 0:
+ print ("All-to-all transmission of %s..." % (kind,)),
+
+ values = list()
+ for p in range(0, comm.size):
+ values.append(generator(p))
+ result = mpi.all_to_all(comm, values)
+
+ for p in range(0, comm.size):
+ assert result[p] == generator(comm.rank)
+
+ if comm.rank == 0: print "OK."
+ return
+
+all_to_all_test(mpi.world, int_generator, "integers")
+all_to_all_test(mpi.world, gps_generator, "GPS positions")
+all_to_all_test(mpi.world, string_generator, "strings")
+all_to_all_test(mpi.world, string_list_generator, "list of strings")
diff --git a/src/boost/libs/mpi/test/python/broadcast_test.py b/src/boost/libs/mpi/test/python/broadcast_test.py
new file mode 100644
index 000000000..dbd53d1be
--- /dev/null
+++ b/src/boost/libs/mpi/test/python/broadcast_test.py
@@ -0,0 +1,29 @@
+# Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
+
+# 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)
+
+# Test broadcast() collective.
+
+import boost.parallel.mpi as mpi
+
+def broadcast_test(comm, value, kind, root):
+ if comm.rank == root:
+ print ("Broadcasting %s from root %d..." % (kind, root)),
+
+ got_value = mpi.broadcast(comm, value, root)
+ assert got_value == value
+ if comm.rank == root:
+ print "OK."
+ return
+
+broadcast_test(mpi.world, 17, 'integer', 0)
+broadcast_test(mpi.world, 17, 'integer', 1)
+broadcast_test(mpi.world, 'Hello, World!', 'string', 0)
+broadcast_test(mpi.world, 'Hello, World!', 'string', 1)
+broadcast_test(mpi.world, ['Hello', 'MPI', 'Python', 'World'],
+ 'list of strings', 0)
+broadcast_test(mpi.world, ['Hello', 'MPI', 'Python', 'World'],
+ 'list of strings', 1)
+
diff --git a/src/boost/libs/mpi/test/python/gather_test.py b/src/boost/libs/mpi/test/python/gather_test.py
new file mode 100644
index 000000000..d56b3a416
--- /dev/null
+++ b/src/boost/libs/mpi/test/python/gather_test.py
@@ -0,0 +1,32 @@
+# Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
+
+# 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)
+
+# Test gather() collective.
+
+import boost.parallel.mpi as mpi
+from generators import *
+
+def gather_test(comm, generator, kind, root):
+ if comm.rank == root:
+ print ("Gathering %s to root %d..." % (kind, root)),
+ my_value = generator(comm.rank)
+ result = mpi.gather(comm, my_value, root)
+ if comm.rank == root:
+ for p in range(0, comm.size):
+ assert result[p] == generator(p)
+ print "OK."
+ else:
+ assert result == None
+ return
+
+gather_test(mpi.world, int_generator, "integers", 0)
+gather_test(mpi.world, int_generator, "integers", 1)
+gather_test(mpi.world, gps_generator, "GPS positions", 0)
+gather_test(mpi.world, gps_generator, "GPS positions", 1)
+gather_test(mpi.world, string_generator, "strings", 0)
+gather_test(mpi.world, string_generator, "strings", 1)
+gather_test(mpi.world, string_list_generator, "list of strings", 0)
+gather_test(mpi.world, string_list_generator, "list of strings", 1)
diff --git a/src/boost/libs/mpi/test/python/generators.py b/src/boost/libs/mpi/test/python/generators.py
new file mode 100644
index 000000000..8cdd3e056
--- /dev/null
+++ b/src/boost/libs/mpi/test/python/generators.py
@@ -0,0 +1,23 @@
+# Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
+
+# 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)
+
+# Value generators used in the Boost.MPI Python regression tests
+def int_generator(p):
+ return 17 + p
+
+def gps_generator(p):
+ return (39 + p, 16, 20.2799)
+
+def string_generator(p):
+ result = "%d rosebud" % p;
+ if p != 1: result = result + 's'
+ return result
+
+def string_list_generator(p):
+ result = list()
+ for i in range(0,p):
+ result.append(str(i))
+ return result
diff --git a/src/boost/libs/mpi/test/python/nonblocking_test.py b/src/boost/libs/mpi/test/python/nonblocking_test.py
new file mode 100644
index 000000000..73b451c53
--- /dev/null
+++ b/src/boost/libs/mpi/test/python/nonblocking_test.py
@@ -0,0 +1,131 @@
+# (C) Copyright 2007
+# Andreas Kloeckner <inform -at- tiker.net>
+#
+# 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)
+#
+# Authors: Andreas Kloeckner
+
+
+
+
+import boost.mpi as mpi
+import random
+import sys
+
+MAX_GENERATIONS = 20
+TAG_DEBUG = 0
+TAG_DATA = 1
+TAG_TERMINATE = 2
+TAG_PROGRESS_REPORT = 3
+
+
+
+
+class TagGroupListener:
+ """Class to help listen for only a given set of tags.
+
+ This is contrived: Typicallly you could just listen for
+ mpi.any_tag and filter."""
+ def __init__(self, comm, tags):
+ self.tags = tags
+ self.comm = comm
+ self.active_requests = {}
+
+ def wait(self):
+ for tag in self.tags:
+ if tag not in self.active_requests:
+ self.active_requests[tag] = self.comm.irecv(tag=tag)
+ requests = mpi.RequestList(self.active_requests.values())
+ data, status, index = mpi.wait_any(requests)
+ del self.active_requests[status.tag]
+ return status, data
+
+ def cancel(self):
+ for r in self.active_requests.itervalues():
+ r.cancel()
+ #r.wait()
+ self.active_requests = {}
+
+
+
+def rank0():
+ sent_histories = (mpi.size-1)*15
+ print "sending %d packets on their way" % sent_histories
+ send_reqs = mpi.RequestList()
+ for i in range(sent_histories):
+ dest = random.randrange(1, mpi.size)
+ send_reqs.append(mpi.world.isend(dest, TAG_DATA, []))
+
+ mpi.wait_all(send_reqs)
+
+ completed_histories = []
+ progress_reports = {}
+ dead_kids = []
+
+ tgl = TagGroupListener(mpi.world,
+ [TAG_DATA, TAG_DEBUG, TAG_PROGRESS_REPORT, TAG_TERMINATE])
+
+ def is_complete():
+ for i in progress_reports.values():
+ if i != sent_histories:
+ return False
+ return len(dead_kids) == mpi.size-1
+
+ while True:
+ status, data = tgl.wait()
+
+ if status.tag == TAG_DATA:
+ #print "received completed history %s from %d" % (data, status.source)
+ completed_histories.append(data)
+ if len(completed_histories) == sent_histories:
+ print "all histories received, exiting"
+ for rank in range(1, mpi.size):
+ mpi.world.send(rank, TAG_TERMINATE, None)
+ elif status.tag == TAG_PROGRESS_REPORT:
+ progress_reports[len(data)] = progress_reports.get(len(data), 0) + 1
+ elif status.tag == TAG_DEBUG:
+ print "[DBG %d] %s" % (status.source, data)
+ elif status.tag == TAG_TERMINATE:
+ dead_kids.append(status.source)
+ else:
+ print "unexpected tag %d from %d" % (status.tag, status.source)
+
+ if is_complete():
+ break
+
+ print "OK"
+
+def comm_rank():
+ while True:
+ data, status = mpi.world.recv(return_status=True)
+ if status.tag == TAG_DATA:
+ mpi.world.send(0, TAG_PROGRESS_REPORT, data)
+ data.append(mpi.rank)
+ if len(data) >= MAX_GENERATIONS:
+ dest = 0
+ else:
+ dest = random.randrange(1, mpi.size)
+ mpi.world.send(dest, TAG_DATA, data)
+ elif status.tag == TAG_TERMINATE:
+ from time import sleep
+ mpi.world.send(0, TAG_TERMINATE, 0)
+ break
+ else:
+ print "[DIRECTDBG %d] unexpected tag %d from %d" % (mpi.rank, status.tag, status.source)
+
+
+def main():
+ # this program sends around messages consisting of lists of visited nodes
+ # randomly. After MAX_GENERATIONS, they are returned to rank 0.
+
+ if mpi.rank == 0:
+ rank0()
+ else:
+ comm_rank()
+
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/boost/libs/mpi/test/python/reduce_test.py b/src/boost/libs/mpi/test/python/reduce_test.py
new file mode 100644
index 000000000..65f09f5ba
--- /dev/null
+++ b/src/boost/libs/mpi/test/python/reduce_test.py
@@ -0,0 +1,31 @@
+# Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
+
+# 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)
+
+# Test reduce() collective.
+
+import boost.parallel.mpi as mpi
+from generators import *
+
+def reduce_test(comm, generator, kind, op, op_kind, root):
+ if comm.rank == root:
+ print ("Reducing to %s of %s at root %d..." % (op_kind, kind, root)),
+ my_value = generator(comm.rank)
+ result = mpi.reduce(comm, my_value, op, root)
+ if comm.rank == root:
+ expected_result = generator(0);
+ for p in range(1, comm.size):
+ expected_result = op(expected_result, generator(p))
+ assert result == expected_result
+ print "OK."
+ else:
+ assert result == None
+ return
+
+reduce_test(mpi.world, int_generator, "integers", lambda x,y:x + y, "sum", 0)
+reduce_test(mpi.world, int_generator, "integers", lambda x,y:x * y, "product", 1)
+reduce_test(mpi.world, int_generator, "integers", min, "minimum", 0)
+reduce_test(mpi.world, string_generator, "strings", lambda x,y:x + y, "concatenation", 0)
+reduce_test(mpi.world, string_list_generator, "list of strings", lambda x,y:x + y, "concatenation", 0)
diff --git a/src/boost/libs/mpi/test/python/ring_test.py b/src/boost/libs/mpi/test/python/ring_test.py
new file mode 100644
index 000000000..3c8b5b92f
--- /dev/null
+++ b/src/boost/libs/mpi/test/python/ring_test.py
@@ -0,0 +1,42 @@
+# Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
+
+# 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)
+
+# Test basic communication.
+
+import boost.parallel.mpi as mpi
+
+def ring_test(comm, value, kind, root):
+ next_peer = (comm.rank + 1) % comm.size;
+ prior_peer = (comm.rank + comm.size - 1) % comm.size;
+
+ if comm.rank == root:
+ print ("Passing %s around a ring from root %d..." % (kind, root)),
+ comm.send(next_peer, 0, value)
+ (other_value, stat) = comm.recv(return_status = True)
+ assert value == other_value
+ assert stat.source == prior_peer
+ assert stat.tag == 0
+ else:
+ msg = comm.probe()
+ other_value = comm.recv(msg.source, msg.tag)
+ assert value == other_value
+ comm.send(next_peer, 0, other_value)
+
+ comm.barrier()
+ if comm.rank == root:
+ print "OK"
+ pass
+
+if mpi.world.size < 2:
+ print "ERROR: ring_test.py must be executed with more than one process"
+ mpi.world.abort(-1);
+
+ring_test(mpi.world, 17, 'integers', 0)
+ring_test(mpi.world, 17, 'integers', 1)
+ring_test(mpi.world, 'Hello, World!', 'string', 0)
+ring_test(mpi.world, 'Hello, World!', 'string', 1)
+ring_test(mpi.world, ['Hello', 'MPI', 'Python', 'World'], 'list of strings', 0)
+ring_test(mpi.world, ['Hello', 'MPI', 'Python', 'World'], 'list of strings', 1)
diff --git a/src/boost/libs/mpi/test/python/scan_test.py b/src/boost/libs/mpi/test/python/scan_test.py
new file mode 100644
index 000000000..193a6a448
--- /dev/null
+++ b/src/boost/libs/mpi/test/python/scan_test.py
@@ -0,0 +1,29 @@
+# Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
+
+# 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)
+
+# Test scan() collective.
+
+import boost.parallel.mpi as mpi
+from generators import *
+
+def scan_test(comm, generator, kind, op, op_kind):
+ if comm.rank == 0:
+ print ("Prefix reduction to %s of %s..." % (op_kind, kind)),
+ my_value = generator(comm.rank)
+ result = mpi.scan(comm, my_value, op)
+ expected_result = generator(0);
+ for p in range(1, comm.rank+1):
+ expected_result = op(expected_result, generator(p))
+
+ assert result == expected_result
+ if comm.rank == 0:
+ print "OK."
+ return
+
+scan_test(mpi.world, int_generator, "integers", lambda x,y:x + y, "sum")
+scan_test(mpi.world, int_generator, "integers", lambda x,y:x * y, "product")
+scan_test(mpi.world, string_generator, "strings", lambda x,y:x + y, "concatenation")
+scan_test(mpi.world, string_list_generator, "list of strings", lambda x,y:x + y, "concatenation")
diff --git a/src/boost/libs/mpi/test/python/scatter_test.py b/src/boost/libs/mpi/test/python/scatter_test.py
new file mode 100644
index 000000000..e0bad9673
--- /dev/null
+++ b/src/boost/libs/mpi/test/python/scatter_test.py
@@ -0,0 +1,36 @@
+# Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
+
+# 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)
+
+# Test scatter() collective.
+
+import boost.parallel.mpi as mpi
+from generators import *
+
+def scatter_test(comm, generator, kind, root):
+ if comm.rank == root:
+ print ("Scattering %s from root %d..." % (kind, root)),
+
+ if comm.rank == root:
+ values = list()
+ for p in range(0, comm.size):
+ values.append(generator(p))
+ result = mpi.scatter(comm, values, root = root)
+ else:
+ result = mpi.scatter(comm, root = root);
+
+ assert result == generator(comm.rank)
+
+ if comm.rank == root: print "OK."
+ return
+
+scatter_test(mpi.world, int_generator, "integers", 0)
+scatter_test(mpi.world, int_generator, "integers", 1)
+scatter_test(mpi.world, gps_generator, "GPS positions", 0)
+scatter_test(mpi.world, gps_generator, "GPS positions", 1)
+scatter_test(mpi.world, string_generator, "strings", 0)
+scatter_test(mpi.world, string_generator, "strings", 1)
+scatter_test(mpi.world, string_list_generator, "list of strings", 0)
+scatter_test(mpi.world, string_list_generator, "list of strings", 1)
diff --git a/src/boost/libs/mpi/test/python/skeleton_content_test.cpp b/src/boost/libs/mpi/test/python/skeleton_content_test.cpp
new file mode 100644
index 000000000..7ccae00ef
--- /dev/null
+++ b/src/boost/libs/mpi/test/python/skeleton_content_test.cpp
@@ -0,0 +1,37 @@
+// (C) Copyright 2006 Douglas Gregor <doug.gregor -at- gmail.com>
+
+// 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)
+
+// Authors: Douglas Gregor
+
+#include <boost/parallel/mpi/python.hpp>
+#include <boost/python.hpp>
+#include <boost/serialization/list.hpp>
+using namespace boost::python;
+
+template<typename T>
+boost::python::list list_to_python(const std::list<T>& value) {
+ boost::python::list result;
+ for (typename std::list<T>::const_iterator i = value.begin();
+ i != value.end(); ++i)
+ result.append(*i);
+ return result;
+}
+
+BOOST_PYTHON_MODULE(skeleton_content)
+{
+ using boost::python::arg;
+
+ class_<std::list<int> >("list_int")
+ .def("push_back", &std::list<int>::push_back, arg("value"))
+ .def("pop_back", &std::list<int>::pop_back)
+ .def("reverse", &std::list<int>::reverse)
+ .def(boost::python::self == boost::python::self)
+ .def(boost::python::self != boost::python::self)
+ .add_property("size", &std::list<int>::size)
+ .def("to_python", &list_to_python<int>);
+
+ boost::parallel::mpi::python::register_skeleton_and_content<std::list<int> >();
+}
diff --git a/src/boost/libs/mpi/test/python/skeleton_content_test.py b/src/boost/libs/mpi/test/python/skeleton_content_test.py
new file mode 100644
index 000000000..1dfde3cf7
--- /dev/null
+++ b/src/boost/libs/mpi/test/python/skeleton_content_test.py
@@ -0,0 +1,75 @@
+# Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
+
+# 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)
+
+# Test skeleton/content
+
+import boost.parallel.mpi as mpi
+import skeleton_content
+
+def test_skeleton_and_content(comm, root, manual_broadcast = True):
+ assert manual_broadcast
+
+ # Setup data
+ list_size = comm.size + 7
+ original_list = skeleton_content.list_int()
+ for i in range(0,list_size):
+ original_list.push_back(i)
+
+ if comm.rank == root:
+ # Broadcast skeleton
+ print ("Broadcasting integer list skeleton from root %d..." % (root)),
+ if manual_broadcast:
+ for p in range(0,comm.size):
+ if p != comm.rank:
+ comm.send(p, 0, value = mpi.skeleton(original_list))
+ print "OK."
+
+ # Broadcast content
+ print ("Broadcasting integer list content from root %d..." % (root)),
+ if manual_broadcast:
+ for p in range(0,comm.size):
+ if p != comm.rank:
+ comm.send(p, 0, value = mpi.get_content(original_list))
+
+ print "OK."
+
+ # Broadcast reversed content
+ original_list.reverse()
+ print ("Broadcasting reversed integer list content from root %d..." % (root)),
+ if manual_broadcast:
+ for p in range(0,comm.size):
+ if p != comm.rank:
+ comm.send(p, 0, value = mpi.get_content(original_list))
+
+ print "OK."
+ else:
+ # Allocate some useless data, to try to get the addresses of
+ # the underlying lists used later to be different across
+ # processors.
+ junk_list = skeleton_content.list_int()
+ for i in range(0,comm.rank * 3 + 1):
+ junk_list.push_back(i)
+
+ # Receive the skeleton of the list
+ if manual_broadcast:
+ transferred_list_skeleton = comm.recv(root, 0)
+ assert transferred_list_skeleton.object.size == list_size
+
+ # Receive the content and check it
+ transferred_list = transferred_list_skeleton.object
+ if manual_broadcast:
+ comm.recv(root, 0, mpi.get_content(transferred_list))
+ assert transferred_list == original_list
+
+ # Receive the content (again) and check it
+ original_list.reverse()
+ if manual_broadcast:
+ comm.recv(root, 0, mpi.get_content(transferred_list))
+ assert transferred_list == original_list
+
+
+test_skeleton_and_content(mpi.world, 0)
+test_skeleton_and_content(mpi.world, 1)
diff --git a/src/boost/libs/mpi/test/reduce_test.cpp b/src/boost/libs/mpi/test/reduce_test.cpp
new file mode 100644
index 000000000..44532cd5b
--- /dev/null
+++ b/src/boost/libs/mpi/test/reduce_test.cpp
@@ -0,0 +1,237 @@
+// Copyright (C) 2005, 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
+
+// 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 reduce() collective.
+#include <boost/mpi/collectives/reduce.hpp>
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/environment.hpp>
+#include <algorithm>
+#include <boost/serialization/string.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/lexical_cast.hpp>
+#include <numeric>
+
+#define BOOST_TEST_MODULE mpi_reduce_test
+#include <boost/test/included/unit_test.hpp>
+
+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
+reduce_test(const communicator& comm, Generator generator,
+ const char* type_kind, Op op, const char* op_kind,
+ typename Generator::result_type init,
+ int root = -1)
+{
+ typedef typename Generator::result_type value_type;
+ value_type value = generator(comm.rank());
+
+ if (root == -1) {
+ for (root = 0; root < comm.size(); ++root)
+ reduce_test(comm, generator, type_kind, op, op_kind, init, root);
+ } else {
+ using boost::mpi::reduce;
+
+ if (comm.rank() == root) {
+ std::cout << "Reducing to " << op_kind << " of " << type_kind
+ << " at root " << root << "...";
+ std::cout.flush();
+
+ value_type result_value;
+ reduce(comm, value, result_value, op, root);
+
+ // 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)
+ std::cout << "OK." << std::endl;
+ } else {
+ reduce(comm, value, op, root);
+ }
+ }
+
+ (comm.barrier)();
+}
+
+// Generates integers to test with 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 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 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
+
+BOOST_AUTO_TEST_CASE(reduce_check)
+{
+ using namespace boost::mpi;
+ environment env;
+
+ communicator comm;
+
+ // Built-in MPI datatypes with built-in MPI operations
+ reduce_test(comm, int_generator(), "integers", std::plus<int>(), "sum", 0);
+ reduce_test(comm, int_generator(), "integers", std::multiplies<int>(),
+ "product", 1);
+ reduce_test(comm, int_generator(), "integers", maximum<int>(),
+ "maximum", 0);
+ 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.
+ reduce_test(comm, point_generator(point(0,0,0)), "points",
+ std::plus<point>(), "sum", point());
+
+ // Built-in MPI datatypes with user-defined operations
+ reduce_test(comm, int_generator(17), "integers", secret_int_bit_and(),
+ "bitwise and", -1);
+
+ // Arbitrary types with user-defined, commutative operations.
+ 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
+ reduce_test(comm, string_generator(), "strings",
+ std::plus<std::string>(), "concatenation", std::string());
+}
diff --git a/src/boost/libs/mpi/test/ring_test.cpp b/src/boost/libs/mpi/test/ring_test.cpp
new file mode 100644
index 000000000..573d3d387
--- /dev/null
+++ b/src/boost/libs/mpi/test/ring_test.cpp
@@ -0,0 +1,124 @@
+// 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 communicator that passes data around a ring and
+// verifies that the same data makes it all the way. Should test all
+// of the various kinds of data that can be sent (primitive types, POD
+// types, serializable objects, etc.)
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/environment.hpp>
+#include <algorithm>
+#include "gps_position.hpp"
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/list.hpp>
+//#include "debugger.cpp"
+
+#define BOOST_TEST_MODULE mpi_reduce_ring
+#include <boost/test/included/unit_test.hpp>
+
+using boost::mpi::communicator;
+using boost::mpi::status;
+
+template<typename T>
+void
+ring_test(const communicator& comm, const T& pass_value, const char* kind,
+ int root = 0)
+{
+ T transferred_value;
+
+ int rank = comm.rank();
+ int size = comm.size();
+
+ if (rank == root) {
+ std::cout << "Passing " << kind << " around a ring from root " << root
+ << "...";
+ comm.send((rank + 1) % size, 0, pass_value);
+ comm.recv((rank + size - 1) % size, 0, transferred_value);
+ BOOST_CHECK(transferred_value == pass_value);
+ if (transferred_value == pass_value) std::cout << " OK." << std::endl;
+ } else {
+ comm.recv((rank + size - 1) % size, 0, transferred_value);
+ BOOST_CHECK(transferred_value == pass_value);
+ comm.send((rank + 1) % size, 0, transferred_value);
+ }
+
+ (comm.barrier)();
+}
+
+
+template<typename T>
+void
+ring_array_test(const communicator& comm, const T* pass_values,
+ int n, const char* kind, int root = 0)
+{
+ T* transferred_values = new T[n];
+ int rank = comm.rank();
+ int size = comm.size();
+
+ if (rank == root) {
+
+ std::cout << "Passing " << kind << " array around a ring from root "
+ << root << "...";
+ comm.send((rank + 1) % size, 0, pass_values, n);
+ comm.recv((rank + size - 1) % size, 0, transferred_values, n);
+ bool okay = std::equal(pass_values, pass_values + n,
+ transferred_values);
+ BOOST_CHECK(okay);
+ if (okay) std::cout << " OK." << std::endl;
+ } else {
+ status stat = comm.probe(boost::mpi::any_source, 0);
+ boost::optional<int> num_values = stat.template count<T>();
+ if (boost::mpi::is_mpi_datatype<T>())
+ BOOST_CHECK(num_values && *num_values == n);
+ else
+ BOOST_CHECK(!num_values || *num_values == n);
+ comm.recv(stat.source(), 0, transferred_values, n);
+ BOOST_CHECK(std::equal(pass_values, pass_values + n,
+ transferred_values));
+ comm.send((rank + 1) % size, 0, transferred_values, n);
+ }
+ (comm.barrier)();
+ delete [] transferred_values;
+}
+
+enum color_t {red, green, blue};
+BOOST_IS_MPI_DATATYPE(color_t)
+
+BOOST_AUTO_TEST_CASE(ring)
+{
+ boost::mpi::environment env;
+ communicator comm;
+
+ BOOST_TEST_REQUIRE(comm.size() > 1);
+
+ // Check transfer of individual objects
+ ring_test(comm, 17, "integers", 0);
+ ring_test(comm, 17, "integers", 1);
+ ring_test(comm, red, "enums", 1);
+ ring_test(comm, red, "enums", 1);
+ ring_test(comm, gps_position(39,16,20.2799), "GPS positions", 0);
+ ring_test(comm, gps_position(26,25,30.0), "GPS positions", 1);
+ ring_test(comm, std::string("Rosie"), "string", 0);
+
+ std::list<std::string> strings;
+ strings.push_back("Hello");
+ strings.push_back("MPI");
+ strings.push_back("World");
+ ring_test(comm, strings, "list of strings", 1);
+
+ // Check transfer of arrays
+ int int_array[2] = { 17, 42 };
+ ring_array_test(comm, int_array, 2, "integer", 1);
+ gps_position gps_position_array[2] = {
+ gps_position(39,16,20.2799),
+ gps_position(26,25,30.0)
+ };
+ ring_array_test(comm, gps_position_array, 2, "GPS position", 1);
+
+ std::string string_array[3] = { "Hello", "MPI", "World" };
+ ring_array_test(comm, string_array, 3, "string", 0);
+ ring_array_test(comm, string_array, 3, "string", 1);
+}
diff --git a/src/boost/libs/mpi/test/scan_test.cpp b/src/boost/libs/mpi/test/scan_test.cpp
new file mode 100644
index 000000000..579ce8ded
--- /dev/null
+++ b/src/boost/libs/mpi/test/scan_test.cpp
@@ -0,0 +1,228 @@
+// Copyright (C) 2005, 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
+
+// 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 scan() collective.
+#include <boost/mpi/collectives/scan.hpp>
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/environment.hpp>
+#include <algorithm>
+#include <boost/serialization/string.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/lexical_cast.hpp>
+#include <numeric>
+
+#define BOOST_TEST_MODULE mpi_scan_test
+#include <boost/test/included/unit_test.hpp>
+
+
+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
+scan_test(const communicator& comm, Generator generator,
+ const char* type_kind, Op op, const char* op_kind)
+{
+ typedef typename Generator::result_type value_type;
+ value_type value = generator(comm.rank());
+ using boost::mpi::scan;
+
+ if (comm.rank() == 0) {
+ std::cout << "Prefix reducing to " << op_kind << " of " << type_kind
+ << "...";
+ std::cout.flush();
+ }
+
+ value_type result_value;
+ scan(comm, value, result_value, op);
+ value_type scan_result = scan(comm, value, op);
+ BOOST_CHECK(scan_result == result_value);
+
+ // Compute expected result
+ std::vector<value_type> generated_values;
+ for (int p = 0; p < comm.size(); ++p)
+ generated_values.push_back(generator(p));
+ std::vector<value_type> expected_results(comm.size());
+ std::partial_sum(generated_values.begin(), generated_values.end(),
+ expected_results.begin(), op);
+ BOOST_CHECK(result_value == expected_results[comm.rank()]);
+ if (comm.rank() == 0) std::cout << "Done." << std::endl;
+
+ (comm.barrier)();
+}
+
+// Generates integers to test with scan()
+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 scan()
+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 scan()
+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
+
+BOOST_AUTO_TEST_CASE(scan_check)
+{
+ using namespace boost::mpi;
+ environment env;
+ communicator comm;
+
+ // Built-in MPI datatypes with built-in MPI operations
+ scan_test(comm, int_generator(), "integers", std::plus<int>(), "sum");
+ scan_test(comm, int_generator(), "integers", std::multiplies<int>(),
+ "product");
+ scan_test(comm, int_generator(), "integers", maximum<int>(),
+ "maximum");
+ scan_test(comm, int_generator(), "integers", minimum<int>(),
+ "minimum");
+
+ // User-defined MPI datatypes with operations that have the
+ // same name as built-in operations.
+ scan_test(comm, point_generator(point(0,0,0)), "points",
+ std::plus<point>(), "sum");
+
+ // Built-in MPI datatypes with user-defined operations
+ scan_test(comm, int_generator(17), "integers", secret_int_bit_and(),
+ "bitwise and");
+
+ // Arbitrary types with user-defined, commutative operations.
+ scan_test(comm, wrapped_int_generator(17), "wrapped integers",
+ std::plus<wrapped_int>(), "sum");
+
+ // Arbitrary types with (non-commutative) user-defined operations
+ scan_test(comm, string_generator(), "strings",
+ std::plus<std::string>(), "concatenation");
+}
diff --git a/src/boost/libs/mpi/test/scatter_test.cpp b/src/boost/libs/mpi/test/scatter_test.cpp
new file mode 100644
index 000000000..f116bb342
--- /dev/null
+++ b/src/boost/libs/mpi/test/scatter_test.cpp
@@ -0,0 +1,233 @@
+// 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 scatter() and scatterv() collectives.
+#include <iterator>
+#include <boost/mpi/collectives/scatter.hpp>
+#include <boost/mpi/collectives/scatterv.hpp>
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/environment.hpp>
+#include "gps_position.hpp"
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/list.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/lexical_cast.hpp>
+
+#define BOOST_TEST_MODULE mpi_scatter
+#include <boost/test/included/unit_test.hpp>
+
+using namespace boost::mpi;
+
+template<typename Generator>
+void
+scatter_test(const communicator& comm, Generator generator,
+ const char* kind, int root = -1)
+{
+ typedef typename Generator::result_type value_type;
+
+ if (root == -1) {
+ for (root = 0; root < comm.size(); ++root)
+ scatter_test(comm, generator, kind, root);
+ } else {
+ using boost::mpi::scatter;
+
+ value_type value;
+
+ if (comm.rank() == root) {
+ std::vector<value_type> values;
+
+ for (int p = 0; p < comm.size(); ++p)
+ values.push_back(generator(p));
+
+ std::cout << "Scattering " << kind << " from root "
+ << root << "..." << std::endl;
+
+ scatter(comm, values, value, root);
+ } else {
+ scatter(comm, value, root);
+ }
+
+ BOOST_CHECK(value == generator(comm.rank()));
+ }
+
+ comm.barrier();
+}
+
+
+//
+// Generators to test with scatter/scatterv
+//
+struct int_generator
+{
+ typedef int result_type;
+
+ int operator()(int p) const { return 17 + p; }
+};
+
+struct gps_generator
+{
+ typedef gps_position result_type;
+
+ gps_position operator()(int p) const
+ {
+ return gps_position(39 + p, 16, 20.2799);
+ }
+};
+
+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 string_list_generator
+{
+ typedef std::list<std::string> result_type;
+
+ std::list<std::string> operator()(int p) const
+ {
+ std::list<std::string> result;
+ for (int i = 0; i <= p; ++i) {
+ std::string value = boost::lexical_cast<std::string>(i);
+ result.push_back(value);
+ }
+ return result;
+ }
+};
+
+std::ostream&
+operator<<(std::ostream& out, std::list<std::string> const& l) {
+ out << '[';
+ std::copy(l.begin(), l.end(), std::ostream_iterator<std::string>(out, " "));
+ out << ']';
+ return out;
+}
+
+template<typename Generator>
+void
+scatterv_test(const communicator& comm, Generator generator,
+ const char* kind, int root = -1)
+{
+ typedef typename Generator::result_type value_type;
+
+ if (root == -1) {
+ for (root = 0; root < comm.size(); ++root)
+ scatterv_test(comm, generator, kind, root);
+ } else {
+ using boost::mpi::scatterv;
+
+ int mysize = comm.rank() + 1;
+ std::vector<value_type> myvalues(mysize);
+
+ if (comm.rank() == root) {
+ std::vector<value_type> values;
+ std::vector<int> sizes(comm.size());
+
+ // process p will receive p+1 identical generator(p) elements
+ for (int p = 0; p < comm.size(); ++p) {
+ for (int i = 0; i < p+1; ++i)
+ values.push_back(generator(p));
+ sizes[p] = p + 1;
+ }
+
+ std::cout << "Scatteringv " << kind << " from root "
+ << root << "..." << std::endl;
+ assert(mysize == sizes[comm.rank()]);
+ scatterv(comm, values, sizes, &(myvalues[0]), root);
+ } else {
+ scatterv(comm, &(myvalues[0]), mysize, root);
+ }
+
+ for (int i = 0; i < mysize; ++i)
+ BOOST_CHECK(myvalues[i] == generator(comm.rank()));
+ }
+
+ comm.barrier();
+}
+
+template<typename Generator>
+void
+scatterd_test(const communicator& comm, Generator generator,
+ const char* kind, int root = -1)
+{
+ typedef typename Generator::result_type value_type;
+
+ if (root == -1) {
+ for (root = 0; root < comm.size(); ++root)
+ scatterv_test(comm, generator, kind, root);
+ } else {
+ using boost::mpi::scatterv;
+
+ int mysize = comm.rank() + 1;
+ std::vector<value_type> myvalues(mysize);
+
+ if (comm.rank() == root) {
+ std::vector<value_type> values;
+ std::vector<int> sizes(comm.size());
+ std::vector<int> displs(comm.size());
+ value_type noise = generator(comm.size()+1);
+ // process p will receive a payload of p+1 identical generator(p) elements
+ // root will insert pseudo random pading between each payload.
+ int shift = 0; // the current position of next payload in source array
+ for (int p = 0; p < comm.size(); ++p) {
+ int size = p+1;
+ int pad = p % 3;
+ // padding
+ for (int i = 0; i < pad; ++i) {
+ values.push_back(noise);
+ }
+ // payload
+ for (int i = 0; i < size; ++i)
+ values.push_back(generator(p));
+ shift += pad;
+ displs[p] = shift;
+ sizes[p] = size;
+ shift += size;
+ }
+
+ std::cout << "Scatteringv " << kind << " from root "
+ << root << "..." << std::endl;
+ assert(mysize == sizes[comm.rank()]);
+ scatterv(comm, values, sizes, displs, &(myvalues[0]), mysize, root);
+ } else {
+ scatterv(comm, &(myvalues[0]), mysize, root);
+ }
+
+ for (int i = 0; i < mysize; ++i)
+ BOOST_CHECK(myvalues[i] == generator(comm.rank()));
+ }
+
+ comm.barrier();
+}
+
+
+BOOST_AUTO_TEST_CASE(simple_scatter)
+{
+ environment env;
+ communicator comm;
+
+ scatter_test(comm, int_generator(), "integers");
+ scatter_test(comm, gps_generator(), "GPS positions");
+ scatter_test(comm, string_generator(), "string");
+ scatter_test(comm, string_list_generator(), "list of strings");
+
+ scatterv_test(comm, int_generator(), "integers");
+ scatterv_test(comm, gps_generator(), "GPS positions");
+ scatterv_test(comm, string_generator(), "string");
+ scatterv_test(comm, string_list_generator(), "list of strings");
+
+ scatterd_test(comm, int_generator(), "integers");
+ scatterd_test(comm, gps_generator(), "GPS positions");
+ scatterd_test(comm, string_generator(), "string");
+ scatterd_test(comm, string_list_generator(), "list of strings");
+}
diff --git a/src/boost/libs/mpi/test/sendrecv_test.cpp b/src/boost/libs/mpi/test/sendrecv_test.cpp
new file mode 100644
index 000000000..a7fe3a3ee
--- /dev/null
+++ b/src/boost/libs/mpi/test/sendrecv_test.cpp
@@ -0,0 +1,62 @@
+// Copyright Alain Miniussi 2014.
+// Distributed under 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 sendrecv() operation.
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/environment.hpp>
+#include <vector>
+#include <algorithm>
+#include <boost/serialization/string.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/lexical_cast.hpp>
+#include <numeric>
+
+#define BOOST_TEST_MODULE mpi_sendrecv
+#include <boost/test/included/unit_test.hpp>
+
+namespace mpi = boost::mpi;
+
+struct blob {
+ blob(int i) : value(i) {}
+ int value;
+ template<class Archive>
+ void serialize(Archive& s, const unsigned int version) {
+ s & value;
+ }
+};
+
+std::ostream& operator<<(std::ostream& out, blob const& b) {
+ out << "blob(" << b.value << ")";
+ return out;
+}
+
+bool operator==(blob const& b1, blob const& b2) {
+ return b1.value == b2.value;
+}
+
+template<typename T>
+void test_sendrecv(mpi::communicator& com) {
+ int const wrank = com.rank();
+ int const wsize = com.size();
+ int const wnext((wrank + 1) % wsize);
+ int const wprev((wrank + wsize - 1) % wsize);
+ T recv(-1);
+ com.sendrecv(wnext, 1, T(wrank), wprev, 1, recv);
+ for(int r = 0; r < wsize; ++r) {
+ com.barrier();
+ if (r == wrank) {
+ std::cout << "rank " << wrank << " received " << recv << " from " << wprev << '\n';
+ }
+ }
+ BOOST_CHECK(recv == T(wprev));
+}
+
+BOOST_AUTO_TEST_CASE(sendrecv)
+{
+ mpi::environment env;
+ mpi::communicator world;
+ test_sendrecv<int>(world);
+ test_sendrecv<blob>(world);
+}
diff --git a/src/boost/libs/mpi/test/sendrecv_vector.cpp b/src/boost/libs/mpi/test/sendrecv_vector.cpp
new file mode 100644
index 000000000..dc1392858
--- /dev/null
+++ b/src/boost/libs/mpi/test/sendrecv_vector.cpp
@@ -0,0 +1,95 @@
+// Author: K. Noel Belcourt <kbelco -at- sandia.gov>
+
+// Distributed under 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)
+
+#if defined(__cplusplus) && (201103L <= __cplusplus)
+
+#include <array>
+#include <cassert>
+#include <vector>
+
+#include "boost/mpi/environment.hpp"
+#include "boost/mpi/communicator.hpp"
+
+using std::array;
+using std::vector;
+
+namespace mpi = boost::mpi;
+
+struct blob : array<int, 9>, array<double, 3>, array<char, 8> {
+};
+
+namespace boost {
+ namespace mpi {
+
+ template <>
+ struct is_mpi_datatype<blob> : mpl::true_ {
+ };
+
+ template <>
+ MPI_Datatype get_mpi_datatype<blob>(const blob& b) {
+ array<unsigned long, 3> block_lengths{
+ { 9, 3, 8 }
+ };
+
+ array<MPI_Aint, 3> displacements{
+ { 0, 40, 64 }
+ };
+
+ array<MPI_Datatype, 3> datatypes{
+ { MPI_INT, MPI_DOUBLE, MPI_CHAR }
+ };
+
+ MPI_Datatype blob_type;
+ MPI_Type_create_struct(
+ block_lengths.size()
+ , reinterpret_cast<int*>(block_lengths.data())
+ , displacements.data()
+ , datatypes.data()
+ , &blob_type);
+
+ MPI_Type_commit(&blob_type);
+ return blob_type;
+ }
+
+ } // namespace mpi
+} // namespace boost
+
+#endif // defined(__cplusplus)
+
+
+int main(int argc, char* argv[]) {
+#if defined(__cplusplus) && (201103L <= __cplusplus)
+
+ mpi::environment env(argc, argv);
+ mpi::communicator world;
+
+ vector<blob> data;
+
+ if (world.rank() == 0) {
+ int size = 10000000;
+ data.resize(size);
+ // initialize data at vector ends
+ blob& b1= data[0];
+ array<int, 9>& i = b1;
+ i[0] = -1;
+ blob& b2= data[size-1];
+ array<int, 9>& d = b2;
+ d[2] = -17;
+ world.send(1, 0, data);
+ } else {
+ world.recv(0, 0, data);
+ // check data at vector ends
+ blob& b1 = data[0];
+ array<int, 9>& i = b1;
+ assert(i[0] == -1);
+ // blob& b2 = data[data.size()-1];
+ // array<int, 9>& d = b2;
+ // assert(d[2] == -17);
+ }
+#endif // defined(__cplusplus)
+
+ return 0;
+}
diff --git a/src/boost/libs/mpi/test/skeleton_content_test.cpp b/src/boost/libs/mpi/test/skeleton_content_test.cpp
new file mode 100644
index 000000000..6a42fd5e0
--- /dev/null
+++ b/src/boost/libs/mpi/test/skeleton_content_test.cpp
@@ -0,0 +1,200 @@
+// Copyright 2005 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 communicator that transmits skeletons and
+// content for data types.
+#include <boost/mpi/communicator.hpp>
+#include <boost/mpi/environment.hpp>
+#include <boost/serialization/list.hpp>
+#include <boost/mpi/skeleton_and_content.hpp>
+#include <boost/mpi/nonblocking.hpp>
+#include <algorithm>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/mpi/collectives/broadcast.hpp>
+
+#define BOOST_TEST_MODULE mpi_skeleton_content
+#include <boost/test/included/unit_test.hpp>
+
+using boost::mpi::communicator;
+
+using boost::mpi::packed_skeleton_iarchive;
+using boost::mpi::packed_skeleton_oarchive;
+
+void
+test_skeleton_and_content(const communicator& comm, int root,
+ bool manual_broadcast)
+{
+ using boost::mpi::skeleton;
+ using boost::mpi::content;
+ using boost::mpi::get_content;
+ using boost::make_counting_iterator;
+ using boost::mpi::broadcast;
+
+ int list_size = comm.size() + 7;
+ if (comm.rank() == root) {
+ // Fill in the seed data
+ std::list<int> original_list;
+ for (int i = 0; i < list_size; ++i)
+ original_list.push_back(i);
+
+ std::cout << "Broadcasting integer list skeleton from root " << root
+ << "...";
+ if (manual_broadcast) {
+ // Broadcast the skeleton (manually)
+ for (int p = 0; p < comm.size(); ++p)
+ if (p != root) comm.send(p, 0, skeleton(original_list));
+ } else {
+ broadcast(comm, skeleton(original_list), root);
+ }
+ std::cout << "OK." << std::endl;
+
+ // Broadcast the content (manually)
+ std::cout << "Broadcasting integer list content from root " << root
+ << "...";
+ {
+ content c = get_content(original_list);
+ for (int p = 0; p < comm.size(); ++p)
+ if (p != root) comm.send(p, 1, c);
+ }
+ std::cout << "OK." << std::endl;
+
+ // Reverse the list, broadcast the content again
+ std::reverse(original_list.begin(), original_list.end());
+ std::cout << "Broadcasting reversed integer list content from root "
+ << root << "...";
+ {
+ content c = get_content(original_list);
+ for (int p = 0; p < comm.size(); ++p)
+ if (p != root) comm.send(p, 2, c);
+ }
+ std::cout << "OK." << std::endl;
+ } else {
+ // Allocate some useless data, to try to get the addresses of the
+ // list<int>'s used later to be different across processes.
+ std::list<int> junk_list(comm.rank() * 3 + 1, 17);
+
+ // Receive the skeleton to build up the transferred list
+ std::list<int> transferred_list;
+ if (manual_broadcast) {
+ comm.recv(root, 0, skeleton(transferred_list));
+ } else {
+ broadcast(comm, skeleton(transferred_list), root);
+ }
+ BOOST_CHECK((int)transferred_list.size() == list_size);
+
+ // Receive the content and check it
+ comm.recv(root, 1, get_content(transferred_list));
+ BOOST_CHECK(std::equal(make_counting_iterator(0),
+ make_counting_iterator(list_size),
+ transferred_list.begin()));
+
+ // Receive the reversed content and check it
+ comm.recv(root, 2, get_content(transferred_list));
+ BOOST_CHECK(std::equal(make_counting_iterator(0),
+ make_counting_iterator(list_size),
+ transferred_list.rbegin()));
+ }
+
+ (comm.barrier)();
+}
+
+void
+test_skeleton_and_content_nonblocking(const communicator& comm, int root)
+{
+ using boost::mpi::skeleton;
+ using boost::mpi::content;
+ using boost::mpi::get_content;
+ using boost::make_counting_iterator;
+ using boost::mpi::broadcast;
+ using boost::mpi::request;
+ using boost::mpi::wait_all;
+
+ int list_size = comm.size() + 7;
+ if (comm.rank() == root) {
+ // Fill in the seed data
+ std::list<int> original_list;
+ for (int i = 0; i < list_size; ++i)
+ original_list.push_back(i);
+
+ std::cout << "Non-blocking broadcast of integer list skeleton from root " << root
+ << "...";
+
+ // Broadcast the skeleton (manually)
+ {
+ std::vector<request> reqs;
+ for (int p = 0; p < comm.size(); ++p)
+ if (p != root)
+ reqs.push_back(comm.isend(p, 0, skeleton(original_list)));
+ wait_all(reqs.begin(), reqs.end());
+ }
+ std::cout << "OK." << std::endl;
+
+ // Broadcast the content (manually)
+ std::cout << "Non-blocking broadcast of integer list content from root " << root
+ << "...";
+ {
+ content c = get_content(original_list);
+ std::vector<request> reqs;
+ for (int p = 0; p < comm.size(); ++p)
+ if (p != root) reqs.push_back(comm.isend(p, 1, c));
+ wait_all(reqs.begin(), reqs.end());
+ }
+ std::cout << "OK." << std::endl;
+
+ // Reverse the list, broadcast the content again
+ std::reverse(original_list.begin(), original_list.end());
+ std::cout << "Non-blocking broadcast of reversed integer list content from root "
+ << root << "...";
+ {
+ std::vector<request> reqs;
+ content c = get_content(original_list);
+ for (int p = 0; p < comm.size(); ++p)
+ if (p != root) reqs.push_back(comm.isend(p, 2, c));
+ wait_all(reqs.begin(), reqs.end());
+ }
+ std::cout << "OK." << std::endl;
+ } else {
+ // Allocate some useless data, to try to get the addresses of the
+ // list<int>'s used later to be different across processes.
+ std::list<int> junk_list(comm.rank() * 3 + 1, 17);
+
+ // Receive the skeleton to build up the transferred list
+ std::list<int> transferred_list;
+ request req = comm.irecv(root, 0, skeleton(transferred_list));
+ req.wait();
+ BOOST_CHECK((int)transferred_list.size() == list_size);
+
+ // Receive the content and check it
+ req = comm.irecv(root, 1, get_content(transferred_list));
+ req.wait();
+ BOOST_CHECK(std::equal(make_counting_iterator(0),
+ make_counting_iterator(list_size),
+ transferred_list.begin()));
+
+ // Receive the reversed content and check it
+ req = comm.irecv(root, 2, get_content(transferred_list));
+ req.wait();
+ BOOST_CHECK(std::equal(make_counting_iterator(0),
+ make_counting_iterator(list_size),
+ transferred_list.rbegin()));
+ }
+
+ (comm.barrier)();
+}
+
+BOOST_AUTO_TEST_CASE(sendrecv)
+{
+ boost::mpi::environment env;
+ communicator comm;
+ BOOST_TEST_REQUIRE(comm.size() > 1);
+
+ test_skeleton_and_content(comm, 0, true);
+ test_skeleton_and_content(comm, 0, false);
+ test_skeleton_and_content(comm, 1, true);
+ test_skeleton_and_content(comm, 1, false);
+ test_skeleton_and_content_nonblocking(comm, 0);
+ test_skeleton_and_content_nonblocking(comm, 1);
+}
diff --git a/src/boost/libs/mpi/test/version_test.cpp b/src/boost/libs/mpi/test/version_test.cpp
new file mode 100644
index 000000000..0895b74f4
--- /dev/null
+++ b/src/boost/libs/mpi/test/version_test.cpp
@@ -0,0 +1,60 @@
+// Copyright (C) 2013 Alain Miniussi <alain.miniussi@oca.eu>
+
+// 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)
+
+// test mpi version
+
+#include <boost/mpi/environment.hpp>
+#include <boost/mpi/communicator.hpp>
+#include <iostream>
+
+#define BOOST_TEST_MODULE mpi_version
+#include <boost/test/included/unit_test.hpp>
+
+namespace mpi = boost::mpi;
+
+void
+test_version(mpi::communicator const& comm) {
+#if defined(MPI_VERSION)
+ int mpi_version = MPI_VERSION;
+ int mpi_subversion = MPI_SUBVERSION;
+#else
+ int mpi_version = 0;
+ int mpi_subversion = 0;
+#endif
+
+ std::pair<int,int> version = mpi::environment::version();
+ if (comm.rank() == 0) {
+ std::cout << "MPI Version: " << version.first << ',' << version.second << '\n';
+ }
+ BOOST_CHECK(version.first == mpi_version);
+ BOOST_CHECK(version.second == mpi_subversion);
+}
+
+std::string
+yesno(bool b) {
+ return b ? std::string("yes") : std::string("no");
+}
+
+void
+report_features(mpi::communicator const& comm) {
+ if (comm.rank() == 0) {
+ std::cout << "Assuming working MPI_Improbe:" <<
+#if defined(BOOST_MPI_USE_IMPROBE)
+ "yes" << '\n';
+#else
+ "no" << '\n';
+#endif
+ }
+}
+
+BOOST_AUTO_TEST_CASE(version)
+{
+ mpi::environment env;
+ mpi::communicator world;
+
+ test_version(world);
+ report_features(world);
+}
diff --git a/src/boost/libs/mpi/test/wait_all_vector_test.cpp b/src/boost/libs/mpi/test/wait_all_vector_test.cpp
new file mode 100644
index 000000000..0e4c800bb
--- /dev/null
+++ b/src/boost/libs/mpi/test/wait_all_vector_test.cpp
@@ -0,0 +1,46 @@
+// Copyright (C) 2017 Alain Miniussi & Vincent Chabannes
+
+// 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)
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include <boost/mpi.hpp>
+#include <boost/mpi/nonblocking.hpp>
+#include <boost/serialization/string.hpp>
+
+#define BOOST_TEST_MODULE mpi_wait_any
+#include <boost/test/included/unit_test.hpp>
+
+namespace mpi = boost::mpi;
+
+BOOST_AUTO_TEST_CASE(wait_any)
+{
+ mpi::environment env;
+ mpi::communicator comm;
+
+ int rank = comm.rank();
+ int const sz = 10;
+ std::vector<int> data;
+ std::vector< mpi::request> reqs;
+ if ( rank == 0 ) {
+ for ( int i=0; i<sz; ++i ) {
+ data.push_back( i );
+ }
+ reqs.push_back( comm.isend(1, 0, data) );
+ } else if ( rank == 1 ) {
+ reqs.push_back( comm.irecv(0, 0, data) );
+ }
+ mpi::wait_all( reqs.begin(), reqs.end() );
+
+ if ( rank == 1 ) {
+ BOOST_CHECK(data.size() == sz);
+ for ( int i=0; i<sz; ++i ) {
+ BOOST_CHECK(data[i] == i);
+ }
+ }
+}
diff --git a/src/boost/libs/mpi/test/wait_any_test.cpp b/src/boost/libs/mpi/test/wait_any_test.cpp
new file mode 100644
index 000000000..e1f4c556d
--- /dev/null
+++ b/src/boost/libs/mpi/test/wait_any_test.cpp
@@ -0,0 +1,64 @@
+// Copyright (C) 2017 Alain Miniussi & Steffen Hirschmann
+
+// 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)
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <set>
+
+#include <boost/mpi.hpp>
+#include <boost/mpi/nonblocking.hpp>
+#include <boost/serialization/string.hpp>
+
+#define BOOST_TEST_MODULE mpi_wait_any
+#include <boost/test/included/unit_test.hpp>
+
+namespace mpi = boost::mpi;
+
+BOOST_AUTO_TEST_CASE(wait_any)
+{
+ mpi::environment env;
+ mpi::communicator world;
+
+ std::vector<std::string> ss(world.size());
+ typedef std::vector<mpi::request> requests;
+ requests rreqs;
+
+ std::set<int> pending_senders;
+ for (int i = 0; i < world.size(); ++i) {
+ rreqs.push_back(world.irecv(i, i, ss[i]));
+ pending_senders.insert(i);
+ }
+
+ std::ostringstream fmt;
+ std::string msg = "Hello, World! this is ";
+ fmt << msg << world.rank();
+
+ requests sreqs;
+ for (int i = 0; i < world.size(); ++i) {
+ sreqs.push_back(world.isend(i, world.rank(), fmt.str()));
+ }
+
+ for (int i = 0; i < world.size(); ++i) {
+ std::pair<mpi::status, requests::iterator> completed = mpi::wait_any(rreqs.begin(), rreqs.end());
+ std::ostringstream out;
+ out << "Proc " << world.rank() << " got message from " << completed.first.source() << '\n';
+ std::cout << out.str();
+ }
+
+ for (int i = 0; i < world.size(); ++i) {
+ std::ostringstream fmt;
+ fmt << msg << i;
+ std::vector<std::string>::iterator found = std::find(ss.begin(), ss.end(), fmt.str());
+ BOOST_CHECK(found != ss.end());
+ fmt.str("");
+ fmt << "Proc " << world.rank() << " Got msg from " << i << '\n';
+ std::cout << fmt.str();
+ }
+
+ mpi::wait_all(sreqs.begin(), sreqs.end());
+}