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