1 /**CFile***********************************************************************
7 Synopsis [Unique table management functions.]
9 Description [External procedures included in this module:
13 Internal procedures included in this module:
18 <li> cuddGarbageCollect()
20 <li> cuddZddGetNodeIVO()
21 <li> cuddUniqueInter()
22 <li> cuddUniqueInterIVO()
23 <li> cuddUniqueInterZdd()
24 <li> cuddUniqueConst()
26 <li> cuddShrinkSubtable()
27 <li> cuddInsertSubtables()
28 <li> cuddDestroySubtables()
29 <li> cuddResizeTableZdd()
30 <li> cuddSlowTableGrowth()
32 Static procedures included in this module:
37 <li> cuddOrderedInsert()
38 <li> cuddOrderedThread()
40 <li> cuddRotateRight()
41 <li> cuddDoRebalance()
42 <li> cuddCheckCollisionOrdering()
47 Author [Fabio Somenzi]
49 Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado
53 Redistribution and use in source and binary forms, with or without
54 modification, are permitted provided that the following conditions
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 ******************************************************************************/
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
96 #define DD_PAGE_SIZE 8192
97 #define DD_PAGE_MASK ~(DD_PAGE_SIZE - 1)
101 /*---------------------------------------------------------------------------*/
102 /* Stucture declarations */
103 /*---------------------------------------------------------------------------*/
105 /* This is a hack for when CUDD_VALUE_TYPE is double */
107 CUDD_VALUE_TYPE value
;
108 unsigned int bits
[2];
111 /*---------------------------------------------------------------------------*/
112 /* Type declarations */
113 /*---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------*/
116 /* Variable declarations */
117 /*---------------------------------------------------------------------------*/
120 static char rcsid
[] DD_UNUSED
= "$Id: cuddTable.c,v 1.122 2009/02/19 16:24:28 fabio Exp $";
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)
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
);
160 static void ddPatchTree (DdManager
*dd
, MtrNode
*treenode
);
162 static int cuddCheckCollisionOrdering (DdManager
*unique
, int i
, int j
);
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 >= p.]
182 ******************************************************************************/
195 while ((unsigned) (i
* i
) <= 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.]
227 SeeAlso [cuddDynamicAllocNode]
229 ******************************************************************************/
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
) >
244 unique
->errorCode
= CUDD_TOO_MANY_NODES
;
247 if (unique
->stash
== NULL
|| unique
->memused
> unique
->maxmemhard
) {
248 (void) cuddGarbageCollect(unique
,1);
251 if (unique
->nextFree
== NULL
) {
252 if (unique
->memused
> unique
->maxmemhard
) {
253 unique
->errorCode
= CUDD_MAX_MEM_EXCEEDED
;
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
;
262 /* No more memory: Try collecting garbage. If this succeeds,
263 ** we end up with mem still NULL, but unique->nextFree !=
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
) {
271 unique
->stash
= NULL
;
272 /* Inhibit resizing of tables. */
273 cuddSlowTableGrowth(unique
);
275 mem
= (DdNodePtr
*) ALLOC(DdNode
,DD_MEM_CHUNK
+ 1);
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
;
285 (void) fprintf(unique
->err
,
286 "cuddAllocNode: out of memory");
287 (void) fprintf(unique
->err
, "Memory in use = %lu\n",
294 if (mem
!= NULL
) { /* successful allocation; slice memory */
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
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
;
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];
321 node
= unique
->nextFree
;
322 unique
->nextFree
= node
->next
;
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.]
337 SeeAlso [Cudd_Init cuddFreeTable]
339 ******************************************************************************/
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);
354 if (unique
== NULL
) {
357 sentinel
= &(unique
->sentinel
);
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. */
374 while (slots
< numSlots
) {
377 unique
->initSlots
= slots
;
378 shift
= sizeof(int) * 8 - cuddComputeFloorLog2(slots
);
380 unique
->slots
= (numVars
+ numVarsZ
+ 1) * slots
;
382 unique
->maxLive
= ~0; /* very large number */
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
) {
397 unique
->subtableZ
= ALLOC(DdSubtable
,unique
->maxSizeZ
);
398 if (unique
->subtableZ
== NULL
) {
399 FREE(unique
->subtables
);
403 unique
->perm
= ALLOC(int,unique
->maxSize
);
404 if (unique
->perm
== NULL
) {
405 FREE(unique
->subtables
);
406 FREE(unique
->subtableZ
);
410 unique
->invperm
= ALLOC(int,unique
->maxSize
);
411 if (unique
->invperm
== NULL
) {
412 FREE(unique
->subtables
);
413 FREE(unique
->subtableZ
);
418 unique
->permZ
= ALLOC(int,unique
->maxSizeZ
);
419 if (unique
->permZ
== NULL
) {
420 FREE(unique
->subtables
);
421 FREE(unique
->subtableZ
);
423 FREE(unique
->invperm
);
427 unique
->invpermZ
= ALLOC(int,unique
->maxSizeZ
);
428 if (unique
->invpermZ
== NULL
) {
429 FREE(unique
->subtables
);
430 FREE(unique
->subtableZ
);
432 FREE(unique
->invperm
);
438 unique
->stack
= ALLOC(DdNodePtr
,ddMax(unique
->maxSize
,unique
->maxSizeZ
)+1);
439 if (unique
->stack
== NULL
) {
440 FREE(unique
->subtables
);
441 FREE(unique
->subtableZ
);
443 FREE(unique
->invperm
);
445 FREE(unique
->invpermZ
);
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
);
458 FREE(unique
->invperm
);
460 FREE(unique
->invpermZ
);
465 for (i
= 0; i
< unique
->deathRowDepth
; i
++) {
466 unique
->deathRow
[i
] = NULL
;
468 unique
->nextDead
= 0;
469 unique
->deadMask
= unique
->deathRowDepth
- 1;
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
);
492 FREE(unique
->invperm
);
494 FREE(unique
->invpermZ
);
499 for (j
= 0; (unsigned) j
< slots
; j
++) {
500 nodelist
[j
] = sentinel
;
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
);
522 FREE(unique
->invperm
);
524 FREE(unique
->invpermZ
);
529 for (j
= 0; (unsigned) j
< slots
; j
++) {
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
);
551 FREE(unique
->invperm
);
553 FREE(unique
->invpermZ
);
558 for (j
= 0; (unsigned) j
< slots
; j
++) {
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
);
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
;
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;
614 unique
->reordTime
= 0;
616 unique
->nodesDropped
= 0;
617 unique
->nodesFreed
= 0;
619 unique
->peakLiveNodes
= 0;
620 #ifdef DD_UNIQUE_PROFILE
621 unique
->uniqueLookUps
= 0;
622 unique
->uniqueLinks
= 0;
625 unique
->recursiveCalls
= 0;
626 unique
->swapSteps
= 0;
628 unique
->nextSample
= 250000;
634 } /* end of cuddInitTable */
637 /**Function********************************************************************
639 Synopsis [Frees the resources associated to a unique table.]
645 SeeAlso [cuddInitTable]
647 ******************************************************************************/
653 DdNodePtr
*memlist
= unique
->memoryList
;
656 if (unique
->univ
!= NULL
) cuddZddFreeUniv(unique
);
657 while (memlist
!= NULL
) {
658 next
= (DdNodePtr
*) memlist
[0]; /* link to next block */
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
);
677 FREE(unique
->invperm
);
678 FREE(unique
->invpermZ
);
680 if (unique
->map
!= NULL
) FREE(unique
->map
);
682 #ifndef DD_NO_DEATH_ROW
683 FREE(unique
->deathRow
);
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
);
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.]
717 ******************************************************************************/
724 DdCache
*cache
= unique
->cache
;
725 DdNode
*sentinel
= &(unique
->sentinel
);
727 int i
, j
, deleted
, totalDeleted
, totalDeletedZ
;
733 #ifndef DD_UNSORTED_FREE_LIST
734 #ifdef DD_RED_BLACK_FREE_LIST
737 DdNodePtr
*memListTrav
, *nxtNode
;
738 DdNode
*downTrav
, *sentry
;
743 #ifndef DD_NO_DEATH_ROW
744 cuddClearDeathRow(unique
);
747 hook
= unique
->preGCHook
;
748 while (hook
!= NULL
) {
749 int res
= (hook
->f
)(unique
,"DD",NULL
);
750 if (res
== 0) return(0);
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);
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
);
771 (void) fprintf(unique
->err
,"GC fraction = %.2f\t", DD_GC_FRAC_HI
);
772 (void) fprintf(unique
->err
,"minDead = %d\n", unique
->minDead
);
774 unique
->gcFrac
= DD_GC_FRAC_HI
;
778 localTime
= util_cpu_time();
780 unique
->garbageCollections
++;
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
);
790 /* Remove references to garbage collected nodes from the cache. */
792 slots
= unique
->cacheSlots
;
793 for (i
= 0; i
< slots
; 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)) {
802 unique
->cachedeletions
++;
806 cuddLocalCacheClearDead(unique
);
809 /* Now return dead nodes to free list. Count them for sanity check. */
811 #ifndef DD_UNSORTED_FREE_LIST
812 #ifdef DD_RED_BLACK_FREE_LIST
817 for (i
= 0; i
< unique
->size
; i
++) {
818 if (unique
->subtables
[i
].dead
== 0) continue;
819 nodelist
= unique
->subtables
[i
].nodelist
;
822 slots
= unique
->subtables
[i
].slots
;
823 for (j
= 0; j
< slots
; j
++) {
824 lastP
= &(nodelist
[j
]);
826 while (node
!= sentinel
) {
828 if (node
->ref
== 0) {
830 #ifndef DD_UNSORTED_FREE_LIST
831 #ifdef DD_RED_BLACK_FREE_LIST
833 #pragma pointer_size save
834 #pragma pointer_size short
836 cuddOrderedInsert(&tree
,node
);
838 #pragma pointer_size restore
842 cuddDeallocNode(unique
,node
);
846 lastP
= &(node
->next
);
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
;
862 slots
= unique
->constants
.slots
;
863 for (j
= 0; j
< slots
; j
++) {
864 lastP
= &(nodelist
[j
]);
866 while (node
!= NULL
) {
868 if (node
->ref
== 0) {
870 #ifndef DD_UNSORTED_FREE_LIST
871 #ifdef DD_RED_BLACK_FREE_LIST
873 #pragma pointer_size save
874 #pragma pointer_size short
876 cuddOrderedInsert(&tree
,node
);
878 #pragma pointer_size restore
882 cuddDeallocNode(unique
,node
);
886 lastP
= &(node
->next
);
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
;
905 unique
->nodesFreed
+= (double) totalDeleted
;
910 for (i
= 0; i
< unique
->sizeZ
; i
++) {
911 if (unique
->subtableZ
[i
].dead
== 0) continue;
912 nodelist
= unique
->subtableZ
[i
].nodelist
;
915 slots
= unique
->subtableZ
[i
].slots
;
916 for (j
= 0; j
< slots
; j
++) {
917 lastP
= &(nodelist
[j
]);
919 while (node
!= NULL
) {
921 if (node
->ref
== 0) {
923 #ifndef DD_UNSORTED_FREE_LIST
924 #ifdef DD_RED_BLACK_FREE_LIST
926 #pragma pointer_size save
927 #pragma pointer_size short
929 cuddOrderedInsert(&tree
,node
);
931 #pragma pointer_size restore
935 cuddDeallocNode(unique
,node
);
939 lastP
= &(node
->next
);
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
;
962 unique
->nodesFreed
+= (double) totalDeletedZ
;
966 #ifndef DD_UNSORTED_FREE_LIST
967 #ifdef DD_RED_BLACK_FREE_LIST
968 unique
->nextFree
= cuddOrderedThread(tree
,unique
->nextFree
);
970 memListTrav
= unique
->memoryList
;
972 while (memListTrav
!= NULL
) {
974 nxtNode
= (DdNodePtr
*)memListTrav
[0];
975 offset
= (ptruint
) memListTrav
& (sizeof(DdNode
) - 1);
976 memListTrav
+= (sizeof(DdNode
) - offset
) / sizeof(DdNodePtr
);
977 downTrav
= (DdNode
*)memListTrav
;
980 if (downTrav
[k
].ref
== 0) {
981 if (sentry
== NULL
) {
982 unique
->nextFree
= sentry
= &downTrav
[k
];
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
;
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);
1006 (void) fprintf(unique
->err
," done\n");
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.]
1024 SeeAlso [cuddUniqueInterZdd]
1026 ******************************************************************************/
1036 if (T
== DD_ZERO(zdd
))
1038 node
= cuddUniqueInterZdd(zdd
, id
, T
, E
);
1041 } /* end of cuddZddGetNode */
1044 /**Function********************************************************************
1046 Synopsis [Wrapper for cuddUniqueInterZdd that is independent of variable
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.]
1057 SeeAlso [cuddZddGetNode cuddZddIsop]
1059 ******************************************************************************/
1068 DdNode
*zdd_one
= DD_ONE(dd
);
1069 DdNode
*zdd_zero
= DD_ZERO(dd
);
1071 f
= cuddUniqueInterZdd(dd
, index
, zdd_one
, zdd_zero
);
1076 t
= cuddZddProduct(dd
, f
, g
);
1078 Cudd_RecursiveDerefZdd(dd
, f
);
1082 Cudd_RecursiveDerefZdd(dd
, f
);
1083 r
= cuddZddUnion(dd
, t
, h
);
1085 Cudd_RecursiveDerefZdd(dd
, t
);
1089 Cudd_RecursiveDerefZdd(dd
, t
);
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.]
1111 SeeAlso [cuddUniqueInterZdd]
1113 ******************************************************************************/
1124 DdNodePtr
*nodelist
;
1126 DdNodePtr
*previousP
;
1127 DdSubtable
*subtable
;
1130 #ifdef DD_UNIQUE_PROFILE
1131 unique
->uniqueLookUps
++;
1134 if (index
>= unique
->size
) {
1135 if (!ddResizeTable(unique
,index
)) return(NULL
);
1138 level
= unique
->perm
[index
];
1139 subtable
= &(unique
->subtables
[level
]);
1142 assert(level
< (unsigned) cuddI(unique
,T
->index
));
1143 assert(level
< (unsigned) cuddI(unique
,Cudd_Regular(E
)->index
));
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
++;
1158 while (T
== cuddT(looking
) && E
< cuddE(looking
)) {
1159 previousP
= &(looking
->next
);
1160 looking
= *previousP
;
1161 #ifdef DD_UNIQUE_PROFILE
1162 unique
->uniqueLinks
++;
1165 if (T
== cuddT(looking
) && E
== cuddE(looking
)) {
1166 if (looking
->ref
== 0) {
1167 cuddReclaim(unique
,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
) {
1176 retval
= Cudd_DebugCheck(unique
);
1177 if (retval
!= 0) return(NULL
);
1178 retval
= Cudd_CheckKeys(unique
);
1179 if (retval
!= 0) return(NULL
);
1181 retval
= Cudd_ReduceHeap(unique
,unique
->autoMethod
,10); /* 10 = whatever */
1182 if (retval
== 0) unique
->reordered
= 2;
1184 retval
= Cudd_DebugCheck(unique
);
1185 if (retval
!= 0) unique
->reordered
= 2;
1186 retval
= Cudd_CheckKeys(unique
);
1187 if (retval
!= 0) unique
->reordered
= 2;
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);
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
++;
1216 while (T
== cuddT(looking
) && E
< cuddE(looking
)) {
1217 previousP
= &(looking
->next
);
1218 looking
= *previousP
;
1219 #ifdef DD_UNIQUE_PROFILE
1220 unique
->uniqueLinks
++;
1225 gcNumber
= unique
->garbageCollections
;
1226 looking
= cuddAllocNode(unique
);
1227 if (looking
== NULL
) {
1233 if (gcNumber
!= unique
->garbageCollections
) {
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
++;
1247 while (T
== cuddT(looking2
) && E
< cuddE(looking2
)) {
1248 previousP
= &(looking2
->next
);
1249 looking2
= *previousP
;
1250 #ifdef DD_UNIQUE_PROFILE
1251 unique
->uniqueLinks
++;
1255 looking
->index
= index
;
1258 looking
->next
= *previousP
;
1259 *previousP
= looking
;
1260 cuddSatInc(T
->ref
); /* we know T is a regular pointer */
1264 cuddCheckCollisionOrdering(unique
,level
,pos
);
1269 } /* end of cuddUniqueInter */
1272 /**Function********************************************************************
1274 Synopsis [Wrapper for cuddUniqueInter that is independent of variable
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.]
1285 SeeAlso [cuddUniqueInter Cudd_MakeBddFromZddCover]
1287 ******************************************************************************/
1298 v
= cuddUniqueInter(unique
, index
, DD_ONE(unique
),
1299 Cudd_Not(DD_ONE(unique
)));
1303 result
= cuddBddIteRecur(unique
, v
, T
, E
);
1304 Cudd_RecursiveDeref(unique
, v
);
1309 /**Function********************************************************************
1311 Synopsis [Checks the unique table for the existence of an internal
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.]
1324 SeeAlso [cuddUniqueInter]
1326 ******************************************************************************/
1337 DdNodePtr
*nodelist
;
1339 DdSubtable
*subtable
;
1341 #ifdef DD_UNIQUE_PROFILE
1342 unique
->uniqueLookUps
++;
1345 if (index
>= unique
->sizeZ
) {
1346 if (!cuddResizeTableZdd(unique
,index
)) return(NULL
);
1349 level
= unique
->permZ
[index
];
1350 subtable
= &(unique
->subtableZ
[level
]);
1353 assert(level
< (unsigned) cuddIZ(unique
,T
->index
));
1354 assert(level
< (unsigned) cuddIZ(unique
,Cudd_Regular(E
)->index
));
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);
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
);
1377 looking
= looking
->next
;
1378 #ifdef DD_UNIQUE_PROFILE
1379 unique
->uniqueLinks
++;
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
) {
1387 retval
= Cudd_DebugCheck(unique
);
1388 if (retval
!= 0) return(NULL
);
1389 retval
= Cudd_CheckKeys(unique
);
1390 if (retval
!= 0) return(NULL
);
1392 retval
= Cudd_zddReduceHeap(unique
,unique
->autoMethodZ
,10); /* 10 = whatever */
1393 if (retval
== 0) unique
->reordered
= 2;
1395 retval
= Cudd_DebugCheck(unique
);
1396 if (retval
!= 0) unique
->reordered
= 2;
1397 retval
= Cudd_CheckKeys(unique
);
1398 if (retval
!= 0) unique
->reordered
= 2;
1406 looking
= cuddAllocNode(unique
);
1407 if (looking
== NULL
) return(NULL
);
1408 looking
->index
= index
;
1411 looking
->next
= nodelist
[pos
];
1412 nodelist
[pos
] = 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.]
1433 ******************************************************************************/
1437 CUDD_VALUE_TYPE value
)
1440 DdNodePtr
*nodelist
;
1444 #ifdef DD_UNIQUE_PROFILE
1445 unique
->uniqueLookUps
++;
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);
1453 cuddRehash(unique
,CUDD_CONST_INDEX
);
1457 cuddAdjust(value
); /* for the case of crippled infinities */
1459 if (ddAbs(value
) < unique
->epsilon
) {
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
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
);
1481 looking
= looking
->next
;
1482 #ifdef DD_UNIQUE_PROFILE
1483 unique
->uniqueLinks
++;
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
;
1499 } /* end of cuddUniqueConst */
1502 /**Function********************************************************************
1504 Synopsis [Rehashes a unique subtable.]
1506 Description [Doubles the size of a unique subtable and rehashes its
1513 ******************************************************************************/
1519 unsigned int slots
, oldslots
;
1520 int shift
, oldshift
;
1522 DdNodePtr
*nodelist
, *oldnodelist
;
1523 DdNode
*node
, *next
;
1524 DdNode
*sentinel
= &(unique
->sentinel
);
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
);
1533 (void) fprintf(unique
->err
,"GC fraction = %.2f\t", DD_GC_FRAC_LO
);
1534 (void) fprintf(unique
->err
,"minDead = %d\n", unique
->minDead
);
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
);
1542 (void) fprintf(unique
->err
,"GC fraction = %.2f\t", DD_GC_FRAC_MIN
);
1543 (void) fprintf(unique
->err
,"minDead = %d\n", unique
->minDead
);
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
);
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
) {
1593 pos
= ddHash(cuddT(node
), cuddE(node
), shift
);
1596 oddP
= &(node
->next
);
1599 evenP
= &(node
->next
);
1603 *evenP
= *oddP
= sentinel
;
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
);
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;
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
++) {
1646 for (j
= 0; (unsigned) j
< oldslots
; j
++) {
1647 node
= oldnodelist
[j
];
1648 while (node
!= NULL
) {
1650 split
.value
= cuddV(node
);
1651 pos
= ddHash(split
.bits
[0], split
.bits
[1], shift
);
1652 node
->next
= nodelist
[pos
];
1653 nodelist
[pos
] = node
;
1660 (void) fprintf(unique
->err
,
1661 "rehashing constants: keys %d dead %d new size %d\n",
1662 unique
->constants
.keys
,unique
->constants
.dead
,slots
);
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.]
1683 SeeAlso [cuddRehash]
1685 ******************************************************************************/
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
) {
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
;
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
);
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
;
1730 posn
= ddHash(cuddT(node
), cuddE(node
), shift
);
1731 previousP
= &(nodelist
[posn
]);
1732 looking
= *previousP
;
1735 while (T
< cuddT(looking
)) {
1736 previousP
= &(looking
->next
);
1737 looking
= *previousP
;
1738 #ifdef DD_UNIQUE_PROFILE
1739 unique
->uniqueLinks
++;
1742 while (T
== cuddT(looking
) && E
< cuddE(looking
)) {
1743 previousP
= &(looking
->next
);
1744 looking
= *previousP
;
1745 #ifdef DD_UNIQUE_PROFILE
1746 unique
->uniqueLinks
++;
1749 node
->next
= *previousP
;
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.]
1776 SeeAlso [cuddDestroySubtables]
1778 ******************************************************************************/
1780 cuddInsertSubtables(
1785 DdSubtable
*newsubtables
;
1786 DdNodePtr
*newnodelist
;
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
;
1796 assert(n
> 0 && level
< unique
->size
);
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
;
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
;
1853 /* The current table is too small: we need to allocate a new,
1854 ** larger one; move all old subtables, and initialize the new
1857 newsize
= oldsize
+ n
+ DD_DEFAULT_RESIZE
;
1859 (void) fprintf(unique
->err
,
1860 "Increasing the table size from %d to %d\n",
1861 unique
->maxSize
, newsize
);
1863 /* Allocate memory for new arrays (except nodelists). */
1864 newsubtables
= ALLOC(DdSubtable
,newsize
);
1865 if (newsubtables
== NULL
) {
1866 unique
->errorCode
= CUDD_MEMORY_OUT
;
1869 newvars
= ALLOC(DdNodePtr
,newsize
);
1870 if (newvars
== NULL
) {
1871 unique
->errorCode
= CUDD_MEMORY_OUT
;
1875 newperm
= ALLOC(int,newsize
);
1876 if (newperm
== NULL
) {
1877 unique
->errorCode
= CUDD_MEMORY_OUT
;
1882 newinvperm
= ALLOC(int,newsize
);
1883 if (newinvperm
== NULL
) {
1884 unique
->errorCode
= CUDD_MEMORY_OUT
;
1890 if (unique
->map
!= NULL
) {
1891 newmap
= ALLOC(int,newsize
);
1892 if (newmap
== NULL
) {
1893 unique
->errorCode
= CUDD_MEMORY_OUT
;
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
;
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
++) {
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
;
1988 unique
->vars
= newvars
;
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
;
2001 unique
->stack
[0] = NULL
; /* to suppress harmless UMR */
2003 (newsize
- ddMax(unique
->maxSize
,unique
->maxSizeZ
))
2007 /* Update manager parameters to account for the new subtables. */
2008 unique
->slots
+= n
* numSlots
;
2009 ddFixLimits(unique
);
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.
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
);
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
;
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(
2097 DdSubtable
*subtables
;
2098 DdNodePtr
*nodelist
;
2100 int firstIndex
, lastIndex
;
2101 int index
, level
, newlevel
;
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
]);
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
;
2155 assert(subtables
[level
].keys
== 0);
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.
2171 for (level
= lowestLevel
+ 1; level
< unique
->size
; level
++) {
2172 if (subtables
[level
].keys
== 0) {
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
);
2201 unique
->minDead
= (unsigned) (unique
->gcFrac
* (double) unique
->slots
);
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.]
2222 SeeAlso [ddResizeTable]
2224 ******************************************************************************/
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
;
2255 for (j
= 0; (unsigned) j
< numSlots
; j
++) {
2256 newnodelist
[j
] = NULL
;
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
;
2266 (void) fprintf(unique
->err
,
2267 "Increasing the ZDD table size from %d to %d\n",
2268 unique
->maxSizeZ
, newsize
);
2270 newsubtables
= ALLOC(DdSubtable
,newsize
);
2271 if (newsubtables
== NULL
) {
2272 unique
->errorCode
= CUDD_MEMORY_OUT
;
2275 newperm
= ALLOC(int,newsize
);
2276 if (newperm
== NULL
) {
2277 unique
->errorCode
= CUDD_MEMORY_OUT
;
2280 newinvperm
= ALLOC(int,newsize
);
2281 if (newinvperm
== NULL
) {
2282 unique
->errorCode
= CUDD_MEMORY_OUT
;
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
;
2294 unique
->stack
[0] = NULL
; /* to suppress harmless UMR */
2296 (newsize
- ddMax(unique
->maxSize
,unique
->maxSizeZ
))
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;
2318 newnodelist
= newsubtables
[i
].nodelist
= ALLOC(DdNodePtr
, numSlots
);
2319 if (newnodelist
== NULL
) {
2320 unique
->errorCode
= CUDD_MEMORY_OUT
;
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
;
2351 unique
->autoDynZ
= reorderSave
;
2355 } /* end of cuddResizeTableZdd */
2358 /**Function********************************************************************
2360 Synopsis [Adjusts parameters of a table to slow down its growth.]
2368 ******************************************************************************/
2370 cuddSlowTableGrowth(
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.]
2403 SeeAlso [cuddRehash]
2405 ******************************************************************************/
2411 unsigned int slots
, oldslots
;
2412 int shift
, oldshift
;
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
);
2422 if (unique
->gcFrac
== DD_GC_FRAC_HI
) {
2423 (void) fprintf(unique
->err
,"GC fraction = %.2f\t",
2425 (void) fprintf(unique
->err
,"minDead = %d\n", unique
->minDead
);
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. */
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;
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
++) {
2467 for (j
= 0; (unsigned) j
< oldslots
; j
++) {
2468 node
= oldnodelist
[j
];
2469 while (node
!= NULL
) {
2471 pos
= ddHash(cuddT(node
), cuddE(node
), shift
);
2472 node
->next
= nodelist
[pos
];
2473 nodelist
[pos
] = node
;
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
);
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.]
2504 SeeAlso [cuddResizeTableZdd]
2506 ******************************************************************************/
2512 DdSubtable
*newsubtables
;
2513 DdNodePtr
*newnodelist
;
2515 DdNode
*sentinel
= &(unique
->sentinel
);
2516 int oldsize
,newsize
;
2517 int i
,j
,reorderSave
;
2518 int numSlots
= unique
->initSlots
;
2519 int *newperm
, *newinvperm
, *newmap
;
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
;
2549 for (j
= 0; j
< numSlots
; j
++) {
2550 newnodelist
[j
] = sentinel
;
2553 if (unique
->map
!= NULL
) {
2554 for (i
= oldsize
; i
<= index
; i
++) {
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
;
2565 (void) fprintf(unique
->err
,
2566 "Increasing the table size from %d to %d\n",
2567 unique
->maxSize
, newsize
);
2569 newsubtables
= ALLOC(DdSubtable
,newsize
);
2570 if (newsubtables
== NULL
) {
2571 unique
->errorCode
= CUDD_MEMORY_OUT
;
2574 newvars
= ALLOC(DdNodePtr
,newsize
);
2575 if (newvars
== NULL
) {
2577 unique
->errorCode
= CUDD_MEMORY_OUT
;
2580 newperm
= ALLOC(int,newsize
);
2581 if (newperm
== NULL
) {
2584 unique
->errorCode
= CUDD_MEMORY_OUT
;
2587 newinvperm
= ALLOC(int,newsize
);
2588 if (newinvperm
== NULL
) {
2592 unique
->errorCode
= CUDD_MEMORY_OUT
;
2595 if (unique
->map
!= NULL
) {
2596 newmap
= ALLOC(int,newsize
);
2597 if (newmap
== NULL
) {
2602 unique
->errorCode
= CUDD_MEMORY_OUT
;
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
) {
2617 if (unique
->map
!= NULL
) {
2620 unique
->errorCode
= CUDD_MEMORY_OUT
;
2623 unique
->stack
[0] = NULL
; /* to suppress harmless UMR */
2625 (newsize
- ddMax(unique
->maxSize
,unique
->maxSizeZ
))
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
;
2660 newnodelist
= newsubtables
[i
].nodelist
= ALLOC(DdNodePtr
, numSlots
);
2661 if (newnodelist
== NULL
) {
2662 unique
->errorCode
= CUDD_MEMORY_OUT
;
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
++) {
2677 unique
->map
= newmap
;
2679 FREE(unique
->subtables
);
2680 unique
->subtables
= newsubtables
;
2681 unique
->maxSize
= newsize
;
2683 unique
->vars
= newvars
;
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.
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
);
2721 cuddRef(unique
->vars
[i
]);
2723 unique
->autoDyn
= reorderSave
;
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.]
2741 ******************************************************************************/
2749 DdNodePtr
*nodelist
;
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
++) {
2758 while (cuddT(f
) > node
) {
2761 while (cuddT(f
) == node
&& Cudd_Regular(cuddE(f
)) > node
) {
2764 if (cuddT(f
) == node
&& Cudd_Regular(cuddE(f
)) == node
) {
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.]
2787 ******************************************************************************/
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
);
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.]
2815 SeeAlso [cuddOrderedThread]
2817 ******************************************************************************/
2825 DdNodePtr
*stack
[DD_STACK_SIZE
];
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
;
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
;
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 ******************************************************************************/
2872 DdNode
*current
, *next
, *prev
, *end
;
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
;
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
;
2921 } /* end of cuddOrderedThread */
2924 /**Function********************************************************************
2926 Synopsis [Performs the left rotation for red/black trees.]
2932 SeeAlso [cuddRotateRight]
2934 ******************************************************************************/
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.]
2958 SeeAlso [cuddRotateLeft]
2960 ******************************************************************************/
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.]
2986 ******************************************************************************/
2992 DdNodePtr
*xP
, *parentP
, *grandpaP
;
2993 DdNode
*x
, *y
, *parent
, *grandpa
;
2997 /* Work our way back up, re-balancing the tree. */
2998 while (--stackN
>= 0) {
2999 parentP
= stack
[stackN
];
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
;
3014 if (x
== DD_RIGHT(parent
)) {
3015 cuddRotateLeft(parentP
);
3016 DD_COLOR(x
) = DD_BLACK
;
3018 DD_COLOR(parent
) = DD_BLACK
;
3020 DD_COLOR(grandpa
) = DD_RED
;
3021 cuddRotateRight(grandpaP
);
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
;
3033 if (x
== DD_LEFT(parent
)) {
3034 cuddRotateRight(parentP
);
3035 DD_COLOR(x
) = DD_BLACK
;
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 */
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.]
3063 ******************************************************************************/
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
;
3081 } /* end of ddPatchTree */
3085 /**Function********************************************************************
3087 Synopsis [Checks whether a collision list is ordered.]
3095 ******************************************************************************/
3097 cuddCheckCollisionOrdering(
3103 DdNode
*node
, *next
;
3104 DdNodePtr
*nodelist
;
3105 DdNode
*sentinel
= &(unique
->sentinel
);
3107 nodelist
= unique
->subtables
[i
].nodelist
;
3108 slots
= unique
->subtables
[i
].slots
;
3110 if (node
== sentinel
) return(1);
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
);
3124 } /* end of cuddCheckCollisionOrdering */
3130 /**Function********************************************************************
3132 Synopsis [Reports problem in garbage collection.]
3138 SeeAlso [cuddGarbageCollect cuddGarbageCollectZdd]
3140 ******************************************************************************/
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.");
3160 } /* end of ddReportRefMess */