xref: /petsc/src/binding/petsc4py/src/petsc4py/PETSc/IS.pyx (revision 124b60a56262a80503e09b9eaaec281e19388b1e)
1# --------------------------------------------------------------------
2
3class ISType(object):
4    """The index set types."""
5    GENERAL = S_(ISGENERAL)
6    BLOCK   = S_(ISBLOCK)
7    STRIDE  = S_(ISSTRIDE)
8
9# --------------------------------------------------------------------
10
11
12cdef class IS(Object):
13    """A collection of indices.
14
15    IS objects are used to index into vectors and matrices and to set up vector
16    scatters.
17
18    See Also
19    --------
20    petsc.IS
21
22    """
23
24    Type = ISType
25
26    #
27
28    def __cinit__(self):
29        self.obj = <PetscObject*> &self.iset
30        self.iset = NULL
31
32    # buffer interface (PEP 3118)
33
34    def __getbuffer__(self, Py_buffer *view, int flags):
35        cdef _IS_buffer buf = _IS_buffer(self)
36        buf.acquirebuffer(view, flags)
37
38    def __releasebuffer__(self, Py_buffer *view):
39        cdef _IS_buffer buf = <_IS_buffer>(view.obj)
40        buf.releasebuffer(view)
41        <void>self # unused
42
43    # 'with' statement (PEP 343)
44
45    def __enter__(self):
46        cdef _IS_buffer buf = _IS_buffer(self)
47        self.set_attr('__buffer__', buf)
48        return buf.enter()
49
50    def __exit__(self, *exc):
51        cdef _IS_buffer buf = self.get_attr('__buffer__')
52        self.set_attr('__buffer__', None)
53        return buf.exit()
54    #
55
56    def view(self, Viewer viewer=None) -> None:
57        """Display the index set.
58
59        Collective.
60
61        Parameters
62        ----------
63        viewer
64            Viewer used to display the IS.
65
66        See Also
67        --------
68        petsc.ISView
69
70        """
71        cdef PetscViewer cviewer = NULL
72        if viewer is not None: cviewer = viewer.vwr
73        CHKERR(ISView(self.iset, cviewer))
74
75    def destroy(self) -> Self:
76        """Destroy the index set.
77
78        Collective.
79
80        See Also
81        --------
82        petsc.ISDestroy
83
84        """
85        CHKERR(ISDestroy(&self.iset))
86        return self
87
88    def create(self, comm: Comm | None = None) -> Self:
89        """Create an IS.
90
91        Collective.
92
93        Parameters
94        ----------
95        comm
96            MPI communicator, defaults to `Sys.getDefaultComm`.
97
98        See Also
99        --------
100        petsc.ISCreate
101
102        """
103        cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_DEFAULT)
104        cdef PetscIS newiset = NULL
105        CHKERR(ISCreate(ccomm, &newiset))
106        CHKERR(PetscCLEAR(self.obj)); self.iset = newiset
107        return self
108
109    def setType(self, is_type: IS.Type | str) -> None:
110        """Set the type of the index set.
111
112        Collective.
113
114        Parameters
115        ----------
116        is_type
117            The index set type.
118
119        See Also
120        --------
121        petsc.ISSetType
122
123        """
124        cdef PetscISType cval = NULL
125        is_type = str2bytes(is_type, &cval)
126        CHKERR(ISSetType(self.iset, cval))
127
128    def getType(self) -> str:
129        """Return the index set type associated with the IS.
130
131        Not collective.
132
133        See Also
134        --------
135        petsc.ISGetType
136
137        """
138        cdef PetscISType cval = NULL
139        CHKERR(ISGetType(self.iset, &cval))
140        return bytes2str(cval)
141
142    def createGeneral(
143        self,
144        indices: Sequence[int],
145        comm: Comm | None = None) -> Self:
146        """Create an IS with indices.
147
148        Collective.
149
150        Parameters
151        ----------
152        indices
153            Integer array.
154        comm
155            MPI communicator, defaults to `Sys.getDefaultComm`.
156
157        See Also
158        --------
159        petsc.ISCreateGeneral
160
161        """
162        cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_DEFAULT)
163        cdef PetscInt nidx = 0, *idx = NULL
164        cdef PetscCopyMode cm = PETSC_COPY_VALUES
165        cdef PetscIS newiset = NULL
166        indices = iarray_i(indices, &nidx, &idx)
167        CHKERR(ISCreateGeneral(ccomm, nidx, idx, cm, &newiset))
168        CHKERR(PetscCLEAR(self.obj)); self.iset = newiset
169        return self
170
171    def createBlock(
172        self,
173        bsize: int,
174        indices: Sequence[int],
175        comm: Comm | None = None) -> Self:
176        """Create a blocked index set.
177
178        Collective.
179
180        Parameters
181        ----------
182        bsize
183            Block size.
184        indices
185            Integer array of indices.
186        comm
187            MPI communicator, defaults to `Sys.getDefaultComm`.
188
189        See Also
190        --------
191        petsc.ISCreateBlock
192
193        """
194        cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_DEFAULT)
195        cdef PetscInt bs = asInt(bsize)
196        cdef PetscInt nidx = 0, *idx = NULL
197        cdef PetscCopyMode cm = PETSC_COPY_VALUES
198        cdef PetscIS newiset = NULL
199        indices = iarray_i(indices, &nidx, &idx)
200        CHKERR(ISCreateBlock(ccomm, bs, nidx, idx, cm, &newiset))
201        CHKERR(PetscCLEAR(self.obj)); self.iset = newiset
202        return self
203
204    def createStride(
205        self,
206        size: int,
207        first: int = 0,
208        step: int = 1,
209        comm: Comm | None = None) -> Self:
210        """Create an index set consisting of evenly spaced values.
211
212        Collective.
213
214        Parameters
215        ----------
216        size
217            The length of the locally owned portion of the index set.
218        first
219            The first element of the index set.
220        step
221            The difference between adjacent indices.
222        comm
223            MPI communicator, defaults to `Sys.getDefaultComm`.
224
225        See Also
226        --------
227        petsc.ISCreateStride
228
229        """
230        cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_DEFAULT)
231        cdef PetscInt csize  = asInt(size)
232        cdef PetscInt cfirst = asInt(first)
233        cdef PetscInt cstep  = asInt(step)
234        cdef PetscIS newiset = NULL
235        CHKERR(ISCreateStride(ccomm, csize, cfirst, cstep, &newiset))
236        CHKERR(PetscCLEAR(self.obj)); self.iset = newiset
237        return self
238
239    def duplicate(self) -> IS:
240        """Create a copy of the index set.
241
242        Collective.
243
244        See Also
245        --------
246        IS.copy, petsc.ISDuplicate
247
248        """
249        cdef IS iset = type(self)()
250        CHKERR(ISDuplicate(self.iset, &iset.iset))
251        return iset
252
253    def copy(self, IS result=None) -> IS:
254        """Copy the contents of the index set into another.
255
256        Collective.
257
258        Parameters
259        ----------
260        result
261            The target index set. If `None` then `IS.duplicate` is called first.
262
263        Returns
264        -------
265        IS
266            The copied index set. If ``result`` is not `None` then this is
267            returned here.
268
269        See Also
270        --------
271        IS.duplicate, petsc.ISCopy
272
273        """
274        if result is None:
275            result = type(self)()
276        if result.iset == NULL:
277            CHKERR(ISDuplicate(self.iset, &result.iset))
278        CHKERR(ISCopy(self.iset, result.iset))
279        return result
280
281    def load(self, Viewer viewer) -> Self:
282        """Load a stored index set.
283
284        Collective.
285
286        Parameters
287        ----------
288        viewer
289            Binary file viewer, either `Viewer.Type.BINARY` or `Viewer.Type.HDF5`.
290
291        See Also
292        --------
293        petsc.ISLoad
294
295        """
296        cdef MPI_Comm comm = MPI_COMM_NULL
297        cdef PetscObject obj = <PetscObject>(viewer.vwr)
298        if self.iset == NULL:
299            CHKERR(PetscObjectGetComm(obj, &comm))
300            CHKERR(ISCreate(comm, &self.iset))
301        CHKERR(ISLoad(self.iset, viewer.vwr))
302        return self
303
304    def allGather(self) -> IS:
305        """Concatenate index sets stored across processors.
306
307        Collective.
308
309        The returned index set will be the same on every processor.
310
311        See Also
312        --------
313        petsc.ISAllGather
314
315        """
316        cdef IS iset = IS()
317        CHKERR(ISAllGather(self.iset, &iset.iset))
318        return iset
319
320    def toGeneral(self) -> Self:
321        """Convert the index set type to `IS.Type.GENERAL`.
322
323        Collective.
324
325        See Also
326        --------
327        petsc.ISToGeneral, petsc.ISType
328
329        """
330        CHKERR(ISToGeneral(self.iset))
331        return self
332
333    def buildTwoSided(self, IS toindx=None) -> IS:
334        """Create an index set describing a global mapping.
335
336        Collective.
337
338        This function generates an index set that contains new numbers from
339        remote or local on the index set.
340
341        Parameters
342        ----------
343        toindx
344            Index set describing which indices to send, default is to send
345            natural numbering.
346
347        Returns
348        -------
349        IS
350            New index set containing the new numbers from remote or local.
351
352        See Also
353        --------
354        petsc.ISBuildTwoSided
355
356        """
357        cdef PetscIS ctoindx = NULL
358        if toindx is not None: ctoindx = toindx.iset
359        cdef IS result = IS()
360        CHKERR(ISBuildTwoSided(self.iset, ctoindx, &result.iset))
361        return result
362
363    def invertPermutation(self, nlocal: int | None = None) -> IS:
364        """Invert the index set.
365
366        Collective.
367
368        For this to be correct the index set must be a permutation.
369
370        Parameters
371        ----------
372        nlocal
373            The number of indices on this processor in the resulting index set,
374            defaults to ``PETSC_DECIDE``.
375
376        See Also
377        --------
378        petsc.ISInvertPermutation
379
380        """
381        cdef PetscInt cnlocal = PETSC_DECIDE
382        if nlocal is not None: cnlocal = asInt(nlocal)
383        cdef IS iset = IS()
384        CHKERR(ISInvertPermutation(self.iset, cnlocal, &iset.iset))
385        return iset
386
387    def partitioningToNumbering(self) -> IS:
388        """Return the new global numbering after a partitioning.
389
390        Collective.
391
392        Assuming that the index set represents a partitioning, generate another
393        index set with the new global node number in the new ordering.
394
395        See Also
396        --------
397        petsc.ISPartitioningToNumbering
398
399        """
400        cdef IS iset = IS()
401        CHKERR(ISPartitioningToNumbering(self.iset, &iset.iset))
402        return iset
403
404    def partitioningCount(self, npart: int | None = None) -> ArrayInt:
405        """Return the number of elements per process after a partitioning.
406
407        Collective.
408
409        Assuming that the index set represents a partitioning, determine the
410        number of elements on each (partition) rank.
411
412        Parameters
413        ----------
414        npart
415            The number of partitions,
416            defaults to the size of the communicator.
417
418        See Also
419        --------
420        petsc.ISPartitioningCount
421
422        """
423        cdef PetscInt size
424        if npart is None: size = getCommSize(self.iset)
425        else: size = asInt(npart)
426        cdef PetscInt *counts = NULL
427        CHKERR(PetscMalloc(<size_t>size*sizeof(PetscInt), &counts))
428        CHKERR(ISPartitioningCount(self.iset, size, counts))
429        cdef object ocounts = None
430        try:
431            ocounts = array_i(size, counts)
432        finally:
433            CHKERR(PetscFree(counts))
434        return ocounts
435
436    def getSize(self) -> int:
437        """Return the global length of an index set.
438
439        Not collective.
440
441        See Also
442        --------
443        petsc.ISGetSize
444
445        """
446        cdef PetscInt N = 0
447        CHKERR(ISGetSize(self.iset, &N))
448        return toInt(N)
449
450    def getLocalSize(self) -> int:
451        """Return the process-local length of the index set.
452
453        Not collective.
454
455        See Also
456        --------
457        petsc.ISGetLocalSize
458
459        """
460        cdef PetscInt n = 0
461        CHKERR(ISGetLocalSize(self.iset, &n))
462        return toInt(n)
463
464    def getSizes(self) -> tuple[int, int]:
465        """Return the local and global sizes of the index set.
466
467        Not collective.
468
469        Returns
470        -------
471        local_size : int
472            The local size.
473        global_size : int
474            The global size.
475
476        See Also
477        --------
478        IS.getLocalSize, IS.getSize
479
480        """
481        cdef PetscInt n = 0, N = 0
482        CHKERR(ISGetLocalSize(self.iset, &n))
483        CHKERR(ISGetSize(self.iset, &N))
484        return (toInt(n), toInt(N))
485
486    def getBlockSize(self) -> int:
487        """Return the number of elements in a block.
488
489        Not collective.
490
491        See Also
492        --------
493        petsc.ISGetBlockSize
494
495        """
496        cdef PetscInt bs = 1
497        CHKERR(ISGetBlockSize(self.iset, &bs))
498        return toInt(bs)
499
500    def setBlockSize(self, bs: int) -> None:
501        """Set the block size of the index set.
502
503        Logically collective.
504
505        Parameters
506        ----------
507        bs
508            Block size.
509
510        See Also
511        --------
512        petsc.ISSetBlockSize
513
514        """
515        cdef PetscInt cbs = asInt(bs)
516        CHKERR(ISSetBlockSize(self.iset, cbs))
517
518    def sort(self) -> Self:
519        """Sort the indices of an index set.
520
521        Collective.
522
523        See Also
524        --------
525        petsc.ISSort
526
527        """
528        CHKERR(ISSort(self.iset))
529        return self
530
531    def isSorted(self) -> bool:
532        """Return whether the indices have been sorted.
533
534        Collective.
535
536        See Also
537        --------
538        petsc.ISSorted
539
540        """
541        cdef PetscBool flag = PETSC_FALSE
542        CHKERR(ISSorted(self.iset, &flag))
543        return toBool(flag)
544
545    def setPermutation(self) -> Self:
546        """Mark the index set as being a permutation.
547
548        Logically collective.
549
550        See Also
551        --------
552        petsc.ISSetPermutation
553
554        """
555        CHKERR(ISSetPermutation(self.iset))
556        return self
557
558    def isPermutation(self) -> bool:
559        """Return whether an index set has been declared to be a permutation.
560
561        Logically collective.
562
563        See Also
564        --------
565        petsc.ISPermutation
566
567        """
568        cdef PetscBool flag = PETSC_FALSE
569        CHKERR(ISPermutation(self.iset, &flag))
570        return toBool(flag)
571
572    def setIdentity(self) -> Self:
573        """Mark the index set as being an identity.
574
575        Logically collective.
576
577        See Also
578        --------
579        petsc.ISSetIdentity
580
581        """
582        CHKERR(ISSetIdentity(self.iset))
583        return self
584
585    def isIdentity(self) -> bool:
586        """Return whether the index set has been declared as an identity.
587
588        Collective.
589
590        See Also
591        --------
592        petsc.ISIdentity
593
594        """
595        cdef PetscBool flag = PETSC_FALSE
596        CHKERR(ISIdentity(self.iset, &flag))
597        return toBool(flag)
598
599    def equal(self, IS iset) -> bool:
600        """Return whether the index sets have the same set of indices or not.
601
602        Collective.
603
604        Parameters
605        ----------
606        iset
607            The index set to compare indices with.
608
609        See Also
610        --------
611        petsc.ISEqual
612
613        """
614        cdef PetscBool flag = PETSC_FALSE
615        CHKERR(ISEqual(self.iset, iset.iset, &flag))
616        return toBool(flag)
617
618    def sum(self, IS iset) -> IS:
619        """Return the union of two (sorted) index sets.
620
621        Collective.
622
623        Parameters
624        ----------
625        iset
626            The index set to compute the union with.
627
628        See Also
629        --------
630        petsc.ISSum
631
632        """
633        cdef IS out = IS()
634        CHKERR(ISSum(self.iset, iset.iset, &out.iset))
635        return out
636
637    def expand(self, IS iset) -> IS:
638        """Return the union of two (possibly unsorted) index sets.
639
640        Collective.
641
642        To compute the union, `expand` concatenates the two index sets
643        and removes any duplicates.
644
645        Parameters
646        ----------
647        iset
648            Index set to compute the union with.
649
650        Returns
651        -------
652        IS
653            The new, combined, index set.
654
655        See Also
656        --------
657        petsc.ISExpand
658
659        """
660        cdef IS out = IS()
661        CHKERR(ISExpand(self.iset, iset.iset, &out.iset))
662        return out
663
664    def union(self, IS iset) -> IS:
665        """Return the union of two (possibly unsorted) index sets.
666
667        Collective.
668
669        This function will call either `petsc.ISSum` or `petsc.ISExpand` depending
670        on whether or not the input sets are already sorted.
671
672        Sequential only (as `petsc.ISSum` is sequential only).
673
674        Parameters
675        ----------
676        iset
677            Index set to compute the union with.
678
679        Returns
680        -------
681        IS
682            The new, combined, index set.
683
684        See Also
685        --------
686        IS.expand, IS.sum
687
688        """
689        cdef PetscBool flag1=PETSC_FALSE, flag2=PETSC_FALSE
690        CHKERR(ISSorted(self.iset, &flag1))
691        CHKERR(ISSorted(iset.iset, &flag2))
692        cdef IS out = IS()
693        if flag1==PETSC_TRUE and flag2==PETSC_TRUE:
694            CHKERR(ISSum(self.iset, iset.iset, &out.iset))
695        else:
696            CHKERR(ISExpand(self.iset, iset.iset, &out.iset))
697        return out
698
699    def difference(self, IS iset: IS) -> IS:
700        """Return the difference between two index sets.
701
702        Collective.
703
704        Parameters
705        ----------
706        iset
707            Index set to compute the difference with.
708
709        Returns
710        -------
711        IS
712            Index set representing the difference between ``self`` and ``iset``.
713
714        See Also
715        --------
716        petsc.ISDifference
717
718        """
719        cdef IS out = IS()
720        CHKERR(ISDifference(self.iset, iset.iset, &out.iset))
721        return out
722
723    def complement(self, nmin: int, nmax: int) -> IS:
724        """Create a complement index set.
725
726        Collective.
727
728        The complement set of indices is all indices that are not
729        in the provided set (and within the provided bounds).
730
731        Parameters
732        ----------
733        nmin
734            Minimum index that can be found in the local part of the complement
735            index set.
736        nmax
737            One greater than the maximum index that can be found in the local
738            part of the complement index set.
739
740        Notes
741        -----
742        For a parallel index set, this will generate the local part of the
743        complement on each process.
744
745        To generate the entire complement (on each process) of a parallel
746        index set, first call `IS.allGather` and then call this method.
747
748        See Also
749        --------
750        IS.allGather, petsc.ISComplement
751
752        """
753        cdef PetscInt cnmin = asInt(nmin)
754        cdef PetscInt cnmax = asInt(nmax)
755        cdef IS out = IS()
756        CHKERR(ISComplement(self.iset, cnmin, cnmax, &out.iset))
757        return out
758
759    def embed(self, IS iset, drop: bool) -> IS:
760        """Embed ``self`` into ``iset``.
761
762        Not collective.
763
764        The embedding is performed by finding the locations in ``iset`` that
765        have the same indices as ``self``.
766
767        Parameters
768        ----------
769        iset
770            The index set to embed into.
771        drop
772            Flag indicating whether to drop indices from ``self`` that are not
773            in ``iset``.
774
775        Returns
776        -------
777        IS
778            The embedded index set.
779
780        See Also
781        --------
782        petsc.ISEmbed
783
784        """
785        cdef PetscBool bval = drop
786        cdef IS out = IS()
787        CHKERR(ISEmbed(self.iset, iset.iset, bval, &out.iset))
788        return out
789
790    def renumber(self, IS mult=None) -> tuple[int, IS]:
791        """Renumber the non-negative entries of an index set, starting from 0.
792
793        Collective.
794
795        Parameters
796        ----------
797        mult
798            The multiplicity of each entry in ``self``, default implies a
799            multiplicity of 1.
800
801        Returns
802        -------
803        int
804            One past the largest entry of the new index set.
805        IS
806            The renumbered index set.
807
808        See Also
809        --------
810        petsc.ISRenumber
811
812        """
813        cdef PetscIS mlt = NULL
814        if mult is not None: mlt = mult.iset
815        cdef IS out = IS()
816        cdef PetscInt n = 0
817        CHKERR(ISRenumber(self.iset, mlt, &n, &out.iset))
818        return (toInt(n), out)
819    #
820
821    def setIndices(self, indices: Sequence[int]) -> None:
822        """Set the indices of an index set.
823
824        Logically collective.
825
826        The index set is assumed to be of type `IS.Type.GENERAL`.
827
828        See Also
829        --------
830        petsc.ISGeneralSetIndices
831
832        """
833        cdef PetscInt nidx = 0, *idx = NULL
834        cdef PetscCopyMode cm = PETSC_COPY_VALUES
835        indices = iarray_i(indices, &nidx, &idx)
836        CHKERR(ISGeneralSetIndices(self.iset, nidx, idx, cm))
837
838    def getIndices(self) -> ArrayInt:
839        """Return the indices of the index set.
840
841        Not collective.
842
843        See Also
844        --------
845        petsc.ISGetIndices
846
847        """
848        cdef PetscInt size = 0
849        cdef const PetscInt *indices = NULL
850        CHKERR(ISGetLocalSize(self.iset, &size))
851        CHKERR(ISGetIndices(self.iset, &indices))
852        cdef object oindices = None
853        try:
854            oindices = array_i(size, indices)
855        finally:
856            CHKERR(ISRestoreIndices(self.iset, &indices))
857        return oindices
858
859    def setBlockIndices(self, bsize: int, indices: Sequence[int]) -> None:
860        """Set the indices for an index set with type `IS.Type.BLOCK`.
861
862        Collective.
863
864        Parameters
865        ----------
866        bsize
867            Number of elements in each block.
868        indices
869            List of integers.
870
871        See Also
872        --------
873        petsc.ISBlockSetIndices
874
875        """
876        cdef PetscInt bs = asInt(bsize)
877        cdef PetscInt nidx = 0, *idx = NULL
878        cdef PetscCopyMode cm = PETSC_COPY_VALUES
879        indices = iarray_i(indices, &nidx, &idx)
880        CHKERR(ISBlockSetIndices(self.iset, bs, nidx, idx, cm))
881
882    def getBlockIndices(self) -> ArrayInt:
883        """Return the indices of an index set with type `IS.Type.BLOCK`.
884
885        Not collective.
886
887        See Also
888        --------
889        petsc.ISBlockGetIndices
890
891        """
892        cdef PetscInt size = 0, bs = 1
893        cdef const PetscInt *indices = NULL
894        CHKERR(ISGetLocalSize(self.iset, &size))
895        CHKERR(ISGetBlockSize(self.iset, &bs))
896        CHKERR(ISBlockGetIndices(self.iset, &indices))
897        cdef object oindices = None
898        try:
899            oindices = array_i(size//bs, indices)
900        finally:
901            CHKERR(ISBlockRestoreIndices(self.iset, &indices))
902        return oindices
903
904    def setStride(self, size: int, first: int = 0, step: int = 1) -> None:
905        """Set the stride information for an index set with type `IS.Type.STRIDE`.
906
907        Logically collective.
908
909        Parameters
910        ----------
911        size
912            Length of the locally owned portion of the index set.
913        first
914            First element of the index set.
915        step
916            Difference between adjacent indices.
917
918        See Also
919        --------
920        petsc.ISStrideSetStride
921
922        """
923        cdef PetscInt csize = asInt(size)
924        cdef PetscInt cfirst = asInt(first)
925        cdef PetscInt cstep = asInt(step)
926        CHKERR(ISStrideSetStride(self.iset, csize, cfirst, cstep))
927
928    def getStride(self) -> tuple[int, int, int]:
929        """Return size and stride information.
930
931        Not collective.
932
933        Returns
934        -------
935        size : int
936            Length of the locally owned portion of the index set.
937        first : int
938            First element of the index set.
939        step : int
940            Difference between adjacent indices.
941
942        See Also
943        --------
944        petsc.ISGetLocalSize, petsc.ISStrideGetInfo
945
946        """
947        cdef PetscInt size=0, first=0, step=0
948        CHKERR(ISGetLocalSize(self.iset, &size))
949        CHKERR(ISStrideGetInfo(self.iset, &first, &step))
950        return (toInt(size), toInt(first), toInt(step))
951
952    def getInfo(self) -> tuple[int, int]:
953        """Return stride information for an index set with type `IS.Type.STRIDE`.
954
955        Not collective.
956
957        Returns
958        -------
959        first : int
960            First element of the index set.
961        step : int
962            Difference between adjacent indices.
963
964        See Also
965        --------
966        IS.getStride, petsc.ISStrideGetInfo
967
968        """
969        cdef PetscInt first = 0, step = 0
970        CHKERR(ISStrideGetInfo(self.iset, &first, &step))
971        return (toInt(first), toInt(step))
972
973    #
974
975    property permutation:
976        """`True` if index set is a permutation, `False` otherwise.
977
978        Logically collective.
979
980        See Also
981        --------
982        IS.isPermutation
983
984        """
985        def __get__(self) -> bool:
986            return self.isPermutation()
987
988    property identity:
989        """`True` if index set is an identity, `False` otherwise.
990
991        Collective.
992
993        See Also
994        --------
995        IS.isIdentity
996
997        """
998        def __get__(self) -> bool:
999            return self.isIdentity()
1000
1001    property sorted:
1002        """`True` if index set is sorted, `False` otherwise.
1003
1004        Collective.
1005
1006        See Also
1007        --------
1008        IS.isSorted
1009
1010        """
1011        def __get__(self) -> bool:
1012            return self.isSorted()
1013
1014    #
1015
1016    property sizes:
1017        """The local and global sizes of the index set.
1018
1019        Not collective.
1020
1021        See Also
1022        --------
1023        IS.getSizes
1024
1025        """
1026        def __get__(self) -> tuple[int, int]:
1027            return self.getSizes()
1028
1029    property size:
1030        """The global size of the index set.
1031
1032        Not collective.
1033
1034        See Also
1035        --------
1036        IS.getSize
1037
1038        """
1039        def __get__(self) -> int:
1040            return self.getSize()
1041
1042    property local_size:
1043        """The local size of the index set.
1044
1045        Not collective.
1046
1047        See Also
1048        --------
1049        IS.getLocalSize
1050
1051        """
1052        def __get__(self) -> int:
1053            return self.getLocalSize()
1054
1055    property block_size:
1056        """The number of elements in a block.
1057
1058        Not collective.
1059
1060        See Also
1061        --------
1062        IS.getBlockSize
1063
1064        """
1065        def __get__(self) -> int:
1066            return self.getBlockSize()
1067
1068    property indices:
1069        """The indices of the index set.
1070
1071        Not collective.
1072
1073        See Also
1074        --------
1075        IS.getIndices
1076
1077        """
1078        def __get__(self) -> ArrayInt:
1079            return self.getIndices()
1080
1081    property array:
1082        """View of the index set as an array of integers.
1083
1084        Not collective.
1085
1086        """
1087        def __get__(self) -> ArrayInt:
1088            return asarray(self)
1089
1090    # --- NumPy array interface (legacy) ---
1091
1092    property __array_interface__:
1093        def __get__(self):
1094            cdef _IS_buffer buf = _IS_buffer(self)
1095            return buf.__array_interface__
1096
1097# --------------------------------------------------------------------
1098
1099
1100class LGMapMapMode(object):
1101    """Enum describing mapping behavior when global indices are missing.
1102
1103    MASK
1104        Give missing global indices a local index of -1.
1105    DROP
1106        Drop missing global indices.
1107
1108    See Also
1109    --------
1110    petsc.ISGlobalToLocalMappingMode
1111
1112    """
1113    MASK = PETSC_IS_GTOLM_MASK
1114    DROP = PETSC_IS_GTOLM_DROP
1115
1116
1117class LGMapType(object):
1118    """Local to global map types."""
1119    BASIC = S_(ISLOCALTOGLOBALMAPPINGBASIC)
1120    HASH  = S_(ISLOCALTOGLOBALMAPPINGHASH)
1121
1122
1123# --------------------------------------------------------------------
1124
1125cdef class LGMap(Object):
1126    """Mapping from a local to a global ordering.
1127
1128    See Also
1129    --------
1130    petsc.ISLocalToGlobalMapping
1131
1132    """
1133
1134    MapMode = LGMapMapMode
1135
1136    Type = LGMapType
1137    #
1138
1139    def __cinit__(self) -> None:
1140        self.obj = <PetscObject*> &self.lgm
1141        self.lgm = NULL
1142
1143    def __call__(
1144        self,
1145        indices: Sequence[int],
1146        result: ArrayInt | None = None) -> None:
1147        """Convert a locally numbered list of integers to a global numbering.
1148
1149        Not collective.
1150
1151        Parameters
1152        ----------
1153        indices
1154            Input indices in local numbering.
1155        result
1156            Array to write the global numbering to. If `None` then a
1157            new array will be allocated.
1158
1159        See Also
1160        --------
1161        IS.apply, petsc.ISLocalToGlobalMappingApply
1162
1163        """
1164        self.apply(indices, result)
1165
1166    #
1167
1168    def setType(self, lgmap_type: LGMap.Type | str) -> None:
1169        """Set the type of the local-to-global map.
1170
1171        Logically collective.
1172
1173        Parameters
1174        ----------
1175        lgmap_type
1176            The type of the local-to-global mapping.
1177
1178        Notes
1179        -----
1180        Use ``-islocaltoglobalmapping_type`` to set the type in the
1181        options database.
1182
1183        See Also
1184        --------
1185        petsc_options, petsc.ISLocalToGlobalMappingSetType
1186
1187        """
1188        cdef PetscISLocalToGlobalMappingType cval = NULL
1189        lgmap_type = str2bytes(lgmap_type, &cval)
1190        CHKERR(ISLocalToGlobalMappingSetType(self.lgm, cval))
1191
1192    def setFromOptions(self) -> None:
1193        """Set mapping options from the options database.
1194
1195        Not collective.
1196
1197        See Also
1198        --------
1199        petsc_options, petsc.ISLocalToGlobalMappingSetFromOptions
1200
1201        """
1202        CHKERR(ISLocalToGlobalMappingSetFromOptions(self.lgm))
1203
1204    def view(self, Viewer viewer=None) -> None:
1205        """View the local-to-global mapping.
1206
1207        Not collective.
1208
1209        Parameters
1210        ----------
1211        viewer
1212            Viewer instance, defaults to an instance of `Viewer.Type.ASCII`.
1213
1214        See Also
1215        --------
1216        load, petsc.ISLocalToGlobalMappingView
1217
1218        """
1219        cdef PetscViewer cviewer = NULL
1220        if viewer is not None: cviewer = viewer.vwr
1221        CHKERR(ISLocalToGlobalMappingView(self.lgm, cviewer))
1222
1223    def load(self, Viewer viewer) -> Self:
1224        """Load a local-to-global mapping.
1225
1226        Collective.
1227
1228        See Also
1229        --------
1230        view, petsc.ISLocalToGlobalMappingLoad
1231
1232        """
1233        cdef MPI_Comm comm = MPI_COMM_NULL
1234        cdef PetscObject obj = <PetscObject>(viewer.vwr)
1235        if self.lgm == NULL:
1236            CHKERR(PetscObjectGetComm(obj, &comm))
1237            CHKERR(ISLocalToGlobalMappingCreate(comm, 1, 0, NULL, PETSC_USE_POINTER, &self.lgm))
1238        CHKERR(ISLocalToGlobalMappingLoad(self.lgm, viewer.vwr))
1239        return self
1240
1241    def destroy(self) -> Self:
1242        """Destroy the local-to-global mapping.
1243
1244        Not collective.
1245
1246        See Also
1247        --------
1248        petsc.ISLocalToGlobalMappingDestroy
1249
1250        """
1251        CHKERR(ISLocalToGlobalMappingDestroy(&self.lgm))
1252        return self
1253
1254    def create(
1255        self,
1256        indices: Sequence[int],
1257        bsize: int | None = None,
1258        comm: Comm | None = None) -> Self:
1259        """Create a local-to-global mapping.
1260
1261        Not collective.
1262
1263        Parameters
1264        ----------
1265        indices
1266            Global index for each local element.
1267        bsize
1268            Block size, defaults to 1.
1269        comm
1270            MPI communicator, defaults to `Sys.getDefaultComm`.
1271
1272        See Also
1273        --------
1274        petsc.ISLocalToGlobalMappingCreate
1275
1276        """
1277        cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_DEFAULT)
1278        cdef PetscInt bs = 1, nidx = 0, *idx = NULL
1279        cdef PetscCopyMode cm = PETSC_COPY_VALUES
1280        cdef PetscLGMap newlgm = NULL
1281        if bsize is not None: bs = asInt(bsize)
1282        if bs == PETSC_DECIDE: bs = 1
1283        indices = iarray_i(indices, &nidx, &idx)
1284        CHKERR(ISLocalToGlobalMappingCreate(
1285                ccomm, bs, nidx, idx, cm, &newlgm))
1286        CHKERR(PetscCLEAR(self.obj)); self.lgm = newlgm
1287        return self
1288
1289    def createIS(self, IS iset) -> Self:
1290        """Create a local-to-global mapping from an index set.
1291
1292        Not collective.
1293
1294        Parameters
1295        ----------
1296        iset
1297            Index set containing the global numbers for each local number.
1298
1299        See Also
1300        --------
1301        petsc.ISLocalToGlobalMappingCreateIS
1302
1303        """
1304        cdef PetscLGMap newlgm = NULL
1305        CHKERR(ISLocalToGlobalMappingCreateIS(
1306            iset.iset, &newlgm))
1307        CHKERR(PetscCLEAR(self.obj)); self.lgm = newlgm
1308        return self
1309
1310    def createSF(self, SF sf, start: int) -> Self:
1311        """Create a local-to-global mapping from a star forest.
1312
1313        Collective.
1314
1315        Parameters
1316        ----------
1317        sf
1318            Star forest mapping contiguous local indices to (rank, offset).
1319        start
1320            First global index on this process.
1321
1322        See Also
1323        --------
1324        petsc.ISLocalToGlobalMappingCreateSF
1325
1326        """
1327        cdef PetscLGMap newlgm = NULL
1328        cdef PetscInt cstart = asInt(start)
1329        CHKERR(ISLocalToGlobalMappingCreateSF(sf.sf, cstart, &newlgm))
1330        CHKERR(PetscCLEAR(self.obj)); self.lgm = newlgm
1331        return self
1332
1333    def getSize(self) -> int:
1334        """Return the local size of the local-to-global mapping.
1335
1336        Not collective.
1337
1338        See Also
1339        --------
1340        petsc.ISLocalToGlobalMappingGetSize
1341
1342        """
1343        cdef PetscInt n = 0
1344        CHKERR(ISLocalToGlobalMappingGetSize(self.lgm, &n))
1345        return toInt(n)
1346
1347    def getBlockSize(self) -> int:
1348        """Return the block size of the local-to-global mapping.
1349
1350        Not collective.
1351
1352        See Also
1353        --------
1354        petsc.ISLocalToGlobalMappingGetBlockSize
1355
1356        """
1357        cdef PetscInt bs = 1
1358        CHKERR(ISLocalToGlobalMappingGetBlockSize(self.lgm, &bs))
1359        return toInt(bs)
1360
1361    def getIndices(self) -> ArrayInt:
1362        """Return the global indices for each local point in the mapping.
1363
1364        Not collective.
1365
1366        See Also
1367        --------
1368        petsc.ISLocalToGlobalMappingGetIndices
1369
1370        """
1371        cdef PetscInt size = 0
1372        cdef const PetscInt *indices = NULL
1373        CHKERR(ISLocalToGlobalMappingGetSize(
1374                self.lgm, &size))
1375        CHKERR(ISLocalToGlobalMappingGetIndices(
1376                self.lgm, &indices))
1377        cdef object oindices = None
1378        try:
1379            oindices = array_i(size, indices)
1380        finally:
1381            CHKERR(ISLocalToGlobalMappingRestoreIndices(
1382                    self.lgm, &indices))
1383        return oindices
1384
1385    def getBlockIndices(self) -> ArrayInt:
1386        """Return the global indices for each local block.
1387
1388        Not collective.
1389
1390        See Also
1391        --------
1392        petsc.ISLocalToGlobalMappingGetBlockIndices
1393
1394        """
1395        cdef PetscInt size = 0, bs = 1
1396        cdef const PetscInt *indices = NULL
1397        CHKERR(ISLocalToGlobalMappingGetSize(
1398                self.lgm, &size))
1399        CHKERR(ISLocalToGlobalMappingGetBlockSize(
1400                self.lgm, &bs))
1401        CHKERR(ISLocalToGlobalMappingGetBlockIndices(
1402                self.lgm, &indices))
1403        cdef object oindices = None
1404        try:
1405            oindices = array_i(size//bs, indices)
1406        finally:
1407            CHKERR(ISLocalToGlobalMappingRestoreBlockIndices(
1408                    self.lgm, &indices))
1409        return oindices
1410
1411    def getInfo(self) -> dict[int, ArrayInt]:
1412        """Determine the indices shared with neighboring processes.
1413
1414        Collective.
1415
1416        Returns
1417        -------
1418        dict
1419            Mapping from neighboring processor number to an array of shared
1420            indices (in local numbering).
1421
1422        See Also
1423        --------
1424        petsc.ISLocalToGlobalMappingGetInfo
1425
1426        """
1427        cdef PetscInt i, nproc = 0, *procs = NULL,
1428        cdef PetscInt *numprocs = NULL, **indices = NULL
1429        cdef dict neighs = {}
1430        CHKERR(ISLocalToGlobalMappingGetInfo(
1431                self.lgm, &nproc, &procs, &numprocs, &indices))
1432        try:
1433            for i from 0 <= i < nproc:
1434                neighs[toInt(procs[i])] = array_i(numprocs[i], indices[i])
1435        finally:
1436            ISLocalToGlobalMappingRestoreInfo(
1437                self.lgm, &nproc, &procs, &numprocs, &indices)
1438        return neighs
1439
1440    def getBlockInfo(self) -> dict[int, ArrayInt]:
1441        """Determine the block indices shared with neighboring processes.
1442
1443        Collective.
1444
1445        Returns
1446        -------
1447        dict
1448            Mapping from neighboring processor number to an array of shared
1449            block indices (in local numbering).
1450
1451        See Also
1452        --------
1453        petsc.ISLocalToGlobalMappingGetBlockInfo
1454
1455        """
1456        cdef PetscInt i, nproc = 0, *procs = NULL,
1457        cdef PetscInt *numprocs = NULL, **indices = NULL
1458        cdef dict neighs = {}
1459        CHKERR(ISLocalToGlobalMappingGetBlockInfo(
1460                self.lgm, &nproc, &procs, &numprocs, &indices))
1461        try:
1462            for i from 0 <= i < nproc:
1463                neighs[toInt(procs[i])] = array_i(numprocs[i], indices[i])
1464        finally:
1465            ISLocalToGlobalMappingRestoreBlockInfo(
1466                self.lgm, &nproc, &procs, &numprocs, &indices)
1467        return neighs
1468
1469    #
1470
1471    def apply(
1472        self,
1473        indices: Sequence[int],
1474        result: ArrayInt | None = None) -> ArrayInt:
1475        """Convert a locally numbered list of integers to a global numbering.
1476
1477        Not collective.
1478
1479        Parameters
1480        ----------
1481        indices
1482            Input indices in local numbering.
1483        result
1484            Array to write the global numbering to. If `None` then a
1485            new array will be allocated.
1486
1487        Returns
1488        -------
1489        ArrayInt
1490            Indices in global numbering. If ``result`` is not `None` then this is
1491            returned here.
1492
1493        See Also
1494        --------
1495        LGMap.applyBlock, petsc.ISLocalToGlobalMappingApply
1496
1497        """
1498        cdef PetscInt niidx = 0, *iidx = NULL
1499        cdef PetscInt noidx = 0, *oidx = NULL
1500        indices = iarray_i(indices, &niidx, &iidx)
1501        if result is None: result = empty_i(niidx)
1502        result  = oarray_i(result,  &noidx, &oidx)
1503        assert niidx == noidx, "incompatible array sizes"
1504        CHKERR(ISLocalToGlobalMappingApply(
1505            self.lgm, niidx, iidx, oidx))
1506        return result
1507
1508    def applyBlock(
1509        self,
1510        indices: Sequence[int],
1511        result: ArrayInt | None = None) -> ArrayInt:
1512        """Convert a local block numbering to a global block numbering.
1513
1514        Not collective.
1515
1516        Parameters
1517        ----------
1518        indices
1519            Input block indices in local numbering.
1520        result
1521            Array to write the global numbering to. If `None` then a
1522            new array will be allocated.
1523
1524        Returns
1525        -------
1526        ArrayInt
1527            Block indices in global numbering. If ``result`` is not `None`
1528            then this is returned here.
1529
1530        See Also
1531        --------
1532        LGMap.apply, petsc.ISLocalToGlobalMappingApplyBlock
1533
1534        """
1535        cdef PetscInt niidx = 0, *iidx = NULL
1536        cdef PetscInt noidx = 0, *oidx = NULL
1537        indices = iarray_i(indices, &niidx, &iidx)
1538        if result is None: result = empty_i(niidx)
1539        result  = oarray_i(result,  &noidx, &oidx)
1540        assert niidx == noidx, "incompatible array sizes"
1541        CHKERR(ISLocalToGlobalMappingApplyBlock(
1542            self.lgm, niidx, iidx, oidx))
1543        return result
1544
1545    def applyIS(self, IS iset) -> IS:
1546        """Create an index set with global numbering from a local numbering.
1547
1548        Collective.
1549
1550        Parameters
1551        ----------
1552        iset
1553            Index set with local numbering.
1554
1555        Returns
1556        -------
1557        IS
1558            Index set with global numbering.
1559
1560        See Also
1561        --------
1562        petsc.ISLocalToGlobalMappingApplyIS
1563
1564        """
1565        cdef IS result = IS()
1566        CHKERR(ISLocalToGlobalMappingApplyIS(
1567            self.lgm, iset.iset, &result.iset))
1568        return result
1569
1570    def applyInverse(
1571        self,
1572        indices: Sequence[int],
1573        mode: LGMap.MapMode | str | None = None) -> ArrayInt:
1574        """Compute local numbering from global numbering.
1575
1576        Not collective.
1577
1578        Parameters
1579        ----------
1580        indices
1581            Indices with a global numbering.
1582        mode
1583            Flag indicating what to do with indices that have no local value,
1584            defaults to ``"mask"``.
1585
1586        Returns
1587        -------
1588        ArrayInt
1589            Indices with a local numbering.
1590
1591        See Also
1592        --------
1593        petsc.ISGlobalToLocalMappingApply
1594
1595        """
1596        cdef PetscGLMapMode cmode = PETSC_IS_GTOLM_MASK
1597        if mode is not None: cmode = mode
1598        cdef PetscInt n = 0, *idx = NULL
1599        indices = iarray_i(indices, &n, &idx)
1600        cdef PetscInt nout = n, *idxout = NULL
1601        if cmode != PETSC_IS_GTOLM_MASK:
1602            CHKERR(ISGlobalToLocalMappingApply(
1603                    self.lgm, cmode, n, idx, &nout, NULL))
1604        result = oarray_i(empty_i(nout), &nout, &idxout)
1605        CHKERR(ISGlobalToLocalMappingApply(
1606                self.lgm, cmode, n, idx, &nout, idxout))
1607        return result
1608
1609    def applyBlockInverse(
1610        self,
1611        indices: Sequence[int],
1612        mode: LGMap.MapMode | str | None = None) -> ArrayInt:
1613        """Compute blocked local numbering from blocked global numbering.
1614
1615        Not collective.
1616
1617        Parameters
1618        ----------
1619        indices
1620            Indices with a global block numbering.
1621        mode
1622            Flag indicating what to do with indices that have no local value,
1623            defaults to ``"mask"``.
1624
1625        Returns
1626        -------
1627        ArrayInt
1628            Indices with a local block numbering.
1629
1630        See Also
1631        --------
1632        petsc.ISGlobalToLocalMappingApplyBlock
1633
1634        """
1635        cdef PetscGLMapMode cmode = PETSC_IS_GTOLM_MASK
1636        if mode is not None: cmode = mode
1637        cdef PetscInt n = 0, *idx = NULL
1638        indices = iarray_i(indices, &n, &idx)
1639        cdef PetscInt nout = n, *idxout = NULL
1640        if cmode != PETSC_IS_GTOLM_MASK:
1641            CHKERR(ISGlobalToLocalMappingApply(
1642                    self.lgm, cmode, n, idx, &nout, NULL))
1643        result = oarray_i(empty_i(nout), &nout, &idxout)
1644        CHKERR(ISGlobalToLocalMappingApplyBlock(
1645                self.lgm, cmode, n, idx, &nout, idxout))
1646        return result
1647    #
1648
1649    property size:
1650        """The local size.
1651
1652        Not collective.
1653
1654        See Also
1655        --------
1656        LGMap.getSize
1657
1658        """
1659        def __get__(self) -> int:
1660            return self.getSize()
1661
1662    property block_size:
1663        """The block size.
1664
1665        Not collective.
1666
1667        See Also
1668        --------
1669        LGMap.getBlockSize
1670
1671        """
1672        def __get__(self) -> int:
1673            return self.getBlockSize()
1674
1675    property indices:
1676        """The global indices for each local point in the mapping.
1677
1678        Not collective.
1679
1680        See Also
1681        --------
1682        LGMap.getIndices, petsc.ISLocalToGlobalMappingGetIndices
1683
1684        """
1685        def __get__(self) -> ArrayInt:
1686            return self.getIndices()
1687
1688    property block_indices:
1689        """The global indices for each local block in the mapping.
1690
1691        Not collective.
1692
1693        See Also
1694        --------
1695        LGMap.getBlockIndices, petsc.ISLocalToGlobalMappingGetBlockIndices
1696
1697        """
1698        def __get__(self) -> ArrayInt:
1699            return self.getBlockIndices()
1700
1701    property info:
1702        """Mapping describing indices shared with neighboring processes.
1703
1704        Collective.
1705
1706        See Also
1707        --------
1708        LGMap.getInfo, petsc.ISLocalToGlobalMappingGetInfo
1709
1710        """
1711        def __get__(self) -> dict[int, ArrayInt]:
1712            return self.getInfo()
1713
1714    property block_info:
1715        """Mapping describing block indices shared with neighboring processes.
1716
1717        Collective.
1718
1719        See Also
1720        --------
1721        LGMap.getBlockInfo, petsc.ISLocalToGlobalMappingGetBlockInfo
1722
1723        """
1724        def __get__(self) -> dict[int, ArrayInt]:
1725            return self.getBlockInfo()
1726
1727# --------------------------------------------------------------------
1728
1729del ISType
1730del LGMapMapMode
1731del LGMapType
1732# --------------------------------------------------------------------
1733