Update of /cvsroot/boost/boost/libs/parallel/test
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv657/libs/parallel/test

Added Files:
        all_gather_test.cpp all_reduce_test.cpp all_to_all_test.cpp 
        broadcast_test.cpp gather_test.cpp is_mpi_op_test.cpp 
        nonblocking_test.cpp reduce_test.cpp ring_test.cpp 
        scan_test.cpp scatter_test.cpp skeleton_content_test.cpp 
Log Message:
Import Boost.MPI with the beginnings of a BBv2-based build system

--- NEW FILE: all_gather_test.cpp ---
// Copyright (C) 2005-2006 Douglas Gregor <[EMAIL PROTECTED]>

// 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 <boost/parallel/mpi/collectives/all_gather.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/test/minimal.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>

using boost::parallel::mpi::communicator;

using boost::parallel::mpi::packed_skeleton_iarchive;
using boost::parallel::mpi::packed_skeleton_oarchive;

template<typename Generator>
void
all_gather_test(const communicator& comm, Generator generator,
                const char* kind)
{
  typedef typename Generator::result_type value_type;
  value_type value = generator(comm.rank());

  using boost::parallel::mpi::all_gather;

  std::vector<value_type> values;
  if (comm.rank() == 0) {
    std::cout << "Gathering " << kind << "...";
    std::cout.flush();
  }

  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)();
}

// 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;
  }
};

int test_main(int argc, char* argv[])
{
  boost::parallel::mpi::environment env(argc, argv);
  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");
  return 0;
}

--- NEW FILE: all_reduce_test.cpp ---
// 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/parallel/mpi/collectives/all_reduce.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <algorithm>
#include <boost/serialization/string.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/lexical_cast.hpp>
#include <numeric>

using boost::parallel::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 parallel { namespace mpi {

  template <>
  struct is_mpi_datatype<point> : public mpl::true_ { };

} } } // end namespace boost::parallel::mpi

template<typename Generator, typename Op>
void
all_reduce_test(const communicator& comm, Generator generator,
                const char* type_kind, Op op, const char* op_kind,
                typename Generator::result_type init)
{
  typedef typename Generator::result_type value_type;
  value_type value = generator(comm.rank());

  using boost::parallel::mpi::all_reduce;

  if (comm.rank() == 0) {
    std::cout << "Reducing to " << op_kind << " of " << type_kind << "...";
    std::cout.flush();
  }

  value_type result_value = all_reduce(comm, value, op);

  // Compute expected result
  std::vector<value_type> generated_values;
  for (int p = 0; p < comm.size(); ++p)
    generated_values.push_back(generator(p));
  value_type expected_result = std::accumulate(generated_values.begin(),
                                               generated_values.end(),
                                               init, op);
  BOOST_CHECK(result_value == expected_result);
  if (result_value == expected_result && comm.rank() == 0)
    std::cout << "OK." << std::endl;

  (comm.barrier)();
}

// Generates integers to test with all_reduce()
struct int_generator
{
  typedef int result_type;

  int_generator(int base = 1) : base(base) { }

  int operator()(int p) const { return base + p; }

 private:
  int base;
};

// Generate points to test with all_reduce()
struct point_generator
{
  typedef point result_type;

  point_generator(point origin) : origin(origin) { }

  point operator()(int p) const
  {
    return point(origin.x + 1, origin.y + 1, origin.z + 1);
  }

 private:
  point origin;
};

struct string_generator
{
  typedef std::string result_type;

  std::string operator()(int p) const
  {
    std::string result = boost::lexical_cast<std::string>(p);
    result += " rosebud";
    if (p != 1) result += 's';
    return result;
  }
};

struct secret_int_bit_and
{
  int operator()(int x, int y) const { return x & y; }
};

struct wrapped_int
{
  wrapped_int() : value(0) { }
  explicit wrapped_int(int value) : value(value) { }

  template<typename Archive>
  void serialize(Archive& ar, unsigned int /* version */)
  {
    ar & value;
  }

  int value;
};

wrapped_int operator+(const wrapped_int& x, const wrapped_int& y)
{
  return wrapped_int(x.value + y.value);
}

bool operator==(const wrapped_int& x, const wrapped_int& y)
{
  return x.value == y.value;
}

// Generates wrapped_its to test with all_reduce()
struct wrapped_int_generator
{
  typedef wrapped_int result_type;

  wrapped_int_generator(int base = 1) : base(base) { }

  wrapped_int operator()(int p) const { return wrapped_int(base + p); }

 private:
  int base;
};

namespace boost { namespace parallel { namespace mpi {

// Make std::plus<wrapped_int> commutative.
template<>
struct is_commutative<std::plus<wrapped_int>, wrapped_int>
  : mpl::true_ { };

} } } // end namespace boost::parallel::mpi

int test_main(int argc, char* argv[])
{
  using namespace boost::parallel::mpi;
  environment env(argc, argv);

  communicator comm;

  // Built-in MPI datatypes with built-in MPI operations
  all_reduce_test(comm, int_generator(), "integers", std::plus<int>(), "sum",
                  0);
  all_reduce_test(comm, int_generator(), "integers", std::multiplies<int>(),
                  "product", 1);
  all_reduce_test(comm, int_generator(), "integers", maximum<int>(),
                  "maximum", 0);
  all_reduce_test(comm, int_generator(), "integers", minimum<int>(),
                  "minimum", 2);

  // User-defined MPI datatypes with operations that have the
  // same name as built-in operations.
  all_reduce_test(comm, point_generator(point(0,0,0)), "points",
                  std::plus<point>(), "sum", point());

  // Built-in MPI datatypes with user-defined operations
  all_reduce_test(comm, int_generator(17), "integers", secret_int_bit_and(),
                  "bitwise and", -1);

    // Arbitrary types with user-defined, commutative operations.
  all_reduce_test(comm, wrapped_int_generator(17), "wrapped integers",
                  std::plus<wrapped_int>(), "sum", wrapped_int(0));

  // Arbitrary types with (non-commutative) user-defined operations
  all_reduce_test(comm, string_generator(), "strings",
                  std::plus<std::string>(), "concatenation", std::string());

  return 0;
}

--- NEW FILE: all_to_all_test.cpp ---
// 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/parallel/mpi/collectives/all_to_all.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.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>

using boost::parallel::mpi::communicator;

using boost::parallel::mpi::packed_skeleton_iarchive;
using boost::parallel::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::parallel::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)));

  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)));
  }

  (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;
  }
};

int test_main(int argc, char* argv[])
{
  boost::parallel::mpi::environment env(argc, argv);

  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");

  return 0;
}

--- NEW FILE: broadcast_test.cpp ---
// 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/parallel/mpi/collectives/broadcast.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <algorithm>
#include "gps_position.hpp"
#include <boost/serialization/string.hpp>
#include <boost/serialization/list.hpp>
#include <boost/parallel/mpi/skeleton_and_content.hpp>
#include <boost/iterator/counting_iterator.hpp>

using boost::parallel::mpi::communicator;

using boost::parallel::mpi::packed_skeleton_iarchive;
using boost::parallel::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::parallel::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::parallel::mpi::content;
  using boost::parallel::mpi::get_content;
  using boost::make_counting_iterator;
  using boost::parallel::mpi::broadcast;
  using boost::parallel::mpi::content;
  using boost::parallel::mpi::get_content;

  typedef std::list<int>::iterator iterator;

  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
              << "...";
    broadcast(comm, oa, root);
    std::cout << "OK." << std::endl;

    // Broadcast the content
    std::cout << "Broadcasting integer list content from root " << root
              << "...";
    {
      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 << "...";
    {
      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);
    BOOST_CHECK(std::equal(make_counting_iterator(0),
                           make_counting_iterator(list_size),
                           transferred_list.begin()));

    // Receive the reversed content and check it
    broadcast(comm, get_content(transferred_list), root);
    BOOST_CHECK(std::equal(make_counting_iterator(0),
                           make_counting_iterator(list_size),
                           transferred_list.rbegin()));
  }

  (comm.barrier)();
}

int test_main(int argc, char* argv[])
{
  boost::parallel::mpi::environment env(argc, argv);

  communicator comm;
  if (comm.size() == 1) {
    std::cerr << "ERROR: Must run the broadcast test with more than one "
              << "process." << std::endl;
    MPI_Abort(comm, -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);
  return 0;
}

--- NEW FILE: gather_test.cpp ---
// 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() collective.
#include <boost/parallel/mpi/collectives/gather.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.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>

using boost::parallel::mpi::communicator;

using boost::parallel::mpi::packed_skeleton_iarchive;
using boost::parallel::mpi::packed_skeleton_oarchive;

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::parallel::mpi::gather;

    std::vector<value_type> values;
    if (comm.rank() == root) {
      std::cout << "Gathering " << kind << " from root " << root << "...";
      std::cout.flush();
    }

    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);
      if (values == expected_values)
        std::cout << "OK." << std::endl;
    } else {
      BOOST_CHECK(values.empty());
    }
  }

  (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;
  }
};

int test_main(int argc, char* argv[])
{
  boost::parallel::mpi::environment env(argc, argv);

  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");

  return 0;
}

--- NEW FILE: is_mpi_op_test.cpp ---
// Copyright (C) 2005-2006 Douglas Gregor <[EMAIL PROTECTED]>

// 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/parallel/mpi/operations.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/type_traits/is_base_and_derived.hpp>
#include <boost/test/minimal.hpp>

using namespace boost::parallel::mpi;
using namespace std;
using boost::is_base_and_derived;

int test_main(int argc, char* argv[])
{
  boost::parallel::mpi::environment env(argc, argv);

  // Check each predefined MPI_Op type that we support directly.
  BOOST_CHECK((is_mpi_op<maximum<int>, int>::op() == MPI_MAX));
  BOOST_CHECK((is_mpi_op<minimum<float>, float>::op() == MPI_MIN));
  BOOST_CHECK((is_mpi_op<plus<double>, double>::op() == MPI_SUM));
  BOOST_CHECK((is_mpi_op<multiplies<long>, long>::op() == MPI_PROD));
  BOOST_CHECK((is_mpi_op<logical_and<int>, int>::op() == MPI_LAND));
  BOOST_CHECK((is_mpi_op<bitwise_and<int>, int>::op() == MPI_BAND));
  BOOST_CHECK((is_mpi_op<logical_or<int>, int>::op() == MPI_LOR));
  BOOST_CHECK((is_mpi_op<bitwise_or<int>, int>::op() == MPI_BOR));
  BOOST_CHECK((is_mpi_op<logical_xor<int>, int>::op() == MPI_LXOR));
  BOOST_CHECK((is_mpi_op<bitwise_xor<int>, int>::op() == MPI_BXOR));

  return 0;
}

--- NEW FILE: nonblocking_test.cpp ---
// 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/parallel/mpi/nonblocking.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include "gps_position.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/list.hpp>
#include <iterator>
#include <algorithm>

using boost::parallel::mpi::communicator;
using boost::parallel::mpi::request;
using boost::parallel::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_all,                // use to run all of the different methods
  mk_all_except_test_all // use for serialized types
};

static char* method_kind_names[mk_all] = {
  "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_test(const communicator& comm, const T* values, int num_values, 
                 const char* kind, method_kind method = mk_all)
{
  using boost::parallel::mpi::wait_any;
  using boost::parallel::mpi::test_any;
  using boost::parallel::mpi::wait_all;
  using boost::parallel::mpi::test_all;
  using boost::parallel::mpi::wait_some;
  using boost::parallel::mpi::test_some;

  if (method == mk_all || method == mk_all_except_test_all) {
    nonblocking_test(comm, values, num_values, kind, mk_wait_any);
    nonblocking_test(comm, values, num_values, kind, mk_test_any);
    nonblocking_test(comm, values, num_values, kind, mk_wait_all);
    nonblocking_test(comm, values, num_values, kind, mk_wait_all_keep);
    if (method == mk_all) {
      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);
  } else {
    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((comm.rank() + 1) % comm.size(), 0, values[0]));
    reqs.push_back(comm.irecv((comm.rank() + comm.size() - 1) % comm.size(),
                              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((comm.rank() + 1) % comm.size(), 1));
      reqs.push_back(comm.irecv((comm.rank() + comm.size() - 1) % comm.size(),
                                1));
#endif

      // Send/receive an array
      reqs.push_back(comm.isend((comm.rank() + 1) % comm.size(), 2, values,
                                num_values));
      reqs.push_back(comm.irecv((comm.rank() + comm.size() - 1) % comm.size(),
                                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));
  }
}

int test_main(int argc, char* argv[])
{
  boost::parallel::mpi::environment env(argc, argv);

  communicator comm;

  int int_array[3] = {17, 42, 256};
  nonblocking_test(comm, int_array, 3, "integers");

  gps_position gps_array[2] = {
    gps_position(17, 42, .06),
    gps_position(42, 17, .06)
  };
  nonblocking_test(comm, gps_array, 2, "gps positions");

  std::string string_array[2] = { "Hello", "World" };
  nonblocking_test(comm, string_array, 2, "strings", 
                   mk_all_except_test_all);

  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_test(comm, &lst_of_strings, 1, "list of strings", 
                   mk_all_except_test_all);

  return 0;
}

--- NEW FILE: reduce_test.cpp ---
// 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/parallel/mpi/collectives/reduce.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <algorithm>
#include <boost/serialization/string.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/lexical_cast.hpp>
#include <numeric>

using boost::parallel::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 parallel { namespace mpi {

  template <>
  struct is_mpi_datatype<point> : public mpl::true_ { };

} } } // end namespace boost::parallel::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::parallel::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 parallel { namespace mpi {

// Make std::plus<wrapped_int> commutative.
template<>
struct is_commutative<std::plus<wrapped_int>, wrapped_int>
  : mpl::true_ { };

} } } // end namespace boost::parallel::mpi

int test_main(int argc, char* argv[])
{
  using namespace boost::parallel::mpi;
  environment env(argc, argv);

  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());

  return 0;
}

--- NEW FILE: ring_test.cpp ---
// 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/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <algorithm>
#include "gps_position.hpp"
#include <boost/serialization/string.hpp>
#include <boost/serialization/list.hpp>

using boost::parallel::mpi::communicator;
using boost::parallel::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::parallel::mpi::any_source, 0);
    boost::optional<int> num_values = stat.template count<T>();
    if (boost::parallel::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;
}

int test_main(int argc, char* argv[])
{
  boost::parallel::mpi::environment env(argc, argv);

  communicator comm;
  if (comm.size() == 1) {
    std::cerr << "ERROR: Must run the ring test with more than one process."
              << std::endl;
    MPI_Abort(comm, -1);
  }

  // Check transfer of individual objects
  ring_test(comm, 17, "integers", 0);
  ring_test(comm, 17, "integers", 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);

  return 0;
}

--- NEW FILE: scan_test.cpp ---
// 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/parallel/mpi/collectives/scan.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <algorithm>
#include <boost/serialization/string.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/lexical_cast.hpp>
#include <numeric>

using boost::parallel::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 parallel { namespace mpi {

  template <>
  struct is_mpi_datatype<point> : public mpl::true_ { };

} } } // end namespace boost::parallel::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::parallel::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);
  BOOST_CHECK(scan(comm, value, op) == 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 parallel { namespace mpi {

// Make std::plus<wrapped_int> commutative.
template<>
struct is_commutative<std::plus<wrapped_int>, wrapped_int>
  : mpl::true_ { };

} } } // end namespace boost::parallel::mpi

int test_main(int argc, char* argv[])
{
  using namespace boost::parallel::mpi;
  environment env(argc, argv);

  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");

  return 0;
}

--- NEW FILE: scatter_test.cpp ---
// 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() collective.
#include <boost/parallel/mpi/collectives/scatter.hpp>
#include <boost/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.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>

using boost::parallel::mpi::communicator;

using boost::parallel::mpi::packed_skeleton_iarchive;
using boost::parallel::mpi::packed_skeleton_oarchive;

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::parallel::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));

      if (comm.rank() == root) {
        std::cout << "Scattering " << kind << " from root " << root << "...";
        std::cout.flush();
      }

      scatter(comm, values, value, root);
    } else {
      scatter(comm, value, root);
    }

    BOOST_CHECK(value == generator(comm.rank()));
  }

  (comm.barrier)();
}

// Generates integers to test with scatter()
struct int_generator
{
  typedef int result_type;

  int operator()(int p) const { return 17 + p; }
};

// Generates GPS positions to test with scatter()
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;
  }
};

int test_main(int argc, char* argv[])
{
  boost::parallel::mpi::environment env(argc, argv);

  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");

  return 0;
}

--- NEW FILE: skeleton_content_test.cpp ---
// 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/parallel/mpi/communicator.hpp>
#include <boost/parallel/mpi/environment.hpp>
#include <boost/test/minimal.hpp>
#include <boost/serialization/list.hpp>
#include <boost/parallel/mpi/skeleton_and_content.hpp>
#include <boost/parallel/mpi/nonblocking.hpp>
#include <algorithm>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/parallel/mpi/collectives/broadcast.hpp>

using boost::parallel::mpi::communicator;

using boost::parallel::mpi::packed_skeleton_iarchive;
using boost::parallel::mpi::packed_skeleton_oarchive;

void
test_skeleton_and_content(const communicator& comm, int root,
                          bool manual_broadcast)
{
  using boost::parallel::mpi::skeleton;
  using boost::parallel::mpi::content;
  using boost::parallel::mpi::get_content;
  using boost::make_counting_iterator;
  using boost::parallel::mpi::broadcast;

  typedef std::list<int>::iterator iterator;

  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::parallel::mpi::skeleton;
  using boost::parallel::mpi::content;
  using boost::parallel::mpi::get_content;
  using boost::make_counting_iterator;
  using boost::parallel::mpi::broadcast;
  using boost::parallel::mpi::request;
  using boost::parallel::mpi::wait_all;

  typedef std::list<int>::iterator iterator;

  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)();
}

int test_main(int argc, char* argv[])
{
  boost::parallel::mpi::environment env(argc, argv);

  communicator comm;
  if (comm.size() == 1) {
    std::cerr << "ERROR: Must run the skeleton and content test with more "
      "than one process."
              << std::endl;
    MPI_Abort(comm, -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);

  return 0;
}


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Boost-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/boost-cvs

Reply via email to