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