00001
00057 #include "util_hack.h"
00058 #include "cuddInt.h"
00059
00060
00061
00062
00063
00064 #ifndef DD_UNSORTED_FREE_LIST
00065
00066 #define DD_STACK_SIZE 128
00067 #define DD_RED 0
00068 #define DD_BLACK 1
00069 #define DD_PAGE_SIZE 8192
00070 #define DD_PAGE_MASK ~(DD_PAGE_SIZE - 1)
00071 #define DD_INSERT_COMPARE(x,y) \
00072 (((ptruint) (x) & DD_PAGE_MASK) - ((ptruint) (y) & DD_PAGE_MASK))
00073 #endif
00074
00075
00076
00077
00078
00079
00080 typedef union hack {
00081 CUDD_VALUE_TYPE value;
00082 unsigned int bits[2];
00083 } hack;
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093 #ifndef lint
00094 static char rcsid[] DD_UNUSED = "$Id: cuddTable.c,v 1.1.1.1 2003/02/24 22:23:53 wjiang Exp $";
00095 #endif
00096
00097
00098
00099
00100
00101
00102 #ifndef DD_UNSORTED_FREE_LIST
00103
00104 #define DD_COLOR(p) ((p)->index)
00105 #define DD_IS_BLACK(p) ((p)->index == DD_BLACK)
00106 #define DD_IS_RED(p) ((p)->index == DD_RED)
00107 #define DD_LEFT(p) cuddT(p)
00108 #define DD_RIGHT(p) cuddE(p)
00109 #define DD_NEXT(p) ((p)->next)
00110 #endif
00111
00112
00115
00116
00117
00118
00119 static void ddRehashZdd ARGS((DdManager *unique, int i));
00120 static int ddResizeTable ARGS((DdManager *unique, int index));
00121 static int cuddFindParent ARGS((DdManager *table, DdNode *node));
00122 DD_INLINE static void ddFixLimits ARGS((DdManager *unique));
00123 static void cuddOrderedInsert ARGS((DdNodePtr *root, DdNodePtr node));
00124 static DdNode * cuddOrderedThread ARGS((DdNode *root, DdNode *list));
00125 static void cuddRotateLeft ARGS((DdNodePtr *nodeP));
00126 static void cuddRotateRight ARGS((DdNodePtr *nodeP));
00127 static void cuddDoRebalance ARGS((DdNodePtr **stack, int stackN));
00128 static void ddPatchTree ARGS((DdManager *dd, MtrNode *treenode));
00129 #ifdef DD_DEBUG
00130 static int cuddCheckCollisionOrdering ARGS((DdManager *unique, int i, int j));
00131 #endif
00132 static void ddReportRefMess ARGS((DdManager *unique, int i, char *caller));
00133
00137
00138
00139
00140
00141
00151 unsigned int
00152 Cudd_Prime(
00153 unsigned int p)
00154 {
00155 int i,pn;
00156
00157 p--;
00158 do {
00159 p++;
00160 if (p&1) {
00161 pn = 1;
00162 i = 3;
00163 while ((unsigned) (i * i) <= p) {
00164 if (p % i == 0) {
00165 pn = 0;
00166 break;
00167 }
00168 i += 2;
00169 }
00170 } else {
00171 pn = 0;
00172 }
00173 } while (!pn);
00174 return(p);
00175
00176 }
00177
00178
00179
00180
00181
00182
00183
00198 DdNode *
00199 cuddAllocNode(
00200 DdManager * unique)
00201 {
00202 int i;
00203 DdNodePtr *mem;
00204 DdNode *list, *node;
00205 extern void (*MMoutOfMemory)(long);
00206 void (*saveHandler)(long);
00207
00208 if (unique->nextFree == NULL) {
00209
00210 if ((unique->keys - unique->dead) + (unique->keysZ - unique->deadZ) >
00211 unique->maxLive) {
00212 unique->errorCode = CUDD_TOO_MANY_NODES;
00213 return(NULL);
00214 }
00215 if (unique->stash == NULL || unique->memused > unique->maxmemhard) {
00216 (void) cuddGarbageCollect(unique,1);
00217 mem = NULL;
00218 }
00219 if (unique->nextFree == NULL) {
00220 if (unique->memused > unique->maxmemhard) {
00221 unique->errorCode = CUDD_MAX_MEM_EXCEEDED;
00222 return(NULL);
00223 }
00224
00225 saveHandler = MMoutOfMemory;
00226 MMoutOfMemory = Cudd_OutOfMem;
00227 mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
00228 MMoutOfMemory = saveHandler;
00229 if (mem == NULL) {
00230
00231
00232
00233 if (cuddGarbageCollect(unique,1) == 0) {
00234
00235
00236
00237 if (unique->stash != NULL) {
00238 FREE(unique->stash);
00239 unique->stash = NULL;
00240
00241 cuddSlowTableGrowth(unique);
00242
00243 mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
00244 }
00245 if (mem == NULL) {
00246
00247
00248
00249
00250 (*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1));
00251 unique->errorCode = CUDD_MEMORY_OUT;
00252 #ifdef DD_VERBOSE
00253 (void) fprintf(unique->err,
00254 "cuddAllocNode: out of memory");
00255 (void) fprintf(unique->err, "Memory in use = %ld\n",
00256 unique->memused);
00257 #endif
00258 return(NULL);
00259 }
00260 }
00261 }
00262 if (mem != NULL) {
00263 ptruint offset;
00264 unique->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode);
00265 mem[0] = (DdNodePtr) unique->memoryList;
00266 unique->memoryList = mem;
00267
00268
00269
00270 offset = (ptruint) mem & (sizeof(DdNode) - 1);
00271 mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
00272 assert(((ptruint) mem & (sizeof(DdNode) - 1)) == 0);
00273 list = (DdNode *) mem;
00274
00275 i = 1;
00276 do {
00277 list[i - 1].next = &list[i];
00278 } while (++i < DD_MEM_CHUNK);
00279
00280 list[DD_MEM_CHUNK-1].next = NULL;
00281
00282 unique->nextFree = &list[0];
00283 }
00284 }
00285 }
00286 unique->allocated++;
00287 node = unique->nextFree;
00288 unique->nextFree = node->next;
00289 return(node);
00290
00291 }
00292
00293
00306 DdManager *
00307 cuddInitTable(
00308 unsigned int numVars ,
00309 unsigned int numVarsZ ,
00310 unsigned int numSlots ,
00311 unsigned int looseUpTo )
00312 {
00313 DdManager *unique = ALLOC(DdManager,1);
00314 int i, j;
00315 DdNodePtr *nodelist;
00316 DdNode *sentinel;
00317 unsigned int slots;
00318 int shift;
00319
00320 if (unique == NULL) {
00321 return(NULL);
00322 }
00323 sentinel = &(unique->sentinel);
00324 sentinel->ref = 0;
00325 sentinel->index = 0;
00326 cuddT(sentinel) = NULL;
00327 cuddE(sentinel) = NULL;
00328 sentinel->next = NULL;
00329 unique->epsilon = DD_EPSILON;
00330 unique->maxGrowth = DD_MAX_REORDER_GROWTH;
00331 unique->maxGrowthAlt = 2.0 * DD_MAX_REORDER_GROWTH;
00332 unique->reordCycle = 0;
00333 unique->size = numVars;
00334 unique->sizeZ = numVarsZ;
00335 unique->maxSize = ddMax(DD_DEFAULT_RESIZE, numVars);
00336 unique->maxSizeZ = ddMax(DD_DEFAULT_RESIZE, numVarsZ);
00337
00338
00339 slots = 8;
00340 while (slots < numSlots) {
00341 slots <<= 1;
00342 }
00343 unique->initSlots = slots;
00344 shift = sizeof(int) * 8 - cuddComputeFloorLog2(slots);
00345
00346 unique->slots = (numVars + numVarsZ + 1) * slots;
00347 unique->keys = 0;
00348 unique->maxLive = ~0;
00349 unique->keysZ = 0;
00350 unique->dead = 0;
00351 unique->deadZ = 0;
00352 unique->gcFrac = DD_GC_FRAC_HI;
00353 unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
00354 unique->looseUpTo = looseUpTo;
00355 unique->gcEnabled = 1;
00356 unique->allocated = 0;
00357 unique->reclaimed = 0;
00358 unique->subtables = ALLOC(DdSubtable,unique->maxSize);
00359 if (unique->subtables == NULL) {
00360 unique->errorCode = CUDD_MEMORY_OUT;
00361 return(0);
00362 }
00363 unique->subtableZ = ALLOC(DdSubtable,unique->maxSizeZ);
00364 if (unique->subtableZ == NULL) {
00365 unique->errorCode = CUDD_MEMORY_OUT;
00366 return(0);
00367 }
00368 unique->perm = ALLOC(int,unique->maxSize);
00369 if (unique->perm == NULL) {
00370 unique->errorCode = CUDD_MEMORY_OUT;
00371 return(0);
00372 }
00373 unique->invperm = ALLOC(int,unique->maxSize);
00374 if (unique->invperm == NULL) {
00375 unique->errorCode = CUDD_MEMORY_OUT;
00376 return(0);
00377 }
00378 unique->permZ = ALLOC(int,unique->maxSizeZ);
00379 if (unique->permZ == NULL) {
00380 unique->errorCode = CUDD_MEMORY_OUT;
00381 return(0);
00382 }
00383 unique->invpermZ = ALLOC(int,unique->maxSizeZ);
00384 if (unique->invpermZ == NULL) {
00385 unique->errorCode = CUDD_MEMORY_OUT;
00386 return(0);
00387 }
00388 unique->map = NULL;
00389 unique->stack = ALLOC(DdNodePtr,ddMax(unique->maxSize,unique->maxSizeZ)+1);
00390 if (unique->stack == NULL) {
00391 unique->errorCode = CUDD_MEMORY_OUT;
00392 return(0);
00393 }
00394 unique->stack[0] = NULL;
00395
00396 #ifndef DD_NO_DEATH_ROW
00397 unique->deathRowDepth = 1 << cuddComputeFloorLog2(unique->looseUpTo >> 2);
00398 unique->deathRow = ALLOC(DdNodePtr,unique->deathRowDepth);
00399 if (unique->deathRow == NULL) {
00400 unique->errorCode = CUDD_MEMORY_OUT;
00401 return(0);
00402 }
00403 for (i = 0; i < unique->deathRowDepth; i++) {
00404 unique->deathRow[i] = NULL;
00405 }
00406 unique->nextDead = 0;
00407 unique->deadMask = unique->deathRowDepth - 1;
00408 #endif
00409
00410 for (i = 0; (unsigned) i < numVars; i++) {
00411 unique->subtables[i].slots = slots;
00412 unique->subtables[i].shift = shift;
00413 unique->subtables[i].keys = 0;
00414 unique->subtables[i].dead = 0;
00415 unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
00416 unique->subtables[i].bindVar = 0;
00417 unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
00418 unique->subtables[i].pairIndex = 0;
00419 unique->subtables[i].varHandled = 0;
00420 unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
00421
00422 nodelist = unique->subtables[i].nodelist = ALLOC(DdNodePtr,slots);
00423 if (nodelist == NULL) {
00424 unique->errorCode = CUDD_MEMORY_OUT;
00425 return(NULL);
00426 }
00427 for (j = 0; (unsigned) j < slots; j++) {
00428 nodelist[j] = sentinel;
00429 }
00430 unique->perm[i] = i;
00431 unique->invperm[i] = i;
00432 }
00433 for (i = 0; (unsigned) i < numVarsZ; i++) {
00434 unique->subtableZ[i].slots = slots;
00435 unique->subtableZ[i].shift = shift;
00436 unique->subtableZ[i].keys = 0;
00437 unique->subtableZ[i].dead = 0;
00438 unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
00439 nodelist = unique->subtableZ[i].nodelist = ALLOC(DdNodePtr,slots);
00440 if (nodelist == NULL) {
00441 unique->errorCode = CUDD_MEMORY_OUT;
00442 return(NULL);
00443 }
00444 for (j = 0; (unsigned) j < slots; j++) {
00445 nodelist[j] = NULL;
00446 }
00447 unique->permZ[i] = i;
00448 unique->invpermZ[i] = i;
00449 }
00450 unique->constants.slots = slots;
00451 unique->constants.shift = shift;
00452 unique->constants.keys = 0;
00453 unique->constants.dead = 0;
00454 unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
00455 nodelist = unique->constants.nodelist = ALLOC(DdNodePtr,slots);
00456 if (nodelist == NULL) {
00457 unique->errorCode = CUDD_MEMORY_OUT;
00458 return(NULL);
00459 }
00460 for (j = 0; (unsigned) j < slots; j++) {
00461 nodelist[j] = NULL;
00462 }
00463
00464 unique->memoryList = NULL;
00465 unique->nextFree = NULL;
00466
00467 unique->memused = sizeof(DdManager) + (unique->maxSize + unique->maxSizeZ)
00468 * (sizeof(DdSubtable) + 2 * sizeof(int)) + (numVars + 1) *
00469 slots * sizeof(DdNodePtr) +
00470 (ddMax(unique->maxSize,unique->maxSizeZ) + 1) * sizeof(DdNodePtr);
00471 #ifndef DD_NO_DEATH_ROW
00472 unique->memused += unique->deathRowDepth * sizeof(DdNodePtr);
00473 #endif
00474
00475
00476 unique->reorderings = 0;
00477 unique->autoDyn = 0;
00478 unique->autoDynZ = 0;
00479 unique->realign = 0;
00480 unique->realignZ = 0;
00481 unique->reordered = 0;
00482 unique->autoMethod = CUDD_REORDER_SIFT;
00483 unique->autoMethodZ = CUDD_REORDER_SIFT;
00484 unique->nextDyn = DD_FIRST_REORDER;
00485 unique->countDead = ~0;
00486 unique->siftMaxVar = DD_SIFT_MAX_VAR;
00487 unique->siftMaxSwap = DD_SIFT_MAX_SWAPS;
00488 unique->tree = NULL;
00489 unique->treeZ = NULL;
00490 unique->groupcheck = CUDD_GROUP_CHECK7;
00491 unique->recomb = DD_DEFAULT_RECOMB;
00492 unique->symmviolation = 0;
00493 unique->arcviolation = 0;
00494 unique->populationSize = 0;
00495 unique->numberXovers = 0;
00496 unique->linear = NULL;
00497 unique->linearSize = 0;
00498
00499
00500 unique->univ = (DdNodePtr *)NULL;
00501
00502
00503 unique->localCaches = NULL;
00504 unique->preGCHook = NULL;
00505 unique->postGCHook = NULL;
00506 unique->preReorderingHook = NULL;
00507 unique->postReorderingHook = NULL;
00508 unique->out = stdout;
00509 unique->err = stderr;
00510 unique->errorCode = CUDD_NO_ERROR;
00511
00512
00513 unique->maxmemhard = (long) ((~ (unsigned long) 0) >> 1);
00514 unique->garbageCollections = 0;
00515 unique->GCTime = 0;
00516 unique->reordTime = 0;
00517 #ifdef DD_STATS
00518 unique->nodesDropped = 0;
00519 unique->nodesFreed = 0;
00520 #endif
00521 unique->peakLiveNodes = 0;
00522 #ifdef DD_UNIQUE_PROFILE
00523 unique->uniqueLookUps = 0;
00524 unique->uniqueLinks = 0;
00525 #endif
00526 #ifdef DD_COUNT
00527 unique->recursiveCalls = 0;
00528 unique->swapSteps = 0;
00529 #ifdef DD_STATS
00530 unique->nextSample = 250000;
00531 #endif
00532 #endif
00533
00534 return(unique);
00535
00536 }
00537
00538
00550 void
00551 cuddFreeTable(
00552 DdManager * unique)
00553 {
00554 DdNodePtr *next;
00555 DdNodePtr *memlist = unique->memoryList;
00556 int i;
00557
00558 if (unique->univ != NULL) cuddZddFreeUniv(unique);
00559 while (memlist != NULL) {
00560 next = (DdNodePtr *) memlist[0];
00561 FREE(memlist);
00562 memlist = next;
00563 }
00564 unique->nextFree = NULL;
00565 unique->memoryList = NULL;
00566
00567 for (i = 0; i < unique->size; i++) {
00568 FREE(unique->subtables[i].nodelist);
00569 }
00570 for (i = 0; i < unique->sizeZ; i++) {
00571 FREE(unique->subtableZ[i].nodelist);
00572 }
00573 FREE(unique->constants.nodelist);
00574 FREE(unique->subtables);
00575 FREE(unique->subtableZ);
00576 FREE(unique->acache);
00577 FREE(unique->perm);
00578 FREE(unique->permZ);
00579 FREE(unique->invperm);
00580 FREE(unique->invpermZ);
00581 FREE(unique->vars);
00582 if (unique->map != NULL) FREE(unique->map);
00583 FREE(unique->stack);
00584 #ifndef DD_NO_DEATH_ROW
00585 FREE(unique->deathRow);
00586 #endif
00587 if (unique->tree != NULL) Mtr_FreeTree(unique->tree);
00588 if (unique->treeZ != NULL) Mtr_FreeTree(unique->treeZ);
00589 if (unique->linear != NULL) FREE(unique->linear);
00590 while (unique->preGCHook != NULL)
00591 Cudd_RemoveHook(unique,unique->preGCHook->f,CUDD_PRE_GC_HOOK);
00592 while (unique->postGCHook != NULL)
00593 Cudd_RemoveHook(unique,unique->postGCHook->f,CUDD_POST_GC_HOOK);
00594 while (unique->preReorderingHook != NULL)
00595 Cudd_RemoveHook(unique,unique->preReorderingHook->f,
00596 CUDD_PRE_REORDERING_HOOK);
00597 while (unique->postReorderingHook != NULL)
00598 Cudd_RemoveHook(unique,unique->postReorderingHook->f,
00599 CUDD_POST_REORDERING_HOOK);
00600 FREE(unique);
00601
00602 }
00603
00604
00620 int
00621 cuddGarbageCollect(
00622 DdManager * unique,
00623 int clearCache)
00624 {
00625 DdHook *hook;
00626 DdCache *cache = unique->cache;
00627 DdNode *sentinel = &(unique->sentinel);
00628 DdNodePtr *nodelist;
00629 int i, j, deleted, totalDeleted;
00630 DdCache *c;
00631 DdNode *node,*next;
00632 DdNodePtr *lastP;
00633 int slots;
00634 long localTime;
00635 #ifndef DD_UNSORTED_FREE_LIST
00636 DdNodePtr tree;
00637 #endif
00638
00639 #ifndef DD_NO_DEATH_ROW
00640 cuddClearDeathRow(unique);
00641 #endif
00642
00643 hook = unique->preGCHook;
00644 while (hook != NULL) {
00645 int res = (hook->f)(unique,"BDD",NULL);
00646 if (res == 0) return(0);
00647 hook = hook->next;
00648 }
00649
00650 if (unique->dead == 0) {
00651 hook = unique->postGCHook;
00652 while (hook != NULL) {
00653 int res = (hook->f)(unique,"BDD",NULL);
00654 if (res == 0) return(0);
00655 hook = hook->next;
00656 }
00657 return(0);
00658 }
00659
00660
00661
00662
00663 if (clearCache && unique->gcFrac == DD_GC_FRAC_LO &&
00664 unique->slots <= unique->looseUpTo && unique->stash != NULL) {
00665 unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
00666 #ifdef DD_VERBOSE
00667 (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_HI);
00668 (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
00669 #endif
00670 unique->gcFrac = DD_GC_FRAC_HI;
00671 return(0);
00672 }
00673
00674 localTime = util_cpu_time();
00675
00676 unique->garbageCollections++;
00677 #ifdef DD_VERBOSE
00678 (void) fprintf(unique->err,
00679 "garbage collecting (%d dead out of %d, min %d)...",
00680 unique->dead, unique->keys, unique->minDead);
00681 #endif
00682
00683
00684 if (clearCache) {
00685 slots = unique->cacheSlots;
00686 for (i = 0; i < slots; i++) {
00687 c = &cache[i];
00688 if (c->data != NULL) {
00689 if (cuddClean(c->f)->ref == 0 ||
00690 cuddClean(c->g)->ref == 0 ||
00691 (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) ||
00692 (c->data != DD_NON_CONSTANT &&
00693 Cudd_Regular(c->data)->ref == 0)) {
00694 c->data = NULL;
00695 unique->cachedeletions++;
00696 }
00697 }
00698 }
00699 cuddLocalCacheClearDead(unique);
00700 }
00701
00702
00703 totalDeleted = 0;
00704 #ifndef DD_UNSORTED_FREE_LIST
00705 tree = NULL;
00706 #endif
00707
00708 for (i = 0; i < unique->size; i++) {
00709 if (unique->subtables[i].dead == 0) continue;
00710 nodelist = unique->subtables[i].nodelist;
00711
00712 deleted = 0;
00713 slots = unique->subtables[i].slots;
00714 for (j = 0; j < slots; j++) {
00715 lastP = &(nodelist[j]);
00716 node = *lastP;
00717 while (node != sentinel) {
00718 next = node->next;
00719 if (node->ref == 0) {
00720 deleted++;
00721 #ifndef DD_UNSORTED_FREE_LIST
00722 #ifdef __osf__
00723 #pragma pointer_size save
00724 #pragma pointer_size short
00725 #endif
00726 cuddOrderedInsert(&tree,node);
00727 #ifdef __osf__
00728 #pragma pointer_size restore
00729 #endif
00730 #else
00731 cuddDeallocNode(unique,node);
00732 #endif
00733 } else {
00734 *lastP = node;
00735 lastP = &(node->next);
00736 }
00737 node = next;
00738 }
00739 *lastP = sentinel;
00740 }
00741 if ((unsigned) deleted != unique->subtables[i].dead) {
00742 ddReportRefMess(unique, i, "cuddGarbageCollect");
00743 }
00744 totalDeleted += deleted;
00745 unique->subtables[i].keys -= deleted;
00746 unique->subtables[i].dead = 0;
00747 }
00748 if (unique->constants.dead != 0) {
00749 nodelist = unique->constants.nodelist;
00750 deleted = 0;
00751 slots = unique->constants.slots;
00752 for (j = 0; j < slots; j++) {
00753 lastP = &(nodelist[j]);
00754 node = *lastP;
00755 while (node != NULL) {
00756 next = node->next;
00757 if (node->ref == 0) {
00758 deleted++;
00759 #ifndef DD_UNSORTED_FREE_LIST
00760 #ifdef __osf__
00761 #pragma pointer_size save
00762 #pragma pointer_size short
00763 #endif
00764 cuddOrderedInsert(&tree,node);
00765 #ifdef __osf__
00766 #pragma pointer_size restore
00767 #endif
00768 #else
00769 cuddDeallocNode(unique,node);
00770 #endif
00771 } else {
00772 *lastP = node;
00773 lastP = &(node->next);
00774 }
00775 node = next;
00776 }
00777 *lastP = NULL;
00778 }
00779 if ((unsigned) deleted != unique->constants.dead) {
00780 ddReportRefMess(unique, CUDD_CONST_INDEX, "cuddGarbageCollect");
00781 }
00782 totalDeleted += deleted;
00783 unique->constants.keys -= deleted;
00784 unique->constants.dead = 0;
00785 }
00786 if ((unsigned) totalDeleted != unique->dead) {
00787 ddReportRefMess(unique, -1, "cuddGarbageCollect");
00788 }
00789 unique->keys -= totalDeleted;
00790 unique->dead = 0;
00791 #ifdef DD_STATS
00792 unique->nodesFreed += (double) totalDeleted;
00793 #endif
00794
00795 #ifndef DD_UNSORTED_FREE_LIST
00796 unique->nextFree = cuddOrderedThread(tree,unique->nextFree);
00797 #endif
00798
00799 unique->GCTime += util_cpu_time() - localTime;
00800
00801 hook = unique->postGCHook;
00802 while (hook != NULL) {
00803 int res = (hook->f)(unique,"BDD",NULL);
00804 if (res == 0) return(0);
00805 hook = hook->next;
00806 }
00807
00808 #ifdef DD_VERBOSE
00809 (void) fprintf(unique->err," done\n");
00810 #endif
00811
00812 return(totalDeleted);
00813
00814 }
00815
00816
00832 int
00833 cuddGarbageCollectZdd(
00834 DdManager * unique,
00835 int clearCache)
00836 {
00837 DdHook *hook;
00838 DdCache *cache = unique->cache;
00839 DdNodePtr *nodelist;
00840 int i, j, deleted, totalDeleted;
00841 DdCache *c;
00842 DdNode *node,*next;
00843 DdNodePtr *lastP;
00844 int slots;
00845 long localTime;
00846 #ifndef DD_UNSORTED_FREE_LIST
00847 DdNodePtr tree;
00848 #endif
00849
00850 hook = unique->preGCHook;
00851 while (hook != NULL) {
00852 int res = (hook->f)(unique,"ZDD",NULL);
00853 if (res == 0) return(0);
00854 hook = hook->next;
00855 }
00856
00857 if (unique->deadZ == 0) {
00858 hook = unique->postGCHook;
00859 while (hook != NULL) {
00860 int res = (hook->f)(unique,"ZDD",NULL);
00861 if (res == 0) return(0);
00862 hook = hook->next;
00863 }
00864 return(0);
00865 }
00866
00867
00868
00869
00870 if (clearCache && unique->slots <= unique->looseUpTo) {
00871 unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
00872 #ifdef DD_VERBOSE
00873 if (unique->gcFrac == DD_GC_FRAC_LO) {
00874 (void) fprintf(unique->err,"GC fraction = %.2f\t",
00875 DD_GC_FRAC_HI);
00876 (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
00877 }
00878 #endif
00879 unique->gcFrac = DD_GC_FRAC_HI;
00880 }
00881
00882 localTime = util_cpu_time();
00883
00884 unique->garbageCollections++;
00885 #ifdef DD_VERBOSE
00886 (void) fprintf(unique->err,"garbage collecting (%d dead out of %d)...",
00887 unique->deadZ,unique->keysZ);
00888 #endif
00889
00890
00891 if (clearCache) {
00892 slots = unique->cacheSlots;
00893 for (i = 0; i < slots; i++) {
00894 c = &cache[i];
00895 if (c->data != NULL) {
00896 if (cuddClean(c->f)->ref == 0 ||
00897 cuddClean(c->g)->ref == 0 ||
00898 (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) ||
00899 (c->data != DD_NON_CONSTANT &&
00900 Cudd_Regular(c->data)->ref == 0)) {
00901 c->data = NULL;
00902 unique->cachedeletions++;
00903 }
00904 }
00905 }
00906 }
00907
00908
00909 totalDeleted = 0;
00910 #ifndef DD_UNSORTED_FREE_LIST
00911 tree = NULL;
00912 #endif
00913
00914 for (i = 0; i < unique->sizeZ; i++) {
00915 if (unique->subtableZ[i].dead == 0) continue;
00916 nodelist = unique->subtableZ[i].nodelist;
00917
00918 deleted = 0;
00919 slots = unique->subtableZ[i].slots;
00920 for (j = 0; j < slots; j++) {
00921 lastP = &(nodelist[j]);
00922 node = *lastP;
00923 while (node != NULL) {
00924 next = node->next;
00925 if (node->ref == 0) {
00926 deleted++;
00927 #ifndef DD_UNSORTED_FREE_LIST
00928 #ifdef __osf__
00929 #pragma pointer_size save
00930 #pragma pointer_size short
00931 #endif
00932 cuddOrderedInsert(&tree,node);
00933 #ifdef __osf__
00934 #pragma pointer_size restore
00935 #endif
00936 #else
00937 cuddDeallocNode(unique,node);
00938 #endif
00939 } else {
00940 *lastP = node;
00941 lastP = &(node->next);
00942 }
00943 node = next;
00944 }
00945 *lastP = NULL;
00946 }
00947 if ((unsigned) deleted != unique->subtableZ[i].dead) {
00948 ddReportRefMess(unique, i, "cuddGarbageCollectZdd");
00949 }
00950 totalDeleted += deleted;
00951 unique->subtableZ[i].keys -= deleted;
00952 unique->subtableZ[i].dead = 0;
00953 }
00954
00955
00956
00957
00958 if ((unsigned) totalDeleted != unique->deadZ) {
00959 ddReportRefMess(unique, -1, "cuddGarbageCollectZdd");
00960 }
00961 unique->keysZ -= totalDeleted;
00962 unique->deadZ = 0;
00963 #ifdef DD_STATS
00964 unique->nodesFreed += (double) totalDeleted;
00965 #endif
00966
00967 #ifndef DD_UNSORTED_FREE_LIST
00968 unique->nextFree = cuddOrderedThread(tree,unique->nextFree);
00969 #endif
00970
00971 unique->GCTime += util_cpu_time() - localTime;
00972
00973 hook = unique->postGCHook;
00974 while (hook != NULL) {
00975 int res = (hook->f)(unique,"ZDD",NULL);
00976 if (res == 0) return(0);
00977 hook = hook->next;
00978 }
00979
00980 #ifdef DD_VERBOSE
00981 (void) fprintf(unique->err," done\n");
00982 #endif
00983
00984 return(totalDeleted);
00985
00986 }
00987
00988
01002 DdNode *
01003 cuddZddGetNode(
01004 DdManager * zdd,
01005 int id,
01006 DdNode * T,
01007 DdNode * E)
01008 {
01009 DdNode *node;
01010
01011 if (T == DD_ZERO(zdd))
01012 return(E);
01013 node = cuddUniqueInterZdd(zdd, id, T, E);
01014 return(node);
01015
01016 }
01017
01018
01035 DdNode *
01036 cuddZddGetNodeIVO(
01037 DdManager * dd,
01038 int index,
01039 DdNode * g,
01040 DdNode * h)
01041 {
01042 DdNode *f, *r, *t;
01043 DdNode *zdd_one = DD_ONE(dd);
01044 DdNode *zdd_zero = DD_ZERO(dd);
01045
01046 f = cuddUniqueInterZdd(dd, index, zdd_one, zdd_zero);
01047 if (f == NULL) {
01048 return(NULL);
01049 }
01050 cuddRef(f);
01051 t = cuddZddProduct(dd, f, g);
01052 if (t == NULL) {
01053 Cudd_RecursiveDerefZdd(dd, f);
01054 return(NULL);
01055 }
01056 cuddRef(t);
01057 Cudd_RecursiveDerefZdd(dd, f);
01058 r = cuddZddUnion(dd, t, h);
01059 if (r == NULL) {
01060 Cudd_RecursiveDerefZdd(dd, t);
01061 return(NULL);
01062 }
01063 cuddRef(r);
01064 Cudd_RecursiveDerefZdd(dd, t);
01065
01066 cuddDeref(r);
01067 return(r);
01068
01069 }
01070
01071
01089 DdNode *
01090 cuddUniqueInter(
01091 DdManager * unique,
01092 int index,
01093 DdNode * T,
01094 DdNode * E)
01095 {
01096 int pos;
01097 unsigned int level;
01098 int retval;
01099 DdNodePtr *nodelist;
01100 DdNode *looking;
01101 DdNodePtr *previousP;
01102 DdSubtable *subtable;
01103 int gcNumber;
01104
01105 #ifdef DD_UNIQUE_PROFILE
01106 unique->uniqueLookUps++;
01107 #endif
01108
01109 if (index >= unique->size) {
01110 if (!ddResizeTable(unique,index)) return(NULL);
01111 }
01112
01113 level = unique->perm[index];
01114 subtable = &(unique->subtables[level]);
01115
01116 #ifdef DD_DEBUG
01117 assert(level < (unsigned) cuddI(unique,T->index));
01118 assert(level < (unsigned) cuddI(unique,Cudd_Regular(E)->index));
01119 #endif
01120
01121 pos = ddHash(T, E, subtable->shift);
01122 nodelist = subtable->nodelist;
01123 previousP = &(nodelist[pos]);
01124 looking = *previousP;
01125
01126 while (T < cuddT(looking)) {
01127 previousP = &(looking->next);
01128 looking = *previousP;
01129 #ifdef DD_UNIQUE_PROFILE
01130 unique->uniqueLinks++;
01131 #endif
01132 }
01133 while (T == cuddT(looking) && E < cuddE(looking)) {
01134 previousP = &(looking->next);
01135 looking = *previousP;
01136 #ifdef DD_UNIQUE_PROFILE
01137 unique->uniqueLinks++;
01138 #endif
01139 }
01140 if (T == cuddT(looking) && E == cuddE(looking)) {
01141 if (looking->ref == 0) {
01142 cuddReclaim(unique,looking);
01143 }
01144 return(looking);
01145 }
01146
01147
01148 if (unique->autoDyn &&
01149 unique->keys - (unique->dead & unique->countDead) >= unique->nextDyn) {
01150 #ifdef DD_DEBUG
01151 retval = Cudd_DebugCheck(unique);
01152 if (retval != 0) return(NULL);
01153 retval = Cudd_CheckKeys(unique);
01154 if (retval != 0) return(NULL);
01155 #endif
01156 retval = Cudd_ReduceHeap(unique,unique->autoMethod,10);
01157 if (retval == 0) unique->reordered = 2;
01158 #ifdef DD_DEBUG
01159 retval = Cudd_DebugCheck(unique);
01160 if (retval != 0) unique->reordered = 2;
01161 retval = Cudd_CheckKeys(unique);
01162 if (retval != 0) unique->reordered = 2;
01163 #endif
01164 return(NULL);
01165 }
01166
01167 if (subtable->keys > subtable->maxKeys) {
01168 if (unique->gcEnabled &&
01169 ((unique->dead > unique->minDead) ||
01170 ((unique->dead > unique->minDead / 2) &&
01171 (subtable->dead > subtable->keys * 0.95)))) {
01172 (void) cuddGarbageCollect(unique,1);
01173 } else {
01174 cuddRehash(unique,(int)level);
01175 }
01176
01177
01178
01179 pos = ddHash(T, E, subtable->shift);
01180 nodelist = subtable->nodelist;
01181 previousP = &(nodelist[pos]);
01182 looking = *previousP;
01183
01184 while (T < cuddT(looking)) {
01185 previousP = &(looking->next);
01186 looking = *previousP;
01187 #ifdef DD_UNIQUE_PROFILE
01188 unique->uniqueLinks++;
01189 #endif
01190 }
01191 while (T == cuddT(looking) && E < cuddE(looking)) {
01192 previousP = &(looking->next);
01193 looking = *previousP;
01194 #ifdef DD_UNIQUE_PROFILE
01195 unique->uniqueLinks++;
01196 #endif
01197 }
01198 }
01199
01200 gcNumber = unique->garbageCollections;
01201 looking = cuddAllocNode(unique);
01202 if (looking == NULL) {
01203 return(NULL);
01204 }
01205 unique->keys++;
01206 subtable->keys++;
01207
01208 if (gcNumber != unique->garbageCollections) {
01209 DdNode *looking2;
01210 pos = ddHash(T, E, subtable->shift);
01211 nodelist = subtable->nodelist;
01212 previousP = &(nodelist[pos]);
01213 looking2 = *previousP;
01214
01215 while (T < cuddT(looking2)) {
01216 previousP = &(looking2->next);
01217 looking2 = *previousP;
01218 #ifdef DD_UNIQUE_PROFILE
01219 unique->uniqueLinks++;
01220 #endif
01221 }
01222 while (T == cuddT(looking2) && E < cuddE(looking2)) {
01223 previousP = &(looking2->next);
01224 looking2 = *previousP;
01225 #ifdef DD_UNIQUE_PROFILE
01226 unique->uniqueLinks++;
01227 #endif
01228 }
01229 }
01230 looking->ref = 0;
01231 looking->index = index;
01232 cuddT(looking) = T;
01233 cuddE(looking) = E;
01234 looking->next = *previousP;
01235 *previousP = looking;
01236 cuddSatInc(T->ref);
01237 cuddRef(E);
01238
01239 #ifdef DD_DEBUG
01240 cuddCheckCollisionOrdering(unique,level,pos);
01241 #endif
01242
01243 return(looking);
01244
01245 }
01246
01247
01264 DdNode *
01265 cuddUniqueInterIVO(
01266 DdManager * unique,
01267 int index,
01268 DdNode * T,
01269 DdNode * E)
01270 {
01271 DdNode *result;
01272 DdNode *v;
01273
01274 v = cuddUniqueInter(unique, index, DD_ONE(unique),
01275 Cudd_Not(DD_ONE(unique)));
01276 if (v == NULL)
01277 return(NULL);
01278 cuddRef(v);
01279 result = cuddBddIteRecur(unique, v, T, E);
01280 Cudd_RecursiveDeref(unique, v);
01281 return(result);
01282 }
01283
01284
01303 DdNode *
01304 cuddUniqueInterZdd(
01305 DdManager * unique,
01306 int index,
01307 DdNode * T,
01308 DdNode * E)
01309 {
01310 int pos;
01311 unsigned int level;
01312 int retval;
01313 DdNodePtr *nodelist;
01314 DdNode *looking;
01315 DdSubtable *subtable;
01316
01317 #ifdef DD_UNIQUE_PROFILE
01318 unique->uniqueLookUps++;
01319 #endif
01320
01321 if (index >= unique->sizeZ) {
01322 if (!cuddResizeTableZdd(unique,index)) return(NULL);
01323 }
01324
01325 level = unique->permZ[index];
01326 subtable = &(unique->subtableZ[level]);
01327
01328 #ifdef DD_DEBUG
01329 assert(level < (unsigned) cuddIZ(unique,T->index));
01330 assert(level < (unsigned) cuddIZ(unique,Cudd_Regular(E)->index));
01331 #endif
01332
01333 if (subtable->keys > subtable->maxKeys) {
01334 if (unique->gcEnabled && ((unique->deadZ > unique->minDead) ||
01335 (10 * subtable->dead > 9 * subtable->keys))) {
01336 (void) cuddGarbageCollectZdd(unique,1);
01337 } else {
01338 ddRehashZdd(unique,(int)level);
01339 }
01340 }
01341
01342 pos = ddHash(T, E, subtable->shift);
01343 nodelist = subtable->nodelist;
01344 looking = nodelist[pos];
01345
01346 while (looking != NULL) {
01347 if (cuddT(looking) == T && cuddE(looking) == E) {
01348 if (looking->ref == 0) {
01349 cuddReclaimZdd(unique,looking);
01350 }
01351 return(looking);
01352 }
01353 looking = looking->next;
01354 #ifdef DD_UNIQUE_PROFILE
01355 unique->uniqueLinks++;
01356 #endif
01357 }
01358
01359
01360 if (unique->autoDynZ &&
01361 unique->keysZ - (unique->deadZ & unique->countDead) >= unique->nextDyn) {
01362 #ifdef DD_DEBUG
01363 retval = Cudd_DebugCheck(unique);
01364 if (retval != 0) return(NULL);
01365 retval = Cudd_CheckKeys(unique);
01366 if (retval != 0) return(NULL);
01367 #endif
01368 retval = Cudd_zddReduceHeap(unique,unique->autoMethodZ,10);
01369 if (retval == 0) unique->reordered = 2;
01370 #ifdef DD_DEBUG
01371 retval = Cudd_DebugCheck(unique);
01372 if (retval != 0) unique->reordered = 2;
01373 retval = Cudd_CheckKeys(unique);
01374 if (retval != 0) unique->reordered = 2;
01375 #endif
01376 return(NULL);
01377 }
01378
01379 unique->keysZ++;
01380 subtable->keys++;
01381
01382 looking = cuddAllocNode(unique);
01383 if (looking == NULL) return(NULL);
01384 looking->ref = 0;
01385 looking->index = index;
01386 cuddT(looking) = T;
01387 cuddE(looking) = E;
01388 looking->next = nodelist[pos];
01389 nodelist[pos] = looking;
01390 cuddRef(T);
01391 cuddRef(E);
01392
01393 return(looking);
01394
01395 }
01396
01397
01411 DdNode *
01412 cuddUniqueConst(
01413 DdManager * unique,
01414 CUDD_VALUE_TYPE value)
01415 {
01416 int pos;
01417 DdNodePtr *nodelist;
01418 DdNode *looking;
01419 hack split;
01420
01421 #ifdef DD_UNIQUE_PROFILE
01422 unique->uniqueLookUps++;
01423 #endif
01424
01425 if (unique->constants.keys > unique->constants.maxKeys) {
01426 if (unique->gcEnabled && ((unique->dead > unique->minDead) ||
01427 (10 * unique->constants.dead > 9 * unique->constants.keys))) {
01428 (void) cuddGarbageCollect(unique,1);
01429 } else {
01430 cuddRehash(unique,CUDD_CONST_INDEX);
01431 }
01432 }
01433
01434 cuddAdjust(value);
01435
01436 if (ddAbs(value) < unique->epsilon) {
01437 value = 0.0;
01438 }
01439 split.value = value;
01440
01441 pos = ddHash(split.bits[0], split.bits[1], unique->constants.shift);
01442 nodelist = unique->constants.nodelist;
01443 looking = nodelist[pos];
01444
01445
01446
01447
01448
01449
01450 while (looking != NULL) {
01451 if (looking->type.value == value ||
01452 ddEqualVal(looking->type.value,value,unique->epsilon)) {
01453 if (looking->ref == 0) {
01454 cuddReclaim(unique,looking);
01455 }
01456 return(looking);
01457 }
01458 looking = looking->next;
01459 #ifdef DD_UNIQUE_PROFILE
01460 unique->uniqueLinks++;
01461 #endif
01462 }
01463
01464 unique->keys++;
01465 unique->constants.keys++;
01466
01467 looking = cuddAllocNode(unique);
01468 if (looking == NULL) return(NULL);
01469 looking->ref = 0;
01470 looking->index = CUDD_CONST_INDEX;
01471 looking->type.value = value;
01472 looking->next = nodelist[pos];
01473 nodelist[pos] = looking;
01474
01475 return(looking);
01476
01477 }
01478
01479
01492 void
01493 cuddRehash(
01494 DdManager * unique,
01495 int i)
01496 {
01497 unsigned int slots, oldslots;
01498 int shift, oldshift;
01499 int j, pos;
01500 DdNodePtr *nodelist, *oldnodelist;
01501 DdNode *node, *next;
01502 DdNode *sentinel = &(unique->sentinel);
01503 hack split;
01504 extern void (*MMoutOfMemory)(long);
01505 void (*saveHandler)(long);
01506
01507 if (unique->gcFrac == DD_GC_FRAC_HI && unique->slots > unique->looseUpTo) {
01508 unique->gcFrac = DD_GC_FRAC_LO;
01509 unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
01510 #ifdef DD_VERBOSE
01511 (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_LO);
01512 (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
01513 #endif
01514 }
01515
01516 if (unique->gcFrac != DD_GC_FRAC_MIN && unique->memused > unique->maxmem) {
01517 unique->gcFrac = DD_GC_FRAC_MIN;
01518 unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
01519 #ifdef DD_VERBOSE
01520 (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_MIN);
01521 (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
01522 #endif
01523 cuddShrinkDeathRow(unique);
01524 if (cuddGarbageCollect(unique,1) > 0) return;
01525 }
01526
01527 if (i != CUDD_CONST_INDEX) {
01528 oldslots = unique->subtables[i].slots;
01529 oldshift = unique->subtables[i].shift;
01530 oldnodelist = unique->subtables[i].nodelist;
01531
01532
01533 slots = oldslots << 1;
01534 shift = oldshift - 1;
01535
01536 saveHandler = MMoutOfMemory;
01537 MMoutOfMemory = Cudd_OutOfMem;
01538 nodelist = ALLOC(DdNodePtr, slots);
01539 MMoutOfMemory = saveHandler;
01540 if (nodelist == NULL) {
01541 (void) fprintf(unique->err,
01542 "Unable to resize subtable %d for lack of memory\n",
01543 i);
01544
01545 (void) cuddGarbageCollect(unique,1);
01546 if (unique->stash != NULL) {
01547 FREE(unique->stash);
01548 unique->stash = NULL;
01549
01550 cuddSlowTableGrowth(unique);
01551 }
01552 return;
01553 }
01554 unique->subtables[i].nodelist = nodelist;
01555 unique->subtables[i].slots = slots;
01556 unique->subtables[i].shift = shift;
01557 unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
01558
01559
01560
01561
01562
01563
01564 for (j = 0; (unsigned) j < oldslots; j++) {
01565 DdNodePtr *evenP, *oddP;
01566 node = oldnodelist[j];
01567 evenP = &(nodelist[j<<1]);
01568 oddP = &(nodelist[(j<<1)+1]);
01569 while (node != sentinel) {
01570 next = node->next;
01571 pos = ddHash(cuddT(node), cuddE(node), shift);
01572 if (pos & 1) {
01573 *oddP = node;
01574 oddP = &(node->next);
01575 } else {
01576 *evenP = node;
01577 evenP = &(node->next);
01578 }
01579 node = next;
01580 }
01581 *evenP = *oddP = sentinel;
01582 }
01583 FREE(oldnodelist);
01584
01585 #ifdef DD_VERBOSE
01586 (void) fprintf(unique->err,
01587 "rehashing layer %d: keys %d dead %d new size %d\n",
01588 i, unique->subtables[i].keys,
01589 unique->subtables[i].dead, slots);
01590 #endif
01591 } else {
01592 oldslots = unique->constants.slots;
01593 oldshift = unique->constants.shift;
01594 oldnodelist = unique->constants.nodelist;
01595
01596
01597
01598
01599
01600
01601 slots = oldslots << 1;
01602 shift = oldshift - 1;
01603 saveHandler = MMoutOfMemory;
01604 MMoutOfMemory = Cudd_OutOfMem;
01605 nodelist = ALLOC(DdNodePtr, slots);
01606 MMoutOfMemory = saveHandler;
01607 if (nodelist == NULL) {
01608 int j;
01609 (void) fprintf(unique->err,
01610 "Unable to resize constant subtable for lack of memory\n");
01611 (void) cuddGarbageCollect(unique,1);
01612 for (j = 0; j < unique->size; j++) {
01613 unique->subtables[j].maxKeys <<= 1;
01614 }
01615 unique->constants.maxKeys <<= 1;
01616 return;
01617 }
01618 unique->constants.slots = slots;
01619 unique->constants.shift = shift;
01620 unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
01621 unique->constants.nodelist = nodelist;
01622 for (j = 0; (unsigned) j < slots; j++) {
01623 nodelist[j] = NULL;
01624 }
01625 for (j = 0; (unsigned) j < oldslots; j++) {
01626 node = oldnodelist[j];
01627 while (node != NULL) {
01628 next = node->next;
01629 split.value = cuddV(node);
01630 pos = ddHash(split.bits[0], split.bits[1], shift);
01631 node->next = nodelist[pos];
01632 nodelist[pos] = node;
01633 node = next;
01634 }
01635 }
01636 FREE(oldnodelist);
01637
01638 #ifdef DD_VERBOSE
01639 (void) fprintf(unique->err,
01640 "rehashing constants: keys %d dead %d new size %d\n",
01641 unique->constants.keys,unique->constants.dead,slots);
01642 #endif
01643 }
01644
01645
01646
01647 unique->memused += (slots - oldslots) * sizeof(DdNodePtr);
01648 unique->slots += (slots - oldslots);
01649 ddFixLimits(unique);
01650
01651 }
01652
01653
01665 void
01666 cuddShrinkSubtable(
01667 DdManager *unique,
01668 int i)
01669 {
01670 int j;
01671 int shift, posn;
01672 DdNodePtr *nodelist, *oldnodelist;
01673 DdNode *node, *next;
01674 DdNode *sentinel = &(unique->sentinel);
01675 unsigned int slots, oldslots;
01676 extern void (*MMoutOfMemory)(long);
01677 void (*saveHandler)(long);
01678
01679 oldnodelist = unique->subtables[i].nodelist;
01680 oldslots = unique->subtables[i].slots;
01681 slots = oldslots >> 1;
01682 saveHandler = MMoutOfMemory;
01683 MMoutOfMemory = Cudd_OutOfMem;
01684 nodelist = ALLOC(DdNodePtr, slots);
01685 MMoutOfMemory = saveHandler;
01686 if (nodelist == NULL) {
01687 return;
01688 }
01689 unique->subtables[i].nodelist = nodelist;
01690 unique->subtables[i].slots = slots;
01691 unique->subtables[i].shift++;
01692 unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
01693 #ifdef DD_VERBOSE
01694 (void) fprintf(unique->err,
01695 "shrunk layer %d (%d keys) from %d to %d slots\n",
01696 i, unique->subtables[i].keys, oldslots, slots);
01697 #endif
01698
01699 for (j = 0; (unsigned) j < slots; j++) {
01700 nodelist[j] = sentinel;
01701 }
01702 shift = unique->subtables[i].shift;
01703 for (j = 0; (unsigned) j < oldslots; j++) {
01704 node = oldnodelist[j];
01705 while (node != sentinel) {
01706 DdNode *looking, *T, *E;
01707 DdNodePtr *previousP;
01708 next = node->next;
01709 posn = ddHash(cuddT(node), cuddE(node), shift);
01710 previousP = &(nodelist[posn]);
01711 looking = *previousP;
01712 T = cuddT(node);
01713 E = cuddE(node);
01714 while (T < cuddT(looking)) {
01715 previousP = &(looking->next);
01716 looking = *previousP;
01717 #ifdef DD_UNIQUE_PROFILE
01718 unique->uniqueLinks++;
01719 #endif
01720 }
01721 while (T == cuddT(looking) && E < cuddE(looking)) {
01722 previousP = &(looking->next);
01723 looking = *previousP;
01724 #ifdef DD_UNIQUE_PROFILE
01725 unique->uniqueLinks++;
01726 #endif
01727 }
01728 node->next = *previousP;
01729 *previousP = node;
01730 node = next;
01731 }
01732 }
01733 FREE(oldnodelist);
01734
01735 unique->memused += ((long) slots - (long) oldslots) * sizeof(DdNode *);
01736 unique->slots += slots - oldslots;
01737 unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
01738 unique->cacheSlack = (int)
01739 ddMin(unique->maxCacheHard,DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots)
01740 - 2 * (int) unique->cacheSlots;
01741
01742 }
01743
01744
01758 int
01759 cuddInsertSubtables(
01760 DdManager * unique,
01761 int n,
01762 int level)
01763 {
01764 DdSubtable *newsubtables;
01765 DdNodePtr *newnodelist;
01766 DdNodePtr *newvars;
01767 DdNode *sentinel = &(unique->sentinel);
01768 int oldsize,newsize;
01769 int i,j,index,reorderSave;
01770 unsigned int numSlots = unique->initSlots;
01771 int *newperm, *newinvperm, *newmap;
01772 DdNode *one, *zero;
01773
01774 #ifdef DD_DEBUG
01775 assert(n > 0 && level < unique->size);
01776 #endif
01777
01778 oldsize = unique->size;
01779
01780 if (oldsize + n <= unique->maxSize) {
01781
01782 for (i = oldsize - 1; i >= level; i--) {
01783 unique->subtables[i+n].slots = unique->subtables[i].slots;
01784 unique->subtables[i+n].shift = unique->subtables[i].shift;
01785 unique->subtables[i+n].keys = unique->subtables[i].keys;
01786 unique->subtables[i+n].maxKeys = unique->subtables[i].maxKeys;
01787 unique->subtables[i+n].dead = unique->subtables[i].dead;
01788 unique->subtables[i+n].nodelist = unique->subtables[i].nodelist;
01789 unique->subtables[i+n].bindVar = unique->subtables[i].bindVar;
01790 unique->subtables[i+n].varType = unique->subtables[i].varType;
01791 unique->subtables[i+n].pairIndex = unique->subtables[i].pairIndex;
01792 unique->subtables[i+n].varHandled = unique->subtables[i].varHandled;
01793 unique->subtables[i+n].varToBeGrouped =
01794 unique->subtables[i].varToBeGrouped;
01795
01796 index = unique->invperm[i];
01797 unique->invperm[i+n] = index;
01798 unique->perm[index] += n;
01799 }
01800
01801 for (i = 0; i < n; i++) {
01802 unique->subtables[level+i].slots = numSlots;
01803 unique->subtables[level+i].shift = sizeof(int) * 8 -
01804 cuddComputeFloorLog2(numSlots);
01805 unique->subtables[level+i].keys = 0;
01806 unique->subtables[level+i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
01807 unique->subtables[level+i].dead = 0;
01808 unique->subtables[level+i].bindVar = 0;
01809 unique->subtables[level+i].varType = CUDD_VAR_PRIMARY_INPUT;
01810 unique->subtables[level+i].pairIndex = 0;
01811 unique->subtables[level+i].varHandled = 0;
01812 unique->subtables[level+i].varToBeGrouped = CUDD_LAZY_NONE;
01813
01814 unique->perm[oldsize+i] = level + i;
01815 unique->invperm[level+i] = oldsize + i;
01816 newnodelist = unique->subtables[level+i].nodelist =
01817 ALLOC(DdNodePtr, numSlots);
01818 if (newnodelist == NULL) {
01819 unique->errorCode = CUDD_MEMORY_OUT;
01820 return(0);
01821 }
01822 for (j = 0; j < numSlots; j++) {
01823 newnodelist[j] = sentinel;
01824 }
01825 }
01826 if (unique->map != NULL) {
01827 for (i = 0; i < n; i++) {
01828 unique->map[oldsize+i] = oldsize + i;
01829 }
01830 }
01831 } else {
01832
01833
01834
01835
01836 newsize = oldsize + n + DD_DEFAULT_RESIZE;
01837 #ifdef DD_VERBOSE
01838 (void) fprintf(unique->err,
01839 "Increasing the table size from %d to %d\n",
01840 unique->maxSize, newsize);
01841 #endif
01842
01843 newsubtables = ALLOC(DdSubtable,newsize);
01844 if (newsubtables == NULL) {
01845 unique->errorCode = CUDD_MEMORY_OUT;
01846 return(0);
01847 }
01848 newvars = ALLOC(DdNodePtr,newsize);
01849 if (newvars == NULL) {
01850 unique->errorCode = CUDD_MEMORY_OUT;
01851 FREE(newsubtables);
01852 return(0);
01853 }
01854 newperm = ALLOC(int,newsize);
01855 if (newperm == NULL) {
01856 unique->errorCode = CUDD_MEMORY_OUT;
01857 FREE(newsubtables);
01858 FREE(newvars);
01859 return(0);
01860 }
01861 newinvperm = ALLOC(int,newsize);
01862 if (newinvperm == NULL) {
01863 unique->errorCode = CUDD_MEMORY_OUT;
01864 FREE(newsubtables);
01865 FREE(newvars);
01866 FREE(newperm);
01867 return(0);
01868 }
01869 if (unique->map != NULL) {
01870 newmap = ALLOC(int,newsize);
01871 if (newmap == NULL) {
01872 unique->errorCode = CUDD_MEMORY_OUT;
01873 FREE(newsubtables);
01874 FREE(newvars);
01875 FREE(newperm);
01876 FREE(newinvperm);
01877 return(0);
01878 }
01879 unique->memused += (newsize - unique->maxSize) * sizeof(int);
01880 }
01881 unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
01882 sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
01883
01884 for (i = 0; i < level; i++) {
01885 newsubtables[i].slots = unique->subtables[i].slots;
01886 newsubtables[i].shift = unique->subtables[i].shift;
01887 newsubtables[i].keys = unique->subtables[i].keys;
01888 newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
01889 newsubtables[i].dead = unique->subtables[i].dead;
01890 newsubtables[i].nodelist = unique->subtables[i].nodelist;
01891 newsubtables[i].bindVar = unique->subtables[i].bindVar;
01892 newsubtables[i].varType = unique->subtables[i].varType;
01893 newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
01894 newsubtables[i].varHandled = unique->subtables[i].varHandled;
01895 newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
01896
01897 newvars[i] = unique->vars[i];
01898 newperm[i] = unique->perm[i];
01899 newinvperm[i] = unique->invperm[i];
01900 }
01901
01902 for (i = level; i < oldsize; i++) {
01903 newperm[i] = unique->perm[i];
01904 }
01905
01906 for (i = level; i < level + n; i++) {
01907 newsubtables[i].slots = numSlots;
01908 newsubtables[i].shift = sizeof(int) * 8 -
01909 cuddComputeFloorLog2(numSlots);
01910 newsubtables[i].keys = 0;
01911 newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
01912 newsubtables[i].dead = 0;
01913 newsubtables[i].bindVar = 0;
01914 newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
01915 newsubtables[i].pairIndex = 0;
01916 newsubtables[i].varHandled = 0;
01917 newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
01918
01919 newperm[oldsize + i - level] = i;
01920 newinvperm[i] = oldsize + i - level;
01921 newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
01922 if (newnodelist == NULL) {
01923
01924 unique->errorCode = CUDD_MEMORY_OUT;
01925 return(0);
01926 }
01927 for (j = 0; j < numSlots; j++) {
01928 newnodelist[j] = sentinel;
01929 }
01930 }
01931
01932 for (i = level; i < oldsize; i++) {
01933 newsubtables[i+n].slots = unique->subtables[i].slots;
01934 newsubtables[i+n].shift = unique->subtables[i].shift;
01935 newsubtables[i+n].keys = unique->subtables[i].keys;
01936 newsubtables[i+n].maxKeys = unique->subtables[i].maxKeys;
01937 newsubtables[i+n].dead = unique->subtables[i].dead;
01938 newsubtables[i+n].nodelist = unique->subtables[i].nodelist;
01939 newsubtables[i+n].bindVar = unique->subtables[i].bindVar;
01940 newsubtables[i+n].varType = unique->subtables[i].varType;
01941 newsubtables[i+n].pairIndex = unique->subtables[i].pairIndex;
01942 newsubtables[i+n].varHandled = unique->subtables[i].varHandled;
01943 newsubtables[i+n].varToBeGrouped =
01944 unique->subtables[i].varToBeGrouped;
01945
01946 newvars[i] = unique->vars[i];
01947 index = unique->invperm[i];
01948 newinvperm[i+n] = index;
01949 newperm[index] += n;
01950 }
01951
01952 if (unique->map != NULL) {
01953 for (i = 0; i < oldsize; i++) {
01954 newmap[i] = unique->map[i];
01955 }
01956 for (i = oldsize; i < oldsize + n; i++) {
01957 newmap[i] = i;
01958 }
01959 FREE(unique->map);
01960 unique->map = newmap;
01961 }
01962
01963 FREE(unique->subtables);
01964 unique->subtables = newsubtables;
01965 unique->maxSize = newsize;
01966 FREE(unique->vars);
01967 unique->vars = newvars;
01968 FREE(unique->perm);
01969 unique->perm = newperm;
01970 FREE(unique->invperm);
01971 unique->invperm = newinvperm;
01972
01973 if (newsize > unique->maxSizeZ) {
01974 FREE(unique->stack);
01975 unique->stack = ALLOC(DdNodePtr,newsize + 1);
01976 if (unique->stack == NULL) {
01977 unique->errorCode = CUDD_MEMORY_OUT;
01978 return(0);
01979 }
01980 unique->stack[0] = NULL;
01981 unique->memused +=
01982 (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
01983 * sizeof(DdNode *);
01984 }
01985 }
01986
01987 unique->slots += n * numSlots;
01988 ddFixLimits(unique);
01989 unique->size += n;
01990
01991
01992
01993
01994
01995 one = unique->one;
01996 zero = Cudd_Not(one);
01997
01998 reorderSave = unique->autoDyn;
01999 unique->autoDyn = 0;
02000 for (i = oldsize; i < oldsize + n; i++) {
02001 unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
02002 if (unique->vars[i] == NULL) {
02003 unique->autoDyn = reorderSave;
02004
02005 for (j = oldsize; j < i; j++) {
02006 Cudd_IterDerefBdd(unique,unique->vars[j]);
02007 cuddDeallocNode(unique,unique->vars[j]);
02008 unique->vars[j] = NULL;
02009 }
02010 for (j = level; j < oldsize; j++) {
02011 unique->subtables[j].slots = unique->subtables[j+n].slots;
02012 unique->subtables[j].slots = unique->subtables[j+n].slots;
02013 unique->subtables[j].shift = unique->subtables[j+n].shift;
02014 unique->subtables[j].keys = unique->subtables[j+n].keys;
02015 unique->subtables[j].maxKeys =
02016 unique->subtables[j+n].maxKeys;
02017 unique->subtables[j].dead = unique->subtables[j+n].dead;
02018 FREE(unique->subtables[j].nodelist);
02019 unique->subtables[j].nodelist =
02020 unique->subtables[j+n].nodelist;
02021 unique->subtables[j+n].nodelist = NULL;
02022 unique->subtables[j].bindVar =
02023 unique->subtables[j+n].bindVar;
02024 unique->subtables[j].varType =
02025 unique->subtables[j+n].varType;
02026 unique->subtables[j].pairIndex =
02027 unique->subtables[j+n].pairIndex;
02028 unique->subtables[j].varHandled =
02029 unique->subtables[j+n].varHandled;
02030 unique->subtables[j].varToBeGrouped =
02031 unique->subtables[j+n].varToBeGrouped;
02032 index = unique->invperm[j+n];
02033 unique->invperm[j] = index;
02034 unique->perm[index] -= n;
02035 }
02036 unique->size = oldsize;
02037 unique->slots -= n * numSlots;
02038 ddFixLimits(unique);
02039 (void) Cudd_DebugCheck(unique);
02040 return(0);
02041 }
02042 cuddRef(unique->vars[i]);
02043 }
02044 if (unique->tree != NULL) {
02045 unique->tree->size += n;
02046 unique->tree->index = unique->invperm[0];
02047 ddPatchTree(unique,unique->tree);
02048 }
02049 unique->autoDyn = reorderSave;
02050
02051 return(1);
02052
02053 }
02054
02055
02071 int
02072 cuddDestroySubtables(
02073 DdManager * unique,
02074 int n)
02075 {
02076 DdSubtable *subtables;
02077 DdNodePtr *nodelist;
02078 DdNodePtr *vars;
02079 int firstIndex, lastIndex;
02080 int index, level, newlevel;
02081 int lowestLevel;
02082 int shift;
02083 int found;
02084
02085
02086 if (n <= 0) return(0);
02087 if (n > unique->size) n = unique->size;
02088
02089 subtables = unique->subtables;
02090 vars = unique->vars;
02091 firstIndex = unique->size - n;
02092 lastIndex = unique->size;
02093
02094
02095
02096
02097
02098
02099
02100 lowestLevel = unique->size;
02101 for (index = firstIndex; index < lastIndex; index++) {
02102 level = unique->perm[index];
02103 if (level < lowestLevel) lowestLevel = level;
02104 nodelist = subtables[level].nodelist;
02105 if (subtables[level].keys - subtables[level].dead != 1) return(0);
02106
02107
02108
02109
02110
02111
02112 if (vars[index]->ref != 1) {
02113 if (vars[index]->ref != DD_MAXREF) return(0);
02114 found = cuddFindParent(unique,vars[index]);
02115 if (found) {
02116 return(0);
02117 } else {
02118 vars[index]->ref = 1;
02119 }
02120 }
02121 Cudd_RecursiveDeref(unique,vars[index]);
02122 }
02123
02124
02125
02126
02127 (void) cuddGarbageCollect(unique,1);
02128
02129
02130 for (index = firstIndex; index < lastIndex; index++) {
02131 level = unique->perm[index];
02132 nodelist = subtables[level].nodelist;
02133 #ifdef DD_DEBUG
02134 assert(subtables[level].keys == 0);
02135 #endif
02136 FREE(nodelist);
02137 unique->memused -= sizeof(DdNodePtr) * subtables[level].slots;
02138 unique->slots -= subtables[level].slots;
02139 unique->dead -= subtables[level].dead;
02140 }
02141
02142
02143
02144
02145
02146
02147
02148
02149 shift = 1;
02150 for (level = lowestLevel + 1; level < unique->size; level++) {
02151 if (subtables[level].keys == 0) {
02152 shift++;
02153 continue;
02154 }
02155 newlevel = level - shift;
02156 subtables[newlevel].slots = subtables[level].slots;
02157 subtables[newlevel].shift = subtables[level].shift;
02158 subtables[newlevel].keys = subtables[level].keys;
02159 subtables[newlevel].maxKeys = subtables[level].maxKeys;
02160 subtables[newlevel].dead = subtables[level].dead;
02161 subtables[newlevel].nodelist = subtables[level].nodelist;
02162 index = unique->invperm[level];
02163 unique->perm[index] = newlevel;
02164 unique->invperm[newlevel] = index;
02165 subtables[newlevel].bindVar = subtables[level].bindVar;
02166 subtables[newlevel].varType = subtables[level].varType;
02167 subtables[newlevel].pairIndex = subtables[level].pairIndex;
02168 subtables[newlevel].varHandled = subtables[level].varHandled;
02169 subtables[newlevel].varToBeGrouped = subtables[level].varToBeGrouped;
02170 }
02171
02172
02173
02174 if (unique->map != NULL) {
02175 cuddCacheFlush(unique);
02176 FREE(unique->map);
02177 unique->map = NULL;
02178 }
02179
02180 unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
02181 unique->size -= n;
02182
02183 return(1);
02184
02185 }
02186
02187
02204 int
02205 cuddResizeTableZdd(
02206 DdManager * unique,
02207 int index)
02208 {
02209 DdSubtable *newsubtables;
02210 DdNodePtr *newnodelist;
02211 int oldsize,newsize;
02212 int i,j,reorderSave;
02213 unsigned int numSlots = unique->initSlots;
02214 int *newperm, *newinvperm;
02215 DdNode *one, *zero;
02216
02217 oldsize = unique->sizeZ;
02218
02219 if (index < unique->maxSizeZ) {
02220 for (i = oldsize; i <= index; i++) {
02221 unique->subtableZ[i].slots = numSlots;
02222 unique->subtableZ[i].shift = sizeof(int) * 8 -
02223 cuddComputeFloorLog2(numSlots);
02224 unique->subtableZ[i].keys = 0;
02225 unique->subtableZ[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
02226 unique->subtableZ[i].dead = 0;
02227 unique->permZ[i] = i;
02228 unique->invpermZ[i] = i;
02229 newnodelist = unique->subtableZ[i].nodelist =
02230 ALLOC(DdNodePtr, numSlots);
02231 if (newnodelist == NULL) {
02232 unique->errorCode = CUDD_MEMORY_OUT;
02233 return(0);
02234 }
02235 for (j = 0; j < numSlots; j++) {
02236 newnodelist[j] = NULL;
02237 }
02238 }
02239 } else {
02240
02241
02242
02243
02244 newsize = index + DD_DEFAULT_RESIZE;
02245 #ifdef DD_VERBOSE
02246 (void) fprintf(unique->err,
02247 "Increasing the ZDD table size from %d to %d\n",
02248 unique->maxSizeZ, newsize);
02249 #endif
02250 newsubtables = ALLOC(DdSubtable,newsize);
02251 if (newsubtables == NULL) {
02252 unique->errorCode = CUDD_MEMORY_OUT;
02253 return(0);
02254 }
02255 newperm = ALLOC(int,newsize);
02256 if (newperm == NULL) {
02257 unique->errorCode = CUDD_MEMORY_OUT;
02258 return(0);
02259 }
02260 newinvperm = ALLOC(int,newsize);
02261 if (newinvperm == NULL) {
02262 unique->errorCode = CUDD_MEMORY_OUT;
02263 return(0);
02264 }
02265 unique->memused += (newsize - unique->maxSizeZ) * ((numSlots+1) *
02266 sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
02267 if (newsize > unique->maxSize) {
02268 FREE(unique->stack);
02269 unique->stack = ALLOC(DdNodePtr,newsize + 1);
02270 if (unique->stack == NULL) {
02271 unique->errorCode = CUDD_MEMORY_OUT;
02272 return(0);
02273 }
02274 unique->stack[0] = NULL;
02275 unique->memused +=
02276 (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
02277 * sizeof(DdNode *);
02278 }
02279 for (i = 0; i < oldsize; i++) {
02280 newsubtables[i].slots = unique->subtableZ[i].slots;
02281 newsubtables[i].shift = unique->subtableZ[i].shift;
02282 newsubtables[i].keys = unique->subtableZ[i].keys;
02283 newsubtables[i].maxKeys = unique->subtableZ[i].maxKeys;
02284 newsubtables[i].dead = unique->subtableZ[i].dead;
02285 newsubtables[i].nodelist = unique->subtableZ[i].nodelist;
02286 newperm[i] = unique->permZ[i];
02287 newinvperm[i] = unique->invpermZ[i];
02288 }
02289 for (i = oldsize; i <= index; i++) {
02290 newsubtables[i].slots = numSlots;
02291 newsubtables[i].shift = sizeof(int) * 8 -
02292 cuddComputeFloorLog2(numSlots);
02293 newsubtables[i].keys = 0;
02294 newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
02295 newsubtables[i].dead = 0;
02296 newperm[i] = i;
02297 newinvperm[i] = i;
02298 newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
02299 if (newnodelist == NULL) {
02300 unique->errorCode = CUDD_MEMORY_OUT;
02301 return(0);
02302 }
02303 for (j = 0; j < numSlots; j++) {
02304 newnodelist[j] = NULL;
02305 }
02306 }
02307 FREE(unique->subtableZ);
02308 unique->subtableZ = newsubtables;
02309 unique->maxSizeZ = newsize;
02310 FREE(unique->permZ);
02311 unique->permZ = newperm;
02312 FREE(unique->invpermZ);
02313 unique->invpermZ = newinvperm;
02314 }
02315 unique->slots += (index + 1 - unique->sizeZ) * numSlots;
02316 ddFixLimits(unique);
02317 unique->sizeZ = index + 1;
02318
02319
02320
02321
02322
02323 one = unique->one;
02324 zero = unique->zero;
02325
02326 reorderSave = unique->autoDynZ;
02327 unique->autoDynZ = 0;
02328 cuddZddFreeUniv(unique);
02329 if (!cuddZddInitUniv(unique)) {
02330 unique->autoDynZ = reorderSave;
02331 return(0);
02332 }
02333 unique->autoDynZ = reorderSave;
02334
02335 return(1);
02336
02337 }
02338
02339
02351 void
02352 cuddSlowTableGrowth(
02353 DdManager *unique)
02354 {
02355 int i;
02356
02357 unique->maxCacheHard = unique->cacheSlots - 1;
02358 unique->cacheSlack = -(unique->cacheSlots + 1);
02359 for (i = 0; i < unique->size; i++) {
02360 unique->subtables[i].maxKeys <<= 2;
02361 }
02362 unique->gcFrac = DD_GC_FRAC_MIN;
02363 unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
02364 cuddShrinkDeathRow(unique);
02365 (void) fprintf(unique->err,"Slowing down table growth: ");
02366 (void) fprintf(unique->err,"GC fraction = %.2f\t", unique->gcFrac);
02367 (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
02368
02369 }
02370
02371
02372
02373
02374
02375
02376
02388 static void
02389 ddRehashZdd(
02390 DdManager * unique,
02391 int i)
02392 {
02393 unsigned int slots, oldslots;
02394 int shift, oldshift;
02395 int j, pos;
02396 DdNodePtr *nodelist, *oldnodelist;
02397 DdNode *node, *next;
02398 extern void (*MMoutOfMemory)(long);
02399 void (*saveHandler)(long);
02400
02401 if (unique->slots > unique->looseUpTo) {
02402 unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
02403 #ifdef DD_VERBOSE
02404 if (unique->gcFrac == DD_GC_FRAC_HI) {
02405 (void) fprintf(unique->err,"GC fraction = %.2f\t",
02406 DD_GC_FRAC_LO);
02407 (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
02408 }
02409 #endif
02410 unique->gcFrac = DD_GC_FRAC_LO;
02411 }
02412
02413 assert(i != CUDD_MAXINDEX);
02414 oldslots = unique->subtableZ[i].slots;
02415 oldshift = unique->subtableZ[i].shift;
02416 oldnodelist = unique->subtableZ[i].nodelist;
02417
02418
02419
02420
02421 slots = oldslots;
02422 shift = oldshift;
02423 do {
02424 slots <<= 1;
02425 shift--;
02426 } while (slots * DD_MAX_SUBTABLE_DENSITY < unique->subtableZ[i].keys);
02427
02428 saveHandler = MMoutOfMemory;
02429 MMoutOfMemory = Cudd_OutOfMem;
02430 nodelist = ALLOC(DdNodePtr, slots);
02431 MMoutOfMemory = saveHandler;
02432 if (nodelist == NULL) {
02433 int j;
02434 (void) fprintf(unique->err,
02435 "Unable to resize ZDD subtable %d for lack of memory.\n",
02436 i);
02437 (void) cuddGarbageCollectZdd(unique,1);
02438 for (j = 0; j < unique->sizeZ; j++) {
02439 unique->subtableZ[j].maxKeys <<= 1;
02440 }
02441 return;
02442 }
02443 unique->subtableZ[i].nodelist = nodelist;
02444 unique->subtableZ[i].slots = slots;
02445 unique->subtableZ[i].shift = shift;
02446 unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
02447 for (j = 0; (unsigned) j < slots; j++) {
02448 nodelist[j] = NULL;
02449 }
02450 for (j = 0; (unsigned) j < oldslots; j++) {
02451 node = oldnodelist[j];
02452 while (node != NULL) {
02453 next = node->next;
02454 pos = ddHash(cuddT(node), cuddE(node), shift);
02455 node->next = nodelist[pos];
02456 nodelist[pos] = node;
02457 node = next;
02458 }
02459 }
02460 FREE(oldnodelist);
02461
02462 #ifdef DD_VERBOSE
02463 (void) fprintf(unique->err,
02464 "rehashing layer %d: keys %d dead %d new size %d\n",
02465 i, unique->subtableZ[i].keys,
02466 unique->subtableZ[i].dead, slots);
02467 #endif
02468
02469
02470 unique->memused += (slots - oldslots) * sizeof(DdNode *);
02471 unique->slots += (slots - oldslots);
02472 ddFixLimits(unique);
02473
02474 }
02475
02476
02490 static int
02491 ddResizeTable(
02492 DdManager * unique,
02493 int index)
02494 {
02495 DdSubtable *newsubtables;
02496 DdNodePtr *newnodelist;
02497 DdNodePtr *newvars;
02498 DdNode *sentinel = &(unique->sentinel);
02499 int oldsize,newsize;
02500 int i,j,reorderSave;
02501 int numSlots = unique->initSlots;
02502 int *newperm, *newinvperm, *newmap;
02503 DdNode *one, *zero;
02504
02505 oldsize = unique->size;
02506
02507 if (index < unique->maxSize) {
02508 for (i = oldsize; i <= index; i++) {
02509 unique->subtables[i].slots = numSlots;
02510 unique->subtables[i].shift = sizeof(int) * 8 -
02511 cuddComputeFloorLog2(numSlots);
02512 unique->subtables[i].keys = 0;
02513 unique->subtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
02514 unique->subtables[i].dead = 0;
02515 unique->subtables[i].bindVar = 0;
02516 unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
02517 unique->subtables[i].pairIndex = 0;
02518 unique->subtables[i].varHandled = 0;
02519 unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
02520
02521 unique->perm[i] = i;
02522 unique->invperm[i] = i;
02523 newnodelist = unique->subtables[i].nodelist =
02524 ALLOC(DdNodePtr, numSlots);
02525 if (newnodelist == NULL) {
02526 for (j = oldsize; j < i; j++) {
02527 FREE(unique->subtables[j].nodelist);
02528 }
02529 unique->errorCode = CUDD_MEMORY_OUT;
02530 return(0);
02531 }
02532 for (j = 0; j < numSlots; j++) {
02533 newnodelist[j] = sentinel;
02534 }
02535 }
02536 if (unique->map != NULL) {
02537 for (i = oldsize; i <= index; i++) {
02538 unique->map[i] = i;
02539 }
02540 }
02541 } else {
02542
02543
02544
02545
02546 newsize = index + DD_DEFAULT_RESIZE;
02547 #ifdef DD_VERBOSE
02548 (void) fprintf(unique->err,
02549 "Increasing the table size from %d to %d\n",
02550 unique->maxSize, newsize);
02551 #endif
02552 newsubtables = ALLOC(DdSubtable,newsize);
02553 if (newsubtables == NULL) {
02554 unique->errorCode = CUDD_MEMORY_OUT;
02555 return(0);
02556 }
02557 newvars = ALLOC(DdNodePtr,newsize);
02558 if (newvars == NULL) {
02559 FREE(newsubtables);
02560 unique->errorCode = CUDD_MEMORY_OUT;
02561 return(0);
02562 }
02563 newperm = ALLOC(int,newsize);
02564 if (newperm == NULL) {
02565 FREE(newsubtables);
02566 FREE(newvars);
02567 unique->errorCode = CUDD_MEMORY_OUT;
02568 return(0);
02569 }
02570 newinvperm = ALLOC(int,newsize);
02571 if (newinvperm == NULL) {
02572 FREE(newsubtables);
02573 FREE(newvars);
02574 FREE(newperm);
02575 unique->errorCode = CUDD_MEMORY_OUT;
02576 return(0);
02577 }
02578 if (unique->map != NULL) {
02579 newmap = ALLOC(int,newsize);
02580 if (newmap == NULL) {
02581 FREE(newsubtables);
02582 FREE(newvars);
02583 FREE(newperm);
02584 FREE(newinvperm);
02585 unique->errorCode = CUDD_MEMORY_OUT;
02586 return(0);
02587 }
02588 unique->memused += (newsize - unique->maxSize) * sizeof(int);
02589 }
02590 unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
02591 sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
02592 if (newsize > unique->maxSizeZ) {
02593 FREE(unique->stack);
02594 unique->stack = ALLOC(DdNodePtr,newsize + 1);
02595 if (unique->stack == NULL) {
02596 FREE(newsubtables);
02597 FREE(newvars);
02598 FREE(newperm);
02599 FREE(newinvperm);
02600 if (unique->map != NULL) {
02601 FREE(newmap);
02602 }
02603 unique->errorCode = CUDD_MEMORY_OUT;
02604 return(0);
02605 }
02606 unique->stack[0] = NULL;
02607 unique->memused +=
02608 (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
02609 * sizeof(DdNode *);
02610 }
02611 for (i = 0; i < oldsize; i++) {
02612 newsubtables[i].slots = unique->subtables[i].slots;
02613 newsubtables[i].shift = unique->subtables[i].shift;
02614 newsubtables[i].keys = unique->subtables[i].keys;
02615 newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
02616 newsubtables[i].dead = unique->subtables[i].dead;
02617 newsubtables[i].nodelist = unique->subtables[i].nodelist;
02618 newsubtables[i].bindVar = unique->subtables[i].bindVar;
02619 newsubtables[i].varType = unique->subtables[i].varType;
02620 newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
02621 newsubtables[i].varHandled = unique->subtables[i].varHandled;
02622 newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
02623
02624 newvars[i] = unique->vars[i];
02625 newperm[i] = unique->perm[i];
02626 newinvperm[i] = unique->invperm[i];
02627 }
02628 for (i = oldsize; i <= index; i++) {
02629 newsubtables[i].slots = numSlots;
02630 newsubtables[i].shift = sizeof(int) * 8 -
02631 cuddComputeFloorLog2(numSlots);
02632 newsubtables[i].keys = 0;
02633 newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
02634 newsubtables[i].dead = 0;
02635 newsubtables[i].bindVar = 0;
02636 newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
02637 newsubtables[i].pairIndex = 0;
02638 newsubtables[i].varHandled = 0;
02639 newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
02640
02641 newperm[i] = i;
02642 newinvperm[i] = i;
02643 newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
02644 if (newnodelist == NULL) {
02645 unique->errorCode = CUDD_MEMORY_OUT;
02646 return(0);
02647 }
02648 for (j = 0; j < numSlots; j++) {
02649 newnodelist[j] = sentinel;
02650 }
02651 }
02652 if (unique->map != NULL) {
02653 for (i = 0; i < oldsize; i++) {
02654 newmap[i] = unique->map[i];
02655 }
02656 for (i = oldsize; i <= index; i++) {
02657 newmap[i] = i;
02658 }
02659 FREE(unique->map);
02660 unique->map = newmap;
02661 }
02662 FREE(unique->subtables);
02663 unique->subtables = newsubtables;
02664 unique->maxSize = newsize;
02665 FREE(unique->vars);
02666 unique->vars = newvars;
02667 FREE(unique->perm);
02668 unique->perm = newperm;
02669 FREE(unique->invperm);
02670 unique->invperm = newinvperm;
02671 }
02672
02673
02674
02675
02676
02677 one = unique->one;
02678 zero = Cudd_Not(one);
02679
02680 unique->size = index + 1;
02681 unique->slots += (index + 1 - oldsize) * numSlots;
02682 ddFixLimits(unique);
02683
02684 reorderSave = unique->autoDyn;
02685 unique->autoDyn = 0;
02686 for (i = oldsize; i <= index; i++) {
02687 unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
02688 if (unique->vars[i] == NULL) {
02689 unique->autoDyn = reorderSave;
02690 for (j = oldsize; j < i; j++) {
02691 Cudd_IterDerefBdd(unique,unique->vars[j]);
02692 cuddDeallocNode(unique,unique->vars[j]);
02693 unique->vars[j] = NULL;
02694 }
02695 for (j = oldsize; j <= index; j++) {
02696 FREE(unique->subtables[j].nodelist);
02697 unique->subtables[j].nodelist = NULL;
02698 }
02699 unique->size = oldsize;
02700 unique->slots -= (index + 1 - oldsize) * numSlots;
02701 ddFixLimits(unique);
02702 return(0);
02703 }
02704 cuddRef(unique->vars[i]);
02705 }
02706 unique->autoDyn = reorderSave;
02707
02708 return(1);
02709
02710 }
02711
02712
02725 static int
02726 cuddFindParent(
02727 DdManager * table,
02728 DdNode * node)
02729 {
02730 int i,j;
02731 int slots;
02732 DdNodePtr *nodelist;
02733 DdNode *f;
02734
02735 for (i = cuddI(table,node->index) - 1; i >= 0; i--) {
02736 nodelist = table->subtables[i].nodelist;
02737 slots = table->subtables[i].slots;
02738
02739 for (j = 0; j < slots; j++) {
02740 f = nodelist[j];
02741 while (cuddT(f) > node) {
02742 f = f->next;
02743 }
02744 while (cuddT(f) == node && Cudd_Regular(cuddE(f)) > node) {
02745 f = f->next;
02746 }
02747 if (cuddT(f) == node && Cudd_Regular(cuddE(f)) == node) {
02748 return(1);
02749 }
02750 }
02751 }
02752
02753 return(0);
02754
02755 }
02756
02757
02771 DD_INLINE
02772 static void
02773 ddFixLimits(
02774 DdManager *unique)
02775 {
02776 unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
02777 unique->cacheSlack = (int) ddMin(unique->maxCacheHard,
02778 DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots) -
02779 2 * (int) unique->cacheSlots;
02780 if (unique->cacheSlots < unique->slots/2 && unique->cacheSlack >= 0)
02781 cuddCacheResize(unique);
02782 return;
02783
02784 }
02785
02786
02787 #ifndef DD_UNSORTED_FREE_LIST
02788
02800 static void
02801 cuddOrderedInsert(
02802 DdNodePtr * root,
02803 DdNodePtr node)
02804 {
02805 DdNode *scan;
02806 DdNodePtr *scanP;
02807 DdNodePtr *stack[DD_STACK_SIZE];
02808 int stackN = 0;
02809
02810 scanP = root;
02811 while ((scan = *scanP) != NULL) {
02812 stack[stackN++] = scanP;
02813 if (DD_INSERT_COMPARE(node, scan) == 0) {
02814 DD_NEXT(node) = DD_NEXT(scan);
02815 DD_NEXT(scan) = node;
02816 return;
02817 }
02818 scanP = (node < scan) ? &DD_LEFT(scan) : &DD_RIGHT(scan);
02819 }
02820 DD_RIGHT(node) = DD_LEFT(node) = DD_NEXT(node) = NULL;
02821 DD_COLOR(node) = DD_RED;
02822 *scanP = node;
02823 stack[stackN] = &node;
02824 cuddDoRebalance(stack,stackN);
02825
02826 }
02827
02828
02849 static DdNode *
02850 cuddOrderedThread(
02851 DdNode * root,
02852 DdNode * list)
02853 {
02854 DdNode *current, *next, *prev, *end;
02855
02856 current = root;
02857
02858
02859
02860
02861 *((DdNodePtr *) current) = NULL;
02862
02863 while (current != NULL) {
02864 if (DD_RIGHT(current) != NULL) {
02865
02866
02867
02868
02869
02870
02871
02872 next = DD_RIGHT(current);
02873 DD_RIGHT(current) = NULL;
02874 *((DdNodePtr *)next) = current;
02875 current = next;
02876 } else {
02877
02878
02879
02880
02881
02882
02883 prev = *((DdNodePtr *) current);
02884
02885 for (end = current; DD_NEXT(end) != NULL; end = DD_NEXT(end));
02886 DD_NEXT(end) = list;
02887 list = current;
02888
02889
02890
02891 if (DD_LEFT(current) != NULL) {
02892 next = DD_LEFT(current);
02893 *((DdNodePtr *) next) = prev;
02894 current = next;
02895 } else {
02896 current = prev;
02897 }
02898 }
02899 }
02900
02901 return(list);
02902
02903 }
02904
02905
02917 DD_INLINE
02918 static void
02919 cuddRotateLeft(
02920 DdNodePtr * nodeP)
02921 {
02922 DdNode *newRoot;
02923 DdNode *oldRoot = *nodeP;
02924
02925 *nodeP = newRoot = DD_RIGHT(oldRoot);
02926 DD_RIGHT(oldRoot) = DD_LEFT(newRoot);
02927 DD_LEFT(newRoot) = oldRoot;
02928
02929 }
02930
02931
02943 DD_INLINE
02944 static void
02945 cuddRotateRight(
02946 DdNodePtr * nodeP)
02947 {
02948 DdNode *newRoot;
02949 DdNode *oldRoot = *nodeP;
02950
02951 *nodeP = newRoot = DD_LEFT(oldRoot);
02952 DD_LEFT(oldRoot) = DD_RIGHT(newRoot);
02953 DD_RIGHT(newRoot) = oldRoot;
02954
02955 }
02956
02957
02969 static void
02970 cuddDoRebalance(
02971 DdNodePtr ** stack,
02972 int stackN)
02973 {
02974 DdNodePtr *xP, *parentP, *grandpaP;
02975 DdNode *x, *y, *parent, *grandpa;
02976
02977 xP = stack[stackN];
02978 x = *xP;
02979
02980 while (--stackN >= 0) {
02981 parentP = stack[stackN];
02982 parent = *parentP;
02983 if (DD_IS_BLACK(parent)) break;
02984
02985 grandpaP = stack[stackN-1];
02986 grandpa = *grandpaP;
02987 if (parent == DD_LEFT(grandpa)) {
02988 y = DD_RIGHT(grandpa);
02989 if (y != NULL && DD_IS_RED(y)) {
02990 DD_COLOR(parent) = DD_BLACK;
02991 DD_COLOR(y) = DD_BLACK;
02992 DD_COLOR(grandpa) = DD_RED;
02993 x = grandpa;
02994 stackN--;
02995 } else {
02996 if (x == DD_RIGHT(parent)) {
02997 cuddRotateLeft(parentP);
02998 DD_COLOR(x) = DD_BLACK;
02999 } else {
03000 DD_COLOR(parent) = DD_BLACK;
03001 }
03002 DD_COLOR(grandpa) = DD_RED;
03003 cuddRotateRight(grandpaP);
03004 break;
03005 }
03006 } else {
03007 y = DD_LEFT(grandpa);
03008 if (y != NULL && DD_IS_RED(y)) {
03009 DD_COLOR(parent) = DD_BLACK;
03010 DD_COLOR(y) = DD_BLACK;
03011 DD_COLOR(grandpa) = DD_RED;
03012 x = grandpa;
03013 stackN--;
03014 } else {
03015 if (x == DD_LEFT(parent)) {
03016 cuddRotateRight(parentP);
03017 DD_COLOR(x) = DD_BLACK;
03018 } else {
03019 DD_COLOR(parent) = DD_BLACK;
03020 }
03021 DD_COLOR(grandpa) = DD_RED;
03022 cuddRotateLeft(grandpaP);
03023 }
03024 }
03025 }
03026 DD_COLOR(*(stack[0])) = DD_BLACK;
03027
03028 }
03029 #endif
03030
03031
03045 static void
03046 ddPatchTree(
03047 DdManager *dd,
03048 MtrNode *treenode)
03049 {
03050 MtrNode *auxnode = treenode;
03051
03052 while (auxnode != NULL) {
03053 auxnode->low = dd->perm[auxnode->index];
03054 if (auxnode->child != NULL) {
03055 ddPatchTree(dd, auxnode->child);
03056 }
03057 auxnode = auxnode->younger;
03058 }
03059
03060 return;
03061
03062 }
03063
03064
03065 #ifdef DD_DEBUG
03066
03077 static int
03078 cuddCheckCollisionOrdering(
03079 DdManager *unique,
03080 int i,
03081 int j)
03082 {
03083 int slots;
03084 DdNode *node, *next;
03085 DdNodePtr *nodelist;
03086 DdNode *sentinel = &(unique->sentinel);
03087
03088 nodelist = unique->subtables[i].nodelist;
03089 slots = unique->subtables[i].slots;
03090 node = nodelist[j];
03091 if (node == sentinel) return(1);
03092 next = node->next;
03093 while (next != sentinel) {
03094 if (cuddT(node) < cuddT(next) ||
03095 (cuddT(node) == cuddT(next) && cuddE(node) < cuddE(next))) {
03096 (void) fprintf(unique->err,
03097 "Unordered list: index %u, position %d\n", i, j);
03098 return(0);
03099 }
03100 node = next;
03101 next = node->next;
03102 }
03103 return(1);
03104
03105 }
03106 #endif
03107
03108
03109
03110
03122 static void
03123 ddReportRefMess(
03124 DdManager *unique ,
03125 int i ,
03126 char *caller )
03127 {
03128 if (i == CUDD_CONST_INDEX) {
03129 (void) fprintf(unique->err,
03130 "%s: problem in constants\n", caller);
03131 } else if (i != -1) {
03132 (void) fprintf(unique->err,
03133 "%s: problem in table %d\n", caller, i);
03134 }
03135 (void) fprintf(unique->err, " dead count != deleted\n");
03136 (void) fprintf(unique->err, " This problem is often due to a missing \
03137 call to Cudd_Ref\n or to an extra call to Cudd_RecursiveDeref.\n \
03138 See the CUDD Programmer's Guide for additional details.");
03139 abort();
03140
03141 }