00001
00083 #include "util.h"
00084 #include "cuddInt.h"
00085
00086
00087
00088
00089
00090 #ifndef DD_UNSORTED_FREE_LIST
00091 #ifdef DD_RED_BLACK_FREE_LIST
00092
00093 #define DD_STACK_SIZE 128
00094 #define DD_RED 0
00095 #define DD_BLACK 1
00096 #define DD_PAGE_SIZE 8192
00097 #define DD_PAGE_MASK ~(DD_PAGE_SIZE - 1)
00098 #endif
00099 #endif
00100
00101
00102
00103
00104
00105
00106 typedef union hack {
00107 CUDD_VALUE_TYPE value;
00108 unsigned int bits[2];
00109 } hack;
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 #ifndef lint
00120 static char rcsid[] DD_UNUSED = "$Id: cuddTable.c,v 1.122 2009/02/19 16:24:28 fabio Exp $";
00121 #endif
00122
00123
00124
00125
00126
00127
00128 #ifndef DD_UNSORTED_FREE_LIST
00129 #ifdef DD_RED_BLACK_FREE_LIST
00130
00131 #define DD_INSERT_COMPARE(x,y) \
00132 (((ptruint) (x) & DD_PAGE_MASK) - ((ptruint) (y) & DD_PAGE_MASK))
00133 #define DD_COLOR(p) ((p)->index)
00134 #define DD_IS_BLACK(p) ((p)->index == DD_BLACK)
00135 #define DD_IS_RED(p) ((p)->index == DD_RED)
00136 #define DD_LEFT(p) cuddT(p)
00137 #define DD_RIGHT(p) cuddE(p)
00138 #define DD_NEXT(p) ((p)->next)
00139 #endif
00140 #endif
00141
00142
00145
00146
00147
00148
00149 static void ddRehashZdd (DdManager *unique, int i);
00150 static int ddResizeTable (DdManager *unique, int index);
00151 static int cuddFindParent (DdManager *table, DdNode *node);
00152 DD_INLINE static void ddFixLimits (DdManager *unique);
00153 #ifdef DD_RED_BLACK_FREE_LIST
00154 static void cuddOrderedInsert (DdNodePtr *root, DdNodePtr node);
00155 static DdNode * cuddOrderedThread (DdNode *root, DdNode *list);
00156 static void cuddRotateLeft (DdNodePtr *nodeP);
00157 static void cuddRotateRight (DdNodePtr *nodeP);
00158 static void cuddDoRebalance (DdNodePtr **stack, int stackN);
00159 #endif
00160 static void ddPatchTree (DdManager *dd, MtrNode *treenode);
00161 #ifdef DD_DEBUG
00162 static int cuddCheckCollisionOrdering (DdManager *unique, int i, int j);
00163 #endif
00164 static void ddReportRefMess (DdManager *unique, int i, const char *caller);
00165
00169
00170
00171
00172
00173
00183 unsigned int
00184 Cudd_Prime(
00185 unsigned int p)
00186 {
00187 int i,pn;
00188
00189 p--;
00190 do {
00191 p++;
00192 if (p&1) {
00193 pn = 1;
00194 i = 3;
00195 while ((unsigned) (i * i) <= p) {
00196 if (p % i == 0) {
00197 pn = 0;
00198 break;
00199 }
00200 i += 2;
00201 }
00202 } else {
00203 pn = 0;
00204 }
00205 } while (!pn);
00206 return(p);
00207
00208 }
00209
00210
00211
00212
00213
00214
00215
00230 DdNode *
00231 cuddAllocNode(
00232 DdManager * unique)
00233 {
00234 int i;
00235 DdNodePtr *mem;
00236 DdNode *list, *node;
00237 extern DD_OOMFP MMoutOfMemory;
00238 DD_OOMFP saveHandler;
00239
00240 if (unique->nextFree == NULL) {
00241
00242 if ((unique->keys - unique->dead) + (unique->keysZ - unique->deadZ) >
00243 unique->maxLive) {
00244 unique->errorCode = CUDD_TOO_MANY_NODES;
00245 return(NULL);
00246 }
00247 if (unique->stash == NULL || unique->memused > unique->maxmemhard) {
00248 (void) cuddGarbageCollect(unique,1);
00249 mem = NULL;
00250 }
00251 if (unique->nextFree == NULL) {
00252 if (unique->memused > unique->maxmemhard) {
00253 unique->errorCode = CUDD_MAX_MEM_EXCEEDED;
00254 return(NULL);
00255 }
00256
00257 saveHandler = MMoutOfMemory;
00258 MMoutOfMemory = Cudd_OutOfMem;
00259 mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
00260 MMoutOfMemory = saveHandler;
00261 if (mem == NULL) {
00262
00263
00264
00265 if (cuddGarbageCollect(unique,1) == 0) {
00266
00267
00268
00269 if (unique->stash != NULL) {
00270 FREE(unique->stash);
00271 unique->stash = NULL;
00272
00273 cuddSlowTableGrowth(unique);
00274
00275 mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
00276 }
00277 if (mem == NULL) {
00278
00279
00280
00281
00282 (*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1));
00283 unique->errorCode = CUDD_MEMORY_OUT;
00284 #ifdef DD_VERBOSE
00285 (void) fprintf(unique->err,
00286 "cuddAllocNode: out of memory");
00287 (void) fprintf(unique->err, "Memory in use = %lu\n",
00288 unique->memused);
00289 #endif
00290 return(NULL);
00291 }
00292 }
00293 }
00294 if (mem != NULL) {
00295 ptruint offset;
00296 unique->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode);
00297 mem[0] = (DdNodePtr) unique->memoryList;
00298 unique->memoryList = mem;
00299
00300
00301
00302 offset = (ptruint) mem & (sizeof(DdNode) - 1);
00303 mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
00304 assert(((ptruint) mem & (sizeof(DdNode) - 1)) == 0);
00305 list = (DdNode *) mem;
00306
00307 i = 1;
00308 do {
00309 list[i - 1].ref = 0;
00310 list[i - 1].next = &list[i];
00311 } while (++i < DD_MEM_CHUNK);
00312
00313 list[DD_MEM_CHUNK-1].ref = 0;
00314 list[DD_MEM_CHUNK-1].next = NULL;
00315
00316 unique->nextFree = &list[0];
00317 }
00318 }
00319 }
00320 unique->allocated++;
00321 node = unique->nextFree;
00322 unique->nextFree = node->next;
00323 return(node);
00324
00325 }
00326
00327
00340 DdManager *
00341 cuddInitTable(
00342 unsigned int numVars ,
00343 unsigned int numVarsZ ,
00344 unsigned int numSlots ,
00345 unsigned int looseUpTo )
00346 {
00347 DdManager *unique = ALLOC(DdManager,1);
00348 int i, j;
00349 DdNodePtr *nodelist;
00350 DdNode *sentinel;
00351 unsigned int slots;
00352 int shift;
00353
00354 if (unique == NULL) {
00355 return(NULL);
00356 }
00357 sentinel = &(unique->sentinel);
00358 sentinel->ref = 0;
00359 sentinel->index = 0;
00360 cuddT(sentinel) = NULL;
00361 cuddE(sentinel) = NULL;
00362 sentinel->next = NULL;
00363 unique->epsilon = DD_EPSILON;
00364 unique->maxGrowth = DD_MAX_REORDER_GROWTH;
00365 unique->maxGrowthAlt = 2.0 * DD_MAX_REORDER_GROWTH;
00366 unique->reordCycle = 0;
00367 unique->size = numVars;
00368 unique->sizeZ = numVarsZ;
00369 unique->maxSize = ddMax(DD_DEFAULT_RESIZE, numVars);
00370 unique->maxSizeZ = ddMax(DD_DEFAULT_RESIZE, numVarsZ);
00371
00372
00373 slots = 8;
00374 while (slots < numSlots) {
00375 slots <<= 1;
00376 }
00377 unique->initSlots = slots;
00378 shift = sizeof(int) * 8 - cuddComputeFloorLog2(slots);
00379
00380 unique->slots = (numVars + numVarsZ + 1) * slots;
00381 unique->keys = 0;
00382 unique->maxLive = ~0;
00383 unique->keysZ = 0;
00384 unique->dead = 0;
00385 unique->deadZ = 0;
00386 unique->gcFrac = DD_GC_FRAC_HI;
00387 unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
00388 unique->looseUpTo = looseUpTo;
00389 unique->gcEnabled = 1;
00390 unique->allocated = 0;
00391 unique->reclaimed = 0;
00392 unique->subtables = ALLOC(DdSubtable,unique->maxSize);
00393 if (unique->subtables == NULL) {
00394 FREE(unique);
00395 return(NULL);
00396 }
00397 unique->subtableZ = ALLOC(DdSubtable,unique->maxSizeZ);
00398 if (unique->subtableZ == NULL) {
00399 FREE(unique->subtables);
00400 FREE(unique);
00401 return(NULL);
00402 }
00403 unique->perm = ALLOC(int,unique->maxSize);
00404 if (unique->perm == NULL) {
00405 FREE(unique->subtables);
00406 FREE(unique->subtableZ);
00407 FREE(unique);
00408 return(NULL);
00409 }
00410 unique->invperm = ALLOC(int,unique->maxSize);
00411 if (unique->invperm == NULL) {
00412 FREE(unique->subtables);
00413 FREE(unique->subtableZ);
00414 FREE(unique->perm);
00415 FREE(unique);
00416 return(NULL);
00417 }
00418 unique->permZ = ALLOC(int,unique->maxSizeZ);
00419 if (unique->permZ == NULL) {
00420 FREE(unique->subtables);
00421 FREE(unique->subtableZ);
00422 FREE(unique->perm);
00423 FREE(unique->invperm);
00424 FREE(unique);
00425 return(NULL);
00426 }
00427 unique->invpermZ = ALLOC(int,unique->maxSizeZ);
00428 if (unique->invpermZ == NULL) {
00429 FREE(unique->subtables);
00430 FREE(unique->subtableZ);
00431 FREE(unique->perm);
00432 FREE(unique->invperm);
00433 FREE(unique->permZ);
00434 FREE(unique);
00435 return(NULL);
00436 }
00437 unique->map = NULL;
00438 unique->stack = ALLOC(DdNodePtr,ddMax(unique->maxSize,unique->maxSizeZ)+1);
00439 if (unique->stack == NULL) {
00440 FREE(unique->subtables);
00441 FREE(unique->subtableZ);
00442 FREE(unique->perm);
00443 FREE(unique->invperm);
00444 FREE(unique->permZ);
00445 FREE(unique->invpermZ);
00446 FREE(unique);
00447 return(NULL);
00448 }
00449 unique->stack[0] = NULL;
00450
00451 #ifndef DD_NO_DEATH_ROW
00452 unique->deathRowDepth = 1 << cuddComputeFloorLog2(unique->looseUpTo >> 2);
00453 unique->deathRow = ALLOC(DdNodePtr,unique->deathRowDepth);
00454 if (unique->deathRow == NULL) {
00455 FREE(unique->subtables);
00456 FREE(unique->subtableZ);
00457 FREE(unique->perm);
00458 FREE(unique->invperm);
00459 FREE(unique->permZ);
00460 FREE(unique->invpermZ);
00461 FREE(unique->stack);
00462 FREE(unique);
00463 return(NULL);
00464 }
00465 for (i = 0; i < unique->deathRowDepth; i++) {
00466 unique->deathRow[i] = NULL;
00467 }
00468 unique->nextDead = 0;
00469 unique->deadMask = unique->deathRowDepth - 1;
00470 #endif
00471
00472 for (i = 0; (unsigned) i < numVars; i++) {
00473 unique->subtables[i].slots = slots;
00474 unique->subtables[i].shift = shift;
00475 unique->subtables[i].keys = 0;
00476 unique->subtables[i].dead = 0;
00477 unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
00478 unique->subtables[i].bindVar = 0;
00479 unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
00480 unique->subtables[i].pairIndex = 0;
00481 unique->subtables[i].varHandled = 0;
00482 unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
00483
00484 nodelist = unique->subtables[i].nodelist = ALLOC(DdNodePtr,slots);
00485 if (nodelist == NULL) {
00486 for (j = 0; j < i; j++) {
00487 FREE(unique->subtables[j].nodelist);
00488 }
00489 FREE(unique->subtables);
00490 FREE(unique->subtableZ);
00491 FREE(unique->perm);
00492 FREE(unique->invperm);
00493 FREE(unique->permZ);
00494 FREE(unique->invpermZ);
00495 FREE(unique->stack);
00496 FREE(unique);
00497 return(NULL);
00498 }
00499 for (j = 0; (unsigned) j < slots; j++) {
00500 nodelist[j] = sentinel;
00501 }
00502 unique->perm[i] = i;
00503 unique->invperm[i] = i;
00504 }
00505 for (i = 0; (unsigned) i < numVarsZ; i++) {
00506 unique->subtableZ[i].slots = slots;
00507 unique->subtableZ[i].shift = shift;
00508 unique->subtableZ[i].keys = 0;
00509 unique->subtableZ[i].dead = 0;
00510 unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
00511 nodelist = unique->subtableZ[i].nodelist = ALLOC(DdNodePtr,slots);
00512 if (nodelist == NULL) {
00513 for (j = 0; (unsigned) j < numVars; j++) {
00514 FREE(unique->subtables[j].nodelist);
00515 }
00516 FREE(unique->subtables);
00517 for (j = 0; j < i; j++) {
00518 FREE(unique->subtableZ[j].nodelist);
00519 }
00520 FREE(unique->subtableZ);
00521 FREE(unique->perm);
00522 FREE(unique->invperm);
00523 FREE(unique->permZ);
00524 FREE(unique->invpermZ);
00525 FREE(unique->stack);
00526 FREE(unique);
00527 return(NULL);
00528 }
00529 for (j = 0; (unsigned) j < slots; j++) {
00530 nodelist[j] = NULL;
00531 }
00532 unique->permZ[i] = i;
00533 unique->invpermZ[i] = i;
00534 }
00535 unique->constants.slots = slots;
00536 unique->constants.shift = shift;
00537 unique->constants.keys = 0;
00538 unique->constants.dead = 0;
00539 unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
00540 nodelist = unique->constants.nodelist = ALLOC(DdNodePtr,slots);
00541 if (nodelist == NULL) {
00542 for (j = 0; (unsigned) j < numVars; j++) {
00543 FREE(unique->subtables[j].nodelist);
00544 }
00545 FREE(unique->subtables);
00546 for (j = 0; (unsigned) j < numVarsZ; j++) {
00547 FREE(unique->subtableZ[j].nodelist);
00548 }
00549 FREE(unique->subtableZ);
00550 FREE(unique->perm);
00551 FREE(unique->invperm);
00552 FREE(unique->permZ);
00553 FREE(unique->invpermZ);
00554 FREE(unique->stack);
00555 FREE(unique);
00556 return(NULL);
00557 }
00558 for (j = 0; (unsigned) j < slots; j++) {
00559 nodelist[j] = NULL;
00560 }
00561
00562 unique->memoryList = NULL;
00563 unique->nextFree = NULL;
00564
00565 unique->memused = sizeof(DdManager) + (unique->maxSize + unique->maxSizeZ)
00566 * (sizeof(DdSubtable) + 2 * sizeof(int)) + (numVars + 1) *
00567 slots * sizeof(DdNodePtr) +
00568 (ddMax(unique->maxSize,unique->maxSizeZ) + 1) * sizeof(DdNodePtr);
00569 #ifndef DD_NO_DEATH_ROW
00570 unique->memused += unique->deathRowDepth * sizeof(DdNodePtr);
00571 #endif
00572
00573
00574 unique->reorderings = 0;
00575 unique->autoDyn = 0;
00576 unique->autoDynZ = 0;
00577 unique->realign = 0;
00578 unique->realignZ = 0;
00579 unique->reordered = 0;
00580 unique->autoMethod = CUDD_REORDER_SIFT;
00581 unique->autoMethodZ = CUDD_REORDER_SIFT;
00582 unique->nextDyn = DD_FIRST_REORDER;
00583 unique->countDead = ~0;
00584 unique->siftMaxVar = DD_SIFT_MAX_VAR;
00585 unique->siftMaxSwap = DD_SIFT_MAX_SWAPS;
00586 unique->tree = NULL;
00587 unique->treeZ = NULL;
00588 unique->groupcheck = CUDD_GROUP_CHECK7;
00589 unique->recomb = DD_DEFAULT_RECOMB;
00590 unique->symmviolation = 0;
00591 unique->arcviolation = 0;
00592 unique->populationSize = 0;
00593 unique->numberXovers = 0;
00594 unique->linear = NULL;
00595 unique->linearSize = 0;
00596
00597
00598 unique->univ = (DdNodePtr *)NULL;
00599
00600
00601 unique->localCaches = NULL;
00602 unique->preGCHook = NULL;
00603 unique->postGCHook = NULL;
00604 unique->preReorderingHook = NULL;
00605 unique->postReorderingHook = NULL;
00606 unique->out = stdout;
00607 unique->err = stderr;
00608 unique->errorCode = CUDD_NO_ERROR;
00609
00610
00611 unique->maxmemhard = ~ 0UL;
00612 unique->garbageCollections = 0;
00613 unique->GCTime = 0;
00614 unique->reordTime = 0;
00615 #ifdef DD_STATS
00616 unique->nodesDropped = 0;
00617 unique->nodesFreed = 0;
00618 #endif
00619 unique->peakLiveNodes = 0;
00620 #ifdef DD_UNIQUE_PROFILE
00621 unique->uniqueLookUps = 0;
00622 unique->uniqueLinks = 0;
00623 #endif
00624 #ifdef DD_COUNT
00625 unique->recursiveCalls = 0;
00626 unique->swapSteps = 0;
00627 #ifdef DD_STATS
00628 unique->nextSample = 250000;
00629 #endif
00630 #endif
00631
00632 return(unique);
00633
00634 }
00635
00636
00648 void
00649 cuddFreeTable(
00650 DdManager * unique)
00651 {
00652 DdNodePtr *next;
00653 DdNodePtr *memlist = unique->memoryList;
00654 int i;
00655
00656 if (unique->univ != NULL) cuddZddFreeUniv(unique);
00657 while (memlist != NULL) {
00658 next = (DdNodePtr *) memlist[0];
00659 FREE(memlist);
00660 memlist = next;
00661 }
00662 unique->nextFree = NULL;
00663 unique->memoryList = NULL;
00664
00665 for (i = 0; i < unique->size; i++) {
00666 FREE(unique->subtables[i].nodelist);
00667 }
00668 for (i = 0; i < unique->sizeZ; i++) {
00669 FREE(unique->subtableZ[i].nodelist);
00670 }
00671 FREE(unique->constants.nodelist);
00672 FREE(unique->subtables);
00673 FREE(unique->subtableZ);
00674 FREE(unique->acache);
00675 FREE(unique->perm);
00676 FREE(unique->permZ);
00677 FREE(unique->invperm);
00678 FREE(unique->invpermZ);
00679 FREE(unique->vars);
00680 if (unique->map != NULL) FREE(unique->map);
00681 FREE(unique->stack);
00682 #ifndef DD_NO_DEATH_ROW
00683 FREE(unique->deathRow);
00684 #endif
00685 if (unique->tree != NULL) Mtr_FreeTree(unique->tree);
00686 if (unique->treeZ != NULL) Mtr_FreeTree(unique->treeZ);
00687 if (unique->linear != NULL) FREE(unique->linear);
00688 while (unique->preGCHook != NULL)
00689 Cudd_RemoveHook(unique,unique->preGCHook->f,CUDD_PRE_GC_HOOK);
00690 while (unique->postGCHook != NULL)
00691 Cudd_RemoveHook(unique,unique->postGCHook->f,CUDD_POST_GC_HOOK);
00692 while (unique->preReorderingHook != NULL)
00693 Cudd_RemoveHook(unique,unique->preReorderingHook->f,
00694 CUDD_PRE_REORDERING_HOOK);
00695 while (unique->postReorderingHook != NULL)
00696 Cudd_RemoveHook(unique,unique->postReorderingHook->f,
00697 CUDD_POST_REORDERING_HOOK);
00698 FREE(unique);
00699
00700 }
00701
00702
00718 int
00719 cuddGarbageCollect(
00720 DdManager * unique,
00721 int clearCache)
00722 {
00723 DdHook *hook;
00724 DdCache *cache = unique->cache;
00725 DdNode *sentinel = &(unique->sentinel);
00726 DdNodePtr *nodelist;
00727 int i, j, deleted, totalDeleted, totalDeletedZ;
00728 DdCache *c;
00729 DdNode *node,*next;
00730 DdNodePtr *lastP;
00731 int slots;
00732 long localTime;
00733 #ifndef DD_UNSORTED_FREE_LIST
00734 #ifdef DD_RED_BLACK_FREE_LIST
00735 DdNodePtr tree;
00736 #else
00737 DdNodePtr *memListTrav, *nxtNode;
00738 DdNode *downTrav, *sentry;
00739 int k;
00740 #endif
00741 #endif
00742
00743 #ifndef DD_NO_DEATH_ROW
00744 cuddClearDeathRow(unique);
00745 #endif
00746
00747 hook = unique->preGCHook;
00748 while (hook != NULL) {
00749 int res = (hook->f)(unique,"DD",NULL);
00750 if (res == 0) return(0);
00751 hook = hook->next;
00752 }
00753
00754 if (unique->dead + unique->deadZ == 0) {
00755 hook = unique->postGCHook;
00756 while (hook != NULL) {
00757 int res = (hook->f)(unique,"DD",NULL);
00758 if (res == 0) return(0);
00759 hook = hook->next;
00760 }
00761 return(0);
00762 }
00763
00764
00765
00766
00767 if (clearCache && unique->gcFrac == DD_GC_FRAC_LO &&
00768 unique->slots <= unique->looseUpTo && unique->stash != NULL) {
00769 unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
00770 #ifdef DD_VERBOSE
00771 (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_HI);
00772 (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
00773 #endif
00774 unique->gcFrac = DD_GC_FRAC_HI;
00775 return(0);
00776 }
00777
00778 localTime = util_cpu_time();
00779
00780 unique->garbageCollections++;
00781 #ifdef DD_VERBOSE
00782 (void) fprintf(unique->err,
00783 "garbage collecting (%d dead BDD nodes out of %d, min %d)...",
00784 unique->dead, unique->keys, unique->minDead);
00785 (void) fprintf(unique->err,
00786 " (%d dead ZDD nodes out of %d)...",
00787 unique->deadZ, unique->keysZ);
00788 #endif
00789
00790
00791 if (clearCache) {
00792 slots = unique->cacheSlots;
00793 for (i = 0; i < slots; i++) {
00794 c = &cache[i];
00795 if (c->data != NULL) {
00796 if (cuddClean(c->f)->ref == 0 ||
00797 cuddClean(c->g)->ref == 0 ||
00798 (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) ||
00799 (c->data != DD_NON_CONSTANT &&
00800 Cudd_Regular(c->data)->ref == 0)) {
00801 c->data = NULL;
00802 unique->cachedeletions++;
00803 }
00804 }
00805 }
00806 cuddLocalCacheClearDead(unique);
00807 }
00808
00809
00810 totalDeleted = 0;
00811 #ifndef DD_UNSORTED_FREE_LIST
00812 #ifdef DD_RED_BLACK_FREE_LIST
00813 tree = NULL;
00814 #endif
00815 #endif
00816
00817 for (i = 0; i < unique->size; i++) {
00818 if (unique->subtables[i].dead == 0) continue;
00819 nodelist = unique->subtables[i].nodelist;
00820
00821 deleted = 0;
00822 slots = unique->subtables[i].slots;
00823 for (j = 0; j < slots; j++) {
00824 lastP = &(nodelist[j]);
00825 node = *lastP;
00826 while (node != sentinel) {
00827 next = node->next;
00828 if (node->ref == 0) {
00829 deleted++;
00830 #ifndef DD_UNSORTED_FREE_LIST
00831 #ifdef DD_RED_BLACK_FREE_LIST
00832 #ifdef __osf__
00833 #pragma pointer_size save
00834 #pragma pointer_size short
00835 #endif
00836 cuddOrderedInsert(&tree,node);
00837 #ifdef __osf__
00838 #pragma pointer_size restore
00839 #endif
00840 #endif
00841 #else
00842 cuddDeallocNode(unique,node);
00843 #endif
00844 } else {
00845 *lastP = node;
00846 lastP = &(node->next);
00847 }
00848 node = next;
00849 }
00850 *lastP = sentinel;
00851 }
00852 if ((unsigned) deleted != unique->subtables[i].dead) {
00853 ddReportRefMess(unique, i, "cuddGarbageCollect");
00854 }
00855 totalDeleted += deleted;
00856 unique->subtables[i].keys -= deleted;
00857 unique->subtables[i].dead = 0;
00858 }
00859 if (unique->constants.dead != 0) {
00860 nodelist = unique->constants.nodelist;
00861 deleted = 0;
00862 slots = unique->constants.slots;
00863 for (j = 0; j < slots; j++) {
00864 lastP = &(nodelist[j]);
00865 node = *lastP;
00866 while (node != NULL) {
00867 next = node->next;
00868 if (node->ref == 0) {
00869 deleted++;
00870 #ifndef DD_UNSORTED_FREE_LIST
00871 #ifdef DD_RED_BLACK_FREE_LIST
00872 #ifdef __osf__
00873 #pragma pointer_size save
00874 #pragma pointer_size short
00875 #endif
00876 cuddOrderedInsert(&tree,node);
00877 #ifdef __osf__
00878 #pragma pointer_size restore
00879 #endif
00880 #endif
00881 #else
00882 cuddDeallocNode(unique,node);
00883 #endif
00884 } else {
00885 *lastP = node;
00886 lastP = &(node->next);
00887 }
00888 node = next;
00889 }
00890 *lastP = NULL;
00891 }
00892 if ((unsigned) deleted != unique->constants.dead) {
00893 ddReportRefMess(unique, CUDD_CONST_INDEX, "cuddGarbageCollect");
00894 }
00895 totalDeleted += deleted;
00896 unique->constants.keys -= deleted;
00897 unique->constants.dead = 0;
00898 }
00899 if ((unsigned) totalDeleted != unique->dead) {
00900 ddReportRefMess(unique, -1, "cuddGarbageCollect");
00901 }
00902 unique->keys -= totalDeleted;
00903 unique->dead = 0;
00904 #ifdef DD_STATS
00905 unique->nodesFreed += (double) totalDeleted;
00906 #endif
00907
00908 totalDeletedZ = 0;
00909
00910 for (i = 0; i < unique->sizeZ; i++) {
00911 if (unique->subtableZ[i].dead == 0) continue;
00912 nodelist = unique->subtableZ[i].nodelist;
00913
00914 deleted = 0;
00915 slots = unique->subtableZ[i].slots;
00916 for (j = 0; j < slots; j++) {
00917 lastP = &(nodelist[j]);
00918 node = *lastP;
00919 while (node != NULL) {
00920 next = node->next;
00921 if (node->ref == 0) {
00922 deleted++;
00923 #ifndef DD_UNSORTED_FREE_LIST
00924 #ifdef DD_RED_BLACK_FREE_LIST
00925 #ifdef __osf__
00926 #pragma pointer_size save
00927 #pragma pointer_size short
00928 #endif
00929 cuddOrderedInsert(&tree,node);
00930 #ifdef __osf__
00931 #pragma pointer_size restore
00932 #endif
00933 #endif
00934 #else
00935 cuddDeallocNode(unique,node);
00936 #endif
00937 } else {
00938 *lastP = node;
00939 lastP = &(node->next);
00940 }
00941 node = next;
00942 }
00943 *lastP = NULL;
00944 }
00945 if ((unsigned) deleted != unique->subtableZ[i].dead) {
00946 ddReportRefMess(unique, i, "cuddGarbageCollect");
00947 }
00948 totalDeletedZ += deleted;
00949 unique->subtableZ[i].keys -= deleted;
00950 unique->subtableZ[i].dead = 0;
00951 }
00952
00953
00954
00955
00956 if ((unsigned) totalDeletedZ != unique->deadZ) {
00957 ddReportRefMess(unique, -1, "cuddGarbageCollect");
00958 }
00959 unique->keysZ -= totalDeletedZ;
00960 unique->deadZ = 0;
00961 #ifdef DD_STATS
00962 unique->nodesFreed += (double) totalDeletedZ;
00963 #endif
00964
00965
00966 #ifndef DD_UNSORTED_FREE_LIST
00967 #ifdef DD_RED_BLACK_FREE_LIST
00968 unique->nextFree = cuddOrderedThread(tree,unique->nextFree);
00969 #else
00970 memListTrav = unique->memoryList;
00971 sentry = NULL;
00972 while (memListTrav != NULL) {
00973 ptruint offset;
00974 nxtNode = (DdNodePtr *)memListTrav[0];
00975 offset = (ptruint) memListTrav & (sizeof(DdNode) - 1);
00976 memListTrav += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
00977 downTrav = (DdNode *)memListTrav;
00978 k = 0;
00979 do {
00980 if (downTrav[k].ref == 0) {
00981 if (sentry == NULL) {
00982 unique->nextFree = sentry = &downTrav[k];
00983 } else {
00984
00985
00986 sentry = (sentry->next = &downTrav[k]);
00987 }
00988 }
00989 } while (++k < DD_MEM_CHUNK);
00990 memListTrav = nxtNode;
00991 }
00992 sentry->next = NULL;
00993 #endif
00994 #endif
00995
00996 unique->GCTime += util_cpu_time() - localTime;
00997
00998 hook = unique->postGCHook;
00999 while (hook != NULL) {
01000 int res = (hook->f)(unique,"DD",NULL);
01001 if (res == 0) return(0);
01002 hook = hook->next;
01003 }
01004
01005 #ifdef DD_VERBOSE
01006 (void) fprintf(unique->err," done\n");
01007 #endif
01008
01009 return(totalDeleted+totalDeletedZ);
01010
01011 }
01012
01013
01027 DdNode *
01028 cuddZddGetNode(
01029 DdManager * zdd,
01030 int id,
01031 DdNode * T,
01032 DdNode * E)
01033 {
01034 DdNode *node;
01035
01036 if (T == DD_ZERO(zdd))
01037 return(E);
01038 node = cuddUniqueInterZdd(zdd, id, T, E);
01039 return(node);
01040
01041 }
01042
01043
01060 DdNode *
01061 cuddZddGetNodeIVO(
01062 DdManager * dd,
01063 int index,
01064 DdNode * g,
01065 DdNode * h)
01066 {
01067 DdNode *f, *r, *t;
01068 DdNode *zdd_one = DD_ONE(dd);
01069 DdNode *zdd_zero = DD_ZERO(dd);
01070
01071 f = cuddUniqueInterZdd(dd, index, zdd_one, zdd_zero);
01072 if (f == NULL) {
01073 return(NULL);
01074 }
01075 cuddRef(f);
01076 t = cuddZddProduct(dd, f, g);
01077 if (t == NULL) {
01078 Cudd_RecursiveDerefZdd(dd, f);
01079 return(NULL);
01080 }
01081 cuddRef(t);
01082 Cudd_RecursiveDerefZdd(dd, f);
01083 r = cuddZddUnion(dd, t, h);
01084 if (r == NULL) {
01085 Cudd_RecursiveDerefZdd(dd, t);
01086 return(NULL);
01087 }
01088 cuddRef(r);
01089 Cudd_RecursiveDerefZdd(dd, t);
01090
01091 cuddDeref(r);
01092 return(r);
01093
01094 }
01095
01096
01114 DdNode *
01115 cuddUniqueInter(
01116 DdManager * unique,
01117 int index,
01118 DdNode * T,
01119 DdNode * E)
01120 {
01121 int pos;
01122 unsigned int level;
01123 int retval;
01124 DdNodePtr *nodelist;
01125 DdNode *looking;
01126 DdNodePtr *previousP;
01127 DdSubtable *subtable;
01128 int gcNumber;
01129
01130 #ifdef DD_UNIQUE_PROFILE
01131 unique->uniqueLookUps++;
01132 #endif
01133
01134 if (index >= unique->size) {
01135 if (!ddResizeTable(unique,index)) return(NULL);
01136 }
01137
01138 level = unique->perm[index];
01139 subtable = &(unique->subtables[level]);
01140
01141 #ifdef DD_DEBUG
01142 assert(level < (unsigned) cuddI(unique,T->index));
01143 assert(level < (unsigned) cuddI(unique,Cudd_Regular(E)->index));
01144 #endif
01145
01146 pos = ddHash(T, E, subtable->shift);
01147 nodelist = subtable->nodelist;
01148 previousP = &(nodelist[pos]);
01149 looking = *previousP;
01150
01151 while (T < cuddT(looking)) {
01152 previousP = &(looking->next);
01153 looking = *previousP;
01154 #ifdef DD_UNIQUE_PROFILE
01155 unique->uniqueLinks++;
01156 #endif
01157 }
01158 while (T == cuddT(looking) && E < cuddE(looking)) {
01159 previousP = &(looking->next);
01160 looking = *previousP;
01161 #ifdef DD_UNIQUE_PROFILE
01162 unique->uniqueLinks++;
01163 #endif
01164 }
01165 if (T == cuddT(looking) && E == cuddE(looking)) {
01166 if (looking->ref == 0) {
01167 cuddReclaim(unique,looking);
01168 }
01169 return(looking);
01170 }
01171
01172
01173 if (unique->autoDyn &&
01174 unique->keys - (unique->dead & unique->countDead) >= unique->nextDyn) {
01175 #ifdef DD_DEBUG
01176 retval = Cudd_DebugCheck(unique);
01177 if (retval != 0) return(NULL);
01178 retval = Cudd_CheckKeys(unique);
01179 if (retval != 0) return(NULL);
01180 #endif
01181 retval = Cudd_ReduceHeap(unique,unique->autoMethod,10);
01182 if (retval == 0) unique->reordered = 2;
01183 #ifdef DD_DEBUG
01184 retval = Cudd_DebugCheck(unique);
01185 if (retval != 0) unique->reordered = 2;
01186 retval = Cudd_CheckKeys(unique);
01187 if (retval != 0) unique->reordered = 2;
01188 #endif
01189 return(NULL);
01190 }
01191
01192 if (subtable->keys > subtable->maxKeys) {
01193 if (unique->gcEnabled &&
01194 ((unique->dead > unique->minDead) ||
01195 ((unique->dead > unique->minDead / 2) &&
01196 (subtable->dead > subtable->keys * 0.95)))) {
01197 (void) cuddGarbageCollect(unique,1);
01198 } else {
01199 cuddRehash(unique,(int)level);
01200 }
01201
01202
01203
01204 pos = ddHash(T, E, subtable->shift);
01205 nodelist = subtable->nodelist;
01206 previousP = &(nodelist[pos]);
01207 looking = *previousP;
01208
01209 while (T < cuddT(looking)) {
01210 previousP = &(looking->next);
01211 looking = *previousP;
01212 #ifdef DD_UNIQUE_PROFILE
01213 unique->uniqueLinks++;
01214 #endif
01215 }
01216 while (T == cuddT(looking) && E < cuddE(looking)) {
01217 previousP = &(looking->next);
01218 looking = *previousP;
01219 #ifdef DD_UNIQUE_PROFILE
01220 unique->uniqueLinks++;
01221 #endif
01222 }
01223 }
01224
01225 gcNumber = unique->garbageCollections;
01226 looking = cuddAllocNode(unique);
01227 if (looking == NULL) {
01228 return(NULL);
01229 }
01230 unique->keys++;
01231 subtable->keys++;
01232
01233 if (gcNumber != unique->garbageCollections) {
01234 DdNode *looking2;
01235 pos = ddHash(T, E, subtable->shift);
01236 nodelist = subtable->nodelist;
01237 previousP = &(nodelist[pos]);
01238 looking2 = *previousP;
01239
01240 while (T < cuddT(looking2)) {
01241 previousP = &(looking2->next);
01242 looking2 = *previousP;
01243 #ifdef DD_UNIQUE_PROFILE
01244 unique->uniqueLinks++;
01245 #endif
01246 }
01247 while (T == cuddT(looking2) && E < cuddE(looking2)) {
01248 previousP = &(looking2->next);
01249 looking2 = *previousP;
01250 #ifdef DD_UNIQUE_PROFILE
01251 unique->uniqueLinks++;
01252 #endif
01253 }
01254 }
01255 looking->index = index;
01256 cuddT(looking) = T;
01257 cuddE(looking) = E;
01258 looking->next = *previousP;
01259 *previousP = looking;
01260 cuddSatInc(T->ref);
01261 cuddRef(E);
01262
01263 #ifdef DD_DEBUG
01264 cuddCheckCollisionOrdering(unique,level,pos);
01265 #endif
01266
01267 return(looking);
01268
01269 }
01270
01271
01288 DdNode *
01289 cuddUniqueInterIVO(
01290 DdManager * unique,
01291 int index,
01292 DdNode * T,
01293 DdNode * E)
01294 {
01295 DdNode *result;
01296 DdNode *v;
01297
01298 v = cuddUniqueInter(unique, index, DD_ONE(unique),
01299 Cudd_Not(DD_ONE(unique)));
01300 if (v == NULL)
01301 return(NULL);
01302 cuddRef(v);
01303 result = cuddBddIteRecur(unique, v, T, E);
01304 Cudd_RecursiveDeref(unique, v);
01305 return(result);
01306 }
01307
01308
01327 DdNode *
01328 cuddUniqueInterZdd(
01329 DdManager * unique,
01330 int index,
01331 DdNode * T,
01332 DdNode * E)
01333 {
01334 int pos;
01335 unsigned int level;
01336 int retval;
01337 DdNodePtr *nodelist;
01338 DdNode *looking;
01339 DdSubtable *subtable;
01340
01341 #ifdef DD_UNIQUE_PROFILE
01342 unique->uniqueLookUps++;
01343 #endif
01344
01345 if (index >= unique->sizeZ) {
01346 if (!cuddResizeTableZdd(unique,index)) return(NULL);
01347 }
01348
01349 level = unique->permZ[index];
01350 subtable = &(unique->subtableZ[level]);
01351
01352 #ifdef DD_DEBUG
01353 assert(level < (unsigned) cuddIZ(unique,T->index));
01354 assert(level < (unsigned) cuddIZ(unique,Cudd_Regular(E)->index));
01355 #endif
01356
01357 if (subtable->keys > subtable->maxKeys) {
01358 if (unique->gcEnabled && ((unique->deadZ > unique->minDead) ||
01359 (10 * subtable->dead > 9 * subtable->keys))) {
01360 (void) cuddGarbageCollect(unique,1);
01361 } else {
01362 ddRehashZdd(unique,(int)level);
01363 }
01364 }
01365
01366 pos = ddHash(T, E, subtable->shift);
01367 nodelist = subtable->nodelist;
01368 looking = nodelist[pos];
01369
01370 while (looking != NULL) {
01371 if (cuddT(looking) == T && cuddE(looking) == E) {
01372 if (looking->ref == 0) {
01373 cuddReclaimZdd(unique,looking);
01374 }
01375 return(looking);
01376 }
01377 looking = looking->next;
01378 #ifdef DD_UNIQUE_PROFILE
01379 unique->uniqueLinks++;
01380 #endif
01381 }
01382
01383
01384 if (unique->autoDynZ &&
01385 unique->keysZ - (unique->deadZ & unique->countDead) >= unique->nextDyn) {
01386 #ifdef DD_DEBUG
01387 retval = Cudd_DebugCheck(unique);
01388 if (retval != 0) return(NULL);
01389 retval = Cudd_CheckKeys(unique);
01390 if (retval != 0) return(NULL);
01391 #endif
01392 retval = Cudd_zddReduceHeap(unique,unique->autoMethodZ,10);
01393 if (retval == 0) unique->reordered = 2;
01394 #ifdef DD_DEBUG
01395 retval = Cudd_DebugCheck(unique);
01396 if (retval != 0) unique->reordered = 2;
01397 retval = Cudd_CheckKeys(unique);
01398 if (retval != 0) unique->reordered = 2;
01399 #endif
01400 return(NULL);
01401 }
01402
01403 unique->keysZ++;
01404 subtable->keys++;
01405
01406 looking = cuddAllocNode(unique);
01407 if (looking == NULL) return(NULL);
01408 looking->index = index;
01409 cuddT(looking) = T;
01410 cuddE(looking) = E;
01411 looking->next = nodelist[pos];
01412 nodelist[pos] = looking;
01413 cuddRef(T);
01414 cuddRef(E);
01415
01416 return(looking);
01417
01418 }
01419
01420
01434 DdNode *
01435 cuddUniqueConst(
01436 DdManager * unique,
01437 CUDD_VALUE_TYPE value)
01438 {
01439 int pos;
01440 DdNodePtr *nodelist;
01441 DdNode *looking;
01442 hack split;
01443
01444 #ifdef DD_UNIQUE_PROFILE
01445 unique->uniqueLookUps++;
01446 #endif
01447
01448 if (unique->constants.keys > unique->constants.maxKeys) {
01449 if (unique->gcEnabled && ((unique->dead > unique->minDead) ||
01450 (10 * unique->constants.dead > 9 * unique->constants.keys))) {
01451 (void) cuddGarbageCollect(unique,1);
01452 } else {
01453 cuddRehash(unique,CUDD_CONST_INDEX);
01454 }
01455 }
01456
01457 cuddAdjust(value);
01458
01459 if (ddAbs(value) < unique->epsilon) {
01460 value = 0.0;
01461 }
01462 split.value = value;
01463
01464 pos = ddHash(split.bits[0], split.bits[1], unique->constants.shift);
01465 nodelist = unique->constants.nodelist;
01466 looking = nodelist[pos];
01467
01468
01469
01470
01471
01472
01473 while (looking != NULL) {
01474 if (looking->type.value == value ||
01475 ddEqualVal(looking->type.value,value,unique->epsilon)) {
01476 if (looking->ref == 0) {
01477 cuddReclaim(unique,looking);
01478 }
01479 return(looking);
01480 }
01481 looking = looking->next;
01482 #ifdef DD_UNIQUE_PROFILE
01483 unique->uniqueLinks++;
01484 #endif
01485 }
01486
01487 unique->keys++;
01488 unique->constants.keys++;
01489
01490 looking = cuddAllocNode(unique);
01491 if (looking == NULL) return(NULL);
01492 looking->index = CUDD_CONST_INDEX;
01493 looking->type.value = value;
01494 looking->next = nodelist[pos];
01495 nodelist[pos] = looking;
01496
01497 return(looking);
01498
01499 }
01500
01501
01514 void
01515 cuddRehash(
01516 DdManager * unique,
01517 int i)
01518 {
01519 unsigned int slots, oldslots;
01520 int shift, oldshift;
01521 int j, pos;
01522 DdNodePtr *nodelist, *oldnodelist;
01523 DdNode *node, *next;
01524 DdNode *sentinel = &(unique->sentinel);
01525 hack split;
01526 extern DD_OOMFP MMoutOfMemory;
01527 DD_OOMFP saveHandler;
01528
01529 if (unique->gcFrac == DD_GC_FRAC_HI && unique->slots > unique->looseUpTo) {
01530 unique->gcFrac = DD_GC_FRAC_LO;
01531 unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
01532 #ifdef DD_VERBOSE
01533 (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_LO);
01534 (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
01535 #endif
01536 }
01537
01538 if (unique->gcFrac != DD_GC_FRAC_MIN && unique->memused > unique->maxmem) {
01539 unique->gcFrac = DD_GC_FRAC_MIN;
01540 unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
01541 #ifdef DD_VERBOSE
01542 (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_MIN);
01543 (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
01544 #endif
01545 cuddShrinkDeathRow(unique);
01546 if (cuddGarbageCollect(unique,1) > 0) return;
01547 }
01548
01549 if (i != CUDD_CONST_INDEX) {
01550 oldslots = unique->subtables[i].slots;
01551 oldshift = unique->subtables[i].shift;
01552 oldnodelist = unique->subtables[i].nodelist;
01553
01554
01555 slots = oldslots << 1;
01556 shift = oldshift - 1;
01557
01558 saveHandler = MMoutOfMemory;
01559 MMoutOfMemory = Cudd_OutOfMem;
01560 nodelist = ALLOC(DdNodePtr, slots);
01561 MMoutOfMemory = saveHandler;
01562 if (nodelist == NULL) {
01563 (void) fprintf(unique->err,
01564 "Unable to resize subtable %d for lack of memory\n",
01565 i);
01566
01567 (void) cuddGarbageCollect(unique,1);
01568 if (unique->stash != NULL) {
01569 FREE(unique->stash);
01570 unique->stash = NULL;
01571
01572 cuddSlowTableGrowth(unique);
01573 }
01574 return;
01575 }
01576 unique->subtables[i].nodelist = nodelist;
01577 unique->subtables[i].slots = slots;
01578 unique->subtables[i].shift = shift;
01579 unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
01580
01581
01582
01583
01584
01585
01586 for (j = 0; (unsigned) j < oldslots; j++) {
01587 DdNodePtr *evenP, *oddP;
01588 node = oldnodelist[j];
01589 evenP = &(nodelist[j<<1]);
01590 oddP = &(nodelist[(j<<1)+1]);
01591 while (node != sentinel) {
01592 next = node->next;
01593 pos = ddHash(cuddT(node), cuddE(node), shift);
01594 if (pos & 1) {
01595 *oddP = node;
01596 oddP = &(node->next);
01597 } else {
01598 *evenP = node;
01599 evenP = &(node->next);
01600 }
01601 node = next;
01602 }
01603 *evenP = *oddP = sentinel;
01604 }
01605 FREE(oldnodelist);
01606
01607 #ifdef DD_VERBOSE
01608 (void) fprintf(unique->err,
01609 "rehashing layer %d: keys %d dead %d new size %d\n",
01610 i, unique->subtables[i].keys,
01611 unique->subtables[i].dead, slots);
01612 #endif
01613 } else {
01614 oldslots = unique->constants.slots;
01615 oldshift = unique->constants.shift;
01616 oldnodelist = unique->constants.nodelist;
01617
01618
01619
01620
01621
01622
01623 slots = oldslots << 1;
01624 shift = oldshift - 1;
01625 saveHandler = MMoutOfMemory;
01626 MMoutOfMemory = Cudd_OutOfMem;
01627 nodelist = ALLOC(DdNodePtr, slots);
01628 MMoutOfMemory = saveHandler;
01629 if (nodelist == NULL) {
01630 (void) fprintf(unique->err,
01631 "Unable to resize constant subtable for lack of memory\n");
01632 (void) cuddGarbageCollect(unique,1);
01633 for (j = 0; j < unique->size; j++) {
01634 unique->subtables[j].maxKeys <<= 1;
01635 }
01636 unique->constants.maxKeys <<= 1;
01637 return;
01638 }
01639 unique->constants.slots = slots;
01640 unique->constants.shift = shift;
01641 unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
01642 unique->constants.nodelist = nodelist;
01643 for (j = 0; (unsigned) j < slots; j++) {
01644 nodelist[j] = NULL;
01645 }
01646 for (j = 0; (unsigned) j < oldslots; j++) {
01647 node = oldnodelist[j];
01648 while (node != NULL) {
01649 next = node->next;
01650 split.value = cuddV(node);
01651 pos = ddHash(split.bits[0], split.bits[1], shift);
01652 node->next = nodelist[pos];
01653 nodelist[pos] = node;
01654 node = next;
01655 }
01656 }
01657 FREE(oldnodelist);
01658
01659 #ifdef DD_VERBOSE
01660 (void) fprintf(unique->err,
01661 "rehashing constants: keys %d dead %d new size %d\n",
01662 unique->constants.keys,unique->constants.dead,slots);
01663 #endif
01664 }
01665
01666
01667
01668 unique->memused += (slots - oldslots) * sizeof(DdNodePtr);
01669 unique->slots += (slots - oldslots);
01670 ddFixLimits(unique);
01671
01672 }
01673
01674
01686 void
01687 cuddShrinkSubtable(
01688 DdManager *unique,
01689 int i)
01690 {
01691 int j;
01692 int shift, posn;
01693 DdNodePtr *nodelist, *oldnodelist;
01694 DdNode *node, *next;
01695 DdNode *sentinel = &(unique->sentinel);
01696 unsigned int slots, oldslots;
01697 extern DD_OOMFP MMoutOfMemory;
01698 DD_OOMFP saveHandler;
01699
01700 oldnodelist = unique->subtables[i].nodelist;
01701 oldslots = unique->subtables[i].slots;
01702 slots = oldslots >> 1;
01703 saveHandler = MMoutOfMemory;
01704 MMoutOfMemory = Cudd_OutOfMem;
01705 nodelist = ALLOC(DdNodePtr, slots);
01706 MMoutOfMemory = saveHandler;
01707 if (nodelist == NULL) {
01708 return;
01709 }
01710 unique->subtables[i].nodelist = nodelist;
01711 unique->subtables[i].slots = slots;
01712 unique->subtables[i].shift++;
01713 unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
01714 #ifdef DD_VERBOSE
01715 (void) fprintf(unique->err,
01716 "shrunk layer %d (%d keys) from %d to %d slots\n",
01717 i, unique->subtables[i].keys, oldslots, slots);
01718 #endif
01719
01720 for (j = 0; (unsigned) j < slots; j++) {
01721 nodelist[j] = sentinel;
01722 }
01723 shift = unique->subtables[i].shift;
01724 for (j = 0; (unsigned) j < oldslots; j++) {
01725 node = oldnodelist[j];
01726 while (node != sentinel) {
01727 DdNode *looking, *T, *E;
01728 DdNodePtr *previousP;
01729 next = node->next;
01730 posn = ddHash(cuddT(node), cuddE(node), shift);
01731 previousP = &(nodelist[posn]);
01732 looking = *previousP;
01733 T = cuddT(node);
01734 E = cuddE(node);
01735 while (T < cuddT(looking)) {
01736 previousP = &(looking->next);
01737 looking = *previousP;
01738 #ifdef DD_UNIQUE_PROFILE
01739 unique->uniqueLinks++;
01740 #endif
01741 }
01742 while (T == cuddT(looking) && E < cuddE(looking)) {
01743 previousP = &(looking->next);
01744 looking = *previousP;
01745 #ifdef DD_UNIQUE_PROFILE
01746 unique->uniqueLinks++;
01747 #endif
01748 }
01749 node->next = *previousP;
01750 *previousP = node;
01751 node = next;
01752 }
01753 }
01754 FREE(oldnodelist);
01755
01756 unique->memused += ((long) slots - (long) oldslots) * sizeof(DdNode *);
01757 unique->slots += slots - oldslots;
01758 unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
01759 unique->cacheSlack = (int)
01760 ddMin(unique->maxCacheHard,DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots)
01761 - 2 * (int) unique->cacheSlots;
01762
01763 }
01764
01765
01779 int
01780 cuddInsertSubtables(
01781 DdManager * unique,
01782 int n,
01783 int level)
01784 {
01785 DdSubtable *newsubtables;
01786 DdNodePtr *newnodelist;
01787 DdNodePtr *newvars;
01788 DdNode *sentinel = &(unique->sentinel);
01789 int oldsize,newsize;
01790 int i,j,index,reorderSave;
01791 unsigned int numSlots = unique->initSlots;
01792 int *newperm, *newinvperm, *newmap;
01793 DdNode *one, *zero;
01794
01795 #ifdef DD_DEBUG
01796 assert(n > 0 && level < unique->size);
01797 #endif
01798
01799 oldsize = unique->size;
01800
01801 if (oldsize + n <= unique->maxSize) {
01802
01803 for (i = oldsize - 1; i >= level; i--) {
01804 unique->subtables[i+n].slots = unique->subtables[i].slots;
01805 unique->subtables[i+n].shift = unique->subtables[i].shift;
01806 unique->subtables[i+n].keys = unique->subtables[i].keys;
01807 unique->subtables[i+n].maxKeys = unique->subtables[i].maxKeys;
01808 unique->subtables[i+n].dead = unique->subtables[i].dead;
01809 unique->subtables[i+n].nodelist = unique->subtables[i].nodelist;
01810 unique->subtables[i+n].bindVar = unique->subtables[i].bindVar;
01811 unique->subtables[i+n].varType = unique->subtables[i].varType;
01812 unique->subtables[i+n].pairIndex = unique->subtables[i].pairIndex;
01813 unique->subtables[i+n].varHandled = unique->subtables[i].varHandled;
01814 unique->subtables[i+n].varToBeGrouped =
01815 unique->subtables[i].varToBeGrouped;
01816
01817 index = unique->invperm[i];
01818 unique->invperm[i+n] = index;
01819 unique->perm[index] += n;
01820 }
01821
01822 for (i = 0; i < n; i++) {
01823 unique->subtables[level+i].slots = numSlots;
01824 unique->subtables[level+i].shift = sizeof(int) * 8 -
01825 cuddComputeFloorLog2(numSlots);
01826 unique->subtables[level+i].keys = 0;
01827 unique->subtables[level+i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
01828 unique->subtables[level+i].dead = 0;
01829 unique->subtables[level+i].bindVar = 0;
01830 unique->subtables[level+i].varType = CUDD_VAR_PRIMARY_INPUT;
01831 unique->subtables[level+i].pairIndex = 0;
01832 unique->subtables[level+i].varHandled = 0;
01833 unique->subtables[level+i].varToBeGrouped = CUDD_LAZY_NONE;
01834
01835 unique->perm[oldsize+i] = level + i;
01836 unique->invperm[level+i] = oldsize + i;
01837 newnodelist = unique->subtables[level+i].nodelist =
01838 ALLOC(DdNodePtr, numSlots);
01839 if (newnodelist == NULL) {
01840 unique->errorCode = CUDD_MEMORY_OUT;
01841 return(0);
01842 }
01843 for (j = 0; (unsigned) j < numSlots; j++) {
01844 newnodelist[j] = sentinel;
01845 }
01846 }
01847 if (unique->map != NULL) {
01848 for (i = 0; i < n; i++) {
01849 unique->map[oldsize+i] = oldsize + i;
01850 }
01851 }
01852 } else {
01853
01854
01855
01856
01857 newsize = oldsize + n + DD_DEFAULT_RESIZE;
01858 #ifdef DD_VERBOSE
01859 (void) fprintf(unique->err,
01860 "Increasing the table size from %d to %d\n",
01861 unique->maxSize, newsize);
01862 #endif
01863
01864 newsubtables = ALLOC(DdSubtable,newsize);
01865 if (newsubtables == NULL) {
01866 unique->errorCode = CUDD_MEMORY_OUT;
01867 return(0);
01868 }
01869 newvars = ALLOC(DdNodePtr,newsize);
01870 if (newvars == NULL) {
01871 unique->errorCode = CUDD_MEMORY_OUT;
01872 FREE(newsubtables);
01873 return(0);
01874 }
01875 newperm = ALLOC(int,newsize);
01876 if (newperm == NULL) {
01877 unique->errorCode = CUDD_MEMORY_OUT;
01878 FREE(newsubtables);
01879 FREE(newvars);
01880 return(0);
01881 }
01882 newinvperm = ALLOC(int,newsize);
01883 if (newinvperm == NULL) {
01884 unique->errorCode = CUDD_MEMORY_OUT;
01885 FREE(newsubtables);
01886 FREE(newvars);
01887 FREE(newperm);
01888 return(0);
01889 }
01890 if (unique->map != NULL) {
01891 newmap = ALLOC(int,newsize);
01892 if (newmap == NULL) {
01893 unique->errorCode = CUDD_MEMORY_OUT;
01894 FREE(newsubtables);
01895 FREE(newvars);
01896 FREE(newperm);
01897 FREE(newinvperm);
01898 return(0);
01899 }
01900 unique->memused += (newsize - unique->maxSize) * sizeof(int);
01901 }
01902 unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
01903 sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
01904
01905 for (i = 0; i < level; i++) {
01906 newsubtables[i].slots = unique->subtables[i].slots;
01907 newsubtables[i].shift = unique->subtables[i].shift;
01908 newsubtables[i].keys = unique->subtables[i].keys;
01909 newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
01910 newsubtables[i].dead = unique->subtables[i].dead;
01911 newsubtables[i].nodelist = unique->subtables[i].nodelist;
01912 newsubtables[i].bindVar = unique->subtables[i].bindVar;
01913 newsubtables[i].varType = unique->subtables[i].varType;
01914 newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
01915 newsubtables[i].varHandled = unique->subtables[i].varHandled;
01916 newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
01917
01918 newvars[i] = unique->vars[i];
01919 newperm[i] = unique->perm[i];
01920 newinvperm[i] = unique->invperm[i];
01921 }
01922
01923 for (i = level; i < oldsize; i++) {
01924 newperm[i] = unique->perm[i];
01925 }
01926
01927 for (i = level; i < level + n; i++) {
01928 newsubtables[i].slots = numSlots;
01929 newsubtables[i].shift = sizeof(int) * 8 -
01930 cuddComputeFloorLog2(numSlots);
01931 newsubtables[i].keys = 0;
01932 newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
01933 newsubtables[i].dead = 0;
01934 newsubtables[i].bindVar = 0;
01935 newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
01936 newsubtables[i].pairIndex = 0;
01937 newsubtables[i].varHandled = 0;
01938 newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
01939
01940 newperm[oldsize + i - level] = i;
01941 newinvperm[i] = oldsize + i - level;
01942 newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
01943 if (newnodelist == NULL) {
01944
01945 unique->errorCode = CUDD_MEMORY_OUT;
01946 return(0);
01947 }
01948 for (j = 0; (unsigned) j < numSlots; j++) {
01949 newnodelist[j] = sentinel;
01950 }
01951 }
01952
01953 for (i = level; i < oldsize; i++) {
01954 newsubtables[i+n].slots = unique->subtables[i].slots;
01955 newsubtables[i+n].shift = unique->subtables[i].shift;
01956 newsubtables[i+n].keys = unique->subtables[i].keys;
01957 newsubtables[i+n].maxKeys = unique->subtables[i].maxKeys;
01958 newsubtables[i+n].dead = unique->subtables[i].dead;
01959 newsubtables[i+n].nodelist = unique->subtables[i].nodelist;
01960 newsubtables[i+n].bindVar = unique->subtables[i].bindVar;
01961 newsubtables[i+n].varType = unique->subtables[i].varType;
01962 newsubtables[i+n].pairIndex = unique->subtables[i].pairIndex;
01963 newsubtables[i+n].varHandled = unique->subtables[i].varHandled;
01964 newsubtables[i+n].varToBeGrouped =
01965 unique->subtables[i].varToBeGrouped;
01966
01967 newvars[i] = unique->vars[i];
01968 index = unique->invperm[i];
01969 newinvperm[i+n] = index;
01970 newperm[index] += n;
01971 }
01972
01973 if (unique->map != NULL) {
01974 for (i = 0; i < oldsize; i++) {
01975 newmap[i] = unique->map[i];
01976 }
01977 for (i = oldsize; i < oldsize + n; i++) {
01978 newmap[i] = i;
01979 }
01980 FREE(unique->map);
01981 unique->map = newmap;
01982 }
01983
01984 FREE(unique->subtables);
01985 unique->subtables = newsubtables;
01986 unique->maxSize = newsize;
01987 FREE(unique->vars);
01988 unique->vars = newvars;
01989 FREE(unique->perm);
01990 unique->perm = newperm;
01991 FREE(unique->invperm);
01992 unique->invperm = newinvperm;
01993
01994 if (newsize > unique->maxSizeZ) {
01995 FREE(unique->stack);
01996 unique->stack = ALLOC(DdNodePtr,newsize + 1);
01997 if (unique->stack == NULL) {
01998 unique->errorCode = CUDD_MEMORY_OUT;
01999 return(0);
02000 }
02001 unique->stack[0] = NULL;
02002 unique->memused +=
02003 (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
02004 * sizeof(DdNode *);
02005 }
02006 }
02007
02008 unique->slots += n * numSlots;
02009 ddFixLimits(unique);
02010 unique->size += n;
02011
02012
02013
02014
02015
02016 one = unique->one;
02017 zero = Cudd_Not(one);
02018
02019 reorderSave = unique->autoDyn;
02020 unique->autoDyn = 0;
02021 for (i = oldsize; i < oldsize + n; i++) {
02022 unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
02023 if (unique->vars[i] == NULL) {
02024 unique->autoDyn = reorderSave;
02025
02026 for (j = oldsize; j < i; j++) {
02027 Cudd_IterDerefBdd(unique,unique->vars[j]);
02028 cuddDeallocNode(unique,unique->vars[j]);
02029 unique->vars[j] = NULL;
02030 }
02031 for (j = level; j < oldsize; j++) {
02032 unique->subtables[j].slots = unique->subtables[j+n].slots;
02033 unique->subtables[j].slots = unique->subtables[j+n].slots;
02034 unique->subtables[j].shift = unique->subtables[j+n].shift;
02035 unique->subtables[j].keys = unique->subtables[j+n].keys;
02036 unique->subtables[j].maxKeys =
02037 unique->subtables[j+n].maxKeys;
02038 unique->subtables[j].dead = unique->subtables[j+n].dead;
02039 FREE(unique->subtables[j].nodelist);
02040 unique->subtables[j].nodelist =
02041 unique->subtables[j+n].nodelist;
02042 unique->subtables[j+n].nodelist = NULL;
02043 unique->subtables[j].bindVar =
02044 unique->subtables[j+n].bindVar;
02045 unique->subtables[j].varType =
02046 unique->subtables[j+n].varType;
02047 unique->subtables[j].pairIndex =
02048 unique->subtables[j+n].pairIndex;
02049 unique->subtables[j].varHandled =
02050 unique->subtables[j+n].varHandled;
02051 unique->subtables[j].varToBeGrouped =
02052 unique->subtables[j+n].varToBeGrouped;
02053 index = unique->invperm[j+n];
02054 unique->invperm[j] = index;
02055 unique->perm[index] -= n;
02056 }
02057 unique->size = oldsize;
02058 unique->slots -= n * numSlots;
02059 ddFixLimits(unique);
02060 (void) Cudd_DebugCheck(unique);
02061 return(0);
02062 }
02063 cuddRef(unique->vars[i]);
02064 }
02065 if (unique->tree != NULL) {
02066 unique->tree->size += n;
02067 unique->tree->index = unique->invperm[0];
02068 ddPatchTree(unique,unique->tree);
02069 }
02070 unique->autoDyn = reorderSave;
02071
02072 return(1);
02073
02074 }
02075
02076
02092 int
02093 cuddDestroySubtables(
02094 DdManager * unique,
02095 int n)
02096 {
02097 DdSubtable *subtables;
02098 DdNodePtr *nodelist;
02099 DdNodePtr *vars;
02100 int firstIndex, lastIndex;
02101 int index, level, newlevel;
02102 int lowestLevel;
02103 int shift;
02104 int found;
02105
02106
02107 if (n <= 0) return(0);
02108 if (n > unique->size) n = unique->size;
02109
02110 subtables = unique->subtables;
02111 vars = unique->vars;
02112 firstIndex = unique->size - n;
02113 lastIndex = unique->size;
02114
02115
02116
02117
02118
02119
02120
02121 lowestLevel = unique->size;
02122 for (index = firstIndex; index < lastIndex; index++) {
02123 level = unique->perm[index];
02124 if (level < lowestLevel) lowestLevel = level;
02125 nodelist = subtables[level].nodelist;
02126 if (subtables[level].keys - subtables[level].dead != 1) return(0);
02127
02128
02129
02130
02131
02132
02133 if (vars[index]->ref != 1) {
02134 if (vars[index]->ref != DD_MAXREF) return(0);
02135 found = cuddFindParent(unique,vars[index]);
02136 if (found) {
02137 return(0);
02138 } else {
02139 vars[index]->ref = 1;
02140 }
02141 }
02142 Cudd_RecursiveDeref(unique,vars[index]);
02143 }
02144
02145
02146
02147
02148 (void) cuddGarbageCollect(unique,1);
02149
02150
02151 for (index = firstIndex; index < lastIndex; index++) {
02152 level = unique->perm[index];
02153 nodelist = subtables[level].nodelist;
02154 #ifdef DD_DEBUG
02155 assert(subtables[level].keys == 0);
02156 #endif
02157 FREE(nodelist);
02158 unique->memused -= sizeof(DdNodePtr) * subtables[level].slots;
02159 unique->slots -= subtables[level].slots;
02160 unique->dead -= subtables[level].dead;
02161 }
02162
02163
02164
02165
02166
02167
02168
02169
02170 shift = 1;
02171 for (level = lowestLevel + 1; level < unique->size; level++) {
02172 if (subtables[level].keys == 0) {
02173 shift++;
02174 continue;
02175 }
02176 newlevel = level - shift;
02177 subtables[newlevel].slots = subtables[level].slots;
02178 subtables[newlevel].shift = subtables[level].shift;
02179 subtables[newlevel].keys = subtables[level].keys;
02180 subtables[newlevel].maxKeys = subtables[level].maxKeys;
02181 subtables[newlevel].dead = subtables[level].dead;
02182 subtables[newlevel].nodelist = subtables[level].nodelist;
02183 index = unique->invperm[level];
02184 unique->perm[index] = newlevel;
02185 unique->invperm[newlevel] = index;
02186 subtables[newlevel].bindVar = subtables[level].bindVar;
02187 subtables[newlevel].varType = subtables[level].varType;
02188 subtables[newlevel].pairIndex = subtables[level].pairIndex;
02189 subtables[newlevel].varHandled = subtables[level].varHandled;
02190 subtables[newlevel].varToBeGrouped = subtables[level].varToBeGrouped;
02191 }
02192
02193
02194
02195 if (unique->map != NULL) {
02196 cuddCacheFlush(unique);
02197 FREE(unique->map);
02198 unique->map = NULL;
02199 }
02200
02201 unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
02202 unique->size -= n;
02203
02204 return(1);
02205
02206 }
02207
02208
02225 int
02226 cuddResizeTableZdd(
02227 DdManager * unique,
02228 int index)
02229 {
02230 DdSubtable *newsubtables;
02231 DdNodePtr *newnodelist;
02232 int oldsize,newsize;
02233 int i,j,reorderSave;
02234 unsigned int numSlots = unique->initSlots;
02235 int *newperm, *newinvperm;
02236
02237 oldsize = unique->sizeZ;
02238
02239 if (index < unique->maxSizeZ) {
02240 for (i = oldsize; i <= index; i++) {
02241 unique->subtableZ[i].slots = numSlots;
02242 unique->subtableZ[i].shift = sizeof(int) * 8 -
02243 cuddComputeFloorLog2(numSlots);
02244 unique->subtableZ[i].keys = 0;
02245 unique->subtableZ[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
02246 unique->subtableZ[i].dead = 0;
02247 unique->permZ[i] = i;
02248 unique->invpermZ[i] = i;
02249 newnodelist = unique->subtableZ[i].nodelist =
02250 ALLOC(DdNodePtr, numSlots);
02251 if (newnodelist == NULL) {
02252 unique->errorCode = CUDD_MEMORY_OUT;
02253 return(0);
02254 }
02255 for (j = 0; (unsigned) j < numSlots; j++) {
02256 newnodelist[j] = NULL;
02257 }
02258 }
02259 } else {
02260
02261
02262
02263
02264 newsize = index + DD_DEFAULT_RESIZE;
02265 #ifdef DD_VERBOSE
02266 (void) fprintf(unique->err,
02267 "Increasing the ZDD table size from %d to %d\n",
02268 unique->maxSizeZ, newsize);
02269 #endif
02270 newsubtables = ALLOC(DdSubtable,newsize);
02271 if (newsubtables == NULL) {
02272 unique->errorCode = CUDD_MEMORY_OUT;
02273 return(0);
02274 }
02275 newperm = ALLOC(int,newsize);
02276 if (newperm == NULL) {
02277 unique->errorCode = CUDD_MEMORY_OUT;
02278 return(0);
02279 }
02280 newinvperm = ALLOC(int,newsize);
02281 if (newinvperm == NULL) {
02282 unique->errorCode = CUDD_MEMORY_OUT;
02283 return(0);
02284 }
02285 unique->memused += (newsize - unique->maxSizeZ) * ((numSlots+1) *
02286 sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
02287 if (newsize > unique->maxSize) {
02288 FREE(unique->stack);
02289 unique->stack = ALLOC(DdNodePtr,newsize + 1);
02290 if (unique->stack == NULL) {
02291 unique->errorCode = CUDD_MEMORY_OUT;
02292 return(0);
02293 }
02294 unique->stack[0] = NULL;
02295 unique->memused +=
02296 (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
02297 * sizeof(DdNode *);
02298 }
02299 for (i = 0; i < oldsize; i++) {
02300 newsubtables[i].slots = unique->subtableZ[i].slots;
02301 newsubtables[i].shift = unique->subtableZ[i].shift;
02302 newsubtables[i].keys = unique->subtableZ[i].keys;
02303 newsubtables[i].maxKeys = unique->subtableZ[i].maxKeys;
02304 newsubtables[i].dead = unique->subtableZ[i].dead;
02305 newsubtables[i].nodelist = unique->subtableZ[i].nodelist;
02306 newperm[i] = unique->permZ[i];
02307 newinvperm[i] = unique->invpermZ[i];
02308 }
02309 for (i = oldsize; i <= index; i++) {
02310 newsubtables[i].slots = numSlots;
02311 newsubtables[i].shift = sizeof(int) * 8 -
02312 cuddComputeFloorLog2(numSlots);
02313 newsubtables[i].keys = 0;
02314 newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
02315 newsubtables[i].dead = 0;
02316 newperm[i] = i;
02317 newinvperm[i] = i;
02318 newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
02319 if (newnodelist == NULL) {
02320 unique->errorCode = CUDD_MEMORY_OUT;
02321 return(0);
02322 }
02323 for (j = 0; (unsigned) j < numSlots; j++) {
02324 newnodelist[j] = NULL;
02325 }
02326 }
02327 FREE(unique->subtableZ);
02328 unique->subtableZ = newsubtables;
02329 unique->maxSizeZ = newsize;
02330 FREE(unique->permZ);
02331 unique->permZ = newperm;
02332 FREE(unique->invpermZ);
02333 unique->invpermZ = newinvperm;
02334 }
02335 unique->slots += (index + 1 - unique->sizeZ) * numSlots;
02336 ddFixLimits(unique);
02337 unique->sizeZ = index + 1;
02338
02339
02340
02341
02342
02343
02344 reorderSave = unique->autoDynZ;
02345 unique->autoDynZ = 0;
02346 cuddZddFreeUniv(unique);
02347 if (!cuddZddInitUniv(unique)) {
02348 unique->autoDynZ = reorderSave;
02349 return(0);
02350 }
02351 unique->autoDynZ = reorderSave;
02352
02353 return(1);
02354
02355 }
02356
02357
02369 void
02370 cuddSlowTableGrowth(
02371 DdManager *unique)
02372 {
02373 int i;
02374
02375 unique->maxCacheHard = unique->cacheSlots - 1;
02376 unique->cacheSlack = - (int) (unique->cacheSlots + 1);
02377 for (i = 0; i < unique->size; i++) {
02378 unique->subtables[i].maxKeys <<= 2;
02379 }
02380 unique->gcFrac = DD_GC_FRAC_MIN;
02381 unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
02382 cuddShrinkDeathRow(unique);
02383 (void) fprintf(unique->err,"Slowing down table growth: ");
02384 (void) fprintf(unique->err,"GC fraction = %.2f\t", unique->gcFrac);
02385 (void) fprintf(unique->err,"minDead = %u\n", unique->minDead);
02386
02387 }
02388
02389
02390
02391
02392
02393
02394
02406 static void
02407 ddRehashZdd(
02408 DdManager * unique,
02409 int i)
02410 {
02411 unsigned int slots, oldslots;
02412 int shift, oldshift;
02413 int j, pos;
02414 DdNodePtr *nodelist, *oldnodelist;
02415 DdNode *node, *next;
02416 extern DD_OOMFP MMoutOfMemory;
02417 DD_OOMFP saveHandler;
02418
02419 if (unique->slots > unique->looseUpTo) {
02420 unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
02421 #ifdef DD_VERBOSE
02422 if (unique->gcFrac == DD_GC_FRAC_HI) {
02423 (void) fprintf(unique->err,"GC fraction = %.2f\t",
02424 DD_GC_FRAC_LO);
02425 (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
02426 }
02427 #endif
02428 unique->gcFrac = DD_GC_FRAC_LO;
02429 }
02430
02431 assert(i != CUDD_MAXINDEX);
02432 oldslots = unique->subtableZ[i].slots;
02433 oldshift = unique->subtableZ[i].shift;
02434 oldnodelist = unique->subtableZ[i].nodelist;
02435
02436
02437
02438
02439 slots = oldslots;
02440 shift = oldshift;
02441 do {
02442 slots <<= 1;
02443 shift--;
02444 } while (slots * DD_MAX_SUBTABLE_DENSITY < unique->subtableZ[i].keys);
02445
02446 saveHandler = MMoutOfMemory;
02447 MMoutOfMemory = Cudd_OutOfMem;
02448 nodelist = ALLOC(DdNodePtr, slots);
02449 MMoutOfMemory = saveHandler;
02450 if (nodelist == NULL) {
02451 (void) fprintf(unique->err,
02452 "Unable to resize ZDD subtable %d for lack of memory.\n",
02453 i);
02454 (void) cuddGarbageCollect(unique,1);
02455 for (j = 0; j < unique->sizeZ; j++) {
02456 unique->subtableZ[j].maxKeys <<= 1;
02457 }
02458 return;
02459 }
02460 unique->subtableZ[i].nodelist = nodelist;
02461 unique->subtableZ[i].slots = slots;
02462 unique->subtableZ[i].shift = shift;
02463 unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
02464 for (j = 0; (unsigned) j < slots; j++) {
02465 nodelist[j] = NULL;
02466 }
02467 for (j = 0; (unsigned) j < oldslots; j++) {
02468 node = oldnodelist[j];
02469 while (node != NULL) {
02470 next = node->next;
02471 pos = ddHash(cuddT(node), cuddE(node), shift);
02472 node->next = nodelist[pos];
02473 nodelist[pos] = node;
02474 node = next;
02475 }
02476 }
02477 FREE(oldnodelist);
02478
02479 #ifdef DD_VERBOSE
02480 (void) fprintf(unique->err,
02481 "rehashing layer %d: keys %d dead %d new size %d\n",
02482 i, unique->subtableZ[i].keys,
02483 unique->subtableZ[i].dead, slots);
02484 #endif
02485
02486
02487 unique->memused += (slots - oldslots) * sizeof(DdNode *);
02488 unique->slots += (slots - oldslots);
02489 ddFixLimits(unique);
02490
02491 }
02492
02493
02507 static int
02508 ddResizeTable(
02509 DdManager * unique,
02510 int index)
02511 {
02512 DdSubtable *newsubtables;
02513 DdNodePtr *newnodelist;
02514 DdNodePtr *newvars;
02515 DdNode *sentinel = &(unique->sentinel);
02516 int oldsize,newsize;
02517 int i,j,reorderSave;
02518 int numSlots = unique->initSlots;
02519 int *newperm, *newinvperm, *newmap;
02520 DdNode *one, *zero;
02521
02522 oldsize = unique->size;
02523
02524 if (index < unique->maxSize) {
02525 for (i = oldsize; i <= index; i++) {
02526 unique->subtables[i].slots = numSlots;
02527 unique->subtables[i].shift = sizeof(int) * 8 -
02528 cuddComputeFloorLog2(numSlots);
02529 unique->subtables[i].keys = 0;
02530 unique->subtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
02531 unique->subtables[i].dead = 0;
02532 unique->subtables[i].bindVar = 0;
02533 unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
02534 unique->subtables[i].pairIndex = 0;
02535 unique->subtables[i].varHandled = 0;
02536 unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
02537
02538 unique->perm[i] = i;
02539 unique->invperm[i] = i;
02540 newnodelist = unique->subtables[i].nodelist =
02541 ALLOC(DdNodePtr, numSlots);
02542 if (newnodelist == NULL) {
02543 for (j = oldsize; j < i; j++) {
02544 FREE(unique->subtables[j].nodelist);
02545 }
02546 unique->errorCode = CUDD_MEMORY_OUT;
02547 return(0);
02548 }
02549 for (j = 0; j < numSlots; j++) {
02550 newnodelist[j] = sentinel;
02551 }
02552 }
02553 if (unique->map != NULL) {
02554 for (i = oldsize; i <= index; i++) {
02555 unique->map[i] = i;
02556 }
02557 }
02558 } else {
02559
02560
02561
02562
02563 newsize = index + DD_DEFAULT_RESIZE;
02564 #ifdef DD_VERBOSE
02565 (void) fprintf(unique->err,
02566 "Increasing the table size from %d to %d\n",
02567 unique->maxSize, newsize);
02568 #endif
02569 newsubtables = ALLOC(DdSubtable,newsize);
02570 if (newsubtables == NULL) {
02571 unique->errorCode = CUDD_MEMORY_OUT;
02572 return(0);
02573 }
02574 newvars = ALLOC(DdNodePtr,newsize);
02575 if (newvars == NULL) {
02576 FREE(newsubtables);
02577 unique->errorCode = CUDD_MEMORY_OUT;
02578 return(0);
02579 }
02580 newperm = ALLOC(int,newsize);
02581 if (newperm == NULL) {
02582 FREE(newsubtables);
02583 FREE(newvars);
02584 unique->errorCode = CUDD_MEMORY_OUT;
02585 return(0);
02586 }
02587 newinvperm = ALLOC(int,newsize);
02588 if (newinvperm == NULL) {
02589 FREE(newsubtables);
02590 FREE(newvars);
02591 FREE(newperm);
02592 unique->errorCode = CUDD_MEMORY_OUT;
02593 return(0);
02594 }
02595 if (unique->map != NULL) {
02596 newmap = ALLOC(int,newsize);
02597 if (newmap == NULL) {
02598 FREE(newsubtables);
02599 FREE(newvars);
02600 FREE(newperm);
02601 FREE(newinvperm);
02602 unique->errorCode = CUDD_MEMORY_OUT;
02603 return(0);
02604 }
02605 unique->memused += (newsize - unique->maxSize) * sizeof(int);
02606 }
02607 unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
02608 sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
02609 if (newsize > unique->maxSizeZ) {
02610 FREE(unique->stack);
02611 unique->stack = ALLOC(DdNodePtr,newsize + 1);
02612 if (unique->stack == NULL) {
02613 FREE(newsubtables);
02614 FREE(newvars);
02615 FREE(newperm);
02616 FREE(newinvperm);
02617 if (unique->map != NULL) {
02618 FREE(newmap);
02619 }
02620 unique->errorCode = CUDD_MEMORY_OUT;
02621 return(0);
02622 }
02623 unique->stack[0] = NULL;
02624 unique->memused +=
02625 (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
02626 * sizeof(DdNode *);
02627 }
02628 for (i = 0; i < oldsize; i++) {
02629 newsubtables[i].slots = unique->subtables[i].slots;
02630 newsubtables[i].shift = unique->subtables[i].shift;
02631 newsubtables[i].keys = unique->subtables[i].keys;
02632 newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
02633 newsubtables[i].dead = unique->subtables[i].dead;
02634 newsubtables[i].nodelist = unique->subtables[i].nodelist;
02635 newsubtables[i].bindVar = unique->subtables[i].bindVar;
02636 newsubtables[i].varType = unique->subtables[i].varType;
02637 newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
02638 newsubtables[i].varHandled = unique->subtables[i].varHandled;
02639 newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
02640
02641 newvars[i] = unique->vars[i];
02642 newperm[i] = unique->perm[i];
02643 newinvperm[i] = unique->invperm[i];
02644 }
02645 for (i = oldsize; i <= index; i++) {
02646 newsubtables[i].slots = numSlots;
02647 newsubtables[i].shift = sizeof(int) * 8 -
02648 cuddComputeFloorLog2(numSlots);
02649 newsubtables[i].keys = 0;
02650 newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
02651 newsubtables[i].dead = 0;
02652 newsubtables[i].bindVar = 0;
02653 newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
02654 newsubtables[i].pairIndex = 0;
02655 newsubtables[i].varHandled = 0;
02656 newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
02657
02658 newperm[i] = i;
02659 newinvperm[i] = i;
02660 newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
02661 if (newnodelist == NULL) {
02662 unique->errorCode = CUDD_MEMORY_OUT;
02663 return(0);
02664 }
02665 for (j = 0; j < numSlots; j++) {
02666 newnodelist[j] = sentinel;
02667 }
02668 }
02669 if (unique->map != NULL) {
02670 for (i = 0; i < oldsize; i++) {
02671 newmap[i] = unique->map[i];
02672 }
02673 for (i = oldsize; i <= index; i++) {
02674 newmap[i] = i;
02675 }
02676 FREE(unique->map);
02677 unique->map = newmap;
02678 }
02679 FREE(unique->subtables);
02680 unique->subtables = newsubtables;
02681 unique->maxSize = newsize;
02682 FREE(unique->vars);
02683 unique->vars = newvars;
02684 FREE(unique->perm);
02685 unique->perm = newperm;
02686 FREE(unique->invperm);
02687 unique->invperm = newinvperm;
02688 }
02689
02690
02691
02692
02693
02694 one = unique->one;
02695 zero = Cudd_Not(one);
02696
02697 unique->size = index + 1;
02698 unique->slots += (index + 1 - oldsize) * numSlots;
02699 ddFixLimits(unique);
02700
02701 reorderSave = unique->autoDyn;
02702 unique->autoDyn = 0;
02703 for (i = oldsize; i <= index; i++) {
02704 unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
02705 if (unique->vars[i] == NULL) {
02706 unique->autoDyn = reorderSave;
02707 for (j = oldsize; j < i; j++) {
02708 Cudd_IterDerefBdd(unique,unique->vars[j]);
02709 cuddDeallocNode(unique,unique->vars[j]);
02710 unique->vars[j] = NULL;
02711 }
02712 for (j = oldsize; j <= index; j++) {
02713 FREE(unique->subtables[j].nodelist);
02714 unique->subtables[j].nodelist = NULL;
02715 }
02716 unique->size = oldsize;
02717 unique->slots -= (index + 1 - oldsize) * numSlots;
02718 ddFixLimits(unique);
02719 return(0);
02720 }
02721 cuddRef(unique->vars[i]);
02722 }
02723 unique->autoDyn = reorderSave;
02724
02725 return(1);
02726
02727 }
02728
02729
02742 static int
02743 cuddFindParent(
02744 DdManager * table,
02745 DdNode * node)
02746 {
02747 int i,j;
02748 int slots;
02749 DdNodePtr *nodelist;
02750 DdNode *f;
02751
02752 for (i = cuddI(table,node->index) - 1; i >= 0; i--) {
02753 nodelist = table->subtables[i].nodelist;
02754 slots = table->subtables[i].slots;
02755
02756 for (j = 0; j < slots; j++) {
02757 f = nodelist[j];
02758 while (cuddT(f) > node) {
02759 f = f->next;
02760 }
02761 while (cuddT(f) == node && Cudd_Regular(cuddE(f)) > node) {
02762 f = f->next;
02763 }
02764 if (cuddT(f) == node && Cudd_Regular(cuddE(f)) == node) {
02765 return(1);
02766 }
02767 }
02768 }
02769
02770 return(0);
02771
02772 }
02773
02774
02788 DD_INLINE
02789 static void
02790 ddFixLimits(
02791 DdManager *unique)
02792 {
02793 unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
02794 unique->cacheSlack = (int) ddMin(unique->maxCacheHard,
02795 DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots) -
02796 2 * (int) unique->cacheSlots;
02797 if (unique->cacheSlots < unique->slots/2 && unique->cacheSlack >= 0)
02798 cuddCacheResize(unique);
02799 return;
02800
02801 }
02802
02803
02804 #ifndef DD_UNSORTED_FREE_LIST
02805 #ifdef DD_RED_BLACK_FREE_LIST
02806
02818 static void
02819 cuddOrderedInsert(
02820 DdNodePtr * root,
02821 DdNodePtr node)
02822 {
02823 DdNode *scan;
02824 DdNodePtr *scanP;
02825 DdNodePtr *stack[DD_STACK_SIZE];
02826 int stackN = 0;
02827
02828 scanP = root;
02829 while ((scan = *scanP) != NULL) {
02830 stack[stackN++] = scanP;
02831 if (DD_INSERT_COMPARE(node, scan) == 0) {
02832 DD_NEXT(node) = DD_NEXT(scan);
02833 DD_NEXT(scan) = node;
02834 return;
02835 }
02836 scanP = (node < scan) ? &DD_LEFT(scan) : &DD_RIGHT(scan);
02837 }
02838 DD_RIGHT(node) = DD_LEFT(node) = DD_NEXT(node) = NULL;
02839 DD_COLOR(node) = DD_RED;
02840 *scanP = node;
02841 stack[stackN] = &node;
02842 cuddDoRebalance(stack,stackN);
02843
02844 }
02845
02846
02867 static DdNode *
02868 cuddOrderedThread(
02869 DdNode * root,
02870 DdNode * list)
02871 {
02872 DdNode *current, *next, *prev, *end;
02873
02874 current = root;
02875
02876
02877
02878
02879 *((DdNodePtr *) current) = NULL;
02880
02881 while (current != NULL) {
02882 if (DD_RIGHT(current) != NULL) {
02883
02884
02885
02886
02887
02888
02889
02890 next = DD_RIGHT(current);
02891 DD_RIGHT(current) = NULL;
02892 *((DdNodePtr *)next) = current;
02893 current = next;
02894 } else {
02895
02896
02897
02898
02899
02900
02901 prev = *((DdNodePtr *) current);
02902
02903 for (end = current; DD_NEXT(end) != NULL; end = DD_NEXT(end));
02904 DD_NEXT(end) = list;
02905 list = current;
02906
02907
02908
02909 if (DD_LEFT(current) != NULL) {
02910 next = DD_LEFT(current);
02911 *((DdNodePtr *) next) = prev;
02912 current = next;
02913 } else {
02914 current = prev;
02915 }
02916 }
02917 }
02918
02919 return(list);
02920
02921 }
02922
02923
02935 DD_INLINE
02936 static void
02937 cuddRotateLeft(
02938 DdNodePtr * nodeP)
02939 {
02940 DdNode *newRoot;
02941 DdNode *oldRoot = *nodeP;
02942
02943 *nodeP = newRoot = DD_RIGHT(oldRoot);
02944 DD_RIGHT(oldRoot) = DD_LEFT(newRoot);
02945 DD_LEFT(newRoot) = oldRoot;
02946
02947 }
02948
02949
02961 DD_INLINE
02962 static void
02963 cuddRotateRight(
02964 DdNodePtr * nodeP)
02965 {
02966 DdNode *newRoot;
02967 DdNode *oldRoot = *nodeP;
02968
02969 *nodeP = newRoot = DD_LEFT(oldRoot);
02970 DD_LEFT(oldRoot) = DD_RIGHT(newRoot);
02971 DD_RIGHT(newRoot) = oldRoot;
02972
02973 }
02974
02975
02987 static void
02988 cuddDoRebalance(
02989 DdNodePtr ** stack,
02990 int stackN)
02991 {
02992 DdNodePtr *xP, *parentP, *grandpaP;
02993 DdNode *x, *y, *parent, *grandpa;
02994
02995 xP = stack[stackN];
02996 x = *xP;
02997
02998 while (--stackN >= 0) {
02999 parentP = stack[stackN];
03000 parent = *parentP;
03001 if (DD_IS_BLACK(parent)) break;
03002
03003 grandpaP = stack[stackN-1];
03004 grandpa = *grandpaP;
03005 if (parent == DD_LEFT(grandpa)) {
03006 y = DD_RIGHT(grandpa);
03007 if (y != NULL && DD_IS_RED(y)) {
03008 DD_COLOR(parent) = DD_BLACK;
03009 DD_COLOR(y) = DD_BLACK;
03010 DD_COLOR(grandpa) = DD_RED;
03011 x = grandpa;
03012 stackN--;
03013 } else {
03014 if (x == DD_RIGHT(parent)) {
03015 cuddRotateLeft(parentP);
03016 DD_COLOR(x) = DD_BLACK;
03017 } else {
03018 DD_COLOR(parent) = DD_BLACK;
03019 }
03020 DD_COLOR(grandpa) = DD_RED;
03021 cuddRotateRight(grandpaP);
03022 break;
03023 }
03024 } else {
03025 y = DD_LEFT(grandpa);
03026 if (y != NULL && DD_IS_RED(y)) {
03027 DD_COLOR(parent) = DD_BLACK;
03028 DD_COLOR(y) = DD_BLACK;
03029 DD_COLOR(grandpa) = DD_RED;
03030 x = grandpa;
03031 stackN--;
03032 } else {
03033 if (x == DD_LEFT(parent)) {
03034 cuddRotateRight(parentP);
03035 DD_COLOR(x) = DD_BLACK;
03036 } else {
03037 DD_COLOR(parent) = DD_BLACK;
03038 }
03039 DD_COLOR(grandpa) = DD_RED;
03040 cuddRotateLeft(grandpaP);
03041 }
03042 }
03043 }
03044 DD_COLOR(*(stack[0])) = DD_BLACK;
03045
03046 }
03047 #endif
03048 #endif
03049
03050
03064 static void
03065 ddPatchTree(
03066 DdManager *dd,
03067 MtrNode *treenode)
03068 {
03069 MtrNode *auxnode = treenode;
03070
03071 while (auxnode != NULL) {
03072 auxnode->low = dd->perm[auxnode->index];
03073 if (auxnode->child != NULL) {
03074 ddPatchTree(dd, auxnode->child);
03075 }
03076 auxnode = auxnode->younger;
03077 }
03078
03079 return;
03080
03081 }
03082
03083
03084 #ifdef DD_DEBUG
03085
03096 static int
03097 cuddCheckCollisionOrdering(
03098 DdManager *unique,
03099 int i,
03100 int j)
03101 {
03102 int slots;
03103 DdNode *node, *next;
03104 DdNodePtr *nodelist;
03105 DdNode *sentinel = &(unique->sentinel);
03106
03107 nodelist = unique->subtables[i].nodelist;
03108 slots = unique->subtables[i].slots;
03109 node = nodelist[j];
03110 if (node == sentinel) return(1);
03111 next = node->next;
03112 while (next != sentinel) {
03113 if (cuddT(node) < cuddT(next) ||
03114 (cuddT(node) == cuddT(next) && cuddE(node) < cuddE(next))) {
03115 (void) fprintf(unique->err,
03116 "Unordered list: index %u, position %d\n", i, j);
03117 return(0);
03118 }
03119 node = next;
03120 next = node->next;
03121 }
03122 return(1);
03123
03124 }
03125 #endif
03126
03127
03128
03129
03141 static void
03142 ddReportRefMess(
03143 DdManager *unique ,
03144 int i ,
03145 const char *caller )
03146 {
03147 if (i == CUDD_CONST_INDEX) {
03148 (void) fprintf(unique->err,
03149 "%s: problem in constants\n", caller);
03150 } else if (i != -1) {
03151 (void) fprintf(unique->err,
03152 "%s: problem in table %d\n", caller, i);
03153 }
03154 (void) fprintf(unique->err, " dead count != deleted\n");
03155 (void) fprintf(unique->err, " This problem is often due to a missing \
03156 call to Cudd_Ref\n or to an extra call to Cudd_RecursiveDeref.\n \
03157 See the CUDD Programmer's Guide for additional details.");
03158 abort();
03159
03160 }