diff options
Diffstat (limited to 'abc70930/src/bdd/cudd/cuddTable.c')
-rw-r--r-- | abc70930/src/bdd/cudd/cuddTable.c | 3141 |
1 files changed, 0 insertions, 3141 deletions
diff --git a/abc70930/src/bdd/cudd/cuddTable.c b/abc70930/src/bdd/cudd/cuddTable.c deleted file mode 100644 index 7f14aed1..00000000 --- a/abc70930/src/bdd/cudd/cuddTable.c +++ /dev/null @@ -1,3141 +0,0 @@ -/**CFile*********************************************************************** - - FileName [cuddTable.c] - - PackageName [cudd] - - Synopsis [Unique table management functions.] - - Description [External procedures included in this module: - <ul> - <li> Cudd_Prime() - </ul> - Internal procedures included in this module: - <ul> - <li> cuddAllocNode() - <li> cuddInitTable() - <li> cuddFreeTable() - <li> cuddGarbageCollect() - <li> cuddGarbageCollectZdd() - <li> cuddZddGetNode() - <li> cuddZddGetNodeIVO() - <li> cuddUniqueInter() - <li> cuddUniqueInterIVO() - <li> cuddUniqueInterZdd() - <li> cuddUniqueConst() - <li> cuddRehash() - <li> cuddShrinkSubtable() - <li> cuddInsertSubtables() - <li> cuddDestroySubtables() - <li> cuddResizeTableZdd() - <li> cuddSlowTableGrowth() - </ul> - Static procedures included in this module: - <ul> - <li> ddRehashZdd() - <li> ddResizeTable() - <li> cuddFindParent() - <li> cuddOrderedInsert() - <li> cuddOrderedThread() - <li> cuddRotateLeft() - <li> cuddRotateRight() - <li> cuddDoRebalance() - <li> cuddCheckCollisionOrdering() - </ul>] - - SeeAlso [] - - Author [Fabio Somenzi] - - Copyright [This file was created at the University of Colorado at - Boulder. The University of Colorado at Boulder makes no warranty - about the suitability of this software for any purpose. It is - presented on an AS IS basis.] - -******************************************************************************/ - -#include "util_hack.h" -#include "cuddInt.h" - -/*---------------------------------------------------------------------------*/ -/* Constant declarations */ -/*---------------------------------------------------------------------------*/ - -#ifndef DD_UNSORTED_FREE_LIST -/* Constants for red/black trees. */ -#define DD_STACK_SIZE 128 -#define DD_RED 0 -#define DD_BLACK 1 -#define DD_PAGE_SIZE 8192 -#define DD_PAGE_MASK ~(DD_PAGE_SIZE - 1) -#define DD_INSERT_COMPARE(x,y) \ - (((ptruint) (x) & DD_PAGE_MASK) - ((ptruint) (y) & DD_PAGE_MASK)) -#endif - -/*---------------------------------------------------------------------------*/ -/* Stucture declarations */ -/*---------------------------------------------------------------------------*/ - -/* This is a hack for when CUDD_VALUE_TYPE is double */ -typedef union hack { - CUDD_VALUE_TYPE value; - unsigned int bits[2]; -} hack; - -/*---------------------------------------------------------------------------*/ -/* Type declarations */ -/*---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------*/ -/* Variable declarations */ -/*---------------------------------------------------------------------------*/ - -#ifndef lint -static char rcsid[] DD_UNUSED = "$Id: cuddTable.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $"; -#endif - -/*---------------------------------------------------------------------------*/ -/* Macro declarations */ -/*---------------------------------------------------------------------------*/ - - -#ifndef DD_UNSORTED_FREE_LIST -/* Macros for red/black trees. */ -#define DD_COLOR(p) ((p)->index) -#define DD_IS_BLACK(p) ((p)->index == DD_BLACK) -#define DD_IS_RED(p) ((p)->index == DD_RED) -#define DD_LEFT(p) cuddT(p) -#define DD_RIGHT(p) cuddE(p) -#define DD_NEXT(p) ((p)->next) -#endif - - -/**AutomaticStart*************************************************************/ - -/*---------------------------------------------------------------------------*/ -/* Static function prototypes */ -/*---------------------------------------------------------------------------*/ - -static void ddRehashZdd ARGS((DdManager *unique, int i)); -static int ddResizeTable ARGS((DdManager *unique, int index)); -static int cuddFindParent ARGS((DdManager *table, DdNode *node)); -DD_INLINE static void ddFixLimits ARGS((DdManager *unique)); -static void cuddOrderedInsert ARGS((DdNodePtr *root, DdNodePtr node)); -static DdNode * cuddOrderedThread ARGS((DdNode *root, DdNode *list)); -static void cuddRotateLeft ARGS((DdNodePtr *nodeP)); -static void cuddRotateRight ARGS((DdNodePtr *nodeP)); -static void cuddDoRebalance ARGS((DdNodePtr **stack, int stackN)); -static void ddPatchTree ARGS((DdManager *dd, MtrNode *treenode)); -#ifdef DD_DEBUG -static int cuddCheckCollisionOrdering ARGS((DdManager *unique, int i, int j)); -#endif -static void ddReportRefMess ARGS((DdManager *unique, int i, char *caller)); - -/**AutomaticEnd***************************************************************/ - - -/*---------------------------------------------------------------------------*/ -/* Definition of exported functions */ -/*---------------------------------------------------------------------------*/ - - -/**Function******************************************************************** - - Synopsis [Returns the next prime >= p.] - - Description [] - - SideEffects [None] - -******************************************************************************/ -unsigned int -Cudd_Prime( - unsigned int p) -{ - int i,pn; - - p--; - do { - p++; - if (p&1) { - pn = 1; - i = 3; - while ((unsigned) (i * i) <= p) { - if (p % i == 0) { - pn = 0; - break; - } - i += 2; - } - } else { - pn = 0; - } - } while (!pn); - return(p); - -} /* end of Cudd_Prime */ - - -/*---------------------------------------------------------------------------*/ -/* Definition of internal functions */ -/*---------------------------------------------------------------------------*/ - - -/**Function******************************************************************** - - Synopsis [Fast storage allocation for DdNodes in the table.] - - Description [Fast storage allocation for DdNodes in the table. The - first 4 bytes of a chunk contain a pointer to the next block; the - rest contains DD_MEM_CHUNK spaces for DdNodes. Returns a pointer to - a new node if successful; NULL is memory is full.] - - SideEffects [None] - - SeeAlso [cuddDynamicAllocNode] - -******************************************************************************/ -DdNode * -cuddAllocNode( - DdManager * unique) -{ - int i; - DdNodePtr *mem; - DdNode *list, *node; - extern void (*MMoutOfMemory)(long); - void (*saveHandler)(long); - - if (unique->nextFree == NULL) { /* free list is empty */ - /* Check for exceeded limits. */ - if ((unique->keys - unique->dead) + (unique->keysZ - unique->deadZ) > - unique->maxLive) { - unique->errorCode = CUDD_TOO_MANY_NODES; - return(NULL); - } - if (unique->stash == NULL || unique->memused > unique->maxmemhard) { - (void) cuddGarbageCollect(unique,1); - mem = NULL; - } - if (unique->nextFree == NULL) { - if (unique->memused > unique->maxmemhard) { - unique->errorCode = CUDD_MAX_MEM_EXCEEDED; - return(NULL); - } - /* Try to allocate a new block. */ - saveHandler = MMoutOfMemory; - MMoutOfMemory = Cudd_OutOfMem; - mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1); - MMoutOfMemory = saveHandler; - if (mem == NULL) { - /* No more memory: Try collecting garbage. If this succeeds, - ** we end up with mem still NULL, but unique->nextFree != - ** NULL. */ - if (cuddGarbageCollect(unique,1) == 0) { - /* Last resort: Free the memory stashed away, if there - ** any. If this succeeeds, mem != NULL and - ** unique->nextFree still NULL. */ - if (unique->stash != NULL) { - FREE(unique->stash); - unique->stash = NULL; - /* Inhibit resizing of tables. */ - cuddSlowTableGrowth(unique); - /* Now try again. */ - mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1); - } - if (mem == NULL) { - /* Out of luck. Call the default handler to do - ** whatever it specifies for a failed malloc. - ** If this handler returns, then set error code, - ** print warning, and return. */ - (*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1)); - unique->errorCode = CUDD_MEMORY_OUT; -#ifdef DD_VERBOSE - (void) fprintf(unique->err, - "cuddAllocNode: out of memory"); - (void) fprintf(unique->err, "Memory in use = %ld\n", - unique->memused); -#endif - return(NULL); - } - } - } - if (mem != NULL) { /* successful allocation; slice memory */ - ptruint offset; - unique->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode); - mem[0] = (DdNodePtr) unique->memoryList; - unique->memoryList = mem; - - /* Here we rely on the fact that a DdNode is as large - ** as 4 pointers. */ - offset = (ptruint) mem & (sizeof(DdNode) - 1); - mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr); - assert(((ptruint) mem & (sizeof(DdNode) - 1)) == 0); - list = (DdNode *) mem; - - i = 1; - do { - list[i - 1].next = &list[i]; - } while (++i < DD_MEM_CHUNK); - - list[DD_MEM_CHUNK-1].next = NULL; - - unique->nextFree = &list[0]; - } - } - } - unique->allocated++; - node = unique->nextFree; - unique->nextFree = node->next; - return(node); - -} /* end of cuddAllocNode */ - - -/**Function******************************************************************** - - Synopsis [Creates and initializes the unique table.] - - Description [Creates and initializes the unique table. Returns a pointer - to the table if successful; NULL otherwise.] - - SideEffects [None] - - SeeAlso [Cudd_Init cuddFreeTable] - -******************************************************************************/ -DdManager * -cuddInitTable( - unsigned int numVars /* Initial number of BDD variables (and subtables) */, - unsigned int numVarsZ /* Initial number of ZDD variables (and subtables) */, - unsigned int numSlots /* Initial size of the BDD subtables */, - unsigned int looseUpTo /* Limit for fast table growth */) -{ - DdManager *unique = ALLOC(DdManager,1); - int i, j; - DdNodePtr *nodelist; - DdNode *sentinel; - unsigned int slots; - int shift; - - if (unique == NULL) { - return(NULL); - } - sentinel = &(unique->sentinel); - sentinel->ref = 0; - sentinel->index = 0; - cuddT(sentinel) = NULL; - cuddE(sentinel) = NULL; - sentinel->next = NULL; - unique->epsilon = DD_EPSILON; - unique->maxGrowth = DD_MAX_REORDER_GROWTH; - unique->maxGrowthAlt = 2.0 * DD_MAX_REORDER_GROWTH; - unique->reordCycle = 0; /* do not use alternate threshold */ - unique->size = numVars; - unique->sizeZ = numVarsZ; - unique->maxSize = ddMax(DD_DEFAULT_RESIZE, numVars); - unique->maxSizeZ = ddMax(DD_DEFAULT_RESIZE, numVarsZ); - - /* Adjust the requested number of slots to a power of 2. */ - slots = 8; - while (slots < numSlots) { - slots <<= 1; - } - unique->initSlots = slots; - shift = sizeof(int) * 8 - cuddComputeFloorLog2(slots); - - unique->slots = (numVars + numVarsZ + 1) * slots; - unique->keys = 0; - unique->maxLive = ~0; /* very large number */ - unique->keysZ = 0; - unique->dead = 0; - unique->deadZ = 0; - unique->gcFrac = DD_GC_FRAC_HI; - unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots); - unique->looseUpTo = looseUpTo; - unique->gcEnabled = 1; - unique->allocated = 0; - unique->reclaimed = 0; - unique->subtables = ALLOC(DdSubtable,unique->maxSize); - if (unique->subtables == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - unique->subtableZ = ALLOC(DdSubtable,unique->maxSizeZ); - if (unique->subtableZ == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - unique->perm = ALLOC(int,unique->maxSize); - if (unique->perm == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - unique->invperm = ALLOC(int,unique->maxSize); - if (unique->invperm == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - unique->permZ = ALLOC(int,unique->maxSizeZ); - if (unique->permZ == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - unique->invpermZ = ALLOC(int,unique->maxSizeZ); - if (unique->invpermZ == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - unique->map = NULL; - unique->stack = ALLOC(DdNodePtr,ddMax(unique->maxSize,unique->maxSizeZ)+1); - if (unique->stack == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - unique->stack[0] = NULL; /* to suppress harmless UMR */ - -#ifndef DD_NO_DEATH_ROW - unique->deathRowDepth = 1 << cuddComputeFloorLog2(unique->looseUpTo >> 2); - unique->deathRow = ALLOC(DdNodePtr,unique->deathRowDepth); - if (unique->deathRow == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - for (i = 0; i < unique->deathRowDepth; i++) { - unique->deathRow[i] = NULL; - } - unique->nextDead = 0; - unique->deadMask = unique->deathRowDepth - 1; -#endif - - for (i = 0; (unsigned) i < numVars; i++) { - unique->subtables[i].slots = slots; - unique->subtables[i].shift = shift; - unique->subtables[i].keys = 0; - unique->subtables[i].dead = 0; - unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY; - unique->subtables[i].bindVar = 0; - unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT; - unique->subtables[i].pairIndex = 0; - unique->subtables[i].varHandled = 0; - unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE; - - nodelist = unique->subtables[i].nodelist = ALLOC(DdNodePtr,slots); - if (nodelist == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(NULL); - } - for (j = 0; (unsigned) j < slots; j++) { - nodelist[j] = sentinel; - } - unique->perm[i] = i; - unique->invperm[i] = i; - } - for (i = 0; (unsigned) i < numVarsZ; i++) { - unique->subtableZ[i].slots = slots; - unique->subtableZ[i].shift = shift; - unique->subtableZ[i].keys = 0; - unique->subtableZ[i].dead = 0; - unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY; - nodelist = unique->subtableZ[i].nodelist = ALLOC(DdNodePtr,slots); - if (nodelist == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(NULL); - } - for (j = 0; (unsigned) j < slots; j++) { - nodelist[j] = NULL; - } - unique->permZ[i] = i; - unique->invpermZ[i] = i; - } - unique->constants.slots = slots; - unique->constants.shift = shift; - unique->constants.keys = 0; - unique->constants.dead = 0; - unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY; - nodelist = unique->constants.nodelist = ALLOC(DdNodePtr,slots); - if (nodelist == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(NULL); - } - for (j = 0; (unsigned) j < slots; j++) { - nodelist[j] = NULL; - } - - unique->memoryList = NULL; - unique->nextFree = NULL; - - unique->memused = sizeof(DdManager) + (unique->maxSize + unique->maxSizeZ) - * (sizeof(DdSubtable) + 2 * sizeof(int)) + (numVars + 1) * - slots * sizeof(DdNodePtr) + - (ddMax(unique->maxSize,unique->maxSizeZ) + 1) * sizeof(DdNodePtr); -#ifndef DD_NO_DEATH_ROW - unique->memused += unique->deathRowDepth * sizeof(DdNodePtr); -#endif - - /* Initialize fields concerned with automatic dynamic reordering */ - unique->reorderings = 0; - unique->autoDyn = 0; /* initially disabled */ - unique->autoDynZ = 0; /* initially disabled */ - unique->realign = 0; /* initially disabled */ - unique->realignZ = 0; /* initially disabled */ - unique->reordered = 0; - unique->autoMethod = CUDD_REORDER_SIFT; - unique->autoMethodZ = CUDD_REORDER_SIFT; - unique->nextDyn = DD_FIRST_REORDER; - unique->countDead = ~0; - unique->siftMaxVar = DD_SIFT_MAX_VAR; - unique->siftMaxSwap = DD_SIFT_MAX_SWAPS; - unique->tree = NULL; - unique->treeZ = NULL; - unique->groupcheck = CUDD_GROUP_CHECK7; - unique->recomb = DD_DEFAULT_RECOMB; - unique->symmviolation = 0; - unique->arcviolation = 0; - unique->populationSize = 0; - unique->numberXovers = 0; - unique->linear = NULL; - unique->linearSize = 0; - - /* Initialize ZDD universe. */ - unique->univ = (DdNodePtr *)NULL; - - /* Initialize auxiliary fields. */ - unique->localCaches = NULL; - unique->preGCHook = NULL; - unique->postGCHook = NULL; - unique->preReorderingHook = NULL; - unique->postReorderingHook = NULL; - unique->out = stdout; - unique->err = stderr; - unique->errorCode = CUDD_NO_ERROR; - - /* Initialize statistical counters. */ - unique->maxmemhard = (long) ((~ (unsigned long) 0) >> 1); - unique->garbageCollections = 0; - unique->GCTime = 0; - unique->reordTime = 0; -#ifdef DD_STATS - unique->nodesDropped = 0; - unique->nodesFreed = 0; -#endif - unique->peakLiveNodes = 0; -#ifdef DD_UNIQUE_PROFILE - unique->uniqueLookUps = 0; - unique->uniqueLinks = 0; -#endif -#ifdef DD_COUNT - unique->recursiveCalls = 0; - unique->swapSteps = 0; -#ifdef DD_STATS - unique->nextSample = 250000; -#endif -#endif - - return(unique); - -} /* end of cuddInitTable */ - - -/**Function******************************************************************** - - Synopsis [Frees the resources associated to a unique table.] - - Description [] - - SideEffects [None] - - SeeAlso [cuddInitTable] - -******************************************************************************/ -void -cuddFreeTable( - DdManager * unique) -{ - DdNodePtr *next; - DdNodePtr *memlist = unique->memoryList; - int i; - - if (unique->univ != NULL) cuddZddFreeUniv(unique); - while (memlist != NULL) { - next = (DdNodePtr *) memlist[0]; /* link to next block */ - FREE(memlist); - memlist = next; - } - unique->nextFree = NULL; - unique->memoryList = NULL; - - for (i = 0; i < unique->size; i++) { - FREE(unique->subtables[i].nodelist); - } - for (i = 0; i < unique->sizeZ; i++) { - FREE(unique->subtableZ[i].nodelist); - } - FREE(unique->constants.nodelist); - FREE(unique->subtables); - FREE(unique->subtableZ); - FREE(unique->acache); - FREE(unique->perm); - FREE(unique->permZ); - FREE(unique->invperm); - FREE(unique->invpermZ); - FREE(unique->vars); - if (unique->map != NULL) FREE(unique->map); - FREE(unique->stack); -#ifndef DD_NO_DEATH_ROW - FREE(unique->deathRow); -#endif - if (unique->tree != NULL) Mtr_FreeTree(unique->tree); - if (unique->treeZ != NULL) Mtr_FreeTree(unique->treeZ); - if (unique->linear != NULL) FREE(unique->linear); - while (unique->preGCHook != NULL) - Cudd_RemoveHook(unique,unique->preGCHook->f,CUDD_PRE_GC_HOOK); - while (unique->postGCHook != NULL) - Cudd_RemoveHook(unique,unique->postGCHook->f,CUDD_POST_GC_HOOK); - while (unique->preReorderingHook != NULL) - Cudd_RemoveHook(unique,unique->preReorderingHook->f, - CUDD_PRE_REORDERING_HOOK); - while (unique->postReorderingHook != NULL) - Cudd_RemoveHook(unique,unique->postReorderingHook->f, - CUDD_POST_REORDERING_HOOK); - FREE(unique); - -} /* end of cuddFreeTable */ - - -/**Function******************************************************************** - - Synopsis [Performs garbage collection on a unique table.] - - Description [Performs garbage collection on a unique table. - If clearCache is 0, the cache is not cleared. This should only be - specified if the cache has been cleared right before calling - cuddGarbageCollect. (As in the case of dynamic reordering.) - Returns the total number of deleted nodes.] - - SideEffects [None] - - SeeAlso [cuddGarbageCollectZdd] - -******************************************************************************/ -int -cuddGarbageCollect( - DdManager * unique, - int clearCache) -{ - DdHook *hook; - DdCache *cache = unique->cache; - DdNode *sentinel = &(unique->sentinel); - DdNodePtr *nodelist; - int i, j, deleted, totalDeleted; - DdCache *c; - DdNode *node,*next; - DdNodePtr *lastP; - int slots; - long localTime; -#ifndef DD_UNSORTED_FREE_LIST - DdNodePtr tree; -#endif - -#ifndef DD_NO_DEATH_ROW - cuddClearDeathRow(unique); -#endif - - hook = unique->preGCHook; - while (hook != NULL) { - int res = (hook->f)(unique,"BDD",NULL); - if (res == 0) return(0); - hook = hook->next; - } - - if (unique->dead == 0) { - hook = unique->postGCHook; - while (hook != NULL) { - int res = (hook->f)(unique,"BDD",NULL); - if (res == 0) return(0); - hook = hook->next; - } - return(0); - } - - /* If many nodes are being reclaimed, we want to resize the tables - ** more aggressively, to reduce the frequency of garbage collection. - */ - if (clearCache && unique->gcFrac == DD_GC_FRAC_LO && - unique->slots <= unique->looseUpTo && unique->stash != NULL) { - unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots); -#ifdef DD_VERBOSE - (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_HI); - (void) fprintf(unique->err,"minDead = %d\n", unique->minDead); -#endif - unique->gcFrac = DD_GC_FRAC_HI; - return(0); - } - - localTime = util_cpu_time(); - - unique->garbageCollections++; -#ifdef DD_VERBOSE - (void) fprintf(unique->err, - "garbage collecting (%d dead out of %d, min %d)...", - unique->dead, unique->keys, unique->minDead); -#endif - - /* Remove references to garbage collected nodes from the cache. */ - if (clearCache) { - slots = unique->cacheSlots; - for (i = 0; i < slots; i++) { - c = &cache[i]; - if (c->data != NULL) { - if (cuddClean(c->f)->ref == 0 || - cuddClean(c->g)->ref == 0 || - (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) || - (c->data != DD_NON_CONSTANT && - Cudd_Regular(c->data)->ref == 0)) { - c->data = NULL; - unique->cachedeletions++; - } - } - } - cuddLocalCacheClearDead(unique); - } - - /* Now return dead nodes to free list. Count them for sanity check. */ - totalDeleted = 0; -#ifndef DD_UNSORTED_FREE_LIST - tree = NULL; -#endif - - for (i = 0; i < unique->size; i++) { - if (unique->subtables[i].dead == 0) continue; - nodelist = unique->subtables[i].nodelist; - - deleted = 0; - slots = unique->subtables[i].slots; - for (j = 0; j < slots; j++) { - lastP = &(nodelist[j]); - node = *lastP; - while (node != sentinel) { - next = node->next; - if (node->ref == 0) { - deleted++; -#ifndef DD_UNSORTED_FREE_LIST -#ifdef __osf__ -#pragma pointer_size save -#pragma pointer_size short -#endif - cuddOrderedInsert(&tree,node); -#ifdef __osf__ -#pragma pointer_size restore -#endif -#else - cuddDeallocNode(unique,node); -#endif - } else { - *lastP = node; - lastP = &(node->next); - } - node = next; - } - *lastP = sentinel; - } - if ((unsigned) deleted != unique->subtables[i].dead) { - ddReportRefMess(unique, i, "cuddGarbageCollect"); - } - totalDeleted += deleted; - unique->subtables[i].keys -= deleted; - unique->subtables[i].dead = 0; - } - if (unique->constants.dead != 0) { - nodelist = unique->constants.nodelist; - deleted = 0; - slots = unique->constants.slots; - for (j = 0; j < slots; j++) { - lastP = &(nodelist[j]); - node = *lastP; - while (node != NULL) { - next = node->next; - if (node->ref == 0) { - deleted++; -#ifndef DD_UNSORTED_FREE_LIST -#ifdef __osf__ -#pragma pointer_size save -#pragma pointer_size short -#endif - cuddOrderedInsert(&tree,node); -#ifdef __osf__ -#pragma pointer_size restore -#endif -#else - cuddDeallocNode(unique,node); -#endif - } else { - *lastP = node; - lastP = &(node->next); - } - node = next; - } - *lastP = NULL; - } - if ((unsigned) deleted != unique->constants.dead) { - ddReportRefMess(unique, CUDD_CONST_INDEX, "cuddGarbageCollect"); - } - totalDeleted += deleted; - unique->constants.keys -= deleted; - unique->constants.dead = 0; - } - if ((unsigned) totalDeleted != unique->dead) { - ddReportRefMess(unique, -1, "cuddGarbageCollect"); - } - unique->keys -= totalDeleted; - unique->dead = 0; -#ifdef DD_STATS - unique->nodesFreed += (double) totalDeleted; -#endif - -#ifndef DD_UNSORTED_FREE_LIST - unique->nextFree = cuddOrderedThread(tree,unique->nextFree); -#endif - - unique->GCTime += util_cpu_time() - localTime; - - hook = unique->postGCHook; - while (hook != NULL) { - int res = (hook->f)(unique,"BDD",NULL); - if (res == 0) return(0); - hook = hook->next; - } - -#ifdef DD_VERBOSE - (void) fprintf(unique->err," done\n"); -#endif - - return(totalDeleted); - -} /* end of cuddGarbageCollect */ - - -/**Function******************************************************************** - - Synopsis [Performs garbage collection on a ZDD unique table.] - - Description [Performs garbage collection on a ZDD unique table. - If clearCache is 0, the cache is not cleared. This should only be - specified if the cache has been cleared right before calling - cuddGarbageCollectZdd. (As in the case of dynamic reordering.) - Returns the total number of deleted nodes.] - - SideEffects [None] - - SeeAlso [cuddGarbageCollect] - -******************************************************************************/ -int -cuddGarbageCollectZdd( - DdManager * unique, - int clearCache) -{ - DdHook *hook; - DdCache *cache = unique->cache; - DdNodePtr *nodelist; - int i, j, deleted, totalDeleted; - DdCache *c; - DdNode *node,*next; - DdNodePtr *lastP; - int slots; - long localTime; -#ifndef DD_UNSORTED_FREE_LIST - DdNodePtr tree; -#endif - - hook = unique->preGCHook; - while (hook != NULL) { - int res = (hook->f)(unique,"ZDD",NULL); - if (res == 0) return(0); - hook = hook->next; - } - - if (unique->deadZ == 0) { - hook = unique->postGCHook; - while (hook != NULL) { - int res = (hook->f)(unique,"ZDD",NULL); - if (res == 0) return(0); - hook = hook->next; - } - return(0); - } - - /* If many nodes are being reclaimed, we want to resize the tables - ** more aggressively, to reduce the frequency of garbage collection. - */ - if (clearCache && unique->slots <= unique->looseUpTo) { - unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots); -#ifdef DD_VERBOSE - if (unique->gcFrac == DD_GC_FRAC_LO) { - (void) fprintf(unique->err,"GC fraction = %.2f\t", - DD_GC_FRAC_HI); - (void) fprintf(unique->err,"minDead = %d\n", unique->minDead); - } -#endif - unique->gcFrac = DD_GC_FRAC_HI; - } - - localTime = util_cpu_time(); - - unique->garbageCollections++; -#ifdef DD_VERBOSE - (void) fprintf(unique->err,"garbage collecting (%d dead out of %d)...", - unique->deadZ,unique->keysZ); -#endif - - /* Remove references to garbage collected nodes from the cache. */ - if (clearCache) { - slots = unique->cacheSlots; - for (i = 0; i < slots; i++) { - c = &cache[i]; - if (c->data != NULL) { - if (cuddClean(c->f)->ref == 0 || - cuddClean(c->g)->ref == 0 || - (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) || - (c->data != DD_NON_CONSTANT && - Cudd_Regular(c->data)->ref == 0)) { - c->data = NULL; - unique->cachedeletions++; - } - } - } - } - - /* Now return dead nodes to free list. Count them for sanity check. */ - totalDeleted = 0; -#ifndef DD_UNSORTED_FREE_LIST - tree = NULL; -#endif - - for (i = 0; i < unique->sizeZ; i++) { - if (unique->subtableZ[i].dead == 0) continue; - nodelist = unique->subtableZ[i].nodelist; - - deleted = 0; - slots = unique->subtableZ[i].slots; - for (j = 0; j < slots; j++) { - lastP = &(nodelist[j]); - node = *lastP; - while (node != NULL) { - next = node->next; - if (node->ref == 0) { - deleted++; -#ifndef DD_UNSORTED_FREE_LIST -#ifdef __osf__ -#pragma pointer_size save -#pragma pointer_size short -#endif - cuddOrderedInsert(&tree,node); -#ifdef __osf__ -#pragma pointer_size restore -#endif -#else - cuddDeallocNode(unique,node); -#endif - } else { - *lastP = node; - lastP = &(node->next); - } - node = next; - } - *lastP = NULL; - } - if ((unsigned) deleted != unique->subtableZ[i].dead) { - ddReportRefMess(unique, i, "cuddGarbageCollectZdd"); - } - totalDeleted += deleted; - unique->subtableZ[i].keys -= deleted; - unique->subtableZ[i].dead = 0; - } - - /* No need to examine the constant table for ZDDs. - ** If we did we should be careful not to count whatever dead - ** nodes we found there among the dead ZDD nodes. */ - if ((unsigned) totalDeleted != unique->deadZ) { - ddReportRefMess(unique, -1, "cuddGarbageCollectZdd"); - } - unique->keysZ -= totalDeleted; - unique->deadZ = 0; -#ifdef DD_STATS - unique->nodesFreed += (double) totalDeleted; -#endif - -#ifndef DD_UNSORTED_FREE_LIST - unique->nextFree = cuddOrderedThread(tree,unique->nextFree); -#endif - - unique->GCTime += util_cpu_time() - localTime; - - hook = unique->postGCHook; - while (hook != NULL) { - int res = (hook->f)(unique,"ZDD",NULL); - if (res == 0) return(0); - hook = hook->next; - } - -#ifdef DD_VERBOSE - (void) fprintf(unique->err," done\n"); -#endif - - return(totalDeleted); - -} /* end of cuddGarbageCollectZdd */ - - -/**Function******************************************************************** - - Synopsis [Wrapper for cuddUniqueInterZdd.] - - Description [Wrapper for cuddUniqueInterZdd, which applies the ZDD - reduction rule. Returns a pointer to the result node under normal - conditions; NULL if reordering occurred or memory was exhausted.] - - SideEffects [None] - - SeeAlso [cuddUniqueInterZdd] - -******************************************************************************/ -DdNode * -cuddZddGetNode( - DdManager * zdd, - int id, - DdNode * T, - DdNode * E) -{ - DdNode *node; - - if (T == DD_ZERO(zdd)) - return(E); - node = cuddUniqueInterZdd(zdd, id, T, E); - return(node); - -} /* end of cuddZddGetNode */ - - -/**Function******************************************************************** - - Synopsis [Wrapper for cuddUniqueInterZdd that is independent of variable - ordering.] - - Description [Wrapper for cuddUniqueInterZdd that is independent of - variable ordering (IVO). This function does not require parameter - index to precede the indices of the top nodes of g and h in the - variable order. Returns a pointer to the result node under normal - conditions; NULL if reordering occurred or memory was exhausted.] - - SideEffects [None] - - SeeAlso [cuddZddGetNode cuddZddIsop] - -******************************************************************************/ -DdNode * -cuddZddGetNodeIVO( - DdManager * dd, - int index, - DdNode * g, - DdNode * h) -{ - DdNode *f, *r, *t; - DdNode *zdd_one = DD_ONE(dd); - DdNode *zdd_zero = DD_ZERO(dd); - - f = cuddUniqueInterZdd(dd, index, zdd_one, zdd_zero); - if (f == NULL) { - return(NULL); - } - cuddRef(f); - t = cuddZddProduct(dd, f, g); - if (t == NULL) { - Cudd_RecursiveDerefZdd(dd, f); - return(NULL); - } - cuddRef(t); - Cudd_RecursiveDerefZdd(dd, f); - r = cuddZddUnion(dd, t, h); - if (r == NULL) { - Cudd_RecursiveDerefZdd(dd, t); - return(NULL); - } - cuddRef(r); - Cudd_RecursiveDerefZdd(dd, t); - - cuddDeref(r); - return(r); - -} /* end of cuddZddGetNodeIVO */ - - -/**Function******************************************************************** - - Synopsis [Checks the unique table for the existence of an internal node.] - - Description [Checks the unique table for the existence of an internal - node. If it does not exist, it creates a new one. Does not - modify the reference count of whatever is returned. A newly created - internal node comes back with a reference count 0. For a newly - created node, increments the reference counts of what T and E point - to. Returns a pointer to the new node if successful; NULL if memory - is exhausted or if reordering took place.] - - SideEffects [None] - - SeeAlso [cuddUniqueInterZdd] - -******************************************************************************/ -DdNode * -cuddUniqueInter( - DdManager * unique, - int index, - DdNode * T, - DdNode * E) -{ - int pos; - unsigned int level; - int retval; - DdNodePtr *nodelist; - DdNode *looking; - DdNodePtr *previousP; - DdSubtable *subtable; - int gcNumber; - -#ifdef DD_UNIQUE_PROFILE - unique->uniqueLookUps++; -#endif - - if (index >= unique->size) { - if (!ddResizeTable(unique,index)) return(NULL); - } - - level = unique->perm[index]; - subtable = &(unique->subtables[level]); - -#ifdef DD_DEBUG - assert(level < (unsigned) cuddI(unique,T->index)); - assert(level < (unsigned) cuddI(unique,Cudd_Regular(E)->index)); -#endif - - pos = ddHash(T, E, subtable->shift); - nodelist = subtable->nodelist; - previousP = &(nodelist[pos]); - looking = *previousP; - - while (T < cuddT(looking)) { - previousP = &(looking->next); - looking = *previousP; -#ifdef DD_UNIQUE_PROFILE - unique->uniqueLinks++; -#endif - } - while (T == cuddT(looking) && E < cuddE(looking)) { - previousP = &(looking->next); - looking = *previousP; -#ifdef DD_UNIQUE_PROFILE - unique->uniqueLinks++; -#endif - } - if (T == cuddT(looking) && E == cuddE(looking)) { - if (looking->ref == 0) { - cuddReclaim(unique,looking); - } - return(looking); - } - - /* countDead is 0 if deads should be counted and ~0 if they should not. */ - if (unique->autoDyn && - unique->keys - (unique->dead & unique->countDead) >= unique->nextDyn) { -#ifdef DD_DEBUG - retval = Cudd_DebugCheck(unique); - if (retval != 0) return(NULL); - retval = Cudd_CheckKeys(unique); - if (retval != 0) return(NULL); -#endif - retval = Cudd_ReduceHeap(unique,unique->autoMethod,10); /* 10 = whatever */ - if (retval == 0) unique->reordered = 2; -#ifdef DD_DEBUG - retval = Cudd_DebugCheck(unique); - if (retval != 0) unique->reordered = 2; - retval = Cudd_CheckKeys(unique); - if (retval != 0) unique->reordered = 2; -#endif - return(NULL); - } - - if (subtable->keys > subtable->maxKeys) { - if (unique->gcEnabled && - ((unique->dead > unique->minDead) || - ((unique->dead > unique->minDead / 2) && - (subtable->dead > subtable->keys * 0.95)))) { /* too many dead */ - (void) cuddGarbageCollect(unique,1); - } else { - cuddRehash(unique,(int)level); - } - /* Update pointer to insertion point. In the case of rehashing, - ** the slot may have changed. In the case of garbage collection, - ** the predecessor may have been dead. */ - pos = ddHash(T, E, subtable->shift); - nodelist = subtable->nodelist; - previousP = &(nodelist[pos]); - looking = *previousP; - - while (T < cuddT(looking)) { - previousP = &(looking->next); - looking = *previousP; -#ifdef DD_UNIQUE_PROFILE - unique->uniqueLinks++; -#endif - } - while (T == cuddT(looking) && E < cuddE(looking)) { - previousP = &(looking->next); - looking = *previousP; -#ifdef DD_UNIQUE_PROFILE - unique->uniqueLinks++; -#endif - } - } - - gcNumber = unique->garbageCollections; - looking = cuddAllocNode(unique); - if (looking == NULL) { - return(NULL); - } - unique->keys++; - subtable->keys++; - - if (gcNumber != unique->garbageCollections) { - DdNode *looking2; - pos = ddHash(T, E, subtable->shift); - nodelist = subtable->nodelist; - previousP = &(nodelist[pos]); - looking2 = *previousP; - - while (T < cuddT(looking2)) { - previousP = &(looking2->next); - looking2 = *previousP; -#ifdef DD_UNIQUE_PROFILE - unique->uniqueLinks++; -#endif - } - while (T == cuddT(looking2) && E < cuddE(looking2)) { - previousP = &(looking2->next); - looking2 = *previousP; -#ifdef DD_UNIQUE_PROFILE - unique->uniqueLinks++; -#endif - } - } - looking->ref = 0; - looking->index = index; - cuddT(looking) = T; - cuddE(looking) = E; - looking->next = *previousP; - *previousP = looking; - cuddSatInc(T->ref); /* we know T is a regular pointer */ - cuddRef(E); - -#ifdef DD_DEBUG - cuddCheckCollisionOrdering(unique,level,pos); -#endif - - return(looking); - -} /* end of cuddUniqueInter */ - - -/**Function******************************************************************** - - Synopsis [Wrapper for cuddUniqueInter that is independent of variable - ordering.] - - Description [Wrapper for cuddUniqueInter that is independent of - variable ordering (IVO). This function does not require parameter - index to precede the indices of the top nodes of T and E in the - variable order. Returns a pointer to the result node under normal - conditions; NULL if reordering occurred or memory was exhausted.] - - SideEffects [None] - - SeeAlso [cuddUniqueInter Cudd_MakeBddFromZddCover] - -******************************************************************************/ -DdNode * -cuddUniqueInterIVO( - DdManager * unique, - int index, - DdNode * T, - DdNode * E) -{ - DdNode *result; - DdNode *v; - - v = cuddUniqueInter(unique, index, DD_ONE(unique), - Cudd_Not(DD_ONE(unique))); - if (v == NULL) - return(NULL); - cuddRef(v); - result = cuddBddIteRecur(unique, v, T, E); - Cudd_RecursiveDeref(unique, v); - return(result); -} - - -/**Function******************************************************************** - - Synopsis [Checks the unique table for the existence of an internal - ZDD node.] - - Description [Checks the unique table for the existence of an internal - ZDD node. If it does not exist, it creates a new one. Does not - modify the reference count of whatever is returned. A newly created - internal node comes back with a reference count 0. For a newly - created node, increments the reference counts of what T and E point - to. Returns a pointer to the new node if successful; NULL if memory - is exhausted or if reordering took place.] - - SideEffects [None] - - SeeAlso [cuddUniqueInter] - -******************************************************************************/ -DdNode * -cuddUniqueInterZdd( - DdManager * unique, - int index, - DdNode * T, - DdNode * E) -{ - int pos; - unsigned int level; - int retval; - DdNodePtr *nodelist; - DdNode *looking; - DdSubtable *subtable; - -#ifdef DD_UNIQUE_PROFILE - unique->uniqueLookUps++; -#endif - - if (index >= unique->sizeZ) { - if (!cuddResizeTableZdd(unique,index)) return(NULL); - } - - level = unique->permZ[index]; - subtable = &(unique->subtableZ[level]); - -#ifdef DD_DEBUG - assert(level < (unsigned) cuddIZ(unique,T->index)); - assert(level < (unsigned) cuddIZ(unique,Cudd_Regular(E)->index)); -#endif - - if (subtable->keys > subtable->maxKeys) { - if (unique->gcEnabled && ((unique->deadZ > unique->minDead) || - (10 * subtable->dead > 9 * subtable->keys))) { /* too many dead */ - (void) cuddGarbageCollectZdd(unique,1); - } else { - ddRehashZdd(unique,(int)level); - } - } - - pos = ddHash(T, E, subtable->shift); - nodelist = subtable->nodelist; - looking = nodelist[pos]; - - while (looking != NULL) { - if (cuddT(looking) == T && cuddE(looking) == E) { - if (looking->ref == 0) { - cuddReclaimZdd(unique,looking); - } - return(looking); - } - looking = looking->next; -#ifdef DD_UNIQUE_PROFILE - unique->uniqueLinks++; -#endif - } - - /* countDead is 0 if deads should be counted and ~0 if they should not. */ - if (unique->autoDynZ && - unique->keysZ - (unique->deadZ & unique->countDead) >= unique->nextDyn) { -#ifdef DD_DEBUG - retval = Cudd_DebugCheck(unique); - if (retval != 0) return(NULL); - retval = Cudd_CheckKeys(unique); - if (retval != 0) return(NULL); -#endif - retval = Cudd_zddReduceHeap(unique,unique->autoMethodZ,10); /* 10 = whatever */ - if (retval == 0) unique->reordered = 2; -#ifdef DD_DEBUG - retval = Cudd_DebugCheck(unique); - if (retval != 0) unique->reordered = 2; - retval = Cudd_CheckKeys(unique); - if (retval != 0) unique->reordered = 2; -#endif - return(NULL); - } - - unique->keysZ++; - subtable->keys++; - - looking = cuddAllocNode(unique); - if (looking == NULL) return(NULL); - looking->ref = 0; - looking->index = index; - cuddT(looking) = T; - cuddE(looking) = E; - looking->next = nodelist[pos]; - nodelist[pos] = looking; - cuddRef(T); - cuddRef(E); - - return(looking); - -} /* end of cuddUniqueInterZdd */ - - -/**Function******************************************************************** - - Synopsis [Checks the unique table for the existence of a constant node.] - - Description [Checks the unique table for the existence of a constant node. - If it does not exist, it creates a new one. Does not - modify the reference count of whatever is returned. A newly created - internal node comes back with a reference count 0. Returns a - pointer to the new node.] - - SideEffects [None] - -******************************************************************************/ -DdNode * -cuddUniqueConst( - DdManager * unique, - CUDD_VALUE_TYPE value) -{ - int pos; - DdNodePtr *nodelist; - DdNode *looking; - hack split; - -#ifdef DD_UNIQUE_PROFILE - unique->uniqueLookUps++; -#endif - - if (unique->constants.keys > unique->constants.maxKeys) { - if (unique->gcEnabled && ((unique->dead > unique->minDead) || - (10 * unique->constants.dead > 9 * unique->constants.keys))) { /* too many dead */ - (void) cuddGarbageCollect(unique,1); - } else { - cuddRehash(unique,CUDD_CONST_INDEX); - } - } - - cuddAdjust(value); /* for the case of crippled infinities */ - - if (ddAbs(value) < unique->epsilon) { - value = 0.0; - } - split.value = value; - - pos = ddHash(split.bits[0], split.bits[1], unique->constants.shift); - nodelist = unique->constants.nodelist; - looking = nodelist[pos]; - - /* Here we compare values both for equality and for difference less - * than epsilon. The first comparison is required when values are - * infinite, since Infinity - Infinity is NaN and NaN < X is 0 for - * every X. - */ - while (looking != NULL) { - if (looking->type.value == value || - ddEqualVal(looking->type.value,value,unique->epsilon)) { - if (looking->ref == 0) { - cuddReclaim(unique,looking); - } - return(looking); - } - looking = looking->next; -#ifdef DD_UNIQUE_PROFILE - unique->uniqueLinks++; -#endif - } - - unique->keys++; - unique->constants.keys++; - - looking = cuddAllocNode(unique); - if (looking == NULL) return(NULL); - looking->ref = 0; - looking->index = CUDD_CONST_INDEX; - looking->type.value = value; - looking->next = nodelist[pos]; - nodelist[pos] = looking; - - return(looking); - -} /* end of cuddUniqueConst */ - - -/**Function******************************************************************** - - Synopsis [Rehashes a unique subtable.] - - Description [Doubles the size of a unique subtable and rehashes its - contents.] - - SideEffects [None] - - SeeAlso [] - -******************************************************************************/ -void -cuddRehash( - DdManager * unique, - int i) -{ - unsigned int slots, oldslots; - int shift, oldshift; - int j, pos; - DdNodePtr *nodelist, *oldnodelist; - DdNode *node, *next; - DdNode *sentinel = &(unique->sentinel); - hack split; - extern void (*MMoutOfMemory)(long); - void (*saveHandler)(long); - - if (unique->gcFrac == DD_GC_FRAC_HI && unique->slots > unique->looseUpTo) { - unique->gcFrac = DD_GC_FRAC_LO; - unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots); -#ifdef DD_VERBOSE - (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_LO); - (void) fprintf(unique->err,"minDead = %d\n", unique->minDead); -#endif - } - - if (unique->gcFrac != DD_GC_FRAC_MIN && unique->memused > unique->maxmem) { - unique->gcFrac = DD_GC_FRAC_MIN; - unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots); -#ifdef DD_VERBOSE - (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_MIN); - (void) fprintf(unique->err,"minDead = %d\n", unique->minDead); -#endif - cuddShrinkDeathRow(unique); - if (cuddGarbageCollect(unique,1) > 0) return; - } - - if (i != CUDD_CONST_INDEX) { - oldslots = unique->subtables[i].slots; - oldshift = unique->subtables[i].shift; - oldnodelist = unique->subtables[i].nodelist; - - /* Compute the new size of the subtable. */ - slots = oldslots << 1; - shift = oldshift - 1; - - saveHandler = MMoutOfMemory; - MMoutOfMemory = Cudd_OutOfMem; - nodelist = ALLOC(DdNodePtr, slots); - MMoutOfMemory = saveHandler; - if (nodelist == NULL) { - (void) fprintf(unique->err, - "Unable to resize subtable %d for lack of memory\n", - i); - /* Prevent frequent resizing attempts. */ - (void) cuddGarbageCollect(unique,1); - if (unique->stash != NULL) { - FREE(unique->stash); - unique->stash = NULL; - /* Inhibit resizing of tables. */ - cuddSlowTableGrowth(unique); - } - return; - } - unique->subtables[i].nodelist = nodelist; - unique->subtables[i].slots = slots; - unique->subtables[i].shift = shift; - unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY; - - /* Move the nodes from the old table to the new table. - ** This code depends on the type of hash function. - ** It assumes that the effect of doubling the size of the table - ** is to retain one more bit of the 32-bit hash value. - ** The additional bit is the LSB. */ - for (j = 0; (unsigned) j < oldslots; j++) { - DdNodePtr *evenP, *oddP; - node = oldnodelist[j]; - evenP = &(nodelist[j<<1]); - oddP = &(nodelist[(j<<1)+1]); - while (node != sentinel) { - next = node->next; - pos = ddHash(cuddT(node), cuddE(node), shift); - if (pos & 1) { - *oddP = node; - oddP = &(node->next); - } else { - *evenP = node; - evenP = &(node->next); - } - node = next; - } - *evenP = *oddP = sentinel; - } - FREE(oldnodelist); - -#ifdef DD_VERBOSE - (void) fprintf(unique->err, - "rehashing layer %d: keys %d dead %d new size %d\n", - i, unique->subtables[i].keys, - unique->subtables[i].dead, slots); -#endif - } else { - oldslots = unique->constants.slots; - oldshift = unique->constants.shift; - oldnodelist = unique->constants.nodelist; - - /* The constant subtable is never subjected to reordering. - ** Therefore, when it is resized, it is because it has just - ** reached the maximum load. We can safely just double the size, - ** with no need for the loop we use for the other tables. - */ - slots = oldslots << 1; - shift = oldshift - 1; - saveHandler = MMoutOfMemory; - MMoutOfMemory = Cudd_OutOfMem; - nodelist = ALLOC(DdNodePtr, slots); - MMoutOfMemory = saveHandler; - if (nodelist == NULL) { - int j; - (void) fprintf(unique->err, - "Unable to resize constant subtable for lack of memory\n"); - (void) cuddGarbageCollect(unique,1); - for (j = 0; j < unique->size; j++) { - unique->subtables[j].maxKeys <<= 1; - } - unique->constants.maxKeys <<= 1; - return; - } - unique->constants.slots = slots; - unique->constants.shift = shift; - unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY; - unique->constants.nodelist = nodelist; - for (j = 0; (unsigned) j < slots; j++) { - nodelist[j] = NULL; - } - for (j = 0; (unsigned) j < oldslots; j++) { - node = oldnodelist[j]; - while (node != NULL) { - next = node->next; - split.value = cuddV(node); - pos = ddHash(split.bits[0], split.bits[1], shift); - node->next = nodelist[pos]; - nodelist[pos] = node; - node = next; - } - } - FREE(oldnodelist); - -#ifdef DD_VERBOSE - (void) fprintf(unique->err, - "rehashing constants: keys %d dead %d new size %d\n", - unique->constants.keys,unique->constants.dead,slots); -#endif - } - - /* Update global data */ - - unique->memused += (slots - oldslots) * sizeof(DdNodePtr); - unique->slots += (slots - oldslots); - ddFixLimits(unique); - -} /* end of cuddRehash */ - - -/**Function******************************************************************** - - Synopsis [Shrinks a subtable.] - - Description [Shrinks a subtable.] - - SideEffects [None] - - SeeAlso [cuddRehash] - -******************************************************************************/ -void -cuddShrinkSubtable( - DdManager *unique, - int i) -{ - int j; - int shift, posn; - DdNodePtr *nodelist, *oldnodelist; - DdNode *node, *next; - DdNode *sentinel = &(unique->sentinel); - unsigned int slots, oldslots; - extern void (*MMoutOfMemory)(long); - void (*saveHandler)(long); - - oldnodelist = unique->subtables[i].nodelist; - oldslots = unique->subtables[i].slots; - slots = oldslots >> 1; - saveHandler = MMoutOfMemory; - MMoutOfMemory = Cudd_OutOfMem; - nodelist = ALLOC(DdNodePtr, slots); - MMoutOfMemory = saveHandler; - if (nodelist == NULL) { - return; - } - unique->subtables[i].nodelist = nodelist; - unique->subtables[i].slots = slots; - unique->subtables[i].shift++; - unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY; -#ifdef DD_VERBOSE - (void) fprintf(unique->err, - "shrunk layer %d (%d keys) from %d to %d slots\n", - i, unique->subtables[i].keys, oldslots, slots); -#endif - - for (j = 0; (unsigned) j < slots; j++) { - nodelist[j] = sentinel; - } - shift = unique->subtables[i].shift; - for (j = 0; (unsigned) j < oldslots; j++) { - node = oldnodelist[j]; - while (node != sentinel) { - DdNode *looking, *T, *E; - DdNodePtr *previousP; - next = node->next; - posn = ddHash(cuddT(node), cuddE(node), shift); - previousP = &(nodelist[posn]); - looking = *previousP; - T = cuddT(node); - E = cuddE(node); - while (T < cuddT(looking)) { - previousP = &(looking->next); - looking = *previousP; -#ifdef DD_UNIQUE_PROFILE - unique->uniqueLinks++; -#endif - } - while (T == cuddT(looking) && E < cuddE(looking)) { - previousP = &(looking->next); - looking = *previousP; -#ifdef DD_UNIQUE_PROFILE - unique->uniqueLinks++; -#endif - } - node->next = *previousP; - *previousP = node; - node = next; - } - } - FREE(oldnodelist); - - unique->memused += ((long) slots - (long) oldslots) * sizeof(DdNode *); - unique->slots += slots - oldslots; - unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots); - unique->cacheSlack = (int) - ddMin(unique->maxCacheHard,DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots) - - 2 * (int) unique->cacheSlots; - -} /* end of cuddShrinkSubtable */ - - -/**Function******************************************************************** - - Synopsis [Inserts n new subtables in a unique table at level.] - - Description [Inserts n new subtables in a unique table at level. - The number n should be positive, and level should be an existing level. - Returns 1 if successful; 0 otherwise.] - - SideEffects [None] - - SeeAlso [cuddDestroySubtables] - -******************************************************************************/ -int -cuddInsertSubtables( - DdManager * unique, - int n, - int level) -{ - DdSubtable *newsubtables; - DdNodePtr *newnodelist; - DdNodePtr *newvars; - DdNode *sentinel = &(unique->sentinel); - int oldsize,newsize; - int i,j,index,reorderSave; - unsigned int numSlots = unique->initSlots; - int *newperm, *newinvperm, *newmap; - DdNode *one, *zero; - -#ifdef DD_DEBUG - assert(n > 0 && level < unique->size); -#endif - - oldsize = unique->size; - /* Easy case: there is still room in the current table. */ - if (oldsize + n <= unique->maxSize) { - /* Shift the tables at and below level. */ - for (i = oldsize - 1; i >= level; i--) { - unique->subtables[i+n].slots = unique->subtables[i].slots; - unique->subtables[i+n].shift = unique->subtables[i].shift; - unique->subtables[i+n].keys = unique->subtables[i].keys; - unique->subtables[i+n].maxKeys = unique->subtables[i].maxKeys; - unique->subtables[i+n].dead = unique->subtables[i].dead; - unique->subtables[i+n].nodelist = unique->subtables[i].nodelist; - unique->subtables[i+n].bindVar = unique->subtables[i].bindVar; - unique->subtables[i+n].varType = unique->subtables[i].varType; - unique->subtables[i+n].pairIndex = unique->subtables[i].pairIndex; - unique->subtables[i+n].varHandled = unique->subtables[i].varHandled; - unique->subtables[i+n].varToBeGrouped = - unique->subtables[i].varToBeGrouped; - - index = unique->invperm[i]; - unique->invperm[i+n] = index; - unique->perm[index] += n; - } - /* Create new subtables. */ - for (i = 0; i < n; i++) { - unique->subtables[level+i].slots = numSlots; - unique->subtables[level+i].shift = sizeof(int) * 8 - - cuddComputeFloorLog2(numSlots); - unique->subtables[level+i].keys = 0; - unique->subtables[level+i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY; - unique->subtables[level+i].dead = 0; - unique->subtables[level+i].bindVar = 0; - unique->subtables[level+i].varType = CUDD_VAR_PRIMARY_INPUT; - unique->subtables[level+i].pairIndex = 0; - unique->subtables[level+i].varHandled = 0; - unique->subtables[level+i].varToBeGrouped = CUDD_LAZY_NONE; - - unique->perm[oldsize+i] = level + i; - unique->invperm[level+i] = oldsize + i; - newnodelist = unique->subtables[level+i].nodelist = - ALLOC(DdNodePtr, numSlots); - if (newnodelist == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - for (j = 0; j < numSlots; j++) { - newnodelist[j] = sentinel; - } - } - if (unique->map != NULL) { - for (i = 0; i < n; i++) { - unique->map[oldsize+i] = oldsize + i; - } - } - } else { - /* The current table is too small: we need to allocate a new, - ** larger one; move all old subtables, and initialize the new - ** subtables. - */ - newsize = oldsize + n + DD_DEFAULT_RESIZE; -#ifdef DD_VERBOSE - (void) fprintf(unique->err, - "Increasing the table size from %d to %d\n", - unique->maxSize, newsize); -#endif - /* Allocate memory for new arrays (except nodelists). */ - newsubtables = ALLOC(DdSubtable,newsize); - if (newsubtables == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - newvars = ALLOC(DdNodePtr,newsize); - if (newvars == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - FREE(newsubtables); - return(0); - } - newperm = ALLOC(int,newsize); - if (newperm == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - FREE(newsubtables); - FREE(newvars); - return(0); - } - newinvperm = ALLOC(int,newsize); - if (newinvperm == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - FREE(newsubtables); - FREE(newvars); - FREE(newperm); - return(0); - } - if (unique->map != NULL) { - newmap = ALLOC(int,newsize); - if (newmap == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - FREE(newsubtables); - FREE(newvars); - FREE(newperm); - FREE(newinvperm); - return(0); - } - unique->memused += (newsize - unique->maxSize) * sizeof(int); - } - unique->memused += (newsize - unique->maxSize) * ((numSlots+1) * - sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable)); - /* Copy levels before insertion points from old tables. */ - for (i = 0; i < level; i++) { - newsubtables[i].slots = unique->subtables[i].slots; - newsubtables[i].shift = unique->subtables[i].shift; - newsubtables[i].keys = unique->subtables[i].keys; - newsubtables[i].maxKeys = unique->subtables[i].maxKeys; - newsubtables[i].dead = unique->subtables[i].dead; - newsubtables[i].nodelist = unique->subtables[i].nodelist; - newsubtables[i].bindVar = unique->subtables[i].bindVar; - newsubtables[i].varType = unique->subtables[i].varType; - newsubtables[i].pairIndex = unique->subtables[i].pairIndex; - newsubtables[i].varHandled = unique->subtables[i].varHandled; - newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped; - - newvars[i] = unique->vars[i]; - newperm[i] = unique->perm[i]; - newinvperm[i] = unique->invperm[i]; - } - /* Finish initializing permutation for new table to old one. */ - for (i = level; i < oldsize; i++) { - newperm[i] = unique->perm[i]; - } - /* Initialize new levels. */ - for (i = level; i < level + n; i++) { - newsubtables[i].slots = numSlots; - newsubtables[i].shift = sizeof(int) * 8 - - cuddComputeFloorLog2(numSlots); - newsubtables[i].keys = 0; - newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY; - newsubtables[i].dead = 0; - newsubtables[i].bindVar = 0; - newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT; - newsubtables[i].pairIndex = 0; - newsubtables[i].varHandled = 0; - newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE; - - newperm[oldsize + i - level] = i; - newinvperm[i] = oldsize + i - level; - newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots); - if (newnodelist == NULL) { - /* We are going to leak some memory. We should clean up. */ - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - for (j = 0; j < numSlots; j++) { - newnodelist[j] = sentinel; - } - } - /* Copy the old tables for levels past the insertion point. */ - for (i = level; i < oldsize; i++) { - newsubtables[i+n].slots = unique->subtables[i].slots; - newsubtables[i+n].shift = unique->subtables[i].shift; - newsubtables[i+n].keys = unique->subtables[i].keys; - newsubtables[i+n].maxKeys = unique->subtables[i].maxKeys; - newsubtables[i+n].dead = unique->subtables[i].dead; - newsubtables[i+n].nodelist = unique->subtables[i].nodelist; - newsubtables[i+n].bindVar = unique->subtables[i].bindVar; - newsubtables[i+n].varType = unique->subtables[i].varType; - newsubtables[i+n].pairIndex = unique->subtables[i].pairIndex; - newsubtables[i+n].varHandled = unique->subtables[i].varHandled; - newsubtables[i+n].varToBeGrouped = - unique->subtables[i].varToBeGrouped; - - newvars[i] = unique->vars[i]; - index = unique->invperm[i]; - newinvperm[i+n] = index; - newperm[index] += n; - } - /* Update the map. */ - if (unique->map != NULL) { - for (i = 0; i < oldsize; i++) { - newmap[i] = unique->map[i]; - } - for (i = oldsize; i < oldsize + n; i++) { - newmap[i] = i; - } - FREE(unique->map); - unique->map = newmap; - } - /* Install the new tables and free the old ones. */ - FREE(unique->subtables); - unique->subtables = newsubtables; - unique->maxSize = newsize; - FREE(unique->vars); - unique->vars = newvars; - FREE(unique->perm); - unique->perm = newperm; - FREE(unique->invperm); - unique->invperm = newinvperm; - /* Update the stack for iterative procedures. */ - if (newsize > unique->maxSizeZ) { - FREE(unique->stack); - unique->stack = ALLOC(DdNodePtr,newsize + 1); - if (unique->stack == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - unique->stack[0] = NULL; /* to suppress harmless UMR */ - unique->memused += - (newsize - ddMax(unique->maxSize,unique->maxSizeZ)) - * sizeof(DdNode *); - } - } - /* Update manager parameters to account for the new subtables. */ - unique->slots += n * numSlots; - ddFixLimits(unique); - unique->size += n; - - /* Now that the table is in a coherent state, create the new - ** projection functions. We need to temporarily disable reordering, - ** because we cannot reorder without projection functions in place. - **/ - one = unique->one; - zero = Cudd_Not(one); - - reorderSave = unique->autoDyn; - unique->autoDyn = 0; - for (i = oldsize; i < oldsize + n; i++) { - unique->vars[i] = cuddUniqueInter(unique,i,one,zero); - if (unique->vars[i] == NULL) { - unique->autoDyn = reorderSave; - /* Shift everything back so table remains coherent. */ - for (j = oldsize; j < i; j++) { - Cudd_IterDerefBdd(unique,unique->vars[j]); - cuddDeallocNode(unique,unique->vars[j]); - unique->vars[j] = NULL; - } - for (j = level; j < oldsize; j++) { - unique->subtables[j].slots = unique->subtables[j+n].slots; - unique->subtables[j].slots = unique->subtables[j+n].slots; - unique->subtables[j].shift = unique->subtables[j+n].shift; - unique->subtables[j].keys = unique->subtables[j+n].keys; - unique->subtables[j].maxKeys = - unique->subtables[j+n].maxKeys; - unique->subtables[j].dead = unique->subtables[j+n].dead; - FREE(unique->subtables[j].nodelist); - unique->subtables[j].nodelist = - unique->subtables[j+n].nodelist; - unique->subtables[j+n].nodelist = NULL; - unique->subtables[j].bindVar = - unique->subtables[j+n].bindVar; - unique->subtables[j].varType = - unique->subtables[j+n].varType; - unique->subtables[j].pairIndex = - unique->subtables[j+n].pairIndex; - unique->subtables[j].varHandled = - unique->subtables[j+n].varHandled; - unique->subtables[j].varToBeGrouped = - unique->subtables[j+n].varToBeGrouped; - index = unique->invperm[j+n]; - unique->invperm[j] = index; - unique->perm[index] -= n; - } - unique->size = oldsize; - unique->slots -= n * numSlots; - ddFixLimits(unique); - (void) Cudd_DebugCheck(unique); - return(0); - } - cuddRef(unique->vars[i]); - } - if (unique->tree != NULL) { - unique->tree->size += n; - unique->tree->index = unique->invperm[0]; - ddPatchTree(unique,unique->tree); - } - unique->autoDyn = reorderSave; - - return(1); - -} /* end of cuddInsertSubtables */ - - -/**Function******************************************************************** - - Synopsis [Destroys the n most recently created subtables in a unique table.] - - Description [Destroys the n most recently created subtables in a unique - table. n should be positive. The subtables should not contain any live - nodes, except the (isolated) projection function. The projection - functions are freed. Returns 1 if successful; 0 otherwise.] - - SideEffects [The variable map used for fast variable substitution is - destroyed if it exists. In this case the cache is also cleared.] - - SeeAlso [cuddInsertSubtables Cudd_SetVarMap] - -******************************************************************************/ -int -cuddDestroySubtables( - DdManager * unique, - int n) -{ - DdSubtable *subtables; - DdNodePtr *nodelist; - DdNodePtr *vars; - int firstIndex, lastIndex; - int index, level, newlevel; - int lowestLevel; - int shift; - int found; - - /* Sanity check and set up. */ - if (n <= 0) return(0); - if (n > unique->size) n = unique->size; - - subtables = unique->subtables; - vars = unique->vars; - firstIndex = unique->size - n; - lastIndex = unique->size; - - /* Check for nodes labeled by the variables being destroyed - ** that may still be in use. It is allowed to destroy a variable - ** only if there are no such nodes. Also, find the lowest level - ** among the variables being destroyed. This will make further - ** processing more efficient. - */ - lowestLevel = unique->size; - for (index = firstIndex; index < lastIndex; index++) { - level = unique->perm[index]; - if (level < lowestLevel) lowestLevel = level; - nodelist = subtables[level].nodelist; - if (subtables[level].keys - subtables[level].dead != 1) return(0); - /* The projection function should be isolated. If the ref count - ** is 1, everything is OK. If the ref count is saturated, then - ** we need to make sure that there are no nodes pointing to it. - ** As for the external references, we assume the application is - ** responsible for them. - */ - if (vars[index]->ref != 1) { - if (vars[index]->ref != DD_MAXREF) return(0); - found = cuddFindParent(unique,vars[index]); - if (found) { - return(0); - } else { - vars[index]->ref = 1; - } - } - Cudd_RecursiveDeref(unique,vars[index]); - } - - /* Collect garbage, because we cannot afford having dead nodes pointing - ** to the dead nodes in the subtables being destroyed. - */ - (void) cuddGarbageCollect(unique,1); - - /* Here we know we can destroy our subtables. */ - for (index = firstIndex; index < lastIndex; index++) { - level = unique->perm[index]; - nodelist = subtables[level].nodelist; -#ifdef DD_DEBUG - assert(subtables[level].keys == 0); -#endif - FREE(nodelist); - unique->memused -= sizeof(DdNodePtr) * subtables[level].slots; - unique->slots -= subtables[level].slots; - unique->dead -= subtables[level].dead; - } - - /* Here all subtables to be destroyed have their keys field == 0 and - ** their hash tables have been freed. - ** We now scan the subtables from level lowestLevel + 1 to level size - 1, - ** shifting the subtables as required. We keep a running count of - ** how many subtables have been moved, so that we know by how many - ** positions each subtable should be shifted. - */ - shift = 1; - for (level = lowestLevel + 1; level < unique->size; level++) { - if (subtables[level].keys == 0) { - shift++; - continue; - } - newlevel = level - shift; - subtables[newlevel].slots = subtables[level].slots; - subtables[newlevel].shift = subtables[level].shift; - subtables[newlevel].keys = subtables[level].keys; - subtables[newlevel].maxKeys = subtables[level].maxKeys; - subtables[newlevel].dead = subtables[level].dead; - subtables[newlevel].nodelist = subtables[level].nodelist; - index = unique->invperm[level]; - unique->perm[index] = newlevel; - unique->invperm[newlevel] = index; - subtables[newlevel].bindVar = subtables[level].bindVar; - subtables[newlevel].varType = subtables[level].varType; - subtables[newlevel].pairIndex = subtables[level].pairIndex; - subtables[newlevel].varHandled = subtables[level].varHandled; - subtables[newlevel].varToBeGrouped = subtables[level].varToBeGrouped; - } - /* Destroy the map. If a surviving variable is - ** mapped to a dying variable, and the map were used again, - ** an out-of-bounds access to unique->vars would result. */ - if (unique->map != NULL) { - cuddCacheFlush(unique); - FREE(unique->map); - unique->map = NULL; - } - - unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots); - unique->size -= n; - - return(1); - -} /* end of cuddDestroySubtables */ - - -/**Function******************************************************************** - - Synopsis [Increases the number of ZDD subtables in a unique table so - that it meets or exceeds index.] - - Description [Increases the number of ZDD subtables in a unique table so - that it meets or exceeds index. When new ZDD variables are created, it - is possible to preserve the functions unchanged, or it is possible to - preserve the covers unchanged, but not both. cuddResizeTableZdd preserves - the covers. Returns 1 if successful; 0 otherwise.] - - SideEffects [None] - - SeeAlso [ddResizeTable] - -******************************************************************************/ -int -cuddResizeTableZdd( - DdManager * unique, - int index) -{ - DdSubtable *newsubtables; - DdNodePtr *newnodelist; - int oldsize,newsize; - int i,j,reorderSave; - unsigned int numSlots = unique->initSlots; - int *newperm, *newinvperm; - DdNode *one, *zero; - - oldsize = unique->sizeZ; - /* Easy case: there is still room in the current table. */ - if (index < unique->maxSizeZ) { - for (i = oldsize; i <= index; i++) { - unique->subtableZ[i].slots = numSlots; - unique->subtableZ[i].shift = sizeof(int) * 8 - - cuddComputeFloorLog2(numSlots); - unique->subtableZ[i].keys = 0; - unique->subtableZ[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY; - unique->subtableZ[i].dead = 0; - unique->permZ[i] = i; - unique->invpermZ[i] = i; - newnodelist = unique->subtableZ[i].nodelist = - ALLOC(DdNodePtr, numSlots); - if (newnodelist == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - for (j = 0; j < numSlots; j++) { - newnodelist[j] = NULL; - } - } - } else { - /* The current table is too small: we need to allocate a new, - ** larger one; move all old subtables, and initialize the new - ** subtables up to index included. - */ - newsize = index + DD_DEFAULT_RESIZE; -#ifdef DD_VERBOSE - (void) fprintf(unique->err, - "Increasing the ZDD table size from %d to %d\n", - unique->maxSizeZ, newsize); -#endif - newsubtables = ALLOC(DdSubtable,newsize); - if (newsubtables == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - newperm = ALLOC(int,newsize); - if (newperm == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - newinvperm = ALLOC(int,newsize); - if (newinvperm == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - unique->memused += (newsize - unique->maxSizeZ) * ((numSlots+1) * - sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable)); - if (newsize > unique->maxSize) { - FREE(unique->stack); - unique->stack = ALLOC(DdNodePtr,newsize + 1); - if (unique->stack == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - unique->stack[0] = NULL; /* to suppress harmless UMR */ - unique->memused += - (newsize - ddMax(unique->maxSize,unique->maxSizeZ)) - * sizeof(DdNode *); - } - for (i = 0; i < oldsize; i++) { - newsubtables[i].slots = unique->subtableZ[i].slots; - newsubtables[i].shift = unique->subtableZ[i].shift; - newsubtables[i].keys = unique->subtableZ[i].keys; - newsubtables[i].maxKeys = unique->subtableZ[i].maxKeys; - newsubtables[i].dead = unique->subtableZ[i].dead; - newsubtables[i].nodelist = unique->subtableZ[i].nodelist; - newperm[i] = unique->permZ[i]; - newinvperm[i] = unique->invpermZ[i]; - } - for (i = oldsize; i <= index; i++) { - newsubtables[i].slots = numSlots; - newsubtables[i].shift = sizeof(int) * 8 - - cuddComputeFloorLog2(numSlots); - newsubtables[i].keys = 0; - newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY; - newsubtables[i].dead = 0; - newperm[i] = i; - newinvperm[i] = i; - newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots); - if (newnodelist == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - for (j = 0; j < numSlots; j++) { - newnodelist[j] = NULL; - } - } - FREE(unique->subtableZ); - unique->subtableZ = newsubtables; - unique->maxSizeZ = newsize; - FREE(unique->permZ); - unique->permZ = newperm; - FREE(unique->invpermZ); - unique->invpermZ = newinvperm; - } - unique->slots += (index + 1 - unique->sizeZ) * numSlots; - ddFixLimits(unique); - unique->sizeZ = index + 1; - - /* Now that the table is in a coherent state, update the ZDD - ** universe. We need to temporarily disable reordering, - ** because we cannot reorder without universe in place. - */ - one = unique->one; - zero = unique->zero; - - reorderSave = unique->autoDynZ; - unique->autoDynZ = 0; - cuddZddFreeUniv(unique); - if (!cuddZddInitUniv(unique)) { - unique->autoDynZ = reorderSave; - return(0); - } - unique->autoDynZ = reorderSave; - - return(1); - -} /* end of cuddResizeTableZdd */ - - -/**Function******************************************************************** - - Synopsis [Adjusts parameters of a table to slow down its growth.] - - Description [] - - SideEffects [None] - - SeeAlso [] - -******************************************************************************/ -void -cuddSlowTableGrowth( - DdManager *unique) -{ - int i; - - unique->maxCacheHard = unique->cacheSlots - 1; - unique->cacheSlack = -(unique->cacheSlots + 1); - for (i = 0; i < unique->size; i++) { - unique->subtables[i].maxKeys <<= 2; - } - unique->gcFrac = DD_GC_FRAC_MIN; - unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots); - cuddShrinkDeathRow(unique); - (void) fprintf(unique->err,"Slowing down table growth: "); - (void) fprintf(unique->err,"GC fraction = %.2f\t", unique->gcFrac); - (void) fprintf(unique->err,"minDead = %d\n", unique->minDead); - -} /* end of cuddSlowTableGrowth */ - - -/*---------------------------------------------------------------------------*/ -/* Definition of static functions */ -/*---------------------------------------------------------------------------*/ - - -/**Function******************************************************************** - - Synopsis [Rehashes a ZDD unique subtable.] - - Description [] - - SideEffects [None] - - SeeAlso [cuddRehash] - -******************************************************************************/ -static void -ddRehashZdd( - DdManager * unique, - int i) -{ - unsigned int slots, oldslots; - int shift, oldshift; - int j, pos; - DdNodePtr *nodelist, *oldnodelist; - DdNode *node, *next; - extern void (*MMoutOfMemory)(long); - void (*saveHandler)(long); - - if (unique->slots > unique->looseUpTo) { - unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots); -#ifdef DD_VERBOSE - if (unique->gcFrac == DD_GC_FRAC_HI) { - (void) fprintf(unique->err,"GC fraction = %.2f\t", - DD_GC_FRAC_LO); - (void) fprintf(unique->err,"minDead = %d\n", unique->minDead); - } -#endif - unique->gcFrac = DD_GC_FRAC_LO; - } - - assert(i != CUDD_MAXINDEX); - oldslots = unique->subtableZ[i].slots; - oldshift = unique->subtableZ[i].shift; - oldnodelist = unique->subtableZ[i].nodelist; - - /* Compute the new size of the subtable. Normally, we just - ** double. However, after reordering, a table may be severely - ** overloaded. Therefore, we iterate. */ - slots = oldslots; - shift = oldshift; - do { - slots <<= 1; - shift--; - } while (slots * DD_MAX_SUBTABLE_DENSITY < unique->subtableZ[i].keys); - - saveHandler = MMoutOfMemory; - MMoutOfMemory = Cudd_OutOfMem; - nodelist = ALLOC(DdNodePtr, slots); - MMoutOfMemory = saveHandler; - if (nodelist == NULL) { - int j; - (void) fprintf(unique->err, - "Unable to resize ZDD subtable %d for lack of memory.\n", - i); - (void) cuddGarbageCollectZdd(unique,1); - for (j = 0; j < unique->sizeZ; j++) { - unique->subtableZ[j].maxKeys <<= 1; - } - return; - } - unique->subtableZ[i].nodelist = nodelist; - unique->subtableZ[i].slots = slots; - unique->subtableZ[i].shift = shift; - unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY; - for (j = 0; (unsigned) j < slots; j++) { - nodelist[j] = NULL; - } - for (j = 0; (unsigned) j < oldslots; j++) { - node = oldnodelist[j]; - while (node != NULL) { - next = node->next; - pos = ddHash(cuddT(node), cuddE(node), shift); - node->next = nodelist[pos]; - nodelist[pos] = node; - node = next; - } - } - FREE(oldnodelist); - -#ifdef DD_VERBOSE - (void) fprintf(unique->err, - "rehashing layer %d: keys %d dead %d new size %d\n", - i, unique->subtableZ[i].keys, - unique->subtableZ[i].dead, slots); -#endif - - /* Update global data. */ - unique->memused += (slots - oldslots) * sizeof(DdNode *); - unique->slots += (slots - oldslots); - ddFixLimits(unique); - -} /* end of ddRehashZdd */ - - -/**Function******************************************************************** - - Synopsis [Increases the number of subtables in a unique table so - that it meets or exceeds index.] - - Description [Increases the number of subtables in a unique table so - that it meets or exceeds index. Returns 1 if successful; 0 otherwise.] - - SideEffects [None] - - SeeAlso [cuddResizeTableZdd] - -******************************************************************************/ -static int -ddResizeTable( - DdManager * unique, - int index) -{ - DdSubtable *newsubtables; - DdNodePtr *newnodelist; - DdNodePtr *newvars; - DdNode *sentinel = &(unique->sentinel); - int oldsize,newsize; - int i,j,reorderSave; - int numSlots = unique->initSlots; - int *newperm, *newinvperm, *newmap; - DdNode *one, *zero; - - oldsize = unique->size; - /* Easy case: there is still room in the current table. */ - if (index < unique->maxSize) { - for (i = oldsize; i <= index; i++) { - unique->subtables[i].slots = numSlots; - unique->subtables[i].shift = sizeof(int) * 8 - - cuddComputeFloorLog2(numSlots); - unique->subtables[i].keys = 0; - unique->subtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY; - unique->subtables[i].dead = 0; - unique->subtables[i].bindVar = 0; - unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT; - unique->subtables[i].pairIndex = 0; - unique->subtables[i].varHandled = 0; - unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE; - - unique->perm[i] = i; - unique->invperm[i] = i; - newnodelist = unique->subtables[i].nodelist = - ALLOC(DdNodePtr, numSlots); - if (newnodelist == NULL) { - for (j = oldsize; j < i; j++) { - FREE(unique->subtables[j].nodelist); - } - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - for (j = 0; j < numSlots; j++) { - newnodelist[j] = sentinel; - } - } - if (unique->map != NULL) { - for (i = oldsize; i <= index; i++) { - unique->map[i] = i; - } - } - } else { - /* The current table is too small: we need to allocate a new, - ** larger one; move all old subtables, and initialize the new - ** subtables up to index included. - */ - newsize = index + DD_DEFAULT_RESIZE; -#ifdef DD_VERBOSE - (void) fprintf(unique->err, - "Increasing the table size from %d to %d\n", - unique->maxSize, newsize); -#endif - newsubtables = ALLOC(DdSubtable,newsize); - if (newsubtables == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - newvars = ALLOC(DdNodePtr,newsize); - if (newvars == NULL) { - FREE(newsubtables); - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - newperm = ALLOC(int,newsize); - if (newperm == NULL) { - FREE(newsubtables); - FREE(newvars); - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - newinvperm = ALLOC(int,newsize); - if (newinvperm == NULL) { - FREE(newsubtables); - FREE(newvars); - FREE(newperm); - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - if (unique->map != NULL) { - newmap = ALLOC(int,newsize); - if (newmap == NULL) { - FREE(newsubtables); - FREE(newvars); - FREE(newperm); - FREE(newinvperm); - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - unique->memused += (newsize - unique->maxSize) * sizeof(int); - } - unique->memused += (newsize - unique->maxSize) * ((numSlots+1) * - sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable)); - if (newsize > unique->maxSizeZ) { - FREE(unique->stack); - unique->stack = ALLOC(DdNodePtr,newsize + 1); - if (unique->stack == NULL) { - FREE(newsubtables); - FREE(newvars); - FREE(newperm); - FREE(newinvperm); - if (unique->map != NULL) { - FREE(newmap); - } - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - unique->stack[0] = NULL; /* to suppress harmless UMR */ - unique->memused += - (newsize - ddMax(unique->maxSize,unique->maxSizeZ)) - * sizeof(DdNode *); - } - for (i = 0; i < oldsize; i++) { - newsubtables[i].slots = unique->subtables[i].slots; - newsubtables[i].shift = unique->subtables[i].shift; - newsubtables[i].keys = unique->subtables[i].keys; - newsubtables[i].maxKeys = unique->subtables[i].maxKeys; - newsubtables[i].dead = unique->subtables[i].dead; - newsubtables[i].nodelist = unique->subtables[i].nodelist; - newsubtables[i].bindVar = unique->subtables[i].bindVar; - newsubtables[i].varType = unique->subtables[i].varType; - newsubtables[i].pairIndex = unique->subtables[i].pairIndex; - newsubtables[i].varHandled = unique->subtables[i].varHandled; - newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped; - - newvars[i] = unique->vars[i]; - newperm[i] = unique->perm[i]; - newinvperm[i] = unique->invperm[i]; - } - for (i = oldsize; i <= index; i++) { - newsubtables[i].slots = numSlots; - newsubtables[i].shift = sizeof(int) * 8 - - cuddComputeFloorLog2(numSlots); - newsubtables[i].keys = 0; - newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY; - newsubtables[i].dead = 0; - newsubtables[i].bindVar = 0; - newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT; - newsubtables[i].pairIndex = 0; - newsubtables[i].varHandled = 0; - newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE; - - newperm[i] = i; - newinvperm[i] = i; - newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots); - if (newnodelist == NULL) { - unique->errorCode = CUDD_MEMORY_OUT; - return(0); - } - for (j = 0; j < numSlots; j++) { - newnodelist[j] = sentinel; - } - } - if (unique->map != NULL) { - for (i = 0; i < oldsize; i++) { - newmap[i] = unique->map[i]; - } - for (i = oldsize; i <= index; i++) { - newmap[i] = i; - } - FREE(unique->map); - unique->map = newmap; - } - FREE(unique->subtables); - unique->subtables = newsubtables; - unique->maxSize = newsize; - FREE(unique->vars); - unique->vars = newvars; - FREE(unique->perm); - unique->perm = newperm; - FREE(unique->invperm); - unique->invperm = newinvperm; - } - - /* Now that the table is in a coherent state, create the new - ** projection functions. We need to temporarily disable reordering, - ** because we cannot reorder without projection functions in place. - **/ - one = unique->one; - zero = Cudd_Not(one); - - unique->size = index + 1; - unique->slots += (index + 1 - oldsize) * numSlots; - ddFixLimits(unique); - - reorderSave = unique->autoDyn; - unique->autoDyn = 0; - for (i = oldsize; i <= index; i++) { - unique->vars[i] = cuddUniqueInter(unique,i,one,zero); - if (unique->vars[i] == NULL) { - unique->autoDyn = reorderSave; - for (j = oldsize; j < i; j++) { - Cudd_IterDerefBdd(unique,unique->vars[j]); - cuddDeallocNode(unique,unique->vars[j]); - unique->vars[j] = NULL; - } - for (j = oldsize; j <= index; j++) { - FREE(unique->subtables[j].nodelist); - unique->subtables[j].nodelist = NULL; - } - unique->size = oldsize; - unique->slots -= (index + 1 - oldsize) * numSlots; - ddFixLimits(unique); - return(0); - } - cuddRef(unique->vars[i]); - } - unique->autoDyn = reorderSave; - - return(1); - -} /* end of ddResizeTable */ - - -/**Function******************************************************************** - - Synopsis [Searches the subtables above node for a parent.] - - Description [Searches the subtables above node for a parent. Returns 1 - as soon as one parent is found. Returns 0 is the search is fruitless.] - - SideEffects [None] - - SeeAlso [] - -******************************************************************************/ -static int -cuddFindParent( - DdManager * table, - DdNode * node) -{ - int i,j; - int slots; - DdNodePtr *nodelist; - DdNode *f; - - for (i = cuddI(table,node->index) - 1; i >= 0; i--) { - nodelist = table->subtables[i].nodelist; - slots = table->subtables[i].slots; - - for (j = 0; j < slots; j++) { - f = nodelist[j]; - while (cuddT(f) > node) { - f = f->next; - } - while (cuddT(f) == node && Cudd_Regular(cuddE(f)) > node) { - f = f->next; - } - if (cuddT(f) == node && Cudd_Regular(cuddE(f)) == node) { - return(1); - } - } - } - - return(0); - -} /* end of cuddFindParent */ - - -/**Function******************************************************************** - - Synopsis [Adjusts the values of table limits.] - - Description [Adjusts the values of table fields controlling the. - sizes of subtables and computed table. If the computed table is too small - according to the new values, it is resized.] - - SideEffects [Modifies manager fields. May resize computed table.] - - SeeAlso [] - -******************************************************************************/ -DD_INLINE -static void -ddFixLimits( - DdManager *unique) -{ - unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots); - unique->cacheSlack = (int) ddMin(unique->maxCacheHard, - DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots) - - 2 * (int) unique->cacheSlots; - if (unique->cacheSlots < unique->slots/2 && unique->cacheSlack >= 0) - cuddCacheResize(unique); - return; - -} /* end of ddFixLimits */ - - -#ifndef DD_UNSORTED_FREE_LIST -/**Function******************************************************************** - - Synopsis [Inserts a DdNode in a red/black search tree.] - - Description [Inserts a DdNode in a red/black search tree. Nodes from - the same "page" (defined by DD_PAGE_MASK) are linked in a LIFO list.] - - SideEffects [None] - - SeeAlso [cuddOrderedThread] - -******************************************************************************/ -static void -cuddOrderedInsert( - DdNodePtr * root, - DdNodePtr node) -{ - DdNode *scan; - DdNodePtr *scanP; - DdNodePtr *stack[DD_STACK_SIZE]; - int stackN = 0; - - scanP = root; - while ((scan = *scanP) != NULL) { - stack[stackN++] = scanP; - if (DD_INSERT_COMPARE(node, scan) == 0) { /* add to page list */ - DD_NEXT(node) = DD_NEXT(scan); - DD_NEXT(scan) = node; - return; - } - scanP = (node < scan) ? &DD_LEFT(scan) : &DD_RIGHT(scan); - } - DD_RIGHT(node) = DD_LEFT(node) = DD_NEXT(node) = NULL; - DD_COLOR(node) = DD_RED; - *scanP = node; - stack[stackN] = &node; - cuddDoRebalance(stack,stackN); - -} /* end of cuddOrderedInsert */ - - -/**Function******************************************************************** - - Synopsis [Threads all the nodes of a search tree into a linear list.] - - Description [Threads all the nodes of a search tree into a linear - list. For each node of the search tree, the "left" child, if non-null, has - a lower address than its parent, and the "right" child, if non-null, has a - higher address than its parent. - The list is sorted in order of increasing addresses. The search - tree is destroyed as a result of this operation. The last element of - the linear list is made to point to the address passed in list. Each - node if the search tree is a linearly-linked list of nodes from the - same memory page (as defined in DD_PAGE_MASK). When a node is added to - the linear list, all the elements of the linked list are added.] - - SideEffects [The search tree is destroyed as a result of this operation.] - - SeeAlso [cuddOrderedInsert] - -******************************************************************************/ -static DdNode * -cuddOrderedThread( - DdNode * root, - DdNode * list) -{ - DdNode *current, *next, *prev, *end; - - current = root; - /* The first word in the node is used to implement a stack that holds - ** the nodes from the root of the tree to the current node. Here we - ** put the root of the tree at the bottom of the stack. - */ - *((DdNodePtr *) current) = NULL; - - while (current != NULL) { - if (DD_RIGHT(current) != NULL) { - /* If possible, we follow the "right" link. Eventually we'll - ** find the node with the largest address in the current tree. - ** In this phase we use the first word of a node to implemen - ** a stack of the nodes on the path from the root to "current". - ** Also, we disconnect the "right" pointers to indicate that - ** we have already followed them. - */ - next = DD_RIGHT(current); - DD_RIGHT(current) = NULL; - *((DdNodePtr *)next) = current; - current = next; - } else { - /* We can't proceed along the "right" links any further. - ** Hence "current" is the largest element in the current tree. - ** We make this node the new head of "list". (Repeating this - ** operation until the tree is empty yields the desired linear - ** threading of all nodes.) - */ - prev = *((DdNodePtr *) current); /* save prev node on stack in prev */ - /* Traverse the linked list of current until the end. */ - for (end = current; DD_NEXT(end) != NULL; end = DD_NEXT(end)); - DD_NEXT(end) = list; /* attach "list" at end and make */ - list = current; /* "current" the new head of "list" */ - /* Now, if current has a "left" child, we push it on the stack. - ** Otherwise, we just continue with the parent of "current". - */ - if (DD_LEFT(current) != NULL) { - next = DD_LEFT(current); - *((DdNodePtr *) next) = prev; - current = next; - } else { - current = prev; - } - } - } - - return(list); - -} /* end of cuddOrderedThread */ - - -/**Function******************************************************************** - - Synopsis [Performs the left rotation for red/black trees.] - - Description [] - - SideEffects [None] - - SeeAlso [cuddRotateRight] - -******************************************************************************/ -DD_INLINE -static void -cuddRotateLeft( - DdNodePtr * nodeP) -{ - DdNode *newRoot; - DdNode *oldRoot = *nodeP; - - *nodeP = newRoot = DD_RIGHT(oldRoot); - DD_RIGHT(oldRoot) = DD_LEFT(newRoot); - DD_LEFT(newRoot) = oldRoot; - -} /* end of cuddRotateLeft */ - - -/**Function******************************************************************** - - Synopsis [Performs the right rotation for red/black trees.] - - Description [] - - SideEffects [None] - - SeeAlso [cuddRotateLeft] - -******************************************************************************/ -DD_INLINE -static void -cuddRotateRight( - DdNodePtr * nodeP) -{ - DdNode *newRoot; - DdNode *oldRoot = *nodeP; - - *nodeP = newRoot = DD_LEFT(oldRoot); - DD_LEFT(oldRoot) = DD_RIGHT(newRoot); - DD_RIGHT(newRoot) = oldRoot; - -} /* end of cuddRotateRight */ - - -/**Function******************************************************************** - - Synopsis [Rebalances a red/black tree.] - - Description [] - - SideEffects [None] - - SeeAlso [] - -******************************************************************************/ -static void -cuddDoRebalance( - DdNodePtr ** stack, - int stackN) -{ - DdNodePtr *xP, *parentP, *grandpaP; - DdNode *x, *y, *parent, *grandpa; - - xP = stack[stackN]; - x = *xP; - /* Work our way back up, re-balancing the tree. */ - while (--stackN >= 0) { - parentP = stack[stackN]; - parent = *parentP; - if (DD_IS_BLACK(parent)) break; - /* Since the root is black, here a non-null grandparent exists. */ - grandpaP = stack[stackN-1]; - grandpa = *grandpaP; - if (parent == DD_LEFT(grandpa)) { - y = DD_RIGHT(grandpa); - if (y != NULL && DD_IS_RED(y)) { - DD_COLOR(parent) = DD_BLACK; - DD_COLOR(y) = DD_BLACK; - DD_COLOR(grandpa) = DD_RED; - x = grandpa; - stackN--; - } else { - if (x == DD_RIGHT(parent)) { - cuddRotateLeft(parentP); - DD_COLOR(x) = DD_BLACK; - } else { - DD_COLOR(parent) = DD_BLACK; - } - DD_COLOR(grandpa) = DD_RED; - cuddRotateRight(grandpaP); - break; - } - } else { - y = DD_LEFT(grandpa); - if (y != NULL && DD_IS_RED(y)) { - DD_COLOR(parent) = DD_BLACK; - DD_COLOR(y) = DD_BLACK; - DD_COLOR(grandpa) = DD_RED; - x = grandpa; - stackN--; - } else { - if (x == DD_LEFT(parent)) { - cuddRotateRight(parentP); - DD_COLOR(x) = DD_BLACK; - } else { - DD_COLOR(parent) = DD_BLACK; - } - DD_COLOR(grandpa) = DD_RED; - cuddRotateLeft(grandpaP); - } - } - } - DD_COLOR(*(stack[0])) = DD_BLACK; - -} /* end of cuddDoRebalance */ -#endif - - -/**Function******************************************************************** - - Synopsis [Fixes a variable tree after the insertion of new subtables.] - - Description [Fixes a variable tree after the insertion of new subtables. - After such an insertion, the low fields of the tree below the insertion - point are inconsistent.] - - SideEffects [None] - - SeeAlso [] - -******************************************************************************/ -static void -ddPatchTree( - DdManager *dd, - MtrNode *treenode) -{ - MtrNode *auxnode = treenode; - - while (auxnode != NULL) { - auxnode->low = dd->perm[auxnode->index]; - if (auxnode->child != NULL) { - ddPatchTree(dd, auxnode->child); - } - auxnode = auxnode->younger; - } - - return; - -} /* end of ddPatchTree */ - - -#ifdef DD_DEBUG -/**Function******************************************************************** - - Synopsis [Checks whether a collision list is ordered.] - - Description [] - - SideEffects [None] - - SeeAlso [] - -******************************************************************************/ -static int -cuddCheckCollisionOrdering( - DdManager *unique, - int i, - int j) -{ - int slots; - DdNode *node, *next; - DdNodePtr *nodelist; - DdNode *sentinel = &(unique->sentinel); - - nodelist = unique->subtables[i].nodelist; - slots = unique->subtables[i].slots; - node = nodelist[j]; - if (node == sentinel) return(1); - next = node->next; - while (next != sentinel) { - if (cuddT(node) < cuddT(next) || - (cuddT(node) == cuddT(next) && cuddE(node) < cuddE(next))) { - (void) fprintf(unique->err, - "Unordered list: index %u, position %d\n", i, j); - return(0); - } - node = next; - next = node->next; - } - return(1); - -} /* end of cuddCheckCollisionOrdering */ -#endif - - - - -/**Function******************************************************************** - - Synopsis [Reports problem in garbage collection.] - - Description [] - - SideEffects [None] - - SeeAlso [cuddGarbageCollect cuddGarbageCollectZdd] - -******************************************************************************/ -static void -ddReportRefMess( - DdManager *unique /* manager */, - int i /* table in which the problem occurred */, - char *caller /* procedure that detected the problem */) -{ - if (i == CUDD_CONST_INDEX) { - (void) fprintf(unique->err, - "%s: problem in constants\n", caller); - } else if (i != -1) { - (void) fprintf(unique->err, - "%s: problem in table %d\n", caller, i); - } - (void) fprintf(unique->err, " dead count != deleted\n"); - (void) fprintf(unique->err, " This problem is often due to a missing \ -call to Cudd_Ref\n or to an extra call to Cudd_RecursiveDeref.\n \ -See the CUDD Programmer's Guide for additional details."); - abort(); - -} /* end of ddReportRefMess */ |