xref: /petsc/src/sys/utils/sorti.c (revision 487a658c8b32ba712a1dc8280daad2fd70c1dcd9)
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 SWAP2IntScalar(a,b,c,d,t,ts) {t=a;a=b;b=t;ts=c;c=d;d=ts;}
530 
531 /*
532    Modified from PetscSortIntWithArray_Private().
533 */
534 static PetscErrorCode PetscSortIntWithScalarArray_Private(PetscInt *v,PetscScalar *V,PetscInt right)
535 {
536   PetscErrorCode ierr;
537   PetscInt       i,vl,last,tmp;
538   PetscScalar    stmp;
539 
540   PetscFunctionBegin;
541   if (right <= 1) {
542     if (right == 1) {
543       if (v[0] > v[1]) SWAP2IntScalar(v[0],v[1],V[0],V[1],tmp,stmp);
544     }
545     PetscFunctionReturn(0);
546   }
547   SWAP2IntScalar(v[0],v[right/2],V[0],V[right/2],tmp,stmp);
548   vl   = v[0];
549   last = 0;
550   for (i=1; i<=right; i++) {
551     if (v[i] < vl) {last++; SWAP2IntScalar(v[last],v[i],V[last],V[i],tmp,stmp);}
552   }
553   SWAP2IntScalar(v[0],v[last],V[0],V[last],tmp,stmp);
554   ierr = PetscSortIntWithScalarArray_Private(v,V,last-1);CHKERRQ(ierr);
555   ierr = PetscSortIntWithScalarArray_Private(v+last+1,V+last+1,right-(last+1));CHKERRQ(ierr);
556   PetscFunctionReturn(0);
557 }
558 
559 /*@
560    PetscSortIntWithScalarArray - Sorts an array of integers in place in increasing order;
561        changes a second SCALAR array to match the sorted first INTEGER array.
562 
563    Not Collective
564 
565    Input Parameters:
566 +  n  - number of values
567 .  i  - array of integers
568 -  I - second array of scalars
569 
570    Level: intermediate
571 
572    Concepts: sorting^ints with array
573 
574 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
575 @*/
576 PetscErrorCode  PetscSortIntWithScalarArray(PetscInt n,PetscInt i[],PetscScalar Ii[])
577 {
578   PetscErrorCode ierr;
579   PetscInt       j,k,tmp,ik;
580   PetscScalar    stmp;
581 
582   PetscFunctionBegin;
583   if (n<8) {
584     for (k=0; k<n; k++) {
585       ik = i[k];
586       for (j=k+1; j<n; j++) {
587         if (ik > i[j]) {
588           SWAP2IntScalar(i[k],i[j],Ii[k],Ii[j],tmp,stmp);
589           ik = i[k];
590         }
591       }
592     }
593   } else {
594     ierr = PetscSortIntWithScalarArray_Private(i,Ii,n-1);CHKERRQ(ierr);
595   }
596   PetscFunctionReturn(0);
597 }
598 
599 #define SWAP2IntData(a,b,c,d,t,td,siz)          \
600   do {                                          \
601   PetscErrorCode _ierr;                         \
602   t=a;a=b;b=t;                                  \
603   _ierr = PetscMemcpy(td,c,siz);CHKERRQ(_ierr); \
604   _ierr = PetscMemcpy(c,d,siz);CHKERRQ(_ierr);  \
605   _ierr = PetscMemcpy(d,td,siz);CHKERRQ(_ierr); \
606 } while(0)
607 
608 /*
609    Modified from PetscSortIntWithArray_Private().
610 */
611 static PetscErrorCode PetscSortIntWithDataArray_Private(PetscInt *v,char *V,PetscInt right,size_t size,void *work)
612 {
613   PetscErrorCode ierr;
614   PetscInt       i,vl,last,tmp;
615 
616   PetscFunctionBegin;
617   if (right <= 1) {
618     if (right == 1) {
619       if (v[0] > v[1]) SWAP2IntData(v[0],v[1],V,V+size,tmp,work,size);
620     }
621     PetscFunctionReturn(0);
622   }
623   SWAP2IntData(v[0],v[right/2],V,V+size*(right/2),tmp,work,size);
624   vl   = v[0];
625   last = 0;
626   for (i=1; i<=right; i++) {
627     if (v[i] < vl) {last++; SWAP2IntData(v[last],v[i],V+size*last,V+size*i,tmp,work,size);}
628   }
629   SWAP2IntData(v[0],v[last],V,V + size*last,tmp,work,size);
630   ierr = PetscSortIntWithDataArray_Private(v,V,last-1,size,work);CHKERRQ(ierr);
631   ierr = PetscSortIntWithDataArray_Private(v+last+1,V+size*(last+1),right-(last+1),size,work);CHKERRQ(ierr);
632   PetscFunctionReturn(0);
633 }
634 
635 /*@C
636    PetscSortIntWithDataArray - Sorts an array of integers in place in increasing order;
637        changes a second array to match the sorted first INTEGER array.  Unlike other sort routines, the user must
638        provide workspace (the size of an element in the data array) to use when sorting.
639 
640    Not Collective
641 
642    Input Parameters:
643 +  n  - number of values
644 .  i  - array of integers
645 .  Ii - second array of data
646 .  size - sizeof elements in the data array in bytes
647 -  work - workspace of "size" bytes used when sorting
648 
649    Level: intermediate
650 
651    Concepts: sorting^ints with array
652 
653 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
654 @*/
655 PetscErrorCode  PetscSortIntWithDataArray(PetscInt n,PetscInt i[],void *Ii,size_t size,void *work)
656 {
657   char           *V = (char *) Ii;
658   PetscErrorCode ierr;
659   PetscInt       j,k,tmp,ik;
660 
661   PetscFunctionBegin;
662   if (n<8) {
663     for (k=0; k<n; k++) {
664       ik = i[k];
665       for (j=k+1; j<n; j++) {
666         if (ik > i[j]) {
667           SWAP2IntData(i[k],i[j],V+size*k,V+size*j,tmp,work,size);
668           ik = i[k];
669         }
670       }
671     }
672   } else {
673     ierr = PetscSortIntWithDataArray_Private(i,V,n-1,size,work);CHKERRQ(ierr);
674   }
675   PetscFunctionReturn(0);
676 }
677 
678 
679 /*@
680    PetscMergeIntArray -     Merges two SORTED integer arrays, removes duplicate elements.
681 
682    Not Collective
683 
684    Input Parameters:
685 +  an  - number of values in the first array
686 .  aI  - first sorted array of integers
687 .  bn  - number of values in the second array
688 -  bI  - second array of integers
689 
690    Output Parameters:
691 +  n   - number of values in the merged array
692 -  L   - merged sorted array, this is allocated if an array is not provided
693 
694    Level: intermediate
695 
696    Concepts: merging^arrays
697 
698 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
699 @*/
700 PetscErrorCode  PetscMergeIntArray(PetscInt an,const PetscInt aI[], PetscInt bn, const PetscInt bI[],  PetscInt *n, PetscInt **L)
701 {
702   PetscErrorCode ierr;
703   PetscInt       *L_ = *L, ak, bk, k;
704 
705   if (!L_) {
706     ierr = PetscMalloc1(an+bn, L);CHKERRQ(ierr);
707     L_   = *L;
708   }
709   k = ak = bk = 0;
710   while (ak < an && bk < bn) {
711     if (aI[ak] == bI[bk]) {
712       L_[k] = aI[ak];
713       ++ak;
714       ++bk;
715       ++k;
716     } else if (aI[ak] < bI[bk]) {
717       L_[k] = aI[ak];
718       ++ak;
719       ++k;
720     } else {
721       L_[k] = bI[bk];
722       ++bk;
723       ++k;
724     }
725   }
726   if (ak < an) {
727     ierr = PetscMemcpy(L_+k,aI+ak,(an-ak)*sizeof(PetscInt));CHKERRQ(ierr);
728     k   += (an-ak);
729   }
730   if (bk < bn) {
731     ierr = PetscMemcpy(L_+k,bI+bk,(bn-bk)*sizeof(PetscInt));CHKERRQ(ierr);
732     k   += (bn-bk);
733   }
734   *n = k;
735   PetscFunctionReturn(0);
736 }
737 
738 /*@
739    PetscMergeIntArrayPair -     Merges two SORTED integer arrays that share NO common values along with an additional array of integers.
740                                 The additional arrays are the same length as sorted arrays and are merged
741                                 in the order determined by the merging of the sorted pair.
742 
743    Not Collective
744 
745    Input Parameters:
746 +  an  - number of values in the first array
747 .  aI  - first sorted array of integers
748 .  aJ  - first additional array of integers
749 .  bn  - number of values in the second array
750 .  bI  - second array of integers
751 -  bJ  - second additional of integers
752 
753    Output Parameters:
754 +  n   - number of values in the merged array (== an + bn)
755 .  L   - merged sorted array
756 -  J   - merged additional array
757 
758    Notes:
759     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
760    Level: intermediate
761 
762    Concepts: merging^arrays
763 
764 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
765 @*/
766 PetscErrorCode  PetscMergeIntArrayPair(PetscInt an,const PetscInt aI[], const PetscInt aJ[], PetscInt bn, const PetscInt bI[], const PetscInt bJ[], PetscInt *n, PetscInt **L, PetscInt **J)
767 {
768   PetscErrorCode ierr;
769   PetscInt       n_, *L_, *J_, ak, bk, k;
770 
771   PetscFunctionBegin;
772   PetscValidIntPointer(L,8);
773   PetscValidIntPointer(J,9);
774   n_ = an + bn;
775   *n = n_;
776   if (!*L) {
777     ierr = PetscMalloc1(n_, L);CHKERRQ(ierr);
778   }
779   L_ = *L;
780   if (!*J) {
781     ierr = PetscMalloc1(n_, J);CHKERRQ(ierr);
782   }
783   J_   = *J;
784   k = ak = bk = 0;
785   while (ak < an && bk < bn) {
786     if (aI[ak] <= bI[bk]) {
787       L_[k] = aI[ak];
788       J_[k] = aJ[ak];
789       ++ak;
790       ++k;
791     } else {
792       L_[k] = bI[bk];
793       J_[k] = bJ[bk];
794       ++bk;
795       ++k;
796     }
797   }
798   if (ak < an) {
799     ierr = PetscMemcpy(L_+k,aI+ak,(an-ak)*sizeof(PetscInt));CHKERRQ(ierr);
800     ierr = PetscMemcpy(J_+k,aJ+ak,(an-ak)*sizeof(PetscInt));CHKERRQ(ierr);
801     k   += (an-ak);
802   }
803   if (bk < bn) {
804     ierr = PetscMemcpy(L_+k,bI+bk,(bn-bk)*sizeof(PetscInt));CHKERRQ(ierr);
805     ierr = PetscMemcpy(J_+k,bJ+bk,(bn-bk)*sizeof(PetscInt));CHKERRQ(ierr);
806   }
807   PetscFunctionReturn(0);
808 }
809 
810 /*@
811    PetscMergeMPIIntArray -     Merges two SORTED integer arrays.
812 
813    Not Collective
814 
815    Input Parameters:
816 +  an  - number of values in the first array
817 .  aI  - first sorted array of integers
818 .  bn  - number of values in the second array
819 -  bI  - second array of integers
820 
821    Output Parameters:
822 +  n   - number of values in the merged array (<= an + bn)
823 -  L   - merged sorted array, allocated if address of NULL pointer is passed
824 
825    Level: intermediate
826 
827    Concepts: merging^arrays
828 
829 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
830 @*/
831 PetscErrorCode PetscMergeMPIIntArray(PetscInt an,const PetscMPIInt aI[],PetscInt bn,const PetscMPIInt bI[],PetscInt *n,PetscMPIInt **L)
832 {
833   PetscErrorCode ierr;
834   PetscInt       ai,bi,k;
835 
836   PetscFunctionBegin;
837   if (!*L) {ierr = PetscMalloc1((an+bn),L);CHKERRQ(ierr);}
838   for (ai=0,bi=0,k=0; ai<an || bi<bn; ) {
839     PetscInt t = -1;
840     for ( ; ai<an && (!bn || aI[ai] <= bI[bi]); ai++) (*L)[k++] = t = aI[ai];
841     for ( ; bi<bn && bI[bi] == t; bi++);
842     for ( ; bi<bn && (!an || bI[bi] <= aI[ai]); bi++) (*L)[k++] = t = bI[bi];
843     for ( ; ai<an && aI[ai] == t; ai++);
844   }
845   *n = k;
846   PetscFunctionReturn(0);
847 }
848 
849 /*@C
850    PetscProcessTree - Prepares tree data to be displayed graphically
851 
852    Not Collective
853 
854    Input Parameters:
855 +  n  - number of values
856 .  mask - indicates those entries in the tree, location 0 is always masked
857 -  parentid - indicates the parent of each entry
858 
859    Output Parameters:
860 +  Nlevels - the number of levels
861 .  Level - for each node tells its level
862 .  Levelcnts - the number of nodes on each level
863 .  Idbylevel - a list of ids on each of the levels, first level followed by second etc
864 -  Column - for each id tells its column index
865 
866    Level: developer
867 
868    Notes:
869     This code is not currently used
870 
871 .seealso: PetscSortReal(), PetscSortIntWithPermutation()
872 @*/
873 PetscErrorCode  PetscProcessTree(PetscInt n,const PetscBool mask[],const PetscInt parentid[],PetscInt *Nlevels,PetscInt **Level,PetscInt **Levelcnt,PetscInt **Idbylevel,PetscInt **Column)
874 {
875   PetscInt       i,j,cnt,nmask = 0,nlevels = 0,*level,*levelcnt,levelmax = 0,*workid,*workparentid,tcnt = 0,*idbylevel,*column;
876   PetscErrorCode ierr;
877   PetscBool      done = PETSC_FALSE;
878 
879   PetscFunctionBegin;
880   if (!mask[0]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Mask of 0th location must be set");
881   for (i=0; i<n; i++) {
882     if (mask[i]) continue;
883     if (parentid[i]  == i) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Node labeled as own parent");
884     if (parentid[i] && mask[parentid[i]]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Parent is masked");
885   }
886 
887   for (i=0; i<n; i++) {
888     if (!mask[i]) nmask++;
889   }
890 
891   /* determine the level in the tree of each node */
892   ierr = PetscCalloc1(n,&level);CHKERRQ(ierr);
893 
894   level[0] = 1;
895   while (!done) {
896     done = PETSC_TRUE;
897     for (i=0; i<n; i++) {
898       if (mask[i]) continue;
899       if (!level[i] && level[parentid[i]]) level[i] = level[parentid[i]] + 1;
900       else if (!level[i]) done = PETSC_FALSE;
901     }
902   }
903   for (i=0; i<n; i++) {
904     level[i]--;
905     nlevels = PetscMax(nlevels,level[i]);
906   }
907 
908   /* count the number of nodes on each level and its max */
909   ierr = PetscCalloc1(nlevels,&levelcnt);CHKERRQ(ierr);
910   for (i=0; i<n; i++) {
911     if (mask[i]) continue;
912     levelcnt[level[i]-1]++;
913   }
914   for (i=0; i<nlevels;i++) levelmax = PetscMax(levelmax,levelcnt[i]);
915 
916   /* for each level sort the ids by the parent id */
917   ierr = PetscMalloc2(levelmax,&workid,levelmax,&workparentid);CHKERRQ(ierr);
918   ierr = PetscMalloc1(nmask,&idbylevel);CHKERRQ(ierr);
919   for (j=1; j<=nlevels;j++) {
920     cnt = 0;
921     for (i=0; i<n; i++) {
922       if (mask[i]) continue;
923       if (level[i] != j) continue;
924       workid[cnt]         = i;
925       workparentid[cnt++] = parentid[i];
926     }
927     /*  PetscIntView(cnt,workparentid,0);
928     PetscIntView(cnt,workid,0);
929     ierr = PetscSortIntWithArray(cnt,workparentid,workid);CHKERRQ(ierr);
930     PetscIntView(cnt,workparentid,0);
931     PetscIntView(cnt,workid,0);*/
932     ierr  = PetscMemcpy(idbylevel+tcnt,workid,cnt*sizeof(PetscInt));CHKERRQ(ierr);
933     tcnt += cnt;
934   }
935   if (tcnt != nmask) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Inconsistent count of unmasked nodes");
936   ierr = PetscFree2(workid,workparentid);CHKERRQ(ierr);
937 
938   /* for each node list its column */
939   ierr = PetscMalloc1(n,&column);CHKERRQ(ierr);
940   cnt = 0;
941   for (j=0; j<nlevels; j++) {
942     for (i=0; i<levelcnt[j]; i++) {
943       column[idbylevel[cnt++]] = i;
944     }
945   }
946 
947   *Nlevels   = nlevels;
948   *Level     = level;
949   *Levelcnt  = levelcnt;
950   *Idbylevel = idbylevel;
951   *Column    = column;
952   PetscFunctionReturn(0);
953 }
954