1 /**CFile***********************************************************************
3 FileName [cuddZddSymm.c]
7 Synopsis [Functions for symmetry-based ZDD variable reordering.]
9 Description [External procedures included in this module:
11 <li> Cudd_zddSymmProfile()
13 Internal procedures included in this module:
15 <li> cuddZddSymmCheck()
16 <li> cuddZddSymmSifting()
17 <li> cuddZddSymmSiftingConv()
19 Static procedures included in this module:
21 <li> cuddZddUniqueCompare()
22 <li> cuddZddSymmSiftingAux()
23 <li> cuddZddSymmSiftingConvAux()
24 <li> cuddZddSymmSifting_up()
25 <li> cuddZddSymmSifting_down()
27 <li> cuddZddSymmSiftingBackward()
28 <li> zdd_group_move_backward()
32 SeeAlso [cuddSymmetry.c]
34 Author [Hyong-Kyoon Shin, In-Ho Moon]
36 Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado
40 Redistribution and use in source and binary forms, with or without
41 modification, are permitted provided that the following conditions
44 Redistributions of source code must retain the above copyright
45 notice, this list of conditions and the following disclaimer.
47 Redistributions in binary form must reproduce the above copyright
48 notice, this list of conditions and the following disclaimer in the
49 documentation and/or other materials provided with the distribution.
51 Neither the name of the University of Colorado nor the names of its
52 contributors may be used to endorse or promote products derived from
53 this software without specific prior written permission.
55 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
56 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
57 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
58 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
59 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
60 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
61 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
62 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
63 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
65 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
66 POSSIBILITY OF SUCH DAMAGE.]
68 ******************************************************************************/
73 /*---------------------------------------------------------------------------*/
74 /* Constant declarations */
75 /*---------------------------------------------------------------------------*/
77 #define ZDD_MV_OOM (Move *)1
79 /*---------------------------------------------------------------------------*/
80 /* Stucture declarations */
81 /*---------------------------------------------------------------------------*/
83 /*---------------------------------------------------------------------------*/
84 /* Type declarations */
85 /*---------------------------------------------------------------------------*/
87 /*---------------------------------------------------------------------------*/
88 /* Variable declarations */
89 /*---------------------------------------------------------------------------*/
92 static char rcsid
[] DD_UNUSED
= "$Id: cuddZddSymm.c,v 1.29 2004/08/13 18:04:54 fabio Exp $";
95 extern int *zdd_entry
;
97 extern int zddTotalNumberSwapping
;
101 /*---------------------------------------------------------------------------*/
102 /* Macro declarations */
103 /*---------------------------------------------------------------------------*/
106 /**AutomaticStart*************************************************************/
108 /*---------------------------------------------------------------------------*/
109 /* Static function prototypes */
110 /*---------------------------------------------------------------------------*/
112 static int cuddZddSymmSiftingAux (DdManager
*table
, int x
, int x_low
, int x_high
);
113 static int cuddZddSymmSiftingConvAux (DdManager
*table
, int x
, int x_low
, int x_high
);
114 static Move
* cuddZddSymmSifting_up (DdManager
*table
, int x
, int x_low
, int initial_size
);
115 static Move
* cuddZddSymmSifting_down (DdManager
*table
, int x
, int x_high
, int initial_size
);
116 static int cuddZddSymmSiftingBackward (DdManager
*table
, Move
*moves
, int size
);
117 static int zdd_group_move (DdManager
*table
, int x
, int y
, Move
**moves
);
118 static int zdd_group_move_backward (DdManager
*table
, int x
, int y
);
119 static void cuddZddSymmSummary (DdManager
*table
, int lower
, int upper
, int *symvars
, int *symgroups
);
121 /**AutomaticEnd***************************************************************/
124 /*---------------------------------------------------------------------------*/
125 /* Definition of exported functions */
126 /*---------------------------------------------------------------------------*/
129 /**Function********************************************************************
131 Synopsis [Prints statistics on symmetric ZDD variables.]
139 ******************************************************************************/
148 int TotalSymmGroups
= 0;
150 for (i
= lower
; i
< upper
; i
++) {
151 if (table
->subtableZ
[i
].next
!= (unsigned) i
) {
153 (void) fprintf(table
->out
,"Group:");
155 (void) fprintf(table
->out
," %d", table
->invpermZ
[x
]);
158 x
= table
->subtableZ
[x
].next
;
162 assert(table
->subtableZ
[gbot
].next
== (unsigned) i
);
165 (void) fprintf(table
->out
,"\n");
168 (void) fprintf(table
->out
,"Total Symmetric = %d\n", TotalSymm
);
169 (void) fprintf(table
->out
,"Total Groups = %d\n", TotalSymmGroups
);
171 } /* end of Cudd_zddSymmProfile */
174 /*---------------------------------------------------------------------------*/
175 /* Definition of internal functions */
176 /*---------------------------------------------------------------------------*/
179 /**Function********************************************************************
181 Synopsis [Checks for symmetry of x and y.]
183 Description [Checks for symmetry of x and y. Ignores projection
184 functions, unless they are isolated. Returns 1 in case of
185 symmetry; 0 otherwise.]
191 ******************************************************************************/
199 DdNode
*f
, *f0
, *f1
, *f01
, *f00
, *f11
, *f10
;
204 int TotalRefCount
= 0;
209 yindex
= table
->invpermZ
[y
];
210 for (i
= table
->subtableZ
[x
].slots
- 1; i
>= 0; i
--) {
211 f
= table
->subtableZ
[x
].nodelist
[i
];
213 /* Find f1, f0, f11, f10, f01, f00 */
216 if ((int) f1
->index
== yindex
) {
222 if ((int) f0
->index
!= yindex
) {
223 return(0); /* f bypasses layer y */
228 if ((int) f0
->index
== yindex
) {
241 if ((xsymmy
== 0) && (xsymmyp
== 0))
245 } /* for each element of the collision list */
246 } /* for each slot of the subtable */
248 /* Calculate the total reference counts of y
249 ** whose else arc is not empty.
251 for (i
= table
->subtableZ
[y
].slots
- 1; i
>= 0; i
--) {
252 f
= table
->subtableZ
[y
].nodelist
[i
];
253 while (f
!= NIL(DdNode
)) {
254 if (cuddE(f
) != empty
)
255 TotalRefCount
+= f
->ref
;
260 symm_found
= (arccount
== TotalRefCount
);
261 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
263 int xindex
= table
->invpermZ
[x
];
264 (void) fprintf(table
->out
,
265 "Found symmetry! x =%d\ty = %d\tPos(%d,%d)\n",
272 } /* end cuddZddSymmCheck */
275 /**Function********************************************************************
277 Synopsis [Symmetric sifting algorithm for ZDDs.]
279 Description [Symmetric sifting algorithm.
280 Assumes that no dead nodes are present.
282 <li> Order all the variables according to the number of entries in
283 each unique subtable.
284 <li> Sift the variable up and down, remembering each time the total
285 size of the ZDD heap and grouping variables that are symmetric.
286 <li> Select the best permutation.
287 <li> Repeat 3 and 4 for all variables.
289 Returns 1 plus the number of symmetric variables if successful; 0
294 SeeAlso [cuddZddSymmSiftingConv]
296 ******************************************************************************/
315 nvars
= table
->sizeZ
;
317 /* Find order in which to sift variables. */
319 zdd_entry
= ALLOC(int, nvars
);
320 if (zdd_entry
== NULL
) {
321 table
->errorCode
= CUDD_MEMORY_OUT
;
322 goto cuddZddSymmSiftingOutOfMem
;
324 var
= ALLOC(int, nvars
);
326 table
->errorCode
= CUDD_MEMORY_OUT
;
327 goto cuddZddSymmSiftingOutOfMem
;
330 for (i
= 0; i
< nvars
; i
++) {
332 zdd_entry
[i
] = table
->subtableZ
[x
].keys
;
336 qsort((void *)var
, nvars
, sizeof(int), (DD_QSFP
)cuddZddUniqueCompare
);
338 /* Initialize the symmetry of each subtable to itself. */
339 for (i
= lower
; i
<= upper
; i
++)
340 table
->subtableZ
[i
].next
= i
;
342 iteration
= ddMin(table
->siftMaxVar
, nvars
);
343 for (i
= 0; i
< iteration
; i
++) {
344 if (zddTotalNumberSwapping
>= table
->siftMaxSwap
)
346 x
= table
->permZ
[var
[i
]];
348 previousSize
= table
->keysZ
;
350 if (x
< lower
|| x
> upper
) continue;
351 if (table
->subtableZ
[x
].next
== (unsigned) x
) {
352 result
= cuddZddSymmSiftingAux(table
, x
, lower
, upper
);
354 goto cuddZddSymmSiftingOutOfMem
;
356 if (table
->keysZ
< (unsigned) previousSize
) {
357 (void) fprintf(table
->out
,"-");
358 } else if (table
->keysZ
> (unsigned) previousSize
) {
359 (void) fprintf(table
->out
,"+");
361 (void) fprintf(table
->out
,"\nSize increased from %d to %d while sifting variable %d\n", previousSize
, table
->keysZ
, var
[i
]);
364 (void) fprintf(table
->out
,"=");
374 cuddZddSymmSummary(table
, lower
, upper
, &symvars
, &symgroups
);
377 (void) fprintf(table
->out
,"\n#:S_SIFTING %8d: symmetric variables\n",symvars
);
378 (void) fprintf(table
->out
,"#:G_SIFTING %8d: symmetric groups\n",symgroups
);
383 cuddZddSymmSiftingOutOfMem
:
385 if (zdd_entry
!= NULL
)
392 } /* end of cuddZddSymmSifting */
395 /**Function********************************************************************
397 Synopsis [Symmetric sifting to convergence algorithm for ZDDs.]
399 Description [Symmetric sifting to convergence algorithm for ZDDs.
400 Assumes that no dead nodes are present.
402 <li> Order all the variables according to the number of entries in
403 each unique subtable.
404 <li> Sift the variable up and down, remembering each time the total
405 size of the ZDD heap and grouping variables that are symmetric.
406 <li> Select the best permutation.
407 <li> Repeat 3 and 4 for all variables.
408 <li> Repeat 1-4 until no further improvement.
410 Returns 1 plus the number of symmetric variables if successful; 0
415 SeeAlso [cuddZddSymmSifting]
417 ******************************************************************************/
419 cuddZddSymmSiftingConv(
438 initialSize
= table
->keysZ
;
440 nvars
= table
->sizeZ
;
442 /* Find order in which to sift variables. */
444 zdd_entry
= ALLOC(int, nvars
);
445 if (zdd_entry
== NULL
) {
446 table
->errorCode
= CUDD_MEMORY_OUT
;
447 goto cuddZddSymmSiftingConvOutOfMem
;
449 var
= ALLOC(int, nvars
);
451 table
->errorCode
= CUDD_MEMORY_OUT
;
452 goto cuddZddSymmSiftingConvOutOfMem
;
455 for (i
= 0; i
< nvars
; i
++) {
457 zdd_entry
[i
] = table
->subtableZ
[x
].keys
;
461 qsort((void *)var
, nvars
, sizeof(int), (DD_QSFP
)cuddZddUniqueCompare
);
463 /* Initialize the symmetry of each subtable to itself
464 ** for first pass of converging symmetric sifting.
466 for (i
= lower
; i
<= upper
; i
++)
467 table
->subtableZ
[i
].next
= i
;
469 iteration
= ddMin(table
->siftMaxVar
, table
->sizeZ
);
470 for (i
= 0; i
< iteration
; i
++) {
471 if (zddTotalNumberSwapping
>= table
->siftMaxSwap
)
473 x
= table
->permZ
[var
[i
]];
474 if (x
< lower
|| x
> upper
) continue;
475 /* Only sift if not in symmetry group already. */
476 if (table
->subtableZ
[x
].next
== (unsigned) x
) {
478 previousSize
= table
->keysZ
;
480 result
= cuddZddSymmSiftingAux(table
, x
, lower
, upper
);
482 goto cuddZddSymmSiftingConvOutOfMem
;
484 if (table
->keysZ
< (unsigned) previousSize
) {
485 (void) fprintf(table
->out
,"-");
486 } else if (table
->keysZ
> (unsigned) previousSize
) {
487 (void) fprintf(table
->out
,"+");
489 (void) fprintf(table
->out
,"\nSize increased from %d to %d while sifting variable %d\n", previousSize
, table
->keysZ
, var
[i
]);
492 (void) fprintf(table
->out
,"=");
499 /* Sifting now until convergence. */
500 while ((unsigned) initialSize
> table
->keysZ
) {
501 initialSize
= table
->keysZ
;
503 (void) fprintf(table
->out
,"\n");
505 /* Here we consider only one representative for each symmetry class. */
506 for (x
= lower
, classes
= 0; x
<= upper
; x
++, classes
++) {
507 while ((unsigned) x
< table
->subtableZ
[x
].next
)
508 x
= table
->subtableZ
[x
].next
;
509 /* Here x is the largest index in a group.
510 ** Groups consists of adjacent variables.
511 ** Hence, the next increment of x will move it to a new group.
513 i
= table
->invpermZ
[x
];
514 zdd_entry
[i
] = table
->subtableZ
[x
].keys
;
518 qsort((void *)var
,classes
,sizeof(int),(DD_QSFP
)cuddZddUniqueCompare
);
521 iteration
= ddMin(table
->siftMaxVar
, nvars
);
522 for (i
= 0; i
< iteration
; i
++) {
523 if (zddTotalNumberSwapping
>= table
->siftMaxSwap
)
525 x
= table
->permZ
[var
[i
]];
526 if ((unsigned) x
>= table
->subtableZ
[x
].next
) {
528 previousSize
= table
->keysZ
;
530 result
= cuddZddSymmSiftingConvAux(table
, x
, lower
, upper
);
532 goto cuddZddSymmSiftingConvOutOfMem
;
534 if (table
->keysZ
< (unsigned) previousSize
) {
535 (void) fprintf(table
->out
,"-");
536 } else if (table
->keysZ
> (unsigned) previousSize
) {
537 (void) fprintf(table
->out
,"+");
539 (void) fprintf(table
->out
,"\nSize increased from %d to %d while sifting variable %d\n", previousSize
, table
->keysZ
, var
[i
]);
542 (void) fprintf(table
->out
,"=");
550 cuddZddSymmSummary(table
, lower
, upper
, &symvars
, &symgroups
);
553 (void) fprintf(table
->out
,"\n#:S_SIFTING %8d: symmetric variables\n",
555 (void) fprintf(table
->out
,"#:G_SIFTING %8d: symmetric groups\n",
564 cuddZddSymmSiftingConvOutOfMem
:
566 if (zdd_entry
!= NULL
)
573 } /* end of cuddZddSymmSiftingConv */
576 /*---------------------------------------------------------------------------*/
577 /* Definition of static functions */
578 /*---------------------------------------------------------------------------*/
581 /**Function********************************************************************
583 Synopsis [Given x_low <= x <= x_high moves x up and down between the
586 Description [Given x_low <= x <= x_high moves x up and down between the
587 boundaries. Finds the best position and does the required changes.
588 Assumes that x is not part of a symmetry group. Returns 1 if
589 successful; 0 otherwise.]
595 ******************************************************************************/
597 cuddZddSymmSiftingAux(
604 Move
*move_up
; /* list of up move */
605 Move
*move_down
; /* list of down move */
609 int topbot
; /* index to either top or bottom of symmetry group */
610 int init_group_size
, final_group_size
;
612 initial_size
= table
->keysZ
;
617 /* Look for consecutive symmetries above x. */
618 for (i
= x
; i
> x_low
; i
--) {
619 if (!cuddZddSymmCheck(table
, i
- 1, i
))
621 /* find top of i-1's symmetry */
622 topbot
= table
->subtableZ
[i
- 1].next
;
623 table
->subtableZ
[i
- 1].next
= i
;
624 table
->subtableZ
[x
].next
= topbot
;
625 /* x is bottom of group so its symmetry is top of i-1's
627 i
= topbot
+ 1; /* add 1 for i--, new i is top of symm group */
629 /* Look for consecutive symmetries below x. */
630 for (i
= x
; i
< x_high
; i
++) {
631 if (!cuddZddSymmCheck(table
, i
, i
+ 1))
633 /* find bottom of i+1's symm group */
635 while ((unsigned) topbot
< table
->subtableZ
[topbot
].next
)
636 topbot
= table
->subtableZ
[topbot
].next
;
638 table
->subtableZ
[topbot
].next
= table
->subtableZ
[i
].next
;
639 table
->subtableZ
[i
].next
= i
+ 1;
640 i
= topbot
- 1; /* add 1 for i++,
641 new i is bottom of symm group */
644 /* Now x maybe in the middle of a symmetry group. */
645 if (x
== x_low
) { /* Sift down */
646 /* Find bottom of x's symm group */
647 while ((unsigned) x
< table
->subtableZ
[x
].next
)
648 x
= table
->subtableZ
[x
].next
;
650 i
= table
->subtableZ
[x
].next
;
651 init_group_size
= x
- i
+ 1;
653 move_down
= cuddZddSymmSifting_down(table
, x
, x_high
,
655 /* after that point x --> x_high, unless early term */
656 if (move_down
== ZDD_MV_OOM
)
657 goto cuddZddSymmSiftingAuxOutOfMem
;
659 if (move_down
== NULL
||
660 table
->subtableZ
[move_down
->y
].next
!= move_down
->y
) {
661 /* symmetry detected may have to make another complete
663 if (move_down
!= NULL
)
666 x
= table
->subtableZ
[x
].next
;
668 while ((unsigned) i
< table
->subtableZ
[i
].next
) {
669 i
= table
->subtableZ
[i
].next
;
671 final_group_size
= i
- x
+ 1;
673 if (init_group_size
== final_group_size
) {
674 /* No new symmetry groups detected,
675 return to best position */
676 result
= cuddZddSymmSiftingBackward(table
,
677 move_down
, initial_size
);
680 initial_size
= table
->keysZ
;
681 move_up
= cuddZddSymmSifting_up(table
, x
, x_low
,
683 result
= cuddZddSymmSiftingBackward(table
, move_up
,
688 result
= cuddZddSymmSiftingBackward(table
, move_down
,
690 /* move backward and stop at best position */
693 goto cuddZddSymmSiftingAuxOutOfMem
;
695 else if (x
== x_high
) { /* Sift up */
696 /* Find top of x's symm group */
697 while ((unsigned) x
< table
->subtableZ
[x
].next
)
698 x
= table
->subtableZ
[x
].next
;
699 x
= table
->subtableZ
[x
].next
;
702 while ((unsigned) i
< table
->subtableZ
[i
].next
) {
703 i
= table
->subtableZ
[i
].next
;
705 init_group_size
= i
- x
+ 1;
707 move_up
= cuddZddSymmSifting_up(table
, x
, x_low
, initial_size
);
708 /* after that point x --> x_low, unless early term */
709 if (move_up
== ZDD_MV_OOM
)
710 goto cuddZddSymmSiftingAuxOutOfMem
;
712 if (move_up
== NULL
||
713 table
->subtableZ
[move_up
->x
].next
!= move_up
->x
) {
714 /* symmetry detected may have to make another complete
719 while ((unsigned) x
< table
->subtableZ
[x
].next
)
720 x
= table
->subtableZ
[x
].next
;
722 i
= table
->subtableZ
[x
].next
;
723 final_group_size
= x
- i
+ 1;
725 if (init_group_size
== final_group_size
) {
726 /* No new symmetry groups detected,
727 return to best position */
728 result
= cuddZddSymmSiftingBackward(table
, move_up
,
732 initial_size
= table
->keysZ
;
733 move_down
= cuddZddSymmSifting_down(table
, x
, x_high
,
735 result
= cuddZddSymmSiftingBackward(table
, move_down
,
740 result
= cuddZddSymmSiftingBackward(table
, move_up
,
742 /* move backward and stop at best position */
745 goto cuddZddSymmSiftingAuxOutOfMem
;
747 else if ((x
- x_low
) > (x_high
- x
)) { /* must go down first:
749 /* Find bottom of x's symm group */
750 while ((unsigned) x
< table
->subtableZ
[x
].next
)
751 x
= table
->subtableZ
[x
].next
;
753 move_down
= cuddZddSymmSifting_down(table
, x
, x_high
,
755 /* after that point x --> x_high, unless early term */
756 if (move_down
== ZDD_MV_OOM
)
757 goto cuddZddSymmSiftingAuxOutOfMem
;
759 if (move_down
!= NULL
) {
763 x
= table
->subtableZ
[x
].next
;
766 while ((unsigned) i
< table
->subtableZ
[i
].next
) {
767 i
= table
->subtableZ
[i
].next
;
769 init_group_size
= i
- x
+ 1;
771 move_up
= cuddZddSymmSifting_up(table
, x
, x_low
, initial_size
);
772 if (move_up
== ZDD_MV_OOM
)
773 goto cuddZddSymmSiftingAuxOutOfMem
;
775 if (move_up
== NULL
||
776 table
->subtableZ
[move_up
->x
].next
!= move_up
->x
) {
777 /* symmetry detected may have to make another complete
779 if (move_up
!= NULL
) {
783 while ((unsigned) x
< table
->subtableZ
[x
].next
)
784 x
= table
->subtableZ
[x
].next
;
786 i
= table
->subtableZ
[x
].next
;
787 final_group_size
= x
- i
+ 1;
789 if (init_group_size
== final_group_size
) {
790 /* No new symmetry groups detected,
791 return to best position */
792 result
= cuddZddSymmSiftingBackward(table
, move_up
,
796 while (move_down
!= NULL
) {
797 move
= move_down
->next
;
798 cuddDeallocMove(table
, move_down
);
801 initial_size
= table
->keysZ
;
802 move_down
= cuddZddSymmSifting_down(table
, x
, x_high
,
804 result
= cuddZddSymmSiftingBackward(table
, move_down
,
809 result
= cuddZddSymmSiftingBackward(table
, move_up
,
811 /* move backward and stop at best position */
814 goto cuddZddSymmSiftingAuxOutOfMem
;
816 else { /* moving up first:shorter */
817 /* Find top of x's symmetry group */
818 while ((unsigned) x
< table
->subtableZ
[x
].next
)
819 x
= table
->subtableZ
[x
].next
;
820 x
= table
->subtableZ
[x
].next
;
822 move_up
= cuddZddSymmSifting_up(table
, x
, x_low
, initial_size
);
823 /* after that point x --> x_high, unless early term */
824 if (move_up
== ZDD_MV_OOM
)
825 goto cuddZddSymmSiftingAuxOutOfMem
;
827 if (move_up
!= NULL
) {
831 while ((unsigned) x
< table
->subtableZ
[x
].next
)
832 x
= table
->subtableZ
[x
].next
;
834 i
= table
->subtableZ
[x
].next
;
835 init_group_size
= x
- i
+ 1;
837 move_down
= cuddZddSymmSifting_down(table
, x
, x_high
,
839 if (move_down
== ZDD_MV_OOM
)
840 goto cuddZddSymmSiftingAuxOutOfMem
;
842 if (move_down
== NULL
||
843 table
->subtableZ
[move_down
->y
].next
!= move_down
->y
) {
844 /* symmetry detected may have to make another complete
846 if (move_down
!= NULL
) {
850 x
= table
->subtableZ
[x
].next
;
853 while ((unsigned) i
< table
->subtableZ
[i
].next
) {
854 i
= table
->subtableZ
[i
].next
;
856 final_group_size
= i
- x
+ 1;
858 if (init_group_size
== final_group_size
) {
859 /* No new symmetries detected,
860 go back to best position */
861 result
= cuddZddSymmSiftingBackward(table
, move_down
,
865 while (move_up
!= NULL
) {
866 move
= move_up
->next
;
867 cuddDeallocMove(table
, move_up
);
870 initial_size
= table
->keysZ
;
871 move_up
= cuddZddSymmSifting_up(table
, x
, x_low
,
873 result
= cuddZddSymmSiftingBackward(table
, move_up
,
878 result
= cuddZddSymmSiftingBackward(table
, move_down
,
880 /* move backward and stop at best position */
883 goto cuddZddSymmSiftingAuxOutOfMem
;
886 while (move_down
!= NULL
) {
887 move
= move_down
->next
;
888 cuddDeallocMove(table
, move_down
);
891 while (move_up
!= NULL
) {
892 move
= move_up
->next
;
893 cuddDeallocMove(table
, move_up
);
899 cuddZddSymmSiftingAuxOutOfMem
:
900 if (move_down
!= ZDD_MV_OOM
) {
901 while (move_down
!= NULL
) {
902 move
= move_down
->next
;
903 cuddDeallocMove(table
, move_down
);
907 if (move_up
!= ZDD_MV_OOM
) {
908 while (move_up
!= NULL
) {
909 move
= move_up
->next
;
910 cuddDeallocMove(table
, move_up
);
917 } /* end of cuddZddSymmSiftingAux */
920 /**Function********************************************************************
922 Synopsis [Given x_low <= x <= x_high moves x up and down between the
925 Description [Given x_low <= x <= x_high moves x up and down between the
926 boundaries. Finds the best position and does the required changes.
927 Assumes that x is either an isolated variable, or it is the bottom of
928 a symmetry group. All symmetries may not have been found, because of
929 exceeded growth limit. Returns 1 if successful; 0 otherwise.]
935 ******************************************************************************/
937 cuddZddSymmSiftingConvAux(
944 Move
*move_up
; /* list of up move */
945 Move
*move_down
; /* list of down move */
949 int init_group_size
, final_group_size
;
951 initial_size
= table
->keysZ
;
956 if (x
== x_low
) { /* Sift down */
957 i
= table
->subtableZ
[x
].next
;
958 init_group_size
= x
- i
+ 1;
960 move_down
= cuddZddSymmSifting_down(table
, x
, x_high
,
962 /* after that point x --> x_high, unless early term */
963 if (move_down
== ZDD_MV_OOM
)
964 goto cuddZddSymmSiftingConvAuxOutOfMem
;
966 if (move_down
== NULL
||
967 table
->subtableZ
[move_down
->y
].next
!= move_down
->y
) {
968 /* symmetry detected may have to make another complete
970 if (move_down
!= NULL
)
973 while ((unsigned) x
< table
->subtableZ
[x
].next
)
974 x
= table
->subtableZ
[x
].next
;
975 x
= table
->subtableZ
[x
].next
;
978 while ((unsigned) i
< table
->subtableZ
[i
].next
) {
979 i
= table
->subtableZ
[i
].next
;
981 final_group_size
= i
- x
+ 1;
983 if (init_group_size
== final_group_size
) {
984 /* No new symmetries detected,
985 go back to best position */
986 result
= cuddZddSymmSiftingBackward(table
, move_down
,
990 initial_size
= table
->keysZ
;
991 move_up
= cuddZddSymmSifting_up(table
, x
, x_low
,
993 result
= cuddZddSymmSiftingBackward(table
, move_up
,
998 result
= cuddZddSymmSiftingBackward(table
, move_down
,
1000 /* move backward and stop at best position */
1003 goto cuddZddSymmSiftingConvAuxOutOfMem
;
1005 else if (x
== x_high
) { /* Sift up */
1006 /* Find top of x's symm group */
1007 while ((unsigned) x
< table
->subtableZ
[x
].next
)
1008 x
= table
->subtableZ
[x
].next
;
1009 x
= table
->subtableZ
[x
].next
;
1012 while ((unsigned) i
< table
->subtableZ
[i
].next
) {
1013 i
= table
->subtableZ
[i
].next
;
1015 init_group_size
= i
- x
+ 1;
1017 move_up
= cuddZddSymmSifting_up(table
, x
, x_low
, initial_size
);
1018 /* after that point x --> x_low, unless early term */
1019 if (move_up
== ZDD_MV_OOM
)
1020 goto cuddZddSymmSiftingConvAuxOutOfMem
;
1022 if (move_up
== NULL
||
1023 table
->subtableZ
[move_up
->x
].next
!= move_up
->x
) {
1024 /* symmetry detected may have to make another complete
1026 if (move_up
!= NULL
)
1029 while ((unsigned) x
< table
->subtableZ
[x
].next
)
1030 x
= table
->subtableZ
[x
].next
;
1032 i
= table
->subtableZ
[x
].next
;
1033 final_group_size
= x
- i
+ 1;
1035 if (init_group_size
== final_group_size
) {
1036 /* No new symmetry groups detected,
1037 return to best position */
1038 result
= cuddZddSymmSiftingBackward(table
, move_up
,
1042 initial_size
= table
->keysZ
;
1043 move_down
= cuddZddSymmSifting_down(table
, x
, x_high
,
1045 result
= cuddZddSymmSiftingBackward(table
, move_down
,
1050 result
= cuddZddSymmSiftingBackward(table
, move_up
,
1052 /* move backward and stop at best position */
1055 goto cuddZddSymmSiftingConvAuxOutOfMem
;
1057 else if ((x
- x_low
) > (x_high
- x
)) { /* must go down first:
1059 move_down
= cuddZddSymmSifting_down(table
, x
, x_high
,
1061 /* after that point x --> x_high */
1062 if (move_down
== ZDD_MV_OOM
)
1063 goto cuddZddSymmSiftingConvAuxOutOfMem
;
1065 if (move_down
!= NULL
) {
1069 while ((unsigned) x
< table
->subtableZ
[x
].next
)
1070 x
= table
->subtableZ
[x
].next
;
1071 x
= table
->subtableZ
[x
].next
;
1074 while ((unsigned) i
< table
->subtableZ
[i
].next
) {
1075 i
= table
->subtableZ
[i
].next
;
1077 init_group_size
= i
- x
+ 1;
1079 move_up
= cuddZddSymmSifting_up(table
, x
, x_low
, initial_size
);
1080 if (move_up
== ZDD_MV_OOM
)
1081 goto cuddZddSymmSiftingConvAuxOutOfMem
;
1083 if (move_up
== NULL
||
1084 table
->subtableZ
[move_up
->x
].next
!= move_up
->x
) {
1085 /* symmetry detected may have to make another complete
1087 if (move_up
!= NULL
) {
1091 while ((unsigned) x
< table
->subtableZ
[x
].next
)
1092 x
= table
->subtableZ
[x
].next
;
1094 i
= table
->subtableZ
[x
].next
;
1095 final_group_size
= x
- i
+ 1;
1097 if (init_group_size
== final_group_size
) {
1098 /* No new symmetry groups detected,
1099 return to best position */
1100 result
= cuddZddSymmSiftingBackward(table
, move_up
,
1104 while (move_down
!= NULL
) {
1105 move
= move_down
->next
;
1106 cuddDeallocMove(table
, move_down
);
1109 initial_size
= table
->keysZ
;
1110 move_down
= cuddZddSymmSifting_down(table
, x
, x_high
,
1112 result
= cuddZddSymmSiftingBackward(table
, move_down
,
1117 result
= cuddZddSymmSiftingBackward(table
, move_up
,
1119 /* move backward and stop at best position */
1122 goto cuddZddSymmSiftingConvAuxOutOfMem
;
1124 else { /* moving up first:shorter */
1125 /* Find top of x's symmetry group */
1126 x
= table
->subtableZ
[x
].next
;
1128 move_up
= cuddZddSymmSifting_up(table
, x
, x_low
, initial_size
);
1129 /* after that point x --> x_high, unless early term */
1130 if (move_up
== ZDD_MV_OOM
)
1131 goto cuddZddSymmSiftingConvAuxOutOfMem
;
1133 if (move_up
!= NULL
) {
1137 while ((unsigned) x
< table
->subtableZ
[x
].next
)
1138 x
= table
->subtableZ
[x
].next
;
1140 i
= table
->subtableZ
[x
].next
;
1141 init_group_size
= x
- i
+ 1;
1143 move_down
= cuddZddSymmSifting_down(table
, x
, x_high
,
1145 if (move_down
== ZDD_MV_OOM
)
1146 goto cuddZddSymmSiftingConvAuxOutOfMem
;
1148 if (move_down
== NULL
||
1149 table
->subtableZ
[move_down
->y
].next
!= move_down
->y
) {
1150 /* symmetry detected may have to make another complete
1152 if (move_down
!= NULL
) {
1156 while ((unsigned) x
< table
->subtableZ
[x
].next
)
1157 x
= table
->subtableZ
[x
].next
;
1158 x
= table
->subtableZ
[x
].next
;
1161 while ((unsigned) i
< table
->subtableZ
[i
].next
) {
1162 i
= table
->subtableZ
[i
].next
;
1164 final_group_size
= i
- x
+ 1;
1166 if (init_group_size
== final_group_size
) {
1167 /* No new symmetries detected,
1168 go back to best position */
1169 result
= cuddZddSymmSiftingBackward(table
, move_down
,
1173 while (move_up
!= NULL
) {
1174 move
= move_up
->next
;
1175 cuddDeallocMove(table
, move_up
);
1178 initial_size
= table
->keysZ
;
1179 move_up
= cuddZddSymmSifting_up(table
, x
, x_low
,
1181 result
= cuddZddSymmSiftingBackward(table
, move_up
,
1186 result
= cuddZddSymmSiftingBackward(table
, move_down
,
1188 /* move backward and stop at best position */
1191 goto cuddZddSymmSiftingConvAuxOutOfMem
;
1194 while (move_down
!= NULL
) {
1195 move
= move_down
->next
;
1196 cuddDeallocMove(table
, move_down
);
1199 while (move_up
!= NULL
) {
1200 move
= move_up
->next
;
1201 cuddDeallocMove(table
, move_up
);
1207 cuddZddSymmSiftingConvAuxOutOfMem
:
1208 if (move_down
!= ZDD_MV_OOM
) {
1209 while (move_down
!= NULL
) {
1210 move
= move_down
->next
;
1211 cuddDeallocMove(table
, move_down
);
1215 if (move_up
!= ZDD_MV_OOM
) {
1216 while (move_up
!= NULL
) {
1217 move
= move_up
->next
;
1218 cuddDeallocMove(table
, move_up
);
1225 } /* end of cuddZddSymmSiftingConvAux */
1228 /**Function********************************************************************
1230 Synopsis [Moves x up until either it reaches the bound (x_low) or
1231 the size of the ZDD heap increases too much.]
1233 Description [Moves x up until either it reaches the bound (x_low) or
1234 the size of the ZDD heap increases too much. Assumes that x is the top
1235 of a symmetry group. Checks x for symmetry to the adjacent
1236 variables. If symmetry is found, the symmetry group of x is merged
1237 with the symmetry group of the other variable. Returns the set of
1238 moves in case of success; ZDD_MV_OOM if memory is full.]
1244 ******************************************************************************/
1246 cuddZddSymmSifting_up(
1256 int limit_size
= initial_size
;
1260 y
= cuddZddNextLow(table
, x
);
1261 while (y
>= x_low
) {
1262 gytop
= table
->subtableZ
[y
].next
;
1263 if (cuddZddSymmCheck(table
, y
, x
)) {
1264 /* Symmetry found, attach symm groups */
1265 table
->subtableZ
[y
].next
= x
;
1266 i
= table
->subtableZ
[x
].next
;
1267 while (table
->subtableZ
[i
].next
!= (unsigned) x
)
1268 i
= table
->subtableZ
[i
].next
;
1269 table
->subtableZ
[i
].next
= gytop
;
1271 else if ((table
->subtableZ
[x
].next
== (unsigned) x
) &&
1272 (table
->subtableZ
[y
].next
== (unsigned) y
)) {
1273 /* x and y have self symmetry */
1274 size
= cuddZddSwapInPlace(table
, y
, x
);
1276 goto cuddZddSymmSifting_upOutOfMem
;
1277 move
= (Move
*)cuddDynamicAllocNode(table
);
1279 goto cuddZddSymmSifting_upOutOfMem
;
1286 (double)limit_size
* table
->maxGrowth
)
1288 if (size
< limit_size
)
1291 else { /* Group move */
1292 size
= zdd_group_move(table
, y
, x
, &moves
);
1294 (double)limit_size
* table
->maxGrowth
)
1296 if (size
< limit_size
)
1300 y
= cuddZddNextLow(table
, x
);
1305 cuddZddSymmSifting_upOutOfMem
:
1306 while (moves
!= NULL
) {
1308 cuddDeallocMove(table
, moves
);
1313 } /* end of cuddZddSymmSifting_up */
1316 /**Function********************************************************************
1318 Synopsis [Moves x down until either it reaches the bound (x_high) or
1319 the size of the ZDD heap increases too much.]
1321 Description [Moves x down until either it reaches the bound (x_high)
1322 or the size of the ZDD heap increases too much. Assumes that x is the
1323 bottom of a symmetry group. Checks x for symmetry to the adjacent
1324 variables. If symmetry is found, the symmetry group of x is merged
1325 with the symmetry group of the other variable. Returns the set of
1326 moves in case of success; ZDD_MV_OOM if memory is full.]
1332 ******************************************************************************/
1334 cuddZddSymmSifting_down(
1344 int limit_size
= initial_size
;
1345 int i
, gxtop
, gybot
;
1348 y
= cuddZddNextHigh(table
, x
);
1349 while (y
<= x_high
) {
1350 gybot
= table
->subtableZ
[y
].next
;
1351 while (table
->subtableZ
[gybot
].next
!= (unsigned) y
)
1352 gybot
= table
->subtableZ
[gybot
].next
;
1353 if (cuddZddSymmCheck(table
, x
, y
)) {
1354 /* Symmetry found, attach symm groups */
1355 gxtop
= table
->subtableZ
[x
].next
;
1356 table
->subtableZ
[x
].next
= y
;
1357 i
= table
->subtableZ
[y
].next
;
1358 while (table
->subtableZ
[i
].next
!= (unsigned) y
)
1359 i
= table
->subtableZ
[i
].next
;
1360 table
->subtableZ
[i
].next
= gxtop
;
1362 else if ((table
->subtableZ
[x
].next
== (unsigned) x
) &&
1363 (table
->subtableZ
[y
].next
== (unsigned) y
)) {
1364 /* x and y have self symmetry */
1365 size
= cuddZddSwapInPlace(table
, x
, y
);
1367 goto cuddZddSymmSifting_downOutOfMem
;
1368 move
= (Move
*)cuddDynamicAllocNode(table
);
1370 goto cuddZddSymmSifting_downOutOfMem
;
1377 (double)limit_size
* table
->maxGrowth
)
1379 if (size
< limit_size
)
1382 y
= cuddZddNextHigh(table
, x
);
1384 else { /* Group move */
1385 size
= zdd_group_move(table
, x
, y
, &moves
);
1387 (double)limit_size
* table
->maxGrowth
)
1389 if (size
< limit_size
)
1393 y
= cuddZddNextHigh(table
, x
);
1398 cuddZddSymmSifting_downOutOfMem
:
1399 while (moves
!= NULL
) {
1401 cuddDeallocMove(table
, moves
);
1406 } /* end of cuddZddSymmSifting_down */
1409 /**Function********************************************************************
1411 Synopsis [Given a set of moves, returns the ZDD heap to the position
1412 giving the minimum size.]
1414 Description [Given a set of moves, returns the ZDD heap to the
1415 position giving the minimum size. In case of ties, returns to the
1416 closest position giving the minimum size. Returns 1 in case of
1417 success; 0 otherwise.]
1423 ******************************************************************************/
1425 cuddZddSymmSiftingBackward(
1436 for (move
= moves
, i
= 0; move
!= NULL
; move
= move
->next
, i
++) {
1437 if (move
->size
< size
) {
1443 for (move
= moves
, i
= 0; move
!= NULL
; move
= move
->next
, i
++) {
1444 if (i
== i_best
) break;
1445 if ((table
->subtableZ
[move
->x
].next
== move
->x
) &&
1446 (table
->subtableZ
[move
->y
].next
== move
->y
)) {
1447 res
= cuddZddSwapInPlace(table
, move
->x
, move
->y
);
1448 if (!res
) return(0);
1450 else { /* Group move necessary */
1451 res
= zdd_group_move_backward(table
, move
->x
, move
->y
);
1453 if (i_best
== -1 && res
== size
)
1459 } /* end of cuddZddSymmSiftingBackward */
1462 /**Function********************************************************************
1464 Synopsis [Swaps two groups.]
1466 Description [Swaps two groups. x is assumed to be the bottom variable
1467 of the first group. y is assumed to be the top variable of the second
1468 group. Updates the list of moves. Returns the number of keys in the
1469 table if successful; 0 otherwise.]
1475 ******************************************************************************/
1485 int i
, temp
, gxtop
, gxbot
, gybot
, yprev
;
1489 assert(x
< y
); /* we assume that x < y */
1491 /* Find top and bottom for the two groups. */
1492 gxtop
= table
->subtableZ
[x
].next
;
1494 gybot
= table
->subtableZ
[y
].next
;
1495 while (table
->subtableZ
[gybot
].next
!= (unsigned) y
)
1496 gybot
= table
->subtableZ
[gybot
].next
;
1501 /* Set correct symmetries. */
1502 temp
= table
->subtableZ
[x
].next
;
1507 if (table
->subtableZ
[i
].next
== (unsigned) x
) {
1508 table
->subtableZ
[i
].next
= y
;
1511 i
= table
->subtableZ
[i
].next
;
1514 if (table
->subtableZ
[y
].next
!= (unsigned) y
) {
1515 table
->subtableZ
[x
].next
= table
->subtableZ
[y
].next
;
1517 table
->subtableZ
[x
].next
= x
;
1521 table
->subtableZ
[yprev
].next
= x
;
1525 table
->subtableZ
[y
].next
= temp
;
1527 size
= cuddZddSwapInPlace(table
, x
, y
);
1529 goto zdd_group_moveOutOfMem
;
1534 } /* while y > gxtop */
1536 /* Trying to find the next y. */
1537 if (table
->subtableZ
[y
].next
<= (unsigned) y
) {
1540 y
= table
->subtableZ
[y
].next
;
1547 } /* while x <= y, end of group movement */
1548 move
= (Move
*)cuddDynamicAllocNode(table
);
1550 goto zdd_group_moveOutOfMem
;
1553 move
->size
= table
->keysZ
;
1554 move
->next
= *moves
;
1557 return(table
->keysZ
);
1559 zdd_group_moveOutOfMem
:
1560 while (*moves
!= NULL
) {
1561 move
= (*moves
)->next
;
1562 cuddDeallocMove(table
, *moves
);
1567 } /* end of zdd_group_move */
1570 /**Function********************************************************************
1572 Synopsis [Undoes the swap of two groups.]
1574 Description [Undoes the swap of two groups. x is assumed to be the
1575 bottom variable of the first group. y is assumed to be the top
1576 variable of the second group. Returns 1 if successful; 0 otherwise.]
1582 ******************************************************************************/
1584 zdd_group_move_backward(
1590 int i
, temp
, gxtop
, gxbot
, gybot
, yprev
;
1593 assert(x
< y
); /* we assume that x < y */
1595 /* Find top and bottom of the two groups. */
1596 gxtop
= table
->subtableZ
[x
].next
;
1598 gybot
= table
->subtableZ
[y
].next
;
1599 while (table
->subtableZ
[gybot
].next
!= (unsigned) y
)
1600 gybot
= table
->subtableZ
[gybot
].next
;
1605 /* Set correct symmetries. */
1606 temp
= table
->subtableZ
[x
].next
;
1611 if (table
->subtableZ
[i
].next
== (unsigned) x
) {
1612 table
->subtableZ
[i
].next
= y
;
1615 i
= table
->subtableZ
[i
].next
;
1618 if (table
->subtableZ
[y
].next
!= (unsigned) y
) {
1619 table
->subtableZ
[x
].next
= table
->subtableZ
[y
].next
;
1621 table
->subtableZ
[x
].next
= x
;
1625 table
->subtableZ
[yprev
].next
= x
;
1629 table
->subtableZ
[y
].next
= temp
;
1631 size
= cuddZddSwapInPlace(table
, x
, y
);
1636 } /* while y > gxtop */
1638 /* Trying to find the next y. */
1639 if (table
->subtableZ
[y
].next
<= (unsigned) y
) {
1642 y
= table
->subtableZ
[y
].next
;
1649 } /* while x <= y, end of group movement backward */
1653 } /* end of zdd_group_move_backward */
1656 /**Function********************************************************************
1658 Synopsis [Counts numbers of symmetric variables and symmetry
1665 ******************************************************************************/
1676 int TotalSymmGroups
= 0;
1678 for (i
= lower
; i
<= upper
; i
++) {
1679 if (table
->subtableZ
[i
].next
!= (unsigned) i
) {
1685 x
= table
->subtableZ
[x
].next
;
1688 assert(table
->subtableZ
[gbot
].next
== (unsigned) i
);
1693 *symvars
= TotalSymm
;
1694 *symgroups
= TotalSymmGroups
;
1698 } /* end of cuddZddSymmSummary */