xref: /petsc/src/sys/utils/sorti.c (revision 84df9cb40eca90ea9b18a456fab7a4ecc7f6c1a4)
1 
2 /*
3    This file contains routines for sorting integers. Values are sorted in place.
4  */
5 #include <petscsys.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 #undef __FUNCT__
23 #define __FUNCT__ "PetscSortInt_Private"
24 /*
25    A simple version of quicksort; taken from Kernighan and Ritchie, page 87.
26    Assumes 0 origin for v, number of elements = right+1 (right is index of
27    right-most member).
28 */
29 static void PetscSortInt_Private(PetscInt *v,PetscInt right)
30 {
31   PetscInt       i,j,pivot,tmp;
32 
33   if (right <= 1) {
34     if (right == 1) {
35       if (v[0] > v[1]) SWAP(v[0],v[1],tmp);
36     }
37     return;
38   }
39   i = MEDIAN(v,right);          /* Choose a pivot */
40   SWAP(v[0],v[i],tmp);          /* Move it out of the way */
41   pivot = v[0];
42   for (i=0,j=right+1;;) {
43     while (++i < j && v[i] <= pivot); /* Scan from the left */
44     while (v[--j] > pivot);           /* Scan from the right */
45     if (i >= j) break;
46     SWAP(v[i],v[j],tmp);
47   }
48   SWAP(v[0],v[j],tmp);          /* Put pivot back in place. */
49   PetscSortInt_Private(v,j-1);
50   PetscSortInt_Private(v+j+1,right-(j+1));
51 }
52 
53 #undef __FUNCT__
54 #define __FUNCT__ "PetscSortInt"
55 /*@
56    PetscSortInt - Sorts an array of integers in place in increasing order.
57 
58    Not Collective
59 
60    Input Parameters:
61 +  n  - number of values
62 -  i  - array of integers
63 
64    Level: intermediate
65 
66    Concepts: sorting^ints
67 
68 .seealso: PetscSortReal(), PetscSortIntWithPermutation()
69 @*/
70 PetscErrorCode  PetscSortInt(PetscInt n,PetscInt i[])
71 {
72   PetscInt       j,k,tmp,ik;
73 
74   PetscFunctionBegin;
75   if (n<8) {
76     for (k=0; k<n; k++) {
77       ik = i[k];
78       for (j=k+1; j<n; j++) {
79 	if (ik > i[j]) {
80 	  SWAP(i[k],i[j],tmp);
81 	  ik = i[k];
82 	}
83       }
84     }
85   } else {
86     PetscSortInt_Private(i,n-1);
87   }
88   PetscFunctionReturn(0);
89 }
90 
91 #undef __FUNCT__
92 #define __FUNCT__ "PetscSortRemoveDupsInt"
93 /*@
94    PetscSortRemoveDupsInt - Sorts an array of integers in place in increasing order removes all duplicate entries
95 
96    Not Collective
97 
98    Input Parameters:
99 +  n  - number of values
100 -  ii  - array of integers
101 
102    Output Parameter:
103 .  n - number of non-redundant values
104 
105    Level: intermediate
106 
107    Concepts: sorting^ints
108 
109 .seealso: PetscSortReal(), PetscSortIntWithPermutation(), PetscSortInt()
110 @*/
111 PetscErrorCode  PetscSortRemoveDupsInt(PetscInt *n,PetscInt ii[])
112 {
113   PetscErrorCode ierr;
114   PetscInt       i,s = 0,N = *n, b = 0;
115 
116   PetscFunctionBegin;
117   ierr = PetscSortInt(N,ii);CHKERRQ(ierr);
118   for (i=0; i<N-1; i++) {
119     if (ii[b+s+1] != ii[b]) {ii[b+1] = ii[b+s+1]; b++;}
120     else s++;
121   }
122   *n = N - s;
123   PetscFunctionReturn(0);
124 }
125 
126 
127 /* -----------------------------------------------------------------------*/
128 #define SWAP2(a,b,c,d,t) {t=a;a=b;b=t;t=c;c=d;d=t;}
129 
130 #undef __FUNCT__
131 #define __FUNCT__ "PetscSortIntWithArray_Private"
132 /*
133    A simple version of quicksort; taken from Kernighan and Ritchie, page 87.
134    Assumes 0 origin for v, number of elements = right+1 (right is index of
135    right-most member).
136 */
137 static PetscErrorCode PetscSortIntWithArray_Private(PetscInt *v,PetscInt *V,PetscInt right)
138 {
139   PetscErrorCode ierr;
140   PetscInt       i,vl,last,tmp;
141 
142   PetscFunctionBegin;
143   if (right <= 1) {
144     if (right == 1) {
145       if (v[0] > v[1]) SWAP2(v[0],v[1],V[0],V[1],tmp);
146     }
147     PetscFunctionReturn(0);
148   }
149   SWAP2(v[0],v[right/2],V[0],V[right/2],tmp);
150   vl   = v[0];
151   last = 0;
152   for (i=1; i<=right; i++) {
153     if (v[i] < vl) {last++; SWAP2(v[last],v[i],V[last],V[i],tmp);}
154   }
155   SWAP2(v[0],v[last],V[0],V[last],tmp);
156   ierr = PetscSortIntWithArray_Private(v,V,last-1);CHKERRQ(ierr);
157   ierr = PetscSortIntWithArray_Private(v+last+1,V+last+1,right-(last+1));CHKERRQ(ierr);
158   PetscFunctionReturn(0);
159 }
160 
161 #undef __FUNCT__
162 #define __FUNCT__ "PetscSortIntWithArray"
163 /*@
164    PetscSortIntWithArray - Sorts an array of integers in place in increasing order;
165        changes a second array to match the sorted first array.
166 
167    Not Collective
168 
169    Input Parameters:
170 +  n  - number of values
171 .  i  - array of integers
172 -  I - second array of integers
173 
174    Level: intermediate
175 
176    Concepts: sorting^ints with array
177 
178 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt()
179 @*/
180 PetscErrorCode  PetscSortIntWithArray(PetscInt n,PetscInt i[],PetscInt Ii[])
181 {
182   PetscErrorCode ierr;
183   PetscInt       j,k,tmp,ik;
184 
185   PetscFunctionBegin;
186   if (n<8) {
187     for (k=0; k<n; k++) {
188       ik = i[k];
189       for (j=k+1; j<n; j++) {
190 	if (ik > i[j]) {
191 	  SWAP2(i[k],i[j],Ii[k],Ii[j],tmp);
192 	  ik = i[k];
193 	}
194       }
195     }
196   } else {
197     ierr = PetscSortIntWithArray_Private(i,Ii,n-1);CHKERRQ(ierr);
198   }
199   PetscFunctionReturn(0);
200 }
201 
202 
203 #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;}
204 
205 #undef __FUNCT__
206 #define __FUNCT__ "PetscSortIntWithArrayPair_Private"
207 /*
208    A simple version of quicksort; taken from Kernighan and Ritchie, page 87.
209    Assumes 0 origin for v, number of elements = right+1 (right is index of
210    right-most member).
211 */
212 static PetscErrorCode PetscSortIntWithArrayPair_Private(PetscInt *I,PetscInt *J, PetscInt *K, PetscInt right)
213 {
214   PetscErrorCode ierr;
215   PetscInt       i,vl,last,tmp;
216 
217   PetscFunctionBegin;
218   if (right <= 1) {
219     if (right == 1) {
220       if (I[0] > I[1]) SWAP3(I[0],I[1],J[0],J[1],K[0],K[1],tmp);
221     }
222     PetscFunctionReturn(0);
223   }
224   SWAP3(I[0],I[right/2],J[0],J[right/2],K[0],K[right/2],tmp);
225   vl   = I[0];
226   last = 0;
227   for (i=1; i<=right; i++) {
228     if (I[i] < vl) {last++; SWAP3(I[last],I[i],J[last],J[i],K[last],K[i],tmp);}
229   }
230   SWAP3(I[0],I[last],J[0],J[last],K[0],K[last],tmp);
231   ierr = PetscSortIntWithArrayPair_Private(I,J,K,last-1);CHKERRQ(ierr);
232   ierr = PetscSortIntWithArrayPair_Private(I+last+1,J+last+1,K+last+1,right-(last+1));CHKERRQ(ierr);
233   PetscFunctionReturn(0);
234 }
235 
236 #undef __FUNCT__
237 #define __FUNCT__ "PetscSortIntWithArrayPair"
238 /*@
239    PetscSortIntWithArrayPair - Sorts an array of integers in place in increasing order;
240        changes a pair of integer arrays to match the sorted first array.
241 
242    Not Collective
243 
244    Input Parameters:
245 +  n  - number of values
246 .  I  - array of integers
247 .  J  - second array of integers (first array of the pair)
248 -  K  - third array of integers  (second array of the pair)
249 
250    Level: intermediate
251 
252    Concepts: sorting^ints with array pair
253 
254 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortIntWithArray()
255 @*/
256 PetscErrorCode  PetscSortIntWithArrayPair(PetscInt n,PetscInt I[],PetscInt J[], PetscInt K[])
257 {
258   PetscErrorCode ierr;
259   PetscInt       j,k,tmp,ik;
260 
261   PetscFunctionBegin;
262   if (n<8) {
263     for (k=0; k<n; k++) {
264       ik = I[k];
265       for (j=k+1; j<n; j++) {
266 	if (ik > I[j]) {
267 	  SWAP3(I[k],I[j],J[k],J[j],K[k],K[j],tmp);
268 	  ik = I[k];
269 	}
270       }
271     }
272   } else {
273     ierr = PetscSortIntWithArrayPair_Private(I,J,K,n-1);CHKERRQ(ierr);
274   }
275   PetscFunctionReturn(0);
276 }
277 
278 
279 #undef __FUNCT__
280 #define __FUNCT__ "PetscSortMPIIntWithArray_Private"
281 /*
282    A simple version of quicksort; taken from Kernighan and Ritchie, page 87.
283    Assumes 0 origin for v, number of elements = right+1 (right is index of
284    right-most member).
285 */
286 static PetscErrorCode PetscSortMPIIntWithArray_Private(PetscMPIInt *v,PetscMPIInt *V,PetscMPIInt right)
287 {
288   PetscErrorCode ierr;
289   PetscMPIInt    i,vl,last,tmp;
290 
291   PetscFunctionBegin;
292   if (right <= 1) {
293     if (right == 1) {
294       if (v[0] > v[1]) SWAP2(v[0],v[1],V[0],V[1],tmp);
295     }
296     PetscFunctionReturn(0);
297   }
298   SWAP2(v[0],v[right/2],V[0],V[right/2],tmp);
299   vl   = v[0];
300   last = 0;
301   for (i=1; i<=right; i++) {
302     if (v[i] < vl) {last++; SWAP2(v[last],v[i],V[last],V[i],tmp);}
303   }
304   SWAP2(v[0],v[last],V[0],V[last],tmp);
305   ierr = PetscSortMPIIntWithArray_Private(v,V,last-1);CHKERRQ(ierr);
306   ierr = PetscSortMPIIntWithArray_Private(v+last+1,V+last+1,right-(last+1));CHKERRQ(ierr);
307   PetscFunctionReturn(0);
308 }
309 
310 #undef __FUNCT__
311 #define __FUNCT__ "PetscSortMPIIntWithArray"
312 /*@
313    PetscSortMPIIntWithArray - Sorts an array of integers in place in increasing order;
314        changes a second array to match the sorted first array.
315 
316    Not Collective
317 
318    Input Parameters:
319 +  n  - number of values
320 .  i  - array of integers
321 -  I - second array of integers
322 
323    Level: intermediate
324 
325    Concepts: sorting^ints with array
326 
327 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt()
328 @*/
329 PetscErrorCode  PetscSortMPIIntWithArray(PetscMPIInt n,PetscMPIInt i[],PetscMPIInt Ii[])
330 {
331   PetscErrorCode ierr;
332   PetscMPIInt    j,k,tmp,ik;
333 
334   PetscFunctionBegin;
335   if (n<8) {
336     for (k=0; k<n; k++) {
337       ik = i[k];
338       for (j=k+1; j<n; j++) {
339 	if (ik > i[j]) {
340 	  SWAP2(i[k],i[j],Ii[k],Ii[j],tmp);
341 	  ik = i[k];
342 	}
343       }
344     }
345   } else {
346     ierr = PetscSortMPIIntWithArray_Private(i,Ii,n-1);CHKERRQ(ierr);
347   }
348   PetscFunctionReturn(0);
349 }
350 
351 /* -----------------------------------------------------------------------*/
352 #define SWAP2IntScalar(a,b,c,d,t,ts) {t=a;a=b;b=t;ts=c;c=d;d=ts;}
353 
354 #undef __FUNCT__
355 #define __FUNCT__ "PetscSortIntWithScalarArray_Private"
356 /*
357    Modified from PetscSortIntWithArray_Private().
358 */
359 static PetscErrorCode PetscSortIntWithScalarArray_Private(PetscInt *v,PetscScalar *V,PetscInt right)
360 {
361   PetscErrorCode ierr;
362   PetscInt       i,vl,last,tmp;
363   PetscScalar    stmp;
364 
365   PetscFunctionBegin;
366   if (right <= 1) {
367     if (right == 1) {
368       if (v[0] > v[1]) SWAP2IntScalar(v[0],v[1],V[0],V[1],tmp,stmp);
369     }
370     PetscFunctionReturn(0);
371   }
372   SWAP2IntScalar(v[0],v[right/2],V[0],V[right/2],tmp,stmp);
373   vl   = v[0];
374   last = 0;
375   for (i=1; i<=right; i++) {
376     if (v[i] < vl) {last++; SWAP2IntScalar(v[last],v[i],V[last],V[i],tmp,stmp);}
377   }
378   SWAP2IntScalar(v[0],v[last],V[0],V[last],tmp,stmp);
379   ierr = PetscSortIntWithScalarArray_Private(v,V,last-1);CHKERRQ(ierr);
380   ierr = PetscSortIntWithScalarArray_Private(v+last+1,V+last+1,right-(last+1));CHKERRQ(ierr);
381   PetscFunctionReturn(0);
382 }
383 
384 #undef __FUNCT__
385 #define __FUNCT__ "PetscSortIntWithScalarArray"
386 /*@
387    PetscSortIntWithScalarArray - Sorts an array of integers in place in increasing order;
388        changes a second SCALAR array to match the sorted first INTEGER array.
389 
390    Not Collective
391 
392    Input Parameters:
393 +  n  - number of values
394 .  i  - array of integers
395 -  I - second array of scalars
396 
397    Level: intermediate
398 
399    Concepts: sorting^ints with array
400 
401 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
402 @*/
403 PetscErrorCode  PetscSortIntWithScalarArray(PetscInt n,PetscInt i[],PetscScalar Ii[])
404 {
405   PetscErrorCode ierr;
406   PetscInt       j,k,tmp,ik;
407   PetscScalar    stmp;
408 
409   PetscFunctionBegin;
410   if (n<8) {
411     for (k=0; k<n; k++) {
412       ik = i[k];
413       for (j=k+1; j<n; j++) {
414 	if (ik > i[j]) {
415 	  SWAP2IntScalar(i[k],i[j],Ii[k],Ii[j],tmp,stmp);
416 	  ik = i[k];
417 	}
418       }
419     }
420   } else {
421     ierr = PetscSortIntWithScalarArray_Private(i,Ii,n-1);CHKERRQ(ierr);
422   }
423   PetscFunctionReturn(0);
424 }
425 
426 #undef __FUNCT__
427 #define __FUNCT__ "PetscMergeIntArrayPair"
428 /*@
429    PetscMergeIntArrayPair -     Merges two SORTED integer arrays along with an additional array of integers.
430                                 The additional arrays are the same length as sorted arrays and are merged
431                                 in the order determined by the merging of the sorted pair.
432 
433    Not Collective
434 
435    Input Parameters:
436 +  an  - number of values in the first array
437 .  aI  - first sorted array of integers
438 .  aJ  - first additional array of integers
439 .  bn  - number of values in the second array
440 .  bI  - second array of integers
441 -  bJ  - second additional of integers
442 
443    Output Parameters:
444 +  n   - number of values in the merged array (== an + bn)
445 .  I   - merged sorted array
446 -  J   - merged additional array
447 
448    Level: intermediate
449 
450    Concepts: merging^arrays
451 
452 .seealso: PetscSortReal(), PetscSortIntPermutation(), PetscSortInt(), PetscSortIntWithArray()
453 @*/
454 PetscErrorCode  PetscMergeIntArrayPair(PetscInt an,const PetscInt aI[], const PetscInt aJ[], PetscInt bn, const PetscInt bI[], const PetscInt bJ[], PetscInt *n, PetscInt *I[], PetscInt *J[])
455 {
456   PetscErrorCode ierr;
457   PetscInt n_, *I_ = *I, *J_= *J, ak, bk, k;
458 
459   n_ = an + bn;
460   *n = n_;
461   if(!I_) {
462     ierr = PetscMalloc(n_*sizeof(PetscInt), I); CHKERRQ(ierr);
463     I_ = *I;
464   }
465   if(!J_){
466     ierr = PetscMalloc(n_*sizeof(PetscInt), &J_); CHKERRQ(ierr);
467     J_ = *J;
468   }
469   k = ak = bk = 0;
470   while(ak < an && bk < bn) {
471     if(aI[ak] <= bI[bk]) {
472       I_[k] = aI[ak];
473       J_[k] = aJ[ak];
474       ++ak;
475       ++k;
476     }
477     else {
478       I_[k] = bI[bk];
479       J_[k] = bJ[bk];
480       ++bk;
481       ++k;
482     }
483   }
484   if(ak < an) {
485     ierr = PetscMemcpy(I_+k,aI+ak,(an-ak)*sizeof(PetscInt)); CHKERRQ(ierr);
486     ierr = PetscMemcpy(J_+k,aJ+ak,(an-ak)*sizeof(PetscInt)); CHKERRQ(ierr);
487     k += (an-ak);
488   }
489   if(bk < bn) {
490     ierr = PetscMemcpy(I_+k,bI+bk,(bn-bk)*sizeof(PetscInt)); CHKERRQ(ierr);
491     ierr = PetscMemcpy(J_+k,bJ+bk,(bn-bk)*sizeof(PetscInt)); CHKERRQ(ierr);
492     k += (bn-bk);
493   }
494   PetscFunctionReturn(0);
495 }
496 
497 
498 #undef __FUNCT__
499 #define __FUNCT__ "PetscProcessTree"
500 /*@
501    PetscProcessTree - Prepares tree data to be displayed graphically
502 
503    Not Collective
504 
505    Input Parameters:
506 +  n  - number of values
507 .  mask - indicates those entries in the tree, location 0 is always masked
508 -  parentid - indicates the parent of each entry
509 
510    Output Parameters:
511 +  Nlevels - the number of levels
512 .  Level - for each node tells its level
513 .  Levelcnts - the number of nodes on each level
514 .  Idbylevel - a list of ids on each of the levels, first level followed by second etc
515 -  Column - for each id tells its column index
516 
517    Level: intermediate
518 
519 
520 .seealso: PetscSortReal(), PetscSortIntWithPermutation()
521 @*/
522 PetscErrorCode  PetscProcessTree(PetscInt n,const PetscBool  mask[],const PetscInt parentid[],PetscInt *Nlevels,PetscInt **Level,PetscInt **Levelcnt,PetscInt **Idbylevel,PetscInt **Column)
523 {
524   PetscInt       i,j,cnt,nmask = 0,nlevels = 0,*level,*levelcnt,levelmax = 0,*workid,*workparentid,tcnt = 0,*idbylevel,*column;
525   PetscErrorCode ierr;
526   PetscBool      done = PETSC_FALSE;
527 
528   PetscFunctionBegin;
529   if (!mask[0]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Mask of 0th location must be set");
530   for (i=0; i<n; i++) {
531     if (mask[i]) continue;
532     if (parentid[i]  == i) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Node labeled as own parent");
533     if (parentid[i] && mask[parentid[i]]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Parent is masked");
534   }
535 
536 
537   for (i=0; i<n; i++) {
538     if (!mask[i]) nmask++;
539   }
540 
541   /* determine the level in the tree of each node */
542   ierr = PetscMalloc(n*sizeof(PetscInt),&level);CHKERRQ(ierr);
543   ierr = PetscMemzero(level,n*sizeof(PetscInt));CHKERRQ(ierr);
544   level[0] = 1;
545   while (!done) {
546     done = PETSC_TRUE;
547     for (i=0; i<n; i++) {
548       if (mask[i]) continue;
549       if (!level[i] && level[parentid[i]]) level[i] = level[parentid[i]] + 1;
550       else if (!level[i]) done = PETSC_FALSE;
551     }
552   }
553   for (i=0; i<n; i++) {
554     level[i]--;
555     nlevels = PetscMax(nlevels,level[i]);
556   }
557 
558   /* count the number of nodes on each level and its max */
559   ierr = PetscMalloc(nlevels*sizeof(PetscInt),&levelcnt);CHKERRQ(ierr);
560   ierr = PetscMemzero(levelcnt,nlevels*sizeof(PetscInt));CHKERRQ(ierr);
561   for (i=0; i<n; i++) {
562     if (mask[i]) continue;
563     levelcnt[level[i]-1]++;
564   }
565   for (i=0; i<nlevels;i++) {
566     levelmax = PetscMax(levelmax,levelcnt[i]);
567   }
568 
569   /* for each level sort the ids by the parent id */
570   ierr = PetscMalloc2(levelmax,PetscInt,&workid,levelmax,PetscInt,&workparentid);CHKERRQ(ierr);
571   ierr = PetscMalloc(nmask*sizeof(PetscInt),&idbylevel);CHKERRQ(ierr);
572   for (j=1; j<=nlevels;j++) {
573     cnt = 0;
574     for (i=0; i<n; i++) {
575       if (mask[i]) continue;
576       if (level[i] != j) continue;
577       workid[cnt]         = i;
578       workparentid[cnt++] = parentid[i];
579     }
580     /*  PetscIntView(cnt,workparentid,0);
581     PetscIntView(cnt,workid,0);
582     ierr = PetscSortIntWithArray(cnt,workparentid,workid);CHKERRQ(ierr);
583     PetscIntView(cnt,workparentid,0);
584     PetscIntView(cnt,workid,0);*/
585     ierr = PetscMemcpy(idbylevel+tcnt,workid,cnt*sizeof(PetscInt));CHKERRQ(ierr);
586     tcnt += cnt;
587   }
588   if (tcnt != nmask) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Inconsistent count of unmasked nodes");
589   ierr = PetscFree2(workid,workparentid);CHKERRQ(ierr);
590 
591   /* for each node list its column */
592   ierr = PetscMalloc(n*sizeof(PetscInt),&column);CHKERRQ(ierr);
593   cnt = 0;
594   for (j=0; j<nlevels; j++) {
595     for (i=0; i<levelcnt[j]; i++) {
596       column[idbylevel[cnt++]] = i;
597     }
598   }
599 
600   *Nlevels   = nlevels;
601   *Level     = level;
602   *Levelcnt  = levelcnt;
603   *Idbylevel = idbylevel;
604   *Column    = column;
605   PetscFunctionReturn(0);
606 }
607