Date: 2022-03-04T17:37:11+00:00

Actual source code: sorti.c

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

      9: #define MEDIAN3(v,a,b,c)                                                        \
     10:   (v[a]<v[b]                                                                    \
     11:    ? (v[b]<v[c]                                                                 \
     12:       ? (b)                                                                     \
     13:       : (v[a]<v[c] ? (c) : (a)))                                                \
     14:    : (v[c]<v[b]                                                                 \
     15:       ? (b)                                                                     \
     16:       : (v[a]<v[c] ? (a) : (c))))

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

     20: /* Swap one, two or three pairs. Each pair can have its own type */
     21: #define SWAP1(a,b,t1)               do {t1=a;a=b;b=t1;} while (0)
     22: #define SWAP2(a,b,c,d,t1,t2)        do {t1=a;a=b;b=t1; t2=c;c=d;d=t2;} while (0)
     23: #define SWAP3(a,b,c,d,e,f,t1,t2,t3) do {t1=a;a=b;b=t1; t2=c;c=d;d=t2; t3=e;e=f;f=t3;} while (0)

     25: /* Swap a & b, *c & *d. c, d, t2 are pointers to a type of size <siz> */
     26: #define SWAP2Data(a,b,c,d,t1,t2,siz)                                             \
     27:   do {                                                                           \
     29:     t1=a; a=b; b=t1;                                                             \
     30:     PetscMemcpy(t2,c,siz);                                  \
     31:     PetscMemcpy(c,d,siz);                                   \
     32:     PetscMemcpy(d,t2,siz);                                  \
     33:   } while (0)

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

     38:    Input Parameters:
     39:     + X         - array to partition
     40:     . pivot     - a pivot of X[]
     41:     . t1        - temp variable for X
     42:     - lo,hi     - lower and upper bound of the array

     44:    Output Parameters:
     45:     + l,r       - of type PetscInt

     47:    Notes:
     48:     The TwoWayPartition2/3 variants also partition other arrays along with X.
     49:     These arrays can have different types, so they provide their own temp t2,t3
     50:  */
     51: #define TwoWayPartition1(X,pivot,t1,lo,hi,l,r)                                   \
     52:   do {                                                                           \
     53:     l = lo;                                                                      \
     54:     r = hi;                                                                      \
     55:     while (1) {                                                                   \
     56:       while (X[l] < pivot) l++;                                                  \
     57:       while (X[r] > pivot) r--;                                                  \
     58:       if (l >= r) {r++; break;}                                                  \
     59:       SWAP1(X[l],X[r],t1);                                                       \
     60:       l++;                                                                       \
     61:       r--;                                                                       \
     62:     }                                                                            \
     63:   } while (0)

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

     68:    Input Parameters:
     69:     + X         - array to partition
     70:     . pivot     - a pivot of X[]
     71:     . t1        - temp variable for X
     72:     - lo,hi     - lower and upper bound of the array

     74:    Output Parameters:
     75:     + l,r       - of type PetscInt

     77:    Notes:
     78:     The TwoWayPartition2/3 variants also partition other arrays along with X.
     79:     These arrays can have different types, so they provide their own temp t2,t3
     80:  */
     81: #define TwoWayPartitionReverse1(X,pivot,t1,lo,hi,l,r)                                   \
     82:   do {                                                                           \
     83:     l = lo;                                                                      \
     84:     r = hi;                                                                      \
     85:     while (1) {                                                                   \
     86:       while (X[l] > pivot) l++;                                                  \
     87:       while (X[r] < pivot) r--;                                                  \
     88:       if (l >= r) {r++; break;}                                                  \
     89:       SWAP1(X[l],X[r],t1);                                                       \
     90:       l++;                                                                       \
     91:       r--;                                                                       \
     92:     }                                                                            \
     93:   } while (0)

     95: #define TwoWayPartition2(X,Y,pivot,t1,t2,lo,hi,l,r)                              \
     96:   do {                                                                           \
     97:     l = lo;                                                                      \
     98:     r = hi;                                                                      \
     99:     while (1) {                                                                   \
    100:       while (X[l] < pivot) l++;                                                  \
    101:       while (X[r] > pivot) r--;                                                  \
    102:       if (l >= r) {r++; break;}                                                  \
    103:       SWAP2(X[l],X[r],Y[l],Y[r],t1,t2);                                          \
    104:       l++;                                                                       \
    105:       r--;                                                                       \
    106:     }                                                                            \
    107:   } while (0)

    109: #define TwoWayPartition3(X,Y,Z,pivot,t1,t2,t3,lo,hi,l,r)                         \
    110:   do {                                                                           \
    111:     l = lo;                                                                      \
    112:     r = hi;                                                                      \
    113:     while (1) {                                                                   \
    114:       while (X[l] < pivot) l++;                                                  \
    115:       while (X[r] > pivot) r--;                                                  \
    116:       if (l >= r) {r++; break;}                                                  \
    117:       SWAP3(X[l],X[r],Y[l],Y[r],Z[l],Z[r],t1,t2,t3);                             \
    118:       l++;                                                                       \
    119:       r--;                                                                       \
    120:     }                                                                            \
    121:   } while (0)

    123: /* Templates for similar functions used below */
    124: #define QuickSort1(FuncName,X,n,pivot,t1,ierr)                                   \
    125:   do {                                                                           \
    126:     PetscInt i,j,p,l,r,hi=n-1;                                                   \
    127:     if (n < 8) {                                                                 \
    128:       for (i=0; i<n; i++) {                                                      \
    129:         pivot = X[i];                                                            \
    130:         for (j=i+1; j<n; j++) {                                                  \
    131:           if (pivot > X[j]) {                                                    \
    132:             SWAP1(X[i],X[j],t1);                                                 \
    133:             pivot = X[i];                                                        \
    134:           }                                                                      \
    135:         }                                                                        \
    136:       }                                                                          \
    137:     } else {                                                                     \
    138:       p     = MEDIAN(X,hi);                                                      \
    139:       pivot = X[p];                                                              \
    140:       TwoWayPartition1(X,pivot,t1,0,hi,l,r);                                     \
    141:       FuncName(l,X);                                       \
    142:       FuncName(hi-r+1,X+r);                                \
    143:     }                                                                            \
    144:   } while (0)

    146: /* Templates for similar functions used below */
    147: #define QuickSortReverse1(FuncName,X,n,pivot,t1,ierr)                            \
    148:   do {                                                                           \
    149:     PetscInt i,j,p,l,r,hi=n-1;                                                   \
    150:     if (n < 8) {                                                                 \
    151:       for (i=0; i<n; i++) {                                                      \
    152:         pivot = X[i];                                                            \
    153:         for (j=i+1; j<n; j++) {                                                  \
    154:           if (pivot < X[j]) {                                                    \
    155:             SWAP1(X[i],X[j],t1);                                                 \
    156:             pivot = X[i];                                                        \
    157:           }                                                                      \
    158:         }                                                                        \
    159:       }                                                                          \
    160:     } else {                                                                     \
    161:       p     = MEDIAN(X,hi);                                                      \
    162:       pivot = X[p];                                                              \
    163:       TwoWayPartitionReverse1(X,pivot,t1,0,hi,l,r);                              \
    164:       FuncName(l,X);                                       \
    165:       FuncName(hi-r+1,X+r);                                \
    166:     }                                                                            \
    167:   } while (0)

    169: #define QuickSort2(FuncName,X,Y,n,pivot,t1,t2,ierr)                              \
    170:   do {                                                                           \
    171:     PetscInt i,j,p,l,r,hi=n-1;                                                   \
    172:     if (n < 8) {                                                                 \
    173:       for (i=0; i<n; i++) {                                                      \
    174:         pivot = X[i];                                                            \
    175:         for (j=i+1; j<n; j++) {                                                  \
    176:           if (pivot > X[j]) {                                                    \
    177:             SWAP2(X[i],X[j],Y[i],Y[j],t1,t2);                                    \
    178:             pivot = X[i];                                                        \
    179:           }                                                                      \
    180:         }                                                                        \
    181:       }                                                                          \
    182:     } else {                                                                     \
    183:       p     = MEDIAN(X,hi);                                                      \
    184:       pivot = X[p];                                                              \
    185:       TwoWayPartition2(X,Y,pivot,t1,t2,0,hi,l,r);                                \
    186:       FuncName(l,X,Y);                                     \
    187:       FuncName(hi-r+1,X+r,Y+r);                            \
    188:     }                                                                            \
    189:   } while (0)

    191: #define QuickSort3(FuncName,X,Y,Z,n,pivot,t1,t2,t3,ierr)                         \
    192:   do {                                                                           \
    193:     PetscInt i,j,p,l,r,hi=n-1;                                                   \
    194:     if (n < 8) {                                                                 \
    195:       for (i=0; i<n; i++) {                                                      \
    196:         pivot = X[i];                                                            \
    197:         for (j=i+1; j<n; j++) {                                                  \
    198:           if (pivot > X[j]) {                                                    \
    199:             SWAP3(X[i],X[j],Y[i],Y[j],Z[i],Z[j],t1,t2,t3);                       \
    200:             pivot = X[i];                                                        \
    201:           }                                                                      \
    202:         }                                                                        \
    203:       }                                                                          \
    204:     } else {                                                                     \
    205:       p     = MEDIAN(X,hi);                                                      \
    206:       pivot = X[p];                                                              \
    207:       TwoWayPartition3(X,Y,Z,pivot,t1,t2,t3,0,hi,l,r);                           \
    208:       FuncName(l,X,Y,Z);                                   \
    209:       FuncName(hi-r+1,X+r,Y+r,Z+r);                        \
    210:     }                                                                            \
    211:   } while (0)

    213: /*@
    214:    PetscSortedInt - Determines whether the array is sorted.

    216:    Not Collective

    218:    Input Parameters:
    219: +  n  - number of values
    220: -  X  - array of integers

    222:    Output Parameters:
    223: .  sorted - flag whether the array is sorted

    225:    Level: intermediate

    227: .seealso: PetscSortInt(), PetscSortedMPIInt(), PetscSortedReal()
    228: @*/
    229: PetscErrorCode  PetscSortedInt(PetscInt n,const PetscInt X[],PetscBool *sorted)
    230: {
    232:   PetscSorted(n,X,*sorted);
    233:   return(0);
    234: }

    236: /*@
    237:    PetscSortInt - Sorts an array of integers in place in increasing order.

    239:    Not Collective

    241:    Input Parameters:
    242: +  n  - number of values
    243: -  X  - array of integers

    245:    Notes:
    246:    This function serves as an alternative to PetscIntSortSemiOrdered(), and may perform faster especially if the array
    247:    is completely random. There are exceptions to this and so it is __highly__ recommended that the user benchmark their
    248:    code to see which routine is fastest.

    250:    Level: intermediate

    252: .seealso: PetscIntSortSemiOrdered(), PetscSortReal(), PetscSortIntWithPermutation()
    253: @*/
    254: PetscErrorCode  PetscSortInt(PetscInt n,PetscInt X[])
    255: {
    257:   PetscInt       pivot,t1;

    260:   QuickSort1(PetscSortInt,X,n,pivot,t1,ierr);
    261:   return(0);
    262: }

    264: /*@
    265:    PetscSortReverseInt - Sorts an array of integers in place in decreasing order.

    267:    Not Collective

    269:    Input Parameters:
    270: +  n  - number of values
    271: -  X  - array of integers

    273:    Level: intermediate

    275: .seealso: PetscIntSortSemiOrdered(), PetscSortInt(), PetscSortIntWithPermutation()
    276: @*/
    277: PetscErrorCode  PetscSortReverseInt(PetscInt n,PetscInt X[])
    278: {
    280:   PetscInt       pivot,t1;

    283:   QuickSortReverse1(PetscSortReverseInt,X,n,pivot,t1,ierr);
    284:   return(0);
    285: }

    287: /*@
    288:    PetscSortedRemoveDupsInt - Removes all duplicate entries of a sorted input array

    290:    Not Collective

    292:    Input Parameters:
    293: +  n  - number of values
    294: -  X  - sorted array of integers

    296:    Output Parameter:
    297: .  n - number of non-redundant values

    299:    Level: intermediate

    301: .seealso: PetscSortInt()
    302: @*/
    303: PetscErrorCode  PetscSortedRemoveDupsInt(PetscInt *n,PetscInt X[])
    304: {
    305:   PetscInt i,s = 0,N = *n, b = 0;

    309:   for (i=0; i<N-1; i++) {
    310:     if (X[b+s+1] != X[b]) {
    311:       X[b+1] = X[b+s+1]; b++;
    312:     } else s++;
    313:   }
    314:   *n = N - s;
    315:   return(0);
    316: }

    318: /*@
    319:    PetscSortRemoveDupsInt - Sorts an array of integers in place in increasing order removes all duplicate entries

    321:    Not Collective

    323:    Input Parameters:
    324: +  n  - number of values
    325: -  X  - array of integers

    327:    Output Parameter:
    328: .  n - number of non-redundant values

    330:    Level: intermediate

    332: .seealso: PetscIntSortSemiOrdered(), PetscSortReal(), PetscSortIntWithPermutation(), PetscSortInt(), PetscSortedRemoveDupsInt()
    333: @*/
    334: PetscErrorCode  PetscSortRemoveDupsInt(PetscInt *n,PetscInt X[])
    335: {

    339:   PetscSortInt(*n,X);
    340:   PetscSortedRemoveDupsInt(n,X);
    341:   return(0);
    342: }

    344: /*@
    345:   PetscFindInt - Finds integer in a sorted array of integers

    347:    Not Collective

    349:    Input Parameters:
    350: +  key - the integer to locate
    351: .  n   - number of values in the array
    352: -  X  - array of integers

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

    357:    Level: intermediate

    359: .seealso: PetscIntSortSemiOrdered(), PetscSortInt(), PetscSortIntWithArray(), PetscSortRemoveDupsInt()
    360: @*/
    361: PetscErrorCode PetscFindInt(PetscInt key, PetscInt n, const PetscInt X[], PetscInt *loc)
    362: {
    363:   PetscInt lo = 0,hi = n;

    367:   if (!n) {*loc = -1; return(0);}
    370:   while (hi - lo > 1) {
    371:     PetscInt mid = lo + (hi - lo)/2;
    372:     if (key < X[mid]) hi = mid;
    373:     else               lo = mid;
    374:   }
    375:   *loc = key == X[lo] ? lo : -(lo + (key > X[lo]) + 1);
    376:   return(0);
    377: }

    379: /*@

    382:    Not Collective

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

    388:    Output Parameter:
    389: .  dups - True if the array has dups, otherwise false

    391:    Level: intermediate

    393: .seealso: PetscSortRemoveDupsInt()
    394: @*/
    396: {
    398:   PetscInt       i;
    399:   PetscHSetI     ht;
    400:   PetscBool      missing;

    404:   *dups = PETSC_FALSE;
    405:   if (n > 1) {
    406:     PetscHSetICreate(&ht);
    407:     PetscHSetIResize(ht,n);
    408:     for (i=0; i<n; i++) {
    409:       PetscHSetIQueryAdd(ht,X[i],&missing);
    410:       if (!missing) {*dups = PETSC_TRUE; break;}
    411:     }
    412:     PetscHSetIDestroy(&ht);
    413:   }
    414:   return(0);
    415: }

    417: /*@
    418:   PetscFindMPIInt - Finds MPI integer in a sorted array of integers

    420:    Not Collective

    422:    Input Parameters:
    423: +  key - the integer to locate
    424: .  n   - number of values in the array
    425: -  X   - array of integers

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

    430:    Level: intermediate

    432: .seealso: PetscMPIIntSortSemiOrdered(), PetscSortInt(), PetscSortIntWithArray(), PetscSortRemoveDupsInt()
    433: @*/
    434: PetscErrorCode PetscFindMPIInt(PetscMPIInt key, PetscInt n, const PetscMPIInt X[], PetscInt *loc)
    435: {
    436:   PetscInt lo = 0,hi = n;

    440:   if (!n) {*loc = -1; return(0);}
    443:   while (hi - lo > 1) {
    444:     PetscInt mid = lo + (hi - lo)/2;
    445:     if (key < X[mid]) hi = mid;
    446:     else               lo = mid;
    447:   }
    448:   *loc = key == X[lo] ? lo : -(lo + (key > X[lo]) + 1);
    449:   return(0);
    450: }

    452: /*@
    453:    PetscSortIntWithArray - Sorts an array of integers in place in increasing order;
    454:        changes a second array to match the sorted first array.

    456:    Not Collective

    458:    Input Parameters:
    459: +  n  - number of values
    460: .  X  - array of integers
    461: -  Y  - second array of integers

    463:    Level: intermediate

    465: .seealso: PetscIntSortSemiOrderedWithArray(), PetscSortReal(), PetscSortIntWithPermutation(), PetscSortInt()
    466: @*/
    467: PetscErrorCode  PetscSortIntWithArray(PetscInt n,PetscInt X[],PetscInt Y[])
    468: {
    470:   PetscInt       pivot,t1,t2;

    473:   QuickSort2(PetscSortIntWithArray,X,Y,n,pivot,t1,t2,ierr);
    474:   return(0);
    475: }

    477: /*@
    478:    PetscSortIntWithArrayPair - Sorts an array of integers in place in increasing order;
    479:        changes a pair of integer arrays to match the sorted first array.

    481:    Not Collective

    483:    Input Parameters:
    484: +  n  - number of values
    485: .  X  - array of integers
    486: .  Y  - second array of integers (first array of the pair)
    487: -  Z  - third array of integers  (second array of the pair)

    489:    Level: intermediate

    491: .seealso: PetscSortReal(), PetscSortIntWithPermutation(), PetscSortIntWithArray(), PetscIntSortSemiOrdered()
    492: @*/
    493: PetscErrorCode  PetscSortIntWithArrayPair(PetscInt n,PetscInt X[],PetscInt Y[],PetscInt Z[])
    494: {
    496:   PetscInt       pivot,t1,t2,t3;

    499:   QuickSort3(PetscSortIntWithArrayPair,X,Y,Z,n,pivot,t1,t2,t3,ierr);
    500:   return(0);
    501: }

    503: /*@
    504:    PetscSortedMPIInt - Determines whether the array is sorted.

    506:    Not Collective

    508:    Input Parameters:
    509: +  n  - number of values
    510: -  X  - array of integers

    512:    Output Parameters:
    513: .  sorted - flag whether the array is sorted

    515:    Level: intermediate

    517: .seealso: PetscMPIIntSortSemiOrdered(), PetscSortMPIInt(), PetscSortedInt(), PetscSortedReal()
    518: @*/
    519: PetscErrorCode  PetscSortedMPIInt(PetscInt n,const PetscMPIInt X[],PetscBool *sorted)
    520: {
    522:   PetscSorted(n,X,*sorted);
    523:   return(0);
    524: }

    526: /*@
    527:    PetscSortMPIInt - Sorts an array of MPI integers in place in increasing order.

    529:    Not Collective

    531:    Input Parameters:
    532: +  n  - number of values
    533: -  X  - array of integers

    535:    Level: intermediate

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

    542: .seealso: PetscMPIIntSortSemiOrdered(), PetscSortReal(), PetscSortIntWithPermutation()
    543: @*/
    544: PetscErrorCode  PetscSortMPIInt(PetscInt n,PetscMPIInt X[])
    545: {
    547:   PetscMPIInt    pivot,t1;

    550:   QuickSort1(PetscSortMPIInt,X,n,pivot,t1,ierr);
    551:   return(0);
    552: }

    554: /*@
    555:    PetscSortRemoveDupsMPIInt - Sorts an array of MPI integers in place in increasing order removes all duplicate entries

    557:    Not Collective

    559:    Input Parameters:
    560: +  n  - number of values
    561: -  X  - array of integers

    563:    Output Parameter:
    564: .  n - number of non-redundant values

    566:    Level: intermediate

    568: .seealso: PetscSortReal(), PetscSortIntWithPermutation(), PetscSortInt()
    569: @*/
    570: PetscErrorCode  PetscSortRemoveDupsMPIInt(PetscInt *n,PetscMPIInt X[])
    571: {
    573:   PetscInt       i,s = 0,N = *n, b = 0;

    576:   PetscSortMPIInt(N,X);
    577:   for (i=0; i<N-1; i++) {
    578:     if (X[b+s+1] != X[b]) {
    579:       X[b+1] = X[b+s+1]; b++;
    580:     } else s++;
    581:   }
    582:   *n = N - s;
    583:   return(0);
    584: }

    586: /*@
    587:    PetscSortMPIIntWithArray - Sorts an array of integers in place in increasing order;
    588:        changes a second array to match the sorted first array.

    590:    Not Collective

    592:    Input Parameters:
    593: +  n  - number of values
    594: .  X  - array of integers
    595: -  Y  - second array of integers

    597:    Level: intermediate

    599: .seealso: PetscMPIIntSortSemiOrderedWithArray(), PetscSortReal(), PetscSortIntWithPermutation(), PetscSortInt()
    600: @*/
    601: PetscErrorCode  PetscSortMPIIntWithArray(PetscMPIInt n,PetscMPIInt X[],PetscMPIInt Y[])
    602: {
    604:   PetscMPIInt    pivot,t1,t2;

    607:   QuickSort2(PetscSortMPIIntWithArray,X,Y,n,pivot,t1,t2,ierr);
    608:   return(0);
    609: }

    611: /*@
    612:    PetscSortMPIIntWithIntArray - Sorts an array of MPI integers in place in increasing order;
    613:        changes a second array of Petsc intergers to match the sorted first array.

    615:    Not Collective

    617:    Input Parameters:
    618: +  n  - number of values
    619: .  X  - array of MPI integers
    620: -  Y  - second array of Petsc integers

    622:    Level: intermediate

    624:    Notes: this routine is useful when one needs to sort MPI ranks with other integer arrays.

    626: .seealso: PetscSortMPIIntWithArray(), PetscIntSortSemiOrderedWithArray(), PetscTimSortWithArray()
    627: @*/
    628: PetscErrorCode PetscSortMPIIntWithIntArray(PetscMPIInt n,PetscMPIInt X[],PetscInt Y[])
    629: {
    631:   PetscMPIInt    pivot,t1;
    632:   PetscInt       t2;

    635:   QuickSort2(PetscSortMPIIntWithIntArray,X,Y,n,pivot,t1,t2,ierr);
    636:   return(0);
    637: }

    639: /*@
    640:    PetscSortIntWithScalarArray - Sorts an array of integers in place in increasing order;
    641:        changes a second SCALAR array to match the sorted first INTEGER array.

    643:    Not Collective

    645:    Input Parameters:
    646: +  n  - number of values
    647: .  X  - array of integers
    648: -  Y  - second array of scalars

    650:    Level: intermediate

    652: .seealso: PetscTimSortWithArray(), PetscSortReal(), PetscSortIntWithPermutation(), PetscSortInt(), PetscSortIntWithArray()
    653: @*/
    654: PetscErrorCode  PetscSortIntWithScalarArray(PetscInt n,PetscInt X[],PetscScalar Y[])
    655: {
    657:   PetscInt       pivot,t1;
    658:   PetscScalar    t2;

    661:   QuickSort2(PetscSortIntWithScalarArray,X,Y,n,pivot,t1,t2,ierr);
    662:   return(0);
    663: }

    665: /*@C
    666:    PetscSortIntWithDataArray - Sorts an array of integers in place in increasing order;
    667:        changes a second array to match the sorted first INTEGER array.  Unlike other sort routines, the user must
    668:        provide workspace (the size of an element in the data array) to use when sorting.

    670:    Not Collective

    672:    Input Parameters:
    673: +  n  - number of values
    674: .  X  - array of integers
    675: .  Y  - second array of data
    676: .  size - sizeof elements in the data array in bytes
    677: -  t2   - workspace of "size" bytes used when sorting

    679:    Level: intermediate

    681: .seealso: PetscTimSortWithArray(), PetscSortReal(), PetscSortIntWithPermutation(), PetscSortInt(), PetscSortIntWithArray()
    682: @*/
    683: PetscErrorCode  PetscSortIntWithDataArray(PetscInt n,PetscInt X[],void *Y,size_t size,void *t2)
    684: {
    686:   char           *YY = (char*)Y;
    687:   PetscInt       i,j,p,t1,pivot,hi=n-1,l,r;

    690:   if (n<8) {
    691:     for (i=0; i<n; i++) {
    692:       pivot = X[i];
    693:       for (j=i+1; j<n; j++) {
    694:         if (pivot > X[j]) {
    695:           SWAP2Data(X[i],X[j],YY+size*i,YY+size*j,t1,t2,size);
    696:           pivot = X[i];
    697:         }
    698:       }
    699:     }
    700:   } else {
    701:     /* Two way partition */
    702:     p     = MEDIAN(X,hi);
    703:     pivot = X[p];
    704:     l     = 0;
    705:     r     = hi;
    706:     while (1) {
    707:       while (X[l] < pivot) l++;
    708:       while (X[r] > pivot) r--;
    709:       if (l >= r) {r++; break;}
    710:       SWAP2Data(X[l],X[r],YY+size*l,YY+size*r,t1,t2,size);
    711:       l++;
    712:       r--;
    713:     }
    714:     PetscSortIntWithDataArray(l,X,Y,size,t2);
    715:     PetscSortIntWithDataArray(hi-r+1,X+r,YY+size*r,size,t2);
    716:   }
    717:   return(0);
    718: }

    720: /*@
    721:    PetscMergeIntArray -     Merges two SORTED integer arrays, removes duplicate elements.

    723:    Not Collective

    725:    Input Parameters:
    726: +  an  - number of values in the first array
    727: .  aI  - first sorted array of integers
    728: .  bn  - number of values in the second array
    729: -  bI  - second array of integers

    731:    Output Parameters:
    732: +  n   - number of values in the merged array
    733: -  L   - merged sorted array, this is allocated if an array is not provided

    735:    Level: intermediate

    737: .seealso: PetscSortReal(), PetscSortIntWithPermutation(), PetscSortInt(), PetscSortIntWithArray()
    738: @*/
    739: PetscErrorCode  PetscMergeIntArray(PetscInt an,const PetscInt aI[], PetscInt bn, const PetscInt bI[], PetscInt *n, PetscInt **L)
    740: {
    742:   PetscInt       *L_ = *L, ak, bk, k;

    745:   if (!L_) {
    746:     PetscMalloc1(an+bn, L);
    747:     L_   = *L;
    748:   }
    749:   k = ak = bk = 0;
    750:   while (ak < an && bk < bn) {
    751:     if (aI[ak] == bI[bk]) {
    752:       L_[k] = aI[ak];
    753:       ++ak;
    754:       ++bk;
    755:       ++k;
    756:     } else if (aI[ak] < bI[bk]) {
    757:       L_[k] = aI[ak];
    758:       ++ak;
    759:       ++k;
    760:     } else {
    761:       L_[k] = bI[bk];
    762:       ++bk;
    763:       ++k;
    764:     }
    765:   }
    766:   if (ak < an) {
    767:     PetscArraycpy(L_+k,aI+ak,an-ak);
    768:     k   += (an-ak);
    769:   }
    770:   if (bk < bn) {
    771:     PetscArraycpy(L_+k,bI+bk,bn-bk);
    772:     k   += (bn-bk);
    773:   }
    774:   *n = k;
    775:   return(0);
    776: }

    778: /*@
    779:    PetscMergeIntArrayPair -     Merges two SORTED integer arrays that share NO common values along with an additional array of integers.
    780:                                 The additional arrays are the same length as sorted arrays and are merged
    781:                                 in the order determined by the merging of the sorted pair.

    783:    Not Collective

    785:    Input Parameters:
    786: +  an  - number of values in the first array
    787: .  aI  - first sorted array of integers
    788: .  aJ  - first additional array of integers
    789: .  bn  - number of values in the second array
    790: .  bI  - second array of integers
    791: -  bJ  - second additional of integers

    793:    Output Parameters:
    794: +  n   - number of values in the merged array (== an + bn)
    795: .  L   - merged sorted array
    796: -  J   - merged additional array

    798:    Notes:
    799:     if L or J point to non-null arrays then this routine will assume they are of the approproate size and use them, otherwise this routine will allocate space for them
    800:    Level: intermediate

    802: .seealso: PetscIntSortSemiOrdered(), PetscSortReal(), PetscSortIntWithPermutation(), PetscSortInt(), PetscSortIntWithArray()
    803: @*/
    804: PetscErrorCode  PetscMergeIntArrayPair(PetscInt an,const PetscInt aI[], const PetscInt aJ[], PetscInt bn, const PetscInt bI[], const PetscInt bJ[], PetscInt *n, PetscInt **L, PetscInt **J)
    805: {
    807:   PetscInt       n_, *L_, *J_, ak, bk, k;

    812:   n_ = an + bn;
    813:   *n = n_;
    814:   if (!*L) {
    815:     PetscMalloc1(n_, L);
    816:   }
    817:   L_ = *L;
    818:   if (!*J) {
    819:     PetscMalloc1(n_, J);
    820:   }
    821:   J_   = *J;
    822:   k = ak = bk = 0;
    823:   while (ak < an && bk < bn) {
    824:     if (aI[ak] <= bI[bk]) {
    825:       L_[k] = aI[ak];
    826:       J_[k] = aJ[ak];
    827:       ++ak;
    828:       ++k;
    829:     } else {
    830:       L_[k] = bI[bk];
    831:       J_[k] = bJ[bk];
    832:       ++bk;
    833:       ++k;
    834:     }
    835:   }
    836:   if (ak < an) {
    837:     PetscArraycpy(L_+k,aI+ak,an-ak);
    838:     PetscArraycpy(J_+k,aJ+ak,an-ak);
    839:     k   += (an-ak);
    840:   }
    841:   if (bk < bn) {
    842:     PetscArraycpy(L_+k,bI+bk,bn-bk);
    843:     PetscArraycpy(J_+k,bJ+bk,bn-bk);
    844:   }
    845:   return(0);
    846: }

    848: /*@
    849:    PetscMergeMPIIntArray -     Merges two SORTED integer arrays.

    851:    Not Collective

    853:    Input Parameters:
    854: +  an  - number of values in the first array
    855: .  aI  - first sorted array of integers
    856: .  bn  - number of values in the second array
    857: -  bI  - second array of integers

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

    863:    Level: intermediate

    865: .seealso: PetscIntSortSemiOrdered(), PetscSortReal(), PetscSortIntWithPermutation(), PetscSortInt(), PetscSortIntWithArray()
    866: @*/
    867: PetscErrorCode PetscMergeMPIIntArray(PetscInt an,const PetscMPIInt aI[],PetscInt bn,const PetscMPIInt bI[],PetscInt *n,PetscMPIInt **L)
    868: {
    870:   PetscInt       ai,bi,k;

    873:   if (!*L) {PetscMalloc1((an+bn),L);}
    874:   for (ai=0,bi=0,k=0; ai<an || bi<bn;) {
    875:     PetscInt t = -1;
    876:     for (; ai<an && (!bn || aI[ai] <= bI[bi]); ai++) (*L)[k++] = t = aI[ai];
    877:     for (; bi<bn && bI[bi] == t; bi++);
    878:     for (; bi<bn && (!an || bI[bi] <= aI[ai]); bi++) (*L)[k++] = t = bI[bi];
    879:     for (; ai<an && aI[ai] == t; ai++);
    880:   }
    881:   *n = k;
    882:   return(0);
    883: }

    885: /*@C
    886:    PetscProcessTree - Prepares tree data to be displayed graphically

    888:    Not Collective

    890:    Input Parameters:
    891: +  n  - number of values
    892: .  mask - indicates those entries in the tree, location 0 is always masked
    893: -  parentid - indicates the parent of each entry

    895:    Output Parameters:
    896: +  Nlevels - the number of levels
    897: .  Level - for each node tells its level
    898: .  Levelcnts - the number of nodes on each level
    899: .  Idbylevel - a list of ids on each of the levels, first level followed by second etc
    900: -  Column - for each id tells its column index

    902:    Level: developer

    904:    Notes:
    905:     This code is not currently used

    907: .seealso: PetscSortReal(), PetscSortIntWithPermutation()
    908: @*/
    909: PetscErrorCode  PetscProcessTree(PetscInt n,const PetscBool mask[],const PetscInt parentid[],PetscInt *Nlevels,PetscInt **Level,PetscInt **Levelcnt,PetscInt **Idbylevel,PetscInt **Column)
    910: {
    911:   PetscInt       i,j,cnt,nmask = 0,nlevels = 0,*level,*levelcnt,levelmax = 0,*workid,*workparentid,tcnt = 0,*idbylevel,*column;
    913:   PetscBool      done = PETSC_FALSE;

    916:   if (!mask[0]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Mask of 0th location must be set");
    917:   for (i=0; i<n; i++) {
    918:     if (mask[i]) continue;
    919:     if (parentid[i]  == i) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Node labeled as own parent");
    920:     if (parentid[i] && mask[parentid[i]]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Parent is masked");
    921:   }

    923:   for (i=0; i<n; i++) {
    924:     if (!mask[i]) nmask++;
    925:   }

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

    930:   level[0] = 1;
    931:   while (!done) {
    932:     done = PETSC_TRUE;
    933:     for (i=0; i<n; i++) {
    934:       if (mask[i]) continue;
    935:       if (!level[i] && level[parentid[i]]) level[i] = level[parentid[i]] + 1;
    936:       else if (!level[i]) done = PETSC_FALSE;
    937:     }
    938:   }
    939:   for (i=0; i<n; i++) {
    940:     level[i]--;
    941:     nlevels = PetscMax(nlevels,level[i]);
    942:   }

    944:   /* count the number of nodes on each level and its max */
    945:   PetscCalloc1(nlevels,&levelcnt);
    946:   for (i=0; i<n; i++) {
    947:     if (mask[i]) continue;
    948:     levelcnt[level[i]-1]++;
    949:   }
    950:   for (i=0; i<nlevels;i++) levelmax = PetscMax(levelmax,levelcnt[i]);

    952:   /* for each level sort the ids by the parent id */
    953:   PetscMalloc2(levelmax,&workid,levelmax,&workparentid);
    954:   PetscMalloc1(nmask,&idbylevel);
    955:   for (j=1; j<=nlevels;j++) {
    956:     cnt = 0;
    957:     for (i=0; i<n; i++) {
    958:       if (mask[i]) continue;
    959:       if (level[i] != j) continue;
    960:       workid[cnt]         = i;
    961:       workparentid[cnt++] = parentid[i];
    962:     }
    963:     /*  PetscIntView(cnt,workparentid,0);
    964:     PetscIntView(cnt,workid,0);
    965:     PetscSortIntWithArray(cnt,workparentid,workid);
    966:     PetscIntView(cnt,workparentid,0);
    967:     PetscIntView(cnt,workid,0);*/
    968:     PetscArraycpy(idbylevel+tcnt,workid,cnt);
    969:     tcnt += cnt;
    970:   }
    971:   if (tcnt != nmask) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Inconsistent count of unmasked nodes");
    972:   PetscFree2(workid,workparentid);

    974:   /* for each node list its column */
    975:   PetscMalloc1(n,&column);
    976:   cnt = 0;
    977:   for (j=0; j<nlevels; j++) {
    978:     for (i=0; i<levelcnt[j]; i++) {
    979:       column[idbylevel[cnt++]] = i;
    980:     }
    981:   }

    983:   *Nlevels   = nlevels;
    984:   *Level     = level;
    985:   *Levelcnt  = levelcnt;
    986:   *Idbylevel = idbylevel;
    987:   *Column    = column;
    988:   return(0);
    989: }

    991: /*@
    992:   PetscParallelSortedInt - Check whether an integer array, distributed over a communicator, is globally sorted.

    994:   Collective

    996:   Input Parameters:
    997: + comm - the MPI communicator
    998: . n - the local number of integers
    999: - keys - the local array of integers

    1001:   Output Parameters:
    1002: . is_sorted - whether the array is globally sorted

    1004:   Level: developer

    1006: .seealso: PetscParallelSortInt()
    1007: @*/
    1008: PetscErrorCode PetscParallelSortedInt(MPI_Comm comm, PetscInt n, const PetscInt keys[], PetscBool *is_sorted)
    1009: {
    1010:   PetscBool      sorted;
    1011:   PetscInt       i, min, max, prevmax;
    1012:   PetscMPIInt    rank;

    1016:   sorted = PETSC_TRUE;
    1017:   min    = PETSC_MAX_INT;
    1018:   max    = PETSC_MIN_INT;
    1019:   if (n) {
    1020:     min = keys[0];
    1021:     max = keys[0];
    1022:   }
    1023:   for (i = 1; i < n; i++) {
    1024:     if (keys[i] < keys[i - 1]) break;
    1025:     min = PetscMin(min,keys[i]);
    1026:     max = PetscMax(max,keys[i]);
    1027:   }
    1028:   if (i < n) sorted = PETSC_FALSE;
    1029:   prevmax = PETSC_MIN_INT;
    1030:   MPI_Exscan(&max, &prevmax, 1, MPIU_INT, MPI_MAX, comm);
    1031:   MPI_Comm_rank(comm, &rank);
    1032:   if (rank == 0) prevmax = PETSC_MIN_INT;
    1033:   if (prevmax > min) sorted = PETSC_FALSE;
    1034:   MPI_Allreduce(&sorted, is_sorted, 1, MPIU_BOOL, MPI_LAND, comm);
    1035:   return(0);
    1036: }