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