summaryrefslogtreecommitdiffstats
path: root/abc70930/src/bdd/cudd/cuddZddSymm.c
diff options
context:
space:
mode:
Diffstat (limited to 'abc70930/src/bdd/cudd/cuddZddSymm.c')
-rw-r--r--abc70930/src/bdd/cudd/cuddZddSymm.c1677
1 files changed, 1677 insertions, 0 deletions
diff --git a/abc70930/src/bdd/cudd/cuddZddSymm.c b/abc70930/src/bdd/cudd/cuddZddSymm.c
new file mode 100644
index 00000000..54019892
--- /dev/null
+++ b/abc70930/src/bdd/cudd/cuddZddSymm.c
@@ -0,0 +1,1677 @@
+/**CFile***********************************************************************
+
+ FileName [cuddZddSymm.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for symmetry-based ZDD variable reordering.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_zddSymmProfile()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddZddSymmCheck()
+ <li> cuddZddSymmSifting()
+ <li> cuddZddSymmSiftingConv()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddZddUniqueCompare()
+ <li> cuddZddSymmSiftingAux()
+ <li> cuddZddSymmSiftingConvAux()
+ <li> cuddZddSymmSifting_up()
+ <li> cuddZddSymmSifting_down()
+ <li> zdd_group_move()
+ <li> cuddZddSymmSiftingBackward()
+ <li> zdd_group_move_backward()
+ </ul>
+ ]
+
+ SeeAlso [cuddSymmetry.c]
+
+ Author [Hyong-Kyoon Shin, In-Ho Moon]
+
+ Copyright [ This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util_hack.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+#define ZDD_MV_OOM (Move *)1
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddZddSymm.c,v 1.1.1.1 2003/02/24 22:23:54 wjiang Exp $";
+#endif
+
+extern int *zdd_entry;
+
+extern int zddTotalNumberSwapping;
+
+static DdNode *empty;
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int cuddZddSymmSiftingAux ARGS((DdManager *table, int x, int x_low, int x_high));
+static int cuddZddSymmSiftingConvAux ARGS((DdManager *table, int x, int x_low, int x_high));
+static Move * cuddZddSymmSifting_up ARGS((DdManager *table, int x, int x_low, int initial_size));
+static Move * cuddZddSymmSifting_down ARGS((DdManager *table, int x, int x_high, int initial_size));
+static int cuddZddSymmSiftingBackward ARGS((DdManager *table, Move *moves, int size));
+static int zdd_group_move ARGS((DdManager *table, int x, int y, Move **moves));
+static int zdd_group_move_backward ARGS((DdManager *table, int x, int y));
+static void cuddZddSymmSummary ARGS((DdManager *table, int lower, int upper, int *symvars, int *symgroups));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Prints statistics on symmetric ZDD variables.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+void
+Cudd_zddSymmProfile(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i, x, gbot;
+ int TotalSymm = 0;
+ int TotalSymmGroups = 0;
+ int nvars;
+
+ nvars = table->sizeZ;
+
+ for (i = lower; i < upper; i++) {
+ if (table->subtableZ[i].next != (unsigned) i) {
+ x = i;
+ (void) fprintf(table->out,"Group:");
+ do {
+ (void) fprintf(table->out," %d", table->invpermZ[x]);
+ TotalSymm++;
+ gbot = x;
+ x = table->subtableZ[x].next;
+ } while (x != i);
+ TotalSymmGroups++;
+#ifdef DD_DEBUG
+ assert(table->subtableZ[gbot].next == (unsigned) i);
+#endif
+ i = gbot;
+ (void) fprintf(table->out,"\n");
+ }
+ }
+ (void) fprintf(table->out,"Total Symmetric = %d\n", TotalSymm);
+ (void) fprintf(table->out,"Total Groups = %d\n", TotalSymmGroups);
+
+} /* end of Cudd_zddSymmProfile */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Checks for symmetry of x and y.]
+
+ Description [Checks for symmetry of x and y. Ignores projection
+ functions, unless they are isolated. Returns 1 in case of
+ symmetry; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+int
+cuddZddSymmCheck(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int i;
+ DdNode *f, *f0, *f1, *f01, *f00, *f11, *f10;
+ int yindex;
+ int xsymmy = 1;
+ int xsymmyp = 1;
+ int arccount = 0;
+ int TotalRefCount = 0;
+ int symm_found;
+
+ empty = table->zero;
+
+ yindex = table->invpermZ[y];
+ for (i = table->subtableZ[x].slots - 1; i >= 0; i--) {
+ f = table->subtableZ[x].nodelist[i];
+ while (f != NULL) {
+ /* Find f1, f0, f11, f10, f01, f00 */
+ f1 = cuddT(f);
+ f0 = cuddE(f);
+ if ((int) f1->index == yindex) {
+ f11 = cuddT(f1);
+ f10 = cuddE(f1);
+ if (f10 != empty)
+ arccount++;
+ } else {
+ if ((int) f0->index != yindex) {
+ return(0); /* f bypasses layer y */
+ }
+ f11 = empty;
+ f10 = f1;
+ }
+ if ((int) f0->index == yindex) {
+ f01 = cuddT(f0);
+ f00 = cuddE(f0);
+ if (f00 != empty)
+ arccount++;
+ } else {
+ f01 = empty;
+ f00 = f0;
+ }
+ if (f01 != f10)
+ xsymmy = 0;
+ if (f11 != f00)
+ xsymmyp = 0;
+ if ((xsymmy == 0) && (xsymmyp == 0))
+ return(0);
+
+ f = f->next;
+ } /* for each element of the collision list */
+ } /* for each slot of the subtable */
+
+ /* Calculate the total reference counts of y
+ ** whose else arc is not empty.
+ */
+ for (i = table->subtableZ[y].slots - 1; i >= 0; i--) {
+ f = table->subtableZ[y].nodelist[i];
+ while (f != NIL(DdNode)) {
+ if (cuddE(f) != empty)
+ TotalRefCount += f->ref;
+ f = f->next;
+ }
+ }
+
+ symm_found = (arccount == TotalRefCount);
+#if defined(DD_DEBUG) && defined(DD_VERBOSE)
+ if (symm_found) {
+ int xindex = table->invpermZ[x];
+ (void) fprintf(table->out,
+ "Found symmetry! x =%d\ty = %d\tPos(%d,%d)\n",
+ xindex,yindex,x,y);
+ }
+#endif
+
+ return(symm_found);
+
+} /* end cuddZddSymmCheck */
+
+
+/**Function********************************************************************
+
+ Synopsis [Symmetric sifting algorithm for ZDDs.]
+
+ Description [Symmetric sifting algorithm.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries in
+ each unique subtable.
+ <li> Sift the variable up and down, remembering each time the total
+ size of the ZDD heap and grouping variables that are symmetric.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ </ol>
+ Returns 1 plus the number of symmetric variables if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddSymmSiftingConv]
+
+******************************************************************************/
+int
+cuddZddSymmSifting(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int nvars;
+ int x;
+ int result;
+ int symvars;
+ int symgroups;
+ int iteration;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ nvars = table->sizeZ;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ zdd_entry = ALLOC(int, nvars);
+ if (zdd_entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSymmSiftingOutOfMem;
+ }
+ var = ALLOC(int, nvars);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSymmSiftingOutOfMem;
+ }
+
+ for (i = 0; i < nvars; i++) {
+ x = table->permZ[i];
+ zdd_entry[i] = table->subtableZ[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var, nvars, sizeof(int), (int (*)(const void *, const void *))cuddZddUniqueCompare);
+
+ /* Initialize the symmetry of each subtable to itself. */
+ for (i = lower; i <= upper; i++)
+ table->subtableZ[i].next = i;
+
+ iteration = ddMin(table->siftMaxVar, nvars);
+ for (i = 0; i < iteration; i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->permZ[var[i]];
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ if (x < lower || x > upper) continue;
+ if (table->subtableZ[x].next == (unsigned) x) {
+ result = cuddZddSymmSiftingAux(table, x, lower, upper);
+ if (!result)
+ goto cuddZddSymmSiftingOutOfMem;
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+");
+#ifdef DD_VERBOSE
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]);
+#endif
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+
+ FREE(var);
+ FREE(zdd_entry);
+
+ cuddZddSymmSummary(table, lower, upper, &symvars, &symgroups);
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n#:S_SIFTING %8d: symmetric variables\n",symvars);
+ (void) fprintf(table->out,"#:G_SIFTING %8d: symmetric groups\n",symgroups);
+#endif
+
+ return(1+symvars);
+
+cuddZddSymmSiftingOutOfMem:
+
+ if (zdd_entry != NULL)
+ FREE(zdd_entry);
+ if (var != NULL)
+ FREE(var);
+
+ return(0);
+
+} /* end of cuddZddSymmSifting */
+
+
+/**Function********************************************************************
+
+ Synopsis [Symmetric sifting to convergence algorithm for ZDDs.]
+
+ Description [Symmetric sifting to convergence algorithm for ZDDs.
+ Assumes that no dead nodes are present.
+ <ol>
+ <li> Order all the variables according to the number of entries in
+ each unique subtable.
+ <li> Sift the variable up and down, remembering each time the total
+ size of the ZDD heap and grouping variables that are symmetric.
+ <li> Select the best permutation.
+ <li> Repeat 3 and 4 for all variables.
+ <li> Repeat 1-4 until no further improvement.
+ </ol>
+ Returns 1 plus the number of symmetric variables if successful; 0
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [cuddZddSymmSifting]
+
+******************************************************************************/
+int
+cuddZddSymmSiftingConv(
+ DdManager * table,
+ int lower,
+ int upper)
+{
+ int i;
+ int *var;
+ int nvars;
+ int initialSize;
+ int x;
+ int result;
+ int symvars;
+ int symgroups;
+ int classes;
+ int iteration;
+#ifdef DD_STATS
+ int previousSize;
+#endif
+
+ initialSize = table->keysZ;
+
+ nvars = table->sizeZ;
+
+ /* Find order in which to sift variables. */
+ var = NULL;
+ zdd_entry = ALLOC(int, nvars);
+ if (zdd_entry == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSymmSiftingConvOutOfMem;
+ }
+ var = ALLOC(int, nvars);
+ if (var == NULL) {
+ table->errorCode = CUDD_MEMORY_OUT;
+ goto cuddZddSymmSiftingConvOutOfMem;
+ }
+
+ for (i = 0; i < nvars; i++) {
+ x = table->permZ[i];
+ zdd_entry[i] = table->subtableZ[x].keys;
+ var[i] = i;
+ }
+
+ qsort((void *)var, nvars, sizeof(int), (int (*)(const void *, const void *))cuddZddUniqueCompare);
+
+ /* Initialize the symmetry of each subtable to itself
+ ** for first pass of converging symmetric sifting.
+ */
+ for (i = lower; i <= upper; i++)
+ table->subtableZ[i].next = i;
+
+ iteration = ddMin(table->siftMaxVar, table->sizeZ);
+ for (i = 0; i < iteration; i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->permZ[var[i]];
+ if (x < lower || x > upper) continue;
+ /* Only sift if not in symmetry group already. */
+ if (table->subtableZ[x].next == (unsigned) x) {
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ result = cuddZddSymmSiftingAux(table, x, lower, upper);
+ if (!result)
+ goto cuddZddSymmSiftingConvOutOfMem;
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+");
+#ifdef DD_VERBOSE
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]);
+#endif
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ }
+
+ /* Sifting now until convergence. */
+ while ((unsigned) initialSize > table->keysZ) {
+ initialSize = table->keysZ;
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n");
+#endif
+ /* Here we consider only one representative for each symmetry class. */
+ for (x = lower, classes = 0; x <= upper; x++, classes++) {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ /* Here x is the largest index in a group.
+ ** Groups consists of adjacent variables.
+ ** Hence, the next increment of x will move it to a new group.
+ */
+ i = table->invpermZ[x];
+ zdd_entry[i] = table->subtableZ[x].keys;
+ var[classes] = i;
+ }
+
+ qsort((void *)var,classes,sizeof(int),(int (*)(const void *, const void *))cuddZddUniqueCompare);
+
+ /* Now sift. */
+ iteration = ddMin(table->siftMaxVar, nvars);
+ for (i = 0; i < iteration; i++) {
+ if (zddTotalNumberSwapping >= table->siftMaxSwap)
+ break;
+ x = table->permZ[var[i]];
+ if ((unsigned) x >= table->subtableZ[x].next) {
+#ifdef DD_STATS
+ previousSize = table->keysZ;
+#endif
+ result = cuddZddSymmSiftingConvAux(table, x, lower, upper);
+ if (!result)
+ goto cuddZddSymmSiftingConvOutOfMem;
+#ifdef DD_STATS
+ if (table->keysZ < (unsigned) previousSize) {
+ (void) fprintf(table->out,"-");
+ } else if (table->keysZ > (unsigned) previousSize) {
+ (void) fprintf(table->out,"+");
+#ifdef DD_VERBOSE
+ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]);
+#endif
+ } else {
+ (void) fprintf(table->out,"=");
+ }
+ fflush(table->out);
+#endif
+ }
+ } /* for */
+ }
+
+ cuddZddSymmSummary(table, lower, upper, &symvars, &symgroups);
+
+#ifdef DD_STATS
+ (void) fprintf(table->out,"\n#:S_SIFTING %8d: symmetric variables\n",
+ symvars);
+ (void) fprintf(table->out,"#:G_SIFTING %8d: symmetric groups\n",
+ symgroups);
+#endif
+
+ FREE(var);
+ FREE(zdd_entry);
+
+ return(1+symvars);
+
+cuddZddSymmSiftingConvOutOfMem:
+
+ if (zdd_entry != NULL)
+ FREE(zdd_entry);
+ if (var != NULL)
+ FREE(var);
+
+ return(0);
+
+} /* end of cuddZddSymmSiftingConv */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Given x_low <= x <= x_high moves x up and down between the
+ boundaries.]
+
+ Description [Given x_low <= x <= x_high moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Assumes that x is not part of a symmetry group. Returns 1 if
+ successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddSymmSiftingAux(
+ DdManager * table,
+ int x,
+ int x_low,
+ int x_high)
+{
+ Move *move;
+ Move *move_up; /* list of up move */
+ Move *move_down; /* list of down move */
+ int initial_size;
+ int result;
+ int i;
+ int topbot; /* index to either top or bottom of symmetry group */
+ int init_group_size, final_group_size;
+
+ initial_size = table->keysZ;
+
+ move_down = NULL;
+ move_up = NULL;
+
+ /* Look for consecutive symmetries above x. */
+ for (i = x; i > x_low; i--) {
+ if (!cuddZddSymmCheck(table, i - 1, i))
+ break;
+ /* find top of i-1's symmetry */
+ topbot = table->subtableZ[i - 1].next;
+ table->subtableZ[i - 1].next = i;
+ table->subtableZ[x].next = topbot;
+ /* x is bottom of group so its symmetry is top of i-1's
+ group */
+ i = topbot + 1; /* add 1 for i--, new i is top of symm group */
+ }
+ /* Look for consecutive symmetries below x. */
+ for (i = x; i < x_high; i++) {
+ if (!cuddZddSymmCheck(table, i, i + 1))
+ break;
+ /* find bottom of i+1's symm group */
+ topbot = i + 1;
+ while ((unsigned) topbot < table->subtableZ[topbot].next)
+ topbot = table->subtableZ[topbot].next;
+
+ table->subtableZ[topbot].next = table->subtableZ[i].next;
+ table->subtableZ[i].next = i + 1;
+ i = topbot - 1; /* add 1 for i++,
+ new i is bottom of symm group */
+ }
+
+ /* Now x maybe in the middle of a symmetry group. */
+ if (x == x_low) { /* Sift down */
+ /* Find bottom of x's symm group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+
+ i = table->subtableZ[x].next;
+ init_group_size = x - i + 1;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_down == NULL ||
+ table->subtableZ[move_down->y].next != move_down->y) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_down != NULL)
+ x = move_down->y;
+ else
+ x = table->subtableZ[x].next;
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ final_group_size = i - x + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table,
+ move_down, initial_size);
+ }
+ else {
+ initial_size = table->keysZ;
+ move_up = cuddZddSymmSifting_up(table, x, x_low,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+ }
+ else if (x == x_high) { /* Sift up */
+ /* Find top of x's symm group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ init_group_size = i - x + 1;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ /* after that point x --> x_low, unless early term */
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_up == NULL ||
+ table->subtableZ[move_up->x].next != move_up->x) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_up != NULL)
+ x = move_up->x;
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ final_group_size = x - i + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ else {
+ initial_size = table->keysZ;
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+ }
+ else if ((x - x_low) > (x_high - x)) { /* must go down first:
+ shorter */
+ /* Find bottom of x's symm group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_down != NULL) {
+ x = move_down->y;
+ }
+ else {
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ init_group_size = i - x + 1;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_up == NULL ||
+ table->subtableZ[move_up->x].next != move_up->x) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_up != NULL) {
+ x = move_up->x;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ final_group_size = x - i + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ else {
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ initial_size = table->keysZ;
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+ }
+ else { /* moving up first:shorter */
+ /* Find top of x's symmetry group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_up != NULL) {
+ x = move_up->x;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ init_group_size = x - i + 1;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+
+ if (move_down == NULL ||
+ table->subtableZ[move_down->y].next != move_down->y) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_down != NULL) {
+ x = move_down->y;
+ }
+ else {
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ final_group_size = i - x + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetries detected,
+ go back to best position */
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ else {
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+ initial_size = table->keysZ;
+ move_up = cuddZddSymmSifting_up(table, x, x_low,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingAuxOutOfMem;
+ }
+
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+
+ return(1);
+
+cuddZddSymmSiftingAuxOutOfMem:
+ if (move_down != ZDD_MV_OOM) {
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ }
+ if (move_up != ZDD_MV_OOM) {
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+ }
+
+ return(0);
+
+} /* end of cuddZddSymmSiftingAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given x_low <= x <= x_high moves x up and down between the
+ boundaries.]
+
+ Description [Given x_low <= x <= x_high moves x up and down between the
+ boundaries. Finds the best position and does the required changes.
+ Assumes that x is either an isolated variable, or it is the bottom of
+ a symmetry group. All symmetries may not have been found, because of
+ exceeded growth limit. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddSymmSiftingConvAux(
+ DdManager * table,
+ int x,
+ int x_low,
+ int x_high)
+{
+ Move *move;
+ Move *move_up; /* list of up move */
+ Move *move_down; /* list of down move */
+ int initial_size;
+ int result;
+ int i;
+ int init_group_size, final_group_size;
+
+ initial_size = table->keysZ;
+
+ move_down = NULL;
+ move_up = NULL;
+
+ if (x == x_low) { /* Sift down */
+ i = table->subtableZ[x].next;
+ init_group_size = x - i + 1;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_down == NULL ||
+ table->subtableZ[move_down->y].next != move_down->y) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_down != NULL)
+ x = move_down->y;
+ else {
+ while ((unsigned) x < table->subtableZ[x].next);
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ final_group_size = i - x + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetries detected,
+ go back to best position */
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ else {
+ initial_size = table->keysZ;
+ move_up = cuddZddSymmSifting_up(table, x, x_low,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+ }
+ else if (x == x_high) { /* Sift up */
+ /* Find top of x's symm group */
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ init_group_size = i - x + 1;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ /* after that point x --> x_low, unless early term */
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_up == NULL ||
+ table->subtableZ[move_up->x].next != move_up->x) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_up != NULL)
+ x = move_up->x;
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ final_group_size = x - i + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ else {
+ initial_size = table->keysZ;
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+ }
+ else if ((x - x_low) > (x_high - x)) { /* must go down first:
+ shorter */
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ /* after that point x --> x_high */
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_down != NULL) {
+ x = move_down->y;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ init_group_size = i - x + 1;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_up == NULL ||
+ table->subtableZ[move_up->x].next != move_up->x) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_up != NULL) {
+ x = move_up->x;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ final_group_size = x - i + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetry groups detected,
+ return to best position */
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ else {
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ initial_size = table->keysZ;
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+ }
+ else { /* moving up first:shorter */
+ /* Find top of x's symmetry group */
+ x = table->subtableZ[x].next;
+
+ move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size);
+ /* after that point x --> x_high, unless early term */
+ if (move_up == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_up != NULL) {
+ x = move_up->x;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ }
+ i = table->subtableZ[x].next;
+ init_group_size = x - i + 1;
+
+ move_down = cuddZddSymmSifting_down(table, x, x_high,
+ initial_size);
+ if (move_down == ZDD_MV_OOM)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+
+ if (move_down == NULL ||
+ table->subtableZ[move_down->y].next != move_down->y) {
+ /* symmetry detected may have to make another complete
+ pass */
+ if (move_down != NULL) {
+ x = move_down->y;
+ }
+ else {
+ while ((unsigned) x < table->subtableZ[x].next)
+ x = table->subtableZ[x].next;
+ x = table->subtableZ[x].next;
+ }
+ i = x;
+ while ((unsigned) i < table->subtableZ[i].next) {
+ i = table->subtableZ[i].next;
+ }
+ final_group_size = i - x + 1;
+
+ if (init_group_size == final_group_size) {
+ /* No new symmetries detected,
+ go back to best position */
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ }
+ else {
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+ initial_size = table->keysZ;
+ move_up = cuddZddSymmSifting_up(table, x, x_low,
+ initial_size);
+ result = cuddZddSymmSiftingBackward(table, move_up,
+ initial_size);
+ }
+ }
+ else {
+ result = cuddZddSymmSiftingBackward(table, move_down,
+ initial_size);
+ /* move backward and stop at best position */
+ }
+ if (!result)
+ goto cuddZddSymmSiftingConvAuxOutOfMem;
+ }
+
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+
+ return(1);
+
+cuddZddSymmSiftingConvAuxOutOfMem:
+ if (move_down != ZDD_MV_OOM) {
+ while (move_down != NULL) {
+ move = move_down->next;
+ cuddDeallocNode(table, (DdNode *)move_down);
+ move_down = move;
+ }
+ }
+ if (move_up != ZDD_MV_OOM) {
+ while (move_up != NULL) {
+ move = move_up->next;
+ cuddDeallocNode(table, (DdNode *)move_up);
+ move_up = move;
+ }
+ }
+
+ return(0);
+
+} /* end of cuddZddSymmSiftingConvAux */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves x up until either it reaches the bound (x_low) or
+ the size of the ZDD heap increases too much.]
+
+ Description [Moves x up until either it reaches the bound (x_low) or
+ the size of the ZDD heap increases too much. Assumes that x is the top
+ of a symmetry group. Checks x for symmetry to the adjacent
+ variables. If symmetry is found, the symmetry group of x is merged
+ with the symmetry group of the other variable. Returns the set of
+ moves in case of success; ZDD_MV_OOM if memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+cuddZddSymmSifting_up(
+ DdManager * table,
+ int x,
+ int x_low,
+ int initial_size)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limit_size = initial_size;
+ int i, gytop;
+
+ moves = NULL;
+ y = cuddZddNextLow(table, x);
+ while (y >= x_low) {
+ gytop = table->subtableZ[y].next;
+ if (cuddZddSymmCheck(table, y, x)) {
+ /* Symmetry found, attach symm groups */
+ table->subtableZ[y].next = x;
+ i = table->subtableZ[x].next;
+ while (table->subtableZ[i].next != (unsigned) x)
+ i = table->subtableZ[i].next;
+ table->subtableZ[i].next = gytop;
+ }
+ else if ((table->subtableZ[x].next == (unsigned) x) &&
+ (table->subtableZ[y].next == (unsigned) y)) {
+ /* x and y have self symmetry */
+ size = cuddZddSwapInPlace(table, y, x);
+ if (size == 0)
+ goto cuddZddSymmSifting_upOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto cuddZddSymmSifting_upOutOfMem;
+ move->x = y;
+ move->y = x;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double)size >
+ (double)limit_size * table->maxGrowth)
+ return(moves);
+ if (size < limit_size)
+ limit_size = size;
+ }
+ else { /* Group move */
+ size = zdd_group_move(table, y, x, &moves);
+ if ((double)size >
+ (double)limit_size * table->maxGrowth)
+ return(moves);
+ if (size < limit_size)
+ limit_size = size;
+ }
+ x = gytop;
+ y = cuddZddNextLow(table, x);
+ }
+
+ return(moves);
+
+cuddZddSymmSifting_upOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return(ZDD_MV_OOM);
+
+} /* end of cuddZddSymmSifting_up */
+
+
+/**Function********************************************************************
+
+ Synopsis [Moves x down until either it reaches the bound (x_high) or
+ the size of the ZDD heap increases too much.]
+
+ Description [Moves x down until either it reaches the bound (x_high)
+ or the size of the ZDD heap increases too much. Assumes that x is the
+ bottom of a symmetry group. Checks x for symmetry to the adjacent
+ variables. If symmetry is found, the symmetry group of x is merged
+ with the symmetry group of the other variable. Returns the set of
+ moves in case of success; ZDD_MV_OOM if memory is full.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static Move *
+cuddZddSymmSifting_down(
+ DdManager * table,
+ int x,
+ int x_high,
+ int initial_size)
+{
+ Move *moves;
+ Move *move;
+ int y;
+ int size;
+ int limit_size = initial_size;
+ int i, gxtop, gybot;
+
+ moves = NULL;
+ y = cuddZddNextHigh(table, x);
+ while (y <= x_high) {
+ gybot = table->subtableZ[y].next;
+ while (table->subtableZ[gybot].next != (unsigned) y)
+ gybot = table->subtableZ[gybot].next;
+ if (cuddZddSymmCheck(table, x, y)) {
+ /* Symmetry found, attach symm groups */
+ gxtop = table->subtableZ[x].next;
+ table->subtableZ[x].next = y;
+ i = table->subtableZ[y].next;
+ while (table->subtableZ[i].next != (unsigned) y)
+ i = table->subtableZ[i].next;
+ table->subtableZ[i].next = gxtop;
+ }
+ else if ((table->subtableZ[x].next == (unsigned) x) &&
+ (table->subtableZ[y].next == (unsigned) y)) {
+ /* x and y have self symmetry */
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ goto cuddZddSymmSifting_downOutOfMem;
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto cuddZddSymmSifting_downOutOfMem;
+ move->x = x;
+ move->y = y;
+ move->size = size;
+ move->next = moves;
+ moves = move;
+ if ((double)size >
+ (double)limit_size * table->maxGrowth)
+ return(moves);
+ if (size < limit_size)
+ limit_size = size;
+ x = y;
+ y = cuddZddNextHigh(table, x);
+ }
+ else { /* Group move */
+ size = zdd_group_move(table, x, y, &moves);
+ if ((double)size >
+ (double)limit_size * table->maxGrowth)
+ return(moves);
+ if (size < limit_size)
+ limit_size = size;
+ }
+ x = gybot;
+ y = cuddZddNextHigh(table, x);
+ }
+
+ return(moves);
+
+cuddZddSymmSifting_downOutOfMem:
+ while (moves != NULL) {
+ move = moves->next;
+ cuddDeallocNode(table, (DdNode *)moves);
+ moves = move;
+ }
+ return(ZDD_MV_OOM);
+
+} /* end of cuddZddSymmSifting_down */
+
+
+/**Function********************************************************************
+
+ Synopsis [Given a set of moves, returns the ZDD heap to the position
+ giving the minimum size.]
+
+ Description [Given a set of moves, returns the ZDD heap to the
+ position giving the minimum size. In case of ties, returns to the
+ closest position giving the minimum size. Returns 1 in case of
+ success; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddZddSymmSiftingBackward(
+ DdManager * table,
+ Move * moves,
+ int size)
+{
+ int i;
+ int i_best;
+ Move *move;
+ int res;
+
+ i_best = -1;
+ for (move = moves, i = 0; move != NULL; move = move->next, i++) {
+ if (move->size < size) {
+ i_best = i;
+ size = move->size;
+ }
+ }
+
+ for (move = moves, i = 0; move != NULL; move = move->next, i++) {
+ if (i == i_best) break;
+ if ((table->subtableZ[move->x].next == move->x) &&
+ (table->subtableZ[move->y].next == move->y)) {
+ res = cuddZddSwapInPlace(table, move->x, move->y);
+ if (!res) return(0);
+ }
+ else { /* Group move necessary */
+ res = zdd_group_move_backward(table, move->x, move->y);
+ }
+ if (i_best == -1 && res == size)
+ break;
+ }
+
+ return(1);
+
+} /* end of cuddZddSymmSiftingBackward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Swaps two groups.]
+
+ Description [Swaps two groups. x is assumed to be the bottom variable
+ of the first group. y is assumed to be the top variable of the second
+ group. Updates the list of moves. Returns the number of keys in the
+ table if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+zdd_group_move(
+ DdManager * table,
+ int x,
+ int y,
+ Move ** moves)
+{
+ Move *move;
+ int size;
+ int i, temp, gxtop, gxbot, gytop, gybot, yprev;
+ int swapx, swapy;
+
+#ifdef DD_DEBUG
+ assert(x < y); /* we assume that x < y */
+#endif
+ /* Find top and bottom for the two groups. */
+ gxtop = table->subtableZ[x].next;
+ gytop = y;
+ gxbot = x;
+ gybot = table->subtableZ[y].next;
+ while (table->subtableZ[gybot].next != (unsigned) y)
+ gybot = table->subtableZ[gybot].next;
+ yprev = gybot;
+
+ while (x <= y) {
+ while (y > gxtop) {
+ /* Set correct symmetries. */
+ temp = table->subtableZ[x].next;
+ if (temp == x)
+ temp = y;
+ i = gxtop;
+ for (;;) {
+ if (table->subtableZ[i].next == (unsigned) x) {
+ table->subtableZ[i].next = y;
+ break;
+ } else {
+ i = table->subtableZ[i].next;
+ }
+ }
+ if (table->subtableZ[y].next != (unsigned) y) {
+ table->subtableZ[x].next = table->subtableZ[y].next;
+ } else {
+ table->subtableZ[x].next = x;
+ }
+
+ if (yprev != y) {
+ table->subtableZ[yprev].next = x;
+ } else {
+ yprev = x;
+ }
+ table->subtableZ[y].next = temp;
+
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ goto zdd_group_moveOutOfMem;
+ swapx = x;
+ swapy = y;
+ y = x;
+ x--;
+ } /* while y > gxtop */
+
+ /* Trying to find the next y. */
+ if (table->subtableZ[y].next <= (unsigned) y) {
+ gybot = y;
+ } else {
+ y = table->subtableZ[y].next;
+ }
+
+ yprev = gxtop;
+ gxtop++;
+ gxbot++;
+ x = gxbot;
+ } /* while x <= y, end of group movement */
+ move = (Move *)cuddDynamicAllocNode(table);
+ if (move == NULL)
+ goto zdd_group_moveOutOfMem;
+ move->x = swapx;
+ move->y = swapy;
+ move->size = table->keysZ;
+ move->next = *moves;
+ *moves = move;
+
+ return(table->keysZ);
+
+zdd_group_moveOutOfMem:
+ while (*moves != NULL) {
+ move = (*moves)->next;
+ cuddDeallocNode(table, (DdNode *)(*moves));
+ *moves = move;
+ }
+ return(0);
+
+} /* end of zdd_group_move */
+
+
+/**Function********************************************************************
+
+ Synopsis [Undoes the swap of two groups.]
+
+ Description [Undoes the swap of two groups. x is assumed to be the
+ bottom variable of the first group. y is assumed to be the top
+ variable of the second group. Returns 1 if successful; 0 otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+zdd_group_move_backward(
+ DdManager * table,
+ int x,
+ int y)
+{
+ int size;
+ int i, temp, gxtop, gxbot, gytop, gybot, yprev;
+
+#ifdef DD_DEBUG
+ assert(x < y); /* we assume that x < y */
+#endif
+ /* Find top and bottom of the two groups. */
+ gxtop = table->subtableZ[x].next;
+ gytop = y;
+ gxbot = x;
+ gybot = table->subtableZ[y].next;
+ while (table->subtableZ[gybot].next != (unsigned) y)
+ gybot = table->subtableZ[gybot].next;
+ yprev = gybot;
+
+ while (x <= y) {
+ while (y > gxtop) {
+ /* Set correct symmetries. */
+ temp = table->subtableZ[x].next;
+ if (temp == x)
+ temp = y;
+ i = gxtop;
+ for (;;) {
+ if (table->subtableZ[i].next == (unsigned) x) {
+ table->subtableZ[i].next = y;
+ break;
+ } else {
+ i = table->subtableZ[i].next;
+ }
+ }
+ if (table->subtableZ[y].next != (unsigned) y) {
+ table->subtableZ[x].next = table->subtableZ[y].next;
+ } else {
+ table->subtableZ[x].next = x;
+ }
+
+ if (yprev != y) {
+ table->subtableZ[yprev].next = x;
+ } else {
+ yprev = x;
+ }
+ table->subtableZ[y].next = temp;
+
+ size = cuddZddSwapInPlace(table, x, y);
+ if (size == 0)
+ return(0);
+ y = x;
+ x--;
+ } /* while y > gxtop */
+
+ /* Trying to find the next y. */
+ if (table->subtableZ[y].next <= (unsigned) y) {
+ gybot = y;
+ } else {
+ y = table->subtableZ[y].next;
+ }
+
+ yprev = gxtop;
+ gxtop++;
+ gxbot++;
+ x = gxbot;
+ } /* while x <= y, end of group movement backward */
+
+ return(size);
+
+} /* end of zdd_group_move_backward */
+
+
+/**Function********************************************************************
+
+ Synopsis [Counts numbers of symmetric variables and symmetry
+ groups.]
+
+ Description []
+
+ SideEffects [None]
+
+******************************************************************************/
+static void
+cuddZddSymmSummary(
+ DdManager * table,
+ int lower,
+ int upper,
+ int * symvars,
+ int * symgroups)
+{
+ int i,x,gbot;
+ int TotalSymm = 0;
+ int TotalSymmGroups = 0;
+
+ for (i = lower; i <= upper; i++) {
+ if (table->subtableZ[i].next != (unsigned) i) {
+ TotalSymmGroups++;
+ x = i;
+ do {
+ TotalSymm++;
+ gbot = x;
+ x = table->subtableZ[x].next;
+ } while (x != i);
+#ifdef DD_DEBUG
+ assert(table->subtableZ[gbot].next == (unsigned) i);
+#endif
+ i = gbot;
+ }
+ }
+ *symvars = TotalSymm;
+ *symgroups = TotalSymmGroups;
+
+ return;
+
+} /* end of cuddZddSymmSummary */
+