1 #if COMPILATION// -*-indent-tabs-mode:t;c-basic-offset:4;tab-width:4;-*-
2 OMPI_CXX=$CXX mpic++ $0 -o $0x -lboost_serialization&&mpirun --oversubscribe -n 4 $0x&&rm $0x;exit
3 #endif
4 // © Alfredo A. Correa 2018-2020
5 
6 #ifndef MPI3_GROUP_HPP
7 #define MPI3_GROUP_HPP
8 
9 #include "detail/equality.hpp"
10 
11 #include "../mpi3/error.hpp"
12 
13 #include "../mpi3/detail/iterator_traits.hpp"
14 #include "../mpi3/detail/call.hpp"
15 
16 #include<cassert>
17 
18 #define OMPI_SKIP_MPICXX 1  // https://github.com/open-mpi/ompi/issues/5157
19 #include<mpi.h>
20 
21 namespace boost{
22 namespace mpi3{
23 
24 //class communicator;
25 //template<class T = void> struct window;
26 
27 class group{
28 	MPI_Group impl_ = MPI_GROUP_EMPTY;
29 public:
30 	friend class communicator;
31 	template<class T> friend struct window;
operator &()32 	MPI_Group operator&(){return impl_;}
get()33 	MPI_Group& get(){return impl_;}
34 //	std::pointer_traits<MPI_Group>::element_type const* operator&() const{return impl_;} // this doesn't work because in mpich MPI_Group is not a pointer type
35 	group() = default;
group(group && other)36 	group(group&& other) noexcept : impl_{std::exchange(other.impl_, MPI_GROUP_EMPTY)}{}
group(group const & other)37 	group(group const& other){MPI_(Group_excl)(other.impl_, 0, nullptr, &impl_);}
38 //	explicit group(communicator const& c);//{MPI_Comm_group(c.impl_, &impl_);}
39 //	explicit group(window<> const& w);
swap(group & other)40 	void swap(group& other) noexcept{std::swap(impl_, other.impl_);}
operator =(group other)41 	group& operator=(group other) noexcept{swap(other); return *this;}
clear()42 	void clear(){
43 		if(impl_ != MPI_GROUP_EMPTY) MPI_(Group_free)(&impl_);
44 		impl_ = MPI_GROUP_EMPTY;
45 	}
~group()46 	~group(){if(impl_ != MPI_GROUP_EMPTY) MPI_(Group_free)(&impl_);}
include(std::initializer_list<int> il)47 	group include(std::initializer_list<int> il){
48 		group ret; MPI_(Group_incl)(impl_, il.size(), il.begin(), &ret.impl_); return ret;
49 	}
exclude(std::initializer_list<int> il)50 	group exclude(std::initializer_list<int> il){
51 		group ret; MPI_(Group_excl)(impl_, il.size(), il.begin(), &ret.impl_); return ret;
52 	}
rank() const53 	int rank() const{int rank = -1; MPI_(Group_rank)(impl_, &rank); return rank;}
root() const54 	bool root() const{assert(not empty()); return rank() == 0;}
size() const55 	int size() const{int size=-1; MPI_(Group_size)(impl_, &size); return size;}
sliced(int first,int last,int stride=1) const56 	group sliced(int first, int last, int stride = 1) const{
57 		int ranges[][3] = {{first, last - 1, stride}};
58 		group ret; MPI_(Group_range_incl)(impl_, 1, ranges, &ret.impl_); return ret;
59 	}
empty() const60 	bool empty() const{return size()==0;}
compare(group const & self,group const & other)61 	friend auto compare(group const& self, group const& other){
62 		int result; MPI_(Group_compare)(self.impl_, other.impl_, &result);
63 		return static_cast<mpi3::detail::equality>(result);
64 	}
operator ==(group const & other) const65 	bool operator==(group const& other) const{
66 		auto e=compare(*this, other);
67 		return e == mpi3::detail::identical or e == mpi3::detail::congruent;
68 	}
operator !=(group const & other) const69 	bool operator!=(group const& other) const{return not operator==(other);}
is_permutation(group const & self,group const & other)70 	bool friend is_permutation(group const& self, group const& other){
71 		return compare(self, other) != mpi3::detail::unequal;
72 	}
set_intersection(group const & self,group const & other)73 	friend group set_intersection(group const& self, group const& other){
74 		group ret; MPI_(Group_intersection)(self.impl_, other.impl_, &ret.impl_); return ret;
75 	}
set_difference(group const & self,group const & other)76 	friend group set_difference(group const& self, group const& other){
77 		group ret; MPI_(Group_difference)(self.impl_, other.impl_, &ret.impl_); return ret;
78 	}
set_union(group const & self,group const & other)79 	friend group set_union(group const& self, group const& other){
80 		group ret; MPI_(Group_union)(self.impl_, other.impl_, &ret.impl_); return ret;
81 	}
translate_rank(int rank,group const & other) const82 	int translate_rank(int rank, group const& other) const{
83 		int out; MPI_(Group_translate_ranks)(impl_, 1, &rank, other.impl_, &out); return out;
84 	}
85 };
86 
87 }}
88 
89 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
90 
91 #if not __INCLUDE_LEVEL__ // def _TEST_MPI3_GROUP
92 
93 #include "../mpi3/main.hpp"
94 
95 #include<iostream>
96 
97 using std::cout;
98 namespace mpi3 = boost::mpi3;
99 
main(int,char * [],mpi3::communicator world)100 int mpi3::main(int, char*[], mpi3::communicator world){
101 
102 	mpi3::communicator w1 = world;
103 	assert( w1.size() == world.size() );
104 	assert( w1.rank() == world.rank() );
105 
106 	mpi3::group g1{w1};
107 	{
108 		mpi3::group g2 = g1;
109 		assert( g1 == g2 );
110 	}
111 	assert( g1.rank() == w1.rank() );
112 
113 	mpi3::communicator w2 = w1.create(g1);
114 	assert( w2.size() == w1.size() );
115 	assert( w2.rank() == w1.rank() );
116 	assert( w2.rank() == world.rank() );
117 
118 	return 0;
119 }
120 
121 #endif
122 #endif
123 
124 
125