1 /**CFile***********************************************************************
3 FileName [cuddLinear.c]
7 Synopsis [Functions for DD reduction by linear transformations.]
9 Description [ Internal procedures included in this module:
11 <li> cuddLinearAndSifting()
12 <li> cuddLinearInPlace()
13 <li> cuddUpdateInteractionMatrix()
15 <li> cuddResizeLinear()
17 Static procedures included in this module:
19 <li> ddLinearUniqueCompare()
20 <li> ddLinearAndSiftingAux()
21 <li> ddLinearAndSiftingUp()
22 <li> ddLinearAndSiftingDown()
23 <li> ddLinearAndSiftingBackward()
28 Author [Fabio Somenzi]
30 Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado
34 Redistribution and use in source and binary forms, with or without
35 modification, are permitted provided that the following conditions
38 Redistributions of source code must retain the above copyright
39 notice, this list of conditions and the following disclaimer.
41 Redistributions in binary form must reproduce the above copyright
42 notice, this list of conditions and the following disclaimer in the
43 documentation and/or other materials provided with the distribution.
45 Neither the name of the University of Colorado nor the names of its
46 contributors may be used to endorse or promote products derived from
47 this software without specific prior written permission.
49 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
52 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
53 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
54 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
55 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
56 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
57 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
59 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60 POSSIBILITY OF SUCH DAMAGE.]
62 ******************************************************************************/
67 /*---------------------------------------------------------------------------*/
68 /* Constant declarations */
69 /*---------------------------------------------------------------------------*/
71 #define CUDD_SWAP_MOVE 0
72 #define CUDD_LINEAR_TRANSFORM_MOVE 1
73 #define CUDD_INVERSE_TRANSFORM_MOVE 2
82 /*---------------------------------------------------------------------------*/
83 /* Stucture declarations */
84 /*---------------------------------------------------------------------------*/
86 /*---------------------------------------------------------------------------*/
87 /* Type declarations */
88 /*---------------------------------------------------------------------------*/
90 /*---------------------------------------------------------------------------*/
91 /* Variable declarations */
92 /*---------------------------------------------------------------------------*/
95 static char rcsid
[] DD_UNUSED
= "$Id: cuddLinear.c,v 1.28 2009/02/19 16:21:03 fabio Exp $";
101 extern int ddTotalNumberSwapping
;
102 extern int ddTotalNISwaps
;
103 static int ddTotalNumberLinearTr
;
110 /*---------------------------------------------------------------------------*/
111 /* Macro declarations */
112 /*---------------------------------------------------------------------------*/
114 /**AutomaticStart*************************************************************/
116 /*---------------------------------------------------------------------------*/
117 /* Static function prototypes */
118 /*---------------------------------------------------------------------------*/
120 static int ddLinearUniqueCompare (int *ptrX
, int *ptrY
);
121 static int ddLinearAndSiftingAux (DdManager
*table
, int x
, int xLow
, int xHigh
);
122 static Move
* ddLinearAndSiftingUp (DdManager
*table
, int y
, int xLow
, Move
*prevMoves
);
123 static Move
* ddLinearAndSiftingDown (DdManager
*table
, int x
, int xHigh
, Move
*prevMoves
);
124 static int ddLinearAndSiftingBackward (DdManager
*table
, int size
, Move
*moves
);
125 static Move
* ddUndoMoves (DdManager
*table
, Move
*moves
);
126 static void cuddXorLinear (DdManager
*table
, int x
, int y
);
128 /**AutomaticEnd***************************************************************/
131 /*---------------------------------------------------------------------------*/
132 /* Definition of exported functions */
133 /*---------------------------------------------------------------------------*/
136 /**Function********************************************************************
138 Synopsis [Prints the linear transform matrix.]
140 Description [Prints the linear transform matrix. Returns 1 in case of
141 success; 0 otherwise.]
147 ******************************************************************************/
154 int nvars
= table
->linearSize
;
155 int wordsPerRow
= ((nvars
- 1) >> LOGBPL
) + 1;
158 for (i
= 0; i
< nvars
; i
++) {
159 for (j
= 0; j
< wordsPerRow
; j
++) {
160 word
= table
->linear
[i
*wordsPerRow
+ j
];
161 for (k
= 0; k
< BPL
; k
++) {
162 retval
= fprintf(table
->out
,"%ld",word
& 1);
163 if (retval
== 0) return(0);
167 retval
= fprintf(table
->out
,"\n");
168 if (retval
== 0) return(0);
172 } /* end of Cudd_PrintLinear */
175 /**Function********************************************************************
177 Synopsis [Reads an entry of the linear transform matrix.]
179 Description [Reads an entry of the linear transform matrix.]
185 ******************************************************************************/
188 DdManager
* table
/* CUDD manager */,
189 int x
/* row index */,
190 int y
/* column index */)
192 int nvars
= table
->size
;
193 int wordsPerRow
= ((nvars
- 1) >> LOGBPL
) + 1;
198 assert(table
->size
== table
->linearSize
);
200 word
= wordsPerRow
* x
+ (y
>> LOGBPL
);
202 result
= (int) ((table
->linear
[word
] >> bit
) & 1);
205 } /* end of Cudd_ReadLinear */
208 /*---------------------------------------------------------------------------*/
209 /* Definition of internal functions */
210 /*---------------------------------------------------------------------------*/
213 /**Function********************************************************************
215 Synopsis [BDD reduction based on combination of sifting and linear
218 Description [BDD reduction based on combination of sifting and linear
219 transformations. Assumes that no dead nodes are present.
221 <li> Order all the variables according to the number of entries
222 in each unique table.
223 <li> Sift the variable up and down, remembering each time the
224 total size of the DD heap. At each position, linear transformation
225 of the two adjacent variables is tried and is accepted if it reduces
227 <li> Select the best permutation.
228 <li> Repeat 3 and 4 for all variables.
230 Returns 1 if successful; 0 otherwise.]
234 ******************************************************************************/
236 cuddLinearAndSifting(
251 ddTotalNumberLinearTr
= 0;
258 if (table
->linear
== NULL
) {
259 result
= cuddInitLinear(table
);
260 if (result
== 0) goto cuddLinearAndSiftingOutOfMem
;
262 (void) fprintf(table
->out
,"\n");
263 result
= Cudd_PrintLinear(table
);
264 if (result
== 0) goto cuddLinearAndSiftingOutOfMem
;
266 } else if (table
->size
!= table
->linearSize
) {
267 result
= cuddResizeLinear(table
);
268 if (result
== 0) goto cuddLinearAndSiftingOutOfMem
;
270 (void) fprintf(table
->out
,"\n");
271 result
= Cudd_PrintLinear(table
);
272 if (result
== 0) goto cuddLinearAndSiftingOutOfMem
;
276 /* Find order in which to sift variables. */
277 entry
= ALLOC(int,size
);
279 table
->errorCode
= CUDD_MEMORY_OUT
;
280 goto cuddLinearAndSiftingOutOfMem
;
282 var
= ALLOC(int,size
);
284 table
->errorCode
= CUDD_MEMORY_OUT
;
285 goto cuddLinearAndSiftingOutOfMem
;
288 for (i
= 0; i
< size
; i
++) {
290 entry
[i
] = table
->subtables
[x
].keys
;
294 qsort((void *)var
,size
,sizeof(int),(DD_QSFP
)ddLinearUniqueCompare
);
297 for (i
= 0; i
< ddMin(table
->siftMaxVar
,size
); i
++) {
298 x
= table
->perm
[var
[i
]];
299 if (x
< lower
|| x
> upper
) continue;
301 previousSize
= table
->keys
- table
->isolated
;
303 result
= ddLinearAndSiftingAux(table
,x
,lower
,upper
);
304 if (!result
) goto cuddLinearAndSiftingOutOfMem
;
306 if (table
->keys
< (unsigned) previousSize
+ table
->isolated
) {
307 (void) fprintf(table
->out
,"-");
308 } else if (table
->keys
> (unsigned) previousSize
+ table
->isolated
) {
309 (void) fprintf(table
->out
,"+"); /* should never happen */
310 (void) fprintf(table
->out
,"\nSize increased from %d to %d while sifting variable %d\n", previousSize
, table
->keys
- table
->isolated
, var
[i
]);
312 (void) fprintf(table
->out
,"=");
317 (void) Cudd_DebugCheck(table
);
325 (void) fprintf(table
->out
,"\n#:L_LINSIFT %8d: linear trans.",
326 ddTotalNumberLinearTr
);
331 cuddLinearAndSiftingOutOfMem
:
333 if (entry
!= NULL
) FREE(entry
);
334 if (var
!= NULL
) FREE(var
);
338 } /* end of cuddLinearAndSifting */
341 /**Function********************************************************************
343 Synopsis [Linearly combines two adjacent variables.]
345 Description [Linearly combines two adjacent variables. Specifically,
346 replaces the top variable with the exclusive nor of the two variables.
347 It assumes that no dead nodes are present on entry to this
348 procedure. The procedure then guarantees that no dead nodes will be
349 present when it terminates. cuddLinearInPlace assumes that x <
350 y. Returns the number of keys in the table if successful; 0
353 SideEffects [The two subtables corrresponding to variables x and y are
354 modified. The global counters of the unique table are also affected.]
356 SeeAlso [cuddSwapInPlace]
358 ******************************************************************************/
365 DdNodePtr
*xlist
, *ylist
;
369 int oldxkeys
, oldykeys
;
370 int newxkeys
, newykeys
;
371 int comple
, newcomplement
;
375 DdNode
*f
,*f0
,*f1
,*f01
,*f00
,*f11
,*f10
,*newf1
,*newf0
;
376 DdNode
*g
,*next
,*last
;
377 DdNodePtr
*previousP
;
379 DdNode
*sentinel
= &(table
->sentinel
);
386 assert(cuddNextHigh(table
,x
) == y
);
387 assert(table
->subtables
[x
].keys
!= 0);
388 assert(table
->subtables
[y
].keys
!= 0);
389 assert(table
->subtables
[x
].dead
== 0);
390 assert(table
->subtables
[y
].dead
== 0);
393 xindex
= table
->invperm
[x
];
394 yindex
= table
->invperm
[y
];
396 if (cuddTestInteract(table
,xindex
,yindex
)) {
398 ddTotalNumberLinearTr
++;
400 /* Get parameters of x subtable. */
401 xlist
= table
->subtables
[x
].nodelist
;
402 oldxkeys
= table
->subtables
[x
].keys
;
403 xslots
= table
->subtables
[x
].slots
;
404 xshift
= table
->subtables
[x
].shift
;
406 /* Get parameters of y subtable. */
407 ylist
= table
->subtables
[y
].nodelist
;
408 oldykeys
= table
->subtables
[y
].keys
;
409 yslots
= table
->subtables
[y
].slots
;
410 yshift
= table
->subtables
[y
].shift
;
415 /* Check whether the two projection functions involved in this
416 ** swap are isolated. At the end, we'll be able to tell how many
417 ** isolated projection functions are there by checking only these
418 ** two functions again. This is done to eliminate the isolated
419 ** projection functions from the node count.
421 isolated
= - ((table
->vars
[xindex
]->ref
== 1) +
422 (table
->vars
[yindex
]->ref
== 1));
424 /* The nodes in the x layer are put in a chain.
425 ** The chain is handled as a FIFO; g points to the beginning and
426 ** last points to the end.
432 for (i
= 0; i
< xslots
; i
++) {
434 if (f
== sentinel
) continue;
441 while ((next
= f
->next
) != sentinel
) {
443 } /* while there are elements in the collision chain */
445 } /* for each slot of the x subtable */
447 /* last is always assigned in the for loop because there is at
449 assert(last
!= NULL
);
454 table
->swapSteps
+= oldxkeys
;
456 /* Take care of the x nodes that must be re-expressed.
457 ** They form a linked list pointed by g.
462 /* Find f1, f0, f11, f10, f01, f00. */
465 assert(!(Cudd_IsComplement(f1
)));
467 if ((int) f1
->index
== yindex
) {
468 f11
= cuddT(f1
); f10
= cuddE(f1
);
473 assert(!(Cudd_IsComplement(f11
)));
476 comple
= Cudd_IsComplement(f0
);
477 f0
= Cudd_Regular(f0
);
478 if ((int) f0
->index
== yindex
) {
479 f01
= cuddT(f0
); f00
= cuddE(f0
);
487 /* Decrease ref count of f1. */
489 /* Create the new T child. */
492 cuddSatInc(newf1
->ref
);
494 /* Check ylist for triple (yindex,f11,f00). */
495 posn
= ddHash(f11
, f00
, yshift
);
496 /* For each element newf1 in collision list ylist[posn]. */
497 previousP
= &(ylist
[posn
]);
499 while (f11
< cuddT(newf1
)) {
500 previousP
= &(newf1
->next
);
503 while (f11
== cuddT(newf1
) && f00
< cuddE(newf1
)) {
504 previousP
= &(newf1
->next
);
507 if (cuddT(newf1
) == f11
&& cuddE(newf1
) == f00
) {
508 cuddSatInc(newf1
->ref
);
509 } else { /* no match */
510 newf1
= cuddDynamicAllocNode(table
);
512 goto cuddLinearOutOfMem
;
513 newf1
->index
= yindex
; newf1
->ref
= 1;
516 /* Insert newf1 in the collision list ylist[posn];
517 ** increase the ref counts of f11 and f00.
520 newf1
->next
= *previousP
;
522 cuddSatInc(f11
->ref
);
523 tmp
= Cudd_Regular(f00
);
524 cuddSatInc(tmp
->ref
);
529 assert(!(Cudd_IsComplement(newf1
)));
532 /* Do the same for f0, keeping complement dots into account. */
533 /* decrease ref count of f0 */
534 tmp
= Cudd_Regular(f0
);
535 cuddSatDec(tmp
->ref
);
536 /* create the new E child */
539 tmp
= Cudd_Regular(newf0
);
540 cuddSatInc(tmp
->ref
);
542 /* make sure f01 is regular */
543 newcomplement
= Cudd_IsComplement(f01
);
548 /* Check ylist for triple (yindex,f01,f10). */
549 posn
= ddHash(f01
, f10
, yshift
);
550 /* For each element newf0 in collision list ylist[posn]. */
551 previousP
= &(ylist
[posn
]);
553 while (f01
< cuddT(newf0
)) {
554 previousP
= &(newf0
->next
);
557 while (f01
== cuddT(newf0
) && f10
< cuddE(newf0
)) {
558 previousP
= &(newf0
->next
);
561 if (cuddT(newf0
) == f01
&& cuddE(newf0
) == f10
) {
562 cuddSatInc(newf0
->ref
);
563 } else { /* no match */
564 newf0
= cuddDynamicAllocNode(table
);
566 goto cuddLinearOutOfMem
;
567 newf0
->index
= yindex
; newf0
->ref
= 1;
570 /* Insert newf0 in the collision list ylist[posn];
571 ** increase the ref counts of f01 and f10.
574 newf0
->next
= *previousP
;
576 cuddSatInc(f01
->ref
);
577 tmp
= Cudd_Regular(f10
);
578 cuddSatInc(tmp
->ref
);
581 newf0
= Cudd_Not(newf0
);
586 /* Re-insert the modified f in xlist.
587 ** The modified f does not already exists in xlist.
588 ** (Because of the uniqueness of the cofactors.)
590 posn
= ddHash(newf1
, newf0
, xshift
);
592 previousP
= &(xlist
[posn
]);
594 while (newf1
< cuddT(tmp
)) {
595 previousP
= &(tmp
->next
);
598 while (newf1
== cuddT(tmp
) && newf0
< cuddE(tmp
)) {
599 previousP
= &(tmp
->next
);
602 f
->next
= *previousP
;
605 } /* while f != NULL */
607 /* GC the y layer. */
609 /* For each node f in ylist. */
610 for (i
= 0; i
< yslots
; i
++) {
611 previousP
= &(ylist
[i
]);
613 while (f
!= sentinel
) {
617 cuddSatDec(tmp
->ref
);
618 tmp
= Cudd_Regular(cuddE(f
));
619 cuddSatDec(tmp
->ref
);
620 cuddDeallocNode(table
,f
);
624 previousP
= &(f
->next
);
628 *previousP
= sentinel
;
629 } /* for every collision list */
633 (void) fprintf(table
->out
,"Linearly combining %d and %d\n",x
,y
);
637 for (i
= 0; i
< yslots
; i
++) {
639 while (f
!= sentinel
) {
641 if (f
->index
!= (DdHalfWord
) yindex
)
646 if (count
!= newykeys
) {
647 fprintf(table
->err
,"Error in finding newykeys\toldykeys = %d\tnewykeys = %d\tactual = %d\n",oldykeys
,newykeys
,count
);
650 fprintf(table
->err
,"Error in id's of ylist\twrong id's = %d\n",idcheck
);
653 for (i
= 0; i
< xslots
; i
++) {
655 while (f
!= sentinel
) {
657 if (f
->index
!= (DdHalfWord
) xindex
)
662 if (count
!= newxkeys
|| newxkeys
!= oldxkeys
) {
663 fprintf(table
->err
,"Error in finding newxkeys\toldxkeys = %d \tnewxkeys = %d \tactual = %d\n",oldxkeys
,newxkeys
,count
);
666 fprintf(table
->err
,"Error in id's of xlist\twrong id's = %d\n",idcheck
);
669 isolated
+= (table
->vars
[xindex
]->ref
== 1) +
670 (table
->vars
[yindex
]->ref
== 1);
671 table
->isolated
+= isolated
;
673 /* Set the appropriate fields in table. */
674 table
->subtables
[y
].keys
= newykeys
;
676 /* Here we should update the linear combination table
677 ** to record that x <- x EXNOR y. This is done by complementing
678 ** the (x,y) entry of the table.
681 table
->keys
+= newykeys
- oldykeys
;
683 cuddXorLinear(table
,xindex
,yindex
);
688 (void) Cudd_DebugCheck(table
);
692 return(table
->keys
- table
->isolated
);
695 (void) fprintf(table
->err
,"Error: cuddLinearInPlace out of memory\n");
699 } /* end of cuddLinearInPlace */
702 /**Function********************************************************************
704 Synopsis [Updates the interaction matrix.]
712 ******************************************************************************/
714 cuddUpdateInteractionMatrix(
720 for (i
= 0; i
< yindex
; i
++) {
721 if (i
!= xindex
&& cuddTestInteract(table
,i
,yindex
)) {
723 cuddSetInteract(table
,i
,xindex
);
725 cuddSetInteract(table
,xindex
,i
);
729 for (i
= yindex
+1; i
< table
->size
; i
++) {
730 if (i
!= xindex
&& cuddTestInteract(table
,yindex
,i
)) {
732 cuddSetInteract(table
,i
,xindex
);
734 cuddSetInteract(table
,xindex
,i
);
739 } /* end of cuddUpdateInteractionMatrix */
742 /**Function********************************************************************
744 Synopsis [Initializes the linear transform matrix.]
746 Description [Initializes the linear transform matrix. Returns 1 if
747 successful; 0 otherwise.]
753 ******************************************************************************/
767 wordsPerRow
= ((nvars
- 1) >> LOGBPL
) + 1;
768 words
= wordsPerRow
* nvars
;
769 table
->linear
= linear
= ALLOC(long,words
);
770 if (linear
== NULL
) {
771 table
->errorCode
= CUDD_MEMORY_OUT
;
774 table
->memused
+= words
* sizeof(long);
775 table
->linearSize
= nvars
;
776 for (i
= 0; i
< words
; i
++) linear
[i
] = 0;
777 for (i
= 0; i
< nvars
; i
++) {
778 word
= wordsPerRow
* i
+ (i
>> LOGBPL
);
780 linear
[word
] = 1 << bit
;
784 } /* end of cuddInitLinear */
787 /**Function********************************************************************
789 Synopsis [Resizes the linear transform matrix.]
791 Description [Resizes the linear transform matrix. Returns 1 if
792 successful; 0 otherwise.]
798 ******************************************************************************/
804 int wordsPerRow
,oldWordsPerRow
;
809 long *linear
,*oldLinear
;
811 oldNvars
= table
->linearSize
;
812 oldWordsPerRow
= ((oldNvars
- 1) >> LOGBPL
) + 1;
813 oldWords
= oldWordsPerRow
* oldNvars
;
814 oldLinear
= table
->linear
;
817 wordsPerRow
= ((nvars
- 1) >> LOGBPL
) + 1;
818 words
= wordsPerRow
* nvars
;
819 table
->linear
= linear
= ALLOC(long,words
);
820 if (linear
== NULL
) {
821 table
->errorCode
= CUDD_MEMORY_OUT
;
824 table
->memused
+= (words
- oldWords
) * sizeof(long);
825 for (i
= 0; i
< words
; i
++) linear
[i
] = 0;
827 /* Copy old matrix. */
828 for (i
= 0; i
< oldNvars
; i
++) {
829 for (j
= 0; j
< oldWordsPerRow
; j
++) {
830 oldWord
= oldWordsPerRow
* i
+ j
;
831 word
= wordsPerRow
* i
+ j
;
832 linear
[word
] = oldLinear
[oldWord
];
837 /* Add elements to the diagonal. */
838 for (i
= oldNvars
; i
< nvars
; i
++) {
839 word
= wordsPerRow
* i
+ (i
>> LOGBPL
);
841 linear
[word
] = 1 << bit
;
843 table
->linearSize
= nvars
;
847 } /* end of cuddResizeLinear */
850 /*---------------------------------------------------------------------------*/
851 /* Definition of static functions */
852 /*---------------------------------------------------------------------------*/
855 /**Function********************************************************************
857 Synopsis [Comparison function used by qsort.]
859 Description [Comparison function used by qsort to order the
860 variables according to the number of keys in the subtables.
861 Returns the difference in number of keys between the two
862 variables being compared.]
866 ******************************************************************************/
868 ddLinearUniqueCompare(
873 if (entry
[*ptrY
] == entry
[*ptrX
]) {
874 return((*ptrX
) - (*ptrY
));
877 return(entry
[*ptrY
] - entry
[*ptrX
]);
879 } /* end of ddLinearUniqueCompare */
882 /**Function********************************************************************
884 Synopsis [Given xLow <= x <= xHigh moves x up and down between the
887 Description [Given xLow <= x <= xHigh moves x up and down between the
888 boundaries. At each step a linear transformation is tried, and, if it
889 decreases the size of the DD, it is accepted. Finds the best position
890 and does the required changes. Returns 1 if successful; 0 otherwise.]
894 ******************************************************************************/
896 ddLinearAndSiftingAux(
904 Move
*moveUp
; /* list of up moves */
905 Move
*moveDown
; /* list of down moves */
909 initialSize
= table
->keys
- table
->isolated
;
915 moveDown
= ddLinearAndSiftingDown(table
,x
,xHigh
,NULL
);
916 /* At this point x --> xHigh unless bounding occurred. */
917 if (moveDown
== (Move
*) CUDD_OUT_OF_MEM
) goto ddLinearAndSiftingAuxOutOfMem
;
918 /* Move backward and stop at best position. */
919 result
= ddLinearAndSiftingBackward(table
,initialSize
,moveDown
);
920 if (!result
) goto ddLinearAndSiftingAuxOutOfMem
;
922 } else if (x
== xHigh
) {
923 moveUp
= ddLinearAndSiftingUp(table
,x
,xLow
,NULL
);
924 /* At this point x --> xLow unless bounding occurred. */
925 if (moveUp
== (Move
*) CUDD_OUT_OF_MEM
) goto ddLinearAndSiftingAuxOutOfMem
;
926 /* Move backward and stop at best position. */
927 result
= ddLinearAndSiftingBackward(table
,initialSize
,moveUp
);
928 if (!result
) goto ddLinearAndSiftingAuxOutOfMem
;
930 } else if ((x
- xLow
) > (xHigh
- x
)) { /* must go down first: shorter */
931 moveDown
= ddLinearAndSiftingDown(table
,x
,xHigh
,NULL
);
932 /* At this point x --> xHigh unless bounding occurred. */
933 if (moveDown
== (Move
*) CUDD_OUT_OF_MEM
) goto ddLinearAndSiftingAuxOutOfMem
;
934 moveUp
= ddUndoMoves(table
,moveDown
);
936 assert(moveUp
== NULL
|| moveUp
->x
== x
);
938 moveUp
= ddLinearAndSiftingUp(table
,x
,xLow
,moveUp
);
939 if (moveUp
== (Move
*) CUDD_OUT_OF_MEM
) goto ddLinearAndSiftingAuxOutOfMem
;
940 /* Move backward and stop at best position. */
941 result
= ddLinearAndSiftingBackward(table
,initialSize
,moveUp
);
942 if (!result
) goto ddLinearAndSiftingAuxOutOfMem
;
944 } else { /* must go up first: shorter */
945 moveUp
= ddLinearAndSiftingUp(table
,x
,xLow
,NULL
);
946 /* At this point x --> xLow unless bounding occurred. */
947 if (moveUp
== (Move
*) CUDD_OUT_OF_MEM
) goto ddLinearAndSiftingAuxOutOfMem
;
948 moveDown
= ddUndoMoves(table
,moveUp
);
950 assert(moveDown
== NULL
|| moveDown
->y
== x
);
952 moveDown
= ddLinearAndSiftingDown(table
,x
,xHigh
,moveDown
);
953 if (moveDown
== (Move
*) CUDD_OUT_OF_MEM
) goto ddLinearAndSiftingAuxOutOfMem
;
954 /* Move backward and stop at best position. */
955 result
= ddLinearAndSiftingBackward(table
,initialSize
,moveDown
);
956 if (!result
) goto ddLinearAndSiftingAuxOutOfMem
;
959 while (moveDown
!= NULL
) {
960 move
= moveDown
->next
;
961 cuddDeallocMove(table
, moveDown
);
964 while (moveUp
!= NULL
) {
966 cuddDeallocMove(table
, moveUp
);
972 ddLinearAndSiftingAuxOutOfMem
:
973 while (moveDown
!= NULL
) {
974 move
= moveDown
->next
;
975 cuddDeallocMove(table
, moveDown
);
978 while (moveUp
!= NULL
) {
980 cuddDeallocMove(table
, moveUp
);
986 } /* end of ddLinearAndSiftingAux */
989 /**Function********************************************************************
991 Synopsis [Sifts a variable up and applies linear transformations.]
993 Description [Sifts a variable up and applies linear transformations.
994 Moves y up until either it reaches the bound (xLow) or the size of
995 the DD heap increases too much. Returns the set of moves in case of
996 success; NULL if memory is full.]
1000 ******************************************************************************/
1002 ddLinearAndSiftingUp(
1015 int L
; /* lower bound on DD size */
1023 yindex
= table
->invperm
[y
];
1025 /* Initialize the lower bound.
1026 ** The part of the DD below y will not change.
1027 ** The part of the DD above y that does not interact with y will not
1028 ** change. The rest may vanish in the best case, except for
1029 ** the nodes at level xLow, which will not vanish, regardless.
1031 limitSize
= L
= table
->keys
- table
->isolated
;
1032 for (x
= xLow
+ 1; x
< y
; x
++) {
1033 xindex
= table
->invperm
[x
];
1034 if (cuddTestInteract(table
,xindex
,yindex
)) {
1035 isolated
= table
->vars
[xindex
]->ref
== 1;
1036 L
-= table
->subtables
[x
].keys
- isolated
;
1039 isolated
= table
->vars
[yindex
]->ref
== 1;
1040 L
-= table
->subtables
[y
].keys
- isolated
;
1042 x
= cuddNextLow(table
,y
);
1043 while (x
>= xLow
&& L
<= limitSize
) {
1044 xindex
= table
->invperm
[x
];
1046 checkL
= table
->keys
- table
->isolated
;
1047 for (z
= xLow
+ 1; z
< y
; z
++) {
1048 zindex
= table
->invperm
[z
];
1049 if (cuddTestInteract(table
,zindex
,yindex
)) {
1050 isolated
= table
->vars
[zindex
]->ref
== 1;
1051 checkL
-= table
->subtables
[z
].keys
- isolated
;
1054 isolated
= table
->vars
[yindex
]->ref
== 1;
1055 checkL
-= table
->subtables
[y
].keys
- isolated
;
1057 (void) fprintf(table
->out
, "checkL(%d) != L(%d)\n",checkL
,L
);
1060 size
= cuddSwapInPlace(table
,x
,y
);
1061 if (size
== 0) goto ddLinearAndSiftingUpOutOfMem
;
1062 newsize
= cuddLinearInPlace(table
,x
,y
);
1063 if (newsize
== 0) goto ddLinearAndSiftingUpOutOfMem
;
1064 move
= (Move
*) cuddDynamicAllocNode(table
);
1065 if (move
== NULL
) goto ddLinearAndSiftingUpOutOfMem
;
1070 move
->flags
= CUDD_SWAP_MOVE
;
1071 if (newsize
>= size
) {
1072 /* Undo transformation. The transformation we apply is
1073 ** its own inverse. Hence, we just apply the transformation
1076 newsize
= cuddLinearInPlace(table
,x
,y
);
1077 if (newsize
== 0) goto ddLinearAndSiftingUpOutOfMem
;
1079 if (newsize
!= size
) {
1080 (void) fprintf(table
->out
,"Change in size after identity transformation! From %d to %d\n",size
,newsize
);
1083 } else if (cuddTestInteract(table
,xindex
,yindex
)) {
1085 move
->flags
= CUDD_LINEAR_TRANSFORM_MOVE
;
1086 cuddUpdateInteractionMatrix(table
,xindex
,yindex
);
1089 /* Update the lower bound. */
1090 if (cuddTestInteract(table
,xindex
,yindex
)) {
1091 isolated
= table
->vars
[xindex
]->ref
== 1;
1092 L
+= table
->subtables
[y
].keys
- isolated
;
1094 if ((double) size
> (double) limitSize
* table
->maxGrowth
) break;
1095 if (size
< limitSize
) limitSize
= size
;
1097 x
= cuddNextLow(table
,y
);
1101 ddLinearAndSiftingUpOutOfMem
:
1102 while (moves
!= NULL
) {
1104 cuddDeallocMove(table
, moves
);
1107 return((Move
*) CUDD_OUT_OF_MEM
);
1109 } /* end of ddLinearAndSiftingUp */
1112 /**Function********************************************************************
1114 Synopsis [Sifts a variable down and applies linear transformations.]
1116 Description [Sifts a variable down and applies linear
1117 transformations. Moves x down until either it reaches the bound
1118 (xHigh) or the size of the DD heap increases too much. Returns the
1119 set of moves in case of success; NULL if memory is full.]
1123 ******************************************************************************/
1125 ddLinearAndSiftingDown(
1135 int R
; /* upper bound on node decrease */
1147 xindex
= table
->invperm
[x
];
1148 limitSize
= size
= table
->keys
- table
->isolated
;
1150 for (y
= xHigh
; y
> x
; y
--) {
1151 yindex
= table
->invperm
[y
];
1152 if (cuddTestInteract(table
,xindex
,yindex
)) {
1153 isolated
= table
->vars
[yindex
]->ref
== 1;
1154 R
+= table
->subtables
[y
].keys
- isolated
;
1158 y
= cuddNextHigh(table
,x
);
1159 while (y
<= xHigh
&& size
- R
< limitSize
) {
1162 for (z
= xHigh
; z
> x
; z
--) {
1163 zindex
= table
->invperm
[z
];
1164 if (cuddTestInteract(table
,xindex
,zindex
)) {
1165 isolated
= table
->vars
[zindex
]->ref
== 1;
1166 checkR
+= table
->subtables
[z
].keys
- isolated
;
1170 (void) fprintf(table
->out
, "checkR(%d) != R(%d)\n",checkR
,R
);
1173 /* Update upper bound on node decrease. */
1174 yindex
= table
->invperm
[y
];
1175 if (cuddTestInteract(table
,xindex
,yindex
)) {
1176 isolated
= table
->vars
[yindex
]->ref
== 1;
1177 R
-= table
->subtables
[y
].keys
- isolated
;
1179 size
= cuddSwapInPlace(table
,x
,y
);
1180 if (size
== 0) goto ddLinearAndSiftingDownOutOfMem
;
1181 newsize
= cuddLinearInPlace(table
,x
,y
);
1182 if (newsize
== 0) goto ddLinearAndSiftingDownOutOfMem
;
1183 move
= (Move
*) cuddDynamicAllocNode(table
);
1184 if (move
== NULL
) goto ddLinearAndSiftingDownOutOfMem
;
1189 move
->flags
= CUDD_SWAP_MOVE
;
1190 if (newsize
>= size
) {
1191 /* Undo transformation. The transformation we apply is
1192 ** its own inverse. Hence, we just apply the transformation
1195 newsize
= cuddLinearInPlace(table
,x
,y
);
1196 if (newsize
== 0) goto ddLinearAndSiftingDownOutOfMem
;
1197 if (newsize
!= size
) {
1198 (void) fprintf(table
->out
,"Change in size after identity transformation! From %d to %d\n",size
,newsize
);
1200 } else if (cuddTestInteract(table
,xindex
,yindex
)) {
1202 move
->flags
= CUDD_LINEAR_TRANSFORM_MOVE
;
1203 cuddUpdateInteractionMatrix(table
,xindex
,yindex
);
1206 if ((double) size
> (double) limitSize
* table
->maxGrowth
) break;
1207 if (size
< limitSize
) limitSize
= size
;
1209 y
= cuddNextHigh(table
,x
);
1213 ddLinearAndSiftingDownOutOfMem
:
1214 while (moves
!= NULL
) {
1216 cuddDeallocMove(table
, moves
);
1219 return((Move
*) CUDD_OUT_OF_MEM
);
1221 } /* end of ddLinearAndSiftingDown */
1224 /**Function********************************************************************
1226 Synopsis [Given a set of moves, returns the DD heap to the order
1227 giving the minimum size.]
1229 Description [Given a set of moves, returns the DD heap to the
1230 position giving the minimum size. In case of ties, returns to the
1231 closest position giving the minimum size. Returns 1 in case of
1232 success; 0 otherwise.]
1236 ******************************************************************************/
1238 ddLinearAndSiftingBackward(
1246 for (move
= moves
; move
!= NULL
; move
= move
->next
) {
1247 if (move
->size
< size
) {
1252 for (move
= moves
; move
!= NULL
; move
= move
->next
) {
1253 if (move
->size
== size
) return(1);
1254 if (move
->flags
== CUDD_LINEAR_TRANSFORM_MOVE
) {
1255 res
= cuddLinearInPlace(table
,(int)move
->x
,(int)move
->y
);
1256 if (!res
) return(0);
1258 res
= cuddSwapInPlace(table
,(int)move
->x
,(int)move
->y
);
1259 if (!res
) return(0);
1260 if (move
->flags
== CUDD_INVERSE_TRANSFORM_MOVE
) {
1261 res
= cuddLinearInPlace(table
,(int)move
->x
,(int)move
->y
);
1262 if (!res
) return(0);
1268 } /* end of ddLinearAndSiftingBackward */
1271 /**Function********************************************************************
1273 Synopsis [Given a set of moves, returns the DD heap to the order
1274 in effect before the moves.]
1276 Description [Given a set of moves, returns the DD heap to the
1277 order in effect before the moves. Returns 1 in case of success;
1282 ******************************************************************************/
1288 Move
*invmoves
= NULL
;
1293 for (move
= moves
; move
!= NULL
; move
= move
->next
) {
1294 invmove
= (Move
*) cuddDynamicAllocNode(table
);
1295 if (invmove
== NULL
) goto ddUndoMovesOutOfMem
;
1296 invmove
->x
= move
->x
;
1297 invmove
->y
= move
->y
;
1298 invmove
->next
= invmoves
;
1300 if (move
->flags
== CUDD_SWAP_MOVE
) {
1301 invmove
->flags
= CUDD_SWAP_MOVE
;
1302 size
= cuddSwapInPlace(table
,(int)move
->x
,(int)move
->y
);
1303 if (!size
) goto ddUndoMovesOutOfMem
;
1304 } else if (move
->flags
== CUDD_LINEAR_TRANSFORM_MOVE
) {
1305 invmove
->flags
= CUDD_INVERSE_TRANSFORM_MOVE
;
1306 size
= cuddLinearInPlace(table
,(int)move
->x
,(int)move
->y
);
1307 if (!size
) goto ddUndoMovesOutOfMem
;
1308 size
= cuddSwapInPlace(table
,(int)move
->x
,(int)move
->y
);
1309 if (!size
) goto ddUndoMovesOutOfMem
;
1310 } else { /* must be CUDD_INVERSE_TRANSFORM_MOVE */
1312 (void) fprintf(table
->err
,"Unforseen event in ddUndoMoves!\n");
1314 invmove
->flags
= CUDD_LINEAR_TRANSFORM_MOVE
;
1315 size
= cuddSwapInPlace(table
,(int)move
->x
,(int)move
->y
);
1316 if (!size
) goto ddUndoMovesOutOfMem
;
1317 size
= cuddLinearInPlace(table
,(int)move
->x
,(int)move
->y
);
1318 if (!size
) goto ddUndoMovesOutOfMem
;
1320 invmove
->size
= size
;
1325 ddUndoMovesOutOfMem
:
1326 while (invmoves
!= NULL
) {
1327 move
= invmoves
->next
;
1328 cuddDeallocMove(table
, invmoves
);
1331 return((Move
*) CUDD_OUT_OF_MEM
);
1333 } /* end of ddUndoMoves */
1336 /**Function********************************************************************
1338 Synopsis [XORs two rows of the linear transform matrix.]
1340 Description [XORs two rows of the linear transform matrix and replaces
1341 the first row with the result.]
1347 ******************************************************************************/
1355 int nvars
= table
->size
;
1356 int wordsPerRow
= ((nvars
- 1) >> LOGBPL
) + 1;
1357 int xstart
= wordsPerRow
* x
;
1358 int ystart
= wordsPerRow
* y
;
1359 long *linear
= table
->linear
;
1361 for (i
= 0; i
< wordsPerRow
; i
++) {
1362 linear
[xstart
+i
] ^= linear
[ystart
+i
];
1365 } /* end of cuddXorLinear */