xref: /petsc/src/sys/utils/sorti.c (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795)
1 
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> /*I  "petscsys.h"  I*/
7 #include <petsc/private/hashseti.h>
8 
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))))
10 
11 #define MEDIAN(v, right) MEDIAN3(v, right / 4, right / 2, right / 4 * 3)
12 
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)
41 
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     PetscCall(PetscMemcpy(t2, c, siz)); \
49     PetscCall(PetscMemcpy(c, d, siz)); \
50     PetscCall(PetscMemcpy(d, t2, siz)); \
51   } while (0)
52 
53 /*
54    Partition X[lo,hi] into two parts: X[lo,l) <= pivot; X[r,hi] > pivot
55 
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
61 
62    Output Parameters:
63     + l,r       - of type PetscInt
64 
65    Notes:
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)
85 
86 /*
87    Partition X[lo,hi] into two parts: X[lo,l) >= pivot; X[r,hi] < pivot
88 
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
94 
95    Output Parameters:
96     + l,r       - of type PetscInt
97 
98    Notes:
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)
118 
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)
135 
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)
152 
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       PetscCall(FuncName(l, X)); \
172       PetscCall(FuncName(hi - r + 1, X + r)); \
173     } \
174   } while (0)
175 
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       PetscCall(FuncName(l, X)); \
195       PetscCall(FuncName(hi - r + 1, X + r)); \
196     } \
197   } while (0)
198 
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       PetscCall(FuncName(l, X, Y)); \
217       PetscCall(FuncName(hi - r + 1, X + r, Y + r)); \
218     } \
219   } while (0)
220 
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       PetscCall(FuncName(l, X, Y, Z)); \
239       PetscCall(FuncName(hi - r + 1, X + r, Y + r, Z + r)); \
240     } \
241   } while (0)
242 
243 /*@
244    PetscSortedInt - Determines whether the array is sorted.
245 
246    Not Collective
247 
248    Input Parameters:
249 +  n  - number of values
250 -  X  - array of integers
251 
252    Output Parameters:
253 .  sorted - flag whether the array is sorted
254 
255    Level: intermediate
256 
257 .seealso: `PetscSortInt()`, `PetscSortedMPIInt()`, `PetscSortedReal()`
258 @*/
259 PetscErrorCode PetscSortedInt(PetscInt n, const PetscInt X[], PetscBool *sorted) {
260   PetscFunctionBegin;
261   if (n) PetscValidIntPointer(X, 2);
262   PetscValidBoolPointer(sorted, 3);
263   PetscSorted(n, X, *sorted);
264   PetscFunctionReturn(0);
265 }
266 
267 /*@
268    PetscSortInt - Sorts an array of integers in place in increasing order.
269 
270    Not Collective
271 
272    Input Parameters:
273 +  n  - number of values
274 -  X  - array of integers
275 
276    Notes:
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.
280 
281    Level: intermediate
282 
283 .seealso: `PetscIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`
284 @*/
285 PetscErrorCode PetscSortInt(PetscInt n, PetscInt X[]) {
286   PetscInt pivot, t1;
287 
288   PetscFunctionBegin;
289   if (n) PetscValidIntPointer(X, 2);
290   QuickSort1(PetscSortInt, X, n, pivot, t1);
291   PetscFunctionReturn(0);
292 }
293 
294 /*@
295    PetscSortReverseInt - Sorts an array of integers in place in decreasing order.
296 
297    Not Collective
298 
299    Input Parameters:
300 +  n  - number of values
301 -  X  - array of integers
302 
303    Level: intermediate
304 
305 .seealso: `PetscIntSortSemiOrdered()`, `PetscSortInt()`, `PetscSortIntWithPermutation()`
306 @*/
307 PetscErrorCode PetscSortReverseInt(PetscInt n, PetscInt X[]) {
308   PetscInt pivot, t1;
309 
310   PetscFunctionBegin;
311   if (n) PetscValidIntPointer(X, 2);
312   QuickSortReverse1(PetscSortReverseInt, X, n, pivot, t1);
313   PetscFunctionReturn(0);
314 }
315 
316 /*@
317    PetscSortedRemoveDupsInt - Removes all duplicate entries of a sorted input array
318 
319    Not Collective
320 
321    Input Parameters:
322 +  n  - number of values
323 -  X  - sorted array of integers
324 
325    Output Parameter:
326 .  n - number of non-redundant values
327 
328    Level: intermediate
329 
330 .seealso: `PetscSortInt()`
331 @*/
332 PetscErrorCode PetscSortedRemoveDupsInt(PetscInt *n, PetscInt X[]) {
333   PetscInt i, s = 0, N = *n, b = 0;
334 
335   PetscFunctionBegin;
336   PetscValidIntPointer(n, 1);
337   PetscCheckSorted(*n, X);
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   PetscFunctionReturn(0);
346 }
347 
348 /*@
349    PetscSortedCheckDupsInt - Checks if a sorted integer array has duplicates
350 
351    Not Collective
352 
353    Input Parameters:
354 +  n  - number of values
355 -  X  - sorted array of integers
356 
357    Output Parameter:
358 .  dups - True if the array has dups, otherwise false
359 
360    Level: intermediate
361 
362 .seealso: `PetscSortInt()`, `PetscCheckDupsInt()`, `PetscSortRemoveDupsInt()`, `PetscSortedRemoveDupsInt()`
363 @*/
364 PetscErrorCode PetscSortedCheckDupsInt(PetscInt n, const PetscInt X[], PetscBool *flg) {
365   PetscInt i;
366 
367   PetscFunctionBegin;
368   PetscCheckSorted(n, X);
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   PetscFunctionReturn(0);
377 }
378 
379 /*@
380    PetscSortRemoveDupsInt - Sorts an array of integers in place in increasing order removes all duplicate entries
381 
382    Not Collective
383 
384    Input Parameters:
385 +  n  - number of values
386 -  X  - array of integers
387 
388    Output Parameter:
389 .  n - number of non-redundant values
390 
391    Level: intermediate
392 
393 .seealso: `PetscIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortedRemoveDupsInt()`
394 @*/
395 PetscErrorCode PetscSortRemoveDupsInt(PetscInt *n, PetscInt X[]) {
396   PetscFunctionBegin;
397   PetscValidIntPointer(n, 1);
398   PetscCall(PetscSortInt(*n, X));
399   PetscCall(PetscSortedRemoveDupsInt(n, X));
400   PetscFunctionReturn(0);
401 }
402 
403 /*@
404   PetscFindInt - Finds integer in a sorted array of integers
405 
406    Not Collective
407 
408    Input Parameters:
409 +  key - the integer to locate
410 .  n   - number of values in the array
411 -  X  - array of integers
412 
413    Output Parameter:
414 .  loc - the location if found, otherwise -(slot+1) where slot is the place the value would go
415 
416    Level: intermediate
417 
418 .seealso: `PetscIntSortSemiOrdered()`, `PetscSortInt()`, `PetscSortIntWithArray()`, `PetscSortRemoveDupsInt()`
419 @*/
420 PetscErrorCode PetscFindInt(PetscInt key, PetscInt n, const PetscInt X[], PetscInt *loc) {
421   PetscInt lo = 0, hi = n;
422 
423   PetscFunctionBegin;
424   PetscValidIntPointer(loc, 4);
425   if (!n) {
426     *loc = -1;
427     PetscFunctionReturn(0);
428   }
429   PetscValidIntPointer(X, 3);
430   PetscCheckSorted(n, X);
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   PetscFunctionReturn(0);
438 }
439 
440 /*@
441   PetscCheckDupsInt - Checks if an integer array has duplicates
442 
443    Not Collective
444 
445    Input Parameters:
446 +  n  - number of values in the array
447 -  X  - array of integers
448 
449    Output Parameter:
450 .  dups - True if the array has dups, otherwise false
451 
452    Level: intermediate
453 
454 .seealso: `PetscSortRemoveDupsInt()`, `PetscSortedCheckDupsInt()`
455 @*/
456 PetscErrorCode PetscCheckDupsInt(PetscInt n, const PetscInt X[], PetscBool *dups) {
457   PetscInt   i;
458   PetscHSetI ht;
459   PetscBool  missing;
460 
461   PetscFunctionBegin;
462   if (n) PetscValidIntPointer(X, 2);
463   PetscValidBoolPointer(dups, 3);
464   *dups = PETSC_FALSE;
465   if (n > 1) {
466     PetscCall(PetscHSetICreate(&ht));
467     PetscCall(PetscHSetIResize(ht, n));
468     for (i = 0; i < n; i++) {
469       PetscCall(PetscHSetIQueryAdd(ht, X[i], &missing));
470       if (!missing) {
471         *dups = PETSC_TRUE;
472         break;
473       }
474     }
475     PetscCall(PetscHSetIDestroy(&ht));
476   }
477   PetscFunctionReturn(0);
478 }
479 
480 /*@
481   PetscFindMPIInt - Finds MPI integer in a sorted array of integers
482 
483    Not Collective
484 
485    Input Parameters:
486 +  key - the integer to locate
487 .  n   - number of values in the array
488 -  X   - array of integers
489 
490    Output Parameter:
491 .  loc - the location if found, otherwise -(slot+1) where slot is the place the value would go
492 
493    Level: intermediate
494 
495 .seealso: `PetscMPIIntSortSemiOrdered()`, `PetscSortInt()`, `PetscSortIntWithArray()`, `PetscSortRemoveDupsInt()`
496 @*/
497 PetscErrorCode PetscFindMPIInt(PetscMPIInt key, PetscInt n, const PetscMPIInt X[], PetscInt *loc) {
498   PetscInt lo = 0, hi = n;
499 
500   PetscFunctionBegin;
501   PetscValidIntPointer(loc, 4);
502   if (!n) {
503     *loc = -1;
504     PetscFunctionReturn(0);
505   }
506   PetscValidIntPointer(X, 3);
507   PetscCheckSorted(n, X);
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   PetscFunctionReturn(0);
515 }
516 
517 /*@
518    PetscSortIntWithArray - Sorts an array of integers in place in increasing order;
519        changes a second array to match the sorted first array.
520 
521    Not Collective
522 
523    Input Parameters:
524 +  n  - number of values
525 .  X  - array of integers
526 -  Y  - second array of integers
527 
528    Level: intermediate
529 
530 .seealso: `PetscIntSortSemiOrderedWithArray()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithCountArray()`
531 @*/
532 PetscErrorCode PetscSortIntWithArray(PetscInt n, PetscInt X[], PetscInt Y[]) {
533   PetscInt pivot, t1, t2;
534 
535   PetscFunctionBegin;
536   QuickSort2(PetscSortIntWithArray, X, Y, n, pivot, t1, t2);
537   PetscFunctionReturn(0);
538 }
539 
540 /*@
541    PetscSortIntWithArrayPair - Sorts an array of integers in place in increasing order;
542        changes a pair of integer arrays to match the sorted first array.
543 
544    Not Collective
545 
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)
551 
552    Level: intermediate
553 
554 .seealso: `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortIntWithArray()`, `PetscIntSortSemiOrdered()`, `PetscSortIntWithIntCountArrayPair()`
555 @*/
556 PetscErrorCode PetscSortIntWithArrayPair(PetscInt n, PetscInt X[], PetscInt Y[], PetscInt Z[]) {
557   PetscInt pivot, t1, t2, t3;
558 
559   PetscFunctionBegin;
560   QuickSort3(PetscSortIntWithArrayPair, X, Y, Z, n, pivot, t1, t2, t3);
561   PetscFunctionReturn(0);
562 }
563 
564 /*@
565    PetscSortIntWithCountArray - Sorts an array of integers in place in increasing order;
566        changes a second array to match the sorted first array.
567 
568    Not Collective
569 
570    Input Parameters:
571 +  n  - number of values
572 .  X  - array of integers
573 -  Y  - second array of PetscCounts (signed integers)
574 
575    Level: intermediate
576 
577 .seealso: `PetscIntSortSemiOrderedWithArray()`, `PetscSortReal()`, `PetscSortIntPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
578 @*/
579 PetscErrorCode PetscSortIntWithCountArray(PetscCount n, PetscInt X[], PetscCount Y[]) {
580   PetscInt   pivot, t1;
581   PetscCount t2;
582 
583   PetscFunctionBegin;
584   QuickSort2(PetscSortIntWithCountArray, X, Y, n, pivot, t1, t2);
585   PetscFunctionReturn(0);
586 }
587 
588 /*@
589    PetscSortIntWithIntCountArrayPair - Sorts an array of integers in place in increasing order;
590        changes an integer array and a PetscCount array to match the sorted first array.
591 
592    Not Collective
593 
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)
599 
600    Level: intermediate
601 
602    Notes:
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.
604 
605 .seealso: `PetscSortReal()`, `PetscSortIntPermutation()`, `PetscSortIntWithArray()`, `PetscIntSortSemiOrdered()`, `PetscSortIntWithArrayPair()`
606 @*/
607 PetscErrorCode PetscSortIntWithIntCountArrayPair(PetscCount n, PetscInt X[], PetscInt Y[], PetscCount Z[]) {
608   PetscInt   pivot, t1, t2; /* pivot is take from X[], so its type is still PetscInt */
609   PetscCount t3;            /* temp for Z[] */
610 
611   PetscFunctionBegin;
612   QuickSort3(PetscSortIntWithIntCountArrayPair, X, Y, Z, n, pivot, t1, t2, t3);
613   PetscFunctionReturn(0);
614 }
615 
616 /*@
617    PetscSortedMPIInt - Determines whether the array is sorted.
618 
619    Not Collective
620 
621    Input Parameters:
622 +  n  - number of values
623 -  X  - array of integers
624 
625    Output Parameters:
626 .  sorted - flag whether the array is sorted
627 
628    Level: intermediate
629 
630 .seealso: `PetscMPIIntSortSemiOrdered()`, `PetscSortMPIInt()`, `PetscSortedInt()`, `PetscSortedReal()`
631 @*/
632 PetscErrorCode PetscSortedMPIInt(PetscInt n, const PetscMPIInt X[], PetscBool *sorted) {
633   PetscFunctionBegin;
634   PetscSorted(n, X, *sorted);
635   PetscFunctionReturn(0);
636 }
637 
638 /*@
639    PetscSortMPIInt - Sorts an array of MPI integers in place in increasing order.
640 
641    Not Collective
642 
643    Input Parameters:
644 +  n  - number of values
645 -  X  - array of integers
646 
647    Level: intermediate
648 
649    Notes:
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.
653 
654 .seealso: `PetscMPIIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`
655 @*/
656 PetscErrorCode PetscSortMPIInt(PetscInt n, PetscMPIInt X[]) {
657   PetscMPIInt pivot, t1;
658 
659   PetscFunctionBegin;
660   QuickSort1(PetscSortMPIInt, X, n, pivot, t1);
661   PetscFunctionReturn(0);
662 }
663 
664 /*@
665    PetscSortRemoveDupsMPIInt - Sorts an array of MPI integers in place in increasing order removes all duplicate entries
666 
667    Not Collective
668 
669    Input Parameters:
670 +  n  - number of values
671 -  X  - array of integers
672 
673    Output Parameter:
674 .  n - number of non-redundant values
675 
676    Level: intermediate
677 
678 .seealso: `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`
679 @*/
680 PetscErrorCode PetscSortRemoveDupsMPIInt(PetscInt *n, PetscMPIInt X[]) {
681   PetscInt s = 0, N = *n, b = 0;
682 
683   PetscFunctionBegin;
684   PetscCall(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   PetscFunctionReturn(0);
693 }
694 
695 /*@
696    PetscSortMPIIntWithArray - Sorts an array of integers in place in increasing order;
697        changes a second array to match the sorted first array.
698 
699    Not Collective
700 
701    Input Parameters:
702 +  n  - number of values
703 .  X  - array of integers
704 -  Y  - second array of integers
705 
706    Level: intermediate
707 
708 .seealso: `PetscMPIIntSortSemiOrderedWithArray()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`
709 @*/
710 PetscErrorCode PetscSortMPIIntWithArray(PetscMPIInt n, PetscMPIInt X[], PetscMPIInt Y[]) {
711   PetscMPIInt pivot, t1, t2;
712 
713   PetscFunctionBegin;
714   QuickSort2(PetscSortMPIIntWithArray, X, Y, n, pivot, t1, t2);
715   PetscFunctionReturn(0);
716 }
717 
718 /*@
719    PetscSortMPIIntWithIntArray - Sorts an array of MPI integers in place in increasing order;
720        changes a second array of Petsc intergers to match the sorted first array.
721 
722    Not Collective
723 
724    Input Parameters:
725 +  n  - number of values
726 .  X  - array of MPI integers
727 -  Y  - second array of Petsc integers
728 
729    Level: intermediate
730 
731    Notes: this routine is useful when one needs to sort MPI ranks with other integer arrays.
732 
733 .seealso: `PetscSortMPIIntWithArray()`, `PetscIntSortSemiOrderedWithArray()`, `PetscTimSortWithArray()`
734 @*/
735 PetscErrorCode PetscSortMPIIntWithIntArray(PetscMPIInt n, PetscMPIInt X[], PetscInt Y[]) {
736   PetscMPIInt pivot, t1;
737   PetscInt    t2;
738 
739   PetscFunctionBegin;
740   QuickSort2(PetscSortMPIIntWithIntArray, X, Y, n, pivot, t1, t2);
741   PetscFunctionReturn(0);
742 }
743 
744 /*@
745    PetscSortIntWithScalarArray - Sorts an array of integers in place in increasing order;
746        changes a second SCALAR array to match the sorted first INTEGER array.
747 
748    Not Collective
749 
750    Input Parameters:
751 +  n  - number of values
752 .  X  - array of integers
753 -  Y  - second array of scalars
754 
755    Level: intermediate
756 
757 .seealso: `PetscTimSortWithArray()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
758 @*/
759 PetscErrorCode PetscSortIntWithScalarArray(PetscInt n, PetscInt X[], PetscScalar Y[]) {
760   PetscInt    pivot, t1;
761   PetscScalar t2;
762 
763   PetscFunctionBegin;
764   QuickSort2(PetscSortIntWithScalarArray, X, Y, n, pivot, t1, t2);
765   PetscFunctionReturn(0);
766 }
767 
768 /*@C
769    PetscSortIntWithDataArray - Sorts an array of integers in place in increasing order;
770        changes a second array to match the sorted first INTEGER array.  Unlike other sort routines, the user must
771        provide workspace (the size of an element in the data array) to use when sorting.
772 
773    Not Collective
774 
775    Input Parameters:
776 +  n  - number of values
777 .  X  - array of integers
778 .  Y  - second array of data
779 .  size - sizeof elements in the data array in bytes
780 -  t2   - workspace of "size" bytes used when sorting
781 
782    Level: intermediate
783 
784 .seealso: `PetscTimSortWithArray()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
785 @*/
786 PetscErrorCode PetscSortIntWithDataArray(PetscInt n, PetscInt X[], void *Y, size_t size, void *t2) {
787   char    *YY = (char *)Y;
788   PetscInt t1, pivot, hi = n - 1;
789 
790   PetscFunctionBegin;
791   if (n < 8) {
792     for (PetscInt i = 0; i < n; i++) {
793       pivot = X[i];
794       for (PetscInt j = i + 1; j < n; j++) {
795         if (pivot > X[j]) {
796           SWAP2Data(X[i], X[j], YY + size * i, YY + size * j, t1, t2, size);
797           pivot = X[i];
798         }
799       }
800     }
801   } else {
802     /* Two way partition */
803     PetscInt l = 0, r = hi;
804 
805     pivot = X[MEDIAN(X, hi)];
806     while (1) {
807       while (X[l] < pivot) l++;
808       while (X[r] > pivot) r--;
809       if (l >= r) {
810         r++;
811         break;
812       }
813       SWAP2Data(X[l], X[r], YY + size * l, YY + size * r, t1, t2, size);
814       l++;
815       r--;
816     }
817     PetscCall(PetscSortIntWithDataArray(l, X, Y, size, t2));
818     PetscCall(PetscSortIntWithDataArray(hi - r + 1, X + r, YY + size * r, size, t2));
819   }
820   PetscFunctionReturn(0);
821 }
822 
823 /*@
824    PetscMergeIntArray -     Merges two SORTED integer arrays, removes duplicate elements.
825 
826    Not Collective
827 
828    Input Parameters:
829 +  an  - number of values in the first array
830 .  aI  - first sorted array of integers
831 .  bn  - number of values in the second array
832 -  bI  - second array of integers
833 
834    Output Parameters:
835 +  n   - number of values in the merged array
836 -  L   - merged sorted array, this is allocated if an array is not provided
837 
838    Level: intermediate
839 
840 .seealso: `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
841 @*/
842 PetscErrorCode PetscMergeIntArray(PetscInt an, const PetscInt aI[], PetscInt bn, const PetscInt bI[], PetscInt *n, PetscInt **L) {
843   PetscInt *L_ = *L, ak, bk, k;
844 
845   PetscFunctionBegin;
846   if (!L_) {
847     PetscCall(PetscMalloc1(an + bn, L));
848     L_ = *L;
849   }
850   k = ak = bk = 0;
851   while (ak < an && bk < bn) {
852     if (aI[ak] == bI[bk]) {
853       L_[k] = aI[ak];
854       ++ak;
855       ++bk;
856       ++k;
857     } else if (aI[ak] < bI[bk]) {
858       L_[k] = aI[ak];
859       ++ak;
860       ++k;
861     } else {
862       L_[k] = bI[bk];
863       ++bk;
864       ++k;
865     }
866   }
867   if (ak < an) {
868     PetscCall(PetscArraycpy(L_ + k, aI + ak, an - ak));
869     k += (an - ak);
870   }
871   if (bk < bn) {
872     PetscCall(PetscArraycpy(L_ + k, bI + bk, bn - bk));
873     k += (bn - bk);
874   }
875   *n = k;
876   PetscFunctionReturn(0);
877 }
878 
879 /*@
880    PetscMergeIntArrayPair -     Merges two SORTED integer arrays that share NO common values along with an additional array of integers.
881                                 The additional arrays are the same length as sorted arrays and are merged
882                                 in the order determined by the merging of the sorted pair.
883 
884    Not Collective
885 
886    Input Parameters:
887 +  an  - number of values in the first array
888 .  aI  - first sorted array of integers
889 .  aJ  - first additional array of integers
890 .  bn  - number of values in the second array
891 .  bI  - second array of integers
892 -  bJ  - second additional of integers
893 
894    Output Parameters:
895 +  n   - number of values in the merged array (== an + bn)
896 .  L   - merged sorted array
897 -  J   - merged additional array
898 
899    Notes:
900     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
901    Level: intermediate
902 
903 .seealso: `PetscIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
904 @*/
905 PetscErrorCode PetscMergeIntArrayPair(PetscInt an, const PetscInt aI[], const PetscInt aJ[], PetscInt bn, const PetscInt bI[], const PetscInt bJ[], PetscInt *n, PetscInt **L, PetscInt **J) {
906   PetscInt n_, *L_, *J_, ak, bk, k;
907 
908   PetscFunctionBegin;
909   PetscValidPointer(L, 8);
910   PetscValidPointer(J, 9);
911   n_ = an + bn;
912   *n = n_;
913   if (!*L) PetscCall(PetscMalloc1(n_, L));
914   L_ = *L;
915   if (!*J) PetscCall(PetscMalloc1(n_, J));
916   J_ = *J;
917   k = ak = bk = 0;
918   while (ak < an && bk < bn) {
919     if (aI[ak] <= bI[bk]) {
920       L_[k] = aI[ak];
921       J_[k] = aJ[ak];
922       ++ak;
923       ++k;
924     } else {
925       L_[k] = bI[bk];
926       J_[k] = bJ[bk];
927       ++bk;
928       ++k;
929     }
930   }
931   if (ak < an) {
932     PetscCall(PetscArraycpy(L_ + k, aI + ak, an - ak));
933     PetscCall(PetscArraycpy(J_ + k, aJ + ak, an - ak));
934     k += (an - ak);
935   }
936   if (bk < bn) {
937     PetscCall(PetscArraycpy(L_ + k, bI + bk, bn - bk));
938     PetscCall(PetscArraycpy(J_ + k, bJ + bk, bn - bk));
939   }
940   PetscFunctionReturn(0);
941 }
942 
943 /*@
944    PetscMergeMPIIntArray -     Merges two SORTED integer arrays.
945 
946    Not Collective
947 
948    Input Parameters:
949 +  an  - number of values in the first array
950 .  aI  - first sorted array of integers
951 .  bn  - number of values in the second array
952 -  bI  - second array of integers
953 
954    Output Parameters:
955 +  n   - number of values in the merged array (<= an + bn)
956 -  L   - merged sorted array, allocated if address of NULL pointer is passed
957 
958    Level: intermediate
959 
960 .seealso: `PetscIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
961 @*/
962 PetscErrorCode PetscMergeMPIIntArray(PetscInt an, const PetscMPIInt aI[], PetscInt bn, const PetscMPIInt bI[], PetscInt *n, PetscMPIInt **L) {
963   PetscInt ai, bi, k;
964 
965   PetscFunctionBegin;
966   if (!*L) PetscCall(PetscMalloc1((an + bn), L));
967   for (ai = 0, bi = 0, k = 0; ai < an || bi < bn;) {
968     PetscInt t = -1;
969     for (; ai < an && (!bn || aI[ai] <= bI[bi]); ai++) (*L)[k++] = t = aI[ai];
970     for (; bi < bn && bI[bi] == t; bi++)
971       ;
972     for (; bi < bn && (!an || bI[bi] <= aI[ai]); bi++) (*L)[k++] = t = bI[bi];
973     for (; ai < an && aI[ai] == t; ai++)
974       ;
975   }
976   *n = k;
977   PetscFunctionReturn(0);
978 }
979 
980 /*@C
981    PetscProcessTree - Prepares tree data to be displayed graphically
982 
983    Not Collective
984 
985    Input Parameters:
986 +  n  - number of values
987 .  mask - indicates those entries in the tree, location 0 is always masked
988 -  parentid - indicates the parent of each entry
989 
990    Output Parameters:
991 +  Nlevels - the number of levels
992 .  Level - for each node tells its level
993 .  Levelcnts - the number of nodes on each level
994 .  Idbylevel - a list of ids on each of the levels, first level followed by second etc
995 -  Column - for each id tells its column index
996 
997    Level: developer
998 
999    Notes:
1000     This code is not currently used
1001 
1002 .seealso: `PetscSortReal()`, `PetscSortIntWithPermutation()`
1003 @*/
1004 PetscErrorCode PetscProcessTree(PetscInt n, const PetscBool mask[], const PetscInt parentid[], PetscInt *Nlevels, PetscInt **Level, PetscInt **Levelcnt, PetscInt **Idbylevel, PetscInt **Column) {
1005   PetscInt  i, j, cnt, nmask = 0, nlevels = 0, *level, *levelcnt, levelmax = 0, *workid, *workparentid, tcnt = 0, *idbylevel, *column;
1006   PetscBool done = PETSC_FALSE;
1007 
1008   PetscFunctionBegin;
1009   PetscCheck(mask[0], PETSC_COMM_SELF, PETSC_ERR_SUP, "Mask of 0th location must be set");
1010   for (i = 0; i < n; i++) {
1011     if (mask[i]) continue;
1012     PetscCheck(parentid[i] != i, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Node labeled as own parent");
1013     PetscCheck(!parentid[i] || !mask[parentid[i]], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Parent is masked");
1014   }
1015 
1016   for (i = 0; i < n; i++) {
1017     if (!mask[i]) nmask++;
1018   }
1019 
1020   /* determine the level in the tree of each node */
1021   PetscCall(PetscCalloc1(n, &level));
1022 
1023   level[0] = 1;
1024   while (!done) {
1025     done = PETSC_TRUE;
1026     for (i = 0; i < n; i++) {
1027       if (mask[i]) continue;
1028       if (!level[i] && level[parentid[i]]) level[i] = level[parentid[i]] + 1;
1029       else if (!level[i]) done = PETSC_FALSE;
1030     }
1031   }
1032   for (i = 0; i < n; i++) {
1033     level[i]--;
1034     nlevels = PetscMax(nlevels, level[i]);
1035   }
1036 
1037   /* count the number of nodes on each level and its max */
1038   PetscCall(PetscCalloc1(nlevels, &levelcnt));
1039   for (i = 0; i < n; i++) {
1040     if (mask[i]) continue;
1041     levelcnt[level[i] - 1]++;
1042   }
1043   for (i = 0; i < nlevels; i++) levelmax = PetscMax(levelmax, levelcnt[i]);
1044 
1045   /* for each level sort the ids by the parent id */
1046   PetscCall(PetscMalloc2(levelmax, &workid, levelmax, &workparentid));
1047   PetscCall(PetscMalloc1(nmask, &idbylevel));
1048   for (j = 1; j <= nlevels; j++) {
1049     cnt = 0;
1050     for (i = 0; i < n; i++) {
1051       if (mask[i]) continue;
1052       if (level[i] != j) continue;
1053       workid[cnt]         = i;
1054       workparentid[cnt++] = parentid[i];
1055     }
1056     /*  PetscIntView(cnt,workparentid,0);
1057     PetscIntView(cnt,workid,0);
1058     PetscCall(PetscSortIntWithArray(cnt,workparentid,workid));
1059     PetscIntView(cnt,workparentid,0);
1060     PetscIntView(cnt,workid,0);*/
1061     PetscCall(PetscArraycpy(idbylevel + tcnt, workid, cnt));
1062     tcnt += cnt;
1063   }
1064   PetscCheck(tcnt == nmask, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent count of unmasked nodes");
1065   PetscCall(PetscFree2(workid, workparentid));
1066 
1067   /* for each node list its column */
1068   PetscCall(PetscMalloc1(n, &column));
1069   cnt = 0;
1070   for (j = 0; j < nlevels; j++) {
1071     for (i = 0; i < levelcnt[j]; i++) column[idbylevel[cnt++]] = i;
1072   }
1073 
1074   *Nlevels   = nlevels;
1075   *Level     = level;
1076   *Levelcnt  = levelcnt;
1077   *Idbylevel = idbylevel;
1078   *Column    = column;
1079   PetscFunctionReturn(0);
1080 }
1081 
1082 /*@
1083   PetscParallelSortedInt - Check whether an integer array, distributed over a communicator, is globally sorted.
1084 
1085   Collective
1086 
1087   Input Parameters:
1088 + comm - the MPI communicator
1089 . n - the local number of integers
1090 - keys - the local array of integers
1091 
1092   Output Parameters:
1093 . is_sorted - whether the array is globally sorted
1094 
1095   Level: developer
1096 
1097 .seealso: `PetscParallelSortInt()`
1098 @*/
1099 PetscErrorCode PetscParallelSortedInt(MPI_Comm comm, PetscInt n, const PetscInt keys[], PetscBool *is_sorted) {
1100   PetscBool   sorted;
1101   PetscInt    i, min, max, prevmax;
1102   PetscMPIInt rank;
1103 
1104   PetscFunctionBegin;
1105   sorted = PETSC_TRUE;
1106   min    = PETSC_MAX_INT;
1107   max    = PETSC_MIN_INT;
1108   if (n) {
1109     min = keys[0];
1110     max = keys[0];
1111   }
1112   for (i = 1; i < n; i++) {
1113     if (keys[i] < keys[i - 1]) break;
1114     min = PetscMin(min, keys[i]);
1115     max = PetscMax(max, keys[i]);
1116   }
1117   if (i < n) sorted = PETSC_FALSE;
1118   prevmax = PETSC_MIN_INT;
1119   PetscCallMPI(MPI_Exscan(&max, &prevmax, 1, MPIU_INT, MPI_MAX, comm));
1120   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1121   if (rank == 0) prevmax = PETSC_MIN_INT;
1122   if (prevmax > min) sorted = PETSC_FALSE;
1123   PetscCallMPI(MPI_Allreduce(&sorted, is_sorted, 1, MPIU_BOOL, MPI_LAND, comm));
1124   PetscFunctionReturn(0);
1125 }
1126