src/cuBdd/cuddGroup.c File Reference

#include "util.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

Typedefs

typedef int(* DD_CHKFP )(DdManager *, int, int)

Functions

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, DD_CHKFP checkFunction, int lazyFlag)
static void ddCreateGroup (DdManager *table, int x, int y)
static int ddGroupSiftingAux (DdManager *table, int x, int xLow, int xHigh, DD_CHKFP checkFunction, int lazyFlag)
static int ddGroupSiftingUp (DdManager *table, int y, int xLow, DD_CHKFP checkFunction, Move **moves)
static int ddGroupSiftingDown (DdManager *table, int x, int xHigh, DD_CHKFP checkFunction, 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)
MtrNodeCudd_MakeTreeNode (DdManager *dd, unsigned int low, unsigned int size, unsigned int type)
int cuddTreeSifting (DdManager *table, Cudd_ReorderingType method)

Variables

static char rcsid[] DD_UNUSED = "$Id: cuddGroup.c,v 1.44 2009/02/21 18:24:10 fabio Exp $"
static int * entry
int ddTotalNumberSwapping
static unsigned int originalSize

Define Documentation

#define DD_LAZY_SIFT   1

Definition at line 88 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 [Copyright (c) 1995-2004, Regents of the University of Colorado

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

Neither the name of the University of Colorado nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.]

Definition at line 87 of file cuddGroup.c.

#define DD_SIFT_DOWN   0

Definition at line 91 of file cuddGroup.c.

#define DD_SIFT_UP   1

Definition at line 92 of file cuddGroup.c.


Typedef Documentation

typedef int(* DD_CHKFP)(DdManager *, int, int)

Definition at line 105 of file cuddGroup.c.


Function Documentation

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 202 of file cuddGroup.c.

00207 {
00208     MtrNode *group;
00209     MtrNode *tree;
00210     unsigned int level;
00211 
00212     /* If the variable does not exist yet, the position is assumed to be
00213     ** the same as the index. Therefore, applications that rely on
00214     ** Cudd_bddNewVarAtLevel or Cudd_addNewVarAtLevel to create new
00215     ** variables have to create the variables before they group them.
00216     */
00217     level = (low < (unsigned int) dd->size) ? dd->perm[low] : low;
00218 
00219     if (level + size - 1> (int) MTR_MAXHIGH)
00220         return(NULL);
00221 
00222     /* If the tree does not exist yet, create it. */
00223     tree = dd->tree;
00224     if (tree == NULL) {
00225         dd->tree = tree = Mtr_InitGroupTree(0, dd->size);
00226         if (tree == NULL)
00227             return(NULL);
00228         tree->index = dd->invperm[0];
00229     }
00230 
00231     /* Extend the upper bound of the tree if necessary. This allows the
00232     ** application to create groups even before the variables are created.
00233     */
00234     tree->size = ddMax(tree->size, ddMax(level + size, (unsigned) dd->size));
00235 
00236     /* Create the group. */
00237     group = Mtr_MakeGroup(tree, level, size, type);
00238     if (group == NULL)
00239         return(NULL);
00240 
00241     /* Initialize the index field to the index of the variable currently
00242     ** in position low. This field will be updated by the reordering
00243     ** procedure to provide a handle to the group once it has been moved.
00244     */
00245     group->index = (MtrHalfWord) low;
00246 
00247     return(group);
00248 
00249 } /* 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 270 of file cuddGroup.c.

00273 {
00274     int i;
00275     int nvars;
00276     int result;
00277     int tempTree;
00278 
00279     /* If no tree is provided we create a temporary one in which all
00280     ** variables are in a single group. After reordering this tree is
00281     ** destroyed.
00282     */
00283     tempTree = table->tree == NULL;
00284     if (tempTree) {
00285         table->tree = Mtr_InitGroupTree(0,table->size);
00286         table->tree->index = table->invperm[0];
00287     }
00288     nvars = table->size;
00289 
00290 #ifdef DD_DEBUG
00291     if (pr > 0 && !tempTree) (void) fprintf(table->out,"cuddTreeSifting:");
00292     Mtr_PrintGroups(table->tree,pr <= 0);
00293 #endif
00294 
00295 #ifdef DD_STATS
00296     extsymmcalls = 0;
00297     extsymm = 0;
00298     secdiffcalls = 0;
00299     secdiff = 0;
00300     secdiffmisfire = 0;
00301 
00302     (void) fprintf(table->out,"\n");
00303     if (!tempTree)
00304         (void) fprintf(table->out,"#:IM_NODES  %8d: group tree nodes\n",
00305                        ddCountInternalMtrNodes(table,table->tree));
00306 #endif
00307 
00308     /* Initialize the group of each subtable to itself. Initially
00309     ** there are no groups. Groups are created according to the tree
00310     ** structure in postorder fashion.
00311     */
00312     for (i = 0; i < nvars; i++)
00313         table->subtables[i].next = i;
00314 
00315 
00316     /* Reorder. */
00317     result = ddTreeSiftingAux(table, table->tree, method);
00318 
00319 #ifdef DD_STATS         /* print stats */
00320     if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
00321         (table->groupcheck == CUDD_GROUP_CHECK7 ||
00322          table->groupcheck == CUDD_GROUP_CHECK5)) {
00323         (void) fprintf(table->out,"\nextsymmcalls = %d\n",extsymmcalls);
00324         (void) fprintf(table->out,"extsymm = %d",extsymm);
00325     }
00326     if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
00327         table->groupcheck == CUDD_GROUP_CHECK7) {
00328         (void) fprintf(table->out,"\nsecdiffcalls = %d\n",secdiffcalls);
00329         (void) fprintf(table->out,"secdiff = %d\n",secdiff);
00330         (void) fprintf(table->out,"secdiffmisfire = %d",secdiffmisfire);
00331     }
00332 #endif
00333 
00334     if (tempTree)
00335         Cudd_FreeTree(table);
00336     return(result);
00337 
00338 } /* 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 911 of file cuddGroup.c.

00915 {
00916     int  gybot;
00917 
00918 #ifdef DD_DEBUG
00919     assert(y == x+1);
00920 #endif
00921 
00922     /* Find bottom of second group. */
00923     gybot = y;
00924     while ((unsigned) gybot < table->subtables[gybot].next)
00925         gybot = table->subtables[gybot].next;
00926 
00927     /* Link groups. */
00928     table->subtables[x].next = y;
00929     table->subtables[gybot].next = x;
00930 
00931     return;
00932 
00933 } /* 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 1819 of file cuddGroup.c.

01823 {
01824     int topx;
01825     int boty;
01826 
01827     /* find top and bottom of the two groups */
01828     boty = y;
01829     while ((unsigned) boty < table->subtables[boty].next)
01830         boty = table->subtables[boty].next;
01831 
01832     topx = table->subtables[boty].next;
01833 
01834     table->subtables[boty].next = y;
01835     table->subtables[x].next = topx;
01836 
01837     return;
01838 
01839 } /* 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 1934 of file cuddGroup.c.

01938 {
01939     DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10;
01940     DdNode *one;
01941     unsigned comple;    /* f0 is complemented */
01942     int notproj;        /* f is not a projection function */
01943     int arccount;       /* number of arcs from layer x to layer y */
01944     int TotalRefCount;  /* total reference count of layer y minus 1 */
01945     int counter;        /* number of nodes of layer x that are allowed */
01946                         /* to violate extended symmetry conditions */
01947     int arccounter;     /* number of arcs into layer y that are allowed */
01948                         /* to come from layers other than x */
01949     int i;
01950     int xindex;
01951     int yindex;
01952     int res;
01953     int slots;
01954     DdNodePtr *list;
01955     DdNode *sentinel = &(table->sentinel);
01956 
01957     xindex = table->invperm[x];
01958     yindex = table->invperm[y];
01959 
01960     /* If the two variables do not interact, we do not want to merge them. */
01961     if (!cuddTestInteract(table,xindex,yindex))
01962         return(0);
01963 
01964 #ifdef DD_DEBUG
01965     /* Checks that x and y do not contain just the projection functions.
01966     ** With the test on interaction, these test become redundant,
01967     ** because an isolated projection function does not interact with
01968     ** any other variable.
01969     */
01970     if (table->subtables[x].keys == 1) {
01971         assert(table->vars[xindex]->ref != 1);
01972     }
01973     if (table->subtables[y].keys == 1) {
01974         assert(table->vars[yindex]->ref != 1);
01975     }
01976 #endif
01977 
01978 #ifdef DD_STATS
01979     extsymmcalls++;
01980 #endif
01981 
01982     arccount = 0;
01983     counter = (int) (table->subtables[x].keys *
01984               (table->symmviolation/100.0) + 0.5);
01985     one = DD_ONE(table);
01986 
01987     slots = table->subtables[x].slots;
01988     list = table->subtables[x].nodelist;
01989     for (i = 0; i < slots; i++) {
01990         f = list[i];
01991         while (f != sentinel) {
01992             /* Find f1, f0, f11, f10, f01, f00. */
01993             f1 = cuddT(f);
01994             f0 = Cudd_Regular(cuddE(f));
01995             comple = Cudd_IsComplement(cuddE(f));
01996             notproj = f1 != one || f0 != one || f->ref != (DdHalfWord) 1;
01997             if (f1->index == (unsigned) yindex) {
01998                 arccount++;
01999                 f11 = cuddT(f1); f10 = cuddE(f1);
02000             } else {
02001                 if ((int) f0->index != yindex) {
02002                     /* If f is an isolated projection function it is
02003                     ** allowed to bypass layer y.
02004                     */
02005                     if (notproj) {
02006                         if (counter == 0)
02007                             return(0);
02008                         counter--; /* f bypasses layer y */
02009                     }
02010                 }
02011                 f11 = f10 = f1;
02012             }
02013             if ((int) f0->index == yindex) {
02014                 arccount++;
02015                 f01 = cuddT(f0); f00 = cuddE(f0);
02016             } else {
02017                 f01 = f00 = f0;
02018             }
02019             if (comple) {
02020                 f01 = Cudd_Not(f01);
02021                 f00 = Cudd_Not(f00);
02022             }
02023 
02024             /* Unless we are looking at a projection function
02025             ** without external references except the one from the
02026             ** table, we insist that f01 == f10 or f11 == f00
02027             */
02028             if (notproj) {
02029                 if (f01 != f10 && f11 != f00) {
02030                     if (counter == 0)
02031                         return(0);
02032                     counter--;
02033                 }
02034             }
02035 
02036             f = f->next;
02037         } /* while */
02038     } /* for */
02039 
02040     /* Calculate the total reference counts of y */
02041     TotalRefCount = -1; /* -1 for projection function */
02042     slots = table->subtables[y].slots;
02043     list = table->subtables[y].nodelist;
02044     for (i = 0; i < slots; i++) {
02045         f = list[i];
02046         while (f != sentinel) {
02047             TotalRefCount += f->ref;
02048             f = f->next;
02049         }
02050     }
02051 
02052     arccounter = (int) (table->subtables[y].keys *
02053                  (table->arcviolation/100.0) + 0.5);
02054     res = arccount >= TotalRefCount - arccounter;
02055 
02056 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
02057     if (res) {
02058         (void) fprintf(table->out,
02059                        "Found extended symmetry! x = %d\ty = %d\tPos(%d,%d)\n",
02060                        xindex,yindex,x,y);
02061     }
02062 #endif
02063 
02064 #ifdef DD_STATS
02065     if (res)
02066         extsymm++;
02067 #endif
02068     return(res);
02069 
02070 } /* 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 613 of file cuddGroup.c.

00618 {
00619     int low;
00620     int high;
00621 
00622     /* Check whether no variables in this group already exist.
00623     ** If so, return immediately. The calling procedure will know from
00624     ** the values of upper that no reordering is needed.
00625     */
00626     if ((int) treenode->low >= table->size) {
00627         *lower = table->size;
00628         *upper = -1;
00629         return;
00630     }
00631 
00632     *lower = low = (unsigned int) table->perm[treenode->index];
00633     high = (int) (low + treenode->size - 1);
00634 
00635     if (high >= table->size) {
00636         /* This is the case of a partially existing group. The aim is to
00637         ** reorder as many variables as safely possible.  If the tree
00638         ** node is terminal, we just reorder the subset of the group
00639         ** that is currently in existence.  If the group has
00640         ** subgroups, then we only reorder those subgroups that are
00641         ** fully instantiated.  This way we avoid breaking up a group.
00642         */
00643         MtrNode *auxnode = treenode->child;
00644         if (auxnode == NULL) {
00645             *upper = (unsigned int) table->size - 1;
00646         } else {
00647             /* Search the subgroup that strands the table->size line.
00648             ** If the first group starts at 0 and goes past table->size
00649             ** upper will get -1, thus correctly signaling that no reordering
00650             ** should take place.
00651             */
00652             while (auxnode != NULL) {
00653                 int thisLower = table->perm[auxnode->low];
00654                 int thisUpper = thisLower + auxnode->size - 1;
00655                 if (thisUpper >= table->size && thisLower < table->size)
00656                     *upper = (unsigned int) thisLower - 1;
00657                 auxnode = auxnode->younger;
00658             }
00659         }
00660     } else {
00661         /* Normal case: All the variables of the group exist. */
00662         *upper = (unsigned int) high;
00663     }
00664 
00665 #ifdef DD_DEBUG
00666     /* Make sure that all variables in group are contiguous. */
00667     assert(treenode->size >= *upper - *lower + 1);
00668 #endif
00669 
00670     return;
00671 
00672 } /* 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 1484 of file cuddGroup.c.

01489 {
01490     Move *move;
01491     int  size;
01492     int  i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
01493     int  swapx,swapy;
01494 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01495     int  initialSize,bestSize;
01496 #endif
01497 
01498 #ifdef DD_DEBUG
01499     /* We assume that x < y */
01500     assert(x < y);
01501 #endif
01502     /* Find top, bottom, and size for the two groups. */
01503     xbot = x;
01504     xtop = table->subtables[x].next;
01505     xsize = xbot - xtop + 1;
01506     ybot = y;
01507     while ((unsigned) ybot < table->subtables[ybot].next)
01508         ybot = table->subtables[ybot].next;
01509     ytop = y;
01510     ysize = ybot - ytop + 1;
01511 
01512 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01513     initialSize = bestSize = table->keys - table->isolated;
01514 #endif
01515     /* Sift the variables of the second group up through the first group */
01516     for (i = 1; i <= ysize; i++) {
01517         for (j = 1; j <= xsize; j++) {
01518             size = cuddSwapInPlace(table,x,y);
01519             if (size == 0) goto ddGroupMoveOutOfMem;
01520 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01521             if (size < bestSize)
01522                 bestSize = size;
01523 #endif
01524             swapx = x; swapy = y;
01525             y = x;
01526             x = cuddNextLow(table,y);
01527         }
01528         y = ytop + i;
01529         x = cuddNextLow(table,y);
01530     }
01531 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01532     if ((bestSize < initialSize) && (bestSize < size))
01533         (void) fprintf(table->out,"Missed local minimum: initialSize:%d  bestSize:%d  finalSize:%d\n",initialSize,bestSize,size);
01534 #endif
01535 
01536     /* fix groups */
01537     y = xtop; /* ytop is now where xtop used to be */
01538     for (i = 0; i < ysize - 1; i++) {
01539         table->subtables[y].next = cuddNextHigh(table,y);
01540         y = cuddNextHigh(table,y);
01541     }
01542     table->subtables[y].next = xtop; /* y is bottom of its group, join */
01543                                     /* it to top of its group */
01544     x = cuddNextHigh(table,y);
01545     newxtop = x;
01546     for (i = 0; i < xsize - 1; i++) {
01547         table->subtables[x].next = cuddNextHigh(table,x);
01548         x = cuddNextHigh(table,x);
01549     }
01550     table->subtables[x].next = newxtop; /* x is bottom of its group, join */
01551                                     /* it to top of its group */
01552 #ifdef DD_DEBUG
01553     if (pr > 0) (void) fprintf(table->out,"ddGroupMove:\n");
01554 #endif
01555 
01556     /* Store group move */
01557     move = (Move *) cuddDynamicAllocNode(table);
01558     if (move == NULL) goto ddGroupMoveOutOfMem;
01559     move->x = swapx;
01560     move->y = swapy;
01561     move->flags = MTR_DEFAULT;
01562     move->size = table->keys - table->isolated;
01563     move->next = *moves;
01564     *moves = move;
01565 
01566     return(table->keys - table->isolated);
01567 
01568 ddGroupMoveOutOfMem:
01569     while (*moves != NULL) {
01570         move = (*moves)->next;
01571         cuddDeallocMove(table, *moves);
01572         *moves = move;
01573     }
01574     return(0);
01575 
01576 } /* 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 1590 of file cuddGroup.c.

01594 {
01595     int size;
01596     int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
01597 
01598 
01599 #ifdef DD_DEBUG
01600     /* We assume that x < y */
01601     assert(x < y);
01602 #endif
01603 
01604     /* Find top, bottom, and size for the two groups. */
01605     xbot = x;
01606     xtop = table->subtables[x].next;
01607     xsize = xbot - xtop + 1;
01608     ybot = y;
01609     while ((unsigned) ybot < table->subtables[ybot].next)
01610         ybot = table->subtables[ybot].next;
01611     ytop = y;
01612     ysize = ybot - ytop + 1;
01613 
01614     /* Sift the variables of the second group up through the first group */
01615     for (i = 1; i <= ysize; i++) {
01616         for (j = 1; j <= xsize; j++) {
01617             size = cuddSwapInPlace(table,x,y);
01618             if (size == 0)
01619                 return(0);
01620             y = x;
01621             x = cuddNextLow(table,y);
01622         }
01623         y = ytop + i;
01624         x = cuddNextLow(table,y);
01625     }
01626 
01627     /* fix groups */
01628     y = xtop;
01629     for (i = 0; i < ysize - 1; i++) {
01630         table->subtables[y].next = cuddNextHigh(table,y);
01631         y = cuddNextHigh(table,y);
01632     }
01633     table->subtables[y].next = xtop; /* y is bottom of its group, join */
01634                                     /* to its top */
01635     x = cuddNextHigh(table,y);
01636     newxtop = x;
01637     for (i = 0; i < xsize - 1; i++) {
01638         table->subtables[x].next = cuddNextHigh(table,x);
01639         x = cuddNextHigh(table,x);
01640     }
01641     table->subtables[x].next = newxtop; /* x is bottom of its group, join */
01642                                     /* to its top */
01643 #ifdef DD_DEBUG
01644     if (pr > 0) (void) fprintf(table->out,"ddGroupMoveBackward:\n");
01645 #endif
01646 
01647     return(1);
01648 
01649 } /* end of ddGroupMoveBackward */

static int ddGroupSifting ( DdManager table,
int  lower,
int  upper,
DD_CHKFP  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 716 of file cuddGroup.c.

00722 {
00723     int         *var;
00724     int         i,j,x,xInit;
00725     int         nvars;
00726     int         classes;
00727     int         result;
00728     int         *sifted;
00729     int         merged;
00730     int         dissolve;
00731 #ifdef DD_STATS
00732     unsigned    previousSize;
00733 #endif
00734     int         xindex;
00735 
00736     nvars = table->size;
00737 
00738     /* Order variables to sift. */
00739     entry = NULL;
00740     sifted = NULL;
00741     var = ALLOC(int,nvars);
00742     if (var == NULL) {
00743         table->errorCode = CUDD_MEMORY_OUT;
00744         goto ddGroupSiftingOutOfMem;
00745     }
00746     entry = ALLOC(int,nvars);
00747     if (entry == NULL) {
00748         table->errorCode = CUDD_MEMORY_OUT;
00749         goto ddGroupSiftingOutOfMem;
00750     }
00751     sifted = ALLOC(int,nvars);
00752     if (sifted == NULL) {
00753         table->errorCode = CUDD_MEMORY_OUT;
00754         goto ddGroupSiftingOutOfMem;
00755     }
00756 
00757     /* Here we consider only one representative for each group. */
00758     for (i = 0, classes = 0; i < nvars; i++) {
00759         sifted[i] = 0;
00760         x = table->perm[i];
00761         if ((unsigned) x >= table->subtables[x].next) {
00762             entry[i] = table->subtables[x].keys;
00763             var[classes] = i;
00764             classes++;
00765         }
00766     }
00767 
00768     qsort((void *)var,classes,sizeof(int),
00769           (DD_QSFP) ddUniqueCompareGroup);
00770 
00771     if (lazyFlag) {
00772         for (i = 0; i < nvars; i ++) {
00773             ddResetVarHandled(table, i);
00774         }
00775     }
00776 
00777     /* Now sift. */
00778     for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
00779         if (ddTotalNumberSwapping >= table->siftMaxSwap)
00780             break;
00781         xindex = var[i];
00782         if (sifted[xindex] == 1) /* variable already sifted as part of group */
00783             continue;
00784         x = table->perm[xindex]; /* find current level of this variable */
00785 
00786         if (x < lower || x > upper || table->subtables[x].bindVar == 1)
00787             continue;
00788 #ifdef DD_STATS
00789         previousSize = table->keys - table->isolated;
00790 #endif
00791 #ifdef DD_DEBUG
00792         /* x is bottom of group */
00793         assert((unsigned) x >= table->subtables[x].next);
00794 #endif
00795         if ((unsigned) x == table->subtables[x].next) {
00796             dissolve = 1;
00797             result = ddGroupSiftingAux(table,x,lower,upper,checkFunction,
00798                                         lazyFlag);
00799         } else {
00800             dissolve = 0;
00801             result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag);
00802         }
00803         if (!result) goto ddGroupSiftingOutOfMem;
00804 
00805         /* check for aggregation */
00806         merged = 0;
00807         if (lazyFlag == 0 && table->groupcheck == CUDD_GROUP_CHECK7) {
00808             x = table->perm[xindex]; /* find current level */
00809             if ((unsigned) x == table->subtables[x].next) { /* not part of a group */
00810                 if (x != upper && sifted[table->invperm[x+1]] == 0 &&
00811                 (unsigned) x+1 == table->subtables[x+1].next) {
00812                     if (ddSecDiffCheck(table,x,x+1)) {
00813                         merged =1;
00814                         ddCreateGroup(table,x,x+1);
00815                     }
00816                 }
00817                 if (x != lower && sifted[table->invperm[x-1]] == 0 &&
00818                 (unsigned) x-1 == table->subtables[x-1].next) {
00819                     if (ddSecDiffCheck(table,x-1,x)) {
00820                         merged =1;
00821                         ddCreateGroup(table,x-1,x);
00822                     }
00823                 }
00824             }
00825         }
00826 
00827         if (merged) { /* a group was created */
00828             /* move x to bottom of group */
00829             while ((unsigned) x < table->subtables[x].next)
00830                 x = table->subtables[x].next;
00831             /* sift */
00832             result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag);
00833             if (!result) goto ddGroupSiftingOutOfMem;
00834 #ifdef DD_STATS
00835             if (table->keys < previousSize + table->isolated) {
00836                 (void) fprintf(table->out,"_");
00837             } else if (table->keys > previousSize + table->isolated) {
00838                 (void) fprintf(table->out,"^");
00839             } else {
00840                 (void) fprintf(table->out,"*");
00841             }
00842             fflush(table->out);
00843         } else {
00844             if (table->keys < previousSize + table->isolated) {
00845                 (void) fprintf(table->out,"-");
00846             } else if (table->keys > previousSize + table->isolated) {
00847                 (void) fprintf(table->out,"+");
00848             } else {
00849                 (void) fprintf(table->out,"=");
00850             }
00851             fflush(table->out);
00852 #endif
00853         }
00854 
00855         /* Mark variables in the group just sifted. */
00856         x = table->perm[xindex];
00857         if ((unsigned) x != table->subtables[x].next) {
00858             xInit = x;
00859             do {
00860                 j = table->invperm[x];
00861                 sifted[j] = 1;
00862                 x = table->subtables[x].next;
00863             } while (x != xInit);
00864 
00865             /* Dissolve the group if it was created. */
00866             if (lazyFlag == 0 && dissolve) {
00867                 do {
00868                     j = table->subtables[x].next;
00869                     table->subtables[x].next = x;
00870                     x = j;
00871                 } while (x != xInit);
00872             }
00873         }
00874 
00875 #ifdef DD_DEBUG
00876         if (pr > 0) (void) fprintf(table->out,"ddGroupSifting:");
00877 #endif
00878 
00879       if (lazyFlag) ddSetVarHandled(table, xindex);
00880     } /* for */
00881 
00882     FREE(sifted);
00883     FREE(var);
00884     FREE(entry);
00885 
00886     return(1);
00887 
00888 ddGroupSiftingOutOfMem:
00889     if (entry != NULL)  FREE(entry);
00890     if (var != NULL)    FREE(var);
00891     if (sifted != NULL) FREE(sifted);
00892 
00893     return(0);
00894 
00895 } /* end of ddGroupSifting */

static int ddGroupSiftingAux ( DdManager table,
int  x,
int  xLow,
int  xHigh,
DD_CHKFP  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 952 of file cuddGroup.c.

00959 {
00960     Move *move;
00961     Move *moves;        /* list of moves */
00962     int  initialSize;
00963     int  result;
00964     int  y;
00965     int  topbot;
00966 
00967 #ifdef DD_DEBUG
00968     if (pr > 0) (void) fprintf(table->out,
00969                                "ddGroupSiftingAux from %d to %d\n",xLow,xHigh);
00970     assert((unsigned) x >= table->subtables[x].next); /* x is bottom of group */
00971 #endif
00972 
00973     initialSize = table->keys - table->isolated;
00974     moves = NULL;
00975 
00976     originalSize = initialSize;         /* for lazy sifting */
00977 
00978     /* If we have a singleton, we check for aggregation in both
00979     ** directions before we sift.
00980     */
00981     if ((unsigned) x == table->subtables[x].next) {
00982         /* Will go down first, unless x == xHigh:
00983         ** Look for aggregation above x.
00984         */
00985         for (y = x; y > xLow; y--) {
00986             if (!checkFunction(table,y-1,y))
00987                 break;
00988             topbot = table->subtables[y-1].next; /* find top of y-1's group */
00989             table->subtables[y-1].next = y;
00990             table->subtables[x].next = topbot; /* x is bottom of group so its */
00991                                                /* next is top of y-1's group */
00992             y = topbot + 1; /* add 1 for y--; new y is top of group */
00993         }
00994         /* Will go up first unless x == xlow:
00995         ** Look for aggregation below x.
00996         */
00997         for (y = x; y < xHigh; y++) {
00998             if (!checkFunction(table,y,y+1))
00999                 break;
01000             /* find bottom of y+1's group */
01001             topbot = y + 1;
01002             while ((unsigned) topbot < table->subtables[topbot].next) {
01003                 topbot = table->subtables[topbot].next;
01004             }
01005             table->subtables[topbot].next = table->subtables[y].next;
01006             table->subtables[y].next = y + 1;
01007             y = topbot - 1; /* subtract 1 for y++; new y is bottom of group */
01008         }
01009     }
01010 
01011     /* Now x may be in the middle of a group.
01012     ** Find bottom of x's group.
01013     */
01014     while ((unsigned) x < table->subtables[x].next)
01015         x = table->subtables[x].next;
01016 
01017     if (x == xLow) { /* Sift down */
01018 #ifdef DD_DEBUG
01019         /* x must be a singleton */
01020         assert((unsigned) x == table->subtables[x].next);
01021 #endif
01022         if (x == xHigh) return(1);      /* just one variable */
01023 
01024         if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
01025             goto ddGroupSiftingAuxOutOfMem;
01026         /* at this point x == xHigh, unless early term */
01027 
01028         /* move backward and stop at best position */
01029         result = ddGroupSiftingBackward(table,moves,initialSize,
01030                                         DD_SIFT_DOWN,lazyFlag);
01031 #ifdef DD_DEBUG
01032         assert(table->keys - table->isolated <= (unsigned) initialSize);
01033 #endif
01034         if (!result) goto ddGroupSiftingAuxOutOfMem;
01035 
01036     } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */
01037 #ifdef DD_DEBUG
01038         /* x is bottom of group */
01039         assert((unsigned) x >= table->subtables[x].next);
01040 #endif
01041         /* Find top of x's group */
01042         x = table->subtables[x].next;
01043 
01044         if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
01045             goto ddGroupSiftingAuxOutOfMem;
01046         /* at this point x == xLow, unless early term */
01047 
01048         /* move backward and stop at best position */
01049         result = ddGroupSiftingBackward(table,moves,initialSize,
01050                                         DD_SIFT_UP,lazyFlag);
01051 #ifdef DD_DEBUG
01052         assert(table->keys - table->isolated <= (unsigned) initialSize);
01053 #endif
01054         if (!result) goto ddGroupSiftingAuxOutOfMem;
01055 
01056     } else if (x - xLow > xHigh - x) { /* must go down first: shorter */
01057         if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
01058             goto ddGroupSiftingAuxOutOfMem;
01059         /* at this point x == xHigh, unless early term */
01060 
01061         /* Find top of group */
01062         if (moves) {
01063             x = moves->y;
01064         }
01065         while ((unsigned) x < table->subtables[x].next)
01066             x = table->subtables[x].next;
01067         x = table->subtables[x].next;
01068 #ifdef DD_DEBUG
01069         /* x should be the top of a group */
01070         assert((unsigned) x <= table->subtables[x].next);
01071 #endif
01072 
01073         if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
01074             goto ddGroupSiftingAuxOutOfMem;
01075 
01076         /* move backward and stop at best position */
01077         result = ddGroupSiftingBackward(table,moves,initialSize,
01078                                         DD_SIFT_UP,lazyFlag);
01079 #ifdef DD_DEBUG
01080         assert(table->keys - table->isolated <= (unsigned) initialSize);
01081 #endif
01082         if (!result) goto ddGroupSiftingAuxOutOfMem;
01083 
01084     } else { /* moving up first: shorter */
01085         /* Find top of x's group */
01086         x = table->subtables[x].next;
01087 
01088         if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
01089             goto ddGroupSiftingAuxOutOfMem;
01090         /* at this point x == xHigh, unless early term */
01091 
01092         if (moves) {
01093             x = moves->x;
01094         }
01095         while ((unsigned) x < table->subtables[x].next)
01096             x = table->subtables[x].next;
01097 #ifdef DD_DEBUG
01098         /* x is bottom of a group */
01099         assert((unsigned) x >= table->subtables[x].next);
01100 #endif
01101 
01102         if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
01103             goto ddGroupSiftingAuxOutOfMem;
01104 
01105         /* move backward and stop at best position */
01106         result = ddGroupSiftingBackward(table,moves,initialSize,
01107                                         DD_SIFT_DOWN,lazyFlag);
01108 #ifdef DD_DEBUG
01109         assert(table->keys - table->isolated <= (unsigned) initialSize);
01110 #endif
01111         if (!result) goto ddGroupSiftingAuxOutOfMem;
01112     }
01113 
01114     while (moves != NULL) {
01115         move = moves->next;
01116         cuddDeallocMove(table, moves);
01117         moves = move;
01118     }
01119 
01120     return(1);
01121 
01122 ddGroupSiftingAuxOutOfMem:
01123     while (moves != NULL) {
01124         move = moves->next;
01125         cuddDeallocMove(table, moves);
01126         moves = move;
01127     }
01128 
01129     return(0);
01130 
01131 } /* 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 1664 of file cuddGroup.c.

01670 {
01671     Move *move;
01672     int  res;
01673     Move *end_move;
01674     int diff, tmp_diff;
01675     int index;
01676     unsigned int pairlev;
01677 
01678     if (lazyFlag) {
01679         end_move = NULL;
01680 
01681         /* Find the minimum size, and the earliest position at which it
01682         ** was achieved. */
01683         for (move = moves; move != NULL; move = move->next) {
01684             if (move->size < size) {
01685                 size = move->size;
01686                 end_move = move;
01687             } else if (move->size == size) {
01688                 if (end_move == NULL) end_move = move;
01689             }
01690         }
01691 
01692         /* Find among the moves that give minimum size the one that
01693         ** minimizes the distance from the corresponding variable. */
01694         if (moves != NULL) {
01695             diff = Cudd_ReadSize(table) + 1;
01696             index = (upFlag == 1) ?
01697                     table->invperm[moves->x] : table->invperm[moves->y];
01698             pairlev =
01699                 (unsigned) table->perm[Cudd_bddReadPairIndex(table, index)];
01700 
01701             for (move = moves; move != NULL; move = move->next) {
01702                 if (move->size == size) {
01703                     if (upFlag == 1) {
01704                         tmp_diff = (move->x > pairlev) ?
01705                                     move->x - pairlev : pairlev - move->x;
01706                     } else {
01707                         tmp_diff = (move->y > pairlev) ?
01708                                     move->y - pairlev : pairlev - move->y;
01709                     }
01710                     if (tmp_diff < diff) {
01711                         diff = tmp_diff;
01712                         end_move = move;
01713                     }
01714                 }
01715             }
01716         }
01717     } else {
01718         /* Find the minimum size. */
01719         for (move = moves; move != NULL; move = move->next) {
01720             if (move->size < size) {
01721                 size = move->size;
01722             }
01723         }
01724     }
01725 
01726     /* In case of lazy sifting, end_move identifies the position at
01727     ** which we want to stop.  Otherwise, we stop as soon as we meet
01728     ** the minimum size. */
01729     for (move = moves; move != NULL; move = move->next) {
01730         if (lazyFlag) {
01731             if (move == end_move) return(1);
01732         } else {
01733             if (move->size == size) return(1);
01734         }
01735         if ((table->subtables[move->x].next == move->x) &&
01736         (table->subtables[move->y].next == move->y)) {
01737             res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
01738             if (!res) return(0);
01739 #ifdef DD_DEBUG
01740             if (pr > 0) (void) fprintf(table->out,"ddGroupSiftingBackward:\n");
01741             assert(table->subtables[move->x].next == move->x);
01742             assert(table->subtables[move->y].next == move->y);
01743 #endif
01744         } else { /* Group move necessary */
01745             if (move->flags == MTR_NEWNODE) {
01746                 ddDissolveGroup(table,(int)move->x,(int)move->y);
01747             } else {
01748                 res = ddGroupMoveBackward(table,(int)move->x,(int)move->y);
01749                 if (!res) return(0);
01750             }
01751         }
01752 
01753     }
01754 
01755     return(1);
01756 
01757 } /* end of ddGroupSiftingBackward */

static int ddGroupSiftingDown ( DdManager table,
int  x,
int  xHigh,
DD_CHKFP  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 1308 of file cuddGroup.c.

01314 {
01315     Move *move;
01316     int  y;
01317     int  size;
01318     int  limitSize;
01319     int  gxtop,gybot;
01320     int  R;     /* upper bound on node decrease */
01321     int  xindex, yindex;
01322     int  isolated, allVars;
01323     int  z;
01324     int  zindex;
01325 #ifdef DD_DEBUG
01326     int  checkR;
01327 #endif
01328 
01329     /* If the group consists of simple variables, there is no point in
01330     ** sifting it down. This check is redundant if the projection functions
01331     ** do not have external references, because the computation of the
01332     ** lower bound takes care of the problem.  It is necessary otherwise to
01333     ** prevent the sifting down of simple variables. */
01334     y = x;
01335     allVars = 1;
01336     do {
01337         if (table->subtables[y].keys != 1) {
01338             allVars = 0;
01339             break;
01340         }
01341         y = table->subtables[y].next;
01342     } while (table->subtables[y].next != (unsigned) x);
01343     if (allVars)
01344         return(1);
01345 
01346     /* Initialize R. */
01347     xindex = table->invperm[x];
01348     gxtop = table->subtables[x].next;
01349     limitSize = size = table->keys - table->isolated;
01350     R = 0;
01351     for (z = xHigh; z > gxtop; z--) {
01352         zindex = table->invperm[z];
01353         if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
01354             isolated = table->vars[zindex]->ref == 1;
01355             R += table->subtables[z].keys - isolated;
01356         }
01357     }
01358 
01359     y = cuddNextHigh(table,x);
01360     while (y <= xHigh && size - R < limitSize) {
01361 #ifdef DD_DEBUG
01362         gxtop = table->subtables[x].next;
01363         checkR = 0;
01364         for (z = xHigh; z > gxtop; z--) {
01365             zindex = table->invperm[z];
01366             if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
01367                 isolated = table->vars[zindex]->ref == 1;
01368                 checkR += table->subtables[z].keys - isolated;
01369             }
01370         }
01371         assert(R >= checkR);
01372 #endif
01373         /* Find bottom of y group. */
01374         gybot = table->subtables[y].next;
01375         while (table->subtables[gybot].next != (unsigned) y)
01376             gybot = table->subtables[gybot].next;
01377 
01378         if (checkFunction(table,x,y)) {
01379             /* Group found: attach groups and record move. */
01380             gxtop = table->subtables[x].next;
01381             table->subtables[x].next = y;
01382             table->subtables[gybot].next = gxtop;
01383             move = (Move *)cuddDynamicAllocNode(table);
01384             if (move == NULL) goto ddGroupSiftingDownOutOfMem;
01385             move->x = x;
01386             move->y = y;
01387             move->flags = MTR_NEWNODE;
01388             move->size = table->keys - table->isolated;
01389             move->next = *moves;
01390             *moves = move;
01391         } else if (table->subtables[x].next == (unsigned) x &&
01392                    table->subtables[y].next == (unsigned) y) {
01393             /* x and y are self groups */
01394             /* Update upper bound on node decrease. */
01395             yindex = table->invperm[y];
01396             if (cuddTestInteract(table,xindex,yindex)) {
01397                 isolated = table->vars[yindex]->ref == 1;
01398                 R -= table->subtables[y].keys - isolated;
01399             }
01400             size = cuddSwapInPlace(table,x,y);
01401 #ifdef DD_DEBUG
01402             assert(table->subtables[x].next == (unsigned) x);
01403             assert(table->subtables[y].next == (unsigned) y);
01404 #endif
01405             if (size == 0) goto ddGroupSiftingDownOutOfMem;
01406 
01407             /* Record move. */
01408             move = (Move *) cuddDynamicAllocNode(table);
01409             if (move == NULL) goto ddGroupSiftingDownOutOfMem;
01410             move->x = x;
01411             move->y = y;
01412             move->flags = MTR_DEFAULT;
01413             move->size = size;
01414             move->next = *moves;
01415             *moves = move;
01416 
01417 #ifdef DD_DEBUG
01418             if (pr > 0) (void) fprintf(table->out,
01419                                        "ddGroupSiftingDown (2 single groups):\n");
01420 #endif
01421             if ((double) size > (double) limitSize * table->maxGrowth)
01422                 return(1);
01423             if (size < limitSize) limitSize = size;
01424 
01425             x = y;
01426             y = cuddNextHigh(table,x);
01427         } else { /* Group move */
01428             /* Update upper bound on node decrease: first phase. */
01429             gxtop = table->subtables[x].next;
01430             z = gxtop + 1;
01431             do {
01432                 zindex = table->invperm[z];
01433                 if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
01434                     isolated = table->vars[zindex]->ref == 1;
01435                     R -= table->subtables[z].keys - isolated;
01436                 }
01437                 z++;
01438             } while (z <= gybot);
01439             size = ddGroupMove(table,x,y,moves);
01440             if (size == 0) goto ddGroupSiftingDownOutOfMem;
01441             if ((double) size > (double) limitSize * table->maxGrowth)
01442                 return(1);
01443             if (size < limitSize) limitSize = size;
01444 
01445             /* Update upper bound on node decrease: second phase. */
01446             gxtop = table->subtables[gybot].next;
01447             for (z = gxtop + 1; z <= gybot; z++) {
01448                 zindex = table->invperm[z];
01449                 if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
01450                     isolated = table->vars[zindex]->ref == 1;
01451                     R += table->subtables[z].keys - isolated;
01452                 }
01453             }
01454         }
01455         x = gybot;
01456         y = cuddNextHigh(table,x);
01457     }
01458 
01459     return(1);
01460 
01461 ddGroupSiftingDownOutOfMem:
01462     while (*moves != NULL) {
01463         move = (*moves)->next;
01464         cuddDeallocMove(table, *moves);
01465         *moves = move;
01466     }
01467 
01468     return(0);
01469 
01470 } /* end of ddGroupSiftingDown */

static int ddGroupSiftingUp ( DdManager table,
int  y,
int  xLow,
DD_CHKFP  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 1150 of file cuddGroup.c.

01156 {
01157     Move *move;
01158     int  x;
01159     int  size;
01160     int  i;
01161     int  gxtop,gybot;
01162     int  limitSize;
01163     int  xindex, yindex;
01164     int  zindex;
01165     int  z;
01166     int  isolated;
01167     int  L;     /* lower bound on DD size */
01168 #ifdef DD_DEBUG
01169     int  checkL;
01170 #endif
01171 
01172     yindex = table->invperm[y];
01173 
01174     /* Initialize the lower bound.
01175     ** The part of the DD below the bottom of y's group will not change.
01176     ** The part of the DD above y that does not interact with any
01177     ** variable of y's group will not change.
01178     ** The rest may vanish in the best case, except for
01179     ** the nodes at level xLow, which will not vanish, regardless.
01180     ** What we use here is not really a lower bound, because we ignore
01181     ** the interactions with all variables except y.
01182     */
01183     limitSize = L = table->keys - table->isolated;
01184     gybot = y;
01185     while ((unsigned) gybot < table->subtables[gybot].next)
01186         gybot = table->subtables[gybot].next;
01187     for (z = xLow + 1; z <= gybot; z++) {
01188         zindex = table->invperm[z];
01189         if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
01190             isolated = table->vars[zindex]->ref == 1;
01191             L -= table->subtables[z].keys - isolated;
01192         }
01193     }
01194 
01195     x = cuddNextLow(table,y);
01196     while (x >= xLow && L <= limitSize) {
01197 #ifdef DD_DEBUG
01198         gybot = y;
01199         while ((unsigned) gybot < table->subtables[gybot].next)
01200             gybot = table->subtables[gybot].next;
01201         checkL = table->keys - table->isolated;
01202         for (z = xLow + 1; z <= gybot; z++) {
01203             zindex = table->invperm[z];
01204             if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
01205                 isolated = table->vars[zindex]->ref == 1;
01206                 checkL -= table->subtables[z].keys - isolated;
01207             }
01208         }
01209         if (pr > 0 && L != checkL) {
01210             (void) fprintf(table->out,
01211                            "Inaccurate lower bound: L = %d checkL = %d\n",
01212                            L, checkL);
01213         }
01214 #endif
01215         gxtop = table->subtables[x].next;
01216         if (checkFunction(table,x,y)) {
01217             /* Group found, attach groups */
01218             table->subtables[x].next = y;
01219             i = table->subtables[y].next;
01220             while (table->subtables[i].next != (unsigned) y)
01221                 i = table->subtables[i].next;
01222             table->subtables[i].next = gxtop;
01223             move = (Move *)cuddDynamicAllocNode(table);
01224             if (move == NULL) goto ddGroupSiftingUpOutOfMem;
01225             move->x = x;
01226             move->y = y;
01227             move->flags = MTR_NEWNODE;
01228             move->size = table->keys - table->isolated;
01229             move->next = *moves;
01230             *moves = move;
01231         } else if (table->subtables[x].next == (unsigned) x &&
01232                    table->subtables[y].next == (unsigned) y) {
01233             /* x and y are self groups */
01234             xindex = table->invperm[x];
01235             size = cuddSwapInPlace(table,x,y);
01236 #ifdef DD_DEBUG
01237             assert(table->subtables[x].next == (unsigned) x);
01238             assert(table->subtables[y].next == (unsigned) y);
01239 #endif
01240             if (size == 0) goto ddGroupSiftingUpOutOfMem;
01241             /* Update the lower bound. */
01242             if (cuddTestInteract(table,xindex,yindex)) {
01243                 isolated = table->vars[xindex]->ref == 1;
01244                 L += table->subtables[y].keys - isolated;
01245             }
01246             move = (Move *)cuddDynamicAllocNode(table);
01247             if (move == NULL) goto ddGroupSiftingUpOutOfMem;
01248             move->x = x;
01249             move->y = y;
01250             move->flags = MTR_DEFAULT;
01251             move->size = size;
01252             move->next = *moves;
01253             *moves = move;
01254 
01255 #ifdef DD_DEBUG
01256             if (pr > 0) (void) fprintf(table->out,
01257                                        "ddGroupSiftingUp (2 single groups):\n");
01258 #endif
01259             if ((double) size > (double) limitSize * table->maxGrowth)
01260                 return(1);
01261             if (size < limitSize) limitSize = size;
01262         } else { /* Group move */
01263             size = ddGroupMove(table,x,y,moves);
01264             if (size == 0) goto ddGroupSiftingUpOutOfMem;
01265             /* Update the lower bound. */
01266             z = (*moves)->y;
01267             do {
01268                 zindex = table->invperm[z];
01269                 if (cuddTestInteract(table,zindex,yindex)) {
01270                     isolated = table->vars[zindex]->ref == 1;
01271                     L += table->subtables[z].keys - isolated;
01272                 }
01273                 z = table->subtables[z].next;
01274             } while (z != (int) (*moves)->y);
01275             if ((double) size > (double) limitSize * table->maxGrowth)
01276                 return(1);
01277             if (size < limitSize) limitSize = size;
01278         }
01279         y = gxtop;
01280         x = cuddNextLow(table,y);
01281     }
01282 
01283     return(1);
01284 
01285 ddGroupSiftingUpOutOfMem:
01286     while (*moves != NULL) {
01287         move = (*moves)->next;
01288         cuddDeallocMove(table, *moves);
01289         *moves = move;
01290     }
01291     return(0);
01292 
01293 } /* 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 2172 of file cuddGroup.c.

02175 {
02176     if (index >= dd->size || index < 0) return(-1);
02177     return dd->subtables[dd->perm[index]].varHandled;
02178 
02179 } /* 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 1771 of file cuddGroup.c.

01776 {
01777     int i;
01778     MtrNode *auxnode;
01779     int saveindex;
01780     int newindex;
01781 
01782     /* Merge all variables from low to high in one group, unless
01783     ** this is the topmost group. In such a case we do not merge lest
01784     ** we lose the symmetry information. */
01785     if (treenode != table->tree) {
01786         for (i = low; i < high; i++)
01787             table->subtables[i].next = i+1;
01788         table->subtables[high].next = low;
01789     }
01790 
01791     /* Adjust the index fields of the tree nodes. If a node is the
01792     ** first child of its parent, then the parent may also need adjustment. */
01793     saveindex = treenode->index;
01794     newindex = table->invperm[low];
01795     auxnode = treenode;
01796     do {
01797         auxnode->index = newindex;
01798         if (auxnode->parent == NULL ||
01799                 (int) auxnode->parent->index != saveindex)
01800             break;
01801         auxnode = auxnode->parent;
01802     } while (1);
01803     return;
01804 
01805 } /* 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 1853 of file cuddGroup.c.

01857 {
01858     return(0);
01859 
01860 } /* 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 449 of file cuddGroup.c.

00453 {
00454     int lower;
00455     int upper;
00456     int result;
00457     unsigned int initialSize;
00458 
00459     ddFindNodeHiLo(table,treenode,&lower,&upper);
00460     /* If upper == -1 these variables do not exist yet. */
00461     if (upper == -1)
00462         return(1);
00463 
00464     if (treenode->flags == MTR_FIXED) {
00465         result = 1;
00466     } else {
00467 #ifdef DD_STATS
00468         (void) fprintf(table->out," ");
00469 #endif
00470         switch (method) {
00471         case CUDD_REORDER_RANDOM:
00472         case CUDD_REORDER_RANDOM_PIVOT:
00473             result = cuddSwapping(table,lower,upper,method);
00474             break;
00475         case CUDD_REORDER_SIFT:
00476             result = cuddSifting(table,lower,upper);
00477             break;
00478         case CUDD_REORDER_SIFT_CONVERGE:
00479             do {
00480                 initialSize = table->keys - table->isolated;
00481                 result = cuddSifting(table,lower,upper);
00482                 if (initialSize <= table->keys - table->isolated)
00483                     break;
00484 #ifdef DD_STATS
00485                 else
00486                     (void) fprintf(table->out,"\n");
00487 #endif
00488             } while (result != 0);
00489             break;
00490         case CUDD_REORDER_SYMM_SIFT:
00491             result = cuddSymmSifting(table,lower,upper);
00492             break;
00493         case CUDD_REORDER_SYMM_SIFT_CONV:
00494             result = cuddSymmSiftingConv(table,lower,upper);
00495             break;
00496         case CUDD_REORDER_GROUP_SIFT:
00497             if (table->groupcheck == CUDD_NO_CHECK) {
00498                 result = ddGroupSifting(table,lower,upper,ddNoCheck,
00499                                         DD_NORMAL_SIFT);
00500             } else if (table->groupcheck == CUDD_GROUP_CHECK5) {
00501                 result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
00502                                         DD_NORMAL_SIFT);
00503             } else if (table->groupcheck == CUDD_GROUP_CHECK7) {
00504                 result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
00505                                         DD_NORMAL_SIFT);
00506             } else {
00507                 (void) fprintf(table->err,
00508                                "Unknown group ckecking method\n");
00509                 result = 0;
00510             }
00511             break;
00512         case CUDD_REORDER_GROUP_SIFT_CONV:
00513             do {
00514                 initialSize = table->keys - table->isolated;
00515                 if (table->groupcheck == CUDD_NO_CHECK) {
00516                     result = ddGroupSifting(table,lower,upper,ddNoCheck,
00517                                             DD_NORMAL_SIFT);
00518                 } else if (table->groupcheck == CUDD_GROUP_CHECK5) {
00519                     result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
00520                                             DD_NORMAL_SIFT);
00521                 } else if (table->groupcheck == CUDD_GROUP_CHECK7) {
00522                     result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
00523                                             DD_NORMAL_SIFT);
00524                 } else {
00525                     (void) fprintf(table->err,
00526                                    "Unknown group ckecking method\n");
00527                     result = 0;
00528                 }
00529 #ifdef DD_STATS
00530                 (void) fprintf(table->out,"\n");
00531 #endif
00532                 result = cuddWindowReorder(table,lower,upper,
00533                                            CUDD_REORDER_WINDOW4);
00534                 if (initialSize <= table->keys - table->isolated)
00535                     break;
00536 #ifdef DD_STATS
00537                 else
00538                     (void) fprintf(table->out,"\n");
00539 #endif
00540             } while (result != 0);
00541             break;
00542         case CUDD_REORDER_WINDOW2:
00543         case CUDD_REORDER_WINDOW3:
00544         case CUDD_REORDER_WINDOW4:
00545         case CUDD_REORDER_WINDOW2_CONV:
00546         case CUDD_REORDER_WINDOW3_CONV:
00547         case CUDD_REORDER_WINDOW4_CONV:
00548             result = cuddWindowReorder(table,lower,upper,method);
00549             break;
00550         case CUDD_REORDER_ANNEALING:
00551             result = cuddAnnealing(table,lower,upper);
00552             break;
00553         case CUDD_REORDER_GENETIC:
00554             result = cuddGa(table,lower,upper);
00555             break;
00556         case CUDD_REORDER_LINEAR:
00557             result = cuddLinearAndSifting(table,lower,upper);
00558             break;
00559         case CUDD_REORDER_LINEAR_CONVERGE:
00560             do {
00561                 initialSize = table->keys - table->isolated;
00562                 result = cuddLinearAndSifting(table,lower,upper);
00563                 if (initialSize <= table->keys - table->isolated)
00564                     break;
00565 #ifdef DD_STATS
00566                 else
00567                     (void) fprintf(table->out,"\n");
00568 #endif
00569             } while (result != 0);
00570             break;
00571         case CUDD_REORDER_EXACT:
00572             result = cuddExact(table,lower,upper);
00573             break;
00574         case CUDD_REORDER_LAZY_SIFT:
00575             result = ddGroupSifting(table,lower,upper,ddVarGroupCheck,
00576                                     DD_LAZY_SIFT);
00577             break;
00578         default:
00579             return(0);
00580         }
00581     }
00582 
00583     /* Create a single group for all the variables that were sifted,
00584     ** so that they will be treated as a single block by successive
00585     ** invocations of ddGroupSifting.
00586     */
00587     ddMergeGroups(table,treenode,lower,upper);
00588 
00589 #ifdef DD_DEBUG
00590     if (pr > 0) (void) fprintf(table->out,"ddReorderChildren:");
00591 #endif
00592 
00593     return(result);
00594 
00595 } /* 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 2148 of file cuddGroup.c.

02151 {
02152     if (index >= dd->size || index < 0) return(0);
02153     dd->subtables[dd->perm[index]].varHandled = 0;
02154     return(1);
02155 
02156 } /* 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 1877 of file cuddGroup.c.

01881 {
01882     double Nx,Nx_1;
01883     double Sx;
01884     double threshold;
01885     int    xindex,yindex;
01886 
01887     if (x==0) return(0);
01888 
01889 #ifdef DD_STATS
01890     secdiffcalls++;
01891 #endif
01892     Nx = (double) table->subtables[x].keys;
01893     Nx_1 = (double) table->subtables[x-1].keys;
01894     Sx = (table->subtables[y].keys/Nx) - (Nx/Nx_1);
01895 
01896     threshold = table->recomb / 100.0;
01897     if (Sx < threshold) {
01898         xindex = table->invperm[x];
01899         yindex = table->invperm[y];
01900         if (cuddTestInteract(table,xindex,yindex)) {
01901 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01902             (void) fprintf(table->out,
01903                            "Second difference for %d = %g Pos(%d)\n",
01904                            table->invperm[x],Sx,x);
01905 #endif
01906 #ifdef DD_STATS
01907             secdiff++;
01908 #endif
01909             return(1);
01910         } else {
01911 #ifdef DD_STATS
01912             secdiffmisfire++;
01913 #endif
01914             return(0);
01915         }
01916 
01917     }
01918     return(0);
01919 
01920 } /* 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 2124 of file cuddGroup.c.

02127 {
02128     if (index >= dd->size || index < 0) return(0);
02129     dd->subtables[dd->perm[index]].varHandled = 1;
02130     return(1);
02131 
02132 } /* end of ddSetVarHandled */

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

AutomaticStart

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 357 of file cuddGroup.c.

00361 {
00362     MtrNode  *auxnode;
00363     int res;
00364     Cudd_AggregationType saveCheck;
00365 
00366 #ifdef DD_DEBUG
00367     Mtr_PrintGroups(treenode,1);
00368 #endif
00369 
00370     auxnode = treenode;
00371     while (auxnode != NULL) {
00372         if (auxnode->child != NULL) {
00373             if (!ddTreeSiftingAux(table, auxnode->child, method))
00374                 return(0);
00375             saveCheck = table->groupcheck;
00376             table->groupcheck = CUDD_NO_CHECK;
00377             if (method != CUDD_REORDER_LAZY_SIFT)
00378               res = ddReorderChildren(table, auxnode, CUDD_REORDER_GROUP_SIFT);
00379             else
00380               res = ddReorderChildren(table, auxnode, CUDD_REORDER_LAZY_SIFT);
00381             table->groupcheck = saveCheck;
00382 
00383             if (res == 0)
00384                 return(0);
00385         } else if (auxnode->size > 1) {
00386             if (!ddReorderChildren(table, auxnode, method))
00387                 return(0);
00388         }
00389         auxnode = auxnode->younger;
00390     }
00391 
00392     return(1);
00393 
00394 } /* 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 688 of file cuddGroup.c.

00691 {
00692 #if 0
00693     if (entry[*ptrY] == entry[*ptrX]) {
00694         return((*ptrX) - (*ptrY));
00695     }
00696 #endif
00697     return(entry[*ptrY] - entry[*ptrX]);
00698 
00699 } /* 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 2084 of file cuddGroup.c.

02088 {
02089     int xindex = table->invperm[x];
02090     int yindex = table->invperm[y];
02091 
02092     if (Cudd_bddIsVarToBeUngrouped(table, xindex)) return(0);
02093 
02094     if (Cudd_bddReadPairIndex(table, xindex) == yindex) {
02095         if (ddIsVarHandled(table, xindex) ||
02096             ddIsVarHandled(table, yindex)) {
02097             if (Cudd_bddIsVarToBeGrouped(table, xindex) ||
02098                 Cudd_bddIsVarToBeGrouped(table, yindex) ) {
02099                 if (table->keys - table->isolated <= originalSize) {
02100                     return(1);
02101                 }
02102             }
02103         }
02104     }
02105 
02106     return(0);
02107 
02108 } /* end of ddVarGroupCheck */


Variable Documentation

char rcsid [] DD_UNUSED = "$Id: cuddGroup.c,v 1.44 2009/02/21 18:24:10 fabio Exp $" [static]

Definition at line 115 of file cuddGroup.c.

Definition at line 103 of file cuddReorder.c.

int* entry [static]

Definition at line 118 of file cuddGroup.c.

unsigned int originalSize [static]

Definition at line 132 of file cuddGroup.c.


Generated on Tue Jan 12 13:57:19 2010 for glu-2.2 by  doxygen 1.6.1