abc-master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
cuddLevelQ.c
Go to the documentation of this file.
1 /**CFile***********************************************************************
2 
3  FileName [cuddLevelQ.c]
4 
5  PackageName [cudd]
6 
7  Synopsis [Procedure to manage level queues.]
8 
9  Description [The functions in this file allow an application to
10  easily manipulate a queue where nodes are prioritized by level. The
11  emphasis is on efficiency. Therefore, the queue items can have
12  variable size. If the application does not need to attach
13  information to the nodes, it can declare the queue items to be of
14  type DdQueueItem. Otherwise, it can declare them to be of a
15  structure type such that the first three fields are data
16  pointers. The third pointer points to the node. The first two
17  pointers are used by the level queue functions. The remaining fields
18  are initialized to 0 when a new item is created, and are then left
19  to the exclusive use of the application. On the DEC Alphas the three
20  pointers must be 32-bit pointers when CUDD is compiled with 32-bit
21  pointers. The level queue functions make sure that each node
22  appears at most once in the queue. They do so by keeping a hash
23  table where the node is used as key. Queue items are recycled via a
24  free list for efficiency.
25 
26  Internal procedures provided by this module:
27  <ul>
28  <li> cuddLevelQueueInit()
29  <li> cuddLevelQueueQuit()
30  <li> cuddLevelQueueEnqueue()
31  <li> cuddLevelQueueDequeue()
32  </ul>
33  Static procedures included in this module:
34  <ul>
35  <li> hashLookup()
36  <li> hashInsert()
37  <li> hashDelete()
38  <li> hashResize()
39  </ul>
40  ]
41 
42  SeeAlso []
43 
44  Author [Fabio Somenzi]
45 
46  Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado
47 
48  All rights reserved.
49 
50  Redistribution and use in source and binary forms, with or without
51  modification, are permitted provided that the following conditions
52  are met:
53 
54  Redistributions of source code must retain the above copyright
55  notice, this list of conditions and the following disclaimer.
56 
57  Redistributions in binary form must reproduce the above copyright
58  notice, this list of conditions and the following disclaimer in the
59  documentation and/or other materials provided with the distribution.
60 
61  Neither the name of the University of Colorado nor the names of its
62  contributors may be used to endorse or promote products derived from
63  this software without specific prior written permission.
64 
65  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
66  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
67  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
68  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
69  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
70  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
71  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
72  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
73  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
74  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
75  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
76  POSSIBILITY OF SUCH DAMAGE.]
77 
78 ******************************************************************************/
79 
80 #include "misc/util/util_hack.h"
81 #include "cuddInt.h"
82 
84 
85 
86 
87 /*---------------------------------------------------------------------------*/
88 /* Constant declarations */
89 /*---------------------------------------------------------------------------*/
90 
91 
92 /*---------------------------------------------------------------------------*/
93 /* Stucture declarations */
94 /*---------------------------------------------------------------------------*/
95 
96 /*---------------------------------------------------------------------------*/
97 /* Type declarations */
98 /*---------------------------------------------------------------------------*/
99 
100 /*---------------------------------------------------------------------------*/
101 /* Variable declarations */
102 /*---------------------------------------------------------------------------*/
103 
104 #ifndef lint
105 static char rcsid[] DD_UNUSED = "$Id: cuddLevelQ.c,v 1.13 2009/03/08 02:49:02 fabio Exp $";
106 #endif
107 
108 /*---------------------------------------------------------------------------*/
109 /* Macro declarations */
110 /*---------------------------------------------------------------------------*/
111 
112 
113 /**Macro***********************************************************************
114 
115  Synopsis [Hash function for the table of a level queue.]
116 
117  Description [Hash function for the table of a level queue.]
118 
119  SideEffects [None]
120 
121  SeeAlso [hashInsert hashLookup hashDelete]
122 
123 ******************************************************************************/
124 #if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
125 #define lqHash(key,shift) \
126 (((unsigned)(ptruint)(key) * DD_P1) >> (shift))
127 #else
128 #define lqHash(key,shift) \
129 (((unsigned)(key) * DD_P1) >> (shift))
130 #endif
131 
132 
133 /**AutomaticStart*************************************************************/
134 
135 /*---------------------------------------------------------------------------*/
136 /* Static function prototypes */
137 /*---------------------------------------------------------------------------*/
138 
139 static DdQueueItem * hashLookup (DdLevelQueue *queue, void *key);
140 static int hashInsert (DdLevelQueue *queue, DdQueueItem *item);
141 static void hashDelete (DdLevelQueue *queue, DdQueueItem *item);
142 static int hashResize (DdLevelQueue *queue);
143 
144 /**AutomaticEnd***************************************************************/
145 
146 
147 /*---------------------------------------------------------------------------*/
148 /* Definition of internal functions */
149 /*---------------------------------------------------------------------------*/
150 
151 
152 /**Function********************************************************************
153 
154  Synopsis [Initializes a level queue.]
155 
156  Description [Initializes a level queue. A level queue is a queue
157  where inserts are based on the levels of the nodes. Within each
158  level the policy is FIFO. Level queues are useful in traversing a
159  BDD top-down. Queue items are kept in a free list when dequeued for
160  efficiency. Returns a pointer to the new queue if successful; NULL
161  otherwise.]
162 
163  SideEffects [None]
164 
165  SeeAlso [cuddLevelQueueQuit cuddLevelQueueEnqueue cuddLevelQueueDequeue]
166 
167 ******************************************************************************/
168 DdLevelQueue *
170  int levels /* number of levels */,
171  int itemSize /* size of the item */,
172  int numBuckets /* initial number of hash buckets */)
173 {
174  DdLevelQueue *queue;
175  int logSize;
176 
177  queue = ABC_ALLOC(DdLevelQueue,1);
178  if (queue == NULL)
179  return(NULL);
180 #ifdef __osf__
181 #pragma pointer_size save
182 #pragma pointer_size short
183 #endif
184  /* Keep pointers to the insertion points for all levels. */
185  queue->last = ABC_ALLOC(DdQueueItem *, levels);
186 #ifdef __osf__
187 #pragma pointer_size restore
188 #endif
189  if (queue->last == NULL) {
190  ABC_FREE(queue);
191  return(NULL);
192  }
193  /* Use a hash table to test for uniqueness. */
194  if (numBuckets < 2) numBuckets = 2;
195  logSize = cuddComputeFloorLog2(numBuckets);
196  queue->numBuckets = 1 << logSize;
197  queue->shift = sizeof(int) * 8 - logSize;
198 #ifdef __osf__
199 #pragma pointer_size save
200 #pragma pointer_size short
201 #endif
202  queue->buckets = ABC_ALLOC(DdQueueItem *, queue->numBuckets);
203 #ifdef __osf__
204 #pragma pointer_size restore
205 #endif
206  if (queue->buckets == NULL) {
207  ABC_FREE(queue->last);
208  ABC_FREE(queue);
209  return(NULL);
210  }
211 #ifdef __osf__
212 #pragma pointer_size save
213 #pragma pointer_size short
214 #endif
215  memset(queue->last, 0, levels * sizeof(DdQueueItem *));
216  memset(queue->buckets, 0, queue->numBuckets * sizeof(DdQueueItem *));
217 #ifdef __osf__
218 #pragma pointer_size restore
219 #endif
220  queue->first = NULL;
221  queue->freelist = NULL;
222  queue->levels = levels;
223  queue->itemsize = itemSize;
224  queue->size = 0;
225  queue->maxsize = queue->numBuckets * DD_MAX_SUBTABLE_DENSITY;
226  return(queue);
227 
228 } /* end of cuddLevelQueueInit */
229 
230 
231 /**Function********************************************************************
232 
233  Synopsis [Shuts down a level queue.]
234 
235  Description [Shuts down a level queue and releases all the
236  associated memory.]
237 
238  SideEffects [None]
239 
240  SeeAlso [cuddLevelQueueInit]
241 
242 ******************************************************************************/
243 void
245  DdLevelQueue * queue)
246 {
247  DdQueueItem *item;
248 
249  while (queue->freelist != NULL) {
250  item = queue->freelist;
251  queue->freelist = item->next;
252  ABC_FREE(item);
253  }
254  while (queue->first != NULL) {
255  item = (DdQueueItem *) queue->first;
256  queue->first = item->next;
257  ABC_FREE(item);
258  }
259  ABC_FREE(queue->buckets);
260  ABC_FREE(queue->last);
261  ABC_FREE(queue);
262  return;
263 
264 } /* end of cuddLevelQueueQuit */
265 
266 
267 /**Function********************************************************************
268 
269  Synopsis [Inserts a new key in a level queue.]
270 
271  Description [Inserts a new key in a level queue. A new entry is
272  created in the queue only if the node is not already
273  enqueued. Returns a pointer to the queue item if successful; NULL
274  otherwise.]
275 
276  SideEffects [None]
277 
278  SeeAlso [cuddLevelQueueInit cuddLevelQueueDequeue]
279 
280 ******************************************************************************/
281 void *
283  DdLevelQueue * queue /* level queue */,
284  void * key /* key to be enqueued */,
285  int level /* level at which to insert */)
286 {
287  int plevel;
288  DdQueueItem *item;
289 
290 #ifdef DD_DEBUG
291  assert(level < queue->levels);
292 #endif
293  /* Check whether entry for this node exists. */
294  item = hashLookup(queue,key);
295  if (item != NULL) return(item);
296 
297  /* Get a free item from either the free list or the memory manager. */
298  if (queue->freelist == NULL) {
299  item = (DdQueueItem *) ABC_ALLOC(char, queue->itemsize);
300  if (item == NULL)
301  return(NULL);
302  } else {
303  item = queue->freelist;
304  queue->freelist = item->next;
305  }
306  /* Initialize. */
307  memset(item, 0, queue->itemsize);
308  item->key = key;
309  /* Update stats. */
310  queue->size++;
311 
312  if (queue->last[level]) {
313  /* There are already items for this level in the queue. */
314  item->next = queue->last[level]->next;
315  queue->last[level]->next = item;
316  } else {
317  /* There are no items at the current level. Look for the first
318  ** non-empty level preceeding this one. */
319  plevel = level;
320  while (plevel != 0 && queue->last[plevel] == NULL)
321  plevel--;
322  if (queue->last[plevel] == NULL) {
323  /* No element precedes this one in the queue. */
324  item->next = (DdQueueItem *) queue->first;
325  queue->first = item;
326  } else {
327  item->next = queue->last[plevel]->next;
328  queue->last[plevel]->next = item;
329  }
330  }
331  queue->last[level] = item;
332 
333  /* Insert entry for the key in the hash table. */
334  if (hashInsert(queue,item) == 0) {
335  return(NULL);
336  }
337  return(item);
338 
339 } /* end of cuddLevelQueueEnqueue */
340 
341 
342 /**Function********************************************************************
343 
344  Synopsis [Remove an item from the front of a level queue.]
345 
346  Description [Remove an item from the front of a level queue.]
347 
348  SideEffects [None]
349 
350  SeeAlso [cuddLevelQueueEnqueue]
351 
352 ******************************************************************************/
353 void
355  DdLevelQueue * queue,
356  int level)
357 {
358  DdQueueItem *item = (DdQueueItem *) queue->first;
359 
360  /* Delete from the hash table. */
361  hashDelete(queue,item);
362 
363  /* Since we delete from the front, if this is the last item for
364  ** its level, there are no other items for the same level. */
365  if (queue->last[level] == item)
366  queue->last[level] = NULL;
367 
368  queue->first = item->next;
369  /* Put item on the free list. */
370  item->next = queue->freelist;
371  queue->freelist = item;
372  /* Update stats. */
373  queue->size--;
374  return;
375 
376 } /* end of cuddLevelQueueDequeue */
377 
378 
379 /*---------------------------------------------------------------------------*/
380 /* Definition of static functions */
381 /*---------------------------------------------------------------------------*/
382 
383 
384 /**Function********************************************************************
385 
386  Synopsis [Looks up a key in the hash table of a level queue.]
387 
388  Description [Looks up a key in the hash table of a level queue. Returns
389  a pointer to the item with the given key if the key is found; NULL
390  otherwise.]
391 
392  SideEffects [None]
393 
394  SeeAlso [cuddLevelQueueEnqueue hashInsert]
395 
396 ******************************************************************************/
397 static DdQueueItem *
399  DdLevelQueue * queue,
400  void * key)
401 {
402  int posn;
403  DdQueueItem *item;
404 
405  posn = lqHash(key,queue->shift);
406  item = queue->buckets[posn];
407 
408  while (item != NULL) {
409  if (item->key == key) {
410  return(item);
411  }
412  item = item->cnext;
413  }
414  return(NULL);
415 
416 } /* end of hashLookup */
417 
418 
419 /**Function********************************************************************
420 
421  Synopsis [Inserts an item in the hash table of a level queue.]
422 
423  Description [Inserts an item in the hash table of a level queue. Returns
424  1 if successful; 0 otherwise. No check is performed to see if an item with
425  the same key is already in the hash table.]
426 
427  SideEffects [None]
428 
429  SeeAlso [cuddLevelQueueEnqueue]
430 
431 ******************************************************************************/
432 static int
434  DdLevelQueue * queue,
435  DdQueueItem * item)
436 {
437  int result;
438  int posn;
439 
440  if (queue->size > queue->maxsize) {
441  result = hashResize(queue);
442  if (result == 0) return(0);
443  }
444 
445  posn = lqHash(item->key,queue->shift);
446  item->cnext = queue->buckets[posn];
447  queue->buckets[posn] = item;
448 
449  return(1);
450 
451 } /* end of hashInsert */
452 
453 
454 /**Function********************************************************************
455 
456  Synopsis [Removes an item from the hash table of a level queue.]
457 
458  Description [Removes an item from the hash table of a level queue.
459  Nothing is done if the item is not in the table.]
460 
461  SideEffects [None]
462 
463  SeeAlso [cuddLevelQueueDequeue hashInsert]
464 
465 ******************************************************************************/
466 static void
468  DdLevelQueue * queue,
469  DdQueueItem * item)
470 {
471  int posn;
472  DdQueueItem *prevItem;
473 
474  posn = lqHash(item->key,queue->shift);
475  prevItem = queue->buckets[posn];
476 
477  if (prevItem == NULL) return;
478  if (prevItem == item) {
479  queue->buckets[posn] = prevItem->cnext;
480  return;
481  }
482 
483  while (prevItem->cnext != NULL) {
484  if (prevItem->cnext == item) {
485  prevItem->cnext = item->cnext;
486  return;
487  }
488  prevItem = prevItem->cnext;
489  }
490  return;
491 
492 } /* end of hashDelete */
493 
494 
495 /**Function********************************************************************
496 
497  Synopsis [Resizes the hash table of a level queue.]
498 
499  Description [Resizes the hash table of a level queue. Returns 1 if
500  successful; 0 otherwise.]
501 
502  SideEffects [None]
503 
504  SeeAlso [hashInsert]
505 
506 ******************************************************************************/
507 static int
509  DdLevelQueue * queue)
510 {
511  int j;
512  int posn;
513  DdQueueItem *item;
514  DdQueueItem *next;
515  int numBuckets;
516 #ifdef __osf__
517 #pragma pointer_size save
518 #pragma pointer_size short
519 #endif
520  DdQueueItem **buckets;
521  DdQueueItem **oldBuckets = queue->buckets;
522 #ifdef __osf__
523 #pragma pointer_size restore
524 #endif
525  int shift;
526  int oldNumBuckets = queue->numBuckets;
527  extern DD_OOMFP MMoutOfMemory;
528  DD_OOMFP saveHandler;
529 
530  /* Compute the new size of the subtable. */
531  numBuckets = oldNumBuckets << 1;
532  saveHandler = MMoutOfMemory;
533  MMoutOfMemory = Cudd_OutOfMem;
534 #ifdef __osf__
535 #pragma pointer_size save
536 #pragma pointer_size short
537 #endif
538  buckets = queue->buckets = ABC_ALLOC(DdQueueItem *, numBuckets);
539  MMoutOfMemory = saveHandler;
540  if (buckets == NULL) {
541  queue->maxsize <<= 1;
542  return(1);
543  }
544 
545  queue->numBuckets = numBuckets;
546  shift = --(queue->shift);
547  queue->maxsize <<= 1;
548  memset(buckets, 0, numBuckets * sizeof(DdQueueItem *));
549 #ifdef __osf__
550 #pragma pointer_size restore
551 #endif
552  for (j = 0; j < oldNumBuckets; j++) {
553  item = oldBuckets[j];
554  while (item != NULL) {
555  next = item->cnext;
556  posn = lqHash(item->key, shift);
557  item->cnext = buckets[posn];
558  buckets[posn] = item;
559  item = next;
560  }
561  }
562  ABC_FREE(oldBuckets);
563  return(1);
564 
565 } /* end of hashResize */
566 
567 
569 
char * memset()
int maxsize
Definition: cuddInt.h:516
int levels
Definition: cuddInt.h:513
void(* DD_OOMFP)(long)
Definition: cudd.h:324
void Cudd_OutOfMem(long size)
Definition: cuddUtil.c:2837
DdLevelQueue * cuddLevelQueueInit(int levels, int itemSize, int numBuckets)
Definition: cuddLevelQ.c:169
void cuddLevelQueueDequeue(DdLevelQueue *queue, int level)
Definition: cuddLevelQ.c:354
int numBuckets
Definition: cuddInt.h:517
#define ABC_ALLOC(type, num)
Definition: abc_global.h:229
static void hashDelete(DdLevelQueue *queue, DdQueueItem *item)
Definition: cuddLevelQ.c:467
#define DD_MAX_SUBTABLE_DENSITY
Definition: cuddInt.h:126
struct DdQueueItem * next
Definition: cuddInt.h:502
void cuddLevelQueueQuit(DdLevelQueue *queue)
Definition: cuddLevelQ.c:244
void * cuddLevelQueueEnqueue(DdLevelQueue *queue, void *key, int level)
Definition: cuddLevelQ.c:282
int cuddComputeFloorLog2(unsigned int value)
Definition: cuddCache.c:1079
#define ABC_NAMESPACE_IMPL_END
Definition: abc_global.h:108
static int hashInsert(DdLevelQueue *queue, DdQueueItem *item)
Definition: cuddLevelQ.c:433
void * first
Definition: cuddInt.h:509
static DdQueueItem * hashLookup(DdLevelQueue *queue, void *key)
Definition: cuddLevelQ.c:398
static ABC_NAMESPACE_IMPL_START char rcsid[] DD_UNUSED
Definition: cuddLevelQ.c:105
#define ABC_NAMESPACE_IMPL_START
Definition: abc_global.h:107
static int hashResize(DdLevelQueue *queue)
Definition: cuddLevelQ.c:508
#define ABC_FREE(obj)
Definition: abc_global.h:232
enum keys key
DdQueueItem * freelist
Definition: cuddInt.h:511
#define assert(ex)
Definition: util_old.h:213
DdQueueItem ** buckets
Definition: cuddInt.h:512
static int result
Definition: cuddGenetic.c:125
DdQueueItem ** last
Definition: cuddInt.h:510
#define lqHash(key, shift)
Definition: cuddLevelQ.c:128
struct DdQueueItem * cnext
Definition: cuddInt.h:503
void * key
Definition: cuddInt.h:504
int itemsize
Definition: cuddInt.h:514
#define MMoutOfMemory
Definition: util_hack.h:38