xref: /petsc/src/vec/is/is/interface/index.c (revision 5a884c48ab0c46bab83cd9bb8710f380fa6d8bcf)
1 /*
2    Defines the abstract operations on index sets, i.e. the public interface.
3 */
4 #include <petsc/private/isimpl.h> /*I "petscis.h" I*/
5 #include <petscviewer.h>
6 #include <petscsf.h>
7 
8 /* Logging support */
9 PetscClassId IS_CLASSID;
10 /* TODO: Much more events are missing! */
11 PetscLogEvent IS_View;
12 PetscLogEvent IS_Load;
13 
14 /*@
15   ISRenumber - Renumbers the non-negative entries of an index set in a contiguous way, starting from 0.
16 
17   Collective
18 
19   Input Parameters:
20 + subset      - the index set
21 - subset_mult - the multiplicity of each entry in subset (optional, can be `NULL`)
22 
23   Output Parameters:
24 + N        - one past the largest entry of the new `IS`
25 - subset_n - the new `IS`
26 
27   Level: intermediate
28 
29   Note:
30   All negative entries are mapped to -1. Indices with non positive multiplicities are skipped.
31 
32 .seealso: `IS`
33 @*/
ISRenumber(IS subset,IS subset_mult,PetscInt * N,IS * subset_n)34 PetscErrorCode ISRenumber(IS subset, IS subset_mult, PetscInt *N, IS *subset_n)
35 {
36   PetscSF         sf;
37   PetscLayout     map;
38   const PetscInt *idxs, *idxs_mult = NULL;
39   PetscInt       *leaf_data, *root_data, *gidxs, *ilocal, *ilocalneg;
40   PetscInt        N_n, n, i, lbounds[2], gbounds[2], Nl, ibs;
41   PetscInt        n_n, nlocals, start, first_index, npos, nneg;
42   PetscMPIInt     commsize;
43   PetscBool       first_found, isblock;
44 
45   PetscFunctionBegin;
46   PetscValidHeaderSpecific(subset, IS_CLASSID, 1);
47   if (subset_mult) PetscValidHeaderSpecific(subset_mult, IS_CLASSID, 2);
48   if (N) PetscAssertPointer(N, 3);
49   else if (!subset_n) PetscFunctionReturn(PETSC_SUCCESS);
50   PetscCall(ISGetLocalSize(subset, &n));
51   if (subset_mult) {
52     PetscCall(ISGetLocalSize(subset_mult, &i));
53     PetscCheck(i == n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local subset and multiplicity sizes don't match! %" PetscInt_FMT " != %" PetscInt_FMT, n, i);
54   }
55   /* create workspace layout for computing global indices of subset */
56   PetscCall(PetscMalloc1(n, &ilocal));
57   PetscCall(PetscMalloc1(n, &ilocalneg));
58   PetscCall(ISGetIndices(subset, &idxs));
59   PetscCall(ISGetBlockSize(subset, &ibs));
60   PetscCall(PetscObjectTypeCompare((PetscObject)subset, ISBLOCK, &isblock));
61   if (subset_mult) PetscCall(ISGetIndices(subset_mult, &idxs_mult));
62   lbounds[0] = PETSC_INT_MAX;
63   lbounds[1] = PETSC_INT_MIN;
64   for (i = 0, npos = 0, nneg = 0; i < n; i++) {
65     if (idxs[i] < 0) {
66       ilocalneg[nneg++] = i;
67       continue;
68     }
69     if (idxs[i] < lbounds[0]) lbounds[0] = idxs[i];
70     if (idxs[i] > lbounds[1]) lbounds[1] = idxs[i];
71     ilocal[npos++] = i;
72   }
73   if (npos == n) {
74     PetscCall(PetscFree(ilocal));
75     PetscCall(PetscFree(ilocalneg));
76   }
77 
78   /* create sf : leaf_data == multiplicity of indexes, root data == global index in layout */
79   PetscCall(PetscMalloc1(n, &leaf_data));
80   for (i = 0; i < n; i++) leaf_data[i] = idxs_mult ? PetscMax(idxs_mult[i], 0) : 1;
81 
82   /* local size of new subset */
83   n_n = 0;
84   for (i = 0; i < n; i++) n_n += leaf_data[i];
85   if (ilocalneg)
86     for (i = 0; i < nneg; i++) leaf_data[ilocalneg[i]] = 0;
87   PetscCall(PetscFree(ilocalneg));
88   PetscCall(PetscMalloc1(PetscMax(n_n, n), &gidxs)); /* allocating extra space to reuse gidxs */
89   /* check for early termination (all negative) */
90   PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)subset), lbounds, gbounds));
91   if (gbounds[1] < gbounds[0]) {
92     if (N) *N = 0;
93     if (subset_n) { /* all negative */
94       for (i = 0; i < n_n; i++) gidxs[i] = -1;
95       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)subset), n_n, gidxs, PETSC_COPY_VALUES, subset_n));
96     }
97     PetscCall(PetscFree(leaf_data));
98     PetscCall(PetscFree(gidxs));
99     PetscCall(ISRestoreIndices(subset, &idxs));
100     if (subset_mult) PetscCall(ISRestoreIndices(subset_mult, &idxs_mult));
101     PetscCall(PetscFree(ilocal));
102     PetscCall(PetscFree(ilocalneg));
103     PetscFunctionReturn(PETSC_SUCCESS);
104   }
105 
106   /* split work */
107   N_n = gbounds[1] - gbounds[0] + 1;
108   PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)subset), &map));
109   PetscCall(PetscLayoutSetBlockSize(map, 1));
110   PetscCall(PetscLayoutSetSize(map, N_n));
111   PetscCall(PetscLayoutSetUp(map));
112   PetscCall(PetscLayoutGetLocalSize(map, &Nl));
113 
114   /* global indexes in layout */
115   for (i = 0; i < npos; i++) gidxs[i] = (ilocal ? idxs[ilocal[i]] : idxs[i]) - gbounds[0];
116   PetscCall(ISRestoreIndices(subset, &idxs));
117   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)subset), &sf));
118   PetscCall(PetscSFSetGraphLayout(sf, map, npos, ilocal, PETSC_USE_POINTER, gidxs));
119   PetscCall(PetscLayoutDestroy(&map));
120 
121   /* reduce from leaves to roots */
122   PetscCall(PetscCalloc1(Nl, &root_data));
123   PetscCall(PetscSFReduceBegin(sf, MPIU_INT, leaf_data, root_data, MPI_MAX));
124   PetscCall(PetscSFReduceEnd(sf, MPIU_INT, leaf_data, root_data, MPI_MAX));
125 
126   /* count indexes in local part of layout */
127   nlocals     = 0;
128   first_index = -1;
129   first_found = PETSC_FALSE;
130   for (i = 0; i < Nl; i++) {
131     if (!first_found && root_data[i]) {
132       first_found = PETSC_TRUE;
133       first_index = i;
134     }
135     nlocals += root_data[i];
136   }
137 
138   /* cumulative of number of indexes and size of subset without holes */
139 #if defined(PETSC_HAVE_MPI_EXSCAN)
140   start = 0;
141   PetscCallMPI(MPI_Exscan(&nlocals, &start, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)subset)));
142 #else
143   PetscCallMPI(MPI_Scan(&nlocals, &start, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)subset)));
144   start = start - nlocals;
145 #endif
146 
147   if (N) { /* compute total size of new subset if requested */
148     *N = start + nlocals;
149     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)subset), &commsize));
150     PetscCallMPI(MPI_Bcast(N, 1, MPIU_INT, commsize - 1, PetscObjectComm((PetscObject)subset)));
151   }
152 
153   if (!subset_n) {
154     PetscCall(PetscFree(gidxs));
155     PetscCall(PetscSFDestroy(&sf));
156     PetscCall(PetscFree(leaf_data));
157     PetscCall(PetscFree(root_data));
158     PetscCall(PetscFree(ilocal));
159     if (subset_mult) PetscCall(ISRestoreIndices(subset_mult, &idxs_mult));
160     PetscFunctionReturn(PETSC_SUCCESS);
161   }
162 
163   /* adapt root data with cumulative */
164   if (first_found) {
165     PetscInt old_index;
166 
167     root_data[first_index] += start;
168     old_index = first_index;
169     for (i = first_index + 1; i < Nl; i++) {
170       if (root_data[i]) {
171         root_data[i] += root_data[old_index];
172         old_index = i;
173       }
174     }
175   }
176 
177   /* from roots to leaves */
178   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, root_data, leaf_data, MPI_REPLACE));
179   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, root_data, leaf_data, MPI_REPLACE));
180   PetscCall(PetscSFDestroy(&sf));
181 
182   /* create new IS with global indexes without holes */
183   for (i = 0; i < n_n; i++) gidxs[i] = -1;
184   if (subset_mult) {
185     PetscInt cum;
186 
187     isblock = PETSC_FALSE;
188     for (i = 0, cum = 0; i < n; i++)
189       for (PetscInt j = 0; j < idxs_mult[i]; j++) gidxs[cum++] = leaf_data[i] - idxs_mult[i] + j;
190   } else
191     for (i = 0; i < n; i++) gidxs[i] = leaf_data[i] - 1;
192 
193   if (isblock) {
194     if (ibs > 1)
195       for (i = 0; i < n_n / ibs; i++) gidxs[i] = gidxs[i * ibs] / ibs;
196     PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)subset), ibs, n_n / ibs, gidxs, PETSC_COPY_VALUES, subset_n));
197   } else {
198     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)subset), n_n, gidxs, PETSC_COPY_VALUES, subset_n));
199   }
200   if (subset_mult) PetscCall(ISRestoreIndices(subset_mult, &idxs_mult));
201   PetscCall(PetscFree(gidxs));
202   PetscCall(PetscFree(leaf_data));
203   PetscCall(PetscFree(root_data));
204   PetscCall(PetscFree(ilocal));
205   PetscFunctionReturn(PETSC_SUCCESS);
206 }
207 
208 /*@
209   ISCreateSubIS - Create a sub index set from a global index set selecting some components.
210 
211   Collective
212 
213   Input Parameters:
214 + is    - the index set
215 - comps - which components we will extract from `is`
216 
217   Output Parameters:
218 . subis - the new sub index set
219 
220   Example usage:
221   We have an index set `is` living on 3 processes with the following values\:
222   | 4 9 0 | 2 6 7 | 10 11 1|
223   and another index set `comps` used to indicate which components of is  we want to take,
224   | 7 5  | 1 2 | 0 4|
225   The output index set `subis` should look like\:
226   | 11 7 | 9 0 | 4 6|
227 
228   Level: intermediate
229 
230 .seealso: `IS`, `VecGetSubVector()`, `MatCreateSubMatrix()`
231 @*/
ISCreateSubIS(IS is,IS comps,IS * subis)232 PetscErrorCode ISCreateSubIS(IS is, IS comps, IS *subis)
233 {
234   PetscSF         sf;
235   const PetscInt *is_indices, *comps_indices;
236   PetscInt       *subis_indices, nroots, nleaves, *mine, i, lidx;
237   PetscMPIInt     owner;
238   PetscSFNode    *remote;
239   MPI_Comm        comm;
240 
241   PetscFunctionBegin;
242   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
243   PetscValidHeaderSpecific(comps, IS_CLASSID, 2);
244   PetscAssertPointer(subis, 3);
245 
246   PetscCall(PetscObjectGetComm((PetscObject)is, &comm));
247   PetscCall(ISGetLocalSize(comps, &nleaves));
248   PetscCall(ISGetLocalSize(is, &nroots));
249   PetscCall(PetscMalloc1(nleaves, &remote));
250   PetscCall(PetscMalloc1(nleaves, &mine));
251   PetscCall(ISGetIndices(comps, &comps_indices));
252   /*
253    * Construct a PetscSF in which "is" data serves as roots and "subis" is leaves.
254    * Root data are sent to leaves using PetscSFBcast().
255    * */
256   for (i = 0; i < nleaves; i++) {
257     mine[i] = i;
258     /* Connect a remote root with the current leaf. The value on the remote root
259      * will be received by the current local leaf.
260      * */
261     owner = -1;
262     lidx  = -1;
263     PetscCall(PetscLayoutFindOwnerIndex(is->map, comps_indices[i], &owner, &lidx));
264     remote[i].rank  = owner;
265     remote[i].index = lidx;
266   }
267   PetscCall(ISRestoreIndices(comps, &comps_indices));
268   PetscCall(PetscSFCreate(comm, &sf));
269   PetscCall(PetscSFSetFromOptions(sf));
270   PetscCall(PetscSFSetGraph(sf, nroots, nleaves, mine, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
271 
272   PetscCall(PetscMalloc1(nleaves, &subis_indices));
273   PetscCall(ISGetIndices(is, &is_indices));
274   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, is_indices, subis_indices, MPI_REPLACE));
275   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, is_indices, subis_indices, MPI_REPLACE));
276   PetscCall(ISRestoreIndices(is, &is_indices));
277   PetscCall(PetscSFDestroy(&sf));
278   PetscCall(ISCreateGeneral(comm, nleaves, subis_indices, PETSC_OWN_POINTER, subis));
279   PetscFunctionReturn(PETSC_SUCCESS);
280 }
281 
282 /*@
283   ISClearInfoCache - clear the cache of computed index set properties
284 
285   Not Collective
286 
287   Input Parameters:
288 + is                    - the index set
289 - clear_permanent_local - whether to remove the permanent status of local properties
290 
291   Level: developer
292 
293   Note:
294   Because all processes must agree on the global permanent status of a property,
295   the permanent status can only be changed with `ISSetInfo()`, because this routine is not collective
296 
297 .seealso: `IS`, `ISInfo`, `ISInfoType`, `ISSetInfo()`
298 @*/
ISClearInfoCache(IS is,PetscBool clear_permanent_local)299 PetscErrorCode ISClearInfoCache(IS is, PetscBool clear_permanent_local)
300 {
301   PetscInt i, j;
302 
303   PetscFunctionBegin;
304   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
305   PetscValidType(is, 1);
306   for (i = 0; i < IS_INFO_MAX; i++) {
307     if (clear_permanent_local) is->info_permanent[IS_LOCAL][i] = PETSC_FALSE;
308     for (j = 0; j < 2; j++) {
309       if (!is->info_permanent[j][i]) is->info[j][i] = IS_INFO_UNKNOWN;
310     }
311   }
312   PetscFunctionReturn(PETSC_SUCCESS);
313 }
314 
ISSetInfo_Internal(IS is,ISInfo info,ISInfoType type,ISInfoBool ipermanent,PetscBool flg)315 static PetscErrorCode ISSetInfo_Internal(IS is, ISInfo info, ISInfoType type, ISInfoBool ipermanent, PetscBool flg)
316 {
317   ISInfoBool iflg          = flg ? IS_INFO_TRUE : IS_INFO_FALSE;
318   PetscInt   itype         = (type == IS_LOCAL) ? 0 : 1;
319   PetscBool  permanent_set = (ipermanent == IS_INFO_UNKNOWN) ? PETSC_FALSE : PETSC_TRUE;
320   PetscBool  permanent     = (ipermanent == IS_INFO_TRUE) ? PETSC_TRUE : PETSC_FALSE;
321 
322   PetscFunctionBegin;
323   /* set this property */
324   is->info[itype][(int)info] = iflg;
325   if (permanent_set) is->info_permanent[itype][(int)info] = permanent;
326   /* set implications */
327   switch (info) {
328   case IS_SORTED:
329     if (PetscDefined(USE_DEBUG) && flg) {
330       PetscInt        n;
331       const PetscInt *indices;
332 
333       PetscCall(ISGetLocalSize(is, &n));
334       PetscCall(ISGetIndices(is, &indices));
335       PetscCall(PetscSortedInt(n, indices, &flg));
336       if (type == IS_GLOBAL) PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &flg, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)is)));
337       PetscCheck(flg, type == IS_GLOBAL ? PetscObjectComm((PetscObject)is) : PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "IS is not sorted");
338       PetscCall(ISRestoreIndices(is, &indices));
339     }
340     if (flg && type == IS_GLOBAL) { /* an array that is globally sorted is also locally sorted */
341       is->info[IS_LOCAL][(int)info] = IS_INFO_TRUE;
342       /* global permanence implies local permanence */
343       if (permanent_set && permanent) is->info_permanent[IS_LOCAL][(int)info] = PETSC_TRUE;
344     }
345     if (!flg) { /* if an array is not sorted, it cannot be an interval or the identity */
346       is->info[itype][IS_INTERVAL] = IS_INFO_FALSE;
347       is->info[itype][IS_IDENTITY] = IS_INFO_FALSE;
348       if (permanent_set) {
349         is->info_permanent[itype][IS_INTERVAL] = permanent;
350         is->info_permanent[itype][IS_IDENTITY] = permanent;
351       }
352     }
353     break;
354   case IS_UNIQUE:
355     if (flg && type == IS_GLOBAL) { /* an array that is globally unique is also locally unique */
356       is->info[IS_LOCAL][(int)info] = IS_INFO_TRUE;
357       /* global permanence implies local permanence */
358       if (permanent_set && permanent) is->info_permanent[IS_LOCAL][(int)info] = PETSC_TRUE;
359     }
360     if (!flg) { /* if an array is not unique, it cannot be a permutation, and interval, or the identity */
361       is->info[itype][IS_PERMUTATION] = IS_INFO_FALSE;
362       is->info[itype][IS_INTERVAL]    = IS_INFO_FALSE;
363       is->info[itype][IS_IDENTITY]    = IS_INFO_FALSE;
364       if (permanent_set) {
365         is->info_permanent[itype][IS_PERMUTATION] = permanent;
366         is->info_permanent[itype][IS_INTERVAL]    = permanent;
367         is->info_permanent[itype][IS_IDENTITY]    = permanent;
368       }
369     }
370     break;
371   case IS_PERMUTATION:
372     if (flg) { /* an array that is a permutation is unique and is unique locally */
373       is->info[itype][IS_UNIQUE]    = IS_INFO_TRUE;
374       is->info[IS_LOCAL][IS_UNIQUE] = IS_INFO_TRUE;
375       if (permanent_set && permanent) {
376         is->info_permanent[itype][IS_UNIQUE]    = PETSC_TRUE;
377         is->info_permanent[IS_LOCAL][IS_UNIQUE] = PETSC_TRUE;
378       }
379     } else { /* an array that is not a permutation cannot be the identity */
380       is->info[itype][IS_IDENTITY] = IS_INFO_FALSE;
381       if (permanent_set) is->info_permanent[itype][IS_IDENTITY] = permanent;
382     }
383     break;
384   case IS_INTERVAL:
385     if (flg) { /* an array that is an interval is sorted and unique */
386       is->info[itype][IS_SORTED]    = IS_INFO_TRUE;
387       is->info[IS_LOCAL][IS_SORTED] = IS_INFO_TRUE;
388       is->info[itype][IS_UNIQUE]    = IS_INFO_TRUE;
389       is->info[IS_LOCAL][IS_UNIQUE] = IS_INFO_TRUE;
390       if (permanent_set && permanent) {
391         is->info_permanent[itype][IS_SORTED]    = PETSC_TRUE;
392         is->info_permanent[IS_LOCAL][IS_SORTED] = PETSC_TRUE;
393         is->info_permanent[itype][IS_UNIQUE]    = PETSC_TRUE;
394         is->info_permanent[IS_LOCAL][IS_UNIQUE] = PETSC_TRUE;
395       }
396     } else { /* an array that is not an interval cannot be the identity */
397       is->info[itype][IS_IDENTITY] = IS_INFO_FALSE;
398       if (permanent_set) is->info_permanent[itype][IS_IDENTITY] = permanent;
399     }
400     break;
401   case IS_IDENTITY:
402     if (flg) { /* an array that is the identity is sorted, unique, an interval, and a permutation */
403       is->info[itype][IS_SORTED]      = IS_INFO_TRUE;
404       is->info[IS_LOCAL][IS_SORTED]   = IS_INFO_TRUE;
405       is->info[itype][IS_UNIQUE]      = IS_INFO_TRUE;
406       is->info[IS_LOCAL][IS_UNIQUE]   = IS_INFO_TRUE;
407       is->info[itype][IS_PERMUTATION] = IS_INFO_TRUE;
408       is->info[itype][IS_INTERVAL]    = IS_INFO_TRUE;
409       is->info[IS_LOCAL][IS_INTERVAL] = IS_INFO_TRUE;
410       if (permanent_set && permanent) {
411         is->info_permanent[itype][IS_SORTED]      = PETSC_TRUE;
412         is->info_permanent[IS_LOCAL][IS_SORTED]   = PETSC_TRUE;
413         is->info_permanent[itype][IS_UNIQUE]      = PETSC_TRUE;
414         is->info_permanent[IS_LOCAL][IS_UNIQUE]   = PETSC_TRUE;
415         is->info_permanent[itype][IS_PERMUTATION] = PETSC_TRUE;
416         is->info_permanent[itype][IS_INTERVAL]    = PETSC_TRUE;
417         is->info_permanent[IS_LOCAL][IS_INTERVAL] = PETSC_TRUE;
418       }
419     }
420     break;
421   default:
422     PetscCheck(type != IS_LOCAL, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown IS property");
423     SETERRQ(PetscObjectComm((PetscObject)is), PETSC_ERR_ARG_OUTOFRANGE, "Unknown IS property");
424   }
425   PetscFunctionReturn(PETSC_SUCCESS);
426 }
427 
428 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
429 /*@
430   ISSetInfo - Set known information about an index set.
431 
432   Logically Collective if `ISInfoType` is `IS_GLOBAL`
433 
434   Input Parameters:
435 + is        - the index set
436 . info      - describing a property of the index set, one of those listed below,
437 . type      - `IS_LOCAL` if the information describes the local portion of the index set,
438           `IS_GLOBAL` if it describes the whole index set
439 . permanent - `PETSC_TRUE` if it is known that the property will persist through changes to the index set, `PETSC_FALSE` otherwise
440                If the user sets a property as permanently known, it will bypass computation of that property
441 - flg       - set the described property as true (`PETSC_TRUE`) or false (`PETSC_FALSE`)
442 
443   Values of `info` Describing `IS` Structure:
444 + `IS_SORTED`      - the [local part of the] index set is sorted in ascending order
445 . `IS_UNIQUE`      - each entry in the [local part of the] index set is unique
446 . `IS_PERMUTATION` - the [local part of the] index set is a permutation of the integers {0, 1, ..., N-1}, where N is the size of the [local part of the] index set
447 . `IS_INTERVAL`    - the [local part of the] index set is equal to a contiguous range of integers {f, f + 1, ..., f + N-1}
448 - `IS_IDENTITY`    - the [local part of the] index set is equal to the integers {0, 1, ..., N-1}
449 
450   Level: advanced
451 
452   Notes:
453   If type is `IS_GLOBAL`, all processes that share the index set must pass the same value in flg
454 
455   It is possible to set a property with `ISSetInfo()` that contradicts what would be previously computed with `ISGetInfo()`
456 
457 .seealso: `ISInfo`, `ISInfoType`, `IS`
458 @*/
ISSetInfo(IS is,ISInfo info,ISInfoType type,PetscBool permanent,PetscBool flg)459 PetscErrorCode ISSetInfo(IS is, ISInfo info, ISInfoType type, PetscBool permanent, PetscBool flg)
460 {
461   MPI_Comm    comm, errcomm;
462   PetscMPIInt size;
463 
464   PetscFunctionBegin;
465   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
466   PetscValidType(is, 1);
467   comm = PetscObjectComm((PetscObject)is);
468   if (type == IS_GLOBAL) {
469     PetscValidLogicalCollectiveEnum(is, info, 2);
470     PetscValidLogicalCollectiveBool(is, permanent, 4);
471     PetscValidLogicalCollectiveBool(is, flg, 5);
472     errcomm = comm;
473   } else {
474     errcomm = PETSC_COMM_SELF;
475   }
476 
477   PetscCheck((int)info > IS_INFO_MIN && (int)info < IS_INFO_MAX, errcomm, PETSC_ERR_ARG_OUTOFRANGE, "Option %d is out of range", (int)info);
478 
479   PetscCallMPI(MPI_Comm_size(comm, &size));
480   /* do not use global values if size == 1: it makes it easier to keep the implications straight */
481   if (size == 1) type = IS_LOCAL;
482   PetscCall(ISSetInfo_Internal(is, info, type, permanent ? IS_INFO_TRUE : IS_INFO_FALSE, flg));
483   PetscFunctionReturn(PETSC_SUCCESS);
484 }
485 
ISGetInfo_Sorted_Private(IS is,ISInfoType type,PetscBool * flg)486 static PetscErrorCode ISGetInfo_Sorted_Private(IS is, ISInfoType type, PetscBool *flg)
487 {
488   MPI_Comm    comm;
489   PetscMPIInt size, rank;
490 
491   PetscFunctionBegin;
492   comm = PetscObjectComm((PetscObject)is);
493   PetscCallMPI(MPI_Comm_size(comm, &size));
494   PetscCallMPI(MPI_Comm_rank(comm, &rank));
495   if (type == IS_GLOBAL && is->ops->sortedglobal) {
496     PetscUseTypeMethod(is, sortedglobal, flg);
497   } else {
498     PetscBool sortedLocal = PETSC_FALSE;
499 
500     /* determine if the array is locally sorted */
501     if (type == IS_GLOBAL && size > 1) {
502       /* call ISGetInfo so that a cached value will be used if possible */
503       PetscCall(ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, &sortedLocal));
504     } else if (is->ops->sortedlocal) {
505       PetscUseTypeMethod(is, sortedlocal, &sortedLocal);
506     } else {
507       /* default: get the local indices and directly check */
508       const PetscInt *idx;
509       PetscInt        n;
510 
511       PetscCall(ISGetIndices(is, &idx));
512       PetscCall(ISGetLocalSize(is, &n));
513       PetscCall(PetscSortedInt(n, idx, &sortedLocal));
514       PetscCall(ISRestoreIndices(is, &idx));
515     }
516 
517     if (type == IS_LOCAL || size == 1) {
518       *flg = sortedLocal;
519     } else {
520       PetscCallMPI(MPIU_Allreduce(&sortedLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
521       if (*flg) {
522         PetscInt n, min = PETSC_INT_MAX, max = PETSC_INT_MIN;
523         PetscInt maxprev;
524 
525         PetscCall(ISGetLocalSize(is, &n));
526         if (n) PetscCall(ISGetMinMax(is, &min, &max));
527         maxprev = PETSC_INT_MIN;
528         PetscCallMPI(MPI_Exscan(&max, &maxprev, 1, MPIU_INT, MPI_MAX, comm));
529         if (rank && (maxprev > min)) sortedLocal = PETSC_FALSE;
530         PetscCallMPI(MPIU_Allreduce(&sortedLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
531       }
532     }
533   }
534   PetscFunctionReturn(PETSC_SUCCESS);
535 }
536 
537 static PetscErrorCode ISGetIndicesCopy_Private(IS is, PetscInt idx[]);
538 
ISGetInfo_Unique_Private(IS is,ISInfoType type,PetscBool * flg)539 static PetscErrorCode ISGetInfo_Unique_Private(IS is, ISInfoType type, PetscBool *flg)
540 {
541   MPI_Comm    comm;
542   PetscMPIInt size, rank;
543   PetscInt    i;
544 
545   PetscFunctionBegin;
546   comm = PetscObjectComm((PetscObject)is);
547   PetscCallMPI(MPI_Comm_size(comm, &size));
548   PetscCallMPI(MPI_Comm_rank(comm, &rank));
549   if (type == IS_GLOBAL && is->ops->uniqueglobal) {
550     PetscUseTypeMethod(is, uniqueglobal, flg);
551   } else {
552     PetscBool uniqueLocal;
553     PetscInt  n   = -1;
554     PetscInt *idx = NULL;
555 
556     /* determine if the array is locally unique */
557     if (type == IS_GLOBAL && size > 1) {
558       /* call ISGetInfo so that a cached value will be used if possible */
559       PetscCall(ISGetInfo(is, IS_UNIQUE, IS_LOCAL, PETSC_TRUE, &uniqueLocal));
560     } else if (is->ops->uniquelocal) {
561       PetscUseTypeMethod(is, uniquelocal, &uniqueLocal);
562     } else {
563       /* default: get the local indices and directly check */
564       uniqueLocal = PETSC_TRUE;
565       PetscCall(ISGetLocalSize(is, &n));
566       PetscCall(PetscMalloc1(n, &idx));
567       PetscCall(ISGetIndicesCopy_Private(is, idx));
568       PetscCall(PetscIntSortSemiOrdered(n, idx));
569       for (i = 1; i < n; i++)
570         if (idx[i] == idx[i - 1]) break;
571       if (i < n) uniqueLocal = PETSC_FALSE;
572     }
573 
574     PetscCall(PetscFree(idx));
575     if (type == IS_LOCAL || size == 1) {
576       *flg = uniqueLocal;
577     } else {
578       PetscCallMPI(MPIU_Allreduce(&uniqueLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
579       if (*flg) {
580         PetscInt min = PETSC_INT_MAX, max = PETSC_INT_MIN, maxprev;
581 
582         if (!idx) {
583           PetscCall(ISGetLocalSize(is, &n));
584           PetscCall(PetscMalloc1(n, &idx));
585           PetscCall(ISGetIndicesCopy_Private(is, idx));
586         }
587         PetscCall(PetscParallelSortInt(is->map, is->map, idx, idx));
588         if (n) {
589           min = idx[0];
590           max = idx[n - 1];
591         }
592         for (i = 1; i < n; i++)
593           if (idx[i] == idx[i - 1]) break;
594         if (i < n) uniqueLocal = PETSC_FALSE;
595         maxprev = PETSC_INT_MIN;
596         PetscCallMPI(MPI_Exscan(&max, &maxprev, 1, MPIU_INT, MPI_MAX, comm));
597         if (rank && (maxprev == min)) uniqueLocal = PETSC_FALSE;
598         PetscCallMPI(MPIU_Allreduce(&uniqueLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
599       }
600     }
601     PetscCall(PetscFree(idx));
602   }
603   PetscFunctionReturn(PETSC_SUCCESS);
604 }
605 
ISGetInfo_Permutation(IS is,ISInfoType type,PetscBool * flg)606 static PetscErrorCode ISGetInfo_Permutation(IS is, ISInfoType type, PetscBool *flg)
607 {
608   MPI_Comm    comm;
609   PetscMPIInt size;
610 
611   PetscFunctionBegin;
612   comm = PetscObjectComm((PetscObject)is);
613   PetscCallMPI(MPI_Comm_size(comm, &size));
614   if (type == IS_GLOBAL && is->ops->permglobal) {
615     PetscUseTypeMethod(is, permglobal, flg);
616   } else if (type == IS_LOCAL && is->ops->permlocal) {
617     PetscUseTypeMethod(is, permlocal, flg);
618   } else {
619     PetscBool permLocal;
620     PetscInt  n, i, rStart;
621     PetscInt *idx;
622 
623     PetscCall(ISGetLocalSize(is, &n));
624     PetscCall(PetscMalloc1(n, &idx));
625     PetscCall(ISGetIndicesCopy_Private(is, idx));
626     if (type == IS_GLOBAL) {
627       PetscCall(PetscParallelSortInt(is->map, is->map, idx, idx));
628       PetscCall(PetscLayoutGetRange(is->map, &rStart, NULL));
629     } else {
630       PetscCall(PetscIntSortSemiOrdered(n, idx));
631       rStart = 0;
632     }
633     permLocal = PETSC_TRUE;
634     for (i = 0; i < n; i++) {
635       if (idx[i] != rStart + i) break;
636     }
637     if (i < n) permLocal = PETSC_FALSE;
638     if (type == IS_LOCAL || size == 1) {
639       *flg = permLocal;
640     } else {
641       PetscCallMPI(MPIU_Allreduce(&permLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
642     }
643     PetscCall(PetscFree(idx));
644   }
645   PetscFunctionReturn(PETSC_SUCCESS);
646 }
647 
ISGetInfo_Interval(IS is,ISInfoType type,PetscBool * flg)648 static PetscErrorCode ISGetInfo_Interval(IS is, ISInfoType type, PetscBool *flg)
649 {
650   MPI_Comm    comm;
651   PetscMPIInt size, rank;
652   PetscInt    i;
653 
654   PetscFunctionBegin;
655   comm = PetscObjectComm((PetscObject)is);
656   PetscCallMPI(MPI_Comm_size(comm, &size));
657   PetscCallMPI(MPI_Comm_rank(comm, &rank));
658   if (type == IS_GLOBAL && is->ops->intervalglobal) {
659     PetscUseTypeMethod(is, intervalglobal, flg);
660   } else {
661     PetscBool intervalLocal;
662 
663     /* determine if the array is locally an interval */
664     if (type == IS_GLOBAL && size > 1) {
665       /* call ISGetInfo so that a cached value will be used if possible */
666       PetscCall(ISGetInfo(is, IS_INTERVAL, IS_LOCAL, PETSC_TRUE, &intervalLocal));
667     } else if (is->ops->intervallocal) {
668       PetscUseTypeMethod(is, intervallocal, &intervalLocal);
669     } else {
670       PetscInt        n;
671       const PetscInt *idx;
672       /* default: get the local indices and directly check */
673       intervalLocal = PETSC_TRUE;
674       PetscCall(ISGetLocalSize(is, &n));
675       PetscCall(ISGetIndices(is, &idx));
676       for (i = 1; i < n; i++)
677         if (idx[i] != idx[i - 1] + 1) break;
678       if (i < n) intervalLocal = PETSC_FALSE;
679       PetscCall(ISRestoreIndices(is, &idx));
680     }
681 
682     if (type == IS_LOCAL || size == 1) {
683       *flg = intervalLocal;
684     } else {
685       PetscCallMPI(MPIU_Allreduce(&intervalLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
686       if (*flg) {
687         PetscInt n, min = PETSC_INT_MAX, max = PETSC_INT_MIN;
688         PetscInt maxprev;
689 
690         PetscCall(ISGetLocalSize(is, &n));
691         if (n) PetscCall(ISGetMinMax(is, &min, &max));
692         maxprev = PETSC_INT_MIN;
693         PetscCallMPI(MPI_Exscan(&max, &maxprev, 1, MPIU_INT, MPI_MAX, comm));
694         if (rank && n && (maxprev != min - 1)) intervalLocal = PETSC_FALSE;
695         PetscCallMPI(MPIU_Allreduce(&intervalLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
696       }
697     }
698   }
699   PetscFunctionReturn(PETSC_SUCCESS);
700 }
701 
ISGetInfo_Identity(IS is,ISInfoType type,PetscBool * flg)702 static PetscErrorCode ISGetInfo_Identity(IS is, ISInfoType type, PetscBool *flg)
703 {
704   MPI_Comm    comm;
705   PetscMPIInt size;
706 
707   PetscFunctionBegin;
708   comm = PetscObjectComm((PetscObject)is);
709   PetscCallMPI(MPI_Comm_size(comm, &size));
710   if (type == IS_GLOBAL && is->ops->intervalglobal) {
711     PetscBool isinterval;
712 
713     PetscUseTypeMethod(is, intervalglobal, &isinterval);
714     *flg = PETSC_FALSE;
715     if (isinterval) {
716       PetscInt min;
717 
718       PetscCall(ISGetMinMax(is, &min, NULL));
719       PetscCallMPI(MPI_Bcast(&min, 1, MPIU_INT, 0, comm));
720       if (min == 0) *flg = PETSC_TRUE;
721     }
722   } else if (type == IS_LOCAL && is->ops->intervallocal) {
723     PetscBool isinterval;
724 
725     PetscUseTypeMethod(is, intervallocal, &isinterval);
726     *flg = PETSC_FALSE;
727     if (isinterval) {
728       PetscInt min;
729 
730       PetscCall(ISGetMinMax(is, &min, NULL));
731       if (min == 0) *flg = PETSC_TRUE;
732     }
733   } else {
734     PetscBool       identLocal;
735     PetscInt        n, i, rStart;
736     const PetscInt *idx;
737 
738     PetscCall(ISGetLocalSize(is, &n));
739     PetscCall(ISGetIndices(is, &idx));
740     PetscCall(PetscLayoutGetRange(is->map, &rStart, NULL));
741     identLocal = PETSC_TRUE;
742     for (i = 0; i < n; i++) {
743       if (idx[i] != rStart + i) break;
744     }
745     if (i < n) identLocal = PETSC_FALSE;
746     if (type == IS_LOCAL || size == 1) {
747       *flg = identLocal;
748     } else {
749       PetscCallMPI(MPIU_Allreduce(&identLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
750     }
751     PetscCall(ISRestoreIndices(is, &idx));
752   }
753   PetscFunctionReturn(PETSC_SUCCESS);
754 }
755 
756 /*@
757   ISGetInfo - Determine whether an index set satisfies a given property
758 
759   Collective or Logically Collective if the type is `IS_GLOBAL` (logically collective if the value of the property has been permanently set with `ISSetInfo()`)
760 
761   Input Parameters:
762 + is      - the index set
763 . info    - describing a property of the index set, one of those listed in the documentation of `ISSetInfo()`
764 . compute - if `PETSC_FALSE`, the property will not be computed if it is not already known and the property will be assumed to be false
765 - type    - whether the property is local (`IS_LOCAL`) or global (`IS_GLOBAL`)
766 
767   Output Parameter:
768 . flg - whether the property is true (`PETSC_TRUE`) or false (`PETSC_FALSE`)
769 
770   Level: advanced
771 
772   Notes:
773   `ISGetInfo()` uses cached values when possible, which will be incorrect if `ISSetInfo()` has been called with incorrect information.
774 
775   To clear cached values, use `ISClearInfoCache()`.
776 
777 .seealso: `IS`, `ISInfo`, `ISInfoType`, `ISSetInfo()`, `ISClearInfoCache()`
778 @*/
ISGetInfo(IS is,ISInfo info,ISInfoType type,PetscBool compute,PetscBool * flg)779 PetscErrorCode ISGetInfo(IS is, ISInfo info, ISInfoType type, PetscBool compute, PetscBool *flg)
780 {
781   MPI_Comm    comm, errcomm;
782   PetscMPIInt rank, size;
783   PetscInt    itype;
784   PetscBool   hasprop;
785   PetscBool   infer;
786 
787   PetscFunctionBegin;
788   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
789   PetscValidType(is, 1);
790   comm = PetscObjectComm((PetscObject)is);
791   if (type == IS_GLOBAL) {
792     PetscValidLogicalCollectiveEnum(is, info, 2);
793     errcomm = comm;
794   } else {
795     errcomm = PETSC_COMM_SELF;
796   }
797 
798   PetscCallMPI(MPI_Comm_size(comm, &size));
799   PetscCallMPI(MPI_Comm_rank(comm, &rank));
800 
801   PetscCheck((int)info > IS_INFO_MIN && (int)info < IS_INFO_MAX, errcomm, PETSC_ERR_ARG_OUTOFRANGE, "Option %d is out of range", (int)info);
802   if (size == 1) type = IS_LOCAL;
803   itype   = (type == IS_LOCAL) ? 0 : 1;
804   hasprop = PETSC_FALSE;
805   infer   = PETSC_FALSE;
806   if (is->info_permanent[itype][(int)info]) {
807     hasprop = (is->info[itype][(int)info] == IS_INFO_TRUE) ? PETSC_TRUE : PETSC_FALSE;
808     infer   = PETSC_TRUE;
809   } else if ((itype == IS_LOCAL) && (is->info[IS_LOCAL][info] != IS_INFO_UNKNOWN)) {
810     /* we can cache local properties as long as we clear them when the IS changes */
811     /* NOTE: we only cache local values because there is no ISAssemblyBegin()/ISAssemblyEnd(),
812      so we have no way of knowing when a cached value has been invalidated by changes on a different process */
813     hasprop = (is->info[itype][(int)info] == IS_INFO_TRUE) ? PETSC_TRUE : PETSC_FALSE;
814     infer   = PETSC_TRUE;
815   } else if (compute) {
816     switch (info) {
817     case IS_SORTED:
818       PetscCall(ISGetInfo_Sorted_Private(is, type, &hasprop));
819       break;
820     case IS_UNIQUE:
821       PetscCall(ISGetInfo_Unique_Private(is, type, &hasprop));
822       break;
823     case IS_PERMUTATION:
824       PetscCall(ISGetInfo_Permutation(is, type, &hasprop));
825       break;
826     case IS_INTERVAL:
827       PetscCall(ISGetInfo_Interval(is, type, &hasprop));
828       break;
829     case IS_IDENTITY:
830       PetscCall(ISGetInfo_Identity(is, type, &hasprop));
831       break;
832     default:
833       SETERRQ(errcomm, PETSC_ERR_ARG_OUTOFRANGE, "Unknown IS property");
834     }
835     infer = PETSC_TRUE;
836   }
837   /* call ISSetInfo_Internal to keep all of the implications straight */
838   if (infer) PetscCall(ISSetInfo_Internal(is, info, type, IS_INFO_UNKNOWN, hasprop));
839   *flg = hasprop;
840   PetscFunctionReturn(PETSC_SUCCESS);
841 }
842 
ISCopyInfo_Private(IS source,IS dest)843 static PetscErrorCode ISCopyInfo_Private(IS source, IS dest)
844 {
845   PetscFunctionBegin;
846   PetscCall(PetscArraycpy(&dest->info[0], &source->info[0], 2));
847   PetscCall(PetscArraycpy(&dest->info_permanent[0], &source->info_permanent[0], 2));
848   PetscFunctionReturn(PETSC_SUCCESS);
849 }
850 
851 /*@
852   ISIdentity - Determines whether index set is the identity mapping.
853 
854   Collective
855 
856   Input Parameter:
857 . is - the index set
858 
859   Output Parameter:
860 . ident - `PETSC_TRUE` if an identity, else `PETSC_FALSE`
861 
862   Level: intermediate
863 
864   Note:
865   If `ISSetIdentity()` (or `ISSetInfo()` for a permanent property) has been called,
866   `ISIdentity()` will return its answer without communication between processes, but
867   otherwise the output ident will be computed from `ISGetInfo()`,
868   which may require synchronization on the communicator of `is`.  To avoid this computation,
869   call `ISGetInfo()` directly with the compute flag set to `PETSC_FALSE`, and ident will be assumed false.
870 
871 .seealso: `IS`, `ISSetIdentity()`, `ISGetInfo()`
872 @*/
ISIdentity(IS is,PetscBool * ident)873 PetscErrorCode ISIdentity(IS is, PetscBool *ident)
874 {
875   PetscFunctionBegin;
876   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
877   PetscAssertPointer(ident, 2);
878   PetscCall(ISGetInfo(is, IS_IDENTITY, IS_GLOBAL, PETSC_TRUE, ident));
879   PetscFunctionReturn(PETSC_SUCCESS);
880 }
881 
882 /*@
883   ISSetIdentity - Informs the index set that it is an identity.
884 
885   Logically Collective
886 
887   Input Parameter:
888 . is - the index set
889 
890   Level: intermediate
891 
892   Notes:
893   `is` will be considered the identity permanently, even if indices have been changes (for example, with
894   `ISGeneralSetIndices()`).  It's a good idea to only set this property if `is` will not change in the future.
895 
896   To clear this property, use `ISClearInfoCache()`.
897 
898   Developer Notes:
899   Some of these info routines have statements about values changing in the `IS`, this seems to contradict the fact that `IS` cannot be changed?
900 
901 .seealso: `IS`, `ISIdentity()`, `ISSetInfo()`, `ISClearInfoCache()`
902 @*/
ISSetIdentity(IS is)903 PetscErrorCode ISSetIdentity(IS is)
904 {
905   PetscFunctionBegin;
906   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
907   PetscCall(ISSetInfo(is, IS_IDENTITY, IS_GLOBAL, PETSC_TRUE, PETSC_TRUE));
908   PetscFunctionReturn(PETSC_SUCCESS);
909 }
910 
911 /*@
912   ISContiguousLocal - Locates an index set with contiguous range within a global range, if possible
913 
914   Not Collective
915 
916   Input Parameters:
917 + is     - the index set
918 . gstart - global start
919 - gend   - global end
920 
921   Output Parameters:
922 + start  - start of contiguous block, as an offset from `gstart`
923 - contig - `PETSC_TRUE` if the index set refers to contiguous entries on this process, else `PETSC_FALSE`
924 
925   Level: developer
926 
927 .seealso: `IS`, `ISGetLocalSize()`, `VecGetOwnershipRange()`
928 @*/
ISContiguousLocal(IS is,PetscInt gstart,PetscInt gend,PetscInt * start,PetscBool * contig)929 PetscErrorCode ISContiguousLocal(IS is, PetscInt gstart, PetscInt gend, PetscInt *start, PetscBool *contig)
930 {
931   PetscFunctionBegin;
932   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
933   PetscAssertPointer(start, 4);
934   PetscAssertPointer(contig, 5);
935   PetscCheck(gstart <= gend, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "gstart %" PetscInt_FMT " must be less than or equal to gend %" PetscInt_FMT, gstart, gend);
936   *start  = -1;
937   *contig = PETSC_FALSE;
938   PetscTryTypeMethod(is, contiguous, gstart, gend, start, contig);
939   PetscFunctionReturn(PETSC_SUCCESS);
940 }
941 
942 /*@
943   ISPermutation - `PETSC_TRUE` or `PETSC_FALSE` depending on whether the
944   index set has been declared to be a permutation.
945 
946   Logically Collective
947 
948   Input Parameter:
949 . is - the index set
950 
951   Output Parameter:
952 . perm - `PETSC_TRUE` if a permutation, else `PETSC_FALSE`
953 
954   Level: intermediate
955 
956   Note:
957   If it is not already known that `is` is a permutation (if `ISSetPermutation()`
958   or `ISSetInfo()` has not been called), this routine will not attempt to compute
959   whether the index set is a permutation and will assume `perm` is `PETSC_FALSE`.
960   To compute the value when it is not already known, use `ISGetInfo()` with
961   the compute flag set to `PETSC_TRUE`.
962 
963   Developer Notes:
964   Perhaps some of these routines should use the `PetscBool3` enum to return appropriate values
965 
966 .seealso: `IS`, `ISSetPermutation()`, `ISGetInfo()`
967 @*/
ISPermutation(IS is,PetscBool * perm)968 PetscErrorCode ISPermutation(IS is, PetscBool *perm)
969 {
970   PetscFunctionBegin;
971   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
972   PetscAssertPointer(perm, 2);
973   PetscCall(ISGetInfo(is, IS_PERMUTATION, IS_GLOBAL, PETSC_FALSE, perm));
974   PetscFunctionReturn(PETSC_SUCCESS);
975 }
976 
977 /*@
978   ISSetPermutation - Informs the index set that it is a permutation.
979 
980   Logically Collective
981 
982   Input Parameter:
983 . is - the index set
984 
985   Level: intermediate
986 
987   Notes:
988   `is` will be considered a permutation permanently, even if indices have been changes (for example, with
989   `ISGeneralSetIndices()`).  It's a good idea to only set this property if `is` will not change in the future.
990 
991   To clear this property, use `ISClearInfoCache()`.
992 
993   The debug version of the libraries (./configure --with-debugging=1) checks if the
994   index set is actually a permutation. The optimized version just believes you.
995 
996 .seealso: `IS`, `ISPermutation()`, `ISSetInfo()`, `ISClearInfoCache().`
997 @*/
ISSetPermutation(IS is)998 PetscErrorCode ISSetPermutation(IS is)
999 {
1000   PetscFunctionBegin;
1001   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1002   if (PetscDefined(USE_DEBUG)) {
1003     PetscMPIInt size;
1004 
1005     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)is), &size));
1006     if (size == 1) {
1007       PetscInt        i, n, *idx;
1008       const PetscInt *iidx;
1009 
1010       PetscCall(ISGetSize(is, &n));
1011       PetscCall(PetscMalloc1(n, &idx));
1012       PetscCall(ISGetIndices(is, &iidx));
1013       PetscCall(PetscArraycpy(idx, iidx, n));
1014       PetscCall(PetscIntSortSemiOrdered(n, idx));
1015       for (i = 0; i < n; i++) PetscCheck(idx[i] == i, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Index set is not a permutation");
1016       PetscCall(PetscFree(idx));
1017       PetscCall(ISRestoreIndices(is, &iidx));
1018     }
1019   }
1020   PetscCall(ISSetInfo(is, IS_PERMUTATION, IS_GLOBAL, PETSC_TRUE, PETSC_TRUE));
1021   PetscFunctionReturn(PETSC_SUCCESS);
1022 }
1023 
1024 /*@
1025   ISDestroy - Destroys an index set.
1026 
1027   Collective
1028 
1029   Input Parameter:
1030 . is - the index set
1031 
1032   Level: beginner
1033 
1034 .seealso: `IS`, `ISCreateGeneral()`, `ISCreateStride()`, `ISCreateBlock()`
1035 @*/
ISDestroy(IS * is)1036 PetscErrorCode ISDestroy(IS *is)
1037 {
1038   PetscFunctionBegin;
1039   if (!*is) PetscFunctionReturn(PETSC_SUCCESS);
1040   PetscValidHeaderSpecific(*is, IS_CLASSID, 1);
1041   if (--((PetscObject)*is)->refct > 0) {
1042     *is = NULL;
1043     PetscFunctionReturn(PETSC_SUCCESS);
1044   }
1045   if ((*is)->complement) {
1046     PetscInt refcnt;
1047     PetscCall(PetscObjectGetReference((PetscObject)((*is)->complement), &refcnt));
1048     PetscCheck(refcnt <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Nonlocal IS has not been restored");
1049     PetscCall(ISDestroy(&(*is)->complement));
1050   }
1051   PetscTryTypeMethod(*is, destroy);
1052   PetscCall(PetscLayoutDestroy(&(*is)->map));
1053   /* Destroy local representations of offproc data. */
1054   PetscCall(PetscFree((*is)->total));
1055   PetscCall(PetscFree((*is)->nonlocal));
1056   PetscCall(PetscHeaderDestroy(is));
1057   PetscFunctionReturn(PETSC_SUCCESS);
1058 }
1059 
1060 /*@
1061   ISInvertPermutation - Creates a new permutation that is the inverse of
1062   a given permutation.
1063 
1064   Collective
1065 
1066   Input Parameters:
1067 + is     - the index set
1068 - nlocal - number of indices on this processor in result (ignored for 1 processor) or
1069             use `PETSC_DECIDE`
1070 
1071   Output Parameter:
1072 . isout - the inverse permutation
1073 
1074   Level: intermediate
1075 
1076   Note:
1077   For parallel index sets this does the complete parallel permutation, but the
1078   code is not efficient for huge index sets (10,000,000 indices).
1079 
1080 .seealso: `IS`, `ISGetInfo()`, `ISSetPermutation()`, `ISGetPermutation()`
1081 @*/
ISInvertPermutation(IS is,PetscInt nlocal,IS * isout)1082 PetscErrorCode ISInvertPermutation(IS is, PetscInt nlocal, IS *isout)
1083 {
1084   PetscBool isperm, isidentity, issame;
1085 
1086   PetscFunctionBegin;
1087   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1088   PetscAssertPointer(isout, 3);
1089   PetscCall(ISGetInfo(is, IS_PERMUTATION, IS_GLOBAL, PETSC_TRUE, &isperm));
1090   PetscCheck(isperm, PetscObjectComm((PetscObject)is), PETSC_ERR_ARG_WRONG, "Not a permutation");
1091   PetscCall(ISGetInfo(is, IS_IDENTITY, IS_GLOBAL, PETSC_TRUE, &isidentity));
1092   issame = PETSC_FALSE;
1093   if (isidentity) {
1094     PetscInt  n;
1095     PetscBool isallsame;
1096 
1097     PetscCall(ISGetLocalSize(is, &n));
1098     issame = (PetscBool)(n == nlocal);
1099     PetscCallMPI(MPIU_Allreduce(&issame, &isallsame, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)is)));
1100     issame = isallsame;
1101   }
1102   if (issame) {
1103     PetscCall(ISDuplicate(is, isout));
1104   } else {
1105     PetscUseTypeMethod(is, invertpermutation, nlocal, isout);
1106     PetscCall(ISSetPermutation(*isout));
1107   }
1108   PetscFunctionReturn(PETSC_SUCCESS);
1109 }
1110 
1111 /*@
1112   ISGetSize - Returns the global length of an index set.
1113 
1114   Not Collective
1115 
1116   Input Parameter:
1117 . is - the index set
1118 
1119   Output Parameter:
1120 . size - the global size
1121 
1122   Level: beginner
1123 
1124 .seealso: `IS`
1125 @*/
ISGetSize(IS is,PetscInt * size)1126 PetscErrorCode ISGetSize(IS is, PetscInt *size)
1127 {
1128   PetscFunctionBegin;
1129   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1130   PetscAssertPointer(size, 2);
1131   *size = is->map->N;
1132   PetscFunctionReturn(PETSC_SUCCESS);
1133 }
1134 
1135 /*@
1136   ISGetLocalSize - Returns the local (processor) length of an index set.
1137 
1138   Not Collective
1139 
1140   Input Parameter:
1141 . is - the index set
1142 
1143   Output Parameter:
1144 . size - the local size
1145 
1146   Level: beginner
1147 
1148 .seealso: `IS`, `ISGetSize()`
1149 @*/
ISGetLocalSize(IS is,PetscInt * size)1150 PetscErrorCode ISGetLocalSize(IS is, PetscInt *size)
1151 {
1152   PetscFunctionBegin;
1153   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1154   PetscAssertPointer(size, 2);
1155   *size = is->map->n;
1156   PetscFunctionReturn(PETSC_SUCCESS);
1157 }
1158 
1159 /*@
1160   ISGetLayout - get `PetscLayout` describing index set layout
1161 
1162   Not Collective
1163 
1164   Input Parameter:
1165 . is - the index set
1166 
1167   Output Parameter:
1168 . map - the layout
1169 
1170   Level: developer
1171 
1172 .seealso: `IS`, `PetscLayout`, `ISSetLayout()`, `ISGetSize()`, `ISGetLocalSize()`
1173 @*/
ISGetLayout(IS is,PetscLayout * map)1174 PetscErrorCode ISGetLayout(IS is, PetscLayout *map)
1175 {
1176   PetscFunctionBegin;
1177   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1178   PetscAssertPointer(map, 2);
1179   *map = is->map;
1180   PetscFunctionReturn(PETSC_SUCCESS);
1181 }
1182 
1183 /*@
1184   ISSetLayout - set `PetscLayout` describing index set layout
1185 
1186   Collective
1187 
1188   Input Parameters:
1189 + is  - the index set
1190 - map - the layout
1191 
1192   Level: developer
1193 
1194   Notes:
1195   Users should typically use higher level functions such as `ISCreateGeneral()`.
1196 
1197   This function can be useful in some special cases of constructing a new `IS`, e.g. after `ISCreate()` and before `ISLoad()`.
1198   Otherwise, it is only valid to replace the layout with a layout known to be equivalent.
1199 
1200 .seealso: `IS`, `PetscLayout`, `ISCreate()`, `ISGetLayout()`, `ISGetSize()`, `ISGetLocalSize()`
1201 @*/
ISSetLayout(IS is,PetscLayout map)1202 PetscErrorCode ISSetLayout(IS is, PetscLayout map)
1203 {
1204   PetscFunctionBegin;
1205   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1206   PetscAssertPointer(map, 2);
1207   PetscCall(PetscLayoutReference(map, &is->map));
1208   PetscFunctionReturn(PETSC_SUCCESS);
1209 }
1210 
1211 /*@C
1212   ISGetIndices - Returns a pointer to the indices.  The user should call
1213   `ISRestoreIndices()` after having looked at the indices.  The user should
1214   NOT change the indices.
1215 
1216   Not Collective
1217 
1218   Input Parameter:
1219 . is - the index set
1220 
1221   Output Parameter:
1222 . ptr - the location to put the pointer to the indices
1223 
1224   Level: intermediate
1225 
1226   Fortran Note:
1227 .vb
1228   PetscInt, pointer :: ptr(:)
1229 .ve
1230 
1231 .seealso: `IS`, `ISRestoreIndices()`
1232 @*/
ISGetIndices(IS is,const PetscInt * ptr[])1233 PetscErrorCode ISGetIndices(IS is, const PetscInt *ptr[])
1234 {
1235   PetscFunctionBegin;
1236   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1237   PetscAssertPointer(ptr, 2);
1238   PetscUseTypeMethod(is, getindices, ptr);
1239   PetscFunctionReturn(PETSC_SUCCESS);
1240 }
1241 
1242 /*@
1243   ISGetMinMax - Gets the minimum and maximum values in an `IS`
1244 
1245   Not Collective
1246 
1247   Input Parameter:
1248 . is - the index set
1249 
1250   Output Parameters:
1251 + min - the minimum value, you may pass `NULL`
1252 - max - the maximum value, you may pass `NULL`
1253 
1254   Level: intermediate
1255 
1256   Notes:
1257   Empty index sets return min=`PETSC_INT_MAX` and max=`PETSC_INT_MIN`.
1258 
1259   In parallel, it returns the `min` and `max` of the local portion of `is`
1260 
1261 .seealso: `IS`, `ISGetIndices()`, `ISRestoreIndices()`
1262 @*/
ISGetMinMax(IS is,PetscInt * min,PetscInt * max)1263 PetscErrorCode ISGetMinMax(IS is, PetscInt *min, PetscInt *max)
1264 {
1265   PetscFunctionBegin;
1266   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1267   if (min) *min = is->min;
1268   if (max) *max = is->max;
1269   PetscFunctionReturn(PETSC_SUCCESS);
1270 }
1271 
1272 /*@
1273   ISLocate - determine the location of an index within the local component of an index set
1274 
1275   Not Collective
1276 
1277   Input Parameters:
1278 + is  - the index set
1279 - key - the search key
1280 
1281   Output Parameter:
1282 . location - if >= 0, a location within the index set that is equal to the key, otherwise the key is not in the index set
1283 
1284   Level: intermediate
1285 
1286 .seealso: `IS`
1287  @*/
ISLocate(IS is,PetscInt key,PetscInt * location)1288 PetscErrorCode ISLocate(IS is, PetscInt key, PetscInt *location)
1289 {
1290   PetscFunctionBegin;
1291   if (is->ops->locate) {
1292     PetscUseTypeMethod(is, locate, key, location);
1293   } else {
1294     PetscInt        numIdx;
1295     PetscBool       sorted;
1296     const PetscInt *idx;
1297 
1298     PetscCall(ISGetLocalSize(is, &numIdx));
1299     PetscCall(ISGetIndices(is, &idx));
1300     PetscCall(ISSorted(is, &sorted));
1301     if (sorted) {
1302       PetscCall(PetscFindInt(key, numIdx, idx, location));
1303     } else {
1304       PetscInt i;
1305 
1306       *location = -1;
1307       for (i = 0; i < numIdx; i++) {
1308         if (idx[i] == key) {
1309           *location = i;
1310           break;
1311         }
1312       }
1313     }
1314     PetscCall(ISRestoreIndices(is, &idx));
1315   }
1316   PetscFunctionReturn(PETSC_SUCCESS);
1317 }
1318 
1319 /*@C
1320   ISRestoreIndices - Restores an index set to a usable state after a call to `ISGetIndices()`.
1321 
1322   Not Collective
1323 
1324   Input Parameters:
1325 + is  - the index set
1326 - ptr - the pointer obtained by `ISGetIndices()`
1327 
1328   Level: intermediate
1329 
1330   Fortran Note:
1331 .vb
1332   PetscInt, pointer :: ptr(:)
1333 .ve
1334 
1335 .seealso: `IS`, `ISGetIndices()`
1336 @*/
ISRestoreIndices(IS is,const PetscInt * ptr[])1337 PetscErrorCode ISRestoreIndices(IS is, const PetscInt *ptr[])
1338 {
1339   PetscFunctionBegin;
1340   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1341   PetscAssertPointer(ptr, 2);
1342   PetscTryTypeMethod(is, restoreindices, ptr);
1343   PetscFunctionReturn(PETSC_SUCCESS);
1344 }
1345 
ISGatherTotal_Private(IS is)1346 static PetscErrorCode ISGatherTotal_Private(IS is)
1347 {
1348   PetscInt        i, n, N;
1349   const PetscInt *lindices;
1350   MPI_Comm        comm;
1351   PetscMPIInt     rank, size, *sizes = NULL, *offsets = NULL, nn;
1352 
1353   PetscFunctionBegin;
1354   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1355 
1356   PetscCall(PetscObjectGetComm((PetscObject)is, &comm));
1357   PetscCallMPI(MPI_Comm_size(comm, &size));
1358   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1359   PetscCall(ISGetLocalSize(is, &n));
1360   PetscCall(PetscMalloc2(size, &sizes, size, &offsets));
1361 
1362   PetscCall(PetscMPIIntCast(n, &nn));
1363   PetscCallMPI(MPI_Allgather(&nn, 1, MPI_INT, sizes, 1, MPI_INT, comm));
1364   offsets[0] = 0;
1365   for (i = 1; i < size; ++i) offsets[i] = offsets[i - 1] + sizes[i - 1];
1366   N = offsets[size - 1] + sizes[size - 1];
1367 
1368   PetscCall(PetscMalloc1(N, &is->total));
1369   PetscCall(ISGetIndices(is, &lindices));
1370   PetscCallMPI(MPI_Allgatherv((void *)lindices, nn, MPIU_INT, is->total, sizes, offsets, MPIU_INT, comm));
1371   PetscCall(ISRestoreIndices(is, &lindices));
1372   is->local_offset = offsets[rank];
1373   PetscCall(PetscFree2(sizes, offsets));
1374   PetscFunctionReturn(PETSC_SUCCESS);
1375 }
1376 
1377 /*@C
1378   ISGetTotalIndices - Retrieve an array containing all indices across the communicator.
1379 
1380   Collective
1381 
1382   Input Parameter:
1383 . is - the index set
1384 
1385   Output Parameter:
1386 . indices - total indices with rank 0 indices first, and so on; total array size is
1387              the same as returned with `ISGetSize()`.
1388 
1389   Level: intermediate
1390 
1391   Notes:
1392   this is potentially nonscalable, but depends on the size of the total index set
1393   and the size of the communicator. This may be feasible for index sets defined on
1394   subcommunicators, such that the set size does not grow with `PETSC_WORLD_COMM`.
1395   Note also that there is no way to tell where the local part of the indices starts
1396   (use `ISGetIndices()` and `ISGetNonlocalIndices()` to retrieve just the local and just
1397   the nonlocal part (complement), respectively).
1398 
1399 .seealso: `IS`, `ISRestoreTotalIndices()`, `ISGetNonlocalIndices()`, `ISGetSize()`
1400 @*/
ISGetTotalIndices(IS is,const PetscInt * indices[])1401 PetscErrorCode ISGetTotalIndices(IS is, const PetscInt *indices[])
1402 {
1403   PetscMPIInt size;
1404 
1405   PetscFunctionBegin;
1406   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1407   PetscAssertPointer(indices, 2);
1408   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)is), &size));
1409   if (size == 1) {
1410     PetscUseTypeMethod(is, getindices, indices);
1411   } else {
1412     if (!is->total) PetscCall(ISGatherTotal_Private(is));
1413     *indices = is->total;
1414   }
1415   PetscFunctionReturn(PETSC_SUCCESS);
1416 }
1417 
1418 /*@C
1419   ISRestoreTotalIndices - Restore the index array obtained with `ISGetTotalIndices()`.
1420 
1421   Not Collective.
1422 
1423   Input Parameters:
1424 + is      - the index set
1425 - indices - index array; must be the array obtained with `ISGetTotalIndices()`
1426 
1427   Level: intermediate
1428 
1429 .seealso: `IS`, `ISGetNonlocalIndices()`
1430 @*/
ISRestoreTotalIndices(IS is,const PetscInt * indices[])1431 PetscErrorCode ISRestoreTotalIndices(IS is, const PetscInt *indices[])
1432 {
1433   PetscMPIInt size;
1434 
1435   PetscFunctionBegin;
1436   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1437   PetscAssertPointer(indices, 2);
1438   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)is), &size));
1439   if (size == 1) {
1440     PetscUseTypeMethod(is, restoreindices, indices);
1441   } else {
1442     PetscCheck(is->total == *indices, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Index array pointer being restored does not point to the array obtained from the IS.");
1443   }
1444   PetscFunctionReturn(PETSC_SUCCESS);
1445 }
1446 
1447 /*@C
1448   ISGetNonlocalIndices - Retrieve an array of indices from remote processors
1449   in this communicator.
1450 
1451   Collective
1452 
1453   Input Parameter:
1454 . is - the index set
1455 
1456   Output Parameter:
1457 . indices - indices with rank 0 indices first, and so on,  omitting
1458              the current rank.  Total number of indices is the difference
1459              total and local, obtained with `ISGetSize()` and `ISGetLocalSize()`,
1460              respectively.
1461 
1462   Level: intermediate
1463 
1464   Notes:
1465   Restore the indices using `ISRestoreNonlocalIndices()`.
1466 
1467   The same scalability considerations as those for `ISGetTotalIndices()` apply here.
1468 
1469 .seealso: `IS`, `ISGetTotalIndices()`, `ISRestoreNonlocalIndices()`, `ISGetSize()`, `ISGetLocalSize().`
1470 @*/
ISGetNonlocalIndices(IS is,const PetscInt * indices[])1471 PetscErrorCode ISGetNonlocalIndices(IS is, const PetscInt *indices[])
1472 {
1473   PetscMPIInt size;
1474   PetscInt    n, N;
1475 
1476   PetscFunctionBegin;
1477   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1478   PetscAssertPointer(indices, 2);
1479   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)is), &size));
1480   if (size == 1) *indices = NULL;
1481   else {
1482     if (!is->total) PetscCall(ISGatherTotal_Private(is));
1483     PetscCall(ISGetLocalSize(is, &n));
1484     PetscCall(ISGetSize(is, &N));
1485     PetscCall(PetscMalloc1(N - n, &is->nonlocal));
1486     PetscCall(PetscArraycpy(is->nonlocal, is->total, is->local_offset));
1487     PetscCall(PetscArraycpy(is->nonlocal + is->local_offset, is->total + is->local_offset + n, N - is->local_offset - n));
1488     *indices = is->nonlocal;
1489   }
1490   PetscFunctionReturn(PETSC_SUCCESS);
1491 }
1492 
1493 /*@C
1494   ISRestoreNonlocalIndices - Restore the index array obtained with `ISGetNonlocalIndices()`.
1495 
1496   Not Collective.
1497 
1498   Input Parameters:
1499 + is      - the index set
1500 - indices - index array; must be the array obtained with `ISGetNonlocalIndices()`
1501 
1502   Level: intermediate
1503 
1504 .seealso: `IS`, `ISGetTotalIndices()`, `ISGetNonlocalIndices()`, `ISRestoreTotalIndices()`
1505 @*/
ISRestoreNonlocalIndices(IS is,const PetscInt * indices[])1506 PetscErrorCode ISRestoreNonlocalIndices(IS is, const PetscInt *indices[])
1507 {
1508   PetscFunctionBegin;
1509   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1510   PetscAssertPointer(indices, 2);
1511   PetscCheck(is->nonlocal == *indices, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Index array pointer being restored does not point to the array obtained from the IS.");
1512   PetscFunctionReturn(PETSC_SUCCESS);
1513 }
1514 
1515 /*@
1516   ISGetNonlocalIS - Gather all nonlocal indices for this `IS` and present
1517   them as another sequential index set.
1518 
1519   Collective
1520 
1521   Input Parameter:
1522 . is - the index set
1523 
1524   Output Parameter:
1525 . complement - sequential `IS` with indices identical to the result of
1526                 `ISGetNonlocalIndices()`
1527 
1528   Level: intermediate
1529 
1530   Notes:
1531   Complement represents the result of `ISGetNonlocalIndices()` as an `IS`.
1532   Therefore scalability issues similar to `ISGetNonlocalIndices()` apply.
1533 
1534   The resulting `IS` must be restored using `ISRestoreNonlocalIS()`.
1535 
1536 .seealso: `IS`, `ISGetNonlocalIndices()`, `ISRestoreNonlocalIndices()`, `ISAllGather()`, `ISGetSize()`
1537 @*/
ISGetNonlocalIS(IS is,IS * complement)1538 PetscErrorCode ISGetNonlocalIS(IS is, IS *complement)
1539 {
1540   PetscFunctionBegin;
1541   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1542   PetscAssertPointer(complement, 2);
1543   /* Check if the complement exists already. */
1544   if (is->complement) {
1545     *complement = is->complement;
1546     PetscCall(PetscObjectReference((PetscObject)is->complement));
1547   } else {
1548     PetscInt        N, n;
1549     const PetscInt *idx;
1550     PetscCall(ISGetSize(is, &N));
1551     PetscCall(ISGetLocalSize(is, &n));
1552     PetscCall(ISGetNonlocalIndices(is, &idx));
1553     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, N - n, idx, PETSC_USE_POINTER, &is->complement));
1554     PetscCall(PetscObjectReference((PetscObject)is->complement));
1555     *complement = is->complement;
1556   }
1557   PetscFunctionReturn(PETSC_SUCCESS);
1558 }
1559 
1560 /*@
1561   ISRestoreNonlocalIS - Restore the `IS` obtained with `ISGetNonlocalIS()`.
1562 
1563   Not collective.
1564 
1565   Input Parameters:
1566 + is         - the index set
1567 - complement - index set of `is`'s nonlocal indices
1568 
1569   Level: intermediate
1570 
1571 .seealso: `IS`, `ISGetNonlocalIS()`, `ISGetNonlocalIndices()`, `ISRestoreNonlocalIndices()`
1572 @*/
ISRestoreNonlocalIS(IS is,IS * complement)1573 PetscErrorCode ISRestoreNonlocalIS(IS is, IS *complement)
1574 {
1575   PetscInt refcnt;
1576 
1577   PetscFunctionBegin;
1578   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1579   PetscAssertPointer(complement, 2);
1580   PetscCheck(*complement == is->complement, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Complement IS being restored was not obtained with ISGetNonlocalIS()");
1581   PetscCall(PetscObjectGetReference((PetscObject)is->complement, &refcnt));
1582   PetscCheck(refcnt > 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Duplicate call to ISRestoreNonlocalIS() detected");
1583   PetscCall(PetscObjectDereference((PetscObject)is->complement));
1584   PetscFunctionReturn(PETSC_SUCCESS);
1585 }
1586 
1587 /*@
1588   ISViewFromOptions - View an `IS` based on options in the options database
1589 
1590   Collective
1591 
1592   Input Parameters:
1593 + A    - the index set
1594 . obj  - Optional object that provides the prefix for the options database
1595 - name - command line option
1596 
1597   Level: intermediate
1598 
1599   Note:
1600   See `PetscObjectViewFromOptions()` for possible `PetscViewer` and `PetscViewerFormat` values
1601 
1602 .seealso: `IS`, `ISView()`, `PetscObjectViewFromOptions()`, `ISCreate()`
1603 @*/
ISViewFromOptions(IS A,PetscObject obj,const char name[])1604 PetscErrorCode ISViewFromOptions(IS A, PetscObject obj, const char name[])
1605 {
1606   PetscFunctionBegin;
1607   PetscValidHeaderSpecific(A, IS_CLASSID, 1);
1608   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
1609   PetscFunctionReturn(PETSC_SUCCESS);
1610 }
1611 
1612 /*@
1613   ISView - Displays an index set.
1614 
1615   Collective
1616 
1617   Input Parameters:
1618 + is     - the index set
1619 - viewer - viewer used to display the set, for example `PETSC_VIEWER_STDOUT_SELF`.
1620 
1621   Level: intermediate
1622 
1623 .seealso: `IS`, `PetscViewer`, `PetscViewerASCIIOpen()`, `ISViewFromOptions()`
1624 @*/
ISView(IS is,PetscViewer viewer)1625 PetscErrorCode ISView(IS is, PetscViewer viewer)
1626 {
1627   PetscFunctionBegin;
1628   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1629   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)is), &viewer));
1630   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1631   PetscCheckSameComm(is, 1, viewer, 2);
1632 
1633   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)is, viewer));
1634   PetscCall(PetscLogEventBegin(IS_View, is, viewer, 0, 0));
1635   PetscUseTypeMethod(is, view, viewer);
1636   PetscCall(PetscLogEventEnd(IS_View, is, viewer, 0, 0));
1637   PetscFunctionReturn(PETSC_SUCCESS);
1638 }
1639 
1640 /*@
1641   ISLoad - Loads an index set that has been stored in binary or HDF5 format with `ISView()`.
1642 
1643   Collective
1644 
1645   Input Parameters:
1646 + is     - the newly loaded index set, this needs to have been created with `ISCreate()` or some related function before a call to `ISLoad()`.
1647 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or HDF5 file viewer, obtained from `PetscViewerHDF5Open()`
1648 
1649   Level: intermediate
1650 
1651   Notes:
1652   IF using HDF5, you must assign the IS the same name as was used in `is`
1653   that was stored in the file using `PetscObjectSetName()`. Otherwise you will
1654   get the error message: "Cannot H5DOpen2() with Vec name NAMEOFOBJECT"
1655 
1656 .seealso: `IS`, `PetscViewerBinaryOpen()`, `ISView()`, `MatLoad()`, `VecLoad()`
1657 @*/
ISLoad(IS is,PetscViewer viewer)1658 PetscErrorCode ISLoad(IS is, PetscViewer viewer)
1659 {
1660   PetscBool isbinary, ishdf5;
1661 
1662   PetscFunctionBegin;
1663   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1664   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1665   PetscCheckSameComm(is, 1, viewer, 2);
1666   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
1667   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1668   PetscCheck(isbinary || ishdf5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen()");
1669   if (!((PetscObject)is)->type_name) PetscCall(ISSetType(is, ISGENERAL));
1670   PetscCall(PetscLogEventBegin(IS_Load, is, viewer, 0, 0));
1671   PetscUseTypeMethod(is, load, viewer);
1672   PetscCall(PetscLogEventEnd(IS_Load, is, viewer, 0, 0));
1673   PetscFunctionReturn(PETSC_SUCCESS);
1674 }
1675 
1676 /*@
1677   ISSort - Sorts the indices of an index set.
1678 
1679   Collective
1680 
1681   Input Parameter:
1682 . is - the index set
1683 
1684   Level: intermediate
1685 
1686 .seealso: `IS`, `ISSortRemoveDups()`, `ISSorted()`
1687 @*/
ISSort(IS is)1688 PetscErrorCode ISSort(IS is)
1689 {
1690   PetscBool flg;
1691 
1692   PetscFunctionBegin;
1693   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1694   PetscCall(ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_FALSE, &flg));
1695   if (!flg) {
1696     PetscUseTypeMethod(is, sort);
1697     PetscCall(ISSetInfo(is, IS_SORTED, IS_LOCAL, is->info_permanent[IS_LOCAL][IS_SORTED], PETSC_TRUE));
1698   }
1699   PetscFunctionReturn(PETSC_SUCCESS);
1700 }
1701 
1702 /*@
1703   ISSortRemoveDups - Sorts the indices of an index set, removing duplicates.
1704 
1705   Collective
1706 
1707   Input Parameter:
1708 . is - the index set
1709 
1710   Level: intermediate
1711 
1712 .seealso: `IS`, `ISSort()`, `ISSorted()`
1713 @*/
ISSortRemoveDups(IS is)1714 PetscErrorCode ISSortRemoveDups(IS is)
1715 {
1716   PetscFunctionBegin;
1717   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1718   PetscCall(ISClearInfoCache(is, PETSC_FALSE));
1719   PetscUseTypeMethod(is, sortremovedups);
1720   PetscCall(ISSetInfo(is, IS_SORTED, IS_LOCAL, is->info_permanent[IS_LOCAL][IS_SORTED], PETSC_TRUE));
1721   PetscCall(ISSetInfo(is, IS_UNIQUE, IS_LOCAL, is->info_permanent[IS_LOCAL][IS_UNIQUE], PETSC_TRUE));
1722   PetscFunctionReturn(PETSC_SUCCESS);
1723 }
1724 
1725 /*@
1726   ISToGeneral - Converts an IS object of any type to `ISGENERAL` type
1727 
1728   Collective
1729 
1730   Input Parameter:
1731 . is - the index set
1732 
1733   Level: intermediate
1734 
1735 .seealso: `IS`, `ISSorted()`
1736 @*/
ISToGeneral(IS is)1737 PetscErrorCode ISToGeneral(IS is)
1738 {
1739   PetscFunctionBegin;
1740   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1741   PetscUseTypeMethod(is, togeneral);
1742   PetscFunctionReturn(PETSC_SUCCESS);
1743 }
1744 
1745 /*@
1746   ISSorted - Checks the indices to determine whether they have been sorted.
1747 
1748   Not Collective
1749 
1750   Input Parameter:
1751 . is - the index set
1752 
1753   Output Parameter:
1754 . flg - output flag, either `PETSC_TRUE` if the index set is sorted,
1755          or `PETSC_FALSE` otherwise.
1756 
1757   Level: intermediate
1758 
1759   Note:
1760   For parallel IS objects this only indicates if the local part of `is`
1761   is sorted. So some processors may return `PETSC_TRUE` while others may
1762   return `PETSC_FALSE`.
1763 
1764 .seealso: `ISSort()`, `ISSortRemoveDups()`
1765 @*/
ISSorted(IS is,PetscBool * flg)1766 PetscErrorCode ISSorted(IS is, PetscBool *flg)
1767 {
1768   PetscFunctionBegin;
1769   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1770   PetscAssertPointer(flg, 2);
1771   PetscCall(ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, flg));
1772   PetscFunctionReturn(PETSC_SUCCESS);
1773 }
1774 
1775 /*@
1776   ISDuplicate - Creates a duplicate copy of an index set.
1777 
1778   Collective
1779 
1780   Input Parameter:
1781 . is - the index set
1782 
1783   Output Parameter:
1784 . newIS - the copy of the index set
1785 
1786   Level: beginner
1787 
1788 .seealso: `IS`, `ISCreateGeneral()`, `ISCopy()`
1789 @*/
ISDuplicate(IS is,IS * newIS)1790 PetscErrorCode ISDuplicate(IS is, IS *newIS)
1791 {
1792   PetscFunctionBegin;
1793   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1794   PetscAssertPointer(newIS, 2);
1795   PetscUseTypeMethod(is, duplicate, newIS);
1796   PetscCall(ISCopyInfo_Private(is, *newIS));
1797   PetscFunctionReturn(PETSC_SUCCESS);
1798 }
1799 
1800 /*@
1801   ISCopy - Copies an index set.
1802 
1803   Collective
1804 
1805   Input Parameter:
1806 . is - the index set
1807 
1808   Output Parameter:
1809 . isy - the copy of the index set
1810 
1811   Level: beginner
1812 
1813 .seealso: `IS`, `ISDuplicate()`, `ISShift()`
1814 @*/
ISCopy(IS is,IS isy)1815 PetscErrorCode ISCopy(IS is, IS isy)
1816 {
1817   PetscInt bs, bsy;
1818 
1819   PetscFunctionBegin;
1820   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1821   PetscValidHeaderSpecific(isy, IS_CLASSID, 2);
1822   PetscCheckSameComm(is, 1, isy, 2);
1823   if (is == isy) PetscFunctionReturn(PETSC_SUCCESS);
1824   PetscCall(PetscLayoutGetBlockSize(is->map, &bs));
1825   PetscCall(PetscLayoutGetBlockSize(isy->map, &bsy));
1826   PetscCheck(is->map->N == isy->map->N, PetscObjectComm((PetscObject)is), PETSC_ERR_ARG_INCOMP, "Index sets have different global size %" PetscInt_FMT " != %" PetscInt_FMT, is->map->N, isy->map->N);
1827   PetscCheck(is->map->n == isy->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Index sets have different local size %" PetscInt_FMT " != %" PetscInt_FMT, is->map->n, isy->map->n);
1828   PetscCheck(bs == bsy, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Index sets have different block size %" PetscInt_FMT " != %" PetscInt_FMT, bs, bsy);
1829   PetscCall(ISCopyInfo_Private(is, isy));
1830   isy->max = is->max;
1831   isy->min = is->min;
1832   PetscUseTypeMethod(is, copy, isy);
1833   PetscFunctionReturn(PETSC_SUCCESS);
1834 }
1835 
1836 /*@
1837   ISShift - Shift all indices by given offset
1838 
1839   Collective
1840 
1841   Input Parameters:
1842 + is     - the index set
1843 - offset - the offset
1844 
1845   Output Parameter:
1846 . isy - the shifted copy of the input index set
1847 
1848   Level: beginner
1849 
1850   Notes:
1851   The `offset` can be different across processes.
1852 
1853   `is` and `isy` can be the same.
1854 
1855 .seealso: `ISDuplicate()`, `ISCopy()`
1856 @*/
ISShift(IS is,PetscInt offset,IS isy)1857 PetscErrorCode ISShift(IS is, PetscInt offset, IS isy)
1858 {
1859   PetscFunctionBegin;
1860   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1861   PetscValidHeaderSpecific(isy, IS_CLASSID, 3);
1862   PetscCheckSameComm(is, 1, isy, 3);
1863   if (!offset) {
1864     PetscCall(ISCopy(is, isy));
1865     PetscFunctionReturn(PETSC_SUCCESS);
1866   }
1867   PetscCheck(is->map->N == isy->map->N, PetscObjectComm((PetscObject)is), PETSC_ERR_ARG_INCOMP, "Index sets have different global size %" PetscInt_FMT " != %" PetscInt_FMT, is->map->N, isy->map->N);
1868   PetscCheck(is->map->n == isy->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Index sets have different local size %" PetscInt_FMT " != %" PetscInt_FMT, is->map->n, isy->map->n);
1869   PetscCheck(is->map->bs == isy->map->bs, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Index sets have different block size %" PetscInt_FMT " != %" PetscInt_FMT, is->map->bs, isy->map->bs);
1870   PetscCall(ISCopyInfo_Private(is, isy));
1871   isy->max = is->max + offset;
1872   isy->min = is->min + offset;
1873   PetscUseMethod(is, "ISShift_C", (IS, PetscInt, IS), (is, offset, isy));
1874   PetscFunctionReturn(PETSC_SUCCESS);
1875 }
1876 
1877 /*@
1878   ISOnComm - Split a parallel `IS` on subcomms (usually self) or concatenate index sets on subcomms into a parallel index set
1879 
1880   Collective
1881 
1882   Input Parameters:
1883 + is   - index set
1884 . comm - communicator for new index set
1885 - mode - copy semantics, `PETSC_USE_POINTER` for no-copy if possible, otherwise `PETSC_COPY_VALUES`
1886 
1887   Output Parameter:
1888 . newis - new `IS` on `comm`
1889 
1890   Level: advanced
1891 
1892   Notes:
1893   It is usually desirable to create a parallel `IS` and look at the local part when necessary.
1894 
1895   This function is useful if serial `IS`s must be created independently, or to view many
1896   logically independent serial `IS`s.
1897 
1898   The input `IS` must have the same type on every MPI process.
1899 
1900 .seealso: `IS`
1901 @*/
ISOnComm(IS is,MPI_Comm comm,PetscCopyMode mode,IS * newis)1902 PetscErrorCode ISOnComm(IS is, MPI_Comm comm, PetscCopyMode mode, IS *newis)
1903 {
1904   PetscMPIInt match;
1905 
1906   PetscFunctionBegin;
1907   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1908   PetscAssertPointer(newis, 4);
1909   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)is), comm, &match));
1910   if (mode != PETSC_COPY_VALUES && (match == MPI_IDENT || match == MPI_CONGRUENT)) {
1911     PetscCall(PetscObjectReference((PetscObject)is));
1912     *newis = is;
1913   } else PetscUseTypeMethod(is, oncomm, comm, mode, newis);
1914   PetscFunctionReturn(PETSC_SUCCESS);
1915 }
1916 
1917 /*@
1918   ISSetBlockSize - informs an index set that it has a given block size
1919 
1920   Logicall Collective
1921 
1922   Input Parameters:
1923 + is - index set
1924 - bs - block size
1925 
1926   Level: intermediate
1927 
1928   Notes:
1929   This is much like the block size for `Vec`s. It indicates that one can think of the indices as
1930   being in a collection of equal size blocks. For `ISBLOCK` these collections of blocks are all contiguous
1931   within a block but this is not the case for other `IS`. For example, an `IS` with entries {0, 2, 3, 4, 6, 7} could
1932   have a block size of three set.
1933 
1934   `ISBlockGetIndices()` only works for `ISBLOCK`, not others.
1935 
1936 .seealso: `IS`, `ISGetBlockSize()`, `ISCreateBlock()`, `ISBlockGetIndices()`,
1937 @*/
ISSetBlockSize(IS is,PetscInt bs)1938 PetscErrorCode ISSetBlockSize(IS is, PetscInt bs)
1939 {
1940   PetscFunctionBegin;
1941   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1942   PetscValidLogicalCollectiveInt(is, bs, 2);
1943   PetscCheck(bs >= 1, PetscObjectComm((PetscObject)is), PETSC_ERR_ARG_OUTOFRANGE, "Block size %" PetscInt_FMT ", must be positive", bs);
1944   if (PetscDefined(USE_DEBUG)) {
1945     const PetscInt *indices;
1946     PetscInt        length, i, j;
1947     PetscCall(ISGetIndices(is, &indices));
1948     if (indices) {
1949       PetscCall(ISGetLocalSize(is, &length));
1950       PetscCheck(length % bs == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local size %" PetscInt_FMT " not compatible with proposed block size %" PetscInt_FMT, length, bs);
1951       for (i = 1; i < length / bs; i += bs) {
1952         for (j = 1; j < bs - 1; j++) {
1953           PetscCheck(indices[i * bs + j] == indices[(i - 1) * bs + j] + indices[i * bs] - indices[(i - 1) * bs], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Proposed block size %" PetscInt_FMT " is incompatible with the indices", bs);
1954         }
1955       }
1956     }
1957     PetscCall(ISRestoreIndices(is, &indices));
1958   }
1959   PetscUseTypeMethod(is, setblocksize, bs);
1960   PetscFunctionReturn(PETSC_SUCCESS);
1961 }
1962 
1963 /*@
1964   ISGetBlockSize - Returns the number of elements in a block.
1965 
1966   Not Collective
1967 
1968   Input Parameter:
1969 . is - the index set
1970 
1971   Output Parameter:
1972 . size - the number of elements in a block
1973 
1974   Level: intermediate
1975 
1976   Note:
1977   See `ISSetBlockSize()`
1978 
1979 .seealso: `IS`, `ISBlockGetSize()`, `ISGetSize()`, `ISCreateBlock()`, `ISSetBlockSize()`
1980 @*/
ISGetBlockSize(IS is,PetscInt * size)1981 PetscErrorCode ISGetBlockSize(IS is, PetscInt *size)
1982 {
1983   PetscFunctionBegin;
1984   PetscCall(PetscLayoutGetBlockSize(is->map, size));
1985   PetscFunctionReturn(PETSC_SUCCESS);
1986 }
1987 
1988 /*@
1989   ISSetCompressOutput - set the flag for output compression
1990 
1991   Logicall Collective
1992 
1993   Input Parameters:
1994 + is       - index set
1995 - compress - flag for output compression
1996 
1997   Level: intermediate
1998 
1999 .seealso: `IS`, `ISGetCompressOutput()`, `ISView()`
2000 @*/
ISSetCompressOutput(IS is,PetscBool compress)2001 PetscErrorCode ISSetCompressOutput(IS is, PetscBool compress)
2002 {
2003   PetscFunctionBegin;
2004   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
2005   PetscValidLogicalCollectiveBool(is, compress, 2);
2006   is->compressOutput = compress;
2007   PetscFunctionReturn(PETSC_SUCCESS);
2008 }
2009 
2010 /*@
2011   ISGetCompressOutput - Returns the flag for output compression
2012 
2013   Not Collective
2014 
2015   Input Parameter:
2016 . is - the index set
2017 
2018   Output Parameter:
2019 . compress - the flag to compress output
2020 
2021   Level: intermediate
2022 
2023 .seealso: `IS`, `ISSetCompressOutput()`, `ISView()`
2024 @*/
ISGetCompressOutput(IS is,PetscBool * compress)2025 PetscErrorCode ISGetCompressOutput(IS is, PetscBool *compress)
2026 {
2027   PetscFunctionBegin;
2028   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
2029   PetscAssertPointer(compress, 2);
2030   *compress = is->compressOutput;
2031   PetscFunctionReturn(PETSC_SUCCESS);
2032 }
2033 
ISGetIndicesCopy_Private(IS is,PetscInt idx[])2034 static PetscErrorCode ISGetIndicesCopy_Private(IS is, PetscInt idx[])
2035 {
2036   PetscInt        len, i;
2037   const PetscInt *ptr;
2038 
2039   PetscFunctionBegin;
2040   PetscCall(ISGetLocalSize(is, &len));
2041   PetscCall(ISGetIndices(is, &ptr));
2042   for (i = 0; i < len; i++) idx[i] = ptr[i];
2043   PetscCall(ISRestoreIndices(is, &ptr));
2044   PetscFunctionReturn(PETSC_SUCCESS);
2045 }
2046