SVF
cuddTable.c
Go to the documentation of this file.
1 
84 #include "CUDD/util.h"
85 #include "CUDD/cuddInt.h"
86 
87 /*---------------------------------------------------------------------------*/
88 /* Constant declarations */
89 /*---------------------------------------------------------------------------*/
90 
91 #ifndef DD_UNSORTED_FREE_LIST
92 #ifdef DD_RED_BLACK_FREE_LIST
93 /* Constants for red/black trees. */
94 #define DD_STACK_SIZE 128
95 #define DD_RED 0
96 #define DD_BLACK 1
97 #define DD_PAGE_SIZE 8192
98 #define DD_PAGE_MASK ~(DD_PAGE_SIZE - 1)
99 #endif
100 #endif
101 
102 /*---------------------------------------------------------------------------*/
103 /* Stucture declarations */
104 /*---------------------------------------------------------------------------*/
105 
106 /* This is a hack for when CUDD_VALUE_TYPE is double */
107 typedef union hack {
109  unsigned int bits[2];
110 } hack;
111 
112 /*---------------------------------------------------------------------------*/
113 /* Type declarations */
114 /*---------------------------------------------------------------------------*/
115 
116 /*---------------------------------------------------------------------------*/
117 /* Variable declarations */
118 /*---------------------------------------------------------------------------*/
119 
120 #ifndef lint
121 static char rcsid[] DD_UNUSED = "$Id: cuddTable.c,v 1.126 2012/02/05 01:07:19 fabio Exp $";
122 #endif
123 
124 /*---------------------------------------------------------------------------*/
125 /* Macro declarations */
126 /*---------------------------------------------------------------------------*/
127 
128 
129 #ifndef DD_UNSORTED_FREE_LIST
130 #ifdef DD_RED_BLACK_FREE_LIST
131 /* Macros for red/black trees. */
132 #define DD_INSERT_COMPARE(x,y) \
133  (((ptruint) (x) & DD_PAGE_MASK) - ((ptruint) (y) & DD_PAGE_MASK))
134 #define DD_COLOR(p) ((p)->index)
135 #define DD_IS_BLACK(p) ((p)->index == DD_BLACK)
136 #define DD_IS_RED(p) ((p)->index == DD_RED)
137 #define DD_LEFT(p) cuddT(p)
138 #define DD_RIGHT(p) cuddE(p)
139 #define DD_NEXT(p) ((p)->next)
140 #endif
141 #endif
142 
143 
146 /*---------------------------------------------------------------------------*/
147 /* Static function prototypes */
148 /*---------------------------------------------------------------------------*/
149 
150 static void ddRehashZdd (DdManager *unique, int i);
151 static int ddResizeTable (DdManager *unique, int index, int amount);
152 static int cuddFindParent (DdManager *table, DdNode *node);
153 DD_INLINE static void ddFixLimits (DdManager *unique);
154 #ifdef DD_RED_BLACK_FREE_LIST
155 static void cuddOrderedInsert (DdNodePtr *root, DdNodePtr node);
156 static DdNode * cuddOrderedThread (DdNode *root, DdNode *list);
157 static void cuddRotateLeft (DdNodePtr *nodeP);
158 static void cuddRotateRight (DdNodePtr *nodeP);
159 static void cuddDoRebalance (DdNodePtr **stack, int stackN);
160 #endif
161 static void ddPatchTree (DdManager *dd, MtrNode *treenode);
162 #ifdef DD_DEBUG
163 static int cuddCheckCollisionOrdering (DdManager *unique, int i, int j);
164 #endif
165 static void ddReportRefMess (DdManager *unique, int i, const char *caller);
166 
170 /*---------------------------------------------------------------------------*/
171 /* Definition of exported functions */
172 /*---------------------------------------------------------------------------*/
173 
174 
184 unsigned int
186  unsigned int p)
187 {
188  int i,pn;
189 
190  p--;
191  do {
192  p++;
193  if (p&1) {
194  pn = 1;
195  i = 3;
196  while ((unsigned) (i * i) <= p) {
197  if (p % i == 0) {
198  pn = 0;
199  break;
200  }
201  i += 2;
202  }
203  } else {
204  pn = 0;
205  }
206  } while (!pn);
207  return(p);
208 
209 } /* end of Cudd_Prime */
210 
211 
229 int
231  DdManager *manager,
232  int amount)
233 {
234  int currentSize = manager->size;
235  if (amount < 0)
236  return(0);
237  if (currentSize + amount < currentSize) /* overflow */
238  return(0);
239  if (amount <= manager->maxSize - manager->size)
240  return(1);
241  return ddResizeTable(manager, -1, amount);
242 
243 } /* end of Cudd_Reserve */
244 
245 
246 /*---------------------------------------------------------------------------*/
247 /* Definition of internal functions */
248 /*---------------------------------------------------------------------------*/
249 
250 
265 DdNode *
267  DdManager * unique)
268 {
269  int i;
270  DdNodePtr *mem;
271  DdNode *list, *node;
272  extern DD_OOMFP MMoutOfMemory;
273  DD_OOMFP saveHandler;
274 
275  if (unique->nextFree == NULL) { /* free list is empty */
276  /* Check for exceeded limits. */
277  if ((unique->keys - unique->dead) + (unique->keysZ - unique->deadZ) >
278  unique->maxLive) {
279  unique->errorCode = CUDD_TOO_MANY_NODES;
280  return(NULL);
281  }
282  if (util_cpu_time() - unique->startTime > unique->timeLimit) {
284  return(NULL);
285  }
286  if (unique->stash == NULL || unique->memused > unique->maxmemhard) {
287  (void) cuddGarbageCollect(unique,1);
288  mem = NULL;
289  }
290  if (unique->nextFree == NULL) {
291  if (unique->memused > unique->maxmemhard) {
293  return(NULL);
294  }
295  /* Try to allocate a new block. */
296  saveHandler = MMoutOfMemory;
297  MMoutOfMemory = Cudd_OutOfMem;
298  mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
299  MMoutOfMemory = saveHandler;
300  if (mem == NULL) {
301  /* No more memory: Try collecting garbage. If this succeeds,
302  ** we end up with mem still NULL, but unique->nextFree !=
303  ** NULL. */
304  if (cuddGarbageCollect(unique,1) == 0) {
305  /* Last resort: Free the memory stashed away, if there
306  ** any. If this succeeeds, mem != NULL and
307  ** unique->nextFree still NULL. */
308  if (unique->stash != NULL) {
309  FREE(unique->stash);
310  unique->stash = NULL;
311  /* Inhibit resizing of tables. */
312  cuddSlowTableGrowth(unique);
313  /* Now try again. */
314  mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
315  }
316  if (mem == NULL) {
317  /* Out of luck. Call the default handler to do
318  ** whatever it specifies for a failed malloc.
319  ** If this handler returns, then set error code,
320  ** print warning, and return. */
321  (*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1));
322  unique->errorCode = CUDD_MEMORY_OUT;
323 #ifdef DD_VERBOSE
324  (void) fprintf(unique->err,
325  "cuddAllocNode: out of memory");
326  (void) fprintf(unique->err, "Memory in use = %lu\n",
327  unique->memused);
328 #endif
329  return(NULL);
330  }
331  }
332  }
333  if (mem != NULL) { /* successful allocation; slice memory */
334  ptruint offset;
335  unique->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode);
336  mem[0] = (DdNodePtr) unique->memoryList;
337  unique->memoryList = mem;
338 
339  /* Here we rely on the fact that a DdNode is as large
340  ** as 4 pointers. */
341  offset = (ptruint) mem & (sizeof(DdNode) - 1);
342  mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
343  assert(((ptruint) mem & (sizeof(DdNode) - 1)) == 0);
344  list = (DdNode *) mem;
345 
346  i = 1;
347  do {
348  list[i - 1].ref = 0;
349  list[i - 1].next = &list[i];
350  } while (++i < DD_MEM_CHUNK);
351 
352  list[DD_MEM_CHUNK-1].ref = 0;
353  list[DD_MEM_CHUNK-1].next = NULL;
354 
355  unique->nextFree = &list[0];
356  }
357  }
358  }
359  unique->allocated++;
360  node = unique->nextFree;
361  unique->nextFree = node->next;
362  return(node);
363 
364 } /* end of cuddAllocNode */
365 
366 
379 DdManager *
381  unsigned int numVars /* Initial number of BDD variables (and subtables) */,
382  unsigned int numVarsZ /* Initial number of ZDD variables (and subtables) */,
383  unsigned int numSlots /* Initial size of the BDD subtables */,
384  unsigned int looseUpTo /* Limit for fast table growth */)
385 {
386  DdManager *unique = ALLOC(DdManager,1);
387  int i, j;
388  DdNodePtr *nodelist;
389  DdNode *sentinel;
390  unsigned int slots;
391  int shift;
392 
393  if (unique == NULL) {
394  return(NULL);
395  }
396  sentinel = &(unique->sentinel);
397  sentinel->ref = 0;
398  sentinel->index = 0;
399  cuddT(sentinel) = NULL;
400  cuddE(sentinel) = NULL;
401  sentinel->next = NULL;
402  unique->epsilon = DD_EPSILON;
403  unique->size = numVars;
404  unique->sizeZ = numVarsZ;
405  unique->maxSize = ddMax(DD_DEFAULT_RESIZE, numVars);
406  unique->maxSizeZ = ddMax(DD_DEFAULT_RESIZE, numVarsZ);
407 
408  /* Adjust the requested number of slots to a power of 2. */
409  slots = 8;
410  while (slots < numSlots) {
411  slots <<= 1;
412  }
413  unique->initSlots = slots;
414  shift = sizeof(int) * 8 - cuddComputeFloorLog2(slots);
415 
416  unique->slots = (numVars + numVarsZ + 1) * slots;
417  unique->keys = 0;
418  unique->maxLive = ~0; /* very large number */
419  unique->keysZ = 0;
420  unique->dead = 0;
421  unique->deadZ = 0;
422  unique->gcFrac = DD_GC_FRAC_HI;
423  unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
424  unique->looseUpTo = looseUpTo;
425  unique->gcEnabled = 1;
426  unique->allocated = 0;
427  unique->reclaimed = 0;
428  unique->subtables = ALLOC(DdSubtable,unique->maxSize);
429  if (unique->subtables == NULL) {
430  FREE(unique);
431  return(NULL);
432  }
433  unique->subtableZ = ALLOC(DdSubtable,unique->maxSizeZ);
434  if (unique->subtableZ == NULL) {
435  FREE(unique->subtables);
436  FREE(unique);
437  return(NULL);
438  }
439  unique->perm = ALLOC(int,unique->maxSize);
440  if (unique->perm == NULL) {
441  FREE(unique->subtables);
442  FREE(unique->subtableZ);
443  FREE(unique);
444  return(NULL);
445  }
446  unique->invperm = ALLOC(int,unique->maxSize);
447  if (unique->invperm == NULL) {
448  FREE(unique->subtables);
449  FREE(unique->subtableZ);
450  FREE(unique->perm);
451  FREE(unique);
452  return(NULL);
453  }
454  unique->permZ = ALLOC(int,unique->maxSizeZ);
455  if (unique->permZ == NULL) {
456  FREE(unique->subtables);
457  FREE(unique->subtableZ);
458  FREE(unique->perm);
459  FREE(unique->invperm);
460  FREE(unique);
461  return(NULL);
462  }
463  unique->invpermZ = ALLOC(int,unique->maxSizeZ);
464  if (unique->invpermZ == NULL) {
465  FREE(unique->subtables);
466  FREE(unique->subtableZ);
467  FREE(unique->perm);
468  FREE(unique->invperm);
469  FREE(unique->permZ);
470  FREE(unique);
471  return(NULL);
472  }
473  unique->map = NULL;
474  unique->stack = ALLOC(DdNodePtr,ddMax(unique->maxSize,unique->maxSizeZ)+1);
475  if (unique->stack == NULL) {
476  FREE(unique->subtables);
477  FREE(unique->subtableZ);
478  FREE(unique->perm);
479  FREE(unique->invperm);
480  FREE(unique->permZ);
481  FREE(unique->invpermZ);
482  FREE(unique);
483  return(NULL);
484  }
485  unique->stack[0] = NULL; /* to suppress harmless UMR */
486 
487 #ifndef DD_NO_DEATH_ROW
488  unique->deathRowDepth = 1 << cuddComputeFloorLog2(unique->looseUpTo >> 2);
489  unique->deathRow = ALLOC(DdNodePtr,unique->deathRowDepth);
490  if (unique->deathRow == NULL) {
491  FREE(unique->subtables);
492  FREE(unique->subtableZ);
493  FREE(unique->perm);
494  FREE(unique->invperm);
495  FREE(unique->permZ);
496  FREE(unique->invpermZ);
497  FREE(unique->stack);
498  FREE(unique);
499  return(NULL);
500  }
501  for (i = 0; i < unique->deathRowDepth; i++) {
502  unique->deathRow[i] = NULL;
503  }
504  unique->nextDead = 0;
505  unique->deadMask = unique->deathRowDepth - 1;
506 #endif
507 
508  for (i = 0; (unsigned) i < numVars; i++) {
509  unique->subtables[i].slots = slots;
510  unique->subtables[i].shift = shift;
511  unique->subtables[i].keys = 0;
512  unique->subtables[i].dead = 0;
513  unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
514  unique->subtables[i].bindVar = 0;
516  unique->subtables[i].pairIndex = 0;
517  unique->subtables[i].varHandled = 0;
519 
520  nodelist = unique->subtables[i].nodelist = ALLOC(DdNodePtr,slots);
521  if (nodelist == NULL) {
522  for (j = 0; j < i; j++) {
523  FREE(unique->subtables[j].nodelist);
524  }
525  FREE(unique->subtables);
526  FREE(unique->subtableZ);
527  FREE(unique->perm);
528  FREE(unique->invperm);
529  FREE(unique->permZ);
530  FREE(unique->invpermZ);
531  FREE(unique->stack);
532  FREE(unique);
533  return(NULL);
534  }
535  for (j = 0; (unsigned) j < slots; j++) {
536  nodelist[j] = sentinel;
537  }
538  unique->perm[i] = i;
539  unique->invperm[i] = i;
540  }
541  for (i = 0; (unsigned) i < numVarsZ; i++) {
542  unique->subtableZ[i].slots = slots;
543  unique->subtableZ[i].shift = shift;
544  unique->subtableZ[i].keys = 0;
545  unique->subtableZ[i].dead = 0;
546  unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
547  nodelist = unique->subtableZ[i].nodelist = ALLOC(DdNodePtr,slots);
548  if (nodelist == NULL) {
549  for (j = 0; (unsigned) j < numVars; j++) {
550  FREE(unique->subtables[j].nodelist);
551  }
552  FREE(unique->subtables);
553  for (j = 0; j < i; j++) {
554  FREE(unique->subtableZ[j].nodelist);
555  }
556  FREE(unique->subtableZ);
557  FREE(unique->perm);
558  FREE(unique->invperm);
559  FREE(unique->permZ);
560  FREE(unique->invpermZ);
561  FREE(unique->stack);
562  FREE(unique);
563  return(NULL);
564  }
565  for (j = 0; (unsigned) j < slots; j++) {
566  nodelist[j] = NULL;
567  }
568  unique->permZ[i] = i;
569  unique->invpermZ[i] = i;
570  }
571  unique->constants.slots = slots;
572  unique->constants.shift = shift;
573  unique->constants.keys = 0;
574  unique->constants.dead = 0;
575  unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
576  nodelist = unique->constants.nodelist = ALLOC(DdNodePtr,slots);
577  if (nodelist == NULL) {
578  for (j = 0; (unsigned) j < numVars; j++) {
579  FREE(unique->subtables[j].nodelist);
580  }
581  FREE(unique->subtables);
582  for (j = 0; (unsigned) j < numVarsZ; j++) {
583  FREE(unique->subtableZ[j].nodelist);
584  }
585  FREE(unique->subtableZ);
586  FREE(unique->perm);
587  FREE(unique->invperm);
588  FREE(unique->permZ);
589  FREE(unique->invpermZ);
590  FREE(unique->stack);
591  FREE(unique);
592  return(NULL);
593  }
594  for (j = 0; (unsigned) j < slots; j++) {
595  nodelist[j] = NULL;
596  }
597 
598  unique->memoryList = NULL;
599  unique->nextFree = NULL;
600 
601  unique->memused = sizeof(DdManager) + (unique->maxSize + unique->maxSizeZ)
602  * (sizeof(DdSubtable) + 2 * sizeof(int)) + (numVars + 1) *
603  slots * sizeof(DdNodePtr) +
604  (ddMax(unique->maxSize,unique->maxSizeZ) + 1) * sizeof(DdNodePtr);
605 #ifndef DD_NO_DEATH_ROW
606  unique->memused += unique->deathRowDepth * sizeof(DdNodePtr);
607 #endif
608 
609  /* Initialize fields concerned with automatic dynamic reordering. */
610  unique->reordered = 0;
611  unique->reorderings = 0;
612  unique->maxReorderings = ~0;
613  unique->siftMaxVar = DD_SIFT_MAX_VAR;
614  unique->siftMaxSwap = DD_SIFT_MAX_SWAPS;
616  unique->maxGrowthAlt = 2.0 * DD_MAX_REORDER_GROWTH;
617  unique->reordCycle = 0; /* do not use alternate threshold */
618  unique->autoDyn = 0; /* initially disabled */
619  unique->autoDynZ = 0; /* initially disabled */
620  unique->autoMethod = CUDD_REORDER_SIFT;
621  unique->autoMethodZ = CUDD_REORDER_SIFT;
622  unique->realign = 0; /* initially disabled */
623  unique->realignZ = 0; /* initially disabled */
624  unique->nextDyn = DD_FIRST_REORDER;
625  unique->countDead = ~0;
626  unique->tree = NULL;
627  unique->treeZ = NULL;
628  unique->groupcheck = CUDD_GROUP_CHECK7;
629  unique->recomb = DD_DEFAULT_RECOMB;
630  unique->symmviolation = 0;
631  unique->arcviolation = 0;
632  unique->populationSize = 0;
633  unique->numberXovers = 0;
634  unique->randomizeOrder = 0;
635  unique->linear = NULL;
636  unique->linearSize = 0;
637 
638  /* Initialize ZDD universe. */
639  unique->univ = (DdNodePtr *)NULL;
640 
641  /* Initialize auxiliary fields. */
642  unique->localCaches = NULL;
643  unique->preGCHook = NULL;
644  unique->postGCHook = NULL;
645  unique->preReorderingHook = NULL;
646  unique->postReorderingHook = NULL;
647  unique->out = stdout;
648  unique->err = stderr;
649  unique->errorCode = CUDD_NO_ERROR;
650  unique->startTime = util_cpu_time();
651  unique->timeLimit = ~0UL;
652 
653  /* Initialize statistical counters. */
654  unique->maxmemhard = ~ 0UL;
655  unique->garbageCollections = 0;
656  unique->GCTime = 0;
657  unique->reordTime = 0;
658 #ifdef DD_STATS
659  unique->nodesDropped = 0;
660  unique->nodesFreed = 0;
661 #endif
662  unique->peakLiveNodes = 0;
663 #ifdef DD_UNIQUE_PROFILE
664  unique->uniqueLookUps = 0;
665  unique->uniqueLinks = 0;
666 #endif
667 #ifdef DD_COUNT
668  unique->recursiveCalls = 0;
669  unique->swapSteps = 0;
670 #ifdef DD_STATS
671  unique->nextSample = 250000;
672 #endif
673 #endif
674 
675  return(unique);
676 
677 } /* end of cuddInitTable */
678 
679 
691 void
693  DdManager * unique)
694 {
695  DdNodePtr *next;
696  DdNodePtr *memlist = unique->memoryList;
697  int i;
698 
699  if (unique->univ != NULL) cuddZddFreeUniv(unique);
700  while (memlist != NULL) {
701  next = (DdNodePtr *) memlist[0]; /* link to next block */
702  FREE(memlist);
703  memlist = next;
704  }
705  unique->nextFree = NULL;
706  unique->memoryList = NULL;
707 
708  for (i = 0; i < unique->size; i++) {
709  FREE(unique->subtables[i].nodelist);
710  }
711  for (i = 0; i < unique->sizeZ; i++) {
712  FREE(unique->subtableZ[i].nodelist);
713  }
714  FREE(unique->constants.nodelist);
715  FREE(unique->subtables);
716  FREE(unique->subtableZ);
717  FREE(unique->acache);
718  FREE(unique->perm);
719  FREE(unique->permZ);
720  FREE(unique->invperm);
721  FREE(unique->invpermZ);
722  FREE(unique->vars);
723  if (unique->map != NULL) FREE(unique->map);
724  FREE(unique->stack);
725 #ifndef DD_NO_DEATH_ROW
726  FREE(unique->deathRow);
727 #endif
728  if (unique->tree != NULL) Mtr_FreeTree(unique->tree);
729  if (unique->treeZ != NULL) Mtr_FreeTree(unique->treeZ);
730  if (unique->linear != NULL) FREE(unique->linear);
731  while (unique->preGCHook != NULL)
732  Cudd_RemoveHook(unique,unique->preGCHook->f,CUDD_PRE_GC_HOOK);
733  while (unique->postGCHook != NULL)
735  while (unique->preReorderingHook != NULL)
736  Cudd_RemoveHook(unique,unique->preReorderingHook->f,
738  while (unique->postReorderingHook != NULL)
739  Cudd_RemoveHook(unique,unique->postReorderingHook->f,
741  FREE(unique);
742 
743 } /* end of cuddFreeTable */
744 
745 
761 int
763  DdManager * unique,
764  int clearCache)
765 {
766  DdHook *hook;
767  DdCache *cache = unique->cache;
768  DdNode *sentinel = &(unique->sentinel);
769  DdNodePtr *nodelist;
770  int i, j, deleted, totalDeleted, totalDeletedZ;
771  DdCache *c;
772  DdNode *node,*next;
773  DdNodePtr *lastP;
774  int slots;
775  unsigned long localTime;
776 #ifndef DD_UNSORTED_FREE_LIST
777 #ifdef DD_RED_BLACK_FREE_LIST
778  DdNodePtr tree;
779 #else
780  DdNodePtr *memListTrav, *nxtNode;
781  DdNode *downTrav, *sentry;
782  int k;
783 #endif
784 #endif
785 
786 #ifndef DD_NO_DEATH_ROW
787  cuddClearDeathRow(unique);
788 #endif
789 
790  hook = unique->preGCHook;
791  while (hook != NULL) {
792  int res = (hook->f)(unique,"DD",NULL);
793  if (res == 0) return(0);
794  hook = hook->next;
795  }
796 
797  if (unique->dead + unique->deadZ == 0) {
798  hook = unique->postGCHook;
799  while (hook != NULL) {
800  int res = (hook->f)(unique,"DD",NULL);
801  if (res == 0) return(0);
802  hook = hook->next;
803  }
804  return(0);
805  }
806 
807  /* If many nodes are being reclaimed, we want to resize the tables
808  ** more aggressively, to reduce the frequency of garbage collection.
809  */
810  if (clearCache && unique->gcFrac == DD_GC_FRAC_LO &&
811  unique->slots <= unique->looseUpTo && unique->stash != NULL) {
812  unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
813 #ifdef DD_VERBOSE
814  (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_HI);
815  (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
816 #endif
817  unique->gcFrac = DD_GC_FRAC_HI;
818  return(0);
819  }
820 
821  localTime = util_cpu_time();
822 
823  unique->garbageCollections++;
824 #ifdef DD_VERBOSE
825  (void) fprintf(unique->err,
826  "garbage collecting (%d dead BDD nodes out of %d, min %d)...",
827  unique->dead, unique->keys, unique->minDead);
828  (void) fprintf(unique->err,
829  " (%d dead ZDD nodes out of %d)...",
830  unique->deadZ, unique->keysZ);
831 #endif
832 
833  /* Remove references to garbage collected nodes from the cache. */
834  if (clearCache) {
835  slots = unique->cacheSlots;
836  for (i = 0; i < slots; i++) {
837  c = &cache[i];
838  if (c->data != NULL) {
839  if (cuddClean(c->f)->ref == 0 ||
840  cuddClean(c->g)->ref == 0 ||
841  (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) ||
842  (c->data != DD_NON_CONSTANT &&
843  Cudd_Regular(c->data)->ref == 0)) {
844  c->data = NULL;
845  unique->cachedeletions++;
846  }
847  }
848  }
849  cuddLocalCacheClearDead(unique);
850  }
851 
852  /* Now return dead nodes to free list. Count them for sanity check. */
853  totalDeleted = 0;
854 #ifndef DD_UNSORTED_FREE_LIST
855 #ifdef DD_RED_BLACK_FREE_LIST
856  tree = NULL;
857 #endif
858 #endif
859 
860  for (i = 0; i < unique->size; i++) {
861  if (unique->subtables[i].dead == 0) continue;
862  nodelist = unique->subtables[i].nodelist;
863 
864  deleted = 0;
865  slots = unique->subtables[i].slots;
866  for (j = 0; j < slots; j++) {
867  lastP = &(nodelist[j]);
868  node = *lastP;
869  while (node != sentinel) {
870  next = node->next;
871  if (node->ref == 0) {
872  deleted++;
873 #ifndef DD_UNSORTED_FREE_LIST
874 #ifdef DD_RED_BLACK_FREE_LIST
875  cuddOrderedInsert(&tree,node);
876 #endif
877 #else
878  cuddDeallocNode(unique,node);
879 #endif
880  } else {
881  *lastP = node;
882  lastP = &(node->next);
883  }
884  node = next;
885  }
886  *lastP = sentinel;
887  }
888  if ((unsigned) deleted != unique->subtables[i].dead) {
889  ddReportRefMess(unique, i, "cuddGarbageCollect");
890  }
891  totalDeleted += deleted;
892  unique->subtables[i].keys -= deleted;
893  unique->subtables[i].dead = 0;
894  }
895  if (unique->constants.dead != 0) {
896  nodelist = unique->constants.nodelist;
897  deleted = 0;
898  slots = unique->constants.slots;
899  for (j = 0; j < slots; j++) {
900  lastP = &(nodelist[j]);
901  node = *lastP;
902  while (node != NULL) {
903  next = node->next;
904  if (node->ref == 0) {
905  deleted++;
906 #ifndef DD_UNSORTED_FREE_LIST
907 #ifdef DD_RED_BLACK_FREE_LIST
908  cuddOrderedInsert(&tree,node);
909 #endif
910 #else
911  cuddDeallocNode(unique,node);
912 #endif
913  } else {
914  *lastP = node;
915  lastP = &(node->next);
916  }
917  node = next;
918  }
919  *lastP = NULL;
920  }
921  if ((unsigned) deleted != unique->constants.dead) {
922  ddReportRefMess(unique, CUDD_CONST_INDEX, "cuddGarbageCollect");
923  }
924  totalDeleted += deleted;
925  unique->constants.keys -= deleted;
926  unique->constants.dead = 0;
927  }
928  if ((unsigned) totalDeleted != unique->dead) {
929  ddReportRefMess(unique, -1, "cuddGarbageCollect");
930  }
931  unique->keys -= totalDeleted;
932  unique->dead = 0;
933 #ifdef DD_STATS
934  unique->nodesFreed += (double) totalDeleted;
935 #endif
936 
937  totalDeletedZ = 0;
938 
939  for (i = 0; i < unique->sizeZ; i++) {
940  if (unique->subtableZ[i].dead == 0) continue;
941  nodelist = unique->subtableZ[i].nodelist;
942 
943  deleted = 0;
944  slots = unique->subtableZ[i].slots;
945  for (j = 0; j < slots; j++) {
946  lastP = &(nodelist[j]);
947  node = *lastP;
948  while (node != NULL) {
949  next = node->next;
950  if (node->ref == 0) {
951  deleted++;
952 #ifndef DD_UNSORTED_FREE_LIST
953 #ifdef DD_RED_BLACK_FREE_LIST
954  cuddOrderedInsert(&tree,node);
955 #endif
956 #else
957  cuddDeallocNode(unique,node);
958 #endif
959  } else {
960  *lastP = node;
961  lastP = &(node->next);
962  }
963  node = next;
964  }
965  *lastP = NULL;
966  }
967  if ((unsigned) deleted != unique->subtableZ[i].dead) {
968  ddReportRefMess(unique, i, "cuddGarbageCollect");
969  }
970  totalDeletedZ += deleted;
971  unique->subtableZ[i].keys -= deleted;
972  unique->subtableZ[i].dead = 0;
973  }
974 
975  /* No need to examine the constant table for ZDDs.
976  ** If we did we should be careful not to count whatever dead
977  ** nodes we found there among the dead ZDD nodes. */
978  if ((unsigned) totalDeletedZ != unique->deadZ) {
979  ddReportRefMess(unique, -1, "cuddGarbageCollect");
980  }
981  unique->keysZ -= totalDeletedZ;
982  unique->deadZ = 0;
983 #ifdef DD_STATS
984  unique->nodesFreed += (double) totalDeletedZ;
985 #endif
986 
987 
988 #ifndef DD_UNSORTED_FREE_LIST
989 #ifdef DD_RED_BLACK_FREE_LIST
990  unique->nextFree = cuddOrderedThread(tree,unique->nextFree);
991 #else
992  memListTrav = unique->memoryList;
993  sentry = NULL;
994  while (memListTrav != NULL) {
995  ptruint offset;
996  nxtNode = (DdNodePtr *)memListTrav[0];
997  offset = (ptruint) memListTrav & (sizeof(DdNode) - 1);
998  memListTrav += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
999  downTrav = (DdNode *)memListTrav;
1000  k = 0;
1001  do {
1002  if (downTrav[k].ref == 0) {
1003  if (sentry == NULL) {
1004  unique->nextFree = sentry = &downTrav[k];
1005  } else {
1006  /* First hook sentry->next to the dead node and then
1007  ** reassign sentry to the dead node. */
1008  sentry = (sentry->next = &downTrav[k]);
1009  }
1010  }
1011  } while (++k < DD_MEM_CHUNK);
1012  memListTrav = nxtNode;
1013  }
1014  sentry->next = NULL;
1015 #endif
1016 #endif
1017 
1018  unique->GCTime += util_cpu_time() - localTime;
1019 
1020  hook = unique->postGCHook;
1021  while (hook != NULL) {
1022  int res = (hook->f)(unique,"DD",NULL);
1023  if (res == 0) return(0);
1024  hook = hook->next;
1025  }
1026 
1027 #ifdef DD_VERBOSE
1028  (void) fprintf(unique->err," done\n");
1029 #endif
1030 
1031  return(totalDeleted+totalDeletedZ);
1032 
1033 } /* end of cuddGarbageCollect */
1034 
1035 
1049 DdNode *
1051  DdManager * zdd,
1052  int id,
1053  DdNode * T,
1054  DdNode * E)
1055 {
1056  DdNode *node;
1057 
1058  if (T == DD_ZERO(zdd))
1059  return(E);
1060  node = cuddUniqueInterZdd(zdd, id, T, E);
1061  return(node);
1062 
1063 } /* end of cuddZddGetNode */
1064 
1065 
1082 DdNode *
1084  DdManager * dd,
1085  int index,
1086  DdNode * g,
1087  DdNode * h)
1088 {
1089  DdNode *f, *r, *t;
1090  DdNode *zdd_one = DD_ONE(dd);
1091  DdNode *zdd_zero = DD_ZERO(dd);
1092 
1093  f = cuddUniqueInterZdd(dd, index, zdd_one, zdd_zero);
1094  if (f == NULL) {
1095  return(NULL);
1096  }
1097  cuddRef(f);
1098  t = cuddZddProduct(dd, f, g);
1099  if (t == NULL) {
1100  Cudd_RecursiveDerefZdd(dd, f);
1101  return(NULL);
1102  }
1103  cuddRef(t);
1104  Cudd_RecursiveDerefZdd(dd, f);
1105  r = cuddZddUnion(dd, t, h);
1106  if (r == NULL) {
1107  Cudd_RecursiveDerefZdd(dd, t);
1108  return(NULL);
1109  }
1110  cuddRef(r);
1111  Cudd_RecursiveDerefZdd(dd, t);
1112 
1113  cuddDeref(r);
1114  return(r);
1115 
1116 } /* end of cuddZddGetNodeIVO */
1117 
1118 
1136 DdNode *
1138  DdManager * unique,
1139  int index,
1140  DdNode * T,
1141  DdNode * E)
1142 {
1143  int pos;
1144  unsigned int level;
1145  int retval;
1146  DdNodePtr *nodelist;
1147  DdNode *looking;
1148  DdNodePtr *previousP;
1149  DdSubtable *subtable;
1150  int gcNumber;
1151 
1152 #ifdef DD_UNIQUE_PROFILE
1153  unique->uniqueLookUps++;
1154 #endif
1155 
1156  if ((0x1ffffUL & (unsigned long) unique->cacheMisses) == 0) {
1157  if (util_cpu_time() - unique->startTime > unique->timeLimit) {
1158  unique->errorCode = CUDD_TIMEOUT_EXPIRED;
1159  return(NULL);
1160  }
1161  }
1162  if (index >= unique->size) {
1163  int amount = ddMax(DD_DEFAULT_RESIZE,unique->size/20);
1164  if (!ddResizeTable(unique,index,amount)) return(NULL);
1165  }
1166 
1167  level = unique->perm[index];
1168  subtable = &(unique->subtables[level]);
1169 
1170 #ifdef DD_DEBUG
1171  assert(level < (unsigned) cuddI(unique,T->index));
1172  assert(level < (unsigned) cuddI(unique,Cudd_Regular(E)->index));
1173 #endif
1174 
1175  pos = ddHash(T, E, subtable->shift);
1176  nodelist = subtable->nodelist;
1177  previousP = &(nodelist[pos]);
1178  looking = *previousP;
1179 
1180  while (T < cuddT(looking)) {
1181  previousP = &(looking->next);
1182  looking = *previousP;
1183 #ifdef DD_UNIQUE_PROFILE
1184  unique->uniqueLinks++;
1185 #endif
1186  }
1187  while (T == cuddT(looking) && E < cuddE(looking)) {
1188  previousP = &(looking->next);
1189  looking = *previousP;
1190 #ifdef DD_UNIQUE_PROFILE
1191  unique->uniqueLinks++;
1192 #endif
1193  }
1194  if (T == cuddT(looking) && E == cuddE(looking)) {
1195  if (looking->ref == 0) {
1196  cuddReclaim(unique,looking);
1197  }
1198  return(looking);
1199  }
1200 
1201  /* countDead is 0 if deads should be counted and ~0 if they should not. */
1202  if (unique->autoDyn &&
1203  unique->keys - (unique->dead & unique->countDead) >= unique->nextDyn &&
1204  unique->maxReorderings > 0) {
1205  unsigned long cpuTime;
1206 #ifdef DD_DEBUG
1207  retval = Cudd_DebugCheck(unique);
1208  if (retval != 0) return(NULL);
1209  retval = Cudd_CheckKeys(unique);
1210  if (retval != 0) return(NULL);
1211 #endif
1212  retval = Cudd_ReduceHeap(unique,unique->autoMethod,10); /* 10 = whatever */
1213  unique->maxReorderings--;
1214  if (retval == 0) {
1215  unique->reordered = 2;
1216  } else if ((cpuTime = util_cpu_time()) - unique->startTime > unique->timeLimit) {
1217  unique->errorCode = CUDD_TIMEOUT_EXPIRED;
1218  unique->reordered = 0;
1219  } else if (unique->timeLimit - (cpuTime - unique->startTime)
1220  < unique->reordTime) {
1221  unique->autoDyn = 0;
1222  }
1223 #ifdef DD_DEBUG
1224  retval = Cudd_DebugCheck(unique);
1225  if (retval != 0) unique->reordered = 2;
1226  retval = Cudd_CheckKeys(unique);
1227  if (retval != 0) unique->reordered = 2;
1228 #endif
1229  return(NULL);
1230  }
1231 
1232  if (subtable->keys > subtable->maxKeys) {
1233  if (unique->gcEnabled &&
1234  ((unique->dead > unique->minDead) ||
1235  ((unique->dead > unique->minDead / 2) &&
1236  (subtable->dead > subtable->keys * 0.95)))) { /* too many dead */
1237  if (util_cpu_time() - unique->startTime > unique->timeLimit) {
1238  unique->errorCode = CUDD_TIMEOUT_EXPIRED;
1239  return(NULL);
1240  }
1241  (void) cuddGarbageCollect(unique,1);
1242  } else {
1243  cuddRehash(unique,(int)level);
1244  }
1245  /* Update pointer to insertion point. In the case of rehashing,
1246  ** the slot may have changed. In the case of garbage collection,
1247  ** the predecessor may have been dead. */
1248  pos = ddHash(T, E, subtable->shift);
1249  nodelist = subtable->nodelist;
1250  previousP = &(nodelist[pos]);
1251  looking = *previousP;
1252 
1253  while (T < cuddT(looking)) {
1254  previousP = &(looking->next);
1255  looking = *previousP;
1256 #ifdef DD_UNIQUE_PROFILE
1257  unique->uniqueLinks++;
1258 #endif
1259  }
1260  while (T == cuddT(looking) && E < cuddE(looking)) {
1261  previousP = &(looking->next);
1262  looking = *previousP;
1263 #ifdef DD_UNIQUE_PROFILE
1264  unique->uniqueLinks++;
1265 #endif
1266  }
1267  }
1268 
1269  gcNumber = unique->garbageCollections;
1270  looking = cuddAllocNode(unique);
1271  if (looking == NULL) {
1272  return(NULL);
1273  }
1274  unique->keys++;
1275  subtable->keys++;
1276 
1277  if (gcNumber != unique->garbageCollections) {
1278  DdNode *looking2;
1279  pos = ddHash(T, E, subtable->shift);
1280  nodelist = subtable->nodelist;
1281  previousP = &(nodelist[pos]);
1282  looking2 = *previousP;
1283 
1284  while (T < cuddT(looking2)) {
1285  previousP = &(looking2->next);
1286  looking2 = *previousP;
1287 #ifdef DD_UNIQUE_PROFILE
1288  unique->uniqueLinks++;
1289 #endif
1290  }
1291  while (T == cuddT(looking2) && E < cuddE(looking2)) {
1292  previousP = &(looking2->next);
1293  looking2 = *previousP;
1294 #ifdef DD_UNIQUE_PROFILE
1295  unique->uniqueLinks++;
1296 #endif
1297  }
1298  }
1299  looking->index = index;
1300  cuddT(looking) = T;
1301  cuddE(looking) = E;
1302  looking->next = *previousP;
1303  *previousP = looking;
1304  cuddSatInc(T->ref); /* we know T is a regular pointer */
1305  cuddRef(E);
1306 
1307 #ifdef DD_DEBUG
1308  cuddCheckCollisionOrdering(unique,level,pos);
1309 #endif
1310 
1311  return(looking);
1312 
1313 } /* end of cuddUniqueInter */
1314 
1315 
1332 DdNode *
1334  DdManager * unique,
1335  int index,
1336  DdNode * T,
1337  DdNode * E)
1338 {
1339  DdNode *result;
1340  DdNode *v;
1341 
1342  v = cuddUniqueInter(unique, index, DD_ONE(unique),
1343  Cudd_Not(DD_ONE(unique)));
1344  if (v == NULL)
1345  return(NULL);
1346  /* Since v is a projection function, we can skip the call to cuddRef. */
1347  result = cuddBddIteRecur(unique, v, T, E);
1348  return(result);
1349 
1350 } /* end of cuddUniqueInterIVO */
1351 
1352 
1371 DdNode *
1373  DdManager * unique,
1374  int index,
1375  DdNode * T,
1376  DdNode * E)
1377 {
1378  int pos;
1379  unsigned int level;
1380  int retval;
1381  DdNodePtr *nodelist;
1382  DdNode *looking;
1383  DdSubtable *subtable;
1384 
1385 #ifdef DD_UNIQUE_PROFILE
1386  unique->uniqueLookUps++;
1387 #endif
1388 
1389  if (index >= unique->sizeZ) {
1390  if (!cuddResizeTableZdd(unique,index)) return(NULL);
1391  }
1392 
1393  level = unique->permZ[index];
1394  subtable = &(unique->subtableZ[level]);
1395 
1396 #ifdef DD_DEBUG
1397  assert(level < (unsigned) cuddIZ(unique,T->index));
1398  assert(level < (unsigned) cuddIZ(unique,Cudd_Regular(E)->index));
1399 #endif
1400 
1401  if (subtable->keys > subtable->maxKeys) {
1402  if (unique->gcEnabled && ((unique->deadZ > unique->minDead) ||
1403  (10 * subtable->dead > 9 * subtable->keys))) { /* too many dead */
1404  (void) cuddGarbageCollect(unique,1);
1405  } else {
1406  ddRehashZdd(unique,(int)level);
1407  }
1408  }
1409 
1410  pos = ddHash(T, E, subtable->shift);
1411  nodelist = subtable->nodelist;
1412  looking = nodelist[pos];
1413 
1414  while (looking != NULL) {
1415  if (cuddT(looking) == T && cuddE(looking) == E) {
1416  if (looking->ref == 0) {
1417  cuddReclaimZdd(unique,looking);
1418  }
1419  return(looking);
1420  }
1421  looking = looking->next;
1422 #ifdef DD_UNIQUE_PROFILE
1423  unique->uniqueLinks++;
1424 #endif
1425  }
1426 
1427  /* countDead is 0 if deads should be counted and ~0 if they should not. */
1428  if (unique->autoDynZ &&
1429  unique->keysZ - (unique->deadZ & unique->countDead) >= unique->nextDyn) {
1430 #ifdef DD_DEBUG
1431  retval = Cudd_DebugCheck(unique);
1432  if (retval != 0) return(NULL);
1433  retval = Cudd_CheckKeys(unique);
1434  if (retval != 0) return(NULL);
1435 #endif
1436  retval = Cudd_zddReduceHeap(unique,unique->autoMethodZ,10); /* 10 = whatever */
1437  if (retval == 0) unique->reordered = 2;
1438 #ifdef DD_DEBUG
1439  retval = Cudd_DebugCheck(unique);
1440  if (retval != 0) unique->reordered = 2;
1441  retval = Cudd_CheckKeys(unique);
1442  if (retval != 0) unique->reordered = 2;
1443 #endif
1444  return(NULL);
1445  }
1446 
1447  unique->keysZ++;
1448  subtable->keys++;
1449 
1450  looking = cuddAllocNode(unique);
1451  if (looking == NULL) return(NULL);
1452  looking->index = index;
1453  cuddT(looking) = T;
1454  cuddE(looking) = E;
1455  looking->next = nodelist[pos];
1456  nodelist[pos] = looking;
1457  cuddRef(T);
1458  cuddRef(E);
1459 
1460  return(looking);
1461 
1462 } /* end of cuddUniqueInterZdd */
1463 
1464 
1478 DdNode *
1480  DdManager * unique,
1482 {
1483  int pos;
1484  DdNodePtr *nodelist;
1485  DdNode *looking;
1486  hack split;
1487 
1488 #ifdef DD_UNIQUE_PROFILE
1489  unique->uniqueLookUps++;
1490 #endif
1491 
1492  if (unique->constants.keys > unique->constants.maxKeys) {
1493  if (unique->gcEnabled && ((unique->dead > unique->minDead) ||
1494  (10 * unique->constants.dead > 9 * unique->constants.keys))) { /* too many dead */
1495  (void) cuddGarbageCollect(unique,1);
1496  } else {
1497  cuddRehash(unique,CUDD_CONST_INDEX);
1498  }
1499  }
1500 
1501  cuddAdjust(value); /* for the case of crippled infinities */
1502 
1503  if (ddAbs(value) < unique->epsilon) {
1504  value = 0.0;
1505  }
1506  split.value = value;
1507 
1508  pos = ddHash(split.bits[0], split.bits[1], unique->constants.shift);
1509  nodelist = unique->constants.nodelist;
1510  looking = nodelist[pos];
1511 
1512  /* Here we compare values both for equality and for difference less
1513  * than epsilon. The first comparison is required when values are
1514  * infinite, since Infinity - Infinity is NaN and NaN < X is 0 for
1515  * every X.
1516  */
1517  while (looking != NULL) {
1518  if (looking->type.value == value ||
1519  ddEqualVal(looking->type.value,value,unique->epsilon)) {
1520  if (looking->ref == 0) {
1521  cuddReclaim(unique,looking);
1522  }
1523  return(looking);
1524  }
1525  looking = looking->next;
1526 #ifdef DD_UNIQUE_PROFILE
1527  unique->uniqueLinks++;
1528 #endif
1529  }
1530 
1531  unique->keys++;
1532  unique->constants.keys++;
1533 
1534  looking = cuddAllocNode(unique);
1535  if (looking == NULL) return(NULL);
1536  looking->index = CUDD_CONST_INDEX;
1537  looking->type.value = value;
1538  looking->next = nodelist[pos];
1539  nodelist[pos] = looking;
1540 
1541  return(looking);
1542 
1543 } /* end of cuddUniqueConst */
1544 
1545 
1558 void
1560  DdManager * unique,
1561  int i)
1562 {
1563  unsigned int slots, oldslots;
1564  int shift, oldshift;
1565  int j, pos;
1566  DdNodePtr *nodelist, *oldnodelist;
1567  DdNode *node, *next;
1568  DdNode *sentinel = &(unique->sentinel);
1569  hack split;
1570  extern DD_OOMFP MMoutOfMemory;
1571  DD_OOMFP saveHandler;
1572 
1573  if (unique->gcFrac == DD_GC_FRAC_HI && unique->slots > unique->looseUpTo) {
1574  unique->gcFrac = DD_GC_FRAC_LO;
1575  unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
1576 #ifdef DD_VERBOSE
1577  (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_LO);
1578  (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
1579 #endif
1580  }
1581 
1582  if (unique->gcFrac != DD_GC_FRAC_MIN && unique->memused > unique->maxmem) {
1583  unique->gcFrac = DD_GC_FRAC_MIN;
1584  unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
1585 #ifdef DD_VERBOSE
1586  (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_MIN);
1587  (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
1588 #endif
1589  cuddShrinkDeathRow(unique);
1590  if (cuddGarbageCollect(unique,1) > 0) return;
1591  }
1592 
1593  if (i != CUDD_CONST_INDEX) {
1594  oldslots = unique->subtables[i].slots;
1595  oldshift = unique->subtables[i].shift;
1596  oldnodelist = unique->subtables[i].nodelist;
1597 
1598  /* Compute the new size of the subtable. */
1599  slots = oldslots << 1;
1600  shift = oldshift - 1;
1601 
1602  saveHandler = MMoutOfMemory;
1603  MMoutOfMemory = Cudd_OutOfMem;
1604  nodelist = ALLOC(DdNodePtr, slots);
1605  MMoutOfMemory = saveHandler;
1606  if (nodelist == NULL) {
1607  (void) fprintf(unique->err,
1608  "Unable to resize subtable %d for lack of memory\n",
1609  i);
1610  /* Prevent frequent resizing attempts. */
1611  (void) cuddGarbageCollect(unique,1);
1612  if (unique->stash != NULL) {
1613  FREE(unique->stash);
1614  unique->stash = NULL;
1615  /* Inhibit resizing of tables. */
1616  cuddSlowTableGrowth(unique);
1617  }
1618  return;
1619  }
1620  unique->subtables[i].nodelist = nodelist;
1621  unique->subtables[i].slots = slots;
1622  unique->subtables[i].shift = shift;
1623  unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
1624 
1625  /* Move the nodes from the old table to the new table.
1626  ** This code depends on the type of hash function.
1627  ** It assumes that the effect of doubling the size of the table
1628  ** is to retain one more bit of the 32-bit hash value.
1629  ** The additional bit is the LSB. */
1630  for (j = 0; (unsigned) j < oldslots; j++) {
1631  DdNodePtr *evenP, *oddP;
1632  node = oldnodelist[j];
1633  evenP = &(nodelist[j<<1]);
1634  oddP = &(nodelist[(j<<1)+1]);
1635  while (node != sentinel) {
1636  next = node->next;
1637  pos = ddHash(cuddT(node), cuddE(node), shift);
1638  if (pos & 1) {
1639  *oddP = node;
1640  oddP = &(node->next);
1641  } else {
1642  *evenP = node;
1643  evenP = &(node->next);
1644  }
1645  node = next;
1646  }
1647  *evenP = *oddP = sentinel;
1648  }
1649  FREE(oldnodelist);
1650 
1651 #ifdef DD_VERBOSE
1652  (void) fprintf(unique->err,
1653  "rehashing layer %d: keys %d dead %d new size %d\n",
1654  i, unique->subtables[i].keys,
1655  unique->subtables[i].dead, slots);
1656 #endif
1657  } else {
1658  oldslots = unique->constants.slots;
1659  oldshift = unique->constants.shift;
1660  oldnodelist = unique->constants.nodelist;
1661 
1662  /* The constant subtable is never subjected to reordering.
1663  ** Therefore, when it is resized, it is because it has just
1664  ** reached the maximum load. We can safely just double the size,
1665  ** with no need for the loop we use for the other tables.
1666  */
1667  slots = oldslots << 1;
1668  shift = oldshift - 1;
1669  saveHandler = MMoutOfMemory;
1670  MMoutOfMemory = Cudd_OutOfMem;
1671  nodelist = ALLOC(DdNodePtr, slots);
1672  MMoutOfMemory = saveHandler;
1673  if (nodelist == NULL) {
1674  (void) fprintf(unique->err,
1675  "Unable to resize constant subtable for lack of memory\n");
1676  (void) cuddGarbageCollect(unique,1);
1677  for (j = 0; j < unique->size; j++) {
1678  unique->subtables[j].maxKeys <<= 1;
1679  }
1680  unique->constants.maxKeys <<= 1;
1681  return;
1682  }
1683  unique->constants.slots = slots;
1684  unique->constants.shift = shift;
1685  unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
1686  unique->constants.nodelist = nodelist;
1687  for (j = 0; (unsigned) j < slots; j++) {
1688  nodelist[j] = NULL;
1689  }
1690  for (j = 0; (unsigned) j < oldslots; j++) {
1691  node = oldnodelist[j];
1692  while (node != NULL) {
1693  next = node->next;
1694  split.value = cuddV(node);
1695  pos = ddHash(split.bits[0], split.bits[1], shift);
1696  node->next = nodelist[pos];
1697  nodelist[pos] = node;
1698  node = next;
1699  }
1700  }
1701  FREE(oldnodelist);
1702 
1703 #ifdef DD_VERBOSE
1704  (void) fprintf(unique->err,
1705  "rehashing constants: keys %d dead %d new size %d\n",
1706  unique->constants.keys,unique->constants.dead,slots);
1707 #endif
1708  }
1709 
1710  /* Update global data */
1711 
1712  unique->memused += (slots - oldslots) * sizeof(DdNodePtr);
1713  unique->slots += (slots - oldslots);
1714  ddFixLimits(unique);
1715 
1716 } /* end of cuddRehash */
1717 
1718 
1730 void
1732  DdManager *unique,
1733  int i)
1734 {
1735  int j;
1736  int shift, posn;
1737  DdNodePtr *nodelist, *oldnodelist;
1738  DdNode *node, *next;
1739  DdNode *sentinel = &(unique->sentinel);
1740  unsigned int slots, oldslots;
1741  extern DD_OOMFP MMoutOfMemory;
1742  DD_OOMFP saveHandler;
1743 
1744  oldnodelist = unique->subtables[i].nodelist;
1745  oldslots = unique->subtables[i].slots;
1746  slots = oldslots >> 1;
1747  saveHandler = MMoutOfMemory;
1748  MMoutOfMemory = Cudd_OutOfMem;
1749  nodelist = ALLOC(DdNodePtr, slots);
1750  MMoutOfMemory = saveHandler;
1751  if (nodelist == NULL) {
1752  return;
1753  }
1754  unique->subtables[i].nodelist = nodelist;
1755  unique->subtables[i].slots = slots;
1756  unique->subtables[i].shift++;
1757  unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
1758 #ifdef DD_VERBOSE
1759  (void) fprintf(unique->err,
1760  "shrunk layer %d (%d keys) from %d to %d slots\n",
1761  i, unique->subtables[i].keys, oldslots, slots);
1762 #endif
1763 
1764  for (j = 0; (unsigned) j < slots; j++) {
1765  nodelist[j] = sentinel;
1766  }
1767  shift = unique->subtables[i].shift;
1768  for (j = 0; (unsigned) j < oldslots; j++) {
1769  node = oldnodelist[j];
1770  while (node != sentinel) {
1771  DdNode *looking, *T, *E;
1772  DdNodePtr *previousP;
1773  next = node->next;
1774  posn = ddHash(cuddT(node), cuddE(node), shift);
1775  previousP = &(nodelist[posn]);
1776  looking = *previousP;
1777  T = cuddT(node);
1778  E = cuddE(node);
1779  while (T < cuddT(looking)) {
1780  previousP = &(looking->next);
1781  looking = *previousP;
1782 #ifdef DD_UNIQUE_PROFILE
1783  unique->uniqueLinks++;
1784 #endif
1785  }
1786  while (T == cuddT(looking) && E < cuddE(looking)) {
1787  previousP = &(looking->next);
1788  looking = *previousP;
1789 #ifdef DD_UNIQUE_PROFILE
1790  unique->uniqueLinks++;
1791 #endif
1792  }
1793  node->next = *previousP;
1794  *previousP = node;
1795  node = next;
1796  }
1797  }
1798  FREE(oldnodelist);
1799 
1800  unique->memused += ((long) slots - (long) oldslots) * sizeof(DdNode *);
1801  unique->slots += slots - oldslots;
1802  unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
1803  unique->cacheSlack = (int)
1805  - 2 * (int) unique->cacheSlots;
1806 
1807 } /* end of cuddShrinkSubtable */
1808 
1809 
1823 int
1825  DdManager * unique,
1826  int n,
1827  int level)
1828 {
1829  DdSubtable *newsubtables;
1830  DdNodePtr *newnodelist;
1831  DdNodePtr *newvars;
1832  DdNode *sentinel = &(unique->sentinel);
1833  int oldsize,newsize;
1834  int i,j,index,reorderSave;
1835  unsigned int numSlots = unique->initSlots;
1836  int *newperm, *newinvperm, *newmap;
1837  DdNode *one, *zero;
1838 
1839 #ifdef DD_DEBUG
1840  assert(n > 0 && level < unique->size);
1841 #endif
1842 
1843  oldsize = unique->size;
1844  /* Easy case: there is still room in the current table. */
1845  if (oldsize + n <= unique->maxSize) {
1846  /* Shift the tables at and below level. */
1847  for (i = oldsize - 1; i >= level; i--) {
1848  unique->subtables[i+n].slots = unique->subtables[i].slots;
1849  unique->subtables[i+n].shift = unique->subtables[i].shift;
1850  unique->subtables[i+n].keys = unique->subtables[i].keys;
1851  unique->subtables[i+n].maxKeys = unique->subtables[i].maxKeys;
1852  unique->subtables[i+n].dead = unique->subtables[i].dead;
1853  unique->subtables[i+n].nodelist = unique->subtables[i].nodelist;
1854  unique->subtables[i+n].bindVar = unique->subtables[i].bindVar;
1855  unique->subtables[i+n].varType = unique->subtables[i].varType;
1856  unique->subtables[i+n].pairIndex = unique->subtables[i].pairIndex;
1857  unique->subtables[i+n].varHandled = unique->subtables[i].varHandled;
1858  unique->subtables[i+n].varToBeGrouped =
1859  unique->subtables[i].varToBeGrouped;
1860 
1861  index = unique->invperm[i];
1862  unique->invperm[i+n] = index;
1863  unique->perm[index] += n;
1864  }
1865  /* Create new subtables. */
1866  for (i = 0; i < n; i++) {
1867  unique->subtables[level+i].slots = numSlots;
1868  unique->subtables[level+i].shift = sizeof(int) * 8 -
1869  cuddComputeFloorLog2(numSlots);
1870  unique->subtables[level+i].keys = 0;
1871  unique->subtables[level+i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
1872  unique->subtables[level+i].dead = 0;
1873  unique->subtables[level+i].bindVar = 0;
1874  unique->subtables[level+i].varType = CUDD_VAR_PRIMARY_INPUT;
1875  unique->subtables[level+i].pairIndex = 0;
1876  unique->subtables[level+i].varHandled = 0;
1877  unique->subtables[level+i].varToBeGrouped = CUDD_LAZY_NONE;
1878 
1879  unique->perm[oldsize+i] = level + i;
1880  unique->invperm[level+i] = oldsize + i;
1881  newnodelist = unique->subtables[level+i].nodelist =
1882  ALLOC(DdNodePtr, numSlots);
1883  if (newnodelist == NULL) {
1884  unique->errorCode = CUDD_MEMORY_OUT;
1885  return(0);
1886  }
1887  for (j = 0; (unsigned) j < numSlots; j++) {
1888  newnodelist[j] = sentinel;
1889  }
1890  }
1891  if (unique->map != NULL) {
1892  for (i = 0; i < n; i++) {
1893  unique->map[oldsize+i] = oldsize + i;
1894  }
1895  }
1896  } else {
1897  /* The current table is too small: we need to allocate a new,
1898  ** larger one; move all old subtables, and initialize the new
1899  ** subtables.
1900  */
1901  newsize = oldsize + n + DD_DEFAULT_RESIZE;
1902 #ifdef DD_VERBOSE
1903  (void) fprintf(unique->err,
1904  "Increasing the table size from %d to %d\n",
1905  unique->maxSize, newsize);
1906 #endif
1907  /* Allocate memory for new arrays (except nodelists). */
1908  newsubtables = ALLOC(DdSubtable,newsize);
1909  if (newsubtables == NULL) {
1910  unique->errorCode = CUDD_MEMORY_OUT;
1911  return(0);
1912  }
1913  newvars = ALLOC(DdNodePtr,newsize);
1914  if (newvars == NULL) {
1915  unique->errorCode = CUDD_MEMORY_OUT;
1916  FREE(newsubtables);
1917  return(0);
1918  }
1919  newperm = ALLOC(int,newsize);
1920  if (newperm == NULL) {
1921  unique->errorCode = CUDD_MEMORY_OUT;
1922  FREE(newsubtables);
1923  FREE(newvars);
1924  return(0);
1925  }
1926  newinvperm = ALLOC(int,newsize);
1927  if (newinvperm == NULL) {
1928  unique->errorCode = CUDD_MEMORY_OUT;
1929  FREE(newsubtables);
1930  FREE(newvars);
1931  FREE(newperm);
1932  return(0);
1933  }
1934  if (unique->map != NULL) {
1935  newmap = ALLOC(int,newsize);
1936  if (newmap == NULL) {
1937  unique->errorCode = CUDD_MEMORY_OUT;
1938  FREE(newsubtables);
1939  FREE(newvars);
1940  FREE(newperm);
1941  FREE(newinvperm);
1942  return(0);
1943  }
1944  unique->memused += (newsize - unique->maxSize) * sizeof(int);
1945  }
1946  unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
1947  sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
1948  /* Copy levels before insertion points from old tables. */
1949  for (i = 0; i < level; i++) {
1950  newsubtables[i].slots = unique->subtables[i].slots;
1951  newsubtables[i].shift = unique->subtables[i].shift;
1952  newsubtables[i].keys = unique->subtables[i].keys;
1953  newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
1954  newsubtables[i].dead = unique->subtables[i].dead;
1955  newsubtables[i].nodelist = unique->subtables[i].nodelist;
1956  newsubtables[i].bindVar = unique->subtables[i].bindVar;
1957  newsubtables[i].varType = unique->subtables[i].varType;
1958  newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
1959  newsubtables[i].varHandled = unique->subtables[i].varHandled;
1960  newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
1961 
1962  newvars[i] = unique->vars[i];
1963  newperm[i] = unique->perm[i];
1964  newinvperm[i] = unique->invperm[i];
1965  }
1966  /* Finish initializing permutation for new table to old one. */
1967  for (i = level; i < oldsize; i++) {
1968  newperm[i] = unique->perm[i];
1969  }
1970  /* Initialize new levels. */
1971  for (i = level; i < level + n; i++) {
1972  newsubtables[i].slots = numSlots;
1973  newsubtables[i].shift = sizeof(int) * 8 -
1974  cuddComputeFloorLog2(numSlots);
1975  newsubtables[i].keys = 0;
1976  newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
1977  newsubtables[i].dead = 0;
1978  newsubtables[i].bindVar = 0;
1979  newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
1980  newsubtables[i].pairIndex = 0;
1981  newsubtables[i].varHandled = 0;
1982  newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
1983 
1984  newperm[oldsize + i - level] = i;
1985  newinvperm[i] = oldsize + i - level;
1986  newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
1987  if (newnodelist == NULL) {
1988  /* We are going to leak some memory. We should clean up. */
1989  unique->errorCode = CUDD_MEMORY_OUT;
1990  return(0);
1991  }
1992  for (j = 0; (unsigned) j < numSlots; j++) {
1993  newnodelist[j] = sentinel;
1994  }
1995  }
1996  /* Copy the old tables for levels past the insertion point. */
1997  for (i = level; i < oldsize; i++) {
1998  newsubtables[i+n].slots = unique->subtables[i].slots;
1999  newsubtables[i+n].shift = unique->subtables[i].shift;
2000  newsubtables[i+n].keys = unique->subtables[i].keys;
2001  newsubtables[i+n].maxKeys = unique->subtables[i].maxKeys;
2002  newsubtables[i+n].dead = unique->subtables[i].dead;
2003  newsubtables[i+n].nodelist = unique->subtables[i].nodelist;
2004  newsubtables[i+n].bindVar = unique->subtables[i].bindVar;
2005  newsubtables[i+n].varType = unique->subtables[i].varType;
2006  newsubtables[i+n].pairIndex = unique->subtables[i].pairIndex;
2007  newsubtables[i+n].varHandled = unique->subtables[i].varHandled;
2008  newsubtables[i+n].varToBeGrouped =
2009  unique->subtables[i].varToBeGrouped;
2010 
2011  newvars[i] = unique->vars[i];
2012  index = unique->invperm[i];
2013  newinvperm[i+n] = index;
2014  newperm[index] += n;
2015  }
2016  /* Update the map. */
2017  if (unique->map != NULL) {
2018  for (i = 0; i < oldsize; i++) {
2019  newmap[i] = unique->map[i];
2020  }
2021  for (i = oldsize; i < oldsize + n; i++) {
2022  newmap[i] = i;
2023  }
2024  FREE(unique->map);
2025  unique->map = newmap;
2026  }
2027  /* Install the new tables and free the old ones. */
2028  FREE(unique->subtables);
2029  unique->subtables = newsubtables;
2030  unique->maxSize = newsize;
2031  FREE(unique->vars);
2032  unique->vars = newvars;
2033  FREE(unique->perm);
2034  unique->perm = newperm;
2035  FREE(unique->invperm);
2036  unique->invperm = newinvperm;
2037  /* Update the stack for iterative procedures. */
2038  if (newsize > unique->maxSizeZ) {
2039  FREE(unique->stack);
2040  unique->stack = ALLOC(DdNodePtr,newsize + 1);
2041  if (unique->stack == NULL) {
2042  unique->errorCode = CUDD_MEMORY_OUT;
2043  return(0);
2044  }
2045  unique->stack[0] = NULL; /* to suppress harmless UMR */
2046  unique->memused +=
2047  (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
2048  * sizeof(DdNode *);
2049  }
2050  }
2051  /* Update manager parameters to account for the new subtables. */
2052  unique->slots += n * numSlots;
2053  ddFixLimits(unique);
2054  unique->size += n;
2055 
2056  /* Now that the table is in a coherent state, create the new
2057  ** projection functions. We need to temporarily disable reordering,
2058  ** because we cannot reorder without projection functions in place.
2059  **/
2060  one = unique->one;
2061  zero = Cudd_Not(one);
2062 
2063  reorderSave = unique->autoDyn;
2064  unique->autoDyn = 0;
2065  for (i = oldsize; i < oldsize + n; i++) {
2066  unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
2067  if (unique->vars[i] == NULL) {
2068  unique->autoDyn = reorderSave;
2069  /* Shift everything back so table remains coherent. */
2070  for (j = oldsize; j < i; j++) {
2071  Cudd_IterDerefBdd(unique,unique->vars[j]);
2072  cuddDeallocNode(unique,unique->vars[j]);
2073  unique->vars[j] = NULL;
2074  }
2075  for (j = level; j < oldsize; j++) {
2076  unique->subtables[j].slots = unique->subtables[j+n].slots;
2077  unique->subtables[j].slots = unique->subtables[j+n].slots;
2078  unique->subtables[j].shift = unique->subtables[j+n].shift;
2079  unique->subtables[j].keys = unique->subtables[j+n].keys;
2080  unique->subtables[j].maxKeys =
2081  unique->subtables[j+n].maxKeys;
2082  unique->subtables[j].dead = unique->subtables[j+n].dead;
2083  FREE(unique->subtables[j].nodelist);
2084  unique->subtables[j].nodelist =
2085  unique->subtables[j+n].nodelist;
2086  unique->subtables[j+n].nodelist = NULL;
2087  unique->subtables[j].bindVar =
2088  unique->subtables[j+n].bindVar;
2089  unique->subtables[j].varType =
2090  unique->subtables[j+n].varType;
2091  unique->subtables[j].pairIndex =
2092  unique->subtables[j+n].pairIndex;
2093  unique->subtables[j].varHandled =
2094  unique->subtables[j+n].varHandled;
2095  unique->subtables[j].varToBeGrouped =
2096  unique->subtables[j+n].varToBeGrouped;
2097  index = unique->invperm[j+n];
2098  unique->invperm[j] = index;
2099  unique->perm[index] -= n;
2100  }
2101  unique->size = oldsize;
2102  unique->slots -= n * numSlots;
2103  ddFixLimits(unique);
2104  (void) Cudd_DebugCheck(unique);
2105  return(0);
2106  }
2107  cuddRef(unique->vars[i]);
2108  }
2109  if (unique->tree != NULL) {
2110  unique->tree->size += n;
2111  unique->tree->index = unique->invperm[0];
2112  ddPatchTree(unique,unique->tree);
2113  }
2114  unique->autoDyn = reorderSave;
2115 
2116  return(1);
2117 
2118 } /* end of cuddInsertSubtables */
2119 
2120 
2136 int
2138  DdManager * unique,
2139  int n)
2140 {
2141  DdSubtable *subtables;
2142  DdNodePtr *nodelist;
2143  DdNodePtr *vars;
2144  int firstIndex, lastIndex;
2145  int index, level, newlevel;
2146  int lowestLevel;
2147  int shift;
2148  int found;
2149 
2150  /* Sanity check and set up. */
2151  if (n <= 0) return(0);
2152  if (n > unique->size) n = unique->size;
2153 
2154  subtables = unique->subtables;
2155  vars = unique->vars;
2156  firstIndex = unique->size - n;
2157  lastIndex = unique->size;
2158 
2159  /* Check for nodes labeled by the variables being destroyed
2160  ** that may still be in use. It is allowed to destroy a variable
2161  ** only if there are no such nodes. Also, find the lowest level
2162  ** among the variables being destroyed. This will make further
2163  ** processing more efficient.
2164  */
2165  lowestLevel = unique->size;
2166  for (index = firstIndex; index < lastIndex; index++) {
2167  level = unique->perm[index];
2168  if (level < lowestLevel) lowestLevel = level;
2169  nodelist = subtables[level].nodelist;
2170  if (subtables[level].keys - subtables[level].dead != 1) return(0);
2171  /* The projection function should be isolated. If the ref count
2172  ** is 1, everything is OK. If the ref count is saturated, then
2173  ** we need to make sure that there are no nodes pointing to it.
2174  ** As for the external references, we assume the application is
2175  ** responsible for them.
2176  */
2177  if (vars[index]->ref != 1) {
2178  if (vars[index]->ref != DD_MAXREF) return(0);
2179  found = cuddFindParent(unique,vars[index]);
2180  if (found) {
2181  return(0);
2182  } else {
2183  vars[index]->ref = 1;
2184  }
2185  }
2186  Cudd_RecursiveDeref(unique,vars[index]);
2187  }
2188 
2189  /* Collect garbage, because we cannot afford having dead nodes pointing
2190  ** to the dead nodes in the subtables being destroyed.
2191  */
2192  (void) cuddGarbageCollect(unique,1);
2193 
2194  /* Here we know we can destroy our subtables. */
2195  for (index = firstIndex; index < lastIndex; index++) {
2196  level = unique->perm[index];
2197  nodelist = subtables[level].nodelist;
2198 #ifdef DD_DEBUG
2199  assert(subtables[level].keys == 0);
2200 #endif
2201  FREE(nodelist);
2202  unique->memused -= sizeof(DdNodePtr) * subtables[level].slots;
2203  unique->slots -= subtables[level].slots;
2204  unique->dead -= subtables[level].dead;
2205  }
2206 
2207  /* Here all subtables to be destroyed have their keys field == 0 and
2208  ** their hash tables have been freed.
2209  ** We now scan the subtables from level lowestLevel + 1 to level size - 1,
2210  ** shifting the subtables as required. We keep a running count of
2211  ** how many subtables have been moved, so that we know by how many
2212  ** positions each subtable should be shifted.
2213  */
2214  shift = 1;
2215  for (level = lowestLevel + 1; level < unique->size; level++) {
2216  if (subtables[level].keys == 0) {
2217  shift++;
2218  continue;
2219  }
2220  newlevel = level - shift;
2221  subtables[newlevel].slots = subtables[level].slots;
2222  subtables[newlevel].shift = subtables[level].shift;
2223  subtables[newlevel].keys = subtables[level].keys;
2224  subtables[newlevel].maxKeys = subtables[level].maxKeys;
2225  subtables[newlevel].dead = subtables[level].dead;
2226  subtables[newlevel].nodelist = subtables[level].nodelist;
2227  index = unique->invperm[level];
2228  unique->perm[index] = newlevel;
2229  unique->invperm[newlevel] = index;
2230  subtables[newlevel].bindVar = subtables[level].bindVar;
2231  subtables[newlevel].varType = subtables[level].varType;
2232  subtables[newlevel].pairIndex = subtables[level].pairIndex;
2233  subtables[newlevel].varHandled = subtables[level].varHandled;
2234  subtables[newlevel].varToBeGrouped = subtables[level].varToBeGrouped;
2235  }
2236  /* Destroy the map. If a surviving variable is
2237  ** mapped to a dying variable, and the map were used again,
2238  ** an out-of-bounds access to unique->vars would result. */
2239  if (unique->map != NULL) {
2240  cuddCacheFlush(unique);
2241  FREE(unique->map);
2242  unique->map = NULL;
2243  }
2244 
2245  unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
2246  unique->size -= n;
2247 
2248  return(1);
2249 
2250 } /* end of cuddDestroySubtables */
2251 
2252 
2269 int
2271  DdManager * unique,
2272  int index)
2273 {
2274  DdSubtable *newsubtables;
2275  DdNodePtr *newnodelist;
2276  int oldsize,newsize;
2277  int i,j,reorderSave;
2278  unsigned int numSlots = unique->initSlots;
2279  int *newperm, *newinvperm;
2280 
2281  oldsize = unique->sizeZ;
2282  /* Easy case: there is still room in the current table. */
2283  if (index < unique->maxSizeZ) {
2284  for (i = oldsize; i <= index; i++) {
2285  unique->subtableZ[i].slots = numSlots;
2286  unique->subtableZ[i].shift = sizeof(int) * 8 -
2287  cuddComputeFloorLog2(numSlots);
2288  unique->subtableZ[i].keys = 0;
2289  unique->subtableZ[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
2290  unique->subtableZ[i].dead = 0;
2291  unique->permZ[i] = i;
2292  unique->invpermZ[i] = i;
2293  newnodelist = unique->subtableZ[i].nodelist =
2294  ALLOC(DdNodePtr, numSlots);
2295  if (newnodelist == NULL) {
2296  unique->errorCode = CUDD_MEMORY_OUT;
2297  return(0);
2298  }
2299  for (j = 0; (unsigned) j < numSlots; j++) {
2300  newnodelist[j] = NULL;
2301  }
2302  }
2303  } else {
2304  /* The current table is too small: we need to allocate a new,
2305  ** larger one; move all old subtables, and initialize the new
2306  ** subtables up to index included.
2307  */
2308  newsize = index + DD_DEFAULT_RESIZE;
2309 #ifdef DD_VERBOSE
2310  (void) fprintf(unique->err,
2311  "Increasing the ZDD table size from %d to %d\n",
2312  unique->maxSizeZ, newsize);
2313 #endif
2314  newsubtables = ALLOC(DdSubtable,newsize);
2315  if (newsubtables == NULL) {
2316  unique->errorCode = CUDD_MEMORY_OUT;
2317  return(0);
2318  }
2319  newperm = ALLOC(int,newsize);
2320  if (newperm == NULL) {
2321  unique->errorCode = CUDD_MEMORY_OUT;
2322  return(0);
2323  }
2324  newinvperm = ALLOC(int,newsize);
2325  if (newinvperm == NULL) {
2326  unique->errorCode = CUDD_MEMORY_OUT;
2327  return(0);
2328  }
2329  unique->memused += (newsize - unique->maxSizeZ) * ((numSlots+1) *
2330  sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
2331  if (newsize > unique->maxSize) {
2332  FREE(unique->stack);
2333  unique->stack = ALLOC(DdNodePtr,newsize + 1);
2334  if (unique->stack == NULL) {
2335  unique->errorCode = CUDD_MEMORY_OUT;
2336  return(0);
2337  }
2338  unique->stack[0] = NULL; /* to suppress harmless UMR */
2339  unique->memused +=
2340  (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
2341  * sizeof(DdNode *);
2342  }
2343  for (i = 0; i < oldsize; i++) {
2344  newsubtables[i].slots = unique->subtableZ[i].slots;
2345  newsubtables[i].shift = unique->subtableZ[i].shift;
2346  newsubtables[i].keys = unique->subtableZ[i].keys;
2347  newsubtables[i].maxKeys = unique->subtableZ[i].maxKeys;
2348  newsubtables[i].dead = unique->subtableZ[i].dead;
2349  newsubtables[i].nodelist = unique->subtableZ[i].nodelist;
2350  newperm[i] = unique->permZ[i];
2351  newinvperm[i] = unique->invpermZ[i];
2352  }
2353  for (i = oldsize; i <= index; i++) {
2354  newsubtables[i].slots = numSlots;
2355  newsubtables[i].shift = sizeof(int) * 8 -
2356  cuddComputeFloorLog2(numSlots);
2357  newsubtables[i].keys = 0;
2358  newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
2359  newsubtables[i].dead = 0;
2360  newperm[i] = i;
2361  newinvperm[i] = i;
2362  newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
2363  if (newnodelist == NULL) {
2364  unique->errorCode = CUDD_MEMORY_OUT;
2365  return(0);
2366  }
2367  for (j = 0; (unsigned) j < numSlots; j++) {
2368  newnodelist[j] = NULL;
2369  }
2370  }
2371  FREE(unique->subtableZ);
2372  unique->subtableZ = newsubtables;
2373  unique->maxSizeZ = newsize;
2374  FREE(unique->permZ);
2375  unique->permZ = newperm;
2376  FREE(unique->invpermZ);
2377  unique->invpermZ = newinvperm;
2378  }
2379  unique->slots += (index + 1 - unique->sizeZ) * numSlots;
2380  ddFixLimits(unique);
2381  unique->sizeZ = index + 1;
2382 
2383  /* Now that the table is in a coherent state, update the ZDD
2384  ** universe. We need to temporarily disable reordering,
2385  ** because we cannot reorder without universe in place.
2386  */
2387 
2388  reorderSave = unique->autoDynZ;
2389  unique->autoDynZ = 0;
2390  cuddZddFreeUniv(unique);
2391  if (!cuddZddInitUniv(unique)) {
2392  unique->autoDynZ = reorderSave;
2393  return(0);
2394  }
2395  unique->autoDynZ = reorderSave;
2396 
2397  return(1);
2398 
2399 } /* end of cuddResizeTableZdd */
2400 
2401 
2413 void
2415  DdManager *unique)
2416 {
2417  int i;
2418 
2419  unique->maxCacheHard = unique->cacheSlots - 1;
2420  unique->cacheSlack = - (int) (unique->cacheSlots + 1);
2421  for (i = 0; i < unique->size; i++) {
2422  unique->subtables[i].maxKeys <<= 2;
2423  }
2424  unique->gcFrac = DD_GC_FRAC_MIN;
2425  unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
2426  cuddShrinkDeathRow(unique);
2427  (void) fprintf(unique->err,"Slowing down table growth: ");
2428  (void) fprintf(unique->err,"GC fraction = %.2f\t", unique->gcFrac);
2429  (void) fprintf(unique->err,"minDead = %u\n", unique->minDead);
2430 
2431 } /* end of cuddSlowTableGrowth */
2432 
2433 
2434 /*---------------------------------------------------------------------------*/
2435 /* Definition of static functions */
2436 /*---------------------------------------------------------------------------*/
2437 
2438 
2450 static void
2452  DdManager * unique,
2453  int i)
2454 {
2455  unsigned int slots, oldslots;
2456  int shift, oldshift;
2457  int j, pos;
2458  DdNodePtr *nodelist, *oldnodelist;
2459  DdNode *node, *next;
2460  extern DD_OOMFP MMoutOfMemory;
2461  DD_OOMFP saveHandler;
2462 
2463  if (unique->slots > unique->looseUpTo) {
2464  unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
2465 #ifdef DD_VERBOSE
2466  if (unique->gcFrac == DD_GC_FRAC_HI) {
2467  (void) fprintf(unique->err,"GC fraction = %.2f\t",
2468  DD_GC_FRAC_LO);
2469  (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
2470  }
2471 #endif
2472  unique->gcFrac = DD_GC_FRAC_LO;
2473  }
2474 
2475  assert(i != CUDD_MAXINDEX);
2476  oldslots = unique->subtableZ[i].slots;
2477  oldshift = unique->subtableZ[i].shift;
2478  oldnodelist = unique->subtableZ[i].nodelist;
2479 
2480  /* Compute the new size of the subtable. Normally, we just
2481  ** double. However, after reordering, a table may be severely
2482  ** overloaded. Therefore, we iterate. */
2483  slots = oldslots;
2484  shift = oldshift;
2485  do {
2486  slots <<= 1;
2487  shift--;
2488  } while (slots * DD_MAX_SUBTABLE_DENSITY < unique->subtableZ[i].keys);
2489 
2490  saveHandler = MMoutOfMemory;
2491  MMoutOfMemory = Cudd_OutOfMem;
2492  nodelist = ALLOC(DdNodePtr, slots);
2493  MMoutOfMemory = saveHandler;
2494  if (nodelist == NULL) {
2495  (void) fprintf(unique->err,
2496  "Unable to resize ZDD subtable %d for lack of memory.\n",
2497  i);
2498  (void) cuddGarbageCollect(unique,1);
2499  for (j = 0; j < unique->sizeZ; j++) {
2500  unique->subtableZ[j].maxKeys <<= 1;
2501  }
2502  return;
2503  }
2504  unique->subtableZ[i].nodelist = nodelist;
2505  unique->subtableZ[i].slots = slots;
2506  unique->subtableZ[i].shift = shift;
2507  unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
2508  for (j = 0; (unsigned) j < slots; j++) {
2509  nodelist[j] = NULL;
2510  }
2511  for (j = 0; (unsigned) j < oldslots; j++) {
2512  node = oldnodelist[j];
2513  while (node != NULL) {
2514  next = node->next;
2515  pos = ddHash(cuddT(node), cuddE(node), shift);
2516  node->next = nodelist[pos];
2517  nodelist[pos] = node;
2518  node = next;
2519  }
2520  }
2521  FREE(oldnodelist);
2522 
2523 #ifdef DD_VERBOSE
2524  (void) fprintf(unique->err,
2525  "rehashing layer %d: keys %d dead %d new size %d\n",
2526  i, unique->subtableZ[i].keys,
2527  unique->subtableZ[i].dead, slots);
2528 #endif
2529 
2530  /* Update global data. */
2531  unique->memused += (slots - oldslots) * sizeof(DdNode *);
2532  unique->slots += (slots - oldslots);
2533  ddFixLimits(unique);
2534 
2535 } /* end of ddRehashZdd */
2536 
2537 
2554 static int
2556  DdManager * unique,
2557  int index,
2558  int amount)
2559 {
2560  DdSubtable *newsubtables;
2561  DdNodePtr *newnodelist;
2562  DdNodePtr *newvars;
2563  DdNode *sentinel = &(unique->sentinel);
2564  int oldsize,newsize;
2565  int i,j,reorderSave;
2566  int numSlots = unique->initSlots;
2567  int *newperm, *newinvperm, *newmap;
2568  DdNode *one, *zero;
2569 
2570  oldsize = unique->size;
2571  /* Easy case: there is still room in the current table. */
2572  if (index >= 0 && index < unique->maxSize) {
2573  for (i = oldsize; i <= index; i++) {
2574  unique->subtables[i].slots = numSlots;
2575  unique->subtables[i].shift = sizeof(int) * 8 -
2576  cuddComputeFloorLog2(numSlots);
2577  unique->subtables[i].keys = 0;
2578  unique->subtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
2579  unique->subtables[i].dead = 0;
2580  unique->subtables[i].bindVar = 0;
2582  unique->subtables[i].pairIndex = 0;
2583  unique->subtables[i].varHandled = 0;
2585 
2586  unique->perm[i] = i;
2587  unique->invperm[i] = i;
2588  newnodelist = unique->subtables[i].nodelist =
2589  ALLOC(DdNodePtr, numSlots);
2590  if (newnodelist == NULL) {
2591  for (j = oldsize; j < i; j++) {
2592  FREE(unique->subtables[j].nodelist);
2593  }
2594  unique->errorCode = CUDD_MEMORY_OUT;
2595  return(0);
2596  }
2597  for (j = 0; j < numSlots; j++) {
2598  newnodelist[j] = sentinel;
2599  }
2600  }
2601  if (unique->map != NULL) {
2602  for (i = oldsize; i <= index; i++) {
2603  unique->map[i] = i;
2604  }
2605  }
2606  } else {
2607  /* The current table is too small: we need to allocate a new,
2608  ** larger one; move all old subtables, and initialize the new
2609  ** subtables up to index included.
2610  */
2611  newsize = (index < 0) ? amount : index + amount;
2612 #ifdef DD_VERBOSE
2613  (void) fprintf(unique->err,
2614  "Increasing the table size from %d to %d\n",
2615  unique->maxSize, newsize);
2616 #endif
2617  newsubtables = ALLOC(DdSubtable,newsize);
2618  if (newsubtables == NULL) {
2619  unique->errorCode = CUDD_MEMORY_OUT;
2620  return(0);
2621  }
2622  newvars = ALLOC(DdNodePtr,newsize);
2623  if (newvars == NULL) {
2624  FREE(newsubtables);
2625  unique->errorCode = CUDD_MEMORY_OUT;
2626  return(0);
2627  }
2628  newperm = ALLOC(int,newsize);
2629  if (newperm == NULL) {
2630  FREE(newsubtables);
2631  FREE(newvars);
2632  unique->errorCode = CUDD_MEMORY_OUT;
2633  return(0);
2634  }
2635  newinvperm = ALLOC(int,newsize);
2636  if (newinvperm == NULL) {
2637  FREE(newsubtables);
2638  FREE(newvars);
2639  FREE(newperm);
2640  unique->errorCode = CUDD_MEMORY_OUT;
2641  return(0);
2642  }
2643  if (unique->map != NULL) {
2644  newmap = ALLOC(int,newsize);
2645  if (newmap == NULL) {
2646  FREE(newsubtables);
2647  FREE(newvars);
2648  FREE(newperm);
2649  FREE(newinvperm);
2650  unique->errorCode = CUDD_MEMORY_OUT;
2651  return(0);
2652  }
2653  unique->memused += (newsize - unique->maxSize) * sizeof(int);
2654  }
2655  unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
2656  sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
2657  if (newsize > unique->maxSizeZ) {
2658  FREE(unique->stack);
2659  unique->stack = ALLOC(DdNodePtr,newsize + 1);
2660  if (unique->stack == NULL) {
2661  FREE(newsubtables);
2662  FREE(newvars);
2663  FREE(newperm);
2664  FREE(newinvperm);
2665  if (unique->map != NULL) {
2666  FREE(newmap);
2667  }
2668  unique->errorCode = CUDD_MEMORY_OUT;
2669  return(0);
2670  }
2671  unique->stack[0] = NULL; /* to suppress harmless UMR */
2672  unique->memused +=
2673  (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
2674  * sizeof(DdNode *);
2675  }
2676  for (i = 0; i < oldsize; i++) {
2677  newsubtables[i].slots = unique->subtables[i].slots;
2678  newsubtables[i].shift = unique->subtables[i].shift;
2679  newsubtables[i].keys = unique->subtables[i].keys;
2680  newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
2681  newsubtables[i].dead = unique->subtables[i].dead;
2682  newsubtables[i].nodelist = unique->subtables[i].nodelist;
2683  newsubtables[i].bindVar = unique->subtables[i].bindVar;
2684  newsubtables[i].varType = unique->subtables[i].varType;
2685  newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
2686  newsubtables[i].varHandled = unique->subtables[i].varHandled;
2687  newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
2688 
2689  newvars[i] = unique->vars[i];
2690  newperm[i] = unique->perm[i];
2691  newinvperm[i] = unique->invperm[i];
2692  }
2693  for (i = oldsize; i <= index; i++) {
2694  newsubtables[i].slots = numSlots;
2695  newsubtables[i].shift = sizeof(int) * 8 -
2696  cuddComputeFloorLog2(numSlots);
2697  newsubtables[i].keys = 0;
2698  newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
2699  newsubtables[i].dead = 0;
2700  newsubtables[i].bindVar = 0;
2701  newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
2702  newsubtables[i].pairIndex = 0;
2703  newsubtables[i].varHandled = 0;
2704  newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
2705 
2706  newperm[i] = i;
2707  newinvperm[i] = i;
2708  newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
2709  if (newnodelist == NULL) {
2710  unique->errorCode = CUDD_MEMORY_OUT;
2711  return(0);
2712  }
2713  for (j = 0; j < numSlots; j++) {
2714  newnodelist[j] = sentinel;
2715  }
2716  }
2717  if (unique->map != NULL) {
2718  for (i = 0; i < oldsize; i++) {
2719  newmap[i] = unique->map[i];
2720  }
2721  for (i = oldsize; i <= index; i++) {
2722  newmap[i] = i;
2723  }
2724  FREE(unique->map);
2725  unique->map = newmap;
2726  }
2727  FREE(unique->subtables);
2728  unique->subtables = newsubtables;
2729  unique->maxSize = newsize;
2730  FREE(unique->vars);
2731  unique->vars = newvars;
2732  FREE(unique->perm);
2733  unique->perm = newperm;
2734  FREE(unique->invperm);
2735  unique->invperm = newinvperm;
2736  }
2737 
2738  /* Now that the table is in a coherent state, create the new
2739  ** projection functions. We need to temporarily disable reordering,
2740  ** because we cannot reorder without projection functions in place.
2741  **/
2742  if (index >= 0) {
2743  one = unique->one;
2744  zero = Cudd_Not(one);
2745 
2746  unique->size = index + 1;
2747  if (unique->tree != NULL) {
2748  unique->tree->size = ddMax(unique->tree->size, unique->size);
2749  }
2750  unique->slots += (index + 1 - oldsize) * numSlots;
2751  ddFixLimits(unique);
2752 
2753  reorderSave = unique->autoDyn;
2754  unique->autoDyn = 0;
2755  for (i = oldsize; i <= index; i++) {
2756  unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
2757  if (unique->vars[i] == NULL) {
2758  unique->autoDyn = reorderSave;
2759  for (j = oldsize; j < i; j++) {
2760  Cudd_IterDerefBdd(unique,unique->vars[j]);
2761  cuddDeallocNode(unique,unique->vars[j]);
2762  unique->vars[j] = NULL;
2763  }
2764  for (j = oldsize; j <= index; j++) {
2765  FREE(unique->subtables[j].nodelist);
2766  unique->subtables[j].nodelist = NULL;
2767  }
2768  unique->size = oldsize;
2769  unique->slots -= (index + 1 - oldsize) * numSlots;
2770  ddFixLimits(unique);
2771  return(0);
2772  }
2773  cuddRef(unique->vars[i]);
2774  }
2775  unique->autoDyn = reorderSave;
2776  }
2777 
2778  return(1);
2779 
2780 } /* end of ddResizeTable */
2781 
2782 
2795 static int
2797  DdManager * table,
2798  DdNode * node)
2799 {
2800  int i,j;
2801  int slots;
2802  DdNodePtr *nodelist;
2803  DdNode *f;
2804 
2805  for (i = cuddI(table,node->index) - 1; i >= 0; i--) {
2806  nodelist = table->subtables[i].nodelist;
2807  slots = table->subtables[i].slots;
2808 
2809  for (j = 0; j < slots; j++) {
2810  f = nodelist[j];
2811  while (cuddT(f) > node) {
2812  f = f->next;
2813  }
2814  while (cuddT(f) == node && Cudd_Regular(cuddE(f)) > node) {
2815  f = f->next;
2816  }
2817  if (cuddT(f) == node && Cudd_Regular(cuddE(f)) == node) {
2818  return(1);
2819  }
2820  }
2821  }
2822 
2823  return(0);
2824 
2825 } /* end of cuddFindParent */
2826 
2827 
2841 DD_INLINE
2842 static void
2844  DdManager *unique)
2845 {
2846  unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
2847  unique->cacheSlack = (int) ddMin(unique->maxCacheHard,
2848  DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots) -
2849  2 * (int) unique->cacheSlots;
2850  if (unique->cacheSlots < unique->slots/2 && unique->cacheSlack >= 0)
2851  cuddCacheResize(unique);
2852  return;
2853 
2854 } /* end of ddFixLimits */
2855 
2856 
2857 #ifndef DD_UNSORTED_FREE_LIST
2858 #ifdef DD_RED_BLACK_FREE_LIST
2859 
2871 static void
2872 cuddOrderedInsert(
2873  DdNodePtr * root,
2874  DdNodePtr node)
2875 {
2876  DdNode *scan;
2877  DdNodePtr *scanP;
2878  DdNodePtr *stack[DD_STACK_SIZE];
2879  int stackN = 0;
2880 
2881  scanP = root;
2882  while ((scan = *scanP) != NULL) {
2883  stack[stackN++] = scanP;
2884  if (DD_INSERT_COMPARE(node, scan) == 0) { /* add to page list */
2885  DD_NEXT(node) = DD_NEXT(scan);
2886  DD_NEXT(scan) = node;
2887  return;
2888  }
2889  scanP = (node < scan) ? &DD_LEFT(scan) : &DD_RIGHT(scan);
2890  }
2891  DD_RIGHT(node) = DD_LEFT(node) = DD_NEXT(node) = NULL;
2892  DD_COLOR(node) = DD_RED;
2893  *scanP = node;
2894  stack[stackN] = &node;
2895  cuddDoRebalance(stack,stackN);
2896 
2897 } /* end of cuddOrderedInsert */
2898 
2899 
2920 static DdNode *
2921 cuddOrderedThread(
2922  DdNode * root,
2923  DdNode * list)
2924 {
2925  DdNode *current, *next, *prev, *end;
2926 
2927  current = root;
2928  /* The first word in the node is used to implement a stack that holds
2929  ** the nodes from the root of the tree to the current node. Here we
2930  ** put the root of the tree at the bottom of the stack.
2931  */
2932  *((DdNodePtr *) current) = NULL;
2933 
2934  while (current != NULL) {
2935  if (DD_RIGHT(current) != NULL) {
2936  /* If possible, we follow the "right" link. Eventually we'll
2937  ** find the node with the largest address in the current tree.
2938  ** In this phase we use the first word of a node to implemen
2939  ** a stack of the nodes on the path from the root to "current".
2940  ** Also, we disconnect the "right" pointers to indicate that
2941  ** we have already followed them.
2942  */
2943  next = DD_RIGHT(current);
2944  DD_RIGHT(current) = NULL;
2945  *((DdNodePtr *)next) = current;
2946  current = next;
2947  } else {
2948  /* We can't proceed along the "right" links any further.
2949  ** Hence "current" is the largest element in the current tree.
2950  ** We make this node the new head of "list". (Repeating this
2951  ** operation until the tree is empty yields the desired linear
2952  ** threading of all nodes.)
2953  */
2954  prev = *((DdNodePtr *) current); /* save prev node on stack in prev */
2955  /* Traverse the linked list of current until the end. */
2956  for (end = current; DD_NEXT(end) != NULL; end = DD_NEXT(end));
2957  DD_NEXT(end) = list; /* attach "list" at end and make */
2958  list = current; /* "current" the new head of "list" */
2959  /* Now, if current has a "left" child, we push it on the stack.
2960  ** Otherwise, we just continue with the parent of "current".
2961  */
2962  if (DD_LEFT(current) != NULL) {
2963  next = DD_LEFT(current);
2964  *((DdNodePtr *) next) = prev;
2965  current = next;
2966  } else {
2967  current = prev;
2968  }
2969  }
2970  }
2971 
2972  return(list);
2973 
2974 } /* end of cuddOrderedThread */
2975 
2976 
2988 DD_INLINE
2989 static void
2990 cuddRotateLeft(
2991  DdNodePtr * nodeP)
2992 {
2993  DdNode *newRoot;
2994  DdNode *oldRoot = *nodeP;
2995 
2996  *nodeP = newRoot = DD_RIGHT(oldRoot);
2997  DD_RIGHT(oldRoot) = DD_LEFT(newRoot);
2998  DD_LEFT(newRoot) = oldRoot;
2999 
3000 } /* end of cuddRotateLeft */
3001 
3002 
3014 DD_INLINE
3015 static void
3016 cuddRotateRight(
3017  DdNodePtr * nodeP)
3018 {
3019  DdNode *newRoot;
3020  DdNode *oldRoot = *nodeP;
3021 
3022  *nodeP = newRoot = DD_LEFT(oldRoot);
3023  DD_LEFT(oldRoot) = DD_RIGHT(newRoot);
3024  DD_RIGHT(newRoot) = oldRoot;
3025 
3026 } /* end of cuddRotateRight */
3027 
3028 
3040 static void
3041 cuddDoRebalance(
3042  DdNodePtr ** stack,
3043  int stackN)
3044 {
3045  DdNodePtr *xP, *parentP, *grandpaP;
3046  DdNode *x, *y, *parent, *grandpa;
3047 
3048  xP = stack[stackN];
3049  x = *xP;
3050  /* Work our way back up, re-balancing the tree. */
3051  while (--stackN >= 0) {
3052  parentP = stack[stackN];
3053  parent = *parentP;
3054  if (DD_IS_BLACK(parent)) break;
3055  /* Since the root is black, here a non-null grandparent exists. */
3056  grandpaP = stack[stackN-1];
3057  grandpa = *grandpaP;
3058  if (parent == DD_LEFT(grandpa)) {
3059  y = DD_RIGHT(grandpa);
3060  if (y != NULL && DD_IS_RED(y)) {
3061  DD_COLOR(parent) = DD_BLACK;
3062  DD_COLOR(y) = DD_BLACK;
3063  DD_COLOR(grandpa) = DD_RED;
3064  x = grandpa;
3065  stackN--;
3066  } else {
3067  if (x == DD_RIGHT(parent)) {
3068  cuddRotateLeft(parentP);
3069  DD_COLOR(x) = DD_BLACK;
3070  } else {
3071  DD_COLOR(parent) = DD_BLACK;
3072  }
3073  DD_COLOR(grandpa) = DD_RED;
3074  cuddRotateRight(grandpaP);
3075  break;
3076  }
3077  } else {
3078  y = DD_LEFT(grandpa);
3079  if (y != NULL && DD_IS_RED(y)) {
3080  DD_COLOR(parent) = DD_BLACK;
3081  DD_COLOR(y) = DD_BLACK;
3082  DD_COLOR(grandpa) = DD_RED;
3083  x = grandpa;
3084  stackN--;
3085  } else {
3086  if (x == DD_LEFT(parent)) {
3087  cuddRotateRight(parentP);
3088  DD_COLOR(x) = DD_BLACK;
3089  } else {
3090  DD_COLOR(parent) = DD_BLACK;
3091  }
3092  DD_COLOR(grandpa) = DD_RED;
3093  cuddRotateLeft(grandpaP);
3094  }
3095  }
3096  }
3097  DD_COLOR(*(stack[0])) = DD_BLACK;
3098 
3099 } /* end of cuddDoRebalance */
3100 #endif
3101 #endif
3102 
3103 
3117 static void
3119  DdManager *dd,
3120  MtrNode *treenode)
3121 {
3122  MtrNode *auxnode = treenode;
3123 
3124  while (auxnode != NULL) {
3125  auxnode->low = dd->perm[auxnode->index];
3126  if (auxnode->child != NULL) {
3127  ddPatchTree(dd, auxnode->child);
3128  }
3129  auxnode = auxnode->younger;
3130  }
3131 
3132  return;
3133 
3134 } /* end of ddPatchTree */
3135 
3136 
3137 #ifdef DD_DEBUG
3138 
3149 static int
3150 cuddCheckCollisionOrdering(
3151  DdManager *unique,
3152  int i,
3153  int j)
3154 {
3155  int slots;
3156  DdNode *node, *next;
3157  DdNodePtr *nodelist;
3158  DdNode *sentinel = &(unique->sentinel);
3159 
3160  nodelist = unique->subtables[i].nodelist;
3161  slots = unique->subtables[i].slots;
3162  node = nodelist[j];
3163  if (node == sentinel) return(1);
3164  next = node->next;
3165  while (next != sentinel) {
3166  if (cuddT(node) < cuddT(next) ||
3167  (cuddT(node) == cuddT(next) && cuddE(node) < cuddE(next))) {
3168  (void) fprintf(unique->err,
3169  "Unordered list: index %u, position %d\n", i, j);
3170  return(0);
3171  }
3172  node = next;
3173  next = node->next;
3174  }
3175  return(1);
3176 
3177 } /* end of cuddCheckCollisionOrdering */
3178 #endif
3179 
3180 
3181 
3182 
3194 static void
3196  DdManager *unique /* manager */,
3197  int i /* table in which the problem occurred */,
3198  const char *caller /* procedure that detected the problem */)
3199 {
3200  if (i == CUDD_CONST_INDEX) {
3201  (void) fprintf(unique->err,
3202  "%s: problem in constants\n", caller);
3203  } else if (i != -1) {
3204  (void) fprintf(unique->err,
3205  "%s: problem in table %d\n", caller, i);
3206  }
3207  (void) fprintf(unique->err, " dead count != deleted\n");
3208  (void) fprintf(unique->err, " This problem is often due to a missing \
3209 call to Cudd_Ref\n or to an extra call to Cudd_RecursiveDeref.\n \
3210 See the CUDD Programmer's Guide for additional details.");
3211  abort();
3212 
3213 } /* end of ddReportRefMess */
static void ddReportRefMess(DdManager *unique, int i, const char *caller)
Definition: cuddTable.c:3195
void Cudd_IterDerefBdd(DdManager *table, DdNode *n)
Definition: cuddRef.c:213
DdHalfWord ref
Definition: cudd.h:272
unsigned int Cudd_Prime(unsigned int p)
Definition: cuddTable.c:185
#define DD_MAXREF
Definition: cuddInt.h:101
#define cuddRef(n)
Definition: cuddInt.h:557
Cudd_AggregationType groupcheck
Definition: cuddInt.h:410
unsigned int keys
Definition: cuddInt.h:314
void Cudd_RecursiveDerefZdd(DdManager *table, DdNode *n)
Definition: cuddRef.c:381
void cuddZddFreeUniv(DdManager *zdd)
Definition: cuddInit.c:294
static int ddResizeTable(DdManager *unique, int index, int amount)
Definition: cuddTable.c:2555
#define ddHash(f, g, s)
Definition: cuddInt.h:696
union DdNode::@0 type
#define cuddDeref(n)
Definition: cuddInt.h:577
void Cudd_OutOfMem(long size)
Definition: cuddUtil.c:2845
unsigned long reordTime
Definition: cuddInt.h:434
Cudd_ReorderingType autoMethod
Definition: cuddInt.h:402
#define cuddIZ(dd, index)
Definition: cuddInt.h:677
#define DD_SIFT_MAX_VAR
Definition: cuddInt.h:148
unsigned int peakLiveNodes
Definition: cuddInt.h:445
int maxSizeZ
Definition: cuddInt.h:348
double allocated
Definition: cuddInt.h:365
void Cudd_RecursiveDeref(DdManager *table, DdNode *n)
Definition: cuddRef.c:150
DdNode * f
Definition: cuddInt.h:302
int * map
Definition: cuddInt.h:374
Definition: cudd.h:270
static void ddPatchTree(DdManager *dd, MtrNode *treenode)
Definition: cuddTable.c:3118
#define Cudd_Not(node)
Definition: cudd.h:354
unsigned int deadZ
Definition: cuddInt.h:356
MtrHalfWord size
Definition: mtr.h:129
#define FREE(obj)
Definition: util.h:80
DdNode * data
Definition: cuddInt.h:304
int siftMaxSwap
Definition: cuddInt.h:396
DdHook * preReorderingHook
Definition: cuddInt.h:421
unsigned deadMask
Definition: cuddInt.h:387
unsigned long startTime
Definition: cuddInt.h:426
int * invpermZ
Definition: cuddInt.h:372
int reordCycle
Definition: cuddInt.h:399
unsigned int bits[2]
Definition: cuddTable.c:109
#define assert(ex)
Definition: util.h:141
int size
Definition: cuddInt.h:345
double gcFrac
Definition: cuddInt.h:359
struct DdManager DdManager
Definition: cudd.h:280
unsigned int maxCacheHard
Definition: cuddInt.h:343
DdNode * cuddUniqueConst(DdManager *unique, CUDD_VALUE_TYPE value)
Definition: cuddTable.c:1479
unsigned int slots
Definition: cuddInt.h:352
ptruint h
Definition: cuddInt.h:303
#define Cudd_Regular(node)
Definition: cudd.h:384
void cuddReclaim(DdManager *table, DdNode *n)
Definition: cuddRef.c:580
double maxGrowthAlt
Definition: cuddInt.h:398
int realign
Definition: cuddInt.h:404
double maxGrowth
Definition: cuddInt.h:397
void cuddShrinkSubtable(DdManager *unique, int i)
Definition: cuddTable.c:1731
FILE * err
Definition: cuddInt.h:424
DdNode * g
Definition: cuddInt.h:302
int garbageCollections
Definition: cuddInt.h:432
int populationSize
Definition: cuddInt.h:414
void Mtr_FreeTree(MtrNode *node)
Definition: mtrBasic.c:187
#define DD_FIRST_REORDER
Definition: cuddInt.h:152
Cudd_ReorderingType autoMethodZ
Definition: cuddInt.h:403
int bindVar
Definition: cuddInt.h:318
DdSubtable * subtables
Definition: cuddInt.h:349
int * permZ
Definition: cuddInt.h:370
DdNode * DdNodePtr
Definition: cuddInt.h:253
#define DD_EPSILON
Definition: cuddInt.h:110
MtrNode * tree
Definition: cuddInt.h:408
struct DdSubtable DdSubtable
#define DD_MAX_SUBTABLE_DENSITY
Definition: cuddInt.h:127
#define DD_DEFAULT_RECOMB
Definition: cuddInt.h:150
DD_HFP f
Definition: cuddInt.h:241
DdNode ** deathRow
Definition: cuddInt.h:384
DdNode ** stack
Definition: cuddInt.h:364
void(* DD_OOMFP)(long)
Definition: cudd.h:311
static char rcsid [] DD_UNUSED
Definition: cuddTable.c:121
union hack hack
void cuddCacheResize(DdManager *table)
Definition: cuddCache.c:889
struct DdNode DdNode
Definition: cudd.h:262
#define cuddV(node)
Definition: cuddInt.h:641
#define DD_INLINE
Definition: cuddInt.h:91
unsigned int countDead
Definition: cuddInt.h:407
struct MtrNode * younger
Definition: mtr.h:134
unsigned int initSlots
Definition: cuddInt.h:363
unsigned int randomizeOrder
Definition: cuddInt.h:416
Cudd_VariableType varType
Definition: cuddInt.h:320
int reordered
Definition: cuddInt.h:392
unsigned int nextDyn
Definition: cuddInt.h:406
#define DD_GC_FRAC_HI
Definition: cuddInt.h:135
unsigned int dead
Definition: cuddInt.h:355
static DdNode * one
Definition: cuddSat.c:105
void cuddFreeTable(DdManager *unique)
Definition: cuddTable.c:692
DdNode * cuddUniqueInterIVO(DdManager *unique, int index, DdNode *T, DdNode *E)
Definition: cuddTable.c:1333
unsigned int cacheSlots
Definition: cuddInt.h:337
DdNode * cuddZddProduct(DdManager *dd, DdNode *f, DdNode *g)
Definition: cuddZddFuncs.c:376
int cuddDestroySubtables(DdManager *unique, int n)
Definition: cuddTable.c:2137
unsigned int maxLive
Definition: cuddInt.h:357
CUDD_VALUE_TYPE value
Definition: cudd.h:275
int recomb
Definition: cuddInt.h:411
DdNode sentinel
Definition: cuddInt.h:328
int cuddResizeTableZdd(DdManager *unique, int index)
Definition: cuddTable.c:2270
char * stash
Definition: cuddInt.h:382
MtrHalfWord index
Definition: mtr.h:130
DdHook * postReorderingHook
Definition: cuddInt.h:422
unsigned int keys
Definition: cuddInt.h:353
int cuddGarbageCollect(DdManager *unique, int clearCache)
Definition: cuddTable.c:762
#define ALLOC(type, num)
Definition: util.h:76
unsigned int dead
Definition: cuddInt.h:316
FILE * out
Definition: cuddInt.h:423
#define DD_SIFT_MAX_SWAPS
Definition: cuddInt.h:149
int realignZ
Definition: cuddInt.h:405
DdCache * cache
Definition: cuddInt.h:336
DdNode * next
Definition: cudd.h:273
#define DD_GC_FRAC_LO
Definition: cuddInt.h:134
Cudd_LazyGroupType varToBeGrouped
Definition: cuddInt.h:323
int maxSize
Definition: cuddInt.h:347
#define ddAbs(x)
Definition: cuddInt.h:799
static int cuddFindParent(DdManager *table, DdNode *node)
Definition: cuddTable.c:2796
void cuddRehash(DdManager *unique, int i)
Definition: cuddTable.c:1559
unsigned int maxKeys
Definition: cuddInt.h:315
long * linear
Definition: cuddInt.h:378
int cuddInsertSubtables(DdManager *unique, int n, int level)
Definition: cuddTable.c:1824
int gcEnabled
Definition: cuddInt.h:360
#define ddMax(x, y)
Definition: cuddInt.h:785
int symmviolation
Definition: cuddInt.h:412
int numberXovers
Definition: cuddInt.h:415
#define CUDD_CONST_INDEX
Definition: cudd.h:113
DdNode ** nodelist
Definition: cuddInt.h:311
int Cudd_DebugCheck(DdManager *table)
Definition: cuddCheck.c:138
int linearSize
Definition: cuddInt.h:376
#define ddMin(x, y)
Definition: cuddInt.h:771
MtrHalfWord low
Definition: mtr.h:128
DdLocalCache * localCaches
Definition: cuddInt.h:417
DdNode * cuddBddIteRecur(DdManager *dd, DdNode *f, DdNode *g, DdNode *h)
Definition: cuddBddIte.c:742
#define DD_MAX_CACHE_TO_SLOTS_RATIO
Definition: cuddInt.h:145
int cacheSlack
Definition: cuddInt.h:342
long util_cpu_time(void)
Definition: cpu_time.c:34
#define cuddT(node)
Definition: cuddInt.h:609
static void ddRehashZdd(DdManager *unique, int i)
Definition: cuddTable.c:2451
CUDD_VALUE_TYPE value
Definition: cuddTable.c:108
int nextDead
Definition: cuddInt.h:386
void(* MMoutOfMemory)(long)
Definition: safe_mem.c:32
Definition: mtr.h:126
int varHandled
Definition: cuddInt.h:322
void cuddLocalCacheClearDead(DdManager *manager)
Definition: cuddLCache.c:371
#define cuddDeallocNode(unique, node)
Definition: cuddInt.h:520
#define DD_GC_FRAC_MIN
Definition: cuddInt.h:136
void cuddReclaimZdd(DdManager *table, DdNode *n)
Definition: cuddRef.c:634
int Cudd_Reserve(DdManager *manager, int amount)
Definition: cuddTable.c:230
unsigned long GCTime
Definition: cuddInt.h:433
int Cudd_RemoveHook(DdManager *dd, DD_HFP f, Cudd_HookType where)
Definition: cuddAPI.c:3631
#define ddEqualVal(x, y, e)
Definition: cuddInt.h:814
DdNode * cuddZddGetNode(DdManager *zdd, int id, DdNode *T, DdNode *E)
Definition: cuddTable.c:1050
int cuddZddInitUniv(DdManager *zdd)
Definition: cuddInit.c:245
DdNode ** memoryList
Definition: cuddInt.h:380
void cuddSlowTableGrowth(DdManager *unique)
Definition: cuddTable.c:2414
unsigned int maxReorderings
Definition: cuddInt.h:394
unsigned long memused
Definition: cuddInt.h:429
int siftMaxVar
Definition: cuddInt.h:395
#define cuddI(dd, index)
Definition: cuddInt.h:659
int Cudd_zddReduceHeap(DdManager *table, Cudd_ReorderingType heuristic, int minsize)
Definition: cuddZddReord.c:167
unsigned int ptruint
Definition: cuddInt.h:250
DdNode * cuddZddUnion(DdManager *zdd, DdNode *P, DdNode *Q)
Definition: cuddZddSetop.c:549
#define CUDD_VALUE_TYPE
Definition: cudd.h:90
int deathRowDepth
Definition: cuddInt.h:385
DdNode * nextFree
Definition: cuddInt.h:381
void cuddCacheFlush(DdManager *table)
Definition: cuddCache.c:1004
struct DdHook * next
Definition: cuddInt.h:242
#define DD_DEFAULT_RESIZE
Definition: cuddInt.h:103
VOID_OR_INT abort()
void cuddClearDeathRow(DdManager *table)
Definition: cuddRef.c:722
int sizeZ
Definition: cuddInt.h:346
DdHalfWord index
Definition: cudd.h:271
unsigned int looseUpTo
Definition: cuddInt.h:361
unsigned int slots
Definition: cuddInt.h:313
unsigned int reorderings
Definition: cuddInt.h:393
DdNode ** vars
Definition: cuddInt.h:373
double cacheMisses
Definition: cuddInt.h:339
unsigned long maxmemhard
Definition: cuddInt.h:431
DdHook * postGCHook
Definition: cuddInt.h:420
static DdNode * zero
Definition: cuddSat.c:105
int pairIndex
Definition: cuddInt.h:321
int Cudd_CheckKeys(DdManager *table)
Definition: cuddCheck.c:460
#define DD_MAX_REORDER_GROWTH
Definition: cuddInt.h:151
#define cuddClean(p)
Definition: cuddInt.h:757
CUDD_VALUE_TYPE epsilon
Definition: cuddInt.h:390
DdNode * one
Definition: cuddInt.h:329
#define CUDD_MAXINDEX
Definition: cudd.h:108
MtrNode * treeZ
Definition: cuddInt.h:409
int autoDynZ
Definition: cuddInt.h:401
#define cuddE(node)
Definition: cuddInt.h:625
static DD_INLINE void ddFixLimits(DdManager *unique)
Definition: cuddTable.c:2843
DdNode * cuddZddGetNodeIVO(DdManager *dd, int index, DdNode *g, DdNode *h)
Definition: cuddTable.c:1083
int arcviolation
Definition: cuddInt.h:413
int * invperm
Definition: cuddInt.h:371
DdSubtable constants
Definition: cuddInt.h:351
double cachedeletions
Definition: cuddInt.h:440
static int result
Definition: cuddGenetic.c:121
DdNode * cuddUniqueInter(DdManager *unique, int index, DdNode *T, DdNode *E)
Definition: cuddTable.c:1137
unsigned long maxmem
Definition: cuddInt.h:430
DdManager * cuddInitTable(unsigned int numVars, unsigned int numVarsZ, unsigned int numSlots, unsigned int looseUpTo)
Definition: cuddTable.c:380
int cuddComputeFloorLog2(unsigned int value)
Definition: cuddCache.c:1036
int Cudd_ReduceHeap(DdManager *table, Cudd_ReorderingType heuristic, int minsize)
Definition: cuddReorder.c:172
#define DD_MEM_CHUNK
Definition: cuddInt.h:105
#define cuddAdjust(x)
Definition: cuddInt.h:932
int autoDyn
Definition: cuddInt.h:400
DdNode * cuddUniqueInterZdd(DdManager *unique, int index, DdNode *T, DdNode *E)
Definition: cuddTable.c:1372
#define DD_ONE(dd)
Definition: cuddInt.h:864
int shift
Definition: cuddInt.h:312
DdCache * acache
Definition: cuddInt.h:335
void cuddShrinkDeathRow(DdManager *table)
Definition: cuddRef.c:684
unsigned int keysZ
Definition: cuddInt.h:354
DdHook * preGCHook
Definition: cuddInt.h:419
struct MtrNode * child
Definition: mtr.h:132
int * perm
Definition: cuddInt.h:369
unsigned long timeLimit
Definition: cuddInt.h:427
DdNode * cuddAllocNode(DdManager *unique)
Definition: cuddTable.c:266
Cudd_ErrorType errorCode
Definition: cuddInt.h:425
unsigned int minDead
Definition: cuddInt.h:358
#define cuddSatInc(x)
Definition: cuddInt.h:831
double reclaimed
Definition: cuddInt.h:367
DdSubtable * subtableZ
Definition: cuddInt.h:350
DdNode ** univ
Definition: cuddInt.h:375
if(DEFINED IN_SOURCE_BUILD) set(LLVM_LINK_COMPONENTS BitWriter Core IPO IrReader InstCombine Instrumentation Target Linker Analysis ScalarOpts Support Svf Cudd) add_llvm_tool(dvf dda.cpp) else() add_executable(dvf dda.cpp) target_link_libraries(dvf Svf Cudd $
Definition: CMakeLists.txt:2
#define DD_NON_CONSTANT
Definition: cuddInt.h:124
#define DD_ZERO(dd)
Definition: cuddInt.h:880