xref: /petsc/src/sys/utils/sorti.c (revision 4e97f8ebb84dd841ee7d0d48926a4de5d5170225)
1 
2 /*
3    This file contains routines for sorting integers. Values are sorted in place.
4  */
5 #include <petsc/private/petscimpl.h>                /*I  "petscsys.h"  I*/
6 
7 #define SWAP(a,b,t) {t=a;a=b;b=t;}
8 
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)))
17 
18 #define MEDIAN(v,right) MEDIAN3(v,right/4,right/2,right/4*3)
19 
20 /* -----------------------------------------------------------------------*/
21 
22 /*
23    A simple version of quicksort; taken from Kernighan and Ritchie, page 87.
24    Assumes 0 origin for v, number of elements = right+1 (right is index of
25    right-most member).
26 */
27 static void PetscSortInt_Private(PetscInt *v,PetscInt right)
28 {
29   PetscInt i,j,pivot,tmp;
30 
31   if (right <= 1) {
32     if (right == 1) {
33       if (v[0] > v[1]) SWAP(v[0],v[1],tmp);
34     }
35     return;
36   }
37   i = MEDIAN(v,right);          /* Choose a pivot */
38   SWAP(v[0],v[i],tmp);          /* Move it out of the way */
39   pivot = v[0];
40   for (i=0,j=right+1;; ) {
41     while (++i < j && v[i] <= pivot) ; /* Scan from the left */
42     while (v[--j] > pivot) ;           /* Scan from the right */
43     if (i >= j) break;
44     SWAP(v[i],v[j],tmp);
45   }
46   SWAP(v[0],v[j],tmp);          /* Put pivot back in place. */
47   PetscSortInt_Private(v,j-1);
48   PetscSortInt_Private(v+j+1,right-(j+1));
49 }
50 
51 /*@
52    PetscSortInt - Sorts an array of integers in place in increasing order.
53 
54    Not Collective
55 
56    Input Parameters:
57 +  n  - number of values
58 -  i  - array of integers
59 
60    Level: intermediate
61 
62    Concepts: sorting^ints
63 
64 .seealso: PetscSortReal(), PetscSortIntWithPermutation()
65 @*/
66 PetscErrorCode  PetscSortInt(PetscInt n,PetscInt i[])
67 {
68   PetscInt j,k,tmp,ik;
69 
70   PetscFunctionBegin;
71   if (n<8) {
72     for (k=0; k<n; k++) {
73       ik = i[k];
74       for (j=k+1; j<n; j++) {
75         if (ik > i[j]) {
76           SWAP(i[k],i[j],tmp);
77           ik = i[k];
78         }
79       }
80     }
81   } else PetscSortInt_Private(i,n-1);
82   PetscFunctionReturn(0);
83 }
84 
85 /*@
86    PetscSortedRemoveDupsInt - Removes all duplicate entries of a sorted input array
87 
88    Not Collective
89 
90    Input Parameters:
91 +  n  - number of values
92 -  ii  - sorted array of integers
93 
94    Output Parameter:
95 .  n - number of non-redundant values
96 
97    Level: intermediate
98 
99    Concepts: sorting^ints
100 
101 .seealso: PetscSortInt()
102 @*/
103 PetscErrorCode  PetscSortedRemoveDupsInt(PetscInt *n,PetscInt ii[])
104 {
105   PetscInt i,s = 0,N = *n, b = 0;
106 
107   PetscFunctionBegin;
108   for (i=0; i<N-1; i++) {
109     if (PetscUnlikely(ii[b+s+1] < ii[b])) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Input array is not sorted");
110     if (ii[b+s+1] != ii[b]) {
111       ii[b+1] = ii[b+s+1]; b++;
112     } else s++;
113   }
114   *n = N - s;
115   PetscFunctionReturn(0);
116 }
117 
118 /*@
119    PetscSortRemoveDupsInt - Sorts an array of integers in place in increasing order removes all duplicate entries
120 
121    Not Collective
122 
123    Input Parameters:
124 +  n  - number of values
125 -  ii  - array of integers
126 
127    Output Parameter:
128 .  n - number of non-redundant values
129 
130    Level: intermediate
131 
132    Concepts: sorting^ints
133 
134 .seealso: PetscSortReal(), PetscSortIntWithPermutation(), PetscSortInt(), PetscSortedRemoveDupsInt()
135 @*/
136 PetscErrorCode  PetscSortRemoveDupsInt(PetscInt *n,PetscInt ii[])
137 {
138   PetscErrorCode ierr;
139 
140   PetscFunctionBegin;
141   ierr = PetscSortInt(*n,ii);CHKERRQ(ierr);
142   ierr = PetscSortedRemoveDupsInt(n,ii);CHKERRQ(ierr);
143   PetscFunctionReturn(0);
144 }
145 
146 /*@
147   PetscFindInt - Finds integer in a sorted array of integers
148 
149    Not Collective
150 
151    Input Parameters:
152 +  key - the integer to locate
153 .  n   - number of values in the array
154 -  ii  - array of integers
155 
156    Output Parameter:
157 .  loc - the location if found, otherwise -(slot+1) where slot is the place the value would go
158 
159    Level: intermediate
160 
161    Concepts: sorting^ints
162 
163 .seealso: PetscSortInt(), PetscSortIntWithArray(), PetscSortRemoveDupsInt()
164 @*/
165 PetscErrorCode PetscFindInt(PetscInt key, PetscInt n, const PetscInt ii[], PetscInt *loc)
166 {
167   PetscInt lo = 0,hi = n;
168 
169   PetscFunctionBegin;
170   PetscValidPointer(loc,4);
171   if (!n) {*loc = -1; PetscFunctionReturn(0);}
172   PetscValidPointer(ii,3);
173   while (hi - lo > 1) {
174     PetscInt mid = lo + (hi - lo)/2;
175     if (key < ii[mid]) hi = mid;
176     else               lo = mid;
177   }
178   *loc = key == ii[lo] ? lo : -(lo + (key > ii[lo]) + 1);
179   PetscFunctionReturn(0);
180 }
181 
182 /*@
183   PetscFindMPIInt - Finds MPI integer in a sorted array of integers
184 
185    Not Collective
186 
187    Input Parameters:
188 +  key - the integer to locate
189 .  n   - number of values in the array
190 -  ii  - array of integers
191 
192    Output Parameter:
193 .  loc - the location if found, otherwise -(slot+1) where slot is the place the value would go
194 
195    Level: intermediate
196 
197    Concepts: sorting^ints
198 
199 .seealso: PetscSortInt(), PetscSortIntWithArray(), PetscSortRemoveDupsInt()
200 @*/
201 PetscErrorCode PetscFindMPIInt(PetscMPIInt key, PetscInt n, const PetscMPIInt ii[], PetscInt *loc)
202 {
203   PetscInt lo = 0,hi = n;
204 
205   PetscFunctionBegin;
206   PetscValidPointer(loc,4);
207   if (!n) {*loc = -1; PetscFunctionReturn(0);}
208   PetscValidPointer(ii,3);
209   while (hi - lo > 1) {
210     PetscInt mid = lo + (hi - lo)/2;
211     if (key < ii[mid]) hi = mid;
212     else               lo = mid;
213   }
214   *loc = key == ii[lo] ? lo : -(lo + (key > ii[lo]) + 1);
215   PetscFunctionReturn(0);
216 }
217 
218 /* -----------------------------------------------------------------------*/
219 #define SWAP2(a,b,c,d,t) {t=a;a=b;b=t;t=c;c=d;d=t;}
220 
221 /*
222    A simple version of quicksort; taken from Kernighan and Ritchie, page 87.
223    Assumes 0 origin for v, number of elements = right+1 (right is index of
224    right-most member).
225 */
226 static PetscErrorCode PetscSortIntWithArray_Private(PetscInt *v,PetscInt *V,PetscInt right)
227 {
228   PetscErrorCode ierr;
229   PetscInt       i,vl,last,tmp;
230 
231   PetscFunctionBegin;
232   if (right <= 1) {
233     if (right == 1) {
234       if (v[0] > v[1]) SWAP2(v[0],v[1],V[0],V[1],tmp);
235     }
236     PetscFunctionReturn(0);
237   }
238   SWAP2(v[0],v[right/2],V[0],V[right/2],tmp);
239   vl   = v[0];
240   last = 0;
241   for (i=1; i<=right; i++) {
242     if (v[i] < vl) {last++; SWAP2(v[last],v[i],V[last],V[i],tmp);}
243   }
244   SWAP2(v[0],v[last],V[0],V[last],tmp);
245   ierr = PetscSortIntWithArray_Private(v,V,last-1);CHKERRQ(ierr);
246   ierr = PetscSortIntWithArray_Private(v+last+1,V+last+1,right-(last+1));CHKERRQ(ierr);
247   PetscFunctionReturn(0);
248 }
249 
250 /*@
251    PetscSortIntWithArray - Sorts an array of integers in place in increasing order;
252        changes a second array to match the sorted first array.
253 
254    Not Collective
255 
256    Input Parameters:
257 +  n  - number of values
258 .  i  - array of integers
259 -  I - second array of integers
260 
261    Level: intermediate
262 
263    Concepts: sorting^ints with array
264 
265 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt()
266 @*/
267 PetscErrorCode  PetscSortIntWithArray(PetscInt n,PetscInt i[],PetscInt Ii[])
268 {
269   PetscErrorCode ierr;
270   PetscInt       j,k,tmp,ik;
271 
272   PetscFunctionBegin;
273   if (n<8) {
274     for (k=0; k<n; k++) {
275       ik = i[k];
276       for (j=k+1; j<n; j++) {
277         if (ik > i[j]) {
278           SWAP2(i[k],i[j],Ii[k],Ii[j],tmp);
279           ik = i[k];
280         }
281       }
282     }
283   } else {
284     ierr = PetscSortIntWithArray_Private(i,Ii,n-1);CHKERRQ(ierr);
285   }
286   PetscFunctionReturn(0);
287 }
288 
289 
290 #define SWAP3(a,b,c,d,e,f,t) {t=a;a=b;b=t;t=c;c=d;d=t;t=e;e=f;f=t;}
291 
292 /*
293    A simple version of quicksort; taken from Kernighan and Ritchie, page 87.
294    Assumes 0 origin for v, number of elements = right+1 (right is index of
295    right-most member).
296 */
297 static PetscErrorCode PetscSortIntWithArrayPair_Private(PetscInt *L,PetscInt *J, PetscInt *K, PetscInt right)
298 {
299   PetscErrorCode ierr;
300   PetscInt       i,vl,last,tmp;
301 
302   PetscFunctionBegin;
303   if (right <= 1) {
304     if (right == 1) {
305       if (L[0] > L[1]) SWAP3(L[0],L[1],J[0],J[1],K[0],K[1],tmp);
306     }
307     PetscFunctionReturn(0);
308   }
309   SWAP3(L[0],L[right/2],J[0],J[right/2],K[0],K[right/2],tmp);
310   vl   = L[0];
311   last = 0;
312   for (i=1; i<=right; i++) {
313     if (L[i] < vl) {last++; SWAP3(L[last],L[i],J[last],J[i],K[last],K[i],tmp);}
314   }
315   SWAP3(L[0],L[last],J[0],J[last],K[0],K[last],tmp);
316   ierr = PetscSortIntWithArrayPair_Private(L,J,K,last-1);CHKERRQ(ierr);
317   ierr = PetscSortIntWithArrayPair_Private(L+last+1,J+last+1,K+last+1,right-(last+1));CHKERRQ(ierr);
318   PetscFunctionReturn(0);
319 }
320 
321 /*@
322    PetscSortIntWithArrayPair - Sorts an array of integers in place in increasing order;
323        changes a pair of integer arrays to match the sorted first array.
324 
325    Not Collective
326 
327    Input Parameters:
328 +  n  - number of values
329 .  I  - array of integers
330 .  J  - second array of integers (first array of the pair)
331 -  K  - third array of integers  (second array of the pair)
332 
333    Level: intermediate
334 
335    Concepts: sorting^ints with array pair
336 
337 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortIntWithArray()
338 @*/
339 PetscErrorCode  PetscSortIntWithArrayPair(PetscInt n,PetscInt L[],PetscInt J[], PetscInt K[])
340 {
341   PetscErrorCode ierr;
342   PetscInt       j,k,tmp,ik;
343 
344   PetscFunctionBegin;
345   if (n<8) {
346     for (k=0; k<n; k++) {
347       ik = L[k];
348       for (j=k+1; j<n; j++) {
349         if (ik > L[j]) {
350           SWAP3(L[k],L[j],J[k],J[j],K[k],K[j],tmp);
351           ik = L[k];
352         }
353       }
354     }
355   } else {
356     ierr = PetscSortIntWithArrayPair_Private(L,J,K,n-1);CHKERRQ(ierr);
357   }
358   PetscFunctionReturn(0);
359 }
360 
361 /*
362    A simple version of quicksort; taken from Kernighan and Ritchie, page 87.
363    Assumes 0 origin for v, number of elements = right+1 (right is index of
364    right-most member).
365 */
366 static void PetscSortMPIInt_Private(PetscMPIInt *v,PetscInt right)
367 {
368   PetscInt          i,j;
369   PetscMPIInt       pivot,tmp;
370 
371   if (right <= 1) {
372     if (right == 1) {
373       if (v[0] > v[1]) SWAP(v[0],v[1],tmp);
374     }
375     return;
376   }
377   i = MEDIAN(v,right);          /* Choose a pivot */
378   SWAP(v[0],v[i],tmp);          /* Move it out of the way */
379   pivot = v[0];
380   for (i=0,j=right+1;; ) {
381     while (++i < j && v[i] <= pivot) ; /* Scan from the left */
382     while (v[--j] > pivot) ;           /* Scan from the right */
383     if (i >= j) break;
384     SWAP(v[i],v[j],tmp);
385   }
386   SWAP(v[0],v[j],tmp);          /* Put pivot back in place. */
387   PetscSortMPIInt_Private(v,j-1);
388   PetscSortMPIInt_Private(v+j+1,right-(j+1));
389 }
390 
391 /*@
392    PetscSortMPIInt - Sorts an array of MPI integers in place in increasing order.
393 
394    Not Collective
395 
396    Input Parameters:
397 +  n  - number of values
398 -  i  - array of integers
399 
400    Level: intermediate
401 
402    Concepts: sorting^ints
403 
404 .seealso: PetscSortReal(), PetscSortIntWithPermutation()
405 @*/
406 PetscErrorCode  PetscSortMPIInt(PetscInt n,PetscMPIInt i[])
407 {
408   PetscInt    j,k;
409   PetscMPIInt tmp,ik;
410 
411   PetscFunctionBegin;
412   if (n<8) {
413     for (k=0; k<n; k++) {
414       ik = i[k];
415       for (j=k+1; j<n; j++) {
416         if (ik > i[j]) {
417           SWAP(i[k],i[j],tmp);
418           ik = i[k];
419         }
420       }
421     }
422   } else PetscSortMPIInt_Private(i,n-1);
423   PetscFunctionReturn(0);
424 }
425 
426 /*@
427    PetscSortRemoveDupsMPIInt - Sorts an array of MPI integers in place in increasing order removes all duplicate entries
428 
429    Not Collective
430 
431    Input Parameters:
432 +  n  - number of values
433 -  ii  - array of integers
434 
435    Output Parameter:
436 .  n - number of non-redundant values
437 
438    Level: intermediate
439 
440    Concepts: sorting^ints
441 
442 .seealso: PetscSortReal(), PetscSortIntWithPermutation(), PetscSortInt()
443 @*/
444 PetscErrorCode  PetscSortRemoveDupsMPIInt(PetscInt *n,PetscMPIInt ii[])
445 {
446   PetscErrorCode ierr;
447   PetscInt       i,s = 0,N = *n, b = 0;
448 
449   PetscFunctionBegin;
450   ierr = PetscSortMPIInt(N,ii);CHKERRQ(ierr);
451   for (i=0; i<N-1; i++) {
452     if (ii[b+s+1] != ii[b]) {
453       ii[b+1] = ii[b+s+1]; b++;
454     } else s++;
455   }
456   *n = N - s;
457   PetscFunctionReturn(0);
458 }
459 
460 /*
461    A simple version of quicksort; taken from Kernighan and Ritchie, page 87.
462    Assumes 0 origin for v, number of elements = right+1 (right is index of
463    right-most member).
464 */
465 static PetscErrorCode PetscSortMPIIntWithArray_Private(PetscMPIInt *v,PetscMPIInt *V,PetscMPIInt right)
466 {
467   PetscErrorCode ierr;
468   PetscMPIInt    i,vl,last,tmp;
469 
470   PetscFunctionBegin;
471   if (right <= 1) {
472     if (right == 1) {
473       if (v[0] > v[1]) SWAP2(v[0],v[1],V[0],V[1],tmp);
474     }
475     PetscFunctionReturn(0);
476   }
477   SWAP2(v[0],v[right/2],V[0],V[right/2],tmp);
478   vl   = v[0];
479   last = 0;
480   for (i=1; i<=right; i++) {
481     if (v[i] < vl) {last++; SWAP2(v[last],v[i],V[last],V[i],tmp);}
482   }
483   SWAP2(v[0],v[last],V[0],V[last],tmp);
484   ierr = PetscSortMPIIntWithArray_Private(v,V,last-1);CHKERRQ(ierr);
485   ierr = PetscSortMPIIntWithArray_Private(v+last+1,V+last+1,right-(last+1));CHKERRQ(ierr);
486   PetscFunctionReturn(0);
487 }
488 
489 /*@
490    PetscSortMPIIntWithArray - Sorts an array of integers in place in increasing order;
491        changes a second array to match the sorted first array.
492 
493    Not Collective
494 
495    Input Parameters:
496 +  n  - number of values
497 .  i  - array of integers
498 -  I - second array of integers
499 
500    Level: intermediate
501 
502    Concepts: sorting^ints with array
503 
504 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt()
505 @*/
506 PetscErrorCode  PetscSortMPIIntWithArray(PetscMPIInt n,PetscMPIInt i[],PetscMPIInt Ii[])
507 {
508   PetscErrorCode ierr;
509   PetscMPIInt    j,k,tmp,ik;
510 
511   PetscFunctionBegin;
512   if (n<8) {
513     for (k=0; k<n; k++) {
514       ik = i[k];
515       for (j=k+1; j<n; j++) {
516         if (ik > i[j]) {
517           SWAP2(i[k],i[j],Ii[k],Ii[j],tmp);
518           ik = i[k];
519         }
520       }
521     }
522   } else {
523     ierr = PetscSortMPIIntWithArray_Private(i,Ii,n-1);CHKERRQ(ierr);
524   }
525   PetscFunctionReturn(0);
526 }
527 
528 /* -----------------------------------------------------------------------*/
529 #define SWAP2MPIIntInt(a,b,c,d,t1,t2) {t1=a;a=b;b=t1;t2=c;c=d;d=t2;}
530 
531 /*
532    A simple version of quicksort; taken from Kernighan and Ritchie, page 87.
533    Assumes 0 origin for v, number of elements = right+1 (right is index of
534    right-most member).
535 */
536 static PetscErrorCode PetscSortMPIIntWithIntArray_Private(PetscMPIInt *v,PetscInt *V,PetscMPIInt right)
537 {
538   PetscErrorCode ierr;
539   PetscMPIInt    i,vl,last,t1;
540   PetscInt       t2;
541 
542   PetscFunctionBegin;
543   if (right <= 1) {
544     if (right == 1) {
545       if (v[0] > v[1]) SWAP2MPIIntInt(v[0],v[1],V[0],V[1],t1,t2);
546     }
547     PetscFunctionReturn(0);
548   }
549   SWAP2MPIIntInt(v[0],v[right/2],V[0],V[right/2],t1,t2);
550   vl   = v[0];
551   last = 0;
552   for (i=1; i<=right; i++) {
553     if (v[i] < vl) {last++; SWAP2MPIIntInt(v[last],v[i],V[last],V[i],t1,t2);}
554   }
555   SWAP2MPIIntInt(v[0],v[last],V[0],V[last],t1,t2);
556   ierr = PetscSortMPIIntWithIntArray_Private(v,V,last-1);CHKERRQ(ierr);
557   ierr = PetscSortMPIIntWithIntArray_Private(v+last+1,V+last+1,right-(last+1));CHKERRQ(ierr);
558   PetscFunctionReturn(0);
559 }
560 
561 /*@
562    PetscSortMPIIntWithIntArray - Sorts an array of MPI integers in place in increasing order;
563        changes a second array of Petsc intergers to match the sorted first array.
564 
565    Not Collective
566 
567    Input Parameters:
568 +  n  - number of values
569 .  i  - array of MPI integers
570 -  I - second array of Petsc integers
571 
572    Level: intermediate
573 
574    Notes: this routine is useful when one needs to sort MPI ranks with other integer arrays.
575 
576    Concepts: sorting^ints with array
577 
578 .seealso: PetscSortMPIIntWithArray()
579 @*/
580 PetscErrorCode PetscSortMPIIntWithIntArray(PetscMPIInt n,PetscMPIInt i[],PetscInt Ii[])
581 {
582   PetscErrorCode ierr;
583   PetscMPIInt    j,k,t1,ik;
584   PetscInt       t2;
585 
586   PetscFunctionBegin;
587   if (n<8) {
588     for (k=0; k<n; k++) {
589       ik = i[k];
590       for (j=k+1; j<n; j++) {
591         if (ik > i[j]) {
592           SWAP2MPIIntInt(i[k],i[j],Ii[k],Ii[j],t1,t2);
593           ik = i[k];
594         }
595       }
596     }
597   } else {
598     ierr = PetscSortMPIIntWithIntArray_Private(i,Ii,n-1);CHKERRQ(ierr);
599   }
600   PetscFunctionReturn(0);
601 }
602 
603 /* -----------------------------------------------------------------------*/
604 #define SWAP2IntScalar(a,b,c,d,t,ts) {t=a;a=b;b=t;ts=c;c=d;d=ts;}
605 
606 /*
607    Modified from PetscSortIntWithArray_Private().
608 */
609 static PetscErrorCode PetscSortIntWithScalarArray_Private(PetscInt *v,PetscScalar *V,PetscInt right)
610 {
611   PetscErrorCode ierr;
612   PetscInt       i,vl,last,tmp;
613   PetscScalar    stmp;
614 
615   PetscFunctionBegin;
616   if (right <= 1) {
617     if (right == 1) {
618       if (v[0] > v[1]) SWAP2IntScalar(v[0],v[1],V[0],V[1],tmp,stmp);
619     }
620     PetscFunctionReturn(0);
621   }
622   SWAP2IntScalar(v[0],v[right/2],V[0],V[right/2],tmp,stmp);
623   vl   = v[0];
624   last = 0;
625   for (i=1; i<=right; i++) {
626     if (v[i] < vl) {last++; SWAP2IntScalar(v[last],v[i],V[last],V[i],tmp,stmp);}
627   }
628   SWAP2IntScalar(v[0],v[last],V[0],V[last],tmp,stmp);
629   ierr = PetscSortIntWithScalarArray_Private(v,V,last-1);CHKERRQ(ierr);
630   ierr = PetscSortIntWithScalarArray_Private(v+last+1,V+last+1,right-(last+1));CHKERRQ(ierr);
631   PetscFunctionReturn(0);
632 }
633 
634 /*@
635    PetscSortIntWithScalarArray - Sorts an array of integers in place in increasing order;
636        changes a second SCALAR array to match the sorted first INTEGER array.
637 
638    Not Collective
639 
640    Input Parameters:
641 +  n  - number of values
642 .  i  - array of integers
643 -  I - second array of scalars
644 
645    Level: intermediate
646 
647    Concepts: sorting^ints with array
648 
649 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
650 @*/
651 PetscErrorCode  PetscSortIntWithScalarArray(PetscInt n,PetscInt i[],PetscScalar Ii[])
652 {
653   PetscErrorCode ierr;
654   PetscInt       j,k,tmp,ik;
655   PetscScalar    stmp;
656 
657   PetscFunctionBegin;
658   if (n<8) {
659     for (k=0; k<n; k++) {
660       ik = i[k];
661       for (j=k+1; j<n; j++) {
662         if (ik > i[j]) {
663           SWAP2IntScalar(i[k],i[j],Ii[k],Ii[j],tmp,stmp);
664           ik = i[k];
665         }
666       }
667     }
668   } else {
669     ierr = PetscSortIntWithScalarArray_Private(i,Ii,n-1);CHKERRQ(ierr);
670   }
671   PetscFunctionReturn(0);
672 }
673 
674 #define SWAP2IntData(a,b,c,d,t,td,siz)          \
675   do {                                          \
676   PetscErrorCode _ierr;                         \
677   t=a;a=b;b=t;                                  \
678   _ierr = PetscMemcpy(td,c,siz);CHKERRQ(_ierr); \
679   _ierr = PetscMemcpy(c,d,siz);CHKERRQ(_ierr);  \
680   _ierr = PetscMemcpy(d,td,siz);CHKERRQ(_ierr); \
681 } while(0)
682 
683 /*
684    Modified from PetscSortIntWithArray_Private().
685 */
686 static PetscErrorCode PetscSortIntWithDataArray_Private(PetscInt *v,char *V,PetscInt right,size_t size,void *work)
687 {
688   PetscErrorCode ierr;
689   PetscInt       i,vl,last,tmp;
690 
691   PetscFunctionBegin;
692   if (right <= 1) {
693     if (right == 1) {
694       if (v[0] > v[1]) SWAP2IntData(v[0],v[1],V,V+size,tmp,work,size);
695     }
696     PetscFunctionReturn(0);
697   }
698   SWAP2IntData(v[0],v[right/2],V,V+size*(right/2),tmp,work,size);
699   vl   = v[0];
700   last = 0;
701   for (i=1; i<=right; i++) {
702     if (v[i] < vl) {last++; SWAP2IntData(v[last],v[i],V+size*last,V+size*i,tmp,work,size);}
703   }
704   SWAP2IntData(v[0],v[last],V,V + size*last,tmp,work,size);
705   ierr = PetscSortIntWithDataArray_Private(v,V,last-1,size,work);CHKERRQ(ierr);
706   ierr = PetscSortIntWithDataArray_Private(v+last+1,V+size*(last+1),right-(last+1),size,work);CHKERRQ(ierr);
707   PetscFunctionReturn(0);
708 }
709 
710 /*@C
711    PetscSortIntWithDataArray - Sorts an array of integers in place in increasing order;
712        changes a second array to match the sorted first INTEGER array.  Unlike other sort routines, the user must
713        provide workspace (the size of an element in the data array) to use when sorting.
714 
715    Not Collective
716 
717    Input Parameters:
718 +  n  - number of values
719 .  i  - array of integers
720 .  Ii - second array of data
721 .  size - sizeof elements in the data array in bytes
722 -  work - workspace of "size" bytes used when sorting
723 
724    Level: intermediate
725 
726    Concepts: sorting^ints with array
727 
728 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
729 @*/
730 PetscErrorCode  PetscSortIntWithDataArray(PetscInt n,PetscInt i[],void *Ii,size_t size,void *work)
731 {
732   char           *V = (char *) Ii;
733   PetscErrorCode ierr;
734   PetscInt       j,k,tmp,ik;
735 
736   PetscFunctionBegin;
737   if (n<8) {
738     for (k=0; k<n; k++) {
739       ik = i[k];
740       for (j=k+1; j<n; j++) {
741         if (ik > i[j]) {
742           SWAP2IntData(i[k],i[j],V+size*k,V+size*j,tmp,work,size);
743           ik = i[k];
744         }
745       }
746     }
747   } else {
748     ierr = PetscSortIntWithDataArray_Private(i,V,n-1,size,work);CHKERRQ(ierr);
749   }
750   PetscFunctionReturn(0);
751 }
752 
753 
754 /*@
755    PetscMergeIntArray -     Merges two SORTED integer arrays, removes duplicate elements.
756 
757    Not Collective
758 
759    Input Parameters:
760 +  an  - number of values in the first array
761 .  aI  - first sorted array of integers
762 .  bn  - number of values in the second array
763 -  bI  - second array of integers
764 
765    Output Parameters:
766 +  n   - number of values in the merged array
767 -  L   - merged sorted array, this is allocated if an array is not provided
768 
769    Level: intermediate
770 
771    Concepts: merging^arrays
772 
773 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
774 @*/
775 PetscErrorCode  PetscMergeIntArray(PetscInt an,const PetscInt aI[], PetscInt bn, const PetscInt bI[],  PetscInt *n, PetscInt **L)
776 {
777   PetscErrorCode ierr;
778   PetscInt       *L_ = *L, ak, bk, k;
779 
780   if (!L_) {
781     ierr = PetscMalloc1(an+bn, L);CHKERRQ(ierr);
782     L_   = *L;
783   }
784   k = ak = bk = 0;
785   while (ak < an && bk < bn) {
786     if (aI[ak] == bI[bk]) {
787       L_[k] = aI[ak];
788       ++ak;
789       ++bk;
790       ++k;
791     } else if (aI[ak] < bI[bk]) {
792       L_[k] = aI[ak];
793       ++ak;
794       ++k;
795     } else {
796       L_[k] = bI[bk];
797       ++bk;
798       ++k;
799     }
800   }
801   if (ak < an) {
802     ierr = PetscMemcpy(L_+k,aI+ak,(an-ak)*sizeof(PetscInt));CHKERRQ(ierr);
803     k   += (an-ak);
804   }
805   if (bk < bn) {
806     ierr = PetscMemcpy(L_+k,bI+bk,(bn-bk)*sizeof(PetscInt));CHKERRQ(ierr);
807     k   += (bn-bk);
808   }
809   *n = k;
810   PetscFunctionReturn(0);
811 }
812 
813 /*@
814    PetscMergeIntArrayPair -     Merges two SORTED integer arrays that share NO common values along with an additional array of integers.
815                                 The additional arrays are the same length as sorted arrays and are merged
816                                 in the order determined by the merging of the sorted pair.
817 
818    Not Collective
819 
820    Input Parameters:
821 +  an  - number of values in the first array
822 .  aI  - first sorted array of integers
823 .  aJ  - first additional array of integers
824 .  bn  - number of values in the second array
825 .  bI  - second array of integers
826 -  bJ  - second additional of integers
827 
828    Output Parameters:
829 +  n   - number of values in the merged array (== an + bn)
830 .  L   - merged sorted array
831 -  J   - merged additional array
832 
833    Notes:
834     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
835    Level: intermediate
836 
837    Concepts: merging^arrays
838 
839 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
840 @*/
841 PetscErrorCode  PetscMergeIntArrayPair(PetscInt an,const PetscInt aI[], const PetscInt aJ[], PetscInt bn, const PetscInt bI[], const PetscInt bJ[], PetscInt *n, PetscInt **L, PetscInt **J)
842 {
843   PetscErrorCode ierr;
844   PetscInt       n_, *L_, *J_, ak, bk, k;
845 
846   PetscFunctionBegin;
847   PetscValidIntPointer(L,8);
848   PetscValidIntPointer(J,9);
849   n_ = an + bn;
850   *n = n_;
851   if (!*L) {
852     ierr = PetscMalloc1(n_, L);CHKERRQ(ierr);
853   }
854   L_ = *L;
855   if (!*J) {
856     ierr = PetscMalloc1(n_, J);CHKERRQ(ierr);
857   }
858   J_   = *J;
859   k = ak = bk = 0;
860   while (ak < an && bk < bn) {
861     if (aI[ak] <= bI[bk]) {
862       L_[k] = aI[ak];
863       J_[k] = aJ[ak];
864       ++ak;
865       ++k;
866     } else {
867       L_[k] = bI[bk];
868       J_[k] = bJ[bk];
869       ++bk;
870       ++k;
871     }
872   }
873   if (ak < an) {
874     ierr = PetscMemcpy(L_+k,aI+ak,(an-ak)*sizeof(PetscInt));CHKERRQ(ierr);
875     ierr = PetscMemcpy(J_+k,aJ+ak,(an-ak)*sizeof(PetscInt));CHKERRQ(ierr);
876     k   += (an-ak);
877   }
878   if (bk < bn) {
879     ierr = PetscMemcpy(L_+k,bI+bk,(bn-bk)*sizeof(PetscInt));CHKERRQ(ierr);
880     ierr = PetscMemcpy(J_+k,bJ+bk,(bn-bk)*sizeof(PetscInt));CHKERRQ(ierr);
881   }
882   PetscFunctionReturn(0);
883 }
884 
885 /*@
886    PetscMergeMPIIntArray -     Merges two SORTED integer arrays.
887 
888    Not Collective
889 
890    Input Parameters:
891 +  an  - number of values in the first array
892 .  aI  - first sorted array of integers
893 .  bn  - number of values in the second array
894 -  bI  - second array of integers
895 
896    Output Parameters:
897 +  n   - number of values in the merged array (<= an + bn)
898 -  L   - merged sorted array, allocated if address of NULL pointer is passed
899 
900    Level: intermediate
901 
902    Concepts: merging^arrays
903 
904 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
905 @*/
906 PetscErrorCode PetscMergeMPIIntArray(PetscInt an,const PetscMPIInt aI[],PetscInt bn,const PetscMPIInt bI[],PetscInt *n,PetscMPIInt **L)
907 {
908   PetscErrorCode ierr;
909   PetscInt       ai,bi,k;
910 
911   PetscFunctionBegin;
912   if (!*L) {ierr = PetscMalloc1((an+bn),L);CHKERRQ(ierr);}
913   for (ai=0,bi=0,k=0; ai<an || bi<bn; ) {
914     PetscInt t = -1;
915     for ( ; ai<an && (!bn || aI[ai] <= bI[bi]); ai++) (*L)[k++] = t = aI[ai];
916     for ( ; bi<bn && bI[bi] == t; bi++);
917     for ( ; bi<bn && (!an || bI[bi] <= aI[ai]); bi++) (*L)[k++] = t = bI[bi];
918     for ( ; ai<an && aI[ai] == t; ai++);
919   }
920   *n = k;
921   PetscFunctionReturn(0);
922 }
923 
924 /*@C
925    PetscProcessTree - Prepares tree data to be displayed graphically
926 
927    Not Collective
928 
929    Input Parameters:
930 +  n  - number of values
931 .  mask - indicates those entries in the tree, location 0 is always masked
932 -  parentid - indicates the parent of each entry
933 
934    Output Parameters:
935 +  Nlevels - the number of levels
936 .  Level - for each node tells its level
937 .  Levelcnts - the number of nodes on each level
938 .  Idbylevel - a list of ids on each of the levels, first level followed by second etc
939 -  Column - for each id tells its column index
940 
941    Level: developer
942 
943    Notes:
944     This code is not currently used
945 
946 .seealso: PetscSortReal(), PetscSortIntWithPermutation()
947 @*/
948 PetscErrorCode  PetscProcessTree(PetscInt n,const PetscBool mask[],const PetscInt parentid[],PetscInt *Nlevels,PetscInt **Level,PetscInt **Levelcnt,PetscInt **Idbylevel,PetscInt **Column)
949 {
950   PetscInt       i,j,cnt,nmask = 0,nlevels = 0,*level,*levelcnt,levelmax = 0,*workid,*workparentid,tcnt = 0,*idbylevel,*column;
951   PetscErrorCode ierr;
952   PetscBool      done = PETSC_FALSE;
953 
954   PetscFunctionBegin;
955   if (!mask[0]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Mask of 0th location must be set");
956   for (i=0; i<n; i++) {
957     if (mask[i]) continue;
958     if (parentid[i]  == i) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Node labeled as own parent");
959     if (parentid[i] && mask[parentid[i]]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Parent is masked");
960   }
961 
962   for (i=0; i<n; i++) {
963     if (!mask[i]) nmask++;
964   }
965 
966   /* determine the level in the tree of each node */
967   ierr = PetscCalloc1(n,&level);CHKERRQ(ierr);
968 
969   level[0] = 1;
970   while (!done) {
971     done = PETSC_TRUE;
972     for (i=0; i<n; i++) {
973       if (mask[i]) continue;
974       if (!level[i] && level[parentid[i]]) level[i] = level[parentid[i]] + 1;
975       else if (!level[i]) done = PETSC_FALSE;
976     }
977   }
978   for (i=0; i<n; i++) {
979     level[i]--;
980     nlevels = PetscMax(nlevels,level[i]);
981   }
982 
983   /* count the number of nodes on each level and its max */
984   ierr = PetscCalloc1(nlevels,&levelcnt);CHKERRQ(ierr);
985   for (i=0; i<n; i++) {
986     if (mask[i]) continue;
987     levelcnt[level[i]-1]++;
988   }
989   for (i=0; i<nlevels;i++) levelmax = PetscMax(levelmax,levelcnt[i]);
990 
991   /* for each level sort the ids by the parent id */
992   ierr = PetscMalloc2(levelmax,&workid,levelmax,&workparentid);CHKERRQ(ierr);
993   ierr = PetscMalloc1(nmask,&idbylevel);CHKERRQ(ierr);
994   for (j=1; j<=nlevels;j++) {
995     cnt = 0;
996     for (i=0; i<n; i++) {
997       if (mask[i]) continue;
998       if (level[i] != j) continue;
999       workid[cnt]         = i;
1000       workparentid[cnt++] = parentid[i];
1001     }
1002     /*  PetscIntView(cnt,workparentid,0);
1003     PetscIntView(cnt,workid,0);
1004     ierr = PetscSortIntWithArray(cnt,workparentid,workid);CHKERRQ(ierr);
1005     PetscIntView(cnt,workparentid,0);
1006     PetscIntView(cnt,workid,0);*/
1007     ierr  = PetscMemcpy(idbylevel+tcnt,workid,cnt*sizeof(PetscInt));CHKERRQ(ierr);
1008     tcnt += cnt;
1009   }
1010   if (tcnt != nmask) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Inconsistent count of unmasked nodes");
1011   ierr = PetscFree2(workid,workparentid);CHKERRQ(ierr);
1012 
1013   /* for each node list its column */
1014   ierr = PetscMalloc1(n,&column);CHKERRQ(ierr);
1015   cnt = 0;
1016   for (j=0; j<nlevels; j++) {
1017     for (i=0; i<levelcnt[j]; i++) {
1018       column[idbylevel[cnt++]] = i;
1019     }
1020   }
1021 
1022   *Nlevels   = nlevels;
1023   *Level     = level;
1024   *Levelcnt  = levelcnt;
1025   *Idbylevel = idbylevel;
1026   *Column    = column;
1027   PetscFunctionReturn(0);
1028 }
1029