#include "util.h"
#include "cuddInt.h"
Go to the source code of this file.
Defines | |
#define | DD_MAX_SUBTABLE_SPARSITY 8 |
#define | DD_SHRINK_FACTOR 2 |
Functions | |
static int | ddUniqueCompare (int *ptrX, int *ptrY) |
static Move * | ddSwapAny (DdManager *table, int x, int y) |
static int | ddSiftingAux (DdManager *table, int x, int xLow, int xHigh) |
static Move * | ddSiftingUp (DdManager *table, int y, int xLow) |
static Move * | ddSiftingDown (DdManager *table, int x, int xHigh) |
static int | ddSiftingBackward (DdManager *table, int size, Move *moves) |
static int | ddReorderPreprocess (DdManager *table) |
static int | ddReorderPostprocess (DdManager *table) |
static int | ddShuffle (DdManager *table, int *permutation) |
static int | ddSiftUp (DdManager *table, int x, int xLow) |
static void | bddFixTree (DdManager *table, MtrNode *treenode) |
static int | ddUpdateMtrTree (DdManager *table, MtrNode *treenode, int *perm, int *invperm) |
static int | ddCheckPermuation (DdManager *table, MtrNode *treenode, int *perm, int *invperm) |
int | Cudd_ReduceHeap (DdManager *table, Cudd_ReorderingType heuristic, int minsize) |
int | Cudd_ShuffleHeap (DdManager *table, int *permutation) |
DdNode * | cuddDynamicAllocNode (DdManager *table) |
int | cuddSifting (DdManager *table, int lower, int upper) |
int | cuddSwapping (DdManager *table, int lower, int upper, Cudd_ReorderingType heuristic) |
int | cuddNextHigh (DdManager *table, int x) |
int | cuddNextLow (DdManager *table, int x) |
int | cuddSwapInPlace (DdManager *table, int x, int y) |
int | cuddBddAlignToZdd (DdManager *table) |
Variables | |
static char rcsid[] | DD_UNUSED = "$Id: cuddReorder.c,v 1.69 2009/02/21 18:24:10 fabio Exp $" |
static int * | entry |
int | ddTotalNumberSwapping |
#define DD_MAX_SUBTABLE_SPARSITY 8 |
CFile***********************************************************************
FileName [cuddReorder.c]
PackageName [cudd]
Synopsis [Functions for dynamic variable reordering.]
Description [External procedures included in this file:
Internal procedures included in this module:
Static procedures included in this module:
]
Author [Shipra Panda, Bernard Plessier, 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 82 of file cuddReorder.c.
#define DD_SHRINK_FACTOR 2 |
Definition at line 83 of file cuddReorder.c.
Function********************************************************************
Synopsis [Fixes the BDD variable group tree after a shuffle.]
Description [Fixes the BDD variable group tree after a shuffle. Assumes that the order of the variables in a terminal node has not been changed.]
SideEffects [Changes the BDD variable group tree.]
SeeAlso []
Definition at line 2001 of file cuddReorder.c.
02004 { 02005 if (treenode == NULL) return; 02006 treenode->low = ((int) treenode->index < table->size) ? 02007 table->perm[treenode->index] : treenode->index; 02008 if (treenode->child != NULL) { 02009 bddFixTree(table, treenode->child); 02010 } 02011 if (treenode->younger != NULL) 02012 bddFixTree(table, treenode->younger); 02013 if (treenode->parent != NULL && treenode->low < treenode->parent->low) { 02014 treenode->parent->low = treenode->low; 02015 treenode->parent->index = treenode->index; 02016 } 02017 return; 02018 02019 } /* end of bddFixTree */
int Cudd_ReduceHeap | ( | DdManager * | table, | |
Cudd_ReorderingType | heuristic, | |||
int | minsize | |||
) |
AutomaticEnd Function********************************************************************
Synopsis [Main dynamic reordering routine.]
Description [Main dynamic reordering routine. Calls one of the possible reordering procedures:
For sifting, symmetric sifting, group sifting, and window permutation it is possible to request reordering to convergence.
The core of all methods is the reordering procedure cuddSwapInPlace() which swaps two adjacent variables and is based on Rudell's paper. Returns 1 in case of success; 0 otherwise. In the case of symmetric sifting (with and without convergence) returns 1 plus the number of symmetric variables, in case of success.]
SideEffects [Changes the variable order for all diagrams and clears the cache.]
Definition at line 172 of file cuddReorder.c.
00176 { 00177 DdHook *hook; 00178 int result; 00179 unsigned int nextDyn; 00180 #ifdef DD_STATS 00181 unsigned int initialSize; 00182 unsigned int finalSize; 00183 #endif 00184 long localTime; 00185 00186 /* Don't reorder if there are too many dead nodes. */ 00187 if (table->keys - table->dead < (unsigned) minsize) 00188 return(1); 00189 00190 if (heuristic == CUDD_REORDER_SAME) { 00191 heuristic = table->autoMethod; 00192 } 00193 if (heuristic == CUDD_REORDER_NONE) { 00194 return(1); 00195 } 00196 00197 /* This call to Cudd_ReduceHeap does initiate reordering. Therefore 00198 ** we count it. 00199 */ 00200 table->reorderings++; 00201 00202 localTime = util_cpu_time(); 00203 00204 /* Run the hook functions. */ 00205 hook = table->preReorderingHook; 00206 while (hook != NULL) { 00207 int res = (hook->f)(table, "BDD", (void *)heuristic); 00208 if (res == 0) return(0); 00209 hook = hook->next; 00210 } 00211 00212 if (!ddReorderPreprocess(table)) return(0); 00213 ddTotalNumberSwapping = 0; 00214 00215 if (table->keys > table->peakLiveNodes) { 00216 table->peakLiveNodes = table->keys; 00217 } 00218 #ifdef DD_STATS 00219 initialSize = table->keys - table->isolated; 00220 ddTotalNISwaps = 0; 00221 00222 switch(heuristic) { 00223 case CUDD_REORDER_RANDOM: 00224 case CUDD_REORDER_RANDOM_PIVOT: 00225 (void) fprintf(table->out,"#:I_RANDOM "); 00226 break; 00227 case CUDD_REORDER_SIFT: 00228 case CUDD_REORDER_SIFT_CONVERGE: 00229 case CUDD_REORDER_SYMM_SIFT: 00230 case CUDD_REORDER_SYMM_SIFT_CONV: 00231 case CUDD_REORDER_GROUP_SIFT: 00232 case CUDD_REORDER_GROUP_SIFT_CONV: 00233 (void) fprintf(table->out,"#:I_SIFTING "); 00234 break; 00235 case CUDD_REORDER_WINDOW2: 00236 case CUDD_REORDER_WINDOW3: 00237 case CUDD_REORDER_WINDOW4: 00238 case CUDD_REORDER_WINDOW2_CONV: 00239 case CUDD_REORDER_WINDOW3_CONV: 00240 case CUDD_REORDER_WINDOW4_CONV: 00241 (void) fprintf(table->out,"#:I_WINDOW "); 00242 break; 00243 case CUDD_REORDER_ANNEALING: 00244 (void) fprintf(table->out,"#:I_ANNEAL "); 00245 break; 00246 case CUDD_REORDER_GENETIC: 00247 (void) fprintf(table->out,"#:I_GENETIC "); 00248 break; 00249 case CUDD_REORDER_LINEAR: 00250 case CUDD_REORDER_LINEAR_CONVERGE: 00251 (void) fprintf(table->out,"#:I_LINSIFT "); 00252 break; 00253 case CUDD_REORDER_EXACT: 00254 (void) fprintf(table->out,"#:I_EXACT "); 00255 break; 00256 default: 00257 return(0); 00258 } 00259 (void) fprintf(table->out,"%8d: initial size",initialSize); 00260 #endif 00261 00262 /* See if we should use alternate threshold for maximum growth. */ 00263 if (table->reordCycle && table->reorderings % table->reordCycle == 0) { 00264 double saveGrowth = table->maxGrowth; 00265 table->maxGrowth = table->maxGrowthAlt; 00266 result = cuddTreeSifting(table,heuristic); 00267 table->maxGrowth = saveGrowth; 00268 } else { 00269 result = cuddTreeSifting(table,heuristic); 00270 } 00271 00272 #ifdef DD_STATS 00273 (void) fprintf(table->out,"\n"); 00274 finalSize = table->keys - table->isolated; 00275 (void) fprintf(table->out,"#:F_REORDER %8d: final size\n",finalSize); 00276 (void) fprintf(table->out,"#:T_REORDER %8g: total time (sec)\n", 00277 ((double)(util_cpu_time() - localTime)/1000.0)); 00278 (void) fprintf(table->out,"#:N_REORDER %8d: total swaps\n", 00279 ddTotalNumberSwapping); 00280 (void) fprintf(table->out,"#:M_REORDER %8d: NI swaps\n",ddTotalNISwaps); 00281 #endif 00282 00283 if (result == 0) 00284 return(0); 00285 00286 if (!ddReorderPostprocess(table)) 00287 return(0); 00288 00289 if (table->realign) { 00290 if (!cuddZddAlignToBdd(table)) 00291 return(0); 00292 } 00293 00294 nextDyn = (table->keys - table->constants.keys + 1) * 00295 DD_DYN_RATIO + table->constants.keys; 00296 if (table->reorderings < 20 || nextDyn > table->nextDyn) 00297 table->nextDyn = nextDyn; 00298 else 00299 table->nextDyn += 20; 00300 table->reordered = 1; 00301 00302 /* Run hook functions. */ 00303 hook = table->postReorderingHook; 00304 while (hook != NULL) { 00305 int res = (hook->f)(table, "BDD", (void *)localTime); 00306 if (res == 0) return(0); 00307 hook = hook->next; 00308 } 00309 /* Update cumulative reordering time. */ 00310 table->reordTime += util_cpu_time() - localTime; 00311 00312 return(result); 00313 00314 } /* end of Cudd_ReduceHeap */
int Cudd_ShuffleHeap | ( | DdManager * | table, | |
int * | permutation | |||
) |
Function********************************************************************
Synopsis [Reorders variables according to given permutation.]
Description [Reorders variables according to given permutation. The i-th entry of the permutation array contains the index of the variable that should be brought to the i-th level. The size of the array should be equal or greater to the number of variables currently in use. Returns 1 in case of success; 0 otherwise.]
SideEffects [Changes the variable order for all diagrams and clears the cache.]
SeeAlso [Cudd_ReduceHeap]
Definition at line 334 of file cuddReorder.c.
00337 { 00338 00339 int result; 00340 int i; 00341 int identity = 1; 00342 int *perm; 00343 00344 /* Don't waste time in case of identity permutation. */ 00345 for (i = 0; i < table->size; i++) { 00346 if (permutation[i] != table->invperm[i]) { 00347 identity = 0; 00348 break; 00349 } 00350 } 00351 if (identity == 1) { 00352 return(1); 00353 } 00354 if (!ddReorderPreprocess(table)) return(0); 00355 if (table->keys > table->peakLiveNodes) { 00356 table->peakLiveNodes = table->keys; 00357 } 00358 00359 perm = ALLOC(int, table->size); 00360 for (i = 0; i < table->size; i++) 00361 perm[permutation[i]] = i; 00362 if (!ddCheckPermuation(table,table->tree,perm,permutation)) { 00363 FREE(perm); 00364 return(0); 00365 } 00366 if (!ddUpdateMtrTree(table,table->tree,perm,permutation)) { 00367 FREE(perm); 00368 return(0); 00369 } 00370 FREE(perm); 00371 00372 result = ddShuffle(table,permutation); 00373 00374 if (!ddReorderPostprocess(table)) return(0); 00375 00376 return(result); 00377 00378 } /* end of Cudd_ShuffleHeap */
int cuddBddAlignToZdd | ( | DdManager * | table | ) |
Function********************************************************************
Synopsis [Reorders BDD variables according to the order of the ZDD variables.]
Description [Reorders BDD variables according to the order of the ZDD variables. This function can be called at the end of ZDD reordering to insure that the order of the BDD variables is consistent with the order of the ZDD variables. The number of ZDD variables must be a multiple of the number of BDD variables. Let M
be the ratio of the two numbers. cuddBddAlignToZdd then considers the ZDD variables from M*i
to (M+1)*i-1
as corresponding to BDD variable i
. This function should be normally called from Cudd_zddReduceHeap, which clears the cache. Returns 1 in case of success; 0 otherwise.]
SideEffects [Changes the BDD variable order for all diagrams and performs garbage collection of the BDD unique table.]
SeeAlso [Cudd_ShuffleHeap Cudd_zddReduceHeap]
Definition at line 1242 of file cuddReorder.c.
01244 { 01245 int *invperm; /* permutation array */ 01246 int M; /* ratio of ZDD variables to BDD variables */ 01247 int i; /* loop index */ 01248 int result; /* return value */ 01249 01250 /* We assume that a ratio of 0 is OK. */ 01251 if (table->size == 0) 01252 return(1); 01253 01254 M = table->sizeZ / table->size; 01255 /* Check whether the number of ZDD variables is a multiple of the 01256 ** number of BDD variables. 01257 */ 01258 if (M * table->size != table->sizeZ) 01259 return(0); 01260 /* Create and initialize the inverse permutation array. */ 01261 invperm = ALLOC(int,table->size); 01262 if (invperm == NULL) { 01263 table->errorCode = CUDD_MEMORY_OUT; 01264 return(0); 01265 } 01266 for (i = 0; i < table->sizeZ; i += M) { 01267 int indexZ = table->invpermZ[i]; 01268 int index = indexZ / M; 01269 invperm[i / M] = index; 01270 } 01271 /* Eliminate dead nodes. Do not scan the cache again, because we 01272 ** assume that Cudd_zddReduceHeap has already cleared it. 01273 */ 01274 cuddGarbageCollect(table,0); 01275 01276 /* Initialize number of isolated projection functions. */ 01277 table->isolated = 0; 01278 for (i = 0; i < table->size; i++) { 01279 if (table->vars[i]->ref == 1) table->isolated++; 01280 } 01281 01282 /* Initialize the interaction matrix. */ 01283 result = cuddInitInteract(table); 01284 if (result == 0) return(0); 01285 01286 result = ddShuffle(table, invperm); 01287 FREE(invperm); 01288 /* Free interaction matrix. */ 01289 FREE(table->interact); 01290 /* Fix the BDD variable group tree. */ 01291 bddFixTree(table,table->tree); 01292 return(result); 01293 01294 } /* end of cuddBddAlignToZdd */
Function********************************************************************
Synopsis [Dynamically allocates a Node.]
Description [Dynamically allocates a Node. This procedure is similar to cuddAllocNode in Cudd_Table.c, but it does not attempt garbage collection, because during reordering there are no dead nodes. Returns a pointer to a new node if successful; NULL is memory is full.]
SideEffects [None]
SeeAlso [cuddAllocNode]
Definition at line 402 of file cuddReorder.c.
00404 { 00405 int i; 00406 DdNodePtr *mem; 00407 DdNode *list, *node; 00408 extern DD_OOMFP MMoutOfMemory; 00409 DD_OOMFP saveHandler; 00410 00411 if (table->nextFree == NULL) { /* free list is empty */ 00412 /* Try to allocate a new block. */ 00413 saveHandler = MMoutOfMemory; 00414 MMoutOfMemory = Cudd_OutOfMem; 00415 mem = (DdNodePtr *) ALLOC(DdNode, DD_MEM_CHUNK + 1); 00416 MMoutOfMemory = saveHandler; 00417 if (mem == NULL && table->stash != NULL) { 00418 FREE(table->stash); 00419 table->stash = NULL; 00420 /* Inhibit resizing of tables. */ 00421 table->maxCacheHard = table->cacheSlots - 1; 00422 table->cacheSlack = - (int) (table->cacheSlots + 1); 00423 for (i = 0; i < table->size; i++) { 00424 table->subtables[i].maxKeys <<= 2; 00425 } 00426 mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1); 00427 } 00428 if (mem == NULL) { 00429 /* Out of luck. Call the default handler to do 00430 ** whatever it specifies for a failed malloc. If this 00431 ** handler returns, then set error code, print 00432 ** warning, and return. */ 00433 (*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1)); 00434 table->errorCode = CUDD_MEMORY_OUT; 00435 #ifdef DD_VERBOSE 00436 (void) fprintf(table->err, 00437 "cuddDynamicAllocNode: out of memory"); 00438 (void) fprintf(table->err,"Memory in use = %lu\n", 00439 table->memused); 00440 #endif 00441 return(NULL); 00442 } else { /* successful allocation; slice memory */ 00443 unsigned long offset; 00444 table->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode); 00445 mem[0] = (DdNode *) table->memoryList; 00446 table->memoryList = mem; 00447 00448 /* Here we rely on the fact that the size of a DdNode is a 00449 ** power of 2 and a multiple of the size of a pointer. 00450 ** If we align one node, all the others will be aligned 00451 ** as well. */ 00452 offset = (unsigned long) mem & (sizeof(DdNode) - 1); 00453 mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr); 00454 #ifdef DD_DEBUG 00455 assert(((unsigned long) mem & (sizeof(DdNode) - 1)) == 0); 00456 #endif 00457 list = (DdNode *) mem; 00458 00459 i = 1; 00460 do { 00461 list[i - 1].ref = 0; 00462 list[i - 1].next = &list[i]; 00463 } while (++i < DD_MEM_CHUNK); 00464 00465 list[DD_MEM_CHUNK-1].ref = 0; 00466 list[DD_MEM_CHUNK - 1].next = NULL; 00467 00468 table->nextFree = &list[0]; 00469 } 00470 } /* if free list empty */ 00471 00472 node = table->nextFree; 00473 table->nextFree = node->next; 00474 return (node); 00475 00476 } /* end of cuddDynamicAllocNode */
int cuddNextHigh | ( | DdManager * | table, | |
int | x | |||
) |
Function********************************************************************
Synopsis [Finds the next subtable with a larger index.]
Description [Finds the next subtable with a larger index. Returns the index.]
SideEffects [None]
SeeAlso [cuddNextLow]
Definition at line 707 of file cuddReorder.c.
int cuddNextLow | ( | DdManager * | table, | |
int | x | |||
) |
Function********************************************************************
Synopsis [Finds the next subtable with a smaller index.]
Description [Finds the next subtable with a smaller index. Returns the index.]
SideEffects [None]
SeeAlso [cuddNextHigh]
Definition at line 729 of file cuddReorder.c.
int cuddSifting | ( | DdManager * | table, | |
int | lower, | |||
int | upper | |||
) |
Function********************************************************************
Synopsis [Implementation of Rudell's sifting algorithm.]
Description [Implementation of Rudell's sifting algorithm. Assumes that no dead nodes are present.
Returns 1 if successful; 0 otherwise.]
SideEffects [None]
Definition at line 499 of file cuddReorder.c.
00503 { 00504 int i; 00505 int *var; 00506 int size; 00507 int x; 00508 int result; 00509 #ifdef DD_STATS 00510 int previousSize; 00511 #endif 00512 00513 size = table->size; 00514 00515 /* Find order in which to sift variables. */ 00516 var = NULL; 00517 entry = ALLOC(int,size); 00518 if (entry == NULL) { 00519 table->errorCode = CUDD_MEMORY_OUT; 00520 goto cuddSiftingOutOfMem; 00521 } 00522 var = ALLOC(int,size); 00523 if (var == NULL) { 00524 table->errorCode = CUDD_MEMORY_OUT; 00525 goto cuddSiftingOutOfMem; 00526 } 00527 00528 for (i = 0; i < size; i++) { 00529 x = table->perm[i]; 00530 entry[i] = table->subtables[x].keys; 00531 var[i] = i; 00532 } 00533 00534 qsort((void *)var,size,sizeof(int),(DD_QSFP)ddUniqueCompare); 00535 00536 /* Now sift. */ 00537 for (i = 0; i < ddMin(table->siftMaxVar,size); i++) { 00538 if (ddTotalNumberSwapping >= table->siftMaxSwap) 00539 break; 00540 x = table->perm[var[i]]; 00541 00542 if (x < lower || x > upper || table->subtables[x].bindVar == 1) 00543 continue; 00544 #ifdef DD_STATS 00545 previousSize = table->keys - table->isolated; 00546 #endif 00547 result = ddSiftingAux(table, x, lower, upper); 00548 if (!result) goto cuddSiftingOutOfMem; 00549 #ifdef DD_STATS 00550 if (table->keys < (unsigned) previousSize + table->isolated) { 00551 (void) fprintf(table->out,"-"); 00552 } else if (table->keys > (unsigned) previousSize + table->isolated) { 00553 (void) fprintf(table->out,"+"); /* should never happen */ 00554 (void) fprintf(table->err,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keys - table->isolated, var[i]); 00555 } else { 00556 (void) fprintf(table->out,"="); 00557 } 00558 fflush(table->out); 00559 #endif 00560 } 00561 00562 FREE(var); 00563 FREE(entry); 00564 00565 return(1); 00566 00567 cuddSiftingOutOfMem: 00568 00569 if (entry != NULL) FREE(entry); 00570 if (var != NULL) FREE(var); 00571 00572 return(0); 00573 00574 } /* end of cuddSifting */
int cuddSwapInPlace | ( | DdManager * | table, | |
int | x, | |||
int | y | |||
) |
Function********************************************************************
Synopsis [Swaps two adjacent variables.]
Description [Swaps two adjacent variables. It assumes that no dead nodes are present on entry to this procedure. The procedure then guarantees that no dead nodes will be present when it terminates. cuddSwapInPlace assumes that x < y. Returns the number of keys in the table if successful; 0 otherwise.]
SideEffects [None]
Definition at line 752 of file cuddReorder.c.
00756 { 00757 DdNodePtr *xlist, *ylist; 00758 int xindex, yindex; 00759 int xslots, yslots; 00760 int xshift, yshift; 00761 int oldxkeys, oldykeys; 00762 int newxkeys, newykeys; 00763 int comple, newcomplement; 00764 int i; 00765 Cudd_VariableType varType; 00766 Cudd_LazyGroupType groupType; 00767 int posn; 00768 int isolated; 00769 DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10,*newf1,*newf0; 00770 DdNode *g,*next; 00771 DdNodePtr *previousP; 00772 DdNode *tmp; 00773 DdNode *sentinel = &(table->sentinel); 00774 extern DD_OOMFP MMoutOfMemory; 00775 DD_OOMFP saveHandler; 00776 00777 #ifdef DD_DEBUG 00778 int count,idcheck; 00779 #endif 00780 00781 #ifdef DD_DEBUG 00782 assert(x < y); 00783 assert(cuddNextHigh(table,x) == y); 00784 assert(table->subtables[x].keys != 0); 00785 assert(table->subtables[y].keys != 0); 00786 assert(table->subtables[x].dead == 0); 00787 assert(table->subtables[y].dead == 0); 00788 #endif 00789 00790 ddTotalNumberSwapping++; 00791 00792 /* Get parameters of x subtable. */ 00793 xindex = table->invperm[x]; 00794 xlist = table->subtables[x].nodelist; 00795 oldxkeys = table->subtables[x].keys; 00796 xslots = table->subtables[x].slots; 00797 xshift = table->subtables[x].shift; 00798 00799 /* Get parameters of y subtable. */ 00800 yindex = table->invperm[y]; 00801 ylist = table->subtables[y].nodelist; 00802 oldykeys = table->subtables[y].keys; 00803 yslots = table->subtables[y].slots; 00804 yshift = table->subtables[y].shift; 00805 00806 if (!cuddTestInteract(table,xindex,yindex)) { 00807 #ifdef DD_STATS 00808 ddTotalNISwaps++; 00809 #endif 00810 newxkeys = oldxkeys; 00811 newykeys = oldykeys; 00812 } else { 00813 newxkeys = 0; 00814 newykeys = oldykeys; 00815 00816 /* Check whether the two projection functions involved in this 00817 ** swap are isolated. At the end, we'll be able to tell how many 00818 ** isolated projection functions are there by checking only these 00819 ** two functions again. This is done to eliminate the isolated 00820 ** projection functions from the node count. 00821 */ 00822 isolated = - ((table->vars[xindex]->ref == 1) + 00823 (table->vars[yindex]->ref == 1)); 00824 00825 /* The nodes in the x layer that do not depend on 00826 ** y will stay there; the others are put in a chain. 00827 ** The chain is handled as a LIFO; g points to the beginning. 00828 */ 00829 g = NULL; 00830 if ((oldxkeys >= xslots || (unsigned) xslots == table->initSlots) && 00831 oldxkeys <= DD_MAX_SUBTABLE_DENSITY * xslots) { 00832 for (i = 0; i < xslots; i++) { 00833 previousP = &(xlist[i]); 00834 f = *previousP; 00835 while (f != sentinel) { 00836 next = f->next; 00837 f1 = cuddT(f); f0 = cuddE(f); 00838 if (f1->index != (DdHalfWord) yindex && 00839 Cudd_Regular(f0)->index != (DdHalfWord) yindex) { 00840 /* stays */ 00841 newxkeys++; 00842 *previousP = f; 00843 previousP = &(f->next); 00844 } else { 00845 f->index = yindex; 00846 f->next = g; 00847 g = f; 00848 } 00849 f = next; 00850 } /* while there are elements in the collision chain */ 00851 *previousP = sentinel; 00852 } /* for each slot of the x subtable */ 00853 } else { /* resize xlist */ 00854 DdNode *h = NULL; 00855 DdNodePtr *newxlist; 00856 unsigned int newxslots; 00857 int newxshift; 00858 /* Empty current xlist. Nodes that stay go to list h; 00859 ** nodes that move go to list g. */ 00860 for (i = 0; i < xslots; i++) { 00861 f = xlist[i]; 00862 while (f != sentinel) { 00863 next = f->next; 00864 f1 = cuddT(f); f0 = cuddE(f); 00865 if (f1->index != (DdHalfWord) yindex && 00866 Cudd_Regular(f0)->index != (DdHalfWord) yindex) { 00867 /* stays */ 00868 f->next = h; 00869 h = f; 00870 newxkeys++; 00871 } else { 00872 f->index = yindex; 00873 f->next = g; 00874 g = f; 00875 } 00876 f = next; 00877 } /* while there are elements in the collision chain */ 00878 } /* for each slot of the x subtable */ 00879 /* Decide size of new subtable. */ 00880 newxshift = xshift; 00881 newxslots = xslots; 00882 while ((unsigned) oldxkeys > DD_MAX_SUBTABLE_DENSITY * newxslots) { 00883 newxshift--; 00884 newxslots <<= 1; 00885 } 00886 while ((unsigned) oldxkeys < newxslots && 00887 newxslots > table->initSlots) { 00888 newxshift++; 00889 newxslots >>= 1; 00890 } 00891 /* Try to allocate new table. Be ready to back off. */ 00892 saveHandler = MMoutOfMemory; 00893 MMoutOfMemory = Cudd_OutOfMem; 00894 newxlist = ALLOC(DdNodePtr, newxslots); 00895 MMoutOfMemory = saveHandler; 00896 if (newxlist == NULL) { 00897 (void) fprintf(table->err, "Unable to resize subtable %d for lack of memory\n", i); 00898 newxlist = xlist; 00899 newxslots = xslots; 00900 newxshift = xshift; 00901 } else { 00902 table->slots += ((int) newxslots - xslots); 00903 table->minDead = (unsigned) 00904 (table->gcFrac * (double) table->slots); 00905 table->cacheSlack = (int) 00906 ddMin(table->maxCacheHard, DD_MAX_CACHE_TO_SLOTS_RATIO 00907 * table->slots) - 2 * (int) table->cacheSlots; 00908 table->memused += 00909 ((int) newxslots - xslots) * sizeof(DdNodePtr); 00910 FREE(xlist); 00911 xslots = newxslots; 00912 xshift = newxshift; 00913 xlist = newxlist; 00914 } 00915 /* Initialize new subtable. */ 00916 for (i = 0; i < xslots; i++) { 00917 xlist[i] = sentinel; 00918 } 00919 /* Move nodes that were parked in list h to their new home. */ 00920 f = h; 00921 while (f != NULL) { 00922 next = f->next; 00923 f1 = cuddT(f); 00924 f0 = cuddE(f); 00925 /* Check xlist for pair (f11,f01). */ 00926 posn = ddHash(f1, f0, xshift); 00927 /* For each element tmp in collision list xlist[posn]. */ 00928 previousP = &(xlist[posn]); 00929 tmp = *previousP; 00930 while (f1 < cuddT(tmp)) { 00931 previousP = &(tmp->next); 00932 tmp = *previousP; 00933 } 00934 while (f1 == cuddT(tmp) && f0 < cuddE(tmp)) { 00935 previousP = &(tmp->next); 00936 tmp = *previousP; 00937 } 00938 f->next = *previousP; 00939 *previousP = f; 00940 f = next; 00941 } 00942 } 00943 00944 #ifdef DD_COUNT 00945 table->swapSteps += oldxkeys - newxkeys; 00946 #endif 00947 /* Take care of the x nodes that must be re-expressed. 00948 ** They form a linked list pointed by g. Their index has been 00949 ** already changed to yindex. 00950 */ 00951 f = g; 00952 while (f != NULL) { 00953 next = f->next; 00954 /* Find f1, f0, f11, f10, f01, f00. */ 00955 f1 = cuddT(f); 00956 #ifdef DD_DEBUG 00957 assert(!(Cudd_IsComplement(f1))); 00958 #endif 00959 if ((int) f1->index == yindex) { 00960 f11 = cuddT(f1); f10 = cuddE(f1); 00961 } else { 00962 f11 = f10 = f1; 00963 } 00964 #ifdef DD_DEBUG 00965 assert(!(Cudd_IsComplement(f11))); 00966 #endif 00967 f0 = cuddE(f); 00968 comple = Cudd_IsComplement(f0); 00969 f0 = Cudd_Regular(f0); 00970 if ((int) f0->index == yindex) { 00971 f01 = cuddT(f0); f00 = cuddE(f0); 00972 } else { 00973 f01 = f00 = f0; 00974 } 00975 if (comple) { 00976 f01 = Cudd_Not(f01); 00977 f00 = Cudd_Not(f00); 00978 } 00979 /* Decrease ref count of f1. */ 00980 cuddSatDec(f1->ref); 00981 /* Create the new T child. */ 00982 if (f11 == f01) { 00983 newf1 = f11; 00984 cuddSatInc(newf1->ref); 00985 } else { 00986 /* Check xlist for triple (xindex,f11,f01). */ 00987 posn = ddHash(f11, f01, xshift); 00988 /* For each element newf1 in collision list xlist[posn]. */ 00989 previousP = &(xlist[posn]); 00990 newf1 = *previousP; 00991 while (f11 < cuddT(newf1)) { 00992 previousP = &(newf1->next); 00993 newf1 = *previousP; 00994 } 00995 while (f11 == cuddT(newf1) && f01 < cuddE(newf1)) { 00996 previousP = &(newf1->next); 00997 newf1 = *previousP; 00998 } 00999 if (cuddT(newf1) == f11 && cuddE(newf1) == f01) { 01000 cuddSatInc(newf1->ref); 01001 } else { /* no match */ 01002 newf1 = cuddDynamicAllocNode(table); 01003 if (newf1 == NULL) 01004 goto cuddSwapOutOfMem; 01005 newf1->index = xindex; newf1->ref = 1; 01006 cuddT(newf1) = f11; 01007 cuddE(newf1) = f01; 01008 /* Insert newf1 in the collision list xlist[posn]; 01009 ** increase the ref counts of f11 and f01. 01010 */ 01011 newxkeys++; 01012 newf1->next = *previousP; 01013 *previousP = newf1; 01014 cuddSatInc(f11->ref); 01015 tmp = Cudd_Regular(f01); 01016 cuddSatInc(tmp->ref); 01017 } 01018 } 01019 cuddT(f) = newf1; 01020 #ifdef DD_DEBUG 01021 assert(!(Cudd_IsComplement(newf1))); 01022 #endif 01023 01024 /* Do the same for f0, keeping complement dots into account. */ 01025 /* Decrease ref count of f0. */ 01026 tmp = Cudd_Regular(f0); 01027 cuddSatDec(tmp->ref); 01028 /* Create the new E child. */ 01029 if (f10 == f00) { 01030 newf0 = f00; 01031 tmp = Cudd_Regular(newf0); 01032 cuddSatInc(tmp->ref); 01033 } else { 01034 /* make sure f10 is regular */ 01035 newcomplement = Cudd_IsComplement(f10); 01036 if (newcomplement) { 01037 f10 = Cudd_Not(f10); 01038 f00 = Cudd_Not(f00); 01039 } 01040 /* Check xlist for triple (xindex,f10,f00). */ 01041 posn = ddHash(f10, f00, xshift); 01042 /* For each element newf0 in collision list xlist[posn]. */ 01043 previousP = &(xlist[posn]); 01044 newf0 = *previousP; 01045 while (f10 < cuddT(newf0)) { 01046 previousP = &(newf0->next); 01047 newf0 = *previousP; 01048 } 01049 while (f10 == cuddT(newf0) && f00 < cuddE(newf0)) { 01050 previousP = &(newf0->next); 01051 newf0 = *previousP; 01052 } 01053 if (cuddT(newf0) == f10 && cuddE(newf0) == f00) { 01054 cuddSatInc(newf0->ref); 01055 } else { /* no match */ 01056 newf0 = cuddDynamicAllocNode(table); 01057 if (newf0 == NULL) 01058 goto cuddSwapOutOfMem; 01059 newf0->index = xindex; newf0->ref = 1; 01060 cuddT(newf0) = f10; 01061 cuddE(newf0) = f00; 01062 /* Insert newf0 in the collision list xlist[posn]; 01063 ** increase the ref counts of f10 and f00. 01064 */ 01065 newxkeys++; 01066 newf0->next = *previousP; 01067 *previousP = newf0; 01068 cuddSatInc(f10->ref); 01069 tmp = Cudd_Regular(f00); 01070 cuddSatInc(tmp->ref); 01071 } 01072 if (newcomplement) { 01073 newf0 = Cudd_Not(newf0); 01074 } 01075 } 01076 cuddE(f) = newf0; 01077 01078 /* Insert the modified f in ylist. 01079 ** The modified f does not already exists in ylist. 01080 ** (Because of the uniqueness of the cofactors.) 01081 */ 01082 posn = ddHash(newf1, newf0, yshift); 01083 newykeys++; 01084 previousP = &(ylist[posn]); 01085 tmp = *previousP; 01086 while (newf1 < cuddT(tmp)) { 01087 previousP = &(tmp->next); 01088 tmp = *previousP; 01089 } 01090 while (newf1 == cuddT(tmp) && newf0 < cuddE(tmp)) { 01091 previousP = &(tmp->next); 01092 tmp = *previousP; 01093 } 01094 f->next = *previousP; 01095 *previousP = f; 01096 f = next; 01097 } /* while f != NULL */ 01098 01099 /* GC the y layer. */ 01100 01101 /* For each node f in ylist. */ 01102 for (i = 0; i < yslots; i++) { 01103 previousP = &(ylist[i]); 01104 f = *previousP; 01105 while (f != sentinel) { 01106 next = f->next; 01107 if (f->ref == 0) { 01108 tmp = cuddT(f); 01109 cuddSatDec(tmp->ref); 01110 tmp = Cudd_Regular(cuddE(f)); 01111 cuddSatDec(tmp->ref); 01112 cuddDeallocNode(table,f); 01113 newykeys--; 01114 } else { 01115 *previousP = f; 01116 previousP = &(f->next); 01117 } 01118 f = next; 01119 } /* while f */ 01120 *previousP = sentinel; 01121 } /* for i */ 01122 01123 #ifdef DD_DEBUG 01124 #if 0 01125 (void) fprintf(table->out,"Swapping %d and %d\n",x,y); 01126 #endif 01127 count = 0; 01128 idcheck = 0; 01129 for (i = 0; i < yslots; i++) { 01130 f = ylist[i]; 01131 while (f != sentinel) { 01132 count++; 01133 if (f->index != (DdHalfWord) yindex) 01134 idcheck++; 01135 f = f->next; 01136 } 01137 } 01138 if (count != newykeys) { 01139 (void) fprintf(table->out, 01140 "Error in finding newykeys\toldykeys = %d\tnewykeys = %d\tactual = %d\n", 01141 oldykeys,newykeys,count); 01142 } 01143 if (idcheck != 0) 01144 (void) fprintf(table->out, 01145 "Error in id's of ylist\twrong id's = %d\n", 01146 idcheck); 01147 count = 0; 01148 idcheck = 0; 01149 for (i = 0; i < xslots; i++) { 01150 f = xlist[i]; 01151 while (f != sentinel) { 01152 count++; 01153 if (f->index != (DdHalfWord) xindex) 01154 idcheck++; 01155 f = f->next; 01156 } 01157 } 01158 if (count != newxkeys) { 01159 (void) fprintf(table->out, 01160 "Error in finding newxkeys\toldxkeys = %d \tnewxkeys = %d \tactual = %d\n", 01161 oldxkeys,newxkeys,count); 01162 } 01163 if (idcheck != 0) 01164 (void) fprintf(table->out, 01165 "Error in id's of xlist\twrong id's = %d\n", 01166 idcheck); 01167 #endif 01168 01169 isolated += (table->vars[xindex]->ref == 1) + 01170 (table->vars[yindex]->ref == 1); 01171 table->isolated += isolated; 01172 } 01173 01174 /* Set the appropriate fields in table. */ 01175 table->subtables[x].nodelist = ylist; 01176 table->subtables[x].slots = yslots; 01177 table->subtables[x].shift = yshift; 01178 table->subtables[x].keys = newykeys; 01179 table->subtables[x].maxKeys = yslots * DD_MAX_SUBTABLE_DENSITY; 01180 i = table->subtables[x].bindVar; 01181 table->subtables[x].bindVar = table->subtables[y].bindVar; 01182 table->subtables[y].bindVar = i; 01183 /* Adjust filds for lazy sifting. */ 01184 varType = table->subtables[x].varType; 01185 table->subtables[x].varType = table->subtables[y].varType; 01186 table->subtables[y].varType = varType; 01187 i = table->subtables[x].pairIndex; 01188 table->subtables[x].pairIndex = table->subtables[y].pairIndex; 01189 table->subtables[y].pairIndex = i; 01190 i = table->subtables[x].varHandled; 01191 table->subtables[x].varHandled = table->subtables[y].varHandled; 01192 table->subtables[y].varHandled = i; 01193 groupType = table->subtables[x].varToBeGrouped; 01194 table->subtables[x].varToBeGrouped = table->subtables[y].varToBeGrouped; 01195 table->subtables[y].varToBeGrouped = groupType; 01196 01197 table->subtables[y].nodelist = xlist; 01198 table->subtables[y].slots = xslots; 01199 table->subtables[y].shift = xshift; 01200 table->subtables[y].keys = newxkeys; 01201 table->subtables[y].maxKeys = xslots * DD_MAX_SUBTABLE_DENSITY; 01202 01203 table->perm[xindex] = y; table->perm[yindex] = x; 01204 table->invperm[x] = yindex; table->invperm[y] = xindex; 01205 01206 table->keys += newxkeys + newykeys - oldxkeys - oldykeys; 01207 01208 return(table->keys - table->isolated); 01209 01210 cuddSwapOutOfMem: 01211 (void) fprintf(table->err,"Error: cuddSwapInPlace out of memory\n"); 01212 01213 return (0); 01214 01215 } /* end of cuddSwapInPlace */
int cuddSwapping | ( | DdManager * | table, | |
int | lower, | |||
int | upper, | |||
Cudd_ReorderingType | heuristic | |||
) |
Function********************************************************************
Synopsis [Reorders variables by a sequence of (non-adjacent) swaps.]
Description [Implementation of Plessier's algorithm that reorders variables by a sequence of (non-adjacent) swaps.
Returns 1 in case of success; 0 otherwise.]
SideEffects [None]
Definition at line 596 of file cuddReorder.c.
00601 { 00602 int i, j; 00603 int max, keys; 00604 int nvars; 00605 int x, y; 00606 int iterate; 00607 int previousSize; 00608 Move *moves, *move; 00609 int pivot; 00610 int modulo; 00611 int result; 00612 00613 #ifdef DD_DEBUG 00614 /* Sanity check */ 00615 assert(lower >= 0 && upper < table->size && lower <= upper); 00616 #endif 00617 00618 nvars = upper - lower + 1; 00619 iterate = nvars; 00620 00621 for (i = 0; i < iterate; i++) { 00622 if (ddTotalNumberSwapping >= table->siftMaxSwap) 00623 break; 00624 if (heuristic == CUDD_REORDER_RANDOM_PIVOT) { 00625 max = -1; 00626 for (j = lower; j <= upper; j++) { 00627 if ((keys = table->subtables[j].keys) > max) { 00628 max = keys; 00629 pivot = j; 00630 } 00631 } 00632 00633 modulo = upper - pivot; 00634 if (modulo == 0) { 00635 y = pivot; 00636 } else{ 00637 y = pivot + 1 + ((int) Cudd_Random() % modulo); 00638 } 00639 00640 modulo = pivot - lower - 1; 00641 if (modulo < 1) { 00642 x = lower; 00643 } else{ 00644 do { 00645 x = (int) Cudd_Random() % modulo; 00646 } while (x == y); 00647 } 00648 } else { 00649 x = ((int) Cudd_Random() % nvars) + lower; 00650 do { 00651 y = ((int) Cudd_Random() % nvars) + lower; 00652 } while (x == y); 00653 } 00654 previousSize = table->keys - table->isolated; 00655 moves = ddSwapAny(table,x,y); 00656 if (moves == NULL) goto cuddSwappingOutOfMem; 00657 result = ddSiftingBackward(table,previousSize,moves); 00658 if (!result) goto cuddSwappingOutOfMem; 00659 while (moves != NULL) { 00660 move = moves->next; 00661 cuddDeallocMove(table, moves); 00662 moves = move; 00663 } 00664 #ifdef DD_STATS 00665 if (table->keys < (unsigned) previousSize + table->isolated) { 00666 (void) fprintf(table->out,"-"); 00667 } else if (table->keys > (unsigned) previousSize + table->isolated) { 00668 (void) fprintf(table->out,"+"); /* should never happen */ 00669 } else { 00670 (void) fprintf(table->out,"="); 00671 } 00672 fflush(table->out); 00673 #endif 00674 #if 0 00675 (void) fprintf(table->out,"#:t_SWAPPING %8d: tmp size\n", 00676 table->keys - table->isolated); 00677 #endif 00678 } 00679 00680 return(1); 00681 00682 cuddSwappingOutOfMem: 00683 while (moves != NULL) { 00684 move = moves->next; 00685 cuddDeallocMove(table, moves); 00686 moves = move; 00687 } 00688 00689 return(0); 00690 00691 } /* end of cuddSwapping */
static int ddCheckPermuation | ( | DdManager * | table, | |
MtrNode * | treenode, | |||
int * | perm, | |||
int * | invperm | |||
) | [static] |
Function********************************************************************
Synopsis [Checks the BDD variable group tree before a shuffle.]
Description [Checks the BDD variable group tree before a shuffle. Returns 1 if successful; 0 otherwise.]
SideEffects [Changes the BDD variable group tree.]
SeeAlso []
Definition at line 2094 of file cuddReorder.c.
02099 { 02100 unsigned int i, size; 02101 int index, level, minLevel, maxLevel; 02102 02103 if (treenode == NULL) return(1); 02104 02105 minLevel = table->size; 02106 maxLevel = 0; 02107 /* i : level */ 02108 for (i = treenode->low; i < treenode->low + treenode->size; i++) { 02109 index = table->invperm[i]; 02110 level = perm[index]; 02111 if (level < minLevel) 02112 minLevel = level; 02113 if (level > maxLevel) 02114 maxLevel = level; 02115 } 02116 size = maxLevel - minLevel + 1; 02117 if (size != treenode->size) 02118 return(0); 02119 02120 if (treenode->child != NULL) { 02121 if (!ddCheckPermuation(table, treenode->child, perm, invperm)) 02122 return(0); 02123 } 02124 if (treenode->younger != NULL) { 02125 if (!ddCheckPermuation(table, treenode->younger, perm, invperm)) 02126 return(0); 02127 } 02128 return(1); 02129 }
static int ddReorderPostprocess | ( | DdManager * | table | ) | [static] |
Function********************************************************************
Synopsis [Cleans up at the end of reordering.]
Description []
SideEffects [None]
Definition at line 1855 of file cuddReorder.c.
static int ddReorderPreprocess | ( | DdManager * | table | ) | [static] |
Function********************************************************************
Synopsis [Prepares the DD heap for dynamic reordering.]
Description [Prepares the DD heap for dynamic reordering. Does garbage collection, to guarantee that there are no dead nodes; clears the cache, which is invalidated by dynamic reordering; initializes the number of isolated projection functions; and initializes the interaction matrix. Returns 1 in case of success; 0 otherwise.]
SideEffects [None]
Definition at line 1817 of file cuddReorder.c.
01819 { 01820 int i; 01821 int res; 01822 01823 /* Clear the cache. */ 01824 cuddCacheFlush(table); 01825 cuddLocalCacheClearAll(table); 01826 01827 /* Eliminate dead nodes. Do not scan the cache again. */ 01828 cuddGarbageCollect(table,0); 01829 01830 /* Initialize number of isolated projection functions. */ 01831 table->isolated = 0; 01832 for (i = 0; i < table->size; i++) { 01833 if (table->vars[i]->ref == 1) table->isolated++; 01834 } 01835 01836 /* Initialize the interaction matrix. */ 01837 res = cuddInitInteract(table); 01838 if (res == 0) return(0); 01839 01840 return(1); 01841 01842 } /* end of ddReorderPreprocess */
static int ddShuffle | ( | DdManager * | table, | |
int * | permutation | |||
) | [static] |
Function********************************************************************
Synopsis [Reorders variables according to a given permutation.]
Description [Reorders variables according to a given permutation. The i-th permutation array contains the index of the variable that should be brought to the i-th level. ddShuffle assumes that no dead nodes are present and that the interaction matrix is properly initialized. The reordering is achieved by a series of upward sifts. Returns 1 if successful; 0 otherwise.]
SideEffects [None]
SeeAlso []
Definition at line 1888 of file cuddReorder.c.
01891 { 01892 int index; 01893 int level; 01894 int position; 01895 int numvars; 01896 int result; 01897 #ifdef DD_STATS 01898 long localTime; 01899 int initialSize; 01900 int finalSize; 01901 int previousSize; 01902 #endif 01903 01904 ddTotalNumberSwapping = 0; 01905 #ifdef DD_STATS 01906 localTime = util_cpu_time(); 01907 initialSize = table->keys - table->isolated; 01908 (void) fprintf(table->out,"#:I_SHUFFLE %8d: initial size\n", 01909 initialSize); 01910 ddTotalNISwaps = 0; 01911 #endif 01912 01913 numvars = table->size; 01914 01915 for (level = 0; level < numvars; level++) { 01916 index = permutation[level]; 01917 position = table->perm[index]; 01918 #ifdef DD_STATS 01919 previousSize = table->keys - table->isolated; 01920 #endif 01921 result = ddSiftUp(table,position,level); 01922 if (!result) return(0); 01923 #ifdef DD_STATS 01924 if (table->keys < (unsigned) previousSize + table->isolated) { 01925 (void) fprintf(table->out,"-"); 01926 } else if (table->keys > (unsigned) previousSize + table->isolated) { 01927 (void) fprintf(table->out,"+"); /* should never happen */ 01928 } else { 01929 (void) fprintf(table->out,"="); 01930 } 01931 fflush(table->out); 01932 #endif 01933 } 01934 01935 #ifdef DD_STATS 01936 (void) fprintf(table->out,"\n"); 01937 finalSize = table->keys - table->isolated; 01938 (void) fprintf(table->out,"#:F_SHUFFLE %8d: final size\n",finalSize); 01939 (void) fprintf(table->out,"#:T_SHUFFLE %8g: total time (sec)\n", 01940 ((double)(util_cpu_time() - localTime)/1000.0)); 01941 (void) fprintf(table->out,"#:N_SHUFFLE %8d: total swaps\n", 01942 ddTotalNumberSwapping); 01943 (void) fprintf(table->out,"#:M_SHUFFLE %8d: NI swaps\n",ddTotalNISwaps); 01944 #endif 01945 01946 return(1); 01947 01948 } /* end of ddShuffle */
static int ddSiftingAux | ( | DdManager * | table, | |
int | x, | |||
int | xLow, | |||
int | xHigh | |||
) | [static] |
Function********************************************************************
Synopsis [Given xLow <= x <= xHigh moves x up and down between the boundaries.]
Description [Given xLow <= x <= xHigh moves x up and down between the boundaries. Finds the best position and does the required changes. Returns 1 if successful; 0 otherwise.]
SideEffects [None]
Definition at line 1479 of file cuddReorder.c.
01484 { 01485 01486 Move *move; 01487 Move *moveUp; /* list of up moves */ 01488 Move *moveDown; /* list of down moves */ 01489 int initialSize; 01490 int result; 01491 01492 initialSize = table->keys - table->isolated; 01493 01494 moveDown = NULL; 01495 moveUp = NULL; 01496 01497 if (x == xLow) { 01498 moveDown = ddSiftingDown(table,x,xHigh); 01499 /* At this point x --> xHigh unless bounding occurred. */ 01500 if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem; 01501 /* Move backward and stop at best position. */ 01502 result = ddSiftingBackward(table,initialSize,moveDown); 01503 if (!result) goto ddSiftingAuxOutOfMem; 01504 01505 } else if (x == xHigh) { 01506 moveUp = ddSiftingUp(table,x,xLow); 01507 /* At this point x --> xLow unless bounding occurred. */ 01508 if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem; 01509 /* Move backward and stop at best position. */ 01510 result = ddSiftingBackward(table,initialSize,moveUp); 01511 if (!result) goto ddSiftingAuxOutOfMem; 01512 01513 } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */ 01514 moveDown = ddSiftingDown(table,x,xHigh); 01515 /* At this point x --> xHigh unless bounding occurred. */ 01516 if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem; 01517 if (moveDown != NULL) { 01518 x = moveDown->y; 01519 } 01520 moveUp = ddSiftingUp(table,x,xLow); 01521 if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem; 01522 /* Move backward and stop at best position */ 01523 result = ddSiftingBackward(table,initialSize,moveUp); 01524 if (!result) goto ddSiftingAuxOutOfMem; 01525 01526 } else { /* must go up first: shorter */ 01527 moveUp = ddSiftingUp(table,x,xLow); 01528 /* At this point x --> xLow unless bounding occurred. */ 01529 if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem; 01530 if (moveUp != NULL) { 01531 x = moveUp->x; 01532 } 01533 moveDown = ddSiftingDown(table,x,xHigh); 01534 if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem; 01535 /* Move backward and stop at best position. */ 01536 result = ddSiftingBackward(table,initialSize,moveDown); 01537 if (!result) goto ddSiftingAuxOutOfMem; 01538 } 01539 01540 while (moveDown != NULL) { 01541 move = moveDown->next; 01542 cuddDeallocMove(table, moveDown); 01543 moveDown = move; 01544 } 01545 while (moveUp != NULL) { 01546 move = moveUp->next; 01547 cuddDeallocMove(table, moveUp); 01548 moveUp = move; 01549 } 01550 01551 return(1); 01552 01553 ddSiftingAuxOutOfMem: 01554 if (moveDown != (Move *) CUDD_OUT_OF_MEM) { 01555 while (moveDown != NULL) { 01556 move = moveDown->next; 01557 cuddDeallocMove(table, moveDown); 01558 moveDown = move; 01559 } 01560 } 01561 if (moveUp != (Move *) CUDD_OUT_OF_MEM) { 01562 while (moveUp != NULL) { 01563 move = moveUp->next; 01564 cuddDeallocMove(table, moveUp); 01565 moveUp = move; 01566 } 01567 } 01568 01569 return(0); 01570 01571 } /* end of ddSiftingAux */
Function********************************************************************
Synopsis [Given a set of moves, returns the DD heap to the position giving the minimum size.]
Description [Given a set of moves, returns the DD heap to the position giving the minimum size. In case of ties, returns to the closest position giving the minimum size. Returns 1 in case of success; 0 otherwise.]
SideEffects [None]
Definition at line 1778 of file cuddReorder.c.
01782 { 01783 Move *move; 01784 int res; 01785 01786 for (move = moves; move != NULL; move = move->next) { 01787 if (move->size < size) { 01788 size = move->size; 01789 } 01790 } 01791 01792 for (move = moves; move != NULL; move = move->next) { 01793 if (move->size == size) return(1); 01794 res = cuddSwapInPlace(table,(int)move->x,(int)move->y); 01795 if (!res) return(0); 01796 } 01797 01798 return(1); 01799 01800 } /* end of ddSiftingBackward */
Function********************************************************************
Synopsis [Sifts a variable down.]
Description [Sifts a variable down. Moves x down until either it reaches the bound (xHigh) or the size of the DD heap increases too much. Returns the set of moves in case of success; NULL if memory is full.]
SideEffects [None]
Definition at line 1686 of file cuddReorder.c.
01690 { 01691 Move *moves; 01692 Move *move; 01693 int y; 01694 int size; 01695 int R; /* upper bound on node decrease */ 01696 int limitSize; 01697 int xindex, yindex; 01698 int isolated; 01699 #ifdef DD_DEBUG 01700 int checkR; 01701 int z; 01702 int zindex; 01703 #endif 01704 01705 moves = NULL; 01706 /* Initialize R */ 01707 xindex = table->invperm[x]; 01708 limitSize = size = table->keys - table->isolated; 01709 R = 0; 01710 for (y = xHigh; y > x; y--) { 01711 yindex = table->invperm[y]; 01712 if (cuddTestInteract(table,xindex,yindex)) { 01713 isolated = table->vars[yindex]->ref == 1; 01714 R += table->subtables[y].keys - isolated; 01715 } 01716 } 01717 01718 y = cuddNextHigh(table,x); 01719 while (y <= xHigh && size - R < limitSize) { 01720 #ifdef DD_DEBUG 01721 checkR = 0; 01722 for (z = xHigh; z > x; z--) { 01723 zindex = table->invperm[z]; 01724 if (cuddTestInteract(table,xindex,zindex)) { 01725 isolated = table->vars[zindex]->ref == 1; 01726 checkR += table->subtables[z].keys - isolated; 01727 } 01728 } 01729 assert(R == checkR); 01730 #endif 01731 /* Update upper bound on node decrease. */ 01732 yindex = table->invperm[y]; 01733 if (cuddTestInteract(table,xindex,yindex)) { 01734 isolated = table->vars[yindex]->ref == 1; 01735 R -= table->subtables[y].keys - isolated; 01736 } 01737 size = cuddSwapInPlace(table,x,y); 01738 if (size == 0) goto ddSiftingDownOutOfMem; 01739 move = (Move *) cuddDynamicAllocNode(table); 01740 if (move == NULL) goto ddSiftingDownOutOfMem; 01741 move->x = x; 01742 move->y = y; 01743 move->size = size; 01744 move->next = moves; 01745 moves = move; 01746 if ((double) size > (double) limitSize * table->maxGrowth) break; 01747 if (size < limitSize) limitSize = size; 01748 x = y; 01749 y = cuddNextHigh(table,x); 01750 } 01751 return(moves); 01752 01753 ddSiftingDownOutOfMem: 01754 while (moves != NULL) { 01755 move = moves->next; 01756 cuddDeallocMove(table, moves); 01757 moves = move; 01758 } 01759 return((Move *) CUDD_OUT_OF_MEM); 01760 01761 } /* end of ddSiftingDown */
Function********************************************************************
Synopsis [Sifts a variable up.]
Description [Sifts a variable up. Moves y up until either it reaches the bound (xLow) or the size of the DD heap increases too much. Returns the set of moves in case of success; NULL if memory is full.]
SideEffects [None]
Definition at line 1586 of file cuddReorder.c.
01590 { 01591 Move *moves; 01592 Move *move; 01593 int x; 01594 int size; 01595 int limitSize; 01596 int xindex, yindex; 01597 int isolated; 01598 int L; /* lower bound on DD size */ 01599 #ifdef DD_DEBUG 01600 int checkL; 01601 int z; 01602 int zindex; 01603 #endif 01604 01605 moves = NULL; 01606 yindex = table->invperm[y]; 01607 01608 /* Initialize the lower bound. 01609 ** The part of the DD below y will not change. 01610 ** The part of the DD above y that does not interact with y will not 01611 ** change. The rest may vanish in the best case, except for 01612 ** the nodes at level xLow, which will not vanish, regardless. 01613 */ 01614 limitSize = L = table->keys - table->isolated; 01615 for (x = xLow + 1; x < y; x++) { 01616 xindex = table->invperm[x]; 01617 if (cuddTestInteract(table,xindex,yindex)) { 01618 isolated = table->vars[xindex]->ref == 1; 01619 L -= table->subtables[x].keys - isolated; 01620 } 01621 } 01622 isolated = table->vars[yindex]->ref == 1; 01623 L -= table->subtables[y].keys - isolated; 01624 01625 x = cuddNextLow(table,y); 01626 while (x >= xLow && L <= limitSize) { 01627 xindex = table->invperm[x]; 01628 #ifdef DD_DEBUG 01629 checkL = table->keys - table->isolated; 01630 for (z = xLow + 1; z < y; z++) { 01631 zindex = table->invperm[z]; 01632 if (cuddTestInteract(table,zindex,yindex)) { 01633 isolated = table->vars[zindex]->ref == 1; 01634 checkL -= table->subtables[z].keys - isolated; 01635 } 01636 } 01637 isolated = table->vars[yindex]->ref == 1; 01638 checkL -= table->subtables[y].keys - isolated; 01639 assert(L == checkL); 01640 #endif 01641 size = cuddSwapInPlace(table,x,y); 01642 if (size == 0) goto ddSiftingUpOutOfMem; 01643 /* Update the lower bound. */ 01644 if (cuddTestInteract(table,xindex,yindex)) { 01645 isolated = table->vars[xindex]->ref == 1; 01646 L += table->subtables[y].keys - isolated; 01647 } 01648 move = (Move *) cuddDynamicAllocNode(table); 01649 if (move == NULL) goto ddSiftingUpOutOfMem; 01650 move->x = x; 01651 move->y = y; 01652 move->size = size; 01653 move->next = moves; 01654 moves = move; 01655 if ((double) size > (double) limitSize * table->maxGrowth) break; 01656 if (size < limitSize) limitSize = size; 01657 y = x; 01658 x = cuddNextLow(table,y); 01659 } 01660 return(moves); 01661 01662 ddSiftingUpOutOfMem: 01663 while (moves != NULL) { 01664 move = moves->next; 01665 cuddDeallocMove(table, moves); 01666 moves = move; 01667 } 01668 return((Move *) CUDD_OUT_OF_MEM); 01669 01670 } /* end of ddSiftingUp */
static int ddSiftUp | ( | DdManager * | table, | |
int | x, | |||
int | xLow | |||
) | [static] |
Function********************************************************************
Synopsis [Moves one variable up.]
Description [Takes a variable from position x and sifts it up to position xLow; xLow should be less than or equal to x. Returns 1 if successful; 0 otherwise]
SideEffects [None]
SeeAlso []
Definition at line 1965 of file cuddReorder.c.
01969 { 01970 int y; 01971 int size; 01972 01973 y = cuddNextLow(table,x); 01974 while (y >= xLow) { 01975 size = cuddSwapInPlace(table,y,x); 01976 if (size == 0) { 01977 return(0); 01978 } 01979 x = y; 01980 y = cuddNextLow(table,x); 01981 } 01982 return(1); 01983 01984 } /* end of ddSiftUp */
Function********************************************************************
Synopsis [Swaps any two variables.]
Description [Swaps any two variables. Returns the set of moves.]
SideEffects [None]
Definition at line 1338 of file cuddReorder.c.
01342 { 01343 Move *move, *moves; 01344 int xRef,yRef; 01345 int xNext,yNext; 01346 int size; 01347 int limitSize; 01348 int tmp; 01349 01350 if (x >y) { 01351 tmp = x; x = y; y = tmp; 01352 } 01353 01354 xRef = x; yRef = y; 01355 01356 xNext = cuddNextHigh(table,x); 01357 yNext = cuddNextLow(table,y); 01358 moves = NULL; 01359 limitSize = table->keys - table->isolated; 01360 01361 for (;;) { 01362 if ( xNext == yNext) { 01363 size = cuddSwapInPlace(table,x,xNext); 01364 if (size == 0) goto ddSwapAnyOutOfMem; 01365 move = (Move *) cuddDynamicAllocNode(table); 01366 if (move == NULL) goto ddSwapAnyOutOfMem; 01367 move->x = x; 01368 move->y = xNext; 01369 move->size = size; 01370 move->next = moves; 01371 moves = move; 01372 01373 size = cuddSwapInPlace(table,yNext,y); 01374 if (size == 0) goto ddSwapAnyOutOfMem; 01375 move = (Move *) cuddDynamicAllocNode(table); 01376 if (move == NULL) goto ddSwapAnyOutOfMem; 01377 move->x = yNext; 01378 move->y = y; 01379 move->size = size; 01380 move->next = moves; 01381 moves = move; 01382 01383 size = cuddSwapInPlace(table,x,xNext); 01384 if (size == 0) goto ddSwapAnyOutOfMem; 01385 move = (Move *) cuddDynamicAllocNode(table); 01386 if (move == NULL) goto ddSwapAnyOutOfMem; 01387 move->x = x; 01388 move->y = xNext; 01389 move->size = size; 01390 move->next = moves; 01391 moves = move; 01392 01393 tmp = x; x = y; y = tmp; 01394 01395 } else if (x == yNext) { 01396 01397 size = cuddSwapInPlace(table,x,xNext); 01398 if (size == 0) goto ddSwapAnyOutOfMem; 01399 move = (Move *) cuddDynamicAllocNode(table); 01400 if (move == NULL) goto ddSwapAnyOutOfMem; 01401 move->x = x; 01402 move->y = xNext; 01403 move->size = size; 01404 move->next = moves; 01405 moves = move; 01406 01407 tmp = x; x = y; y = tmp; 01408 01409 } else { 01410 size = cuddSwapInPlace(table,x,xNext); 01411 if (size == 0) goto ddSwapAnyOutOfMem; 01412 move = (Move *) cuddDynamicAllocNode(table); 01413 if (move == NULL) goto ddSwapAnyOutOfMem; 01414 move->x = x; 01415 move->y = xNext; 01416 move->size = size; 01417 move->next = moves; 01418 moves = move; 01419 01420 size = cuddSwapInPlace(table,yNext,y); 01421 if (size == 0) goto ddSwapAnyOutOfMem; 01422 move = (Move *) cuddDynamicAllocNode(table); 01423 if (move == NULL) goto ddSwapAnyOutOfMem; 01424 move->x = yNext; 01425 move->y = y; 01426 move->size = size; 01427 move->next = moves; 01428 moves = move; 01429 01430 x = xNext; 01431 y = yNext; 01432 } 01433 01434 xNext = cuddNextHigh(table,x); 01435 yNext = cuddNextLow(table,y); 01436 if (xNext > yRef) break; 01437 01438 if ((double) size > table->maxGrowth * (double) limitSize) break; 01439 if (size < limitSize) limitSize = size; 01440 } 01441 if (yNext>=xRef) { 01442 size = cuddSwapInPlace(table,yNext,y); 01443 if (size == 0) goto ddSwapAnyOutOfMem; 01444 move = (Move *) cuddDynamicAllocNode(table); 01445 if (move == NULL) goto ddSwapAnyOutOfMem; 01446 move->x = yNext; 01447 move->y = y; 01448 move->size = size; 01449 move->next = moves; 01450 moves = move; 01451 } 01452 01453 return(moves); 01454 01455 ddSwapAnyOutOfMem: 01456 while (moves != NULL) { 01457 move = moves->next; 01458 cuddDeallocMove(table, moves); 01459 moves = move; 01460 } 01461 return(NULL); 01462 01463 } /* end of ddSwapAny */
static int ddUniqueCompare | ( | int * | ptrX, | |
int * | ptrY | |||
) | [static] |
AutomaticStart
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 1314 of file cuddReorder.c.
static int ddUpdateMtrTree | ( | DdManager * | table, | |
MtrNode * | treenode, | |||
int * | perm, | |||
int * | invperm | |||
) | [static] |
Function********************************************************************
Synopsis [Updates the BDD variable group tree before a shuffle.]
Description [Updates the BDD variable group tree before a shuffle. Returns 1 if successful; 0 otherwise.]
SideEffects [Changes the BDD variable group tree.]
SeeAlso []
Definition at line 2035 of file cuddReorder.c.
02040 { 02041 unsigned int i, size; 02042 int index, level, minLevel, maxLevel, minIndex; 02043 02044 if (treenode == NULL) return(1); 02045 02046 minLevel = CUDD_MAXINDEX; 02047 maxLevel = 0; 02048 minIndex = -1; 02049 /* i : level */ 02050 for (i = treenode->low; i < treenode->low + treenode->size; i++) { 02051 index = table->invperm[i]; 02052 level = perm[index]; 02053 if (level < minLevel) { 02054 minLevel = level; 02055 minIndex = index; 02056 } 02057 if (level > maxLevel) 02058 maxLevel = level; 02059 } 02060 size = maxLevel - minLevel + 1; 02061 if (minIndex == -1) return(0); 02062 if (size == treenode->size) { 02063 treenode->low = minLevel; 02064 treenode->index = minIndex; 02065 } else { 02066 return(0); 02067 } 02068 02069 if (treenode->child != NULL) { 02070 if (!ddUpdateMtrTree(table, treenode->child, perm, invperm)) 02071 return(0); 02072 } 02073 if (treenode->younger != NULL) { 02074 if (!ddUpdateMtrTree(table, treenode->younger, perm, invperm)) 02075 return(0); 02076 } 02077 return(1); 02078 }
char rcsid [] DD_UNUSED = "$Id: cuddReorder.c,v 1.69 2009/02/21 18:24:10 fabio Exp $" [static] |
Definition at line 98 of file cuddReorder.c.
Definition at line 103 of file cuddReorder.c.
int* entry [static] |
Definition at line 101 of file cuddReorder.c.