1 /**CFile***********************************************************************
3 FileName [cuddZddReord.c]
7 Synopsis [Procedures for dynamic variable ordering of ZDDs.]
9 Description [External procedures included in this module:
11 <li> Cudd_zddReduceHeap()
12 <li> Cudd_zddShuffleHeap()
14 Internal procedures included in this module:
16 <li> cuddZddAlignToBdd()
17 <li> cuddZddNextHigh()
19 <li> cuddZddUniqueCompare()
20 <li> cuddZddSwapInPlace()
21 <li> cuddZddSwapping()
24 Static procedures included in this module:
27 <li> cuddZddSiftingAux()
28 <li> cuddZddSiftingUp()
29 <li> cuddZddSiftingDown()
30 <li> cuddZddSiftingBackward()
31 <li> zddReorderPreprocess()
32 <li> zddReorderPostprocess()
40 Author [Hyong-Kyoon Shin, In-Ho Moon]
42 Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado
46 Redistribution and use in source and binary forms, with or without
47 modification, are permitted provided that the following conditions
50 Redistributions of source code must retain the above copyright
51 notice, this list of conditions and the following disclaimer.
53 Redistributions in binary form must reproduce the above copyright
54 notice, this list of conditions and the following disclaimer in the
55 documentation and/or other materials provided with the distribution.
57 Neither the name of the University of Colorado nor the names of its
58 contributors may be used to endorse or promote products derived from
59 this software without specific prior written permission.
61 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
62 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
63 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
64 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
65 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
66 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
67 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
68 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
69 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
71 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
72 POSSIBILITY OF SUCH DAMAGE.]
74 ******************************************************************************/
79 /*---------------------------------------------------------------------------*/
80 /* Constant declarations */
81 /*---------------------------------------------------------------------------*/
83 #define DD_MAX_SUBTABLE_SPARSITY 8
84 #define DD_SHRINK_FACTOR 2
86 /*---------------------------------------------------------------------------*/
87 /* Stucture declarations */
88 /*---------------------------------------------------------------------------*/
91 /*---------------------------------------------------------------------------*/
92 /* Type declarations */
93 /*---------------------------------------------------------------------------*/
96 /*---------------------------------------------------------------------------*/
97 /* Variable declarations */
98 /*---------------------------------------------------------------------------*/
101 static char rcsid
[] DD_UNUSED
= "$Id: cuddZddReord.c,v 1.47 2004/08/13 18:04:53 fabio Exp $";
106 int zddTotalNumberSwapping
;
108 static DdNode
*empty
;
111 /*---------------------------------------------------------------------------*/
112 /* Macro declarations */
113 /*---------------------------------------------------------------------------*/
116 /**AutomaticStart*************************************************************/
118 /*---------------------------------------------------------------------------*/
119 /* Static function prototypes */
120 /*---------------------------------------------------------------------------*/
122 static Move
* zddSwapAny (DdManager
*table
, int x
, int y
);
123 static int cuddZddSiftingAux (DdManager
*table
, int x
, int x_low
, int x_high
);
124 static Move
* cuddZddSiftingUp (DdManager
*table
, int x
, int x_low
, int initial_size
);
125 static Move
* cuddZddSiftingDown (DdManager
*table
, int x
, int x_high
, int initial_size
);
126 static int cuddZddSiftingBackward (DdManager
*table
, Move
*moves
, int size
);
127 static void zddReorderPreprocess (DdManager
*table
);
128 static int zddReorderPostprocess (DdManager
*table
);
129 static int zddShuffle (DdManager
*table
, int *permutation
);
130 static int zddSiftUp (DdManager
*table
, int x
, int xLow
);
131 static void zddFixTree (DdManager
*table
, MtrNode
*treenode
);
133 /**AutomaticEnd***************************************************************/
136 /*---------------------------------------------------------------------------*/
137 /* Definition of exported functions */
138 /*---------------------------------------------------------------------------*/
141 /**Function********************************************************************
143 Synopsis [Main dynamic reordering routine for ZDDs.]
145 Description [Main dynamic reordering routine for ZDDs.
146 Calls one of the possible reordering procedures:
150 <li>Symmetric Sifting
153 For sifting and symmetric sifting it is possible to request reordering
156 The core of all methods is the reordering procedure
157 cuddZddSwapInPlace() which swaps two adjacent variables.
158 Returns 1 in case of success; 0 otherwise. In the case of symmetric
159 sifting (with and without convergence) returns 1 plus the number of
160 symmetric variables, in case of success.]
162 SideEffects [Changes the variable order for all ZDDs and clears
165 ******************************************************************************/
168 DdManager
* table
/* DD manager */,
169 Cudd_ReorderingType heuristic
/* method used for reordering */,
170 int minsize
/* bound below which no reordering occurs */)
174 unsigned int nextDyn
;
176 unsigned int initialSize
;
177 unsigned int finalSize
;
181 /* Don't reorder if there are too many dead nodes. */
182 if (table
->keysZ
- table
->deadZ
< (unsigned) minsize
)
185 if (heuristic
== CUDD_REORDER_SAME
) {
186 heuristic
= table
->autoMethodZ
;
188 if (heuristic
== CUDD_REORDER_NONE
) {
192 /* This call to Cudd_zddReduceHeap does initiate reordering. Therefore
195 table
->reorderings
++;
198 localTime
= util_cpu_time();
200 /* Run the hook functions. */
201 hook
= table
->preReorderingHook
;
202 while (hook
!= NULL
) {
203 int res
= (hook
->f
)(table
, "ZDD", (void *)heuristic
);
204 if (res
== 0) return(0);
208 /* Clear the cache and collect garbage. */
209 zddReorderPreprocess(table
);
210 zddTotalNumberSwapping
= 0;
213 initialSize
= table
->keysZ
;
216 case CUDD_REORDER_RANDOM
:
217 case CUDD_REORDER_RANDOM_PIVOT
:
218 (void) fprintf(table
->out
,"#:I_RANDOM ");
220 case CUDD_REORDER_SIFT
:
221 case CUDD_REORDER_SIFT_CONVERGE
:
222 case CUDD_REORDER_SYMM_SIFT
:
223 case CUDD_REORDER_SYMM_SIFT_CONV
:
224 (void) fprintf(table
->out
,"#:I_SIFTING ");
226 case CUDD_REORDER_LINEAR
:
227 case CUDD_REORDER_LINEAR_CONVERGE
:
228 (void) fprintf(table
->out
,"#:I_LINSIFT ");
231 (void) fprintf(table
->err
,"Unsupported ZDD reordering method\n");
234 (void) fprintf(table
->out
,"%8d: initial size",initialSize
);
237 result
= cuddZddTreeSifting(table
,heuristic
);
240 (void) fprintf(table
->out
,"\n");
241 finalSize
= table
->keysZ
;
242 (void) fprintf(table
->out
,"#:F_REORDER %8d: final size\n",finalSize
);
243 (void) fprintf(table
->out
,"#:T_REORDER %8g: total time (sec)\n",
244 ((double)(util_cpu_time() - localTime
)/1000.0));
245 (void) fprintf(table
->out
,"#:N_REORDER %8d: total swaps\n",
246 zddTotalNumberSwapping
);
252 if (!zddReorderPostprocess(table
))
255 if (table
->realignZ
) {
256 if (!cuddBddAlignToZdd(table
))
260 nextDyn
= table
->keysZ
* DD_DYN_RATIO
;
261 if (table
->reorderings
< 20 || nextDyn
> table
->nextDyn
)
262 table
->nextDyn
= nextDyn
;
264 table
->nextDyn
+= 20;
266 table
->reordered
= 1;
268 /* Run hook functions. */
269 hook
= table
->postReorderingHook
;
270 while (hook
!= NULL
) {
271 int res
= (hook
->f
)(table
, "ZDD", (void *)localTime
);
272 if (res
== 0) return(0);
275 /* Update cumulative reordering time. */
276 table
->reordTime
+= util_cpu_time() - localTime
;
280 } /* end of Cudd_zddReduceHeap */
283 /**Function********************************************************************
285 Synopsis [Reorders ZDD variables according to given permutation.]
287 Description [Reorders ZDD variables according to given permutation.
288 The i-th entry of the permutation array contains the index of the variable
289 that should be brought to the i-th level. The size of the array should be
290 equal or greater to the number of variables currently in use.
291 Returns 1 in case of success; 0 otherwise.]
293 SideEffects [Changes the ZDD variable order for all diagrams and clears
296 SeeAlso [Cudd_zddReduceHeap]
298 ******************************************************************************/
301 DdManager
* table
/* DD manager */,
302 int * permutation
/* required variable permutation */)
308 zddReorderPreprocess(table
);
310 result
= zddShuffle(table
,permutation
);
312 if (!zddReorderPostprocess(table
)) return(0);
316 } /* end of Cudd_zddShuffleHeap */
319 /*---------------------------------------------------------------------------*/
320 /* Definition of internal functions */
321 /*---------------------------------------------------------------------------*/
324 /**Function********************************************************************
326 Synopsis [Reorders ZDD variables according to the order of the BDD
329 Description [Reorders ZDD variables according to the order of the
330 BDD variables. This function can be called at the end of BDD
331 reordering to insure that the order of the ZDD variables is
332 consistent with the order of the BDD variables. The number of ZDD
333 variables must be a multiple of the number of BDD variables. Let
334 <code>M</code> be the ratio of the two numbers. cuddZddAlignToBdd
335 then considers the ZDD variables from <code>M*i</code> to
336 <code>(M+1)*i-1</code> as corresponding to BDD variable
337 <code>i</code>. This function should be normally called from
338 Cudd_ReduceHeap, which clears the cache. Returns 1 in case of
339 success; 0 otherwise.]
341 SideEffects [Changes the ZDD variable order for all diagrams and performs
342 garbage collection of the ZDD unique table.]
344 SeeAlso [Cudd_zddShuffleHeap Cudd_ReduceHeap]
346 ******************************************************************************/
349 DdManager
* table
/* DD manager */)
351 int *invpermZ
; /* permutation array */
352 int M
; /* ratio of ZDD variables to BDD variables */
353 int i
,j
; /* loop indices */
354 int result
; /* return value */
356 /* We assume that a ratio of 0 is OK. */
357 if (table
->sizeZ
== 0)
361 M
= table
->sizeZ
/ table
->size
;
362 /* Check whether the number of ZDD variables is a multiple of the
363 ** number of BDD variables.
365 if (M
* table
->size
!= table
->sizeZ
)
367 /* Create and initialize the inverse permutation array. */
368 invpermZ
= ALLOC(int,table
->sizeZ
);
369 if (invpermZ
== NULL
) {
370 table
->errorCode
= CUDD_MEMORY_OUT
;
373 for (i
= 0; i
< table
->size
; i
++) {
374 int index
= table
->invperm
[i
];
375 int indexZ
= index
* M
;
376 int levelZ
= table
->permZ
[indexZ
];
377 levelZ
= (levelZ
/ M
) * M
;
378 for (j
= 0; j
< M
; j
++) {
379 invpermZ
[M
* i
+ j
] = table
->invpermZ
[levelZ
+ j
];
382 /* Eliminate dead nodes. Do not scan the cache again, because we
383 ** assume that Cudd_ReduceHeap has already cleared it.
385 cuddGarbageCollect(table
,0);
387 result
= zddShuffle(table
, invpermZ
);
389 /* Fix the ZDD variable group tree. */
390 zddFixTree(table
,table
->treeZ
);
393 } /* end of cuddZddAlignToBdd */
396 /**Function********************************************************************
398 Synopsis [Finds the next subtable with a larger index.]
400 Description [Finds the next subtable with a larger index. Returns the
407 ******************************************************************************/
415 } /* end of cuddZddNextHigh */
418 /**Function********************************************************************
420 Synopsis [Finds the next subtable with a smaller index.]
422 Description [Finds the next subtable with a smaller index. Returns the
429 ******************************************************************************/
437 } /* end of cuddZddNextLow */
440 /**Function********************************************************************
442 Synopsis [Comparison function used by qsort.]
444 Description [Comparison function used by qsort to order the
445 variables according to the number of keys in the subtables.
446 Returns the difference in number of keys between the two
447 variables being compared.]
453 ******************************************************************************/
455 cuddZddUniqueCompare(
459 return(zdd_entry
[*ptr_y
] - zdd_entry
[*ptr_x
]);
461 } /* end of cuddZddUniqueCompare */
464 /**Function********************************************************************
466 Synopsis [Swaps two adjacent variables.]
468 Description [Swaps two adjacent variables. It assumes that no dead
469 nodes are present on entry to this procedure. The procedure then
470 guarantees that no dead nodes will be present when it terminates.
471 cuddZddSwapInPlace assumes that x < y. Returns the number of keys in
472 the table if successful; 0 otherwise.]
478 ******************************************************************************/
485 DdNodePtr
*xlist
, *ylist
;
489 int oldxkeys
, oldykeys
;
490 int newxkeys
, newykeys
;
493 DdNode
*f
, *f1
, *f0
, *f11
, *f10
, *f01
, *f00
;
494 DdNode
*newf1
, *newf0
, *next
;
495 DdNodePtr g
, *lastP
, *previousP
;
499 assert(cuddZddNextHigh(table
,x
) == y
);
500 assert(table
->subtableZ
[x
].keys
!= 0);
501 assert(table
->subtableZ
[y
].keys
!= 0);
502 assert(table
->subtableZ
[x
].dead
== 0);
503 assert(table
->subtableZ
[y
].dead
== 0);
506 zddTotalNumberSwapping
++;
508 /* Get parameters of x subtable. */
509 xindex
= table
->invpermZ
[x
];
510 xlist
= table
->subtableZ
[x
].nodelist
;
511 oldxkeys
= table
->subtableZ
[x
].keys
;
512 xslots
= table
->subtableZ
[x
].slots
;
513 xshift
= table
->subtableZ
[x
].shift
;
516 yindex
= table
->invpermZ
[y
];
517 ylist
= table
->subtableZ
[y
].nodelist
;
518 oldykeys
= table
->subtableZ
[y
].keys
;
519 yslots
= table
->subtableZ
[y
].slots
;
520 yshift
= table
->subtableZ
[y
].shift
;
523 /* The nodes in the x layer that don't depend on y directly
524 ** will stay there; the others are put in a chain.
525 ** The chain is handled as a FIFO; g points to the beginning and
526 ** last points to the end.
531 for (i
= 0; i
< xslots
; i
++) {
532 previousP
= &(xlist
[i
]);
536 f1
= cuddT(f
); f0
= cuddE(f
);
537 if ((f1
->index
!= (DdHalfWord
) yindex
) &&
538 (f0
->index
!= (DdHalfWord
) yindex
)) { /* stays */
541 previousP
= &(f
->next
);
548 } /* while there are elements in the collision chain */
550 } /* for each slot of the x subtable */
555 table
->swapSteps
+= oldxkeys
- newxkeys
;
557 /* Take care of the x nodes that must be re-expressed.
558 ** They form a linked list pointed by g. Their index has been
559 ** changed to yindex already.
564 /* Find f1, f0, f11, f10, f01, f00. */
566 if ((int) f1
->index
== yindex
) {
567 f11
= cuddT(f1
); f10
= cuddE(f1
);
569 f11
= empty
; f10
= f1
;
572 if ((int) f0
->index
== yindex
) {
573 f01
= cuddT(f0
); f00
= cuddE(f0
);
575 f01
= empty
; f00
= f0
;
578 /* Decrease ref count of f1. */
580 /* Create the new T child. */
584 cuddSatInc(newf1
->ref
);
586 /* else case was already handled when finding nodes
587 ** with both children below level y
590 /* Check xlist for triple (xindex, f11, f01). */
591 posn
= ddHash(f11
, f01
, xshift
);
592 /* For each element newf1 in collision list xlist[posn]. */
594 while (newf1
!= NULL
) {
595 if (cuddT(newf1
) == f11
&& cuddE(newf1
) == f01
) {
596 cuddSatInc(newf1
->ref
);
601 if (newf1
== NULL
) { /* no match */
602 newf1
= cuddDynamicAllocNode(table
);
604 goto zddSwapOutOfMem
;
605 newf1
->index
= xindex
; newf1
->ref
= 1;
608 /* Insert newf1 in the collision list xlist[pos];
609 ** increase the ref counts of f11 and f01
612 newf1
->next
= xlist
[posn
];
614 cuddSatInc(f11
->ref
);
615 cuddSatInc(f01
->ref
);
620 /* Do the same for f0. */
621 /* Decrease ref count of f0. */
623 /* Create the new E child. */
626 cuddSatInc(newf0
->ref
);
628 /* Check xlist for triple (xindex, f10, f00). */
629 posn
= ddHash(f10
, f00
, xshift
);
630 /* For each element newf0 in collision list xlist[posn]. */
632 while (newf0
!= NULL
) {
633 if (cuddT(newf0
) == f10
&& cuddE(newf0
) == f00
) {
634 cuddSatInc(newf0
->ref
);
639 if (newf0
== NULL
) { /* no match */
640 newf0
= cuddDynamicAllocNode(table
);
642 goto zddSwapOutOfMem
;
643 newf0
->index
= xindex
; newf0
->ref
= 1;
644 cuddT(newf0
) = f10
; cuddE(newf0
) = f00
;
645 /* Insert newf0 in the collision list xlist[posn];
646 ** increase the ref counts of f10 and f00.
649 newf0
->next
= xlist
[posn
];
651 cuddSatInc(f10
->ref
);
652 cuddSatInc(f00
->ref
);
657 /* Insert the modified f in ylist.
658 ** The modified f does not already exists in ylist.
659 ** (Because of the uniqueness of the cofactors.)
661 posn
= ddHash(newf1
, newf0
, yshift
);
663 f
->next
= ylist
[posn
];
666 } /* while f != NULL */
668 /* GC the y layer. */
670 /* For each node f in ylist. */
671 for (i
= 0; i
< yslots
; i
++) {
672 previousP
= &(ylist
[i
]);
677 cuddSatDec(cuddT(f
)->ref
);
678 cuddSatDec(cuddE(f
)->ref
);
679 cuddDeallocNode(table
, f
);
683 previousP
= &(f
->next
);
690 /* Set the appropriate fields in table. */
691 table
->subtableZ
[x
].nodelist
= ylist
;
692 table
->subtableZ
[x
].slots
= yslots
;
693 table
->subtableZ
[x
].shift
= yshift
;
694 table
->subtableZ
[x
].keys
= newykeys
;
695 table
->subtableZ
[x
].maxKeys
= yslots
* DD_MAX_SUBTABLE_DENSITY
;
697 table
->subtableZ
[y
].nodelist
= xlist
;
698 table
->subtableZ
[y
].slots
= xslots
;
699 table
->subtableZ
[y
].shift
= xshift
;
700 table
->subtableZ
[y
].keys
= newxkeys
;
701 table
->subtableZ
[y
].maxKeys
= xslots
* DD_MAX_SUBTABLE_DENSITY
;
703 table
->permZ
[xindex
] = y
; table
->permZ
[yindex
] = x
;
704 table
->invpermZ
[x
] = yindex
; table
->invpermZ
[y
] = xindex
;
706 table
->keysZ
+= newxkeys
+ newykeys
- oldxkeys
- oldykeys
;
708 /* Update univ section; univ[x] remains the same. */
709 table
->univ
[y
] = cuddT(table
->univ
[x
]);
711 return (table
->keysZ
);
714 (void) fprintf(table
->err
, "Error: cuddZddSwapInPlace out of memory\n");
718 } /* end of cuddZddSwapInPlace */
721 /**Function********************************************************************
723 Synopsis [Reorders variables by a sequence of (non-adjacent) swaps.]
725 Description [Implementation of Plessier's algorithm that reorders
726 variables by a sequence of (non-adjacent) swaps.
728 <li> Select two variables (RANDOM or HEURISTIC).
729 <li> Permute these variables.
730 <li> If the nodes have decreased accept the permutation.
731 <li> Otherwise reconstruct the original heap.
734 Returns 1 in case of success; 0 otherwise.]
740 ******************************************************************************/
746 Cudd_ReorderingType heuristic
)
761 assert(lower
>= 0 && upper
< table
->sizeZ
&& lower
<= upper
);
764 nvars
= upper
- lower
+ 1;
767 for (i
= 0; i
< iterate
; i
++) {
768 if (heuristic
== CUDD_REORDER_RANDOM_PIVOT
) {
769 /* Find pivot <= id with maximum keys. */
770 for (max
= -1, j
= lower
; j
<= upper
; j
++) {
771 if ((keys
= table
->subtableZ
[j
].keys
) > max
) {
777 modulo
= upper
- pivot
;
779 y
= pivot
; /* y = nvars-1 */
781 /* y = random # from {pivot+1 .. nvars-1} */
782 y
= pivot
+ 1 + (int) (Cudd_Random() % modulo
);
785 modulo
= pivot
- lower
- 1;
786 if (modulo
< 1) { /* if pivot = 1 or 0 */
789 do { /* x = random # from {0 .. pivot-2} */
790 x
= (int) Cudd_Random() % modulo
;
792 /* Is this condition really needed, since x and y
793 are in regions separated by pivot? */
796 x
= (int) (Cudd_Random() % nvars
) + lower
;
798 y
= (int) (Cudd_Random() % nvars
) + lower
;
802 previousSize
= table
->keysZ
;
803 moves
= zddSwapAny(table
, x
, y
);
805 goto cuddZddSwappingOutOfMem
;
807 result
= cuddZddSiftingBackward(table
, moves
, previousSize
);
809 goto cuddZddSwappingOutOfMem
;
811 while (moves
!= NULL
) {
813 cuddDeallocMove(table
, moves
);
817 if (table
->keysZ
< (unsigned) previousSize
) {
818 (void) fprintf(table
->out
,"-");
819 } else if (table
->keysZ
> (unsigned) previousSize
) {
820 (void) fprintf(table
->out
,"+"); /* should never happen */
822 (void) fprintf(table
->out
,"=");
830 cuddZddSwappingOutOfMem
:
831 while (moves
!= NULL
) {
833 cuddDeallocMove(table
, moves
);
838 } /* end of cuddZddSwapping */
841 /**Function********************************************************************
843 Synopsis [Implementation of Rudell's sifting algorithm.]
845 Description [Implementation of Rudell's sifting algorithm.
846 Assumes that no dead nodes are present.
848 <li> Order all the variables according to the number of entries
849 in each unique table.
850 <li> Sift the variable up and down, remembering each time the
851 total size of the DD heap.
852 <li> Select the best permutation.
853 <li> Repeat 3 and 4 for all variables.
855 Returns 1 if successful; 0 otherwise.]
861 ******************************************************************************/
879 /* Find order in which to sift variables. */
881 zdd_entry
= ALLOC(int, size
);
882 if (zdd_entry
== NULL
) {
883 table
->errorCode
= CUDD_MEMORY_OUT
;
884 goto cuddZddSiftingOutOfMem
;
886 var
= ALLOC(int, size
);
888 table
->errorCode
= CUDD_MEMORY_OUT
;
889 goto cuddZddSiftingOutOfMem
;
892 for (i
= 0; i
< size
; i
++) {
894 zdd_entry
[i
] = table
->subtableZ
[x
].keys
;
898 qsort((void *)var
, size
, sizeof(int), (DD_QSFP
)cuddZddUniqueCompare
);
901 for (i
= 0; i
< ddMin(table
->siftMaxVar
, size
); i
++) {
902 if (zddTotalNumberSwapping
>= table
->siftMaxSwap
)
904 x
= table
->permZ
[var
[i
]];
905 if (x
< lower
|| x
> upper
) continue;
907 previousSize
= table
->keysZ
;
909 result
= cuddZddSiftingAux(table
, x
, lower
, upper
);
911 goto cuddZddSiftingOutOfMem
;
913 if (table
->keysZ
< (unsigned) previousSize
) {
914 (void) fprintf(table
->out
,"-");
915 } else if (table
->keysZ
> (unsigned) previousSize
) {
916 (void) fprintf(table
->out
,"+"); /* should never happen */
917 (void) fprintf(table
->out
,"\nSize increased from %d to %d while sifting variable %d\n", previousSize
, table
->keysZ
, var
[i
]);
919 (void) fprintf(table
->out
,"=");
930 cuddZddSiftingOutOfMem
:
932 if (zdd_entry
!= NULL
) FREE(zdd_entry
);
933 if (var
!= NULL
) FREE(var
);
937 } /* end of cuddZddSifting */
940 /*---------------------------------------------------------------------------*/
941 /* Definition of static functions */
942 /*---------------------------------------------------------------------------*/
945 /**Function********************************************************************
947 Synopsis [Swaps any two variables.]
949 Description [Swaps any two variables. Returns the set of moves.]
955 ******************************************************************************/
968 if (x
> y
) { /* make x precede y */
969 tmp
= x
; x
= y
; y
= tmp
;
972 x_ref
= x
; y_ref
= y
;
974 x_next
= cuddZddNextHigh(table
, x
);
975 y_next
= cuddZddNextLow(table
, y
);
977 limit_size
= table
->keysZ
;
980 if (x_next
== y_next
) { /* x < x_next = y_next < y */
981 size
= cuddZddSwapInPlace(table
, x
, x_next
);
983 goto zddSwapAnyOutOfMem
;
984 move
= (Move
*) cuddDynamicAllocNode(table
);
986 goto zddSwapAnyOutOfMem
;
993 size
= cuddZddSwapInPlace(table
, y_next
, y
);
995 goto zddSwapAnyOutOfMem
;
996 move
= (Move
*)cuddDynamicAllocNode(table
);
998 goto zddSwapAnyOutOfMem
;
1005 size
= cuddZddSwapInPlace(table
, x
, x_next
);
1007 goto zddSwapAnyOutOfMem
;
1008 move
= (Move
*)cuddDynamicAllocNode(table
);
1010 goto zddSwapAnyOutOfMem
;
1017 tmp
= x
; x
= y
; y
= tmp
;
1019 } else if (x
== y_next
) { /* x = y_next < y = x_next */
1020 size
= cuddZddSwapInPlace(table
, x
, x_next
);
1022 goto zddSwapAnyOutOfMem
;
1023 move
= (Move
*)cuddDynamicAllocNode(table
);
1025 goto zddSwapAnyOutOfMem
;
1032 tmp
= x
; x
= y
; y
= tmp
;
1034 size
= cuddZddSwapInPlace(table
, x
, x_next
);
1036 goto zddSwapAnyOutOfMem
;
1037 move
= (Move
*)cuddDynamicAllocNode(table
);
1039 goto zddSwapAnyOutOfMem
;
1046 size
= cuddZddSwapInPlace(table
, y_next
, y
);
1048 goto zddSwapAnyOutOfMem
;
1049 move
= (Move
*)cuddDynamicAllocNode(table
);
1051 goto zddSwapAnyOutOfMem
;
1058 x
= x_next
; y
= y_next
;
1061 x_next
= cuddZddNextHigh(table
, x
);
1062 y_next
= cuddZddNextLow(table
, y
);
1064 break; /* if x == y_ref */
1066 if ((double) size
> table
->maxGrowth
* (double) limit_size
)
1068 if (size
< limit_size
)
1071 if (y_next
>= x_ref
) {
1072 size
= cuddZddSwapInPlace(table
, y_next
, y
);
1074 goto zddSwapAnyOutOfMem
;
1075 move
= (Move
*)cuddDynamicAllocNode(table
);
1077 goto zddSwapAnyOutOfMem
;
1088 while (moves
!= NULL
) {
1090 cuddDeallocMove(table
, moves
);
1095 } /* end of zddSwapAny */
1098 /**Function********************************************************************
1100 Synopsis [Given xLow <= x <= xHigh moves x up and down between the
1103 Description [Given xLow <= x <= xHigh moves x up and down between the
1104 boundaries. Finds the best position and does the required changes.
1105 Returns 1 if successful; 0 otherwise.]
1111 ******************************************************************************/
1120 Move
*moveUp
; /* list of up move */
1121 Move
*moveDown
; /* list of down move */
1126 initial_size
= table
->keysZ
;
1129 assert(table
->subtableZ
[x
].keys
> 0);
1136 moveDown
= cuddZddSiftingDown(table
, x
, x_high
, initial_size
);
1137 /* after that point x --> x_high */
1138 if (moveDown
== NULL
)
1139 goto cuddZddSiftingAuxOutOfMem
;
1140 result
= cuddZddSiftingBackward(table
, moveDown
,
1142 /* move backward and stop at best position */
1144 goto cuddZddSiftingAuxOutOfMem
;
1147 else if (x
== x_high
) {
1148 moveUp
= cuddZddSiftingUp(table
, x
, x_low
, initial_size
);
1149 /* after that point x --> x_low */
1151 goto cuddZddSiftingAuxOutOfMem
;
1152 result
= cuddZddSiftingBackward(table
, moveUp
, initial_size
);
1153 /* move backward and stop at best position */
1155 goto cuddZddSiftingAuxOutOfMem
;
1157 else if ((x
- x_low
) > (x_high
- x
)) {
1158 /* must go down first:shorter */
1159 moveDown
= cuddZddSiftingDown(table
, x
, x_high
, initial_size
);
1160 /* after that point x --> x_high */
1161 if (moveDown
== NULL
)
1162 goto cuddZddSiftingAuxOutOfMem
;
1163 moveUp
= cuddZddSiftingUp(table
, moveDown
->y
, x_low
,
1166 goto cuddZddSiftingAuxOutOfMem
;
1167 result
= cuddZddSiftingBackward(table
, moveUp
, initial_size
);
1168 /* move backward and stop at best position */
1170 goto cuddZddSiftingAuxOutOfMem
;
1173 moveUp
= cuddZddSiftingUp(table
, x
, x_low
, initial_size
);
1174 /* after that point x --> x_high */
1176 goto cuddZddSiftingAuxOutOfMem
;
1177 moveDown
= cuddZddSiftingDown(table
, moveUp
->x
, x_high
,
1180 if (moveDown
== NULL
)
1181 goto cuddZddSiftingAuxOutOfMem
;
1182 result
= cuddZddSiftingBackward(table
, moveDown
,
1184 /* move backward and stop at best position */
1186 goto cuddZddSiftingAuxOutOfMem
;
1189 while (moveDown
!= NULL
) {
1190 move
= moveDown
->next
;
1191 cuddDeallocMove(table
, moveDown
);
1194 while (moveUp
!= NULL
) {
1195 move
= moveUp
->next
;
1196 cuddDeallocMove(table
, moveUp
);
1202 cuddZddSiftingAuxOutOfMem
:
1203 while (moveDown
!= NULL
) {
1204 move
= moveDown
->next
;
1205 cuddDeallocMove(table
, moveDown
);
1208 while (moveUp
!= NULL
) {
1209 move
= moveUp
->next
;
1210 cuddDeallocMove(table
, moveUp
);
1216 } /* end of cuddZddSiftingAux */
1219 /**Function********************************************************************
1221 Synopsis [Sifts a variable up.]
1223 Description [Sifts a variable up. Moves y up until either it reaches
1224 the bound (x_low) or the size of the ZDD heap increases too much.
1225 Returns the set of moves in case of success; NULL if memory is full.]
1231 ******************************************************************************/
1243 int limit_size
= initial_size
;
1246 y
= cuddZddNextLow(table
, x
);
1247 while (y
>= x_low
) {
1248 size
= cuddZddSwapInPlace(table
, y
, x
);
1250 goto cuddZddSiftingUpOutOfMem
;
1251 move
= (Move
*)cuddDynamicAllocNode(table
);
1253 goto cuddZddSiftingUpOutOfMem
;
1260 if ((double)size
> (double)limit_size
* table
->maxGrowth
)
1262 if (size
< limit_size
)
1266 y
= cuddZddNextLow(table
, x
);
1270 cuddZddSiftingUpOutOfMem
:
1271 while (moves
!= NULL
) {
1273 cuddDeallocMove(table
, moves
);
1278 } /* end of cuddZddSiftingUp */
1281 /**Function********************************************************************
1283 Synopsis [Sifts a variable down.]
1285 Description [Sifts a variable down. Moves x down until either it
1286 reaches the bound (x_high) or the size of the ZDD heap increases too
1287 much. Returns the set of moves in case of success; NULL if memory is
1294 ******************************************************************************/
1306 int limit_size
= initial_size
;
1309 y
= cuddZddNextHigh(table
, x
);
1310 while (y
<= x_high
) {
1311 size
= cuddZddSwapInPlace(table
, x
, y
);
1313 goto cuddZddSiftingDownOutOfMem
;
1314 move
= (Move
*)cuddDynamicAllocNode(table
);
1316 goto cuddZddSiftingDownOutOfMem
;
1323 if ((double)size
> (double)limit_size
* table
->maxGrowth
)
1325 if (size
< limit_size
)
1329 y
= cuddZddNextHigh(table
, x
);
1333 cuddZddSiftingDownOutOfMem
:
1334 while (moves
!= NULL
) {
1336 cuddDeallocMove(table
, moves
);
1341 } /* end of cuddZddSiftingDown */
1344 /**Function********************************************************************
1346 Synopsis [Given a set of moves, returns the ZDD heap to the position
1347 giving the minimum size.]
1349 Description [Given a set of moves, returns the ZDD heap to the
1350 position giving the minimum size. In case of ties, returns to the
1351 closest position giving the minimum size. Returns 1 in case of
1352 success; 0 otherwise.]
1358 ******************************************************************************/
1360 cuddZddSiftingBackward(
1370 /* Find the minimum size among moves. */
1372 for (move
= moves
, i
= 0; move
!= NULL
; move
= move
->next
, i
++) {
1373 if (move
->size
< size
) {
1379 for (move
= moves
, i
= 0; move
!= NULL
; move
= move
->next
, i
++) {
1382 res
= cuddZddSwapInPlace(table
, move
->x
, move
->y
);
1385 if (i_best
== -1 && res
== size
)
1391 } /* end of cuddZddSiftingBackward */
1394 /**Function********************************************************************
1396 Synopsis [Prepares the ZDD heap for dynamic reordering.]
1398 Description [Prepares the ZDD heap for dynamic reordering. Does
1399 garbage collection, to guarantee that there are no dead nodes;
1400 and clears the cache, which is invalidated by dynamic reordering.]
1404 ******************************************************************************/
1406 zddReorderPreprocess(
1410 /* Clear the cache. */
1411 cuddCacheFlush(table
);
1413 /* Eliminate dead nodes. Do not scan the cache again. */
1414 cuddGarbageCollect(table
,0);
1418 } /* end of ddReorderPreprocess */
1421 /**Function********************************************************************
1423 Synopsis [Shrinks almost empty ZDD subtables at the end of reordering
1424 to guarantee that they have a reasonable load factor.]
1426 Description [Shrinks almost empty subtables at the end of reordering to
1427 guarantee that they have a reasonable load factor. However, if there many
1428 nodes are being reclaimed, then no resizing occurs. Returns 1 in case of
1429 success; 0 otherwise.]
1433 ******************************************************************************/
1435 zddReorderPostprocess(
1439 DdNodePtr
*nodelist
, *oldnodelist
;
1440 DdNode
*node
, *next
;
1441 unsigned int slots
, oldslots
;
1442 extern DD_OOMFP MMoutOfMemory
;
1443 DD_OOMFP saveHandler
;
1446 (void) fflush(table
->out
);
1449 /* If we have very many reclaimed nodes, we do not want to shrink
1450 ** the subtables, because this will lead to more garbage
1451 ** collections. More garbage collections mean shorter mean life for
1452 ** nodes with zero reference count; hence lower probability of finding
1453 ** a result in the cache.
1455 if (table
->reclaimed
> table
->allocated
* 0.5) return(1);
1457 /* Resize subtables. */
1458 for (i
= 0; i
< table
->sizeZ
; i
++) {
1460 oldslots
= table
->subtableZ
[i
].slots
;
1461 if (oldslots
< table
->subtableZ
[i
].keys
* DD_MAX_SUBTABLE_SPARSITY
||
1462 oldslots
<= table
->initSlots
) continue;
1463 oldnodelist
= table
->subtableZ
[i
].nodelist
;
1464 slots
= oldslots
>> 1;
1465 saveHandler
= MMoutOfMemory
;
1466 MMoutOfMemory
= Cudd_OutOfMem
;
1467 nodelist
= ALLOC(DdNodePtr
, slots
);
1468 MMoutOfMemory
= saveHandler
;
1469 if (nodelist
== NULL
) {
1472 table
->subtableZ
[i
].nodelist
= nodelist
;
1473 table
->subtableZ
[i
].slots
= slots
;
1474 table
->subtableZ
[i
].shift
++;
1475 table
->subtableZ
[i
].maxKeys
= slots
* DD_MAX_SUBTABLE_DENSITY
;
1477 (void) fprintf(table
->err
,
1478 "shrunk layer %d (%d keys) from %d to %d slots\n",
1479 i
, table
->subtableZ
[i
].keys
, oldslots
, slots
);
1482 for (j
= 0; (unsigned) j
< slots
; j
++) {
1485 shift
= table
->subtableZ
[i
].shift
;
1486 for (j
= 0; (unsigned) j
< oldslots
; j
++) {
1487 node
= oldnodelist
[j
];
1488 while (node
!= NULL
) {
1490 posn
= ddHash(cuddT(node
), cuddE(node
), shift
);
1491 node
->next
= nodelist
[posn
];
1492 nodelist
[posn
] = node
;
1498 table
->memused
+= (slots
- oldslots
) * sizeof(DdNode
*);
1499 table
->slots
+= slots
- oldslots
;
1500 table
->minDead
= (unsigned) (table
->gcFrac
* (double) table
->slots
);
1501 table
->cacheSlack
= (int) ddMin(table
->maxCacheHard
,
1502 DD_MAX_CACHE_TO_SLOTS_RATIO
*table
->slots
) -
1503 2 * (int) table
->cacheSlots
;
1505 /* We don't look at the constant subtable, because it is not
1506 ** affected by reordering.
1511 } /* end of zddReorderPostprocess */
1514 /**Function********************************************************************
1516 Synopsis [Reorders ZDD variables according to a given permutation.]
1518 Description [Reorders ZDD variables according to a given permutation.
1519 The i-th permutation array contains the index of the variable that
1520 should be brought to the i-th level. zddShuffle assumes that no
1521 dead nodes are present. The reordering is achieved by a series of
1522 upward sifts. Returns 1 if successful; 0 otherwise.]
1528 ******************************************************************************/
1546 zddTotalNumberSwapping
= 0;
1548 localTime
= util_cpu_time();
1549 initialSize
= table
->keysZ
;
1550 (void) fprintf(table
->out
,"#:I_SHUFFLE %8d: initial size\n",
1554 numvars
= table
->sizeZ
;
1556 for (level
= 0; level
< numvars
; level
++) {
1557 index
= permutation
[level
];
1558 position
= table
->permZ
[index
];
1560 previousSize
= table
->keysZ
;
1562 result
= zddSiftUp(table
,position
,level
);
1563 if (!result
) return(0);
1565 if (table
->keysZ
< (unsigned) previousSize
) {
1566 (void) fprintf(table
->out
,"-");
1567 } else if (table
->keysZ
> (unsigned) previousSize
) {
1568 (void) fprintf(table
->out
,"+"); /* should never happen */
1570 (void) fprintf(table
->out
,"=");
1577 (void) fprintf(table
->out
,"\n");
1578 finalSize
= table
->keysZ
;
1579 (void) fprintf(table
->out
,"#:F_SHUFFLE %8d: final size\n",finalSize
);
1580 (void) fprintf(table
->out
,"#:T_SHUFFLE %8g: total time (sec)\n",
1581 ((double)(util_cpu_time() - localTime
)/1000.0));
1582 (void) fprintf(table
->out
,"#:N_SHUFFLE %8d: total swaps\n",
1583 zddTotalNumberSwapping
);
1588 } /* end of zddShuffle */
1591 /**Function********************************************************************
1593 Synopsis [Moves one ZDD variable up.]
1595 Description [Takes a ZDD variable from position x and sifts it up to
1596 position xLow; xLow should be less than or equal to x.
1597 Returns 1 if successful; 0 otherwise]
1603 ******************************************************************************/
1613 y
= cuddZddNextLow(table
,x
);
1615 size
= cuddZddSwapInPlace(table
,y
,x
);
1620 y
= cuddZddNextLow(table
,x
);
1624 } /* end of zddSiftUp */
1627 /**Function********************************************************************
1629 Synopsis [Fixes the ZDD variable group tree after a shuffle.]
1631 Description [Fixes the ZDD variable group tree after a
1632 shuffle. Assumes that the order of the variables in a terminal node
1633 has not been changed.]
1635 SideEffects [Changes the ZDD variable group tree.]
1639 ******************************************************************************/
1645 if (treenode
== NULL
) return;
1646 treenode
->low
= ((int) treenode
->index
< table
->sizeZ
) ?
1647 table
->permZ
[treenode
->index
] : treenode
->index
;
1648 if (treenode
->child
!= NULL
) {
1649 zddFixTree(table
, treenode
->child
);
1651 if (treenode
->younger
!= NULL
)
1652 zddFixTree(table
, treenode
->younger
);
1653 if (treenode
->parent
!= NULL
&& treenode
->low
< treenode
->parent
->low
) {
1654 treenode
->parent
->low
= treenode
->low
;
1655 treenode
->parent
->index
= treenode
->index
;
1659 } /* end of zddFixTree */