1 /**CFile***********************************************************************
3 FileName [cuddZddLin.c]
7 Synopsis [Procedures for dynamic variable ordering of ZDDs.]
9 Description [Internal procedures included in this module:
11 <li> cuddZddLinearSifting()
13 Static procedures included in this module:
15 <li> cuddZddLinearInPlace()
16 <li> cuddZddLinerAux()
17 <li> cuddZddLinearUp()
18 <li> cuddZddLinearDown()
19 <li> cuddZddLinearBackward()
20 <li> cuddZddUndoMoves()
24 SeeAlso [cuddLinear.c cuddZddReord.c]
26 Author [Fabio Somenzi]
28 Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado
32 Redistribution and use in source and binary forms, with or without
33 modification, are permitted provided that the following conditions
36 Redistributions of source code must retain the above copyright
37 notice, this list of conditions and the following disclaimer.
39 Redistributions in binary form must reproduce the above copyright
40 notice, this list of conditions and the following disclaimer in the
41 documentation and/or other materials provided with the distribution.
43 Neither the name of the University of Colorado nor the names of its
44 contributors may be used to endorse or promote products derived from
45 this software without specific prior written permission.
47 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
48 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
49 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
50 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
51 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
52 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
53 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
54 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
55 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
57 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58 POSSIBILITY OF SUCH DAMAGE.]
60 ******************************************************************************/
65 /*---------------------------------------------------------------------------*/
66 /* Constant declarations */
67 /*---------------------------------------------------------------------------*/
69 #define CUDD_SWAP_MOVE 0
70 #define CUDD_LINEAR_TRANSFORM_MOVE 1
71 #define CUDD_INVERSE_TRANSFORM_MOVE 2
73 /*---------------------------------------------------------------------------*/
74 /* Stucture declarations */
75 /*---------------------------------------------------------------------------*/
78 /*---------------------------------------------------------------------------*/
79 /* Type declarations */
80 /*---------------------------------------------------------------------------*/
83 /*---------------------------------------------------------------------------*/
84 /* Variable declarations */
85 /*---------------------------------------------------------------------------*/
88 static char rcsid
[] DD_UNUSED
= "$Id: cuddZddLin.c,v 1.14 2004/08/13 18:04:53 fabio Exp $";
91 extern int *zdd_entry
;
92 extern int zddTotalNumberSwapping
;
93 static int zddTotalNumberLinearTr
;
97 /*---------------------------------------------------------------------------*/
98 /* Macro declarations */
99 /*---------------------------------------------------------------------------*/
102 /**AutomaticStart*************************************************************/
104 /*---------------------------------------------------------------------------*/
105 /* Static function prototypes */
106 /*---------------------------------------------------------------------------*/
108 static int cuddZddLinearInPlace (DdManager
* table
, int x
, int y
);
109 static int cuddZddLinearAux (DdManager
*table
, int x
, int xLow
, int xHigh
);
110 static Move
* cuddZddLinearUp (DdManager
*table
, int y
, int xLow
, Move
*prevMoves
);
111 static Move
* cuddZddLinearDown (DdManager
*table
, int x
, int xHigh
, Move
*prevMoves
);
112 static int cuddZddLinearBackward (DdManager
*table
, int size
, Move
*moves
);
113 static Move
* cuddZddUndoMoves (DdManager
*table
, Move
*moves
);
115 /**AutomaticEnd***************************************************************/
118 /*---------------------------------------------------------------------------*/
119 /* Definition of exported functions */
120 /*---------------------------------------------------------------------------*/
123 /*---------------------------------------------------------------------------*/
124 /* Definition of internal functions */
125 /*---------------------------------------------------------------------------*/
130 /**Function********************************************************************
132 Synopsis [Implementation of the linear sifting algorithm for ZDDs.]
134 Description [Implementation of the linear sifting algorithm for ZDDs.
135 Assumes that no dead nodes are present.
137 <li> Order all the variables according to the number of entries
138 in each unique table.
139 <li> Sift the variable up and down and applies the XOR transformation,
140 remembering each time the total size of the DD heap.
141 <li> Select the best permutation.
142 <li> Repeat 3 and 4 for all variables.
144 Returns 1 if successful; 0 otherwise.]
150 ******************************************************************************/
152 cuddZddLinearSifting(
169 /* Find order in which to sift variables. */
171 zdd_entry
= ALLOC(int, size
);
172 if (zdd_entry
== NULL
) {
173 table
->errorCode
= CUDD_MEMORY_OUT
;
174 goto cuddZddSiftingOutOfMem
;
176 var
= ALLOC(int, size
);
178 table
->errorCode
= CUDD_MEMORY_OUT
;
179 goto cuddZddSiftingOutOfMem
;
182 for (i
= 0; i
< size
; i
++) {
184 zdd_entry
[i
] = table
->subtableZ
[x
].keys
;
188 qsort((void *)var
, size
, sizeof(int), (DD_QSFP
)cuddZddUniqueCompare
);
191 for (i
= 0; i
< ddMin(table
->siftMaxVar
, size
); i
++) {
192 if (zddTotalNumberSwapping
>= table
->siftMaxSwap
)
194 x
= table
->permZ
[var
[i
]];
195 if (x
< lower
|| x
> upper
) continue;
197 previousSize
= table
->keysZ
;
199 result
= cuddZddLinearAux(table
, x
, lower
, upper
);
201 goto cuddZddSiftingOutOfMem
;
203 if (table
->keysZ
< (unsigned) previousSize
) {
204 (void) fprintf(table
->out
,"-");
205 } else if (table
->keysZ
> (unsigned) previousSize
) {
206 (void) fprintf(table
->out
,"+"); /* should never happen */
207 (void) fprintf(table
->out
,"\nSize increased from %d to %d while sifting variable %d\n", previousSize
, table
->keysZ
, var
[i
]);
209 (void) fprintf(table
->out
,"=");
220 cuddZddSiftingOutOfMem
:
222 if (zdd_entry
!= NULL
) FREE(zdd_entry
);
223 if (var
!= NULL
) FREE(var
);
227 } /* end of cuddZddLinearSifting */
230 /*---------------------------------------------------------------------------*/
231 /* Definition of static functions */
232 /*---------------------------------------------------------------------------*/
235 /**Function********************************************************************
237 Synopsis [Linearly combines two adjacent variables.]
239 Description [Linearly combines two adjacent variables. It assumes
240 that no dead nodes are present on entry to this procedure. The
241 procedure then guarantees that no dead nodes will be present when it
242 terminates. cuddZddLinearInPlace assumes that x < y. Returns the
243 number of keys in the table if successful; 0 otherwise.]
247 SeeAlso [cuddZddSwapInPlace cuddLinearInPlace]
249 ******************************************************************************/
251 cuddZddLinearInPlace(
256 DdNodePtr
*xlist
, *ylist
;
260 int oldxkeys
, oldykeys
;
261 int newxkeys
, newykeys
;
264 DdNode
*f
, *f1
, *f0
, *f11
, *f10
, *f01
, *f00
;
265 DdNode
*newf1
, *newf0
, *g
, *next
, *previous
;
270 assert(cuddZddNextHigh(table
,x
) == y
);
271 assert(table
->subtableZ
[x
].keys
!= 0);
272 assert(table
->subtableZ
[y
].keys
!= 0);
273 assert(table
->subtableZ
[x
].dead
== 0);
274 assert(table
->subtableZ
[y
].dead
== 0);
277 zddTotalNumberLinearTr
++;
279 /* Get parameters of x subtable. */
280 xindex
= table
->invpermZ
[x
];
281 xlist
= table
->subtableZ
[x
].nodelist
;
282 oldxkeys
= table
->subtableZ
[x
].keys
;
283 xslots
= table
->subtableZ
[x
].slots
;
284 xshift
= table
->subtableZ
[x
].shift
;
287 /* Get parameters of y subtable. */
288 yindex
= table
->invpermZ
[y
];
289 ylist
= table
->subtableZ
[y
].nodelist
;
290 oldykeys
= table
->subtableZ
[y
].keys
;
291 yslots
= table
->subtableZ
[y
].slots
;
292 yshift
= table
->subtableZ
[y
].shift
;
295 /* The nodes in the x layer are put in two chains. The chain
296 ** pointed by g holds the normal nodes. When re-expressed they stay
297 ** in the x list. The chain pointed by special holds the elements
298 ** that will move to the y list.
301 for (i
= 0; i
< xslots
; i
++) {
303 if (f
== NULL
) continue;
308 /* if (f1->index == yindex) */ cuddSatDec(f1
->ref
);
310 /* if (f0->index == yindex) */ cuddSatDec(f0
->ref
);
311 if ((int) f1
->index
== yindex
&& cuddE(f1
) == empty
&&
312 (int) f0
->index
!= yindex
) {
320 } /* while there are elements in the collision chain */
321 } /* for each slot of the x subtable */
323 /* Mark y nodes with pointers from above x. We mark them by
324 ** changing their index to x.
326 for (i
= 0; i
< yslots
; i
++) {
333 } /* while there are elements in the collision chain */
334 } /* for each slot of the y subtable */
336 /* Move special nodes to the y list. */
343 cuddSatInc(f11
->ref
);
347 /* Insert at the beginning of the list so that it will be
348 ** found first if there is a duplicate. The duplicate will
349 ** eventually be moved or garbage collected. No node
350 ** re-expression will add a pointer to it.
352 posn
= ddHash(f11
, f0
, yshift
);
353 f
->next
= ylist
[posn
];
359 /* Take care of the remaining x nodes that must be re-expressed.
360 ** They form a linked list pointed by g.
368 /* Find f1, f0, f11, f10, f01, f00. */
370 if ((int) f1
->index
== yindex
|| (int) f1
->index
== xindex
) {
371 f11
= cuddT(f1
); f10
= cuddE(f1
);
373 f11
= empty
; f10
= f1
;
376 if ((int) f0
->index
== yindex
|| (int) f0
->index
== xindex
) {
377 f01
= cuddT(f0
); f00
= cuddE(f0
);
379 f01
= empty
; f00
= f0
;
381 /* Create the new T child. */
384 cuddSatInc(newf1
->ref
);
386 /* Check ylist for triple (yindex, f01, f10). */
387 posn
= ddHash(f01
, f10
, yshift
);
388 /* For each element newf1 in collision list ylist[posn]. */
390 /* Search the collision chain skipping the marked nodes. */
391 while (newf1
!= NULL
) {
392 if (cuddT(newf1
) == f01
&& cuddE(newf1
) == f10
&&
393 (int) newf1
->index
== yindex
) {
394 cuddSatInc(newf1
->ref
);
399 if (newf1
== NULL
) { /* no match */
400 newf1
= cuddDynamicAllocNode(table
);
402 goto zddSwapOutOfMem
;
403 newf1
->index
= yindex
; newf1
->ref
= 1;
406 /* Insert newf1 in the collision list ylist[pos];
407 ** increase the ref counts of f01 and f10
410 newf1
->next
= ylist
[posn
];
412 cuddSatInc(f01
->ref
);
413 cuddSatInc(f10
->ref
);
418 /* Do the same for f0. */
419 /* Create the new E child. */
422 cuddSatInc(newf0
->ref
);
424 /* Check ylist for triple (yindex, f11, f00). */
425 posn
= ddHash(f11
, f00
, yshift
);
426 /* For each element newf0 in collision list ylist[posn]. */
428 while (newf0
!= NULL
) {
429 if (cuddT(newf0
) == f11
&& cuddE(newf0
) == f00
&&
430 (int) newf0
->index
== yindex
) {
431 cuddSatInc(newf0
->ref
);
436 if (newf0
== NULL
) { /* no match */
437 newf0
= cuddDynamicAllocNode(table
);
439 goto zddSwapOutOfMem
;
440 newf0
->index
= yindex
; newf0
->ref
= 1;
441 cuddT(newf0
) = f11
; cuddE(newf0
) = f00
;
442 /* Insert newf0 in the collision list ylist[posn];
443 ** increase the ref counts of f11 and f00.
446 newf0
->next
= ylist
[posn
];
448 cuddSatInc(f11
->ref
);
449 cuddSatInc(f00
->ref
);
454 /* Re-insert the modified f in xlist.
455 ** The modified f does not already exists in xlist.
456 ** (Because of the uniqueness of the cofactors.)
458 posn
= ddHash(newf1
, newf0
, xshift
);
460 f
->next
= xlist
[posn
];
463 } /* while f != NULL */
465 /* GC the y layer and move the marked nodes to the x list. */
467 /* For each node f in ylist. */
468 for (i
= 0; i
< yslots
; i
++) {
474 cuddSatDec(cuddT(f
)->ref
);
475 cuddSatDec(cuddE(f
)->ref
);
476 cuddDeallocNode(table
, f
);
478 if (previous
== NULL
)
481 previous
->next
= next
;
482 } else if ((int) f
->index
== xindex
) { /* move marked node */
483 if (previous
== NULL
)
486 previous
->next
= next
;
489 /* Check ylist for triple (yindex, f1, empty). */
490 posn
= ddHash(f1
, empty
, yshift
);
491 /* For each element newf1 in collision list ylist[posn]. */
493 while (newf1
!= NULL
) {
494 if (cuddT(newf1
) == f1
&& cuddE(newf1
) == empty
&&
495 (int) newf1
->index
== yindex
) {
496 cuddSatInc(newf1
->ref
);
501 if (newf1
== NULL
) { /* no match */
502 newf1
= cuddDynamicAllocNode(table
);
504 goto zddSwapOutOfMem
;
505 newf1
->index
= yindex
; newf1
->ref
= 1;
506 cuddT(newf1
) = f1
; cuddE(newf1
) = empty
;
507 /* Insert newf1 in the collision list ylist[posn];
508 ** increase the ref counts of f1 and empty.
511 newf1
->next
= ylist
[posn
];
513 if (posn
== i
&& previous
== NULL
)
516 cuddSatInc(empty
->ref
);
520 /* Insert f in x list. */
521 posn
= ddHash(newf1
, f0
, xshift
);
524 f
->next
= xlist
[posn
];
533 /* Set the appropriate fields in table. */
534 table
->subtableZ
[x
].keys
= newxkeys
;
535 table
->subtableZ
[y
].keys
= newykeys
;
537 table
->keysZ
+= newxkeys
+ newykeys
- oldxkeys
- oldykeys
;
539 /* Update univ section; univ[x] remains the same. */
540 table
->univ
[y
] = cuddT(table
->univ
[x
]);
543 (void) fprintf(table
->out
,"x = %d y = %d\n", x
, y
);
544 (void) Cudd_DebugCheck(table
);
545 (void) Cudd_CheckKeys(table
);
548 return (table
->keysZ
);
551 (void) fprintf(table
->err
, "Error: cuddZddSwapInPlace out of memory\n");
555 } /* end of cuddZddLinearInPlace */
558 /**Function********************************************************************
560 Synopsis [Given xLow <= x <= xHigh moves x up and down between the
563 Description [Given xLow <= x <= xHigh moves x up and down between the
564 boundaries. Finds the best position and does the required changes.
565 Returns 1 if successful; 0 otherwise.]
571 ******************************************************************************/
580 Move
*moveUp
; /* list of up move */
581 Move
*moveDown
; /* list of down move */
586 initial_size
= table
->keysZ
;
589 assert(table
->subtableZ
[x
].keys
> 0);
596 moveDown
= cuddZddLinearDown(table
, x
, xHigh
, NULL
);
597 /* At this point x --> xHigh. */
598 if (moveDown
== (Move
*) CUDD_OUT_OF_MEM
)
599 goto cuddZddLinearAuxOutOfMem
;
600 /* Move backward and stop at best position. */
601 result
= cuddZddLinearBackward(table
, initial_size
, moveDown
);
603 goto cuddZddLinearAuxOutOfMem
;
605 } else if (x
== xHigh
) {
606 moveUp
= cuddZddLinearUp(table
, x
, xLow
, NULL
);
607 /* At this point x --> xLow. */
608 if (moveUp
== (Move
*) CUDD_OUT_OF_MEM
)
609 goto cuddZddLinearAuxOutOfMem
;
610 /* Move backward and stop at best position. */
611 result
= cuddZddLinearBackward(table
, initial_size
, moveUp
);
613 goto cuddZddLinearAuxOutOfMem
;
615 } else if ((x
- xLow
) > (xHigh
- x
)) { /* must go down first: shorter */
616 moveDown
= cuddZddLinearDown(table
, x
, xHigh
, NULL
);
617 /* At this point x --> xHigh. */
618 if (moveDown
== (Move
*) CUDD_OUT_OF_MEM
)
619 goto cuddZddLinearAuxOutOfMem
;
620 moveUp
= cuddZddUndoMoves(table
,moveDown
);
622 assert(moveUp
== NULL
|| moveUp
->x
== x
);
624 moveUp
= cuddZddLinearUp(table
, x
, xLow
, moveUp
);
625 if (moveUp
== (Move
*) CUDD_OUT_OF_MEM
)
626 goto cuddZddLinearAuxOutOfMem
;
627 /* Move backward and stop at best position. */
628 result
= cuddZddLinearBackward(table
, initial_size
, moveUp
);
630 goto cuddZddLinearAuxOutOfMem
;
633 moveUp
= cuddZddLinearUp(table
, x
, xLow
, NULL
);
634 /* At this point x --> xHigh. */
635 if (moveUp
== (Move
*) CUDD_OUT_OF_MEM
)
636 goto cuddZddLinearAuxOutOfMem
;
638 moveDown
= cuddZddUndoMoves(table
,moveUp
);
640 assert(moveDown
== NULL
|| moveDown
->y
== x
);
642 moveDown
= cuddZddLinearDown(table
, x
, xHigh
, moveDown
);
643 if (moveDown
== (Move
*) CUDD_OUT_OF_MEM
)
644 goto cuddZddLinearAuxOutOfMem
;
645 /* Move backward and stop at best position. */
646 result
= cuddZddLinearBackward(table
, initial_size
, moveDown
);
648 goto cuddZddLinearAuxOutOfMem
;
651 while (moveDown
!= NULL
) {
652 move
= moveDown
->next
;
653 cuddDeallocMove(table
, moveDown
);
656 while (moveUp
!= NULL
) {
658 cuddDeallocMove(table
, moveUp
);
664 cuddZddLinearAuxOutOfMem
:
665 if (moveDown
!= (Move
*) CUDD_OUT_OF_MEM
) {
666 while (moveDown
!= NULL
) {
667 move
= moveDown
->next
;
668 cuddDeallocMove(table
, moveDown
);
672 if (moveUp
!= (Move
*) CUDD_OUT_OF_MEM
) {
673 while (moveUp
!= NULL
) {
675 cuddDeallocMove(table
, moveUp
);
682 } /* end of cuddZddLinearAux */
685 /**Function********************************************************************
687 Synopsis [Sifts a variable up applying the XOR transformation.]
689 Description [Sifts a variable up applying the XOR
690 transformation. Moves y up until either it reaches the bound (xLow)
691 or the size of the ZDD heap increases too much. Returns the set of
692 moves in case of success; NULL if memory is full.]
698 ******************************************************************************/
713 limitSize
= table
->keysZ
;
715 x
= cuddZddNextLow(table
, y
);
717 size
= cuddZddSwapInPlace(table
, x
, y
);
719 goto cuddZddLinearUpOutOfMem
;
720 newsize
= cuddZddLinearInPlace(table
, x
, y
);
722 goto cuddZddLinearUpOutOfMem
;
723 move
= (Move
*) cuddDynamicAllocNode(table
);
725 goto cuddZddLinearUpOutOfMem
;
730 move
->flags
= CUDD_SWAP_MOVE
;
731 if (newsize
> size
) {
732 /* Undo transformation. The transformation we apply is
733 ** its own inverse. Hence, we just apply the transformation
736 newsize
= cuddZddLinearInPlace(table
,x
,y
);
737 if (newsize
== 0) goto cuddZddLinearUpOutOfMem
;
739 if (newsize
!= size
) {
740 (void) fprintf(table
->err
,"Change in size after identity transformation! From %d to %d\n",size
,newsize
);
745 move
->flags
= CUDD_LINEAR_TRANSFORM_MOVE
;
749 if ((double)size
> (double)limitSize
* table
->maxGrowth
)
751 if (size
< limitSize
)
755 x
= cuddZddNextLow(table
, y
);
759 cuddZddLinearUpOutOfMem
:
760 while (moves
!= NULL
) {
762 cuddDeallocMove(table
, moves
);
765 return((Move
*) CUDD_OUT_OF_MEM
);
767 } /* end of cuddZddLinearUp */
770 /**Function********************************************************************
772 Synopsis [Sifts a variable down and applies the XOR transformation.]
774 Description [Sifts a variable down. Moves x down until either it
775 reaches the bound (xHigh) or the size of the ZDD heap increases too
776 much. Returns the set of moves in case of success; NULL if memory is
783 ******************************************************************************/
798 limitSize
= table
->keysZ
;
800 y
= cuddZddNextHigh(table
, x
);
802 size
= cuddZddSwapInPlace(table
, x
, y
);
804 goto cuddZddLinearDownOutOfMem
;
805 newsize
= cuddZddLinearInPlace(table
, x
, y
);
807 goto cuddZddLinearDownOutOfMem
;
808 move
= (Move
*) cuddDynamicAllocNode(table
);
810 goto cuddZddLinearDownOutOfMem
;
815 move
->flags
= CUDD_SWAP_MOVE
;
816 if (newsize
> size
) {
817 /* Undo transformation. The transformation we apply is
818 ** its own inverse. Hence, we just apply the transformation
821 newsize
= cuddZddLinearInPlace(table
,x
,y
);
822 if (newsize
== 0) goto cuddZddLinearDownOutOfMem
;
823 if (newsize
!= size
) {
824 (void) fprintf(table
->err
,"Change in size after identity transformation! From %d to %d\n",size
,newsize
);
828 move
->flags
= CUDD_LINEAR_TRANSFORM_MOVE
;
832 if ((double)size
> (double)limitSize
* table
->maxGrowth
)
834 if (size
< limitSize
)
838 y
= cuddZddNextHigh(table
, x
);
842 cuddZddLinearDownOutOfMem
:
843 while (moves
!= NULL
) {
845 cuddDeallocMove(table
, moves
);
848 return((Move
*) CUDD_OUT_OF_MEM
);
850 } /* end of cuddZddLinearDown */
853 /**Function********************************************************************
855 Synopsis [Given a set of moves, returns the ZDD heap to the position
856 giving the minimum size.]
858 Description [Given a set of moves, returns the ZDD heap to the
859 position giving the minimum size. In case of ties, returns to the
860 closest position giving the minimum size. Returns 1 in case of
861 success; 0 otherwise.]
867 ******************************************************************************/
869 cuddZddLinearBackward(
877 /* Find the minimum size among moves. */
878 for (move
= moves
; move
!= NULL
; move
= move
->next
) {
879 if (move
->size
< size
) {
884 for (move
= moves
; move
!= NULL
; move
= move
->next
) {
885 if (move
->size
== size
) return(1);
886 if (move
->flags
== CUDD_LINEAR_TRANSFORM_MOVE
) {
887 res
= cuddZddLinearInPlace(table
,(int)move
->x
,(int)move
->y
);
890 res
= cuddZddSwapInPlace(table
, move
->x
, move
->y
);
893 if (move
->flags
== CUDD_INVERSE_TRANSFORM_MOVE
) {
894 res
= cuddZddLinearInPlace(table
,(int)move
->x
,(int)move
->y
);
901 } /* end of cuddZddLinearBackward */
904 /**Function********************************************************************
906 Synopsis [Given a set of moves, returns the ZDD heap to the order
907 in effect before the moves.]
909 Description [Given a set of moves, returns the ZDD heap to the
910 order in effect before the moves. Returns 1 in case of success;
915 ******************************************************************************/
921 Move
*invmoves
= NULL
;
926 for (move
= moves
; move
!= NULL
; move
= move
->next
) {
927 invmove
= (Move
*) cuddDynamicAllocNode(table
);
928 if (invmove
== NULL
) goto cuddZddUndoMovesOutOfMem
;
929 invmove
->x
= move
->x
;
930 invmove
->y
= move
->y
;
931 invmove
->next
= invmoves
;
933 if (move
->flags
== CUDD_SWAP_MOVE
) {
934 invmove
->flags
= CUDD_SWAP_MOVE
;
935 size
= cuddZddSwapInPlace(table
,(int)move
->x
,(int)move
->y
);
936 if (!size
) goto cuddZddUndoMovesOutOfMem
;
937 } else if (move
->flags
== CUDD_LINEAR_TRANSFORM_MOVE
) {
938 invmove
->flags
= CUDD_INVERSE_TRANSFORM_MOVE
;
939 size
= cuddZddLinearInPlace(table
,(int)move
->x
,(int)move
->y
);
940 if (!size
) goto cuddZddUndoMovesOutOfMem
;
941 size
= cuddZddSwapInPlace(table
,(int)move
->x
,(int)move
->y
);
942 if (!size
) goto cuddZddUndoMovesOutOfMem
;
943 } else { /* must be CUDD_INVERSE_TRANSFORM_MOVE */
945 (void) fprintf(table
->err
,"Unforseen event in ddUndoMoves!\n");
947 invmove
->flags
= CUDD_LINEAR_TRANSFORM_MOVE
;
948 size
= cuddZddSwapInPlace(table
,(int)move
->x
,(int)move
->y
);
949 if (!size
) goto cuddZddUndoMovesOutOfMem
;
950 size
= cuddZddLinearInPlace(table
,(int)move
->x
,(int)move
->y
);
951 if (!size
) goto cuddZddUndoMovesOutOfMem
;
953 invmove
->size
= size
;
958 cuddZddUndoMovesOutOfMem
:
959 while (invmoves
!= NULL
) {
960 move
= invmoves
->next
;
961 cuddDeallocMove(table
, invmoves
);
964 return((Move
*) CUDD_OUT_OF_MEM
);
966 } /* end of cuddZddUndoMoves */