summaryrefslogtreecommitdiff
path: root/libs/mpi/src/python
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2013-06-25 22:59:01 +0000
committer <>2013-09-27 11:49:28 +0000
commit8c4528713d907ee2cfd3bfcbbad272c749867f84 (patch)
treec09e2ce80f47b90c85cc720f5139089ad9c8cfff /libs/mpi/src/python
downloadboost-tarball-baserock/morph.tar.gz
Imported from /home/lorry/working-area/delta_boost-tarball/boost_1_54_0.tar.bz2.boost_1_54_0baserock/morph
Diffstat (limited to 'libs/mpi/src/python')
-rw-r--r--libs/mpi/src/python/collectives.cpp144
-rw-r--r--libs/mpi/src/python/datatypes.cpp25
-rw-r--r--libs/mpi/src/python/documentation.cpp671
-rw-r--r--libs/mpi/src/python/exception.cpp55
-rw-r--r--libs/mpi/src/python/module.cpp55
-rw-r--r--libs/mpi/src/python/py_communicator.cpp133
-rw-r--r--libs/mpi/src/python/py_environment.cpp111
-rw-r--r--libs/mpi/src/python/py_exception.cpp54
-rw-r--r--libs/mpi/src/python/py_nonblocking.cpp255
-rw-r--r--libs/mpi/src/python/py_request.cpp102
-rw-r--r--libs/mpi/src/python/py_timer.cpp48
-rw-r--r--libs/mpi/src/python/request_with_value.hpp71
-rw-r--r--libs/mpi/src/python/serialize.cpp79
-rw-r--r--libs/mpi/src/python/skeleton_and_content.cpp173
-rw-r--r--libs/mpi/src/python/status.cpp41
-rw-r--r--libs/mpi/src/python/utility.hpp43
16 files changed, 2060 insertions, 0 deletions
diff --git a/libs/mpi/src/python/collectives.cpp b/libs/mpi/src/python/collectives.cpp
new file mode 100644
index 000000000..fc4bf7b4c
--- /dev/null
+++ b/libs/mpi/src/python/collectives.cpp
@@ -0,0 +1,144 @@
+// (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
+
+/** @file status.cpp
+ *
+ * This file reflects the Boost.MPI @c status class into
+ * Python.
+ */
+#include <boost/python.hpp>
+#include <boost/mpi.hpp>
+#include <boost/mpi/python/serialize.hpp>
+
+using namespace boost::python;
+using namespace boost::mpi;
+
+namespace boost { namespace mpi { namespace python {
+
+extern const char* all_gather_docstring;
+extern const char* all_reduce_docstring;
+extern const char* all_to_all_docstring;
+extern const char* broadcast_docstring;
+extern const char* gather_docstring;
+extern const char* reduce_docstring;
+extern const char* scan_docstring;
+extern const char* scatter_docstring;
+
+object all_gather(const communicator& comm, object value)
+{
+ std::vector<object> values;
+ boost::mpi::all_gather(comm, value, values);
+
+ boost::python::list l;
+ for (int i = 0; i < comm.size(); ++i)
+ l.append(values[i]);
+ return boost::python::tuple(l);
+}
+
+object all_to_all(const communicator& comm, object in_values)
+{
+ // Build input values
+ std::vector<object> in_values_vec(comm.size());
+ object iterator = object(handle<>(PyObject_GetIter(in_values.ptr())));
+ for (int i = 0; i < comm.size(); ++i)
+ in_values_vec[i] = object(handle<>(PyIter_Next(iterator.ptr())));
+
+ std::vector<object> out_values_vec(comm.size());
+ boost::mpi::all_to_all(comm, in_values_vec, out_values_vec);
+
+ boost::python::list l;
+ for (int i = 0; i < comm.size(); ++i)
+ l.append(out_values_vec[i]);
+ return boost::python::tuple(l);
+}
+
+object broadcast(const communicator& comm, object value, int root)
+{
+ boost::mpi::broadcast(comm, value, root);
+ return value;
+}
+
+object gather(const communicator& comm, object value, int root)
+{
+ if (comm.rank() == root) {
+ std::vector<object> values;
+ boost::mpi::gather(comm, value, values, root);
+
+ boost::python::list l;
+ for (int i = 0; i < comm.size(); ++i)
+ l.append(values[i]);
+ return boost::python::tuple(l);
+ } else {
+ boost::mpi::gather(comm, value, root);
+ return object();
+ }
+}
+
+object reduce(const communicator& comm, object value, object op, int root)
+{
+ if (comm.rank() == root) {
+ object out_value;
+ boost::mpi::reduce(comm, value, out_value, op, root);
+ return out_value;
+ } else {
+ boost::mpi::reduce(comm, value, op, root);
+ return object();
+ }
+}
+
+object scatter(const communicator& comm, object values, int root)
+{
+ object result;
+
+ if (comm.rank() == root) {
+ std::vector<object> values_vec(comm.size());
+ object iterator = object(handle<>(PyObject_GetIter(values.ptr())));
+ for (int i = 0; i < comm.size(); ++i)
+ values_vec[i] = object(handle<>(PyIter_Next(iterator.ptr())));
+
+ boost::mpi::scatter(comm, values_vec, result, root);
+ } else {
+ boost::mpi::scatter(comm, result, root);
+ }
+ return result;
+}
+
+void export_collectives()
+{
+ using boost::python::arg;
+
+ def("all_reduce",
+ (object (*)(const communicator&, const object&, object))&all_reduce,
+ (arg("comm") = communicator(), arg("value"), arg("op")),
+ all_reduce_docstring);
+ def("all_gather", &all_gather,
+ (arg("comm") = communicator(), arg("value") = object()),
+ all_gather_docstring);
+ def("all_to_all", &all_to_all,
+ (arg("comm") = communicator(), arg("values") = object()),
+ all_to_all_docstring);
+ def("broadcast", &broadcast,
+ (arg("comm") = communicator(), arg("value") = object(), arg("root")),
+ broadcast_docstring);
+ def("gather", &gather,
+ (arg("comm") = communicator(), arg("value") = object(), arg("root")),
+ gather_docstring);
+ def("reduce", &reduce,
+ (arg("comm") = communicator(), arg("value"), arg("op"),
+ arg("root")),
+ reduce_docstring);
+ def("scan",
+ (object (*)(const communicator&, const object&, object))&scan,
+ (arg("comm") = communicator(), arg("value"), arg("op")),
+ scan_docstring);
+ def("scatter", &scatter,
+ (arg("comm") = communicator(), arg("values") = object(), arg("root")),
+ scatter_docstring);
+}
+
+} } } // end namespace boost::mpi::python
diff --git a/libs/mpi/src/python/datatypes.cpp b/libs/mpi/src/python/datatypes.cpp
new file mode 100644
index 000000000..586fc0395
--- /dev/null
+++ b/libs/mpi/src/python/datatypes.cpp
@@ -0,0 +1,25 @@
+// (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
+
+/** @file datatypes.cpp
+ *
+ * This file provides datatypes support for Boost.MPI in Python.
+ */
+#include <boost/mpi/python/serialize.hpp>
+#include <boost/mpi.hpp>
+
+namespace boost { namespace mpi { namespace python {
+
+void export_datatypes()
+{
+ register_serialized(long(0), &PyInt_Type);
+ register_serialized(false, &PyBool_Type);
+ register_serialized(double(0.0), &PyFloat_Type);
+}
+
+} } } // end namespace boost::mpi::python
diff --git a/libs/mpi/src/python/documentation.cpp b/libs/mpi/src/python/documentation.cpp
new file mode 100644
index 000000000..ef28fb3b5
--- /dev/null
+++ b/libs/mpi/src/python/documentation.cpp
@@ -0,0 +1,671 @@
+// (C) Copyright 2005 The Trustees of Indiana University.
+// (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
+
+/** @file documentation.cpp
+ *
+ * This file contains all of the documentation strings for the
+ * Boost.MPI Python bindings.
+ */
+namespace boost { namespace mpi { namespace python {
+
+const char* module_docstring =
+ "The boost.mpi module contains Python wrappers for Boost.MPI.\n"
+ "Boost.MPI is a C++ interface to the Message Passing Interface 1.1,\n"
+ "a high-performance message passing library for parallel programming.\n"
+ "\n"
+ "This module supports the most commonly used subset of MPI 1.1. All\n"
+ "communication operations can transmit any Python object that can be\n"
+ "pickled and unpickled, along with C++-serialized data types and\n"
+ "separation of the structure of a data type from its content.\n"
+ "Collectives that have a user-supplied functions,\n"
+ "such as reduce() or scan(), accept arbitrary Python functions, and\n"
+ "all collectives can operate on any serializable or picklable data type.\n"
+ "\n"
+ "IMPORTANT MODULE DATA\n"
+ " any_source This constant may be used for the source parameter of\n"
+ " receive and probe operations to indicate that a\n"
+ " message may be received from any source.\n"
+ "\n"
+ " any_tag This constant may be used for the tag parameter of\n"
+ " receive or probe operations to indicate that a send\n"
+ " with any tag will be matched.\n"
+ "\n"
+ " collectives_tag Returns the reserved tag value used by the Boost.MPI\n"
+ " implementation for collective operations. Although\n"
+ " users are not permitted to use this tag to send or\n"
+ " receive messages with this tag, it may be useful when\n"
+ " monitoring communication patterns.\n"
+ "\n"
+ " host_rank If there is a host process, this is the rank of that\n"
+ " that process. Otherwise, this value will be None. MPI\n"
+ " does not define the meaning of a \"host\" process: \n"
+ " consult the documentation for your MPI implementation.\n"
+ "\n"
+ " io_rank The rank of a process that can perform input/output\n"
+ " via the standard facilities. If every process can\n"
+ " perform I/O using the standard facilities, this value\n"
+ " will be the same as any_source. If no process can\n"
+ " perform I/O, this value will be None.\n"
+ "\n"
+ " max_tag The maximum value that may be used for the tag\n"
+ " parameter of send/receive operations. This value will\n"
+ " be somewhat smaller than the value of MPI_TAG_UB,\n"
+ " because the Boost.MPI implementation reserves some\n"
+ " tags for collective operations.\n"
+ "\n"
+ " processor_name The name of this processor. The actual form of the\n"
+ " of the name is unspecified, but may be documented by\n"
+ " the underlying MPI implementation.\n"
+ "\n"
+ " rank The rank of this process in the \"world\" communicator.\n"
+ "\n"
+ " size The number of processes in the \"world\" communicator.\n"
+ " that process. Otherwise, this value will be None. MPI\n"
+ " does not define the meaning of a \"host\" process: \n"
+ "\n"
+ " world The \"world\" communicator from which all other\n"
+ " communicators will be derived. This is the equivalent\n"
+ " of MPI_COMM_WORLD.\n"
+ "\n"
+ "TRANSMITTING USER-DEFINED DATA\n"
+ " Boost.MPI can transmit user-defined data in several different ways.\n"
+ " Most importantly, it can transmit arbitrary Python objects by pickling\n"
+ " them at the sender and unpickling them at the receiver, allowing\n"
+ " arbitrarily complex Python data structures to interoperate with MPI.\n"
+ "\n"
+ " Boost.MPI also supports efficient serialization and transmission of\n"
+ " C++ objects (that have been exposed to Python) through its C++\n"
+ " interface. Any C++ type that provides (de-)serialization routines that\n"
+ " meet the requirements of the Boost.Serialization library is eligible\n"
+ " for this optimization, but the type must be registered in advance. To\n"
+ " register a C++ type, invoke the C++ function:\n"
+ " boost::mpi::python::register_serialized\n"
+ "\n"
+ " Finally, Boost.MPI supports separation of the structure of an object\n"
+ " from the data it stores, allowing the two pieces to be transmitted\n"
+ " separately. This \"skeleton/content\" mechanism, described in more\n"
+ " detail in a later section, is a communication optimization suitable\n"
+ " for problems with fixed data structures whose internal data changes\n"
+ " frequently.\n"
+ "\n"
+ "COLLECTIVES\n"
+ " Boost.MPI supports all of the MPI collectives (scatter, reduce, scan,\n"
+ " broadcast, etc.) for any type of data that can be transmitted with the\n"
+ " point-to-point communication operations. For the MPI collectives that\n"
+ " require a user-specified operation (e.g., reduce and scan), the\n"
+ " operation can be an arbitrary Python function. For instance, one could\n"
+ " concatenate strings with all_reduce:\n\n"
+ " mpi.all_reduce(my_string, lambda x,y: x + y)\n\n"
+ " The following module-level functions implement MPI collectives:\n"
+ " all_gather Gather the values from all processes.\n"
+ " all_reduce Combine the results from all processes.\n"
+ " all_to_all Every process sends data to every other process.\n"
+ " broadcast Broadcast data from one process to all other processes.\n"
+ " gather Gather the values from all processes to the root.\n"
+ " reduce Combine the results from all processes to the root.\n"
+ " scan Prefix reduction of the values from all processes.\n"
+ " scatter Scatter the values stored at the root to all processes.\n"
+ "\n"
+ "SKELETON/CONTENT MECHANISM\n"
+ " Boost.MPI provides a skeleton/content mechanism that allows the\n"
+ " transfer of large data structures to be split into two separate stages,\n"
+ " with the `skeleton' (or, `shape') of the data structure sent first and\n"
+ " the content (or, `data') of the data structure sent later, potentially\n"
+ " several times, so long as the structure has not changed since the\n"
+ " skeleton was transferred. The skeleton/content mechanism can improve\n"
+ " performance when the data structure is large and its shape is fixed,\n"
+ " because while the skeleton requires serialization (it has an unknown\n"
+ " size), the content transfer is fixed-size and can be done without\n"
+ " extra copies.\n"
+ "\n"
+ " To use the skeleton/content mechanism from Python, you must first\n"
+ " register the type of your data structure with the skeleton/content\n"
+ " mechanism *from C++*. The registration function is\n"
+ " boost::mpi::python::register_skeleton_and_content\n"
+ " and resides in the <boost/mpi/python.hpp> header.\n"
+ "\n"
+ " Once you have registered your C++ data structures, you can extract\n"
+ " the skeleton for an instance of that data structure with skeleton().\n"
+ " The resulting SkeletonProxy can be transmitted via the normal send\n"
+ " routine, e.g.,\n\n"
+ " mpi.world.send(1, 0, skeleton(my_data_structure))\n\n"
+ " SkeletonProxy objects can be received on the other end via recv(),\n"
+ " which stores a newly-created instance of your data structure with the\n"
+ " same `shape' as the sender in its `object' attribute:\n\n"
+ " shape = mpi.world.recv(0, 0)\n"
+ " my_data_structure = shape.object\n\n"
+ " Once the skeleton has been transmitted, the content (accessed via \n"
+ " get_content) can be transmitted in much the same way. Note, however,\n"
+ " that the receiver also specifies get_content(my_data_structure) in its\n"
+ " call to receive:\n\n"
+ " if mpi.rank == 0:\n"
+ " mpi.world.send(1, 0, get_content(my_data_structure))\n"
+ " else:\n"
+ " mpi.world.recv(0, 0, get_content(my_data_structure))\n\n"
+ " Of course, this transmission of content can occur repeatedly, if the\n"
+ " values in the data structure--but not its shape--changes.\n"
+ "\n"
+ " The skeleton/content mechanism is a structured way to exploit the\n"
+ " interaction between custom-built MPI datatypes and MPI_BOTTOM, to\n"
+ " eliminate extra buffer copies.\n"
+ "\n"
+ "C++/PYTHON MPI COMPATIBILITY\n"
+ " Boost.MPI is a C++ library whose facilities have been exposed to Python\n"
+ " via the Boost.Python library. Since the Boost.MPI Python bindings are\n"
+ " build directly on top of the C++ library, and nearly every feature of\n"
+ " C++ library is available in Python, hybrid C++/Python programs using\n"
+ " Boost.MPI can interact, e.g., sending a value from Python but receiving\n"
+ " that value in C++ (or vice versa). However, doing so requires some\n"
+ " care. Because Python objects are dynamically typed, Boost.MPI transfers\n"
+ " type information along with the serialized form of the object, so that\n"
+ " the object can be received even when its type is not known. This\n"
+ " mechanism differs from its C++ counterpart, where the static types of\n"
+ " transmitted values are always known.\n"
+ "\n"
+ " The only way to communicate between the C++ and Python views on \n"
+ " Boost.MPI is to traffic entirely in Python objects. For Python, this is\n"
+ " the normal state of affairs, so nothing will change. For C++, this\n"
+ " means sending and receiving values of type boost::python::object, from\n"
+ " the Boost.Python library. For instance, say we want to transmit an\n"
+ " integer value from Python:\n\n"
+ " comm.send(1, 0, 17)\n\n"
+ " In C++, we would receive that value into a Python object and then\n"
+ " `extract' an integer value:\n\n"
+ " boost::python::object value;\n"
+ " comm.recv(0, 0, value);\n"
+ " int int_value = boost::python::extract<int>(value);\n\n"
+ " In the future, Boost.MPI will be extended to allow improved\n"
+ " interoperability with the C++ Boost.MPI and the C MPI bindings.\n"
+ ;
+
+/***********************************************************
+ * environment documentation *
+ ***********************************************************/
+const char* environment_init_docstring =
+ "Initialize the MPI environment. Users should not need to call\n"
+ "this function directly, because the MPI environment will be\n"
+ "automatically initialized when the Boost.MPI module is loaded.\n";
+
+const char* environment_finalize_docstring =
+ "Finalize (shut down) the MPI environment. Users only need to\n"
+ "invoke this function if MPI should be shut down before program\n"
+ "termination. Boost.MPI will automatically finalize the MPI\n"
+ "environment when the program exits.\n";
+
+const char* environment_abort_docstring =
+ "Aborts all MPI processes and returns to the environment. The\n"
+ "precise behavior will be defined by the underlying MPI\n"
+ "implementation. This is equivalent to a call to MPI_Abort with\n"
+ "MPI_COMM_WORLD.\n"
+ "errcode is the error code to return from aborted processes.\n";
+
+const char* environment_initialized_docstring =
+ "Determine if the MPI environment has already been initialized.\n";
+
+const char* environment_finalized_docstring =
+ "Determine if the MPI environment has already been finalized.\n";
+
+/***********************************************************
+ * nonblocking documentation *
+ ***********************************************************/
+const char* request_list_init_docstring=
+ "Without arguments, constructs an empty RequestList.\n"
+ "With one argument `iterable', copies request objects from this\n"
+ "iterable to the new RequestList.\n";
+
+const char* nonblocking_wait_any_docstring =
+ "Waits until any of the given requests has been completed. It provides\n"
+ "functionality equivalent to MPI_Waitany.\n"
+ "\n"
+ "requests must be a RequestList instance.\n"
+ "\n"
+ "Returns a triple (value, status, index) consisting of received value\n"
+ "(or None), the Status object for the completed request, and its index\n"
+ "in the RequestList.\n";
+
+const char* nonblocking_test_any_docstring =
+ "Tests if any of the given requests have been completed, but does not wait\n"
+ "for completion. It provides functionality equivalent to MPI_Testany.\n"
+ "\n"
+ "requests must be a RequestList instance.\n"
+ "\n"
+ "Returns a triple (value, status, index) like wait_any or None if no request\n"
+ "is complete.\n";
+
+const char* nonblocking_wait_all_docstring =
+ "Waits until all of the given requests have been completed. It provides\n"
+ "functionality equivalent to MPI_Waitall.\n"
+ "\n"
+ "requests must be a RequestList instance.\n"
+ "\n"
+ "If the second parameter `callable' is provided, it is called with each\n"
+ "completed request's received value (or None) and it s Status object as\n"
+ "its arguments. The calls occur in the order given by the `requests' list.\n";
+
+const char* nonblocking_test_all_docstring =
+ "Tests if all of the given requests have been completed. It provides\n"
+ "functionality equivalent to MPI_Testall.\n"
+ "\n"
+ "Returns True if all requests have been completed.\n"
+ "\n"
+ "requests must be a RequestList instance.\n"
+ "\n"
+ "If the second parameter `callable' is provided, it is called with each\n"
+ "completed request's received value (or None) and it s Status object as\n"
+ "its arguments. The calls occur in the order given by the `requests' list.\n";
+
+const char* nonblocking_wait_some_docstring =
+ "Waits until at least one of the given requests has completed. It\n"
+ "then completes all of the requests it can, partitioning the input\n"
+ "sequence into pending requests followed by completed requests.\n"
+ "\n"
+ "This routine provides functionality equivalent to MPI_Waitsome.\n"
+ "\n"
+ "Returns the index of the first completed request."
+ "\n"
+ "requests must be a RequestList instance.\n"
+ "\n"
+ "If the second parameter `callable' is provided, it is called with each\n"
+ "completed request's received value (or None) and it s Status object as\n"
+ "its arguments. The calls occur in the order given by the `requests' list.\n";
+
+const char* nonblocking_test_some_docstring =
+ "Tests to see if any of the given requests has completed. It completes\n"
+ "all of the requests it can, partitioning the input sequence into pending\n"
+ "requests followed by completed requests. This routine is similar to\n"
+ "wait_some, but does not wait until any requests have completed.\n"
+ "\n"
+ "This routine provides functionality equivalent to MPI_Testsome.\n"
+ "\n"
+ "Returns the index of the first completed request."
+ "\n"
+ "requests must be a RequestList instance.\n"
+ "\n"
+ "If the second parameter `callable' is provided, it is called with each\n"
+ "completed request's received value (or None) and it s Status object as\n"
+ "its arguments. The calls occur in the order given by the `requests' list.\n";
+
+/***********************************************************
+ * exception documentation *
+ ***********************************************************/
+const char* exception_docstring =
+ "Instances of this class will be thrown when an MPI error\n"
+ "occurs. MPI failures that trigger these exceptions may or may not\n"
+ "be recoverable, depending on the underlying MPI implementation.\n"
+ "Consult the documentation for your MPI implementation to determine\n"
+ "the effect of MPI errors.\n";
+
+const char* exception_what_docstring =
+ "A description of the error that occured. At present, this refers\n"
+ "only to the name of the MPI routine that failed.\n";
+
+const char* exception_routine_docstring =
+ "The name of the MPI routine that reported the error.\n";
+
+const char* exception_result_code_docstring =
+ "The result code returned from the MPI routine that reported the\n"
+ "error.\n";
+
+/***********************************************************
+ * collectives documentation *
+ ***********************************************************/
+const char* all_gather_docstring =
+ "all_gather is a collective algorithm that collects the values\n"
+ "stored at each process into a tuple of values indexed by the\n"
+ "process number they came from. all_gather is (semantically) a\n"
+ "gather followed by a broadcast. The same tuple of values is\n"
+ "returned to all processes.\n";
+
+const char* all_reduce_docstring =
+ "all_reduce is a collective algorithm that combines the values\n"
+ "stored by each process into a single value. The values can be\n"
+ "combined arbitrarily, specified via any function. The values\n"
+ "a1, a2, .., ap provided by p processors will be combined by the\n"
+ "binary function op into the result\n"
+ " op(a1, op(a2, ... op(ap-1,ap)))\n"
+ "that will be returned to all processes. This function is the\n"
+ "equivalent of calling all_gather() and then applying the built-in\n"
+ "reduce() function to the returned sequence. op is assumed to be\n"
+ "associative.\n";
+
+const char* all_to_all_docstring =
+ "all_to_all is a collective algorithm that transmits values from\n"
+ "every process to every other process. On process i, the jth value\n"
+ "of the values sequence is sent to process j and placed in the ith\n"
+ "position of the tuple that will be returned from all_to_all.\n";
+
+const char* broadcast_docstring =
+ "broadcast is a collective algorithm that transfers a value from an\n"
+ "arbitrary root process to every other process that is part of the\n"
+ "given communicator (comm). The root parameter must be the same for\n"
+ "every process. The value parameter need only be specified at the root\n"
+ "root. broadcast() returns the same broadcasted value to every process.\n";
+
+const char* gather_docstring =
+ "gather is a collective algorithm that collects the values\n"
+ "stored at each process into a tuple of values at the root\n"
+ "process. This tuple is indexed by the process number that the\n"
+ "value came from, and will be returned only by the root process.\n"
+ "All other processes return None.\n";
+
+const char* reduce_docstring =
+ "reduce is a collective algorithm that combines the values\n"
+ "stored by each process into a single value at the root. The\n"
+ "values can be combined arbitrarily, specified via any function.\n"
+ "The values a1, a2, .., ap provided by p processors will be\n"
+ "combined by the binary function op into the result\n"
+ " op(a1, op(a2, ... op(ap-1,ap)))\n"
+ "that will be returned on the root process. This function is the\n"
+ "equivalent of calling gather() to the root and then applying the\n"
+ "built-in reduce() function to the returned sequence. All non-root\n"
+ "processes return None. op is assumed to be associative.\n";
+
+const char* scan_docstring =
+ "@c scan computes a prefix reduction of values from all processes.\n"
+ "It is a collective algorithm that combines the values stored by\n"
+ "each process with the values of all processes with a smaller rank.\n"
+ "The values can be arbitrarily combined, specified via a binary\n"
+ "function op. If each process i provides the value ai, then scan\n"
+ "returns op(a1, op(a2, ... op(ai-1, ai))) to the ith process. op is\n"
+ "assumed to be associative. This routine is the equivalent of an\n"
+ "all_gather(), followed by a built-in reduce() on the first i+1\n"
+ "values in the resulting sequence on processor i. op is assumed\n"
+ "to be associative.\n";
+
+const char* scatter_docstring =
+ "scatter is a collective algorithm that scatters the values stored\n"
+ "in the root process (as a container with comm.size elements) to\n"
+ "all of the processes in the communicator. The values parameter \n"
+ "(only significant at the root) is indexed by the process number to\n"
+ "which the corresponding value will be sent. The value received by \n"
+ "each process is returned from scatter.\n";
+
+/***********************************************************
+ * communicator documentation *
+ ***********************************************************/
+const char* communicator_docstring =
+ "The Communicator class abstracts a set of communicating\n"
+ "processes in MPI. All of the processes that belong to a certain\n"
+ "communicator can determine the size of the communicator, their rank\n"
+ "within the communicator, and communicate with any other processes\n"
+ "in the communicator.\n";
+
+const char* communicator_default_constructor_docstring =
+ "Build a new Boost.MPI Communicator instance for MPI_COMM_WORLD.\n";
+
+const char* communicator_rank_docstring =
+ "Returns the rank of the process in the communicator, which will be a\n"
+ "value in [0, size).\n";
+
+const char* communicator_size_docstring =
+ "Returns the number of processes in the communicator.\n";
+
+const char* communicator_send_docstring =
+ "This routine executes a potentially blocking send with the given\n"
+ "tag to the process with rank dest. It can be received by the\n"
+ "destination process with a matching recv call. The value will be\n"
+ "transmitted in one of several ways:\n"
+ "\n"
+ " - For C++ objects registered via register_serialized(), the value\n"
+ " will be serialized and transmitted.\n"
+ "\n"
+ " - For SkeletonProxy objects, the skeleton of the object will be\n"
+ " serialized and transmitted.\n"
+ "\n"
+ " - For Content objects, the content will be transmitted directly.\n"
+ " This content can be received by a matching recv/irecv call that\n"
+ " provides a suitable `buffer' argument.\n"
+ "\n"
+ " - For all other Python objects, the value will be pickled and\n"
+ " transmitted.\n";
+
+const char* communicator_recv_docstring =
+ "This routine blocks until it receives a message from the process\n"
+ "source with the given tag. If the source parameter is not specified,\n"
+ "the message can be received from any process. Likewise, if the tag\n"
+ "parameter is not specified, a message with any tag can be received.\n"
+ "If return_status is True, returns a tuple containing the received\n"
+ "object followed by a Status object describing the communication.\n"
+ "Otherwise, recv() returns just the received object.\n"
+ "\n"
+ "When receiving the content of a data type that has been sent separately\n"
+ "from its skeleton, user code must provide a value for the `buffer'\n"
+ "argument. This value should be the Content object returned from\n"
+ "get_content().\n";
+
+const char* communicator_isend_docstring =
+ "This routine executes a nonblocking send with the given\n"
+ "tag to the process with rank dest. It can be received by the\n"
+ "destination process with a matching recv call. The value will be\n"
+ "transmitted in the same way as with send().\n"
+ "This routine returns a Request object, which can be used to query\n"
+ "when the transmission has completed, wait for its completion, or\n"
+ "cancel the transmission.\n";
+
+const char* communicator_irecv_docstring =
+ "This routine initiates a non-blocking receive from the process\n"
+ "source with the given tag. If the source parameter is not specified,\n"
+ "the message can be received from any process. Likewise, if the tag\n"
+ "parameter is not specified, a message with any tag can be received.\n"
+ "This routine returns a Request object, which can be used to query\n"
+ "when the transmission has completed, wait for its completion, or\n"
+ "cancel the transmission. The received value be accessible\n"
+ "through the `value' attribute of the Request object once transmission\n"
+ "has completed.\n"
+ "\n"
+ "As with the recv() routine, when receiving the content of a data type\n"
+ "that has been sent separately from its skeleton, user code must provide\n"
+ "a value for the `buffer' argument. This value should be the Content\n"
+ "object returned from get_content().\n";
+
+ const char* communicator_probe_docstring =
+ "This operation waits until a message matching (source, tag)\n"
+ "is available to be received. It then returns information about\n"
+ "that message. If source is omitted, a message from any process\n"
+ "will match. If tag is omitted, a message with any tag will match.\n"
+ "The actual source and tag can be retrieved from the returned Status\n"
+ "object. To check if a message is available without blocking, use\n"
+ "iprobe.\n";
+
+const char* communicator_iprobe_docstring =
+ "This operation determines if a message matching (source, tag) is\n"
+ "available to be received. If so, it returns information about that\n"
+ "message; otherwise, it returns None. If source is omitted, a message\n"
+ "from any process will match. If tag is omitted, a message with any\n"
+ "tag will match. The actual source and tag can be retrieved from the\n"
+ "returned Status object. To wait for a message to become available, use\n"
+ "probe.\n";
+
+const char* communicator_barrier_docstring =
+ "Wait for all processes within a communicator to reach the\n"
+ "barrier.\n";
+
+const char* communicator_split_docstring =
+ "Split the communicator into multiple, disjoint communicators\n"
+ "each of which is based on a particular color. This is a\n"
+ "collective operation that returns a new communicator that is a\n"
+ "subgroup of this. This routine is functionally equivalent to\n"
+ "MPI_Comm_split.\n\n"
+ "color is the color of this process. All processes with the\n"
+ "same color value will be placed into the same group.\n\n"
+ "If provided, key is a key value that will be used to determine\n"
+ "the ordering of processes with the same color in the resulting\n"
+ "communicator. If omitted, the key will default to the rank of\n"
+ "the process in the current communicator.\n\n"
+ "Returns a new Communicator instance containing all of the \n"
+ "processes in this communicator that have the same color.\n";
+
+const char* communicator_abort_docstring =
+ "Makes a \"best attempt\" to abort all of the tasks in the group of\n"
+ "this communicator. Depending on the underlying MPI\n"
+ "implementation, this may either abort the entire program (and\n"
+ "possibly return errcode to the environment) or only abort\n"
+ "some processes, allowing the others to continue. Consult the\n"
+ "documentation for your MPI implementation. This is equivalent to\n"
+ "a call to MPI_Abort\n\n"
+ "errcode is the error code to return from aborted processes.\n";
+
+/***********************************************************
+ * request documentation *
+ ***********************************************************/
+const char* request_docstring =
+ "The Request class contains information about a non-blocking send\n"
+ "or receive and will be returned from isend or irecv, respectively.\n"
+ "When a Request object represents a completed irecv, the `value' \n"
+ "attribute will contain the received value.\n";
+
+const char* request_with_value_docstring =
+ "This class is an implementation detail. Any call that accepts a\n"
+ "Request also accepts a RequestWithValue, and vice versa.\n";
+
+const char* request_wait_docstring =
+ "Wait until the communication associated with this request has\n"
+ "completed. For a request that is associated with an isend(), returns\n"
+ "a Status object describing the communication. For an irecv()\n"
+ "operation, returns the received value by default. However, when\n"
+ "return_status=True, a (value, status) pair is returned by a\n"
+ "completed irecv request.\n";
+
+const char* request_test_docstring =
+ "Determine whether the communication associated with this request\n"
+ "has completed successfully. If so, returns the Status object\n"
+ "describing the communication (for an isend request) or a tuple\n"
+ "containing the received value and a Status object (for an irecv\n"
+ "request). Note that once test() returns a Status object, the\n"
+ "request has completed and wait() should not be called.\n";
+
+const char* request_cancel_docstring =
+ "Cancel a pending communication, assuming it has not already been\n"
+ "completed.\n";
+
+const char* request_value_docstring =
+ "If this request originated in an irecv(), this property makes the"
+ "sent value accessible once the request completes.\n"
+ "\n"
+ "If no value is available, ValueError is raised.\n";
+
+/***********************************************************
+ * skeleton/content documentation *
+ ***********************************************************/
+const char* object_without_skeleton_docstring =
+ "The ObjectWithoutSkeleton class is an exception class used only\n"
+ "when the skeleton() or get_content() function is called with an\n"
+ "object that is not supported by the skeleton/content mechanism.\n"
+ "All C++ types for which skeletons and content can be transmitted\n"
+ "must be registered with the C++ routine:\n"
+ " boost::mpi::python::register_skeleton_and_content\n";
+
+const char* object_without_skeleton_object_docstring =
+ "The object on which skeleton() or get_content() was invoked.\n";
+
+const char* skeleton_proxy_docstring =
+ "The SkeletonProxy class is used to represent the skeleton of an\n"
+ "object. The SkeletonProxy can be used as the value parameter of\n"
+ "send() or isend() operations, but instead of transmitting the\n"
+ "entire object, only its skeleton (\"shape\") will be sent, without\n"
+ "the actual data. Its content can then be transmitted, separately.\n"
+ "\n"
+ "User code cannot generate SkeletonProxy instances directly. To\n"
+ "refer to the skeleton of an object, use skeleton(object). Skeletons\n"
+ "can also be received with the recv() and irecv() methods.\n"
+ "\n"
+ "Note that the skeleton/content mechanism can only be used with C++\n"
+ "types that have been explicitly registered.\n";
+
+const char* skeleton_proxy_object_docstring =
+ "The actual object whose skeleton is represented by this proxy object.\n";
+
+const char* content_docstring =
+ "The content is a proxy class that represents the content of an object,\n"
+ "which can be separately sent or received from its skeleton.\n"
+ "\n"
+ "User code cannot generate content instances directly. Call the\n"
+ "get_content() routine to retrieve the content proxy for a particular\n"
+ "object. The content instance can be used with any of the send() or\n"
+ "recv() variants. Note that get_content() can only be used with C++\n"
+ "data types that have been explicitly registered with the Python\n"
+ "skeleton/content mechanism.\n";
+
+const char* skeleton_docstring =
+ "The skeleton function retrieves the SkeletonProxy for its object\n"
+ "parameter, allowing the transmission of the skeleton (or \"shape\")\n"
+ "of the object separately from its data. The skeleton/content mechanism\n"
+ "is useful when a large data structure remains structurally the same\n"
+ "throughout a computation, but its content (i.e., the values in the\n"
+ "structure) changes several times. Tranmission of the content part does\n"
+ "not require any serialization or unnecessary buffer copies, so it is\n"
+ "very efficient for large data structures.\n"
+ "\n"
+ "Only C++ types that have been explicitly registered with the Boost.MPI\n"
+ "Python library can be used with the skeleton/content mechanism. Use:\b"
+ " boost::mpi::python::register_skeleton_and_content\n";
+
+const char* get_content_docstring =
+ "The get_content function retrieves the content for its object parameter,\n"
+ "allowing the transmission of the data in a data structure separately\n"
+ "from its skeleton (or \"shape\"). The skeleton/content mechanism\n"
+ "is useful when a large data structure remains structurally the same\n"
+ "throughout a computation, but its content (i.e., the values in the\n"
+ "structure) changes several times. Tranmission of the content part does\n"
+ "not require any serialization or unnecessary buffer copies, so it is\n"
+ "very efficient for large data structures.\n"
+ "\n"
+ "Only C++ types that have been explicitly registered with the Boost.MPI\n"
+ "Python library can be used with the skeleton/content mechanism. Use:\b"
+ " boost::mpi::python::register_skeleton_and_content\n";
+
+/***********************************************************
+ * status documentation *
+ ***********************************************************/
+const char* status_docstring =
+ "The Status class stores information about a given message, including\n"
+ "its source, tag, and whether the message transmission was cancelled\n"
+ "or resulted in an error.\n";
+
+const char* status_source_docstring =
+ "The source of the incoming message.\n";
+
+const char* status_tag_docstring =
+ "The tag of the incoming message.\n";
+
+const char* status_error_docstring =
+ "The error code associated with this transmission.\n";
+
+const char* status_cancelled_docstring =
+ "Whether this transmission was cancelled.\n";
+
+/***********************************************************
+ * timer documentation *
+ ***********************************************************/
+const char* timer_docstring =
+ "The Timer class is a simple wrapper around the MPI timing facilities.\n";
+
+const char* timer_default_constructor_docstring =
+ "Initializes the timer. After this call, elapsed == 0.\n";
+
+const char* timer_restart_docstring =
+ "Restart the timer, after which elapsed == 0.\n";
+
+const char* timer_elapsed_docstring =
+ "The time elapsed since initialization or the last restart(),\n"
+ "whichever is more recent.\n";
+
+const char* timer_elapsed_min_docstring =
+ "Returns the minimum non-zero value that elapsed may return\n"
+ "This is the resolution of the timer.\n";
+
+const char* timer_elapsed_max_docstring =
+ "Return an estimate of the maximum possible value of elapsed. Note\n"
+ "that this routine may return too high a value on some systems.\n";
+
+const char* timer_time_is_global_docstring =
+ "Determines whether the elapsed time values are global times or\n"
+ "local processor times.\n";
+
+} } } // end namespace boost::mpi::python
diff --git a/libs/mpi/src/python/exception.cpp b/libs/mpi/src/python/exception.cpp
new file mode 100644
index 000000000..e19c0ebdc
--- /dev/null
+++ b/libs/mpi/src/python/exception.cpp
@@ -0,0 +1,55 @@
+// Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>
+// Copyright (C) 2005 The Trustees of Indiana University.
+
+// 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
+
+/** @file exception.cpp
+ *
+ * This file reflects the Boost.MPI @c mpi_error class into
+ * Python.
+ */
+#include <boost/python.hpp>
+#include <boost/mpi/exception.hpp>
+#include <string>
+#include <boost/lexical_cast.hpp>
+#include "utility.hpp"
+
+using namespace boost::python;
+using namespace boost::mpi;
+
+namespace boost { namespace mpi { namespace python {
+
+extern const char* exception_docstring;
+extern const char* exception_what_docstring;
+extern const char* exception_routine_docstring;
+extern const char* exception_result_code_docstring;
+
+str exception_str(const exception& e)
+{
+ return str("MPI routine `" + std::string(e.routine()) +
+ "' returned error code " +
+ lexical_cast<std::string>(e.result_code()));
+}
+
+void export_exception()
+{
+ using boost::python::arg;
+ using boost::python::object;
+
+ object type =
+ class_<exception>
+ ("exception", exception_docstring, no_init)
+ .add_property("what", &exception::what, exception_what_docstring)
+ .add_property("routine", &exception::what, exception_routine_docstring)
+ .add_property("result_code", &exception::what,
+ exception_result_code_docstring)
+ .def("__str__", &exception_str)
+ ;
+ translate_exception<exception>::declare(type);
+}
+
+} } } // end namespace boost::mpi::python
diff --git a/libs/mpi/src/python/module.cpp b/libs/mpi/src/python/module.cpp
new file mode 100644
index 000000000..5e27e88ca
--- /dev/null
+++ b/libs/mpi/src/python/module.cpp
@@ -0,0 +1,55 @@
+// (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
+
+/** @file module.cpp
+ *
+ * This file provides the top-level module for the Boost.MPI Python
+ * bindings.
+ */
+#include <boost/python.hpp>
+#include <boost/mpi.hpp>
+
+using namespace boost::python;
+using namespace boost::mpi;
+
+namespace boost { namespace mpi { namespace python {
+
+extern void export_environment();
+extern void export_exception();
+extern void export_collectives();
+extern void export_communicator();
+extern void export_datatypes();
+extern void export_request();
+extern void export_status();
+extern void export_timer();
+extern void export_nonblocking();
+
+extern const char* module_docstring;
+
+BOOST_PYTHON_MODULE(mpi)
+{
+ // Setup module documentation
+ scope().attr("__doc__") = module_docstring;
+ scope().attr("__author__") = "Douglas Gregor <doug.gregor@gmail.com>";
+ scope().attr("__date__") = "$LastChangedDate: 2008-06-26 12:25:44 -0700 (Thu, 26 Jun 2008) $";
+ scope().attr("__version__") = "$Revision: 46743 $";
+ scope().attr("__copyright__") = "Copyright (C) 2006 Douglas Gregor";
+ scope().attr("__license__") = "http://www.boost.org/LICENSE_1_0.txt";
+
+ export_environment();
+ export_exception();
+ export_communicator();
+ export_collectives();
+ export_datatypes();
+ export_request();
+ export_status();
+ export_timer();
+ export_nonblocking();
+}
+
+} } } // end namespace boost::mpi::python
diff --git a/libs/mpi/src/python/py_communicator.cpp b/libs/mpi/src/python/py_communicator.cpp
new file mode 100644
index 000000000..6e53f56f9
--- /dev/null
+++ b/libs/mpi/src/python/py_communicator.cpp
@@ -0,0 +1,133 @@
+// (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
+
+/** @file communicator.cpp
+ *
+ * This file reflects the Boost.MPI @c communicator class into
+ * Python.
+ */
+#include <boost/python.hpp>
+#include <boost/mpi.hpp>
+#include <boost/mpi/python/serialize.hpp>
+#include "request_with_value.hpp"
+
+using namespace boost::python;
+using namespace boost::mpi;
+
+namespace boost { namespace mpi { namespace python {
+
+extern const char* communicator_docstring;
+extern const char* communicator_default_constructor_docstring;
+extern const char* communicator_rank_docstring;
+extern const char* communicator_size_docstring;
+extern const char* communicator_send_docstring;
+extern const char* communicator_recv_docstring;
+extern const char* communicator_isend_docstring;
+extern const char* communicator_irecv_docstring;
+extern const char* communicator_probe_docstring;
+extern const char* communicator_iprobe_docstring;
+extern const char* communicator_barrier_docstring;
+extern const char* communicator_split_docstring;
+extern const char* communicator_split_key_docstring;
+extern const char* communicator_abort_docstring;
+
+object
+communicator_recv(const communicator& comm, int source, int tag,
+ bool return_status)
+{
+ using boost::python::make_tuple;
+
+ object result;
+ status stat = comm.recv(source, tag, result);
+ if (return_status)
+ return make_tuple(result, stat);
+ else
+ return result;
+}
+
+request_with_value
+communicator_irecv(const communicator& comm, int source, int tag)
+{
+ boost::shared_ptr<object> result(new object());
+ request_with_value req(comm.irecv(source, tag, *result));
+ req.m_internal_value = result;
+ return req;
+}
+
+object
+communicator_iprobe(const communicator& comm, int source, int tag)
+{
+ if (boost::optional<status> result = comm.iprobe(source, tag))
+ return object(*result);
+ else
+ return object();
+}
+
+extern void export_skeleton_and_content(class_<communicator>&);
+
+void export_communicator()
+{
+ using boost::python::arg;
+ using boost::python::object;
+
+ class_<communicator> comm("Communicator", communicator_docstring);
+ comm
+ .def(init<>())
+ .add_property("rank", &communicator::rank, communicator_rank_docstring)
+ .add_property("size", &communicator::size, communicator_size_docstring)
+ .def("send",
+ (void (communicator::*)(int, int, const object&) const)
+ &communicator::send<object>,
+ (arg("dest"), arg("tag") = 0, arg("value") = object()),
+ communicator_send_docstring)
+ .def("recv", &communicator_recv,
+ (arg("source") = any_source, arg("tag") = any_tag,
+ arg("return_status") = false),
+ communicator_recv_docstring)
+ .def("isend",
+ (request (communicator::*)(int, int, const object&) const)
+ &communicator::isend<object>,
+ (arg("dest"), arg("tag") = 0, arg("value") = object()),
+ communicator_isend_docstring)
+ .def("irecv", &communicator_irecv,
+ (arg("source") = any_source, arg("tag") = any_tag),
+ communicator_irecv_docstring)
+ .def("probe", &communicator::probe,
+ (arg("source") = any_source, arg("tag") = any_tag),
+ communicator_probe_docstring)
+ .def("iprobe", &communicator_iprobe,
+ (arg("source") = any_source, arg("tag") = any_tag),
+ communicator_iprobe_docstring)
+ .def("barrier", &communicator::barrier, communicator_barrier_docstring)
+ .def("__nonzero__", &communicator::operator bool)
+ .def("split",
+ (communicator (communicator::*)(int) const)&communicator::split,
+ (arg("color")), communicator_split_docstring)
+ .def("split",
+ (communicator (communicator::*)(int, int) const)&communicator::split,
+ (arg("color"), arg("key")))
+ .def("abort", &communicator::abort, arg("errcode"),
+ communicator_abort_docstring)
+ ;
+
+ // Module-level attributes
+ scope().attr("any_source") = any_source;
+ scope().attr("any_tag") = any_tag;
+
+ {
+ communicator world;
+ scope().attr("world") = world;
+ scope().attr("rank") = world.rank();
+ scope().attr("size") = world.size();
+ }
+
+ // Export skeleton and content
+ export_skeleton_and_content(comm);
+}
+
+} } } // end namespace boost::mpi::python
diff --git a/libs/mpi/src/python/py_environment.cpp b/libs/mpi/src/python/py_environment.cpp
new file mode 100644
index 000000000..bcd95e4a8
--- /dev/null
+++ b/libs/mpi/src/python/py_environment.cpp
@@ -0,0 +1,111 @@
+// (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
+
+/** @file environment.cpp
+ *
+ * This file reflects the Boost.MPI "environment" class into Python
+ * methods at module level.
+ */
+#include <boost/python.hpp>
+#include <boost/mpi.hpp>
+
+using namespace boost::python;
+using namespace boost::mpi;
+
+namespace boost { namespace mpi { namespace python {
+
+extern const char* environment_init_docstring;
+extern const char* environment_finalize_docstring;
+extern const char* environment_abort_docstring;
+extern const char* environment_initialized_docstring;
+extern const char* environment_finalized_docstring;
+
+/**
+ * The environment used by the Boost.MPI Python module. This will be
+ * zero-initialized before it is used.
+ */
+static environment* env;
+
+bool mpi_init(list python_argv, bool abort_on_exception)
+{
+ // If MPI is already initialized, do nothing.
+ if (environment::initialized())
+ return false;
+
+ // Convert Python argv into C-style argc/argv.
+ int my_argc = extract<int>(python_argv.attr("__len__")());
+ char** my_argv = new char*[my_argc];
+ for (int arg = 0; arg < my_argc; ++arg)
+ my_argv[arg] = strdup(extract<const char*>(python_argv[arg]));
+
+ // Initialize MPI
+ int mpi_argc = my_argc;
+ char** mpi_argv = my_argv;
+ env = new environment(mpi_argc, mpi_argv, abort_on_exception);
+
+ // If anything changed, convert C-style argc/argv into Python argv
+ if (mpi_argv != my_argv)
+ PySys_SetArgv(mpi_argc, mpi_argv);
+
+ for (int arg = 0; arg < my_argc; ++arg)
+ free(my_argv[arg]);
+ delete [] my_argv;
+
+ return true;
+}
+
+void mpi_finalize()
+{
+ if (env) {
+ delete env;
+ env = 0;
+ }
+}
+
+void export_environment()
+{
+ using boost::python::arg;
+
+ def("init", mpi_init, (arg("argv"), arg("abort_on_exception") = true),
+ environment_init_docstring);
+ def("finalize", mpi_finalize, environment_finalize_docstring);
+
+ // Setup initialization and finalization code
+ if (!environment::initialized()) {
+ // MPI_Init from sys.argv
+ object sys = object(handle<>(PyImport_ImportModule("sys")));
+ mpi_init(extract<list>(sys.attr("argv")), true);
+
+ // Setup MPI_Finalize call when the program exits
+ object atexit = object(handle<>(PyImport_ImportModule("atexit")));
+ object finalize = scope().attr("finalize");
+ atexit.attr("register")(finalize);
+ }
+
+ def("abort", &environment::abort, arg("errcode"),
+ environment_abort_docstring);
+ def("initialized", &environment::initialized,
+ environment_initialized_docstring);
+ def("finalized", &environment::finalized,
+ environment_finalized_docstring);
+ scope().attr("max_tag") = environment::max_tag();
+ scope().attr("collectives_tag") = environment::collectives_tag();
+ scope().attr("processor_name") = environment::processor_name();
+
+ if (optional<int> host_rank = environment::host_rank())
+ scope().attr("host_rank") = *host_rank;
+ else
+ scope().attr("host_rank") = object();
+
+ if (optional<int> io_rank = environment::io_rank())
+ scope().attr("io_rank") = *io_rank;
+ else
+ scope().attr("io_rank") = object();
+}
+
+} } } // end namespace boost::mpi::python
diff --git a/libs/mpi/src/python/py_exception.cpp b/libs/mpi/src/python/py_exception.cpp
new file mode 100644
index 000000000..fee48c4d1
--- /dev/null
+++ b/libs/mpi/src/python/py_exception.cpp
@@ -0,0 +1,54 @@
+// Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>
+// Copyright (C) 2005 The Trustees of Indiana University.
+
+// 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
+
+/** @file exception.cpp
+ *
+ * This file reflects the Boost.MPI @c mpi_error class into
+ * Python.
+ */
+#include <boost/python.hpp>
+#include <boost/mpi/exception.hpp>
+#include <string>
+#include <boost/lexical_cast.hpp>
+#include "utility.hpp"
+
+using namespace boost::python;
+using namespace boost::mpi;
+
+namespace boost { namespace mpi { namespace python {
+
+extern const char* exception_docstring;
+extern const char* exception_what_docstring;
+extern const char* exception_routine_docstring;
+extern const char* exception_result_code_docstring;
+
+str exception_str(const exception& e)
+{
+ return str(std::string(e.what()) +
+ " (code " + lexical_cast<std::string>(e.result_code())+")");
+}
+
+void export_exception()
+{
+ using boost::python::arg;
+ using boost::python::object;
+
+ object type =
+ class_<exception>
+ ("Exception", exception_docstring, no_init)
+ .add_property("what", &exception::what, exception_what_docstring)
+ .add_property("routine", &exception::what, exception_routine_docstring)
+ .add_property("result_code", &exception::result_code,
+ exception_result_code_docstring)
+ .def("__str__", &exception_str)
+ ;
+ translate_exception<exception>::declare(type);
+}
+
+} } } // end namespace boost::mpi::python
diff --git a/libs/mpi/src/python/py_nonblocking.cpp b/libs/mpi/src/python/py_nonblocking.cpp
new file mode 100644
index 000000000..22f289f9e
--- /dev/null
+++ b/libs/mpi/src/python/py_nonblocking.cpp
@@ -0,0 +1,255 @@
+// (C) Copyright 2007
+// Douglas Gregor <doug.gregor -at- gmail.com>
+// 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: Douglas Gregor, Andreas Kloeckner
+
+/** @file py_nonblocking.cpp
+ *
+ * This file reflects the Boost.MPI nonblocking operations into Python
+ * functions.
+ */
+
+#include <vector>
+#include <iterator>
+#include <algorithm>
+#include <boost/operators.hpp>
+#include <boost/python.hpp>
+#include <boost/python/stl_iterator.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+#include <boost/mpi.hpp>
+#include "request_with_value.hpp"
+
+using namespace std;
+using namespace boost::python;
+using namespace boost::mpi;
+
+
+
+
+namespace
+{
+ template <class ValueType, class RequestIterator>
+ class py_call_output_iterator :
+ public boost::output_iterator_helper<
+ py_call_output_iterator<ValueType, RequestIterator> >
+ {
+ private:
+ object m_callable;
+ RequestIterator m_request_iterator;
+
+ public:
+ explicit py_call_output_iterator(object callable,
+ const RequestIterator &req_it)
+ : m_callable(callable), m_request_iterator(req_it)
+ { }
+
+ py_call_output_iterator &operator=(ValueType const &v)
+ {
+ m_callable((m_request_iterator++)->get_value_or_none(), v);
+ return *this;
+ }
+ };
+
+
+
+
+ typedef std::vector<python::request_with_value> request_list;
+ typedef py_call_output_iterator<status, request_list::iterator>
+ status_value_iterator;
+
+
+
+
+ std::auto_ptr<request_list> make_request_list_from_py_list(object iterable)
+ {
+ std::auto_ptr<request_list> result(new request_list);
+ std::copy(
+ stl_input_iterator<python::request_with_value>(iterable),
+ stl_input_iterator<python::request_with_value>(),
+ back_inserter(*result));
+ return result;
+ }
+
+
+
+
+ class request_list_indexing_suite :
+ public vector_indexing_suite<request_list, false, request_list_indexing_suite>
+ {
+ public:
+ // FIXME: requests are not comparable, thus __contains__ makes no sense.
+ // Unfortunately, indexing_suites insist on having __contains__ available.
+ // Just make it error out for now.
+
+ static bool
+ contains(request_list& container, request const& key)
+ {
+ PyErr_SetString(PyExc_NotImplementedError, "mpi requests are not comparable");
+ throw error_already_set();
+ }
+ };
+
+
+
+
+ void check_request_list_not_empty(const request_list &requests)
+ {
+ if (requests.size() == 0)
+ {
+ PyErr_SetString(PyExc_ValueError, "cannot wait on an empty request vector");
+ throw error_already_set();
+ }
+
+ }
+
+
+
+
+
+ object wrap_wait_any(request_list &requests)
+ {
+ check_request_list_not_empty(requests);
+
+ pair<status, request_list::iterator> result =
+ wait_any(requests.begin(), requests.end());
+
+ return make_tuple(
+ result.second->get_value_or_none(),
+ result.first,
+ distance(requests.begin(), result.second));
+ }
+
+
+
+
+ object wrap_test_any(request_list &requests)
+ {
+ check_request_list_not_empty(requests);
+ ::boost::optional<pair<status, request_list::iterator> > result =
+ test_any(requests.begin(), requests.end());
+
+ if (result)
+ return make_tuple(
+ result->second->get_value_or_none(),
+ result->first,
+ distance(requests.begin(), result->second));
+ else
+ return object();
+ }
+
+
+
+
+
+ void wrap_wait_all(request_list &requests, object py_callable)
+ {
+ check_request_list_not_empty(requests);
+ if (py_callable != object())
+ wait_all(requests.begin(), requests.end(),
+ status_value_iterator(py_callable, requests.begin()));
+ else
+ wait_all(requests.begin(), requests.end());
+ }
+
+
+
+
+ bool wrap_test_all(request_list &requests, object py_callable)
+ {
+ check_request_list_not_empty(requests);
+ if (py_callable != object())
+ return test_all(requests.begin(), requests.end(),
+ status_value_iterator(py_callable, requests.begin()));
+ else
+ return test_all(requests.begin(), requests.end());
+ }
+
+
+
+
+ int wrap_wait_some(request_list &requests, object py_callable)
+ {
+ check_request_list_not_empty(requests);
+ request_list::iterator first_completed;
+ if (py_callable != object())
+ first_completed = wait_some(requests.begin(), requests.end(),
+ status_value_iterator(py_callable, requests.begin())).second;
+ else
+ first_completed = wait_some(requests.begin(), requests.end());
+
+ return distance(requests.begin(), first_completed);
+ }
+
+
+
+
+ int wrap_test_some(request_list &requests, object py_callable)
+ {
+ check_request_list_not_empty(requests);
+ request_list::iterator first_completed;
+ if (py_callable != object())
+ first_completed = test_some(requests.begin(), requests.end(),
+ status_value_iterator(py_callable, requests.begin())).second;
+ else
+ first_completed = test_some(requests.begin(), requests.end());
+
+ return distance(requests.begin(), first_completed);
+ }
+}
+
+
+
+
+namespace boost { namespace mpi { namespace python {
+
+extern const char* request_list_init_docstring;
+extern const char* request_list_append_docstring;
+
+extern const char* nonblocking_wait_any_docstring;
+extern const char* nonblocking_test_any_docstring;
+extern const char* nonblocking_wait_all_docstring;
+extern const char* nonblocking_test_all_docstring;
+extern const char* nonblocking_wait_some_docstring;
+extern const char* nonblocking_test_some_docstring;
+
+void export_nonblocking()
+{
+ using boost::python::arg;
+
+ {
+ typedef request_list cl;
+ class_<cl>("RequestList", "A list of Request objects.")
+ .def("__init__", make_constructor(make_request_list_from_py_list),
+ /*arg("iterable"),*/ request_list_init_docstring)
+ .def(request_list_indexing_suite())
+ ;
+ }
+
+ def("wait_any", wrap_wait_any,
+ (arg("requests")),
+ nonblocking_wait_any_docstring);
+ def("test_any", wrap_test_any,
+ (arg("requests")),
+ nonblocking_test_any_docstring);
+
+ def("wait_all", wrap_wait_all,
+ (arg("requests"), arg("callable") = object()),
+ nonblocking_wait_all_docstring);
+ def("test_all", wrap_test_all,
+ (arg("requests"), arg("callable") = object()),
+ nonblocking_test_all_docstring);
+
+ def("wait_some", wrap_wait_some,
+ (arg("requests"), arg("callable") = object()),
+ nonblocking_wait_some_docstring);
+ def("test_some", wrap_test_some,
+ (arg("requests"), arg("callable") = object()),
+ nonblocking_test_some_docstring);
+}
+
+} } }
diff --git a/libs/mpi/src/python/py_request.cpp b/libs/mpi/src/python/py_request.cpp
new file mode 100644
index 000000000..53aa4dedf
--- /dev/null
+++ b/libs/mpi/src/python/py_request.cpp
@@ -0,0 +1,102 @@
+// (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
+
+/** @file request.cpp
+ *
+ * This file reflects the Boost.MPI @c request class into
+ * Python.
+ */
+#include <boost/python.hpp>
+#include <boost/mpi.hpp>
+#include "request_with_value.hpp"
+
+using namespace boost::python;
+using namespace boost::mpi;
+
+const object python::request_with_value::get_value() const
+{
+ if (m_internal_value.get())
+ return *m_internal_value;
+ else if (m_external_value)
+ return *m_external_value;
+ else
+ {
+ PyErr_SetString(PyExc_ValueError, "request value not available");
+ throw boost::python::error_already_set();
+ }
+}
+
+const object python::request_with_value::get_value_or_none() const
+{
+ if (m_internal_value.get())
+ return *m_internal_value;
+ else if (m_external_value)
+ return *m_external_value;
+ else
+ return object();
+}
+
+const object python::request_with_value::wrap_wait()
+{
+ status stat = request::wait();
+ if (m_internal_value.get() || m_external_value)
+ return boost::python::make_tuple(get_value(), stat);
+ else
+ return object(stat);
+}
+
+const object python::request_with_value::wrap_test()
+{
+ ::boost::optional<status> stat = request::test();
+ if (stat)
+ {
+ if (m_internal_value.get() || m_external_value)
+ return boost::python::make_tuple(get_value(), *stat);
+ else
+ return object(*stat);
+ }
+ else
+ return object();
+}
+
+
+namespace boost { namespace mpi { namespace python {
+
+extern const char* request_docstring;
+extern const char* request_with_value_docstring;
+extern const char* request_wait_docstring;
+extern const char* request_test_docstring;
+extern const char* request_cancel_docstring;
+extern const char* request_value_docstring;
+
+void export_request()
+{
+ using boost::python::arg;
+ using boost::python::object;
+
+ {
+ typedef request cl;
+ class_<cl>("Request", request_docstring, no_init)
+ .def("wait", &cl::wait, request_wait_docstring)
+ .def("test", &cl::test, request_test_docstring)
+ .def("cancel", &cl::cancel, request_cancel_docstring)
+ ;
+ }
+ {
+ typedef request_with_value cl;
+ class_<cl, bases<request> >(
+ "RequestWithValue", request_with_value_docstring, no_init)
+ .def("wait", &cl::wrap_wait, request_wait_docstring)
+ .def("test", &cl::wrap_test, request_test_docstring)
+ ;
+ }
+
+ implicitly_convertible<request, request_with_value>();
+}
+
+} } } // end namespace boost::mpi::python
diff --git a/libs/mpi/src/python/py_timer.cpp b/libs/mpi/src/python/py_timer.cpp
new file mode 100644
index 000000000..88b1b4062
--- /dev/null
+++ b/libs/mpi/src/python/py_timer.cpp
@@ -0,0 +1,48 @@
+// (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
+
+/** @file timer.cpp
+ *
+ * This file reflects the Boost.MPI @c timer class into
+ * Python.
+ */
+#include <boost/python.hpp>
+#include <boost/mpi/timer.hpp>
+
+using namespace boost::python;
+using namespace boost::mpi;
+
+namespace boost { namespace mpi { namespace python {
+
+extern const char* timer_docstring;
+extern const char* timer_default_constructor_docstring;
+extern const char* timer_restart_docstring;
+extern const char* timer_elapsed_docstring;
+extern const char* timer_elapsed_min_docstring;
+extern const char* timer_elapsed_max_docstring;
+extern const char* timer_time_is_global_docstring;
+
+void export_timer()
+{
+ using boost::python::arg;
+ using boost::python::object;
+
+ class_<timer>("Timer", timer_docstring)
+ .def(init<>())
+ .def("restart", &timer::restart, timer_restart_docstring)
+ .add_property("elapsed", &timer::elapsed, timer_elapsed_docstring)
+ .add_property("elapsed_min", &timer::elapsed_min,
+ timer_elapsed_min_docstring)
+ .add_property("elapsed_max", &timer::elapsed_max,
+ timer_elapsed_max_docstring)
+ .add_property("time_is_global", &timer::time_is_global,
+ timer_time_is_global_docstring)
+ ;
+}
+
+} } } // end namespace boost::mpi::python
diff --git a/libs/mpi/src/python/request_with_value.hpp b/libs/mpi/src/python/request_with_value.hpp
new file mode 100644
index 000000000..04d0c53e9
--- /dev/null
+++ b/libs/mpi/src/python/request_with_value.hpp
@@ -0,0 +1,71 @@
+// (C) Copyright 2006
+// Douglas Gregor <doug.gregor -at- gmail.com>
+// 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: Douglas Gregor, Andreas Kloeckner
+
+#ifndef BOOST_MPI_PYTHON_REQUEST_WITH_VALUE_HPP
+#define BOOST_MPI_PYTHON_REQUEST_WITH_VALUE_HPP
+
+#include <boost/python.hpp>
+#include <boost/mpi.hpp>
+
+namespace boost { namespace mpi { namespace python {
+
+ /** This wrapper adds a @c boost::python::object value to the @c
+ * boost::mpi::request structure, for the benefit of @c irecv() requests.
+ *
+ * In order to be able to return the value of his requests to the user, we
+ * need a handle that we can update to contain the transmitted value once the
+ * request completes. Since we're passing the address on to irecv to fill at
+ * any time in the future, this address may not change over time.
+ *
+ * There are two possible cases:
+ * - plain irecv()
+ * - skeleton-content irecv()
+ *
+ * In the first case, we need to own the storage from this object, the
+ * m_internal_value is used for this. In the second case, the updated
+ * python::object is part of a boost::mpi::python::content object: the
+ * m_external_value field handles this case. Furthermore, in the latter case,
+ * we now have a lifetime dependency on that content object; this can be
+ * handled with the BPL's with_custodian_and_ward facility.
+ *
+ * Since requests and request_with_value are supposed to be copyconstructible,
+ * we can't put the handle immediately inside this instance. Moreover, since
+ * we need to be able to put request_with_value inside request_vectors, any
+ * values we own must be held in a shared_ptr instance.
+ */
+
+ class request_with_value : public request
+ {
+ private:
+ boost::shared_ptr<boost::python::object> m_internal_value;
+ boost::python::object *m_external_value;
+
+ public:
+ request_with_value()
+ : m_external_value(0)
+ { }
+ request_with_value(const request &req)
+ : request(req), m_external_value(0)
+ { }
+
+ const boost::python::object get_value() const;
+ const boost::python::object get_value_or_none() const;
+
+ const boost::python::object wrap_wait();
+ const boost::python::object wrap_test();
+
+ friend request_with_value communicator_irecv(const communicator &, int, int);
+ friend request_with_value communicator_irecv_content(
+ const communicator&, int, int, content&);
+ };
+
+} } }
+
+#endif
diff --git a/libs/mpi/src/python/serialize.cpp b/libs/mpi/src/python/serialize.cpp
new file mode 100644
index 000000000..92004a340
--- /dev/null
+++ b/libs/mpi/src/python/serialize.cpp
@@ -0,0 +1,79 @@
+// (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
+
+/** @file serialize.cpp
+ *
+ * This file provides Boost.Serialization support for Python objects.
+ */
+#include <boost/mpi/python/serialize.hpp>
+#include <boost/mpi/python/skeleton_and_content.hpp>
+#include <boost/mpi.hpp>
+
+namespace boost { namespace python {
+
+struct pickle::data_t {
+ object module;
+ object dumps;
+ object loads;
+};
+
+
+/// Data used for communicating with the Python `pickle' module.
+pickle::data_t* pickle::data;
+
+str pickle::dumps(object obj, int protocol)
+{
+ if (!data) initialize_data();
+ return extract<str>((data->dumps)(obj, protocol));
+}
+
+object pickle::loads(str s)
+{
+ if (!data) initialize_data();
+ return ((data->loads)(s));
+}
+
+void pickle::initialize_data()
+{
+ data = new data_t;
+ data->module = object(handle<>(PyImport_ImportModule("pickle")));
+ data->dumps = data->module.attr("dumps");
+ data->loads = data->module.attr("loads");
+}
+
+} } // end namespace boost::python
+
+BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE_IMPL(
+ ::boost::mpi::packed_iarchive,
+ ::boost::mpi::packed_oarchive)
+
+namespace boost { namespace mpi { namespace python { namespace detail {
+
+ boost::python::object skeleton_proxy_base_type;
+
+ // A map from Python type objects to skeleton/content handlers
+ typedef std::map<PyTypeObject*, skeleton_content_handler>
+ skeleton_content_handlers_type;
+
+ BOOST_MPI_PYTHON_DECL skeleton_content_handlers_type skeleton_content_handlers;
+
+ bool
+ skeleton_and_content_handler_registered(PyTypeObject* type)
+ {
+ return
+ skeleton_content_handlers.find(type) != skeleton_content_handlers.end();
+ }
+
+ void
+ register_skeleton_and_content_handler(PyTypeObject* type,
+ const skeleton_content_handler& handler)
+ {
+ skeleton_content_handlers[type] = handler;
+ }
+
+} } } } // end namespace boost::mpi::python::detail
diff --git a/libs/mpi/src/python/skeleton_and_content.cpp b/libs/mpi/src/python/skeleton_and_content.cpp
new file mode 100644
index 000000000..d5376c14f
--- /dev/null
+++ b/libs/mpi/src/python/skeleton_and_content.cpp
@@ -0,0 +1,173 @@
+// (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
+
+/** @file skeleton_and_content.cpp
+ *
+ * This file reflects the skeleton/content facilities into Python.
+ */
+#include <boost/mpi/python/skeleton_and_content.hpp>
+#include <boost/mpi/python/serialize.hpp>
+#include <boost/python/list.hpp>
+#include <typeinfo>
+#include <list>
+#include "utility.hpp"
+#include "request_with_value.hpp"
+
+using namespace boost::python;
+using namespace boost::mpi;
+
+namespace boost { namespace mpi { namespace python {
+
+namespace detail {
+ typedef std::map<PyTypeObject*, skeleton_content_handler>
+ skeleton_content_handlers_type;
+
+// We're actually importing skeleton_content_handlers from skeleton_and_content.cpp.
+#if defined(BOOST_HAS_DECLSPEC) && (defined(BOOST_MPI_PYTHON_DYN_LINK) || defined(BOOST_ALL_DYN_LINK))
+# define BOOST_SC_DECL __declspec(dllimport)
+#else
+# define BOOST_SC_DECL
+#endif
+
+ extern BOOST_SC_DECL skeleton_content_handlers_type skeleton_content_handlers;
+}
+
+/**
+ * An exception that will be thrown when the object passed to the
+ * Python version of skeleton() does not have a skeleton.
+ */
+struct object_without_skeleton : public std::exception {
+ explicit object_without_skeleton(object value) : value(value) { }
+ virtual ~object_without_skeleton() throw() { }
+
+ object value;
+};
+
+str object_without_skeleton_str(const object_without_skeleton& e)
+{
+ return str("\nThe skeleton() or get_content() function was invoked for a Python\n"
+ "object that is not supported by the Boost.MPI skeleton/content\n"
+ "mechanism. To transfer objects via skeleton/content, you must\n"
+ "register the C++ type of this object with the C++ function:\n"
+ " boost::mpi::python::register_skeleton_and_content()\n"
+ "Object: " + str(e.value) + "\n");
+}
+
+/**
+ * Extract the "skeleton" from a Python object. In truth, all we're
+ * doing at this point is verifying that the object is a C++ type that
+ * has been registered for the skeleton/content mechanism.
+ */
+object skeleton(object value)
+{
+ PyTypeObject* type = value.ptr()->ob_type;
+ detail::skeleton_content_handlers_type::iterator pos =
+ detail::skeleton_content_handlers.find(type);
+ if (pos == detail::skeleton_content_handlers.end())
+ throw object_without_skeleton(value);
+ else
+ return pos->second.get_skeleton_proxy(value);
+}
+
+/**
+ * Extract the "content" from a Python object, which must be a C++
+ * type that has been registered for the skeleton/content mechanism.
+ */
+content get_content(object value)
+{
+ PyTypeObject* type = value.ptr()->ob_type;
+ detail::skeleton_content_handlers_type::iterator pos =
+ detail::skeleton_content_handlers.find(type);
+ if (pos == detail::skeleton_content_handlers.end())
+ throw object_without_skeleton(value);
+ else
+ return pos->second.get_content(value);
+}
+
+/// Send the content part of a Python object.
+void
+communicator_send_content(const communicator& comm, int dest, int tag,
+ const content& c)
+{
+ comm.send(dest, tag, c.base());
+}
+
+/// Receive the content of a Python object. We return the object
+/// received, not the content wrapper.
+object
+communicator_recv_content(const communicator& comm, int source, int tag,
+ const content& c, bool return_status)
+{
+ using boost::python::make_tuple;
+
+ status stat = comm.recv(source, tag, c.base());
+ if (return_status)
+ return make_tuple(c.object, stat);
+ else
+ return c.object;
+}
+
+/// Receive the content of a Python object. The request object's value
+/// attribute will reference the object whose content is being
+/// received, not the content wrapper.
+request_with_value
+communicator_irecv_content(const communicator& comm, int source, int tag,
+ content& c)
+{
+ request_with_value req(comm.irecv(source, tag, c.base()));
+ req.m_external_value = &c.object;
+ return req;
+}
+
+extern const char* object_without_skeleton_docstring;
+extern const char* object_without_skeleton_object_docstring;
+extern const char* skeleton_proxy_docstring;
+extern const char* skeleton_proxy_object_docstring;
+extern const char* content_docstring;
+extern const char* skeleton_docstring;
+extern const char* get_content_docstring;
+
+void export_skeleton_and_content(class_<communicator>& comm)
+{
+ using boost::python::arg;
+
+ // Expose the object_without_skeleton exception
+ object type =
+ class_<object_without_skeleton>
+ ("ObjectWithoutSkeleton", object_without_skeleton_docstring, no_init)
+ .def_readonly("object", &object_without_skeleton::value,
+ object_without_skeleton_object_docstring)
+ .def("__str__", &object_without_skeleton_str)
+ ;
+ translate_exception<object_without_skeleton>::declare(type);
+
+ // Expose the Python variants of "skeleton_proxy" and "content", and
+ // their generator functions.
+ detail::skeleton_proxy_base_type =
+ class_<skeleton_proxy_base>("SkeletonProxy", skeleton_proxy_docstring,
+ no_init)
+ .def_readonly("object", &skeleton_proxy_base::object,
+ skeleton_proxy_object_docstring);
+ class_<content>("Content", content_docstring, no_init);
+ def("skeleton", &skeleton, arg("object"), skeleton_docstring);
+ def("get_content", &get_content, arg("object"), get_content_docstring);
+
+ // Expose communicator send/recv operations for content.
+ comm
+ .def("send", communicator_send_content,
+ (arg("dest"), arg("tag") = 0, arg("value")))
+ .def("recv", communicator_recv_content,
+ (arg("source") = any_source, arg("tag") = any_tag, arg("buffer"),
+ arg("return_status") = false))
+ .def("irecv", communicator_irecv_content,
+ (arg("source") = any_source, arg("tag") = any_tag, arg("buffer")),
+ with_custodian_and_ward_postcall<0, 4>()
+ );
+}
+
+} } } // end namespace boost::mpi::python
diff --git a/libs/mpi/src/python/status.cpp b/libs/mpi/src/python/status.cpp
new file mode 100644
index 000000000..a74221a7a
--- /dev/null
+++ b/libs/mpi/src/python/status.cpp
@@ -0,0 +1,41 @@
+// (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
+
+/** @file status.cpp
+ *
+ * This file reflects the Boost.MPI @c status class into
+ * Python.
+ */
+#include <boost/python.hpp>
+#include <boost/mpi.hpp>
+
+using namespace boost::python;
+using namespace boost::mpi;
+
+namespace boost { namespace mpi { namespace python {
+
+extern const char* status_docstring;
+extern const char* status_source_docstring;
+extern const char* status_tag_docstring;
+extern const char* status_error_docstring;
+extern const char* status_cancelled_docstring;
+
+void export_status()
+{
+ using boost::python::arg;
+ using boost::python::object;
+
+ class_<status>("Status", status_docstring, no_init)
+ .add_property("source", &status::source, status_source_docstring)
+ .add_property("tag", &status::tag, status_tag_docstring)
+ .add_property("error", &status::error, status_error_docstring)
+ .add_property("cancelled", &status::cancelled, status_cancelled_docstring)
+ ;
+}
+
+} } } // end namespace boost::mpi::python
diff --git a/libs/mpi/src/python/utility.hpp b/libs/mpi/src/python/utility.hpp
new file mode 100644
index 000000000..ed0016761
--- /dev/null
+++ b/libs/mpi/src/python/utility.hpp
@@ -0,0 +1,43 @@
+// (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
+#ifndef BOOST_MPI_PYTHON_UTILITY_HPP
+#define BOOST_MPI_PYTHON_UTILITY_HPP
+
+/** @file utility.hpp
+ *
+ * This file is a utility header for the Boost.MPI Python bindings.
+ */
+#include <boost/python.hpp>
+
+namespace boost { namespace mpi { namespace python {
+
+template<typename E>
+class translate_exception
+{
+ explicit translate_exception(boost::python::object type) : type(type) { }
+
+public:
+ static void declare(boost::python::object type)
+ {
+ using boost::python::register_exception_translator;
+ register_exception_translator<E>(translate_exception(type));
+ }
+
+ void operator()(const E& e) const
+ {
+ using boost::python::object;
+ PyErr_SetObject(type.ptr(), object(e).ptr());
+ }
+
+private:
+ boost::python::object type;
+};
+
+} } } // end namespace boost::mpi::python
+
+#endif // BOOST_MPI_PYTHON_UTILITY_HPP