src/bdd/cudd/cuddGroup.c File Reference

#include "util_hack.h"
#include "cuddInt.h"
Include dependency graph for cuddGroup.c:

Go to the source code of this file.

Defines

#define DD_NORMAL_SIFT   0
#define DD_LAZY_SIFT   1
#define DD_SIFT_DOWN   0
#define DD_SIFT_UP   1

Functions

static int ddTreeSiftingAux 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 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 int ddSetVarHandled ARGS ((DdManager *dd, int index))
MtrNodeCudd_MakeTreeNode (DdManager *dd, unsigned int low, unsigned int size, unsigned int type)
int cuddTreeSifting (DdManager *table, Cudd_ReorderingType method)
static int ddTreeSiftingAux (DdManager *table, MtrNode *treenode, Cudd_ReorderingType method)
static int ddReorderChildren (DdManager *table, MtrNode *treenode, Cudd_ReorderingType method)
static void ddFindNodeHiLo (DdManager *table, MtrNode *treenode, int *lower, int *upper)
static int ddUniqueCompareGroup (int *ptrX, int *ptrY)
static int ddGroupSifting (DdManager *table, int lower, int upper, int(*checkFunction)(DdManager *, int, int), int lazyFlag)
static void ddCreateGroup (DdManager *table, int x, int y)
static int ddGroupSiftingAux (DdManager *table, int x, int xLow, int xHigh, int(*checkFunction)(DdManager *, int, int), int lazyFlag)
static int ddGroupSiftingUp (DdManager *table, int y, int xLow, int(*checkFunction)(DdManager *, int, int), Move **moves)
static int ddGroupSiftingDown (DdManager *table, int x, int xHigh, int(*checkFunction)(DdManager *, int, int), Move **moves)
static int ddGroupMove (DdManager *table, int x, int y, Move **moves)
static int ddGroupMoveBackward (DdManager *table, int x, int y)
static int ddGroupSiftingBackward (DdManager *table, Move *moves, int size, int upFlag, int lazyFlag)
static void ddMergeGroups (DdManager *table, MtrNode *treenode, int low, int high)
static void ddDissolveGroup (DdManager *table, int x, int y)
static int ddNoCheck (DdManager *table, int x, int y)
static int ddSecDiffCheck (DdManager *table, int x, int y)
static int ddExtSymmCheck (DdManager *table, int x, int y)
static int ddVarGroupCheck (DdManager *table, int x, int y)
static int ddSetVarHandled (DdManager *dd, int index)
static int ddResetVarHandled (DdManager *dd, int index)
static int ddIsVarHandled (DdManager *dd, int index)

Variables

static char rcsid[] DD_UNUSED = "$Id: cuddGroup.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $"
static int * entry
int ddTotalNumberSwapping
static int originalSize
static int originalLevel

Define Documentation

#define DD_LAZY_SIFT   1

Definition at line 61 of file cuddGroup.c.

#define DD_NORMAL_SIFT   0

CFile***********************************************************************

FileName [cuddGroup.c]

PackageName [cudd]

Synopsis [Functions for group sifting.]

Description [External procedures included in this file:

Internal procedures included in this file:

Static procedures included in this module:

]

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.]

Definition at line 60 of file cuddGroup.c.

#define DD_SIFT_DOWN   0

Definition at line 64 of file cuddGroup.c.

#define DD_SIFT_UP   1

Definition at line 65 of file cuddGroup.c.


Function Documentation

static int ddSetVarHandled ARGS ( (DdManager *dd, int index)   )  [static]
static void ddMergeGroups ARGS ( (DdManager *table, MtrNode *treenode, int low, int high)   )  [static]
static int ddGroupSiftingBackward ARGS ( (DdManager *table, Move *moves, int size, int upFlag, int lazyFlag)   )  [static]
static int ddGroupMove ARGS ( (DdManager *table, int x, int y, Move **moves)   )  [static]
static int ddGroupSiftingDown ARGS ( (DdManager *table, int x, int xHigh, int(*checkFunction)(DdManager *, int, int), Move **moves)   )  [static]
static int ddGroupSiftingUp ARGS ( (DdManager *table, int y, int xLow, int(*checkFunction)(DdManager *, int, int), Move **moves)   )  [static]
static int ddGroupSiftingAux ARGS ( (DdManager *table, int x, int xLow, int xHigh, int(*checkFunction)(DdManager *, int, int), int lazyFlag)   )  [static]
static void ddCreateGroup ARGS ( (DdManager *table, int x, int y)   )  [static]
static int ddGroupSifting ARGS ( (DdManager *table, int lower, int upper, int(*checkFunction)(DdManager *, int, int), int lazyFlag)   )  [static]
static int ddUniqueCompareGroup ARGS ( (int *ptrX, int *ptrY)   )  [static]
static void ddFindNodeHiLo ARGS ( (DdManager *table, MtrNode *treenode, int *lower, int *upper)   )  [static]
static int ddReorderChildren ARGS ( (DdManager *table, MtrNode *treenode, Cudd_ReorderingType method)   )  [static]

AutomaticStart

MtrNode* Cudd_MakeTreeNode ( DdManager dd,
unsigned int  low,
unsigned int  size,
unsigned int  type 
)

AutomaticEnd 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]

Definition at line 161 of file cuddGroup.c.

00166 {
00167     MtrNode *group;
00168     MtrNode *tree;
00169     unsigned int level;
00170 
00171     /* If the variable does not exist yet, the position is assumed to be
00172     ** the same as the index. Therefore, applications that rely on
00173     ** Cudd_bddNewVarAtLevel or Cudd_addNewVarAtLevel to create new
00174     ** variables have to create the variables before they group them.
00175     */
00176     level = (low < (unsigned int) dd->size) ? dd->perm[low] : low;
00177 
00178     if (level + size - 1> (int) MTR_MAXHIGH)
00179         return(NULL);
00180 
00181     /* If the tree does not exist yet, create it. */
00182     tree = dd->tree;
00183     if (tree == NULL) {
00184         dd->tree = tree = Mtr_InitGroupTree(0, dd->size);
00185         if (tree == NULL)
00186             return(NULL);
00187         tree->index = dd->invperm[0];
00188     }
00189 
00190     /* Extend the upper bound of the tree if necessary. This allows the
00191     ** application to create groups even before the variables are created.
00192     */
00193     tree->size = ddMax(tree->size, ddMax(level + size, (unsigned) dd->size));
00194 
00195     /* Create the group. */
00196     group = Mtr_MakeGroup(tree, level, size, type);
00197     if (group == NULL)
00198         return(NULL);
00199 
00200     /* Initialize the index field to the index of the variable currently
00201     ** in position low. This field will be updated by the reordering
00202     ** procedure to provide a handle to the group once it has been moved.
00203     */
00204     group->index = (MtrHalfWord) low;
00205 
00206     return(group);
00207 
00208 } /* end of Cudd_MakeTreeNode */

int cuddTreeSifting ( DdManager table,
Cudd_ReorderingType  method 
)

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]

Definition at line 229 of file cuddGroup.c.

00232 {
00233     int i;
00234     int nvars;
00235     int result;
00236     int tempTree;
00237 
00238     /* If no tree is provided we create a temporary one in which all
00239     ** variables are in a single group. After reordering this tree is
00240     ** destroyed.
00241     */
00242     tempTree = table->tree == NULL;
00243     if (tempTree) {
00244         table->tree = Mtr_InitGroupTree(0,table->size);
00245         table->tree->index = table->invperm[0];
00246     }
00247     nvars = table->size;
00248 
00249 #ifdef DD_DEBUG
00250     if (pr > 0 && !tempTree) (void) fprintf(table->out,"cuddTreeSifting:");
00251     Mtr_PrintGroups(table->tree,pr <= 0);
00252 #endif
00253 
00254 #ifdef DD_STATS
00255     extsymmcalls = 0;
00256     extsymm = 0;
00257     secdiffcalls = 0;
00258     secdiff = 0;
00259     secdiffmisfire = 0;
00260 
00261     (void) fprintf(table->out,"\n");
00262     if (!tempTree)
00263         (void) fprintf(table->out,"#:IM_NODES  %8d: group tree nodes\n",
00264                        ddCountInternalMtrNodes(table,table->tree));
00265 #endif
00266 
00267     /* Initialize the group of each subtable to itself. Initially
00268     ** there are no groups. Groups are created according to the tree
00269     ** structure in postorder fashion.
00270     */
00271     for (i = 0; i < nvars; i++)
00272         table->subtables[i].next = i;
00273 
00274 
00275     /* Reorder. */
00276     result = ddTreeSiftingAux(table, table->tree, method);
00277 
00278 #ifdef DD_STATS         /* print stats */
00279     if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
00280         (table->groupcheck == CUDD_GROUP_CHECK7 ||
00281          table->groupcheck == CUDD_GROUP_CHECK5)) {
00282         (void) fprintf(table->out,"\nextsymmcalls = %d\n",extsymmcalls);
00283         (void) fprintf(table->out,"extsymm = %d",extsymm);
00284     }
00285     if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
00286         table->groupcheck == CUDD_GROUP_CHECK7) {
00287         (void) fprintf(table->out,"\nsecdiffcalls = %d\n",secdiffcalls);
00288         (void) fprintf(table->out,"secdiff = %d\n",secdiff);
00289         (void) fprintf(table->out,"secdiffmisfire = %d",secdiffmisfire);
00290     }
00291 #endif
00292 
00293     if (tempTree)
00294         Cudd_FreeTree(table);
00295     return(result);
00296 
00297 } /* end of cuddTreeSifting */

static void ddCreateGroup ( DdManager table,
int  x,
int  y 
) [static]

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]

Definition at line 870 of file cuddGroup.c.

00874 {
00875     int  gybot;
00876 
00877 #ifdef DD_DEBUG
00878     assert(y == x+1);
00879 #endif
00880 
00881     /* Find bottom of second group. */
00882     gybot = y;
00883     while ((unsigned) gybot < table->subtables[gybot].next)
00884         gybot = table->subtables[gybot].next;
00885 
00886     /* Link groups. */
00887     table->subtables[x].next = y;
00888     table->subtables[gybot].next = x;
00889 
00890     return;
00891 
00892 } /* ddCreateGroup */

static void ddDissolveGroup ( DdManager table,
int  x,
int  y 
) [static]

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]

Definition at line 1782 of file cuddGroup.c.

01786 {
01787     int topx;
01788     int boty;
01789 
01790     /* find top and bottom of the two groups */
01791     boty = y;
01792     while ((unsigned) boty < table->subtables[boty].next)
01793         boty = table->subtables[boty].next;
01794     
01795     topx = table->subtables[boty].next;
01796 
01797     table->subtables[boty].next = y;
01798     table->subtables[x].next = topx;
01799 
01800     return;
01801 
01802 } /* end of ddDissolveGroup */

static int ddExtSymmCheck ( DdManager table,
int  x,
int  y 
) [static]

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]

Definition at line 1897 of file cuddGroup.c.

01901 {
01902     DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10;
01903     DdNode *one;
01904     int comple;         /* f0 is complemented */
01905     int notproj;        /* f is not a projection function */
01906     int arccount;       /* number of arcs from layer x to layer y */
01907     int TotalRefCount;  /* total reference count of layer y minus 1 */
01908     int counter;        /* number of nodes of layer x that are allowed */
01909                         /* to violate extended symmetry conditions */
01910     int arccounter;     /* number of arcs into layer y that are allowed */
01911                         /* to come from layers other than x */
01912     int i;
01913     int xindex;
01914     int yindex;
01915     int res;
01916     int slots;
01917     DdNodePtr *list;
01918     DdNode *sentinel = &(table->sentinel);
01919 
01920     xindex = table->invperm[x];
01921     yindex = table->invperm[y];
01922 
01923     /* If the two variables do not interact, we do not want to merge them. */
01924     if (!cuddTestInteract(table,xindex,yindex))
01925         return(0);
01926 
01927 #ifdef DD_DEBUG
01928     /* Checks that x and y do not contain just the projection functions.
01929     ** With the test on interaction, these test become redundant,
01930     ** because an isolated projection function does not interact with
01931     ** any other variable.
01932     */
01933     if (table->subtables[x].keys == 1) {
01934         assert(table->vars[xindex]->ref != 1);
01935     }
01936     if (table->subtables[y].keys == 1) {
01937         assert(table->vars[yindex]->ref != 1);
01938     }
01939 #endif
01940 
01941 #ifdef DD_STATS
01942     extsymmcalls++;
01943 #endif
01944 
01945     arccount = 0;
01946     counter = (int) (table->subtables[x].keys *
01947               (table->symmviolation/100.0) + 0.5);
01948     one = DD_ONE(table);
01949 
01950     slots = table->subtables[x].slots;
01951     list = table->subtables[x].nodelist;
01952     for (i = 0; i < slots; i++) {
01953         f = list[i];
01954         while (f != sentinel) {
01955             /* Find f1, f0, f11, f10, f01, f00. */
01956             f1 = cuddT(f);
01957             f0 = Cudd_Regular(cuddE(f));
01958             comple = Cudd_IsComplement(cuddE(f));
01959             notproj = f1 != one || f0 != one || f->ref != (DdHalfWord) 1;
01960             if (f1->index == yindex) {
01961                 arccount++;
01962                 f11 = cuddT(f1); f10 = cuddE(f1);
01963             } else {
01964                 if ((int) f0->index != yindex) {
01965                     /* If f is an isolated projection function it is
01966                     ** allowed to bypass layer y.
01967                     */
01968                     if (notproj) {
01969                         if (counter == 0)
01970                             return(0);
01971                         counter--; /* f bypasses layer y */
01972                     }
01973                 }
01974                 f11 = f10 = f1;
01975             }
01976             if ((int) f0->index == yindex) {
01977                 arccount++;
01978                 f01 = cuddT(f0); f00 = cuddE(f0);
01979             } else {
01980                 f01 = f00 = f0;
01981             }
01982             if (comple) {
01983                 f01 = Cudd_Not(f01);
01984                 f00 = Cudd_Not(f00);
01985             }
01986 
01987             /* Unless we are looking at a projection function
01988             ** without external references except the one from the
01989             ** table, we insist that f01 == f10 or f11 == f00
01990             */
01991             if (notproj) {
01992                 if (f01 != f10 && f11 != f00) {
01993                     if (counter == 0)
01994                         return(0);
01995                     counter--;
01996                 }
01997             }
01998 
01999             f = f->next;
02000         } /* while */
02001     } /* for */
02002 
02003     /* Calculate the total reference counts of y */
02004     TotalRefCount = -1; /* -1 for projection function */
02005     slots = table->subtables[y].slots;
02006     list = table->subtables[y].nodelist;
02007     for (i = 0; i < slots; i++) {
02008         f = list[i];
02009         while (f != sentinel) {
02010             TotalRefCount += f->ref;
02011             f = f->next;
02012         }
02013     }
02014 
02015     arccounter = (int) (table->subtables[y].keys *
02016                  (table->arcviolation/100.0) + 0.5);
02017     res = arccount >= TotalRefCount - arccounter;
02018 
02019 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
02020     if (res) {
02021         (void) fprintf(table->out,
02022                        "Found extended symmetry! x = %d\ty = %d\tPos(%d,%d)\n",
02023                        xindex,yindex,x,y);
02024     }
02025 #endif
02026 
02027 #ifdef DD_STATS
02028     if (res)
02029         extsymm++;
02030 #endif
02031     return(res);
02032 
02033 } /* end ddExtSymmCheck */

static void ddFindNodeHiLo ( DdManager table,
MtrNode treenode,
int *  lower,
int *  upper 
) [static]

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 []

Definition at line 572 of file cuddGroup.c.

00577 {
00578     int low;
00579     int high;
00580 
00581     /* Check whether no variables in this group already exist.
00582     ** If so, return immediately. The calling procedure will know from
00583     ** the values of upper that no reordering is needed.
00584     */
00585     if ((int) treenode->low >= table->size) {
00586         *lower = table->size;
00587         *upper = -1;
00588         return;
00589     }
00590 
00591     *lower = low = (unsigned int) table->perm[treenode->index];
00592     high = (int) (low + treenode->size - 1);
00593 
00594     if (high >= table->size) {
00595         /* This is the case of a partially existing group. The aim is to
00596         ** reorder as many variables as safely possible.  If the tree
00597         ** node is terminal, we just reorder the subset of the group
00598         ** that is currently in existence.  If the group has
00599         ** subgroups, then we only reorder those subgroups that are
00600         ** fully instantiated.  This way we avoid breaking up a group.
00601         */
00602         MtrNode *auxnode = treenode->child;
00603         if (auxnode == NULL) {
00604             *upper = (unsigned int) table->size - 1;
00605         } else {
00606             /* Search the subgroup that strands the table->size line.
00607             ** If the first group starts at 0 and goes past table->size
00608             ** upper will get -1, thus correctly signaling that no reordering
00609             ** should take place.
00610             */
00611             while (auxnode != NULL) {
00612                 int thisLower = table->perm[auxnode->low];
00613                 int thisUpper = thisLower + auxnode->size - 1;
00614                 if (thisUpper >= table->size && thisLower < table->size)
00615                     *upper = (unsigned int) thisLower - 1;
00616                 auxnode = auxnode->younger;
00617             }
00618         }
00619     } else {
00620         /* Normal case: All the variables of the group exist. */
00621         *upper = (unsigned int) high;
00622     }
00623 
00624 #ifdef DD_DEBUG
00625     /* Make sure that all variables in group are contiguous. */
00626     assert(treenode->size >= *upper - *lower + 1);
00627 #endif
00628 
00629     return;
00630 
00631 } /* end of ddFindNodeHiLo */

static int ddGroupMove ( DdManager table,
int  x,
int  y,
Move **  moves 
) [static]

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]

Definition at line 1449 of file cuddGroup.c.

01454 {
01455     Move *move;
01456     int  size;
01457     int  i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
01458     int  swapx,swapy;
01459 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01460     int  initialSize,bestSize;
01461 #endif
01462 
01463 #if DD_DEBUG
01464     /* We assume that x < y */
01465     assert(x < y);
01466 #endif
01467     /* Find top, bottom, and size for the two groups. */
01468     xbot = x;
01469     xtop = table->subtables[x].next;
01470     xsize = xbot - xtop + 1;
01471     ybot = y;
01472     while ((unsigned) ybot < table->subtables[ybot].next)
01473         ybot = table->subtables[ybot].next;
01474     ytop = y;
01475     ysize = ybot - ytop + 1;
01476 
01477 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01478     initialSize = bestSize = table->keys - table->isolated;
01479 #endif
01480     /* Sift the variables of the second group up through the first group */
01481     for (i = 1; i <= ysize; i++) {
01482         for (j = 1; j <= xsize; j++) {
01483             size = cuddSwapInPlace(table,x,y);
01484             if (size == 0) goto ddGroupMoveOutOfMem;
01485 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01486             if (size < bestSize)
01487                 bestSize = size;
01488 #endif
01489             swapx = x; swapy = y;
01490             y = x;
01491             x = cuddNextLow(table,y);
01492         }
01493         y = ytop + i;
01494         x = cuddNextLow(table,y);
01495     }
01496 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01497     if ((bestSize < initialSize) && (bestSize < size))
01498         (void) fprintf(table->out,"Missed local minimum: initialSize:%d  bestSize:%d  finalSize:%d\n",initialSize,bestSize,size);
01499 #endif
01500 
01501     /* fix groups */
01502     y = xtop; /* ytop is now where xtop used to be */
01503     for (i = 0; i < ysize - 1; i++) {
01504         table->subtables[y].next = cuddNextHigh(table,y);
01505         y = cuddNextHigh(table,y);
01506     }
01507     table->subtables[y].next = xtop; /* y is bottom of its group, join */
01508                                     /* it to top of its group */
01509     x = cuddNextHigh(table,y);
01510     newxtop = x;
01511     for (i = 0; i < xsize - 1; i++) {
01512         table->subtables[x].next = cuddNextHigh(table,x);
01513         x = cuddNextHigh(table,x);
01514     }
01515     table->subtables[x].next = newxtop; /* x is bottom of its group, join */
01516                                     /* it to top of its group */
01517 #ifdef DD_DEBUG
01518     if (pr > 0) (void) fprintf(table->out,"ddGroupMove:\n");
01519 #endif
01520 
01521     /* Store group move */
01522     move = (Move *) cuddDynamicAllocNode(table);
01523     if (move == NULL) goto ddGroupMoveOutOfMem;
01524     move->x = swapx;
01525     move->y = swapy;
01526     move->flags = MTR_DEFAULT;
01527     move->size = table->keys - table->isolated;
01528     move->next = *moves;
01529     *moves = move;
01530 
01531     return(table->keys - table->isolated);
01532 
01533 ddGroupMoveOutOfMem:
01534     while (*moves != NULL) {
01535         move = (*moves)->next;
01536         cuddDeallocNode(table, (DdNode *) *moves);
01537         *moves = move;
01538     }
01539     return(0);
01540 
01541 } /* end of ddGroupMove */

static int ddGroupMoveBackward ( DdManager table,
int  x,
int  y 
) [static]

Function********************************************************************

Synopsis [Undoes the swap two groups.]

Description [Undoes the swap two groups. Returns 1 in case of success; 0 otherwise.]

SideEffects [None]

Definition at line 1555 of file cuddGroup.c.

01559 {
01560     int size;
01561     int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
01562 
01563 
01564 #if DD_DEBUG
01565     /* We assume that x < y */
01566     assert(x < y);
01567 #endif
01568 
01569     /* Find top, bottom, and size for the two groups. */
01570     xbot = x;
01571     xtop = table->subtables[x].next;
01572     xsize = xbot - xtop + 1;
01573     ybot = y;
01574     while ((unsigned) ybot < table->subtables[ybot].next)
01575         ybot = table->subtables[ybot].next;
01576     ytop = y;
01577     ysize = ybot - ytop + 1;
01578 
01579     /* Sift the variables of the second group up through the first group */
01580     for (i = 1; i <= ysize; i++) {
01581         for (j = 1; j <= xsize; j++) {
01582             size = cuddSwapInPlace(table,x,y);
01583             if (size == 0)
01584                 return(0);
01585             y = x;
01586             x = cuddNextLow(table,y);
01587         }
01588         y = ytop + i;
01589         x = cuddNextLow(table,y);
01590     }
01591 
01592     /* fix groups */
01593     y = xtop;
01594     for (i = 0; i < ysize - 1; i++) {
01595         table->subtables[y].next = cuddNextHigh(table,y);
01596         y = cuddNextHigh(table,y);
01597     }
01598     table->subtables[y].next = xtop; /* y is bottom of its group, join */
01599                                     /* to its top */
01600     x = cuddNextHigh(table,y);
01601     newxtop = x;
01602     for (i = 0; i < xsize - 1; i++) {
01603         table->subtables[x].next = cuddNextHigh(table,x);
01604         x = cuddNextHigh(table,x);
01605     }
01606     table->subtables[x].next = newxtop; /* x is bottom of its group, join */
01607                                     /* to its top */
01608 #ifdef DD_DEBUG
01609     if (pr > 0) (void) fprintf(table->out,"ddGroupMoveBackward:\n");
01610 #endif
01611 
01612     return(1);
01613 
01614 } /* end of ddGroupMoveBackward */

static int ddGroupSifting ( DdManager table,
int  lower,
int  upper,
int(*)(DdManager *, int, int)  checkFunction,
int  lazyFlag 
) [static]

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]

Definition at line 675 of file cuddGroup.c.

00681 {
00682     int         *var;
00683     int         i,j,x,xInit;
00684     int         nvars;
00685     int         classes;
00686     int         result;
00687     int         *sifted;
00688     int         merged;
00689     int         dissolve;
00690 #ifdef DD_STATS
00691     unsigned    previousSize;
00692 #endif
00693     int         xindex;
00694 
00695     nvars = table->size;
00696 
00697     /* Order variables to sift. */
00698     entry = NULL;
00699     sifted = NULL;
00700     var = ALLOC(int,nvars);
00701     if (var == NULL) {
00702         table->errorCode = CUDD_MEMORY_OUT;
00703         goto ddGroupSiftingOutOfMem;
00704     }
00705     entry = ALLOC(int,nvars);
00706     if (entry == NULL) {
00707         table->errorCode = CUDD_MEMORY_OUT;
00708         goto ddGroupSiftingOutOfMem;
00709     }
00710     sifted = ALLOC(int,nvars);
00711     if (sifted == NULL) {
00712         table->errorCode = CUDD_MEMORY_OUT;
00713         goto ddGroupSiftingOutOfMem;
00714     }
00715 
00716     /* Here we consider only one representative for each group. */
00717     for (i = 0, classes = 0; i < nvars; i++) {
00718         sifted[i] = 0;
00719         x = table->perm[i];
00720         if ((unsigned) x >= table->subtables[x].next) {
00721             entry[i] = table->subtables[x].keys;
00722             var[classes] = i;
00723             classes++;
00724         }
00725     }
00726 
00727     qsort((void *)var,classes,sizeof(int),
00728           (int (*)(const void *, const void *)) ddUniqueCompareGroup);
00729 
00730     if (lazyFlag) {
00731         for (i = 0; i < nvars; i ++) {
00732             ddResetVarHandled(table, i);
00733         }
00734     }
00735 
00736     /* Now sift. */
00737     for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
00738         if (ddTotalNumberSwapping >= table->siftMaxSwap)
00739             break;
00740         xindex = var[i];
00741         if (sifted[xindex] == 1) /* variable already sifted as part of group */
00742             continue;
00743         x = table->perm[xindex]; /* find current level of this variable */
00744 
00745         if (x < lower || x > upper || table->subtables[x].bindVar == 1)
00746             continue;
00747 #ifdef DD_STATS
00748         previousSize = table->keys - table->isolated;
00749 #endif
00750 #ifdef DD_DEBUG
00751         /* x is bottom of group */
00752         assert((unsigned) x >= table->subtables[x].next);
00753 #endif
00754         if ((unsigned) x == table->subtables[x].next) {
00755             dissolve = 1;
00756             result = ddGroupSiftingAux(table,x,lower,upper,checkFunction,
00757                                         lazyFlag);
00758         } else {
00759             dissolve = 0;
00760             result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag);
00761         }
00762         if (!result) goto ddGroupSiftingOutOfMem;
00763 
00764         /* check for aggregation */
00765         merged = 0;
00766         if (lazyFlag == 0 && table->groupcheck == CUDD_GROUP_CHECK7) {
00767             x = table->perm[xindex]; /* find current level */
00768             if ((unsigned) x == table->subtables[x].next) { /* not part of a group */
00769                 if (x != upper && sifted[table->invperm[x+1]] == 0 &&
00770                 (unsigned) x+1 == table->subtables[x+1].next) {
00771                     if (ddSecDiffCheck(table,x,x+1)) {
00772                         merged =1;
00773                         ddCreateGroup(table,x,x+1);
00774                     }
00775                 }
00776                 if (x != lower && sifted[table->invperm[x-1]] == 0 &&
00777                 (unsigned) x-1 == table->subtables[x-1].next) {
00778                     if (ddSecDiffCheck(table,x-1,x)) {
00779                         merged =1;
00780                         ddCreateGroup(table,x-1,x);
00781                     }
00782                 }
00783             }
00784         }
00785 
00786         if (merged) { /* a group was created */
00787             /* move x to bottom of group */
00788             while ((unsigned) x < table->subtables[x].next)
00789                 x = table->subtables[x].next;
00790             /* sift */
00791             result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag);
00792             if (!result) goto ddGroupSiftingOutOfMem;
00793 #ifdef DD_STATS
00794             if (table->keys < previousSize + table->isolated) {
00795                 (void) fprintf(table->out,"_");
00796             } else if (table->keys > previousSize + table->isolated) {
00797                 (void) fprintf(table->out,"^");
00798             } else {
00799                 (void) fprintf(table->out,"*");
00800             }
00801             fflush(table->out);
00802         } else {
00803             if (table->keys < previousSize + table->isolated) {
00804                 (void) fprintf(table->out,"-");
00805             } else if (table->keys > previousSize + table->isolated) {
00806                 (void) fprintf(table->out,"+");
00807             } else {
00808                 (void) fprintf(table->out,"=");
00809             }
00810             fflush(table->out);
00811 #endif
00812         }
00813 
00814         /* Mark variables in the group just sifted. */
00815         x = table->perm[xindex];
00816         if ((unsigned) x != table->subtables[x].next) {
00817             xInit = x;
00818             do {
00819                 j = table->invperm[x];
00820                 sifted[j] = 1;
00821                 x = table->subtables[x].next;
00822             } while (x != xInit);
00823 
00824             /* Dissolve the group if it was created. */
00825             if (lazyFlag == 0 && dissolve) {
00826                 do {
00827                     j = table->subtables[x].next;
00828                     table->subtables[x].next = x;
00829                     x = j;
00830                 } while (x != xInit);
00831             }
00832         }
00833 
00834 #ifdef DD_DEBUG
00835         if (pr > 0) (void) fprintf(table->out,"ddGroupSifting:");
00836 #endif
00837 
00838       if (lazyFlag) ddSetVarHandled(table, xindex);
00839     } /* for */
00840 
00841     FREE(sifted);
00842     FREE(var);
00843     FREE(entry);
00844 
00845     return(1);
00846 
00847 ddGroupSiftingOutOfMem:
00848     if (entry != NULL)  FREE(entry);
00849     if (var != NULL)    FREE(var);
00850     if (sifted != NULL) FREE(sifted);
00851 
00852     return(0);
00853 
00854 } /* end of ddGroupSifting */

static int ddGroupSiftingAux ( DdManager table,
int  x,
int  xLow,
int  xHigh,
int(*)(DdManager *, int, int)  checkFunction,
int  lazyFlag 
) [static]

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]

Definition at line 911 of file cuddGroup.c.

00918 {
00919     Move *move;
00920     Move *moves;        /* list of moves */
00921     int  initialSize;
00922     int  result;
00923     int  y;
00924     int  topbot;
00925 
00926 #ifdef DD_DEBUG
00927     if (pr > 0) (void) fprintf(table->out,
00928                                "ddGroupSiftingAux from %d to %d\n",xLow,xHigh);
00929     assert((unsigned) x >= table->subtables[x].next); /* x is bottom of group */
00930 #endif
00931 
00932     initialSize = table->keys - table->isolated;
00933     moves = NULL;
00934 
00935     originalSize = initialSize;         /* for lazy sifting */
00936 
00937     /* If we have a singleton, we check for aggregation in both
00938     ** directions before we sift.
00939     */
00940     if ((unsigned) x == table->subtables[x].next) {
00941         /* Will go down first, unless x == xHigh:
00942         ** Look for aggregation above x.
00943         */
00944         for (y = x; y > xLow; y--) {
00945             if (!checkFunction(table,y-1,y))
00946                 break;
00947             topbot = table->subtables[y-1].next; /* find top of y-1's group */
00948             table->subtables[y-1].next = y;
00949             table->subtables[x].next = topbot; /* x is bottom of group so its */
00950                                                /* next is top of y-1's group */
00951             y = topbot + 1; /* add 1 for y--; new y is top of group */
00952         }
00953         /* Will go up first unless x == xlow:
00954         ** Look for aggregation below x.
00955         */
00956         for (y = x; y < xHigh; y++) {
00957             if (!checkFunction(table,y,y+1))
00958                 break;
00959             /* find bottom of y+1's group */
00960             topbot = y + 1;
00961             while ((unsigned) topbot < table->subtables[topbot].next) {
00962                 topbot = table->subtables[topbot].next;
00963             }
00964             table->subtables[topbot].next = table->subtables[y].next;
00965             table->subtables[y].next = y + 1;
00966             y = topbot - 1; /* subtract 1 for y++; new y is bottom of group */
00967         }
00968     }
00969 
00970     /* Now x may be in the middle of a group.
00971     ** Find bottom of x's group.
00972     */
00973     while ((unsigned) x < table->subtables[x].next)
00974         x = table->subtables[x].next;
00975 
00976     originalLevel = x;                  /* for lazy sifting */
00977 
00978     if (x == xLow) { /* Sift down */
00979 #ifdef DD_DEBUG
00980         /* x must be a singleton */
00981         assert((unsigned) x == table->subtables[x].next);
00982 #endif
00983         if (x == xHigh) return(1);      /* just one variable */
00984 
00985         if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
00986             goto ddGroupSiftingAuxOutOfMem;
00987         /* at this point x == xHigh, unless early term */
00988 
00989         /* move backward and stop at best position */
00990         result = ddGroupSiftingBackward(table,moves,initialSize,
00991                                         DD_SIFT_DOWN,lazyFlag);
00992 #ifdef DD_DEBUG
00993         assert(table->keys - table->isolated <= (unsigned) initialSize);
00994 #endif
00995         if (!result) goto ddGroupSiftingAuxOutOfMem;
00996 
00997     } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */
00998 #ifdef DD_DEBUG
00999         /* x is bottom of group */
01000         assert((unsigned) x >= table->subtables[x].next);
01001 #endif
01002         /* Find top of x's group */
01003         x = table->subtables[x].next;
01004 
01005         if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
01006             goto ddGroupSiftingAuxOutOfMem;
01007         /* at this point x == xLow, unless early term */
01008 
01009         /* move backward and stop at best position */
01010         result = ddGroupSiftingBackward(table,moves,initialSize,
01011                                         DD_SIFT_UP,lazyFlag);
01012 #ifdef DD_DEBUG
01013         assert(table->keys - table->isolated <= (unsigned) initialSize);
01014 #endif
01015         if (!result) goto ddGroupSiftingAuxOutOfMem;
01016 
01017     } else if (x - xLow > xHigh - x) { /* must go down first: shorter */
01018         if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
01019             goto ddGroupSiftingAuxOutOfMem;
01020         /* at this point x == xHigh, unless early term */
01021 
01022         /* Find top of group */
01023         if (moves) {
01024             x = moves->y;
01025         }
01026         while ((unsigned) x < table->subtables[x].next)
01027             x = table->subtables[x].next;
01028         x = table->subtables[x].next;
01029 #ifdef DD_DEBUG
01030         /* x should be the top of a group */
01031         assert((unsigned) x <= table->subtables[x].next);
01032 #endif
01033 
01034         if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
01035             goto ddGroupSiftingAuxOutOfMem;
01036 
01037         /* move backward and stop at best position */
01038         result = ddGroupSiftingBackward(table,moves,initialSize,
01039                                         DD_SIFT_UP,lazyFlag);
01040 #ifdef DD_DEBUG
01041         assert(table->keys - table->isolated <= (unsigned) initialSize);
01042 #endif
01043         if (!result) goto ddGroupSiftingAuxOutOfMem;
01044 
01045     } else { /* moving up first: shorter */
01046         /* Find top of x's group */
01047         x = table->subtables[x].next;
01048 
01049         if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
01050             goto ddGroupSiftingAuxOutOfMem;
01051         /* at this point x == xHigh, unless early term */
01052 
01053         if (moves) {
01054             x = moves->x;
01055         }
01056         while ((unsigned) x < table->subtables[x].next)
01057             x = table->subtables[x].next;
01058 #ifdef DD_DEBUG
01059         /* x is bottom of a group */
01060         assert((unsigned) x >= table->subtables[x].next);
01061 #endif
01062 
01063         if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
01064             goto ddGroupSiftingAuxOutOfMem;
01065 
01066         /* move backward and stop at best position */
01067         result = ddGroupSiftingBackward(table,moves,initialSize,
01068                                         DD_SIFT_DOWN,lazyFlag);
01069 #ifdef DD_DEBUG
01070         assert(table->keys - table->isolated <= (unsigned) initialSize);
01071 #endif
01072         if (!result) goto ddGroupSiftingAuxOutOfMem;
01073     }
01074 
01075     while (moves != NULL) {
01076         move = moves->next;
01077         cuddDeallocNode(table, (DdNode *) moves);
01078         moves = move;
01079     }
01080 
01081     return(1);
01082 
01083 ddGroupSiftingAuxOutOfMem:
01084     while (moves != NULL) {
01085         move = moves->next;
01086         cuddDeallocNode(table, (DdNode *) moves);
01087         moves = move;
01088     }
01089 
01090     return(0);
01091 
01092 } /* end of ddGroupSiftingAux */

static int ddGroupSiftingBackward ( DdManager table,
Move moves,
int  size,
int  upFlag,
int  lazyFlag 
) [static]

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]

Definition at line 1629 of file cuddGroup.c.

01635 {
01636     Move *move;
01637     int  res;
01638     Move *end_move;
01639     int diff, tmp_diff;
01640     int index, pairlev;
01641 
01642     if (lazyFlag) {
01643         end_move = NULL;
01644 
01645         /* Find the minimum size, and the earliest position at which it
01646         ** was achieved. */
01647         for (move = moves; move != NULL; move = move->next) {
01648             if (move->size < size) {
01649                 size = move->size;
01650                 end_move = move;
01651             } else if (move->size == size) {
01652                 if (end_move == NULL) end_move = move;
01653             } 
01654         }
01655 
01656         /* Find among the moves that give minimum size the one that
01657         ** minimizes the distance from the corresponding variable. */
01658         if (moves != NULL) {
01659             diff = Cudd_ReadSize(table) + 1;
01660             index = (upFlag == 1) ? 
01661                     table->invperm[moves->x] : table->invperm[moves->y];
01662             pairlev = table->perm[Cudd_bddReadPairIndex(table, index)];
01663 
01664             for (move = moves; move != NULL; move = move->next) {
01665                 if (move->size == size) {
01666                     if (upFlag == 1) {
01667                         tmp_diff = (move->x > pairlev) ? 
01668                                     move->x - pairlev : pairlev - move->x;
01669                     } else {
01670                         tmp_diff = (move->y > pairlev) ?
01671                                     move->y - pairlev : pairlev - move->y;
01672                     }
01673                     if (tmp_diff < diff) {
01674                         diff = tmp_diff;
01675                         end_move = move;
01676                     } 
01677                 }
01678             }
01679         }
01680     } else {
01681         /* Find the minimum size. */
01682         for (move = moves; move != NULL; move = move->next) {
01683             if (move->size < size) {
01684                 size = move->size;
01685             } 
01686         }
01687     }
01688 
01689     /* In case of lazy sifting, end_move identifies the position at
01690     ** which we want to stop.  Otherwise, we stop as soon as we meet
01691     ** the minimum size. */
01692     for (move = moves; move != NULL; move = move->next) {
01693         if (lazyFlag) {
01694             if (move == end_move) return(1);
01695         } else {
01696             if (move->size == size) return(1);
01697         }
01698         if ((table->subtables[move->x].next == move->x) &&
01699         (table->subtables[move->y].next == move->y)) {
01700             res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
01701             if (!res) return(0);
01702 #ifdef DD_DEBUG
01703             if (pr > 0) (void) fprintf(table->out,"ddGroupSiftingBackward:\n");
01704             assert(table->subtables[move->x].next == move->x);
01705             assert(table->subtables[move->y].next == move->y);
01706 #endif
01707         } else { /* Group move necessary */
01708             if (move->flags == MTR_NEWNODE) {
01709                 ddDissolveGroup(table,(int)move->x,(int)move->y);
01710             } else {
01711                 res = ddGroupMoveBackward(table,(int)move->x,(int)move->y);
01712                 if (!res) return(0);
01713             }
01714         }
01715 
01716     }
01717 
01718     return(1);
01719 
01720 } /* end of ddGroupSiftingBackward */

static int ddGroupSiftingDown ( DdManager table,
int  x,
int  xHigh,
int(*)(DdManager *, int, int)  checkFunction,
Move **  moves 
) [static]

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]

Definition at line 1271 of file cuddGroup.c.

01277 {
01278     Move *move;
01279     int  y;
01280     int  size;
01281     int  limitSize;
01282     int  gxtop,gybot;
01283     int  R;     /* upper bound on node decrease */
01284     int  xindex, yindex;
01285     int  isolated, allVars;
01286     int  z;
01287     int  zindex;
01288 #ifdef DD_DEBUG
01289     int  checkR;
01290 #endif
01291 
01292     /* If the group consists of simple variables, there is no point in
01293     ** sifting it down. This check is redundant if the projection functions
01294     ** do not have external references, because the computation of the
01295     ** lower bound takes care of the problem.  It is necessary otherwise to
01296     ** prevent the sifting down of simple variables. */
01297     y = x;
01298     allVars = 1;
01299     do {
01300         if (table->subtables[y].keys != 1) {
01301             allVars = 0;
01302             break;
01303         }
01304         y = table->subtables[y].next;
01305     } while (table->subtables[y].next != (unsigned) x);
01306     if (allVars)
01307         return(1);
01308     
01309     /* Initialize R. */
01310     xindex = table->invperm[x];
01311     gxtop = table->subtables[x].next;
01312     limitSize = size = table->keys - table->isolated;
01313     R = 0;
01314     for (z = xHigh; z > gxtop; z--) {
01315         zindex = table->invperm[z];
01316         if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
01317             isolated = table->vars[zindex]->ref == 1;
01318             R += table->subtables[z].keys - isolated;
01319         }
01320     }
01321 
01322     originalLevel = x;                  /* for lazy sifting */
01323 
01324     y = cuddNextHigh(table,x);
01325     while (y <= xHigh && size - R < limitSize) {
01326 #ifdef DD_DEBUG
01327         gxtop = table->subtables[x].next;
01328         checkR = 0;
01329         for (z = xHigh; z > gxtop; z--) {
01330             zindex = table->invperm[z];
01331             if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
01332                 isolated = table->vars[zindex]->ref == 1;
01333                 checkR += table->subtables[z].keys - isolated;
01334             }
01335         }
01336         assert(R >= checkR);
01337 #endif
01338         /* Find bottom of y group. */
01339         gybot = table->subtables[y].next;
01340         while (table->subtables[gybot].next != (unsigned) y)
01341             gybot = table->subtables[gybot].next;
01342 
01343         if (checkFunction(table,x,y)) {
01344             /* Group found: attach groups and record move. */
01345             gxtop = table->subtables[x].next;
01346             table->subtables[x].next = y;
01347             table->subtables[gybot].next = gxtop;
01348             move = (Move *)cuddDynamicAllocNode(table);
01349             if (move == NULL) goto ddGroupSiftingDownOutOfMem;
01350             move->x = x;
01351             move->y = y;
01352             move->flags = MTR_NEWNODE;
01353             move->size = table->keys - table->isolated;
01354             move->next = *moves;
01355             *moves = move;
01356         } else if (table->subtables[x].next == (unsigned) x &&
01357                    table->subtables[y].next == (unsigned) y) {
01358             /* x and y are self groups */
01359             /* Update upper bound on node decrease. */
01360             yindex = table->invperm[y];
01361             if (cuddTestInteract(table,xindex,yindex)) {
01362                 isolated = table->vars[yindex]->ref == 1;
01363                 R -= table->subtables[y].keys - isolated;
01364             }
01365             size = cuddSwapInPlace(table,x,y);
01366 #ifdef DD_DEBUG
01367             assert(table->subtables[x].next == (unsigned) x);
01368             assert(table->subtables[y].next == (unsigned) y);
01369 #endif
01370             if (size == 0) goto ddGroupSiftingDownOutOfMem;
01371 
01372             /* Record move. */
01373             move = (Move *) cuddDynamicAllocNode(table);
01374             if (move == NULL) goto ddGroupSiftingDownOutOfMem;
01375             move->x = x;
01376             move->y = y;
01377             move->flags = MTR_DEFAULT;
01378             move->size = size;
01379             move->next = *moves;
01380             *moves = move;
01381 
01382 #ifdef DD_DEBUG
01383             if (pr > 0) (void) fprintf(table->out,
01384                                        "ddGroupSiftingDown (2 single groups):\n");
01385 #endif
01386             if ((double) size > (double) limitSize * table->maxGrowth)
01387                 return(1);
01388             if (size < limitSize) limitSize = size;
01389 
01390             x = y;
01391             y = cuddNextHigh(table,x);
01392         } else { /* Group move */
01393             /* Update upper bound on node decrease: first phase. */
01394             gxtop = table->subtables[x].next;
01395             z = gxtop + 1;
01396             do {
01397                 zindex = table->invperm[z];
01398                 if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
01399                     isolated = table->vars[zindex]->ref == 1;
01400                     R -= table->subtables[z].keys - isolated;
01401                 }
01402                 z++;
01403             } while (z <= gybot);
01404             size = ddGroupMove(table,x,y,moves);
01405             if (size == 0) goto ddGroupSiftingDownOutOfMem;
01406             if ((double) size > (double) limitSize * table->maxGrowth)
01407                 return(1);
01408             if (size < limitSize) limitSize = size;
01409 
01410             /* Update upper bound on node decrease: second phase. */
01411             gxtop = table->subtables[gybot].next;
01412             for (z = gxtop + 1; z <= gybot; z++) {
01413                 zindex = table->invperm[z];
01414                 if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
01415                     isolated = table->vars[zindex]->ref == 1;
01416                     R += table->subtables[z].keys - isolated;
01417                 }
01418             }
01419         }
01420         x = gybot;
01421         y = cuddNextHigh(table,x);
01422     }
01423 
01424     return(1);
01425 
01426 ddGroupSiftingDownOutOfMem:
01427     while (*moves != NULL) {
01428         move = (*moves)->next;
01429         cuddDeallocNode(table, (DdNode *) *moves);
01430         *moves = move;
01431     }
01432 
01433     return(0);
01434 
01435 } /* end of ddGroupSiftingDown */

static int ddGroupSiftingUp ( DdManager table,
int  y,
int  xLow,
int(*)(DdManager *, int, int)  checkFunction,
Move **  moves 
) [static]

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]

Definition at line 1111 of file cuddGroup.c.

01117 {
01118     Move *move;
01119     int  x;
01120     int  size;
01121     int  i;
01122     int  gxtop,gybot;
01123     int  limitSize;
01124     int  xindex, yindex;
01125     int  zindex;
01126     int  z;
01127     int  isolated;
01128     int  L;     /* lower bound on DD size */
01129 #ifdef DD_DEBUG
01130     int  checkL;
01131 #endif
01132 
01133     yindex = table->invperm[y];
01134 
01135     /* Initialize the lower bound.
01136     ** The part of the DD below the bottom of y's group will not change.
01137     ** The part of the DD above y that does not interact with any
01138     ** variable of y's group will not change.
01139     ** The rest may vanish in the best case, except for
01140     ** the nodes at level xLow, which will not vanish, regardless.
01141     ** What we use here is not really a lower bound, because we ignore
01142     ** the interactions with all variables except y.
01143     */
01144     limitSize = L = table->keys - table->isolated;
01145     gybot = y;
01146     while ((unsigned) gybot < table->subtables[gybot].next)
01147         gybot = table->subtables[gybot].next;
01148     for (z = xLow + 1; z <= gybot; z++) {
01149         zindex = table->invperm[z];
01150         if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
01151             isolated = table->vars[zindex]->ref == 1;
01152             L -= table->subtables[z].keys - isolated;
01153         }
01154     }
01155 
01156     originalLevel = y;                  /* for lazy sifting */
01157 
01158     x = cuddNextLow(table,y);
01159     while (x >= xLow && L <= limitSize) {
01160 #ifdef DD_DEBUG
01161         gybot = y;
01162         while ((unsigned) gybot < table->subtables[gybot].next)
01163             gybot = table->subtables[gybot].next;
01164         checkL = table->keys - table->isolated;
01165         for (z = xLow + 1; z <= gybot; z++) {
01166             zindex = table->invperm[z];
01167             if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
01168                 isolated = table->vars[zindex]->ref == 1;
01169                 checkL -= table->subtables[z].keys - isolated;
01170             }
01171         }
01172         if (pr > 0 && L != checkL) {
01173             (void) fprintf(table->out,
01174                            "Inaccurate lower bound: L = %d checkL = %d\n",
01175                            L, checkL);
01176         }
01177 #endif
01178         gxtop = table->subtables[x].next;
01179         if (checkFunction(table,x,y)) {
01180             /* Group found, attach groups */
01181             table->subtables[x].next = y;
01182             i = table->subtables[y].next;
01183             while (table->subtables[i].next != (unsigned) y)
01184                 i = table->subtables[i].next;
01185             table->subtables[i].next = gxtop;
01186             move = (Move *)cuddDynamicAllocNode(table);
01187             if (move == NULL) goto ddGroupSiftingUpOutOfMem;
01188             move->x = x;
01189             move->y = y;
01190             move->flags = MTR_NEWNODE;
01191             move->size = table->keys - table->isolated;
01192             move->next = *moves;
01193             *moves = move;
01194         } else if (table->subtables[x].next == (unsigned) x &&
01195                    table->subtables[y].next == (unsigned) y) {
01196             /* x and y are self groups */
01197             xindex = table->invperm[x];
01198             size = cuddSwapInPlace(table,x,y);
01199 #ifdef DD_DEBUG
01200             assert(table->subtables[x].next == (unsigned) x);
01201             assert(table->subtables[y].next == (unsigned) y);
01202 #endif
01203             if (size == 0) goto ddGroupSiftingUpOutOfMem;
01204             /* Update the lower bound. */
01205             if (cuddTestInteract(table,xindex,yindex)) {
01206                 isolated = table->vars[xindex]->ref == 1;
01207                 L += table->subtables[y].keys - isolated;
01208             }
01209             move = (Move *)cuddDynamicAllocNode(table);
01210             if (move == NULL) goto ddGroupSiftingUpOutOfMem;
01211             move->x = x;
01212             move->y = y;
01213             move->flags = MTR_DEFAULT;
01214             move->size = size;
01215             move->next = *moves;
01216             *moves = move;
01217 
01218 #ifdef DD_DEBUG
01219             if (pr > 0) (void) fprintf(table->out,
01220                                        "ddGroupSiftingUp (2 single groups):\n");
01221 #endif
01222             if ((double) size > (double) limitSize * table->maxGrowth)
01223                 return(1);
01224             if (size < limitSize) limitSize = size;
01225         } else { /* Group move */
01226             size = ddGroupMove(table,x,y,moves);
01227             if (size == 0) goto ddGroupSiftingUpOutOfMem;
01228             /* Update the lower bound. */
01229             z = (*moves)->y;
01230             do {
01231                 zindex = table->invperm[z];
01232                 if (cuddTestInteract(table,zindex,yindex)) {
01233                     isolated = table->vars[zindex]->ref == 1;
01234                     L += table->subtables[z].keys - isolated;
01235                 }
01236                 z = table->subtables[z].next;
01237             } while (z != (int) (*moves)->y);
01238             if ((double) size > (double) limitSize * table->maxGrowth)
01239                 return(1);
01240             if (size < limitSize) limitSize = size;
01241         }
01242         y = gxtop;
01243         x = cuddNextLow(table,y);
01244     }
01245 
01246     return(1);
01247 
01248 ddGroupSiftingUpOutOfMem:
01249     while (*moves != NULL) {
01250         move = (*moves)->next;
01251         cuddDeallocNode(table, (DdNode *) *moves);
01252         *moves = move;
01253     }
01254     return(0);
01255 
01256 } /* end of ddGroupSiftingUp */

static int ddIsVarHandled ( DdManager dd,
int  index 
) [static]

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 []

Definition at line 2135 of file cuddGroup.c.

02138 {
02139     if (index >= dd->size || index < 0) return(-1);
02140     return dd->subtables[dd->perm[index]].varHandled;
02141 
02142 } /* end of ddIsVarHandled */

static void ddMergeGroups ( DdManager table,
MtrNode treenode,
int  low,
int  high 
) [static]

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]

Definition at line 1734 of file cuddGroup.c.

01739 {
01740     int i;
01741     MtrNode *auxnode;
01742     int saveindex;
01743     int newindex;
01744 
01745     /* Merge all variables from low to high in one group, unless
01746     ** this is the topmost group. In such a case we do not merge lest
01747     ** we lose the symmetry information. */
01748     if (treenode != table->tree) {
01749         for (i = low; i < high; i++)
01750             table->subtables[i].next = i+1;
01751         table->subtables[high].next = low;
01752     }
01753 
01754     /* Adjust the index fields of the tree nodes. If a node is the
01755     ** first child of its parent, then the parent may also need adjustment. */
01756     saveindex = treenode->index;
01757     newindex = table->invperm[low];
01758     auxnode = treenode;
01759     do {
01760         auxnode->index = newindex;
01761         if (auxnode->parent == NULL ||
01762                 (int) auxnode->parent->index != saveindex)
01763             break;
01764         auxnode = auxnode->parent;
01765     } while (1);
01766     return;
01767 
01768 } /* end of ddMergeGroups */

static int ddNoCheck ( DdManager table,
int  x,
int  y 
) [static]

Function********************************************************************

Synopsis [Pretends to check two variables for aggregation.]

Description [Pretends to check two variables for aggregation. Always returns 0.]

SideEffects [None]

Definition at line 1816 of file cuddGroup.c.

01820 {
01821     return(0);
01822 
01823 } /* end of ddNoCheck */

static int ddReorderChildren ( DdManager table,
MtrNode treenode,
Cudd_ReorderingType  method 
) [static]

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]

Definition at line 408 of file cuddGroup.c.

00412 {
00413     int lower;
00414     int upper;
00415     int result;
00416     unsigned int initialSize;
00417 
00418     ddFindNodeHiLo(table,treenode,&lower,&upper);
00419     /* If upper == -1 these variables do not exist yet. */
00420     if (upper == -1)
00421         return(1);
00422 
00423     if (treenode->flags == MTR_FIXED) {
00424         result = 1;
00425     } else {
00426 #ifdef DD_STATS
00427         (void) fprintf(table->out," ");
00428 #endif
00429         switch (method) {
00430         case CUDD_REORDER_RANDOM:
00431         case CUDD_REORDER_RANDOM_PIVOT:
00432             result = cuddSwapping(table,lower,upper,method);
00433             break;
00434         case CUDD_REORDER_SIFT:
00435             result = cuddSifting(table,lower,upper);
00436             break;
00437         case CUDD_REORDER_SIFT_CONVERGE:
00438             do {
00439                 initialSize = table->keys - table->isolated;
00440                 result = cuddSifting(table,lower,upper);
00441                 if (initialSize <= table->keys - table->isolated)
00442                     break;
00443 #ifdef DD_STATS
00444                 else
00445                     (void) fprintf(table->out,"\n");
00446 #endif
00447             } while (result != 0);
00448             break;
00449         case CUDD_REORDER_SYMM_SIFT:
00450             result = cuddSymmSifting(table,lower,upper);
00451             break;
00452         case CUDD_REORDER_SYMM_SIFT_CONV:
00453             result = cuddSymmSiftingConv(table,lower,upper);
00454             break;
00455         case CUDD_REORDER_GROUP_SIFT:
00456             if (table->groupcheck == CUDD_NO_CHECK) {
00457                 result = ddGroupSifting(table,lower,upper,ddNoCheck,
00458                                         DD_NORMAL_SIFT);
00459             } else if (table->groupcheck == CUDD_GROUP_CHECK5) {
00460                 result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
00461                                         DD_NORMAL_SIFT);
00462             } else if (table->groupcheck == CUDD_GROUP_CHECK7) {
00463                 result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
00464                                         DD_NORMAL_SIFT);
00465             } else {
00466                 (void) fprintf(table->err,
00467                                "Unknown group ckecking method\n");
00468                 result = 0;
00469             }
00470             break;
00471         case CUDD_REORDER_GROUP_SIFT_CONV:
00472             do {
00473                 initialSize = table->keys - table->isolated;
00474                 if (table->groupcheck == CUDD_NO_CHECK) {
00475                     result = ddGroupSifting(table,lower,upper,ddNoCheck,
00476                                             DD_NORMAL_SIFT);
00477                 } else if (table->groupcheck == CUDD_GROUP_CHECK5) {
00478                     result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
00479                                             DD_NORMAL_SIFT);
00480                 } else if (table->groupcheck == CUDD_GROUP_CHECK7) {
00481                     result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
00482                                             DD_NORMAL_SIFT);
00483                 } else {
00484                     (void) fprintf(table->err,
00485                                    "Unknown group ckecking method\n");
00486                     result = 0;
00487                 }
00488 #ifdef DD_STATS
00489                 (void) fprintf(table->out,"\n");
00490 #endif
00491                 result = cuddWindowReorder(table,lower,upper,
00492                                            CUDD_REORDER_WINDOW4);
00493                 if (initialSize <= table->keys - table->isolated)
00494                     break;
00495 #ifdef DD_STATS
00496                 else
00497                     (void) fprintf(table->out,"\n");
00498 #endif
00499             } while (result != 0);
00500             break;
00501         case CUDD_REORDER_WINDOW2:
00502         case CUDD_REORDER_WINDOW3:
00503         case CUDD_REORDER_WINDOW4:
00504         case CUDD_REORDER_WINDOW2_CONV:
00505         case CUDD_REORDER_WINDOW3_CONV:
00506         case CUDD_REORDER_WINDOW4_CONV:
00507             result = cuddWindowReorder(table,lower,upper,method);
00508             break;
00509         case CUDD_REORDER_ANNEALING:
00510             result = cuddAnnealing(table,lower,upper);
00511             break;
00512         case CUDD_REORDER_GENETIC:
00513             result = cuddGa(table,lower,upper);
00514             break;
00515         case CUDD_REORDER_LINEAR:
00516             result = cuddLinearAndSifting(table,lower,upper);
00517             break;
00518         case CUDD_REORDER_LINEAR_CONVERGE:
00519             do {
00520                 initialSize = table->keys - table->isolated;
00521                 result = cuddLinearAndSifting(table,lower,upper);
00522                 if (initialSize <= table->keys - table->isolated)
00523                     break;
00524 #ifdef DD_STATS
00525                 else
00526                     (void) fprintf(table->out,"\n");
00527 #endif
00528             } while (result != 0);
00529             break;
00530         case CUDD_REORDER_EXACT:
00531             result = cuddExact(table,lower,upper);
00532             break;
00533         case CUDD_REORDER_LAZY_SIFT:
00534             result = ddGroupSifting(table,lower,upper,ddVarGroupCheck,
00535                                     DD_LAZY_SIFT);
00536             break;
00537         default:
00538             return(0);
00539         }
00540     }
00541 
00542     /* Create a single group for all the variables that were sifted,
00543     ** so that they will be treated as a single block by successive
00544     ** invocations of ddGroupSifting.
00545     */
00546     ddMergeGroups(table,treenode,lower,upper);
00547 
00548 #ifdef DD_DEBUG
00549     if (pr > 0) (void) fprintf(table->out,"ddReorderChildren:");
00550 #endif
00551 
00552     return(result);
00553 
00554 } /* end of ddReorderChildren */

static int ddResetVarHandled ( DdManager dd,
int  index 
) [static]

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 []

Definition at line 2111 of file cuddGroup.c.

02114 {
02115     if (index >= dd->size || index < 0) return(0);
02116     dd->subtables[dd->perm[index]].varHandled = 0;
02117     return(1);
02118 
02119 } /* end of ddResetVarHandled */

static int ddSecDiffCheck ( DdManager table,
int  x,
int  y 
) [static]

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]

Definition at line 1840 of file cuddGroup.c.

01844 {
01845     double Nx,Nx_1;
01846     double Sx;
01847     double threshold;
01848     int    xindex,yindex;
01849 
01850     if (x==0) return(0);
01851 
01852 #ifdef DD_STATS
01853     secdiffcalls++;
01854 #endif
01855     Nx = (double) table->subtables[x].keys;
01856     Nx_1 = (double) table->subtables[x-1].keys;
01857     Sx = (table->subtables[y].keys/Nx) - (Nx/Nx_1);
01858 
01859     threshold = table->recomb / 100.0;
01860     if (Sx < threshold) {
01861         xindex = table->invperm[x];
01862         yindex = table->invperm[y];
01863         if (cuddTestInteract(table,xindex,yindex)) {
01864 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01865             (void) fprintf(table->out,
01866                            "Second difference for %d = %g Pos(%d)\n",
01867                            table->invperm[x],Sx,x);
01868 #endif
01869 #ifdef DD_STATS
01870             secdiff++;
01871 #endif
01872             return(1);
01873         } else {
01874 #ifdef DD_STATS
01875             secdiffmisfire++;
01876 #endif
01877             return(0);
01878         }
01879 
01880     }
01881     return(0);
01882 
01883 } /* end of ddSecDiffCheck */

static int ddSetVarHandled ( DdManager dd,
int  index 
) [static]

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 []

Definition at line 2087 of file cuddGroup.c.

02090 {
02091     if (index >= dd->size || index < 0) return(0);
02092     dd->subtables[dd->perm[index]].varHandled = 1;
02093     return(1);
02094 
02095 } /* end of ddSetVarHandled */

static int ddTreeSiftingAux ( DdManager table,
MtrNode treenode,
Cudd_ReorderingType  method 
) [static]

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]

Definition at line 316 of file cuddGroup.c.

00320 {
00321     MtrNode  *auxnode;
00322     int res;
00323     Cudd_AggregationType saveCheck;
00324 
00325 #ifdef DD_DEBUG
00326     Mtr_PrintGroups(treenode,1);
00327 #endif
00328 
00329     auxnode = treenode;
00330     while (auxnode != NULL) {
00331         if (auxnode->child != NULL) {
00332             if (!ddTreeSiftingAux(table, auxnode->child, method))
00333                 return(0);
00334             saveCheck = table->groupcheck;
00335             table->groupcheck = CUDD_NO_CHECK;
00336             if (method != CUDD_REORDER_LAZY_SIFT)
00337               res = ddReorderChildren(table, auxnode, CUDD_REORDER_GROUP_SIFT);
00338             else
00339               res = ddReorderChildren(table, auxnode, CUDD_REORDER_LAZY_SIFT);
00340             table->groupcheck = saveCheck;
00341 
00342             if (res == 0)
00343                 return(0);
00344         } else if (auxnode->size > 1) {
00345             if (!ddReorderChildren(table, auxnode, method))
00346                 return(0);
00347         }
00348         auxnode = auxnode->younger;
00349     }
00350 
00351     return(1);
00352 
00353 } /* end of ddTreeSiftingAux */

static int ddUniqueCompareGroup ( int *  ptrX,
int *  ptrY 
) [static]

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]

Definition at line 647 of file cuddGroup.c.

00650 {
00651 #if 0
00652     if (entry[*ptrY] == entry[*ptrX]) {
00653         return((*ptrX) - (*ptrY));
00654     }
00655 #endif
00656     return(entry[*ptrY] - entry[*ptrX]);
00657 
00658 } /* end of ddUniqueCompareGroup */

static int ddVarGroupCheck ( DdManager table,
int  x,
int  y 
) [static]

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]

Definition at line 2047 of file cuddGroup.c.

02051 {
02052     int xindex = table->invperm[x];
02053     int yindex = table->invperm[y];
02054 
02055     if (Cudd_bddIsVarToBeUngrouped(table, xindex)) return(0);
02056 
02057     if (Cudd_bddReadPairIndex(table, xindex) == yindex) {
02058         if (ddIsVarHandled(table, xindex) ||
02059             ddIsVarHandled(table, yindex)) {
02060             if (Cudd_bddIsVarToBeGrouped(table, xindex) ||
02061                 Cudd_bddIsVarToBeGrouped(table, yindex) ) {
02062                 if (table->keys - table->isolated <= originalSize) {
02063                     return(1);
02064                 }
02065             }
02066         }
02067     }
02068 
02069     return(0);
02070 
02071 } /* end of ddVarGroupCheck */


Variable Documentation

char rcsid [] DD_UNUSED = "$Id: cuddGroup.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $" [static]

Definition at line 80 of file cuddGroup.c.

Definition at line 76 of file cuddReorder.c.

int* entry [static]

Definition at line 83 of file cuddGroup.c.

int originalLevel [static]

Definition at line 98 of file cuddGroup.c.

int originalSize [static]

Definition at line 97 of file cuddGroup.c.


Generated on Tue Jan 5 12:18:54 2010 for abc70930 by  doxygen 1.6.1