1af0996ceSBarry Smith #include <petsc/private/petscimpl.h>
2665c2dedSJed Brown #include <petscviewer.h>
3d5731834SJed Brown
4d5731834SJed Brown typedef struct {
5d5731834SJed Brown PetscInt id;
6d5731834SJed Brown PetscInt value;
7d5731834SJed Brown } HeapNode;
8d5731834SJed Brown
9ce78bad3SBarry Smith struct _n_PetscHeap {
10d5731834SJed Brown PetscInt end; /* one past the last item */
11d5731834SJed Brown PetscInt alloc; /* length of array */
12d5731834SJed Brown PetscInt stash; /* stash grows down, this points to last item */
13d5731834SJed Brown HeapNode *base;
14d5731834SJed Brown };
15d5731834SJed Brown
1644ee04a4SJed Brown /*
172ef1f0ffSBarry Smith The arity of the heap can be changed via the parameter B below. Consider the B=2 (arity=4 case below)
182ef1f0ffSBarry Smith
192ef1f0ffSBarry Smith [00 (sentinel); 01 (min node); 10 (unused); 11 (unused); 0100 (first child); 0101; 0110; 0111; ...]
202ef1f0ffSBarry Smith
212ef1f0ffSBarry Smith Slots 10 and 11 are referred to as the "hole" below in the implementation.
2244ee04a4SJed Brown */
2344ee04a4SJed Brown
2444ee04a4SJed Brown #define B 1 /* log2(ARITY) */
2544ee04a4SJed Brown #define ARITY (1 << B) /* tree branching factor */
Parent(PetscInt loc)26d71ae5a4SJacob Faibussowitsch static inline PetscInt Parent(PetscInt loc)
27d71ae5a4SJacob Faibussowitsch {
2844ee04a4SJed Brown PetscInt p = loc >> B;
2944ee04a4SJed Brown if (p < ARITY) return (PetscInt)(loc != 1); /* Parent(1) is 0, otherwise fix entries ending up in the hole */
3044ee04a4SJed Brown return p;
3144ee04a4SJed Brown }
32d5731834SJed Brown #define Value(h, loc) ((h)->base[loc].value)
33d5731834SJed Brown #define Id(h, loc) ((h)->base[loc].id)
34d5731834SJed Brown
Swap(PetscHeap h,PetscInt loc,PetscInt loc2)35d71ae5a4SJacob Faibussowitsch static inline void Swap(PetscHeap h, PetscInt loc, PetscInt loc2)
36d71ae5a4SJacob Faibussowitsch {
37d5731834SJed Brown PetscInt id, val;
38d5731834SJed Brown id = Id(h, loc);
39d5731834SJed Brown val = Value(h, loc);
40d5731834SJed Brown h->base[loc].id = Id(h, loc2);
41d5731834SJed Brown h->base[loc].value = Value(h, loc2);
42d5731834SJed Brown h->base[loc2].id = id;
43d5731834SJed Brown h->base[loc2].value = val;
44d5731834SJed Brown }
MinChild(PetscHeap h,PetscInt loc)45d71ae5a4SJacob Faibussowitsch static inline PetscInt MinChild(PetscHeap h, PetscInt loc)
46d71ae5a4SJacob Faibussowitsch {
4744ee04a4SJed Brown PetscInt min, chld, left, right;
4844ee04a4SJed Brown left = loc << B;
4944ee04a4SJed Brown right = PetscMin(left + ARITY - 1, h->end - 1);
5044ee04a4SJed Brown chld = 0;
511690c2aeSBarry Smith min = PETSC_INT_MAX;
5244ee04a4SJed Brown for (; left <= right; left++) {
5344ee04a4SJed Brown PetscInt val = Value(h, left);
5444ee04a4SJed Brown if (val < min) {
5544ee04a4SJed Brown min = val;
5644ee04a4SJed Brown chld = left;
5744ee04a4SJed Brown }
5844ee04a4SJed Brown }
5944ee04a4SJed Brown return chld;
60d5731834SJed Brown }
61d5731834SJed Brown
PetscHeapCreate(PetscInt maxsize,PetscHeap * heap)62d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscHeapCreate(PetscInt maxsize, PetscHeap *heap)
63d71ae5a4SJacob Faibussowitsch {
64d5731834SJed Brown PetscHeap h;
65d5731834SJed Brown
66d5731834SJed Brown PetscFunctionBegin;
670298fd71SBarry Smith *heap = NULL;
689566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(1, &h));
69d5731834SJed Brown h->end = 1;
7044ee04a4SJed Brown h->alloc = maxsize + ARITY; /* We waste all but one slot (loc=1) in the first ARITY slots */
71d5731834SJed Brown h->stash = h->alloc;
729566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(h->alloc, &h->base));
73d5731834SJed Brown h->base[0].id = -1;
741690c2aeSBarry Smith h->base[0].value = PETSC_INT_MIN;
75d5731834SJed Brown *heap = h;
763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
77d5731834SJed Brown }
78d5731834SJed Brown
PetscHeapAdd(PetscHeap h,PetscInt id,PetscInt val)79d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscHeapAdd(PetscHeap h, PetscInt id, PetscInt val)
80d71ae5a4SJacob Faibussowitsch {
8144ee04a4SJed Brown PetscInt loc, par;
82d5731834SJed Brown
83d5731834SJed Brown PetscFunctionBegin;
8444ee04a4SJed Brown if (1 < h->end && h->end < ARITY) h->end = ARITY;
85d5731834SJed Brown loc = h->end++;
8657508eceSPierre Jolivet PetscCheck(h->end <= h->stash, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Addition would exceed allocation %" PetscInt_FMT " (%" PetscInt_FMT " stashed)", h->alloc, h->alloc - h->stash);
87d5731834SJed Brown h->base[loc].id = id;
88d5731834SJed Brown h->base[loc].value = val;
89d5731834SJed Brown
90d5731834SJed Brown /* move up until heap condition is satisfied */
91527e7439SSatish Balay while ((void)(par = Parent(loc)), Value(h, par) > val) {
9244ee04a4SJed Brown Swap(h, loc, par);
9344ee04a4SJed Brown loc = par;
94d5731834SJed Brown }
953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
96d5731834SJed Brown }
97d5731834SJed Brown
PetscHeapPop(PetscHeap h,PetscInt * id,PetscInt * val)98d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscHeapPop(PetscHeap h, PetscInt *id, PetscInt *val)
99d71ae5a4SJacob Faibussowitsch {
100d5731834SJed Brown PetscInt loc, chld;
101d5731834SJed Brown
102d5731834SJed Brown PetscFunctionBegin;
103d5731834SJed Brown if (h->end == 1) {
104d5731834SJed Brown *id = h->base[0].id;
105d5731834SJed Brown *val = h->base[0].value;
1063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
107d5731834SJed Brown }
108d5731834SJed Brown
109d5731834SJed Brown *id = h->base[1].id;
110d5731834SJed Brown *val = h->base[1].value;
111d5731834SJed Brown
112d5731834SJed Brown /* rotate last entry into first position */
113d5731834SJed Brown loc = --h->end;
11444ee04a4SJed Brown if (h->end == ARITY) h->end = 2; /* Skip over hole */
115d5731834SJed Brown h->base[1].id = Id(h, loc);
116d5731834SJed Brown h->base[1].value = Value(h, loc);
117d5731834SJed Brown
118d5731834SJed Brown /* move down until min heap condition is satisfied */
119d5731834SJed Brown loc = 1;
120d5731834SJed Brown while ((chld = MinChild(h, loc)) && Value(h, loc) > Value(h, chld)) {
121d5731834SJed Brown Swap(h, loc, chld);
122d5731834SJed Brown loc = chld;
123d5731834SJed Brown }
1243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
125d5731834SJed Brown }
126d5731834SJed Brown
PetscHeapPeek(PetscHeap h,PetscInt * id,PetscInt * val)127d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscHeapPeek(PetscHeap h, PetscInt *id, PetscInt *val)
128d71ae5a4SJacob Faibussowitsch {
129d5731834SJed Brown PetscFunctionBegin;
130d5731834SJed Brown if (h->end == 1) {
131d5731834SJed Brown *id = h->base[0].id;
132d5731834SJed Brown *val = h->base[0].value;
1333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
134d5731834SJed Brown }
135d5731834SJed Brown
136d5731834SJed Brown *id = h->base[1].id;
137d5731834SJed Brown *val = h->base[1].value;
1383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
139d5731834SJed Brown }
140d5731834SJed Brown
PetscHeapStash(PetscHeap h,PetscInt id,PetscInt val)141d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscHeapStash(PetscHeap h, PetscInt id, PetscInt val)
142d71ae5a4SJacob Faibussowitsch {
143d5731834SJed Brown PetscInt loc;
144d5731834SJed Brown
145d5731834SJed Brown PetscFunctionBegin;
146d5731834SJed Brown loc = --h->stash;
147d5731834SJed Brown h->base[loc].id = id;
148d5731834SJed Brown h->base[loc].value = val;
1493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
150d5731834SJed Brown }
151d5731834SJed Brown
PetscHeapUnstash(PetscHeap h)152d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscHeapUnstash(PetscHeap h)
153d71ae5a4SJacob Faibussowitsch {
154d5731834SJed Brown PetscFunctionBegin;
155d5731834SJed Brown while (h->stash < h->alloc) {
156d5731834SJed Brown PetscInt id = Id(h, h->stash), value = Value(h, h->stash);
157d5731834SJed Brown h->stash++;
1589566063dSJacob Faibussowitsch PetscCall(PetscHeapAdd(h, id, value));
159d5731834SJed Brown }
1603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
161d5731834SJed Brown }
162d5731834SJed Brown
PetscHeapDestroy(PetscHeap * heap)163d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscHeapDestroy(PetscHeap *heap)
164d71ae5a4SJacob Faibussowitsch {
165d5731834SJed Brown PetscFunctionBegin;
1669566063dSJacob Faibussowitsch PetscCall(PetscFree((*heap)->base));
1679566063dSJacob Faibussowitsch PetscCall(PetscFree(*heap));
1683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
169d5731834SJed Brown }
170d5731834SJed Brown
PetscHeapView(PetscHeap h,PetscViewer viewer)171d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscHeapView(PetscHeap h, PetscViewer viewer)
172d71ae5a4SJacob Faibussowitsch {
173*9f196a02SMartin Diehl PetscBool isascii;
174d5731834SJed Brown
175d5731834SJed Brown PetscFunctionBegin;
17648a46eb9SPierre Jolivet if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_SELF, &viewer));
177d5731834SJed Brown PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
178*9f196a02SMartin Diehl PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
179*9f196a02SMartin Diehl if (isascii) {
1809566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Heap size %" PetscInt_FMT " with %" PetscInt_FMT " stashed\n", h->end - 1, h->alloc - h->stash));
1819566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Heap in (id,value) pairs\n"));
1829566063dSJacob Faibussowitsch PetscCall(PetscIntView(2 * (h->end - 1), (const PetscInt *)(h->base + 1), viewer));
1839566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Stash in (id,value) pairs\n"));
1849566063dSJacob Faibussowitsch PetscCall(PetscIntView(2 * (h->alloc - h->stash), (const PetscInt *)(h->base + h->stash), viewer));
185d5731834SJed Brown }
1863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
187d5731834SJed Brown }
188