emergency commit
[cl-cudd.git] / distr / cudd / cuddTable.c
blobb6b5436c92b5e59ab1361acea83dba062dc28102
1 /**CFile***********************************************************************
3 FileName [cuddTable.c]
5 PackageName [cudd]
7 Synopsis [Unique table management functions.]
9 Description [External procedures included in this module:
10 <ul>
11 <li> Cudd_Prime()
12 </ul>
13 Internal procedures included in this module:
14 <ul>
15 <li> cuddAllocNode()
16 <li> cuddInitTable()
17 <li> cuddFreeTable()
18 <li> cuddGarbageCollect()
19 <li> cuddZddGetNode()
20 <li> cuddZddGetNodeIVO()
21 <li> cuddUniqueInter()
22 <li> cuddUniqueInterIVO()
23 <li> cuddUniqueInterZdd()
24 <li> cuddUniqueConst()
25 <li> cuddRehash()
26 <li> cuddShrinkSubtable()
27 <li> cuddInsertSubtables()
28 <li> cuddDestroySubtables()
29 <li> cuddResizeTableZdd()
30 <li> cuddSlowTableGrowth()
31 </ul>
32 Static procedures included in this module:
33 <ul>
34 <li> ddRehashZdd()
35 <li> ddResizeTable()
36 <li> cuddFindParent()
37 <li> cuddOrderedInsert()
38 <li> cuddOrderedThread()
39 <li> cuddRotateLeft()
40 <li> cuddRotateRight()
41 <li> cuddDoRebalance()
42 <li> cuddCheckCollisionOrdering()
43 </ul>]
45 SeeAlso []
47 Author [Fabio Somenzi]
49 Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado
51 All rights reserved.
53 Redistribution and use in source and binary forms, with or without
54 modification, are permitted provided that the following conditions
55 are met:
57 Redistributions of source code must retain the above copyright
58 notice, this list of conditions and the following disclaimer.
60 Redistributions in binary form must reproduce the above copyright
61 notice, this list of conditions and the following disclaimer in the
62 documentation and/or other materials provided with the distribution.
64 Neither the name of the University of Colorado nor the names of its
65 contributors may be used to endorse or promote products derived from
66 this software without specific prior written permission.
68 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
69 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
70 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
71 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
72 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
73 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
74 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
75 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
76 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
77 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
78 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
79 POSSIBILITY OF SUCH DAMAGE.]
81 ******************************************************************************/
83 #include "util.h"
84 #include "cuddInt.h"
86 /*---------------------------------------------------------------------------*/
87 /* Constant declarations */
88 /*---------------------------------------------------------------------------*/
90 #ifndef DD_UNSORTED_FREE_LIST
91 #ifdef DD_RED_BLACK_FREE_LIST
92 /* Constants for red/black trees. */
93 #define DD_STACK_SIZE 128
94 #define DD_RED 0
95 #define DD_BLACK 1
96 #define DD_PAGE_SIZE 8192
97 #define DD_PAGE_MASK ~(DD_PAGE_SIZE - 1)
98 #endif
99 #endif
101 /*---------------------------------------------------------------------------*/
102 /* Stucture declarations */
103 /*---------------------------------------------------------------------------*/
105 /* This is a hack for when CUDD_VALUE_TYPE is double */
106 typedef union hack {
107 CUDD_VALUE_TYPE value;
108 unsigned int bits[2];
109 } hack;
111 /*---------------------------------------------------------------------------*/
112 /* Type declarations */
113 /*---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------*/
116 /* Variable declarations */
117 /*---------------------------------------------------------------------------*/
119 #ifndef lint
120 static char rcsid[] DD_UNUSED = "$Id: cuddTable.c,v 1.122 2009/02/19 16:24:28 fabio Exp $";
121 #endif
123 /*---------------------------------------------------------------------------*/
124 /* Macro declarations */
125 /*---------------------------------------------------------------------------*/
128 #ifndef DD_UNSORTED_FREE_LIST
129 #ifdef DD_RED_BLACK_FREE_LIST
130 /* Macros for red/black trees. */
131 #define DD_INSERT_COMPARE(x,y) \
132 (((ptruint) (x) & DD_PAGE_MASK) - ((ptruint) (y) & DD_PAGE_MASK))
133 #define DD_COLOR(p) ((p)->index)
134 #define DD_IS_BLACK(p) ((p)->index == DD_BLACK)
135 #define DD_IS_RED(p) ((p)->index == DD_RED)
136 #define DD_LEFT(p) cuddT(p)
137 #define DD_RIGHT(p) cuddE(p)
138 #define DD_NEXT(p) ((p)->next)
139 #endif
140 #endif
143 /**AutomaticStart*************************************************************/
145 /*---------------------------------------------------------------------------*/
146 /* Static function prototypes */
147 /*---------------------------------------------------------------------------*/
149 static void ddRehashZdd (DdManager *unique, int i);
150 static int ddResizeTable (DdManager *unique, int index);
151 static int cuddFindParent (DdManager *table, DdNode *node);
152 DD_INLINE static void ddFixLimits (DdManager *unique);
153 #ifdef DD_RED_BLACK_FREE_LIST
154 static void cuddOrderedInsert (DdNodePtr *root, DdNodePtr node);
155 static DdNode * cuddOrderedThread (DdNode *root, DdNode *list);
156 static void cuddRotateLeft (DdNodePtr *nodeP);
157 static void cuddRotateRight (DdNodePtr *nodeP);
158 static void cuddDoRebalance (DdNodePtr **stack, int stackN);
159 #endif
160 static void ddPatchTree (DdManager *dd, MtrNode *treenode);
161 #ifdef DD_DEBUG
162 static int cuddCheckCollisionOrdering (DdManager *unique, int i, int j);
163 #endif
164 static void ddReportRefMess (DdManager *unique, int i, const char *caller);
166 /**AutomaticEnd***************************************************************/
169 /*---------------------------------------------------------------------------*/
170 /* Definition of exported functions */
171 /*---------------------------------------------------------------------------*/
174 /**Function********************************************************************
176 Synopsis [Returns the next prime &gt;= p.]
178 Description []
180 SideEffects [None]
182 ******************************************************************************/
183 unsigned int
184 Cudd_Prime(
185 unsigned int p)
187 int i,pn;
189 p--;
190 do {
191 p++;
192 if (p&1) {
193 pn = 1;
194 i = 3;
195 while ((unsigned) (i * i) <= p) {
196 if (p % i == 0) {
197 pn = 0;
198 break;
200 i += 2;
202 } else {
203 pn = 0;
205 } while (!pn);
206 return(p);
208 } /* end of Cudd_Prime */
211 /*---------------------------------------------------------------------------*/
212 /* Definition of internal functions */
213 /*---------------------------------------------------------------------------*/
216 /**Function********************************************************************
218 Synopsis [Fast storage allocation for DdNodes in the table.]
220 Description [Fast storage allocation for DdNodes in the table. The
221 first 4 bytes of a chunk contain a pointer to the next block; the
222 rest contains DD_MEM_CHUNK spaces for DdNodes. Returns a pointer to
223 a new node if successful; NULL is memory is full.]
225 SideEffects [None]
227 SeeAlso [cuddDynamicAllocNode]
229 ******************************************************************************/
230 DdNode *
231 cuddAllocNode(
232 DdManager * unique)
234 int i;
235 DdNodePtr *mem;
236 DdNode *list, *node;
237 extern DD_OOMFP MMoutOfMemory;
238 DD_OOMFP saveHandler;
240 if (unique->nextFree == NULL) { /* free list is empty */
241 /* Check for exceeded limits. */
242 if ((unique->keys - unique->dead) + (unique->keysZ - unique->deadZ) >
243 unique->maxLive) {
244 unique->errorCode = CUDD_TOO_MANY_NODES;
245 return(NULL);
247 if (unique->stash == NULL || unique->memused > unique->maxmemhard) {
248 (void) cuddGarbageCollect(unique,1);
249 mem = NULL;
251 if (unique->nextFree == NULL) {
252 if (unique->memused > unique->maxmemhard) {
253 unique->errorCode = CUDD_MAX_MEM_EXCEEDED;
254 return(NULL);
256 /* Try to allocate a new block. */
257 saveHandler = MMoutOfMemory;
258 MMoutOfMemory = Cudd_OutOfMem;
259 mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
260 MMoutOfMemory = saveHandler;
261 if (mem == NULL) {
262 /* No more memory: Try collecting garbage. If this succeeds,
263 ** we end up with mem still NULL, but unique->nextFree !=
264 ** NULL. */
265 if (cuddGarbageCollect(unique,1) == 0) {
266 /* Last resort: Free the memory stashed away, if there
267 ** any. If this succeeeds, mem != NULL and
268 ** unique->nextFree still NULL. */
269 if (unique->stash != NULL) {
270 FREE(unique->stash);
271 unique->stash = NULL;
272 /* Inhibit resizing of tables. */
273 cuddSlowTableGrowth(unique);
274 /* Now try again. */
275 mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
277 if (mem == NULL) {
278 /* Out of luck. Call the default handler to do
279 ** whatever it specifies for a failed malloc.
280 ** If this handler returns, then set error code,
281 ** print warning, and return. */
282 (*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1));
283 unique->errorCode = CUDD_MEMORY_OUT;
284 #ifdef DD_VERBOSE
285 (void) fprintf(unique->err,
286 "cuddAllocNode: out of memory");
287 (void) fprintf(unique->err, "Memory in use = %lu\n",
288 unique->memused);
289 #endif
290 return(NULL);
294 if (mem != NULL) { /* successful allocation; slice memory */
295 ptruint offset;
296 unique->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode);
297 mem[0] = (DdNodePtr) unique->memoryList;
298 unique->memoryList = mem;
300 /* Here we rely on the fact that a DdNode is as large
301 ** as 4 pointers. */
302 offset = (ptruint) mem & (sizeof(DdNode) - 1);
303 mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
304 assert(((ptruint) mem & (sizeof(DdNode) - 1)) == 0);
305 list = (DdNode *) mem;
307 i = 1;
308 do {
309 list[i - 1].ref = 0;
310 list[i - 1].next = &list[i];
311 } while (++i < DD_MEM_CHUNK);
313 list[DD_MEM_CHUNK-1].ref = 0;
314 list[DD_MEM_CHUNK-1].next = NULL;
316 unique->nextFree = &list[0];
320 unique->allocated++;
321 node = unique->nextFree;
322 unique->nextFree = node->next;
323 return(node);
325 } /* end of cuddAllocNode */
328 /**Function********************************************************************
330 Synopsis [Creates and initializes the unique table.]
332 Description [Creates and initializes the unique table. Returns a pointer
333 to the table if successful; NULL otherwise.]
335 SideEffects [None]
337 SeeAlso [Cudd_Init cuddFreeTable]
339 ******************************************************************************/
340 DdManager *
341 cuddInitTable(
342 unsigned int numVars /* Initial number of BDD variables (and subtables) */,
343 unsigned int numVarsZ /* Initial number of ZDD variables (and subtables) */,
344 unsigned int numSlots /* Initial size of the BDD subtables */,
345 unsigned int looseUpTo /* Limit for fast table growth */)
347 DdManager *unique = ALLOC(DdManager,1);
348 int i, j;
349 DdNodePtr *nodelist;
350 DdNode *sentinel;
351 unsigned int slots;
352 int shift;
354 if (unique == NULL) {
355 return(NULL);
357 sentinel = &(unique->sentinel);
358 sentinel->ref = 0;
359 sentinel->index = 0;
360 cuddT(sentinel) = NULL;
361 cuddE(sentinel) = NULL;
362 sentinel->next = NULL;
363 unique->epsilon = DD_EPSILON;
364 unique->maxGrowth = DD_MAX_REORDER_GROWTH;
365 unique->maxGrowthAlt = 2.0 * DD_MAX_REORDER_GROWTH;
366 unique->reordCycle = 0; /* do not use alternate threshold */
367 unique->size = numVars;
368 unique->sizeZ = numVarsZ;
369 unique->maxSize = ddMax(DD_DEFAULT_RESIZE, numVars);
370 unique->maxSizeZ = ddMax(DD_DEFAULT_RESIZE, numVarsZ);
372 /* Adjust the requested number of slots to a power of 2. */
373 slots = 8;
374 while (slots < numSlots) {
375 slots <<= 1;
377 unique->initSlots = slots;
378 shift = sizeof(int) * 8 - cuddComputeFloorLog2(slots);
380 unique->slots = (numVars + numVarsZ + 1) * slots;
381 unique->keys = 0;
382 unique->maxLive = ~0; /* very large number */
383 unique->keysZ = 0;
384 unique->dead = 0;
385 unique->deadZ = 0;
386 unique->gcFrac = DD_GC_FRAC_HI;
387 unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
388 unique->looseUpTo = looseUpTo;
389 unique->gcEnabled = 1;
390 unique->allocated = 0;
391 unique->reclaimed = 0;
392 unique->subtables = ALLOC(DdSubtable,unique->maxSize);
393 if (unique->subtables == NULL) {
394 FREE(unique);
395 return(NULL);
397 unique->subtableZ = ALLOC(DdSubtable,unique->maxSizeZ);
398 if (unique->subtableZ == NULL) {
399 FREE(unique->subtables);
400 FREE(unique);
401 return(NULL);
403 unique->perm = ALLOC(int,unique->maxSize);
404 if (unique->perm == NULL) {
405 FREE(unique->subtables);
406 FREE(unique->subtableZ);
407 FREE(unique);
408 return(NULL);
410 unique->invperm = ALLOC(int,unique->maxSize);
411 if (unique->invperm == NULL) {
412 FREE(unique->subtables);
413 FREE(unique->subtableZ);
414 FREE(unique->perm);
415 FREE(unique);
416 return(NULL);
418 unique->permZ = ALLOC(int,unique->maxSizeZ);
419 if (unique->permZ == NULL) {
420 FREE(unique->subtables);
421 FREE(unique->subtableZ);
422 FREE(unique->perm);
423 FREE(unique->invperm);
424 FREE(unique);
425 return(NULL);
427 unique->invpermZ = ALLOC(int,unique->maxSizeZ);
428 if (unique->invpermZ == NULL) {
429 FREE(unique->subtables);
430 FREE(unique->subtableZ);
431 FREE(unique->perm);
432 FREE(unique->invperm);
433 FREE(unique->permZ);
434 FREE(unique);
435 return(NULL);
437 unique->map = NULL;
438 unique->stack = ALLOC(DdNodePtr,ddMax(unique->maxSize,unique->maxSizeZ)+1);
439 if (unique->stack == NULL) {
440 FREE(unique->subtables);
441 FREE(unique->subtableZ);
442 FREE(unique->perm);
443 FREE(unique->invperm);
444 FREE(unique->permZ);
445 FREE(unique->invpermZ);
446 FREE(unique);
447 return(NULL);
449 unique->stack[0] = NULL; /* to suppress harmless UMR */
451 #ifndef DD_NO_DEATH_ROW
452 unique->deathRowDepth = 1 << cuddComputeFloorLog2(unique->looseUpTo >> 2);
453 unique->deathRow = ALLOC(DdNodePtr,unique->deathRowDepth);
454 if (unique->deathRow == NULL) {
455 FREE(unique->subtables);
456 FREE(unique->subtableZ);
457 FREE(unique->perm);
458 FREE(unique->invperm);
459 FREE(unique->permZ);
460 FREE(unique->invpermZ);
461 FREE(unique->stack);
462 FREE(unique);
463 return(NULL);
465 for (i = 0; i < unique->deathRowDepth; i++) {
466 unique->deathRow[i] = NULL;
468 unique->nextDead = 0;
469 unique->deadMask = unique->deathRowDepth - 1;
470 #endif
472 for (i = 0; (unsigned) i < numVars; i++) {
473 unique->subtables[i].slots = slots;
474 unique->subtables[i].shift = shift;
475 unique->subtables[i].keys = 0;
476 unique->subtables[i].dead = 0;
477 unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
478 unique->subtables[i].bindVar = 0;
479 unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
480 unique->subtables[i].pairIndex = 0;
481 unique->subtables[i].varHandled = 0;
482 unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
484 nodelist = unique->subtables[i].nodelist = ALLOC(DdNodePtr,slots);
485 if (nodelist == NULL) {
486 for (j = 0; j < i; j++) {
487 FREE(unique->subtables[j].nodelist);
489 FREE(unique->subtables);
490 FREE(unique->subtableZ);
491 FREE(unique->perm);
492 FREE(unique->invperm);
493 FREE(unique->permZ);
494 FREE(unique->invpermZ);
495 FREE(unique->stack);
496 FREE(unique);
497 return(NULL);
499 for (j = 0; (unsigned) j < slots; j++) {
500 nodelist[j] = sentinel;
502 unique->perm[i] = i;
503 unique->invperm[i] = i;
505 for (i = 0; (unsigned) i < numVarsZ; i++) {
506 unique->subtableZ[i].slots = slots;
507 unique->subtableZ[i].shift = shift;
508 unique->subtableZ[i].keys = 0;
509 unique->subtableZ[i].dead = 0;
510 unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
511 nodelist = unique->subtableZ[i].nodelist = ALLOC(DdNodePtr,slots);
512 if (nodelist == NULL) {
513 for (j = 0; (unsigned) j < numVars; j++) {
514 FREE(unique->subtables[j].nodelist);
516 FREE(unique->subtables);
517 for (j = 0; j < i; j++) {
518 FREE(unique->subtableZ[j].nodelist);
520 FREE(unique->subtableZ);
521 FREE(unique->perm);
522 FREE(unique->invperm);
523 FREE(unique->permZ);
524 FREE(unique->invpermZ);
525 FREE(unique->stack);
526 FREE(unique);
527 return(NULL);
529 for (j = 0; (unsigned) j < slots; j++) {
530 nodelist[j] = NULL;
532 unique->permZ[i] = i;
533 unique->invpermZ[i] = i;
535 unique->constants.slots = slots;
536 unique->constants.shift = shift;
537 unique->constants.keys = 0;
538 unique->constants.dead = 0;
539 unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
540 nodelist = unique->constants.nodelist = ALLOC(DdNodePtr,slots);
541 if (nodelist == NULL) {
542 for (j = 0; (unsigned) j < numVars; j++) {
543 FREE(unique->subtables[j].nodelist);
545 FREE(unique->subtables);
546 for (j = 0; (unsigned) j < numVarsZ; j++) {
547 FREE(unique->subtableZ[j].nodelist);
549 FREE(unique->subtableZ);
550 FREE(unique->perm);
551 FREE(unique->invperm);
552 FREE(unique->permZ);
553 FREE(unique->invpermZ);
554 FREE(unique->stack);
555 FREE(unique);
556 return(NULL);
558 for (j = 0; (unsigned) j < slots; j++) {
559 nodelist[j] = NULL;
562 unique->memoryList = NULL;
563 unique->nextFree = NULL;
565 unique->memused = sizeof(DdManager) + (unique->maxSize + unique->maxSizeZ)
566 * (sizeof(DdSubtable) + 2 * sizeof(int)) + (numVars + 1) *
567 slots * sizeof(DdNodePtr) +
568 (ddMax(unique->maxSize,unique->maxSizeZ) + 1) * sizeof(DdNodePtr);
569 #ifndef DD_NO_DEATH_ROW
570 unique->memused += unique->deathRowDepth * sizeof(DdNodePtr);
571 #endif
573 /* Initialize fields concerned with automatic dynamic reordering */
574 unique->reorderings = 0;
575 unique->autoDyn = 0; /* initially disabled */
576 unique->autoDynZ = 0; /* initially disabled */
577 unique->realign = 0; /* initially disabled */
578 unique->realignZ = 0; /* initially disabled */
579 unique->reordered = 0;
580 unique->autoMethod = CUDD_REORDER_SIFT;
581 unique->autoMethodZ = CUDD_REORDER_SIFT;
582 unique->nextDyn = DD_FIRST_REORDER;
583 unique->countDead = ~0;
584 unique->siftMaxVar = DD_SIFT_MAX_VAR;
585 unique->siftMaxSwap = DD_SIFT_MAX_SWAPS;
586 unique->tree = NULL;
587 unique->treeZ = NULL;
588 unique->groupcheck = CUDD_GROUP_CHECK7;
589 unique->recomb = DD_DEFAULT_RECOMB;
590 unique->symmviolation = 0;
591 unique->arcviolation = 0;
592 unique->populationSize = 0;
593 unique->numberXovers = 0;
594 unique->linear = NULL;
595 unique->linearSize = 0;
597 /* Initialize ZDD universe. */
598 unique->univ = (DdNodePtr *)NULL;
600 /* Initialize auxiliary fields. */
601 unique->localCaches = NULL;
602 unique->preGCHook = NULL;
603 unique->postGCHook = NULL;
604 unique->preReorderingHook = NULL;
605 unique->postReorderingHook = NULL;
606 unique->out = stdout;
607 unique->err = stderr;
608 unique->errorCode = CUDD_NO_ERROR;
610 /* Initialize statistical counters. */
611 unique->maxmemhard = ~ 0UL;
612 unique->garbageCollections = 0;
613 unique->GCTime = 0;
614 unique->reordTime = 0;
615 #ifdef DD_STATS
616 unique->nodesDropped = 0;
617 unique->nodesFreed = 0;
618 #endif
619 unique->peakLiveNodes = 0;
620 #ifdef DD_UNIQUE_PROFILE
621 unique->uniqueLookUps = 0;
622 unique->uniqueLinks = 0;
623 #endif
624 #ifdef DD_COUNT
625 unique->recursiveCalls = 0;
626 unique->swapSteps = 0;
627 #ifdef DD_STATS
628 unique->nextSample = 250000;
629 #endif
630 #endif
632 return(unique);
634 } /* end of cuddInitTable */
637 /**Function********************************************************************
639 Synopsis [Frees the resources associated to a unique table.]
641 Description []
643 SideEffects [None]
645 SeeAlso [cuddInitTable]
647 ******************************************************************************/
648 void
649 cuddFreeTable(
650 DdManager * unique)
652 DdNodePtr *next;
653 DdNodePtr *memlist = unique->memoryList;
654 int i;
656 if (unique->univ != NULL) cuddZddFreeUniv(unique);
657 while (memlist != NULL) {
658 next = (DdNodePtr *) memlist[0]; /* link to next block */
659 FREE(memlist);
660 memlist = next;
662 unique->nextFree = NULL;
663 unique->memoryList = NULL;
665 for (i = 0; i < unique->size; i++) {
666 FREE(unique->subtables[i].nodelist);
668 for (i = 0; i < unique->sizeZ; i++) {
669 FREE(unique->subtableZ[i].nodelist);
671 FREE(unique->constants.nodelist);
672 FREE(unique->subtables);
673 FREE(unique->subtableZ);
674 FREE(unique->acache);
675 FREE(unique->perm);
676 FREE(unique->permZ);
677 FREE(unique->invperm);
678 FREE(unique->invpermZ);
679 FREE(unique->vars);
680 if (unique->map != NULL) FREE(unique->map);
681 FREE(unique->stack);
682 #ifndef DD_NO_DEATH_ROW
683 FREE(unique->deathRow);
684 #endif
685 if (unique->tree != NULL) Mtr_FreeTree(unique->tree);
686 if (unique->treeZ != NULL) Mtr_FreeTree(unique->treeZ);
687 if (unique->linear != NULL) FREE(unique->linear);
688 while (unique->preGCHook != NULL)
689 Cudd_RemoveHook(unique,unique->preGCHook->f,CUDD_PRE_GC_HOOK);
690 while (unique->postGCHook != NULL)
691 Cudd_RemoveHook(unique,unique->postGCHook->f,CUDD_POST_GC_HOOK);
692 while (unique->preReorderingHook != NULL)
693 Cudd_RemoveHook(unique,unique->preReorderingHook->f,
694 CUDD_PRE_REORDERING_HOOK);
695 while (unique->postReorderingHook != NULL)
696 Cudd_RemoveHook(unique,unique->postReorderingHook->f,
697 CUDD_POST_REORDERING_HOOK);
698 FREE(unique);
700 } /* end of cuddFreeTable */
703 /**Function********************************************************************
705 Synopsis [Performs garbage collection on the unique tables.]
707 Description [Performs garbage collection on the BDD and ZDD unique tables.
708 If clearCache is 0, the cache is not cleared. This should only be
709 specified if the cache has been cleared right before calling
710 cuddGarbageCollect. (As in the case of dynamic reordering.)
711 Returns the total number of deleted nodes.]
713 SideEffects [None]
715 SeeAlso []
717 ******************************************************************************/
719 cuddGarbageCollect(
720 DdManager * unique,
721 int clearCache)
723 DdHook *hook;
724 DdCache *cache = unique->cache;
725 DdNode *sentinel = &(unique->sentinel);
726 DdNodePtr *nodelist;
727 int i, j, deleted, totalDeleted, totalDeletedZ;
728 DdCache *c;
729 DdNode *node,*next;
730 DdNodePtr *lastP;
731 int slots;
732 long localTime;
733 #ifndef DD_UNSORTED_FREE_LIST
734 #ifdef DD_RED_BLACK_FREE_LIST
735 DdNodePtr tree;
736 #else
737 DdNodePtr *memListTrav, *nxtNode;
738 DdNode *downTrav, *sentry;
739 int k;
740 #endif
741 #endif
743 #ifndef DD_NO_DEATH_ROW
744 cuddClearDeathRow(unique);
745 #endif
747 hook = unique->preGCHook;
748 while (hook != NULL) {
749 int res = (hook->f)(unique,"DD",NULL);
750 if (res == 0) return(0);
751 hook = hook->next;
754 if (unique->dead + unique->deadZ == 0) {
755 hook = unique->postGCHook;
756 while (hook != NULL) {
757 int res = (hook->f)(unique,"DD",NULL);
758 if (res == 0) return(0);
759 hook = hook->next;
761 return(0);
764 /* If many nodes are being reclaimed, we want to resize the tables
765 ** more aggressively, to reduce the frequency of garbage collection.
767 if (clearCache && unique->gcFrac == DD_GC_FRAC_LO &&
768 unique->slots <= unique->looseUpTo && unique->stash != NULL) {
769 unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
770 #ifdef DD_VERBOSE
771 (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_HI);
772 (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
773 #endif
774 unique->gcFrac = DD_GC_FRAC_HI;
775 return(0);
778 localTime = util_cpu_time();
780 unique->garbageCollections++;
781 #ifdef DD_VERBOSE
782 (void) fprintf(unique->err,
783 "garbage collecting (%d dead BDD nodes out of %d, min %d)...",
784 unique->dead, unique->keys, unique->minDead);
785 (void) fprintf(unique->err,
786 " (%d dead ZDD nodes out of %d)...",
787 unique->deadZ, unique->keysZ);
788 #endif
790 /* Remove references to garbage collected nodes from the cache. */
791 if (clearCache) {
792 slots = unique->cacheSlots;
793 for (i = 0; i < slots; i++) {
794 c = &cache[i];
795 if (c->data != NULL) {
796 if (cuddClean(c->f)->ref == 0 ||
797 cuddClean(c->g)->ref == 0 ||
798 (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) ||
799 (c->data != DD_NON_CONSTANT &&
800 Cudd_Regular(c->data)->ref == 0)) {
801 c->data = NULL;
802 unique->cachedeletions++;
806 cuddLocalCacheClearDead(unique);
809 /* Now return dead nodes to free list. Count them for sanity check. */
810 totalDeleted = 0;
811 #ifndef DD_UNSORTED_FREE_LIST
812 #ifdef DD_RED_BLACK_FREE_LIST
813 tree = NULL;
814 #endif
815 #endif
817 for (i = 0; i < unique->size; i++) {
818 if (unique->subtables[i].dead == 0) continue;
819 nodelist = unique->subtables[i].nodelist;
821 deleted = 0;
822 slots = unique->subtables[i].slots;
823 for (j = 0; j < slots; j++) {
824 lastP = &(nodelist[j]);
825 node = *lastP;
826 while (node != sentinel) {
827 next = node->next;
828 if (node->ref == 0) {
829 deleted++;
830 #ifndef DD_UNSORTED_FREE_LIST
831 #ifdef DD_RED_BLACK_FREE_LIST
832 #ifdef __osf__
833 #pragma pointer_size save
834 #pragma pointer_size short
835 #endif
836 cuddOrderedInsert(&tree,node);
837 #ifdef __osf__
838 #pragma pointer_size restore
839 #endif
840 #endif
841 #else
842 cuddDeallocNode(unique,node);
843 #endif
844 } else {
845 *lastP = node;
846 lastP = &(node->next);
848 node = next;
850 *lastP = sentinel;
852 if ((unsigned) deleted != unique->subtables[i].dead) {
853 ddReportRefMess(unique, i, "cuddGarbageCollect");
855 totalDeleted += deleted;
856 unique->subtables[i].keys -= deleted;
857 unique->subtables[i].dead = 0;
859 if (unique->constants.dead != 0) {
860 nodelist = unique->constants.nodelist;
861 deleted = 0;
862 slots = unique->constants.slots;
863 for (j = 0; j < slots; j++) {
864 lastP = &(nodelist[j]);
865 node = *lastP;
866 while (node != NULL) {
867 next = node->next;
868 if (node->ref == 0) {
869 deleted++;
870 #ifndef DD_UNSORTED_FREE_LIST
871 #ifdef DD_RED_BLACK_FREE_LIST
872 #ifdef __osf__
873 #pragma pointer_size save
874 #pragma pointer_size short
875 #endif
876 cuddOrderedInsert(&tree,node);
877 #ifdef __osf__
878 #pragma pointer_size restore
879 #endif
880 #endif
881 #else
882 cuddDeallocNode(unique,node);
883 #endif
884 } else {
885 *lastP = node;
886 lastP = &(node->next);
888 node = next;
890 *lastP = NULL;
892 if ((unsigned) deleted != unique->constants.dead) {
893 ddReportRefMess(unique, CUDD_CONST_INDEX, "cuddGarbageCollect");
895 totalDeleted += deleted;
896 unique->constants.keys -= deleted;
897 unique->constants.dead = 0;
899 if ((unsigned) totalDeleted != unique->dead) {
900 ddReportRefMess(unique, -1, "cuddGarbageCollect");
902 unique->keys -= totalDeleted;
903 unique->dead = 0;
904 #ifdef DD_STATS
905 unique->nodesFreed += (double) totalDeleted;
906 #endif
908 totalDeletedZ = 0;
910 for (i = 0; i < unique->sizeZ; i++) {
911 if (unique->subtableZ[i].dead == 0) continue;
912 nodelist = unique->subtableZ[i].nodelist;
914 deleted = 0;
915 slots = unique->subtableZ[i].slots;
916 for (j = 0; j < slots; j++) {
917 lastP = &(nodelist[j]);
918 node = *lastP;
919 while (node != NULL) {
920 next = node->next;
921 if (node->ref == 0) {
922 deleted++;
923 #ifndef DD_UNSORTED_FREE_LIST
924 #ifdef DD_RED_BLACK_FREE_LIST
925 #ifdef __osf__
926 #pragma pointer_size save
927 #pragma pointer_size short
928 #endif
929 cuddOrderedInsert(&tree,node);
930 #ifdef __osf__
931 #pragma pointer_size restore
932 #endif
933 #endif
934 #else
935 cuddDeallocNode(unique,node);
936 #endif
937 } else {
938 *lastP = node;
939 lastP = &(node->next);
941 node = next;
943 *lastP = NULL;
945 if ((unsigned) deleted != unique->subtableZ[i].dead) {
946 ddReportRefMess(unique, i, "cuddGarbageCollect");
948 totalDeletedZ += deleted;
949 unique->subtableZ[i].keys -= deleted;
950 unique->subtableZ[i].dead = 0;
953 /* No need to examine the constant table for ZDDs.
954 ** If we did we should be careful not to count whatever dead
955 ** nodes we found there among the dead ZDD nodes. */
956 if ((unsigned) totalDeletedZ != unique->deadZ) {
957 ddReportRefMess(unique, -1, "cuddGarbageCollect");
959 unique->keysZ -= totalDeletedZ;
960 unique->deadZ = 0;
961 #ifdef DD_STATS
962 unique->nodesFreed += (double) totalDeletedZ;
963 #endif
966 #ifndef DD_UNSORTED_FREE_LIST
967 #ifdef DD_RED_BLACK_FREE_LIST
968 unique->nextFree = cuddOrderedThread(tree,unique->nextFree);
969 #else
970 memListTrav = unique->memoryList;
971 sentry = NULL;
972 while (memListTrav != NULL) {
973 ptruint offset;
974 nxtNode = (DdNodePtr *)memListTrav[0];
975 offset = (ptruint) memListTrav & (sizeof(DdNode) - 1);
976 memListTrav += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
977 downTrav = (DdNode *)memListTrav;
978 k = 0;
979 do {
980 if (downTrav[k].ref == 0) {
981 if (sentry == NULL) {
982 unique->nextFree = sentry = &downTrav[k];
983 } else {
984 /* First hook sentry->next to the dead node and then
985 ** reassign sentry to the dead node. */
986 sentry = (sentry->next = &downTrav[k]);
989 } while (++k < DD_MEM_CHUNK);
990 memListTrav = nxtNode;
992 sentry->next = NULL;
993 #endif
994 #endif
996 unique->GCTime += util_cpu_time() - localTime;
998 hook = unique->postGCHook;
999 while (hook != NULL) {
1000 int res = (hook->f)(unique,"DD",NULL);
1001 if (res == 0) return(0);
1002 hook = hook->next;
1005 #ifdef DD_VERBOSE
1006 (void) fprintf(unique->err," done\n");
1007 #endif
1009 return(totalDeleted+totalDeletedZ);
1011 } /* end of cuddGarbageCollect */
1014 /**Function********************************************************************
1016 Synopsis [Wrapper for cuddUniqueInterZdd.]
1018 Description [Wrapper for cuddUniqueInterZdd, which applies the ZDD
1019 reduction rule. Returns a pointer to the result node under normal
1020 conditions; NULL if reordering occurred or memory was exhausted.]
1022 SideEffects [None]
1024 SeeAlso [cuddUniqueInterZdd]
1026 ******************************************************************************/
1027 DdNode *
1028 cuddZddGetNode(
1029 DdManager * zdd,
1030 int id,
1031 DdNode * T,
1032 DdNode * E)
1034 DdNode *node;
1036 if (T == DD_ZERO(zdd))
1037 return(E);
1038 node = cuddUniqueInterZdd(zdd, id, T, E);
1039 return(node);
1041 } /* end of cuddZddGetNode */
1044 /**Function********************************************************************
1046 Synopsis [Wrapper for cuddUniqueInterZdd that is independent of variable
1047 ordering.]
1049 Description [Wrapper for cuddUniqueInterZdd that is independent of
1050 variable ordering (IVO). This function does not require parameter
1051 index to precede the indices of the top nodes of g and h in the
1052 variable order. Returns a pointer to the result node under normal
1053 conditions; NULL if reordering occurred or memory was exhausted.]
1055 SideEffects [None]
1057 SeeAlso [cuddZddGetNode cuddZddIsop]
1059 ******************************************************************************/
1060 DdNode *
1061 cuddZddGetNodeIVO(
1062 DdManager * dd,
1063 int index,
1064 DdNode * g,
1065 DdNode * h)
1067 DdNode *f, *r, *t;
1068 DdNode *zdd_one = DD_ONE(dd);
1069 DdNode *zdd_zero = DD_ZERO(dd);
1071 f = cuddUniqueInterZdd(dd, index, zdd_one, zdd_zero);
1072 if (f == NULL) {
1073 return(NULL);
1075 cuddRef(f);
1076 t = cuddZddProduct(dd, f, g);
1077 if (t == NULL) {
1078 Cudd_RecursiveDerefZdd(dd, f);
1079 return(NULL);
1081 cuddRef(t);
1082 Cudd_RecursiveDerefZdd(dd, f);
1083 r = cuddZddUnion(dd, t, h);
1084 if (r == NULL) {
1085 Cudd_RecursiveDerefZdd(dd, t);
1086 return(NULL);
1088 cuddRef(r);
1089 Cudd_RecursiveDerefZdd(dd, t);
1091 cuddDeref(r);
1092 return(r);
1094 } /* end of cuddZddGetNodeIVO */
1097 /**Function********************************************************************
1099 Synopsis [Checks the unique table for the existence of an internal node.]
1101 Description [Checks the unique table for the existence of an internal
1102 node. If it does not exist, it creates a new one. Does not
1103 modify the reference count of whatever is returned. A newly created
1104 internal node comes back with a reference count 0. For a newly
1105 created node, increments the reference counts of what T and E point
1106 to. Returns a pointer to the new node if successful; NULL if memory
1107 is exhausted or if reordering took place.]
1109 SideEffects [None]
1111 SeeAlso [cuddUniqueInterZdd]
1113 ******************************************************************************/
1114 DdNode *
1115 cuddUniqueInter(
1116 DdManager * unique,
1117 int index,
1118 DdNode * T,
1119 DdNode * E)
1121 int pos;
1122 unsigned int level;
1123 int retval;
1124 DdNodePtr *nodelist;
1125 DdNode *looking;
1126 DdNodePtr *previousP;
1127 DdSubtable *subtable;
1128 int gcNumber;
1130 #ifdef DD_UNIQUE_PROFILE
1131 unique->uniqueLookUps++;
1132 #endif
1134 if (index >= unique->size) {
1135 if (!ddResizeTable(unique,index)) return(NULL);
1138 level = unique->perm[index];
1139 subtable = &(unique->subtables[level]);
1141 #ifdef DD_DEBUG
1142 assert(level < (unsigned) cuddI(unique,T->index));
1143 assert(level < (unsigned) cuddI(unique,Cudd_Regular(E)->index));
1144 #endif
1146 pos = ddHash(T, E, subtable->shift);
1147 nodelist = subtable->nodelist;
1148 previousP = &(nodelist[pos]);
1149 looking = *previousP;
1151 while (T < cuddT(looking)) {
1152 previousP = &(looking->next);
1153 looking = *previousP;
1154 #ifdef DD_UNIQUE_PROFILE
1155 unique->uniqueLinks++;
1156 #endif
1158 while (T == cuddT(looking) && E < cuddE(looking)) {
1159 previousP = &(looking->next);
1160 looking = *previousP;
1161 #ifdef DD_UNIQUE_PROFILE
1162 unique->uniqueLinks++;
1163 #endif
1165 if (T == cuddT(looking) && E == cuddE(looking)) {
1166 if (looking->ref == 0) {
1167 cuddReclaim(unique,looking);
1169 return(looking);
1172 /* countDead is 0 if deads should be counted and ~0 if they should not. */
1173 if (unique->autoDyn &&
1174 unique->keys - (unique->dead & unique->countDead) >= unique->nextDyn) {
1175 #ifdef DD_DEBUG
1176 retval = Cudd_DebugCheck(unique);
1177 if (retval != 0) return(NULL);
1178 retval = Cudd_CheckKeys(unique);
1179 if (retval != 0) return(NULL);
1180 #endif
1181 retval = Cudd_ReduceHeap(unique,unique->autoMethod,10); /* 10 = whatever */
1182 if (retval == 0) unique->reordered = 2;
1183 #ifdef DD_DEBUG
1184 retval = Cudd_DebugCheck(unique);
1185 if (retval != 0) unique->reordered = 2;
1186 retval = Cudd_CheckKeys(unique);
1187 if (retval != 0) unique->reordered = 2;
1188 #endif
1189 return(NULL);
1192 if (subtable->keys > subtable->maxKeys) {
1193 if (unique->gcEnabled &&
1194 ((unique->dead > unique->minDead) ||
1195 ((unique->dead > unique->minDead / 2) &&
1196 (subtable->dead > subtable->keys * 0.95)))) { /* too many dead */
1197 (void) cuddGarbageCollect(unique,1);
1198 } else {
1199 cuddRehash(unique,(int)level);
1201 /* Update pointer to insertion point. In the case of rehashing,
1202 ** the slot may have changed. In the case of garbage collection,
1203 ** the predecessor may have been dead. */
1204 pos = ddHash(T, E, subtable->shift);
1205 nodelist = subtable->nodelist;
1206 previousP = &(nodelist[pos]);
1207 looking = *previousP;
1209 while (T < cuddT(looking)) {
1210 previousP = &(looking->next);
1211 looking = *previousP;
1212 #ifdef DD_UNIQUE_PROFILE
1213 unique->uniqueLinks++;
1214 #endif
1216 while (T == cuddT(looking) && E < cuddE(looking)) {
1217 previousP = &(looking->next);
1218 looking = *previousP;
1219 #ifdef DD_UNIQUE_PROFILE
1220 unique->uniqueLinks++;
1221 #endif
1225 gcNumber = unique->garbageCollections;
1226 looking = cuddAllocNode(unique);
1227 if (looking == NULL) {
1228 return(NULL);
1230 unique->keys++;
1231 subtable->keys++;
1233 if (gcNumber != unique->garbageCollections) {
1234 DdNode *looking2;
1235 pos = ddHash(T, E, subtable->shift);
1236 nodelist = subtable->nodelist;
1237 previousP = &(nodelist[pos]);
1238 looking2 = *previousP;
1240 while (T < cuddT(looking2)) {
1241 previousP = &(looking2->next);
1242 looking2 = *previousP;
1243 #ifdef DD_UNIQUE_PROFILE
1244 unique->uniqueLinks++;
1245 #endif
1247 while (T == cuddT(looking2) && E < cuddE(looking2)) {
1248 previousP = &(looking2->next);
1249 looking2 = *previousP;
1250 #ifdef DD_UNIQUE_PROFILE
1251 unique->uniqueLinks++;
1252 #endif
1255 looking->index = index;
1256 cuddT(looking) = T;
1257 cuddE(looking) = E;
1258 looking->next = *previousP;
1259 *previousP = looking;
1260 cuddSatInc(T->ref); /* we know T is a regular pointer */
1261 cuddRef(E);
1263 #ifdef DD_DEBUG
1264 cuddCheckCollisionOrdering(unique,level,pos);
1265 #endif
1267 return(looking);
1269 } /* end of cuddUniqueInter */
1272 /**Function********************************************************************
1274 Synopsis [Wrapper for cuddUniqueInter that is independent of variable
1275 ordering.]
1277 Description [Wrapper for cuddUniqueInter that is independent of
1278 variable ordering (IVO). This function does not require parameter
1279 index to precede the indices of the top nodes of T and E in the
1280 variable order. Returns a pointer to the result node under normal
1281 conditions; NULL if reordering occurred or memory was exhausted.]
1283 SideEffects [None]
1285 SeeAlso [cuddUniqueInter Cudd_MakeBddFromZddCover]
1287 ******************************************************************************/
1288 DdNode *
1289 cuddUniqueInterIVO(
1290 DdManager * unique,
1291 int index,
1292 DdNode * T,
1293 DdNode * E)
1295 DdNode *result;
1296 DdNode *v;
1298 v = cuddUniqueInter(unique, index, DD_ONE(unique),
1299 Cudd_Not(DD_ONE(unique)));
1300 if (v == NULL)
1301 return(NULL);
1302 cuddRef(v);
1303 result = cuddBddIteRecur(unique, v, T, E);
1304 Cudd_RecursiveDeref(unique, v);
1305 return(result);
1309 /**Function********************************************************************
1311 Synopsis [Checks the unique table for the existence of an internal
1312 ZDD node.]
1314 Description [Checks the unique table for the existence of an internal
1315 ZDD node. If it does not exist, it creates a new one. Does not
1316 modify the reference count of whatever is returned. A newly created
1317 internal node comes back with a reference count 0. For a newly
1318 created node, increments the reference counts of what T and E point
1319 to. Returns a pointer to the new node if successful; NULL if memory
1320 is exhausted or if reordering took place.]
1322 SideEffects [None]
1324 SeeAlso [cuddUniqueInter]
1326 ******************************************************************************/
1327 DdNode *
1328 cuddUniqueInterZdd(
1329 DdManager * unique,
1330 int index,
1331 DdNode * T,
1332 DdNode * E)
1334 int pos;
1335 unsigned int level;
1336 int retval;
1337 DdNodePtr *nodelist;
1338 DdNode *looking;
1339 DdSubtable *subtable;
1341 #ifdef DD_UNIQUE_PROFILE
1342 unique->uniqueLookUps++;
1343 #endif
1345 if (index >= unique->sizeZ) {
1346 if (!cuddResizeTableZdd(unique,index)) return(NULL);
1349 level = unique->permZ[index];
1350 subtable = &(unique->subtableZ[level]);
1352 #ifdef DD_DEBUG
1353 assert(level < (unsigned) cuddIZ(unique,T->index));
1354 assert(level < (unsigned) cuddIZ(unique,Cudd_Regular(E)->index));
1355 #endif
1357 if (subtable->keys > subtable->maxKeys) {
1358 if (unique->gcEnabled && ((unique->deadZ > unique->minDead) ||
1359 (10 * subtable->dead > 9 * subtable->keys))) { /* too many dead */
1360 (void) cuddGarbageCollect(unique,1);
1361 } else {
1362 ddRehashZdd(unique,(int)level);
1366 pos = ddHash(T, E, subtable->shift);
1367 nodelist = subtable->nodelist;
1368 looking = nodelist[pos];
1370 while (looking != NULL) {
1371 if (cuddT(looking) == T && cuddE(looking) == E) {
1372 if (looking->ref == 0) {
1373 cuddReclaimZdd(unique,looking);
1375 return(looking);
1377 looking = looking->next;
1378 #ifdef DD_UNIQUE_PROFILE
1379 unique->uniqueLinks++;
1380 #endif
1383 /* countDead is 0 if deads should be counted and ~0 if they should not. */
1384 if (unique->autoDynZ &&
1385 unique->keysZ - (unique->deadZ & unique->countDead) >= unique->nextDyn) {
1386 #ifdef DD_DEBUG
1387 retval = Cudd_DebugCheck(unique);
1388 if (retval != 0) return(NULL);
1389 retval = Cudd_CheckKeys(unique);
1390 if (retval != 0) return(NULL);
1391 #endif
1392 retval = Cudd_zddReduceHeap(unique,unique->autoMethodZ,10); /* 10 = whatever */
1393 if (retval == 0) unique->reordered = 2;
1394 #ifdef DD_DEBUG
1395 retval = Cudd_DebugCheck(unique);
1396 if (retval != 0) unique->reordered = 2;
1397 retval = Cudd_CheckKeys(unique);
1398 if (retval != 0) unique->reordered = 2;
1399 #endif
1400 return(NULL);
1403 unique->keysZ++;
1404 subtable->keys++;
1406 looking = cuddAllocNode(unique);
1407 if (looking == NULL) return(NULL);
1408 looking->index = index;
1409 cuddT(looking) = T;
1410 cuddE(looking) = E;
1411 looking->next = nodelist[pos];
1412 nodelist[pos] = looking;
1413 cuddRef(T);
1414 cuddRef(E);
1416 return(looking);
1418 } /* end of cuddUniqueInterZdd */
1421 /**Function********************************************************************
1423 Synopsis [Checks the unique table for the existence of a constant node.]
1425 Description [Checks the unique table for the existence of a constant node.
1426 If it does not exist, it creates a new one. Does not
1427 modify the reference count of whatever is returned. A newly created
1428 internal node comes back with a reference count 0. Returns a
1429 pointer to the new node.]
1431 SideEffects [None]
1433 ******************************************************************************/
1434 DdNode *
1435 cuddUniqueConst(
1436 DdManager * unique,
1437 CUDD_VALUE_TYPE value)
1439 int pos;
1440 DdNodePtr *nodelist;
1441 DdNode *looking;
1442 hack split;
1444 #ifdef DD_UNIQUE_PROFILE
1445 unique->uniqueLookUps++;
1446 #endif
1448 if (unique->constants.keys > unique->constants.maxKeys) {
1449 if (unique->gcEnabled && ((unique->dead > unique->minDead) ||
1450 (10 * unique->constants.dead > 9 * unique->constants.keys))) { /* too many dead */
1451 (void) cuddGarbageCollect(unique,1);
1452 } else {
1453 cuddRehash(unique,CUDD_CONST_INDEX);
1457 cuddAdjust(value); /* for the case of crippled infinities */
1459 if (ddAbs(value) < unique->epsilon) {
1460 value = 0.0;
1462 split.value = value;
1464 pos = ddHash(split.bits[0], split.bits[1], unique->constants.shift);
1465 nodelist = unique->constants.nodelist;
1466 looking = nodelist[pos];
1468 /* Here we compare values both for equality and for difference less
1469 * than epsilon. The first comparison is required when values are
1470 * infinite, since Infinity - Infinity is NaN and NaN < X is 0 for
1471 * every X.
1473 while (looking != NULL) {
1474 if (looking->type.value == value ||
1475 ddEqualVal(looking->type.value,value,unique->epsilon)) {
1476 if (looking->ref == 0) {
1477 cuddReclaim(unique,looking);
1479 return(looking);
1481 looking = looking->next;
1482 #ifdef DD_UNIQUE_PROFILE
1483 unique->uniqueLinks++;
1484 #endif
1487 unique->keys++;
1488 unique->constants.keys++;
1490 looking = cuddAllocNode(unique);
1491 if (looking == NULL) return(NULL);
1492 looking->index = CUDD_CONST_INDEX;
1493 looking->type.value = value;
1494 looking->next = nodelist[pos];
1495 nodelist[pos] = looking;
1497 return(looking);
1499 } /* end of cuddUniqueConst */
1502 /**Function********************************************************************
1504 Synopsis [Rehashes a unique subtable.]
1506 Description [Doubles the size of a unique subtable and rehashes its
1507 contents.]
1509 SideEffects [None]
1511 SeeAlso []
1513 ******************************************************************************/
1514 void
1515 cuddRehash(
1516 DdManager * unique,
1517 int i)
1519 unsigned int slots, oldslots;
1520 int shift, oldshift;
1521 int j, pos;
1522 DdNodePtr *nodelist, *oldnodelist;
1523 DdNode *node, *next;
1524 DdNode *sentinel = &(unique->sentinel);
1525 hack split;
1526 extern DD_OOMFP MMoutOfMemory;
1527 DD_OOMFP saveHandler;
1529 if (unique->gcFrac == DD_GC_FRAC_HI && unique->slots > unique->looseUpTo) {
1530 unique->gcFrac = DD_GC_FRAC_LO;
1531 unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
1532 #ifdef DD_VERBOSE
1533 (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_LO);
1534 (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
1535 #endif
1538 if (unique->gcFrac != DD_GC_FRAC_MIN && unique->memused > unique->maxmem) {
1539 unique->gcFrac = DD_GC_FRAC_MIN;
1540 unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
1541 #ifdef DD_VERBOSE
1542 (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_MIN);
1543 (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
1544 #endif
1545 cuddShrinkDeathRow(unique);
1546 if (cuddGarbageCollect(unique,1) > 0) return;
1549 if (i != CUDD_CONST_INDEX) {
1550 oldslots = unique->subtables[i].slots;
1551 oldshift = unique->subtables[i].shift;
1552 oldnodelist = unique->subtables[i].nodelist;
1554 /* Compute the new size of the subtable. */
1555 slots = oldslots << 1;
1556 shift = oldshift - 1;
1558 saveHandler = MMoutOfMemory;
1559 MMoutOfMemory = Cudd_OutOfMem;
1560 nodelist = ALLOC(DdNodePtr, slots);
1561 MMoutOfMemory = saveHandler;
1562 if (nodelist == NULL) {
1563 (void) fprintf(unique->err,
1564 "Unable to resize subtable %d for lack of memory\n",
1566 /* Prevent frequent resizing attempts. */
1567 (void) cuddGarbageCollect(unique,1);
1568 if (unique->stash != NULL) {
1569 FREE(unique->stash);
1570 unique->stash = NULL;
1571 /* Inhibit resizing of tables. */
1572 cuddSlowTableGrowth(unique);
1574 return;
1576 unique->subtables[i].nodelist = nodelist;
1577 unique->subtables[i].slots = slots;
1578 unique->subtables[i].shift = shift;
1579 unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
1581 /* Move the nodes from the old table to the new table.
1582 ** This code depends on the type of hash function.
1583 ** It assumes that the effect of doubling the size of the table
1584 ** is to retain one more bit of the 32-bit hash value.
1585 ** The additional bit is the LSB. */
1586 for (j = 0; (unsigned) j < oldslots; j++) {
1587 DdNodePtr *evenP, *oddP;
1588 node = oldnodelist[j];
1589 evenP = &(nodelist[j<<1]);
1590 oddP = &(nodelist[(j<<1)+1]);
1591 while (node != sentinel) {
1592 next = node->next;
1593 pos = ddHash(cuddT(node), cuddE(node), shift);
1594 if (pos & 1) {
1595 *oddP = node;
1596 oddP = &(node->next);
1597 } else {
1598 *evenP = node;
1599 evenP = &(node->next);
1601 node = next;
1603 *evenP = *oddP = sentinel;
1605 FREE(oldnodelist);
1607 #ifdef DD_VERBOSE
1608 (void) fprintf(unique->err,
1609 "rehashing layer %d: keys %d dead %d new size %d\n",
1610 i, unique->subtables[i].keys,
1611 unique->subtables[i].dead, slots);
1612 #endif
1613 } else {
1614 oldslots = unique->constants.slots;
1615 oldshift = unique->constants.shift;
1616 oldnodelist = unique->constants.nodelist;
1618 /* The constant subtable is never subjected to reordering.
1619 ** Therefore, when it is resized, it is because it has just
1620 ** reached the maximum load. We can safely just double the size,
1621 ** with no need for the loop we use for the other tables.
1623 slots = oldslots << 1;
1624 shift = oldshift - 1;
1625 saveHandler = MMoutOfMemory;
1626 MMoutOfMemory = Cudd_OutOfMem;
1627 nodelist = ALLOC(DdNodePtr, slots);
1628 MMoutOfMemory = saveHandler;
1629 if (nodelist == NULL) {
1630 (void) fprintf(unique->err,
1631 "Unable to resize constant subtable for lack of memory\n");
1632 (void) cuddGarbageCollect(unique,1);
1633 for (j = 0; j < unique->size; j++) {
1634 unique->subtables[j].maxKeys <<= 1;
1636 unique->constants.maxKeys <<= 1;
1637 return;
1639 unique->constants.slots = slots;
1640 unique->constants.shift = shift;
1641 unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
1642 unique->constants.nodelist = nodelist;
1643 for (j = 0; (unsigned) j < slots; j++) {
1644 nodelist[j] = NULL;
1646 for (j = 0; (unsigned) j < oldslots; j++) {
1647 node = oldnodelist[j];
1648 while (node != NULL) {
1649 next = node->next;
1650 split.value = cuddV(node);
1651 pos = ddHash(split.bits[0], split.bits[1], shift);
1652 node->next = nodelist[pos];
1653 nodelist[pos] = node;
1654 node = next;
1657 FREE(oldnodelist);
1659 #ifdef DD_VERBOSE
1660 (void) fprintf(unique->err,
1661 "rehashing constants: keys %d dead %d new size %d\n",
1662 unique->constants.keys,unique->constants.dead,slots);
1663 #endif
1666 /* Update global data */
1668 unique->memused += (slots - oldslots) * sizeof(DdNodePtr);
1669 unique->slots += (slots - oldslots);
1670 ddFixLimits(unique);
1672 } /* end of cuddRehash */
1675 /**Function********************************************************************
1677 Synopsis [Shrinks a subtable.]
1679 Description [Shrinks a subtable.]
1681 SideEffects [None]
1683 SeeAlso [cuddRehash]
1685 ******************************************************************************/
1686 void
1687 cuddShrinkSubtable(
1688 DdManager *unique,
1689 int i)
1691 int j;
1692 int shift, posn;
1693 DdNodePtr *nodelist, *oldnodelist;
1694 DdNode *node, *next;
1695 DdNode *sentinel = &(unique->sentinel);
1696 unsigned int slots, oldslots;
1697 extern DD_OOMFP MMoutOfMemory;
1698 DD_OOMFP saveHandler;
1700 oldnodelist = unique->subtables[i].nodelist;
1701 oldslots = unique->subtables[i].slots;
1702 slots = oldslots >> 1;
1703 saveHandler = MMoutOfMemory;
1704 MMoutOfMemory = Cudd_OutOfMem;
1705 nodelist = ALLOC(DdNodePtr, slots);
1706 MMoutOfMemory = saveHandler;
1707 if (nodelist == NULL) {
1708 return;
1710 unique->subtables[i].nodelist = nodelist;
1711 unique->subtables[i].slots = slots;
1712 unique->subtables[i].shift++;
1713 unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
1714 #ifdef DD_VERBOSE
1715 (void) fprintf(unique->err,
1716 "shrunk layer %d (%d keys) from %d to %d slots\n",
1717 i, unique->subtables[i].keys, oldslots, slots);
1718 #endif
1720 for (j = 0; (unsigned) j < slots; j++) {
1721 nodelist[j] = sentinel;
1723 shift = unique->subtables[i].shift;
1724 for (j = 0; (unsigned) j < oldslots; j++) {
1725 node = oldnodelist[j];
1726 while (node != sentinel) {
1727 DdNode *looking, *T, *E;
1728 DdNodePtr *previousP;
1729 next = node->next;
1730 posn = ddHash(cuddT(node), cuddE(node), shift);
1731 previousP = &(nodelist[posn]);
1732 looking = *previousP;
1733 T = cuddT(node);
1734 E = cuddE(node);
1735 while (T < cuddT(looking)) {
1736 previousP = &(looking->next);
1737 looking = *previousP;
1738 #ifdef DD_UNIQUE_PROFILE
1739 unique->uniqueLinks++;
1740 #endif
1742 while (T == cuddT(looking) && E < cuddE(looking)) {
1743 previousP = &(looking->next);
1744 looking = *previousP;
1745 #ifdef DD_UNIQUE_PROFILE
1746 unique->uniqueLinks++;
1747 #endif
1749 node->next = *previousP;
1750 *previousP = node;
1751 node = next;
1754 FREE(oldnodelist);
1756 unique->memused += ((long) slots - (long) oldslots) * sizeof(DdNode *);
1757 unique->slots += slots - oldslots;
1758 unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
1759 unique->cacheSlack = (int)
1760 ddMin(unique->maxCacheHard,DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots)
1761 - 2 * (int) unique->cacheSlots;
1763 } /* end of cuddShrinkSubtable */
1766 /**Function********************************************************************
1768 Synopsis [Inserts n new subtables in a unique table at level.]
1770 Description [Inserts n new subtables in a unique table at level.
1771 The number n should be positive, and level should be an existing level.
1772 Returns 1 if successful; 0 otherwise.]
1774 SideEffects [None]
1776 SeeAlso [cuddDestroySubtables]
1778 ******************************************************************************/
1780 cuddInsertSubtables(
1781 DdManager * unique,
1782 int n,
1783 int level)
1785 DdSubtable *newsubtables;
1786 DdNodePtr *newnodelist;
1787 DdNodePtr *newvars;
1788 DdNode *sentinel = &(unique->sentinel);
1789 int oldsize,newsize;
1790 int i,j,index,reorderSave;
1791 unsigned int numSlots = unique->initSlots;
1792 int *newperm, *newinvperm, *newmap;
1793 DdNode *one, *zero;
1795 #ifdef DD_DEBUG
1796 assert(n > 0 && level < unique->size);
1797 #endif
1799 oldsize = unique->size;
1800 /* Easy case: there is still room in the current table. */
1801 if (oldsize + n <= unique->maxSize) {
1802 /* Shift the tables at and below level. */
1803 for (i = oldsize - 1; i >= level; i--) {
1804 unique->subtables[i+n].slots = unique->subtables[i].slots;
1805 unique->subtables[i+n].shift = unique->subtables[i].shift;
1806 unique->subtables[i+n].keys = unique->subtables[i].keys;
1807 unique->subtables[i+n].maxKeys = unique->subtables[i].maxKeys;
1808 unique->subtables[i+n].dead = unique->subtables[i].dead;
1809 unique->subtables[i+n].nodelist = unique->subtables[i].nodelist;
1810 unique->subtables[i+n].bindVar = unique->subtables[i].bindVar;
1811 unique->subtables[i+n].varType = unique->subtables[i].varType;
1812 unique->subtables[i+n].pairIndex = unique->subtables[i].pairIndex;
1813 unique->subtables[i+n].varHandled = unique->subtables[i].varHandled;
1814 unique->subtables[i+n].varToBeGrouped =
1815 unique->subtables[i].varToBeGrouped;
1817 index = unique->invperm[i];
1818 unique->invperm[i+n] = index;
1819 unique->perm[index] += n;
1821 /* Create new subtables. */
1822 for (i = 0; i < n; i++) {
1823 unique->subtables[level+i].slots = numSlots;
1824 unique->subtables[level+i].shift = sizeof(int) * 8 -
1825 cuddComputeFloorLog2(numSlots);
1826 unique->subtables[level+i].keys = 0;
1827 unique->subtables[level+i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
1828 unique->subtables[level+i].dead = 0;
1829 unique->subtables[level+i].bindVar = 0;
1830 unique->subtables[level+i].varType = CUDD_VAR_PRIMARY_INPUT;
1831 unique->subtables[level+i].pairIndex = 0;
1832 unique->subtables[level+i].varHandled = 0;
1833 unique->subtables[level+i].varToBeGrouped = CUDD_LAZY_NONE;
1835 unique->perm[oldsize+i] = level + i;
1836 unique->invperm[level+i] = oldsize + i;
1837 newnodelist = unique->subtables[level+i].nodelist =
1838 ALLOC(DdNodePtr, numSlots);
1839 if (newnodelist == NULL) {
1840 unique->errorCode = CUDD_MEMORY_OUT;
1841 return(0);
1843 for (j = 0; (unsigned) j < numSlots; j++) {
1844 newnodelist[j] = sentinel;
1847 if (unique->map != NULL) {
1848 for (i = 0; i < n; i++) {
1849 unique->map[oldsize+i] = oldsize + i;
1852 } else {
1853 /* The current table is too small: we need to allocate a new,
1854 ** larger one; move all old subtables, and initialize the new
1855 ** subtables.
1857 newsize = oldsize + n + DD_DEFAULT_RESIZE;
1858 #ifdef DD_VERBOSE
1859 (void) fprintf(unique->err,
1860 "Increasing the table size from %d to %d\n",
1861 unique->maxSize, newsize);
1862 #endif
1863 /* Allocate memory for new arrays (except nodelists). */
1864 newsubtables = ALLOC(DdSubtable,newsize);
1865 if (newsubtables == NULL) {
1866 unique->errorCode = CUDD_MEMORY_OUT;
1867 return(0);
1869 newvars = ALLOC(DdNodePtr,newsize);
1870 if (newvars == NULL) {
1871 unique->errorCode = CUDD_MEMORY_OUT;
1872 FREE(newsubtables);
1873 return(0);
1875 newperm = ALLOC(int,newsize);
1876 if (newperm == NULL) {
1877 unique->errorCode = CUDD_MEMORY_OUT;
1878 FREE(newsubtables);
1879 FREE(newvars);
1880 return(0);
1882 newinvperm = ALLOC(int,newsize);
1883 if (newinvperm == NULL) {
1884 unique->errorCode = CUDD_MEMORY_OUT;
1885 FREE(newsubtables);
1886 FREE(newvars);
1887 FREE(newperm);
1888 return(0);
1890 if (unique->map != NULL) {
1891 newmap = ALLOC(int,newsize);
1892 if (newmap == NULL) {
1893 unique->errorCode = CUDD_MEMORY_OUT;
1894 FREE(newsubtables);
1895 FREE(newvars);
1896 FREE(newperm);
1897 FREE(newinvperm);
1898 return(0);
1900 unique->memused += (newsize - unique->maxSize) * sizeof(int);
1902 unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
1903 sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
1904 /* Copy levels before insertion points from old tables. */
1905 for (i = 0; i < level; i++) {
1906 newsubtables[i].slots = unique->subtables[i].slots;
1907 newsubtables[i].shift = unique->subtables[i].shift;
1908 newsubtables[i].keys = unique->subtables[i].keys;
1909 newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
1910 newsubtables[i].dead = unique->subtables[i].dead;
1911 newsubtables[i].nodelist = unique->subtables[i].nodelist;
1912 newsubtables[i].bindVar = unique->subtables[i].bindVar;
1913 newsubtables[i].varType = unique->subtables[i].varType;
1914 newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
1915 newsubtables[i].varHandled = unique->subtables[i].varHandled;
1916 newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
1918 newvars[i] = unique->vars[i];
1919 newperm[i] = unique->perm[i];
1920 newinvperm[i] = unique->invperm[i];
1922 /* Finish initializing permutation for new table to old one. */
1923 for (i = level; i < oldsize; i++) {
1924 newperm[i] = unique->perm[i];
1926 /* Initialize new levels. */
1927 for (i = level; i < level + n; i++) {
1928 newsubtables[i].slots = numSlots;
1929 newsubtables[i].shift = sizeof(int) * 8 -
1930 cuddComputeFloorLog2(numSlots);
1931 newsubtables[i].keys = 0;
1932 newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
1933 newsubtables[i].dead = 0;
1934 newsubtables[i].bindVar = 0;
1935 newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
1936 newsubtables[i].pairIndex = 0;
1937 newsubtables[i].varHandled = 0;
1938 newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
1940 newperm[oldsize + i - level] = i;
1941 newinvperm[i] = oldsize + i - level;
1942 newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
1943 if (newnodelist == NULL) {
1944 /* We are going to leak some memory. We should clean up. */
1945 unique->errorCode = CUDD_MEMORY_OUT;
1946 return(0);
1948 for (j = 0; (unsigned) j < numSlots; j++) {
1949 newnodelist[j] = sentinel;
1952 /* Copy the old tables for levels past the insertion point. */
1953 for (i = level; i < oldsize; i++) {
1954 newsubtables[i+n].slots = unique->subtables[i].slots;
1955 newsubtables[i+n].shift = unique->subtables[i].shift;
1956 newsubtables[i+n].keys = unique->subtables[i].keys;
1957 newsubtables[i+n].maxKeys = unique->subtables[i].maxKeys;
1958 newsubtables[i+n].dead = unique->subtables[i].dead;
1959 newsubtables[i+n].nodelist = unique->subtables[i].nodelist;
1960 newsubtables[i+n].bindVar = unique->subtables[i].bindVar;
1961 newsubtables[i+n].varType = unique->subtables[i].varType;
1962 newsubtables[i+n].pairIndex = unique->subtables[i].pairIndex;
1963 newsubtables[i+n].varHandled = unique->subtables[i].varHandled;
1964 newsubtables[i+n].varToBeGrouped =
1965 unique->subtables[i].varToBeGrouped;
1967 newvars[i] = unique->vars[i];
1968 index = unique->invperm[i];
1969 newinvperm[i+n] = index;
1970 newperm[index] += n;
1972 /* Update the map. */
1973 if (unique->map != NULL) {
1974 for (i = 0; i < oldsize; i++) {
1975 newmap[i] = unique->map[i];
1977 for (i = oldsize; i < oldsize + n; i++) {
1978 newmap[i] = i;
1980 FREE(unique->map);
1981 unique->map = newmap;
1983 /* Install the new tables and free the old ones. */
1984 FREE(unique->subtables);
1985 unique->subtables = newsubtables;
1986 unique->maxSize = newsize;
1987 FREE(unique->vars);
1988 unique->vars = newvars;
1989 FREE(unique->perm);
1990 unique->perm = newperm;
1991 FREE(unique->invperm);
1992 unique->invperm = newinvperm;
1993 /* Update the stack for iterative procedures. */
1994 if (newsize > unique->maxSizeZ) {
1995 FREE(unique->stack);
1996 unique->stack = ALLOC(DdNodePtr,newsize + 1);
1997 if (unique->stack == NULL) {
1998 unique->errorCode = CUDD_MEMORY_OUT;
1999 return(0);
2001 unique->stack[0] = NULL; /* to suppress harmless UMR */
2002 unique->memused +=
2003 (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
2004 * sizeof(DdNode *);
2007 /* Update manager parameters to account for the new subtables. */
2008 unique->slots += n * numSlots;
2009 ddFixLimits(unique);
2010 unique->size += n;
2012 /* Now that the table is in a coherent state, create the new
2013 ** projection functions. We need to temporarily disable reordering,
2014 ** because we cannot reorder without projection functions in place.
2016 one = unique->one;
2017 zero = Cudd_Not(one);
2019 reorderSave = unique->autoDyn;
2020 unique->autoDyn = 0;
2021 for (i = oldsize; i < oldsize + n; i++) {
2022 unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
2023 if (unique->vars[i] == NULL) {
2024 unique->autoDyn = reorderSave;
2025 /* Shift everything back so table remains coherent. */
2026 for (j = oldsize; j < i; j++) {
2027 Cudd_IterDerefBdd(unique,unique->vars[j]);
2028 cuddDeallocNode(unique,unique->vars[j]);
2029 unique->vars[j] = NULL;
2031 for (j = level; j < oldsize; j++) {
2032 unique->subtables[j].slots = unique->subtables[j+n].slots;
2033 unique->subtables[j].slots = unique->subtables[j+n].slots;
2034 unique->subtables[j].shift = unique->subtables[j+n].shift;
2035 unique->subtables[j].keys = unique->subtables[j+n].keys;
2036 unique->subtables[j].maxKeys =
2037 unique->subtables[j+n].maxKeys;
2038 unique->subtables[j].dead = unique->subtables[j+n].dead;
2039 FREE(unique->subtables[j].nodelist);
2040 unique->subtables[j].nodelist =
2041 unique->subtables[j+n].nodelist;
2042 unique->subtables[j+n].nodelist = NULL;
2043 unique->subtables[j].bindVar =
2044 unique->subtables[j+n].bindVar;
2045 unique->subtables[j].varType =
2046 unique->subtables[j+n].varType;
2047 unique->subtables[j].pairIndex =
2048 unique->subtables[j+n].pairIndex;
2049 unique->subtables[j].varHandled =
2050 unique->subtables[j+n].varHandled;
2051 unique->subtables[j].varToBeGrouped =
2052 unique->subtables[j+n].varToBeGrouped;
2053 index = unique->invperm[j+n];
2054 unique->invperm[j] = index;
2055 unique->perm[index] -= n;
2057 unique->size = oldsize;
2058 unique->slots -= n * numSlots;
2059 ddFixLimits(unique);
2060 (void) Cudd_DebugCheck(unique);
2061 return(0);
2063 cuddRef(unique->vars[i]);
2065 if (unique->tree != NULL) {
2066 unique->tree->size += n;
2067 unique->tree->index = unique->invperm[0];
2068 ddPatchTree(unique,unique->tree);
2070 unique->autoDyn = reorderSave;
2072 return(1);
2074 } /* end of cuddInsertSubtables */
2077 /**Function********************************************************************
2079 Synopsis [Destroys the n most recently created subtables in a unique table.]
2081 Description [Destroys the n most recently created subtables in a unique
2082 table. n should be positive. The subtables should not contain any live
2083 nodes, except the (isolated) projection function. The projection
2084 functions are freed. Returns 1 if successful; 0 otherwise.]
2086 SideEffects [The variable map used for fast variable substitution is
2087 destroyed if it exists. In this case the cache is also cleared.]
2089 SeeAlso [cuddInsertSubtables Cudd_SetVarMap]
2091 ******************************************************************************/
2093 cuddDestroySubtables(
2094 DdManager * unique,
2095 int n)
2097 DdSubtable *subtables;
2098 DdNodePtr *nodelist;
2099 DdNodePtr *vars;
2100 int firstIndex, lastIndex;
2101 int index, level, newlevel;
2102 int lowestLevel;
2103 int shift;
2104 int found;
2106 /* Sanity check and set up. */
2107 if (n <= 0) return(0);
2108 if (n > unique->size) n = unique->size;
2110 subtables = unique->subtables;
2111 vars = unique->vars;
2112 firstIndex = unique->size - n;
2113 lastIndex = unique->size;
2115 /* Check for nodes labeled by the variables being destroyed
2116 ** that may still be in use. It is allowed to destroy a variable
2117 ** only if there are no such nodes. Also, find the lowest level
2118 ** among the variables being destroyed. This will make further
2119 ** processing more efficient.
2121 lowestLevel = unique->size;
2122 for (index = firstIndex; index < lastIndex; index++) {
2123 level = unique->perm[index];
2124 if (level < lowestLevel) lowestLevel = level;
2125 nodelist = subtables[level].nodelist;
2126 if (subtables[level].keys - subtables[level].dead != 1) return(0);
2127 /* The projection function should be isolated. If the ref count
2128 ** is 1, everything is OK. If the ref count is saturated, then
2129 ** we need to make sure that there are no nodes pointing to it.
2130 ** As for the external references, we assume the application is
2131 ** responsible for them.
2133 if (vars[index]->ref != 1) {
2134 if (vars[index]->ref != DD_MAXREF) return(0);
2135 found = cuddFindParent(unique,vars[index]);
2136 if (found) {
2137 return(0);
2138 } else {
2139 vars[index]->ref = 1;
2142 Cudd_RecursiveDeref(unique,vars[index]);
2145 /* Collect garbage, because we cannot afford having dead nodes pointing
2146 ** to the dead nodes in the subtables being destroyed.
2148 (void) cuddGarbageCollect(unique,1);
2150 /* Here we know we can destroy our subtables. */
2151 for (index = firstIndex; index < lastIndex; index++) {
2152 level = unique->perm[index];
2153 nodelist = subtables[level].nodelist;
2154 #ifdef DD_DEBUG
2155 assert(subtables[level].keys == 0);
2156 #endif
2157 FREE(nodelist);
2158 unique->memused -= sizeof(DdNodePtr) * subtables[level].slots;
2159 unique->slots -= subtables[level].slots;
2160 unique->dead -= subtables[level].dead;
2163 /* Here all subtables to be destroyed have their keys field == 0 and
2164 ** their hash tables have been freed.
2165 ** We now scan the subtables from level lowestLevel + 1 to level size - 1,
2166 ** shifting the subtables as required. We keep a running count of
2167 ** how many subtables have been moved, so that we know by how many
2168 ** positions each subtable should be shifted.
2170 shift = 1;
2171 for (level = lowestLevel + 1; level < unique->size; level++) {
2172 if (subtables[level].keys == 0) {
2173 shift++;
2174 continue;
2176 newlevel = level - shift;
2177 subtables[newlevel].slots = subtables[level].slots;
2178 subtables[newlevel].shift = subtables[level].shift;
2179 subtables[newlevel].keys = subtables[level].keys;
2180 subtables[newlevel].maxKeys = subtables[level].maxKeys;
2181 subtables[newlevel].dead = subtables[level].dead;
2182 subtables[newlevel].nodelist = subtables[level].nodelist;
2183 index = unique->invperm[level];
2184 unique->perm[index] = newlevel;
2185 unique->invperm[newlevel] = index;
2186 subtables[newlevel].bindVar = subtables[level].bindVar;
2187 subtables[newlevel].varType = subtables[level].varType;
2188 subtables[newlevel].pairIndex = subtables[level].pairIndex;
2189 subtables[newlevel].varHandled = subtables[level].varHandled;
2190 subtables[newlevel].varToBeGrouped = subtables[level].varToBeGrouped;
2192 /* Destroy the map. If a surviving variable is
2193 ** mapped to a dying variable, and the map were used again,
2194 ** an out-of-bounds access to unique->vars would result. */
2195 if (unique->map != NULL) {
2196 cuddCacheFlush(unique);
2197 FREE(unique->map);
2198 unique->map = NULL;
2201 unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
2202 unique->size -= n;
2204 return(1);
2206 } /* end of cuddDestroySubtables */
2209 /**Function********************************************************************
2211 Synopsis [Increases the number of ZDD subtables in a unique table so
2212 that it meets or exceeds index.]
2214 Description [Increases the number of ZDD subtables in a unique table so
2215 that it meets or exceeds index. When new ZDD variables are created, it
2216 is possible to preserve the functions unchanged, or it is possible to
2217 preserve the covers unchanged, but not both. cuddResizeTableZdd preserves
2218 the covers. Returns 1 if successful; 0 otherwise.]
2220 SideEffects [None]
2222 SeeAlso [ddResizeTable]
2224 ******************************************************************************/
2226 cuddResizeTableZdd(
2227 DdManager * unique,
2228 int index)
2230 DdSubtable *newsubtables;
2231 DdNodePtr *newnodelist;
2232 int oldsize,newsize;
2233 int i,j,reorderSave;
2234 unsigned int numSlots = unique->initSlots;
2235 int *newperm, *newinvperm;
2237 oldsize = unique->sizeZ;
2238 /* Easy case: there is still room in the current table. */
2239 if (index < unique->maxSizeZ) {
2240 for (i = oldsize; i <= index; i++) {
2241 unique->subtableZ[i].slots = numSlots;
2242 unique->subtableZ[i].shift = sizeof(int) * 8 -
2243 cuddComputeFloorLog2(numSlots);
2244 unique->subtableZ[i].keys = 0;
2245 unique->subtableZ[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
2246 unique->subtableZ[i].dead = 0;
2247 unique->permZ[i] = i;
2248 unique->invpermZ[i] = i;
2249 newnodelist = unique->subtableZ[i].nodelist =
2250 ALLOC(DdNodePtr, numSlots);
2251 if (newnodelist == NULL) {
2252 unique->errorCode = CUDD_MEMORY_OUT;
2253 return(0);
2255 for (j = 0; (unsigned) j < numSlots; j++) {
2256 newnodelist[j] = NULL;
2259 } else {
2260 /* The current table is too small: we need to allocate a new,
2261 ** larger one; move all old subtables, and initialize the new
2262 ** subtables up to index included.
2264 newsize = index + DD_DEFAULT_RESIZE;
2265 #ifdef DD_VERBOSE
2266 (void) fprintf(unique->err,
2267 "Increasing the ZDD table size from %d to %d\n",
2268 unique->maxSizeZ, newsize);
2269 #endif
2270 newsubtables = ALLOC(DdSubtable,newsize);
2271 if (newsubtables == NULL) {
2272 unique->errorCode = CUDD_MEMORY_OUT;
2273 return(0);
2275 newperm = ALLOC(int,newsize);
2276 if (newperm == NULL) {
2277 unique->errorCode = CUDD_MEMORY_OUT;
2278 return(0);
2280 newinvperm = ALLOC(int,newsize);
2281 if (newinvperm == NULL) {
2282 unique->errorCode = CUDD_MEMORY_OUT;
2283 return(0);
2285 unique->memused += (newsize - unique->maxSizeZ) * ((numSlots+1) *
2286 sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
2287 if (newsize > unique->maxSize) {
2288 FREE(unique->stack);
2289 unique->stack = ALLOC(DdNodePtr,newsize + 1);
2290 if (unique->stack == NULL) {
2291 unique->errorCode = CUDD_MEMORY_OUT;
2292 return(0);
2294 unique->stack[0] = NULL; /* to suppress harmless UMR */
2295 unique->memused +=
2296 (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
2297 * sizeof(DdNode *);
2299 for (i = 0; i < oldsize; i++) {
2300 newsubtables[i].slots = unique->subtableZ[i].slots;
2301 newsubtables[i].shift = unique->subtableZ[i].shift;
2302 newsubtables[i].keys = unique->subtableZ[i].keys;
2303 newsubtables[i].maxKeys = unique->subtableZ[i].maxKeys;
2304 newsubtables[i].dead = unique->subtableZ[i].dead;
2305 newsubtables[i].nodelist = unique->subtableZ[i].nodelist;
2306 newperm[i] = unique->permZ[i];
2307 newinvperm[i] = unique->invpermZ[i];
2309 for (i = oldsize; i <= index; i++) {
2310 newsubtables[i].slots = numSlots;
2311 newsubtables[i].shift = sizeof(int) * 8 -
2312 cuddComputeFloorLog2(numSlots);
2313 newsubtables[i].keys = 0;
2314 newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
2315 newsubtables[i].dead = 0;
2316 newperm[i] = i;
2317 newinvperm[i] = i;
2318 newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
2319 if (newnodelist == NULL) {
2320 unique->errorCode = CUDD_MEMORY_OUT;
2321 return(0);
2323 for (j = 0; (unsigned) j < numSlots; j++) {
2324 newnodelist[j] = NULL;
2327 FREE(unique->subtableZ);
2328 unique->subtableZ = newsubtables;
2329 unique->maxSizeZ = newsize;
2330 FREE(unique->permZ);
2331 unique->permZ = newperm;
2332 FREE(unique->invpermZ);
2333 unique->invpermZ = newinvperm;
2335 unique->slots += (index + 1 - unique->sizeZ) * numSlots;
2336 ddFixLimits(unique);
2337 unique->sizeZ = index + 1;
2339 /* Now that the table is in a coherent state, update the ZDD
2340 ** universe. We need to temporarily disable reordering,
2341 ** because we cannot reorder without universe in place.
2344 reorderSave = unique->autoDynZ;
2345 unique->autoDynZ = 0;
2346 cuddZddFreeUniv(unique);
2347 if (!cuddZddInitUniv(unique)) {
2348 unique->autoDynZ = reorderSave;
2349 return(0);
2351 unique->autoDynZ = reorderSave;
2353 return(1);
2355 } /* end of cuddResizeTableZdd */
2358 /**Function********************************************************************
2360 Synopsis [Adjusts parameters of a table to slow down its growth.]
2362 Description []
2364 SideEffects [None]
2366 SeeAlso []
2368 ******************************************************************************/
2369 void
2370 cuddSlowTableGrowth(
2371 DdManager *unique)
2373 int i;
2375 unique->maxCacheHard = unique->cacheSlots - 1;
2376 unique->cacheSlack = - (int) (unique->cacheSlots + 1);
2377 for (i = 0; i < unique->size; i++) {
2378 unique->subtables[i].maxKeys <<= 2;
2380 unique->gcFrac = DD_GC_FRAC_MIN;
2381 unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
2382 cuddShrinkDeathRow(unique);
2383 (void) fprintf(unique->err,"Slowing down table growth: ");
2384 (void) fprintf(unique->err,"GC fraction = %.2f\t", unique->gcFrac);
2385 (void) fprintf(unique->err,"minDead = %u\n", unique->minDead);
2387 } /* end of cuddSlowTableGrowth */
2390 /*---------------------------------------------------------------------------*/
2391 /* Definition of static functions */
2392 /*---------------------------------------------------------------------------*/
2395 /**Function********************************************************************
2397 Synopsis [Rehashes a ZDD unique subtable.]
2399 Description []
2401 SideEffects [None]
2403 SeeAlso [cuddRehash]
2405 ******************************************************************************/
2406 static void
2407 ddRehashZdd(
2408 DdManager * unique,
2409 int i)
2411 unsigned int slots, oldslots;
2412 int shift, oldshift;
2413 int j, pos;
2414 DdNodePtr *nodelist, *oldnodelist;
2415 DdNode *node, *next;
2416 extern DD_OOMFP MMoutOfMemory;
2417 DD_OOMFP saveHandler;
2419 if (unique->slots > unique->looseUpTo) {
2420 unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
2421 #ifdef DD_VERBOSE
2422 if (unique->gcFrac == DD_GC_FRAC_HI) {
2423 (void) fprintf(unique->err,"GC fraction = %.2f\t",
2424 DD_GC_FRAC_LO);
2425 (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
2427 #endif
2428 unique->gcFrac = DD_GC_FRAC_LO;
2431 assert(i != CUDD_MAXINDEX);
2432 oldslots = unique->subtableZ[i].slots;
2433 oldshift = unique->subtableZ[i].shift;
2434 oldnodelist = unique->subtableZ[i].nodelist;
2436 /* Compute the new size of the subtable. Normally, we just
2437 ** double. However, after reordering, a table may be severely
2438 ** overloaded. Therefore, we iterate. */
2439 slots = oldslots;
2440 shift = oldshift;
2441 do {
2442 slots <<= 1;
2443 shift--;
2444 } while (slots * DD_MAX_SUBTABLE_DENSITY < unique->subtableZ[i].keys);
2446 saveHandler = MMoutOfMemory;
2447 MMoutOfMemory = Cudd_OutOfMem;
2448 nodelist = ALLOC(DdNodePtr, slots);
2449 MMoutOfMemory = saveHandler;
2450 if (nodelist == NULL) {
2451 (void) fprintf(unique->err,
2452 "Unable to resize ZDD subtable %d for lack of memory.\n",
2454 (void) cuddGarbageCollect(unique,1);
2455 for (j = 0; j < unique->sizeZ; j++) {
2456 unique->subtableZ[j].maxKeys <<= 1;
2458 return;
2460 unique->subtableZ[i].nodelist = nodelist;
2461 unique->subtableZ[i].slots = slots;
2462 unique->subtableZ[i].shift = shift;
2463 unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
2464 for (j = 0; (unsigned) j < slots; j++) {
2465 nodelist[j] = NULL;
2467 for (j = 0; (unsigned) j < oldslots; j++) {
2468 node = oldnodelist[j];
2469 while (node != NULL) {
2470 next = node->next;
2471 pos = ddHash(cuddT(node), cuddE(node), shift);
2472 node->next = nodelist[pos];
2473 nodelist[pos] = node;
2474 node = next;
2477 FREE(oldnodelist);
2479 #ifdef DD_VERBOSE
2480 (void) fprintf(unique->err,
2481 "rehashing layer %d: keys %d dead %d new size %d\n",
2482 i, unique->subtableZ[i].keys,
2483 unique->subtableZ[i].dead, slots);
2484 #endif
2486 /* Update global data. */
2487 unique->memused += (slots - oldslots) * sizeof(DdNode *);
2488 unique->slots += (slots - oldslots);
2489 ddFixLimits(unique);
2491 } /* end of ddRehashZdd */
2494 /**Function********************************************************************
2496 Synopsis [Increases the number of subtables in a unique table so
2497 that it meets or exceeds index.]
2499 Description [Increases the number of subtables in a unique table so
2500 that it meets or exceeds index. Returns 1 if successful; 0 otherwise.]
2502 SideEffects [None]
2504 SeeAlso [cuddResizeTableZdd]
2506 ******************************************************************************/
2507 static int
2508 ddResizeTable(
2509 DdManager * unique,
2510 int index)
2512 DdSubtable *newsubtables;
2513 DdNodePtr *newnodelist;
2514 DdNodePtr *newvars;
2515 DdNode *sentinel = &(unique->sentinel);
2516 int oldsize,newsize;
2517 int i,j,reorderSave;
2518 int numSlots = unique->initSlots;
2519 int *newperm, *newinvperm, *newmap;
2520 DdNode *one, *zero;
2522 oldsize = unique->size;
2523 /* Easy case: there is still room in the current table. */
2524 if (index < unique->maxSize) {
2525 for (i = oldsize; i <= index; i++) {
2526 unique->subtables[i].slots = numSlots;
2527 unique->subtables[i].shift = sizeof(int) * 8 -
2528 cuddComputeFloorLog2(numSlots);
2529 unique->subtables[i].keys = 0;
2530 unique->subtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
2531 unique->subtables[i].dead = 0;
2532 unique->subtables[i].bindVar = 0;
2533 unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
2534 unique->subtables[i].pairIndex = 0;
2535 unique->subtables[i].varHandled = 0;
2536 unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
2538 unique->perm[i] = i;
2539 unique->invperm[i] = i;
2540 newnodelist = unique->subtables[i].nodelist =
2541 ALLOC(DdNodePtr, numSlots);
2542 if (newnodelist == NULL) {
2543 for (j = oldsize; j < i; j++) {
2544 FREE(unique->subtables[j].nodelist);
2546 unique->errorCode = CUDD_MEMORY_OUT;
2547 return(0);
2549 for (j = 0; j < numSlots; j++) {
2550 newnodelist[j] = sentinel;
2553 if (unique->map != NULL) {
2554 for (i = oldsize; i <= index; i++) {
2555 unique->map[i] = i;
2558 } else {
2559 /* The current table is too small: we need to allocate a new,
2560 ** larger one; move all old subtables, and initialize the new
2561 ** subtables up to index included.
2563 newsize = index + DD_DEFAULT_RESIZE;
2564 #ifdef DD_VERBOSE
2565 (void) fprintf(unique->err,
2566 "Increasing the table size from %d to %d\n",
2567 unique->maxSize, newsize);
2568 #endif
2569 newsubtables = ALLOC(DdSubtable,newsize);
2570 if (newsubtables == NULL) {
2571 unique->errorCode = CUDD_MEMORY_OUT;
2572 return(0);
2574 newvars = ALLOC(DdNodePtr,newsize);
2575 if (newvars == NULL) {
2576 FREE(newsubtables);
2577 unique->errorCode = CUDD_MEMORY_OUT;
2578 return(0);
2580 newperm = ALLOC(int,newsize);
2581 if (newperm == NULL) {
2582 FREE(newsubtables);
2583 FREE(newvars);
2584 unique->errorCode = CUDD_MEMORY_OUT;
2585 return(0);
2587 newinvperm = ALLOC(int,newsize);
2588 if (newinvperm == NULL) {
2589 FREE(newsubtables);
2590 FREE(newvars);
2591 FREE(newperm);
2592 unique->errorCode = CUDD_MEMORY_OUT;
2593 return(0);
2595 if (unique->map != NULL) {
2596 newmap = ALLOC(int,newsize);
2597 if (newmap == NULL) {
2598 FREE(newsubtables);
2599 FREE(newvars);
2600 FREE(newperm);
2601 FREE(newinvperm);
2602 unique->errorCode = CUDD_MEMORY_OUT;
2603 return(0);
2605 unique->memused += (newsize - unique->maxSize) * sizeof(int);
2607 unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
2608 sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
2609 if (newsize > unique->maxSizeZ) {
2610 FREE(unique->stack);
2611 unique->stack = ALLOC(DdNodePtr,newsize + 1);
2612 if (unique->stack == NULL) {
2613 FREE(newsubtables);
2614 FREE(newvars);
2615 FREE(newperm);
2616 FREE(newinvperm);
2617 if (unique->map != NULL) {
2618 FREE(newmap);
2620 unique->errorCode = CUDD_MEMORY_OUT;
2621 return(0);
2623 unique->stack[0] = NULL; /* to suppress harmless UMR */
2624 unique->memused +=
2625 (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
2626 * sizeof(DdNode *);
2628 for (i = 0; i < oldsize; i++) {
2629 newsubtables[i].slots = unique->subtables[i].slots;
2630 newsubtables[i].shift = unique->subtables[i].shift;
2631 newsubtables[i].keys = unique->subtables[i].keys;
2632 newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
2633 newsubtables[i].dead = unique->subtables[i].dead;
2634 newsubtables[i].nodelist = unique->subtables[i].nodelist;
2635 newsubtables[i].bindVar = unique->subtables[i].bindVar;
2636 newsubtables[i].varType = unique->subtables[i].varType;
2637 newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
2638 newsubtables[i].varHandled = unique->subtables[i].varHandled;
2639 newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
2641 newvars[i] = unique->vars[i];
2642 newperm[i] = unique->perm[i];
2643 newinvperm[i] = unique->invperm[i];
2645 for (i = oldsize; i <= index; i++) {
2646 newsubtables[i].slots = numSlots;
2647 newsubtables[i].shift = sizeof(int) * 8 -
2648 cuddComputeFloorLog2(numSlots);
2649 newsubtables[i].keys = 0;
2650 newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
2651 newsubtables[i].dead = 0;
2652 newsubtables[i].bindVar = 0;
2653 newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
2654 newsubtables[i].pairIndex = 0;
2655 newsubtables[i].varHandled = 0;
2656 newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
2658 newperm[i] = i;
2659 newinvperm[i] = i;
2660 newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
2661 if (newnodelist == NULL) {
2662 unique->errorCode = CUDD_MEMORY_OUT;
2663 return(0);
2665 for (j = 0; j < numSlots; j++) {
2666 newnodelist[j] = sentinel;
2669 if (unique->map != NULL) {
2670 for (i = 0; i < oldsize; i++) {
2671 newmap[i] = unique->map[i];
2673 for (i = oldsize; i <= index; i++) {
2674 newmap[i] = i;
2676 FREE(unique->map);
2677 unique->map = newmap;
2679 FREE(unique->subtables);
2680 unique->subtables = newsubtables;
2681 unique->maxSize = newsize;
2682 FREE(unique->vars);
2683 unique->vars = newvars;
2684 FREE(unique->perm);
2685 unique->perm = newperm;
2686 FREE(unique->invperm);
2687 unique->invperm = newinvperm;
2690 /* Now that the table is in a coherent state, create the new
2691 ** projection functions. We need to temporarily disable reordering,
2692 ** because we cannot reorder without projection functions in place.
2694 one = unique->one;
2695 zero = Cudd_Not(one);
2697 unique->size = index + 1;
2698 unique->slots += (index + 1 - oldsize) * numSlots;
2699 ddFixLimits(unique);
2701 reorderSave = unique->autoDyn;
2702 unique->autoDyn = 0;
2703 for (i = oldsize; i <= index; i++) {
2704 unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
2705 if (unique->vars[i] == NULL) {
2706 unique->autoDyn = reorderSave;
2707 for (j = oldsize; j < i; j++) {
2708 Cudd_IterDerefBdd(unique,unique->vars[j]);
2709 cuddDeallocNode(unique,unique->vars[j]);
2710 unique->vars[j] = NULL;
2712 for (j = oldsize; j <= index; j++) {
2713 FREE(unique->subtables[j].nodelist);
2714 unique->subtables[j].nodelist = NULL;
2716 unique->size = oldsize;
2717 unique->slots -= (index + 1 - oldsize) * numSlots;
2718 ddFixLimits(unique);
2719 return(0);
2721 cuddRef(unique->vars[i]);
2723 unique->autoDyn = reorderSave;
2725 return(1);
2727 } /* end of ddResizeTable */
2730 /**Function********************************************************************
2732 Synopsis [Searches the subtables above node for a parent.]
2734 Description [Searches the subtables above node for a parent. Returns 1
2735 as soon as one parent is found. Returns 0 is the search is fruitless.]
2737 SideEffects [None]
2739 SeeAlso []
2741 ******************************************************************************/
2742 static int
2743 cuddFindParent(
2744 DdManager * table,
2745 DdNode * node)
2747 int i,j;
2748 int slots;
2749 DdNodePtr *nodelist;
2750 DdNode *f;
2752 for (i = cuddI(table,node->index) - 1; i >= 0; i--) {
2753 nodelist = table->subtables[i].nodelist;
2754 slots = table->subtables[i].slots;
2756 for (j = 0; j < slots; j++) {
2757 f = nodelist[j];
2758 while (cuddT(f) > node) {
2759 f = f->next;
2761 while (cuddT(f) == node && Cudd_Regular(cuddE(f)) > node) {
2762 f = f->next;
2764 if (cuddT(f) == node && Cudd_Regular(cuddE(f)) == node) {
2765 return(1);
2770 return(0);
2772 } /* end of cuddFindParent */
2775 /**Function********************************************************************
2777 Synopsis [Adjusts the values of table limits.]
2779 Description [Adjusts the values of table fields controlling the.
2780 sizes of subtables and computed table. If the computed table is too small
2781 according to the new values, it is resized.]
2783 SideEffects [Modifies manager fields. May resize computed table.]
2785 SeeAlso []
2787 ******************************************************************************/
2788 DD_INLINE
2789 static void
2790 ddFixLimits(
2791 DdManager *unique)
2793 unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
2794 unique->cacheSlack = (int) ddMin(unique->maxCacheHard,
2795 DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots) -
2796 2 * (int) unique->cacheSlots;
2797 if (unique->cacheSlots < unique->slots/2 && unique->cacheSlack >= 0)
2798 cuddCacheResize(unique);
2799 return;
2801 } /* end of ddFixLimits */
2804 #ifndef DD_UNSORTED_FREE_LIST
2805 #ifdef DD_RED_BLACK_FREE_LIST
2806 /**Function********************************************************************
2808 Synopsis [Inserts a DdNode in a red/black search tree.]
2810 Description [Inserts a DdNode in a red/black search tree. Nodes from
2811 the same "page" (defined by DD_PAGE_MASK) are linked in a LIFO list.]
2813 SideEffects [None]
2815 SeeAlso [cuddOrderedThread]
2817 ******************************************************************************/
2818 static void
2819 cuddOrderedInsert(
2820 DdNodePtr * root,
2821 DdNodePtr node)
2823 DdNode *scan;
2824 DdNodePtr *scanP;
2825 DdNodePtr *stack[DD_STACK_SIZE];
2826 int stackN = 0;
2828 scanP = root;
2829 while ((scan = *scanP) != NULL) {
2830 stack[stackN++] = scanP;
2831 if (DD_INSERT_COMPARE(node, scan) == 0) { /* add to page list */
2832 DD_NEXT(node) = DD_NEXT(scan);
2833 DD_NEXT(scan) = node;
2834 return;
2836 scanP = (node < scan) ? &DD_LEFT(scan) : &DD_RIGHT(scan);
2838 DD_RIGHT(node) = DD_LEFT(node) = DD_NEXT(node) = NULL;
2839 DD_COLOR(node) = DD_RED;
2840 *scanP = node;
2841 stack[stackN] = &node;
2842 cuddDoRebalance(stack,stackN);
2844 } /* end of cuddOrderedInsert */
2847 /**Function********************************************************************
2849 Synopsis [Threads all the nodes of a search tree into a linear list.]
2851 Description [Threads all the nodes of a search tree into a linear
2852 list. For each node of the search tree, the "left" child, if non-null, has
2853 a lower address than its parent, and the "right" child, if non-null, has a
2854 higher address than its parent.
2855 The list is sorted in order of increasing addresses. The search
2856 tree is destroyed as a result of this operation. The last element of
2857 the linear list is made to point to the address passed in list. Each
2858 node if the search tree is a linearly-linked list of nodes from the
2859 same memory page (as defined in DD_PAGE_MASK). When a node is added to
2860 the linear list, all the elements of the linked list are added.]
2862 SideEffects [The search tree is destroyed as a result of this operation.]
2864 SeeAlso [cuddOrderedInsert]
2866 ******************************************************************************/
2867 static DdNode *
2868 cuddOrderedThread(
2869 DdNode * root,
2870 DdNode * list)
2872 DdNode *current, *next, *prev, *end;
2874 current = root;
2875 /* The first word in the node is used to implement a stack that holds
2876 ** the nodes from the root of the tree to the current node. Here we
2877 ** put the root of the tree at the bottom of the stack.
2879 *((DdNodePtr *) current) = NULL;
2881 while (current != NULL) {
2882 if (DD_RIGHT(current) != NULL) {
2883 /* If possible, we follow the "right" link. Eventually we'll
2884 ** find the node with the largest address in the current tree.
2885 ** In this phase we use the first word of a node to implemen
2886 ** a stack of the nodes on the path from the root to "current".
2887 ** Also, we disconnect the "right" pointers to indicate that
2888 ** we have already followed them.
2890 next = DD_RIGHT(current);
2891 DD_RIGHT(current) = NULL;
2892 *((DdNodePtr *)next) = current;
2893 current = next;
2894 } else {
2895 /* We can't proceed along the "right" links any further.
2896 ** Hence "current" is the largest element in the current tree.
2897 ** We make this node the new head of "list". (Repeating this
2898 ** operation until the tree is empty yields the desired linear
2899 ** threading of all nodes.)
2901 prev = *((DdNodePtr *) current); /* save prev node on stack in prev */
2902 /* Traverse the linked list of current until the end. */
2903 for (end = current; DD_NEXT(end) != NULL; end = DD_NEXT(end));
2904 DD_NEXT(end) = list; /* attach "list" at end and make */
2905 list = current; /* "current" the new head of "list" */
2906 /* Now, if current has a "left" child, we push it on the stack.
2907 ** Otherwise, we just continue with the parent of "current".
2909 if (DD_LEFT(current) != NULL) {
2910 next = DD_LEFT(current);
2911 *((DdNodePtr *) next) = prev;
2912 current = next;
2913 } else {
2914 current = prev;
2919 return(list);
2921 } /* end of cuddOrderedThread */
2924 /**Function********************************************************************
2926 Synopsis [Performs the left rotation for red/black trees.]
2928 Description []
2930 SideEffects [None]
2932 SeeAlso [cuddRotateRight]
2934 ******************************************************************************/
2935 DD_INLINE
2936 static void
2937 cuddRotateLeft(
2938 DdNodePtr * nodeP)
2940 DdNode *newRoot;
2941 DdNode *oldRoot = *nodeP;
2943 *nodeP = newRoot = DD_RIGHT(oldRoot);
2944 DD_RIGHT(oldRoot) = DD_LEFT(newRoot);
2945 DD_LEFT(newRoot) = oldRoot;
2947 } /* end of cuddRotateLeft */
2950 /**Function********************************************************************
2952 Synopsis [Performs the right rotation for red/black trees.]
2954 Description []
2956 SideEffects [None]
2958 SeeAlso [cuddRotateLeft]
2960 ******************************************************************************/
2961 DD_INLINE
2962 static void
2963 cuddRotateRight(
2964 DdNodePtr * nodeP)
2966 DdNode *newRoot;
2967 DdNode *oldRoot = *nodeP;
2969 *nodeP = newRoot = DD_LEFT(oldRoot);
2970 DD_LEFT(oldRoot) = DD_RIGHT(newRoot);
2971 DD_RIGHT(newRoot) = oldRoot;
2973 } /* end of cuddRotateRight */
2976 /**Function********************************************************************
2978 Synopsis [Rebalances a red/black tree.]
2980 Description []
2982 SideEffects [None]
2984 SeeAlso []
2986 ******************************************************************************/
2987 static void
2988 cuddDoRebalance(
2989 DdNodePtr ** stack,
2990 int stackN)
2992 DdNodePtr *xP, *parentP, *grandpaP;
2993 DdNode *x, *y, *parent, *grandpa;
2995 xP = stack[stackN];
2996 x = *xP;
2997 /* Work our way back up, re-balancing the tree. */
2998 while (--stackN >= 0) {
2999 parentP = stack[stackN];
3000 parent = *parentP;
3001 if (DD_IS_BLACK(parent)) break;
3002 /* Since the root is black, here a non-null grandparent exists. */
3003 grandpaP = stack[stackN-1];
3004 grandpa = *grandpaP;
3005 if (parent == DD_LEFT(grandpa)) {
3006 y = DD_RIGHT(grandpa);
3007 if (y != NULL && DD_IS_RED(y)) {
3008 DD_COLOR(parent) = DD_BLACK;
3009 DD_COLOR(y) = DD_BLACK;
3010 DD_COLOR(grandpa) = DD_RED;
3011 x = grandpa;
3012 stackN--;
3013 } else {
3014 if (x == DD_RIGHT(parent)) {
3015 cuddRotateLeft(parentP);
3016 DD_COLOR(x) = DD_BLACK;
3017 } else {
3018 DD_COLOR(parent) = DD_BLACK;
3020 DD_COLOR(grandpa) = DD_RED;
3021 cuddRotateRight(grandpaP);
3022 break;
3024 } else {
3025 y = DD_LEFT(grandpa);
3026 if (y != NULL && DD_IS_RED(y)) {
3027 DD_COLOR(parent) = DD_BLACK;
3028 DD_COLOR(y) = DD_BLACK;
3029 DD_COLOR(grandpa) = DD_RED;
3030 x = grandpa;
3031 stackN--;
3032 } else {
3033 if (x == DD_LEFT(parent)) {
3034 cuddRotateRight(parentP);
3035 DD_COLOR(x) = DD_BLACK;
3036 } else {
3037 DD_COLOR(parent) = DD_BLACK;
3039 DD_COLOR(grandpa) = DD_RED;
3040 cuddRotateLeft(grandpaP);
3044 DD_COLOR(*(stack[0])) = DD_BLACK;
3046 } /* end of cuddDoRebalance */
3047 #endif
3048 #endif
3051 /**Function********************************************************************
3053 Synopsis [Fixes a variable tree after the insertion of new subtables.]
3055 Description [Fixes a variable tree after the insertion of new subtables.
3056 After such an insertion, the low fields of the tree below the insertion
3057 point are inconsistent.]
3059 SideEffects [None]
3061 SeeAlso []
3063 ******************************************************************************/
3064 static void
3065 ddPatchTree(
3066 DdManager *dd,
3067 MtrNode *treenode)
3069 MtrNode *auxnode = treenode;
3071 while (auxnode != NULL) {
3072 auxnode->low = dd->perm[auxnode->index];
3073 if (auxnode->child != NULL) {
3074 ddPatchTree(dd, auxnode->child);
3076 auxnode = auxnode->younger;
3079 return;
3081 } /* end of ddPatchTree */
3084 #ifdef DD_DEBUG
3085 /**Function********************************************************************
3087 Synopsis [Checks whether a collision list is ordered.]
3089 Description []
3091 SideEffects [None]
3093 SeeAlso []
3095 ******************************************************************************/
3096 static int
3097 cuddCheckCollisionOrdering(
3098 DdManager *unique,
3099 int i,
3100 int j)
3102 int slots;
3103 DdNode *node, *next;
3104 DdNodePtr *nodelist;
3105 DdNode *sentinel = &(unique->sentinel);
3107 nodelist = unique->subtables[i].nodelist;
3108 slots = unique->subtables[i].slots;
3109 node = nodelist[j];
3110 if (node == sentinel) return(1);
3111 next = node->next;
3112 while (next != sentinel) {
3113 if (cuddT(node) < cuddT(next) ||
3114 (cuddT(node) == cuddT(next) && cuddE(node) < cuddE(next))) {
3115 (void) fprintf(unique->err,
3116 "Unordered list: index %u, position %d\n", i, j);
3117 return(0);
3119 node = next;
3120 next = node->next;
3122 return(1);
3124 } /* end of cuddCheckCollisionOrdering */
3125 #endif
3130 /**Function********************************************************************
3132 Synopsis [Reports problem in garbage collection.]
3134 Description []
3136 SideEffects [None]
3138 SeeAlso [cuddGarbageCollect cuddGarbageCollectZdd]
3140 ******************************************************************************/
3141 static void
3142 ddReportRefMess(
3143 DdManager *unique /* manager */,
3144 int i /* table in which the problem occurred */,
3145 const char *caller /* procedure that detected the problem */)
3147 if (i == CUDD_CONST_INDEX) {
3148 (void) fprintf(unique->err,
3149 "%s: problem in constants\n", caller);
3150 } else if (i != -1) {
3151 (void) fprintf(unique->err,
3152 "%s: problem in table %d\n", caller, i);
3154 (void) fprintf(unique->err, " dead count != deleted\n");
3155 (void) fprintf(unique->err, " This problem is often due to a missing \
3156 call to Cudd_Ref\n or to an extra call to Cudd_RecursiveDeref.\n \
3157 See the CUDD Programmer's Guide for additional details.");
3158 abort();
3160 } /* end of ddReportRefMess */