diff options
author | Alan Mishchenko <alanmi@berkeley.edu> | 2007-09-30 08:01:00 -0700 |
---|---|---|
committer | Alan Mishchenko <alanmi@berkeley.edu> | 2007-09-30 08:01:00 -0700 |
commit | e54d9691616b9a0326e2fdb3156bb4eeb8abfcd7 (patch) | |
tree | de3ffe87c3e17950351e3b7d97fa18318bd5ea9a /src/bdd/cudd/cuddGroup.c | |
parent | 7d7e60f2dc84393cd4c5db22d2eaf7b1fb1a79b2 (diff) | |
download | abc-e54d9691616b9a0326e2fdb3156bb4eeb8abfcd7.tar.gz abc-e54d9691616b9a0326e2fdb3156bb4eeb8abfcd7.tar.bz2 abc-e54d9691616b9a0326e2fdb3156bb4eeb8abfcd7.zip |
Version abc70930
Diffstat (limited to 'src/bdd/cudd/cuddGroup.c')
-rw-r--r-- | src/bdd/cudd/cuddGroup.c | 2142 |
1 files changed, 0 insertions, 2142 deletions
diff --git a/src/bdd/cudd/cuddGroup.c b/src/bdd/cudd/cuddGroup.c deleted file mode 100644 index 81c05d2c..00000000 --- a/src/bdd/cudd/cuddGroup.c +++ /dev/null @@ -1,2142 +0,0 @@ -/**CFile*********************************************************************** - - FileName [cuddGroup.c] - - PackageName [cudd] - - Synopsis [Functions for group sifting.] - - Description [External procedures included in this file: - <ul> - <li> Cudd_MakeTreeNode() - </ul> - Internal procedures included in this file: - <ul> - <li> cuddTreeSifting() - </ul> - Static procedures included in this module: - <ul> - <li> ddTreeSiftingAux() - <li> ddCountInternalMtrNodes() - <li> ddReorderChildren() - <li> ddFindNodeHiLo() - <li> ddUniqueCompareGroup() - <li> ddGroupSifting() - <li> ddCreateGroup() - <li> ddGroupSiftingAux() - <li> ddGroupSiftingUp() - <li> ddGroupSiftingDown() - <li> ddGroupMove() - <li> ddGroupMoveBackward() - <li> ddGroupSiftingBackward() - <li> ddMergeGroups() - <li> ddDissolveGroup() - <li> ddNoCheck() - <li> ddSecDiffCheck() - <li> ddExtSymmCheck() - <li> ddVarGroupCheck() - <li> ddSetVarHandled() - <li> ddResetVarHandled() - <li> ddIsVarHandled() - </ul>] - - Author [Shipra Panda, Fabio Somenzi] - - 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 */ -/*---------------------------------------------------------------------------*/ - -/* Constants for lazy sifting */ -#define DD_NORMAL_SIFT 0 -#define DD_LAZY_SIFT 1 - -/* Constants for sifting up and down */ -#define DD_SIFT_DOWN 0 -#define DD_SIFT_UP 1 - -/*---------------------------------------------------------------------------*/ -/* Stucture declarations */ -/*---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------*/ -/* Type declarations */ -/*---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------*/ -/* Variable declarations */ -/*---------------------------------------------------------------------------*/ - -#ifndef lint -static char rcsid[] DD_UNUSED = "$Id: cuddGroup.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $"; -#endif - -static int *entry; -extern int ddTotalNumberSwapping; -#ifdef DD_STATS -extern int ddTotalNISwaps; -static int extsymmcalls; -static int extsymm; -static int secdiffcalls; -static int secdiff; -static int secdiffmisfire; -#endif -#ifdef DD_DEBUG -static int pr = 0; /* flag to enable printing while debugging */ - /* by depositing a 1 into it */ -#endif -static int originalSize; -static int originalLevel; - -/*---------------------------------------------------------------------------*/ -/* Macro declarations */ -/*---------------------------------------------------------------------------*/ - -/**AutomaticStart*************************************************************/ - -/*---------------------------------------------------------------------------*/ -/* Static function prototypes */ -/*---------------------------------------------------------------------------*/ - -static int ddTreeSiftingAux ARGS((DdManager *table, MtrNode *treenode, Cudd_ReorderingType method)); -#ifdef DD_STATS -static int ddCountInternalMtrNodes ARGS((DdManager *table, MtrNode *treenode)); -#endif -static int ddReorderChildren ARGS((DdManager *table, MtrNode *treenode, Cudd_ReorderingType method)); -static void ddFindNodeHiLo ARGS((DdManager *table, MtrNode *treenode, int *lower, int *upper)); -static int ddUniqueCompareGroup ARGS((int *ptrX, int *ptrY)); -static int ddGroupSifting ARGS((DdManager *table, int lower, int upper, int (*checkFunction)(DdManager *, int, int), int lazyFlag)); -static void ddCreateGroup ARGS((DdManager *table, int x, int y)); -static int ddGroupSiftingAux ARGS((DdManager *table, int x, int xLow, int xHigh, int (*checkFunction)(DdManager *, int, int), int lazyFlag)); -static int ddGroupSiftingUp ARGS((DdManager *table, int y, int xLow, int (*checkFunction)(DdManager *, int, int), Move **moves)); -static int ddGroupSiftingDown ARGS((DdManager *table, int x, int xHigh, int (*checkFunction)(DdManager *, int, int), Move **moves)); -static int ddGroupMove ARGS((DdManager *table, int x, int y, Move **moves)); -static int ddGroupMoveBackward ARGS((DdManager *table, int x, int y)); -static int ddGroupSiftingBackward ARGS((DdManager *table, Move *moves, int size, int upFlag, int lazyFlag)); -static void ddMergeGroups ARGS((DdManager *table, MtrNode *treenode, int low, int high)); -static void ddDissolveGroup ARGS((DdManager *table, int x, int y)); -static int ddNoCheck ARGS((DdManager *table, int x, int y)); -static int ddSecDiffCheck ARGS((DdManager *table, int x, int y)); -static int ddExtSymmCheck ARGS((DdManager *table, int x, int y)); -static int ddVarGroupCheck ARGS((DdManager * table, int x, int y)); -static int ddSetVarHandled ARGS((DdManager *dd, int index)); -static int ddResetVarHandled ARGS((DdManager *dd, int index)); -static int ddIsVarHandled ARGS((DdManager *dd, int index)); - -/**AutomaticEnd***************************************************************/ - - -/*---------------------------------------------------------------------------*/ -/* Definition of exported functions */ -/*---------------------------------------------------------------------------*/ - - -/**Function******************************************************************** - - Synopsis [Creates a new variable group.] - - Description [Creates a new variable group. The group starts at - variable and contains size variables. The parameter low is the index - of the first variable. If the variable already exists, its current - position in the order is known to the manager. If the variable does - not exist yet, the position is assumed to be the same as the index. - The group tree is created if it does not exist yet. - Returns a pointer to the group if successful; NULL otherwise.] - - SideEffects [The variable tree is changed.] - - SeeAlso [Cudd_MakeZddTreeNode] - -******************************************************************************/ -MtrNode * -Cudd_MakeTreeNode( - DdManager * dd /* manager */, - unsigned int low /* index of the first group variable */, - unsigned int size /* number of variables in the group */, - unsigned int type /* MTR_DEFAULT or MTR_FIXED */) -{ - MtrNode *group; - MtrNode *tree; - unsigned int level; - - /* If the variable does not exist yet, the position is assumed to be - ** the same as the index. Therefore, applications that rely on - ** Cudd_bddNewVarAtLevel or Cudd_addNewVarAtLevel to create new - ** variables have to create the variables before they group them. - */ - level = (low < (unsigned int) dd->size) ? dd->perm[low] : low; - - if (level + size - 1> (int) MTR_MAXHIGH) - return(NULL); - - /* If the tree does not exist yet, create it. */ - tree = dd->tree; - if (tree == NULL) { - dd->tree = tree = Mtr_InitGroupTree(0, dd->size); - if (tree == NULL) - return(NULL); - tree->index = dd->invperm[0]; - } - - /* Extend the upper bound of the tree if necessary. This allows the - ** application to create groups even before the variables are created. - */ - tree->size = ddMax(tree->size, ddMax(level + size, (unsigned) dd->size)); - - /* Create the group. */ - group = Mtr_MakeGroup(tree, level, size, type); - if (group == NULL) - return(NULL); - - /* Initialize the index field to the index of the variable currently - ** in position low. This field will be updated by the reordering - ** procedure to provide a handle to the group once it has been moved. - */ - group->index = (MtrHalfWord) low; - - return(group); - -} /* end of Cudd_MakeTreeNode */ - - -/*---------------------------------------------------------------------------*/ -/* Definition of internal functions */ -/*---------------------------------------------------------------------------*/ - - -/**Function******************************************************************** - - Synopsis [Tree sifting algorithm.] - - Description [Tree sifting algorithm. Assumes that a tree representing - a group hierarchy is passed as a parameter. It then reorders each - group in postorder fashion by calling ddTreeSiftingAux. Assumes that - no dead nodes are present. Returns 1 if successful; 0 otherwise.] - - SideEffects [None] - -******************************************************************************/ -int -cuddTreeSifting( - DdManager * table /* DD table */, - Cudd_ReorderingType method /* reordering method for the groups of leaves */) -{ - int i; - int nvars; - int result; - int tempTree; - - /* If no tree is provided we create a temporary one in which all - ** variables are in a single group. After reordering this tree is - ** destroyed. - */ - tempTree = table->tree == NULL; - if (tempTree) { - table->tree = Mtr_InitGroupTree(0,table->size); - table->tree->index = table->invperm[0]; - } - nvars = table->size; - -#ifdef DD_DEBUG - if (pr > 0 && !tempTree) (void) fprintf(table->out,"cuddTreeSifting:"); - Mtr_PrintGroups(table->tree,pr <= 0); -#endif - -#ifdef DD_STATS - extsymmcalls = 0; - extsymm = 0; - secdiffcalls = 0; - secdiff = 0; - secdiffmisfire = 0; - - (void) fprintf(table->out,"\n"); - if (!tempTree) - (void) fprintf(table->out,"#:IM_NODES %8d: group tree nodes\n", - ddCountInternalMtrNodes(table,table->tree)); -#endif - - /* Initialize the group of each subtable to itself. Initially - ** there are no groups. Groups are created according to the tree - ** structure in postorder fashion. - */ - for (i = 0; i < nvars; i++) - table->subtables[i].next = i; - - - /* Reorder. */ - result = ddTreeSiftingAux(table, table->tree, method); - -#ifdef DD_STATS /* print stats */ - if (!tempTree && method == CUDD_REORDER_GROUP_SIFT && - (table->groupcheck == CUDD_GROUP_CHECK7 || - table->groupcheck == CUDD_GROUP_CHECK5)) { - (void) fprintf(table->out,"\nextsymmcalls = %d\n",extsymmcalls); - (void) fprintf(table->out,"extsymm = %d",extsymm); - } - if (!tempTree && method == CUDD_REORDER_GROUP_SIFT && - table->groupcheck == CUDD_GROUP_CHECK7) { - (void) fprintf(table->out,"\nsecdiffcalls = %d\n",secdiffcalls); - (void) fprintf(table->out,"secdiff = %d\n",secdiff); - (void) fprintf(table->out,"secdiffmisfire = %d",secdiffmisfire); - } -#endif - - if (tempTree) - Cudd_FreeTree(table); - return(result); - -} /* end of cuddTreeSifting */ - - -/*---------------------------------------------------------------------------*/ -/* Definition of static functions */ -/*---------------------------------------------------------------------------*/ - - -/**Function******************************************************************** - - Synopsis [Visits the group tree and reorders each group.] - - Description [Recursively visits the group tree and reorders each - group in postorder fashion. Returns 1 if successful; 0 otherwise.] - - SideEffects [None] - -******************************************************************************/ -static int -ddTreeSiftingAux( - DdManager * table, - MtrNode * treenode, - Cudd_ReorderingType method) -{ - MtrNode *auxnode; - int res; - Cudd_AggregationType saveCheck; - -#ifdef DD_DEBUG - Mtr_PrintGroups(treenode,1); -#endif - - auxnode = treenode; - while (auxnode != NULL) { - if (auxnode->child != NULL) { - if (!ddTreeSiftingAux(table, auxnode->child, method)) - return(0); - saveCheck = table->groupcheck; - table->groupcheck = CUDD_NO_CHECK; - if (method != CUDD_REORDER_LAZY_SIFT) - res = ddReorderChildren(table, auxnode, CUDD_REORDER_GROUP_SIFT); - else - res = ddReorderChildren(table, auxnode, CUDD_REORDER_LAZY_SIFT); - table->groupcheck = saveCheck; - - if (res == 0) - return(0); - } else if (auxnode->size > 1) { - if (!ddReorderChildren(table, auxnode, method)) - return(0); - } - auxnode = auxnode->younger; - } - - return(1); - -} /* end of ddTreeSiftingAux */ - - -#ifdef DD_STATS -/**Function******************************************************************** - - Synopsis [Counts the number of internal nodes of the group tree.] - - Description [Counts the number of internal nodes of the group tree. - Returns the count.] - - SideEffects [None] - -******************************************************************************/ -static int -ddCountInternalMtrNodes( - DdManager * table, - MtrNode * treenode) -{ - MtrNode *auxnode; - int count,nodeCount; - - - nodeCount = 0; - auxnode = treenode; - while (auxnode != NULL) { - if (!(MTR_TEST(auxnode,MTR_TERMINAL))) { - nodeCount++; - count = ddCountInternalMtrNodes(table,auxnode->child); - nodeCount += count; - } - auxnode = auxnode->younger; - } - - return(nodeCount); - -} /* end of ddCountInternalMtrNodes */ -#endif - - -/**Function******************************************************************** - - Synopsis [Reorders the children of a group tree node according to - the options.] - - Description [Reorders the children of a group tree node according to - the options. After reordering puts all the variables in the group - and/or its descendents in a single group. This allows hierarchical - reordering. If the variables in the group do not exist yet, simply - does nothing. Returns 1 if successful; 0 otherwise.] - - SideEffects [None] - -******************************************************************************/ -static int -ddReorderChildren( - DdManager * table, - MtrNode * treenode, - Cudd_ReorderingType method) -{ - int lower; - int upper; - int result; - unsigned int initialSize; - - ddFindNodeHiLo(table,treenode,&lower,&upper); - /* If upper == -1 these variables do not exist yet. */ - if (upper == -1) - return(1); - - if (treenode->flags == MTR_FIXED) { - result = 1; - } else { -#ifdef DD_STATS - (void) fprintf(table->out," "); -#endif - switch (method) { - case CUDD_REORDER_RANDOM: - case CUDD_REORDER_RANDOM_PIVOT: - result = cuddSwapping(table,lower,upper,method); - break; - case CUDD_REORDER_SIFT: - result = cuddSifting(table,lower,upper); - break; - case CUDD_REORDER_SIFT_CONVERGE: - do { - initialSize = table->keys - table->isolated; - result = cuddSifting(table,lower,upper); - if (initialSize <= table->keys - table->isolated) - break; -#ifdef DD_STATS - else - (void) fprintf(table->out,"\n"); -#endif - } while (result != 0); - break; - case CUDD_REORDER_SYMM_SIFT: - result = cuddSymmSifting(table,lower,upper); - break; - case CUDD_REORDER_SYMM_SIFT_CONV: - result = cuddSymmSiftingConv(table,lower,upper); - break; - case CUDD_REORDER_GROUP_SIFT: - if (table->groupcheck == CUDD_NO_CHECK) { - result = ddGroupSifting(table,lower,upper,ddNoCheck, - DD_NORMAL_SIFT); - } else if (table->groupcheck == CUDD_GROUP_CHECK5) { - result = ddGroupSifting(table,lower,upper,ddExtSymmCheck, - DD_NORMAL_SIFT); - } else if (table->groupcheck == CUDD_GROUP_CHECK7) { - result = ddGroupSifting(table,lower,upper,ddExtSymmCheck, - DD_NORMAL_SIFT); - } else { - (void) fprintf(table->err, - "Unknown group ckecking method\n"); - result = 0; - } - break; - case CUDD_REORDER_GROUP_SIFT_CONV: - do { - initialSize = table->keys - table->isolated; - if (table->groupcheck == CUDD_NO_CHECK) { - result = ddGroupSifting(table,lower,upper,ddNoCheck, - DD_NORMAL_SIFT); - } else if (table->groupcheck == CUDD_GROUP_CHECK5) { - result = ddGroupSifting(table,lower,upper,ddExtSymmCheck, - DD_NORMAL_SIFT); - } else if (table->groupcheck == CUDD_GROUP_CHECK7) { - result = ddGroupSifting(table,lower,upper,ddExtSymmCheck, - DD_NORMAL_SIFT); - } else { - (void) fprintf(table->err, - "Unknown group ckecking method\n"); - result = 0; - } -#ifdef DD_STATS - (void) fprintf(table->out,"\n"); -#endif - result = cuddWindowReorder(table,lower,upper, - CUDD_REORDER_WINDOW4); - if (initialSize <= table->keys - table->isolated) - break; -#ifdef DD_STATS - else - (void) fprintf(table->out,"\n"); -#endif - } while (result != 0); - break; - case CUDD_REORDER_WINDOW2: - case CUDD_REORDER_WINDOW3: - case CUDD_REORDER_WINDOW4: - case CUDD_REORDER_WINDOW2_CONV: - case CUDD_REORDER_WINDOW3_CONV: - case CUDD_REORDER_WINDOW4_CONV: - result = cuddWindowReorder(table,lower,upper,method); - break; - case CUDD_REORDER_ANNEALING: - result = cuddAnnealing(table,lower,upper); - break; - case CUDD_REORDER_GENETIC: - result = cuddGa(table,lower,upper); - break; - case CUDD_REORDER_LINEAR: - result = cuddLinearAndSifting(table,lower,upper); - break; - case CUDD_REORDER_LINEAR_CONVERGE: - do { - initialSize = table->keys - table->isolated; - result = cuddLinearAndSifting(table,lower,upper); - if (initialSize <= table->keys - table->isolated) - break; -#ifdef DD_STATS - else - (void) fprintf(table->out,"\n"); -#endif - } while (result != 0); - break; - case CUDD_REORDER_EXACT: - result = cuddExact(table,lower,upper); - break; - case CUDD_REORDER_LAZY_SIFT: - result = ddGroupSifting(table,lower,upper,ddVarGroupCheck, - DD_LAZY_SIFT); - break; - default: - return(0); - } - } - - /* Create a single group for all the variables that were sifted, - ** so that they will be treated as a single block by successive - ** invocations of ddGroupSifting. - */ - ddMergeGroups(table,treenode,lower,upper); - -#ifdef DD_DEBUG - if (pr > 0) (void) fprintf(table->out,"ddReorderChildren:"); -#endif - - return(result); - -} /* end of ddReorderChildren */ - - -/**Function******************************************************************** - - Synopsis [Finds the lower and upper bounds of the group represented - by treenode.] - - Description [Finds the lower and upper bounds of the group - represented by treenode. From the index and size fields we need to - derive the current positions, and find maximum and minimum.] - - SideEffects [The bounds are returned as side effects.] - - SeeAlso [] - -******************************************************************************/ -static void -ddFindNodeHiLo( - DdManager * table, - MtrNode * treenode, - int * lower, - int * upper) -{ - int low; - int high; - - /* Check whether no variables in this group already exist. - ** If so, return immediately. The calling procedure will know from - ** the values of upper that no reordering is needed. - */ - if ((int) treenode->low >= table->size) { - *lower = table->size; - *upper = -1; - return; - } - - *lower = low = (unsigned int) table->perm[treenode->index]; - high = (int) (low + treenode->size - 1); - - if (high >= table->size) { - /* This is the case of a partially existing group. The aim is to - ** reorder as many variables as safely possible. If the tree - ** node is terminal, we just reorder the subset of the group - ** that is currently in existence. If the group has - ** subgroups, then we only reorder those subgroups that are - ** fully instantiated. This way we avoid breaking up a group. - */ - MtrNode *auxnode = treenode->child; - if (auxnode == NULL) { - *upper = (unsigned int) table->size - 1; - } else { - /* Search the subgroup that strands the table->size line. - ** If the first group starts at 0 and goes past table->size - ** upper will get -1, thus correctly signaling that no reordering - ** should take place. - */ - while (auxnode != NULL) { - int thisLower = table->perm[auxnode->low]; - int thisUpper = thisLower + auxnode->size - 1; - if (thisUpper >= table->size && thisLower < table->size) - *upper = (unsigned int) thisLower - 1; - auxnode = auxnode->younger; - } - } - } else { - /* Normal case: All the variables of the group exist. */ - *upper = (unsigned int) high; - } - -#ifdef DD_DEBUG - /* Make sure that all variables in group are contiguous. */ - assert(treenode->size >= *upper - *lower + 1); -#endif - - return; - -} /* end of ddFindNodeHiLo */ - - -/**Function******************************************************************** - - Synopsis [Comparison function used by qsort.] - - Description [Comparison function used by qsort to order the variables - according to the number of keys in the subtables. Returns the - difference in number of keys between the two variables being - compared.] - - SideEffects [None] - -******************************************************************************/ -static int -ddUniqueCompareGroup( - int * ptrX, - int * ptrY) -{ -#if 0 - if (entry[*ptrY] == entry[*ptrX]) { - return((*ptrX) - (*ptrY)); - } -#endif - return(entry[*ptrY] - entry[*ptrX]); - -} /* end of ddUniqueCompareGroup */ - - -/**Function******************************************************************** - - Synopsis [Sifts from treenode->low to treenode->high.] - - Description [Sifts from treenode->low to treenode->high. If - croupcheck == CUDD_GROUP_CHECK7, it checks for group creation at the - end of the initial sifting. If a group is created, it is then sifted - again. After sifting one variable, the group that contains it is - dissolved. Returns 1 in case of success; 0 otherwise.] - - SideEffects [None] - -******************************************************************************/ -static int -ddGroupSifting( - DdManager * table, - int lower, - int upper, - int (*checkFunction)(DdManager *, int, int), - int lazyFlag) -{ - int *var; - int i,j,x,xInit; - int nvars; - int classes; - int result; - int *sifted; - int merged; - int dissolve; -#ifdef DD_STATS - unsigned previousSize; -#endif - int xindex; - - nvars = table->size; - - /* Order variables to sift. */ - entry = NULL; - sifted = NULL; - var = ALLOC(int,nvars); - if (var == NULL) { - table->errorCode = CUDD_MEMORY_OUT; - goto ddGroupSiftingOutOfMem; - } - entry = ALLOC(int,nvars); - if (entry == NULL) { - table->errorCode = CUDD_MEMORY_OUT; - goto ddGroupSiftingOutOfMem; - } - sifted = ALLOC(int,nvars); - if (sifted == NULL) { - table->errorCode = CUDD_MEMORY_OUT; - goto ddGroupSiftingOutOfMem; - } - - /* Here we consider only one representative for each group. */ - for (i = 0, classes = 0; i < nvars; i++) { - sifted[i] = 0; - x = table->perm[i]; - if ((unsigned) x >= table->subtables[x].next) { - entry[i] = table->subtables[x].keys; - var[classes] = i; - classes++; - } - } - - qsort((void *)var,classes,sizeof(int), - (int (*)(const void *, const void *)) ddUniqueCompareGroup); - - if (lazyFlag) { - for (i = 0; i < nvars; i ++) { - ddResetVarHandled(table, i); - } - } - - /* Now sift. */ - for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) { - if (ddTotalNumberSwapping >= table->siftMaxSwap) - break; - xindex = var[i]; - if (sifted[xindex] == 1) /* variable already sifted as part of group */ - continue; - x = table->perm[xindex]; /* find current level of this variable */ - - if (x < lower || x > upper || table->subtables[x].bindVar == 1) - continue; -#ifdef DD_STATS - previousSize = table->keys - table->isolated; -#endif -#ifdef DD_DEBUG - /* x is bottom of group */ - assert((unsigned) x >= table->subtables[x].next); -#endif - if ((unsigned) x == table->subtables[x].next) { - dissolve = 1; - result = ddGroupSiftingAux(table,x,lower,upper,checkFunction, - lazyFlag); - } else { - dissolve = 0; - result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag); - } - if (!result) goto ddGroupSiftingOutOfMem; - - /* check for aggregation */ - merged = 0; - if (lazyFlag == 0 && table->groupcheck == CUDD_GROUP_CHECK7) { - x = table->perm[xindex]; /* find current level */ - if ((unsigned) x == table->subtables[x].next) { /* not part of a group */ - if (x != upper && sifted[table->invperm[x+1]] == 0 && - (unsigned) x+1 == table->subtables[x+1].next) { - if (ddSecDiffCheck(table,x,x+1)) { - merged =1; - ddCreateGroup(table,x,x+1); - } - } - if (x != lower && sifted[table->invperm[x-1]] == 0 && - (unsigned) x-1 == table->subtables[x-1].next) { - if (ddSecDiffCheck(table,x-1,x)) { - merged =1; - ddCreateGroup(table,x-1,x); - } - } - } - } - - if (merged) { /* a group was created */ - /* move x to bottom of group */ - while ((unsigned) x < table->subtables[x].next) - x = table->subtables[x].next; - /* sift */ - result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag); - if (!result) goto ddGroupSiftingOutOfMem; -#ifdef DD_STATS - if (table->keys < previousSize + table->isolated) { - (void) fprintf(table->out,"_"); - } else if (table->keys > previousSize + table->isolated) { - (void) fprintf(table->out,"^"); - } else { - (void) fprintf(table->out,"*"); - } - fflush(table->out); - } else { - if (table->keys < previousSize + table->isolated) { - (void) fprintf(table->out,"-"); - } else if (table->keys > previousSize + table->isolated) { - (void) fprintf(table->out,"+"); - } else { - (void) fprintf(table->out,"="); - } - fflush(table->out); -#endif - } - - /* Mark variables in the group just sifted. */ - x = table->perm[xindex]; - if ((unsigned) x != table->subtables[x].next) { - xInit = x; - do { - j = table->invperm[x]; - sifted[j] = 1; - x = table->subtables[x].next; - } while (x != xInit); - - /* Dissolve the group if it was created. */ - if (lazyFlag == 0 && dissolve) { - do { - j = table->subtables[x].next; - table->subtables[x].next = x; - x = j; - } while (x != xInit); - } - } - -#ifdef DD_DEBUG - if (pr > 0) (void) fprintf(table->out,"ddGroupSifting:"); -#endif - - if (lazyFlag) ddSetVarHandled(table, xindex); - } /* for */ - - FREE(sifted); - FREE(var); - FREE(entry); - - return(1); - -ddGroupSiftingOutOfMem: - if (entry != NULL) FREE(entry); - if (var != NULL) FREE(var); - if (sifted != NULL) FREE(sifted); - - return(0); - -} /* end of ddGroupSifting */ - - -/**Function******************************************************************** - - Synopsis [Creates a group encompassing variables from x to y in the - DD table.] - - Description [Creates a group encompassing variables from x to y in the - DD table. In the current implementation it must be y == x+1. - Returns 1 in case of success; 0 otherwise.] - - SideEffects [None] - -******************************************************************************/ -static void -ddCreateGroup( - DdManager * table, - int x, - int y) -{ - int gybot; - -#ifdef DD_DEBUG - assert(y == x+1); -#endif - - /* Find bottom of second group. */ - gybot = y; - while ((unsigned) gybot < table->subtables[gybot].next) - gybot = table->subtables[gybot].next; - - /* Link groups. */ - table->subtables[x].next = y; - table->subtables[gybot].next = x; - - return; - -} /* ddCreateGroup */ - - -/**Function******************************************************************** - - Synopsis [Sifts one variable up and down until it has taken all - positions. Checks for aggregation.] - - Description [Sifts one variable up and down until it has taken all - positions. Checks for aggregation. There may be at most two sweeps, - even if the group grows. Assumes that x is either an isolated - variable, or it is the bottom of a group. All groups may not have - been found. The variable being moved is returned to the best position - seen during sifting. Returns 1 in case of success; 0 otherwise.] - - SideEffects [None] - -******************************************************************************/ -static int -ddGroupSiftingAux( - DdManager * table, - int x, - int xLow, - int xHigh, - int (*checkFunction)(DdManager *, int, int), - int lazyFlag) -{ - Move *move; - Move *moves; /* list of moves */ - int initialSize; - int result; - int y; - int topbot; - -#ifdef DD_DEBUG - if (pr > 0) (void) fprintf(table->out, - "ddGroupSiftingAux from %d to %d\n",xLow,xHigh); - assert((unsigned) x >= table->subtables[x].next); /* x is bottom of group */ -#endif - - initialSize = table->keys - table->isolated; - moves = NULL; - - originalSize = initialSize; /* for lazy sifting */ - - /* If we have a singleton, we check for aggregation in both - ** directions before we sift. - */ - if ((unsigned) x == table->subtables[x].next) { - /* Will go down first, unless x == xHigh: - ** Look for aggregation above x. - */ - for (y = x; y > xLow; y--) { - if (!checkFunction(table,y-1,y)) - break; - topbot = table->subtables[y-1].next; /* find top of y-1's group */ - table->subtables[y-1].next = y; - table->subtables[x].next = topbot; /* x is bottom of group so its */ - /* next is top of y-1's group */ - y = topbot + 1; /* add 1 for y--; new y is top of group */ - } - /* Will go up first unless x == xlow: - ** Look for aggregation below x. - */ - for (y = x; y < xHigh; y++) { - if (!checkFunction(table,y,y+1)) - break; - /* find bottom of y+1's group */ - topbot = y + 1; - while ((unsigned) topbot < table->subtables[topbot].next) { - topbot = table->subtables[topbot].next; - } - table->subtables[topbot].next = table->subtables[y].next; - table->subtables[y].next = y + 1; - y = topbot - 1; /* subtract 1 for y++; new y is bottom of group */ - } - } - - /* Now x may be in the middle of a group. - ** Find bottom of x's group. - */ - while ((unsigned) x < table->subtables[x].next) - x = table->subtables[x].next; - - originalLevel = x; /* for lazy sifting */ - - if (x == xLow) { /* Sift down */ -#ifdef DD_DEBUG - /* x must be a singleton */ - assert((unsigned) x == table->subtables[x].next); -#endif - if (x == xHigh) return(1); /* just one variable */ - - if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves)) - goto ddGroupSiftingAuxOutOfMem; - /* at this point x == xHigh, unless early term */ - - /* move backward and stop at best position */ - result = ddGroupSiftingBackward(table,moves,initialSize, - DD_SIFT_DOWN,lazyFlag); -#ifdef DD_DEBUG - assert(table->keys - table->isolated <= (unsigned) initialSize); -#endif - if (!result) goto ddGroupSiftingAuxOutOfMem; - - } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */ -#ifdef DD_DEBUG - /* x is bottom of group */ - assert((unsigned) x >= table->subtables[x].next); -#endif - /* Find top of x's group */ - x = table->subtables[x].next; - - if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves)) - goto ddGroupSiftingAuxOutOfMem; - /* at this point x == xLow, unless early term */ - - /* move backward and stop at best position */ - result = ddGroupSiftingBackward(table,moves,initialSize, - DD_SIFT_UP,lazyFlag); -#ifdef DD_DEBUG - assert(table->keys - table->isolated <= (unsigned) initialSize); -#endif - if (!result) goto ddGroupSiftingAuxOutOfMem; - - } else if (x - xLow > xHigh - x) { /* must go down first: shorter */ - if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves)) - goto ddGroupSiftingAuxOutOfMem; - /* at this point x == xHigh, unless early term */ - - /* Find top of group */ - if (moves) { - x = moves->y; - } - while ((unsigned) x < table->subtables[x].next) - x = table->subtables[x].next; - x = table->subtables[x].next; -#ifdef DD_DEBUG - /* x should be the top of a group */ - assert((unsigned) x <= table->subtables[x].next); -#endif - - if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves)) - goto ddGroupSiftingAuxOutOfMem; - - /* move backward and stop at best position */ - result = ddGroupSiftingBackward(table,moves,initialSize, - DD_SIFT_UP,lazyFlag); -#ifdef DD_DEBUG - assert(table->keys - table->isolated <= (unsigned) initialSize); -#endif - if (!result) goto ddGroupSiftingAuxOutOfMem; - - } else { /* moving up first: shorter */ - /* Find top of x's group */ - x = table->subtables[x].next; - - if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves)) - goto ddGroupSiftingAuxOutOfMem; - /* at this point x == xHigh, unless early term */ - - if (moves) { - x = moves->x; - } - while ((unsigned) x < table->subtables[x].next) - x = table->subtables[x].next; -#ifdef DD_DEBUG - /* x is bottom of a group */ - assert((unsigned) x >= table->subtables[x].next); -#endif - - if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves)) - goto ddGroupSiftingAuxOutOfMem; - - /* move backward and stop at best position */ - result = ddGroupSiftingBackward(table,moves,initialSize, - DD_SIFT_DOWN,lazyFlag); -#ifdef DD_DEBUG - assert(table->keys - table->isolated <= (unsigned) initialSize); -#endif - if (!result) goto ddGroupSiftingAuxOutOfMem; - } - - while (moves != NULL) { - move = moves->next; - cuddDeallocNode(table, (DdNode *) moves); - moves = move; - } - - return(1); - -ddGroupSiftingAuxOutOfMem: - while (moves != NULL) { - move = moves->next; - cuddDeallocNode(table, (DdNode *) moves); - moves = move; - } - - return(0); - -} /* end of ddGroupSiftingAux */ - - -/**Function******************************************************************** - - Synopsis [Sifts up a variable until either it reaches position xLow - or the size of the DD heap increases too much.] - - Description [Sifts up a variable until either it reaches position - xLow or the size of the DD heap increases too much. Assumes that y is - the top of a group (or a singleton). Checks y for aggregation to the - adjacent variables. Records all the moves that are appended to the - list of moves received as input and returned as a side effect. - Returns 1 in case of success; 0 otherwise.] - - SideEffects [None] - -******************************************************************************/ -static int -ddGroupSiftingUp( - DdManager * table, - int y, - int xLow, - int (*checkFunction)(DdManager *, int, int), - Move ** moves) -{ - Move *move; - int x; - int size; - int i; - int gxtop,gybot; - int limitSize; - int xindex, yindex; - int zindex; - int z; - int isolated; - int L; /* lower bound on DD size */ -#ifdef DD_DEBUG - int checkL; -#endif - - yindex = table->invperm[y]; - - /* Initialize the lower bound. - ** The part of the DD below the bottom of y's group will not change. - ** The part of the DD above y that does not interact with any - ** variable of y's group will not change. - ** The rest may vanish in the best case, except for - ** the nodes at level xLow, which will not vanish, regardless. - ** What we use here is not really a lower bound, because we ignore - ** the interactions with all variables except y. - */ - limitSize = L = table->keys - table->isolated; - gybot = y; - while ((unsigned) gybot < table->subtables[gybot].next) - gybot = table->subtables[gybot].next; - for (z = xLow + 1; z <= gybot; z++) { - zindex = table->invperm[z]; - if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) { - isolated = table->vars[zindex]->ref == 1; - L -= table->subtables[z].keys - isolated; - } - } - - originalLevel = y; /* for lazy sifting */ - - x = cuddNextLow(table,y); - while (x >= xLow && L <= limitSize) { -#ifdef DD_DEBUG - gybot = y; - while ((unsigned) gybot < table->subtables[gybot].next) - gybot = table->subtables[gybot].next; - checkL = table->keys - table->isolated; - for (z = xLow + 1; z <= gybot; z++) { - zindex = table->invperm[z]; - if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) { - isolated = table->vars[zindex]->ref == 1; - checkL -= table->subtables[z].keys - isolated; - } - } - if (pr > 0 && L != checkL) { - (void) fprintf(table->out, - "Inaccurate lower bound: L = %d checkL = %d\n", - L, checkL); - } -#endif - gxtop = table->subtables[x].next; - if (checkFunction(table,x,y)) { - /* Group found, attach groups */ - table->subtables[x].next = y; - i = table->subtables[y].next; - while (table->subtables[i].next != (unsigned) y) - i = table->subtables[i].next; - table->subtables[i].next = gxtop; - move = (Move *)cuddDynamicAllocNode(table); - if (move == NULL) goto ddGroupSiftingUpOutOfMem; - move->x = x; - move->y = y; - move->flags = MTR_NEWNODE; - move->size = table->keys - table->isolated; - move->next = *moves; - *moves = move; - } else if (table->subtables[x].next == (unsigned) x && - table->subtables[y].next == (unsigned) y) { - /* x and y are self groups */ - xindex = table->invperm[x]; - size = cuddSwapInPlace(table,x,y); -#ifdef DD_DEBUG - assert(table->subtables[x].next == (unsigned) x); - assert(table->subtables[y].next == (unsigned) y); -#endif - if (size == 0) goto ddGroupSiftingUpOutOfMem; - /* Update the lower bound. */ - if (cuddTestInteract(table,xindex,yindex)) { - isolated = table->vars[xindex]->ref == 1; - L += table->subtables[y].keys - isolated; - } - move = (Move *)cuddDynamicAllocNode(table); - if (move == NULL) goto ddGroupSiftingUpOutOfMem; - move->x = x; - move->y = y; - move->flags = MTR_DEFAULT; - move->size = size; - move->next = *moves; - *moves = move; - -#ifdef DD_DEBUG - if (pr > 0) (void) fprintf(table->out, - "ddGroupSiftingUp (2 single groups):\n"); -#endif - if ((double) size > (double) limitSize * table->maxGrowth) - return(1); - if (size < limitSize) limitSize = size; - } else { /* Group move */ - size = ddGroupMove(table,x,y,moves); - if (size == 0) goto ddGroupSiftingUpOutOfMem; - /* Update the lower bound. */ - z = (*moves)->y; - do { - zindex = table->invperm[z]; - if (cuddTestInteract(table,zindex,yindex)) { - isolated = table->vars[zindex]->ref == 1; - L += table->subtables[z].keys - isolated; - } - z = table->subtables[z].next; - } while (z != (int) (*moves)->y); - if ((double) size > (double) limitSize * table->maxGrowth) - return(1); - if (size < limitSize) limitSize = size; - } - y = gxtop; - x = cuddNextLow(table,y); - } - - return(1); - -ddGroupSiftingUpOutOfMem: - while (*moves != NULL) { - move = (*moves)->next; - cuddDeallocNode(table, (DdNode *) *moves); - *moves = move; - } - return(0); - -} /* end of ddGroupSiftingUp */ - - -/**Function******************************************************************** - - Synopsis [Sifts down a variable until it reaches position xHigh.] - - Description [Sifts down a variable until it reaches position xHigh. - Assumes that x is the bottom of a group (or a singleton). Records - all the moves. Returns 1 in case of success; 0 otherwise.] - - SideEffects [None] - -******************************************************************************/ -static int -ddGroupSiftingDown( - DdManager * table, - int x, - int xHigh, - int (*checkFunction)(DdManager *, int, int), - Move ** moves) -{ - Move *move; - int y; - int size; - int limitSize; - int gxtop,gybot; - int R; /* upper bound on node decrease */ - int xindex, yindex; - int isolated, allVars; - int z; - int zindex; -#ifdef DD_DEBUG - int checkR; -#endif - - /* If the group consists of simple variables, there is no point in - ** sifting it down. This check is redundant if the projection functions - ** do not have external references, because the computation of the - ** lower bound takes care of the problem. It is necessary otherwise to - ** prevent the sifting down of simple variables. */ - y = x; - allVars = 1; - do { - if (table->subtables[y].keys != 1) { - allVars = 0; - break; - } - y = table->subtables[y].next; - } while (table->subtables[y].next != (unsigned) x); - if (allVars) - return(1); - - /* Initialize R. */ - xindex = table->invperm[x]; - gxtop = table->subtables[x].next; - limitSize = size = table->keys - table->isolated; - R = 0; - for (z = xHigh; z > gxtop; z--) { - zindex = table->invperm[z]; - if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) { - isolated = table->vars[zindex]->ref == 1; - R += table->subtables[z].keys - isolated; - } - } - - originalLevel = x; /* for lazy sifting */ - - y = cuddNextHigh(table,x); - while (y <= xHigh && size - R < limitSize) { -#ifdef DD_DEBUG - gxtop = table->subtables[x].next; - checkR = 0; - for (z = xHigh; z > gxtop; z--) { - zindex = table->invperm[z]; - if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) { - isolated = table->vars[zindex]->ref == 1; - checkR += table->subtables[z].keys - isolated; - } - } - assert(R >= checkR); -#endif - /* Find bottom of y group. */ - gybot = table->subtables[y].next; - while (table->subtables[gybot].next != (unsigned) y) - gybot = table->subtables[gybot].next; - - if (checkFunction(table,x,y)) { - /* Group found: attach groups and record move. */ - gxtop = table->subtables[x].next; - table->subtables[x].next = y; - table->subtables[gybot].next = gxtop; - move = (Move *)cuddDynamicAllocNode(table); - if (move == NULL) goto ddGroupSiftingDownOutOfMem; - move->x = x; - move->y = y; - move->flags = MTR_NEWNODE; - move->size = table->keys - table->isolated; - move->next = *moves; - *moves = move; - } else if (table->subtables[x].next == (unsigned) x && - table->subtables[y].next == (unsigned) y) { - /* x and y are self groups */ - /* Update upper bound on node decrease. */ - yindex = table->invperm[y]; - if (cuddTestInteract(table,xindex,yindex)) { - isolated = table->vars[yindex]->ref == 1; - R -= table->subtables[y].keys - isolated; - } - size = cuddSwapInPlace(table,x,y); -#ifdef DD_DEBUG - assert(table->subtables[x].next == (unsigned) x); - assert(table->subtables[y].next == (unsigned) y); -#endif - if (size == 0) goto ddGroupSiftingDownOutOfMem; - - /* Record move. */ - move = (Move *) cuddDynamicAllocNode(table); - if (move == NULL) goto ddGroupSiftingDownOutOfMem; - move->x = x; - move->y = y; - move->flags = MTR_DEFAULT; - move->size = size; - move->next = *moves; - *moves = move; - -#ifdef DD_DEBUG - if (pr > 0) (void) fprintf(table->out, - "ddGroupSiftingDown (2 single groups):\n"); -#endif - if ((double) size > (double) limitSize * table->maxGrowth) - return(1); - if (size < limitSize) limitSize = size; - - x = y; - y = cuddNextHigh(table,x); - } else { /* Group move */ - /* Update upper bound on node decrease: first phase. */ - gxtop = table->subtables[x].next; - z = gxtop + 1; - do { - zindex = table->invperm[z]; - if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) { - isolated = table->vars[zindex]->ref == 1; - R -= table->subtables[z].keys - isolated; - } - z++; - } while (z <= gybot); - size = ddGroupMove(table,x,y,moves); - if (size == 0) goto ddGroupSiftingDownOutOfMem; - if ((double) size > (double) limitSize * table->maxGrowth) - return(1); - if (size < limitSize) limitSize = size; - - /* Update upper bound on node decrease: second phase. */ - gxtop = table->subtables[gybot].next; - for (z = gxtop + 1; z <= gybot; z++) { - zindex = table->invperm[z]; - if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) { - isolated = table->vars[zindex]->ref == 1; - R += table->subtables[z].keys - isolated; - } - } - } - x = gybot; - y = cuddNextHigh(table,x); - } - - return(1); - -ddGroupSiftingDownOutOfMem: - while (*moves != NULL) { - move = (*moves)->next; - cuddDeallocNode(table, (DdNode *) *moves); - *moves = move; - } - - return(0); - -} /* end of ddGroupSiftingDown */ - - -/**Function******************************************************************** - - Synopsis [Swaps two groups and records the move.] - - Description [Swaps two groups and records the move. Returns the - number of keys in the DD table in case of success; 0 otherwise.] - - SideEffects [None] - -******************************************************************************/ -static int -ddGroupMove( - DdManager * table, - int x, - int y, - Move ** moves) -{ - Move *move; - int size; - int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop; - int swapx,swapy; -#if defined(DD_DEBUG) && defined(DD_VERBOSE) - int initialSize,bestSize; -#endif - -#if DD_DEBUG - /* We assume that x < y */ - assert(x < y); -#endif - /* Find top, bottom, and size for the two groups. */ - xbot = x; - xtop = table->subtables[x].next; - xsize = xbot - xtop + 1; - ybot = y; - while ((unsigned) ybot < table->subtables[ybot].next) - ybot = table->subtables[ybot].next; - ytop = y; - ysize = ybot - ytop + 1; - -#if defined(DD_DEBUG) && defined(DD_VERBOSE) - initialSize = bestSize = table->keys - table->isolated; -#endif - /* Sift the variables of the second group up through the first group */ - for (i = 1; i <= ysize; i++) { - for (j = 1; j <= xsize; j++) { - size = cuddSwapInPlace(table,x,y); - if (size == 0) goto ddGroupMoveOutOfMem; -#if defined(DD_DEBUG) && defined(DD_VERBOSE) - if (size < bestSize) - bestSize = size; -#endif - swapx = x; swapy = y; - y = x; - x = cuddNextLow(table,y); - } - y = ytop + i; - x = cuddNextLow(table,y); - } -#if defined(DD_DEBUG) && defined(DD_VERBOSE) - if ((bestSize < initialSize) && (bestSize < size)) - (void) fprintf(table->out,"Missed local minimum: initialSize:%d bestSize:%d finalSize:%d\n",initialSize,bestSize,size); -#endif - - /* fix groups */ - y = xtop; /* ytop is now where xtop used to be */ - for (i = 0; i < ysize - 1; i++) { - table->subtables[y].next = cuddNextHigh(table,y); - y = cuddNextHigh(table,y); - } - table->subtables[y].next = xtop; /* y is bottom of its group, join */ - /* it to top of its group */ - x = cuddNextHigh(table,y); - newxtop = x; - for (i = 0; i < xsize - 1; i++) { - table->subtables[x].next = cuddNextHigh(table,x); - x = cuddNextHigh(table,x); - } - table->subtables[x].next = newxtop; /* x is bottom of its group, join */ - /* it to top of its group */ -#ifdef DD_DEBUG - if (pr > 0) (void) fprintf(table->out,"ddGroupMove:\n"); -#endif - - /* Store group move */ - move = (Move *) cuddDynamicAllocNode(table); - if (move == NULL) goto ddGroupMoveOutOfMem; - move->x = swapx; - move->y = swapy; - move->flags = MTR_DEFAULT; - move->size = table->keys - table->isolated; - move->next = *moves; - *moves = move; - - return(table->keys - table->isolated); - -ddGroupMoveOutOfMem: - while (*moves != NULL) { - move = (*moves)->next; - cuddDeallocNode(table, (DdNode *) *moves); - *moves = move; - } - return(0); - -} /* end of ddGroupMove */ - - -/**Function******************************************************************** - - Synopsis [Undoes the swap two groups.] - - Description [Undoes the swap two groups. Returns 1 in case of - success; 0 otherwise.] - - SideEffects [None] - -******************************************************************************/ -static int -ddGroupMoveBackward( - DdManager * table, - int x, - int y) -{ - int size; - int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop; - - -#if DD_DEBUG - /* We assume that x < y */ - assert(x < y); -#endif - - /* Find top, bottom, and size for the two groups. */ - xbot = x; - xtop = table->subtables[x].next; - xsize = xbot - xtop + 1; - ybot = y; - while ((unsigned) ybot < table->subtables[ybot].next) - ybot = table->subtables[ybot].next; - ytop = y; - ysize = ybot - ytop + 1; - - /* Sift the variables of the second group up through the first group */ - for (i = 1; i <= ysize; i++) { - for (j = 1; j <= xsize; j++) { - size = cuddSwapInPlace(table,x,y); - if (size == 0) - return(0); - y = x; - x = cuddNextLow(table,y); - } - y = ytop + i; - x = cuddNextLow(table,y); - } - - /* fix groups */ - y = xtop; - for (i = 0; i < ysize - 1; i++) { - table->subtables[y].next = cuddNextHigh(table,y); - y = cuddNextHigh(table,y); - } - table->subtables[y].next = xtop; /* y is bottom of its group, join */ - /* to its top */ - x = cuddNextHigh(table,y); - newxtop = x; - for (i = 0; i < xsize - 1; i++) { - table->subtables[x].next = cuddNextHigh(table,x); - x = cuddNextHigh(table,x); - } - table->subtables[x].next = newxtop; /* x is bottom of its group, join */ - /* to its top */ -#ifdef DD_DEBUG - if (pr > 0) (void) fprintf(table->out,"ddGroupMoveBackward:\n"); -#endif - - return(1); - -} /* end of ddGroupMoveBackward */ - - -/**Function******************************************************************** - - Synopsis [Determines the best position for a variables and returns - it there.] - - Description [Determines the best position for a variables and returns - it there. Returns 1 in case of success; 0 otherwise.] - - SideEffects [None] - -******************************************************************************/ -static int -ddGroupSiftingBackward( - DdManager * table, - Move * moves, - int size, - int upFlag, - int lazyFlag) -{ - Move *move; - int res; - Move *end_move; - int diff, tmp_diff; - int index, pairlev; - - if (lazyFlag) { - end_move = NULL; - - /* Find the minimum size, and the earliest position at which it - ** was achieved. */ - for (move = moves; move != NULL; move = move->next) { - if (move->size < size) { - size = move->size; - end_move = move; - } else if (move->size == size) { - if (end_move == NULL) end_move = move; - } - } - - /* Find among the moves that give minimum size the one that - ** minimizes the distance from the corresponding variable. */ - if (moves != NULL) { - diff = Cudd_ReadSize(table) + 1; - index = (upFlag == 1) ? - table->invperm[moves->x] : table->invperm[moves->y]; - pairlev = table->perm[Cudd_bddReadPairIndex(table, index)]; - - for (move = moves; move != NULL; move = move->next) { - if (move->size == size) { - if (upFlag == 1) { - tmp_diff = (move->x > pairlev) ? - move->x - pairlev : pairlev - move->x; - } else { - tmp_diff = (move->y > pairlev) ? - move->y - pairlev : pairlev - move->y; - } - if (tmp_diff < diff) { - diff = tmp_diff; - end_move = move; - } - } - } - } - } else { - /* Find the minimum size. */ - for (move = moves; move != NULL; move = move->next) { - if (move->size < size) { - size = move->size; - } - } - } - - /* In case of lazy sifting, end_move identifies the position at - ** which we want to stop. Otherwise, we stop as soon as we meet - ** the minimum size. */ - for (move = moves; move != NULL; move = move->next) { - if (lazyFlag) { - if (move == end_move) return(1); - } else { - if (move->size == size) return(1); - } - if ((table->subtables[move->x].next == move->x) && - (table->subtables[move->y].next == move->y)) { - res = cuddSwapInPlace(table,(int)move->x,(int)move->y); - if (!res) return(0); -#ifdef DD_DEBUG - if (pr > 0) (void) fprintf(table->out,"ddGroupSiftingBackward:\n"); - assert(table->subtables[move->x].next == move->x); - assert(table->subtables[move->y].next == move->y); -#endif - } else { /* Group move necessary */ - if (move->flags == MTR_NEWNODE) { - ddDissolveGroup(table,(int)move->x,(int)move->y); - } else { - res = ddGroupMoveBackward(table,(int)move->x,(int)move->y); - if (!res) return(0); - } - } - - } - - return(1); - -} /* end of ddGroupSiftingBackward */ - - -/**Function******************************************************************** - - Synopsis [Merges groups in the DD table.] - - Description [Creates a single group from low to high and adjusts the - index field of the tree node.] - - SideEffects [None] - -******************************************************************************/ -static void -ddMergeGroups( - DdManager * table, - MtrNode * treenode, - int low, - int high) -{ - int i; - MtrNode *auxnode; - int saveindex; - int newindex; - - /* Merge all variables from low to high in one group, unless - ** this is the topmost group. In such a case we do not merge lest - ** we lose the symmetry information. */ - if (treenode != table->tree) { - for (i = low; i < high; i++) - table->subtables[i].next = i+1; - table->subtables[high].next = low; - } - - /* Adjust the index fields of the tree nodes. If a node is the - ** first child of its parent, then the parent may also need adjustment. */ - saveindex = treenode->index; - newindex = table->invperm[low]; - auxnode = treenode; - do { - auxnode->index = newindex; - if (auxnode->parent == NULL || - (int) auxnode->parent->index != saveindex) - break; - auxnode = auxnode->parent; - } while (1); - return; - -} /* end of ddMergeGroups */ - - -/**Function******************************************************************** - - Synopsis [Dissolves a group in the DD table.] - - Description [x and y are variables in a group to be cut in two. The cut - is to pass between x and y.] - - SideEffects [None] - -******************************************************************************/ -static void -ddDissolveGroup( - DdManager * table, - int x, - int y) -{ - int topx; - int boty; - - /* find top and bottom of the two groups */ - boty = y; - while ((unsigned) boty < table->subtables[boty].next) - boty = table->subtables[boty].next; - - topx = table->subtables[boty].next; - - table->subtables[boty].next = y; - table->subtables[x].next = topx; - - return; - -} /* end of ddDissolveGroup */ - - -/**Function******************************************************************** - - Synopsis [Pretends to check two variables for aggregation.] - - Description [Pretends to check two variables for aggregation. Always - returns 0.] - - SideEffects [None] - -******************************************************************************/ -static int -ddNoCheck( - DdManager * table, - int x, - int y) -{ - return(0); - -} /* end of ddNoCheck */ - - -/**Function******************************************************************** - - Synopsis [Checks two variables for aggregation.] - - Description [Checks two variables for aggregation. The check is based - on the second difference of the number of nodes as a function of the - layer. If the second difference is lower than a given threshold - (typically negative) then the two variables should be aggregated. - Returns 1 if the two variables pass the test; 0 otherwise.] - - SideEffects [None] - -******************************************************************************/ -static int -ddSecDiffCheck( - DdManager * table, - int x, - int y) -{ - double Nx,Nx_1; - double Sx; - double threshold; - int xindex,yindex; - - if (x==0) return(0); - -#ifdef DD_STATS - secdiffcalls++; -#endif - Nx = (double) table->subtables[x].keys; - Nx_1 = (double) table->subtables[x-1].keys; - Sx = (table->subtables[y].keys/Nx) - (Nx/Nx_1); - - threshold = table->recomb / 100.0; - if (Sx < threshold) { - xindex = table->invperm[x]; - yindex = table->invperm[y]; - if (cuddTestInteract(table,xindex,yindex)) { -#if defined(DD_DEBUG) && defined(DD_VERBOSE) - (void) fprintf(table->out, - "Second difference for %d = %g Pos(%d)\n", - table->invperm[x],Sx,x); -#endif -#ifdef DD_STATS - secdiff++; -#endif - return(1); - } else { -#ifdef DD_STATS - secdiffmisfire++; -#endif - return(0); - } - - } - return(0); - -} /* end of ddSecDiffCheck */ - - -/**Function******************************************************************** - - Synopsis [Checks for extended symmetry of x and y.] - - Description [Checks for extended symmetry of x and y. Returns 1 in - case of extended symmetry; 0 otherwise.] - - SideEffects [None] - -******************************************************************************/ -static int -ddExtSymmCheck( - DdManager * table, - int x, - int y) -{ - DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10; - DdNode *one; - int comple; /* f0 is complemented */ - int notproj; /* f is not a projection function */ - int arccount; /* number of arcs from layer x to layer y */ - int TotalRefCount; /* total reference count of layer y minus 1 */ - int counter; /* number of nodes of layer x that are allowed */ - /* to violate extended symmetry conditions */ - int arccounter; /* number of arcs into layer y that are allowed */ - /* to come from layers other than x */ - int i; - int xindex; - int yindex; - int res; - int slots; - DdNodePtr *list; - DdNode *sentinel = &(table->sentinel); - - xindex = table->invperm[x]; - yindex = table->invperm[y]; - - /* If the two variables do not interact, we do not want to merge them. */ - if (!cuddTestInteract(table,xindex,yindex)) - return(0); - -#ifdef DD_DEBUG - /* Checks that x and y do not contain just the projection functions. - ** With the test on interaction, these test become redundant, - ** because an isolated projection function does not interact with - ** any other variable. - */ - if (table->subtables[x].keys == 1) { - assert(table->vars[xindex]->ref != 1); - } - if (table->subtables[y].keys == 1) { - assert(table->vars[yindex]->ref != 1); - } -#endif - -#ifdef DD_STATS - extsymmcalls++; -#endif - - arccount = 0; - counter = (int) (table->subtables[x].keys * - (table->symmviolation/100.0) + 0.5); - one = DD_ONE(table); - - slots = table->subtables[x].slots; - list = table->subtables[x].nodelist; - for (i = 0; i < slots; i++) { - f = list[i]; - while (f != sentinel) { - /* Find f1, f0, f11, f10, f01, f00. */ - f1 = cuddT(f); - f0 = Cudd_Regular(cuddE(f)); - comple = Cudd_IsComplement(cuddE(f)); - notproj = f1 != one || f0 != one || f->ref != (DdHalfWord) 1; - if (f1->index == yindex) { - arccount++; - f11 = cuddT(f1); f10 = cuddE(f1); - } else { - if ((int) f0->index != yindex) { - /* If f is an isolated projection function it is - ** allowed to bypass layer y. - */ - if (notproj) { - if (counter == 0) - return(0); - counter--; /* f bypasses layer y */ - } - } - f11 = f10 = f1; - } - if ((int) f0->index == yindex) { - arccount++; - f01 = cuddT(f0); f00 = cuddE(f0); - } else { - f01 = f00 = f0; - } - if (comple) { - f01 = Cudd_Not(f01); - f00 = Cudd_Not(f00); - } - - /* Unless we are looking at a projection function - ** without external references except the one from the - ** table, we insist that f01 == f10 or f11 == f00 - */ - if (notproj) { - if (f01 != f10 && f11 != f00) { - if (counter == 0) - return(0); - counter--; - } - } - - f = f->next; - } /* while */ - } /* for */ - - /* Calculate the total reference counts of y */ - TotalRefCount = -1; /* -1 for projection function */ - slots = table->subtables[y].slots; - list = table->subtables[y].nodelist; - for (i = 0; i < slots; i++) { - f = list[i]; - while (f != sentinel) { - TotalRefCount += f->ref; - f = f->next; - } - } - - arccounter = (int) (table->subtables[y].keys * - (table->arcviolation/100.0) + 0.5); - res = arccount >= TotalRefCount - arccounter; - -#if defined(DD_DEBUG) && defined(DD_VERBOSE) - if (res) { - (void) fprintf(table->out, - "Found extended symmetry! x = %d\ty = %d\tPos(%d,%d)\n", - xindex,yindex,x,y); - } -#endif - -#ifdef DD_STATS - if (res) - extsymm++; -#endif - return(res); - -} /* end ddExtSymmCheck */ - - -/**Function******************************************************************** - - Synopsis [Checks for grouping of x and y.] - - Description [Checks for grouping of x and y. Returns 1 in - case of grouping; 0 otherwise. This function is used for lazy sifting.] - - SideEffects [None] - -******************************************************************************/ -static int -ddVarGroupCheck( - DdManager * table, - int x, - int y) -{ - int xindex = table->invperm[x]; - int yindex = table->invperm[y]; - - if (Cudd_bddIsVarToBeUngrouped(table, xindex)) return(0); - - if (Cudd_bddReadPairIndex(table, xindex) == yindex) { - if (ddIsVarHandled(table, xindex) || - ddIsVarHandled(table, yindex)) { - if (Cudd_bddIsVarToBeGrouped(table, xindex) || - Cudd_bddIsVarToBeGrouped(table, yindex) ) { - if (table->keys - table->isolated <= originalSize) { - return(1); - } - } - } - } - - return(0); - -} /* end of ddVarGroupCheck */ - - -/**Function******************************************************************** - - Synopsis [Sets a variable to already handled.] - - Description [Sets a variable to already handled. This function is used - for lazy sifting.] - - SideEffects [none] - - SeeAlso [] - -******************************************************************************/ -static int -ddSetVarHandled( - DdManager *dd, - int index) -{ - if (index >= dd->size || index < 0) return(0); - dd->subtables[dd->perm[index]].varHandled = 1; - return(1); - -} /* end of ddSetVarHandled */ - - -/**Function******************************************************************** - - Synopsis [Resets a variable to be processed.] - - Description [Resets a variable to be processed. This function is used - for lazy sifting.] - - SideEffects [none] - - SeeAlso [] - -******************************************************************************/ -static int -ddResetVarHandled( - DdManager *dd, - int index) -{ - if (index >= dd->size || index < 0) return(0); - dd->subtables[dd->perm[index]].varHandled = 0; - return(1); - -} /* end of ddResetVarHandled */ - - -/**Function******************************************************************** - - Synopsis [Checks whether a variables is already handled.] - - Description [Checks whether a variables is already handled. This - function is used for lazy sifting.] - - SideEffects [none] - - SeeAlso [] - -******************************************************************************/ -static int -ddIsVarHandled( - DdManager *dd, - int index) -{ - if (index >= dd->size || index < 0) return(-1); - return dd->subtables[dd->perm[index]].varHandled; - -} /* end of ddIsVarHandled */ |