src/cuBdd/cuddReorder.c File Reference

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

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

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 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:

  • 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 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 */

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

00710 {
00711     return(x+1);
00712 
00713 } /* 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 729 of file cuddReorder.c.

00732 {
00733     return(x-1);
00734 
00735 } /* 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 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.

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

01857 {
01858 
01859 #ifdef DD_VERBOSE
01860     (void) fflush(table->out);
01861 #endif
01862 
01863     /* Free interaction matrix. */
01864     FREE(table->interact);
01865 
01866     return(1);
01867 
01868 } /* 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 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 */

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 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 */

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 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 */

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 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 */

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

01317 {
01318 #if 0
01319     if (entry[*ptrY] == entry[*ptrX]) {
01320         return((*ptrX) - (*ptrY));
01321     }
01322 #endif
01323     return(entry[*ptrY] - entry[*ptrX]);
01324 
01325 } /* 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 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 }


Variable Documentation

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.


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