LAL  7.5.0.1-ec27e42
LALHeap.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2016 Karl Wette
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with with program; see the file COPYING. If not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17  * MA 02110-1301 USA
18  */
19 
20 #include <lal/LALHeap.h>
21 
22 #define LEFT(i) (2*(i) + 1) /* Left child of binary heap element 'i' */
23 #define RIGHT(i) (2*(i) + 2) /* Right child of binary heap element 'i' */
24 #define PARENT(i) (((i) - 1)/2) /* Parent of binary heap element 'i' */
25 
26 /* Swap elements x and y */
27 #define SWAP(x, y) do { void *z = (x); (x) = (y); (y) = z; } while (0)
28 
29 /* Evaluates true if the pair (x, y) is NOT ordered, according to the heap compare function */
30 #define UNORDERED(h, x, y) ((h)->cmp((h)->cmp_param, (x), (y)) * (h)->min_or_max_heap > 0)
31 
32 /* Function to use when adding an element to the heap */
33 typedef int ( *LALHeapAddFcn )( LALHeap *h, void **x );
34 
35 struct tagLALHeap {
36  void **data; /* Binary heap data */
37  int data_len; /* Size of the memory block 'data', in number of elements */
38  int n; /* Number of valid elements in the heap */
39  LALHeapDtorFcn dtor; /* Function to free memory of elements of heap, if required */
40  int max_size; /* Maximum size of the heap; if zero, heap has unlimited size */
41  int min_or_max_heap; /* -1|+1 if root of heap is minimum|maximum element */
42  LALHeapCmpParamFcn cmp; /* Parameterised heap element comparison function */
43  void *cmp_param; /* Parameter to pass to comparison function */
44  LALHeapAddFcn add; /* Function to use when adding an element to the heap */
45 };
46 
47 /* Call a non-parameterised compare function, which is passed in 'param' */
48 static int heap_no_param_cmp( void *param, const void *x, const void *y )
49 {
50  LALHeapCmpFcn cmp = ( LALHeapCmpFcn ) param;
51  return cmp( x, y );
52 }
53 
54 /* Resize the binary heap to twice the current number of heap elements */
55 static int heap_resize( LALHeap *h )
56 {
57  int new_len = ( h->n > 0 ) ? 2*h->n : 1;
58  h->data = XLALRealloc( h->data, new_len * sizeof( h->data[0] ) );
59  XLAL_CHECK( h->data != NULL, XLAL_ENOMEM );
60  h->data_len = new_len;
61  return XLAL_SUCCESS;
62 }
63 
64 /* Swap element 'i' with its parent until the heap property is satisfied */
65 static void heap_bubble_up( LALHeap *h, int i )
66 {
67  int p = PARENT( i );
68  while ( i > 0 && UNORDERED( h, h->data[i], h->data[p] ) ) {
69  SWAP( h->data[i], h->data[p] );
70  i = p;
71  p = PARENT( i );
72  }
73 }
74 
75 /* Swap element 'i' with either of its children until the heap property is satisfied */
76 static void heap_trickle_down( LALHeap *h, int i )
77 {
78  do {
79  int j = -1, r = RIGHT( i );
80  if ( r < h->n && UNORDERED( h, h->data[r], h->data[i] ) ) {
81  int l = LEFT( i );
82  if ( UNORDERED( h, h->data[l], h->data[r] ) ) {
83  j = l;
84  } else {
85  j = r;
86  }
87  } else {
88  int l = LEFT( i );
89  if ( l < h->n && UNORDERED( h, h->data[l], h->data[i] ) ) {
90  j = l;
91  }
92  }
93  if ( j >= 0 ) {
94  SWAP( h->data[i], h->data[j] );
95  }
96  i = j;
97  } while ( i >= 0 );
98 }
99 
100 /* Add item to heap which is full */
101 static int heap_add_full(
102  LALHeap *h,
103  void **x
104  )
105 {
106 
107  /* If new element should replace root */
108  if ( UNORDERED( h, h->data[0], *x ) ) {
109 
110  /* Swap root with *x, and trickle down new root to restore heap property */
111  SWAP( h->data[0], *x );
112  heap_trickle_down( h, 0 );
113 
114  }
115 
116  return XLAL_SUCCESS;
117 
118 }
119 
120 /* Add item to heap which is unlimited, or not full yet */
121 static int heap_add_not_full(
122  LALHeap *h,
123  void **x
124  )
125 {
126 
127  /* Resize binary heap; designed so that resizing costs amortized constant time */
128  if ( h->n + 1 > h->data_len ) {
130  }
131 
132  /* Add new element to end of binary heap, and bubble up to restore heap property */
133  h->data[h->n++] = *x;
134  *x = NULL;
135  heap_bubble_up( h, h->n - 1 );
136 
137  /* If (limited) heap is now full, switch add function to heap_add_full() */
138  if ( XLALHeapIsFull( h ) ) {
139  h->add = heap_add_full;
140  }
141 
142  return XLAL_SUCCESS;
143 
144 }
145 
146 LALHeap *XLALHeapCreate(
147  LALHeapDtorFcn dtor,
148  int max_size,
149  int min_or_max_heap,
151  )
152 {
153 
154  /* Create a heap using heap_no_param_cmp as the comparison function */
155  LALHeap *h = XLALHeapCreate2( dtor, max_size, min_or_max_heap, heap_no_param_cmp, cmp );
156  XLAL_CHECK_NULL( h != NULL, XLAL_EFUNC );
157 
158  return h;
159 
160 }
161 
163  LALHeapDtorFcn dtor,
164  int max_size,
165  int min_or_max_heap,
167  void *cmp_param
168  )
169 {
170 
171  /* Check input */
172  XLAL_CHECK_NULL( max_size >= 0, XLAL_EINVAL );
173  XLAL_CHECK_NULL( abs( min_or_max_heap ) == 1, XLAL_EINVAL );
174  XLAL_CHECK_NULL( cmp != NULL, XLAL_EFAULT );
175 
176  /* Allocate memory for heap struct */
177  LALHeap *h = XLALCalloc( 1, sizeof( *h ) );
178  XLAL_CHECK_NULL( h != NULL, XLAL_ENOMEM );
179 
180  /* Set heap struct parameters */
181  h->dtor = dtor;
182  h->max_size = max_size;
183  h->min_or_max_heap = min_or_max_heap;
184  h->cmp = cmp;
185  h->cmp_param = cmp_param;
186  h->add = heap_add_not_full;
187 
188  return h;
189 
190 }
191 
193  LALHeap *h
194  )
195 {
196  if ( h != NULL ) {
197  if ( h->data != NULL ) {
198  if ( h->dtor != NULL ) {
199  for ( int i = 0; i < h->n; ++i ) {
200  h->dtor( h->data[i] );
201  }
202  }
203  XLALFree( h->data );
204  }
205  XLALFree( h );
206  }
207 }
208 
210  LALHeap *h
211  )
212 {
213 
214  /* Check input */
215  XLAL_CHECK( h != NULL, XLAL_EFAULT );
216 
217  /* Free heap elements */
218  if ( h->data != NULL ) {
219  if ( h->dtor != NULL ) {
220  for ( int i = 0; i < h->n; ++i ) {
221  h->dtor( h->data[i] );
222  h->data[i] = NULL;
223  }
224  }
225  }
226 
227  /* Remove all elements from heap */
228  h->n = 0;
229  h->add = heap_add_not_full;
230 
231  return XLAL_SUCCESS;
232 
233 }
234 
236  const LALHeap *h
237  )
238 {
239  XLAL_CHECK( h != NULL, XLAL_EFAULT );
240  return h->n;
241 }
242 
244  const LALHeap *h
245  )
246 {
247  XLAL_CHECK( h != NULL, XLAL_EFAULT );
248  return h->max_size;
249 }
250 
252  const LALHeap *h
253  )
254 {
255  XLAL_CHECK( h != NULL, XLAL_EFAULT );
256  return h->max_size > 0 && h->n == h->max_size;
257 }
258 
259 const void *XLALHeapRoot(
260  const LALHeap *h
261  )
262 {
263  XLAL_CHECK_NULL( h != NULL, XLAL_EFAULT );
264  return ( h->n > 0 ) ? h->data[0] : NULL;
265 }
266 
268  LALHeap *h,
269  int max_size
270  )
271 {
272 
273  /* Check input */
274  XLAL_CHECK( h != NULL, XLAL_EFAULT );
275  XLAL_CHECK( max_size >= 0, XLAL_EINVAL );
276 
277  /* If too many heap elements for new (fixed) maximum size, remove some */
278  while ( max_size > 0 && h->n > max_size ) {
280  }
281 
282  /* Set new maximum size */
283  h->max_size = max_size;
284 
285  return XLAL_SUCCESS;
286 
287 }
288 
290  LALHeap *h,
291  void **x
292  )
293 {
294 
295  /* Check input */
296  XLAL_CHECK( h != NULL, XLAL_EFAULT );
297  XLAL_CHECK( x != NULL, XLAL_EFAULT );
298  XLAL_CHECK( *x != NULL, XLAL_EINVAL );
299 
300  /* Call the appropriate function */
301  return ( h->add )( h, x );
302 
303 }
304 
306  LALHeap *h
307  )
308 {
309 
310  /* Check input */
311  XLAL_CHECK_NULL( h != NULL, XLAL_EFAULT );
312  XLAL_CHECK_NULL( h->n > 0, XLAL_ESIZE );
313 
314  /* Save root element */
315  void *x = h->data[0];
316 
317  /* Replace root with last element in binary heap, and trickle down to restore heap property */
318  h->data[0] = h->data[--h->n];
319  heap_trickle_down( h, 0 );
320 
321  /* Resize binary heap; designed so that resizing costs amortized constant time */
322  if ( 3*h->n < h->data_len ) {
324  }
325 
326  /* Heap now cannot be full, so switch add function to heap_add_not_full() */
327  h->add = heap_add_not_full;
328 
329  return x;
330 
331 }
332 
334  LALHeap *h
335  )
336 {
337 
338  /* Check input */
339  XLAL_CHECK( h != NULL, XLAL_EFAULT );
340  XLAL_CHECK( h->n > 0, XLAL_ESIZE );
341 
342  /* Extract root */
343  void *x = XLALHeapExtractRoot( h );
344  XLAL_CHECK( x != NULL, XLAL_EFUNC );
345 
346  /* Free memory associated with root element, if required */
347  if ( h->dtor != NULL ) {
348  h->dtor( x );
349  }
350 
351  return XLAL_SUCCESS;
352 
353 }
354 
356  LALHeap *h,
357  void **x
358  )
359 {
360 
361  /* Check input */
362  XLAL_CHECK( h != NULL, XLAL_EFAULT );
363  XLAL_CHECK( h->n > 0, XLAL_ESIZE );
364  XLAL_CHECK( x != NULL, XLAL_EFAULT );
365 
366  /* Swap root with *x, and trickle down new root to restore heap property */
367  SWAP( h->data[0], *x );
368  heap_trickle_down( h, 0 );
369 
370  return XLAL_SUCCESS;
371 
372 }
373 
375  const LALHeap *h,
376  LALHeapVisitFcn visit,
377  void *visit_param
378  )
379 {
380 
381  /* Check input */
382  XLAL_CHECK( h != NULL, XLAL_EFAULT );
383  XLAL_CHECK( visit != NULL, XLAL_EFAULT );
384 
385  /* Create internal min-heap (without destructor) to get elements in order */
386  LALHeap *h2 = XLALHeapCreate2( NULL, 0, -1, h->cmp, h->cmp_param );
387  XLAL_CHECK( h2 != NULL, XLAL_EFUNC );
388 
389  /* Add all elements in heap to internal min-heap */
390  for ( int i = 0; i < h->n; ++i ) {
391  void *x = h->data[i];
393  }
394 
395  /* Visit root element of internal min-heap and remove, until empty */
396  while ( h2->n > 0 ) {
397  const void *x = XLALHeapRoot( h2 );
398  XLAL_CHECK( visit( visit_param, x ) == XLAL_SUCCESS, XLAL_EFUNC );
400  }
401 
402  /* Cleanup */
403  XLALHeapDestroy( h2 );
404 
405  return XLAL_SUCCESS;
406 
407 }
408 
410  LALHeap *h,
411  LALHeapModifyFcn modify,
412  void *modify_param
413  )
414 {
415 
416  /* Check input */
417  XLAL_CHECK( h != NULL, XLAL_EFAULT );
418  XLAL_CHECK( modify != NULL, XLAL_EFAULT );
419 
420  /* Create internal min-heap (without destructor) to get elements in order */
421  LALHeap *h2 = XLALHeapCreate2( NULL, 0, -1, h->cmp, h->cmp_param );
422  XLAL_CHECK( h2 != NULL, XLAL_EFUNC );
423 
424  /* Add all elements in heap to internal min-heap */
425  for ( int i = 0; i < h->n; ++i ) {
426  void *x = h->data[i];
428  }
429 
430  /* Remove all elements from original heap */
431  h->n = 0;
432  h->add = heap_add_not_full;
433 
434  /* Extract roots element of internal min-heap, until empty */
435  while ( h2->n > 0 ) {
436  void *x = XLALHeapExtractRoot( h2 );
437  XLAL_CHECK( x != NULL, XLAL_EFUNC );
438 
439  /* Visit element, possibly modifying it */
440  XLAL_CHECK( modify( modify_param, x ) == XLAL_SUCCESS, XLAL_EFUNC );
441 
442  /* Add element back to original heap */
444 
445  }
446 
447  /* Cleanup */
448  XLALHeapDestroy( h2 );
449 
450  return XLAL_SUCCESS;
451 
452 }
453 
455  void *param,
456  const void *x
457  )
458 {
459  const void ***elem = ( const void *** ) param;
460  **elem = x;
461  ++(*elem);
462  return XLAL_SUCCESS;
463 }
464 
465 const void **XLALHeapElements(
466  const LALHeap *h
467  )
468 {
469 
470  /* Check input */
471  XLAL_CHECK_NULL( h != NULL, XLAL_EFAULT );
472 
473  /* Allocate memory */
474  const void **elems = XLALMalloc( h->n * sizeof( *elems ) );
475  XLAL_CHECK_NULL( elems != NULL, XLAL_ENOMEM );
476 
477  /* Get elements */
478  const void **elem = elems;
480  XLAL_CHECK_NULL( elems + h->n == elem, XLAL_EFAILED );
481 
482  return elems;
483 
484 }
#define RIGHT(i)
Definition: LALHeap.c:23
static int heap_add_full(LALHeap *h, void **x)
Definition: LALHeap.c:101
static int heap_get_elems_visitor(void *param, const void *x)
Definition: LALHeap.c:454
#define LEFT(i)
Definition: LALHeap.c:22
static int heap_resize(LALHeap *h)
Definition: LALHeap.c:55
int(* LALHeapAddFcn)(LALHeap *h, void **x)
Definition: LALHeap.c:33
static int heap_add_not_full(LALHeap *h, void **x)
Definition: LALHeap.c:121
static int heap_no_param_cmp(void *param, const void *x, const void *y)
Definition: LALHeap.c:48
#define SWAP(x, y)
Definition: LALHeap.c:27
#define PARENT(i)
Definition: LALHeap.c:24
#define UNORDERED(h, x, y)
Definition: LALHeap.c:30
static void heap_trickle_down(LALHeap *h, int i)
Definition: LALHeap.c:76
static void heap_bubble_up(LALHeap *h, int i)
Definition: LALHeap.c:65
static int cmp(REAL4Sequence *a, REAL4Sequence *b)
Definition: SequenceTest.c:62
const void ** XLALHeapElements(const LALHeap *h)
Allocate and return an array containing all elements in the heap.
Definition: LALHeap.c:465
void(* LALHeapDtorFcn)(void *x)
Function which free memory associated with heap element x
Definition: LALHeap.h:45
const void * XLALHeapRoot(const LALHeap *h)
Return the root element of a heap.
Definition: LALHeap.c:259
int XLALHeapResize(LALHeap *h, int max_size)
Change the maximum size of a heap; if the heap is contracted, excess elements are destroyed.
Definition: LALHeap.c:267
int(* LALHeapCmpFcn)(const void *x, const void *y)
Function which compares heap elements x and y
Definition: LALHeap.h:50
int XLALHeapVisit(const LALHeap *h, LALHeapVisitFcn visit, void *visit_param)
Visit each element in the heap in the order given by the comparison function.
Definition: LALHeap.c:374
int XLALHeapAdd(LALHeap *h, void **x)
Add a new element to a heap; if the heap is of fixed size and full, the root element is removed.
Definition: LALHeap.c:289
int(* LALHeapVisitFcn)(void *param, const void *x)
Function to call when visiting heap element x, with a parameter param.
Definition: LALHeap.h:61
void * XLALHeapExtractRoot(LALHeap *h)
Remove the root element of a heap.
Definition: LALHeap.c:305
int(* LALHeapCmpParamFcn)(void *param, const void *x, const void *y)
Function which compares heap elements x and y, with a parameter param.
Definition: LALHeap.h:55
int XLALHeapModify(LALHeap *h, LALHeapModifyFcn modify, void *modify_param)
Visit (and possibly modify) each element in the heap in the order given by the comparison function.
Definition: LALHeap.c:409
int XLALHeapSize(const LALHeap *h)
Return the size of a heap.
Definition: LALHeap.c:235
int XLALHeapExchangeRoot(LALHeap *h, void **x)
Exchange the root element of a non-empty heap with the new element in *x
Definition: LALHeap.c:355
int XLALHeapRemoveRoot(LALHeap *h)
Remove and destroy the root element of a heap.
Definition: LALHeap.c:333
int(* LALHeapModifyFcn)(void *param, void *x)
Function to call when visiting (and possibly modify) heap element x, with a parameter param.
Definition: LALHeap.h:67
int XLALHeapIsFull(const LALHeap *h)
Return >0 if a limited-size heap is full, 0 otherwise (or if heap has unlimited size),...
Definition: LALHeap.c:251
LALHeap * XLALHeapCreate2(LALHeapDtorFcn dtor, int max_size, int min_or_max_heap, LALHeapCmpParamFcn cmp, void *cmp_param)
Create a heap with a parameterised comparison function.
Definition: LALHeap.c:162
int XLALHeapClear(LALHeap *h)
Clear a heap.
Definition: LALHeap.c:209
LALHeap * XLALHeapCreate(LALHeapDtorFcn dtor, int max_size, int min_or_max_heap, LALHeapCmpFcn cmp)
Create a heap.
Definition: LALHeap.c:146
void XLALHeapDestroy(LALHeap *h)
Destroy a heap and its elements.
Definition: LALHeap.c:192
int XLALHeapMaxSize(const LALHeap *h)
Return the maximum size of a heap.
Definition: LALHeap.c:243
#define XLALMalloc(n)
Definition: LALMalloc.h:44
#define XLALCalloc(m, n)
Definition: LALMalloc.h:45
#define XLALFree(p)
Definition: LALMalloc.h:47
#define XLALRealloc(p, n)
Definition: LALMalloc.h:46
static const INT4 r
Definition: Random.c:82
#define XLAL_CHECK(assertion,...)
Macro to test an assertion and invoke a failure if it is not true in a function that returns an integ...
Definition: XLALError.h:810
#define XLAL_CHECK_NULL(assertion,...)
Macro to test an assertion and invoke a failure if it is not true in a function that returns a pointe...
Definition: XLALError.h:825
@ XLAL_ENOMEM
Memory allocation error.
Definition: XLALError.h:407
@ XLAL_SUCCESS
Success return value (not an error number)
Definition: XLALError.h:401
@ XLAL_EFAULT
Invalid pointer.
Definition: XLALError.h:408
@ XLAL_EFUNC
Internal function call failed bit: "or" this with existing error number.
Definition: XLALError.h:462
@ XLAL_ESIZE
Wrong size.
Definition: XLALError.h:420
@ XLAL_EINVAL
Invalid argument.
Definition: XLALError.h:409
@ XLAL_EFAILED
Generic failure.
Definition: XLALError.h:418
Definition: LALBitset.c:31
Generic heap with elements of type void *
Definition: LALHeap.c:35
LALHeapAddFcn add
Definition: LALHeap.c:44
LALHeapCmpParamFcn cmp
Definition: LALHeap.c:42
void ** data
Definition: LALHeap.c:36
LALHeapDtorFcn dtor
Definition: LALHeap.c:39
int min_or_max_heap
Definition: LALHeap.c:41
void * cmp_param
Definition: LALHeap.c:43
int max_size
Definition: LALHeap.c:40
int n
Definition: LALHeap.c:38
int data_len
Definition: LALHeap.c:37