emergency commit
[cl-cudd.git] / distr / cudd / cuddZddSymm.c
blob1fba52f4e04b4c29231d71343e381b44e7659224
1 /**CFile***********************************************************************
3 FileName [cuddZddSymm.c]
5 PackageName [cudd]
7 Synopsis [Functions for symmetry-based ZDD variable reordering.]
9 Description [External procedures included in this module:
10 <ul>
11 <li> Cudd_zddSymmProfile()
12 </ul>
13 Internal procedures included in this module:
14 <ul>
15 <li> cuddZddSymmCheck()
16 <li> cuddZddSymmSifting()
17 <li> cuddZddSymmSiftingConv()
18 </ul>
19 Static procedures included in this module:
20 <ul>
21 <li> cuddZddUniqueCompare()
22 <li> cuddZddSymmSiftingAux()
23 <li> cuddZddSymmSiftingConvAux()
24 <li> cuddZddSymmSifting_up()
25 <li> cuddZddSymmSifting_down()
26 <li> zdd_group_move()
27 <li> cuddZddSymmSiftingBackward()
28 <li> zdd_group_move_backward()
29 </ul>
32 SeeAlso [cuddSymmetry.c]
34 Author [Hyong-Kyoon Shin, In-Ho Moon]
36 Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado
38 All rights reserved.
40 Redistribution and use in source and binary forms, with or without
41 modification, are permitted provided that the following conditions
42 are met:
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 ******************************************************************************/
70 #include "util.h"
71 #include "cuddInt.h"
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 /*---------------------------------------------------------------------------*/
91 #ifndef lint
92 static char rcsid[] DD_UNUSED = "$Id: cuddZddSymm.c,v 1.29 2004/08/13 18:04:54 fabio Exp $";
93 #endif
95 extern int *zdd_entry;
97 extern int zddTotalNumberSwapping;
99 static DdNode *empty;
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.]
133 Description []
135 SideEffects [None]
137 SeeAlso []
139 ******************************************************************************/
140 void
141 Cudd_zddSymmProfile(
142 DdManager * table,
143 int lower,
144 int upper)
146 int i, x, gbot;
147 int TotalSymm = 0;
148 int TotalSymmGroups = 0;
150 for (i = lower; i < upper; i++) {
151 if (table->subtableZ[i].next != (unsigned) i) {
152 x = i;
153 (void) fprintf(table->out,"Group:");
154 do {
155 (void) fprintf(table->out," %d", table->invpermZ[x]);
156 TotalSymm++;
157 gbot = x;
158 x = table->subtableZ[x].next;
159 } while (x != i);
160 TotalSymmGroups++;
161 #ifdef DD_DEBUG
162 assert(table->subtableZ[gbot].next == (unsigned) i);
163 #endif
164 i = gbot;
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.]
187 SideEffects [None]
189 SeeAlso []
191 ******************************************************************************/
193 cuddZddSymmCheck(
194 DdManager * table,
195 int x,
196 int y)
198 int i;
199 DdNode *f, *f0, *f1, *f01, *f00, *f11, *f10;
200 int yindex;
201 int xsymmy = 1;
202 int xsymmyp = 1;
203 int arccount = 0;
204 int TotalRefCount = 0;
205 int symm_found;
207 empty = table->zero;
209 yindex = table->invpermZ[y];
210 for (i = table->subtableZ[x].slots - 1; i >= 0; i--) {
211 f = table->subtableZ[x].nodelist[i];
212 while (f != NULL) {
213 /* Find f1, f0, f11, f10, f01, f00 */
214 f1 = cuddT(f);
215 f0 = cuddE(f);
216 if ((int) f1->index == yindex) {
217 f11 = cuddT(f1);
218 f10 = cuddE(f1);
219 if (f10 != empty)
220 arccount++;
221 } else {
222 if ((int) f0->index != yindex) {
223 return(0); /* f bypasses layer y */
225 f11 = empty;
226 f10 = f1;
228 if ((int) f0->index == yindex) {
229 f01 = cuddT(f0);
230 f00 = cuddE(f0);
231 if (f00 != empty)
232 arccount++;
233 } else {
234 f01 = empty;
235 f00 = f0;
237 if (f01 != f10)
238 xsymmy = 0;
239 if (f11 != f00)
240 xsymmyp = 0;
241 if ((xsymmy == 0) && (xsymmyp == 0))
242 return(0);
244 f = f->next;
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;
256 f = f->next;
260 symm_found = (arccount == TotalRefCount);
261 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
262 if (symm_found) {
263 int xindex = table->invpermZ[x];
264 (void) fprintf(table->out,
265 "Found symmetry! x =%d\ty = %d\tPos(%d,%d)\n",
266 xindex,yindex,x,y);
268 #endif
270 return(symm_found);
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.
281 <ol>
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.
288 </ol>
289 Returns 1 plus the number of symmetric variables if successful; 0
290 otherwise.]
292 SideEffects [None]
294 SeeAlso [cuddZddSymmSiftingConv]
296 ******************************************************************************/
298 cuddZddSymmSifting(
299 DdManager * table,
300 int lower,
301 int upper)
303 int i;
304 int *var;
305 int nvars;
306 int x;
307 int result;
308 int symvars;
309 int symgroups;
310 int iteration;
311 #ifdef DD_STATS
312 int previousSize;
313 #endif
315 nvars = table->sizeZ;
317 /* Find order in which to sift variables. */
318 var = NULL;
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);
325 if (var == NULL) {
326 table->errorCode = CUDD_MEMORY_OUT;
327 goto cuddZddSymmSiftingOutOfMem;
330 for (i = 0; i < nvars; i++) {
331 x = table->permZ[i];
332 zdd_entry[i] = table->subtableZ[x].keys;
333 var[i] = i;
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)
345 break;
346 x = table->permZ[var[i]];
347 #ifdef DD_STATS
348 previousSize = table->keysZ;
349 #endif
350 if (x < lower || x > upper) continue;
351 if (table->subtableZ[x].next == (unsigned) x) {
352 result = cuddZddSymmSiftingAux(table, x, lower, upper);
353 if (!result)
354 goto cuddZddSymmSiftingOutOfMem;
355 #ifdef DD_STATS
356 if (table->keysZ < (unsigned) previousSize) {
357 (void) fprintf(table->out,"-");
358 } else if (table->keysZ > (unsigned) previousSize) {
359 (void) fprintf(table->out,"+");
360 #ifdef DD_VERBOSE
361 (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]);
362 #endif
363 } else {
364 (void) fprintf(table->out,"=");
366 fflush(table->out);
367 #endif
371 FREE(var);
372 FREE(zdd_entry);
374 cuddZddSymmSummary(table, lower, upper, &symvars, &symgroups);
376 #ifdef DD_STATS
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);
379 #endif
381 return(1+symvars);
383 cuddZddSymmSiftingOutOfMem:
385 if (zdd_entry != NULL)
386 FREE(zdd_entry);
387 if (var != NULL)
388 FREE(var);
390 return(0);
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.
401 <ol>
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.
409 </ol>
410 Returns 1 plus the number of symmetric variables if successful; 0
411 otherwise.]
413 SideEffects [None]
415 SeeAlso [cuddZddSymmSifting]
417 ******************************************************************************/
419 cuddZddSymmSiftingConv(
420 DdManager * table,
421 int lower,
422 int upper)
424 int i;
425 int *var;
426 int nvars;
427 int initialSize;
428 int x;
429 int result;
430 int symvars;
431 int symgroups;
432 int classes;
433 int iteration;
434 #ifdef DD_STATS
435 int previousSize;
436 #endif
438 initialSize = table->keysZ;
440 nvars = table->sizeZ;
442 /* Find order in which to sift variables. */
443 var = NULL;
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);
450 if (var == NULL) {
451 table->errorCode = CUDD_MEMORY_OUT;
452 goto cuddZddSymmSiftingConvOutOfMem;
455 for (i = 0; i < nvars; i++) {
456 x = table->permZ[i];
457 zdd_entry[i] = table->subtableZ[x].keys;
458 var[i] = i;
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)
472 break;
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) {
477 #ifdef DD_STATS
478 previousSize = table->keysZ;
479 #endif
480 result = cuddZddSymmSiftingAux(table, x, lower, upper);
481 if (!result)
482 goto cuddZddSymmSiftingConvOutOfMem;
483 #ifdef DD_STATS
484 if (table->keysZ < (unsigned) previousSize) {
485 (void) fprintf(table->out,"-");
486 } else if (table->keysZ > (unsigned) previousSize) {
487 (void) fprintf(table->out,"+");
488 #ifdef DD_VERBOSE
489 (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]);
490 #endif
491 } else {
492 (void) fprintf(table->out,"=");
494 fflush(table->out);
495 #endif
499 /* Sifting now until convergence. */
500 while ((unsigned) initialSize > table->keysZ) {
501 initialSize = table->keysZ;
502 #ifdef DD_STATS
503 (void) fprintf(table->out,"\n");
504 #endif
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;
515 var[classes] = i;
518 qsort((void *)var,classes,sizeof(int),(DD_QSFP)cuddZddUniqueCompare);
520 /* Now sift. */
521 iteration = ddMin(table->siftMaxVar, nvars);
522 for (i = 0; i < iteration; i++) {
523 if (zddTotalNumberSwapping >= table->siftMaxSwap)
524 break;
525 x = table->permZ[var[i]];
526 if ((unsigned) x >= table->subtableZ[x].next) {
527 #ifdef DD_STATS
528 previousSize = table->keysZ;
529 #endif
530 result = cuddZddSymmSiftingConvAux(table, x, lower, upper);
531 if (!result)
532 goto cuddZddSymmSiftingConvOutOfMem;
533 #ifdef DD_STATS
534 if (table->keysZ < (unsigned) previousSize) {
535 (void) fprintf(table->out,"-");
536 } else if (table->keysZ > (unsigned) previousSize) {
537 (void) fprintf(table->out,"+");
538 #ifdef DD_VERBOSE
539 (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]);
540 #endif
541 } else {
542 (void) fprintf(table->out,"=");
544 fflush(table->out);
545 #endif
547 } /* for */
550 cuddZddSymmSummary(table, lower, upper, &symvars, &symgroups);
552 #ifdef DD_STATS
553 (void) fprintf(table->out,"\n#:S_SIFTING %8d: symmetric variables\n",
554 symvars);
555 (void) fprintf(table->out,"#:G_SIFTING %8d: symmetric groups\n",
556 symgroups);
557 #endif
559 FREE(var);
560 FREE(zdd_entry);
562 return(1+symvars);
564 cuddZddSymmSiftingConvOutOfMem:
566 if (zdd_entry != NULL)
567 FREE(zdd_entry);
568 if (var != NULL)
569 FREE(var);
571 return(0);
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
584 boundaries.]
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.]
591 SideEffects [None]
593 SeeAlso []
595 ******************************************************************************/
596 static int
597 cuddZddSymmSiftingAux(
598 DdManager * table,
599 int x,
600 int x_low,
601 int x_high)
603 Move *move;
604 Move *move_up; /* list of up move */
605 Move *move_down; /* list of down move */
606 int initial_size;
607 int result;
608 int i;
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;
614 move_down = NULL;
615 move_up = NULL;
617 /* Look for consecutive symmetries above x. */
618 for (i = x; i > x_low; i--) {
619 if (!cuddZddSymmCheck(table, i - 1, i))
620 break;
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
626 group */
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))
632 break;
633 /* find bottom of i+1's symm group */
634 topbot = i + 1;
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,
654 initial_size);
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
662 pass */
663 if (move_down != NULL)
664 x = move_down->y;
665 else
666 x = table->subtableZ[x].next;
667 i = x;
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);
679 else {
680 initial_size = table->keysZ;
681 move_up = cuddZddSymmSifting_up(table, x, x_low,
682 initial_size);
683 result = cuddZddSymmSiftingBackward(table, move_up,
684 initial_size);
687 else {
688 result = cuddZddSymmSiftingBackward(table, move_down,
689 initial_size);
690 /* move backward and stop at best position */
692 if (!result)
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;
701 i = x;
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
715 pass */
716 if (move_up != NULL)
717 x = move_up->x;
718 else {
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,
729 initial_size);
731 else {
732 initial_size = table->keysZ;
733 move_down = cuddZddSymmSifting_down(table, x, x_high,
734 initial_size);
735 result = cuddZddSymmSiftingBackward(table, move_down,
736 initial_size);
739 else {
740 result = cuddZddSymmSiftingBackward(table, move_up,
741 initial_size);
742 /* move backward and stop at best position */
744 if (!result)
745 goto cuddZddSymmSiftingAuxOutOfMem;
747 else if ((x - x_low) > (x_high - x)) { /* must go down first:
748 shorter */
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,
754 initial_size);
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) {
760 x = move_down->y;
762 else {
763 x = table->subtableZ[x].next;
765 i = x;
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
778 pass */
779 if (move_up != NULL) {
780 x = move_up->x;
782 else {
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,
793 initial_size);
795 else {
796 while (move_down != NULL) {
797 move = move_down->next;
798 cuddDeallocMove(table, move_down);
799 move_down = move;
801 initial_size = table->keysZ;
802 move_down = cuddZddSymmSifting_down(table, x, x_high,
803 initial_size);
804 result = cuddZddSymmSiftingBackward(table, move_down,
805 initial_size);
808 else {
809 result = cuddZddSymmSiftingBackward(table, move_up,
810 initial_size);
811 /* move backward and stop at best position */
813 if (!result)
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) {
828 x = move_up->x;
830 else {
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,
838 initial_size);
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
845 pass */
846 if (move_down != NULL) {
847 x = move_down->y;
849 else {
850 x = table->subtableZ[x].next;
852 i = x;
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,
862 initial_size);
864 else {
865 while (move_up != NULL) {
866 move = move_up->next;
867 cuddDeallocMove(table, move_up);
868 move_up = move;
870 initial_size = table->keysZ;
871 move_up = cuddZddSymmSifting_up(table, x, x_low,
872 initial_size);
873 result = cuddZddSymmSiftingBackward(table, move_up,
874 initial_size);
877 else {
878 result = cuddZddSymmSiftingBackward(table, move_down,
879 initial_size);
880 /* move backward and stop at best position */
882 if (!result)
883 goto cuddZddSymmSiftingAuxOutOfMem;
886 while (move_down != NULL) {
887 move = move_down->next;
888 cuddDeallocMove(table, move_down);
889 move_down = move;
891 while (move_up != NULL) {
892 move = move_up->next;
893 cuddDeallocMove(table, move_up);
894 move_up = move;
897 return(1);
899 cuddZddSymmSiftingAuxOutOfMem:
900 if (move_down != ZDD_MV_OOM) {
901 while (move_down != NULL) {
902 move = move_down->next;
903 cuddDeallocMove(table, move_down);
904 move_down = move;
907 if (move_up != ZDD_MV_OOM) {
908 while (move_up != NULL) {
909 move = move_up->next;
910 cuddDeallocMove(table, move_up);
911 move_up = move;
915 return(0);
917 } /* end of cuddZddSymmSiftingAux */
920 /**Function********************************************************************
922 Synopsis [Given x_low <= x <= x_high moves x up and down between the
923 boundaries.]
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.]
931 SideEffects [None]
933 SeeAlso []
935 ******************************************************************************/
936 static int
937 cuddZddSymmSiftingConvAux(
938 DdManager * table,
939 int x,
940 int x_low,
941 int x_high)
943 Move *move;
944 Move *move_up; /* list of up move */
945 Move *move_down; /* list of down move */
946 int initial_size;
947 int result;
948 int i;
949 int init_group_size, final_group_size;
951 initial_size = table->keysZ;
953 move_down = NULL;
954 move_up = NULL;
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,
961 initial_size);
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
969 pass */
970 if (move_down != NULL)
971 x = move_down->y;
972 else {
973 while ((unsigned) x < table->subtableZ[x].next)
974 x = table->subtableZ[x].next;
975 x = table->subtableZ[x].next;
977 i = x;
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,
987 initial_size);
989 else {
990 initial_size = table->keysZ;
991 move_up = cuddZddSymmSifting_up(table, x, x_low,
992 initial_size);
993 result = cuddZddSymmSiftingBackward(table, move_up,
994 initial_size);
997 else {
998 result = cuddZddSymmSiftingBackward(table, move_down,
999 initial_size);
1000 /* move backward and stop at best position */
1002 if (!result)
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;
1011 i = x;
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
1025 pass */
1026 if (move_up != NULL)
1027 x = move_up->x;
1028 else {
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,
1039 initial_size);
1041 else {
1042 initial_size = table->keysZ;
1043 move_down = cuddZddSymmSifting_down(table, x, x_high,
1044 initial_size);
1045 result = cuddZddSymmSiftingBackward(table, move_down,
1046 initial_size);
1049 else {
1050 result = cuddZddSymmSiftingBackward(table, move_up,
1051 initial_size);
1052 /* move backward and stop at best position */
1054 if (!result)
1055 goto cuddZddSymmSiftingConvAuxOutOfMem;
1057 else if ((x - x_low) > (x_high - x)) { /* must go down first:
1058 shorter */
1059 move_down = cuddZddSymmSifting_down(table, x, x_high,
1060 initial_size);
1061 /* after that point x --> x_high */
1062 if (move_down == ZDD_MV_OOM)
1063 goto cuddZddSymmSiftingConvAuxOutOfMem;
1065 if (move_down != NULL) {
1066 x = move_down->y;
1068 else {
1069 while ((unsigned) x < table->subtableZ[x].next)
1070 x = table->subtableZ[x].next;
1071 x = table->subtableZ[x].next;
1073 i = x;
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
1086 pass */
1087 if (move_up != NULL) {
1088 x = move_up->x;
1090 else {
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,
1101 initial_size);
1103 else {
1104 while (move_down != NULL) {
1105 move = move_down->next;
1106 cuddDeallocMove(table, move_down);
1107 move_down = move;
1109 initial_size = table->keysZ;
1110 move_down = cuddZddSymmSifting_down(table, x, x_high,
1111 initial_size);
1112 result = cuddZddSymmSiftingBackward(table, move_down,
1113 initial_size);
1116 else {
1117 result = cuddZddSymmSiftingBackward(table, move_up,
1118 initial_size);
1119 /* move backward and stop at best position */
1121 if (!result)
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) {
1134 x = move_up->x;
1136 else {
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,
1144 initial_size);
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
1151 pass */
1152 if (move_down != NULL) {
1153 x = move_down->y;
1155 else {
1156 while ((unsigned) x < table->subtableZ[x].next)
1157 x = table->subtableZ[x].next;
1158 x = table->subtableZ[x].next;
1160 i = x;
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,
1170 initial_size);
1172 else {
1173 while (move_up != NULL) {
1174 move = move_up->next;
1175 cuddDeallocMove(table, move_up);
1176 move_up = move;
1178 initial_size = table->keysZ;
1179 move_up = cuddZddSymmSifting_up(table, x, x_low,
1180 initial_size);
1181 result = cuddZddSymmSiftingBackward(table, move_up,
1182 initial_size);
1185 else {
1186 result = cuddZddSymmSiftingBackward(table, move_down,
1187 initial_size);
1188 /* move backward and stop at best position */
1190 if (!result)
1191 goto cuddZddSymmSiftingConvAuxOutOfMem;
1194 while (move_down != NULL) {
1195 move = move_down->next;
1196 cuddDeallocMove(table, move_down);
1197 move_down = move;
1199 while (move_up != NULL) {
1200 move = move_up->next;
1201 cuddDeallocMove(table, move_up);
1202 move_up = move;
1205 return(1);
1207 cuddZddSymmSiftingConvAuxOutOfMem:
1208 if (move_down != ZDD_MV_OOM) {
1209 while (move_down != NULL) {
1210 move = move_down->next;
1211 cuddDeallocMove(table, move_down);
1212 move_down = move;
1215 if (move_up != ZDD_MV_OOM) {
1216 while (move_up != NULL) {
1217 move = move_up->next;
1218 cuddDeallocMove(table, move_up);
1219 move_up = move;
1223 return(0);
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.]
1240 SideEffects [None]
1242 SeeAlso []
1244 ******************************************************************************/
1245 static Move *
1246 cuddZddSymmSifting_up(
1247 DdManager * table,
1248 int x,
1249 int x_low,
1250 int initial_size)
1252 Move *moves;
1253 Move *move;
1254 int y;
1255 int size;
1256 int limit_size = initial_size;
1257 int i, gytop;
1259 moves = NULL;
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);
1275 if (size == 0)
1276 goto cuddZddSymmSifting_upOutOfMem;
1277 move = (Move *)cuddDynamicAllocNode(table);
1278 if (move == NULL)
1279 goto cuddZddSymmSifting_upOutOfMem;
1280 move->x = y;
1281 move->y = x;
1282 move->size = size;
1283 move->next = moves;
1284 moves = move;
1285 if ((double)size >
1286 (double)limit_size * table->maxGrowth)
1287 return(moves);
1288 if (size < limit_size)
1289 limit_size = size;
1291 else { /* Group move */
1292 size = zdd_group_move(table, y, x, &moves);
1293 if ((double)size >
1294 (double)limit_size * table->maxGrowth)
1295 return(moves);
1296 if (size < limit_size)
1297 limit_size = size;
1299 x = gytop;
1300 y = cuddZddNextLow(table, x);
1303 return(moves);
1305 cuddZddSymmSifting_upOutOfMem:
1306 while (moves != NULL) {
1307 move = moves->next;
1308 cuddDeallocMove(table, moves);
1309 moves = move;
1311 return(ZDD_MV_OOM);
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.]
1328 SideEffects [None]
1330 SeeAlso []
1332 ******************************************************************************/
1333 static Move *
1334 cuddZddSymmSifting_down(
1335 DdManager * table,
1336 int x,
1337 int x_high,
1338 int initial_size)
1340 Move *moves;
1341 Move *move;
1342 int y;
1343 int size;
1344 int limit_size = initial_size;
1345 int i, gxtop, gybot;
1347 moves = NULL;
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);
1366 if (size == 0)
1367 goto cuddZddSymmSifting_downOutOfMem;
1368 move = (Move *)cuddDynamicAllocNode(table);
1369 if (move == NULL)
1370 goto cuddZddSymmSifting_downOutOfMem;
1371 move->x = x;
1372 move->y = y;
1373 move->size = size;
1374 move->next = moves;
1375 moves = move;
1376 if ((double)size >
1377 (double)limit_size * table->maxGrowth)
1378 return(moves);
1379 if (size < limit_size)
1380 limit_size = size;
1381 x = y;
1382 y = cuddZddNextHigh(table, x);
1384 else { /* Group move */
1385 size = zdd_group_move(table, x, y, &moves);
1386 if ((double)size >
1387 (double)limit_size * table->maxGrowth)
1388 return(moves);
1389 if (size < limit_size)
1390 limit_size = size;
1392 x = gybot;
1393 y = cuddZddNextHigh(table, x);
1396 return(moves);
1398 cuddZddSymmSifting_downOutOfMem:
1399 while (moves != NULL) {
1400 move = moves->next;
1401 cuddDeallocMove(table, moves);
1402 moves = move;
1404 return(ZDD_MV_OOM);
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.]
1419 SideEffects [None]
1421 SeeAlso []
1423 ******************************************************************************/
1424 static int
1425 cuddZddSymmSiftingBackward(
1426 DdManager * table,
1427 Move * moves,
1428 int size)
1430 int i;
1431 int i_best;
1432 Move *move;
1433 int res;
1435 i_best = -1;
1436 for (move = moves, i = 0; move != NULL; move = move->next, i++) {
1437 if (move->size < size) {
1438 i_best = i;
1439 size = move->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)
1454 break;
1457 return(1);
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.]
1471 SideEffects [None]
1473 SeeAlso []
1475 ******************************************************************************/
1476 static int
1477 zdd_group_move(
1478 DdManager * table,
1479 int x,
1480 int y,
1481 Move ** moves)
1483 Move *move;
1484 int size;
1485 int i, temp, gxtop, gxbot, gybot, yprev;
1486 int swapx, swapy;
1488 #ifdef DD_DEBUG
1489 assert(x < y); /* we assume that x < y */
1490 #endif
1491 /* Find top and bottom for the two groups. */
1492 gxtop = table->subtableZ[x].next;
1493 gxbot = x;
1494 gybot = table->subtableZ[y].next;
1495 while (table->subtableZ[gybot].next != (unsigned) y)
1496 gybot = table->subtableZ[gybot].next;
1497 yprev = gybot;
1499 while (x <= y) {
1500 while (y > gxtop) {
1501 /* Set correct symmetries. */
1502 temp = table->subtableZ[x].next;
1503 if (temp == x)
1504 temp = y;
1505 i = gxtop;
1506 for (;;) {
1507 if (table->subtableZ[i].next == (unsigned) x) {
1508 table->subtableZ[i].next = y;
1509 break;
1510 } else {
1511 i = table->subtableZ[i].next;
1514 if (table->subtableZ[y].next != (unsigned) y) {
1515 table->subtableZ[x].next = table->subtableZ[y].next;
1516 } else {
1517 table->subtableZ[x].next = x;
1520 if (yprev != y) {
1521 table->subtableZ[yprev].next = x;
1522 } else {
1523 yprev = x;
1525 table->subtableZ[y].next = temp;
1527 size = cuddZddSwapInPlace(table, x, y);
1528 if (size == 0)
1529 goto zdd_group_moveOutOfMem;
1530 swapx = x;
1531 swapy = y;
1532 y = x;
1533 x--;
1534 } /* while y > gxtop */
1536 /* Trying to find the next y. */
1537 if (table->subtableZ[y].next <= (unsigned) y) {
1538 gybot = y;
1539 } else {
1540 y = table->subtableZ[y].next;
1543 yprev = gxtop;
1544 gxtop++;
1545 gxbot++;
1546 x = gxbot;
1547 } /* while x <= y, end of group movement */
1548 move = (Move *)cuddDynamicAllocNode(table);
1549 if (move == NULL)
1550 goto zdd_group_moveOutOfMem;
1551 move->x = swapx;
1552 move->y = swapy;
1553 move->size = table->keysZ;
1554 move->next = *moves;
1555 *moves = move;
1557 return(table->keysZ);
1559 zdd_group_moveOutOfMem:
1560 while (*moves != NULL) {
1561 move = (*moves)->next;
1562 cuddDeallocMove(table, *moves);
1563 *moves = move;
1565 return(0);
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.]
1578 SideEffects [None]
1580 SeeAlso []
1582 ******************************************************************************/
1583 static int
1584 zdd_group_move_backward(
1585 DdManager * table,
1586 int x,
1587 int y)
1589 int size;
1590 int i, temp, gxtop, gxbot, gybot, yprev;
1592 #ifdef DD_DEBUG
1593 assert(x < y); /* we assume that x < y */
1594 #endif
1595 /* Find top and bottom of the two groups. */
1596 gxtop = table->subtableZ[x].next;
1597 gxbot = x;
1598 gybot = table->subtableZ[y].next;
1599 while (table->subtableZ[gybot].next != (unsigned) y)
1600 gybot = table->subtableZ[gybot].next;
1601 yprev = gybot;
1603 while (x <= y) {
1604 while (y > gxtop) {
1605 /* Set correct symmetries. */
1606 temp = table->subtableZ[x].next;
1607 if (temp == x)
1608 temp = y;
1609 i = gxtop;
1610 for (;;) {
1611 if (table->subtableZ[i].next == (unsigned) x) {
1612 table->subtableZ[i].next = y;
1613 break;
1614 } else {
1615 i = table->subtableZ[i].next;
1618 if (table->subtableZ[y].next != (unsigned) y) {
1619 table->subtableZ[x].next = table->subtableZ[y].next;
1620 } else {
1621 table->subtableZ[x].next = x;
1624 if (yprev != y) {
1625 table->subtableZ[yprev].next = x;
1626 } else {
1627 yprev = x;
1629 table->subtableZ[y].next = temp;
1631 size = cuddZddSwapInPlace(table, x, y);
1632 if (size == 0)
1633 return(0);
1634 y = x;
1635 x--;
1636 } /* while y > gxtop */
1638 /* Trying to find the next y. */
1639 if (table->subtableZ[y].next <= (unsigned) y) {
1640 gybot = y;
1641 } else {
1642 y = table->subtableZ[y].next;
1645 yprev = gxtop;
1646 gxtop++;
1647 gxbot++;
1648 x = gxbot;
1649 } /* while x <= y, end of group movement backward */
1651 return(size);
1653 } /* end of zdd_group_move_backward */
1656 /**Function********************************************************************
1658 Synopsis [Counts numbers of symmetric variables and symmetry
1659 groups.]
1661 Description []
1663 SideEffects [None]
1665 ******************************************************************************/
1666 static void
1667 cuddZddSymmSummary(
1668 DdManager * table,
1669 int lower,
1670 int upper,
1671 int * symvars,
1672 int * symgroups)
1674 int i,x,gbot;
1675 int TotalSymm = 0;
1676 int TotalSymmGroups = 0;
1678 for (i = lower; i <= upper; i++) {
1679 if (table->subtableZ[i].next != (unsigned) i) {
1680 TotalSymmGroups++;
1681 x = i;
1682 do {
1683 TotalSymm++;
1684 gbot = x;
1685 x = table->subtableZ[x].next;
1686 } while (x != i);
1687 #ifdef DD_DEBUG
1688 assert(table->subtableZ[gbot].next == (unsigned) i);
1689 #endif
1690 i = gbot;
1693 *symvars = TotalSymm;
1694 *symgroups = TotalSymmGroups;
1696 return;
1698 } /* end of cuddZddSymmSummary */