xref: /petsc/src/sys/utils/sorti.c (revision 1f4a21c04b19618a0a5b48c68a30352e5a55bdef)
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 #undef __FUNCT__
183 #define __FUNCT__ "PetscFindMPIInt"
184 /*@
185   PetscFindMPIInt - Finds MPI integer in a sorted array of integers
186 
187    Not Collective
188 
189    Input Parameters:
190 +  key - the integer to locate
191 .  n   - number of values in the array
192 -  ii  - array of integers
193 
194    Output Parameter:
195 .  loc - the location if found, otherwise -(slot+1) where slot is the place the value would go
196 
197    Level: intermediate
198 
199    Concepts: sorting^ints
200 
201 .seealso: PetscSortInt(), PetscSortIntWithArray(), PetscSortRemoveDupsInt()
202 @*/
203 PetscErrorCode PetscFindMPIInt(PetscMPIInt key, PetscInt n, const PetscMPIInt ii[], PetscInt *loc)
204 {
205   PetscInt lo = 0,hi = n;
206 
207   PetscFunctionBegin;
208   PetscValidPointer(loc,4);
209   if (!n) {*loc = -1; PetscFunctionReturn(0);}
210   PetscValidPointer(ii,3);
211   while (hi - lo > 1) {
212     PetscInt mid = lo + (hi - lo)/2;
213     if (key < ii[mid]) hi = mid;
214     else               lo = mid;
215   }
216   *loc = key == ii[lo] ? lo : -(lo + (key > ii[lo]) + 1);
217   PetscFunctionReturn(0);
218 }
219 
220 /* -----------------------------------------------------------------------*/
221 #define SWAP2(a,b,c,d,t) {t=a;a=b;b=t;t=c;c=d;d=t;}
222 
223 /*
224    A simple version of quicksort; taken from Kernighan and Ritchie, page 87.
225    Assumes 0 origin for v, number of elements = right+1 (right is index of
226    right-most member).
227 */
228 static PetscErrorCode PetscSortIntWithArray_Private(PetscInt *v,PetscInt *V,PetscInt right)
229 {
230   PetscErrorCode ierr;
231   PetscInt       i,vl,last,tmp;
232 
233   PetscFunctionBegin;
234   if (right <= 1) {
235     if (right == 1) {
236       if (v[0] > v[1]) SWAP2(v[0],v[1],V[0],V[1],tmp);
237     }
238     PetscFunctionReturn(0);
239   }
240   SWAP2(v[0],v[right/2],V[0],V[right/2],tmp);
241   vl   = v[0];
242   last = 0;
243   for (i=1; i<=right; i++) {
244     if (v[i] < vl) {last++; SWAP2(v[last],v[i],V[last],V[i],tmp);}
245   }
246   SWAP2(v[0],v[last],V[0],V[last],tmp);
247   ierr = PetscSortIntWithArray_Private(v,V,last-1);CHKERRQ(ierr);
248   ierr = PetscSortIntWithArray_Private(v+last+1,V+last+1,right-(last+1));CHKERRQ(ierr);
249   PetscFunctionReturn(0);
250 }
251 
252 /*@
253    PetscSortIntWithArray - Sorts an array of integers in place in increasing order;
254        changes a second array to match the sorted first array.
255 
256    Not Collective
257 
258    Input Parameters:
259 +  n  - number of values
260 .  i  - array of integers
261 -  I - second array of integers
262 
263    Level: intermediate
264 
265    Concepts: sorting^ints with array
266 
267 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt()
268 @*/
269 PetscErrorCode  PetscSortIntWithArray(PetscInt n,PetscInt i[],PetscInt Ii[])
270 {
271   PetscErrorCode ierr;
272   PetscInt       j,k,tmp,ik;
273 
274   PetscFunctionBegin;
275   if (n<8) {
276     for (k=0; k<n; k++) {
277       ik = i[k];
278       for (j=k+1; j<n; j++) {
279         if (ik > i[j]) {
280           SWAP2(i[k],i[j],Ii[k],Ii[j],tmp);
281           ik = i[k];
282         }
283       }
284     }
285   } else {
286     ierr = PetscSortIntWithArray_Private(i,Ii,n-1);CHKERRQ(ierr);
287   }
288   PetscFunctionReturn(0);
289 }
290 
291 
292 #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;}
293 
294 /*
295    A simple version of quicksort; taken from Kernighan and Ritchie, page 87.
296    Assumes 0 origin for v, number of elements = right+1 (right is index of
297    right-most member).
298 */
299 static PetscErrorCode PetscSortIntWithArrayPair_Private(PetscInt *L,PetscInt *J, PetscInt *K, PetscInt right)
300 {
301   PetscErrorCode ierr;
302   PetscInt       i,vl,last,tmp;
303 
304   PetscFunctionBegin;
305   if (right <= 1) {
306     if (right == 1) {
307       if (L[0] > L[1]) SWAP3(L[0],L[1],J[0],J[1],K[0],K[1],tmp);
308     }
309     PetscFunctionReturn(0);
310   }
311   SWAP3(L[0],L[right/2],J[0],J[right/2],K[0],K[right/2],tmp);
312   vl   = L[0];
313   last = 0;
314   for (i=1; i<=right; i++) {
315     if (L[i] < vl) {last++; SWAP3(L[last],L[i],J[last],J[i],K[last],K[i],tmp);}
316   }
317   SWAP3(L[0],L[last],J[0],J[last],K[0],K[last],tmp);
318   ierr = PetscSortIntWithArrayPair_Private(L,J,K,last-1);CHKERRQ(ierr);
319   ierr = PetscSortIntWithArrayPair_Private(L+last+1,J+last+1,K+last+1,right-(last+1));CHKERRQ(ierr);
320   PetscFunctionReturn(0);
321 }
322 
323 /*@
324    PetscSortIntWithArrayPair - Sorts an array of integers in place in increasing order;
325        changes a pair of integer arrays to match the sorted first array.
326 
327    Not Collective
328 
329    Input Parameters:
330 +  n  - number of values
331 .  I  - array of integers
332 .  J  - second array of integers (first array of the pair)
333 -  K  - third array of integers  (second array of the pair)
334 
335    Level: intermediate
336 
337    Concepts: sorting^ints with array pair
338 
339 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortIntWithArray()
340 @*/
341 PetscErrorCode  PetscSortIntWithArrayPair(PetscInt n,PetscInt L[],PetscInt J[], PetscInt K[])
342 {
343   PetscErrorCode ierr;
344   PetscInt       j,k,tmp,ik;
345 
346   PetscFunctionBegin;
347   if (n<8) {
348     for (k=0; k<n; k++) {
349       ik = L[k];
350       for (j=k+1; j<n; j++) {
351         if (ik > L[j]) {
352           SWAP3(L[k],L[j],J[k],J[j],K[k],K[j],tmp);
353           ik = L[k];
354         }
355       }
356     }
357   } else {
358     ierr = PetscSortIntWithArrayPair_Private(L,J,K,n-1);CHKERRQ(ierr);
359   }
360   PetscFunctionReturn(0);
361 }
362 
363 /*
364    A simple version of quicksort; taken from Kernighan and Ritchie, page 87.
365    Assumes 0 origin for v, number of elements = right+1 (right is index of
366    right-most member).
367 */
368 static void PetscSortMPIInt_Private(PetscMPIInt *v,PetscInt right)
369 {
370   PetscInt          i,j;
371   PetscMPIInt       pivot,tmp;
372 
373   if (right <= 1) {
374     if (right == 1) {
375       if (v[0] > v[1]) SWAP(v[0],v[1],tmp);
376     }
377     return;
378   }
379   i = MEDIAN(v,right);          /* Choose a pivot */
380   SWAP(v[0],v[i],tmp);          /* Move it out of the way */
381   pivot = v[0];
382   for (i=0,j=right+1;; ) {
383     while (++i < j && v[i] <= pivot) ; /* Scan from the left */
384     while (v[--j] > pivot) ;           /* Scan from the right */
385     if (i >= j) break;
386     SWAP(v[i],v[j],tmp);
387   }
388   SWAP(v[0],v[j],tmp);          /* Put pivot back in place. */
389   PetscSortMPIInt_Private(v,j-1);
390   PetscSortMPIInt_Private(v+j+1,right-(j+1));
391 }
392 
393 /*@
394    PetscSortMPIInt - Sorts an array of MPI integers in place in increasing order.
395 
396    Not Collective
397 
398    Input Parameters:
399 +  n  - number of values
400 -  i  - array of integers
401 
402    Level: intermediate
403 
404    Concepts: sorting^ints
405 
406 .seealso: PetscSortReal(), PetscSortIntWithPermutation()
407 @*/
408 PetscErrorCode  PetscSortMPIInt(PetscInt n,PetscMPIInt i[])
409 {
410   PetscInt    j,k;
411   PetscMPIInt tmp,ik;
412 
413   PetscFunctionBegin;
414   if (n<8) {
415     for (k=0; k<n; k++) {
416       ik = i[k];
417       for (j=k+1; j<n; j++) {
418         if (ik > i[j]) {
419           SWAP(i[k],i[j],tmp);
420           ik = i[k];
421         }
422       }
423     }
424   } else PetscSortMPIInt_Private(i,n-1);
425   PetscFunctionReturn(0);
426 }
427 
428 /*@
429    PetscSortRemoveDupsMPIInt - Sorts an array of MPI integers in place in increasing order removes all duplicate entries
430 
431    Not Collective
432 
433    Input Parameters:
434 +  n  - number of values
435 -  ii  - array of integers
436 
437    Output Parameter:
438 .  n - number of non-redundant values
439 
440    Level: intermediate
441 
442    Concepts: sorting^ints
443 
444 .seealso: PetscSortReal(), PetscSortIntWithPermutation(), PetscSortInt()
445 @*/
446 PetscErrorCode  PetscSortRemoveDupsMPIInt(PetscInt *n,PetscMPIInt ii[])
447 {
448   PetscErrorCode ierr;
449   PetscInt       i,s = 0,N = *n, b = 0;
450 
451   PetscFunctionBegin;
452   ierr = PetscSortMPIInt(N,ii);CHKERRQ(ierr);
453   for (i=0; i<N-1; i++) {
454     if (ii[b+s+1] != ii[b]) {
455       ii[b+1] = ii[b+s+1]; b++;
456     } else s++;
457   }
458   *n = N - s;
459   PetscFunctionReturn(0);
460 }
461 
462 /*
463    A simple version of quicksort; taken from Kernighan and Ritchie, page 87.
464    Assumes 0 origin for v, number of elements = right+1 (right is index of
465    right-most member).
466 */
467 static PetscErrorCode PetscSortMPIIntWithArray_Private(PetscMPIInt *v,PetscMPIInt *V,PetscMPIInt right)
468 {
469   PetscErrorCode ierr;
470   PetscMPIInt    i,vl,last,tmp;
471 
472   PetscFunctionBegin;
473   if (right <= 1) {
474     if (right == 1) {
475       if (v[0] > v[1]) SWAP2(v[0],v[1],V[0],V[1],tmp);
476     }
477     PetscFunctionReturn(0);
478   }
479   SWAP2(v[0],v[right/2],V[0],V[right/2],tmp);
480   vl   = v[0];
481   last = 0;
482   for (i=1; i<=right; i++) {
483     if (v[i] < vl) {last++; SWAP2(v[last],v[i],V[last],V[i],tmp);}
484   }
485   SWAP2(v[0],v[last],V[0],V[last],tmp);
486   ierr = PetscSortMPIIntWithArray_Private(v,V,last-1);CHKERRQ(ierr);
487   ierr = PetscSortMPIIntWithArray_Private(v+last+1,V+last+1,right-(last+1));CHKERRQ(ierr);
488   PetscFunctionReturn(0);
489 }
490 
491 /*@
492    PetscSortMPIIntWithArray - Sorts an array of integers in place in increasing order;
493        changes a second array to match the sorted first array.
494 
495    Not Collective
496 
497    Input Parameters:
498 +  n  - number of values
499 .  i  - array of integers
500 -  I - second array of integers
501 
502    Level: intermediate
503 
504    Concepts: sorting^ints with array
505 
506 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt()
507 @*/
508 PetscErrorCode  PetscSortMPIIntWithArray(PetscMPIInt n,PetscMPIInt i[],PetscMPIInt Ii[])
509 {
510   PetscErrorCode ierr;
511   PetscMPIInt    j,k,tmp,ik;
512 
513   PetscFunctionBegin;
514   if (n<8) {
515     for (k=0; k<n; k++) {
516       ik = i[k];
517       for (j=k+1; j<n; j++) {
518         if (ik > i[j]) {
519           SWAP2(i[k],i[j],Ii[k],Ii[j],tmp);
520           ik = i[k];
521         }
522       }
523     }
524   } else {
525     ierr = PetscSortMPIIntWithArray_Private(i,Ii,n-1);CHKERRQ(ierr);
526   }
527   PetscFunctionReturn(0);
528 }
529 
530 /* -----------------------------------------------------------------------*/
531 #define SWAP2IntScalar(a,b,c,d,t,ts) {t=a;a=b;b=t;ts=c;c=d;d=ts;}
532 
533 /*
534    Modified from PetscSortIntWithArray_Private().
535 */
536 static PetscErrorCode PetscSortIntWithScalarArray_Private(PetscInt *v,PetscScalar *V,PetscInt right)
537 {
538   PetscErrorCode ierr;
539   PetscInt       i,vl,last,tmp;
540   PetscScalar    stmp;
541 
542   PetscFunctionBegin;
543   if (right <= 1) {
544     if (right == 1) {
545       if (v[0] > v[1]) SWAP2IntScalar(v[0],v[1],V[0],V[1],tmp,stmp);
546     }
547     PetscFunctionReturn(0);
548   }
549   SWAP2IntScalar(v[0],v[right/2],V[0],V[right/2],tmp,stmp);
550   vl   = v[0];
551   last = 0;
552   for (i=1; i<=right; i++) {
553     if (v[i] < vl) {last++; SWAP2IntScalar(v[last],v[i],V[last],V[i],tmp,stmp);}
554   }
555   SWAP2IntScalar(v[0],v[last],V[0],V[last],tmp,stmp);
556   ierr = PetscSortIntWithScalarArray_Private(v,V,last-1);CHKERRQ(ierr);
557   ierr = PetscSortIntWithScalarArray_Private(v+last+1,V+last+1,right-(last+1));CHKERRQ(ierr);
558   PetscFunctionReturn(0);
559 }
560 
561 /*@
562    PetscSortIntWithScalarArray - Sorts an array of integers in place in increasing order;
563        changes a second SCALAR array to match the sorted first INTEGER array.
564 
565    Not Collective
566 
567    Input Parameters:
568 +  n  - number of values
569 .  i  - array of integers
570 -  I - second array of scalars
571 
572    Level: intermediate
573 
574    Concepts: sorting^ints with array
575 
576 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
577 @*/
578 PetscErrorCode  PetscSortIntWithScalarArray(PetscInt n,PetscInt i[],PetscScalar Ii[])
579 {
580   PetscErrorCode ierr;
581   PetscInt       j,k,tmp,ik;
582   PetscScalar    stmp;
583 
584   PetscFunctionBegin;
585   if (n<8) {
586     for (k=0; k<n; k++) {
587       ik = i[k];
588       for (j=k+1; j<n; j++) {
589         if (ik > i[j]) {
590           SWAP2IntScalar(i[k],i[j],Ii[k],Ii[j],tmp,stmp);
591           ik = i[k];
592         }
593       }
594     }
595   } else {
596     ierr = PetscSortIntWithScalarArray_Private(i,Ii,n-1);CHKERRQ(ierr);
597   }
598   PetscFunctionReturn(0);
599 }
600 
601 #define SWAP2IntData(a,b,c,d,t,td,siz)          \
602   do {                                          \
603   PetscErrorCode _ierr;                         \
604   t=a;a=b;b=t;                                  \
605   _ierr = PetscMemcpy(td,c,siz);CHKERRQ(_ierr); \
606   _ierr = PetscMemcpy(c,d,siz);CHKERRQ(_ierr);  \
607   _ierr = PetscMemcpy(d,td,siz);CHKERRQ(_ierr); \
608 } while(0)
609 
610 /*
611    Modified from PetscSortIntWithArray_Private().
612 */
613 static PetscErrorCode PetscSortIntWithDataArray_Private(PetscInt *v,char *V,PetscInt right,size_t size,void *work)
614 {
615   PetscErrorCode ierr;
616   PetscInt       i,vl,last,tmp;
617 
618   PetscFunctionBegin;
619   if (right <= 1) {
620     if (right == 1) {
621       if (v[0] > v[1]) SWAP2IntData(v[0],v[1],V,V+size,tmp,work,size);
622     }
623     PetscFunctionReturn(0);
624   }
625   SWAP2IntData(v[0],v[right/2],V,V+size*(right/2),tmp,work,size);
626   vl   = v[0];
627   last = 0;
628   for (i=1; i<=right; i++) {
629     if (v[i] < vl) {last++; SWAP2IntData(v[last],v[i],V+size*last,V+size*i,tmp,work,size);}
630   }
631   SWAP2IntData(v[0],v[last],V,V + size*last,tmp,work,size);
632   ierr = PetscSortIntWithDataArray_Private(v,V,last-1,size,work);CHKERRQ(ierr);
633   ierr = PetscSortIntWithDataArray_Private(v+last+1,V+size*(last+1),right-(last+1),size,work);CHKERRQ(ierr);
634   PetscFunctionReturn(0);
635 }
636 
637 /*@C
638    PetscSortIntWithDataArray - Sorts an array of integers in place in increasing order;
639        changes a second array to match the sorted first INTEGER array.  Unlike other sort routines, the user must
640        provide workspace (the size of an element in the data array) to use when sorting.
641 
642    Not Collective
643 
644    Input Parameters:
645 +  n  - number of values
646 .  i  - array of integers
647 .  Ii - second array of data
648 .  size - sizeof elements in the data array in bytes
649 -  work - workspace of "size" bytes used when sorting
650 
651    Level: intermediate
652 
653    Concepts: sorting^ints with array
654 
655 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
656 @*/
657 PetscErrorCode  PetscSortIntWithDataArray(PetscInt n,PetscInt i[],void *Ii,size_t size,void *work)
658 {
659   char           *V = (char *) Ii;
660   PetscErrorCode ierr;
661   PetscInt       j,k,tmp,ik;
662 
663   PetscFunctionBegin;
664   if (n<8) {
665     for (k=0; k<n; k++) {
666       ik = i[k];
667       for (j=k+1; j<n; j++) {
668         if (ik > i[j]) {
669           SWAP2IntData(i[k],i[j],V+size*k,V+size*j,tmp,work,size);
670           ik = i[k];
671         }
672       }
673     }
674   } else {
675     ierr = PetscSortIntWithDataArray_Private(i,V,n-1,size,work);CHKERRQ(ierr);
676   }
677   PetscFunctionReturn(0);
678 }
679 
680 
681 /*@
682    PetscMergeIntArray -     Merges two SORTED integer arrays, removes duplicate elements.
683 
684    Not Collective
685 
686    Input Parameters:
687 +  an  - number of values in the first array
688 .  aI  - first sorted array of integers
689 .  bn  - number of values in the second array
690 -  bI  - second array of integers
691 
692    Output Parameters:
693 +  n   - number of values in the merged array
694 -  L   - merged sorted array, this is allocated if an array is not provided
695 
696    Level: intermediate
697 
698    Concepts: merging^arrays
699 
700 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
701 @*/
702 PetscErrorCode  PetscMergeIntArray(PetscInt an,const PetscInt aI[], PetscInt bn, const PetscInt bI[],  PetscInt *n, PetscInt **L)
703 {
704   PetscErrorCode ierr;
705   PetscInt       *L_ = *L, ak, bk, k;
706 
707   if (!L_) {
708     ierr = PetscMalloc1(an+bn, L);CHKERRQ(ierr);
709     L_   = *L;
710   }
711   k = ak = bk = 0;
712   while (ak < an && bk < bn) {
713     if (aI[ak] == bI[bk]) {
714       L_[k] = aI[ak];
715       ++ak;
716       ++bk;
717       ++k;
718     } else if (aI[ak] < bI[bk]) {
719       L_[k] = aI[ak];
720       ++ak;
721       ++k;
722     } else {
723       L_[k] = bI[bk];
724       ++bk;
725       ++k;
726     }
727   }
728   if (ak < an) {
729     ierr = PetscMemcpy(L_+k,aI+ak,(an-ak)*sizeof(PetscInt));CHKERRQ(ierr);
730     k   += (an-ak);
731   }
732   if (bk < bn) {
733     ierr = PetscMemcpy(L_+k,bI+bk,(bn-bk)*sizeof(PetscInt));CHKERRQ(ierr);
734     k   += (bn-bk);
735   }
736   *n = k;
737   PetscFunctionReturn(0);
738 }
739 
740 /*@
741    PetscMergeIntArrayPair -     Merges two SORTED integer arrays that share NO common values along with an additional array of integers.
742                                 The additional arrays are the same length as sorted arrays and are merged
743                                 in the order determined by the merging of the sorted pair.
744 
745    Not Collective
746 
747    Input Parameters:
748 +  an  - number of values in the first array
749 .  aI  - first sorted array of integers
750 .  aJ  - first additional array of integers
751 .  bn  - number of values in the second array
752 .  bI  - second array of integers
753 -  bJ  - second additional of integers
754 
755    Output Parameters:
756 +  n   - number of values in the merged array (== an + bn)
757 .  L   - merged sorted array
758 -  J   - merged additional array
759 
760    Notes: 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
761    Level: intermediate
762 
763    Concepts: merging^arrays
764 
765 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
766 @*/
767 PetscErrorCode  PetscMergeIntArrayPair(PetscInt an,const PetscInt aI[], const PetscInt aJ[], PetscInt bn, const PetscInt bI[], const PetscInt bJ[], PetscInt *n, PetscInt **L, PetscInt **J)
768 {
769   PetscErrorCode ierr;
770   PetscInt       n_, *L_, *J_, ak, bk, k;
771 
772   PetscFunctionBegin;
773   PetscValidIntPointer(L,8);
774   PetscValidIntPointer(J,9);
775   n_ = an + bn;
776   *n = n_;
777   if (!*L) {
778     ierr = PetscMalloc1(n_, L);CHKERRQ(ierr);
779   }
780   L_ = *L;
781   if (!*J) {
782     ierr = PetscMalloc1(n_, J);CHKERRQ(ierr);
783   }
784   J_   = *J;
785   k = ak = bk = 0;
786   while (ak < an && bk < bn) {
787     if (aI[ak] <= bI[bk]) {
788       L_[k] = aI[ak];
789       J_[k] = aJ[ak];
790       ++ak;
791       ++k;
792     } else {
793       L_[k] = bI[bk];
794       J_[k] = bJ[bk];
795       ++bk;
796       ++k;
797     }
798   }
799   if (ak < an) {
800     ierr = PetscMemcpy(L_+k,aI+ak,(an-ak)*sizeof(PetscInt));CHKERRQ(ierr);
801     ierr = PetscMemcpy(J_+k,aJ+ak,(an-ak)*sizeof(PetscInt));CHKERRQ(ierr);
802     k   += (an-ak);
803   }
804   if (bk < bn) {
805     ierr = PetscMemcpy(L_+k,bI+bk,(bn-bk)*sizeof(PetscInt));CHKERRQ(ierr);
806     ierr = PetscMemcpy(J_+k,bJ+bk,(bn-bk)*sizeof(PetscInt));CHKERRQ(ierr);
807   }
808   PetscFunctionReturn(0);
809 }
810 
811 /*@
812    PetscMergeMPIIntArray -     Merges two SORTED integer arrays.
813 
814    Not Collective
815 
816    Input Parameters:
817 +  an  - number of values in the first array
818 .  aI  - first sorted array of integers
819 .  bn  - number of values in the second array
820 -  bI  - second array of integers
821 
822    Output Parameters:
823 +  n   - number of values in the merged array (<= an + bn)
824 -  L   - merged sorted array, allocated if address of NULL pointer is passed
825 
826    Level: intermediate
827 
828    Concepts: merging^arrays
829 
830 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
831 @*/
832 PetscErrorCode PetscMergeMPIIntArray(PetscInt an,const PetscMPIInt aI[],PetscInt bn,const PetscMPIInt bI[],PetscInt *n,PetscMPIInt **L)
833 {
834   PetscErrorCode ierr;
835   PetscInt       ai,bi,k;
836 
837   PetscFunctionBegin;
838   if (!*L) {ierr = PetscMalloc1((an+bn),L);CHKERRQ(ierr);}
839   for (ai=0,bi=0,k=0; ai<an || bi<bn; ) {
840     PetscInt t = -1;
841     for ( ; ai<an && (!bn || aI[ai] <= bI[bi]); ai++) (*L)[k++] = t = aI[ai];
842     for ( ; bi<bn && bI[bi] == t; bi++);
843     for ( ; bi<bn && (!an || bI[bi] <= aI[ai]); bi++) (*L)[k++] = t = bI[bi];
844     for ( ; ai<an && aI[ai] == t; ai++);
845   }
846   *n = k;
847   PetscFunctionReturn(0);
848 }
849 
850 /*@C
851    PetscProcessTree - Prepares tree data to be displayed graphically
852 
853    Not Collective
854 
855    Input Parameters:
856 +  n  - number of values
857 .  mask - indicates those entries in the tree, location 0 is always masked
858 -  parentid - indicates the parent of each entry
859 
860    Output Parameters:
861 +  Nlevels - the number of levels
862 .  Level - for each node tells its level
863 .  Levelcnts - the number of nodes on each level
864 .  Idbylevel - a list of ids on each of the levels, first level followed by second etc
865 -  Column - for each id tells its column index
866 
867    Level: developer
868 
869    Notes: 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