xref: /petsc/src/sys/utils/sorti.c (revision 4ad8454beace47809662cdae21ee081016eaa39a)
1 /*
2    This file contains routines for sorting integers. Values are sorted in place.
3    One can use src/sys/tests/ex52.c for benchmarking.
4  */
5 #include <petsc/private/petscimpl.h> /*I  "petscsys.h"  I*/
6 #include <petsc/private/hashseti.h>
7 
8 #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))))
9 
10 #define MEDIAN(v, right) MEDIAN3(v, right / 4, right / 2, right / 4 * 3)
11 
12 /* Swap one, two or three pairs. Each pair can have its own type */
13 #define SWAP1(a, b, t1) \
14   do { \
15     t1 = a; \
16     a  = b; \
17     b  = t1; \
18   } while (0)
19 #define SWAP2(a, b, c, d, t1, t2) \
20   do { \
21     t1 = a; \
22     a  = b; \
23     b  = t1; \
24     t2 = c; \
25     c  = d; \
26     d  = t2; \
27   } while (0)
28 #define SWAP3(a, b, c, d, e, f, t1, t2, t3) \
29   do { \
30     t1 = a; \
31     a  = b; \
32     b  = t1; \
33     t2 = c; \
34     c  = d; \
35     d  = t2; \
36     t3 = e; \
37     e  = f; \
38     f  = t3; \
39   } while (0)
40 
41 /* Swap a & b, *c & *d. c, d, t2 are pointers to a type of size <siz> */
42 #define SWAP2Data(a, b, c, d, t1, t2, siz) \
43   do { \
44     t1 = a; \
45     a  = b; \
46     b  = t1; \
47     PetscCall(PetscMemcpy(t2, c, siz)); \
48     PetscCall(PetscMemcpy(c, d, siz)); \
49     PetscCall(PetscMemcpy(d, t2, siz)); \
50   } while (0)
51 
52 /*
53    Partition X[lo,hi] into two parts: X[lo,l) <= pivot; X[r,hi] > pivot
54 
55    Input Parameters:
56     + X         - array to partition
57     . pivot     - a pivot of X[]
58     . t1        - temp variable for X
59     - lo,hi     - lower and upper bound of the array
60 
61    Output Parameters:
62     + l,r       - of type PetscInt
63 
64    Note:
65     The TwoWayPartition2/3 variants also partition other arrays along with X.
66     These arrays can have different types, so they provide their own temp t2,t3
67  */
68 #define TwoWayPartition1(X, pivot, t1, lo, hi, l, r) \
69   do { \
70     l = lo; \
71     r = hi; \
72     while (1) { \
73       while (X[l] < pivot) l++; \
74       while (X[r] > pivot) r--; \
75       if (l >= r) { \
76         r++; \
77         break; \
78       } \
79       SWAP1(X[l], X[r], t1); \
80       l++; \
81       r--; \
82     } \
83   } while (0)
84 
85 /*
86    Partition X[lo,hi] into two parts: X[lo,l) >= pivot; X[r,hi] < pivot
87 
88    Input Parameters:
89     + X         - array to partition
90     . pivot     - a pivot of X[]
91     . t1        - temp variable for X
92     - lo,hi     - lower and upper bound of the array
93 
94    Output Parameters:
95     + l,r       - of type PetscInt
96 
97    Note:
98     The TwoWayPartition2/3 variants also partition other arrays along with X.
99     These arrays can have different types, so they provide their own temp t2,t3
100  */
101 #define TwoWayPartitionReverse1(X, pivot, t1, lo, hi, l, r) \
102   do { \
103     l = lo; \
104     r = hi; \
105     while (1) { \
106       while (X[l] > pivot) l++; \
107       while (X[r] < pivot) r--; \
108       if (l >= r) { \
109         r++; \
110         break; \
111       } \
112       SWAP1(X[l], X[r], t1); \
113       l++; \
114       r--; \
115     } \
116   } while (0)
117 
118 #define TwoWayPartition2(X, Y, pivot, t1, t2, lo, hi, l, r) \
119   do { \
120     l = lo; \
121     r = hi; \
122     while (1) { \
123       while (X[l] < pivot) l++; \
124       while (X[r] > pivot) r--; \
125       if (l >= r) { \
126         r++; \
127         break; \
128       } \
129       SWAP2(X[l], X[r], Y[l], Y[r], t1, t2); \
130       l++; \
131       r--; \
132     } \
133   } while (0)
134 
135 #define TwoWayPartition3(X, Y, Z, pivot, t1, t2, t3, lo, hi, l, r) \
136   do { \
137     l = lo; \
138     r = hi; \
139     while (1) { \
140       while (X[l] < pivot) l++; \
141       while (X[r] > pivot) r--; \
142       if (l >= r) { \
143         r++; \
144         break; \
145       } \
146       SWAP3(X[l], X[r], Y[l], Y[r], Z[l], Z[r], t1, t2, t3); \
147       l++; \
148       r--; \
149     } \
150   } while (0)
151 
152 /* Templates for similar functions used below */
153 #define QuickSort1(FuncName, X, n, pivot, t1) \
154   do { \
155     PetscCount i, j, p, l, r, hi = n - 1; \
156     if (n < 8) { \
157       for (i = 0; i < n; i++) { \
158         pivot = X[i]; \
159         for (j = i + 1; j < n; j++) { \
160           if (pivot > X[j]) { \
161             SWAP1(X[i], X[j], t1); \
162             pivot = X[i]; \
163           } \
164         } \
165       } \
166     } else { \
167       p     = MEDIAN(X, hi); \
168       pivot = X[p]; \
169       TwoWayPartition1(X, pivot, t1, 0, hi, l, r); \
170       PetscCall(FuncName(l, X)); \
171       PetscCall(FuncName(hi - r + 1, X + r)); \
172     } \
173   } while (0)
174 
175 /* Templates for similar functions used below */
176 #define QuickSortReverse1(FuncName, X, n, pivot, t1) \
177   do { \
178     PetscCount i, j, p, l, r, hi = n - 1; \
179     if (n < 8) { \
180       for (i = 0; i < n; i++) { \
181         pivot = X[i]; \
182         for (j = i + 1; j < n; j++) { \
183           if (pivot < X[j]) { \
184             SWAP1(X[i], X[j], t1); \
185             pivot = X[i]; \
186           } \
187         } \
188       } \
189     } else { \
190       p     = MEDIAN(X, hi); \
191       pivot = X[p]; \
192       TwoWayPartitionReverse1(X, pivot, t1, 0, hi, l, r); \
193       PetscCall(FuncName(l, X)); \
194       PetscCall(FuncName(hi - r + 1, X + r)); \
195     } \
196   } while (0)
197 
198 #define QuickSort2(FuncName, X, Y, n, pivot, t1, t2) \
199   do { \
200     PetscCount i, j, p, l, r, hi = n - 1; \
201     if (n < 8) { \
202       for (i = 0; i < n; i++) { \
203         pivot = X[i]; \
204         for (j = i + 1; j < n; j++) { \
205           if (pivot > X[j]) { \
206             SWAP2(X[i], X[j], Y[i], Y[j], t1, t2); \
207             pivot = X[i]; \
208           } \
209         } \
210       } \
211     } else { \
212       p     = MEDIAN(X, hi); \
213       pivot = X[p]; \
214       TwoWayPartition2(X, Y, pivot, t1, t2, 0, hi, l, r); \
215       PetscCall(FuncName(l, X, Y)); \
216       PetscCall(FuncName(hi - r + 1, X + r, Y + r)); \
217     } \
218   } while (0)
219 
220 #define QuickSort3(FuncName, X, Y, Z, n, pivot, t1, t2, t3) \
221   do { \
222     PetscCount i, j, p, l, r, hi = n - 1; \
223     if (n < 8) { \
224       for (i = 0; i < n; i++) { \
225         pivot = X[i]; \
226         for (j = i + 1; j < n; j++) { \
227           if (pivot > X[j]) { \
228             SWAP3(X[i], X[j], Y[i], Y[j], Z[i], Z[j], t1, t2, t3); \
229             pivot = X[i]; \
230           } \
231         } \
232       } \
233     } else { \
234       p     = MEDIAN(X, hi); \
235       pivot = X[p]; \
236       TwoWayPartition3(X, Y, Z, pivot, t1, t2, t3, 0, hi, l, r); \
237       PetscCall(FuncName(l, X, Y, Z)); \
238       PetscCall(FuncName(hi - r + 1, X + r, Y + r, Z + r)); \
239     } \
240   } while (0)
241 
242 /*@
243   PetscSortedInt - Determines whether the `PetscInt` array is sorted.
244 
245   Not Collective
246 
247   Input Parameters:
248 + n - number of values
249 - X - array of integers
250 
251   Output Parameter:
252 . sorted - flag whether the array is sorted
253 
254   Level: intermediate
255 
256 .seealso: `PetscSortInt()`, `PetscSortedMPIInt()`, `PetscSortedReal()`
257 @*/
258 PetscErrorCode PetscSortedInt(PetscInt n, const PetscInt X[], PetscBool *sorted)
259 {
260   PetscFunctionBegin;
261   if (n) PetscAssertPointer(X, 2);
262   PetscAssertPointer(sorted, 3);
263   PetscSorted(n, X, *sorted);
264   PetscFunctionReturn(PETSC_SUCCESS);
265 }
266 
267 /*@
268   PetscSortedInt64 - Determines whether the `PetscInt64` array is sorted.
269 
270   Not Collective
271 
272   Input Parameters:
273 + n - number of values
274 - X - array of integers
275 
276   Output Parameter:
277 . sorted - flag whether the array is sorted
278 
279   Level: intermediate
280 
281 .seealso: `PetscSortInt64()`, `PetscSortInt()`, `PetscSortedMPIInt()`, `PetscSortedReal()`
282 @*/
283 PetscErrorCode PetscSortedInt64(PetscInt n, const PetscInt64 X[], PetscBool *sorted)
284 {
285   PetscFunctionBegin;
286   if (n) PetscAssertPointer(X, 2);
287   PetscAssertPointer(sorted, 3);
288   PetscSorted(n, X, *sorted);
289   PetscFunctionReturn(PETSC_SUCCESS);
290 }
291 
292 /*@
293   PetscSortInt - Sorts an array of `PetscInt` in place in increasing order.
294 
295   Not Collective
296 
297   Input Parameters:
298 + n - number of values
299 - X - array of integers
300 
301   Note:
302   This function serves as an alternative to `PetscIntSortSemiOrdered()`, and may perform faster especially if the array
303   is completely random. There are exceptions to this and so it is __highly__ recommended that the user benchmark their
304   code to see which routine is fastest.
305 
306   Level: intermediate
307 
308 .seealso: `PetscIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`
309 @*/
310 PetscErrorCode PetscSortInt(PetscInt n, PetscInt X[])
311 {
312   PetscInt pivot, t1;
313 
314   PetscFunctionBegin;
315   if (n) PetscAssertPointer(X, 2);
316   QuickSort1(PetscSortInt, X, n, pivot, t1);
317   PetscFunctionReturn(PETSC_SUCCESS);
318 }
319 
320 /*@
321   PetscSortInt64 - Sorts an array of `PetscInt64` in place in increasing order.
322 
323   Not Collective
324 
325   Input Parameters:
326 + n - number of values
327 - X - array of integers
328 
329   Notes:
330   This function sorts `PetscInt64`s assumed to be in completely random order
331 
332   Level: intermediate
333 
334 .seealso: `PetscSortInt()`
335 @*/
336 PetscErrorCode PetscSortInt64(PetscInt n, PetscInt64 X[])
337 {
338   PetscCount pivot, t1;
339 
340   PetscFunctionBegin;
341   if (n) PetscAssertPointer(X, 2);
342   QuickSort1(PetscSortInt64, X, n, pivot, t1);
343   PetscFunctionReturn(PETSC_SUCCESS);
344 }
345 
346 /*@
347   PetscSortCount - Sorts an array of integers in place in increasing order.
348 
349   Not Collective
350 
351   Input Parameters:
352 + n - number of values
353 - X - array of integers
354 
355   Notes:
356   This function sorts `PetscCount`s assumed to be in completely random order
357 
358   Level: intermediate
359 
360 .seealso: `PetscSortInt()`
361 @*/
362 PetscErrorCode PetscSortCount(PetscInt n, PetscCount X[])
363 {
364   PetscCount pivot, t1;
365 
366   PetscFunctionBegin;
367   if (n) PetscAssertPointer(X, 2);
368   QuickSort1(PetscSortCount, X, n, pivot, t1);
369   PetscFunctionReturn(PETSC_SUCCESS);
370 }
371 
372 /*@
373   PetscSortReverseInt - Sorts an array of integers in place in decreasing order.
374 
375   Not Collective
376 
377   Input Parameters:
378 + n - number of values
379 - X - array of integers
380 
381   Level: intermediate
382 
383 .seealso: `PetscIntSortSemiOrdered()`, `PetscSortInt()`, `PetscSortIntWithPermutation()`
384 @*/
385 PetscErrorCode PetscSortReverseInt(PetscInt n, PetscInt X[])
386 {
387   PetscInt pivot, t1;
388 
389   PetscFunctionBegin;
390   if (n) PetscAssertPointer(X, 2);
391   QuickSortReverse1(PetscSortReverseInt, X, n, pivot, t1);
392   PetscFunctionReturn(PETSC_SUCCESS);
393 }
394 
395 /*@
396   PetscSortedRemoveDupsInt - Removes all duplicate entries of a sorted `PetscInt` array
397 
398   Not Collective
399 
400   Input Parameters:
401 + n - number of values
402 - X - sorted array of integers
403 
404   Output Parameter:
405 . n - number of non-redundant values
406 
407   Level: intermediate
408 
409 .seealso: `PetscSortInt()`
410 @*/
411 PetscErrorCode PetscSortedRemoveDupsInt(PetscInt *n, PetscInt X[])
412 {
413   PetscInt i, s = 0, N = *n, b = 0;
414 
415   PetscFunctionBegin;
416   PetscAssertPointer(n, 1);
417   PetscCheckSorted(*n, X);
418   for (i = 0; i < N - 1; i++) {
419     if (X[b + s + 1] != X[b]) {
420       X[b + 1] = X[b + s + 1];
421       b++;
422     } else s++;
423   }
424   *n = N - s;
425   PetscFunctionReturn(PETSC_SUCCESS);
426 }
427 
428 /*@
429   PetscSortedCheckDupsInt - Checks if a sorted `PetscInt` array has duplicates
430 
431   Not Collective
432 
433   Input Parameters:
434 + n - number of values
435 - X - sorted array of integers
436 
437   Output Parameter:
438 . flg - True if the array has dups, otherwise false
439 
440   Level: intermediate
441 
442 .seealso: `PetscSortInt()`, `PetscCheckDupsInt()`, `PetscSortRemoveDupsInt()`, `PetscSortedRemoveDupsInt()`
443 @*/
444 PetscErrorCode PetscSortedCheckDupsInt(PetscInt n, const PetscInt X[], PetscBool *flg)
445 {
446   PetscInt i;
447 
448   PetscFunctionBegin;
449   PetscCheckSorted(n, X);
450   *flg = PETSC_FALSE;
451   for (i = 0; i < n - 1; i++) {
452     if (X[i + 1] == X[i]) {
453       *flg = PETSC_TRUE;
454       break;
455     }
456   }
457   PetscFunctionReturn(PETSC_SUCCESS);
458 }
459 
460 /*@
461   PetscSortRemoveDupsInt - Sorts an array of `PetscInt` in place in increasing order removes all duplicate entries
462 
463   Not Collective
464 
465   Input Parameters:
466 + n - number of values
467 - X - array of integers
468 
469   Output Parameter:
470 . n - number of non-redundant values
471 
472   Level: intermediate
473 
474 .seealso: `PetscIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortedRemoveDupsInt()`
475 @*/
476 PetscErrorCode PetscSortRemoveDupsInt(PetscInt *n, PetscInt X[])
477 {
478   PetscFunctionBegin;
479   PetscAssertPointer(n, 1);
480   PetscCall(PetscSortInt(*n, X));
481   PetscCall(PetscSortedRemoveDupsInt(n, X));
482   PetscFunctionReturn(PETSC_SUCCESS);
483 }
484 
485 /*@
486   PetscFindInt - Finds `PetscInt` in a sorted array of `PetscInt`
487 
488   Not Collective
489 
490   Input Parameters:
491 + key - the integer to locate
492 . n   - number of values in the array
493 - X   - array of integers
494 
495   Output Parameter:
496 . loc - the location if found, otherwise -(slot+1) where slot is the place the value would go
497 
498   Level: intermediate
499 
500 .seealso: `PetscIntSortSemiOrdered()`, `PetscSortInt()`, `PetscSortIntWithArray()`, `PetscSortRemoveDupsInt()`
501 @*/
502 PetscErrorCode PetscFindInt(PetscInt key, PetscInt n, const PetscInt X[], PetscInt *loc)
503 {
504   PetscInt lo = 0, hi = n;
505 
506   PetscFunctionBegin;
507   PetscAssertPointer(loc, 4);
508   if (!n) {
509     *loc = -1;
510     PetscFunctionReturn(PETSC_SUCCESS);
511   }
512   PetscAssertPointer(X, 3);
513   PetscCheckSorted(n, X);
514   while (hi - lo > 1) {
515     PetscInt mid = lo + (hi - lo) / 2;
516     if (key < X[mid]) hi = mid;
517     else lo = mid;
518   }
519   *loc = key == X[lo] ? lo : -(lo + (key > X[lo]) + 1);
520   PetscFunctionReturn(PETSC_SUCCESS);
521 }
522 
523 /*@
524   PetscCheckDupsInt - Checks if an `PetscInt` array has duplicates
525 
526   Not Collective
527 
528   Input Parameters:
529 + n - number of values in the array
530 - X - array of integers
531 
532   Output Parameter:
533 . dups - True if the array has dups, otherwise false
534 
535   Level: intermediate
536 
537 .seealso: `PetscSortRemoveDupsInt()`, `PetscSortedCheckDupsInt()`
538 @*/
539 PetscErrorCode PetscCheckDupsInt(PetscInt n, const PetscInt X[], PetscBool *dups)
540 {
541   PetscInt   i;
542   PetscHSetI ht;
543   PetscBool  missing;
544 
545   PetscFunctionBegin;
546   if (n) PetscAssertPointer(X, 2);
547   PetscAssertPointer(dups, 3);
548   *dups = PETSC_FALSE;
549   if (n > 1) {
550     PetscCall(PetscHSetICreate(&ht));
551     PetscCall(PetscHSetIResize(ht, n));
552     for (i = 0; i < n; i++) {
553       PetscCall(PetscHSetIQueryAdd(ht, X[i], &missing));
554       if (!missing) {
555         *dups = PETSC_TRUE;
556         break;
557       }
558     }
559     PetscCall(PetscHSetIDestroy(&ht));
560   }
561   PetscFunctionReturn(PETSC_SUCCESS);
562 }
563 
564 /*@
565   PetscFindMPIInt - Finds `PetscMPIInt` in a sorted array of `PetscMPIInt`
566 
567   Not Collective
568 
569   Input Parameters:
570 + key - the integer to locate
571 . n   - number of values in the array
572 - X   - array of integers
573 
574   Output Parameter:
575 . loc - the location if found, otherwise -(slot+1) where slot is the place the value would go
576 
577   Level: intermediate
578 
579 .seealso: `PetscMPIIntSortSemiOrdered()`, `PetscSortInt()`, `PetscSortIntWithArray()`, `PetscSortRemoveDupsInt()`
580 @*/
581 PetscErrorCode PetscFindMPIInt(PetscMPIInt key, PetscInt n, const PetscMPIInt X[], PetscInt *loc)
582 {
583   PetscInt lo = 0, hi = n;
584 
585   PetscFunctionBegin;
586   PetscAssertPointer(loc, 4);
587   if (!n) {
588     *loc = -1;
589     PetscFunctionReturn(PETSC_SUCCESS);
590   }
591   PetscAssertPointer(X, 3);
592   PetscCheckSorted(n, X);
593   while (hi - lo > 1) {
594     PetscInt mid = lo + (hi - lo) / 2;
595     if (key < X[mid]) hi = mid;
596     else lo = mid;
597   }
598   *loc = key == X[lo] ? lo : -(lo + (key > X[lo]) + 1);
599   PetscFunctionReturn(PETSC_SUCCESS);
600 }
601 
602 /*@
603   PetscSortIntWithArray - Sorts an array of `PetscInt` in place in increasing order;
604   changes a second array of `PetscInt` to match the sorted first array.
605 
606   Not Collective
607 
608   Input Parameters:
609 + n - number of values
610 . X - array of integers
611 - Y - second array of integers
612 
613   Level: intermediate
614 
615 .seealso: `PetscIntSortSemiOrderedWithArray()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithCountArray()`
616 @*/
617 PetscErrorCode PetscSortIntWithArray(PetscInt n, PetscInt X[], PetscInt Y[])
618 {
619   PetscInt pivot, t1, t2;
620 
621   PetscFunctionBegin;
622   QuickSort2(PetscSortIntWithArray, X, Y, n, pivot, t1, t2);
623   PetscFunctionReturn(PETSC_SUCCESS);
624 }
625 
626 /*@
627   PetscSortIntWithArrayPair - Sorts an array of `PetscInt` in place in increasing order;
628   changes a pair of `PetscInt` arrays to match the sorted first array.
629 
630   Not Collective
631 
632   Input Parameters:
633 + n - number of values
634 . X - array of integers
635 . Y - second array of integers (first array of the pair)
636 - Z - third array of integers  (second array of the pair)
637 
638   Level: intermediate
639 
640 .seealso: `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortIntWithArray()`, `PetscIntSortSemiOrdered()`, `PetscSortIntWithIntCountArrayPair()`
641 @*/
642 PetscErrorCode PetscSortIntWithArrayPair(PetscInt n, PetscInt X[], PetscInt Y[], PetscInt Z[])
643 {
644   PetscInt pivot, t1, t2, t3;
645 
646   PetscFunctionBegin;
647   QuickSort3(PetscSortIntWithArrayPair, X, Y, Z, n, pivot, t1, t2, t3);
648   PetscFunctionReturn(PETSC_SUCCESS);
649 }
650 
651 /*@
652   PetscSortIntWithCountArray - Sorts an array of `PetscInt` in place in increasing order;
653   changes a second array of `PetscCount` to match the sorted first array.
654 
655   Not Collective
656 
657   Input Parameters:
658 + n - number of values
659 . X - array of integers
660 - Y - second array of PetscCounts (signed integers)
661 
662   Level: intermediate
663 
664 .seealso: `PetscIntSortSemiOrderedWithArray()`, `PetscSortReal()`, `PetscSortIntPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
665 @*/
666 PetscErrorCode PetscSortIntWithCountArray(PetscCount n, PetscInt X[], PetscCount Y[])
667 {
668   PetscInt   pivot, t1;
669   PetscCount t2;
670 
671   PetscFunctionBegin;
672   QuickSort2(PetscSortIntWithCountArray, X, Y, n, pivot, t1, t2);
673   PetscFunctionReturn(PETSC_SUCCESS);
674 }
675 
676 /*@
677   PetscSortIntWithIntCountArrayPair - Sorts an array of `PetscInt` in place in increasing order;
678   changes a `PetscInt`  array and a `PetscCount` array to match the sorted first array.
679 
680   Not Collective
681 
682   Input Parameters:
683 + n - number of values
684 . X - array of integers
685 . Y - second array of integers (first array of the pair)
686 - Z - third array of PetscCounts  (second array of the pair)
687 
688   Level: intermediate
689 
690   Note:
691   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.
692 
693 .seealso: `PetscSortReal()`, `PetscSortIntPermutation()`, `PetscSortIntWithArray()`, `PetscIntSortSemiOrdered()`, `PetscSortIntWithArrayPair()`
694 @*/
695 PetscErrorCode PetscSortIntWithIntCountArrayPair(PetscCount n, PetscInt X[], PetscInt Y[], PetscCount Z[])
696 {
697   PetscInt   pivot, t1, t2; /* pivot is take from X[], so its type is still PetscInt */
698   PetscCount t3;            /* temp for Z[] */
699 
700   PetscFunctionBegin;
701   QuickSort3(PetscSortIntWithIntCountArrayPair, X, Y, Z, n, pivot, t1, t2, t3);
702   PetscFunctionReturn(PETSC_SUCCESS);
703 }
704 
705 /*@
706   PetscSortedMPIInt - Determines whether the `PetscMPIInt` array is sorted.
707 
708   Not Collective
709 
710   Input Parameters:
711 + n - number of values
712 - X - array of integers
713 
714   Output Parameter:
715 . sorted - flag whether the array is sorted
716 
717   Level: intermediate
718 
719 .seealso: `PetscMPIIntSortSemiOrdered()`, `PetscSortMPIInt()`, `PetscSortedInt()`, `PetscSortedReal()`
720 @*/
721 PetscErrorCode PetscSortedMPIInt(PetscInt n, const PetscMPIInt X[], PetscBool *sorted)
722 {
723   PetscFunctionBegin;
724   PetscSorted(n, X, *sorted);
725   PetscFunctionReturn(PETSC_SUCCESS);
726 }
727 
728 /*@
729   PetscSortMPIInt - Sorts an array of `PetscMPIInt` in place in increasing order.
730 
731   Not Collective
732 
733   Input Parameters:
734 + n - number of values
735 - X - array of integers
736 
737   Level: intermediate
738 
739   Note:
740   This function serves as an alternative to PetscMPIIntSortSemiOrdered(), and may perform faster especially if the array
741   is completely random. There are exceptions to this and so it is __highly__ recommended that the user benchmark their
742   code to see which routine is fastest.
743 
744 .seealso: `PetscMPIIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`
745 @*/
746 PetscErrorCode PetscSortMPIInt(PetscInt n, PetscMPIInt X[])
747 {
748   PetscMPIInt pivot, t1;
749 
750   PetscFunctionBegin;
751   QuickSort1(PetscSortMPIInt, X, n, pivot, t1);
752   PetscFunctionReturn(PETSC_SUCCESS);
753 }
754 
755 /*@
756   PetscSortRemoveDupsMPIInt - Sorts an array of `PetscMPIInt` in place in increasing order removes all duplicate entries
757 
758   Not Collective
759 
760   Input Parameters:
761 + n - number of values
762 - X - array of integers
763 
764   Output Parameter:
765 . n - number of non-redundant values
766 
767   Level: intermediate
768 
769 .seealso: `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`
770 @*/
771 PetscErrorCode PetscSortRemoveDupsMPIInt(PetscInt *n, PetscMPIInt X[])
772 {
773   PetscInt s = 0, N = *n, b = 0;
774 
775   PetscFunctionBegin;
776   PetscCall(PetscSortMPIInt(N, X));
777   for (PetscInt i = 0; i < N - 1; i++) {
778     if (X[b + s + 1] != X[b]) {
779       X[b + 1] = X[b + s + 1];
780       b++;
781     } else s++;
782   }
783   *n = N - s;
784   PetscFunctionReturn(PETSC_SUCCESS);
785 }
786 
787 /*@
788   PetscSortMPIIntWithArray - Sorts an array of `PetscMPIInt` in place in increasing order;
789   changes a second `PetscMPIInt` array to match the sorted first array.
790 
791   Not Collective
792 
793   Input Parameters:
794 + n - number of values
795 . X - array of integers
796 - Y - second array of integers
797 
798   Level: intermediate
799 
800 .seealso: `PetscMPIIntSortSemiOrderedWithArray()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`
801 @*/
802 PetscErrorCode PetscSortMPIIntWithArray(PetscMPIInt n, PetscMPIInt X[], PetscMPIInt Y[])
803 {
804   PetscMPIInt pivot, t1, t2;
805 
806   PetscFunctionBegin;
807   QuickSort2(PetscSortMPIIntWithArray, X, Y, n, pivot, t1, t2);
808   PetscFunctionReturn(PETSC_SUCCESS);
809 }
810 
811 /*@
812   PetscSortMPIIntWithIntArray - Sorts an array of `PetscMPIInt` in place in increasing order;
813   changes a second array of `PetscInt` to match the sorted first array.
814 
815   Not Collective
816 
817   Input Parameters:
818 + n - number of values
819 . X - array of MPI integers
820 - Y - second array of Petsc integers
821 
822   Level: intermediate
823 
824   Note:
825   This routine is useful when one needs to sort MPI ranks with other integer arrays.
826 
827 .seealso: `PetscSortMPIIntWithArray()`, `PetscIntSortSemiOrderedWithArray()`, `PetscTimSortWithArray()`
828 @*/
829 PetscErrorCode PetscSortMPIIntWithIntArray(PetscMPIInt n, PetscMPIInt X[], PetscInt Y[])
830 {
831   PetscMPIInt pivot, t1;
832   PetscInt    t2;
833 
834   PetscFunctionBegin;
835   QuickSort2(PetscSortMPIIntWithIntArray, X, Y, n, pivot, t1, t2);
836   PetscFunctionReturn(PETSC_SUCCESS);
837 }
838 
839 /*@
840   PetscSortIntWithScalarArray - Sorts an array of `PetscInt` in place in increasing order;
841   changes a second `PetscScalar` array to match the sorted first array.
842 
843   Not Collective
844 
845   Input Parameters:
846 + n - number of values
847 . X - array of integers
848 - Y - second array of scalars
849 
850   Level: intermediate
851 
852 .seealso: `PetscTimSortWithArray()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
853 @*/
854 PetscErrorCode PetscSortIntWithScalarArray(PetscInt n, PetscInt X[], PetscScalar Y[])
855 {
856   PetscInt    pivot, t1;
857   PetscScalar t2;
858 
859   PetscFunctionBegin;
860   QuickSort2(PetscSortIntWithScalarArray, X, Y, n, pivot, t1, t2);
861   PetscFunctionReturn(PETSC_SUCCESS);
862 }
863 
864 /*@C
865   PetscSortIntWithDataArray - Sorts an array of `PetscInt` in place in increasing order;
866   changes a second array to match the sorted first INTEGER array.  Unlike other sort routines, the user must
867   provide workspace (the size of an element in the data array) to use when sorting.
868 
869   Not Collective
870 
871   Input Parameters:
872 + n    - number of values
873 . X    - array of integers
874 . Y    - second array of data
875 . size - sizeof elements in the data array in bytes
876 - t2   - workspace of "size" bytes used when sorting
877 
878   Level: intermediate
879 
880 .seealso: `PetscTimSortWithArray()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
881 @*/
882 PetscErrorCode PetscSortIntWithDataArray(PetscInt n, PetscInt X[], void *Y, size_t size, void *t2)
883 {
884   char    *YY = (char *)Y;
885   PetscInt t1, pivot, hi = n - 1;
886 
887   PetscFunctionBegin;
888   if (n < 8) {
889     for (PetscInt i = 0; i < n; i++) {
890       pivot = X[i];
891       for (PetscInt j = i + 1; j < n; j++) {
892         if (pivot > X[j]) {
893           SWAP2Data(X[i], X[j], YY + size * i, YY + size * j, t1, t2, size);
894           pivot = X[i];
895         }
896       }
897     }
898   } else {
899     /* Two way partition */
900     PetscInt l = 0, r = hi;
901 
902     pivot = X[MEDIAN(X, hi)];
903     while (1) {
904       while (X[l] < pivot) l++;
905       while (X[r] > pivot) r--;
906       if (l >= r) {
907         r++;
908         break;
909       }
910       SWAP2Data(X[l], X[r], YY + size * l, YY + size * r, t1, t2, size);
911       l++;
912       r--;
913     }
914     PetscCall(PetscSortIntWithDataArray(l, X, Y, size, t2));
915     PetscCall(PetscSortIntWithDataArray(hi - r + 1, X + r, YY + size * r, size, t2));
916   }
917   PetscFunctionReturn(PETSC_SUCCESS);
918 }
919 
920 /*@
921   PetscMergeIntArray -     Merges two SORTED `PetscInt` arrays, removes duplicate elements.
922 
923   Not Collective
924 
925   Input Parameters:
926 + an - number of values in the first array
927 . aI - first sorted array of integers
928 . bn - number of values in the second array
929 - bI - second array of integers
930 
931   Output Parameters:
932 + n - number of values in the merged array
933 - L - merged sorted array, this is allocated if an array is not provided
934 
935   Level: intermediate
936 
937 .seealso: `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
938 @*/
939 PetscErrorCode PetscMergeIntArray(PetscInt an, const PetscInt aI[], PetscInt bn, const PetscInt bI[], PetscInt *n, PetscInt **L)
940 {
941   PetscInt *L_ = *L, ak, bk, k;
942 
943   PetscFunctionBegin;
944   if (!L_) {
945     PetscCall(PetscMalloc1(an + bn, L));
946     L_ = *L;
947   }
948   k = ak = bk = 0;
949   while (ak < an && bk < bn) {
950     if (aI[ak] == bI[bk]) {
951       L_[k] = aI[ak];
952       ++ak;
953       ++bk;
954       ++k;
955     } else if (aI[ak] < bI[bk]) {
956       L_[k] = aI[ak];
957       ++ak;
958       ++k;
959     } else {
960       L_[k] = bI[bk];
961       ++bk;
962       ++k;
963     }
964   }
965   if (ak < an) {
966     PetscCall(PetscArraycpy(L_ + k, aI + ak, an - ak));
967     k += (an - ak);
968   }
969   if (bk < bn) {
970     PetscCall(PetscArraycpy(L_ + k, bI + bk, bn - bk));
971     k += (bn - bk);
972   }
973   *n = k;
974   PetscFunctionReturn(PETSC_SUCCESS);
975 }
976 
977 /*@
978   PetscMergeIntArrayPair -     Merges two SORTED `PetscInt` arrays that share NO common values along with an additional array of `PetscInt`.
979   The additional arrays are the same length as sorted arrays and are merged
980   in the order determined by the merging of the sorted pair.
981 
982   Not Collective
983 
984   Input Parameters:
985 + an - number of values in the first array
986 . aI - first sorted array of integers
987 . aJ - first additional array of integers
988 . bn - number of values in the second array
989 . bI - second array of integers
990 - bJ - second additional of integers
991 
992   Output Parameters:
993 + n - number of values in the merged array (== an + bn)
994 . L - merged sorted array
995 - J - merged additional array
996 
997   Note:
998   if L or J point to non-null arrays then this routine will assume they are of the appropriate size and use them, otherwise this routine will allocate space for them
999 
1000   Level: intermediate
1001 
1002 .seealso: `PetscIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
1003 @*/
1004 PetscErrorCode PetscMergeIntArrayPair(PetscInt an, const PetscInt aI[], const PetscInt aJ[], PetscInt bn, const PetscInt bI[], const PetscInt bJ[], PetscInt *n, PetscInt **L, PetscInt **J)
1005 {
1006   PetscInt n_, *L_, *J_, ak, bk, k;
1007 
1008   PetscFunctionBegin;
1009   PetscAssertPointer(L, 8);
1010   PetscAssertPointer(J, 9);
1011   n_ = an + bn;
1012   *n = n_;
1013   if (!*L) PetscCall(PetscMalloc1(n_, L));
1014   L_ = *L;
1015   if (!*J) PetscCall(PetscMalloc1(n_, J));
1016   J_ = *J;
1017   k = ak = bk = 0;
1018   while (ak < an && bk < bn) {
1019     if (aI[ak] <= bI[bk]) {
1020       L_[k] = aI[ak];
1021       J_[k] = aJ[ak];
1022       ++ak;
1023       ++k;
1024     } else {
1025       L_[k] = bI[bk];
1026       J_[k] = bJ[bk];
1027       ++bk;
1028       ++k;
1029     }
1030   }
1031   if (ak < an) {
1032     PetscCall(PetscArraycpy(L_ + k, aI + ak, an - ak));
1033     PetscCall(PetscArraycpy(J_ + k, aJ + ak, an - ak));
1034     k += (an - ak);
1035   }
1036   if (bk < bn) {
1037     PetscCall(PetscArraycpy(L_ + k, bI + bk, bn - bk));
1038     PetscCall(PetscArraycpy(J_ + k, bJ + bk, bn - bk));
1039   }
1040   PetscFunctionReturn(PETSC_SUCCESS);
1041 }
1042 
1043 /*@
1044   PetscMergeMPIIntArray -     Merges two SORTED `PetscMPIInt` arrays.
1045 
1046   Not Collective
1047 
1048   Input Parameters:
1049 + an - number of values in the first array
1050 . aI - first sorted array of integers
1051 . bn - number of values in the second array
1052 - bI - second array of integers
1053 
1054   Output Parameters:
1055 + n - number of values in the merged array (<= an + bn)
1056 - L - merged sorted array, allocated if address of NULL pointer is passed
1057 
1058   Level: intermediate
1059 
1060 .seealso: `PetscIntSortSemiOrdered()`, `PetscSortReal()`, `PetscSortIntWithPermutation()`, `PetscSortInt()`, `PetscSortIntWithArray()`
1061 @*/
1062 PetscErrorCode PetscMergeMPIIntArray(PetscInt an, const PetscMPIInt aI[], PetscInt bn, const PetscMPIInt bI[], PetscInt *n, PetscMPIInt **L)
1063 {
1064   PetscInt ai, bi, k;
1065 
1066   PetscFunctionBegin;
1067   if (!*L) PetscCall(PetscMalloc1((an + bn), L));
1068   for (ai = 0, bi = 0, k = 0; ai < an || bi < bn;) {
1069     PetscInt t = -1;
1070     for (; ai < an && (!bn || aI[ai] <= bI[bi]); ai++) (*L)[k++] = t = aI[ai];
1071     for (; bi < bn && bI[bi] == t; bi++)
1072       ;
1073     for (; bi < bn && (!an || bI[bi] <= aI[ai]); bi++) (*L)[k++] = t = bI[bi];
1074     for (; ai < an && aI[ai] == t; ai++)
1075       ;
1076   }
1077   *n = k;
1078   PetscFunctionReturn(PETSC_SUCCESS);
1079 }
1080 
1081 /*@C
1082   PetscProcessTree - Prepares tree data to be displayed graphically
1083 
1084   Not Collective
1085 
1086   Input Parameters:
1087 + n        - number of values
1088 . mask     - indicates those entries in the tree, location 0 is always masked
1089 - parentid - indicates the parent of each entry
1090 
1091   Output Parameters:
1092 + Nlevels   - the number of levels
1093 . Level     - for each node tells its level
1094 . Levelcnt  - the number of nodes on each level
1095 . Idbylevel - a list of ids on each of the levels, first level followed by second etc
1096 - Column    - for each id tells its column index
1097 
1098   Level: developer
1099 
1100   Note:
1101   This code is not currently used
1102 
1103 .seealso: `PetscSortReal()`, `PetscSortIntWithPermutation()`
1104 @*/
1105 PetscErrorCode PetscProcessTree(PetscInt n, const PetscBool mask[], const PetscInt parentid[], PetscInt *Nlevels, PetscInt **Level, PetscInt **Levelcnt, PetscInt **Idbylevel, PetscInt **Column)
1106 {
1107   PetscInt  i, j, cnt, nmask = 0, nlevels = 0, *level, *levelcnt, levelmax = 0, *workid, *workparentid, tcnt = 0, *idbylevel, *column;
1108   PetscBool done = PETSC_FALSE;
1109 
1110   PetscFunctionBegin;
1111   PetscCheck(mask[0], PETSC_COMM_SELF, PETSC_ERR_SUP, "Mask of 0th location must be set");
1112   for (i = 0; i < n; i++) {
1113     if (mask[i]) continue;
1114     PetscCheck(parentid[i] != i, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Node labeled as own parent");
1115     PetscCheck(!parentid[i] || !mask[parentid[i]], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Parent is masked");
1116   }
1117 
1118   for (i = 0; i < n; i++) {
1119     if (!mask[i]) nmask++;
1120   }
1121 
1122   /* determine the level in the tree of each node */
1123   PetscCall(PetscCalloc1(n, &level));
1124 
1125   level[0] = 1;
1126   while (!done) {
1127     done = PETSC_TRUE;
1128     for (i = 0; i < n; i++) {
1129       if (mask[i]) continue;
1130       if (!level[i] && level[parentid[i]]) level[i] = level[parentid[i]] + 1;
1131       else if (!level[i]) done = PETSC_FALSE;
1132     }
1133   }
1134   for (i = 0; i < n; i++) {
1135     level[i]--;
1136     nlevels = PetscMax(nlevels, level[i]);
1137   }
1138 
1139   /* count the number of nodes on each level and its max */
1140   PetscCall(PetscCalloc1(nlevels, &levelcnt));
1141   for (i = 0; i < n; i++) {
1142     if (mask[i]) continue;
1143     levelcnt[level[i] - 1]++;
1144   }
1145   for (i = 0; i < nlevels; i++) levelmax = PetscMax(levelmax, levelcnt[i]);
1146 
1147   /* for each level sort the ids by the parent id */
1148   PetscCall(PetscMalloc2(levelmax, &workid, levelmax, &workparentid));
1149   PetscCall(PetscMalloc1(nmask, &idbylevel));
1150   for (j = 1; j <= nlevels; j++) {
1151     cnt = 0;
1152     for (i = 0; i < n; i++) {
1153       if (mask[i]) continue;
1154       if (level[i] != j) continue;
1155       workid[cnt]         = i;
1156       workparentid[cnt++] = parentid[i];
1157     }
1158     /*  PetscIntView(cnt,workparentid,0);
1159     PetscIntView(cnt,workid,0);
1160     PetscCall(PetscSortIntWithArray(cnt,workparentid,workid));
1161     PetscIntView(cnt,workparentid,0);
1162     PetscIntView(cnt,workid,0);*/
1163     PetscCall(PetscArraycpy(idbylevel + tcnt, workid, cnt));
1164     tcnt += cnt;
1165   }
1166   PetscCheck(tcnt == nmask, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent count of unmasked nodes");
1167   PetscCall(PetscFree2(workid, workparentid));
1168 
1169   /* for each node list its column */
1170   PetscCall(PetscMalloc1(n, &column));
1171   cnt = 0;
1172   for (j = 0; j < nlevels; j++) {
1173     for (i = 0; i < levelcnt[j]; i++) column[idbylevel[cnt++]] = i;
1174   }
1175 
1176   *Nlevels   = nlevels;
1177   *Level     = level;
1178   *Levelcnt  = levelcnt;
1179   *Idbylevel = idbylevel;
1180   *Column    = column;
1181   PetscFunctionReturn(PETSC_SUCCESS);
1182 }
1183 
1184 /*@
1185   PetscParallelSortedInt - Check whether a `PetscInt` array, distributed over a communicator, is globally sorted.
1186 
1187   Collective
1188 
1189   Input Parameters:
1190 + comm - the MPI communicator
1191 . n    - the local number of integers
1192 - keys - the local array of integers
1193 
1194   Output Parameters:
1195 . is_sorted - whether the array is globally sorted
1196 
1197   Level: developer
1198 
1199 .seealso: `PetscParallelSortInt()`
1200 @*/
1201 PetscErrorCode PetscParallelSortedInt(MPI_Comm comm, PetscInt n, const PetscInt keys[], PetscBool *is_sorted)
1202 {
1203   PetscBool   sorted;
1204   PetscInt    i, min, max, prevmax;
1205   PetscMPIInt rank;
1206 
1207   PetscFunctionBegin;
1208   sorted = PETSC_TRUE;
1209   min    = PETSC_MAX_INT;
1210   max    = PETSC_MIN_INT;
1211   if (n) {
1212     min = keys[0];
1213     max = keys[0];
1214   }
1215   for (i = 1; i < n; i++) {
1216     if (keys[i] < keys[i - 1]) break;
1217     min = PetscMin(min, keys[i]);
1218     max = PetscMax(max, keys[i]);
1219   }
1220   if (i < n) sorted = PETSC_FALSE;
1221   prevmax = PETSC_MIN_INT;
1222   PetscCallMPI(MPI_Exscan(&max, &prevmax, 1, MPIU_INT, MPI_MAX, comm));
1223   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1224   if (rank == 0) prevmax = PETSC_MIN_INT;
1225   if (prevmax > min) sorted = PETSC_FALSE;
1226   PetscCall(MPIU_Allreduce(&sorted, is_sorted, 1, MPIU_BOOL, MPI_LAND, comm));
1227   PetscFunctionReturn(PETSC_SUCCESS);
1228 }
1229