Actual source code: sorti.c


  2: /*
  3:    This file contains routines for sorting integers. Values are sorted in place.
  4:    One can use src/sys/tests/ex52.c for benchmarking.
  5:  */
  6: #include <petsc/private/petscimpl.h>
  7: #include <petsc/private/hashseti.h>

  9: #define MEDIAN3(v, a, b, c) (v[a] < v[b] ? (v[b] < v[c] ? (b) : (v[a] < v[c] ? (c) : (a))) : (v[c] < v[b] ? (b) : (v[a] < v[c] ? (a) : (c))))

 11: #define MEDIAN(v, right) MEDIAN3(v, right / 4, right / 2, right / 4 * 3)

 13: /* Swap one, two or three pairs. Each pair can have its own type */
 14: #define SWAP1(a, b, t1) \
 15:   do { \
 16:     t1 = a; \
 17:     a  = b; \
 18:     b  = t1; \
 19:   } while (0)
 20: #define SWAP2(a, b, c, d, t1, t2) \
 21:   do { \
 22:     t1 = a; \
 23:     a  = b; \
 24:     b  = t1; \
 25:     t2 = c; \
 26:     c  = d; \
 27:     d  = t2; \
 28:   } while (0)
 29: #define SWAP3(a, b, c, d, e, f, t1, t2, t3) \
 30:   do { \
 31:     t1 = a; \
 32:     a  = b; \
 33:     b  = t1; \
 34:     t2 = c; \
 35:     c  = d; \
 36:     d  = t2; \
 37:     t3 = e; \
 38:     e  = f; \
 39:     f  = t3; \
 40:   } while (0)

 42: /* Swap a & b, *c & *d. c, d, t2 are pointers to a type of size <siz> */
 43: #define SWAP2Data(a, b, c, d, t1, t2, siz) \
 44:   do { \
 45:     t1 = a; \
 46:     a  = b; \
 47:     b  = t1; \
 48:     PetscMemcpy(t2, c, siz); \
 49:     PetscMemcpy(c, d, siz); \
 50:     PetscMemcpy(d, t2, siz); \
 51:   } while (0)

 53: /*
 54:    Partition X[lo,hi] into two parts: X[lo,l) <= pivot; X[r,hi] > pivot

 56:    Input Parameters:
 57:     + X         - array to partition
 58:     . pivot     - a pivot of X[]
 59:     . t1        - temp variable for X
 60:     - lo,hi     - lower and upper bound of the array

 62:    Output Parameters:
 63:     + l,r       - of type PetscInt

 65:    Note:
 66:     The TwoWayPartition2/3 variants also partition other arrays along with X.
 67:     These arrays can have different types, so they provide their own temp t2,t3
 68:  */
 69: #define TwoWayPartition1(X, pivot, t1, lo, hi, l, r) \
 70:   do { \
 71:     l = lo; \
 72:     r = hi; \
 73:     while (1) { \
 74:       while (X[l] < pivot) l++; \
 75:       while (X[r] > pivot) r--; \
 76:       if (l >= r) { \
 77:         r++; \
 78:         break; \
 79:       } \
 80:       SWAP1(X[l], X[r], t1); \
 81:       l++; \
 82:       r--; \
 83:     } \
 84:   } while (0)

 86: /*
 87:    Partition X[lo,hi] into two parts: X[lo,l) >= pivot; X[r,hi] < pivot

 89:    Input Parameters:
 90:     + X         - array to partition
 91:     . pivot     - a pivot of X[]
 92:     . t1        - temp variable for X
 93:     - lo,hi     - lower and upper bound of the array

 95:    Output Parameters:
 96:     + l,r       - of type PetscInt

 98:    Note:
 99:     The TwoWayPartition2/3 variants also partition other arrays along with X.
100:     These arrays can have different types, so they provide their own temp t2,t3
101:  */
102: #define TwoWayPartitionReverse1(X, pivot, t1, lo, hi, l, r) \
103:   do { \
104:     l = lo; \
105:     r = hi; \
106:     while (1) { \
107:       while (X[l] > pivot) l++; \
108:       while (X[r] < pivot) r--; \
109:       if (l >= r) { \
110:         r++; \
111:         break; \
112:       } \
113:       SWAP1(X[l], X[r], t1); \
114:       l++; \
115:       r--; \
116:     } \
117:   } while (0)

119: #define TwoWayPartition2(X, Y, pivot, t1, t2, lo, hi, l, r) \
120:   do { \
121:     l = lo; \
122:     r = hi; \
123:     while (1) { \
124:       while (X[l] < pivot) l++; \
125:       while (X[r] > pivot) r--; \
126:       if (l >= r) { \
127:         r++; \
128:         break; \
129:       } \
130:       SWAP2(X[l], X[r], Y[l], Y[r], t1, t2); \
131:       l++; \
132:       r--; \
133:     } \
134:   } while (0)

136: #define TwoWayPartition3(X, Y, Z, pivot, t1, t2, t3, lo, hi, l, r) \
137:   do { \
138:     l = lo; \
139:     r = hi; \
140:     while (1) { \
141:       while (X[l] < pivot) l++; \
142:       while (X[r] > pivot) r--; \
143:       if (l >= r) { \
144:         r++; \
145:         break; \
146:       } \
147:       SWAP3(X[l], X[r], Y[l], Y[r], Z[l], Z[r], t1, t2, t3); \
148:       l++; \
149:       r--; \
150:     } \
151:   } while (0)

153: /* Templates for similar functions used below */
154: #define QuickSort1(FuncName, X, n, pivot, t1) \
155:   do { \
156:     PetscCount i, j, p, l, r, hi = n - 1; \
157:     if (n < 8) { \
158:       for (i = 0; i < n; i++) { \
159:         pivot = X[i]; \
160:         for (j = i + 1; j < n; j++) { \
161:           if (pivot > X[j]) { \
162:             SWAP1(X[i], X[j], t1); \
163:             pivot = X[i]; \
164:           } \
165:         } \
166:       } \
167:     } else { \
168:       p     = MEDIAN(X, hi); \
169:       pivot = X[p]; \
170:       TwoWayPartition1(X, pivot, t1, 0, hi, l, r); \
171:       FuncName(l, X); \
172:       FuncName(hi - r + 1, X + r); \
173:     } \
174:   } while (0)

176: /* Templates for similar functions used below */
177: #define QuickSortReverse1(FuncName, X, n, pivot, t1) \
178:   do { \
179:     PetscCount i, j, p, l, r, hi = n - 1; \
180:     if (n < 8) { \
181:       for (i = 0; i < n; i++) { \
182:         pivot = X[i]; \
183:         for (j = i + 1; j < n; j++) { \
184:           if (pivot < X[j]) { \
185:             SWAP1(X[i], X[j], t1); \
186:             pivot = X[i]; \
187:           } \
188:         } \
189:       } \
190:     } else { \
191:       p     = MEDIAN(X, hi); \
192:       pivot = X[p]; \
193:       TwoWayPartitionReverse1(X, pivot, t1, 0, hi, l, r); \
194:       FuncName(l, X); \
195:       FuncName(hi - r + 1, X + r); \
196:     } \
197:   } while (0)

199: #define QuickSort2(FuncName, X, Y, n, pivot, t1, t2) \
200:   do { \
201:     PetscCount i, j, p, l, r, hi = n - 1; \
202:     if (n < 8) { \
203:       for (i = 0; i < n; i++) { \
204:         pivot = X[i]; \
205:         for (j = i + 1; j < n; j++) { \
206:           if (pivot > X[j]) { \
207:             SWAP2(X[i], X[j], Y[i], Y[j], t1, t2); \
208:             pivot = X[i]; \
209:           } \
210:         } \
211:       } \
212:     } else { \
213:       p     = MEDIAN(X, hi); \
214:       pivot = X[p]; \
215:       TwoWayPartition2(X, Y, pivot, t1, t2, 0, hi, l, r); \
216:       FuncName(l, X, Y); \
217:       FuncName(hi - r + 1, X + r, Y + r); \
218:     } \
219:   } while (0)

221: #define QuickSort3(FuncName, X, Y, Z, n, pivot, t1, t2, t3) \
222:   do { \
223:     PetscCount i, j, p, l, r, hi = n - 1; \
224:     if (n < 8) { \
225:       for (i = 0; i < n; i++) { \
226:         pivot = X[i]; \
227:         for (j = i + 1; j < n; j++) { \
228:           if (pivot > X[j]) { \
229:             SWAP3(X[i], X[j], Y[i], Y[j], Z[i], Z[j], t1, t2, t3); \
230:             pivot = X[i]; \
231:           } \
232:         } \
233:       } \
234:     } else { \
235:       p     = MEDIAN(X, hi); \
236:       pivot = X[p]; \
237:       TwoWayPartition3(X, Y, Z, pivot, t1, t2, t3, 0, hi, l, r); \
238:       FuncName(l, X, Y, Z); \
239:       FuncName(hi - r + 1, X + r, Y + r, Z + r); \
240:     } \
241:   } while (0)

243: /*@
244:    PetscSortedInt - Determines whether the `PetscInt` array is sorted.

246:    Not Collective

248:    Input Parameters:
249: +  n  - number of values
250: -  X  - array of integers

252:    Output Parameters:
253: .  sorted - flag whether the array is sorted

255:    Level: intermediate

257: .seealso: `PetscSortInt()`, `PetscSortedMPIInt()`, `PetscSortedReal()`
258: @*/
259: PetscErrorCode PetscSortedInt(PetscInt n, const PetscInt X[], PetscBool *sorted)
260: {
263:   PetscSorted(n, X, *sorted);
264:   return 0;
265: }

267: /*@
268:    PetscSortInt - Sorts an array of `PetscInt` in place in increasing order.

270:    Not Collective

272:    Input Parameters:
273: +  n  - number of values
274: -  X  - array of integers

276:    Note:
277:    This function serves as an alternative to `PetscIntSortSemiOrdered()`, and may perform faster especially if the array
278:    is completely random. There are exceptions to this and so it is __highly__ recommended that the user benchmark their
279:    code to see which routine is fastest.

281:    Level: intermediate

283: .seealso: `PetscIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`
284: @*/
285: PetscErrorCode PetscSortInt(PetscInt n, PetscInt X[])
286: {
287:   PetscInt pivot, t1;

290:   QuickSort1(PetscSortInt, X, n, pivot, t1);
291:   return 0;
292: }

294: /*@
295:    PetscSortReverseInt - Sorts an array of `PetscInt` in place in decreasing order.

297:    Not Collective

299:    Input Parameters:
300: +  n  - number of values
301: -  X  - array of integers

303:    Level: intermediate

305: .seealso: `PetscIntSortSemiOrdered()`, `PetscSortInt()`, `PetscSortIntWithPermutation()`
306: @*/
307: PetscErrorCode PetscSortReverseInt(PetscInt n, PetscInt X[])
308: {
309:   PetscInt pivot, t1;

312:   QuickSortReverse1(PetscSortReverseInt, X, n, pivot, t1);
313:   return 0;
314: }

316: /*@
317:    PetscSortedRemoveDupsInt - Removes all duplicate entries of a sorted `PetscInt` array

319:    Not Collective

321:    Input Parameters:
322: +  n  - number of values
323: -  X  - sorted array of integers

325:    Output Parameter:
326: .  n - number of non-redundant values

328:    Level: intermediate

330: .seealso: `PetscSortInt()`
331: @*/
332: PetscErrorCode PetscSortedRemoveDupsInt(PetscInt *n, PetscInt X[])
333: {
334:   PetscInt i, s = 0, N = *n, b = 0;

338:   for (i = 0; i < N - 1; i++) {
339:     if (X[b + s + 1] != X[b]) {
340:       X[b + 1] = X[b + s + 1];
341:       b++;
342:     } else s++;
343:   }
344:   *n = N - s;
345:   return 0;
346: }

348: /*@
349:    PetscSortedCheckDupsInt - Checks if a sorted `PetscInt` array has duplicates

351:    Not Collective

353:    Input Parameters:
354: +  n  - number of values
355: -  X  - sorted array of integers

357:    Output Parameter:
358: .  dups - True if the array has dups, otherwise false

360:    Level: intermediate

363: @*/
364: PetscErrorCode PetscSortedCheckDupsInt(PetscInt n, const PetscInt X[], PetscBool *flg)
365: {
366:   PetscInt i;

369:   *flg = PETSC_FALSE;
370:   for (i = 0; i < n - 1; i++) {
371:     if (X[i + 1] == X[i]) {
372:       *flg = PETSC_TRUE;
373:       break;
374:     }
375:   }
376:   return 0;
377: }

379: /*@
380:    PetscSortRemoveDupsInt - Sorts an array of `PetscInt` in place in increasing order removes all duplicate entries

382:    Not Collective

384:    Input Parameters:
385: +  n  - number of values
386: -  X  - array of integers

388:    Output Parameter:
389: .  n - number of non-redundant values

391:    Level: intermediate

393: .seealso: `PetscIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortedRemoveDupsInt()`
394: @*/
395: PetscErrorCode PetscSortRemoveDupsInt(PetscInt *n, PetscInt X[])
396: {
398:   PetscSortInt(*n, X);
399:   PetscSortedRemoveDupsInt(n, X);
400:   return 0;
401: }

403: /*@
404:  PetscFindInt - Finds `PetscInt` in a sorted array of `PetscInt`

406:    Not Collective

408:    Input Parameters:
409: +  key - the integer to locate
410: .  n   - number of values in the array
411: -  X  - array of integers

413:    Output Parameter:
414: .  loc - the location if found, otherwise -(slot+1) where slot is the place the value would go

416:    Level: intermediate

418: .seealso: `PetscIntSortSemiOrdered()`, `PetscSortInt()`, `PetscSortIntWithArray()`, `PetscSortRemoveDupsInt()`
419: @*/
420: PetscErrorCode PetscFindInt(PetscInt key, PetscInt n, const PetscInt X[], PetscInt *loc)
421: {
422:   PetscInt lo = 0, hi = n;

425:   if (!n) {
426:     *loc = -1;
427:     return 0;
428:   }
431:   while (hi - lo > 1) {
432:     PetscInt mid = lo + (hi - lo) / 2;
433:     if (key < X[mid]) hi = mid;
434:     else lo = mid;
435:   }
436:   *loc = key == X[lo] ? lo : -(lo + (key > X[lo]) + 1);
437:   return 0;
438: }

440: /*@

443:    Not Collective

445:    Input Parameters:
446: +  n  - number of values in the array
447: -  X  - array of integers

449:    Output Parameter:
450: .  dups - True if the array has dups, otherwise false

452:    Level: intermediate

454: .seealso: `PetscSortRemoveDupsInt()`, `PetscSortedCheckDupsInt()`
455: @*/
457: {
458:   PetscInt   i;
459:   PetscHSetI ht;
460:   PetscBool  missing;

464:   *dups = PETSC_FALSE;
465:   if (n > 1) {
466:     PetscHSetICreate(&ht);
467:     PetscHSetIResize(ht, n);
468:     for (i = 0; i < n; i++) {
469:       PetscHSetIQueryAdd(ht, X[i], &missing);
470:       if (!missing) {
471:         *dups = PETSC_TRUE;
472:         break;
473:       }
474:     }
475:     PetscHSetIDestroy(&ht);
476:   }
477:   return 0;
478: }

480: /*@
481:   PetscFindMPIInt - Finds `PetscMPIInt` in a sorted array of `PetscMPIInt`

483:    Not Collective

485:    Input Parameters:
486: +  key - the integer to locate
487: .  n   - number of values in the array
488: -  X   - array of integers

490:    Output Parameter:
491: .  loc - the location if found, otherwise -(slot+1) where slot is the place the value would go

493:    Level: intermediate

495: .seealso: `PetscMPIIntSortSemiOrdered()`, `PetscSortInt()`, `PetscSortIntWithArray()`, `PetscSortRemoveDupsInt()`
496: @*/
497: PetscErrorCode PetscFindMPIInt(PetscMPIInt key, PetscInt n, const PetscMPIInt X[], PetscInt *loc)
498: {
499:   PetscInt lo = 0, hi = n;

502:   if (!n) {
503:     *loc = -1;
504:     return 0;
505:   }
508:   while (hi - lo > 1) {
509:     PetscInt mid = lo + (hi - lo) / 2;
510:     if (key < X[mid]) hi = mid;
511:     else lo = mid;
512:   }
513:   *loc = key == X[lo] ? lo : -(lo + (key > X[lo]) + 1);
514:   return 0;
515: }

517: /*@
518:    PetscSortIntWithArray - Sorts an array of `PetscInt` in place in increasing order;
519:        changes a second array of `PetscInt` to match the sorted first array.

521:    Not Collective

523:    Input Parameters:
524: +  n  - number of values
525: .  X  - array of integers
526: -  Y  - second array of integers

528:    Level: intermediate

530: .seealso: `PetscIntSortSemiOrderedWithArray()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithCountArray()`
531: @*/
532: PetscErrorCode PetscSortIntWithArray(PetscInt n, PetscInt X[], PetscInt Y[])
533: {
534:   PetscInt pivot, t1, t2;

536:   QuickSort2(PetscSortIntWithArray, X, Y, n, pivot, t1, t2);
537:   return 0;
538: }

540: /*@
541:    PetscSortIntWithArrayPair - Sorts an array of `PetscInt` in place in increasing order;
542:        changes a pair of `PetscInt` arrays to match the sorted first array.

544:    Not Collective

546:    Input Parameters:
547: +  n  - number of values
548: .  X  - array of integers
549: .  Y  - second array of integers (first array of the pair)
550: -  Z  - third array of integers  (second array of the pair)

552:    Level: intermediate

554: .seealso: `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortIntWithArray()`, `PetscIntSortSemiOrdered()`, `PetscSortIntWithIntCountArrayPair()`
555: @*/
556: PetscErrorCode PetscSortIntWithArrayPair(PetscInt n, PetscInt X[], PetscInt Y[], PetscInt Z[])
557: {
558:   PetscInt pivot, t1, t2, t3;

560:   QuickSort3(PetscSortIntWithArrayPair, X, Y, Z, n, pivot, t1, t2, t3);
561:   return 0;
562: }

564: /*@
565:    PetscSortIntWithCountArray - Sorts an array of `PetscInt` in place in increasing order;
566:        changes a second array of `PetscCount` to match the sorted first array.

568:    Not Collective

570:    Input Parameters:
571: +  n  - number of values
572: .  X  - array of integers
573: -  Y  - second array of PetscCounts (signed integers)

575:    Level: intermediate

577: .seealso: `PetscIntSortSemiOrderedWithArray()`, `PetscSortReal()`, `PetscSortIntPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
578: @*/
579: PetscErrorCode PetscSortIntWithCountArray(PetscCount n, PetscInt X[], PetscCount Y[])
580: {
581:   PetscInt   pivot, t1;
582:   PetscCount t2;

584:   QuickSort2(PetscSortIntWithCountArray, X, Y, n, pivot, t1, t2);
585:   return 0;
586: }

588: /*@
589:    PetscSortIntWithIntCountArrayPair - Sorts an array of `PetscInt` in place in increasing order;
590:        changes a `PetscInt`  array and a `PetscCount` array to match the sorted first array.

592:    Not Collective

594:    Input Parameters:
595: +  n  - number of values
596: .  X  - array of integers
597: .  Y  - second array of integers (first array of the pair)
598: -  Z  - third array of PetscCounts  (second array of the pair)

600:    Level: intermediate

602:    Note:
603:     Usually X, Y are matrix row/column indices, and Z is a permutation array and therefore Z's type is PetscCount to allow 2B+ nonzeros even with 32-bit PetscInt.

605: .seealso: `PetscSortReal()`, `PetscSortIntPermutation()`, `PetscSortIntWithArray()`, `PetscIntSortSemiOrdered()`, `PetscSortIntWithArrayPair()`
606: @*/
607: PetscErrorCode PetscSortIntWithIntCountArrayPair(PetscCount n, PetscInt X[], PetscInt Y[], PetscCount Z[])
608: {
609:   PetscInt   pivot, t1, t2; /* pivot is take from X[], so its type is still PetscInt */
610:   PetscCount t3;            /* temp for Z[] */

612:   QuickSort3(PetscSortIntWithIntCountArrayPair, X, Y, Z, n, pivot, t1, t2, t3);
613:   return 0;
614: }

616: /*@
617:   PetscSortedMPIInt - Determines whether the `PetscMPIInt` array is sorted.

619:    Not Collective

621:    Input Parameters:
622: +  n  - number of values
623: -  X  - array of integers

625:    Output Parameters:
626: .  sorted - flag whether the array is sorted

628:    Level: intermediate

630: .seealso: `PetscMPIIntSortSemiOrdered()`, `PetscSortMPIInt()`, `PetscSortedInt()`, `PetscSortedReal()`
631: @*/
632: PetscErrorCode PetscSortedMPIInt(PetscInt n, const PetscMPIInt X[], PetscBool *sorted)
633: {
634:   PetscSorted(n, X, *sorted);
635:   return 0;
636: }

638: /*@
639:    PetscSortMPIInt - Sorts an array of `PetscMPIInt` in place in increasing order.

641:    Not Collective

643:    Input Parameters:
644: +  n  - number of values
645: -  X  - array of integers

647:    Level: intermediate

649:    Note:
650:    This function serves as an alternative to PetscMPIIntSortSemiOrdered(), and may perform faster especially if the array
651:    is completely random. There are exceptions to this and so it is __highly__ recommended that the user benchmark their
652:    code to see which routine is fastest.

654: .seealso: `PetscMPIIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`
655: @*/
656: PetscErrorCode PetscSortMPIInt(PetscInt n, PetscMPIInt X[])
657: {
658:   PetscMPIInt pivot, t1;

660:   QuickSort1(PetscSortMPIInt, X, n, pivot, t1);
661:   return 0;
662: }

664: /*@
665:    PetscSortRemoveDupsMPIInt - Sorts an array of `PetscMPIInt` in place in increasing order removes all duplicate entries

667:    Not Collective

669:    Input Parameters:
670: +  n  - number of values
671: -  X  - array of integers

673:    Output Parameter:
674: .  n - number of non-redundant values

676:    Level: intermediate

678: .seealso: `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`
679: @*/
680: PetscErrorCode PetscSortRemoveDupsMPIInt(PetscInt *n, PetscMPIInt X[])
681: {
682:   PetscInt s = 0, N = *n, b = 0;

684:   PetscSortMPIInt(N, X);
685:   for (PetscInt i = 0; i < N - 1; i++) {
686:     if (X[b + s + 1] != X[b]) {
687:       X[b + 1] = X[b + s + 1];
688:       b++;
689:     } else s++;
690:   }
691:   *n = N - s;
692:   return 0;
693: }

695: /*@
696:    PetscSortMPIIntWithArray - Sorts an array of `PetscMPIInt` in place in increasing order;
697:        changes a second `PetscMPIInt` array to match the sorted first array.

699:    Not Collective

701:    Input Parameters:
702: +  n  - number of values
703: .  X  - array of integers
704: -  Y  - second array of integers

706:    Level: intermediate

708: .seealso: `PetscMPIIntSortSemiOrderedWithArray()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`
709: @*/
710: PetscErrorCode PetscSortMPIIntWithArray(PetscMPIInt n, PetscMPIInt X[], PetscMPIInt Y[])
711: {
712:   PetscMPIInt pivot, t1, t2;

714:   QuickSort2(PetscSortMPIIntWithArray, X, Y, n, pivot, t1, t2);
715:   return 0;
716: }

718: /*@
719:    PetscSortMPIIntWithIntArray - Sorts an array of `PetscMPIInt` in place in increasing order;
720:        changes a second array of `PetscInt` to match the sorted first array.

722:    Not Collective

724:    Input Parameters:
725: +  n  - number of values
726: .  X  - array of MPI integers
727: -  Y  - second array of Petsc integers

729:    Level: intermediate

731:    Note:
732:    This routine is useful when one needs to sort MPI ranks with other integer arrays.

734: .seealso: `PetscSortMPIIntWithArray()`, `PetscIntSortSemiOrderedWithArray()`, `PetscTimSortWithArray()`
735: @*/
736: PetscErrorCode PetscSortMPIIntWithIntArray(PetscMPIInt n, PetscMPIInt X[], PetscInt Y[])
737: {
738:   PetscMPIInt pivot, t1;
739:   PetscInt    t2;

741:   QuickSort2(PetscSortMPIIntWithIntArray, X, Y, n, pivot, t1, t2);
742:   return 0;
743: }

745: /*@
746:    PetscSortIntWithScalarArray - Sorts an array of `PetscInt` in place in increasing order;
747:        changes a second `PetscScalar` array to match the sorted first array.

749:    Not Collective

751:    Input Parameters:
752: +  n  - number of values
753: .  X  - array of integers
754: -  Y  - second array of scalars

756:    Level: intermediate

758: .seealso: `PetscTimSortWithArray()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
759: @*/
760: PetscErrorCode PetscSortIntWithScalarArray(PetscInt n, PetscInt X[], PetscScalar Y[])
761: {
762:   PetscInt    pivot, t1;
763:   PetscScalar t2;

765:   QuickSort2(PetscSortIntWithScalarArray, X, Y, n, pivot, t1, t2);
766:   return 0;
767: }

769: /*@C
770:    PetscSortIntWithDataArray - Sorts an array of `PetscInt` in place in increasing order;
771:        changes a second array to match the sorted first INTEGER array.  Unlike other sort routines, the user must
772:        provide workspace (the size of an element in the data array) to use when sorting.

774:    Not Collective

776:    Input Parameters:
777: +  n  - number of values
778: .  X  - array of integers
779: .  Y  - second array of data
780: .  size - sizeof elements in the data array in bytes
781: -  t2   - workspace of "size" bytes used when sorting

783:    Level: intermediate

785: .seealso: `PetscTimSortWithArray()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
786: @*/
787: PetscErrorCode PetscSortIntWithDataArray(PetscInt n, PetscInt X[], void *Y, size_t size, void *t2)
788: {
789:   char    *YY = (char *)Y;
790:   PetscInt t1, pivot, hi = n - 1;

792:   if (n < 8) {
793:     for (PetscInt i = 0; i < n; i++) {
794:       pivot = X[i];
795:       for (PetscInt j = i + 1; j < n; j++) {
796:         if (pivot > X[j]) {
797:           SWAP2Data(X[i], X[j], YY + size * i, YY + size * j, t1, t2, size);
798:           pivot = X[i];
799:         }
800:       }
801:     }
802:   } else {
803:     /* Two way partition */
804:     PetscInt l = 0, r = hi;

806:     pivot = X[MEDIAN(X, hi)];
807:     while (1) {
808:       while (X[l] < pivot) l++;
809:       while (X[r] > pivot) r--;
810:       if (l >= r) {
811:         r++;
812:         break;
813:       }
814:       SWAP2Data(X[l], X[r], YY + size * l, YY + size * r, t1, t2, size);
815:       l++;
816:       r--;
817:     }
818:     PetscSortIntWithDataArray(l, X, Y, size, t2);
819:     PetscSortIntWithDataArray(hi - r + 1, X + r, YY + size * r, size, t2);
820:   }
821:   return 0;
822: }

824: /*@
825:    PetscMergeIntArray -     Merges two SORTED `PetscInt` arrays, removes duplicate elements.

827:    Not Collective

829:    Input Parameters:
830: +  an  - number of values in the first array
831: .  aI  - first sorted array of integers
832: .  bn  - number of values in the second array
833: -  bI  - second array of integers

835:    Output Parameters:
836: +  n   - number of values in the merged array
837: -  L   - merged sorted array, this is allocated if an array is not provided

839:    Level: intermediate

841: .seealso: `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
842: @*/
843: PetscErrorCode PetscMergeIntArray(PetscInt an, const PetscInt aI[], PetscInt bn, const PetscInt bI[], PetscInt *n, PetscInt **L)
844: {
845:   PetscInt *L_ = *L, ak, bk, k;

847:   if (!L_) {
848:     PetscMalloc1(an + bn, L);
849:     L_ = *L;
850:   }
851:   k = ak = bk = 0;
852:   while (ak < an && bk < bn) {
853:     if (aI[ak] == bI[bk]) {
854:       L_[k] = aI[ak];
855:       ++ak;
856:       ++bk;
857:       ++k;
858:     } else if (aI[ak] < bI[bk]) {
859:       L_[k] = aI[ak];
860:       ++ak;
861:       ++k;
862:     } else {
863:       L_[k] = bI[bk];
864:       ++bk;
865:       ++k;
866:     }
867:   }
868:   if (ak < an) {
869:     PetscArraycpy(L_ + k, aI + ak, an - ak);
870:     k += (an - ak);
871:   }
872:   if (bk < bn) {
873:     PetscArraycpy(L_ + k, bI + bk, bn - bk);
874:     k += (bn - bk);
875:   }
876:   *n = k;
877:   return 0;
878: }

880: /*@
881:    PetscMergeIntArrayPair -     Merges two SORTED `PetscInt` arrays that share NO common values along with an additional array of `PetscInt`.
882:                                 The additional arrays are the same length as sorted arrays and are merged
883:                                 in the order determined by the merging of the sorted pair.

885:    Not Collective

887:    Input Parameters:
888: +  an  - number of values in the first array
889: .  aI  - first sorted array of integers
890: .  aJ  - first additional array of integers
891: .  bn  - number of values in the second array
892: .  bI  - second array of integers
893: -  bJ  - second additional of integers

895:    Output Parameters:
896: +  n   - number of values in the merged array (== an + bn)
897: .  L   - merged sorted array
898: -  J   - merged additional array

900:    Note:
901:     if L or J point to non-null arrays then this routine will assume they are of the approproate size and use them, otherwise this routine will allocate space for them

903:    Level: intermediate

905: .seealso: `PetscIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
906: @*/
907: PetscErrorCode PetscMergeIntArrayPair(PetscInt an, const PetscInt aI[], const PetscInt aJ[], PetscInt bn, const PetscInt bI[], const PetscInt bJ[], PetscInt *n, PetscInt **L, PetscInt **J)
908: {
909:   PetscInt n_, *L_, *J_, ak, bk, k;

913:   n_ = an + bn;
914:   *n = n_;
915:   if (!*L) PetscMalloc1(n_, L);
916:   L_ = *L;
917:   if (!*J) PetscMalloc1(n_, J);
918:   J_ = *J;
919:   k = ak = bk = 0;
920:   while (ak < an && bk < bn) {
921:     if (aI[ak] <= bI[bk]) {
922:       L_[k] = aI[ak];
923:       J_[k] = aJ[ak];
924:       ++ak;
925:       ++k;
926:     } else {
927:       L_[k] = bI[bk];
928:       J_[k] = bJ[bk];
929:       ++bk;
930:       ++k;
931:     }
932:   }
933:   if (ak < an) {
934:     PetscArraycpy(L_ + k, aI + ak, an - ak);
935:     PetscArraycpy(J_ + k, aJ + ak, an - ak);
936:     k += (an - ak);
937:   }
938:   if (bk < bn) {
939:     PetscArraycpy(L_ + k, bI + bk, bn - bk);
940:     PetscArraycpy(J_ + k, bJ + bk, bn - bk);
941:   }
942:   return 0;
943: }

945: /*@
946:    PetscMergeMPIIntArray -     Merges two SORTED `PetscMPIInt` arrays.

948:    Not Collective

950:    Input Parameters:
951: +  an  - number of values in the first array
952: .  aI  - first sorted array of integers
953: .  bn  - number of values in the second array
954: -  bI  - second array of integers

956:    Output Parameters:
957: +  n   - number of values in the merged array (<= an + bn)
958: -  L   - merged sorted array, allocated if address of NULL pointer is passed

960:    Level: intermediate

962: .seealso: `PetscIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
963: @*/
964: PetscErrorCode PetscMergeMPIIntArray(PetscInt an, const PetscMPIInt aI[], PetscInt bn, const PetscMPIInt bI[], PetscInt *n, PetscMPIInt **L)
965: {
966:   PetscInt ai, bi, k;

968:   if (!*L) PetscMalloc1((an + bn), L);
969:   for (ai = 0, bi = 0, k = 0; ai < an || bi < bn;) {
970:     PetscInt t = -1;
971:     for (; ai < an && (!bn || aI[ai] <= bI[bi]); ai++) (*L)[k++] = t = aI[ai];
972:     for (; bi < bn && bI[bi] == t; bi++)
973:       ;
974:     for (; bi < bn && (!an || bI[bi] <= aI[ai]); bi++) (*L)[k++] = t = bI[bi];
975:     for (; ai < an && aI[ai] == t; ai++)
976:       ;
977:   }
978:   *n = k;
979:   return 0;
980: }

982: /*@C
983:    PetscProcessTree - Prepares tree data to be displayed graphically

985:    Not Collective

987:    Input Parameters:
988: +  n  - number of values
989: .  mask - indicates those entries in the tree, location 0 is always masked
990: -  parentid - indicates the parent of each entry

992:    Output Parameters:
993: +  Nlevels - the number of levels
994: .  Level - for each node tells its level
995: .  Levelcnts - the number of nodes on each level
996: .  Idbylevel - a list of ids on each of the levels, first level followed by second etc
997: -  Column - for each id tells its column index

999:    Level: developer

1001:    Note:
1002:     This code is not currently used

1004: .seealso: `PetscSortReal()`, `PetscSortIntWithPermutation()`
1005: @*/
1006: PetscErrorCode PetscProcessTree(PetscInt n, const PetscBool mask[], const PetscInt parentid[], PetscInt *Nlevels, PetscInt **Level, PetscInt **Levelcnt, PetscInt **Idbylevel, PetscInt **Column)
1007: {
1008:   PetscInt  i, j, cnt, nmask = 0, nlevels = 0, *level, *levelcnt, levelmax = 0, *workid, *workparentid, tcnt = 0, *idbylevel, *column;
1009:   PetscBool done = PETSC_FALSE;

1012:   for (i = 0; i < n; i++) {
1013:     if (mask[i]) continue;
1016:   }

1018:   for (i = 0; i < n; i++) {
1019:     if (!mask[i]) nmask++;
1020:   }

1022:   /* determine the level in the tree of each node */
1023:   PetscCalloc1(n, &level);

1025:   level[0] = 1;
1026:   while (!done) {
1027:     done = PETSC_TRUE;
1028:     for (i = 0; i < n; i++) {
1029:       if (mask[i]) continue;
1030:       if (!level[i] && level[parentid[i]]) level[i] = level[parentid[i]] + 1;
1031:       else if (!level[i]) done = PETSC_FALSE;
1032:     }
1033:   }
1034:   for (i = 0; i < n; i++) {
1035:     level[i]--;
1036:     nlevels = PetscMax(nlevels, level[i]);
1037:   }

1039:   /* count the number of nodes on each level and its max */
1040:   PetscCalloc1(nlevels, &levelcnt);
1041:   for (i = 0; i < n; i++) {
1042:     if (mask[i]) continue;
1043:     levelcnt[level[i] - 1]++;
1044:   }
1045:   for (i = 0; i < nlevels; i++) levelmax = PetscMax(levelmax, levelcnt[i]);

1047:   /* for each level sort the ids by the parent id */
1048:   PetscMalloc2(levelmax, &workid, levelmax, &workparentid);
1049:   PetscMalloc1(nmask, &idbylevel);
1050:   for (j = 1; j <= nlevels; j++) {
1051:     cnt = 0;
1052:     for (i = 0; i < n; i++) {
1053:       if (mask[i]) continue;
1054:       if (level[i] != j) continue;
1055:       workid[cnt]         = i;
1056:       workparentid[cnt++] = parentid[i];
1057:     }
1058:     /*  PetscIntView(cnt,workparentid,0);
1059:     PetscIntView(cnt,workid,0);
1060:     PetscSortIntWithArray(cnt,workparentid,workid);
1061:     PetscIntView(cnt,workparentid,0);
1062:     PetscIntView(cnt,workid,0);*/
1063:     PetscArraycpy(idbylevel + tcnt, workid, cnt);
1064:     tcnt += cnt;
1065:   }
1067:   PetscFree2(workid, workparentid);

1069:   /* for each node list its column */
1070:   PetscMalloc1(n, &column);
1071:   cnt = 0;
1072:   for (j = 0; j < nlevels; j++) {
1073:     for (i = 0; i < levelcnt[j]; i++) column[idbylevel[cnt++]] = i;
1074:   }

1076:   *Nlevels   = nlevels;
1077:   *Level     = level;
1078:   *Levelcnt  = levelcnt;
1079:   *Idbylevel = idbylevel;
1080:   *Column    = column;
1081:   return 0;
1082: }

1084: /*@
1085:   PetscParallelSortedInt - Check whether a `PetscInt` array, distributed over a communicator, is globally sorted.

1087:   Collective

1089:   Input Parameters:
1090: + comm - the MPI communicator
1091: . n - the local number of integers
1092: - keys - the local array of integers

1094:   Output Parameters:
1095: . is_sorted - whether the array is globally sorted

1097:   Level: developer

1099: .seealso: `PetscParallelSortInt()`
1100: @*/
1101: PetscErrorCode PetscParallelSortedInt(MPI_Comm comm, PetscInt n, const PetscInt keys[], PetscBool *is_sorted)
1102: {
1103:   PetscBool   sorted;
1104:   PetscInt    i, min, max, prevmax;
1105:   PetscMPIInt rank;

1107:   sorted = PETSC_TRUE;
1108:   min    = PETSC_MAX_INT;
1109:   max    = PETSC_MIN_INT;
1110:   if (n) {
1111:     min = keys[0];
1112:     max = keys[0];
1113:   }
1114:   for (i = 1; i < n; i++) {
1115:     if (keys[i] < keys[i - 1]) break;
1116:     min = PetscMin(min, keys[i]);
1117:     max = PetscMax(max, keys[i]);
1118:   }
1119:   if (i < n) sorted = PETSC_FALSE;
1120:   prevmax = PETSC_MIN_INT;
1121:   MPI_Exscan(&max, &prevmax, 1, MPIU_INT, MPI_MAX, comm);
1122:   MPI_Comm_rank(comm, &rank);
1123:   if (rank == 0) prevmax = PETSC_MIN_INT;
1124:   if (prevmax > min) sorted = PETSC_FALSE;
1125:   MPI_Allreduce(&sorted, is_sorted, 1, MPIU_BOOL, MPI_LAND, comm);
1126:   return 0;
1127: }