Actual source code: index.c

  1: /*
  2:    Defines the abstract operations on index sets, i.e. the public interface.
  3: */
  4: #include <petsc/private/isimpl.h>
  5: #include <petscviewer.h>
  6: #include <petscsf.h>

  8: /* Logging support */
  9: PetscClassId IS_CLASSID;
 10: /* TODO: Much more events are missing! */
 11: PetscLogEvent IS_View;
 12: PetscLogEvent IS_Load;

 14: /*@
 15:   ISRenumber - Renumbers the non-negative entries of an index set in a contiguous way, starting from 0.

 17:   Collective

 19:   Input Parameters:
 20: + subset      - the index set
 21: - subset_mult - the multiplicity of each entry in subset (optional, can be `NULL`)

 23:   Output Parameters:
 24: + N        - one past the largest entry of the new `IS`
 25: - subset_n - the new `IS`

 27:   Level: intermediate

 29:   Note:
 30:   All negative entries are mapped to -1. Indices with non positive multiplicities are skipped.

 32: .seealso: `IS`
 33: @*/
 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;

 45:   PetscFunctionBegin;
 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:   }

 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;

 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:   }

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));

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));

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));

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:   }

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

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:   }

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:   }

163:   /* adapt root data with cumulative */
164:   if (first_found) {
165:     PetscInt old_index;

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:   }

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));

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;

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;

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: }

208: /*@
209:   ISCreateSubIS - Create a sub index set from a global index set selecting some components.

211:   Collective

213:   Input Parameters:
214: + is    - the index set
215: - comps - which components we will extract from `is`

217:   Output Parameters:
218: . subis - the new sub index set

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|

228:   Level: intermediate

230: .seealso: `IS`, `VecGetSubVector()`, `MatCreateSubMatrix()`
231: @*/
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;

241:   PetscFunctionBegin;
244:   PetscAssertPointer(subis, 3);

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));

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: }

282: /*@
283:   ISClearInfoCache - clear the cache of computed index set properties

285:   Not Collective

287:   Input Parameters:
288: + is                    - the index set
289: - clear_permanent_local - whether to remove the permanent status of local properties

291:   Level: developer

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

297: .seealso: `IS`, `ISInfo`, `ISInfoType`, `ISSetInfo()`
298: @*/
299: PetscErrorCode ISClearInfoCache(IS is, PetscBool clear_permanent_local)
300: {
301:   PetscInt i, j;

303:   PetscFunctionBegin;
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: }

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;

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;

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: }

428: // PetscClangLinter pragma disable: -fdoc-section-header-unknown
429: /*@
430:   ISSetInfo - Set known information about an index set.

432:   Logically Collective if `ISInfoType` is `IS_GLOBAL`

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`)

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}

450:   Level: advanced

452:   Notes:
453:   If type is `IS_GLOBAL`, all processes that share the index set must pass the same value in flg

455:   It is possible to set a property with `ISSetInfo()` that contradicts what would be previously computed with `ISGetInfo()`

457: .seealso: `ISInfo`, `ISInfoType`, `IS`
458: @*/
459: PetscErrorCode ISSetInfo(IS is, ISInfo info, ISInfoType type, PetscBool permanent, PetscBool flg)
460: {
461:   MPI_Comm    comm, errcomm;
462:   PetscMPIInt size;

464:   PetscFunctionBegin;
467:   comm = PetscObjectComm((PetscObject)is);
468:   if (type == IS_GLOBAL) {
472:     errcomm = comm;
473:   } else {
474:     errcomm = PETSC_COMM_SELF;
475:   }

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);

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: }

486: static PetscErrorCode ISGetInfo_Sorted_Private(IS is, ISInfoType type, PetscBool *flg)
487: {
488:   MPI_Comm    comm;
489:   PetscMPIInt size, rank;

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;

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;

511:       PetscCall(ISGetIndices(is, &idx));
512:       PetscCall(ISGetLocalSize(is, &n));
513:       PetscCall(PetscSortedInt(n, idx, &sortedLocal));
514:       PetscCall(ISRestoreIndices(is, &idx));
515:     }

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;

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: }

537: static PetscErrorCode ISGetIndicesCopy_Private(IS is, PetscInt idx[]);

539: static PetscErrorCode ISGetInfo_Unique_Private(IS is, ISInfoType type, PetscBool *flg)
540: {
541:   MPI_Comm    comm;
542:   PetscMPIInt size, rank;
543:   PetscInt    i;

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;

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:     }

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;

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: }

606: static PetscErrorCode ISGetInfo_Permutation(IS is, ISInfoType type, PetscBool *flg)
607: {
608:   MPI_Comm    comm;
609:   PetscMPIInt size;

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;

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: }

648: static PetscErrorCode ISGetInfo_Interval(IS is, ISInfoType type, PetscBool *flg)
649: {
650:   MPI_Comm    comm;
651:   PetscMPIInt size, rank;
652:   PetscInt    i;

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;

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:     }

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;

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: }

702: static PetscErrorCode ISGetInfo_Identity(IS is, ISInfoType type, PetscBool *flg)
703: {
704:   MPI_Comm    comm;
705:   PetscMPIInt size;

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;

713:     PetscUseTypeMethod(is, intervalglobal, &isinterval);
714:     *flg = PETSC_FALSE;
715:     if (isinterval) {
716:       PetscInt min;

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;

725:     PetscUseTypeMethod(is, intervallocal, &isinterval);
726:     *flg = PETSC_FALSE;
727:     if (isinterval) {
728:       PetscInt min;

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;

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: }

756: /*@
757:   ISGetInfo - Determine whether an index set satisfies a given property

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()`)

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`)

767:   Output Parameter:
768: . flg - whether the property is true (`PETSC_TRUE`) or false (`PETSC_FALSE`)

770:   Level: advanced

772:   Notes:
773:   `ISGetInfo()` uses cached values when possible, which will be incorrect if `ISSetInfo()` has been called with incorrect information.

775:   To clear cached values, use `ISClearInfoCache()`.

777: .seealso: `IS`, `ISInfo`, `ISInfoType`, `ISSetInfo()`, `ISClearInfoCache()`
778: @*/
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;

787:   PetscFunctionBegin;
790:   comm = PetscObjectComm((PetscObject)is);
791:   if (type == IS_GLOBAL) {
793:     errcomm = comm;
794:   } else {
795:     errcomm = PETSC_COMM_SELF;
796:   }

798:   PetscCallMPI(MPI_Comm_size(comm, &size));
799:   PetscCallMPI(MPI_Comm_rank(comm, &rank));

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: }

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: }

851: /*@
852:   ISIdentity - Determines whether index set is the identity mapping.

854:   Collective

856:   Input Parameter:
857: . is - the index set

859:   Output Parameter:
860: . ident - `PETSC_TRUE` if an identity, else `PETSC_FALSE`

862:   Level: intermediate

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.

871: .seealso: `IS`, `ISSetIdentity()`, `ISGetInfo()`
872: @*/
873: PetscErrorCode ISIdentity(IS is, PetscBool *ident)
874: {
875:   PetscFunctionBegin;
877:   PetscAssertPointer(ident, 2);
878:   PetscCall(ISGetInfo(is, IS_IDENTITY, IS_GLOBAL, PETSC_TRUE, ident));
879:   PetscFunctionReturn(PETSC_SUCCESS);
880: }

882: /*@
883:   ISSetIdentity - Informs the index set that it is an identity.

885:   Logically Collective

887:   Input Parameter:
888: . is - the index set

890:   Level: intermediate

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.

896:   To clear this property, use `ISClearInfoCache()`.

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?

901: .seealso: `IS`, `ISIdentity()`, `ISSetInfo()`, `ISClearInfoCache()`
902: @*/
903: PetscErrorCode ISSetIdentity(IS is)
904: {
905:   PetscFunctionBegin;
907:   PetscCall(ISSetInfo(is, IS_IDENTITY, IS_GLOBAL, PETSC_TRUE, PETSC_TRUE));
908:   PetscFunctionReturn(PETSC_SUCCESS);
909: }

911: /*@
912:   ISContiguousLocal - Locates an index set with contiguous range within a global range, if possible

914:   Not Collective

916:   Input Parameters:
917: + is     - the index set
918: . gstart - global start
919: - gend   - global end

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`

925:   Level: developer

927: .seealso: `IS`, `ISGetLocalSize()`, `VecGetOwnershipRange()`
928: @*/
929: PetscErrorCode ISContiguousLocal(IS is, PetscInt gstart, PetscInt gend, PetscInt *start, PetscBool *contig)
930: {
931:   PetscFunctionBegin;
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: }

942: /*@
943:   ISPermutation - `PETSC_TRUE` or `PETSC_FALSE` depending on whether the
944:   index set has been declared to be a permutation.

946:   Logically Collective

948:   Input Parameter:
949: . is - the index set

951:   Output Parameter:
952: . perm - `PETSC_TRUE` if a permutation, else `PETSC_FALSE`

954:   Level: intermediate

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`.

963:   Developer Notes:
964:   Perhaps some of these routines should use the `PetscBool3` enum to return appropriate values

966: .seealso: `IS`, `ISSetPermutation()`, `ISGetInfo()`
967: @*/
968: PetscErrorCode ISPermutation(IS is, PetscBool *perm)
969: {
970:   PetscFunctionBegin;
972:   PetscAssertPointer(perm, 2);
973:   PetscCall(ISGetInfo(is, IS_PERMUTATION, IS_GLOBAL, PETSC_FALSE, perm));
974:   PetscFunctionReturn(PETSC_SUCCESS);
975: }

977: /*@
978:   ISSetPermutation - Informs the index set that it is a permutation.

980:   Logically Collective

982:   Input Parameter:
983: . is - the index set

985:   Level: intermediate

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.

991:   To clear this property, use `ISClearInfoCache()`.

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.

996: .seealso: `IS`, `ISPermutation()`, `ISSetInfo()`, `ISClearInfoCache().`
997: @*/
998: PetscErrorCode ISSetPermutation(IS is)
999: {
1000:   PetscFunctionBegin;
1002:   if (PetscDefined(USE_DEBUG)) {
1003:     PetscMPIInt size;

1005:     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)is), &size));
1006:     if (size == 1) {
1007:       PetscInt        i, n, *idx;
1008:       const PetscInt *iidx;

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: }

1024: /*@
1025:   ISDestroy - Destroys an index set.

1027:   Collective

1029:   Input Parameter:
1030: . is - the index set

1032:   Level: beginner

1034: .seealso: `IS`, `ISCreateGeneral()`, `ISCreateStride()`, `ISCreateBlock()`
1035: @*/
1036: PetscErrorCode ISDestroy(IS *is)
1037: {
1038:   PetscFunctionBegin;
1039:   if (!*is) PetscFunctionReturn(PETSC_SUCCESS);
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: }

1060: /*@
1061:   ISInvertPermutation - Creates a new permutation that is the inverse of
1062:   a given permutation.

1064:   Collective

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`

1071:   Output Parameter:
1072: . isout - the inverse permutation

1074:   Level: intermediate

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).

1080: .seealso: `IS`, `ISGetInfo()`, `ISSetPermutation()`, `ISGetPermutation()`
1081: @*/
1082: PetscErrorCode ISInvertPermutation(IS is, PetscInt nlocal, IS *isout)
1083: {
1084:   PetscBool isperm, isidentity, issame;

1086:   PetscFunctionBegin;
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;

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: }

1111: /*@
1112:   ISGetSize - Returns the global length of an index set.

1114:   Not Collective

1116:   Input Parameter:
1117: . is - the index set

1119:   Output Parameter:
1120: . size - the global size

1122:   Level: beginner

1124: .seealso: `IS`
1125: @*/
1126: PetscErrorCode ISGetSize(IS is, PetscInt *size)
1127: {
1128:   PetscFunctionBegin;
1130:   PetscAssertPointer(size, 2);
1131:   *size = is->map->N;
1132:   PetscFunctionReturn(PETSC_SUCCESS);
1133: }

1135: /*@
1136:   ISGetLocalSize - Returns the local (processor) length of an index set.

1138:   Not Collective

1140:   Input Parameter:
1141: . is - the index set

1143:   Output Parameter:
1144: . size - the local size

1146:   Level: beginner

1148: .seealso: `IS`, `ISGetSize()`
1149: @*/
1150: PetscErrorCode ISGetLocalSize(IS is, PetscInt *size)
1151: {
1152:   PetscFunctionBegin;
1154:   PetscAssertPointer(size, 2);
1155:   *size = is->map->n;
1156:   PetscFunctionReturn(PETSC_SUCCESS);
1157: }

1159: /*@
1160:   ISGetLayout - get `PetscLayout` describing index set layout

1162:   Not Collective

1164:   Input Parameter:
1165: . is - the index set

1167:   Output Parameter:
1168: . map - the layout

1170:   Level: developer

1172: .seealso: `IS`, `PetscLayout`, `ISSetLayout()`, `ISGetSize()`, `ISGetLocalSize()`
1173: @*/
1174: PetscErrorCode ISGetLayout(IS is, PetscLayout *map)
1175: {
1176:   PetscFunctionBegin;
1178:   PetscAssertPointer(map, 2);
1179:   *map = is->map;
1180:   PetscFunctionReturn(PETSC_SUCCESS);
1181: }

1183: /*@
1184:   ISSetLayout - set `PetscLayout` describing index set layout

1186:   Collective

1188:   Input Parameters:
1189: + is  - the index set
1190: - map - the layout

1192:   Level: developer

1194:   Notes:
1195:   Users should typically use higher level functions such as `ISCreateGeneral()`.

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.

1200: .seealso: `IS`, `PetscLayout`, `ISCreate()`, `ISGetLayout()`, `ISGetSize()`, `ISGetLocalSize()`
1201: @*/
1202: PetscErrorCode ISSetLayout(IS is, PetscLayout map)
1203: {
1204:   PetscFunctionBegin;
1206:   PetscAssertPointer(map, 2);
1207:   PetscCall(PetscLayoutReference(map, &is->map));
1208:   PetscFunctionReturn(PETSC_SUCCESS);
1209: }

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.

1216:   Not Collective

1218:   Input Parameter:
1219: . is - the index set

1221:   Output Parameter:
1222: . ptr - the location to put the pointer to the indices

1224:   Level: intermediate

1226:   Fortran Note:
1227: .vb
1228:   PetscInt, pointer :: ptr(:)
1229: .ve

1231: .seealso: `IS`, `ISRestoreIndices()`
1232: @*/
1233: PetscErrorCode ISGetIndices(IS is, const PetscInt *ptr[])
1234: {
1235:   PetscFunctionBegin;
1237:   PetscAssertPointer(ptr, 2);
1238:   PetscUseTypeMethod(is, getindices, ptr);
1239:   PetscFunctionReturn(PETSC_SUCCESS);
1240: }

1242: /*@
1243:   ISGetMinMax - Gets the minimum and maximum values in an `IS`

1245:   Not Collective

1247:   Input Parameter:
1248: . is - the index set

1250:   Output Parameters:
1251: + min - the minimum value, you may pass `NULL`
1252: - max - the maximum value, you may pass `NULL`

1254:   Level: intermediate

1256:   Notes:
1257:   Empty index sets return min=`PETSC_INT_MAX` and max=`PETSC_INT_MIN`.

1259:   In parallel, it returns the `min` and `max` of the local portion of `is`

1261: .seealso: `IS`, `ISGetIndices()`, `ISRestoreIndices()`
1262: @*/
1263: PetscErrorCode ISGetMinMax(IS is, PetscInt *min, PetscInt *max)
1264: {
1265:   PetscFunctionBegin;
1267:   if (min) *min = is->min;
1268:   if (max) *max = is->max;
1269:   PetscFunctionReturn(PETSC_SUCCESS);
1270: }

1272: /*@
1273:   ISLocate - determine the location of an index within the local component of an index set

1275:   Not Collective

1277:   Input Parameters:
1278: + is  - the index set
1279: - key - the search key

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

1284:   Level: intermediate

1286: .seealso: `IS`
1287:  @*/
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;

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;

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: }

1319: /*@C
1320:   ISRestoreIndices - Restores an index set to a usable state after a call to `ISGetIndices()`.

1322:   Not Collective

1324:   Input Parameters:
1325: + is  - the index set
1326: - ptr - the pointer obtained by `ISGetIndices()`

1328:   Level: intermediate

1330:   Fortran Note:
1331: .vb
1332:   PetscInt, pointer :: ptr(:)
1333: .ve

1335: .seealso: `IS`, `ISGetIndices()`
1336: @*/
1337: PetscErrorCode ISRestoreIndices(IS is, const PetscInt *ptr[])
1338: {
1339:   PetscFunctionBegin;
1341:   PetscAssertPointer(ptr, 2);
1342:   PetscTryTypeMethod(is, restoreindices, ptr);
1343:   PetscFunctionReturn(PETSC_SUCCESS);
1344: }

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;

1353:   PetscFunctionBegin;

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));

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];

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: }

1377: /*@C
1378:   ISGetTotalIndices - Retrieve an array containing all indices across the communicator.

1380:   Collective

1382:   Input Parameter:
1383: . is - the index set

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()`.

1389:   Level: intermediate

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).

1399: .seealso: `IS`, `ISRestoreTotalIndices()`, `ISGetNonlocalIndices()`, `ISGetSize()`
1400: @*/
1401: PetscErrorCode ISGetTotalIndices(IS is, const PetscInt *indices[])
1402: {
1403:   PetscMPIInt size;

1405:   PetscFunctionBegin;
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: }

1418: /*@C
1419:   ISRestoreTotalIndices - Restore the index array obtained with `ISGetTotalIndices()`.

1421:   Not Collective.

1423:   Input Parameters:
1424: + is      - the index set
1425: - indices - index array; must be the array obtained with `ISGetTotalIndices()`

1427:   Level: intermediate

1429: .seealso: `IS`, `ISGetNonlocalIndices()`
1430: @*/
1431: PetscErrorCode ISRestoreTotalIndices(IS is, const PetscInt *indices[])
1432: {
1433:   PetscMPIInt size;

1435:   PetscFunctionBegin;
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: }

1447: /*@C
1448:   ISGetNonlocalIndices - Retrieve an array of indices from remote processors
1449:   in this communicator.

1451:   Collective

1453:   Input Parameter:
1454: . is - the index set

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.

1462:   Level: intermediate

1464:   Notes:
1465:   Restore the indices using `ISRestoreNonlocalIndices()`.

1467:   The same scalability considerations as those for `ISGetTotalIndices()` apply here.

1469: .seealso: `IS`, `ISGetTotalIndices()`, `ISRestoreNonlocalIndices()`, `ISGetSize()`, `ISGetLocalSize().`
1470: @*/
1471: PetscErrorCode ISGetNonlocalIndices(IS is, const PetscInt *indices[])
1472: {
1473:   PetscMPIInt size;
1474:   PetscInt    n, N;

1476:   PetscFunctionBegin;
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: }

1493: /*@C
1494:   ISRestoreNonlocalIndices - Restore the index array obtained with `ISGetNonlocalIndices()`.

1496:   Not Collective.

1498:   Input Parameters:
1499: + is      - the index set
1500: - indices - index array; must be the array obtained with `ISGetNonlocalIndices()`

1502:   Level: intermediate

1504: .seealso: `IS`, `ISGetTotalIndices()`, `ISGetNonlocalIndices()`, `ISRestoreTotalIndices()`
1505: @*/
1506: PetscErrorCode ISRestoreNonlocalIndices(IS is, const PetscInt *indices[])
1507: {
1508:   PetscFunctionBegin;
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: }

1515: /*@
1516:   ISGetNonlocalIS - Gather all nonlocal indices for this `IS` and present
1517:   them as another sequential index set.

1519:   Collective

1521:   Input Parameter:
1522: . is - the index set

1524:   Output Parameter:
1525: . complement - sequential `IS` with indices identical to the result of
1526:                 `ISGetNonlocalIndices()`

1528:   Level: intermediate

1530:   Notes:
1531:   Complement represents the result of `ISGetNonlocalIndices()` as an `IS`.
1532:   Therefore scalability issues similar to `ISGetNonlocalIndices()` apply.

1534:   The resulting `IS` must be restored using `ISRestoreNonlocalIS()`.

1536: .seealso: `IS`, `ISGetNonlocalIndices()`, `ISRestoreNonlocalIndices()`, `ISAllGather()`, `ISGetSize()`
1537: @*/
1538: PetscErrorCode ISGetNonlocalIS(IS is, IS *complement)
1539: {
1540:   PetscFunctionBegin;
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: }

1560: /*@
1561:   ISRestoreNonlocalIS - Restore the `IS` obtained with `ISGetNonlocalIS()`.

1563:   Not collective.

1565:   Input Parameters:
1566: + is         - the index set
1567: - complement - index set of `is`'s nonlocal indices

1569:   Level: intermediate

1571: .seealso: `IS`, `ISGetNonlocalIS()`, `ISGetNonlocalIndices()`, `ISRestoreNonlocalIndices()`
1572: @*/
1573: PetscErrorCode ISRestoreNonlocalIS(IS is, IS *complement)
1574: {
1575:   PetscInt refcnt;

1577:   PetscFunctionBegin;
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: }

1587: /*@
1588:   ISViewFromOptions - View an `IS` based on options in the options database

1590:   Collective

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

1597:   Level: intermediate

1599:   Note:
1600:   See `PetscObjectViewFromOptions()` for possible `PetscViewer` and `PetscViewerFormat` values

1602: .seealso: `IS`, `ISView()`, `PetscObjectViewFromOptions()`, `ISCreate()`
1603: @*/
1604: PetscErrorCode ISViewFromOptions(IS A, PetscObject obj, const char name[])
1605: {
1606:   PetscFunctionBegin;
1608:   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
1609:   PetscFunctionReturn(PETSC_SUCCESS);
1610: }

1612: /*@
1613:   ISView - Displays an index set.

1615:   Collective

1617:   Input Parameters:
1618: + is     - the index set
1619: - viewer - viewer used to display the set, for example `PETSC_VIEWER_STDOUT_SELF`.

1621:   Level: intermediate

1623: .seealso: `IS`, `PetscViewer`, `PetscViewerASCIIOpen()`, `ISViewFromOptions()`
1624: @*/
1625: PetscErrorCode ISView(IS is, PetscViewer viewer)
1626: {
1627:   PetscFunctionBegin;
1629:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)is), &viewer));
1631:   PetscCheckSameComm(is, 1, viewer, 2);

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: }

1640: /*@
1641:   ISLoad - Loads an index set that has been stored in binary or HDF5 format with `ISView()`.

1643:   Collective

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()`

1649:   Level: intermediate

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"

1656: .seealso: `IS`, `PetscViewerBinaryOpen()`, `ISView()`, `MatLoad()`, `VecLoad()`
1657: @*/
1658: PetscErrorCode ISLoad(IS is, PetscViewer viewer)
1659: {
1660:   PetscBool isbinary, ishdf5;

1662:   PetscFunctionBegin;
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: }

1676: /*@
1677:   ISSort - Sorts the indices of an index set.

1679:   Collective

1681:   Input Parameter:
1682: . is - the index set

1684:   Level: intermediate

1686: .seealso: `IS`, `ISSortRemoveDups()`, `ISSorted()`
1687: @*/
1688: PetscErrorCode ISSort(IS is)
1689: {
1690:   PetscBool flg;

1692:   PetscFunctionBegin;
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: }

1702: /*@
1703:   ISSortRemoveDups - Sorts the indices of an index set, removing duplicates.

1705:   Collective

1707:   Input Parameter:
1708: . is - the index set

1710:   Level: intermediate

1712: .seealso: `IS`, `ISSort()`, `ISSorted()`
1713: @*/
1714: PetscErrorCode ISSortRemoveDups(IS is)
1715: {
1716:   PetscFunctionBegin;
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: }

1725: /*@
1726:   ISToGeneral - Converts an IS object of any type to `ISGENERAL` type

1728:   Collective

1730:   Input Parameter:
1731: . is - the index set

1733:   Level: intermediate

1735: .seealso: `IS`, `ISSorted()`
1736: @*/
1737: PetscErrorCode ISToGeneral(IS is)
1738: {
1739:   PetscFunctionBegin;
1741:   PetscUseTypeMethod(is, togeneral);
1742:   PetscFunctionReturn(PETSC_SUCCESS);
1743: }

1745: /*@
1746:   ISSorted - Checks the indices to determine whether they have been sorted.

1748:   Not Collective

1750:   Input Parameter:
1751: . is - the index set

1753:   Output Parameter:
1754: . flg - output flag, either `PETSC_TRUE` if the index set is sorted,
1755:          or `PETSC_FALSE` otherwise.

1757:   Level: intermediate

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`.

1764: .seealso: `ISSort()`, `ISSortRemoveDups()`
1765: @*/
1766: PetscErrorCode ISSorted(IS is, PetscBool *flg)
1767: {
1768:   PetscFunctionBegin;
1770:   PetscAssertPointer(flg, 2);
1771:   PetscCall(ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, flg));
1772:   PetscFunctionReturn(PETSC_SUCCESS);
1773: }

1775: /*@
1776:   ISDuplicate - Creates a duplicate copy of an index set.

1778:   Collective

1780:   Input Parameter:
1781: . is - the index set

1783:   Output Parameter:
1784: . newIS - the copy of the index set

1786:   Level: beginner

1788: .seealso: `IS`, `ISCreateGeneral()`, `ISCopy()`
1789: @*/
1790: PetscErrorCode ISDuplicate(IS is, IS *newIS)
1791: {
1792:   PetscFunctionBegin;
1794:   PetscAssertPointer(newIS, 2);
1795:   PetscUseTypeMethod(is, duplicate, newIS);
1796:   PetscCall(ISCopyInfo_Private(is, *newIS));
1797:   PetscFunctionReturn(PETSC_SUCCESS);
1798: }

1800: /*@
1801:   ISCopy - Copies an index set.

1803:   Collective

1805:   Input Parameter:
1806: . is - the index set

1808:   Output Parameter:
1809: . isy - the copy of the index set

1811:   Level: beginner

1813: .seealso: `IS`, `ISDuplicate()`, `ISShift()`
1814: @*/
1815: PetscErrorCode ISCopy(IS is, IS isy)
1816: {
1817:   PetscInt bs, bsy;

1819:   PetscFunctionBegin;
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: }

1836: /*@
1837:   ISShift - Shift all indices by given offset

1839:   Collective

1841:   Input Parameters:
1842: + is     - the index set
1843: - offset - the offset

1845:   Output Parameter:
1846: . isy - the shifted copy of the input index set

1848:   Level: beginner

1850:   Notes:
1851:   The `offset` can be different across processes.

1853:   `is` and `isy` can be the same.

1855: .seealso: `ISDuplicate()`, `ISCopy()`
1856: @*/
1857: PetscErrorCode ISShift(IS is, PetscInt offset, IS isy)
1858: {
1859:   PetscFunctionBegin;
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: }

1877: /*@
1878:   ISOnComm - Split a parallel `IS` on subcomms (usually self) or concatenate index sets on subcomms into a parallel index set

1880:   Collective

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`

1887:   Output Parameter:
1888: . newis - new `IS` on `comm`

1890:   Level: advanced

1892:   Notes:
1893:   It is usually desirable to create a parallel `IS` and look at the local part when necessary.

1895:   This function is useful if serial `IS`s must be created independently, or to view many
1896:   logically independent serial `IS`s.

1898:   The input `IS` must have the same type on every MPI process.

1900: .seealso: `IS`
1901: @*/
1902: PetscErrorCode ISOnComm(IS is, MPI_Comm comm, PetscCopyMode mode, IS *newis)
1903: {
1904:   PetscMPIInt match;

1906:   PetscFunctionBegin;
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: }

1917: /*@
1918:   ISSetBlockSize - informs an index set that it has a given block size

1920:   Logicall Collective

1922:   Input Parameters:
1923: + is - index set
1924: - bs - block size

1926:   Level: intermediate

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.

1934:   `ISBlockGetIndices()` only works for `ISBLOCK`, not others.

1936: .seealso: `IS`, `ISGetBlockSize()`, `ISCreateBlock()`, `ISBlockGetIndices()`,
1937: @*/
1938: PetscErrorCode ISSetBlockSize(IS is, PetscInt bs)
1939: {
1940:   PetscFunctionBegin;
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: }

1963: /*@
1964:   ISGetBlockSize - Returns the number of elements in a block.

1966:   Not Collective

1968:   Input Parameter:
1969: . is - the index set

1971:   Output Parameter:
1972: . size - the number of elements in a block

1974:   Level: intermediate

1976:   Note:
1977:   See `ISSetBlockSize()`

1979: .seealso: `IS`, `ISBlockGetSize()`, `ISGetSize()`, `ISCreateBlock()`, `ISSetBlockSize()`
1980: @*/
1981: PetscErrorCode ISGetBlockSize(IS is, PetscInt *size)
1982: {
1983:   PetscFunctionBegin;
1984:   PetscCall(PetscLayoutGetBlockSize(is->map, size));
1985:   PetscFunctionReturn(PETSC_SUCCESS);
1986: }

1988: /*@
1989:   ISSetCompressOutput - set the flag for output compression

1991:   Logicall Collective

1993:   Input Parameters:
1994: + is       - index set
1995: - compress - flag for output compression

1997:   Level: intermediate

1999: .seealso: `IS`, `ISGetCompressOutput()`, `ISView()`
2000: @*/
2001: PetscErrorCode ISSetCompressOutput(IS is, PetscBool compress)
2002: {
2003:   PetscFunctionBegin;
2006:   is->compressOutput = compress;
2007:   PetscFunctionReturn(PETSC_SUCCESS);
2008: }

2010: /*@
2011:   ISGetCompressOutput - Returns the flag for output compression

2013:   Not Collective

2015:   Input Parameter:
2016: . is - the index set

2018:   Output Parameter:
2019: . compress - the flag to compress output

2021:   Level: intermediate

2023: .seealso: `IS`, `ISSetCompressOutput()`, `ISView()`
2024: @*/
2025: PetscErrorCode ISGetCompressOutput(IS is, PetscBool *compress)
2026: {
2027:   PetscFunctionBegin;
2029:   PetscAssertPointer(compress, 2);
2030:   *compress = is->compressOutput;
2031:   PetscFunctionReturn(PETSC_SUCCESS);
2032: }

2034: static PetscErrorCode ISGetIndicesCopy_Private(IS is, PetscInt idx[])
2035: {
2036:   PetscInt        len, i;
2037:   const PetscInt *ptr;

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: }