#include "util.h"
#include "cuddInt.h"
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) |
MtrNode * | Cudd_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 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.
Definition at line 105 of file cuddGroup.c.
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 */
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 */
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.
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.
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 */
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.