341 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			341 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| // 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
 | 
