xref: /petsc/src/mat/utils/pheap.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
19962606eSBarry Smith 
2af0996ceSBarry Smith #include <petsc/private/petscimpl.h>
3665c2dedSJed Brown #include <petscviewer.h>
4d5731834SJed Brown 
5d5731834SJed Brown typedef struct {
6d5731834SJed Brown   PetscInt id;
7d5731834SJed Brown   PetscInt value;
8d5731834SJed Brown } HeapNode;
9d5731834SJed Brown 
10d5731834SJed Brown struct _PetscHeap {
11d5731834SJed Brown   PetscInt  end;   /* one past the last item */
12d5731834SJed Brown   PetscInt  alloc; /* length of array */
13d5731834SJed Brown   PetscInt  stash; /* stash grows down, this points to last item */
14d5731834SJed Brown   HeapNode *base;
15d5731834SJed Brown };
16d5731834SJed Brown 
1744ee04a4SJed Brown /*
1844ee04a4SJed Brown  * The arity of the heap can be changed via the parameter B below. Consider the B=2 (arity=4 case below)
1944ee04a4SJed Brown  *
2044ee04a4SJed Brown  * [00 (sentinel); 01 (min node); 10 (unused); 11 (unused); 0100 (first child); 0101; 0110; 0111; ...]
2144ee04a4SJed Brown  *
2244ee04a4SJed Brown  * Slots 10 and 11 are referred to as the "hole" below in the implementation.
2344ee04a4SJed Brown  */
2444ee04a4SJed Brown 
2544ee04a4SJed Brown #define B     1        /* log2(ARITY) */
2644ee04a4SJed Brown #define ARITY (1 << B) /* tree branching factor */
279371c9d4SSatish Balay static inline PetscInt Parent(PetscInt loc) {
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 
359371c9d4SSatish Balay static inline void Swap(PetscHeap h, PetscInt loc, PetscInt loc2) {
36d5731834SJed Brown   PetscInt id, val;
37d5731834SJed Brown   id                  = Id(h, loc);
38d5731834SJed Brown   val                 = Value(h, loc);
39d5731834SJed Brown   h->base[loc].id     = Id(h, loc2);
40d5731834SJed Brown   h->base[loc].value  = Value(h, loc2);
41d5731834SJed Brown   h->base[loc2].id    = id;
42d5731834SJed Brown   h->base[loc2].value = val;
43d5731834SJed Brown }
449371c9d4SSatish Balay static inline PetscInt MinChild(PetscHeap h, PetscInt loc) {
4544ee04a4SJed Brown   PetscInt min, chld, left, right;
4644ee04a4SJed Brown   left  = loc << B;
4744ee04a4SJed Brown   right = PetscMin(left + ARITY - 1, h->end - 1);
4844ee04a4SJed Brown   chld  = 0;
4944ee04a4SJed Brown   min   = PETSC_MAX_INT;
5044ee04a4SJed Brown   for (; left <= right; left++) {
5144ee04a4SJed Brown     PetscInt val = Value(h, left);
5244ee04a4SJed Brown     if (val < min) {
5344ee04a4SJed Brown       min  = val;
5444ee04a4SJed Brown       chld = left;
5544ee04a4SJed Brown     }
5644ee04a4SJed Brown   }
5744ee04a4SJed Brown   return chld;
58d5731834SJed Brown }
59d5731834SJed Brown 
609371c9d4SSatish Balay PetscErrorCode PetscHeapCreate(PetscInt maxsize, PetscHeap *heap) {
61d5731834SJed Brown   PetscHeap h;
62d5731834SJed Brown 
63d5731834SJed Brown   PetscFunctionBegin;
640298fd71SBarry Smith   *heap = NULL;
659566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &h));
66d5731834SJed Brown   h->end   = 1;
6744ee04a4SJed Brown   h->alloc = maxsize + ARITY; /* We waste all but one slot (loc=1) in the first ARITY slots */
68d5731834SJed Brown   h->stash = h->alloc;
699566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(h->alloc, &h->base));
70d5731834SJed Brown   h->base[0].id    = -1;
71d5731834SJed Brown   h->base[0].value = PETSC_MIN_INT;
72d5731834SJed Brown   *heap            = h;
73d5731834SJed Brown   PetscFunctionReturn(0);
74d5731834SJed Brown }
75d5731834SJed Brown 
769371c9d4SSatish Balay PetscErrorCode PetscHeapAdd(PetscHeap h, PetscInt id, PetscInt val) {
7744ee04a4SJed Brown   PetscInt loc, par;
78d5731834SJed Brown 
79d5731834SJed Brown   PetscFunctionBegin;
8044ee04a4SJed Brown   if (1 < h->end && h->end < ARITY) h->end = ARITY;
81d5731834SJed Brown   loc = h->end++;
8208401ef6SPierre 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));
83d5731834SJed Brown   h->base[loc].id    = id;
84d5731834SJed Brown   h->base[loc].value = val;
85d5731834SJed Brown 
86d5731834SJed Brown   /* move up until heap condition is satisfied */
87527e7439SSatish Balay   while ((void)(par = Parent(loc)), Value(h, par) > val) {
8844ee04a4SJed Brown     Swap(h, loc, par);
8944ee04a4SJed Brown     loc = par;
90d5731834SJed Brown   }
91d5731834SJed Brown   PetscFunctionReturn(0);
92d5731834SJed Brown }
93d5731834SJed Brown 
949371c9d4SSatish Balay PetscErrorCode PetscHeapPop(PetscHeap h, PetscInt *id, PetscInt *val) {
95d5731834SJed Brown   PetscInt loc, chld;
96d5731834SJed Brown 
97d5731834SJed Brown   PetscFunctionBegin;
98d5731834SJed Brown   if (h->end == 1) {
99d5731834SJed Brown     *id  = h->base[0].id;
100d5731834SJed Brown     *val = h->base[0].value;
101d5731834SJed Brown     PetscFunctionReturn(0);
102d5731834SJed Brown   }
103d5731834SJed Brown 
104d5731834SJed Brown   *id  = h->base[1].id;
105d5731834SJed Brown   *val = h->base[1].value;
106d5731834SJed Brown 
107d5731834SJed Brown   /* rotate last entry into first position */
108d5731834SJed Brown   loc = --h->end;
10944ee04a4SJed Brown   if (h->end == ARITY) h->end = 2; /* Skip over hole */
110d5731834SJed Brown   h->base[1].id    = Id(h, loc);
111d5731834SJed Brown   h->base[1].value = Value(h, loc);
112d5731834SJed Brown 
113d5731834SJed Brown   /* move down until min heap condition is satisfied */
114d5731834SJed Brown   loc = 1;
115d5731834SJed Brown   while ((chld = MinChild(h, loc)) && Value(h, loc) > Value(h, chld)) {
116d5731834SJed Brown     Swap(h, loc, chld);
117d5731834SJed Brown     loc = chld;
118d5731834SJed Brown   }
119d5731834SJed Brown   PetscFunctionReturn(0);
120d5731834SJed Brown }
121d5731834SJed Brown 
1229371c9d4SSatish Balay PetscErrorCode PetscHeapPeek(PetscHeap h, PetscInt *id, PetscInt *val) {
123d5731834SJed Brown   PetscFunctionBegin;
124d5731834SJed Brown   if (h->end == 1) {
125d5731834SJed Brown     *id  = h->base[0].id;
126d5731834SJed Brown     *val = h->base[0].value;
127d5731834SJed Brown     PetscFunctionReturn(0);
128d5731834SJed Brown   }
129d5731834SJed Brown 
130d5731834SJed Brown   *id  = h->base[1].id;
131d5731834SJed Brown   *val = h->base[1].value;
132d5731834SJed Brown   PetscFunctionReturn(0);
133d5731834SJed Brown }
134d5731834SJed Brown 
1359371c9d4SSatish Balay PetscErrorCode PetscHeapStash(PetscHeap h, PetscInt id, PetscInt val) {
136d5731834SJed Brown   PetscInt loc;
137d5731834SJed Brown 
138d5731834SJed Brown   PetscFunctionBegin;
139d5731834SJed Brown   loc                = --h->stash;
140d5731834SJed Brown   h->base[loc].id    = id;
141d5731834SJed Brown   h->base[loc].value = val;
142d5731834SJed Brown   PetscFunctionReturn(0);
143d5731834SJed Brown }
144d5731834SJed Brown 
1459371c9d4SSatish Balay PetscErrorCode PetscHeapUnstash(PetscHeap h) {
146d5731834SJed Brown   PetscFunctionBegin;
147d5731834SJed Brown   while (h->stash < h->alloc) {
148d5731834SJed Brown     PetscInt id = Id(h, h->stash), value = Value(h, h->stash);
149d5731834SJed Brown     h->stash++;
1509566063dSJacob Faibussowitsch     PetscCall(PetscHeapAdd(h, id, value));
151d5731834SJed Brown   }
152d5731834SJed Brown   PetscFunctionReturn(0);
153d5731834SJed Brown }
154d5731834SJed Brown 
1559371c9d4SSatish Balay PetscErrorCode PetscHeapDestroy(PetscHeap *heap) {
156d5731834SJed Brown   PetscFunctionBegin;
1579566063dSJacob Faibussowitsch   PetscCall(PetscFree((*heap)->base));
1589566063dSJacob Faibussowitsch   PetscCall(PetscFree(*heap));
159d5731834SJed Brown   PetscFunctionReturn(0);
160d5731834SJed Brown }
161d5731834SJed Brown 
1629371c9d4SSatish Balay PetscErrorCode PetscHeapView(PetscHeap h, PetscViewer viewer) {
163d5731834SJed Brown   PetscBool iascii;
164d5731834SJed Brown 
165d5731834SJed Brown   PetscFunctionBegin;
166*48a46eb9SPierre Jolivet   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_SELF, &viewer));
167d5731834SJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1689566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
169d5731834SJed Brown   if (iascii) {
1709566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Heap size %" PetscInt_FMT " with %" PetscInt_FMT " stashed\n", h->end - 1, h->alloc - h->stash));
1719566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Heap in (id,value) pairs\n"));
1729566063dSJacob Faibussowitsch     PetscCall(PetscIntView(2 * (h->end - 1), (const PetscInt *)(h->base + 1), viewer));
1739566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Stash in (id,value) pairs\n"));
1749566063dSJacob Faibussowitsch     PetscCall(PetscIntView(2 * (h->alloc - h->stash), (const PetscInt *)(h->base + h->stash), viewer));
175d5731834SJed Brown   }
176d5731834SJed Brown   PetscFunctionReturn(0);
177d5731834SJed Brown }
178