xref: /petsc/src/sys/utils/sortd.c (revision 811af0c4b09a35de4306c442f88bd09fdc09897d)
17d0a6c19SBarry Smith 
2e5c89e4eSSatish Balay /*
3e5c89e4eSSatish Balay    This file contains routines for sorting doubles.  Values are sorted in place.
4e5c89e4eSSatish Balay    These are provided because the general sort routines incur a great deal
5a5b23f4aSJose E. Roman    of overhead in calling the comparison routines.
6e5c89e4eSSatish Balay 
7e5c89e4eSSatish Balay  */
8c6db04a5SJed Brown #include <petscsys.h> /*I  "petscsys.h"  I*/
939f41f7fSStefano Zampini #include <petsc/private/petscimpl.h>
10e5c89e4eSSatish Balay 
119371c9d4SSatish Balay #define SWAP(a, b, t) \
129371c9d4SSatish Balay   { \
139371c9d4SSatish Balay     t = a; \
149371c9d4SSatish Balay     a = b; \
159371c9d4SSatish Balay     b = t; \
169371c9d4SSatish Balay   }
17e5c89e4eSSatish Balay 
186a7c706bSVaclav Hapla /*@
19*811af0c4SBarry Smith    PetscSortedReal - Determines whether the array of `PetscReal` is sorted.
206a7c706bSVaclav Hapla 
216a7c706bSVaclav Hapla    Not Collective
226a7c706bSVaclav Hapla 
236a7c706bSVaclav Hapla    Input Parameters:
246a7c706bSVaclav Hapla +  n  - number of values
256a7c706bSVaclav Hapla -  X  - array of integers
266a7c706bSVaclav Hapla 
276a7c706bSVaclav Hapla    Output Parameters:
286a7c706bSVaclav Hapla .  sorted - flag whether the array is sorted
296a7c706bSVaclav Hapla 
306a7c706bSVaclav Hapla    Level: intermediate
316a7c706bSVaclav Hapla 
32db781477SPatrick Sanan .seealso: `PetscSortReal()`, `PetscSortedInt()`, `PetscSortedMPIInt()`
336a7c706bSVaclav Hapla @*/
349371c9d4SSatish Balay PetscErrorCode PetscSortedReal(PetscInt n, const PetscReal X[], PetscBool *sorted) {
356a7c706bSVaclav Hapla   PetscFunctionBegin;
366a7c706bSVaclav Hapla   PetscSorted(n, X, *sorted);
376a7c706bSVaclav Hapla   PetscFunctionReturn(0);
386a7c706bSVaclav Hapla }
396a7c706bSVaclav Hapla 
40e5c89e4eSSatish Balay /* A simple version of quicksort; taken from Kernighan and Ritchie, page 87 */
419371c9d4SSatish Balay static PetscErrorCode PetscSortReal_Private(PetscReal *v, PetscInt right) {
42e5c89e4eSSatish Balay   PetscInt  i, last;
43e5c89e4eSSatish Balay   PetscReal vl, tmp;
44e5c89e4eSSatish Balay 
45e5c89e4eSSatish Balay   PetscFunctionBegin;
46e5c89e4eSSatish Balay   if (right <= 1) {
47e5c89e4eSSatish Balay     if (right == 1) {
48e5c89e4eSSatish Balay       if (v[0] > v[1]) SWAP(v[0], v[1], tmp);
49e5c89e4eSSatish Balay     }
50e5c89e4eSSatish Balay     PetscFunctionReturn(0);
51e5c89e4eSSatish Balay   }
52e5c89e4eSSatish Balay   SWAP(v[0], v[right / 2], tmp);
53e5c89e4eSSatish Balay   vl   = v[0];
54e5c89e4eSSatish Balay   last = 0;
55e5c89e4eSSatish Balay   for (i = 1; i <= right; i++) {
569371c9d4SSatish Balay     if (v[i] < vl) {
579371c9d4SSatish Balay       last++;
589371c9d4SSatish Balay       SWAP(v[last], v[i], tmp);
599371c9d4SSatish Balay     }
60e5c89e4eSSatish Balay   }
61e5c89e4eSSatish Balay   SWAP(v[0], v[last], tmp);
62e5c89e4eSSatish Balay   PetscSortReal_Private(v, last - 1);
63e5c89e4eSSatish Balay   PetscSortReal_Private(v + last + 1, right - (last + 1));
64e5c89e4eSSatish Balay   PetscFunctionReturn(0);
65e5c89e4eSSatish Balay }
66e5c89e4eSSatish Balay 
67e5c89e4eSSatish Balay /*@
68*811af0c4SBarry Smith    PetscSortReal - Sorts an array of `PetscReal` in place in increasing order.
69e5c89e4eSSatish Balay 
70e5c89e4eSSatish Balay    Not Collective
71e5c89e4eSSatish Balay 
72e5c89e4eSSatish Balay    Input Parameters:
73e5c89e4eSSatish Balay +  n  - number of values
74e5c89e4eSSatish Balay -  v  - array of doubles
75e5c89e4eSSatish Balay 
76*811af0c4SBarry Smith    Note:
77*811af0c4SBarry Smith    This function serves as an alternative to `PetscRealSortSemiOrdered()`, and may perform faster especially if the array
78a5b23f4aSJose E. Roman    is completely random. There are exceptions to this and so it is __highly__ recommended that the user benchmark their
79676f2a66SJacob Faibussowitsch    code to see which routine is fastest.
80676f2a66SJacob Faibussowitsch 
81e5c89e4eSSatish Balay    Level: intermediate
82e5c89e4eSSatish Balay 
83db781477SPatrick Sanan .seealso: `PetscRealSortSemiOrdered()`, `PetscSortInt()`, `PetscSortRealWithPermutation()`, `PetscSortRealWithArrayInt()`
84e5c89e4eSSatish Balay @*/
859371c9d4SSatish Balay PetscErrorCode PetscSortReal(PetscInt n, PetscReal v[]) {
86e5c89e4eSSatish Balay   PetscInt  j, k;
87e5c89e4eSSatish Balay   PetscReal tmp, vk;
88e5c89e4eSSatish Balay 
89e5c89e4eSSatish Balay   PetscFunctionBegin;
90dadcf809SJacob Faibussowitsch   PetscValidRealPointer(v, 2);
91e5c89e4eSSatish Balay   if (n < 8) {
92e5c89e4eSSatish Balay     for (k = 0; k < n; k++) {
93e5c89e4eSSatish Balay       vk = v[k];
94e5c89e4eSSatish Balay       for (j = k + 1; j < n; j++) {
95e5c89e4eSSatish Balay         if (vk > v[j]) {
96e5c89e4eSSatish Balay           SWAP(v[k], v[j], tmp);
97e5c89e4eSSatish Balay           vk = v[k];
98e5c89e4eSSatish Balay         }
99e5c89e4eSSatish Balay       }
100e5c89e4eSSatish Balay     }
101a297a907SKarl Rupp   } else PetscSortReal_Private(v, n - 1);
102e5c89e4eSSatish Balay   PetscFunctionReturn(0);
103e5c89e4eSSatish Balay }
104e5c89e4eSSatish Balay 
1059371c9d4SSatish Balay #define SWAP2ri(a, b, c, d, rt, it) \
1069371c9d4SSatish Balay   { \
1079371c9d4SSatish Balay     rt = a; \
1089371c9d4SSatish Balay     a  = b; \
1099371c9d4SSatish Balay     b  = rt; \
1109371c9d4SSatish Balay     it = c; \
1119371c9d4SSatish Balay     c  = d; \
1129371c9d4SSatish Balay     d  = it; \
1139371c9d4SSatish Balay   }
11439f41f7fSStefano Zampini 
11539f41f7fSStefano Zampini /* modified from PetscSortIntWithArray_Private */
1169371c9d4SSatish Balay static PetscErrorCode PetscSortRealWithArrayInt_Private(PetscReal *v, PetscInt *V, PetscInt right) {
11739f41f7fSStefano Zampini   PetscInt  i, last, itmp;
11839f41f7fSStefano Zampini   PetscReal rvl, rtmp;
11939f41f7fSStefano Zampini 
12039f41f7fSStefano Zampini   PetscFunctionBegin;
12139f41f7fSStefano Zampini   if (right <= 1) {
12239f41f7fSStefano Zampini     if (right == 1) {
12339f41f7fSStefano Zampini       if (v[0] > v[1]) SWAP2ri(v[0], v[1], V[0], V[1], rtmp, itmp);
12439f41f7fSStefano Zampini     }
12539f41f7fSStefano Zampini     PetscFunctionReturn(0);
12639f41f7fSStefano Zampini   }
12739f41f7fSStefano Zampini   SWAP2ri(v[0], v[right / 2], V[0], V[right / 2], rtmp, itmp);
12839f41f7fSStefano Zampini   rvl  = v[0];
12939f41f7fSStefano Zampini   last = 0;
13039f41f7fSStefano Zampini   for (i = 1; i <= right; i++) {
1319371c9d4SSatish Balay     if (v[i] < rvl) {
1329371c9d4SSatish Balay       last++;
1339371c9d4SSatish Balay       SWAP2ri(v[last], v[i], V[last], V[i], rtmp, itmp);
1349371c9d4SSatish Balay     }
13539f41f7fSStefano Zampini   }
13639f41f7fSStefano Zampini   SWAP2ri(v[0], v[last], V[0], V[last], rtmp, itmp);
1379566063dSJacob Faibussowitsch   PetscCall(PetscSortRealWithArrayInt_Private(v, V, last - 1));
1389566063dSJacob Faibussowitsch   PetscCall(PetscSortRealWithArrayInt_Private(v + last + 1, V + last + 1, right - (last + 1)));
13939f41f7fSStefano Zampini   PetscFunctionReturn(0);
14039f41f7fSStefano Zampini }
14139f41f7fSStefano Zampini /*@
142*811af0c4SBarry Smith    PetscSortRealWithArrayInt - Sorts an array of `PetscReal` in place in increasing order;
143*811af0c4SBarry Smith        changes a second `PetscInt` array to match the sorted first array.
14439f41f7fSStefano Zampini 
14539f41f7fSStefano Zampini    Not Collective
14639f41f7fSStefano Zampini 
14739f41f7fSStefano Zampini    Input Parameters:
14839f41f7fSStefano Zampini +  n  - number of values
14939f41f7fSStefano Zampini .  i  - array of integers
15039f41f7fSStefano Zampini -  I - second array of integers
15139f41f7fSStefano Zampini 
15239f41f7fSStefano Zampini    Level: intermediate
15339f41f7fSStefano Zampini 
154db781477SPatrick Sanan .seealso: `PetscSortReal()`
15539f41f7fSStefano Zampini @*/
1569371c9d4SSatish Balay PetscErrorCode PetscSortRealWithArrayInt(PetscInt n, PetscReal r[], PetscInt Ii[]) {
15739f41f7fSStefano Zampini   PetscInt  j, k, itmp;
15839f41f7fSStefano Zampini   PetscReal rk, rtmp;
15939f41f7fSStefano Zampini 
16039f41f7fSStefano Zampini   PetscFunctionBegin;
161dadcf809SJacob Faibussowitsch   PetscValidRealPointer(r, 2);
162dadcf809SJacob Faibussowitsch   PetscValidIntPointer(Ii, 3);
16339f41f7fSStefano Zampini   if (n < 8) {
16439f41f7fSStefano Zampini     for (k = 0; k < n; k++) {
16539f41f7fSStefano Zampini       rk = r[k];
16639f41f7fSStefano Zampini       for (j = k + 1; j < n; j++) {
16739f41f7fSStefano Zampini         if (rk > r[j]) {
16839f41f7fSStefano Zampini           SWAP2ri(r[k], r[j], Ii[k], Ii[j], rtmp, itmp);
16939f41f7fSStefano Zampini           rk = r[k];
17039f41f7fSStefano Zampini         }
17139f41f7fSStefano Zampini       }
17239f41f7fSStefano Zampini     }
17339f41f7fSStefano Zampini   } else {
1749566063dSJacob Faibussowitsch     PetscCall(PetscSortRealWithArrayInt_Private(r, Ii, n - 1));
17539f41f7fSStefano Zampini   }
17639f41f7fSStefano Zampini   PetscFunctionReturn(0);
17739f41f7fSStefano Zampini }
17839f41f7fSStefano Zampini 
17939f41f7fSStefano Zampini /*@
180*811af0c4SBarry Smith   PetscFindReal - Finds a PetscReal` in a sorted array of `PetscReal`s
18139f41f7fSStefano Zampini 
18239f41f7fSStefano Zampini    Not Collective
18339f41f7fSStefano Zampini 
18439f41f7fSStefano Zampini    Input Parameters:
18539f41f7fSStefano Zampini +  key - the value to locate
18639f41f7fSStefano Zampini .  n   - number of values in the array
18739f41f7fSStefano Zampini .  ii  - array of values
18839f41f7fSStefano Zampini -  eps - tolerance used to compare
18939f41f7fSStefano Zampini 
19039f41f7fSStefano Zampini    Output Parameter:
19139f41f7fSStefano Zampini .  loc - the location if found, otherwise -(slot+1) where slot is the place the value would go
19239f41f7fSStefano Zampini 
19339f41f7fSStefano Zampini    Level: intermediate
19439f41f7fSStefano Zampini 
195db781477SPatrick Sanan .seealso: `PetscSortReal()`, `PetscSortRealWithArrayInt()`
19639f41f7fSStefano Zampini @*/
1979371c9d4SSatish Balay PetscErrorCode PetscFindReal(PetscReal key, PetscInt n, const PetscReal t[], PetscReal eps, PetscInt *loc) {
19839f41f7fSStefano Zampini   PetscInt lo = 0, hi = n;
19939f41f7fSStefano Zampini 
20039f41f7fSStefano Zampini   PetscFunctionBegin;
201dadcf809SJacob Faibussowitsch   PetscValidIntPointer(loc, 5);
2029371c9d4SSatish Balay   if (!n) {
2039371c9d4SSatish Balay     *loc = -1;
2049371c9d4SSatish Balay     PetscFunctionReturn(0);
2059371c9d4SSatish Balay   }
206dadcf809SJacob Faibussowitsch   PetscValidRealPointer(t, 3);
2076a7c706bSVaclav Hapla   PetscCheckSorted(n, t);
20839f41f7fSStefano Zampini   while (hi - lo > 1) {
20939f41f7fSStefano Zampini     PetscInt mid = lo + (hi - lo) / 2;
21039f41f7fSStefano Zampini     if (key < t[mid]) hi = mid;
21139f41f7fSStefano Zampini     else lo = mid;
21239f41f7fSStefano Zampini   }
21339f41f7fSStefano Zampini   *loc = (PetscAbsReal(key - t[lo]) < eps) ? lo : -(lo + (key > t[lo]) + 1);
21439f41f7fSStefano Zampini   PetscFunctionReturn(0);
21539f41f7fSStefano Zampini }
216745b41b2SMatthew G. Knepley 
217745b41b2SMatthew G. Knepley /*@
218*811af0c4SBarry Smith    PetscSortRemoveDupsReal - Sorts an array of `PetscReal` in place in increasing order and removes all duplicate entries
219745b41b2SMatthew G. Knepley 
220745b41b2SMatthew G. Knepley    Not Collective
221745b41b2SMatthew G. Knepley 
222745b41b2SMatthew G. Knepley    Input Parameters:
223745b41b2SMatthew G. Knepley +  n  - number of values
224745b41b2SMatthew G. Knepley -  v  - array of doubles
225745b41b2SMatthew G. Knepley 
226745b41b2SMatthew G. Knepley    Output Parameter:
227745b41b2SMatthew G. Knepley .  n - number of non-redundant values
228745b41b2SMatthew G. Knepley 
229745b41b2SMatthew G. Knepley    Level: intermediate
230745b41b2SMatthew G. Knepley 
231db781477SPatrick Sanan .seealso: `PetscSortReal()`, `PetscSortRemoveDupsInt()`
232745b41b2SMatthew G. Knepley @*/
2339371c9d4SSatish Balay PetscErrorCode PetscSortRemoveDupsReal(PetscInt *n, PetscReal v[]) {
234745b41b2SMatthew G. Knepley   PetscInt i, s = 0, N = *n, b = 0;
235745b41b2SMatthew G. Knepley 
236745b41b2SMatthew G. Knepley   PetscFunctionBegin;
2379566063dSJacob Faibussowitsch   PetscCall(PetscSortReal(N, v));
238745b41b2SMatthew G. Knepley   for (i = 0; i < N - 1; i++) {
239745b41b2SMatthew G. Knepley     if (v[b + s + 1] != v[b]) {
2409371c9d4SSatish Balay       v[b + 1] = v[b + s + 1];
2419371c9d4SSatish Balay       b++;
242745b41b2SMatthew G. Knepley     } else s++;
243745b41b2SMatthew G. Knepley   }
244745b41b2SMatthew G. Knepley   *n = N - s;
245745b41b2SMatthew G. Knepley   PetscFunctionReturn(0);
246745b41b2SMatthew G. Knepley }
247745b41b2SMatthew G. Knepley 
248d97c5584SHong Zhang /*@
249*811af0c4SBarry Smith    PetscSortSplit - Quick-sort split of an array of `PetscScalar`s in place.
250d97c5584SHong Zhang 
251d97c5584SHong Zhang    Not Collective
252d97c5584SHong Zhang 
253d97c5584SHong Zhang    Input Parameters:
254d97c5584SHong Zhang +  ncut  - splitig index
2556b867d5aSJose E. Roman -  n     - number of values to sort
256d97c5584SHong Zhang 
2576b867d5aSJose E. Roman    Input/Output Parameters:
2586b867d5aSJose E. Roman +  a     - array of values, on output the values are permuted such that its elements satisfy:
259d97c5584SHong Zhang            abs(a[i]) >= abs(a[ncut-1]) for i < ncut and
260d97c5584SHong Zhang            abs(a[i]) <= abs(a[ncut-1]) for i >= ncut
2616b867d5aSJose E. Roman -  idx   - index for array a, on output permuted accordingly
262d97c5584SHong Zhang 
263d97c5584SHong Zhang    Level: intermediate
264d97c5584SHong Zhang 
265db781477SPatrick Sanan .seealso: `PetscSortInt()`, `PetscSortRealWithPermutation()`
266d97c5584SHong Zhang @*/
2679371c9d4SSatish Balay PetscErrorCode PetscSortSplit(PetscInt ncut, PetscInt n, PetscScalar a[], PetscInt idx[]) {
268d97c5584SHong Zhang   PetscInt    i, mid, last, itmp, j, first;
269d97c5584SHong Zhang   PetscScalar d, tmp;
270d97c5584SHong Zhang   PetscReal   abskey;
271d97c5584SHong Zhang 
272d97c5584SHong Zhang   PetscFunctionBegin;
273d97c5584SHong Zhang   first = 0;
274d97c5584SHong Zhang   last  = n - 1;
275d97c5584SHong Zhang   if (ncut < first || ncut > last) PetscFunctionReturn(0);
276d97c5584SHong Zhang 
277d97c5584SHong Zhang   while (1) {
278d97c5584SHong Zhang     mid    = first;
2792a274a78SSatish Balay     d      = a[mid];
2802a274a78SSatish Balay     abskey = PetscAbsScalar(d);
281d97c5584SHong Zhang     i      = last;
282d97c5584SHong Zhang     for (j = first + 1; j <= i; ++j) {
2832a274a78SSatish Balay       d = a[j];
2842a274a78SSatish Balay       if (PetscAbsScalar(d) >= abskey) {
285d97c5584SHong Zhang         ++mid;
286d97c5584SHong Zhang         /* interchange */
2879371c9d4SSatish Balay         tmp      = a[mid];
2889371c9d4SSatish Balay         itmp     = idx[mid];
2899371c9d4SSatish Balay         a[mid]   = a[j];
2909371c9d4SSatish Balay         idx[mid] = idx[j];
2919371c9d4SSatish Balay         a[j]     = tmp;
2929371c9d4SSatish Balay         idx[j]   = itmp;
293d97c5584SHong Zhang       }
294d97c5584SHong Zhang     }
295d97c5584SHong Zhang 
296d97c5584SHong Zhang     /* interchange */
2979371c9d4SSatish Balay     tmp        = a[mid];
2989371c9d4SSatish Balay     itmp       = idx[mid];
2999371c9d4SSatish Balay     a[mid]     = a[first];
3009371c9d4SSatish Balay     idx[mid]   = idx[first];
3019371c9d4SSatish Balay     a[first]   = tmp;
3029371c9d4SSatish Balay     idx[first] = itmp;
303d97c5584SHong Zhang 
304d97c5584SHong Zhang     /* test for while loop */
305a297a907SKarl Rupp     if (mid == ncut) break;
306a297a907SKarl Rupp     else if (mid > ncut) last = mid - 1;
307a297a907SKarl Rupp     else first = mid + 1;
308d97c5584SHong Zhang   }
309d97c5584SHong Zhang   PetscFunctionReturn(0);
310d97c5584SHong Zhang }
311021822bcSHong Zhang 
312021822bcSHong Zhang /*@
313*811af0c4SBarry Smith    PetscSortSplitReal - Quick-sort split of an array of `PetscReal`s in place.
314021822bcSHong Zhang 
315021822bcSHong Zhang    Not Collective
316021822bcSHong Zhang 
317021822bcSHong Zhang    Input Parameters:
318021822bcSHong Zhang +  ncut  - splitig index
3196b867d5aSJose E. Roman -  n     - number of values to sort
320021822bcSHong Zhang 
3216b867d5aSJose E. Roman    Input/Output Parameters:
3226b867d5aSJose E. Roman +  a     - array of values, on output the values are permuted such that its elements satisfy:
323021822bcSHong Zhang            abs(a[i]) >= abs(a[ncut-1]) for i < ncut and
324021822bcSHong Zhang            abs(a[i]) <= abs(a[ncut-1]) for i >= ncut
3256b867d5aSJose E. Roman -  idx   - index for array a, on output permuted accordingly
326021822bcSHong Zhang 
327021822bcSHong Zhang    Level: intermediate
328021822bcSHong Zhang 
329db781477SPatrick Sanan .seealso: `PetscSortInt()`, `PetscSortRealWithPermutation()`
330021822bcSHong Zhang @*/
3319371c9d4SSatish Balay PetscErrorCode PetscSortSplitReal(PetscInt ncut, PetscInt n, PetscReal a[], PetscInt idx[]) {
332021822bcSHong Zhang   PetscInt  i, mid, last, itmp, j, first;
333021822bcSHong Zhang   PetscReal d, tmp;
334021822bcSHong Zhang   PetscReal abskey;
335021822bcSHong Zhang 
336021822bcSHong Zhang   PetscFunctionBegin;
337021822bcSHong Zhang   first = 0;
338021822bcSHong Zhang   last  = n - 1;
339021822bcSHong Zhang   if (ncut < first || ncut > last) PetscFunctionReturn(0);
340021822bcSHong Zhang 
341021822bcSHong Zhang   while (1) {
342021822bcSHong Zhang     mid    = first;
3432a274a78SSatish Balay     d      = a[mid];
3442a274a78SSatish Balay     abskey = PetscAbsReal(d);
345021822bcSHong Zhang     i      = last;
346021822bcSHong Zhang     for (j = first + 1; j <= i; ++j) {
3472a274a78SSatish Balay       d = a[j];
3482a274a78SSatish Balay       if (PetscAbsReal(d) >= abskey) {
349021822bcSHong Zhang         ++mid;
350021822bcSHong Zhang         /* interchange */
3519371c9d4SSatish Balay         tmp      = a[mid];
3529371c9d4SSatish Balay         itmp     = idx[mid];
3539371c9d4SSatish Balay         a[mid]   = a[j];
3549371c9d4SSatish Balay         idx[mid] = idx[j];
3559371c9d4SSatish Balay         a[j]     = tmp;
3569371c9d4SSatish Balay         idx[j]   = itmp;
357021822bcSHong Zhang       }
358021822bcSHong Zhang     }
359021822bcSHong Zhang 
360021822bcSHong Zhang     /* interchange */
3619371c9d4SSatish Balay     tmp        = a[mid];
3629371c9d4SSatish Balay     itmp       = idx[mid];
3639371c9d4SSatish Balay     a[mid]     = a[first];
3649371c9d4SSatish Balay     idx[mid]   = idx[first];
3659371c9d4SSatish Balay     a[first]   = tmp;
3669371c9d4SSatish Balay     idx[first] = itmp;
367021822bcSHong Zhang 
368021822bcSHong Zhang     /* test for while loop */
369a297a907SKarl Rupp     if (mid == ncut) break;
370a297a907SKarl Rupp     else if (mid > ncut) last = mid - 1;
371a297a907SKarl Rupp     else first = mid + 1;
372021822bcSHong Zhang   }
373021822bcSHong Zhang   PetscFunctionReturn(0);
374021822bcSHong Zhang }
375