You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
583 lines
17 KiB
583 lines
17 KiB
/**CFile***********************************************************************
|
|
|
|
FileName [cuddLevelQ.c]
|
|
|
|
PackageName [cudd]
|
|
|
|
Synopsis [Procedure to manage level queues.]
|
|
|
|
Description [The functions in this file allow an application to
|
|
easily manipulate a queue where nodes are prioritized by level. The
|
|
emphasis is on efficiency. Therefore, the queue items can have
|
|
variable size. If the application does not need to attach
|
|
information to the nodes, it can declare the queue items to be of
|
|
type DdQueueItem. Otherwise, it can declare them to be of a
|
|
structure type such that the first three fields are data
|
|
pointers. The third pointer points to the node. The first two
|
|
pointers are used by the level queue functions. The remaining fields
|
|
are initialized to 0 when a new item is created, and are then left
|
|
to the exclusive use of the application. On the DEC Alphas the three
|
|
pointers must be 32-bit pointers when CUDD is compiled with 32-bit
|
|
pointers. The level queue functions make sure that each node
|
|
appears at most once in the queue. They do so by keeping a hash
|
|
table where the node is used as key. Queue items are recycled via a
|
|
free list for efficiency.
|
|
|
|
Internal procedures provided by this module:
|
|
<ul>
|
|
<li> cuddLevelQueueInit()
|
|
<li> cuddLevelQueueQuit()
|
|
<li> cuddLevelQueueEnqueue()
|
|
<li> cuddLevelQueueDequeue()
|
|
</ul>
|
|
Static procedures included in this module:
|
|
<ul>
|
|
<li> hashLookup()
|
|
<li> hashInsert()
|
|
<li> hashDelete()
|
|
<li> hashResize()
|
|
</ul>
|
|
]
|
|
|
|
SeeAlso []
|
|
|
|
Author [Fabio Somenzi]
|
|
|
|
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
|
|
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
Neither the name of the University of Colorado nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.]
|
|
|
|
******************************************************************************/
|
|
|
|
#include "util.h"
|
|
#include "cuddInt.h"
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Constant declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Stucture declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Type declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Variable declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#ifndef lint
|
|
static char rcsid[] DD_UNUSED = "$Id: cuddLevelQ.c,v 1.16 2012/02/05 01:07:19 fabio Exp $";
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Macro declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**Macro***********************************************************************
|
|
|
|
Synopsis [Hash function for the table of a level queue.]
|
|
|
|
Description [Hash function for the table of a level queue.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [hashInsert hashLookup hashDelete]
|
|
|
|
******************************************************************************/
|
|
#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
|
|
#define lqHash(key,shift) \
|
|
(((unsigned)(ptruint)(key) * DD_P1) >> (shift))
|
|
#else
|
|
#define lqHash(key,shift) \
|
|
(((unsigned)(key) * DD_P1) >> (shift))
|
|
#endif
|
|
|
|
|
|
/**AutomaticStart*************************************************************/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Static function prototypes */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static DdQueueItem * hashLookup(DdLevelQueue *queue, void *key);
|
|
static int hashInsert(DdLevelQueue *queue, DdQueueItem *item);
|
|
static void hashDelete(DdLevelQueue *queue, DdQueueItem *item);
|
|
static int hashResize(DdLevelQueue *queue);
|
|
|
|
/**AutomaticEnd***************************************************************/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of internal functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Initializes a level queue.]
|
|
|
|
Description [Initializes a level queue. A level queue is a queue
|
|
where inserts are based on the levels of the nodes. Within each
|
|
level the policy is FIFO. Level queues are useful in traversing a
|
|
BDD top-down. Queue items are kept in a free list when dequeued for
|
|
efficiency. Returns a pointer to the new queue if successful; NULL
|
|
otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddLevelQueueQuit cuddLevelQueueEnqueue cuddLevelQueueDequeue]
|
|
|
|
******************************************************************************/
|
|
DdLevelQueue *
|
|
cuddLevelQueueInit(
|
|
int levels /* number of levels */,
|
|
int itemSize /* size of the item */,
|
|
int numBuckets /* initial number of hash buckets */)
|
|
{
|
|
DdLevelQueue *queue;
|
|
int logSize;
|
|
|
|
queue = ALLOC(DdLevelQueue,1);
|
|
if (queue == NULL)
|
|
return(NULL);
|
|
/* Keep pointers to the insertion points for all levels. */
|
|
queue->last = ALLOC(DdQueueItem *, levels);
|
|
if (queue->last == NULL) {
|
|
FREE(queue);
|
|
return(NULL);
|
|
}
|
|
/* Use a hash table to test for uniqueness. */
|
|
if (numBuckets < 2) numBuckets = 2;
|
|
logSize = cuddComputeFloorLog2(numBuckets);
|
|
queue->numBuckets = 1 << logSize;
|
|
queue->shift = sizeof(int) * 8 - logSize;
|
|
queue->buckets = ALLOC(DdQueueItem *, queue->numBuckets);
|
|
if (queue->buckets == NULL) {
|
|
FREE(queue->last);
|
|
FREE(queue);
|
|
return(NULL);
|
|
}
|
|
memset(queue->last, 0, levels * sizeof(DdQueueItem *));
|
|
memset(queue->buckets, 0, queue->numBuckets * sizeof(DdQueueItem *));
|
|
queue->first = NULL;
|
|
queue->freelist = NULL;
|
|
queue->levels = levels;
|
|
queue->itemsize = itemSize;
|
|
queue->size = 0;
|
|
queue->maxsize = queue->numBuckets * DD_MAX_SUBTABLE_DENSITY;
|
|
return(queue);
|
|
|
|
} /* end of cuddLevelQueueInit */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Shuts down a level queue.]
|
|
|
|
Description [Shuts down a level queue and releases all the
|
|
associated memory.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddLevelQueueInit]
|
|
|
|
******************************************************************************/
|
|
void
|
|
cuddLevelQueueQuit(
|
|
DdLevelQueue * queue)
|
|
{
|
|
DdQueueItem *item;
|
|
|
|
while (queue->freelist != NULL) {
|
|
item = queue->freelist;
|
|
queue->freelist = item->next;
|
|
FREE(item);
|
|
}
|
|
while (queue->first != NULL) {
|
|
item = (DdQueueItem *) queue->first;
|
|
queue->first = item->next;
|
|
FREE(item);
|
|
}
|
|
FREE(queue->buckets);
|
|
FREE(queue->last);
|
|
FREE(queue);
|
|
return;
|
|
|
|
} /* end of cuddLevelQueueQuit */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Inserts a new key in a level queue.]
|
|
|
|
Description [Inserts a new key in a level queue. A new entry is
|
|
created in the queue only if the node is not already
|
|
enqueued. Returns a pointer to the queue item if successful; NULL
|
|
otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddLevelQueueInit cuddLevelQueueDequeue]
|
|
|
|
******************************************************************************/
|
|
void *
|
|
cuddLevelQueueEnqueue(
|
|
DdLevelQueue * queue /* level queue */,
|
|
void * key /* key to be enqueued */,
|
|
int level /* level at which to insert */)
|
|
{
|
|
DdQueueItem *item;
|
|
|
|
#ifdef DD_DEBUG
|
|
assert(level < queue->levels);
|
|
#endif
|
|
/* Check whether entry for this node exists. */
|
|
item = hashLookup(queue,key);
|
|
if (item != NULL) return(item);
|
|
|
|
/* Get a free item from either the free list or the memory manager. */
|
|
if (queue->freelist == NULL) {
|
|
item = (DdQueueItem *) ALLOC(char, queue->itemsize);
|
|
if (item == NULL)
|
|
return(NULL);
|
|
} else {
|
|
item = queue->freelist;
|
|
queue->freelist = item->next;
|
|
}
|
|
/* Initialize. */
|
|
memset(item, 0, queue->itemsize);
|
|
item->key = key;
|
|
/* Update stats. */
|
|
queue->size++;
|
|
|
|
if (queue->last[level]) {
|
|
/* There are already items for this level in the queue. */
|
|
item->next = queue->last[level]->next;
|
|
queue->last[level]->next = item;
|
|
} else {
|
|
/* There are no items at the current level. Look for the first
|
|
** non-empty level preceeding this one. */
|
|
int plevel = level;
|
|
while (plevel != 0 && queue->last[plevel] == NULL)
|
|
plevel--;
|
|
if (queue->last[plevel] == NULL) {
|
|
/* No element precedes this one in the queue. */
|
|
item->next = (DdQueueItem *) queue->first;
|
|
queue->first = item;
|
|
} else {
|
|
item->next = queue->last[plevel]->next;
|
|
queue->last[plevel]->next = item;
|
|
}
|
|
}
|
|
queue->last[level] = item;
|
|
|
|
/* Insert entry for the key in the hash table. */
|
|
if (hashInsert(queue,item) == 0) {
|
|
return(NULL);
|
|
}
|
|
return(item);
|
|
|
|
} /* end of cuddLevelQueueEnqueue */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Inserts the first key in a level queue.]
|
|
|
|
Description [Inserts the first key in a level queue. Returns a
|
|
pointer to the queue item if successful; NULL otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddLevelQueueEnqueue]
|
|
|
|
******************************************************************************/
|
|
void *
|
|
cuddLevelQueueFirst(
|
|
DdLevelQueue * queue /* level queue */,
|
|
void * key /* key to be enqueued */,
|
|
int level /* level at which to insert */)
|
|
{
|
|
DdQueueItem *item;
|
|
|
|
#ifdef DD_DEBUG
|
|
assert(level < queue->levels);
|
|
/* Check whether entry for this node exists. */
|
|
item = hashLookup(queue,key);
|
|
assert(item == NULL);
|
|
#endif
|
|
|
|
/* Get a free item from either the free list or the memory manager. */
|
|
if (queue->freelist == NULL) {
|
|
item = (DdQueueItem *) ALLOC(char, queue->itemsize);
|
|
if (item == NULL)
|
|
return(NULL);
|
|
} else {
|
|
item = queue->freelist;
|
|
queue->freelist = item->next;
|
|
}
|
|
/* Initialize. */
|
|
memset(item, 0, queue->itemsize);
|
|
item->key = key;
|
|
/* Update stats. */
|
|
queue->size = 1;
|
|
|
|
/* No element precedes this one in the queue. */
|
|
queue->first = item;
|
|
queue->last[level] = item;
|
|
|
|
/* Insert entry for the key in the hash table. */
|
|
if (hashInsert(queue,item) == 0) {
|
|
return(NULL);
|
|
}
|
|
return(item);
|
|
|
|
} /* end of cuddLevelQueueFirst */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Remove an item from the front of a level queue.]
|
|
|
|
Description [Remove an item from the front of a level queue.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddLevelQueueEnqueue]
|
|
|
|
******************************************************************************/
|
|
void
|
|
cuddLevelQueueDequeue(
|
|
DdLevelQueue * queue,
|
|
int level)
|
|
{
|
|
DdQueueItem *item = (DdQueueItem *) queue->first;
|
|
|
|
/* Delete from the hash table. */
|
|
hashDelete(queue,item);
|
|
|
|
/* Since we delete from the front, if this is the last item for
|
|
** its level, there are no other items for the same level. */
|
|
if (queue->last[level] == item) {
|
|
queue->last[level] = NULL;
|
|
}
|
|
|
|
queue->first = item->next;
|
|
/* Put item on the free list. */
|
|
item->next = queue->freelist;
|
|
queue->freelist = item;
|
|
/* Update stats. */
|
|
queue->size--;
|
|
return;
|
|
|
|
} /* end of cuddLevelQueueDequeue */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of static functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Looks up a key in the hash table of a level queue.]
|
|
|
|
Description [Looks up a key in the hash table of a level queue. Returns
|
|
a pointer to the item with the given key if the key is found; NULL
|
|
otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddLevelQueueEnqueue hashInsert]
|
|
|
|
******************************************************************************/
|
|
static DdQueueItem *
|
|
hashLookup(
|
|
DdLevelQueue * queue,
|
|
void * key)
|
|
{
|
|
int posn;
|
|
DdQueueItem *item;
|
|
|
|
posn = lqHash(key,queue->shift);
|
|
item = queue->buckets[posn];
|
|
|
|
while (item != NULL) {
|
|
if (item->key == key) {
|
|
return(item);
|
|
}
|
|
item = item->cnext;
|
|
}
|
|
return(NULL);
|
|
|
|
} /* end of hashLookup */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Inserts an item in the hash table of a level queue.]
|
|
|
|
Description [Inserts an item in the hash table of a level queue. Returns
|
|
1 if successful; 0 otherwise. No check is performed to see if an item with
|
|
the same key is already in the hash table.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddLevelQueueEnqueue]
|
|
|
|
******************************************************************************/
|
|
static int
|
|
hashInsert(
|
|
DdLevelQueue * queue,
|
|
DdQueueItem * item)
|
|
{
|
|
int result;
|
|
int posn;
|
|
|
|
if (queue->size > queue->maxsize) {
|
|
result = hashResize(queue);
|
|
if (result == 0) return(0);
|
|
}
|
|
|
|
posn = lqHash(item->key,queue->shift);
|
|
item->cnext = queue->buckets[posn];
|
|
queue->buckets[posn] = item;
|
|
|
|
return(1);
|
|
|
|
} /* end of hashInsert */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Removes an item from the hash table of a level queue.]
|
|
|
|
Description [Removes an item from the hash table of a level queue.
|
|
Nothing is done if the item is not in the table.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddLevelQueueDequeue hashInsert]
|
|
|
|
******************************************************************************/
|
|
static void
|
|
hashDelete(
|
|
DdLevelQueue * queue,
|
|
DdQueueItem * item)
|
|
{
|
|
int posn;
|
|
DdQueueItem *prevItem;
|
|
|
|
posn = lqHash(item->key,queue->shift);
|
|
prevItem = queue->buckets[posn];
|
|
|
|
if (prevItem == NULL) return;
|
|
if (prevItem == item) {
|
|
queue->buckets[posn] = prevItem->cnext;
|
|
return;
|
|
}
|
|
|
|
while (prevItem->cnext != NULL) {
|
|
if (prevItem->cnext == item) {
|
|
prevItem->cnext = item->cnext;
|
|
return;
|
|
}
|
|
prevItem = prevItem->cnext;
|
|
}
|
|
return;
|
|
|
|
} /* end of hashDelete */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Resizes the hash table of a level queue.]
|
|
|
|
Description [Resizes the hash table of a level queue. Returns 1 if
|
|
successful; 0 otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [hashInsert]
|
|
|
|
******************************************************************************/
|
|
static int
|
|
hashResize(
|
|
DdLevelQueue * queue)
|
|
{
|
|
int j;
|
|
int posn;
|
|
DdQueueItem *item;
|
|
DdQueueItem *next;
|
|
int numBuckets;
|
|
DdQueueItem **buckets;
|
|
DdQueueItem **oldBuckets = queue->buckets;
|
|
int shift;
|
|
int oldNumBuckets = queue->numBuckets;
|
|
extern DD_OOMFP MMoutOfMemory;
|
|
DD_OOMFP saveHandler;
|
|
|
|
/* Compute the new size of the subtable. */
|
|
numBuckets = oldNumBuckets << 1;
|
|
saveHandler = MMoutOfMemory;
|
|
MMoutOfMemory = Cudd_OutOfMem;
|
|
buckets = queue->buckets = ALLOC(DdQueueItem *, numBuckets);
|
|
MMoutOfMemory = saveHandler;
|
|
if (buckets == NULL) {
|
|
queue->maxsize <<= 1;
|
|
return(1);
|
|
}
|
|
|
|
queue->numBuckets = numBuckets;
|
|
shift = --(queue->shift);
|
|
queue->maxsize <<= 1;
|
|
memset(buckets, 0, numBuckets * sizeof(DdQueueItem *));
|
|
for (j = 0; j < oldNumBuckets; j++) {
|
|
item = oldBuckets[j];
|
|
while (item != NULL) {
|
|
next = item->cnext;
|
|
posn = lqHash(item->key, shift);
|
|
item->cnext = buckets[posn];
|
|
buckets[posn] = item;
|
|
item = next;
|
|
}
|
|
}
|
|
FREE(oldBuckets);
|
|
return(1);
|
|
|
|
} /* end of hashResize */
|