xref: /petsc/src/mat/utils/pheap.c (revision 27aa7340ca9f5aec230511b1b22ffadb73880b07)
1 #include <../src/mat/utils/petscheap.h>
2 
3 typedef struct {
4   PetscInt id;
5   PetscInt value;
6 } HeapNode;
7 
8 struct _PetscHeap {
9   PetscInt end;                 /* one past the last item */
10   PetscInt alloc;               /* length of array */
11   PetscInt stash;               /* stash grows down, this points to last item */
12   HeapNode *base;
13 };
14 
15 /*
16  * The arity of the heap can be changed via the parameter B below. Consider the B=2 (arity=4 case below)
17  *
18  * [00 (sentinel); 01 (min node); 10 (unused); 11 (unused); 0100 (first child); 0101; 0110; 0111; ...]
19  *
20  * Slots 10 and 11 are referred to as the "hole" below in the implementation.
21  */
22 
23 #define B 1                     /* log2(ARITY) */
24 #define ARITY (1 << B)          /* tree branching factor */
25 PETSC_STATIC_INLINE PetscInt Parent(PetscInt loc) {
26   PetscInt p = loc >> B;
27   if (p < ARITY) return (PetscInt)(loc != 1);             /* Parent(1) is 0, otherwise fix entries ending up in the hole */
28   return p;
29 }
30 #define Value(h,loc) ((h)->base[loc].value)
31 #define Id(h,loc)  ((h)->base[loc].id)
32 
33 PETSC_STATIC_INLINE void Swap(PetscHeap h,PetscInt loc,PetscInt loc2) {
34   PetscInt id,val;
35   id = Id(h,loc);
36   val = Value(h,loc);
37   h->base[loc].id = Id(h,loc2);
38   h->base[loc].value = Value(h,loc2);
39   h->base[loc2].id = id;
40   h->base[loc2].value = val;
41 }
42 PETSC_STATIC_INLINE PetscInt MinChild(PetscHeap h,PetscInt loc) {
43   PetscInt min,chld,left,right;
44   left = loc << B;
45   right = PetscMin(left+ARITY-1,h->end-1);
46   chld = 0;
47   min = PETSC_MAX_INT;
48   for ( ; left <= right; left++) {
49     PetscInt val = Value(h,left);
50     if (val < min) {
51       min = val;
52       chld = left;
53     }
54   }
55   return chld;
56 }
57 
58 #undef __FUNCT__
59 #define __FUNCT__ "PetscHeapCreate"
60 PetscErrorCode PetscHeapCreate(PetscInt maxsize,PetscHeap *heap)
61 {
62   PetscErrorCode ierr;
63   PetscHeap h;
64 
65   PetscFunctionBegin;
66   *heap = PETSC_NULL;
67   ierr = PetscMalloc(sizeof *h,&h);CHKERRQ(ierr);
68   h->end = 1;
69   h->alloc = maxsize+ARITY;     /* We waste all but one slot (loc=1) in the first ARITY slots */
70   h->stash = h->alloc;
71   ierr = PetscMalloc(h->alloc*sizeof(HeapNode),&h->base);CHKERRQ(ierr);
72   ierr = PetscMemzero(h->base,h->alloc*sizeof(HeapNode));CHKERRQ(ierr);
73   h->base[0].id    = -1;
74   h->base[0].value = PETSC_MIN_INT;
75   *heap = h;
76   PetscFunctionReturn(0);
77 }
78 
79 #undef __FUNCT__
80 #define __FUNCT__ "PetscHeapAdd"
81 PetscErrorCode PetscHeapAdd(PetscHeap h,PetscInt id,PetscInt val)
82 {
83   PetscInt loc,par;
84 
85   PetscFunctionBegin;
86   if (1 < h->end && h->end < ARITY) h->end = ARITY;
87   loc = h->end++;
88   if (h->end > h->stash) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Addition would exceed allocation %D (%D stashed)",h->alloc,(h->alloc-h->stash));
89   h->base[loc].id    = id;
90   h->base[loc].value = val;
91 
92   /* move up until heap condition is satisfied */
93   while (par = Parent(loc), Value(h,par) > val) {
94     Swap(h,loc,par);
95     loc = par;
96   }
97   PetscFunctionReturn(0);
98 }
99 
100 #undef __FUNCT__
101 #define __FUNCT__ "PetscHeapPop"
102 PetscErrorCode PetscHeapPop(PetscHeap h,PetscInt *id,PetscInt *val)
103 {
104   PetscInt loc,chld;
105 
106   PetscFunctionBegin;
107   if (h->end == 1) {
108     *id = h->base[0].id;
109     *val = h->base[0].value;
110     PetscFunctionReturn(0);
111   }
112 
113   *id = h->base[1].id;
114   *val = h->base[1].value;
115 
116   /* rotate last entry into first position */
117   loc = --h->end;
118   if (h->end == ARITY) h->end = 2; /* Skip over hole */
119   h->base[1].id   = Id(h,loc);
120   h->base[1].value = Value(h,loc);
121 
122   /* move down until min heap condition is satisfied */
123   loc = 1;
124   while ((chld = MinChild(h,loc)) && Value(h,loc) > Value(h,chld)) {
125     Swap(h,loc,chld);
126     loc = chld;
127   }
128   PetscFunctionReturn(0);
129 }
130 
131 #undef __FUNCT__
132 #define __FUNCT__ "PetscHeapPeek"
133 PetscErrorCode PetscHeapPeek(PetscHeap h,PetscInt *id,PetscInt *val)
134 {
135   PetscFunctionBegin;
136   if (h->end == 1) {
137     *id = h->base[0].id;
138     *val = h->base[0].value;
139     PetscFunctionReturn(0);
140   }
141 
142   *id = h->base[1].id;
143   *val = h->base[1].value;
144   PetscFunctionReturn(0);
145 }
146 
147 #undef __FUNCT__
148 #define __FUNCT__ "PetscHeapStash"
149 PetscErrorCode PetscHeapStash(PetscHeap h,PetscInt id,PetscInt val)
150 {
151   PetscInt loc;
152 
153   PetscFunctionBegin;
154   loc = --h->stash;
155   h->base[loc].id = id;
156   h->base[loc].value = val;
157   PetscFunctionReturn(0);
158 }
159 
160 #undef __FUNCT__
161 #define __FUNCT__ "PetscHeapUnstash"
162 PetscErrorCode PetscHeapUnstash(PetscHeap h)
163 {
164   PetscErrorCode ierr;
165 
166   PetscFunctionBegin;
167   while (h->stash < h->alloc) {
168     PetscInt id = Id(h,h->stash),value = Value(h,h->stash);
169     h->stash++;
170     ierr = PetscHeapAdd(h,id,value);CHKERRQ(ierr);
171   }
172   PetscFunctionReturn(0);
173 }
174 
175 #undef __FUNCT__
176 #define __FUNCT__ "PetscHeapDestroy"
177 PetscErrorCode PetscHeapDestroy(PetscHeap *heap)
178 {
179   PetscErrorCode ierr;
180 
181   PetscFunctionBegin;
182   ierr = PetscFree((*heap)->base);CHKERRQ(ierr);
183   ierr = PetscFree(*heap);CHKERRQ(ierr);
184   PetscFunctionReturn(0);
185 }
186 
187 #undef __FUNCT__
188 #define __FUNCT__ "PetscHeapView"
189 PetscErrorCode PetscHeapView(PetscHeap h,PetscViewer viewer)
190 {
191   PetscErrorCode ierr;
192   PetscBool iascii;
193 
194   PetscFunctionBegin;
195   if (!viewer) {
196     ierr = PetscViewerASCIIGetStdout(PETSC_COMM_SELF,&viewer);CHKERRQ(ierr);
197   }
198   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
199   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
200   if (iascii) {
201     ierr = PetscViewerASCIIPrintf(viewer,"Heap size %D with %D stashed\n",h->end-1,h->alloc-h->stash);CHKERRQ(ierr);
202     ierr = PetscViewerASCIIPrintf(viewer,"Heap in (id,value) pairs\n");CHKERRQ(ierr);
203     ierr = PetscIntView(2*(h->end-1),(const PetscInt*)(h->base+1),viewer);CHKERRQ(ierr);
204     ierr = PetscViewerASCIIPrintf(viewer,"Stash in (id,value) pairs\n");CHKERRQ(ierr);
205     ierr = PetscIntView(2*(h->alloc-h->stash),(const PetscInt*)(h->base+h->stash),viewer);CHKERRQ(ierr);
206   }
207   PetscFunctionReturn(0);
208 }
209