src/bdd/cudd/cuddReorder.c File Reference

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

Go to the source code of this file.

Defines

#define DD_MAX_SUBTABLE_SPARSITY   8
#define DD_SHRINK_FACTOR   2

Functions

static int ddUniqueCompare ARGS ((int *ptrX, int *ptrY))
static Move *ddSwapAny ARGS ((DdManager *table, int x, int y))
static int ddSiftingAux ARGS ((DdManager *table, int x, int xLow, int xHigh))
static Move *ddSiftingUp ARGS ((DdManager *table, int y, int xLow))
static Move *ddSiftingDown ARGS ((DdManager *table, int x, int xHigh))
static int ddSiftingBackward ARGS ((DdManager *table, int size, Move *moves))
static int ddReorderPreprocess ARGS ((DdManager *table))
static int ddShuffle ARGS ((DdManager *table, int *permutation))
static int ddSiftUp ARGS ((DdManager *table, int x, int xLow))
static void bddFixTree ARGS ((DdManager *table, MtrNode *treenode))
static int ddUpdateMtrTree ARGS ((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)
DdNodecuddDynamicAllocNode (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)
static int ddUniqueCompare (int *ptrX, int *ptrY)
static MoveddSwapAny (DdManager *table, int x, int y)
static int ddSiftingAux (DdManager *table, int x, int xLow, int xHigh)
static MoveddSiftingUp (DdManager *table, int y, int xLow)
static MoveddSiftingDown (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)

Variables

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

Define Documentation

#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 [This file was created at the University of Colorado at Boulder. The University of Colorado at Boulder makes no warranty about the suitability of this software for any purpose. It is presented on an AS IS basis.]

Definition at line 55 of file cuddReorder.c.

#define DD_SHRINK_FACTOR   2

Definition at line 56 of file cuddReorder.c.


Function Documentation

static int ddCheckPermuation ARGS ( (DdManager *table, MtrNode *treenode, int *perm, int *invperm)   )  [static]
static void bddFixTree ARGS ( (DdManager *table, MtrNode *treenode)   )  [static]
static int ddSiftUp ARGS ( (DdManager *table, int x, int xLow)   )  [static]
static int ddShuffle ARGS ( (DdManager *table, int *permutation)   )  [static]
static int ddReorderPreprocess ARGS ( (DdManager *table)   )  [static]
static int ddSiftingBackward ARGS ( (DdManager *table, int size, Move *moves)   )  [static]
static Move* ddSiftingDown ARGS ( (DdManager *table, int x, int xHigh)   )  [static]
static Move* ddSiftingUp ARGS ( (DdManager *table, int y, int xLow)   )  [static]
static int ddSiftingAux ARGS ( (DdManager *table, int x, int xLow, int xHigh)   )  [static]
static Move* ddSwapAny ARGS ( (DdManager *table, int x, int y)   )  [static]
static int ddUniqueCompare ARGS ( (int *ptrX, int *ptrY)   )  [static]

AutomaticStart

static void bddFixTree ( DdManager table,
MtrNode treenode 
) [static]

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 1967 of file cuddReorder.c.

01970 {
01971     if (treenode == NULL) return;
01972     treenode->low = ((int) treenode->index < table->size) ?
01973         table->perm[treenode->index] : treenode->index;
01974     if (treenode->child != NULL) {
01975         bddFixTree(table, treenode->child);
01976     }
01977     if (treenode->younger != NULL)
01978         bddFixTree(table, treenode->younger);
01979     if (treenode->parent != NULL && treenode->low < treenode->parent->low) {
01980         treenode->parent->low = treenode->low;
01981         treenode->parent->index = treenode->index;
01982     }
01983     return;
01984 
01985 } /* 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:

  • Swapping
  • Sifting
  • Symmetric Sifting
  • Group Sifting
  • Window Permutation
  • Simulated Annealing
  • Genetic Algorithm
  • Dynamic Programming (exact)

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 145 of file cuddReorder.c.

00149 {
00150     DdHook *hook;
00151     int result;
00152     unsigned int nextDyn;
00153 #ifdef DD_STATS
00154     unsigned int initialSize;
00155     unsigned int finalSize;
00156 #endif
00157     long localTime;
00158 
00159     /* Don't reorder if there are too many dead nodes. */
00160     if (table->keys - table->dead < (unsigned) minsize)
00161         return(1);
00162 
00163     if (heuristic == CUDD_REORDER_SAME) {
00164         heuristic = table->autoMethod;
00165     }
00166     if (heuristic == CUDD_REORDER_NONE) {
00167         return(1);
00168     }
00169 
00170     /* This call to Cudd_ReduceHeap does initiate reordering. Therefore
00171     ** we count it.
00172     */
00173     table->reorderings++;
00174 
00175     localTime = util_cpu_time();
00176 
00177     /* Run the hook functions. */
00178     hook = table->preReorderingHook;
00179     while (hook != NULL) {
00180         int res = (hook->f)(table, "BDD", (void *)heuristic);
00181         if (res == 0) return(0);
00182         hook = hook->next;
00183     }
00184 
00185     if (!ddReorderPreprocess(table)) return(0);
00186     ddTotalNumberSwapping = 0;
00187     
00188     if (table->keys > table->peakLiveNodes) {
00189         table->peakLiveNodes = table->keys;
00190     }
00191 #ifdef DD_STATS
00192     initialSize = table->keys - table->isolated;
00193     ddTotalNISwaps = 0;
00194 
00195     switch(heuristic) {
00196     case CUDD_REORDER_RANDOM:
00197     case CUDD_REORDER_RANDOM_PIVOT:
00198         (void) fprintf(table->out,"#:I_RANDOM  ");
00199         break;
00200     case CUDD_REORDER_SIFT:
00201     case CUDD_REORDER_SIFT_CONVERGE:
00202     case CUDD_REORDER_SYMM_SIFT:
00203     case CUDD_REORDER_SYMM_SIFT_CONV:
00204     case CUDD_REORDER_GROUP_SIFT:
00205     case CUDD_REORDER_GROUP_SIFT_CONV:
00206         (void) fprintf(table->out,"#:I_SIFTING ");
00207         break;
00208     case CUDD_REORDER_WINDOW2:
00209     case CUDD_REORDER_WINDOW3:
00210     case CUDD_REORDER_WINDOW4:
00211     case CUDD_REORDER_WINDOW2_CONV:
00212     case CUDD_REORDER_WINDOW3_CONV:
00213     case CUDD_REORDER_WINDOW4_CONV:
00214         (void) fprintf(table->out,"#:I_WINDOW  ");
00215         break;
00216     case CUDD_REORDER_ANNEALING:
00217         (void) fprintf(table->out,"#:I_ANNEAL  ");
00218         break;
00219     case CUDD_REORDER_GENETIC:
00220         (void) fprintf(table->out,"#:I_GENETIC ");
00221         break;
00222     case CUDD_REORDER_LINEAR:
00223     case CUDD_REORDER_LINEAR_CONVERGE:
00224         (void) fprintf(table->out,"#:I_LINSIFT ");
00225         break;
00226     case CUDD_REORDER_EXACT:
00227         (void) fprintf(table->out,"#:I_EXACT   ");
00228         break;
00229     default:
00230         return(0);
00231     }
00232     (void) fprintf(table->out,"%8d: initial size",initialSize); 
00233 #endif
00234 
00235     /* See if we should use alternate threshold for maximum growth. */
00236     if (table->reordCycle && table->reorderings % table->reordCycle == 0) {
00237         double saveGrowth = table->maxGrowth;
00238         table->maxGrowth = table->maxGrowthAlt;
00239         result = cuddTreeSifting(table,heuristic);
00240         table->maxGrowth = saveGrowth;
00241     } else {
00242         result = cuddTreeSifting(table,heuristic);
00243     }
00244 
00245 #ifdef DD_STATS
00246     (void) fprintf(table->out,"\n");
00247     finalSize = table->keys - table->isolated;
00248     (void) fprintf(table->out,"#:F_REORDER %8d: final size\n",finalSize); 
00249     (void) fprintf(table->out,"#:T_REORDER %8g: total time (sec)\n",
00250                    ((double)(util_cpu_time() - localTime)/1000.0)); 
00251     (void) fprintf(table->out,"#:N_REORDER %8d: total swaps\n",
00252                    ddTotalNumberSwapping);
00253     (void) fprintf(table->out,"#:M_REORDER %8d: NI swaps\n",ddTotalNISwaps);
00254 #endif
00255 
00256     if (result == 0)
00257         return(0);
00258 
00259     if (!ddReorderPostprocess(table))
00260         return(0);
00261 
00262     if (table->realign) {
00263         if (!cuddZddAlignToBdd(table))
00264             return(0);
00265     }
00266 
00267     nextDyn = (table->keys - table->constants.keys + 1) *
00268               DD_DYN_RATIO + table->constants.keys;
00269     if (table->reorderings < 20 || nextDyn > table->nextDyn)
00270         table->nextDyn = nextDyn;
00271     else
00272         table->nextDyn += 20;
00273     table->reordered = 1;
00274 
00275     /* Run hook functions. */
00276     hook = table->postReorderingHook;
00277     while (hook != NULL) {
00278         int res = (hook->f)(table, "BDD", (void *)localTime);
00279         if (res == 0) return(0);
00280         hook = hook->next;
00281     }
00282     /* Update cumulative reordering time. */
00283     table->reordTime += util_cpu_time() - localTime;
00284 
00285     return(result);
00286 
00287 } /* 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 307 of file cuddReorder.c.

00310 {
00311 
00312     int result;
00313     int i;
00314     int identity = 1;
00315     int *perm;
00316 
00317     /* Don't waste time in case of identity permutation. */
00318     for (i = 0; i < table->size; i++) {
00319         if (permutation[i] != table->invperm[i]) {
00320             identity = 0;
00321             break;
00322         }
00323     }
00324     if (identity == 1) {
00325         return(1);
00326     }
00327     if (!ddReorderPreprocess(table)) return(0);
00328     if (table->keys > table->peakLiveNodes) {
00329         table->peakLiveNodes = table->keys;
00330     }
00331 
00332     perm = ALLOC(int, table->size);
00333     for (i = 0; i < table->size; i++)
00334         perm[permutation[i]] = i;
00335     if (!ddCheckPermuation(table,table->tree,perm,permutation)) {
00336         FREE(perm);
00337         return(0);
00338     }
00339     if (!ddUpdateMtrTree(table,table->tree,perm,permutation)) {
00340         FREE(perm);
00341         return(0);
00342     }
00343     FREE(perm);
00344 
00345     result = ddShuffle(table,permutation);
00346 
00347     if (!ddReorderPostprocess(table)) return(0);
00348 
00349     return(result);
00350 
00351 } /* 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 1208 of file cuddReorder.c.

01210 {
01211     int *invperm;               /* permutation array */
01212     int M;                      /* ratio of ZDD variables to BDD variables */
01213     int i;                      /* loop index */
01214     int result;                 /* return value */
01215 
01216     /* We assume that a ratio of 0 is OK. */
01217     if (table->size == 0)
01218         return(1);
01219 
01220     M = table->sizeZ / table->size;
01221     /* Check whether the number of ZDD variables is a multiple of the
01222     ** number of BDD variables.
01223     */
01224     if (M * table->size != table->sizeZ)
01225         return(0);
01226     /* Create and initialize the inverse permutation array. */
01227     invperm = ALLOC(int,table->size);
01228     if (invperm == NULL) {
01229         table->errorCode = CUDD_MEMORY_OUT;
01230         return(0);
01231     }
01232     for (i = 0; i < table->sizeZ; i += M) {
01233         int indexZ = table->invpermZ[i];
01234         int index  = indexZ / M;
01235         invperm[i / M] = index;
01236     }
01237     /* Eliminate dead nodes. Do not scan the cache again, because we
01238     ** assume that Cudd_zddReduceHeap has already cleared it.
01239     */
01240     cuddGarbageCollect(table,0);
01241 
01242     /* Initialize number of isolated projection functions. */
01243     table->isolated = 0;
01244     for (i = 0; i < table->size; i++) {
01245         if (table->vars[i]->ref == 1) table->isolated++;
01246     }
01247 
01248     /* Initialize the interaction matrix. */
01249     result = cuddInitInteract(table);
01250     if (result == 0) return(0);
01251 
01252     result = ddShuffle(table, invperm);
01253     FREE(invperm);
01254     /* Free interaction matrix. */
01255     FREE(table->interact);
01256     /* Fix the BDD variable group tree. */
01257     bddFixTree(table,table->tree);
01258     return(result);
01259 
01260 } /* end of cuddBddAlignToZdd */

DdNode* cuddDynamicAllocNode ( DdManager table  ) 

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 375 of file cuddReorder.c.

00377 {
00378     int     i;
00379     DdNodePtr *mem;
00380     DdNode *list, *node;
00381     extern void (*MMoutOfMemory)(long);
00382     void (*saveHandler)(long);
00383 
00384     if (table->nextFree == NULL) {        /* free list is empty */
00385         /* Try to allocate a new block. */
00386         saveHandler = MMoutOfMemory;
00387         MMoutOfMemory = Cudd_OutOfMem;
00388         mem = (DdNodePtr *) ALLOC(DdNode, DD_MEM_CHUNK + 1);
00389         MMoutOfMemory = saveHandler;
00390         if (mem == NULL && table->stash != NULL) {
00391             FREE(table->stash);
00392             table->stash = NULL;
00393             /* Inhibit resizing of tables. */
00394             table->maxCacheHard = table->cacheSlots - 1;
00395             table->cacheSlack = -(table->cacheSlots + 1);
00396             for (i = 0; i < table->size; i++) {
00397                 table->subtables[i].maxKeys <<= 2;
00398             }
00399             mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
00400         }
00401         if (mem == NULL) {
00402             /* Out of luck. Call the default handler to do
00403             ** whatever it specifies for a failed malloc.  If this
00404             ** handler returns, then set error code, print
00405             ** warning, and return. */
00406             (*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1));
00407             table->errorCode = CUDD_MEMORY_OUT;
00408 #ifdef DD_VERBOSE
00409             (void) fprintf(table->err,
00410                            "cuddDynamicAllocNode: out of memory");
00411             (void) fprintf(table->err,"Memory in use = %ld\n",
00412                            table->memused);
00413 #endif
00414             return(NULL);
00415         } else {        /* successful allocation; slice memory */
00416             unsigned long offset;
00417             table->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode);
00418             mem[0] = (DdNode *) table->memoryList;
00419             table->memoryList = mem;
00420 
00421             /* Here we rely on the fact that the size of a DdNode is a
00422             ** power of 2 and a multiple of the size of a pointer.
00423             ** If we align one node, all the others will be aligned
00424             ** as well. */
00425             offset = (unsigned long) mem & (sizeof(DdNode) - 1);
00426             mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
00427 #ifdef DD_DEBUG
00428             assert(((unsigned long) mem & (sizeof(DdNode) - 1)) == 0);
00429 #endif
00430             list = (DdNode *) mem;
00431 
00432             i = 1;
00433             do {
00434                 list[i - 1].next = &list[i];
00435             } while (++i < DD_MEM_CHUNK);
00436 
00437             list[DD_MEM_CHUNK - 1].next = NULL;
00438 
00439             table->nextFree = &list[0];
00440         }
00441     } /* if free list empty */
00442 
00443     node = table->nextFree;
00444     table->nextFree = node->next;
00445     return (node);
00446 
00447 } /* 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 678 of file cuddReorder.c.

00681 {
00682     return(x+1);
00683 
00684 } /* end of cuddNextHigh */

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 700 of file cuddReorder.c.

00703 {
00704     return(x-1);
00705 
00706 } /* end of cuddNextLow */

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.

  1. Order all the variables according to the number of entries in each unique table.
  2. Sift the variable up and down, remembering each time the total size of the DD heap.
  3. Select the best permutation.
  4. Repeat 3 and 4 for all variables.

Returns 1 if successful; 0 otherwise.]

SideEffects [None]

Definition at line 470 of file cuddReorder.c.

00474 {
00475     int i;
00476     int *var;
00477     int size;
00478     int x;
00479     int result;
00480 #ifdef DD_STATS
00481     int previousSize;
00482 #endif
00483 
00484     size = table->size;
00485 
00486     /* Find order in which to sift variables. */
00487     var = NULL;
00488     entry = ALLOC(int,size);
00489     if (entry == NULL) {
00490         table->errorCode = CUDD_MEMORY_OUT;
00491         goto cuddSiftingOutOfMem;
00492     }
00493     var = ALLOC(int,size);
00494     if (var == NULL) {
00495         table->errorCode = CUDD_MEMORY_OUT;
00496         goto cuddSiftingOutOfMem;
00497     }
00498 
00499     for (i = 0; i < size; i++) {
00500         x = table->perm[i];
00501         entry[i] = table->subtables[x].keys;
00502         var[i] = i;
00503     }
00504 
00505     qsort((void *)var,size,sizeof(int),(int (*)(const void *, const void *))ddUniqueCompare);
00506 
00507     /* Now sift. */
00508     for (i = 0; i < ddMin(table->siftMaxVar,size); i++) {
00509         if (ddTotalNumberSwapping >= table->siftMaxSwap)
00510             break;
00511         x = table->perm[var[i]];
00512         
00513         if (x < lower || x > upper || table->subtables[x].bindVar == 1) 
00514             continue;
00515 #ifdef DD_STATS
00516         previousSize = table->keys - table->isolated;
00517 #endif
00518         result = ddSiftingAux(table, x, lower, upper);
00519         if (!result) goto cuddSiftingOutOfMem;
00520 #ifdef DD_STATS
00521         if (table->keys < (unsigned) previousSize + table->isolated) {
00522             (void) fprintf(table->out,"-");
00523         } else if (table->keys > (unsigned) previousSize + table->isolated) {
00524             (void) fprintf(table->out,"+");     /* should never happen */
00525             (void) fprintf(table->err,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keys - table->isolated, var[i]);
00526         } else {
00527             (void) fprintf(table->out,"=");
00528         }
00529         fflush(table->out);
00530 #endif
00531     }
00532 
00533     FREE(var);
00534     FREE(entry);
00535 
00536     return(1);
00537 
00538 cuddSiftingOutOfMem:
00539 
00540     if (entry != NULL) FREE(entry);
00541     if (var != NULL) FREE(var);
00542 
00543     return(0); 
00544 
00545 } /* 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 723 of file cuddReorder.c.

00727 {
00728     DdNodePtr *xlist, *ylist;
00729     int    xindex, yindex;
00730     int    xslots, yslots;
00731     int    xshift, yshift;
00732     int    oldxkeys, oldykeys;
00733     int    newxkeys, newykeys;
00734     int    comple, newcomplement;
00735     int    i;
00736     Cudd_VariableType varType;
00737     Cudd_LazyGroupType groupType;
00738     int    posn;
00739     int    isolated;
00740     DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10,*newf1,*newf0;
00741     DdNode *g,*next;
00742     DdNodePtr *previousP;
00743     DdNode *tmp;
00744     DdNode *sentinel = &(table->sentinel);
00745     extern void (*MMoutOfMemory)(long);
00746     void (*saveHandler)(long);
00747 
00748 #if DD_DEBUG
00749     int    count,idcheck;
00750 #endif
00751 
00752 #ifdef DD_DEBUG
00753     assert(x < y);
00754     assert(cuddNextHigh(table,x) == y);
00755     assert(table->subtables[x].keys != 0);
00756     assert(table->subtables[y].keys != 0);
00757     assert(table->subtables[x].dead == 0);
00758     assert(table->subtables[y].dead == 0);
00759 #endif
00760 
00761     ddTotalNumberSwapping++;
00762 
00763     /* Get parameters of x subtable. */
00764     xindex = table->invperm[x];
00765     xlist = table->subtables[x].nodelist; 
00766     oldxkeys = table->subtables[x].keys;
00767     xslots = table->subtables[x].slots;
00768     xshift = table->subtables[x].shift;
00769 
00770     /* Get parameters of y subtable. */
00771     yindex = table->invperm[y];
00772     ylist = table->subtables[y].nodelist;
00773     oldykeys = table->subtables[y].keys;
00774     yslots = table->subtables[y].slots;
00775     yshift = table->subtables[y].shift;
00776 
00777     if (!cuddTestInteract(table,xindex,yindex)) {
00778 #ifdef DD_STATS
00779         ddTotalNISwaps++;
00780 #endif
00781         newxkeys = oldxkeys;
00782         newykeys = oldykeys;
00783     } else {
00784         newxkeys = 0;
00785         newykeys = oldykeys;
00786 
00787         /* Check whether the two projection functions involved in this
00788         ** swap are isolated. At the end, we'll be able to tell how many
00789         ** isolated projection functions are there by checking only these
00790         ** two functions again. This is done to eliminate the isolated
00791         ** projection functions from the node count.
00792         */
00793         isolated = - ((table->vars[xindex]->ref == 1) +
00794                      (table->vars[yindex]->ref == 1));
00795 
00796         /* The nodes in the x layer that do not depend on
00797         ** y will stay there; the others are put in a chain.
00798         ** The chain is handled as a LIFO; g points to the beginning.
00799         */
00800         g = NULL;
00801         if ((oldxkeys >= xslots || (unsigned) xslots == table->initSlots) &&
00802             oldxkeys <= DD_MAX_SUBTABLE_DENSITY * xslots) {
00803             for (i = 0; i < xslots; i++) {
00804                 previousP = &(xlist[i]);
00805                 f = *previousP;
00806                 while (f != sentinel) {
00807                     next = f->next;
00808                     f1 = cuddT(f); f0 = cuddE(f);
00809                     if (f1->index != (DdHalfWord) yindex &&
00810                         Cudd_Regular(f0)->index != (DdHalfWord) yindex) {
00811                         /* stays */
00812                         newxkeys++;
00813                         *previousP = f;
00814                         previousP = &(f->next);
00815                     } else {
00816                         f->index = yindex;
00817                         f->next = g;
00818                         g = f;
00819                     }
00820                     f = next;
00821                 } /* while there are elements in the collision chain */
00822                 *previousP = sentinel;
00823             } /* for each slot of the x subtable */
00824         } else {                /* resize xlist */
00825             DdNode *h = NULL;
00826             DdNodePtr *newxlist;
00827             unsigned int newxslots;
00828             int newxshift;
00829             /* Empty current xlist. Nodes that stay go to list h;
00830             ** nodes that move go to list g. */
00831             for (i = 0; i < xslots; i++) {
00832                 f = xlist[i];
00833                 while (f != sentinel) {
00834                     next = f->next;
00835                     f1 = cuddT(f); f0 = cuddE(f);
00836                     if (f1->index != (DdHalfWord) yindex &&
00837                         Cudd_Regular(f0)->index != (DdHalfWord) yindex) {
00838                         /* stays */
00839                         f->next = h;
00840                         h = f;
00841                         newxkeys++;
00842                     } else {
00843                         f->index = yindex;
00844                         f->next = g;
00845                         g = f;
00846                     }
00847                     f = next;
00848                 } /* while there are elements in the collision chain */
00849             } /* for each slot of the x subtable */
00850             /* Decide size of new subtable. */
00851             if (oldxkeys > DD_MAX_SUBTABLE_DENSITY * xslots) {
00852                 newxshift = xshift - 1;
00853                 newxslots = xslots << 1;
00854             } else {
00855                 newxshift = xshift + 1;
00856                 newxslots = xslots >> 1;
00857             }
00858             /* Try to allocate new table. Be ready to back off. */
00859             saveHandler = MMoutOfMemory;
00860             MMoutOfMemory = Cudd_OutOfMem;
00861             newxlist = ALLOC(DdNodePtr, newxslots);
00862             MMoutOfMemory = saveHandler;
00863             if (newxlist == NULL) {
00864                 (void) fprintf(table->err, "Unable to resize subtable %d for lack of memory\n", i);
00865                 newxlist = xlist;
00866                 newxslots = xslots;
00867                 newxshift = xshift;
00868             } else {
00869                 table->slots += (newxslots - xslots);
00870                 table->minDead = (unsigned)
00871                     (table->gcFrac * (double) table->slots);
00872                 table->cacheSlack = (int)
00873                     ddMin(table->maxCacheHard, DD_MAX_CACHE_TO_SLOTS_RATIO
00874                           * table->slots) - 2 * (int) table->cacheSlots;
00875                 table->memused += (newxslots - xslots) * sizeof(DdNodePtr);
00876                 FREE(xlist);
00877                 xslots =  newxslots;
00878                 xshift = newxshift;
00879                 xlist = newxlist;
00880             }
00881             /* Initialize new subtable. */
00882             for (i = 0; i < xslots; i++) {
00883                 xlist[i] = sentinel;
00884             }
00885             /* Move nodes that were parked in list h to their new home. */
00886             f = h;
00887             while (f != NULL) {
00888                 next = f->next;
00889                 f1 = cuddT(f);
00890                 f0 = cuddE(f);
00891                 /* Check xlist for pair (f11,f01). */
00892                 posn = ddHash(f1, f0, xshift);
00893                 /* For each element tmp in collision list xlist[posn]. */
00894                 previousP = &(xlist[posn]);
00895                 tmp = *previousP;
00896                 while (f1 < cuddT(tmp)) {
00897                     previousP = &(tmp->next);
00898                     tmp = *previousP;
00899                 }
00900                 while (f1 == cuddT(tmp) && f0 < cuddE(tmp)) {
00901                     previousP = &(tmp->next);
00902                     tmp = *previousP;
00903                 }
00904                 f->next = *previousP;
00905                 *previousP = f;
00906                 f = next;
00907             }
00908         }
00909 
00910 #ifdef DD_COUNT
00911         table->swapSteps += oldxkeys - newxkeys;
00912 #endif
00913         /* Take care of the x nodes that must be re-expressed.
00914         ** They form a linked list pointed by g. Their index has been
00915         ** already changed to yindex.
00916         */
00917         f = g;
00918         while (f != NULL) {
00919             next = f->next;
00920             /* Find f1, f0, f11, f10, f01, f00. */
00921             f1 = cuddT(f);
00922 #ifdef DD_DEBUG
00923             assert(!(Cudd_IsComplement(f1)));
00924 #endif
00925             if ((int) f1->index == yindex) {
00926                 f11 = cuddT(f1); f10 = cuddE(f1);
00927             } else {
00928                 f11 = f10 = f1;
00929             }
00930 #ifdef DD_DEBUG
00931             assert(!(Cudd_IsComplement(f11)));
00932 #endif
00933             f0 = cuddE(f);
00934             comple = Cudd_IsComplement(f0);
00935             f0 = Cudd_Regular(f0);
00936             if ((int) f0->index == yindex) {
00937                 f01 = cuddT(f0); f00 = cuddE(f0);
00938             } else {
00939                 f01 = f00 = f0;
00940             }
00941             if (comple) {
00942                 f01 = Cudd_Not(f01);
00943                 f00 = Cudd_Not(f00);
00944             }
00945             /* Decrease ref count of f1. */
00946             cuddSatDec(f1->ref);
00947             /* Create the new T child. */
00948             if (f11 == f01) {
00949                 newf1 = f11;
00950                 cuddSatInc(newf1->ref);
00951             } else {
00952                 /* Check xlist for triple (xindex,f11,f01). */
00953                 posn = ddHash(f11, f01, xshift);
00954                 /* For each element newf1 in collision list xlist[posn]. */
00955                 previousP = &(xlist[posn]);
00956                 newf1 = *previousP;
00957                 while (f11 < cuddT(newf1)) {
00958                     previousP = &(newf1->next);
00959                     newf1 = *previousP;
00960                 }
00961                 while (f11 == cuddT(newf1) && f01 < cuddE(newf1)) {
00962                     previousP = &(newf1->next);
00963                     newf1 = *previousP;
00964                 }
00965                 if (cuddT(newf1) == f11 && cuddE(newf1) == f01) {
00966                     cuddSatInc(newf1->ref);
00967                 } else { /* no match */
00968                     newf1 = cuddDynamicAllocNode(table);
00969                     if (newf1 == NULL)
00970                         goto cuddSwapOutOfMem;
00971                     newf1->index = xindex; newf1->ref = 1;
00972                     cuddT(newf1) = f11;
00973                     cuddE(newf1) = f01;
00974                     /* Insert newf1 in the collision list xlist[posn];
00975                     ** increase the ref counts of f11 and f01.
00976                     */
00977                     newxkeys++;
00978                     newf1->next = *previousP;
00979                     *previousP = newf1;
00980                     cuddSatInc(f11->ref);
00981                     tmp = Cudd_Regular(f01);
00982                     cuddSatInc(tmp->ref);
00983                 }
00984             }
00985             cuddT(f) = newf1;
00986 #ifdef DD_DEBUG
00987             assert(!(Cudd_IsComplement(newf1)));
00988 #endif
00989 
00990             /* Do the same for f0, keeping complement dots into account. */
00991             /* Decrease ref count of f0. */
00992             tmp = Cudd_Regular(f0);
00993             cuddSatDec(tmp->ref);
00994             /* Create the new E child. */
00995             if (f10 == f00) {
00996                 newf0 = f00;
00997                 tmp = Cudd_Regular(newf0);
00998                 cuddSatInc(tmp->ref); 
00999             } else {
01000                 /* make sure f10 is regular */
01001                 newcomplement = Cudd_IsComplement(f10);
01002                 if (newcomplement) {
01003                     f10 = Cudd_Not(f10);
01004                     f00 = Cudd_Not(f00);
01005                 }
01006                 /* Check xlist for triple (xindex,f10,f00). */
01007                 posn = ddHash(f10, f00, xshift);
01008                 /* For each element newf0 in collision list xlist[posn]. */
01009                 previousP = &(xlist[posn]);
01010                 newf0 = *previousP;
01011                 while (f10 < cuddT(newf0)) {
01012                     previousP = &(newf0->next);
01013                     newf0 = *previousP;
01014                 }
01015                 while (f10 == cuddT(newf0) && f00 < cuddE(newf0)) {
01016                     previousP = &(newf0->next);
01017                     newf0 = *previousP;
01018                 }
01019                 if (cuddT(newf0) == f10 && cuddE(newf0) == f00) {
01020                     cuddSatInc(newf0->ref); 
01021                 } else { /* no match */
01022                     newf0 = cuddDynamicAllocNode(table);
01023                     if (newf0 == NULL)
01024                         goto cuddSwapOutOfMem;
01025                     newf0->index = xindex; newf0->ref = 1;
01026                     cuddT(newf0) = f10;
01027                     cuddE(newf0) = f00;
01028                     /* Insert newf0 in the collision list xlist[posn];
01029                     ** increase the ref counts of f10 and f00.
01030                     */
01031                     newxkeys++;
01032                     newf0->next = *previousP;
01033                     *previousP = newf0;
01034                     cuddSatInc(f10->ref);
01035                     tmp = Cudd_Regular(f00);
01036                     cuddSatInc(tmp->ref);
01037                 }
01038                 if (newcomplement) {
01039                     newf0 = Cudd_Not(newf0);
01040                 }
01041             }
01042             cuddE(f) = newf0;
01043 
01044             /* Insert the modified f in ylist.
01045             ** The modified f does not already exists in ylist.
01046             ** (Because of the uniqueness of the cofactors.)
01047             */
01048             posn = ddHash(newf1, newf0, yshift);
01049             newykeys++;
01050             previousP = &(ylist[posn]);
01051             tmp = *previousP;
01052             while (newf1 < cuddT(tmp)) {
01053                 previousP = &(tmp->next);
01054                 tmp = *previousP;
01055             }
01056             while (newf1 == cuddT(tmp) && newf0 < cuddE(tmp)) {
01057                 previousP = &(tmp->next);
01058                 tmp = *previousP;
01059             }
01060             f->next = *previousP;
01061             *previousP = f;
01062             f = next;
01063         } /* while f != NULL */
01064 
01065         /* GC the y layer. */
01066 
01067         /* For each node f in ylist. */
01068         for (i = 0; i < yslots; i++) {
01069             previousP = &(ylist[i]);
01070             f = *previousP;
01071             while (f != sentinel) {
01072                 next = f->next;
01073                 if (f->ref == 0) {
01074                     tmp = cuddT(f);
01075                     cuddSatDec(tmp->ref);
01076                     tmp = Cudd_Regular(cuddE(f));
01077                     cuddSatDec(tmp->ref);
01078                     cuddDeallocNode(table,f);
01079                     newykeys--;
01080                 } else {
01081                     *previousP = f;
01082                     previousP = &(f->next);
01083                 }
01084                 f = next;
01085             } /* while f */
01086             *previousP = sentinel;
01087         } /* for i */
01088 
01089 #if DD_DEBUG
01090 #if 0
01091         (void) fprintf(table->out,"Swapping %d and %d\n",x,y);
01092 #endif
01093         count = 0;
01094         idcheck = 0;
01095         for (i = 0; i < yslots; i++) {
01096             f = ylist[i];
01097             while (f != sentinel) {
01098                 count++;
01099                 if (f->index != (DdHalfWord) yindex)
01100                     idcheck++;
01101                 f = f->next;
01102             }
01103         }
01104         if (count != newykeys) {
01105             (void) fprintf(table->out,
01106                            "Error in finding newykeys\toldykeys = %d\tnewykeys = %d\tactual = %d\n",
01107                            oldykeys,newykeys,count);
01108         }
01109         if (idcheck != 0)
01110             (void) fprintf(table->out,
01111                            "Error in id's of ylist\twrong id's = %d\n",
01112                            idcheck);
01113         count = 0;
01114         idcheck = 0;
01115         for (i = 0; i < xslots; i++) {
01116             f = xlist[i];
01117             while (f != sentinel) {
01118                 count++;
01119                 if (f->index != (DdHalfWord) xindex)
01120                     idcheck++;
01121                 f = f->next;
01122             }
01123         }
01124         if (count != newxkeys) {
01125             (void) fprintf(table->out,
01126                            "Error in finding newxkeys\toldxkeys = %d \tnewxkeys = %d \tactual = %d\n",
01127                            oldxkeys,newxkeys,count);
01128         }
01129         if (idcheck != 0)
01130             (void) fprintf(table->out,
01131                            "Error in id's of xlist\twrong id's = %d\n",
01132                            idcheck);
01133 #endif
01134 
01135         isolated += (table->vars[xindex]->ref == 1) +
01136                     (table->vars[yindex]->ref == 1);
01137         table->isolated += isolated;
01138     }
01139 
01140     /* Set the appropriate fields in table. */
01141     table->subtables[x].nodelist = ylist;
01142     table->subtables[x].slots = yslots;
01143     table->subtables[x].shift = yshift;
01144     table->subtables[x].keys = newykeys;
01145     table->subtables[x].maxKeys = yslots * DD_MAX_SUBTABLE_DENSITY;
01146     i = table->subtables[x].bindVar;
01147     table->subtables[x].bindVar = table->subtables[y].bindVar;
01148     table->subtables[y].bindVar = i;
01149     /* Adjust filds for lazy sifting. */
01150     varType = table->subtables[x].varType;
01151     table->subtables[x].varType = table->subtables[y].varType;
01152     table->subtables[y].varType = varType;
01153     i = table->subtables[x].pairIndex;
01154     table->subtables[x].pairIndex = table->subtables[y].pairIndex;
01155     table->subtables[y].pairIndex = i;
01156     i = table->subtables[x].varHandled;
01157     table->subtables[x].varHandled = table->subtables[y].varHandled;
01158     table->subtables[y].varHandled = i;
01159     groupType = table->subtables[x].varToBeGrouped;
01160     table->subtables[x].varToBeGrouped = table->subtables[y].varToBeGrouped;
01161     table->subtables[y].varToBeGrouped = groupType;
01162 
01163     table->subtables[y].nodelist = xlist;
01164     table->subtables[y].slots = xslots;
01165     table->subtables[y].shift = xshift;
01166     table->subtables[y].keys = newxkeys;
01167     table->subtables[y].maxKeys = xslots * DD_MAX_SUBTABLE_DENSITY;
01168 
01169     table->perm[xindex] = y; table->perm[yindex] = x;
01170     table->invperm[x] = yindex; table->invperm[y] = xindex;
01171 
01172     table->keys += newxkeys + newykeys - oldxkeys - oldykeys;
01173 
01174     return(table->keys - table->isolated);
01175 
01176 cuddSwapOutOfMem:
01177     (void) fprintf(table->err,"Error: cuddSwapInPlace out of memory\n");
01178 
01179     return (0);
01180 
01181 } /* 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.

  1. Select two variables (RANDOM or HEURISTIC).
  2. Permute these variables.
  3. If the nodes have decreased accept the permutation.
  4. Otherwise reconstruct the original heap.
  5. Loop.

Returns 1 in case of success; 0 otherwise.]

SideEffects [None]

Definition at line 567 of file cuddReorder.c.

00572 {
00573     int i, j;
00574     int max, keys;
00575     int nvars;
00576     int x, y;
00577     int iterate;
00578     int previousSize;
00579     Move *moves, *move;
00580     int pivot;
00581     int modulo;
00582     int result;
00583 
00584 #ifdef DD_DEBUG
00585     /* Sanity check */
00586     assert(lower >= 0 && upper < table->size && lower <= upper);
00587 #endif
00588 
00589     nvars = upper - lower + 1;
00590     iterate = nvars;
00591 
00592     for (i = 0; i < iterate; i++) {
00593         if (ddTotalNumberSwapping >= table->siftMaxSwap)
00594             break;
00595         if (heuristic == CUDD_REORDER_RANDOM_PIVOT) {
00596             max = -1;
00597             for (j = lower; j <= upper; j++) {
00598                 if ((keys = table->subtables[j].keys) > max) {
00599                     max = keys;
00600                     pivot = j;
00601                 }
00602             }
00603 
00604             modulo = upper - pivot;
00605             if (modulo == 0) {
00606                 y = pivot;
00607             } else{
00608                 y = pivot + 1 + ((int) Cudd_Random() % modulo);
00609             }
00610 
00611             modulo = pivot - lower - 1;
00612             if (modulo < 1) {
00613                 x = lower;
00614             } else{
00615                 do {
00616                     x = (int) Cudd_Random() % modulo;
00617                 } while (x == y);
00618             }
00619         } else {
00620             x = ((int) Cudd_Random() % nvars) + lower;
00621             do {
00622                 y = ((int) Cudd_Random() % nvars) + lower;
00623             } while (x == y);
00624         }
00625         previousSize = table->keys - table->isolated;
00626         moves = ddSwapAny(table,x,y);
00627         if (moves == NULL) goto cuddSwappingOutOfMem;
00628         result = ddSiftingBackward(table,previousSize,moves);
00629         if (!result) goto cuddSwappingOutOfMem;
00630         while (moves != NULL) {
00631             move = moves->next;
00632             cuddDeallocNode(table, (DdNode *) moves);
00633             moves = move;
00634         }
00635 #ifdef DD_STATS
00636         if (table->keys < (unsigned) previousSize + table->isolated) {
00637             (void) fprintf(table->out,"-");
00638         } else if (table->keys > (unsigned) previousSize + table->isolated) {
00639             (void) fprintf(table->out,"+");     /* should never happen */
00640         } else {
00641             (void) fprintf(table->out,"=");
00642         }
00643         fflush(table->out);
00644 #endif
00645 #if 0
00646         (void) fprintf(table->out,"#:t_SWAPPING %8d: tmp size\n",
00647                        table->keys - table->isolated); 
00648 #endif
00649     }
00650 
00651     return(1);
00652 
00653 cuddSwappingOutOfMem:
00654     while (moves != NULL) {
00655         move = moves->next;
00656         cuddDeallocNode(table, (DdNode *) moves);
00657         moves = move;
00658     }
00659 
00660     return(0);
00661 
00662 } /* 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 2055 of file cuddReorder.c.

02060 {
02061     int i, size, index, level;
02062     int minLevel, maxLevel;
02063 
02064     if (treenode == NULL) return(1);
02065 
02066     minLevel = table->size;
02067     maxLevel = 0;
02068     /* i : level */
02069     for (i = treenode->low; i < treenode->low + treenode->size; i++) {
02070         index = table->invperm[i];
02071         level = perm[index];
02072         if (level < minLevel)
02073             minLevel = level;
02074         if (level > maxLevel)
02075             maxLevel = level;
02076     }
02077     size = maxLevel - minLevel + 1;
02078     if (size != treenode->size)
02079         return(0);
02080 
02081     if (treenode->child != NULL) {
02082         if (!ddCheckPermuation(table, treenode->child, perm, invperm))
02083             return(0);
02084     }
02085     if (treenode->younger != NULL) {
02086         if (!ddCheckPermuation(table, treenode->younger, perm, invperm))
02087             return(0);
02088     }
02089     return(1);
02090 }

static int ddReorderPostprocess ( DdManager table  )  [static]

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

Synopsis [Cleans up at the end of reordering.]

Description []

SideEffects [None]

Definition at line 1821 of file cuddReorder.c.

01823 {
01824 
01825 #ifdef DD_VERBOSE
01826     (void) fflush(table->out);
01827 #endif
01828 
01829     /* Free interaction matrix. */
01830     FREE(table->interact);
01831 
01832     return(1);
01833 
01834 } /* end of ddReorderPostprocess */

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 1783 of file cuddReorder.c.

01785 {
01786     int i;
01787     int res;
01788 
01789     /* Clear the cache. */
01790     cuddCacheFlush(table);
01791     cuddLocalCacheClearAll(table);
01792 
01793     /* Eliminate dead nodes. Do not scan the cache again. */
01794     cuddGarbageCollect(table,0);
01795 
01796     /* Initialize number of isolated projection functions. */
01797     table->isolated = 0;
01798     for (i = 0; i < table->size; i++) {
01799         if (table->vars[i]->ref == 1) table->isolated++;
01800     }
01801 
01802     /* Initialize the interaction matrix. */
01803     res = cuddInitInteract(table);
01804     if (res == 0) return(0);
01805 
01806     return(1);
01807 
01808 } /* 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 1854 of file cuddReorder.c.

01857 {
01858     int         index;
01859     int         level;
01860     int         position;
01861     int         numvars;
01862     int         result;
01863 #ifdef DD_STATS
01864     long        localTime;
01865     int         initialSize;
01866     int         finalSize;
01867     int         previousSize;
01868 #endif
01869 
01870     ddTotalNumberSwapping = 0;
01871 #ifdef DD_STATS
01872     localTime = util_cpu_time();
01873     initialSize = table->keys - table->isolated;
01874     (void) fprintf(table->out,"#:I_SHUFFLE %8d: initial size\n",
01875                    initialSize); 
01876     ddTotalNISwaps = 0;
01877 #endif
01878 
01879     numvars = table->size;
01880 
01881     for (level = 0; level < numvars; level++) {
01882         index = permutation[level];
01883         position = table->perm[index];
01884 #ifdef DD_STATS
01885         previousSize = table->keys - table->isolated;
01886 #endif
01887         result = ddSiftUp(table,position,level);
01888         if (!result) return(0);
01889 #ifdef DD_STATS
01890         if (table->keys < (unsigned) previousSize + table->isolated) {
01891             (void) fprintf(table->out,"-");
01892         } else if (table->keys > (unsigned) previousSize + table->isolated) {
01893             (void) fprintf(table->out,"+");     /* should never happen */
01894         } else {
01895             (void) fprintf(table->out,"=");
01896         }
01897         fflush(table->out);
01898 #endif
01899     }
01900 
01901 #ifdef DD_STATS
01902     (void) fprintf(table->out,"\n");
01903     finalSize = table->keys - table->isolated;
01904     (void) fprintf(table->out,"#:F_SHUFFLE %8d: final size\n",finalSize); 
01905     (void) fprintf(table->out,"#:T_SHUFFLE %8g: total time (sec)\n",
01906         ((double)(util_cpu_time() - localTime)/1000.0)); 
01907     (void) fprintf(table->out,"#:N_SHUFFLE %8d: total swaps\n",
01908                    ddTotalNumberSwapping);
01909     (void) fprintf(table->out,"#:M_SHUFFLE %8d: NI swaps\n",ddTotalNISwaps);
01910 #endif
01911 
01912     return(1);
01913 
01914 } /* 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 1445 of file cuddReorder.c.

01450 {
01451 
01452     Move        *move;
01453     Move        *moveUp;                /* list of up moves */
01454     Move        *moveDown;              /* list of down moves */
01455     int         initialSize;
01456     int         result;
01457 
01458     initialSize = table->keys - table->isolated;
01459 
01460     moveDown = NULL;
01461     moveUp = NULL;
01462 
01463     if (x == xLow) {
01464         moveDown = ddSiftingDown(table,x,xHigh);
01465         /* At this point x --> xHigh unless bounding occurred. */
01466         if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
01467         /* Move backward and stop at best position. */  
01468         result = ddSiftingBackward(table,initialSize,moveDown);
01469         if (!result) goto ddSiftingAuxOutOfMem;
01470 
01471     } else if (x == xHigh) {
01472         moveUp = ddSiftingUp(table,x,xLow);
01473         /* At this point x --> xLow unless bounding occurred. */
01474         if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
01475         /* Move backward and stop at best position. */
01476         result = ddSiftingBackward(table,initialSize,moveUp);
01477         if (!result) goto ddSiftingAuxOutOfMem;
01478 
01479     } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
01480         moveDown = ddSiftingDown(table,x,xHigh);
01481         /* At this point x --> xHigh unless bounding occurred. */
01482         if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
01483         if (moveDown != NULL) {
01484             x = moveDown->y;
01485         }
01486         moveUp = ddSiftingUp(table,x,xLow);
01487         if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
01488         /* Move backward and stop at best position */   
01489         result = ddSiftingBackward(table,initialSize,moveUp);
01490         if (!result) goto ddSiftingAuxOutOfMem;
01491 
01492     } else { /* must go up first: shorter */
01493         moveUp = ddSiftingUp(table,x,xLow);
01494         /* At this point x --> xLow unless bounding occurred. */
01495         if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddSiftingAuxOutOfMem;
01496         if (moveUp != NULL) {
01497             x = moveUp->x;
01498         }
01499         moveDown = ddSiftingDown(table,x,xHigh);
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 
01506     while (moveDown != NULL) {
01507         move = moveDown->next;
01508         cuddDeallocNode(table, (DdNode *) moveDown);
01509         moveDown = move;
01510     }
01511     while (moveUp != NULL) {
01512         move = moveUp->next;
01513         cuddDeallocNode(table, (DdNode *) moveUp);
01514         moveUp = move;
01515     }
01516 
01517     return(1);
01518 
01519 ddSiftingAuxOutOfMem:
01520     if (moveDown != (Move *) CUDD_OUT_OF_MEM) {
01521         while (moveDown != NULL) {
01522             move = moveDown->next;
01523             cuddDeallocNode(table, (DdNode *) moveDown);
01524             moveDown = move;
01525         }
01526     }
01527     if (moveUp != (Move *) CUDD_OUT_OF_MEM) {
01528         while (moveUp != NULL) {
01529             move = moveUp->next;
01530             cuddDeallocNode(table, (DdNode *) moveUp);
01531             moveUp = move;
01532         }
01533     }
01534 
01535     return(0);
01536 
01537 } /* end of ddSiftingAux */

static int ddSiftingBackward ( DdManager table,
int  size,
Move moves 
) [static]

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 1744 of file cuddReorder.c.

01748 {
01749     Move *move;
01750     int res;
01751 
01752     for (move = moves; move != NULL; move = move->next) {
01753         if (move->size < size) {
01754             size = move->size;
01755         }
01756     }
01757 
01758     for (move = moves; move != NULL; move = move->next) {
01759         if (move->size == size) return(1);
01760         res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
01761         if (!res) return(0);    
01762     }
01763 
01764     return(1);
01765 
01766 } /* end of ddSiftingBackward */

static Move* ddSiftingDown ( DdManager table,
int  x,
int  xHigh 
) [static]

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 1652 of file cuddReorder.c.

01656 {
01657     Move        *moves;
01658     Move        *move;
01659     int         y;
01660     int         size;
01661     int         R;      /* upper bound on node decrease */
01662     int         limitSize;
01663     int         xindex, yindex;
01664     int         isolated;
01665 #ifdef DD_DEBUG
01666     int         checkR;
01667     int         z;
01668     int         zindex;
01669 #endif
01670 
01671     moves = NULL;
01672     /* Initialize R */
01673     xindex = table->invperm[x];
01674     limitSize = size = table->keys - table->isolated;
01675     R = 0;
01676     for (y = xHigh; y > x; y--) {
01677         yindex = table->invperm[y];
01678         if (cuddTestInteract(table,xindex,yindex)) {
01679             isolated = table->vars[yindex]->ref == 1;
01680             R += table->subtables[y].keys - isolated;
01681         }
01682     }
01683 
01684     y = cuddNextHigh(table,x);
01685     while (y <= xHigh && size - R < limitSize) {
01686 #ifdef DD_DEBUG
01687         checkR = 0;
01688         for (z = xHigh; z > x; z--) {
01689             zindex = table->invperm[z];
01690             if (cuddTestInteract(table,xindex,zindex)) {
01691                 isolated = table->vars[zindex]->ref == 1;
01692                 checkR += table->subtables[z].keys - isolated;
01693             }
01694         }
01695         assert(R == checkR);
01696 #endif
01697         /* Update upper bound on node decrease. */
01698         yindex = table->invperm[y];
01699         if (cuddTestInteract(table,xindex,yindex)) {
01700             isolated = table->vars[yindex]->ref == 1;
01701             R -= table->subtables[y].keys - isolated;
01702         }
01703         size = cuddSwapInPlace(table,x,y);
01704         if (size == 0) goto ddSiftingDownOutOfMem; 
01705         move = (Move *) cuddDynamicAllocNode(table);
01706         if (move == NULL) goto ddSiftingDownOutOfMem;
01707         move->x = x;
01708         move->y = y;
01709         move->size = size;
01710         move->next = moves;
01711         moves = move;
01712         if ((double) size > (double) limitSize * table->maxGrowth) break;
01713         if (size < limitSize) limitSize = size;
01714         x = y;
01715         y = cuddNextHigh(table,x);
01716     }
01717     return(moves);
01718 
01719 ddSiftingDownOutOfMem:
01720     while (moves != NULL) {
01721         move = moves->next;
01722         cuddDeallocNode(table, (DdNode *) moves);
01723         moves = move;
01724     }
01725     return((Move *) CUDD_OUT_OF_MEM);
01726 
01727 } /* end of ddSiftingDown */

static Move* ddSiftingUp ( DdManager table,
int  y,
int  xLow 
) [static]

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 1552 of file cuddReorder.c.

01556 {
01557     Move        *moves;
01558     Move        *move;
01559     int         x;
01560     int         size;
01561     int         limitSize;
01562     int         xindex, yindex;
01563     int         isolated;
01564     int         L;      /* lower bound on DD size */
01565 #ifdef DD_DEBUG
01566     int checkL;
01567     int z;
01568     int zindex;
01569 #endif
01570 
01571     moves = NULL;
01572     yindex = table->invperm[y];
01573 
01574     /* Initialize the lower bound.
01575     ** The part of the DD below y will not change.
01576     ** The part of the DD above y that does not interact with y will not
01577     ** change. The rest may vanish in the best case, except for
01578     ** the nodes at level xLow, which will not vanish, regardless.
01579     */
01580     limitSize = L = table->keys - table->isolated;
01581     for (x = xLow + 1; x < y; x++) {
01582         xindex = table->invperm[x];
01583         if (cuddTestInteract(table,xindex,yindex)) {
01584             isolated = table->vars[xindex]->ref == 1;
01585             L -= table->subtables[x].keys - isolated;
01586         }
01587     }
01588     isolated = table->vars[yindex]->ref == 1;
01589     L -= table->subtables[y].keys - isolated;
01590 
01591     x = cuddNextLow(table,y);
01592     while (x >= xLow && L <= limitSize) {
01593         xindex = table->invperm[x];
01594 #ifdef DD_DEBUG
01595         checkL = table->keys - table->isolated;
01596         for (z = xLow + 1; z < y; z++) {
01597             zindex = table->invperm[z];
01598             if (cuddTestInteract(table,zindex,yindex)) {
01599                 isolated = table->vars[zindex]->ref == 1;
01600                 checkL -= table->subtables[z].keys - isolated;
01601             }
01602         }
01603         isolated = table->vars[yindex]->ref == 1;
01604         checkL -= table->subtables[y].keys - isolated;
01605         assert(L == checkL);
01606 #endif
01607         size = cuddSwapInPlace(table,x,y);
01608         if (size == 0) goto ddSiftingUpOutOfMem;
01609         /* Update the lower bound. */
01610         if (cuddTestInteract(table,xindex,yindex)) {
01611             isolated = table->vars[xindex]->ref == 1;
01612             L += table->subtables[y].keys - isolated;
01613         }
01614         move = (Move *) cuddDynamicAllocNode(table);
01615         if (move == NULL) goto ddSiftingUpOutOfMem;
01616         move->x = x;
01617         move->y = y;
01618         move->size = size;
01619         move->next = moves;
01620         moves = move;
01621         if ((double) size > (double) limitSize * table->maxGrowth) break;
01622         if (size < limitSize) limitSize = size;
01623         y = x;
01624         x = cuddNextLow(table,y);
01625     }
01626     return(moves);
01627 
01628 ddSiftingUpOutOfMem:
01629     while (moves != NULL) {
01630         move = moves->next;
01631         cuddDeallocNode(table, (DdNode *) moves);
01632         moves = move;
01633     }
01634     return((Move *) CUDD_OUT_OF_MEM);
01635 
01636 } /* 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 1931 of file cuddReorder.c.

01935 {
01936     int        y;
01937     int        size;
01938 
01939     y = cuddNextLow(table,x);
01940     while (y >= xLow) {
01941         size = cuddSwapInPlace(table,y,x);
01942         if (size == 0) {
01943             return(0);
01944         }
01945         x = y;
01946         y = cuddNextLow(table,x);
01947     }
01948     return(1);
01949 
01950 } /* end of ddSiftUp */

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

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

Synopsis [Swaps any two variables.]

Description [Swaps any two variables. Returns the set of moves.]

SideEffects [None]

Definition at line 1304 of file cuddReorder.c.

01308 {
01309     Move        *move, *moves;
01310     int         xRef,yRef;
01311     int         xNext,yNext;
01312     int         size;
01313     int         limitSize;
01314     int         tmp;
01315 
01316     if (x >y) {
01317         tmp = x; x = y; y = tmp;
01318     }
01319 
01320     xRef = x; yRef = y;
01321 
01322     xNext = cuddNextHigh(table,x);
01323     yNext = cuddNextLow(table,y);
01324     moves = NULL;
01325     limitSize = table->keys - table->isolated;
01326 
01327     for (;;) {
01328         if ( xNext == yNext) {
01329             size = cuddSwapInPlace(table,x,xNext);
01330             if (size == 0) goto ddSwapAnyOutOfMem;
01331             move = (Move *) cuddDynamicAllocNode(table);                        
01332             if (move == NULL) goto ddSwapAnyOutOfMem;
01333             move->x = x;
01334             move->y = xNext;
01335             move->size = size; 
01336             move->next = moves;
01337             moves = move;
01338 
01339             size = cuddSwapInPlace(table,yNext,y);
01340             if (size == 0) goto ddSwapAnyOutOfMem;
01341             move = (Move *) cuddDynamicAllocNode(table);
01342             if (move == NULL) goto ddSwapAnyOutOfMem;
01343             move->x = yNext;
01344             move->y = y;
01345             move->size = size; 
01346             move->next = moves;
01347             moves = move;
01348 
01349             size = cuddSwapInPlace(table,x,xNext);
01350             if (size == 0) goto ddSwapAnyOutOfMem;
01351             move = (Move *) cuddDynamicAllocNode(table);
01352             if (move == NULL) goto ddSwapAnyOutOfMem;
01353             move->x = x;
01354             move->y = xNext;
01355             move->size = size;
01356             move->next = moves;
01357             moves = move;
01358 
01359             tmp = x; x = y; y = tmp;
01360 
01361         } else if (x == yNext) {
01362             
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             tmp = x; x = y; y = tmp;
01374 
01375         } else {
01376             size = cuddSwapInPlace(table,x,xNext);
01377             if (size == 0) goto ddSwapAnyOutOfMem;
01378             move = (Move *) cuddDynamicAllocNode(table);
01379             if (move == NULL) goto ddSwapAnyOutOfMem;
01380             move->x = x;
01381             move->y = xNext;
01382             move->size = size; 
01383             move->next = moves;
01384             moves = move;
01385 
01386             size = cuddSwapInPlace(table,yNext,y);
01387             if (size == 0) goto ddSwapAnyOutOfMem;
01388             move = (Move *) cuddDynamicAllocNode(table);
01389             if (move == NULL) goto ddSwapAnyOutOfMem;
01390             move->x = yNext;
01391             move->y = y;
01392             move->size = size;
01393             move->next = moves;
01394             moves = move;
01395 
01396             x = xNext;
01397             y = yNext;
01398         }
01399 
01400         xNext = cuddNextHigh(table,x);
01401         yNext = cuddNextLow(table,y);
01402         if (xNext > yRef) break;
01403 
01404         if ((double) size > table->maxGrowth * (double) limitSize) break;
01405         if (size < limitSize) limitSize = size;
01406     }
01407     if (yNext>=xRef) {
01408         size = cuddSwapInPlace(table,yNext,y);
01409         if (size == 0) goto ddSwapAnyOutOfMem;
01410         move = (Move *) cuddDynamicAllocNode(table);
01411         if (move == NULL) goto ddSwapAnyOutOfMem;
01412         move->x = yNext;
01413         move->y = y;
01414         move->size = size; 
01415         move->next = moves;
01416         moves = move;
01417     }
01418 
01419     return(moves);
01420     
01421 ddSwapAnyOutOfMem:
01422     while (moves != NULL) {
01423         move = moves->next;
01424         cuddDeallocNode(table, (DdNode *) moves);
01425         moves = move;
01426     }
01427     return(NULL);
01428 
01429 } /* end of ddSwapAny */

static int ddUniqueCompare ( 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 1280 of file cuddReorder.c.

01283 {
01284 #if 0
01285     if (entry[*ptrY] == entry[*ptrX]) {
01286         return((*ptrX) - (*ptrY));
01287     }
01288 #endif
01289     return(entry[*ptrY] - entry[*ptrX]);
01290 
01291 } /* end of ddUniqueCompare */

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 2001 of file cuddReorder.c.

02006 {
02007     int i, size, index, level;
02008     int minLevel, maxLevel, minIndex;
02009 
02010     if (treenode == NULL) return(1);
02011 
02012     /* i : level */
02013     for (i = treenode->low; i < treenode->low + treenode->size; i++) {
02014         index = table->invperm[i];
02015         level = perm[index];
02016         if (level < minLevel) {
02017             minLevel = level;
02018             minIndex = index;
02019         }
02020         if (level > maxLevel)
02021             maxLevel = level;
02022     }
02023     size = maxLevel - minLevel + 1;
02024     if (size == treenode->size) {
02025         treenode->low = minLevel;
02026         treenode->index = minIndex;
02027     } else
02028         return(0);
02029 
02030     if (treenode->child != NULL) {
02031         if (!ddUpdateMtrTree(table, treenode->child, perm, invperm))
02032             return(0);
02033     }
02034     if (treenode->younger != NULL) {
02035         if (!ddUpdateMtrTree(table, treenode->younger, perm, invperm))
02036             return(0);
02037     }
02038     return(1);
02039 }


Variable Documentation

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

Definition at line 71 of file cuddReorder.c.

Definition at line 76 of file cuddReorder.c.

int* entry [static]

Definition at line 74 of file cuddReorder.c.


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