| // Copyright (C) 2007 Trustees of Indiana University |
| |
| // Authors: Douglas Gregor |
| // Andrew Lumsdaine |
| |
| // Use, modification and distribution is subject to the Boost Software |
| // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| |
| /** @file group.hpp |
| * |
| * This header defines the @c group class, which allows one to |
| * manipulate and query groups of processes. |
| */ |
| #ifndef BOOST_MPI_GROUP_HPP |
| #define BOOST_MPI_GROUP_HPP |
| |
| #include <boost/mpi/exception.hpp> |
| #include <boost/shared_ptr.hpp> |
| #include <boost/optional.hpp> |
| #include <vector> |
| |
| namespace boost { namespace mpi { |
| |
| /** |
| * @brief A @c group is a representation of a subset of the processes |
| * within a @c communicator. |
| * |
| * The @c group class allows one to create arbitrary subsets of the |
| * processes within a communicator. One can compute the union, |
| * intersection, or difference of two groups, or create new groups by |
| * specifically including or excluding certain processes. Given a |
| * group, one can create a new communicator containing only the |
| * processes in that group. |
| */ |
| class BOOST_MPI_DECL group |
| { |
| public: |
| /** |
| * @brief Constructs an empty group. |
| */ |
| group() : group_ptr() { } |
| |
| /** |
| * @brief Constructs a group from an @c MPI_Group. |
| * |
| * This routine allows one to construct a Boost.MPI @c group from a |
| * C @c MPI_Group. The @c group object can (optionally) adopt the @c |
| * MPI_Group, after which point the @c group object becomes |
| * responsible for freeing the @c MPI_Group when the last copy of @c |
| * group disappears. |
| * |
| * @param in_group The @c MPI_Group used to construct this @c group. |
| * |
| * @param adopt Whether the @c group should adopt the @c |
| * MPI_Group. When true, the @c group object (or one of its copies) |
| * will free the group (via @c MPI_Comm_free) when the last copy is |
| * destroyed. Otherwise, the user is responsible for calling @c |
| * MPI_Group_free. |
| */ |
| group(const MPI_Group& in_group, bool adopt); |
| |
| /** |
| * @brief Determine the rank of the calling process in the group. |
| * |
| * This routine is equivalent to @c MPI_Group_rank. |
| * |
| * @returns The rank of the calling process in the group, which will |
| * be a value in [0, size()). If the calling process is not in the |
| * group, returns an empty value. |
| */ |
| optional<int> rank() const; |
| |
| /** |
| * @brief Determine the number of processes in the group. |
| * |
| * This routine is equivalent to @c MPI_Group_size. |
| * |
| * @returns The number of processes in the group. |
| */ |
| int size() const; |
| |
| /** |
| * @brief Translates the ranks from one group into the ranks of the |
| * same processes in another group. |
| * |
| * This routine translates each of the integer rank values in the |
| * iterator range @c [first, last) from the current group into rank |
| * values of the corresponding processes in @p to_group. The |
| * corresponding rank values are written via the output iterator @c |
| * out. When there is no correspondence between a rank in the |
| * current group and a rank in @c to_group, the value @c |
| * MPI_UNDEFINED is written to the output iterator. |
| * |
| * @param first Beginning of the iterator range of ranks in the |
| * current group. |
| * |
| * @param last Past the end of the iterator range of ranks in the |
| * current group. |
| * |
| * @param to_group The group that we are translating ranks to. |
| * |
| * @param out The output iterator to which the translated ranks will |
| * be written. |
| * |
| * @returns the output iterator, which points one step past the last |
| * rank written. |
| */ |
| template<typename InputIterator, typename OutputIterator> |
| OutputIterator translate_ranks(InputIterator first, InputIterator last, |
| const group& to_group, OutputIterator out); |
| |
| /** |
| * @brief Determines whether the group is non-empty. |
| * |
| * @returns True if the group is not empty, false if it is empty. |
| */ |
| operator bool() const { return (bool)group_ptr; } |
| |
| /** |
| * @brief Retrieves the underlying @c MPI_Group associated with this |
| * group. |
| * |
| * @returns The @c MPI_Group handle manipulated by this object. If |
| * this object represents the empty group, returns @c |
| * MPI_GROUP_EMPTY. |
| */ |
| operator MPI_Group() const |
| { |
| if (group_ptr) |
| return *group_ptr; |
| else |
| return MPI_GROUP_EMPTY; |
| } |
| |
| /** |
| * @brief Creates a new group including a subset of the processes |
| * in the current group. |
| * |
| * This routine creates a new @c group which includes only those |
| * processes in the current group that are listed in the integer |
| * iterator range @c [first, last). Equivalent to @c |
| * MPI_Group_incl. |
| * |
| * @c first The beginning of the iterator range of ranks to include. |
| * |
| * @c last Past the end of the iterator range of ranks to include. |
| * |
| * @returns A new group containing those processes with ranks @c |
| * [first, last) in the current group. |
| */ |
| template<typename InputIterator> |
| group include(InputIterator first, InputIterator last); |
| |
| /** |
| * @brief Creates a new group from all of the processes in the |
| * current group, exluding a specific subset of the processes. |
| * |
| * This routine creates a new @c group which includes all of the |
| * processes in the current group except those whose ranks are |
| * listed in the integer iterator range @c [first, |
| * last). Equivalent to @c MPI_Group_excl. |
| * |
| * @c first The beginning of the iterator range of ranks to exclude. |
| * |
| * @c last Past the end of the iterator range of ranks to exclude. |
| * |
| * @returns A new group containing all of the processes in the |
| * current group except those processes with ranks @c [first, last) |
| * in the current group. |
| */ |
| template<typename InputIterator> |
| group exclude(InputIterator first, InputIterator last); |
| |
| |
| protected: |
| /** |
| * INTERNAL ONLY |
| * |
| * Function object that frees an MPI group and deletes the |
| * memory associated with it. Intended to be used as a deleter with |
| * shared_ptr. |
| */ |
| struct group_free |
| { |
| void operator()(MPI_Group* comm) const |
| { |
| int finalized; |
| BOOST_MPI_CHECK_RESULT(MPI_Finalized, (&finalized)); |
| if (!finalized) |
| BOOST_MPI_CHECK_RESULT(MPI_Group_free, (comm)); |
| delete comm; |
| } |
| }; |
| |
| /** |
| * The underlying MPI group. This is a shared pointer, so the actual |
| * MPI group which will be shared among all related instances of the |
| * @c group class. When there are no more such instances, the group |
| * will be automatically freed. |
| */ |
| shared_ptr<MPI_Group> group_ptr; |
| }; |
| |
| /** |
| * @brief Determines whether two process groups are identical. |
| * |
| * Equivalent to calling @c MPI_Group_compare and checking whether the |
| * result is @c MPI_IDENT. |
| * |
| * @returns True when the two process groups contain the same |
| * processes in the same order. |
| */ |
| BOOST_MPI_DECL bool operator==(const group& g1, const group& g2); |
| |
| /** |
| * @brief Determines whether two process groups are not identical. |
| * |
| * Equivalent to calling @c MPI_Group_compare and checking whether the |
| * result is not @c MPI_IDENT. |
| * |
| * @returns False when the two process groups contain the same |
| * processes in the same order. |
| */ |
| inline bool operator!=(const group& g1, const group& g2) |
| { |
| return !(g1 == g2); |
| } |
| |
| /** |
| * @brief Computes the union of two process groups. |
| * |
| * This routine returns a new @c group that contains all processes |
| * that are either in group @c g1 or in group @c g2 (or both). The |
| * processes that are in @c g1 will be first in the resulting group, |
| * followed by the processes from @c g2 (but not also in @c |
| * g1). Equivalent to @c MPI_Group_union. |
| */ |
| BOOST_MPI_DECL group operator|(const group& g1, const group& g2); |
| |
| /** |
| * @brief Computes the intersection of two process groups. |
| * |
| * This routine returns a new @c group that contains all processes |
| * that are in group @c g1 and in group @c g2, ordered in the same way |
| * as @c g1. Equivalent to @c MPI_Group_intersection. |
| */ |
| BOOST_MPI_DECL group operator&(const group& g1, const group& g2); |
| |
| /** |
| * @brief Computes the difference between two process groups. |
| * |
| * This routine returns a new @c group that contains all processes |
| * that are in group @c g1 but not in group @c g2, ordered in the same way |
| * as @c g1. Equivalent to @c MPI_Group_difference. |
| */ |
| BOOST_MPI_DECL group operator-(const group& g1, const group& g2); |
| |
| /************************************************************************ |
| * Implementation details * |
| ************************************************************************/ |
| template<typename InputIterator, typename OutputIterator> |
| OutputIterator |
| group::translate_ranks(InputIterator first, InputIterator last, |
| const group& to_group, OutputIterator out) |
| { |
| std::vector<int> in_array(first, last); |
| if (in_array.empty()) |
| return out; |
| |
| std::vector<int> out_array(in_array.size()); |
| BOOST_MPI_CHECK_RESULT(MPI_Group_translate_ranks, |
| ((MPI_Group)*this, |
| in_array.size(), |
| &in_array[0], |
| (MPI_Group)to_group, |
| &out_array[0])); |
| |
| for (std::vector<int>::size_type i = 0, n = out_array.size(); i < n; ++i) |
| *out++ = out_array[i]; |
| return out; |
| } |
| |
| /** |
| * INTERNAL ONLY |
| * |
| * Specialization of translate_ranks that handles the one case where |
| * we can avoid any memory allocation or copying. |
| */ |
| template<> |
| BOOST_MPI_DECL int* |
| group::translate_ranks(int* first, int* last, const group& to_group, int* out); |
| |
| template<typename InputIterator> |
| group group::include(InputIterator first, InputIterator last) |
| { |
| if (first == last) |
| return group(); |
| |
| std::vector<int> ranks(first, last); |
| MPI_Group result; |
| BOOST_MPI_CHECK_RESULT(MPI_Group_incl, |
| ((MPI_Group)*this, ranks.size(), &ranks[0], &result)); |
| return group(result, /*adopt=*/true); |
| } |
| |
| /** |
| * INTERNAL ONLY |
| * |
| * Specialization of group::include that handles the one case where we |
| * can avoid any memory allocation or copying before creating the |
| * group. |
| */ |
| template<> BOOST_MPI_DECL group group::include(int* first, int* last); |
| |
| template<typename InputIterator> |
| group group::exclude(InputIterator first, InputIterator last) |
| { |
| if (first == last) |
| return group(); |
| |
| std::vector<int> ranks(first, last); |
| MPI_Group result; |
| BOOST_MPI_CHECK_RESULT(MPI_Group_excl, |
| ((MPI_Group)*this, ranks.size(), &ranks[0], &result)); |
| return group(result, /*adopt=*/true); |
| } |
| |
| /** |
| * INTERNAL ONLY |
| * |
| * Specialization of group::exclude that handles the one case where we |
| * can avoid any memory allocation or copying before creating the |
| * group. |
| */ |
| template<> BOOST_MPI_DECL group group::exclude(int* first, int* last); |
| |
| } } // end namespace boost::mpi |
| |
| #endif // BOOST_MPI_GROUP_HPP |