src/cuBdd/cuddTable.c File Reference

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

Go to the source code of this file.

Data Structures

union  hack

Functions

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 ddPatchTree (DdManager *dd, MtrNode *treenode)
static int cuddCheckCollisionOrdering (DdManager *unique, int i, int j)
static void ddReportRefMess (DdManager *unique, int i, const 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)
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)

Variables

static char rcsid[] DD_UNUSED = "$Id: cuddTable.c,v 1.122 2009/02/19 16:24:28 fabio Exp $"

Function Documentation

unsigned int Cudd_Prime ( unsigned int  p  ) 

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

Synopsis [Returns the next prime >= p.]

Description []

SideEffects [None]

Definition at line 184 of file cuddTable.c.

00186 {
00187     int i,pn;
00188 
00189     p--;
00190     do {
00191         p++;
00192         if (p&1) {
00193             pn = 1;
00194             i = 3;
00195             while ((unsigned) (i * i) <= p) {
00196                 if (p % i == 0) {
00197                     pn = 0;
00198                     break;
00199                 }
00200                 i += 2;
00201             }
00202         } else {
00203             pn = 0;
00204         }
00205     } while (!pn);
00206     return(p);
00207 
00208 } /* 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 231 of file cuddTable.c.

00233 {
00234     int i;
00235     DdNodePtr *mem;
00236     DdNode *list, *node;
00237     extern DD_OOMFP MMoutOfMemory;
00238     DD_OOMFP saveHandler;
00239 
00240     if (unique->nextFree == NULL) {     /* free list is empty */
00241         /* Check for exceeded limits. */
00242         if ((unique->keys - unique->dead) + (unique->keysZ - unique->deadZ) >
00243             unique->maxLive) {
00244             unique->errorCode = CUDD_TOO_MANY_NODES;
00245             return(NULL);
00246         }
00247         if (unique->stash == NULL || unique->memused > unique->maxmemhard) {
00248             (void) cuddGarbageCollect(unique,1);
00249             mem = NULL;
00250         }
00251         if (unique->nextFree == NULL) {
00252             if (unique->memused > unique->maxmemhard) {
00253                 unique->errorCode = CUDD_MAX_MEM_EXCEEDED;
00254                 return(NULL);
00255             }
00256             /* Try to allocate a new block. */
00257             saveHandler = MMoutOfMemory;
00258             MMoutOfMemory = Cudd_OutOfMem;
00259             mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
00260             MMoutOfMemory = saveHandler;
00261             if (mem == NULL) {
00262                 /* No more memory: Try collecting garbage. If this succeeds,
00263                 ** we end up with mem still NULL, but unique->nextFree !=
00264                 ** NULL. */
00265                 if (cuddGarbageCollect(unique,1) == 0) {
00266                     /* Last resort: Free the memory stashed away, if there
00267                     ** any. If this succeeeds, mem != NULL and
00268                     ** unique->nextFree still NULL. */
00269                     if (unique->stash != NULL) {
00270                         FREE(unique->stash);
00271                         unique->stash = NULL;
00272                         /* Inhibit resizing of tables. */
00273                         cuddSlowTableGrowth(unique);
00274                         /* Now try again. */
00275                         mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
00276                     }
00277                     if (mem == NULL) {
00278                         /* Out of luck. Call the default handler to do
00279                         ** whatever it specifies for a failed malloc.
00280                         ** If this handler returns, then set error code,
00281                         ** print warning, and return. */
00282                         (*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1));
00283                         unique->errorCode = CUDD_MEMORY_OUT;
00284 #ifdef DD_VERBOSE
00285                         (void) fprintf(unique->err,
00286                                        "cuddAllocNode: out of memory");
00287                         (void) fprintf(unique->err, "Memory in use = %lu\n",
00288                                        unique->memused);
00289 #endif
00290                         return(NULL);
00291                     }
00292                 }
00293             }
00294             if (mem != NULL) {  /* successful allocation; slice memory */
00295                 ptruint offset;
00296                 unique->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode);
00297                 mem[0] = (DdNodePtr) unique->memoryList;
00298                 unique->memoryList = mem;
00299 
00300                 /* Here we rely on the fact that a DdNode is as large
00301                 ** as 4 pointers.  */
00302                 offset = (ptruint) mem & (sizeof(DdNode) - 1);
00303                 mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
00304                 assert(((ptruint) mem & (sizeof(DdNode) - 1)) == 0);
00305                 list = (DdNode *) mem;
00306 
00307                 i = 1;
00308                 do {
00309                     list[i - 1].ref = 0;
00310                     list[i - 1].next = &list[i];
00311                 } while (++i < DD_MEM_CHUNK);
00312 
00313                 list[DD_MEM_CHUNK-1].ref = 0;
00314                 list[DD_MEM_CHUNK-1].next = NULL;
00315 
00316                 unique->nextFree = &list[0];
00317             }
00318         }
00319     }
00320     unique->allocated++;
00321     node = unique->nextFree;
00322     unique->nextFree = node->next;
00323     return(node);
00324 
00325 } /* end of cuddAllocNode */

static int cuddCheckCollisionOrdering ( DdManager unique,
int  i,
int  j 
) [static]

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

Synopsis [Checks whether a collision list is ordered.]

Description []

SideEffects [None]

SeeAlso []

Definition at line 3097 of file cuddTable.c.

03101 {
03102     int slots;
03103     DdNode *node, *next;
03104     DdNodePtr *nodelist;
03105     DdNode *sentinel = &(unique->sentinel);
03106 
03107     nodelist = unique->subtables[i].nodelist;
03108     slots = unique->subtables[i].slots;
03109     node = nodelist[j];
03110     if (node == sentinel) return(1);
03111     next = node->next;
03112     while (next != sentinel) {
03113         if (cuddT(node) < cuddT(next) ||
03114             (cuddT(node) == cuddT(next) && cuddE(node) < cuddE(next))) {
03115             (void) fprintf(unique->err,
03116                            "Unordered list: index %u, position %d\n", i, j);
03117             return(0);
03118         }
03119         node = next;
03120         next = node->next;
03121     }
03122     return(1);
03123 
03124 } /* end of cuddCheckCollisionOrdering */

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 2093 of file cuddTable.c.

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

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 2743 of file cuddTable.c.

02746 {
02747     int         i,j;
02748     int         slots;
02749     DdNodePtr   *nodelist;
02750     DdNode      *f;
02751 
02752     for (i = cuddI(table,node->index) - 1; i >= 0; i--) {
02753         nodelist = table->subtables[i].nodelist;
02754         slots = table->subtables[i].slots;
02755 
02756         for (j = 0; j < slots; j++) {
02757             f = nodelist[j];
02758             while (cuddT(f) > node) {
02759                 f = f->next;
02760             }
02761             while (cuddT(f) == node && Cudd_Regular(cuddE(f)) > node) {
02762                 f = f->next;
02763             }
02764             if (cuddT(f) == node && Cudd_Regular(cuddE(f)) == node) {
02765                 return(1);
02766             }
02767         }
02768     }
02769 
02770     return(0);
02771 
02772 } /* 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 649 of file cuddTable.c.

00651 {
00652     DdNodePtr *next;
00653     DdNodePtr *memlist = unique->memoryList;
00654     int i;
00655 
00656     if (unique->univ != NULL) cuddZddFreeUniv(unique);
00657     while (memlist != NULL) {
00658         next = (DdNodePtr *) memlist[0];        /* link to next block */
00659         FREE(memlist);
00660         memlist = next;
00661     }
00662     unique->nextFree = NULL;
00663     unique->memoryList = NULL;
00664 
00665     for (i = 0; i < unique->size; i++) {
00666         FREE(unique->subtables[i].nodelist);
00667     }
00668     for (i = 0; i < unique->sizeZ; i++) {
00669         FREE(unique->subtableZ[i].nodelist);
00670     }
00671     FREE(unique->constants.nodelist);
00672     FREE(unique->subtables);
00673     FREE(unique->subtableZ);
00674     FREE(unique->acache);
00675     FREE(unique->perm);
00676     FREE(unique->permZ);
00677     FREE(unique->invperm);
00678     FREE(unique->invpermZ);
00679     FREE(unique->vars);
00680     if (unique->map != NULL) FREE(unique->map);
00681     FREE(unique->stack);
00682 #ifndef DD_NO_DEATH_ROW
00683     FREE(unique->deathRow);
00684 #endif
00685     if (unique->tree != NULL) Mtr_FreeTree(unique->tree);
00686     if (unique->treeZ != NULL) Mtr_FreeTree(unique->treeZ);
00687     if (unique->linear != NULL) FREE(unique->linear);
00688     while (unique->preGCHook != NULL)
00689         Cudd_RemoveHook(unique,unique->preGCHook->f,CUDD_PRE_GC_HOOK);
00690     while (unique->postGCHook != NULL)
00691         Cudd_RemoveHook(unique,unique->postGCHook->f,CUDD_POST_GC_HOOK);
00692     while (unique->preReorderingHook != NULL)
00693         Cudd_RemoveHook(unique,unique->preReorderingHook->f,
00694                         CUDD_PRE_REORDERING_HOOK);
00695     while (unique->postReorderingHook != NULL)
00696         Cudd_RemoveHook(unique,unique->postReorderingHook->f,
00697                         CUDD_POST_REORDERING_HOOK);
00698     FREE(unique);
00699 
00700 } /* end of cuddFreeTable */

int cuddGarbageCollect ( DdManager unique,
int  clearCache 
)

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

Synopsis [Performs garbage collection on the unique tables.]

Description [Performs garbage collection on the BDD and ZDD unique tables. 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 []

Definition at line 719 of file cuddTable.c.

00722 {
00723     DdHook      *hook;
00724     DdCache     *cache = unique->cache;
00725     DdNode      *sentinel = &(unique->sentinel);
00726     DdNodePtr   *nodelist;
00727     int         i, j, deleted, totalDeleted, totalDeletedZ;
00728     DdCache     *c;
00729     DdNode      *node,*next;
00730     DdNodePtr   *lastP;
00731     int         slots;
00732     long        localTime;
00733 #ifndef DD_UNSORTED_FREE_LIST
00734 #ifdef DD_RED_BLACK_FREE_LIST
00735     DdNodePtr   tree;
00736 #else
00737     DdNodePtr *memListTrav, *nxtNode;
00738     DdNode *downTrav, *sentry;
00739     int k;
00740 #endif
00741 #endif
00742 
00743 #ifndef DD_NO_DEATH_ROW
00744     cuddClearDeathRow(unique);
00745 #endif
00746 
00747     hook = unique->preGCHook;
00748     while (hook != NULL) {
00749         int res = (hook->f)(unique,"DD",NULL);
00750         if (res == 0) return(0);
00751         hook = hook->next;
00752     }
00753 
00754     if (unique->dead + unique->deadZ == 0) {
00755         hook = unique->postGCHook;
00756         while (hook != NULL) {
00757             int res = (hook->f)(unique,"DD",NULL);
00758             if (res == 0) return(0);
00759             hook = hook->next;
00760         }
00761         return(0);
00762     }
00763 
00764     /* If many nodes are being reclaimed, we want to resize the tables
00765     ** more aggressively, to reduce the frequency of garbage collection.
00766     */
00767     if (clearCache && unique->gcFrac == DD_GC_FRAC_LO &&
00768         unique->slots <= unique->looseUpTo && unique->stash != NULL) {
00769         unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
00770 #ifdef DD_VERBOSE
00771         (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_HI);
00772         (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
00773 #endif
00774         unique->gcFrac = DD_GC_FRAC_HI;
00775         return(0);
00776     }
00777 
00778     localTime = util_cpu_time();
00779 
00780     unique->garbageCollections++;
00781 #ifdef DD_VERBOSE
00782     (void) fprintf(unique->err,
00783                    "garbage collecting (%d dead BDD nodes out of %d, min %d)...",
00784                    unique->dead, unique->keys, unique->minDead);
00785     (void) fprintf(unique->err,
00786                    "                   (%d dead ZDD nodes out of %d)...",
00787                    unique->deadZ, unique->keysZ);
00788 #endif
00789 
00790     /* Remove references to garbage collected nodes from the cache. */
00791     if (clearCache) {
00792         slots = unique->cacheSlots;
00793         for (i = 0; i < slots; i++) {
00794             c = &cache[i];
00795             if (c->data != NULL) {
00796                 if (cuddClean(c->f)->ref == 0 ||
00797                 cuddClean(c->g)->ref == 0 ||
00798                 (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) ||
00799                 (c->data != DD_NON_CONSTANT &&
00800                 Cudd_Regular(c->data)->ref == 0)) {
00801                     c->data = NULL;
00802                     unique->cachedeletions++;
00803                 }
00804             }
00805         }
00806         cuddLocalCacheClearDead(unique);
00807     }
00808 
00809     /* Now return dead nodes to free list. Count them for sanity check. */
00810     totalDeleted = 0;
00811 #ifndef DD_UNSORTED_FREE_LIST
00812 #ifdef DD_RED_BLACK_FREE_LIST
00813     tree = NULL;
00814 #endif
00815 #endif
00816 
00817     for (i = 0; i < unique->size; i++) {
00818         if (unique->subtables[i].dead == 0) continue;
00819         nodelist = unique->subtables[i].nodelist;
00820 
00821         deleted = 0;
00822         slots = unique->subtables[i].slots;
00823         for (j = 0; j < slots; j++) {
00824             lastP = &(nodelist[j]);
00825             node = *lastP;
00826             while (node != sentinel) {
00827                 next = node->next;
00828                 if (node->ref == 0) {
00829                     deleted++;
00830 #ifndef DD_UNSORTED_FREE_LIST
00831 #ifdef DD_RED_BLACK_FREE_LIST
00832 #ifdef __osf__
00833 #pragma pointer_size save
00834 #pragma pointer_size short
00835 #endif
00836                     cuddOrderedInsert(&tree,node);
00837 #ifdef __osf__
00838 #pragma pointer_size restore
00839 #endif
00840 #endif
00841 #else
00842                     cuddDeallocNode(unique,node);
00843 #endif
00844                 } else {
00845                     *lastP = node;
00846                     lastP = &(node->next);
00847                 }
00848                 node = next;
00849             }
00850             *lastP = sentinel;
00851         }
00852         if ((unsigned) deleted != unique->subtables[i].dead) {
00853             ddReportRefMess(unique, i, "cuddGarbageCollect");
00854         }
00855         totalDeleted += deleted;
00856         unique->subtables[i].keys -= deleted;
00857         unique->subtables[i].dead = 0;
00858     }
00859     if (unique->constants.dead != 0) {
00860         nodelist = unique->constants.nodelist;
00861         deleted = 0;
00862         slots = unique->constants.slots;
00863         for (j = 0; j < slots; j++) {
00864             lastP = &(nodelist[j]);
00865             node = *lastP;
00866             while (node != NULL) {
00867                 next = node->next;
00868                 if (node->ref == 0) {
00869                     deleted++;
00870 #ifndef DD_UNSORTED_FREE_LIST
00871 #ifdef DD_RED_BLACK_FREE_LIST
00872 #ifdef __osf__
00873 #pragma pointer_size save
00874 #pragma pointer_size short
00875 #endif
00876                     cuddOrderedInsert(&tree,node);
00877 #ifdef __osf__
00878 #pragma pointer_size restore
00879 #endif
00880 #endif
00881 #else
00882                     cuddDeallocNode(unique,node);
00883 #endif
00884                 } else {
00885                     *lastP = node;
00886                     lastP = &(node->next);
00887                 }
00888                 node = next;
00889             }
00890             *lastP = NULL;
00891         }
00892         if ((unsigned) deleted != unique->constants.dead) {
00893             ddReportRefMess(unique, CUDD_CONST_INDEX, "cuddGarbageCollect");
00894         }
00895         totalDeleted += deleted;
00896         unique->constants.keys -= deleted;
00897         unique->constants.dead = 0;
00898     }
00899     if ((unsigned) totalDeleted != unique->dead) {
00900         ddReportRefMess(unique, -1, "cuddGarbageCollect");
00901     }
00902     unique->keys -= totalDeleted;
00903     unique->dead = 0;
00904 #ifdef DD_STATS
00905     unique->nodesFreed += (double) totalDeleted;
00906 #endif
00907 
00908     totalDeletedZ = 0;
00909 
00910     for (i = 0; i < unique->sizeZ; i++) {
00911         if (unique->subtableZ[i].dead == 0) continue;
00912         nodelist = unique->subtableZ[i].nodelist;
00913 
00914         deleted = 0;
00915         slots = unique->subtableZ[i].slots;
00916         for (j = 0; j < slots; j++) {
00917             lastP = &(nodelist[j]);
00918             node = *lastP;
00919             while (node != NULL) {
00920                 next = node->next;
00921                 if (node->ref == 0) {
00922                     deleted++;
00923 #ifndef DD_UNSORTED_FREE_LIST
00924 #ifdef DD_RED_BLACK_FREE_LIST
00925 #ifdef __osf__
00926 #pragma pointer_size save
00927 #pragma pointer_size short
00928 #endif
00929                     cuddOrderedInsert(&tree,node);
00930 #ifdef __osf__
00931 #pragma pointer_size restore
00932 #endif
00933 #endif
00934 #else
00935                     cuddDeallocNode(unique,node);
00936 #endif
00937                 } else {
00938                     *lastP = node;
00939                     lastP = &(node->next);
00940                 }
00941                 node = next;
00942             }
00943             *lastP = NULL;
00944         }
00945         if ((unsigned) deleted != unique->subtableZ[i].dead) {
00946             ddReportRefMess(unique, i, "cuddGarbageCollect");
00947         }
00948         totalDeletedZ += deleted;
00949         unique->subtableZ[i].keys -= deleted;
00950         unique->subtableZ[i].dead = 0;
00951     }
00952 
00953     /* No need to examine the constant table for ZDDs.
00954     ** If we did we should be careful not to count whatever dead
00955     ** nodes we found there among the dead ZDD nodes. */
00956     if ((unsigned) totalDeletedZ != unique->deadZ) {
00957         ddReportRefMess(unique, -1, "cuddGarbageCollect");
00958     }
00959     unique->keysZ -= totalDeletedZ;
00960     unique->deadZ = 0;
00961 #ifdef DD_STATS
00962     unique->nodesFreed += (double) totalDeletedZ;
00963 #endif
00964 
00965 
00966 #ifndef DD_UNSORTED_FREE_LIST
00967 #ifdef DD_RED_BLACK_FREE_LIST
00968     unique->nextFree = cuddOrderedThread(tree,unique->nextFree);
00969 #else
00970     memListTrav = unique->memoryList;
00971     sentry = NULL;
00972     while (memListTrav != NULL) {
00973         ptruint offset;
00974         nxtNode = (DdNodePtr *)memListTrav[0];
00975         offset = (ptruint) memListTrav & (sizeof(DdNode) - 1);
00976         memListTrav += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
00977         downTrav = (DdNode *)memListTrav;
00978         k = 0;
00979         do {
00980             if (downTrav[k].ref == 0) {
00981                 if (sentry == NULL) {
00982                     unique->nextFree = sentry = &downTrav[k];
00983                 } else {
00984                     /* First hook sentry->next to the dead node and then
00985                     ** reassign sentry to the dead node. */
00986                     sentry = (sentry->next = &downTrav[k]);
00987                 }
00988             }
00989         } while (++k < DD_MEM_CHUNK);
00990         memListTrav = nxtNode;
00991     }
00992     sentry->next = NULL;
00993 #endif
00994 #endif
00995 
00996     unique->GCTime += util_cpu_time() - localTime;
00997 
00998     hook = unique->postGCHook;
00999     while (hook != NULL) {
01000         int res = (hook->f)(unique,"DD",NULL);
01001         if (res == 0) return(0);
01002         hook = hook->next;
01003     }
01004 
01005 #ifdef DD_VERBOSE
01006     (void) fprintf(unique->err," done\n");
01007 #endif
01008 
01009     return(totalDeleted+totalDeletedZ);
01010 
01011 } /* end of cuddGarbageCollect */

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 341 of file cuddTable.c.

00346 {
00347     DdManager   *unique = ALLOC(DdManager,1);
00348     int         i, j;
00349     DdNodePtr   *nodelist;
00350     DdNode      *sentinel;
00351     unsigned int slots;
00352     int shift;
00353 
00354     if (unique == NULL) {
00355         return(NULL);
00356     }
00357     sentinel = &(unique->sentinel);
00358     sentinel->ref = 0;
00359     sentinel->index = 0;
00360     cuddT(sentinel) = NULL;
00361     cuddE(sentinel) = NULL;
00362     sentinel->next = NULL;
00363     unique->epsilon = DD_EPSILON;
00364     unique->maxGrowth = DD_MAX_REORDER_GROWTH;
00365     unique->maxGrowthAlt = 2.0 * DD_MAX_REORDER_GROWTH;
00366     unique->reordCycle = 0;     /* do not use alternate threshold */
00367     unique->size = numVars;
00368     unique->sizeZ = numVarsZ;
00369     unique->maxSize = ddMax(DD_DEFAULT_RESIZE, numVars);
00370     unique->maxSizeZ = ddMax(DD_DEFAULT_RESIZE, numVarsZ);
00371 
00372     /* Adjust the requested number of slots to a power of 2. */
00373     slots = 8;
00374     while (slots < numSlots) {
00375         slots <<= 1;
00376     }
00377     unique->initSlots = slots;
00378     shift = sizeof(int) * 8 - cuddComputeFloorLog2(slots);
00379 
00380     unique->slots = (numVars + numVarsZ + 1) * slots;
00381     unique->keys = 0;
00382     unique->maxLive = ~0;       /* very large number */
00383     unique->keysZ = 0;
00384     unique->dead = 0;
00385     unique->deadZ = 0;
00386     unique->gcFrac = DD_GC_FRAC_HI;
00387     unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
00388     unique->looseUpTo = looseUpTo;
00389     unique->gcEnabled = 1;
00390     unique->allocated = 0;
00391     unique->reclaimed = 0;
00392     unique->subtables = ALLOC(DdSubtable,unique->maxSize);
00393     if (unique->subtables == NULL) {
00394         FREE(unique);
00395         return(NULL);
00396     }
00397     unique->subtableZ = ALLOC(DdSubtable,unique->maxSizeZ);
00398     if (unique->subtableZ == NULL) {
00399         FREE(unique->subtables);
00400         FREE(unique);
00401         return(NULL);
00402     }
00403     unique->perm = ALLOC(int,unique->maxSize);
00404     if (unique->perm == NULL) {
00405         FREE(unique->subtables);
00406         FREE(unique->subtableZ);
00407         FREE(unique);
00408         return(NULL);
00409     }
00410     unique->invperm = ALLOC(int,unique->maxSize);
00411     if (unique->invperm == NULL) {
00412         FREE(unique->subtables);
00413         FREE(unique->subtableZ);
00414         FREE(unique->perm);
00415         FREE(unique);
00416         return(NULL);
00417     }
00418     unique->permZ = ALLOC(int,unique->maxSizeZ);
00419     if (unique->permZ == NULL) {
00420         FREE(unique->subtables);
00421         FREE(unique->subtableZ);
00422         FREE(unique->perm);
00423         FREE(unique->invperm);
00424         FREE(unique);
00425         return(NULL);
00426     }
00427     unique->invpermZ = ALLOC(int,unique->maxSizeZ);
00428     if (unique->invpermZ == NULL) {
00429         FREE(unique->subtables);
00430         FREE(unique->subtableZ);
00431         FREE(unique->perm);
00432         FREE(unique->invperm);
00433         FREE(unique->permZ);
00434         FREE(unique);
00435         return(NULL);
00436     }
00437     unique->map = NULL;
00438     unique->stack = ALLOC(DdNodePtr,ddMax(unique->maxSize,unique->maxSizeZ)+1);
00439     if (unique->stack == NULL) {
00440         FREE(unique->subtables);
00441         FREE(unique->subtableZ);
00442         FREE(unique->perm);
00443         FREE(unique->invperm);
00444         FREE(unique->permZ);
00445         FREE(unique->invpermZ);
00446         FREE(unique);
00447         return(NULL);
00448     }
00449     unique->stack[0] = NULL; /* to suppress harmless UMR */
00450 
00451 #ifndef DD_NO_DEATH_ROW
00452     unique->deathRowDepth = 1 << cuddComputeFloorLog2(unique->looseUpTo >> 2);
00453     unique->deathRow = ALLOC(DdNodePtr,unique->deathRowDepth);
00454     if (unique->deathRow == NULL) {
00455         FREE(unique->subtables);
00456         FREE(unique->subtableZ);
00457         FREE(unique->perm);
00458         FREE(unique->invperm);
00459         FREE(unique->permZ);
00460         FREE(unique->invpermZ);
00461         FREE(unique->stack);
00462         FREE(unique);
00463         return(NULL);
00464     }
00465     for (i = 0; i < unique->deathRowDepth; i++) {
00466         unique->deathRow[i] = NULL;
00467     }
00468     unique->nextDead = 0;
00469     unique->deadMask = unique->deathRowDepth - 1;
00470 #endif
00471 
00472     for (i = 0; (unsigned) i < numVars; i++) {
00473         unique->subtables[i].slots = slots;
00474         unique->subtables[i].shift = shift;
00475         unique->subtables[i].keys = 0;
00476         unique->subtables[i].dead = 0;
00477         unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
00478         unique->subtables[i].bindVar = 0;
00479         unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
00480         unique->subtables[i].pairIndex = 0;
00481         unique->subtables[i].varHandled = 0;
00482         unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
00483 
00484         nodelist = unique->subtables[i].nodelist = ALLOC(DdNodePtr,slots);
00485         if (nodelist == NULL) {
00486             for (j = 0; j < i; j++) {
00487                 FREE(unique->subtables[j].nodelist);
00488             }
00489             FREE(unique->subtables);
00490             FREE(unique->subtableZ);
00491             FREE(unique->perm);
00492             FREE(unique->invperm);
00493             FREE(unique->permZ);
00494             FREE(unique->invpermZ);
00495             FREE(unique->stack);
00496             FREE(unique);
00497             return(NULL);
00498         }
00499         for (j = 0; (unsigned) j < slots; j++) {
00500             nodelist[j] = sentinel;
00501         }
00502         unique->perm[i] = i;
00503         unique->invperm[i] = i;
00504     }
00505     for (i = 0; (unsigned) i < numVarsZ; i++) {
00506         unique->subtableZ[i].slots = slots;
00507         unique->subtableZ[i].shift = shift;
00508         unique->subtableZ[i].keys = 0;
00509         unique->subtableZ[i].dead = 0;
00510         unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
00511         nodelist = unique->subtableZ[i].nodelist = ALLOC(DdNodePtr,slots);
00512         if (nodelist == NULL) {
00513             for (j = 0; (unsigned) j < numVars; j++) {
00514                 FREE(unique->subtables[j].nodelist);
00515             }
00516             FREE(unique->subtables);
00517             for (j = 0; j < i; j++) {
00518                 FREE(unique->subtableZ[j].nodelist);
00519             }
00520             FREE(unique->subtableZ);
00521             FREE(unique->perm);
00522             FREE(unique->invperm);
00523             FREE(unique->permZ);
00524             FREE(unique->invpermZ);
00525             FREE(unique->stack);
00526             FREE(unique);
00527             return(NULL);
00528         }
00529         for (j = 0; (unsigned) j < slots; j++) {
00530             nodelist[j] = NULL;
00531         }
00532         unique->permZ[i] = i;
00533         unique->invpermZ[i] = i;
00534     }
00535     unique->constants.slots = slots;
00536     unique->constants.shift = shift;
00537     unique->constants.keys = 0;
00538     unique->constants.dead = 0;
00539     unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
00540     nodelist = unique->constants.nodelist = ALLOC(DdNodePtr,slots);
00541     if (nodelist == NULL) {
00542         for (j = 0; (unsigned) j < numVars; j++) {
00543             FREE(unique->subtables[j].nodelist);
00544         }
00545         FREE(unique->subtables);
00546         for (j = 0; (unsigned) j < numVarsZ; j++) {
00547             FREE(unique->subtableZ[j].nodelist);
00548         }
00549         FREE(unique->subtableZ);
00550         FREE(unique->perm);
00551         FREE(unique->invperm);
00552         FREE(unique->permZ);
00553         FREE(unique->invpermZ);
00554         FREE(unique->stack);
00555         FREE(unique);
00556         return(NULL);
00557     }
00558     for (j = 0; (unsigned) j < slots; j++) {
00559         nodelist[j] = NULL;
00560     }
00561 
00562     unique->memoryList = NULL;
00563     unique->nextFree = NULL;
00564 
00565     unique->memused = sizeof(DdManager) + (unique->maxSize + unique->maxSizeZ)
00566         * (sizeof(DdSubtable) + 2 * sizeof(int)) + (numVars + 1) *
00567         slots * sizeof(DdNodePtr) +
00568         (ddMax(unique->maxSize,unique->maxSizeZ) + 1) * sizeof(DdNodePtr);
00569 #ifndef DD_NO_DEATH_ROW
00570     unique->memused += unique->deathRowDepth * sizeof(DdNodePtr);
00571 #endif
00572 
00573     /* Initialize fields concerned with automatic dynamic reordering */
00574     unique->reorderings = 0;
00575     unique->autoDyn = 0;        /* initially disabled */
00576     unique->autoDynZ = 0;       /* initially disabled */
00577     unique->realign = 0;        /* initially disabled */
00578     unique->realignZ = 0;       /* initially disabled */
00579     unique->reordered = 0;
00580     unique->autoMethod = CUDD_REORDER_SIFT;
00581     unique->autoMethodZ = CUDD_REORDER_SIFT;
00582     unique->nextDyn = DD_FIRST_REORDER;
00583     unique->countDead = ~0;
00584     unique->siftMaxVar = DD_SIFT_MAX_VAR;
00585     unique->siftMaxSwap = DD_SIFT_MAX_SWAPS;
00586     unique->tree = NULL;
00587     unique->treeZ = NULL;
00588     unique->groupcheck = CUDD_GROUP_CHECK7;
00589     unique->recomb = DD_DEFAULT_RECOMB;
00590     unique->symmviolation = 0;
00591     unique->arcviolation = 0;
00592     unique->populationSize = 0;
00593     unique->numberXovers = 0;
00594     unique->linear = NULL;
00595     unique->linearSize = 0;
00596 
00597     /* Initialize ZDD universe. */
00598     unique->univ = (DdNodePtr *)NULL;
00599 
00600     /* Initialize auxiliary fields. */
00601     unique->localCaches = NULL;
00602     unique->preGCHook = NULL;
00603     unique->postGCHook = NULL;
00604     unique->preReorderingHook = NULL;
00605     unique->postReorderingHook = NULL;
00606     unique->out = stdout;
00607     unique->err = stderr;
00608     unique->errorCode = CUDD_NO_ERROR;
00609 
00610     /* Initialize statistical counters. */
00611     unique->maxmemhard = ~ 0UL;
00612     unique->garbageCollections = 0;
00613     unique->GCTime = 0;
00614     unique->reordTime = 0;
00615 #ifdef DD_STATS
00616     unique->nodesDropped = 0;
00617     unique->nodesFreed = 0;
00618 #endif
00619     unique->peakLiveNodes = 0;
00620 #ifdef DD_UNIQUE_PROFILE
00621     unique->uniqueLookUps = 0;
00622     unique->uniqueLinks = 0;
00623 #endif
00624 #ifdef DD_COUNT
00625     unique->recursiveCalls = 0;
00626     unique->swapSteps = 0;
00627 #ifdef DD_STATS
00628     unique->nextSample = 250000;
00629 #endif
00630 #endif
00631 
00632     return(unique);
00633 
00634 } /* 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 1780 of file cuddTable.c.

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

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 1515 of file cuddTable.c.

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

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

void cuddShrinkSubtable ( DdManager unique,
int  i 
)

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

Synopsis [Shrinks a subtable.]

Description [Shrinks a subtable.]

SideEffects [None]

SeeAlso [cuddRehash]

Definition at line 1687 of file cuddTable.c.

01690 {
01691     int j;
01692     int shift, posn;
01693     DdNodePtr *nodelist, *oldnodelist;
01694     DdNode *node, *next;
01695     DdNode *sentinel = &(unique->sentinel);
01696     unsigned int slots, oldslots;
01697     extern DD_OOMFP MMoutOfMemory;
01698     DD_OOMFP saveHandler;
01699 
01700     oldnodelist = unique->subtables[i].nodelist;
01701     oldslots = unique->subtables[i].slots;
01702     slots = oldslots >> 1;
01703     saveHandler = MMoutOfMemory;
01704     MMoutOfMemory = Cudd_OutOfMem;
01705     nodelist = ALLOC(DdNodePtr, slots);
01706     MMoutOfMemory = saveHandler;
01707     if (nodelist == NULL) {
01708         return;
01709     }
01710     unique->subtables[i].nodelist = nodelist;
01711     unique->subtables[i].slots = slots;
01712     unique->subtables[i].shift++;
01713     unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
01714 #ifdef DD_VERBOSE
01715     (void) fprintf(unique->err,
01716                    "shrunk layer %d (%d keys) from %d to %d slots\n",
01717                    i, unique->subtables[i].keys, oldslots, slots);
01718 #endif
01719 
01720     for (j = 0; (unsigned) j < slots; j++) {
01721         nodelist[j] = sentinel;
01722     }
01723     shift = unique->subtables[i].shift;
01724     for (j = 0; (unsigned) j < oldslots; j++) {
01725         node = oldnodelist[j];
01726         while (node != sentinel) {
01727             DdNode *looking, *T, *E;
01728             DdNodePtr *previousP;
01729             next = node->next;
01730             posn = ddHash(cuddT(node), cuddE(node), shift);
01731             previousP = &(nodelist[posn]);
01732             looking = *previousP;
01733             T = cuddT(node);
01734             E = cuddE(node);
01735             while (T < cuddT(looking)) {
01736                 previousP = &(looking->next);
01737                 looking = *previousP;
01738 #ifdef DD_UNIQUE_PROFILE
01739                 unique->uniqueLinks++;
01740 #endif
01741             }
01742             while (T == cuddT(looking) && E < cuddE(looking)) {
01743                 previousP = &(looking->next);
01744                 looking = *previousP;
01745 #ifdef DD_UNIQUE_PROFILE
01746                 unique->uniqueLinks++;
01747 #endif
01748             }
01749             node->next = *previousP;
01750             *previousP = node;
01751             node = next;
01752         }
01753     }
01754     FREE(oldnodelist);
01755 
01756     unique->memused += ((long) slots - (long) oldslots) * sizeof(DdNode *);
01757     unique->slots += slots - oldslots;
01758     unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
01759     unique->cacheSlack = (int)
01760         ddMin(unique->maxCacheHard,DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots)
01761         - 2 * (int) unique->cacheSlots;
01762 
01763 } /* 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 2370 of file cuddTable.c.

02372 {
02373     int i;
02374 
02375     unique->maxCacheHard = unique->cacheSlots - 1;
02376     unique->cacheSlack = - (int) (unique->cacheSlots + 1);
02377     for (i = 0; i < unique->size; i++) {
02378         unique->subtables[i].maxKeys <<= 2;
02379     }
02380     unique->gcFrac = DD_GC_FRAC_MIN;
02381     unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
02382     cuddShrinkDeathRow(unique);
02383     (void) fprintf(unique->err,"Slowing down table growth: ");
02384     (void) fprintf(unique->err,"GC fraction = %.2f\t", unique->gcFrac);
02385     (void) fprintf(unique->err,"minDead = %u\n", unique->minDead);
02386 
02387 } /* 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 1435 of file cuddTable.c.

01438 {
01439     int pos;
01440     DdNodePtr *nodelist;
01441     DdNode *looking;
01442     hack split;
01443 
01444 #ifdef DD_UNIQUE_PROFILE
01445     unique->uniqueLookUps++;
01446 #endif
01447 
01448     if (unique->constants.keys > unique->constants.maxKeys) {
01449         if (unique->gcEnabled && ((unique->dead > unique->minDead) ||
01450         (10 * unique->constants.dead > 9 * unique->constants.keys))) {  /* too many dead */
01451             (void) cuddGarbageCollect(unique,1);
01452         } else {
01453             cuddRehash(unique,CUDD_CONST_INDEX);
01454         }
01455     }
01456 
01457     cuddAdjust(value); /* for the case of crippled infinities */
01458 
01459     if (ddAbs(value) < unique->epsilon) {
01460         value = 0.0;
01461     }
01462     split.value = value;
01463 
01464     pos = ddHash(split.bits[0], split.bits[1], unique->constants.shift);
01465     nodelist = unique->constants.nodelist;
01466     looking = nodelist[pos];
01467 
01468     /* Here we compare values both for equality and for difference less
01469      * than epsilon. The first comparison is required when values are
01470      * infinite, since Infinity - Infinity is NaN and NaN < X is 0 for
01471      * every X.
01472      */
01473     while (looking != NULL) {
01474         if (looking->type.value == value ||
01475         ddEqualVal(looking->type.value,value,unique->epsilon)) {
01476             if (looking->ref == 0) {
01477                 cuddReclaim(unique,looking);
01478             }
01479             return(looking);
01480         }
01481         looking = looking->next;
01482 #ifdef DD_UNIQUE_PROFILE
01483         unique->uniqueLinks++;
01484 #endif
01485     }
01486 
01487     unique->keys++;
01488     unique->constants.keys++;
01489 
01490     looking = cuddAllocNode(unique);
01491     if (looking == NULL) return(NULL);
01492     looking->index = CUDD_CONST_INDEX;
01493     looking->type.value = value;
01494     looking->next = nodelist[pos];
01495     nodelist[pos] = looking;
01496 
01497     return(looking);
01498 
01499 } /* 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 1115 of file cuddTable.c.

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

01294 {
01295     DdNode *result;
01296     DdNode *v;
01297 
01298     v = cuddUniqueInter(unique, index, DD_ONE(unique),
01299                         Cudd_Not(DD_ONE(unique)));
01300     if (v == NULL)
01301         return(NULL);
01302     cuddRef(v);
01303     result = cuddBddIteRecur(unique, v, T, E);
01304     Cudd_RecursiveDeref(unique, v);
01305     return(result);
01306 }

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 1328 of file cuddTable.c.

01333 {
01334     int pos;
01335     unsigned int level;
01336     int retval;
01337     DdNodePtr *nodelist;
01338     DdNode *looking;
01339     DdSubtable *subtable;
01340 
01341 #ifdef DD_UNIQUE_PROFILE
01342     unique->uniqueLookUps++;
01343 #endif
01344 
01345     if (index >= unique->sizeZ) {
01346         if (!cuddResizeTableZdd(unique,index)) return(NULL);
01347     }
01348 
01349     level = unique->permZ[index];
01350     subtable = &(unique->subtableZ[level]);
01351 
01352 #ifdef DD_DEBUG
01353     assert(level < (unsigned) cuddIZ(unique,T->index));
01354     assert(level < (unsigned) cuddIZ(unique,Cudd_Regular(E)->index));
01355 #endif
01356 
01357     if (subtable->keys > subtable->maxKeys) {
01358         if (unique->gcEnabled && ((unique->deadZ > unique->minDead) ||
01359         (10 * subtable->dead > 9 * subtable->keys))) {  /* too many dead */
01360             (void) cuddGarbageCollect(unique,1);
01361         } else {
01362             ddRehashZdd(unique,(int)level);
01363         }
01364     }
01365 
01366     pos = ddHash(T, E, subtable->shift);
01367     nodelist = subtable->nodelist;
01368     looking = nodelist[pos];
01369 
01370     while (looking != NULL) {
01371         if (cuddT(looking) == T && cuddE(looking) == E) {
01372             if (looking->ref == 0) {
01373                 cuddReclaimZdd(unique,looking);
01374             }
01375             return(looking);
01376         }
01377         looking = looking->next;
01378 #ifdef DD_UNIQUE_PROFILE
01379         unique->uniqueLinks++;
01380 #endif
01381     }
01382 
01383     /* countDead is 0 if deads should be counted and ~0 if they should not. */
01384     if (unique->autoDynZ &&
01385     unique->keysZ - (unique->deadZ & unique->countDead) >= unique->nextDyn) {
01386 #ifdef DD_DEBUG
01387         retval = Cudd_DebugCheck(unique);
01388         if (retval != 0) return(NULL);
01389         retval = Cudd_CheckKeys(unique);
01390         if (retval != 0) return(NULL);
01391 #endif
01392         retval = Cudd_zddReduceHeap(unique,unique->autoMethodZ,10); /* 10 = whatever */
01393         if (retval == 0) unique->reordered = 2;
01394 #ifdef DD_DEBUG
01395         retval = Cudd_DebugCheck(unique);
01396         if (retval != 0) unique->reordered = 2;
01397         retval = Cudd_CheckKeys(unique);
01398         if (retval != 0) unique->reordered = 2;
01399 #endif
01400         return(NULL);
01401     }
01402 
01403     unique->keysZ++;
01404     subtable->keys++;
01405 
01406     looking = cuddAllocNode(unique);
01407     if (looking == NULL) return(NULL);
01408     looking->index = index;
01409     cuddT(looking) = T;
01410     cuddE(looking) = E;
01411     looking->next = nodelist[pos];
01412     nodelist[pos] = looking;
01413     cuddRef(T);
01414     cuddRef(E);
01415 
01416     return(looking);
01417 
01418 } /* 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 1028 of file cuddTable.c.

01033 {
01034     DdNode      *node;
01035 
01036     if (T == DD_ZERO(zdd))
01037         return(E);
01038     node = cuddUniqueInterZdd(zdd, id, T, E);
01039     return(node);
01040 
01041 } /* 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 1061 of file cuddTable.c.

01066 {
01067     DdNode      *f, *r, *t;
01068     DdNode      *zdd_one = DD_ONE(dd);
01069     DdNode      *zdd_zero = DD_ZERO(dd);
01070 
01071     f = cuddUniqueInterZdd(dd, index, zdd_one, zdd_zero);
01072     if (f == NULL) {
01073         return(NULL);
01074     }
01075     cuddRef(f);
01076     t = cuddZddProduct(dd, f, g);
01077     if (t == NULL) {
01078         Cudd_RecursiveDerefZdd(dd, f);
01079         return(NULL);
01080     }
01081     cuddRef(t);
01082     Cudd_RecursiveDerefZdd(dd, f);
01083     r = cuddZddUnion(dd, t, h);
01084     if (r == NULL) {
01085         Cudd_RecursiveDerefZdd(dd, t);
01086         return(NULL);
01087     }
01088     cuddRef(r);
01089     Cudd_RecursiveDerefZdd(dd, t);
01090 
01091     cuddDeref(r);
01092     return(r);
01093 
01094 } /* 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 2790 of file cuddTable.c.

02792 {
02793     unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
02794     unique->cacheSlack = (int) ddMin(unique->maxCacheHard,
02795         DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots) -
02796         2 * (int) unique->cacheSlots;
02797     if (unique->cacheSlots < unique->slots/2 && unique->cacheSlack >= 0)
02798         cuddCacheResize(unique);
02799     return;
02800 
02801 } /* 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 3065 of file cuddTable.c.

03068 {
03069     MtrNode *auxnode = treenode;
03070 
03071     while (auxnode != NULL) {
03072         auxnode->low = dd->perm[auxnode->index];
03073         if (auxnode->child != NULL) {
03074             ddPatchTree(dd, auxnode->child);
03075         }
03076         auxnode = auxnode->younger;
03077     }
03078 
03079     return;
03080 
03081 } /* end of ddPatchTree */

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

AutomaticStart

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

Synopsis [Rehashes a ZDD unique subtable.]

Description []

SideEffects [None]

SeeAlso [cuddRehash]

Definition at line 2407 of file cuddTable.c.

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

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

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

Synopsis [Reports problem in garbage collection.]

Description []

SideEffects [None]

SeeAlso [cuddGarbageCollect cuddGarbageCollectZdd]

Definition at line 3142 of file cuddTable.c.

03146 {
03147     if (i == CUDD_CONST_INDEX) {
03148         (void) fprintf(unique->err,
03149                            "%s: problem in constants\n", caller);
03150     } else if (i != -1) {
03151         (void) fprintf(unique->err,
03152                            "%s: problem in table %d\n", caller, i);
03153     }
03154     (void) fprintf(unique->err, "  dead count != deleted\n");
03155     (void) fprintf(unique->err, "  This problem is often due to a missing \
03156 call to Cudd_Ref\n  or to an extra call to Cudd_RecursiveDeref.\n  \
03157 See the CUDD Programmer's Guide for additional details.");
03158     abort();
03159 
03160 } /* 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 2508 of file cuddTable.c.

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


Variable Documentation

char rcsid [] DD_UNUSED = "$Id: cuddTable.c,v 1.122 2009/02/19 16:24:28 fabio Exp $" [static]

Definition at line 120 of file cuddTable.c.


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