src/bdd/cudd/cuddTable.c File Reference

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

Go to the source code of this file.

Data Structures

union  hack

Defines

#define DD_STACK_SIZE   128
#define DD_RED   0
#define DD_BLACK   1
#define DD_PAGE_SIZE   8192
#define DD_PAGE_MASK   ~(DD_PAGE_SIZE - 1)
#define DD_INSERT_COMPARE(x, y)   (((ptruint) (x) & DD_PAGE_MASK) - ((ptruint) (y) & DD_PAGE_MASK))
#define DD_COLOR(p)   ((p)->index)
#define DD_IS_BLACK(p)   ((p)->index == DD_BLACK)
#define DD_IS_RED(p)   ((p)->index == DD_RED)
#define DD_LEFT(p)   cuddT(p)
#define DD_RIGHT(p)   cuddE(p)
#define DD_NEXT(p)   ((p)->next)

Functions

static void ddRehashZdd ARGS ((DdManager *unique, int i))
static int ddResizeTable ARGS ((DdManager *unique, int index))
static int cuddFindParent ARGS ((DdManager *table, DdNode *node))
static DD_INLINE void ddFixLimits ARGS ((DdManager *unique))
static void cuddOrderedInsert ARGS ((DdNodePtr *root, DdNodePtr node))
static DdNode *cuddOrderedThread ARGS ((DdNode *root, DdNode *list))
static void cuddRotateLeft ARGS ((DdNodePtr *nodeP))
static void cuddDoRebalance ARGS ((DdNodePtr **stack, int stackN))
static void ddPatchTree ARGS ((DdManager *dd, MtrNode *treenode))
static void ddReportRefMess ARGS ((DdManager *unique, int i, char *caller))
unsigned int Cudd_Prime (unsigned int p)
DdNodecuddAllocNode (DdManager *unique)
DdManagercuddInitTable (unsigned int numVars, unsigned int numVarsZ, unsigned int numSlots, unsigned int looseUpTo)
void cuddFreeTable (DdManager *unique)
int cuddGarbageCollect (DdManager *unique, int clearCache)
int cuddGarbageCollectZdd (DdManager *unique, int clearCache)
DdNodecuddZddGetNode (DdManager *zdd, int id, DdNode *T, DdNode *E)
DdNodecuddZddGetNodeIVO (DdManager *dd, int index, DdNode *g, DdNode *h)
DdNodecuddUniqueInter (DdManager *unique, int index, DdNode *T, DdNode *E)
DdNodecuddUniqueInterIVO (DdManager *unique, int index, DdNode *T, DdNode *E)
DdNodecuddUniqueInterZdd (DdManager *unique, int index, DdNode *T, DdNode *E)
DdNodecuddUniqueConst (DdManager *unique, CUDD_VALUE_TYPE value)
void cuddRehash (DdManager *unique, int i)
void cuddShrinkSubtable (DdManager *unique, int i)
int cuddInsertSubtables (DdManager *unique, int n, int level)
int cuddDestroySubtables (DdManager *unique, int n)
int cuddResizeTableZdd (DdManager *unique, int index)
void cuddSlowTableGrowth (DdManager *unique)
static void ddRehashZdd (DdManager *unique, int i)
static int ddResizeTable (DdManager *unique, int index)
static int cuddFindParent (DdManager *table, DdNode *node)
static DD_INLINE void ddFixLimits (DdManager *unique)
static void cuddOrderedInsert (DdNodePtr *root, DdNodePtr node)
static DdNodecuddOrderedThread (DdNode *root, DdNode *list)
static DD_INLINE void cuddRotateLeft (DdNodePtr *nodeP)
static DD_INLINE void cuddRotateRight (DdNodePtr *nodeP)
static void cuddDoRebalance (DdNodePtr **stack, int stackN)
static void ddPatchTree (DdManager *dd, MtrNode *treenode)
static void ddReportRefMess (DdManager *unique, int i, char *caller)

Variables

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

Define Documentation

#define DD_BLACK   1

Definition at line 68 of file cuddTable.c.

#define DD_COLOR (  )     ((p)->index)

Definition at line 104 of file cuddTable.c.

#define DD_INSERT_COMPARE ( x,
 )     (((ptruint) (x) & DD_PAGE_MASK) - ((ptruint) (y) & DD_PAGE_MASK))

Definition at line 71 of file cuddTable.c.

#define DD_IS_BLACK (  )     ((p)->index == DD_BLACK)

Definition at line 105 of file cuddTable.c.

#define DD_IS_RED (  )     ((p)->index == DD_RED)

Definition at line 106 of file cuddTable.c.

#define DD_LEFT (  )     cuddT(p)

Definition at line 107 of file cuddTable.c.

#define DD_NEXT (  )     ((p)->next)

Definition at line 109 of file cuddTable.c.

#define DD_PAGE_MASK   ~(DD_PAGE_SIZE - 1)

Definition at line 70 of file cuddTable.c.

#define DD_PAGE_SIZE   8192

Definition at line 69 of file cuddTable.c.

#define DD_RED   0

Definition at line 67 of file cuddTable.c.

#define DD_RIGHT (  )     cuddE(p)

Definition at line 108 of file cuddTable.c.

#define DD_STACK_SIZE   128

CFile***********************************************************************

FileName [cuddTable.c]

PackageName [cudd]

Synopsis [Unique table management functions.]

Description [External procedures included in this module:

Internal procedures included in this module:

Static procedures included in this module:

]

SeeAlso []

Author [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 66 of file cuddTable.c.


Function Documentation

static void ddReportRefMess ARGS ( (DdManager *unique, int i, char *caller)   )  [static]
static void ddPatchTree ARGS ( (DdManager *dd, MtrNode *treenode)   )  [static]
static void cuddDoRebalance ARGS ( (DdNodePtr **stack, int stackN)   )  [static]
static void cuddRotateRight ARGS ( (DdNodePtr *nodeP)   )  [static]
static DdNode* cuddOrderedThread ARGS ( (DdNode *root, DdNode *list)   )  [static]
static void cuddOrderedInsert ARGS ( (DdNodePtr *root, DdNodePtr node)   )  [static]
static DD_INLINE void ddFixLimits ARGS ( (DdManager *unique)   )  [static]
static int cuddFindParent ARGS ( (DdManager *table, DdNode *node)   )  [static]
static int ddResizeTable ARGS ( (DdManager *unique, int index)   )  [static]
static void ddRehashZdd ARGS ( (DdManager *unique, int i)   )  [static]

AutomaticStart

unsigned int Cudd_Prime ( unsigned int  p  ) 

AutomaticEnd Function********************************************************************

Synopsis [Returns the next prime >= p.]

Description []

SideEffects [None]

Definition at line 152 of file cuddTable.c.

00154 {
00155     int i,pn;
00156 
00157     p--;
00158     do {
00159         p++;
00160         if (p&1) {
00161             pn = 1;
00162             i = 3;
00163             while ((unsigned) (i * i) <= p) {
00164                 if (p % i == 0) {
00165                     pn = 0;
00166                     break;
00167                 }
00168                 i += 2;
00169             }
00170         } else {
00171             pn = 0;
00172         }
00173     } while (!pn);
00174     return(p);
00175 
00176 } /* end of Cudd_Prime */

DdNode* cuddAllocNode ( DdManager unique  ) 

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

Synopsis [Fast storage allocation for DdNodes in the table.]

Description [Fast storage allocation for DdNodes in the table. The first 4 bytes of a chunk contain a pointer to the next block; the rest contains DD_MEM_CHUNK spaces for DdNodes. Returns a pointer to a new node if successful; NULL is memory is full.]

SideEffects [None]

SeeAlso [cuddDynamicAllocNode]

Definition at line 199 of file cuddTable.c.

00201 {
00202     int i;
00203     DdNodePtr *mem;
00204     DdNode *list, *node;
00205     extern void (*MMoutOfMemory)(long);
00206     void (*saveHandler)(long);
00207 
00208     if (unique->nextFree == NULL) {     /* free list is empty */
00209         /* Check for exceeded limits. */
00210         if ((unique->keys - unique->dead) + (unique->keysZ - unique->deadZ) >
00211             unique->maxLive) {
00212             unique->errorCode = CUDD_TOO_MANY_NODES;
00213             return(NULL);
00214         }
00215         if (unique->stash == NULL || unique->memused > unique->maxmemhard) {
00216             (void) cuddGarbageCollect(unique,1);
00217             mem = NULL;
00218         }
00219         if (unique->nextFree == NULL) {
00220             if (unique->memused > unique->maxmemhard) {
00221                 unique->errorCode = CUDD_MAX_MEM_EXCEEDED;
00222                 return(NULL);
00223             }
00224             /* Try to allocate a new block. */
00225             saveHandler = MMoutOfMemory;
00226             MMoutOfMemory = Cudd_OutOfMem;
00227             mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
00228             MMoutOfMemory = saveHandler;
00229             if (mem == NULL) {
00230                 /* No more memory: Try collecting garbage. If this succeeds,
00231                 ** we end up with mem still NULL, but unique->nextFree !=
00232                 ** NULL. */
00233                 if (cuddGarbageCollect(unique,1) == 0) {
00234                     /* Last resort: Free the memory stashed away, if there
00235                     ** any. If this succeeeds, mem != NULL and
00236                     ** unique->nextFree still NULL. */
00237                     if (unique->stash != NULL) {
00238                         FREE(unique->stash);
00239                         unique->stash = NULL;
00240                         /* Inhibit resizing of tables. */
00241                         cuddSlowTableGrowth(unique);
00242                         /* Now try again. */
00243                         mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
00244                     }
00245                     if (mem == NULL) {
00246                         /* Out of luck. Call the default handler to do
00247                         ** whatever it specifies for a failed malloc.
00248                         ** If this handler returns, then set error code,
00249                         ** print warning, and return. */
00250                         (*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1));
00251                         unique->errorCode = CUDD_MEMORY_OUT;
00252 #ifdef DD_VERBOSE
00253                         (void) fprintf(unique->err,
00254                                        "cuddAllocNode: out of memory");
00255                         (void) fprintf(unique->err, "Memory in use = %ld\n",
00256                                        unique->memused);
00257 #endif
00258                         return(NULL);
00259                     }
00260                 }
00261             }
00262             if (mem != NULL) {  /* successful allocation; slice memory */
00263                 ptruint offset;
00264                 unique->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode);
00265                 mem[0] = (DdNodePtr) unique->memoryList;
00266                 unique->memoryList = mem;
00267 
00268                 /* Here we rely on the fact that a DdNode is as large
00269                 ** as 4 pointers.  */
00270                 offset = (ptruint) mem & (sizeof(DdNode) - 1);
00271                 mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
00272                 assert(((ptruint) mem & (sizeof(DdNode) - 1)) == 0);
00273                 list = (DdNode *) mem;
00274 
00275                 i = 1;
00276                 do {
00277                     list[i - 1].next = &list[i];
00278                 } while (++i < DD_MEM_CHUNK);
00279 
00280                 list[DD_MEM_CHUNK-1].next = NULL;
00281 
00282                 unique->nextFree = &list[0];
00283             }
00284         }
00285     }
00286     unique->allocated++;
00287     node = unique->nextFree;
00288     unique->nextFree = node->next;
00289     return(node);
00290 
00291 } /* end of cuddAllocNode */

int cuddDestroySubtables ( DdManager unique,
int  n 
)

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

Synopsis [Destroys the n most recently created subtables in a unique table.]

Description [Destroys the n most recently created subtables in a unique table. n should be positive. The subtables should not contain any live nodes, except the (isolated) projection function. The projection functions are freed. Returns 1 if successful; 0 otherwise.]

SideEffects [The variable map used for fast variable substitution is destroyed if it exists. In this case the cache is also cleared.]

SeeAlso [cuddInsertSubtables Cudd_SetVarMap]

Definition at line 2072 of file cuddTable.c.

02075 {
02076     DdSubtable *subtables;
02077     DdNodePtr *nodelist;
02078     DdNodePtr *vars;
02079     int firstIndex, lastIndex;
02080     int index, level, newlevel;
02081     int lowestLevel;
02082     int shift;
02083     int found;
02084 
02085     /* Sanity check and set up. */
02086     if (n <= 0) return(0);
02087     if (n > unique->size) n = unique->size;
02088 
02089     subtables = unique->subtables;
02090     vars = unique->vars;
02091     firstIndex = unique->size - n;
02092     lastIndex  = unique->size;
02093 
02094     /* Check for nodes labeled by the variables being destroyed
02095     ** that may still be in use.  It is allowed to destroy a variable
02096     ** only if there are no such nodes. Also, find the lowest level
02097     ** among the variables being destroyed. This will make further
02098     ** processing more efficient.
02099     */
02100     lowestLevel = unique->size;
02101     for (index = firstIndex; index < lastIndex; index++) {
02102         level = unique->perm[index];
02103         if (level < lowestLevel) lowestLevel = level;
02104         nodelist = subtables[level].nodelist;
02105         if (subtables[level].keys - subtables[level].dead != 1) return(0);
02106         /* The projection function should be isolated. If the ref count
02107         ** is 1, everything is OK. If the ref count is saturated, then
02108         ** we need to make sure that there are no nodes pointing to it.
02109         ** As for the external references, we assume the application is
02110         ** responsible for them.
02111         */
02112         if (vars[index]->ref != 1) {
02113             if (vars[index]->ref != DD_MAXREF) return(0);
02114             found = cuddFindParent(unique,vars[index]);
02115             if (found) {
02116                 return(0);
02117             } else {
02118                 vars[index]->ref = 1;
02119             }
02120         }
02121         Cudd_RecursiveDeref(unique,vars[index]);
02122     }
02123 
02124     /* Collect garbage, because we cannot afford having dead nodes pointing
02125     ** to the dead nodes in the subtables being destroyed.
02126     */
02127     (void) cuddGarbageCollect(unique,1);
02128 
02129     /* Here we know we can destroy our subtables. */
02130     for (index = firstIndex; index < lastIndex; index++) {
02131         level = unique->perm[index];
02132         nodelist = subtables[level].nodelist;
02133 #ifdef DD_DEBUG
02134         assert(subtables[level].keys == 0);
02135 #endif
02136         FREE(nodelist);
02137         unique->memused -= sizeof(DdNodePtr) * subtables[level].slots;
02138         unique->slots -= subtables[level].slots;
02139         unique->dead -= subtables[level].dead;
02140     }
02141 
02142     /* Here all subtables to be destroyed have their keys field == 0 and
02143     ** their hash tables have been freed.
02144     ** We now scan the subtables from level lowestLevel + 1 to level size - 1,
02145     ** shifting the subtables as required. We keep a running count of
02146     ** how many subtables have been moved, so that we know by how many
02147     ** positions each subtable should be shifted.
02148     */
02149     shift = 1;
02150     for (level = lowestLevel + 1; level < unique->size; level++) {
02151         if (subtables[level].keys == 0) {
02152             shift++;
02153             continue;
02154         }
02155         newlevel = level - shift;
02156         subtables[newlevel].slots = subtables[level].slots;
02157         subtables[newlevel].shift = subtables[level].shift;
02158         subtables[newlevel].keys = subtables[level].keys;
02159         subtables[newlevel].maxKeys = subtables[level].maxKeys;
02160         subtables[newlevel].dead = subtables[level].dead;
02161         subtables[newlevel].nodelist = subtables[level].nodelist;
02162         index = unique->invperm[level];
02163         unique->perm[index] = newlevel;
02164         unique->invperm[newlevel]  = index;
02165         subtables[newlevel].bindVar = subtables[level].bindVar;
02166         subtables[newlevel].varType = subtables[level].varType;
02167         subtables[newlevel].pairIndex = subtables[level].pairIndex;
02168         subtables[newlevel].varHandled = subtables[level].varHandled;
02169         subtables[newlevel].varToBeGrouped = subtables[level].varToBeGrouped;
02170     }
02171     /* Destroy the map. If a surviving variable is
02172     ** mapped to a dying variable, and the map were used again,
02173     ** an out-of-bounds access to unique->vars would result. */
02174     if (unique->map != NULL) {
02175         cuddCacheFlush(unique);
02176         FREE(unique->map);
02177         unique->map = NULL;
02178     }
02179 
02180     unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
02181     unique->size -= n;
02182 
02183     return(1);
02184 
02185 } /* end of cuddDestroySubtables */

static void cuddDoRebalance ( DdNodePtr **  stack,
int  stackN 
) [static]

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

Synopsis [Rebalances a red/black tree.]

Description []

SideEffects [None]

SeeAlso []

Definition at line 2970 of file cuddTable.c.

02973 {
02974     DdNodePtr *xP, *parentP, *grandpaP;
02975     DdNode *x, *y, *parent, *grandpa;
02976 
02977     xP = stack[stackN];
02978     x = *xP;
02979     /* Work our way back up, re-balancing the tree. */
02980     while (--stackN >= 0) {
02981         parentP = stack[stackN];
02982         parent = *parentP;
02983         if (DD_IS_BLACK(parent)) break;
02984         /* Since the root is black, here a non-null grandparent exists. */
02985         grandpaP = stack[stackN-1];
02986         grandpa = *grandpaP;
02987         if (parent == DD_LEFT(grandpa)) {
02988             y = DD_RIGHT(grandpa);
02989             if (y != NULL && DD_IS_RED(y)) {
02990                 DD_COLOR(parent) = DD_BLACK;
02991                 DD_COLOR(y) = DD_BLACK;
02992                 DD_COLOR(grandpa) = DD_RED;
02993                 x = grandpa;
02994                 stackN--;
02995             } else {
02996                 if (x == DD_RIGHT(parent)) {
02997                     cuddRotateLeft(parentP);
02998                     DD_COLOR(x) = DD_BLACK;
02999                 } else {
03000                     DD_COLOR(parent) = DD_BLACK;
03001                 }
03002                 DD_COLOR(grandpa) = DD_RED;
03003                 cuddRotateRight(grandpaP);
03004                 break;
03005             }
03006         } else {
03007             y = DD_LEFT(grandpa);
03008             if (y != NULL && DD_IS_RED(y)) {
03009                 DD_COLOR(parent) = DD_BLACK;
03010                 DD_COLOR(y) = DD_BLACK;
03011                 DD_COLOR(grandpa) = DD_RED;
03012                 x = grandpa;
03013                 stackN--;
03014             } else {
03015                 if (x == DD_LEFT(parent)) {
03016                     cuddRotateRight(parentP);
03017                     DD_COLOR(x) = DD_BLACK;
03018                 } else {
03019                     DD_COLOR(parent) = DD_BLACK;
03020                 }
03021                 DD_COLOR(grandpa) = DD_RED;
03022                 cuddRotateLeft(grandpaP);
03023             }
03024         }
03025     }
03026     DD_COLOR(*(stack[0])) = DD_BLACK;
03027 
03028 } /* end of cuddDoRebalance */

static int cuddFindParent ( DdManager table,
DdNode node 
) [static]

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

Synopsis [Searches the subtables above node for a parent.]

Description [Searches the subtables above node for a parent. Returns 1 as soon as one parent is found. Returns 0 is the search is fruitless.]

SideEffects [None]

SeeAlso []

Definition at line 2726 of file cuddTable.c.

02729 {
02730     int         i,j;
02731     int         slots;
02732     DdNodePtr   *nodelist;
02733     DdNode      *f;
02734 
02735     for (i = cuddI(table,node->index) - 1; i >= 0; i--) {
02736         nodelist = table->subtables[i].nodelist;
02737         slots = table->subtables[i].slots;
02738 
02739         for (j = 0; j < slots; j++) {
02740             f = nodelist[j];
02741             while (cuddT(f) > node) {
02742                 f = f->next;
02743             }
02744             while (cuddT(f) == node && Cudd_Regular(cuddE(f)) > node) {
02745                 f = f->next;
02746             }
02747             if (cuddT(f) == node && Cudd_Regular(cuddE(f)) == node) {
02748                 return(1);
02749             }
02750         }
02751     }
02752 
02753     return(0);
02754 
02755 } /* end of cuddFindParent */

void cuddFreeTable ( DdManager unique  ) 

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

Synopsis [Frees the resources associated to a unique table.]

Description []

SideEffects [None]

SeeAlso [cuddInitTable]

Definition at line 551 of file cuddTable.c.

00553 {
00554     DdNodePtr *next;
00555     DdNodePtr *memlist = unique->memoryList;
00556     int i;
00557 
00558     if (unique->univ != NULL) cuddZddFreeUniv(unique);
00559     while (memlist != NULL) {
00560         next = (DdNodePtr *) memlist[0];        /* link to next block */
00561         FREE(memlist);
00562         memlist = next;
00563     }
00564     unique->nextFree = NULL;
00565     unique->memoryList = NULL;
00566 
00567     for (i = 0; i < unique->size; i++) {
00568         FREE(unique->subtables[i].nodelist);
00569     }
00570     for (i = 0; i < unique->sizeZ; i++) {
00571         FREE(unique->subtableZ[i].nodelist);
00572     }
00573     FREE(unique->constants.nodelist);
00574     FREE(unique->subtables);
00575     FREE(unique->subtableZ);
00576     FREE(unique->acache);
00577     FREE(unique->perm);
00578     FREE(unique->permZ);
00579     FREE(unique->invperm);
00580     FREE(unique->invpermZ);
00581     FREE(unique->vars);
00582     if (unique->map != NULL) FREE(unique->map);
00583     FREE(unique->stack);
00584 #ifndef DD_NO_DEATH_ROW
00585     FREE(unique->deathRow);
00586 #endif
00587     if (unique->tree != NULL) Mtr_FreeTree(unique->tree);
00588     if (unique->treeZ != NULL) Mtr_FreeTree(unique->treeZ);
00589     if (unique->linear != NULL) FREE(unique->linear);
00590     while (unique->preGCHook != NULL)
00591         Cudd_RemoveHook(unique,unique->preGCHook->f,CUDD_PRE_GC_HOOK);
00592     while (unique->postGCHook != NULL)
00593         Cudd_RemoveHook(unique,unique->postGCHook->f,CUDD_POST_GC_HOOK);
00594     while (unique->preReorderingHook != NULL)
00595         Cudd_RemoveHook(unique,unique->preReorderingHook->f,
00596                         CUDD_PRE_REORDERING_HOOK);
00597     while (unique->postReorderingHook != NULL)
00598         Cudd_RemoveHook(unique,unique->postReorderingHook->f,
00599                         CUDD_POST_REORDERING_HOOK);
00600     FREE(unique);
00601 
00602 } /* end of cuddFreeTable */

int cuddGarbageCollect ( DdManager unique,
int  clearCache 
)

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

Synopsis [Performs garbage collection on a unique table.]

Description [Performs garbage collection on a unique table. If clearCache is 0, the cache is not cleared. This should only be specified if the cache has been cleared right before calling cuddGarbageCollect. (As in the case of dynamic reordering.) Returns the total number of deleted nodes.]

SideEffects [None]

SeeAlso [cuddGarbageCollectZdd]

Definition at line 621 of file cuddTable.c.

00624 {
00625     DdHook      *hook;
00626     DdCache     *cache = unique->cache;
00627     DdNode      *sentinel = &(unique->sentinel);
00628     DdNodePtr   *nodelist;
00629     int         i, j, deleted, totalDeleted;
00630     DdCache     *c;
00631     DdNode      *node,*next;
00632     DdNodePtr   *lastP;
00633     int         slots;
00634     long        localTime;
00635 #ifndef DD_UNSORTED_FREE_LIST
00636     DdNodePtr   tree;
00637 #endif
00638 
00639 #ifndef DD_NO_DEATH_ROW
00640     cuddClearDeathRow(unique);
00641 #endif
00642 
00643     hook = unique->preGCHook;
00644     while (hook != NULL) {
00645         int res = (hook->f)(unique,"BDD",NULL);
00646         if (res == 0) return(0);
00647         hook = hook->next;
00648     }
00649 
00650     if (unique->dead == 0) {
00651         hook = unique->postGCHook;
00652         while (hook != NULL) {
00653             int res = (hook->f)(unique,"BDD",NULL);
00654             if (res == 0) return(0);
00655             hook = hook->next;
00656         }
00657         return(0);
00658     }
00659 
00660     /* If many nodes are being reclaimed, we want to resize the tables
00661     ** more aggressively, to reduce the frequency of garbage collection.
00662     */
00663     if (clearCache && unique->gcFrac == DD_GC_FRAC_LO &&
00664         unique->slots <= unique->looseUpTo && unique->stash != NULL) {
00665         unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
00666 #ifdef DD_VERBOSE
00667         (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_HI);
00668         (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
00669 #endif
00670         unique->gcFrac = DD_GC_FRAC_HI;
00671         return(0);
00672     }
00673 
00674     localTime = util_cpu_time();
00675 
00676     unique->garbageCollections++;
00677 #ifdef DD_VERBOSE
00678     (void) fprintf(unique->err,
00679                    "garbage collecting (%d dead out of %d, min %d)...",
00680                    unique->dead, unique->keys, unique->minDead);
00681 #endif
00682 
00683     /* Remove references to garbage collected nodes from the cache. */
00684     if (clearCache) {
00685         slots = unique->cacheSlots;
00686         for (i = 0; i < slots; i++) {
00687             c = &cache[i];
00688             if (c->data != NULL) {
00689                 if (cuddClean(c->f)->ref == 0 ||
00690                 cuddClean(c->g)->ref == 0 ||
00691                 (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) ||
00692                 (c->data != DD_NON_CONSTANT &&
00693                 Cudd_Regular(c->data)->ref == 0)) {
00694                     c->data = NULL;
00695                     unique->cachedeletions++;
00696                 }
00697             }
00698         }
00699         cuddLocalCacheClearDead(unique);
00700     }
00701 
00702     /* Now return dead nodes to free list. Count them for sanity check. */
00703     totalDeleted = 0;
00704 #ifndef DD_UNSORTED_FREE_LIST
00705     tree = NULL;
00706 #endif
00707 
00708     for (i = 0; i < unique->size; i++) {
00709         if (unique->subtables[i].dead == 0) continue;
00710         nodelist = unique->subtables[i].nodelist;
00711 
00712         deleted = 0;
00713         slots = unique->subtables[i].slots;
00714         for (j = 0; j < slots; j++) {
00715             lastP = &(nodelist[j]);
00716             node = *lastP;
00717             while (node != sentinel) {
00718                 next = node->next;
00719                 if (node->ref == 0) {
00720                     deleted++;
00721 #ifndef DD_UNSORTED_FREE_LIST
00722 #ifdef __osf__
00723 #pragma pointer_size save
00724 #pragma pointer_size short
00725 #endif
00726                     cuddOrderedInsert(&tree,node);
00727 #ifdef __osf__
00728 #pragma pointer_size restore
00729 #endif
00730 #else
00731                     cuddDeallocNode(unique,node);
00732 #endif
00733                 } else {
00734                     *lastP = node;
00735                     lastP = &(node->next);
00736                 }
00737                 node = next;
00738             }
00739             *lastP = sentinel;
00740         }
00741         if ((unsigned) deleted != unique->subtables[i].dead) {
00742             ddReportRefMess(unique, i, "cuddGarbageCollect");
00743         }
00744         totalDeleted += deleted;
00745         unique->subtables[i].keys -= deleted;
00746         unique->subtables[i].dead = 0;
00747     }
00748     if (unique->constants.dead != 0) {
00749         nodelist = unique->constants.nodelist;
00750         deleted = 0;
00751         slots = unique->constants.slots;
00752         for (j = 0; j < slots; j++) {
00753             lastP = &(nodelist[j]);
00754             node = *lastP;
00755             while (node != NULL) {
00756                 next = node->next;
00757                 if (node->ref == 0) {
00758                     deleted++;
00759 #ifndef DD_UNSORTED_FREE_LIST
00760 #ifdef __osf__
00761 #pragma pointer_size save
00762 #pragma pointer_size short
00763 #endif
00764                     cuddOrderedInsert(&tree,node);
00765 #ifdef __osf__
00766 #pragma pointer_size restore
00767 #endif
00768 #else
00769                     cuddDeallocNode(unique,node);
00770 #endif
00771                 } else {
00772                     *lastP = node;
00773                     lastP = &(node->next);
00774                 }           
00775                 node = next;
00776             }
00777             *lastP = NULL;
00778         }
00779         if ((unsigned) deleted != unique->constants.dead) {
00780             ddReportRefMess(unique, CUDD_CONST_INDEX, "cuddGarbageCollect");
00781         }
00782         totalDeleted += deleted;
00783         unique->constants.keys -= deleted;
00784         unique->constants.dead = 0;
00785     }
00786     if ((unsigned) totalDeleted != unique->dead) {
00787         ddReportRefMess(unique, -1, "cuddGarbageCollect");
00788     }
00789     unique->keys -= totalDeleted;
00790     unique->dead = 0;
00791 #ifdef DD_STATS
00792     unique->nodesFreed += (double) totalDeleted;
00793 #endif
00794 
00795 #ifndef DD_UNSORTED_FREE_LIST
00796     unique->nextFree = cuddOrderedThread(tree,unique->nextFree);
00797 #endif
00798 
00799     unique->GCTime += util_cpu_time() - localTime;
00800 
00801     hook = unique->postGCHook;
00802     while (hook != NULL) {
00803         int res = (hook->f)(unique,"BDD",NULL);
00804         if (res == 0) return(0);
00805         hook = hook->next;
00806     }
00807 
00808 #ifdef DD_VERBOSE
00809     (void) fprintf(unique->err," done\n");
00810 #endif
00811 
00812     return(totalDeleted);
00813 
00814 } /* end of cuddGarbageCollect */

int cuddGarbageCollectZdd ( DdManager unique,
int  clearCache 
)

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

Synopsis [Performs garbage collection on a ZDD unique table.]

Description [Performs garbage collection on a ZDD unique table. If clearCache is 0, the cache is not cleared. This should only be specified if the cache has been cleared right before calling cuddGarbageCollectZdd. (As in the case of dynamic reordering.) Returns the total number of deleted nodes.]

SideEffects [None]

SeeAlso [cuddGarbageCollect]

Definition at line 833 of file cuddTable.c.

00836 {
00837     DdHook      *hook;
00838     DdCache     *cache = unique->cache;
00839     DdNodePtr   *nodelist;
00840     int         i, j, deleted, totalDeleted;
00841     DdCache     *c;
00842     DdNode      *node,*next;
00843     DdNodePtr   *lastP;
00844     int         slots;
00845     long        localTime;
00846 #ifndef DD_UNSORTED_FREE_LIST
00847     DdNodePtr   tree;
00848 #endif
00849 
00850     hook = unique->preGCHook;
00851     while (hook != NULL) {
00852         int res = (hook->f)(unique,"ZDD",NULL);
00853         if (res == 0) return(0);
00854         hook = hook->next;
00855     }
00856 
00857     if (unique->deadZ == 0) {
00858         hook = unique->postGCHook;
00859         while (hook != NULL) {
00860             int res = (hook->f)(unique,"ZDD",NULL);
00861             if (res == 0) return(0);
00862             hook = hook->next;
00863         }
00864         return(0);
00865     }
00866 
00867     /* If many nodes are being reclaimed, we want to resize the tables
00868     ** more aggressively, to reduce the frequency of garbage collection.
00869     */
00870     if (clearCache && unique->slots <= unique->looseUpTo) {
00871         unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
00872 #ifdef DD_VERBOSE
00873         if (unique->gcFrac == DD_GC_FRAC_LO) {
00874             (void) fprintf(unique->err,"GC fraction = %.2f\t",
00875                            DD_GC_FRAC_HI);
00876             (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
00877         }
00878 #endif
00879         unique->gcFrac = DD_GC_FRAC_HI;
00880     }
00881 
00882     localTime = util_cpu_time();
00883 
00884     unique->garbageCollections++;
00885 #ifdef DD_VERBOSE
00886     (void) fprintf(unique->err,"garbage collecting (%d dead out of %d)...",
00887                    unique->deadZ,unique->keysZ);
00888 #endif
00889 
00890     /* Remove references to garbage collected nodes from the cache. */
00891     if (clearCache) {
00892         slots = unique->cacheSlots;
00893         for (i = 0; i < slots; i++) {
00894             c = &cache[i];
00895             if (c->data != NULL) {
00896                 if (cuddClean(c->f)->ref == 0 ||
00897                 cuddClean(c->g)->ref == 0 ||
00898                 (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) ||
00899                 (c->data != DD_NON_CONSTANT &&
00900                 Cudd_Regular(c->data)->ref == 0)) {
00901                     c->data = NULL;
00902                     unique->cachedeletions++;
00903                 }
00904             }
00905         }
00906     }
00907 
00908     /* Now return dead nodes to free list. Count them for sanity check. */
00909     totalDeleted = 0;
00910 #ifndef DD_UNSORTED_FREE_LIST
00911     tree = NULL;
00912 #endif
00913 
00914     for (i = 0; i < unique->sizeZ; i++) {
00915         if (unique->subtableZ[i].dead == 0) continue;
00916         nodelist = unique->subtableZ[i].nodelist;
00917 
00918         deleted = 0;
00919         slots = unique->subtableZ[i].slots;
00920         for (j = 0; j < slots; j++) {
00921             lastP = &(nodelist[j]);
00922             node = *lastP;
00923             while (node != NULL) {
00924                 next = node->next;
00925                 if (node->ref == 0) {
00926                     deleted++;
00927 #ifndef DD_UNSORTED_FREE_LIST
00928 #ifdef __osf__
00929 #pragma pointer_size save
00930 #pragma pointer_size short
00931 #endif
00932                     cuddOrderedInsert(&tree,node);
00933 #ifdef __osf__
00934 #pragma pointer_size restore
00935 #endif
00936 #else
00937                     cuddDeallocNode(unique,node);
00938 #endif
00939                 } else {
00940                     *lastP = node;
00941                     lastP = &(node->next);
00942                 }           
00943                 node = next;
00944             }
00945             *lastP = NULL;
00946         }
00947         if ((unsigned) deleted != unique->subtableZ[i].dead) {
00948             ddReportRefMess(unique, i, "cuddGarbageCollectZdd");
00949         }
00950         totalDeleted += deleted;
00951         unique->subtableZ[i].keys -= deleted;
00952         unique->subtableZ[i].dead = 0;
00953     }
00954 
00955     /* No need to examine the constant table for ZDDs.
00956     ** If we did we should be careful not to count whatever dead
00957     ** nodes we found there among the dead ZDD nodes. */
00958     if ((unsigned) totalDeleted != unique->deadZ) {
00959         ddReportRefMess(unique, -1, "cuddGarbageCollectZdd");
00960     }
00961     unique->keysZ -= totalDeleted;
00962     unique->deadZ = 0;
00963 #ifdef DD_STATS
00964     unique->nodesFreed += (double) totalDeleted;
00965 #endif
00966 
00967 #ifndef DD_UNSORTED_FREE_LIST
00968     unique->nextFree = cuddOrderedThread(tree,unique->nextFree);
00969 #endif
00970 
00971     unique->GCTime += util_cpu_time() - localTime;
00972 
00973     hook = unique->postGCHook;
00974     while (hook != NULL) {
00975         int res = (hook->f)(unique,"ZDD",NULL);
00976         if (res == 0) return(0);
00977         hook = hook->next;
00978     }
00979 
00980 #ifdef DD_VERBOSE
00981     (void) fprintf(unique->err," done\n");
00982 #endif
00983 
00984     return(totalDeleted);
00985 
00986 } /* end of cuddGarbageCollectZdd */

DdManager* cuddInitTable ( unsigned int  numVars,
unsigned int  numVarsZ,
unsigned int  numSlots,
unsigned int  looseUpTo 
)

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

Synopsis [Creates and initializes the unique table.]

Description [Creates and initializes the unique table. Returns a pointer to the table if successful; NULL otherwise.]

SideEffects [None]

SeeAlso [Cudd_Init cuddFreeTable]

Definition at line 307 of file cuddTable.c.

00312 {
00313     DdManager   *unique = ALLOC(DdManager,1);
00314     int         i, j;
00315     DdNodePtr   *nodelist;
00316     DdNode      *sentinel;
00317     unsigned int slots;
00318     int shift;
00319 
00320     if (unique == NULL) {
00321         return(NULL);
00322     }
00323     sentinel = &(unique->sentinel);
00324     sentinel->ref = 0;
00325     sentinel->index = 0;
00326     cuddT(sentinel) = NULL;
00327     cuddE(sentinel) = NULL;
00328     sentinel->next = NULL;
00329     unique->epsilon = DD_EPSILON;
00330     unique->maxGrowth = DD_MAX_REORDER_GROWTH;
00331     unique->maxGrowthAlt = 2.0 * DD_MAX_REORDER_GROWTH;
00332     unique->reordCycle = 0;     /* do not use alternate threshold */
00333     unique->size = numVars;
00334     unique->sizeZ = numVarsZ;
00335     unique->maxSize = ddMax(DD_DEFAULT_RESIZE, numVars);
00336     unique->maxSizeZ = ddMax(DD_DEFAULT_RESIZE, numVarsZ);
00337 
00338     /* Adjust the requested number of slots to a power of 2. */
00339     slots = 8;
00340     while (slots < numSlots) {
00341         slots <<= 1;
00342     }
00343     unique->initSlots = slots;
00344     shift = sizeof(int) * 8 - cuddComputeFloorLog2(slots);
00345 
00346     unique->slots = (numVars + numVarsZ + 1) * slots;
00347     unique->keys = 0;
00348     unique->maxLive = ~0;       /* very large number */
00349     unique->keysZ = 0;
00350     unique->dead = 0;
00351     unique->deadZ = 0;
00352     unique->gcFrac = DD_GC_FRAC_HI;
00353     unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
00354     unique->looseUpTo = looseUpTo;
00355     unique->gcEnabled = 1;
00356     unique->allocated = 0;
00357     unique->reclaimed = 0;
00358     unique->subtables = ALLOC(DdSubtable,unique->maxSize);
00359     if (unique->subtables == NULL) {
00360         unique->errorCode = CUDD_MEMORY_OUT;
00361         return(0);
00362     }
00363     unique->subtableZ = ALLOC(DdSubtable,unique->maxSizeZ);
00364     if (unique->subtableZ == NULL) {
00365         unique->errorCode = CUDD_MEMORY_OUT;
00366         return(0);
00367     }
00368     unique->perm = ALLOC(int,unique->maxSize);
00369     if (unique->perm == NULL) {
00370         unique->errorCode = CUDD_MEMORY_OUT;
00371         return(0);
00372     }
00373     unique->invperm = ALLOC(int,unique->maxSize);
00374     if (unique->invperm == NULL) {
00375         unique->errorCode = CUDD_MEMORY_OUT;
00376         return(0);
00377     }
00378     unique->permZ = ALLOC(int,unique->maxSizeZ);
00379     if (unique->permZ == NULL) {
00380         unique->errorCode = CUDD_MEMORY_OUT;
00381         return(0);
00382     }
00383     unique->invpermZ = ALLOC(int,unique->maxSizeZ);
00384     if (unique->invpermZ == NULL) {
00385         unique->errorCode = CUDD_MEMORY_OUT;
00386         return(0);
00387     }
00388     unique->map = NULL;
00389     unique->stack = ALLOC(DdNodePtr,ddMax(unique->maxSize,unique->maxSizeZ)+1);
00390     if (unique->stack == NULL) {
00391         unique->errorCode = CUDD_MEMORY_OUT;
00392         return(0);
00393     }
00394     unique->stack[0] = NULL; /* to suppress harmless UMR */
00395 
00396 #ifndef DD_NO_DEATH_ROW
00397     unique->deathRowDepth = 1 << cuddComputeFloorLog2(unique->looseUpTo >> 2);
00398     unique->deathRow = ALLOC(DdNodePtr,unique->deathRowDepth);
00399     if (unique->deathRow == NULL) {
00400         unique->errorCode = CUDD_MEMORY_OUT;
00401         return(0);
00402     }
00403     for (i = 0; i < unique->deathRowDepth; i++) {
00404         unique->deathRow[i] = NULL;
00405     }
00406     unique->nextDead = 0;
00407     unique->deadMask = unique->deathRowDepth - 1;
00408 #endif
00409 
00410     for (i = 0; (unsigned) i < numVars; i++) {
00411         unique->subtables[i].slots = slots;
00412         unique->subtables[i].shift = shift;
00413         unique->subtables[i].keys = 0;
00414         unique->subtables[i].dead = 0;
00415         unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
00416         unique->subtables[i].bindVar = 0;
00417         unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
00418         unique->subtables[i].pairIndex = 0;
00419         unique->subtables[i].varHandled = 0;
00420         unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
00421 
00422         nodelist = unique->subtables[i].nodelist = ALLOC(DdNodePtr,slots);
00423         if (nodelist == NULL) {
00424             unique->errorCode = CUDD_MEMORY_OUT;
00425             return(NULL);
00426         }
00427         for (j = 0; (unsigned) j < slots; j++) {
00428             nodelist[j] = sentinel;
00429         }
00430         unique->perm[i] = i;
00431         unique->invperm[i] = i;
00432     }
00433     for (i = 0; (unsigned) i < numVarsZ; i++) {
00434         unique->subtableZ[i].slots = slots;
00435         unique->subtableZ[i].shift = shift;
00436         unique->subtableZ[i].keys = 0;
00437         unique->subtableZ[i].dead = 0;
00438         unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
00439         nodelist = unique->subtableZ[i].nodelist = ALLOC(DdNodePtr,slots);
00440         if (nodelist == NULL) {
00441             unique->errorCode = CUDD_MEMORY_OUT;
00442             return(NULL);
00443         }
00444         for (j = 0; (unsigned) j < slots; j++) {
00445             nodelist[j] = NULL;
00446         }
00447         unique->permZ[i] = i;
00448         unique->invpermZ[i] = i;
00449     }
00450     unique->constants.slots = slots;
00451     unique->constants.shift = shift;
00452     unique->constants.keys = 0;
00453     unique->constants.dead = 0;
00454     unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
00455     nodelist = unique->constants.nodelist = ALLOC(DdNodePtr,slots);
00456     if (nodelist == NULL) {
00457         unique->errorCode = CUDD_MEMORY_OUT;
00458         return(NULL);
00459     }
00460     for (j = 0; (unsigned) j < slots; j++) {
00461         nodelist[j] = NULL;
00462     }
00463 
00464     unique->memoryList = NULL;
00465     unique->nextFree = NULL;
00466 
00467     unique->memused = sizeof(DdManager) + (unique->maxSize + unique->maxSizeZ)
00468         * (sizeof(DdSubtable) + 2 * sizeof(int)) + (numVars + 1) *
00469         slots * sizeof(DdNodePtr) +
00470         (ddMax(unique->maxSize,unique->maxSizeZ) + 1) * sizeof(DdNodePtr);
00471 #ifndef DD_NO_DEATH_ROW
00472     unique->memused += unique->deathRowDepth * sizeof(DdNodePtr);
00473 #endif
00474 
00475     /* Initialize fields concerned with automatic dynamic reordering */
00476     unique->reorderings = 0;
00477     unique->autoDyn = 0;        /* initially disabled */
00478     unique->autoDynZ = 0;       /* initially disabled */
00479     unique->realign = 0;        /* initially disabled */
00480     unique->realignZ = 0;       /* initially disabled */
00481     unique->reordered = 0;
00482     unique->autoMethod = CUDD_REORDER_SIFT;
00483     unique->autoMethodZ = CUDD_REORDER_SIFT;
00484     unique->nextDyn = DD_FIRST_REORDER;
00485     unique->countDead = ~0;
00486     unique->siftMaxVar = DD_SIFT_MAX_VAR;
00487     unique->siftMaxSwap = DD_SIFT_MAX_SWAPS;
00488     unique->tree = NULL;
00489     unique->treeZ = NULL;
00490     unique->groupcheck = CUDD_GROUP_CHECK7;
00491     unique->recomb = DD_DEFAULT_RECOMB;
00492     unique->symmviolation = 0;
00493     unique->arcviolation = 0;
00494     unique->populationSize = 0;
00495     unique->numberXovers = 0;
00496     unique->linear = NULL;
00497     unique->linearSize = 0;
00498 
00499     /* Initialize ZDD universe. */
00500     unique->univ = (DdNodePtr *)NULL;
00501 
00502     /* Initialize auxiliary fields. */
00503     unique->localCaches = NULL;
00504     unique->preGCHook = NULL;
00505     unique->postGCHook = NULL;
00506     unique->preReorderingHook = NULL;
00507     unique->postReorderingHook = NULL;
00508     unique->out = stdout;
00509     unique->err = stderr;
00510     unique->errorCode = CUDD_NO_ERROR;
00511 
00512     /* Initialize statistical counters. */
00513     unique->maxmemhard = (long) ((~ (unsigned long) 0) >> 1);
00514     unique->garbageCollections = 0;
00515     unique->GCTime = 0;
00516     unique->reordTime = 0;
00517 #ifdef DD_STATS
00518     unique->nodesDropped = 0;
00519     unique->nodesFreed = 0;
00520 #endif
00521     unique->peakLiveNodes = 0;
00522 #ifdef DD_UNIQUE_PROFILE
00523     unique->uniqueLookUps = 0;
00524     unique->uniqueLinks = 0;
00525 #endif
00526 #ifdef DD_COUNT
00527     unique->recursiveCalls = 0;
00528     unique->swapSteps = 0;
00529 #ifdef DD_STATS
00530     unique->nextSample = 250000;
00531 #endif
00532 #endif
00533 
00534     return(unique);
00535 
00536 } /* end of cuddInitTable */

int cuddInsertSubtables ( DdManager unique,
int  n,
int  level 
)

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

Synopsis [Inserts n new subtables in a unique table at level.]

Description [Inserts n new subtables in a unique table at level. The number n should be positive, and level should be an existing level. Returns 1 if successful; 0 otherwise.]

SideEffects [None]

SeeAlso [cuddDestroySubtables]

Definition at line 1759 of file cuddTable.c.

01763 {
01764     DdSubtable *newsubtables;
01765     DdNodePtr *newnodelist;
01766     DdNodePtr *newvars;
01767     DdNode *sentinel = &(unique->sentinel);
01768     int oldsize,newsize;
01769     int i,j,index,reorderSave;
01770     unsigned int numSlots = unique->initSlots;
01771     int *newperm, *newinvperm, *newmap;
01772     DdNode *one, *zero;
01773 
01774 #ifdef DD_DEBUG
01775     assert(n > 0 && level < unique->size);
01776 #endif
01777 
01778     oldsize = unique->size;
01779     /* Easy case: there is still room in the current table. */
01780     if (oldsize + n <= unique->maxSize) {
01781         /* Shift the tables at and below level. */
01782         for (i = oldsize - 1; i >= level; i--) {
01783             unique->subtables[i+n].slots    = unique->subtables[i].slots;
01784             unique->subtables[i+n].shift    = unique->subtables[i].shift;
01785             unique->subtables[i+n].keys     = unique->subtables[i].keys;
01786             unique->subtables[i+n].maxKeys  = unique->subtables[i].maxKeys;
01787             unique->subtables[i+n].dead     = unique->subtables[i].dead;
01788             unique->subtables[i+n].nodelist = unique->subtables[i].nodelist;
01789             unique->subtables[i+n].bindVar  = unique->subtables[i].bindVar;
01790             unique->subtables[i+n].varType  = unique->subtables[i].varType;
01791             unique->subtables[i+n].pairIndex  = unique->subtables[i].pairIndex;
01792             unique->subtables[i+n].varHandled = unique->subtables[i].varHandled;
01793             unique->subtables[i+n].varToBeGrouped =
01794                 unique->subtables[i].varToBeGrouped;
01795 
01796             index                           = unique->invperm[i];
01797             unique->invperm[i+n]            = index;
01798             unique->perm[index]            += n;
01799         }
01800         /* Create new subtables. */
01801         for (i = 0; i < n; i++) {
01802             unique->subtables[level+i].slots = numSlots;
01803             unique->subtables[level+i].shift = sizeof(int) * 8 -
01804                 cuddComputeFloorLog2(numSlots);
01805             unique->subtables[level+i].keys = 0;
01806             unique->subtables[level+i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
01807             unique->subtables[level+i].dead = 0;
01808             unique->subtables[level+i].bindVar = 0;
01809             unique->subtables[level+i].varType = CUDD_VAR_PRIMARY_INPUT;
01810             unique->subtables[level+i].pairIndex = 0;
01811             unique->subtables[level+i].varHandled = 0;
01812             unique->subtables[level+i].varToBeGrouped = CUDD_LAZY_NONE;
01813 
01814             unique->perm[oldsize+i] = level + i;
01815             unique->invperm[level+i] = oldsize + i;
01816             newnodelist = unique->subtables[level+i].nodelist =
01817                 ALLOC(DdNodePtr, numSlots);
01818             if (newnodelist == NULL) {
01819                 unique->errorCode = CUDD_MEMORY_OUT;
01820                 return(0);
01821             }
01822             for (j = 0; j < numSlots; j++) {
01823                 newnodelist[j] = sentinel;
01824             }
01825         }
01826         if (unique->map != NULL) {
01827             for (i = 0; i < n; i++) {
01828                 unique->map[oldsize+i] = oldsize + i;
01829             }
01830         }
01831     } else {
01832         /* The current table is too small: we need to allocate a new,
01833         ** larger one; move all old subtables, and initialize the new
01834         ** subtables.
01835         */
01836         newsize = oldsize + n + DD_DEFAULT_RESIZE;
01837 #ifdef DD_VERBOSE
01838         (void) fprintf(unique->err,
01839                        "Increasing the table size from %d to %d\n",
01840             unique->maxSize, newsize);
01841 #endif
01842         /* Allocate memory for new arrays (except nodelists). */
01843         newsubtables = ALLOC(DdSubtable,newsize);
01844         if (newsubtables == NULL) {
01845             unique->errorCode = CUDD_MEMORY_OUT;
01846             return(0);
01847         }
01848         newvars = ALLOC(DdNodePtr,newsize);
01849         if (newvars == NULL) {
01850             unique->errorCode = CUDD_MEMORY_OUT;
01851             FREE(newsubtables);
01852             return(0);
01853         }
01854         newperm = ALLOC(int,newsize);
01855         if (newperm == NULL) {
01856             unique->errorCode = CUDD_MEMORY_OUT;
01857             FREE(newsubtables);
01858             FREE(newvars);
01859             return(0);
01860         }
01861         newinvperm = ALLOC(int,newsize);
01862         if (newinvperm == NULL) {
01863             unique->errorCode = CUDD_MEMORY_OUT;
01864             FREE(newsubtables);
01865             FREE(newvars);
01866             FREE(newperm);
01867             return(0);
01868         }
01869         if (unique->map != NULL) {
01870             newmap = ALLOC(int,newsize);
01871             if (newmap == NULL) {
01872                 unique->errorCode = CUDD_MEMORY_OUT;
01873                 FREE(newsubtables);
01874                 FREE(newvars);
01875                 FREE(newperm);
01876                 FREE(newinvperm);
01877                 return(0);
01878             }
01879             unique->memused += (newsize - unique->maxSize) * sizeof(int);
01880         }
01881         unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
01882             sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
01883         /* Copy levels before insertion points from old tables. */
01884         for (i = 0; i < level; i++) {
01885             newsubtables[i].slots = unique->subtables[i].slots;
01886             newsubtables[i].shift = unique->subtables[i].shift;
01887             newsubtables[i].keys = unique->subtables[i].keys;
01888             newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
01889             newsubtables[i].dead = unique->subtables[i].dead;
01890             newsubtables[i].nodelist = unique->subtables[i].nodelist;
01891             newsubtables[i].bindVar = unique->subtables[i].bindVar;
01892             newsubtables[i].varType = unique->subtables[i].varType;
01893             newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
01894             newsubtables[i].varHandled = unique->subtables[i].varHandled;
01895             newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
01896 
01897             newvars[i] = unique->vars[i];
01898             newperm[i] = unique->perm[i];
01899             newinvperm[i] = unique->invperm[i];
01900         }
01901         /* Finish initializing permutation for new table to old one. */
01902         for (i = level; i < oldsize; i++) {
01903             newperm[i] = unique->perm[i];
01904         }
01905         /* Initialize new levels. */
01906         for (i = level; i < level + n; i++) {
01907             newsubtables[i].slots = numSlots;
01908             newsubtables[i].shift = sizeof(int) * 8 -
01909                 cuddComputeFloorLog2(numSlots);
01910             newsubtables[i].keys = 0;
01911             newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
01912             newsubtables[i].dead = 0;
01913             newsubtables[i].bindVar = 0;
01914             newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
01915             newsubtables[i].pairIndex = 0;
01916             newsubtables[i].varHandled = 0;
01917             newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
01918 
01919             newperm[oldsize + i - level] = i;
01920             newinvperm[i] = oldsize + i - level;
01921             newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
01922             if (newnodelist == NULL) {
01923                 /* We are going to leak some memory.  We should clean up. */
01924                 unique->errorCode = CUDD_MEMORY_OUT;
01925                 return(0);
01926             }
01927             for (j = 0; j < numSlots; j++) {
01928                 newnodelist[j] = sentinel;
01929             }
01930         }
01931         /* Copy the old tables for levels past the insertion point. */
01932         for (i = level; i < oldsize; i++) {
01933             newsubtables[i+n].slots    = unique->subtables[i].slots;
01934             newsubtables[i+n].shift    = unique->subtables[i].shift;
01935             newsubtables[i+n].keys     = unique->subtables[i].keys;
01936             newsubtables[i+n].maxKeys  = unique->subtables[i].maxKeys;
01937             newsubtables[i+n].dead     = unique->subtables[i].dead;
01938             newsubtables[i+n].nodelist = unique->subtables[i].nodelist;
01939             newsubtables[i+n].bindVar  = unique->subtables[i].bindVar;
01940             newsubtables[i+n].varType  = unique->subtables[i].varType;
01941             newsubtables[i+n].pairIndex  = unique->subtables[i].pairIndex;
01942             newsubtables[i+n].varHandled  = unique->subtables[i].varHandled;
01943             newsubtables[i+n].varToBeGrouped  =
01944                 unique->subtables[i].varToBeGrouped;
01945 
01946             newvars[i]                 = unique->vars[i];
01947             index                      = unique->invperm[i];
01948             newinvperm[i+n]            = index;
01949             newperm[index]            += n;
01950         }
01951         /* Update the map. */
01952         if (unique->map != NULL) {
01953             for (i = 0; i < oldsize; i++) {
01954                 newmap[i] = unique->map[i];
01955             }
01956             for (i = oldsize; i < oldsize + n; i++) {
01957                 newmap[i] = i;
01958             }
01959             FREE(unique->map);
01960             unique->map = newmap;
01961         }
01962         /* Install the new tables and free the old ones. */
01963         FREE(unique->subtables);
01964         unique->subtables = newsubtables;
01965         unique->maxSize = newsize;
01966         FREE(unique->vars);
01967         unique->vars = newvars;
01968         FREE(unique->perm);
01969         unique->perm = newperm;
01970         FREE(unique->invperm);
01971         unique->invperm = newinvperm;
01972         /* Update the stack for iterative procedures. */
01973         if (newsize > unique->maxSizeZ) {
01974             FREE(unique->stack);
01975             unique->stack = ALLOC(DdNodePtr,newsize + 1);
01976             if (unique->stack == NULL) {
01977                 unique->errorCode = CUDD_MEMORY_OUT;
01978                 return(0);
01979             }
01980             unique->stack[0] = NULL; /* to suppress harmless UMR */
01981             unique->memused +=
01982                 (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
01983                 * sizeof(DdNode *);
01984         }
01985     }
01986     /* Update manager parameters to account for the new subtables. */
01987     unique->slots += n * numSlots;
01988     ddFixLimits(unique);
01989     unique->size += n;
01990 
01991     /* Now that the table is in a coherent state, create the new
01992     ** projection functions. We need to temporarily disable reordering,
01993     ** because we cannot reorder without projection functions in place.
01994     **/
01995     one = unique->one;
01996     zero = Cudd_Not(one);
01997 
01998     reorderSave = unique->autoDyn;
01999     unique->autoDyn = 0;
02000     for (i = oldsize; i < oldsize + n; i++) {
02001         unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
02002         if (unique->vars[i] == NULL) {
02003             unique->autoDyn = reorderSave;
02004             /* Shift everything back so table remains coherent. */
02005             for (j = oldsize; j < i; j++) {
02006                 Cudd_IterDerefBdd(unique,unique->vars[j]);
02007                 cuddDeallocNode(unique,unique->vars[j]);
02008                 unique->vars[j] = NULL;
02009             }
02010             for (j = level; j < oldsize; j++) {
02011                 unique->subtables[j].slots    = unique->subtables[j+n].slots;
02012                 unique->subtables[j].slots    = unique->subtables[j+n].slots;
02013                 unique->subtables[j].shift    = unique->subtables[j+n].shift;
02014                 unique->subtables[j].keys     = unique->subtables[j+n].keys;
02015                 unique->subtables[j].maxKeys  =
02016                     unique->subtables[j+n].maxKeys;
02017                 unique->subtables[j].dead     = unique->subtables[j+n].dead;
02018                 FREE(unique->subtables[j].nodelist);
02019                 unique->subtables[j].nodelist =
02020                     unique->subtables[j+n].nodelist;
02021                 unique->subtables[j+n].nodelist = NULL;
02022                 unique->subtables[j].bindVar  =
02023                     unique->subtables[j+n].bindVar;
02024                 unique->subtables[j].varType  =
02025                     unique->subtables[j+n].varType;
02026                 unique->subtables[j].pairIndex =
02027                     unique->subtables[j+n].pairIndex;
02028                 unique->subtables[j].varHandled =
02029                     unique->subtables[j+n].varHandled;
02030                 unique->subtables[j].varToBeGrouped =
02031                     unique->subtables[j+n].varToBeGrouped;
02032                 index                         = unique->invperm[j+n];
02033                 unique->invperm[j]            = index;
02034                 unique->perm[index]          -= n;
02035             }
02036             unique->size = oldsize;
02037             unique->slots -= n * numSlots;
02038             ddFixLimits(unique);
02039             (void) Cudd_DebugCheck(unique);
02040             return(0);
02041         }
02042         cuddRef(unique->vars[i]);
02043     }
02044     if (unique->tree != NULL) {
02045         unique->tree->size += n;
02046         unique->tree->index = unique->invperm[0];
02047         ddPatchTree(unique,unique->tree);
02048     }
02049     unique->autoDyn = reorderSave;
02050 
02051     return(1);
02052 
02053 } /* end of cuddInsertSubtables */

static void cuddOrderedInsert ( DdNodePtr root,
DdNodePtr  node 
) [static]

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

Synopsis [Inserts a DdNode in a red/black search tree.]

Description [Inserts a DdNode in a red/black search tree. Nodes from the same "page" (defined by DD_PAGE_MASK) are linked in a LIFO list.]

SideEffects [None]

SeeAlso [cuddOrderedThread]

Definition at line 2801 of file cuddTable.c.

02804 {
02805     DdNode *scan;
02806     DdNodePtr *scanP;
02807     DdNodePtr *stack[DD_STACK_SIZE];
02808     int stackN = 0;
02809 
02810     scanP = root;
02811     while ((scan = *scanP) != NULL) {
02812         stack[stackN++] = scanP;
02813         if (DD_INSERT_COMPARE(node, scan) == 0) { /* add to page list */
02814             DD_NEXT(node) = DD_NEXT(scan);
02815             DD_NEXT(scan) = node;
02816             return;
02817         }
02818         scanP = (node < scan) ? &DD_LEFT(scan) : &DD_RIGHT(scan);
02819     }
02820     DD_RIGHT(node) = DD_LEFT(node) = DD_NEXT(node) = NULL;
02821     DD_COLOR(node) = DD_RED;
02822     *scanP = node;
02823     stack[stackN] = &node;
02824     cuddDoRebalance(stack,stackN);
02825 
02826 } /* end of cuddOrderedInsert */

static DdNode* cuddOrderedThread ( DdNode root,
DdNode list 
) [static]

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

Synopsis [Threads all the nodes of a search tree into a linear list.]

Description [Threads all the nodes of a search tree into a linear list. For each node of the search tree, the "left" child, if non-null, has a lower address than its parent, and the "right" child, if non-null, has a higher address than its parent. The list is sorted in order of increasing addresses. The search tree is destroyed as a result of this operation. The last element of the linear list is made to point to the address passed in list. Each node if the search tree is a linearly-linked list of nodes from the same memory page (as defined in DD_PAGE_MASK). When a node is added to the linear list, all the elements of the linked list are added.]

SideEffects [The search tree is destroyed as a result of this operation.]

SeeAlso [cuddOrderedInsert]

Definition at line 2850 of file cuddTable.c.

02853 {
02854     DdNode *current, *next, *prev, *end;
02855 
02856     current = root;
02857     /* The first word in the node is used to implement a stack that holds
02858     ** the nodes from the root of the tree to the current node. Here we
02859     ** put the root of the tree at the bottom of the stack.
02860     */
02861     *((DdNodePtr *) current) = NULL;
02862 
02863     while (current != NULL) {
02864         if (DD_RIGHT(current) != NULL) {
02865             /* If possible, we follow the "right" link. Eventually we'll
02866             ** find the node with the largest address in the current tree.
02867             ** In this phase we use the first word of a node to implemen
02868             ** a stack of the nodes on the path from the root to "current".
02869             ** Also, we disconnect the "right" pointers to indicate that
02870             ** we have already followed them.
02871             */
02872             next = DD_RIGHT(current);
02873             DD_RIGHT(current) = NULL;
02874             *((DdNodePtr *)next) = current;
02875             current = next;
02876         } else {
02877             /* We can't proceed along the "right" links any further.
02878             ** Hence "current" is the largest element in the current tree.
02879             ** We make this node the new head of "list". (Repeating this
02880             ** operation until the tree is empty yields the desired linear
02881             ** threading of all nodes.)
02882             */
02883             prev = *((DdNodePtr *) current); /* save prev node on stack in prev */
02884             /* Traverse the linked list of current until the end. */
02885             for (end = current; DD_NEXT(end) != NULL; end = DD_NEXT(end));
02886             DD_NEXT(end) = list; /* attach "list" at end and make */
02887             list = current;   /* "current" the new head of "list" */
02888             /* Now, if current has a "left" child, we push it on the stack.
02889             ** Otherwise, we just continue with the parent of "current".
02890             */
02891             if (DD_LEFT(current) != NULL) {
02892                 next = DD_LEFT(current);
02893                 *((DdNodePtr *) next) = prev;
02894                 current = next;
02895             } else {
02896                 current = prev;
02897             }
02898         }
02899     }
02900 
02901     return(list);
02902 
02903 } /* end of cuddOrderedThread */

void cuddRehash ( DdManager unique,
int  i 
)

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

Synopsis [Rehashes a unique subtable.]

Description [Doubles the size of a unique subtable and rehashes its contents.]

SideEffects [None]

SeeAlso []

Definition at line 1493 of file cuddTable.c.

01496 {
01497     unsigned int slots, oldslots;
01498     int shift, oldshift;
01499     int j, pos;
01500     DdNodePtr *nodelist, *oldnodelist;
01501     DdNode *node, *next;
01502     DdNode *sentinel = &(unique->sentinel);
01503     hack split;
01504     extern void (*MMoutOfMemory)(long);
01505     void (*saveHandler)(long);
01506 
01507     if (unique->gcFrac == DD_GC_FRAC_HI && unique->slots > unique->looseUpTo) {
01508         unique->gcFrac = DD_GC_FRAC_LO;
01509         unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
01510 #ifdef DD_VERBOSE
01511         (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_LO);
01512         (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
01513 #endif
01514     }
01515 
01516     if (unique->gcFrac != DD_GC_FRAC_MIN && unique->memused > unique->maxmem) {
01517         unique->gcFrac = DD_GC_FRAC_MIN;
01518         unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
01519 #ifdef DD_VERBOSE
01520         (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_MIN);
01521         (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
01522 #endif
01523         cuddShrinkDeathRow(unique);
01524         if (cuddGarbageCollect(unique,1) > 0) return;
01525     }
01526 
01527     if (i != CUDD_CONST_INDEX) {
01528         oldslots = unique->subtables[i].slots;
01529         oldshift = unique->subtables[i].shift;
01530         oldnodelist = unique->subtables[i].nodelist;
01531 
01532         /* Compute the new size of the subtable. */
01533         slots = oldslots << 1;
01534         shift = oldshift - 1;
01535 
01536         saveHandler = MMoutOfMemory;
01537         MMoutOfMemory = Cudd_OutOfMem;
01538         nodelist = ALLOC(DdNodePtr, slots);
01539         MMoutOfMemory = saveHandler;
01540         if (nodelist == NULL) {
01541             (void) fprintf(unique->err,
01542                            "Unable to resize subtable %d for lack of memory\n",
01543                            i);
01544             /* Prevent frequent resizing attempts. */
01545             (void) cuddGarbageCollect(unique,1);
01546             if (unique->stash != NULL) {
01547                 FREE(unique->stash);
01548                 unique->stash = NULL;
01549                 /* Inhibit resizing of tables. */
01550                 cuddSlowTableGrowth(unique);
01551             }
01552             return;
01553         }
01554         unique->subtables[i].nodelist = nodelist;
01555         unique->subtables[i].slots = slots;
01556         unique->subtables[i].shift = shift;
01557         unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
01558 
01559         /* Move the nodes from the old table to the new table.
01560         ** This code depends on the type of hash function.
01561         ** It assumes that the effect of doubling the size of the table
01562         ** is to retain one more bit of the 32-bit hash value.
01563         ** The additional bit is the LSB. */
01564         for (j = 0; (unsigned) j < oldslots; j++) {
01565             DdNodePtr *evenP, *oddP;
01566             node = oldnodelist[j];
01567             evenP = &(nodelist[j<<1]);
01568             oddP = &(nodelist[(j<<1)+1]);
01569             while (node != sentinel) {
01570                 next = node->next;
01571                 pos = ddHash(cuddT(node), cuddE(node), shift);
01572                 if (pos & 1) {
01573                     *oddP = node;
01574                     oddP = &(node->next);
01575                 } else {
01576                     *evenP = node;
01577                     evenP = &(node->next);
01578                 }
01579                 node = next;
01580             }
01581             *evenP = *oddP = sentinel;
01582         }
01583         FREE(oldnodelist);
01584 
01585 #ifdef DD_VERBOSE
01586         (void) fprintf(unique->err,
01587                        "rehashing layer %d: keys %d dead %d new size %d\n",
01588                        i, unique->subtables[i].keys,
01589                        unique->subtables[i].dead, slots);
01590 #endif
01591     } else {
01592         oldslots = unique->constants.slots;
01593         oldshift = unique->constants.shift;
01594         oldnodelist = unique->constants.nodelist;
01595 
01596         /* The constant subtable is never subjected to reordering.
01597         ** Therefore, when it is resized, it is because it has just
01598         ** reached the maximum load. We can safely just double the size,
01599         ** with no need for the loop we use for the other tables.
01600         */
01601         slots = oldslots << 1;
01602         shift = oldshift - 1;
01603         saveHandler = MMoutOfMemory;
01604         MMoutOfMemory = Cudd_OutOfMem;
01605         nodelist = ALLOC(DdNodePtr, slots);
01606         MMoutOfMemory = saveHandler;
01607         if (nodelist == NULL) {
01608             int j;
01609             (void) fprintf(unique->err,
01610                            "Unable to resize constant subtable for lack of memory\n");
01611             (void) cuddGarbageCollect(unique,1);
01612             for (j = 0; j < unique->size; j++) {
01613                 unique->subtables[j].maxKeys <<= 1;
01614             }
01615             unique->constants.maxKeys <<= 1;
01616             return;
01617         }
01618         unique->constants.slots = slots;
01619         unique->constants.shift = shift;
01620         unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
01621         unique->constants.nodelist = nodelist;
01622         for (j = 0; (unsigned) j < slots; j++) {
01623             nodelist[j] = NULL;
01624         }
01625         for (j = 0; (unsigned) j < oldslots; j++) {
01626             node = oldnodelist[j];
01627             while (node != NULL) {
01628                 next = node->next;
01629                 split.value = cuddV(node);
01630                 pos = ddHash(split.bits[0], split.bits[1], shift);
01631                 node->next = nodelist[pos];
01632                 nodelist[pos] = node;
01633                 node = next;
01634             }
01635         }
01636         FREE(oldnodelist);
01637 
01638 #ifdef DD_VERBOSE
01639         (void) fprintf(unique->err,
01640                        "rehashing constants: keys %d dead %d new size %d\n",
01641                        unique->constants.keys,unique->constants.dead,slots);
01642 #endif
01643     }
01644 
01645     /* Update global data */
01646 
01647     unique->memused += (slots - oldslots) * sizeof(DdNodePtr);
01648     unique->slots += (slots - oldslots);
01649     ddFixLimits(unique);
01650 
01651 } /* end of cuddRehash */

int cuddResizeTableZdd ( DdManager unique,
int  index 
)

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

Synopsis [Increases the number of ZDD subtables in a unique table so that it meets or exceeds index.]

Description [Increases the number of ZDD subtables in a unique table so that it meets or exceeds index. When new ZDD variables are created, it is possible to preserve the functions unchanged, or it is possible to preserve the covers unchanged, but not both. cuddResizeTableZdd preserves the covers. Returns 1 if successful; 0 otherwise.]

SideEffects [None]

SeeAlso [ddResizeTable]

Definition at line 2205 of file cuddTable.c.

02208 {
02209     DdSubtable *newsubtables;
02210     DdNodePtr *newnodelist;
02211     int oldsize,newsize;
02212     int i,j,reorderSave;
02213     unsigned int numSlots = unique->initSlots;
02214     int *newperm, *newinvperm;
02215     DdNode *one, *zero;
02216 
02217     oldsize = unique->sizeZ;
02218     /* Easy case: there is still room in the current table. */
02219     if (index < unique->maxSizeZ) {
02220         for (i = oldsize; i <= index; i++) {
02221             unique->subtableZ[i].slots = numSlots;
02222             unique->subtableZ[i].shift = sizeof(int) * 8 -
02223                 cuddComputeFloorLog2(numSlots);
02224             unique->subtableZ[i].keys = 0;
02225             unique->subtableZ[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
02226             unique->subtableZ[i].dead = 0;
02227             unique->permZ[i] = i;
02228             unique->invpermZ[i] = i;
02229             newnodelist = unique->subtableZ[i].nodelist =
02230                 ALLOC(DdNodePtr, numSlots);
02231             if (newnodelist == NULL) {
02232                 unique->errorCode = CUDD_MEMORY_OUT;
02233                 return(0);
02234             }
02235             for (j = 0; j < numSlots; j++) {
02236                 newnodelist[j] = NULL;
02237             }
02238         }
02239     } else {
02240         /* The current table is too small: we need to allocate a new,
02241         ** larger one; move all old subtables, and initialize the new
02242         ** subtables up to index included.
02243         */
02244         newsize = index + DD_DEFAULT_RESIZE;
02245 #ifdef DD_VERBOSE
02246         (void) fprintf(unique->err,
02247                        "Increasing the ZDD table size from %d to %d\n",
02248             unique->maxSizeZ, newsize);
02249 #endif
02250         newsubtables = ALLOC(DdSubtable,newsize);
02251         if (newsubtables == NULL) {
02252             unique->errorCode = CUDD_MEMORY_OUT;
02253             return(0);
02254         }
02255         newperm = ALLOC(int,newsize);
02256         if (newperm == NULL) {
02257             unique->errorCode = CUDD_MEMORY_OUT;
02258             return(0);
02259         }
02260         newinvperm = ALLOC(int,newsize);
02261         if (newinvperm == NULL) {
02262             unique->errorCode = CUDD_MEMORY_OUT;
02263             return(0);
02264         }
02265         unique->memused += (newsize - unique->maxSizeZ) * ((numSlots+1) *
02266             sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
02267         if (newsize > unique->maxSize) {
02268             FREE(unique->stack);
02269             unique->stack = ALLOC(DdNodePtr,newsize + 1);
02270             if (unique->stack == NULL) {
02271                 unique->errorCode = CUDD_MEMORY_OUT;
02272                 return(0);
02273             }
02274             unique->stack[0] = NULL; /* to suppress harmless UMR */
02275             unique->memused +=
02276                 (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
02277                 * sizeof(DdNode *);
02278         }
02279         for (i = 0; i < oldsize; i++) {
02280             newsubtables[i].slots = unique->subtableZ[i].slots;
02281             newsubtables[i].shift = unique->subtableZ[i].shift;
02282             newsubtables[i].keys = unique->subtableZ[i].keys;
02283             newsubtables[i].maxKeys = unique->subtableZ[i].maxKeys;
02284             newsubtables[i].dead = unique->subtableZ[i].dead;
02285             newsubtables[i].nodelist = unique->subtableZ[i].nodelist;
02286             newperm[i] = unique->permZ[i];
02287             newinvperm[i] = unique->invpermZ[i];
02288         }
02289         for (i = oldsize; i <= index; i++) {
02290             newsubtables[i].slots = numSlots;
02291             newsubtables[i].shift = sizeof(int) * 8 -
02292                 cuddComputeFloorLog2(numSlots);
02293             newsubtables[i].keys = 0;
02294             newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
02295             newsubtables[i].dead = 0;
02296             newperm[i] = i;
02297             newinvperm[i] = i;
02298             newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
02299             if (newnodelist == NULL) {
02300                 unique->errorCode = CUDD_MEMORY_OUT;
02301                 return(0);
02302             }
02303             for (j = 0; j < numSlots; j++) {
02304                 newnodelist[j] = NULL;
02305             }
02306         }
02307         FREE(unique->subtableZ);
02308         unique->subtableZ = newsubtables;
02309         unique->maxSizeZ = newsize;
02310         FREE(unique->permZ);
02311         unique->permZ = newperm;
02312         FREE(unique->invpermZ);
02313         unique->invpermZ = newinvperm;
02314     }
02315     unique->slots += (index + 1 - unique->sizeZ) * numSlots;
02316     ddFixLimits(unique);
02317     unique->sizeZ = index + 1;
02318 
02319     /* Now that the table is in a coherent state, update the ZDD
02320     ** universe. We need to temporarily disable reordering,
02321     ** because we cannot reorder without universe in place.
02322     */
02323     one = unique->one;
02324     zero = unique->zero;
02325 
02326     reorderSave = unique->autoDynZ;
02327     unique->autoDynZ = 0;
02328     cuddZddFreeUniv(unique);
02329     if (!cuddZddInitUniv(unique)) {
02330         unique->autoDynZ = reorderSave;
02331         return(0);
02332     }
02333     unique->autoDynZ = reorderSave;
02334 
02335     return(1);
02336 
02337 } /* end of cuddResizeTableZdd */

static DD_INLINE void cuddRotateLeft ( DdNodePtr nodeP  )  [static]

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

Synopsis [Performs the left rotation for red/black trees.]

Description []

SideEffects [None]

SeeAlso [cuddRotateRight]

Definition at line 2919 of file cuddTable.c.

02921 {
02922     DdNode *newRoot;
02923     DdNode *oldRoot = *nodeP;
02924 
02925     *nodeP = newRoot = DD_RIGHT(oldRoot);
02926     DD_RIGHT(oldRoot) = DD_LEFT(newRoot);
02927     DD_LEFT(newRoot) = oldRoot;
02928 
02929 } /* end of cuddRotateLeft */

static DD_INLINE void cuddRotateRight ( DdNodePtr nodeP  )  [static]

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

Synopsis [Performs the right rotation for red/black trees.]

Description []

SideEffects [None]

SeeAlso [cuddRotateLeft]

Definition at line 2945 of file cuddTable.c.

02947 {
02948     DdNode *newRoot;
02949     DdNode *oldRoot = *nodeP;
02950 
02951     *nodeP = newRoot = DD_LEFT(oldRoot);
02952     DD_LEFT(oldRoot) = DD_RIGHT(newRoot);
02953     DD_RIGHT(newRoot) = oldRoot;
02954 
02955 } /* end of cuddRotateRight */

void cuddShrinkSubtable ( DdManager unique,
int  i 
)

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

Synopsis [Shrinks a subtable.]

Description [Shrinks a subtable.]

SideEffects [None]

SeeAlso [cuddRehash]

Definition at line 1666 of file cuddTable.c.

01669 {
01670     int j;
01671     int shift, posn;
01672     DdNodePtr *nodelist, *oldnodelist;
01673     DdNode *node, *next;
01674     DdNode *sentinel = &(unique->sentinel);
01675     unsigned int slots, oldslots;
01676     extern void (*MMoutOfMemory)(long);
01677     void (*saveHandler)(long);
01678 
01679     oldnodelist = unique->subtables[i].nodelist;
01680     oldslots = unique->subtables[i].slots;
01681     slots = oldslots >> 1;
01682     saveHandler = MMoutOfMemory;
01683     MMoutOfMemory = Cudd_OutOfMem;
01684     nodelist = ALLOC(DdNodePtr, slots);
01685     MMoutOfMemory = saveHandler;
01686     if (nodelist == NULL) {
01687         return;
01688     }
01689     unique->subtables[i].nodelist = nodelist;
01690     unique->subtables[i].slots = slots;
01691     unique->subtables[i].shift++;
01692     unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
01693 #ifdef DD_VERBOSE
01694     (void) fprintf(unique->err,
01695                    "shrunk layer %d (%d keys) from %d to %d slots\n",
01696                    i, unique->subtables[i].keys, oldslots, slots);
01697 #endif
01698 
01699     for (j = 0; (unsigned) j < slots; j++) {
01700         nodelist[j] = sentinel;
01701     }
01702     shift = unique->subtables[i].shift;
01703     for (j = 0; (unsigned) j < oldslots; j++) {
01704         node = oldnodelist[j];
01705         while (node != sentinel) {
01706             DdNode *looking, *T, *E;
01707             DdNodePtr *previousP;
01708             next = node->next;
01709             posn = ddHash(cuddT(node), cuddE(node), shift);
01710             previousP = &(nodelist[posn]);
01711             looking = *previousP;
01712             T = cuddT(node);
01713             E = cuddE(node);
01714             while (T < cuddT(looking)) {
01715                 previousP = &(looking->next);
01716                 looking = *previousP;
01717 #ifdef DD_UNIQUE_PROFILE
01718                 unique->uniqueLinks++;
01719 #endif
01720             }
01721             while (T == cuddT(looking) && E < cuddE(looking)) {
01722                 previousP = &(looking->next);
01723                 looking = *previousP;
01724 #ifdef DD_UNIQUE_PROFILE
01725                 unique->uniqueLinks++;
01726 #endif
01727             }
01728             node->next = *previousP;
01729             *previousP = node;
01730             node = next;
01731         }
01732     }
01733     FREE(oldnodelist);
01734 
01735     unique->memused += ((long) slots - (long) oldslots) * sizeof(DdNode *);
01736     unique->slots += slots - oldslots;
01737     unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
01738     unique->cacheSlack = (int)
01739         ddMin(unique->maxCacheHard,DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots)
01740         - 2 * (int) unique->cacheSlots;
01741 
01742 } /* end of cuddShrinkSubtable */

void cuddSlowTableGrowth ( DdManager unique  ) 

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

Synopsis [Adjusts parameters of a table to slow down its growth.]

Description []

SideEffects [None]

SeeAlso []

Definition at line 2352 of file cuddTable.c.

02354 {
02355     int i;
02356 
02357     unique->maxCacheHard = unique->cacheSlots - 1;
02358     unique->cacheSlack = -(unique->cacheSlots + 1);
02359     for (i = 0; i < unique->size; i++) {
02360         unique->subtables[i].maxKeys <<= 2;
02361     }
02362     unique->gcFrac = DD_GC_FRAC_MIN;
02363     unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
02364     cuddShrinkDeathRow(unique);
02365     (void) fprintf(unique->err,"Slowing down table growth: ");
02366     (void) fprintf(unique->err,"GC fraction = %.2f\t", unique->gcFrac);
02367     (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
02368 
02369 } /* end of cuddSlowTableGrowth */

DdNode* cuddUniqueConst ( DdManager unique,
CUDD_VALUE_TYPE  value 
)

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

Synopsis [Checks the unique table for the existence of a constant node.]

Description [Checks the unique table for the existence of a constant node. If it does not exist, it creates a new one. Does not modify the reference count of whatever is returned. A newly created internal node comes back with a reference count 0. Returns a pointer to the new node.]

SideEffects [None]

Definition at line 1412 of file cuddTable.c.

01415 {
01416     int pos;
01417     DdNodePtr *nodelist;
01418     DdNode *looking;
01419     hack split;
01420 
01421 #ifdef DD_UNIQUE_PROFILE
01422     unique->uniqueLookUps++;
01423 #endif
01424 
01425     if (unique->constants.keys > unique->constants.maxKeys) {
01426         if (unique->gcEnabled && ((unique->dead > unique->minDead) ||
01427         (10 * unique->constants.dead > 9 * unique->constants.keys))) {  /* too many dead */
01428             (void) cuddGarbageCollect(unique,1);
01429         } else {
01430             cuddRehash(unique,CUDD_CONST_INDEX);
01431         }
01432     }
01433 
01434     cuddAdjust(value); /* for the case of crippled infinities */
01435 
01436     if (ddAbs(value) < unique->epsilon) {
01437         value = 0.0;
01438     }
01439     split.value = value;
01440 
01441     pos = ddHash(split.bits[0], split.bits[1], unique->constants.shift);
01442     nodelist = unique->constants.nodelist;
01443     looking = nodelist[pos];
01444 
01445     /* Here we compare values both for equality and for difference less
01446      * than epsilon. The first comparison is required when values are
01447      * infinite, since Infinity - Infinity is NaN and NaN < X is 0 for
01448      * every X.
01449      */
01450     while (looking != NULL) {
01451         if (looking->type.value == value ||
01452         ddEqualVal(looking->type.value,value,unique->epsilon)) {
01453             if (looking->ref == 0) {
01454                 cuddReclaim(unique,looking);
01455             }
01456             return(looking);
01457         }
01458         looking = looking->next;
01459 #ifdef DD_UNIQUE_PROFILE
01460         unique->uniqueLinks++;
01461 #endif
01462     }
01463 
01464     unique->keys++;
01465     unique->constants.keys++;
01466 
01467     looking = cuddAllocNode(unique);
01468     if (looking == NULL) return(NULL);
01469     looking->ref = 0;
01470     looking->index = CUDD_CONST_INDEX;
01471     looking->type.value = value;
01472     looking->next = nodelist[pos];
01473     nodelist[pos] = looking;
01474 
01475     return(looking);
01476 
01477 } /* end of cuddUniqueConst */

DdNode* cuddUniqueInter ( DdManager unique,
int  index,
DdNode T,
DdNode E 
)

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

Synopsis [Checks the unique table for the existence of an internal node.]

Description [Checks the unique table for the existence of an internal node. If it does not exist, it creates a new one. Does not modify the reference count of whatever is returned. A newly created internal node comes back with a reference count 0. For a newly created node, increments the reference counts of what T and E point to. Returns a pointer to the new node if successful; NULL if memory is exhausted or if reordering took place.]

SideEffects [None]

SeeAlso [cuddUniqueInterZdd]

Definition at line 1090 of file cuddTable.c.

01095 {
01096     int pos;
01097     unsigned int level;
01098     int retval;
01099     DdNodePtr *nodelist;
01100     DdNode *looking;
01101     DdNodePtr *previousP;
01102     DdSubtable *subtable;
01103     int gcNumber;
01104 
01105 #ifdef DD_UNIQUE_PROFILE
01106     unique->uniqueLookUps++;
01107 #endif
01108 
01109     if (index >= unique->size) {
01110         if (!ddResizeTable(unique,index)) return(NULL);
01111     }
01112 
01113     level = unique->perm[index];
01114     subtable = &(unique->subtables[level]);
01115 
01116 #ifdef DD_DEBUG
01117     assert(level < (unsigned) cuddI(unique,T->index));
01118     assert(level < (unsigned) cuddI(unique,Cudd_Regular(E)->index));
01119 #endif
01120 
01121     pos = ddHash(T, E, subtable->shift);
01122     nodelist = subtable->nodelist;
01123     previousP = &(nodelist[pos]);
01124     looking = *previousP;
01125 
01126     while (T < cuddT(looking)) {
01127         previousP = &(looking->next);
01128         looking = *previousP;
01129 #ifdef DD_UNIQUE_PROFILE
01130         unique->uniqueLinks++;
01131 #endif
01132     }
01133     while (T == cuddT(looking) && E < cuddE(looking)) {
01134         previousP = &(looking->next);
01135         looking = *previousP;
01136 #ifdef DD_UNIQUE_PROFILE
01137         unique->uniqueLinks++;
01138 #endif
01139     }
01140     if (T == cuddT(looking) && E == cuddE(looking)) {
01141         if (looking->ref == 0) {
01142             cuddReclaim(unique,looking);
01143         }
01144         return(looking);
01145     }
01146 
01147     /* countDead is 0 if deads should be counted and ~0 if they should not. */
01148     if (unique->autoDyn &&
01149     unique->keys - (unique->dead & unique->countDead) >= unique->nextDyn) {
01150 #ifdef DD_DEBUG
01151         retval = Cudd_DebugCheck(unique);
01152         if (retval != 0) return(NULL);
01153         retval = Cudd_CheckKeys(unique);
01154         if (retval != 0) return(NULL);
01155 #endif
01156         retval = Cudd_ReduceHeap(unique,unique->autoMethod,10); /* 10 = whatever */
01157         if (retval == 0) unique->reordered = 2;
01158 #ifdef DD_DEBUG
01159         retval = Cudd_DebugCheck(unique);
01160         if (retval != 0) unique->reordered = 2;
01161         retval = Cudd_CheckKeys(unique);
01162         if (retval != 0) unique->reordered = 2;
01163 #endif
01164         return(NULL);
01165     }
01166 
01167     if (subtable->keys > subtable->maxKeys) {
01168         if (unique->gcEnabled &&
01169             ((unique->dead > unique->minDead) ||
01170             ((unique->dead > unique->minDead / 2) &&
01171             (subtable->dead > subtable->keys * 0.95)))) { /* too many dead */
01172             (void) cuddGarbageCollect(unique,1);
01173         } else {
01174             cuddRehash(unique,(int)level);
01175         }
01176         /* Update pointer to insertion point. In the case of rehashing,
01177         ** the slot may have changed. In the case of garbage collection,
01178         ** the predecessor may have been dead. */
01179         pos = ddHash(T, E, subtable->shift);
01180         nodelist = subtable->nodelist;
01181         previousP = &(nodelist[pos]);
01182         looking = *previousP;
01183 
01184         while (T < cuddT(looking)) {
01185             previousP = &(looking->next);
01186             looking = *previousP;
01187 #ifdef DD_UNIQUE_PROFILE
01188             unique->uniqueLinks++;
01189 #endif
01190         }
01191         while (T == cuddT(looking) && E < cuddE(looking)) {
01192             previousP = &(looking->next);
01193             looking = *previousP;
01194 #ifdef DD_UNIQUE_PROFILE
01195             unique->uniqueLinks++;
01196 #endif
01197         }
01198     }
01199 
01200     gcNumber = unique->garbageCollections;
01201     looking = cuddAllocNode(unique);
01202     if (looking == NULL) {
01203         return(NULL);
01204     }
01205     unique->keys++;
01206     subtable->keys++;
01207 
01208     if (gcNumber != unique->garbageCollections) {
01209         DdNode *looking2;
01210         pos = ddHash(T, E, subtable->shift);
01211         nodelist = subtable->nodelist;
01212         previousP = &(nodelist[pos]);
01213         looking2 = *previousP;
01214 
01215         while (T < cuddT(looking2)) {
01216             previousP = &(looking2->next);
01217             looking2 = *previousP;
01218 #ifdef DD_UNIQUE_PROFILE
01219             unique->uniqueLinks++;
01220 #endif
01221         }
01222         while (T == cuddT(looking2) && E < cuddE(looking2)) {
01223             previousP = &(looking2->next);
01224             looking2 = *previousP;
01225 #ifdef DD_UNIQUE_PROFILE
01226             unique->uniqueLinks++;
01227 #endif
01228         }
01229     }
01230     looking->ref = 0;
01231     looking->index = index;
01232     cuddT(looking) = T;
01233     cuddE(looking) = E;
01234     looking->next = *previousP;
01235     *previousP = looking;
01236     cuddSatInc(T->ref);         /* we know T is a regular pointer */
01237     cuddRef(E);
01238 
01239 #ifdef DD_DEBUG
01240     cuddCheckCollisionOrdering(unique,level,pos);
01241 #endif
01242 
01243     return(looking);
01244 
01245 } /* end of cuddUniqueInter */

DdNode* cuddUniqueInterIVO ( DdManager unique,
int  index,
DdNode T,
DdNode E 
)

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

Synopsis [Wrapper for cuddUniqueInter that is independent of variable ordering.]

Description [Wrapper for cuddUniqueInter that is independent of variable ordering (IVO). This function does not require parameter index to precede the indices of the top nodes of T and E in the variable order. Returns a pointer to the result node under normal conditions; NULL if reordering occurred or memory was exhausted.]

SideEffects [None]

SeeAlso [cuddUniqueInter Cudd_MakeBddFromZddCover]

Definition at line 1265 of file cuddTable.c.

01270 {
01271     DdNode *result;
01272     DdNode *v;
01273 
01274     v = cuddUniqueInter(unique, index, DD_ONE(unique),
01275                         Cudd_Not(DD_ONE(unique)));
01276     if (v == NULL)
01277         return(NULL);
01278     cuddRef(v);
01279     result = cuddBddIteRecur(unique, v, T, E);
01280     Cudd_RecursiveDeref(unique, v);
01281     return(result);
01282 }

DdNode* cuddUniqueInterZdd ( DdManager unique,
int  index,
DdNode T,
DdNode E 
)

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

Synopsis [Checks the unique table for the existence of an internal ZDD node.]

Description [Checks the unique table for the existence of an internal ZDD node. If it does not exist, it creates a new one. Does not modify the reference count of whatever is returned. A newly created internal node comes back with a reference count 0. For a newly created node, increments the reference counts of what T and E point to. Returns a pointer to the new node if successful; NULL if memory is exhausted or if reordering took place.]

SideEffects [None]

SeeAlso [cuddUniqueInter]

Definition at line 1304 of file cuddTable.c.

01309 {
01310     int pos;
01311     unsigned int level;
01312     int retval;
01313     DdNodePtr *nodelist;
01314     DdNode *looking;
01315     DdSubtable *subtable;
01316 
01317 #ifdef DD_UNIQUE_PROFILE
01318     unique->uniqueLookUps++;
01319 #endif
01320 
01321     if (index >= unique->sizeZ) {
01322         if (!cuddResizeTableZdd(unique,index)) return(NULL);
01323     }
01324 
01325     level = unique->permZ[index];
01326     subtable = &(unique->subtableZ[level]);
01327 
01328 #ifdef DD_DEBUG
01329     assert(level < (unsigned) cuddIZ(unique,T->index));
01330     assert(level < (unsigned) cuddIZ(unique,Cudd_Regular(E)->index));
01331 #endif
01332 
01333     if (subtable->keys > subtable->maxKeys) {
01334         if (unique->gcEnabled && ((unique->deadZ > unique->minDead) ||
01335         (10 * subtable->dead > 9 * subtable->keys))) {  /* too many dead */
01336             (void) cuddGarbageCollectZdd(unique,1);
01337         } else {
01338             ddRehashZdd(unique,(int)level);
01339         }
01340     }
01341 
01342     pos = ddHash(T, E, subtable->shift);
01343     nodelist = subtable->nodelist;
01344     looking = nodelist[pos];
01345 
01346     while (looking != NULL) {
01347         if (cuddT(looking) == T && cuddE(looking) == E) {
01348             if (looking->ref == 0) {
01349                 cuddReclaimZdd(unique,looking);
01350             }
01351             return(looking);
01352         }
01353         looking = looking->next;
01354 #ifdef DD_UNIQUE_PROFILE
01355         unique->uniqueLinks++;
01356 #endif
01357     }
01358 
01359     /* countDead is 0 if deads should be counted and ~0 if they should not. */
01360     if (unique->autoDynZ &&
01361     unique->keysZ - (unique->deadZ & unique->countDead) >= unique->nextDyn) {
01362 #ifdef DD_DEBUG
01363         retval = Cudd_DebugCheck(unique);
01364         if (retval != 0) return(NULL);
01365         retval = Cudd_CheckKeys(unique);
01366         if (retval != 0) return(NULL);
01367 #endif
01368         retval = Cudd_zddReduceHeap(unique,unique->autoMethodZ,10); /* 10 = whatever */
01369         if (retval == 0) unique->reordered = 2;
01370 #ifdef DD_DEBUG
01371         retval = Cudd_DebugCheck(unique);
01372         if (retval != 0) unique->reordered = 2;
01373         retval = Cudd_CheckKeys(unique);
01374         if (retval != 0) unique->reordered = 2;
01375 #endif
01376         return(NULL);
01377     }
01378 
01379     unique->keysZ++;
01380     subtable->keys++;
01381 
01382     looking = cuddAllocNode(unique);
01383     if (looking == NULL) return(NULL);
01384     looking->ref = 0;
01385     looking->index = index;
01386     cuddT(looking) = T;
01387     cuddE(looking) = E;
01388     looking->next = nodelist[pos];
01389     nodelist[pos] = looking;
01390     cuddRef(T);
01391     cuddRef(E);
01392 
01393     return(looking);
01394 
01395 } /* end of cuddUniqueInterZdd */

DdNode* cuddZddGetNode ( DdManager zdd,
int  id,
DdNode T,
DdNode E 
)

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

Synopsis [Wrapper for cuddUniqueInterZdd.]

Description [Wrapper for cuddUniqueInterZdd, which applies the ZDD reduction rule. Returns a pointer to the result node under normal conditions; NULL if reordering occurred or memory was exhausted.]

SideEffects [None]

SeeAlso [cuddUniqueInterZdd]

Definition at line 1003 of file cuddTable.c.

01008 {
01009     DdNode      *node;
01010 
01011     if (T == DD_ZERO(zdd))
01012         return(E);
01013     node = cuddUniqueInterZdd(zdd, id, T, E);
01014     return(node);
01015 
01016 } /* end of cuddZddGetNode */

DdNode* cuddZddGetNodeIVO ( DdManager dd,
int  index,
DdNode g,
DdNode h 
)

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

Synopsis [Wrapper for cuddUniqueInterZdd that is independent of variable ordering.]

Description [Wrapper for cuddUniqueInterZdd that is independent of variable ordering (IVO). This function does not require parameter index to precede the indices of the top nodes of g and h in the variable order. Returns a pointer to the result node under normal conditions; NULL if reordering occurred or memory was exhausted.]

SideEffects [None]

SeeAlso [cuddZddGetNode cuddZddIsop]

Definition at line 1036 of file cuddTable.c.

01041 {
01042     DdNode      *f, *r, *t;
01043     DdNode      *zdd_one = DD_ONE(dd);
01044     DdNode      *zdd_zero = DD_ZERO(dd);
01045 
01046     f = cuddUniqueInterZdd(dd, index, zdd_one, zdd_zero);
01047     if (f == NULL) {
01048         return(NULL);
01049     }
01050     cuddRef(f);
01051     t = cuddZddProduct(dd, f, g);
01052     if (t == NULL) {
01053         Cudd_RecursiveDerefZdd(dd, f);
01054         return(NULL);
01055     }
01056     cuddRef(t);
01057     Cudd_RecursiveDerefZdd(dd, f);
01058     r = cuddZddUnion(dd, t, h);
01059     if (r == NULL) {
01060         Cudd_RecursiveDerefZdd(dd, t);
01061         return(NULL);
01062     }
01063     cuddRef(r);
01064     Cudd_RecursiveDerefZdd(dd, t);
01065 
01066     cuddDeref(r);
01067     return(r);
01068 
01069 } /* end of cuddZddGetNodeIVO */

static DD_INLINE void ddFixLimits ( DdManager unique  )  [static]

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

Synopsis [Adjusts the values of table limits.]

Description [Adjusts the values of table fields controlling the. sizes of subtables and computed table. If the computed table is too small according to the new values, it is resized.]

SideEffects [Modifies manager fields. May resize computed table.]

SeeAlso []

Definition at line 2773 of file cuddTable.c.

02775 {
02776     unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
02777     unique->cacheSlack = (int) ddMin(unique->maxCacheHard,
02778         DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots) -
02779         2 * (int) unique->cacheSlots;
02780     if (unique->cacheSlots < unique->slots/2 && unique->cacheSlack >= 0)
02781         cuddCacheResize(unique);
02782     return;
02783 
02784 } /* end of ddFixLimits */

static void ddPatchTree ( DdManager dd,
MtrNode treenode 
) [static]

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

Synopsis [Fixes a variable tree after the insertion of new subtables.]

Description [Fixes a variable tree after the insertion of new subtables. After such an insertion, the low fields of the tree below the insertion point are inconsistent.]

SideEffects [None]

SeeAlso []

Definition at line 3046 of file cuddTable.c.

03049 {
03050     MtrNode *auxnode = treenode;
03051 
03052     while (auxnode != NULL) {
03053         auxnode->low = dd->perm[auxnode->index];
03054         if (auxnode->child != NULL) {
03055             ddPatchTree(dd, auxnode->child);
03056         }
03057         auxnode = auxnode->younger;
03058     }
03059 
03060     return;
03061 
03062 } /* end of ddPatchTree */

static void ddRehashZdd ( DdManager unique,
int  i 
) [static]

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

Synopsis [Rehashes a ZDD unique subtable.]

Description []

SideEffects [None]

SeeAlso [cuddRehash]

Definition at line 2389 of file cuddTable.c.

02392 {
02393     unsigned int slots, oldslots;
02394     int shift, oldshift;
02395     int j, pos;
02396     DdNodePtr *nodelist, *oldnodelist;
02397     DdNode *node, *next;
02398     extern void (*MMoutOfMemory)(long);
02399     void (*saveHandler)(long);
02400 
02401     if (unique->slots > unique->looseUpTo) {
02402         unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
02403 #ifdef DD_VERBOSE
02404         if (unique->gcFrac == DD_GC_FRAC_HI) {
02405             (void) fprintf(unique->err,"GC fraction = %.2f\t",
02406                            DD_GC_FRAC_LO);
02407             (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
02408         }
02409 #endif
02410         unique->gcFrac = DD_GC_FRAC_LO;
02411     }
02412 
02413     assert(i != CUDD_MAXINDEX);
02414     oldslots = unique->subtableZ[i].slots;
02415     oldshift = unique->subtableZ[i].shift;
02416     oldnodelist = unique->subtableZ[i].nodelist;
02417 
02418     /* Compute the new size of the subtable. Normally, we just
02419     ** double.  However, after reordering, a table may be severely
02420     ** overloaded. Therefore, we iterate. */
02421     slots = oldslots;
02422     shift = oldshift;
02423     do {
02424         slots <<= 1;
02425         shift--;
02426     } while (slots * DD_MAX_SUBTABLE_DENSITY < unique->subtableZ[i].keys);
02427 
02428     saveHandler = MMoutOfMemory;
02429     MMoutOfMemory = Cudd_OutOfMem;
02430     nodelist = ALLOC(DdNodePtr, slots);
02431     MMoutOfMemory = saveHandler;
02432     if (nodelist == NULL) {
02433         int j;
02434         (void) fprintf(unique->err,
02435                        "Unable to resize ZDD subtable %d for lack of memory.\n",
02436                        i);
02437         (void) cuddGarbageCollectZdd(unique,1);
02438         for (j = 0; j < unique->sizeZ; j++) {
02439             unique->subtableZ[j].maxKeys <<= 1;
02440         }
02441         return;
02442     }
02443     unique->subtableZ[i].nodelist = nodelist;
02444     unique->subtableZ[i].slots = slots;
02445     unique->subtableZ[i].shift = shift;
02446     unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
02447     for (j = 0; (unsigned) j < slots; j++) {
02448         nodelist[j] = NULL;
02449     }
02450     for (j = 0; (unsigned) j < oldslots; j++) {
02451         node = oldnodelist[j];
02452         while (node != NULL) {
02453             next = node->next;
02454             pos = ddHash(cuddT(node), cuddE(node), shift);
02455             node->next = nodelist[pos];
02456             nodelist[pos] = node;
02457             node = next;
02458         }
02459     }
02460     FREE(oldnodelist);
02461 
02462 #ifdef DD_VERBOSE
02463     (void) fprintf(unique->err,
02464                    "rehashing layer %d: keys %d dead %d new size %d\n",
02465                    i, unique->subtableZ[i].keys,
02466                    unique->subtableZ[i].dead, slots);
02467 #endif
02468 
02469     /* Update global data. */
02470     unique->memused += (slots - oldslots) * sizeof(DdNode *);
02471     unique->slots += (slots - oldslots);
02472     ddFixLimits(unique);
02473 
02474 } /* end of ddRehashZdd */

static void ddReportRefMess ( DdManager unique,
int  i,
char *  caller 
) [static]

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

Synopsis [Reports problem in garbage collection.]

Description []

SideEffects [None]

SeeAlso [cuddGarbageCollect cuddGarbageCollectZdd]

Definition at line 3123 of file cuddTable.c.

03127 {
03128     if (i == CUDD_CONST_INDEX) {
03129         (void) fprintf(unique->err,
03130                            "%s: problem in constants\n", caller);
03131     } else if (i != -1) {
03132         (void) fprintf(unique->err,
03133                            "%s: problem in table %d\n", caller, i);
03134     }
03135     (void) fprintf(unique->err, "  dead count != deleted\n");
03136     (void) fprintf(unique->err, "  This problem is often due to a missing \
03137 call to Cudd_Ref\n  or to an extra call to Cudd_RecursiveDeref.\n  \
03138 See the CUDD Programmer's Guide for additional details.");
03139     abort();
03140 
03141 } /* end of ddReportRefMess */

static int ddResizeTable ( DdManager unique,
int  index 
) [static]

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

Synopsis [Increases the number of subtables in a unique table so that it meets or exceeds index.]

Description [Increases the number of subtables in a unique table so that it meets or exceeds index. Returns 1 if successful; 0 otherwise.]

SideEffects [None]

SeeAlso [cuddResizeTableZdd]

Definition at line 2491 of file cuddTable.c.

02494 {
02495     DdSubtable *newsubtables;
02496     DdNodePtr *newnodelist;
02497     DdNodePtr *newvars;
02498     DdNode *sentinel = &(unique->sentinel);
02499     int oldsize,newsize;
02500     int i,j,reorderSave;
02501     int numSlots = unique->initSlots;
02502     int *newperm, *newinvperm, *newmap;
02503     DdNode *one, *zero;
02504 
02505     oldsize = unique->size;
02506     /* Easy case: there is still room in the current table. */
02507     if (index < unique->maxSize) {
02508         for (i = oldsize; i <= index; i++) {
02509             unique->subtables[i].slots = numSlots;
02510             unique->subtables[i].shift = sizeof(int) * 8 -
02511                 cuddComputeFloorLog2(numSlots);
02512             unique->subtables[i].keys = 0;
02513             unique->subtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
02514             unique->subtables[i].dead = 0;
02515             unique->subtables[i].bindVar = 0;
02516             unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
02517             unique->subtables[i].pairIndex = 0;
02518             unique->subtables[i].varHandled = 0;
02519             unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
02520 
02521             unique->perm[i] = i;
02522             unique->invperm[i] = i;
02523             newnodelist = unique->subtables[i].nodelist =
02524                 ALLOC(DdNodePtr, numSlots);
02525             if (newnodelist == NULL) {
02526                 for (j = oldsize; j < i; j++) {
02527                     FREE(unique->subtables[j].nodelist);
02528                 }
02529                 unique->errorCode = CUDD_MEMORY_OUT;
02530                 return(0);
02531             }
02532             for (j = 0; j < numSlots; j++) {
02533                 newnodelist[j] = sentinel;
02534             }
02535         }
02536         if (unique->map != NULL) {
02537             for (i = oldsize; i <= index; i++) {
02538                 unique->map[i] = i;
02539             }
02540         }
02541     } else {
02542         /* The current table is too small: we need to allocate a new,
02543         ** larger one; move all old subtables, and initialize the new
02544         ** subtables up to index included.
02545         */
02546         newsize = index + DD_DEFAULT_RESIZE;
02547 #ifdef DD_VERBOSE
02548         (void) fprintf(unique->err,
02549                        "Increasing the table size from %d to %d\n",
02550                        unique->maxSize, newsize);
02551 #endif
02552         newsubtables = ALLOC(DdSubtable,newsize);
02553         if (newsubtables == NULL) {
02554             unique->errorCode = CUDD_MEMORY_OUT;
02555             return(0);
02556         }
02557         newvars = ALLOC(DdNodePtr,newsize);
02558         if (newvars == NULL) {
02559             FREE(newsubtables);
02560             unique->errorCode = CUDD_MEMORY_OUT;
02561             return(0);
02562         }
02563         newperm = ALLOC(int,newsize);
02564         if (newperm == NULL) {
02565             FREE(newsubtables);
02566             FREE(newvars);
02567             unique->errorCode = CUDD_MEMORY_OUT;
02568             return(0);
02569         }
02570         newinvperm = ALLOC(int,newsize);
02571         if (newinvperm == NULL) {
02572             FREE(newsubtables);
02573             FREE(newvars);
02574             FREE(newperm);
02575             unique->errorCode = CUDD_MEMORY_OUT;
02576             return(0);
02577         }
02578         if (unique->map != NULL) {
02579             newmap = ALLOC(int,newsize);
02580             if (newmap == NULL) {
02581                 FREE(newsubtables);
02582                 FREE(newvars);
02583                 FREE(newperm);
02584                 FREE(newinvperm);
02585                 unique->errorCode = CUDD_MEMORY_OUT;
02586                 return(0);
02587             }
02588             unique->memused += (newsize - unique->maxSize) * sizeof(int);
02589         }
02590         unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
02591             sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
02592         if (newsize > unique->maxSizeZ) {
02593             FREE(unique->stack);
02594             unique->stack = ALLOC(DdNodePtr,newsize + 1);
02595             if (unique->stack == NULL) {
02596                 FREE(newsubtables);
02597                 FREE(newvars);
02598                 FREE(newperm);
02599                 FREE(newinvperm);
02600                 if (unique->map != NULL) {
02601                     FREE(newmap);
02602                 }
02603                 unique->errorCode = CUDD_MEMORY_OUT;
02604                 return(0);
02605             }
02606             unique->stack[0] = NULL; /* to suppress harmless UMR */
02607             unique->memused +=
02608                 (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
02609                 * sizeof(DdNode *);
02610         }
02611         for (i = 0; i < oldsize; i++) {
02612             newsubtables[i].slots = unique->subtables[i].slots;
02613             newsubtables[i].shift = unique->subtables[i].shift;
02614             newsubtables[i].keys = unique->subtables[i].keys;
02615             newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
02616             newsubtables[i].dead = unique->subtables[i].dead;
02617             newsubtables[i].nodelist = unique->subtables[i].nodelist;
02618             newsubtables[i].bindVar = unique->subtables[i].bindVar;
02619             newsubtables[i].varType = unique->subtables[i].varType;
02620             newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
02621             newsubtables[i].varHandled = unique->subtables[i].varHandled;
02622             newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
02623 
02624             newvars[i] = unique->vars[i];
02625             newperm[i] = unique->perm[i];
02626             newinvperm[i] = unique->invperm[i];
02627         }
02628         for (i = oldsize; i <= index; i++) {
02629             newsubtables[i].slots = numSlots;
02630             newsubtables[i].shift = sizeof(int) * 8 -
02631                 cuddComputeFloorLog2(numSlots);
02632             newsubtables[i].keys = 0;
02633             newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
02634             newsubtables[i].dead = 0;
02635             newsubtables[i].bindVar = 0;
02636             newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
02637             newsubtables[i].pairIndex = 0;
02638             newsubtables[i].varHandled = 0;
02639             newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
02640 
02641             newperm[i] = i;
02642             newinvperm[i] = i;
02643             newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
02644             if (newnodelist == NULL) {
02645                 unique->errorCode = CUDD_MEMORY_OUT;
02646                 return(0);
02647             }
02648             for (j = 0; j < numSlots; j++) {
02649                 newnodelist[j] = sentinel;
02650             }
02651         }
02652         if (unique->map != NULL) {
02653             for (i = 0; i < oldsize; i++) {
02654                 newmap[i] = unique->map[i];
02655             }
02656             for (i = oldsize; i <= index; i++) {
02657                 newmap[i] = i;
02658             }
02659             FREE(unique->map);
02660             unique->map = newmap;
02661         }
02662         FREE(unique->subtables);
02663         unique->subtables = newsubtables;
02664         unique->maxSize = newsize;
02665         FREE(unique->vars);
02666         unique->vars = newvars;
02667         FREE(unique->perm);
02668         unique->perm = newperm;
02669         FREE(unique->invperm);
02670         unique->invperm = newinvperm;
02671     }
02672 
02673     /* Now that the table is in a coherent state, create the new
02674     ** projection functions. We need to temporarily disable reordering,
02675     ** because we cannot reorder without projection functions in place.
02676     **/
02677     one = unique->one;
02678     zero = Cudd_Not(one);
02679 
02680     unique->size = index + 1;
02681     unique->slots += (index + 1 - oldsize) * numSlots;
02682     ddFixLimits(unique);
02683 
02684     reorderSave = unique->autoDyn;
02685     unique->autoDyn = 0;
02686     for (i = oldsize; i <= index; i++) {
02687         unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
02688         if (unique->vars[i] == NULL) {
02689             unique->autoDyn = reorderSave;
02690             for (j = oldsize; j < i; j++) {
02691                 Cudd_IterDerefBdd(unique,unique->vars[j]);
02692                 cuddDeallocNode(unique,unique->vars[j]);
02693                 unique->vars[j] = NULL;
02694             }
02695             for (j = oldsize; j <= index; j++) {
02696                 FREE(unique->subtables[j].nodelist);
02697                 unique->subtables[j].nodelist = NULL;
02698             }
02699             unique->size = oldsize;
02700             unique->slots -= (index + 1 - oldsize) * numSlots;
02701             ddFixLimits(unique);
02702             return(0);
02703         }
02704         cuddRef(unique->vars[i]);
02705     }
02706     unique->autoDyn = reorderSave;
02707 
02708     return(1);
02709 
02710 } /* end of ddResizeTable */


Variable Documentation

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

Definition at line 94 of file cuddTable.c.


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