1cdef class Group:
2
3    """
4    Group
5    """
6
7    def __cinit__(self):
8        self.ob_mpi = MPI_GROUP_NULL
9
10    def __dealloc__(self):
11        if not (self.flags & PyMPI_OWNED): return
12        CHKERR( del_Group(&self.ob_mpi) )
13
14    def __richcmp__(self, other, int op):
15        if not isinstance(self,  Group): return NotImplemented
16        if not isinstance(other, Group): return NotImplemented
17        cdef Group s = <Group>self, o = <Group>other
18        if   op == Py_EQ: return (s.ob_mpi == o.ob_mpi)
19        elif op == Py_NE: return (s.ob_mpi != o.ob_mpi)
20        else: raise TypeError("only '==' and '!='")
21
22    def __bool__(self):
23        return self.ob_mpi != MPI_GROUP_NULL
24
25    # Group Accessors
26    # ---------------
27
28    def Get_size(self):
29        """
30        Return the size of a group
31        """
32        cdef int size = -1
33        CHKERR( MPI_Group_size(self.ob_mpi, &size) )
34        return size
35
36    property size:
37        """number of processes in group"""
38        def __get__(self):
39            return self.Get_size()
40
41    def Get_rank(self):
42        """
43        Return the rank of this process in a group
44        """
45        cdef int rank = -1
46        CHKERR( MPI_Group_rank(self.ob_mpi, &rank) )
47        return rank
48
49    property rank:
50        """rank of this process in group"""
51        def __get__(self):
52            return self.Get_rank()
53
54    @classmethod
55    def Translate_ranks(cls,
56                        Group group1 not None, ranks1,
57                        Group group2=None):
58        """
59        Translate the ranks of processes in
60        one group to those in another group
61        """
62        cdef MPI_Group grp1 = MPI_GROUP_NULL
63        cdef MPI_Group grp2 = MPI_GROUP_NULL
64        cdef int n = 0, *iranks1 = NULL, *iranks2 = NULL
65        cdef object ranks_ = getarray_int(ranks1, &n, &iranks1)
66        cdef object ranks2 = newarray_int(n, &iranks2)
67        #
68        grp1 = group1.ob_mpi
69        if group2 is not None:
70            grp2 = group2.ob_mpi
71        else:
72            CHKERR( MPI_Comm_group(MPI_COMM_WORLD, &grp2) )
73        try:
74            CHKERR( MPI_Group_translate_ranks(grp1, n, iranks1,
75                                              grp2, iranks2) )
76        finally:
77            if group2 is None:
78                CHKERR( MPI_Group_free(&grp2) )
79        #
80        return ranks2
81
82    @classmethod
83    def Compare(cls,
84                Group group1 not None,
85                Group group2 not None):
86        """
87        Compare two groups
88        """
89        cdef int flag = MPI_UNEQUAL
90        CHKERR( MPI_Group_compare(group1.ob_mpi, group2.ob_mpi, &flag) )
91        return flag
92
93    # Group Constructors
94    # ------------------
95
96    def Dup(self):
97        """
98        Duplicate a group
99        """
100        cdef Group group = <Group>type(self)()
101        CHKERR( MPI_Group_union(self.ob_mpi, MPI_GROUP_EMPTY, &group.ob_mpi) )
102        return group
103
104    @classmethod
105    def Union(cls,
106              Group group1 not None,
107              Group group2 not None):
108        """
109        Produce a group by combining
110        two existing groups
111        """
112        cdef Group group = <Group>cls()
113        CHKERR( MPI_Group_union(
114                group1.ob_mpi, group2.ob_mpi, &group.ob_mpi) )
115        return group
116
117    @classmethod
118    def Intersect(cls,
119                  Group group1 not None,
120                  Group group2 not None):
121        """
122        Produce a group as the intersection
123        of two existing groups
124        """
125        cdef Group group = <Group>cls()
126        CHKERR( MPI_Group_intersection(
127                group1.ob_mpi, group2.ob_mpi, &group.ob_mpi) )
128        return group
129
130    @classmethod
131    def Difference(cls,
132                   Group group1 not None,
133                   Group group2 not None):
134        """
135        Produce a group from the difference
136        of two existing groups
137        """
138        cdef Group group = <Group>cls()
139        CHKERR( MPI_Group_difference(
140                group1.ob_mpi, group2.ob_mpi, &group.ob_mpi) )
141        return group
142
143    def Incl(self, ranks):
144        """
145        Produce a group by reordering an existing
146        group and taking only listed members
147        """
148        cdef int n = 0, *iranks = NULL
149        ranks = getarray_int(ranks, &n, &iranks)
150        cdef Group group = <Group>type(self)()
151        CHKERR( MPI_Group_incl(self.ob_mpi, n, iranks, &group.ob_mpi) )
152        return group
153
154    def Excl(self, ranks):
155        """
156        Produce a group by reordering an existing
157        group and taking only unlisted members
158        """
159        cdef int n = 0, *iranks = NULL
160        ranks = getarray_int(ranks, &n, &iranks)
161        cdef Group group = <Group>type(self)()
162        CHKERR( MPI_Group_excl(self.ob_mpi, n, iranks, &group.ob_mpi) )
163        return group
164
165    def Range_incl(self, ranks):
166        """
167        Create a new group from ranges of
168        of ranks in an existing group
169        """
170        cdef int *p = NULL, (*ranges)[3]# = NULL ## XXX cython fails
171        ranges = NULL
172        cdef int i = 0, n = <int>len(ranks)
173        cdef tmp1 = allocate(n, sizeof(int[3]), <void**>&ranges)
174        for i from 0 <= i < n:
175            p = <int*> ranges[i]
176            p[0], p[1], p[2] = ranks[i]
177        cdef Group group = <Group>type(self)()
178        CHKERR( MPI_Group_range_incl(self.ob_mpi, n, ranges, &group.ob_mpi) )
179        return group
180
181    def Range_excl(self, ranks):
182        """
183        Create a new group by excluding ranges
184        of processes from an existing group
185        """
186        cdef int *p = NULL, (*ranges)[3]# = NULL ## XXX cython fails
187        ranges = NULL
188        cdef int i = 0, n = <int>len(ranks)
189        cdef tmp1 = allocate(n, sizeof(int[3]), <void**>&ranges)
190        for i from 0 <= i < n:
191            p = <int*> ranges[i]
192            p[0], p[1], p[2] = ranks[i]
193        cdef Group group = <Group>type(self)()
194        CHKERR( MPI_Group_range_excl(self.ob_mpi, n, ranges, &group.ob_mpi) )
195        return group
196
197    # Group Destructor
198    # ----------------
199
200    def Free(self):
201        """
202        Free a group
203        """
204        if self.ob_mpi != MPI_GROUP_EMPTY:
205            CHKERR( MPI_Group_free(&self.ob_mpi) )
206        elif self is not __GROUP_EMPTY__:
207            self.ob_mpi = MPI_GROUP_NULL
208        else: CHKERR( MPI_ERR_GROUP )
209
210    # Fortran Handle
211    # --------------
212
213    def py2f(self):
214        """
215        """
216        return MPI_Group_c2f(self.ob_mpi)
217
218    @classmethod
219    def f2py(cls, arg):
220        """
221        """
222        cdef Group group = <Group>cls()
223        group.ob_mpi = MPI_Group_f2c(arg)
224        return group
225
226
227
228cdef Group __GROUP_NULL__  = new_Group ( MPI_GROUP_NULL  )
229cdef Group __GROUP_EMPTY__ = new_Group ( MPI_GROUP_EMPTY )
230
231
232# Predefined group handles
233# ------------------------
234
235GROUP_NULL  = __GROUP_NULL__   #: Null group handle
236GROUP_EMPTY = __GROUP_EMPTY__  #: Empty group handle
237