zmaxheap.c
Go to the documentation of this file.
1 /* Copyright (C) 2013-2016, The Regents of The University of Michigan.
2 All rights reserved.
3 
4 This software was developed in the APRIL Robotics Lab under the
5 direction of Edwin Olson, ebolson@umich.edu. This software may be
6 available under alternative licensing terms; contact the address above.
7 
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10 
11 1. Redistributions of source code must retain the above copyright notice, this
12  list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 The views and conclusions contained in the software and documentation are those
29 of the authors and should not be interpreted as representing official policies,
30 either expressed or implied, of the Regents of The University of Michigan.
31 */
32 
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <math.h>
37 #include <assert.h>
38 #include <stdint.h>
39 
40 #include "zmaxheap.h"
41 
42 // 0
43 // 1 2
44 // 3 4 5 6
45 // 7 8 9 10 11 12 13 14
46 //
47 // Children of node i: 2*i+1, 2*i+2
48 // Parent of node i: (i-1) / 2
49 //
50 // Heap property: a parent is greater than (or equal to) its children.
51 
52 #define MIN_CAPACITY 16
53 
54 struct zmaxheap
55 {
56  size_t el_sz;
57 
58  int size;
59  int alloc;
60 
61  float *values;
62  char *data;
63 
64  void (*swap)(zmaxheap_t *heap, int a, int b);
65 };
66 
67 static inline void swap_default(zmaxheap_t *heap, int a, int b)
68 {
69  float t = heap->values[a];
70  heap->values[a] = heap->values[b];
71  heap->values[b] = t;
72 
73  char tmp[heap->el_sz];
74  memcpy(tmp, &heap->data[a*heap->el_sz], heap->el_sz);
75  memcpy(&heap->data[a*heap->el_sz], &heap->data[b*heap->el_sz], heap->el_sz);
76  memcpy(&heap->data[b*heap->el_sz], tmp, heap->el_sz);
77 }
78 
79 static inline void swap_pointer(zmaxheap_t *heap, int a, int b)
80 {
81  float t = heap->values[a];
82  heap->values[a] = heap->values[b];
83  heap->values[b] = t;
84 
85  void **pp = (void**) heap->data;
86  void *tmp = pp[a];
87  pp[a] = pp[b];
88  pp[b] = tmp;
89 }
90 
91 
93 {
94  zmaxheap_t *heap = calloc(1, sizeof(zmaxheap_t));
95  heap->el_sz = el_sz;
96 
97  heap->swap = swap_default;
98 
99  if (el_sz == sizeof(void*))
100  heap->swap = swap_pointer;
101 
102  return heap;
103 }
104 
106 {
107  free(heap->values);
108  free(heap->data);
109  memset(heap, 0, sizeof(zmaxheap_t));
110  free(heap);
111 }
112 
114 {
115  return heap->size;
116 }
117 
118 void zmaxheap_ensure_capacity(zmaxheap_t *heap, int capacity)
119 {
120  if (heap->alloc >= capacity)
121  return;
122 
123  int newcap = heap->alloc;
124 
125  while (newcap < capacity) {
126  if (newcap < MIN_CAPACITY) {
127  newcap = MIN_CAPACITY;
128  continue;
129  }
130 
131  newcap *= 2;
132  }
133 
134  heap->values = realloc(heap->values, newcap * sizeof(float));
135  heap->data = realloc(heap->data, newcap * heap->el_sz);
136  heap->alloc = newcap;
137 }
138 
139 void zmaxheap_add(zmaxheap_t *heap, void *p, float v)
140 {
141 
142  assert (isfinite(v) && "zmaxheap_add: Trying to add non-finite number to heap. NaN's prohibited, could allow INF with testing");
143  zmaxheap_ensure_capacity(heap, heap->size + 1);
144 
145  int idx = heap->size;
146 
147  heap->values[idx] = v;
148  memcpy(&heap->data[idx*heap->el_sz], p, heap->el_sz);
149 
150  heap->size++;
151 
152  while (idx > 0) {
153 
154  int parent = (idx - 1) / 2;
155 
156  // we're done!
157  if (heap->values[parent] >= v)
158  break;
159 
160  // else, swap and recurse upwards.
161  heap->swap(heap, idx, parent);
162  idx = parent;
163  }
164 }
165 
166 void zmaxheap_vmap(zmaxheap_t *heap, void (*f)())
167 {
168  assert(heap != NULL);
169  assert(f != NULL);
170  assert(heap->el_sz == sizeof(void*));
171 
172  for (int idx = 0; idx < heap->size; idx++) {
173  void *p = NULL;
174  memcpy(&p, &heap->data[idx*heap->el_sz], heap->el_sz);
175  if (p == NULL) {
176  printf("Warning: zmaxheap_vmap item %d is NULL\n", idx);
177  fflush(stdout);
178  }
179  f(p);
180  }
181 }
182 
183 // Removes the item in the heap at the given index. Returns 1 if the
184 // item existed. 0 Indicates an invalid idx (heap is smaller than
185 // idx). This is mostly intended to be used by zmaxheap_remove_max.
186 int zmaxheap_remove_index(zmaxheap_t *heap, int idx, void *p, float *v)
187 {
188  if (idx >= heap->size)
189  return 0;
190 
191  // copy out the requested element from the heap.
192  if (v != NULL)
193  *v = heap->values[idx];
194  if (p != NULL)
195  memcpy(p, &heap->data[idx*heap->el_sz], heap->el_sz);
196 
197  heap->size--;
198 
199  // If this element is already the last one, then there's nothing
200  // for us to do.
201  if (idx == heap->size)
202  return 1;
203 
204  // copy last element to first element. (which probably upsets
205  // the heap property).
206  heap->values[idx] = heap->values[heap->size];
207  memcpy(&heap->data[idx*heap->el_sz], &heap->data[heap->el_sz * heap->size], heap->el_sz);
208 
209  // now fix the heap. Note, as we descend, we're "pushing down"
210  // the same node the entire time. Thus, while the index of the
211  // parent might change, the parent_score doesn't.
212  int parent = idx;
213  float parent_score = heap->values[idx];
214 
215  // descend, fixing the heap.
216  while (parent < heap->size) {
217 
218  int left = 2*parent + 1;
219  int right = left + 1;
220 
221 // assert(parent_score == heap->values[parent]);
222 
223  float left_score = (left < heap->size) ? heap->values[left] : -INFINITY;
224  float right_score = (right < heap->size) ? heap->values[right] : -INFINITY;
225 
226  // put the biggest of (parent, left, right) as the parent.
227 
228  // already okay?
229  if (parent_score >= left_score && parent_score >= right_score)
230  break;
231 
232  // if we got here, then one of the children is bigger than the parent.
233  if (left_score >= right_score) {
234  assert(left < heap->size);
235  heap->swap(heap, parent, left);
236  parent = left;
237  } else {
238  // right_score can't be less than left_score if right_score is -INFINITY.
239  assert(right < heap->size);
240  heap->swap(heap, parent, right);
241  parent = right;
242  }
243  }
244 
245  return 1;
246 }
247 
248 int zmaxheap_remove_max(zmaxheap_t *heap, void *p, float *v)
249 {
250  return zmaxheap_remove_index(heap, 0, p, v);
251 }
252 
254 {
255  memset(it, 0, sizeof(zmaxheap_iterator_t));
256  it->heap = heap;
257  it->in = 0;
258  it->out = 0;
259 }
260 
261 int zmaxheap_iterator_next(zmaxheap_iterator_t *it, void *p, float *v)
262 {
263  zmaxheap_t *heap = it->heap;
264 
265  if (it->in >= zmaxheap_size(heap))
266  return 0;
267 
268  *v = heap->values[it->in];
269  memcpy(p, &heap->data[it->in*heap->el_sz], heap->el_sz);
270 
271  if (it->in != it->out) {
272  heap->values[it->out] = heap->values[it->in];
273  memcpy(&heap->data[it->out*heap->el_sz], &heap->data[it->in*heap->el_sz], heap->el_sz);
274  }
275 
276  it->in++;
277  it->out++;
278  return 1;
279 }
280 
282 {
283  zmaxheap_t *heap = it->heap;
284 
285  if (it->in >= zmaxheap_size(heap))
286  return 0;
287 
288  *v = heap->values[it->in];
289  *((void**) p) = &heap->data[it->in*heap->el_sz];
290 
291  if (it->in != it->out) {
292  heap->values[it->out] = heap->values[it->in];
293  memcpy(&heap->data[it->out*heap->el_sz], &heap->data[it->in*heap->el_sz], heap->el_sz);
294  }
295 
296  it->in++;
297  it->out++;
298  return 1;
299 }
300 
302 {
303  it->out--;
304 }
305 
306 static void maxheapify(zmaxheap_t *heap, int parent)
307 {
308  int left = 2*parent + 1;
309  int right = 2*parent + 2;
310 
311  int betterchild = parent;
312 
313  if (left < heap->size && heap->values[left] > heap->values[betterchild])
314  betterchild = left;
315  if (right < heap->size && heap->values[right] > heap->values[betterchild])
316  betterchild = right;
317 
318  if (betterchild != parent) {
319  heap->swap(heap, parent, betterchild);
320  return maxheapify(heap, betterchild);
321  }
322 }
323 
324 #if 0 //won't compile if defined but not used
325 // test the heap property
326 static void validate(zmaxheap_t *heap)
327 {
328  for (int parent = 0; parent < heap->size; parent++) {
329  int left = 2*parent + 1;
330  int right = 2*parent + 2;
331 
332  if (left < heap->size) {
333  assert(heap->values[parent] > heap->values[left]);
334  }
335 
336  if (right < heap->size) {
337  assert(heap->values[parent] > heap->values[right]);
338  }
339  }
340 }
341 #endif
343 {
344  // if nothing was removed, no work to do.
345  if (it->in == it->out)
346  return;
347 
348  zmaxheap_t *heap = it->heap;
349 
350  heap->size = it->out;
351 
352  // restore heap property
353  for (int i = heap->size/2 - 1; i >= 0; i--)
354  maxheapify(heap, i);
355 }
356 
358 {
359  int cap = 10000;
360  int sz = 0;
361  int32_t *vals = calloc(sizeof(int32_t), cap);
362 
363  zmaxheap_t *heap = zmaxheap_create(sizeof(int32_t));
364 
365  int maxsz = 0;
366  int zcnt = 0;
367 
368  for (int iter = 0; iter < 5000000; iter++) {
369  assert(sz == heap->size);
370 
371  if ((random() & 1) == 0 && sz < cap) {
372  // add a value
373  int32_t v = (int32_t) (random() / 1000);
374  float fv = v;
375  assert(v == fv);
376 
377  vals[sz] = v;
378  zmaxheap_add(heap, &v, fv);
379  sz++;
380 
381 // printf("add %d %f\n", v, fv);
382  } else {
383  // remove a value
384  int maxv = -1, maxi = -1;
385 
386  for (int i = 0; i < sz; i++) {
387  if (vals[i] > maxv) {
388  maxv = vals[i];
389  maxi = i;
390  }
391  }
392 
393 
394  int32_t outv;
395  float outfv;
396  int res = zmaxheap_remove_max(heap, &outv, &outfv);
397  if (sz == 0) {
398  assert(res == 0);
399  } else {
400 // printf("%d %d %d %f\n", sz, maxv, outv, outfv);
401  assert(outv == outfv);
402  assert(maxv == outv);
403 
404  // shuffle erase the maximum from our list.
405  vals[maxi] = vals[sz - 1];
406  sz--;
407  }
408  }
409 
410  if (sz > maxsz)
411  maxsz = sz;
412 
413  if (maxsz > 0 && sz == 0)
414  zcnt++;
415  }
416 
417  printf("max size: %d, zcount %d\n", maxsz, zcnt);
418  free (vals);
419 }
float * values
Definition: zmaxheap.c:61
void zmaxheap_iterator_init(zmaxheap_t *heap, zmaxheap_iterator_t *it)
Definition: zmaxheap.c:253
void zmaxheap_iterator_remove(zmaxheap_iterator_t *it)
Definition: zmaxheap.c:301
void zmaxheap_destroy(zmaxheap_t *heap)
Definition: zmaxheap.c:105
#define MIN_CAPACITY
Definition: zmaxheap.c:52
void zmaxheap_vmap(zmaxheap_t *heap, void(*f)())
Definition: zmaxheap.c:166
int zmaxheap_remove_index(zmaxheap_t *heap, int idx, void *p, float *v)
Definition: zmaxheap.c:186
void zmaxheap_test()
Definition: zmaxheap.c:357
int size
Definition: zmaxheap.c:58
void(* swap)(zmaxheap_t *heap, int a, int b)
Definition: zmaxheap.c:64
static void swap_default(zmaxheap_t *heap, int a, int b)
Definition: zmaxheap.c:67
int zmaxheap_size(zmaxheap_t *heap)
Definition: zmaxheap.c:113
zmaxheap_t * zmaxheap_create(size_t el_sz)
Definition: zmaxheap.c:92
static void swap_pointer(zmaxheap_t *heap, int a, int b)
Definition: zmaxheap.c:79
zmaxheap_t * heap
Definition: zmaxheap.h:42
void zmaxheap_iterator_finish(zmaxheap_iterator_t *it)
Definition: zmaxheap.c:342
int zmaxheap_iterator_next(zmaxheap_iterator_t *it, void *p, float *v)
Definition: zmaxheap.c:261
static void maxheapify(zmaxheap_t *heap, int parent)
Definition: zmaxheap.c:306
char * data
Definition: zmaxheap.c:62
void zmaxheap_add(zmaxheap_t *heap, void *p, float v)
Definition: zmaxheap.c:139
int zmaxheap_iterator_next_volatile(zmaxheap_iterator_t *it, void *p, float *v)
Definition: zmaxheap.c:281
void zmaxheap_ensure_capacity(zmaxheap_t *heap, int capacity)
Definition: zmaxheap.c:118
int zmaxheap_remove_max(zmaxheap_t *heap, void *p, float *v)
Definition: zmaxheap.c:248
int alloc
Definition: zmaxheap.c:59
size_t el_sz
Definition: zmaxheap.c:56


apriltags2
Author(s): Danylo Malyuta
autogenerated on Fri Oct 19 2018 04:02:32