// 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 #include #include #include 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 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 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 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 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 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 OutputIterator group::translate_ranks(InputIterator first, InputIterator last, const group& to_group, OutputIterator out) { std::vector in_array(first, last); if (in_array.empty()) return out; std::vector 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::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 group group::include(InputIterator first, InputIterator last) { if (first == last) return group(); std::vector 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 group group::exclude(InputIterator first, InputIterator last) { if (first == last) return group(); std::vector 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