You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3213 lines
94 KiB

  1. /**CFile***********************************************************************
  2. FileName [cuddTable.c]
  3. PackageName [cudd]
  4. Synopsis [Unique table management functions.]
  5. Description [External procedures included in this module:
  6. <ul>
  7. <li> Cudd_Prime()
  8. <li> Cudd_Reserve()
  9. </ul>
  10. Internal procedures included in this module:
  11. <ul>
  12. <li> cuddAllocNode()
  13. <li> cuddInitTable()
  14. <li> cuddFreeTable()
  15. <li> cuddGarbageCollect()
  16. <li> cuddZddGetNode()
  17. <li> cuddZddGetNodeIVO()
  18. <li> cuddUniqueInter()
  19. <li> cuddUniqueInterIVO()
  20. <li> cuddUniqueInterZdd()
  21. <li> cuddUniqueConst()
  22. <li> cuddRehash()
  23. <li> cuddShrinkSubtable()
  24. <li> cuddInsertSubtables()
  25. <li> cuddDestroySubtables()
  26. <li> cuddResizeTableZdd()
  27. <li> cuddSlowTableGrowth()
  28. </ul>
  29. Static procedures included in this module:
  30. <ul>
  31. <li> ddRehashZdd()
  32. <li> ddResizeTable()
  33. <li> cuddFindParent()
  34. <li> cuddOrderedInsert()
  35. <li> cuddOrderedThread()
  36. <li> cuddRotateLeft()
  37. <li> cuddRotateRight()
  38. <li> cuddDoRebalance()
  39. <li> cuddCheckCollisionOrdering()
  40. </ul>]
  41. SeeAlso []
  42. Author [Fabio Somenzi]
  43. Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
  44. All rights reserved.
  45. Redistribution and use in source and binary forms, with or without
  46. modification, are permitted provided that the following conditions
  47. are met:
  48. Redistributions of source code must retain the above copyright
  49. notice, this list of conditions and the following disclaimer.
  50. Redistributions in binary form must reproduce the above copyright
  51. notice, this list of conditions and the following disclaimer in the
  52. documentation and/or other materials provided with the distribution.
  53. Neither the name of the University of Colorado nor the names of its
  54. contributors may be used to endorse or promote products derived from
  55. this software without specific prior written permission.
  56. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  57. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  58. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  59. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  60. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  61. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  62. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  63. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  64. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  65. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  66. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  67. POSSIBILITY OF SUCH DAMAGE.]
  68. ******************************************************************************/
  69. #include "util.h"
  70. #include "cuddInt.h"
  71. /*---------------------------------------------------------------------------*/
  72. /* Constant declarations */
  73. /*---------------------------------------------------------------------------*/
  74. #ifndef DD_UNSORTED_FREE_LIST
  75. #ifdef DD_RED_BLACK_FREE_LIST
  76. /* Constants for red/black trees. */
  77. #define DD_STACK_SIZE 128
  78. #define DD_RED 0
  79. #define DD_BLACK 1
  80. #define DD_PAGE_SIZE 8192
  81. #define DD_PAGE_MASK ~(DD_PAGE_SIZE - 1)
  82. #endif
  83. #endif
  84. /*---------------------------------------------------------------------------*/
  85. /* Stucture declarations */
  86. /*---------------------------------------------------------------------------*/
  87. /* This is a hack for when CUDD_VALUE_TYPE is double */
  88. typedef union hack {
  89. CUDD_VALUE_TYPE value;
  90. unsigned int bits[2];
  91. } hack;
  92. /*---------------------------------------------------------------------------*/
  93. /* Type declarations */
  94. /*---------------------------------------------------------------------------*/
  95. /*---------------------------------------------------------------------------*/
  96. /* Variable declarations */
  97. /*---------------------------------------------------------------------------*/
  98. #ifndef lint
  99. static char rcsid[] DD_UNUSED = "$Id: cuddTable.c,v 1.126 2012/02/05 01:07:19 fabio Exp $";
  100. #endif
  101. /*---------------------------------------------------------------------------*/
  102. /* Macro declarations */
  103. /*---------------------------------------------------------------------------*/
  104. #ifndef DD_UNSORTED_FREE_LIST
  105. #ifdef DD_RED_BLACK_FREE_LIST
  106. /* Macros for red/black trees. */
  107. #define DD_INSERT_COMPARE(x,y) \
  108. (((ptruint) (x) & DD_PAGE_MASK) - ((ptruint) (y) & DD_PAGE_MASK))
  109. #define DD_COLOR(p) ((p)->index)
  110. #define DD_IS_BLACK(p) ((p)->index == DD_BLACK)
  111. #define DD_IS_RED(p) ((p)->index == DD_RED)
  112. #define DD_LEFT(p) cuddT(p)
  113. #define DD_RIGHT(p) cuddE(p)
  114. #define DD_NEXT(p) ((p)->next)
  115. #endif
  116. #endif
  117. /**AutomaticStart*************************************************************/
  118. /*---------------------------------------------------------------------------*/
  119. /* Static function prototypes */
  120. /*---------------------------------------------------------------------------*/
  121. static void ddRehashZdd (DdManager *unique, int i);
  122. static int ddResizeTable (DdManager *unique, int index, int amount);
  123. static int cuddFindParent (DdManager *table, DdNode *node);
  124. DD_INLINE static void ddFixLimits (DdManager *unique);
  125. #ifdef DD_RED_BLACK_FREE_LIST
  126. static void cuddOrderedInsert (DdNodePtr *root, DdNodePtr node);
  127. static DdNode * cuddOrderedThread (DdNode *root, DdNode *list);
  128. static void cuddRotateLeft (DdNodePtr *nodeP);
  129. static void cuddRotateRight (DdNodePtr *nodeP);
  130. static void cuddDoRebalance (DdNodePtr **stack, int stackN);
  131. #endif
  132. static void ddPatchTree (DdManager *dd, MtrNode *treenode);
  133. #ifdef DD_DEBUG
  134. static int cuddCheckCollisionOrdering (DdManager *unique, int i, int j);
  135. #endif
  136. static void ddReportRefMess (DdManager *unique, int i, const char *caller);
  137. /**AutomaticEnd***************************************************************/
  138. /*---------------------------------------------------------------------------*/
  139. /* Definition of exported functions */
  140. /*---------------------------------------------------------------------------*/
  141. /**Function********************************************************************
  142. Synopsis [Returns the next prime &gt;= p.]
  143. Description []
  144. SideEffects [None]
  145. ******************************************************************************/
  146. unsigned int
  147. Cudd_Prime(
  148. unsigned int p)
  149. {
  150. int i,pn;
  151. p--;
  152. do {
  153. p++;
  154. if (p&1) {
  155. pn = 1;
  156. i = 3;
  157. while ((unsigned) (i * i) <= p) {
  158. if (p % i == 0) {
  159. pn = 0;
  160. break;
  161. }
  162. i += 2;
  163. }
  164. } else {
  165. pn = 0;
  166. }
  167. } while (!pn);
  168. return(p);
  169. } /* end of Cudd_Prime */
  170. /**Function********************************************************************
  171. Synopsis [Expand manager without creating variables.]
  172. Description [Expand a manager by a specified number of subtables without
  173. actually creating new variables. This function can be used to reduce the
  174. frequency of resizing when an estimate of the number of variables is
  175. available. One would call this function instead of passing the number
  176. of variables to Cudd_Init if variables should not be created right away
  177. of if the estimate on their number became available only after the manager
  178. has been created. Returns 1 if successful; 0 otherwise.]
  179. SideEffects [None]
  180. SeeAlso [Cudd_Init]
  181. ******************************************************************************/
  182. int
  183. Cudd_Reserve(
  184. DdManager *manager,
  185. int amount)
  186. {
  187. int currentSize = manager->size;
  188. if (amount < 0)
  189. return(0);
  190. if (currentSize + amount < currentSize) /* overflow */
  191. return(0);
  192. if (amount <= manager->maxSize - manager->size)
  193. return(1);
  194. return ddResizeTable(manager, -1, amount);
  195. } /* end of Cudd_Reserve */
  196. /*---------------------------------------------------------------------------*/
  197. /* Definition of internal functions */
  198. /*---------------------------------------------------------------------------*/
  199. /**Function********************************************************************
  200. Synopsis [Fast storage allocation for DdNodes in the table.]
  201. Description [Fast storage allocation for DdNodes in the table. The
  202. first 4 bytes of a chunk contain a pointer to the next block; the
  203. rest contains DD_MEM_CHUNK spaces for DdNodes. Returns a pointer to
  204. a new node if successful; NULL is memory is full.]
  205. SideEffects [None]
  206. SeeAlso [cuddDynamicAllocNode]
  207. ******************************************************************************/
  208. DdNode *
  209. cuddAllocNode(
  210. DdManager * unique)
  211. {
  212. int i;
  213. DdNodePtr *mem;
  214. DdNode *list, *node;
  215. extern DD_OOMFP MMoutOfMemory;
  216. DD_OOMFP saveHandler;
  217. if (unique->nextFree == NULL) { /* free list is empty */
  218. /* Check for exceeded limits. */
  219. if ((unique->keys - unique->dead) + (unique->keysZ - unique->deadZ) >
  220. unique->maxLive) {
  221. unique->errorCode = CUDD_TOO_MANY_NODES;
  222. return(NULL);
  223. }
  224. if (util_cpu_time() - unique->startTime > unique->timeLimit) {
  225. unique->errorCode = CUDD_TIMEOUT_EXPIRED;
  226. return(NULL);
  227. }
  228. if (unique->stash == NULL || unique->memused > unique->maxmemhard) {
  229. (void) cuddGarbageCollect(unique,1);
  230. mem = NULL;
  231. }
  232. if (unique->nextFree == NULL) {
  233. if (unique->memused > unique->maxmemhard) {
  234. unique->errorCode = CUDD_MAX_MEM_EXCEEDED;
  235. return(NULL);
  236. }
  237. /* Try to allocate a new block. */
  238. saveHandler = MMoutOfMemory;
  239. MMoutOfMemory = Cudd_OutOfMem;
  240. mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
  241. MMoutOfMemory = saveHandler;
  242. if (mem == NULL) {
  243. /* No more memory: Try collecting garbage. If this succeeds,
  244. ** we end up with mem still NULL, but unique->nextFree !=
  245. ** NULL. */
  246. if (cuddGarbageCollect(unique,1) == 0) {
  247. /* Last resort: Free the memory stashed away, if there
  248. ** any. If this succeeeds, mem != NULL and
  249. ** unique->nextFree still NULL. */
  250. if (unique->stash != NULL) {
  251. FREE(unique->stash);
  252. unique->stash = NULL;
  253. /* Inhibit resizing of tables. */
  254. cuddSlowTableGrowth(unique);
  255. /* Now try again. */
  256. mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
  257. }
  258. if (mem == NULL) {
  259. /* Out of luck. Call the default handler to do
  260. ** whatever it specifies for a failed malloc.
  261. ** If this handler returns, then set error code,
  262. ** print warning, and return. */
  263. (*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1));
  264. unique->errorCode = CUDD_MEMORY_OUT;
  265. #ifdef DD_VERBOSE
  266. (void) fprintf(unique->err,
  267. "cuddAllocNode: out of memory");
  268. (void) fprintf(unique->err, "Memory in use = %lu\n",
  269. unique->memused);
  270. #endif
  271. return(NULL);
  272. }
  273. }
  274. }
  275. if (mem != NULL) { /* successful allocation; slice memory */
  276. ptruint offset;
  277. unique->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode);
  278. mem[0] = (DdNodePtr) unique->memoryList;
  279. unique->memoryList = mem;
  280. /* Here we rely on the fact that a DdNode is as large
  281. ** as 4 pointers. */
  282. offset = (ptruint) mem & (sizeof(DdNode) - 1);
  283. mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
  284. assert(((ptruint) mem & (sizeof(DdNode) - 1)) == 0);
  285. list = (DdNode *) mem;
  286. i = 1;
  287. do {
  288. list[i - 1].ref = 0;
  289. list[i - 1].next = &list[i];
  290. } while (++i < DD_MEM_CHUNK);
  291. list[DD_MEM_CHUNK-1].ref = 0;
  292. list[DD_MEM_CHUNK-1].next = NULL;
  293. unique->nextFree = &list[0];
  294. }
  295. }
  296. }
  297. unique->allocated++;
  298. node = unique->nextFree;
  299. unique->nextFree = node->next;
  300. return(node);
  301. } /* end of cuddAllocNode */
  302. /**Function********************************************************************
  303. Synopsis [Creates and initializes the unique table.]
  304. Description [Creates and initializes the unique table. Returns a pointer
  305. to the table if successful; NULL otherwise.]
  306. SideEffects [None]
  307. SeeAlso [Cudd_Init cuddFreeTable]
  308. ******************************************************************************/
  309. DdManager *
  310. cuddInitTable(
  311. unsigned int numVars /* Initial number of BDD variables (and subtables) */,
  312. unsigned int numVarsZ /* Initial number of ZDD variables (and subtables) */,
  313. unsigned int numSlots /* Initial size of the BDD subtables */,
  314. unsigned int looseUpTo /* Limit for fast table growth */)
  315. {
  316. DdManager *unique = ALLOC(DdManager,1);
  317. int i, j;
  318. DdNodePtr *nodelist;
  319. DdNode *sentinel;
  320. unsigned int slots;
  321. int shift;
  322. if (unique == NULL) {
  323. return(NULL);
  324. }
  325. sentinel = &(unique->sentinel);
  326. sentinel->ref = 0;
  327. sentinel->index = 0;
  328. cuddT(sentinel) = NULL;
  329. cuddE(sentinel) = NULL;
  330. sentinel->next = NULL;
  331. unique->epsilon = DD_EPSILON;
  332. unique->size = numVars;
  333. unique->sizeZ = numVarsZ;
  334. unique->maxSize = ddMax(DD_DEFAULT_RESIZE, numVars);
  335. unique->maxSizeZ = ddMax(DD_DEFAULT_RESIZE, numVarsZ);
  336. /* Adjust the requested number of slots to a power of 2. */
  337. slots = 8;
  338. while (slots < numSlots) {
  339. slots <<= 1;
  340. }
  341. unique->initSlots = slots;
  342. shift = sizeof(int) * 8 - cuddComputeFloorLog2(slots);
  343. unique->slots = (numVars + numVarsZ + 1) * slots;
  344. unique->keys = 0;
  345. unique->maxLive = ~0; /* very large number */
  346. unique->keysZ = 0;
  347. unique->dead = 0;
  348. unique->deadZ = 0;
  349. unique->gcFrac = DD_GC_FRAC_HI;
  350. unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
  351. unique->looseUpTo = looseUpTo;
  352. unique->gcEnabled = 1;
  353. unique->allocated = 0;
  354. unique->reclaimed = 0;
  355. unique->subtables = ALLOC(DdSubtable,unique->maxSize);
  356. if (unique->subtables == NULL) {
  357. FREE(unique);
  358. return(NULL);
  359. }
  360. unique->subtableZ = ALLOC(DdSubtable,unique->maxSizeZ);
  361. if (unique->subtableZ == NULL) {
  362. FREE(unique->subtables);
  363. FREE(unique);
  364. return(NULL);
  365. }
  366. unique->perm = ALLOC(int,unique->maxSize);
  367. if (unique->perm == NULL) {
  368. FREE(unique->subtables);
  369. FREE(unique->subtableZ);
  370. FREE(unique);
  371. return(NULL);
  372. }
  373. unique->invperm = ALLOC(int,unique->maxSize);
  374. if (unique->invperm == NULL) {
  375. FREE(unique->subtables);
  376. FREE(unique->subtableZ);
  377. FREE(unique->perm);
  378. FREE(unique);
  379. return(NULL);
  380. }
  381. unique->permZ = ALLOC(int,unique->maxSizeZ);
  382. if (unique->permZ == NULL) {
  383. FREE(unique->subtables);
  384. FREE(unique->subtableZ);
  385. FREE(unique->perm);
  386. FREE(unique->invperm);
  387. FREE(unique);
  388. return(NULL);
  389. }
  390. unique->invpermZ = ALLOC(int,unique->maxSizeZ);
  391. if (unique->invpermZ == NULL) {
  392. FREE(unique->subtables);
  393. FREE(unique->subtableZ);
  394. FREE(unique->perm);
  395. FREE(unique->invperm);
  396. FREE(unique->permZ);
  397. FREE(unique);
  398. return(NULL);
  399. }
  400. unique->map = NULL;
  401. unique->stack = ALLOC(DdNodePtr,ddMax(unique->maxSize,unique->maxSizeZ)+1);
  402. if (unique->stack == NULL) {
  403. FREE(unique->subtables);
  404. FREE(unique->subtableZ);
  405. FREE(unique->perm);
  406. FREE(unique->invperm);
  407. FREE(unique->permZ);
  408. FREE(unique->invpermZ);
  409. FREE(unique);
  410. return(NULL);
  411. }
  412. unique->stack[0] = NULL; /* to suppress harmless UMR */
  413. #ifndef DD_NO_DEATH_ROW
  414. unique->deathRowDepth = 1 << cuddComputeFloorLog2(unique->looseUpTo >> 2);
  415. unique->deathRow = ALLOC(DdNodePtr,unique->deathRowDepth);
  416. if (unique->deathRow == NULL) {
  417. FREE(unique->subtables);
  418. FREE(unique->subtableZ);
  419. FREE(unique->perm);
  420. FREE(unique->invperm);
  421. FREE(unique->permZ);
  422. FREE(unique->invpermZ);
  423. FREE(unique->stack);
  424. FREE(unique);
  425. return(NULL);
  426. }
  427. for (i = 0; i < unique->deathRowDepth; i++) {
  428. unique->deathRow[i] = NULL;
  429. }
  430. unique->nextDead = 0;
  431. unique->deadMask = unique->deathRowDepth - 1;
  432. #endif
  433. for (i = 0; (unsigned) i < numVars; i++) {
  434. unique->subtables[i].slots = slots;
  435. unique->subtables[i].shift = shift;
  436. unique->subtables[i].keys = 0;
  437. unique->subtables[i].dead = 0;
  438. unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
  439. unique->subtables[i].bindVar = 0;
  440. unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
  441. unique->subtables[i].pairIndex = 0;
  442. unique->subtables[i].varHandled = 0;
  443. unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
  444. nodelist = unique->subtables[i].nodelist = ALLOC(DdNodePtr,slots);
  445. if (nodelist == NULL) {
  446. for (j = 0; j < i; j++) {
  447. FREE(unique->subtables[j].nodelist);
  448. }
  449. FREE(unique->subtables);
  450. FREE(unique->subtableZ);
  451. FREE(unique->perm);
  452. FREE(unique->invperm);
  453. FREE(unique->permZ);
  454. FREE(unique->invpermZ);
  455. FREE(unique->stack);
  456. FREE(unique);
  457. return(NULL);
  458. }
  459. for (j = 0; (unsigned) j < slots; j++) {
  460. nodelist[j] = sentinel;
  461. }
  462. unique->perm[i] = i;
  463. unique->invperm[i] = i;
  464. }
  465. for (i = 0; (unsigned) i < numVarsZ; i++) {
  466. unique->subtableZ[i].slots = slots;
  467. unique->subtableZ[i].shift = shift;
  468. unique->subtableZ[i].keys = 0;
  469. unique->subtableZ[i].dead = 0;
  470. unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
  471. nodelist = unique->subtableZ[i].nodelist = ALLOC(DdNodePtr,slots);
  472. if (nodelist == NULL) {
  473. for (j = 0; (unsigned) j < numVars; j++) {
  474. FREE(unique->subtables[j].nodelist);
  475. }
  476. FREE(unique->subtables);
  477. for (j = 0; j < i; j++) {
  478. FREE(unique->subtableZ[j].nodelist);
  479. }
  480. FREE(unique->subtableZ);
  481. FREE(unique->perm);
  482. FREE(unique->invperm);
  483. FREE(unique->permZ);
  484. FREE(unique->invpermZ);
  485. FREE(unique->stack);
  486. FREE(unique);
  487. return(NULL);
  488. }
  489. for (j = 0; (unsigned) j < slots; j++) {
  490. nodelist[j] = NULL;
  491. }
  492. unique->permZ[i] = i;
  493. unique->invpermZ[i] = i;
  494. }
  495. unique->constants.slots = slots;
  496. unique->constants.shift = shift;
  497. unique->constants.keys = 0;
  498. unique->constants.dead = 0;
  499. unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
  500. nodelist = unique->constants.nodelist = ALLOC(DdNodePtr,slots);
  501. if (nodelist == NULL) {
  502. for (j = 0; (unsigned) j < numVars; j++) {
  503. FREE(unique->subtables[j].nodelist);
  504. }
  505. FREE(unique->subtables);
  506. for (j = 0; (unsigned) j < numVarsZ; j++) {
  507. FREE(unique->subtableZ[j].nodelist);
  508. }
  509. FREE(unique->subtableZ);
  510. FREE(unique->perm);
  511. FREE(unique->invperm);
  512. FREE(unique->permZ);
  513. FREE(unique->invpermZ);
  514. FREE(unique->stack);
  515. FREE(unique);
  516. return(NULL);
  517. }
  518. for (j = 0; (unsigned) j < slots; j++) {
  519. nodelist[j] = NULL;
  520. }
  521. unique->memoryList = NULL;
  522. unique->nextFree = NULL;
  523. unique->memused = sizeof(DdManager) + (unique->maxSize + unique->maxSizeZ)
  524. * (sizeof(DdSubtable) + 2 * sizeof(int)) + (numVars + 1) *
  525. slots * sizeof(DdNodePtr) +
  526. (ddMax(unique->maxSize,unique->maxSizeZ) + 1) * sizeof(DdNodePtr);
  527. #ifndef DD_NO_DEATH_ROW
  528. unique->memused += unique->deathRowDepth * sizeof(DdNodePtr);
  529. #endif
  530. /* Initialize fields concerned with automatic dynamic reordering. */
  531. unique->reordered = 0;
  532. unique->reorderings = 0;
  533. unique->maxReorderings = ~0;
  534. unique->siftMaxVar = DD_SIFT_MAX_VAR;
  535. unique->siftMaxSwap = DD_SIFT_MAX_SWAPS;
  536. unique->maxGrowth = DD_MAX_REORDER_GROWTH;
  537. unique->maxGrowthAlt = 2.0 * DD_MAX_REORDER_GROWTH;
  538. unique->reordCycle = 0; /* do not use alternate threshold */
  539. unique->autoDyn = 0; /* initially disabled */
  540. unique->autoDynZ = 0; /* initially disabled */
  541. unique->autoMethod = CUDD_REORDER_SIFT;
  542. unique->autoMethodZ = CUDD_REORDER_SIFT;
  543. unique->realign = 0; /* initially disabled */
  544. unique->realignZ = 0; /* initially disabled */
  545. unique->nextDyn = DD_FIRST_REORDER;
  546. unique->countDead = ~0;
  547. unique->tree = NULL;
  548. unique->treeZ = NULL;
  549. unique->groupcheck = CUDD_GROUP_CHECK7;
  550. unique->recomb = DD_DEFAULT_RECOMB;
  551. unique->symmviolation = 0;
  552. unique->arcviolation = 0;
  553. unique->populationSize = 0;
  554. unique->numberXovers = 0;
  555. unique->randomizeOrder = 0;
  556. unique->linear = NULL;
  557. unique->linearSize = 0;
  558. /* Initialize ZDD universe. */
  559. unique->univ = (DdNodePtr *)NULL;
  560. /* Initialize auxiliary fields. */
  561. unique->localCaches = NULL;
  562. unique->preGCHook = NULL;
  563. unique->postGCHook = NULL;
  564. unique->preReorderingHook = NULL;
  565. unique->postReorderingHook = NULL;
  566. unique->out = stdout;
  567. unique->err = stderr;
  568. unique->errorCode = CUDD_NO_ERROR;
  569. unique->startTime = util_cpu_time();
  570. unique->timeLimit = ~0UL;
  571. /* Initialize statistical counters. */
  572. unique->maxmemhard = ~ 0UL;
  573. unique->garbageCollections = 0;
  574. unique->GCTime = 0;
  575. unique->reordTime = 0;
  576. #ifdef DD_STATS
  577. unique->nodesDropped = 0;
  578. unique->nodesFreed = 0;
  579. #endif
  580. unique->peakLiveNodes = 0;
  581. #ifdef DD_UNIQUE_PROFILE
  582. unique->uniqueLookUps = 0;
  583. unique->uniqueLinks = 0;
  584. #endif
  585. #ifdef DD_COUNT
  586. unique->recursiveCalls = 0;
  587. unique->swapSteps = 0;
  588. #ifdef DD_STATS
  589. unique->nextSample = 250000;
  590. #endif
  591. #endif
  592. return(unique);
  593. } /* end of cuddInitTable */
  594. /**Function********************************************************************
  595. Synopsis [Frees the resources associated to a unique table.]
  596. Description []
  597. SideEffects [None]
  598. SeeAlso [cuddInitTable]
  599. ******************************************************************************/
  600. void
  601. cuddFreeTable(
  602. DdManager * unique)
  603. {
  604. DdNodePtr *next;
  605. DdNodePtr *memlist = unique->memoryList;
  606. int i;
  607. if (unique->univ != NULL) cuddZddFreeUniv(unique);
  608. while (memlist != NULL) {
  609. next = (DdNodePtr *) memlist[0]; /* link to next block */
  610. FREE(memlist);
  611. memlist = next;
  612. }
  613. unique->nextFree = NULL;
  614. unique->memoryList = NULL;
  615. for (i = 0; i < unique->size; i++) {
  616. FREE(unique->subtables[i].nodelist);
  617. }
  618. for (i = 0; i < unique->sizeZ; i++) {
  619. FREE(unique->subtableZ[i].nodelist);
  620. }
  621. FREE(unique->constants.nodelist);
  622. FREE(unique->subtables);
  623. FREE(unique->subtableZ);
  624. FREE(unique->acache);
  625. FREE(unique->perm);
  626. FREE(unique->permZ);
  627. FREE(unique->invperm);
  628. FREE(unique->invpermZ);
  629. FREE(unique->vars);
  630. if (unique->map != NULL) FREE(unique->map);
  631. FREE(unique->stack);
  632. #ifndef DD_NO_DEATH_ROW
  633. FREE(unique->deathRow);
  634. #endif
  635. if (unique->tree != NULL) Mtr_FreeTree(unique->tree);
  636. if (unique->treeZ != NULL) Mtr_FreeTree(unique->treeZ);
  637. if (unique->linear != NULL) FREE(unique->linear);
  638. while (unique->preGCHook != NULL)
  639. Cudd_RemoveHook(unique,unique->preGCHook->f,CUDD_PRE_GC_HOOK);
  640. while (unique->postGCHook != NULL)
  641. Cudd_RemoveHook(unique,unique->postGCHook->f,CUDD_POST_GC_HOOK);
  642. while (unique->preReorderingHook != NULL)
  643. Cudd_RemoveHook(unique,unique->preReorderingHook->f,
  644. CUDD_PRE_REORDERING_HOOK);
  645. while (unique->postReorderingHook != NULL)
  646. Cudd_RemoveHook(unique,unique->postReorderingHook->f,
  647. CUDD_POST_REORDERING_HOOK);
  648. FREE(unique);
  649. } /* end of cuddFreeTable */
  650. /**Function********************************************************************
  651. Synopsis [Performs garbage collection on the unique tables.]
  652. Description [Performs garbage collection on the BDD and ZDD unique tables.
  653. If clearCache is 0, the cache is not cleared. This should only be
  654. specified if the cache has been cleared right before calling
  655. cuddGarbageCollect. (As in the case of dynamic reordering.)
  656. Returns the total number of deleted nodes.]
  657. SideEffects [None]
  658. SeeAlso []
  659. ******************************************************************************/
  660. int
  661. cuddGarbageCollect(
  662. DdManager * unique,
  663. int clearCache)
  664. {
  665. DdHook *hook;
  666. DdCache *cache = unique->cache;
  667. DdNode *sentinel = &(unique->sentinel);
  668. DdNodePtr *nodelist;
  669. int i, j, deleted, totalDeleted, totalDeletedZ;
  670. DdCache *c;
  671. DdNode *node,*next;
  672. DdNodePtr *lastP;
  673. int slots;
  674. unsigned long localTime;
  675. #ifndef DD_UNSORTED_FREE_LIST
  676. #ifdef DD_RED_BLACK_FREE_LIST
  677. DdNodePtr tree;
  678. #else
  679. DdNodePtr *memListTrav, *nxtNode;
  680. DdNode *downTrav, *sentry;
  681. int k;
  682. #endif
  683. #endif
  684. #ifndef DD_NO_DEATH_ROW
  685. cuddClearDeathRow(unique);
  686. #endif
  687. hook = unique->preGCHook;
  688. while (hook != NULL) {
  689. int res = (hook->f)(unique,"DD",NULL);
  690. if (res == 0) return(0);
  691. hook = hook->next;
  692. }
  693. if (unique->dead + unique->deadZ == 0) {
  694. hook = unique->postGCHook;
  695. while (hook != NULL) {
  696. int res = (hook->f)(unique,"DD",NULL);
  697. if (res == 0) return(0);
  698. hook = hook->next;
  699. }
  700. return(0);
  701. }
  702. /* If many nodes are being reclaimed, we want to resize the tables
  703. ** more aggressively, to reduce the frequency of garbage collection.
  704. */
  705. if (clearCache && unique->gcFrac == DD_GC_FRAC_LO &&
  706. unique->slots <= unique->looseUpTo && unique->stash != NULL) {
  707. unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
  708. #ifdef DD_VERBOSE
  709. (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_HI);
  710. (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
  711. #endif
  712. unique->gcFrac = DD_GC_FRAC_HI;
  713. return(0);
  714. }
  715. localTime = util_cpu_time();
  716. unique->garbageCollections++;
  717. #ifdef DD_VERBOSE
  718. (void) fprintf(unique->err,
  719. "garbage collecting (%d dead BDD nodes out of %d, min %d)...",
  720. unique->dead, unique->keys, unique->minDead);
  721. (void) fprintf(unique->err,
  722. " (%d dead ZDD nodes out of %d)...",
  723. unique->deadZ, unique->keysZ);
  724. #endif
  725. /* Remove references to garbage collected nodes from the cache. */
  726. if (clearCache) {
  727. slots = unique->cacheSlots;
  728. for (i = 0; i < slots; i++) {
  729. c = &cache[i];
  730. if (c->data != NULL) {
  731. if (cuddClean(c->f)->ref == 0 ||
  732. cuddClean(c->g)->ref == 0 ||
  733. (((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) ||
  734. (c->data != DD_NON_CONSTANT &&
  735. Cudd_Regular(c->data)->ref == 0)) {
  736. c->data = NULL;
  737. unique->cachedeletions++;
  738. }
  739. }
  740. }
  741. cuddLocalCacheClearDead(unique);
  742. }
  743. /* Now return dead nodes to free list. Count them for sanity check. */
  744. totalDeleted = 0;
  745. #ifndef DD_UNSORTED_FREE_LIST
  746. #ifdef DD_RED_BLACK_FREE_LIST
  747. tree = NULL;
  748. #endif
  749. #endif
  750. for (i = 0; i < unique->size; i++) {
  751. if (unique->subtables[i].dead == 0) continue;
  752. nodelist = unique->subtables[i].nodelist;
  753. deleted = 0;
  754. slots = unique->subtables[i].slots;
  755. for (j = 0; j < slots; j++) {
  756. lastP = &(nodelist[j]);
  757. node = *lastP;
  758. while (node != sentinel) {
  759. next = node->next;
  760. if (node->ref == 0) {
  761. deleted++;
  762. #ifndef DD_UNSORTED_FREE_LIST
  763. #ifdef DD_RED_BLACK_FREE_LIST
  764. cuddOrderedInsert(&tree,node);
  765. #endif
  766. #else
  767. cuddDeallocNode(unique,node);
  768. #endif
  769. } else {
  770. *lastP = node;
  771. lastP = &(node->next);
  772. }
  773. node = next;
  774. }
  775. *lastP = sentinel;
  776. }
  777. if ((unsigned) deleted != unique->subtables[i].dead) {
  778. ddReportRefMess(unique, i, "cuddGarbageCollect");
  779. }
  780. totalDeleted += deleted;
  781. unique->subtables[i].keys -= deleted;
  782. unique->subtables[i].dead = 0;
  783. }
  784. if (unique->constants.dead != 0) {
  785. nodelist = unique->constants.nodelist;
  786. deleted = 0;
  787. slots = unique->constants.slots;
  788. for (j = 0; j < slots; j++) {
  789. lastP = &(nodelist[j]);
  790. node = *lastP;
  791. while (node != NULL) {
  792. next = node->next;
  793. if (node->ref == 0) {
  794. deleted++;
  795. #ifndef DD_UNSORTED_FREE_LIST
  796. #ifdef DD_RED_BLACK_FREE_LIST
  797. cuddOrderedInsert(&tree,node);
  798. #endif
  799. #else
  800. cuddDeallocNode(unique,node);
  801. #endif
  802. } else {
  803. *lastP = node;
  804. lastP = &(node->next);
  805. }
  806. node = next;
  807. }
  808. *lastP = NULL;
  809. }
  810. if ((unsigned) deleted != unique->constants.dead) {
  811. ddReportRefMess(unique, CUDD_CONST_INDEX, "cuddGarbageCollect");
  812. }
  813. totalDeleted += deleted;
  814. unique->constants.keys -= deleted;
  815. unique->constants.dead = 0;
  816. }
  817. if ((unsigned) totalDeleted != unique->dead) {
  818. ddReportRefMess(unique, -1, "cuddGarbageCollect");
  819. }
  820. unique->keys -= totalDeleted;
  821. unique->dead = 0;
  822. #ifdef DD_STATS
  823. unique->nodesFreed += (double) totalDeleted;
  824. #endif
  825. totalDeletedZ = 0;
  826. for (i = 0; i < unique->sizeZ; i++) {
  827. if (unique->subtableZ[i].dead == 0) continue;
  828. nodelist = unique->subtableZ[i].nodelist;
  829. deleted = 0;
  830. slots = unique->subtableZ[i].slots;
  831. for (j = 0; j < slots; j++) {
  832. lastP = &(nodelist[j]);
  833. node = *lastP;
  834. while (node != NULL) {
  835. next = node->next;
  836. if (node->ref == 0) {
  837. deleted++;
  838. #ifndef DD_UNSORTED_FREE_LIST
  839. #ifdef DD_RED_BLACK_FREE_LIST
  840. cuddOrderedInsert(&tree,node);
  841. #endif
  842. #else
  843. cuddDeallocNode(unique,node);
  844. #endif
  845. } else {
  846. *lastP = node;
  847. lastP = &(node->next);
  848. }
  849. node = next;
  850. }
  851. *lastP = NULL;
  852. }
  853. if ((unsigned) deleted != unique->subtableZ[i].dead) {
  854. ddReportRefMess(unique, i, "cuddGarbageCollect");
  855. }
  856. totalDeletedZ += deleted;
  857. unique->subtableZ[i].keys -= deleted;
  858. unique->subtableZ[i].dead = 0;
  859. }
  860. /* No need to examine the constant table for ZDDs.
  861. ** If we did we should be careful not to count whatever dead
  862. ** nodes we found there among the dead ZDD nodes. */
  863. if ((unsigned) totalDeletedZ != unique->deadZ) {
  864. ddReportRefMess(unique, -1, "cuddGarbageCollect");
  865. }
  866. unique->keysZ -= totalDeletedZ;
  867. unique->deadZ = 0;
  868. #ifdef DD_STATS
  869. unique->nodesFreed += (double) totalDeletedZ;
  870. #endif
  871. #ifndef DD_UNSORTED_FREE_LIST
  872. #ifdef DD_RED_BLACK_FREE_LIST
  873. unique->nextFree = cuddOrderedThread(tree,unique->nextFree);
  874. #else
  875. memListTrav = unique->memoryList;
  876. sentry = NULL;
  877. while (memListTrav != NULL) {
  878. ptruint offset;
  879. nxtNode = (DdNodePtr *)memListTrav[0];
  880. offset = (ptruint) memListTrav & (sizeof(DdNode) - 1);
  881. memListTrav += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
  882. downTrav = (DdNode *)memListTrav;
  883. k = 0;
  884. do {
  885. if (downTrav[k].ref == 0) {
  886. if (sentry == NULL) {
  887. unique->nextFree = sentry = &downTrav[k];
  888. } else {
  889. /* First hook sentry->next to the dead node and then
  890. ** reassign sentry to the dead node. */
  891. sentry = (sentry->next = &downTrav[k]);
  892. }
  893. }
  894. } while (++k < DD_MEM_CHUNK);
  895. memListTrav = nxtNode;
  896. }
  897. sentry->next = NULL;
  898. #endif
  899. #endif
  900. unique->GCTime += util_cpu_time() - localTime;
  901. hook = unique->postGCHook;
  902. while (hook != NULL) {
  903. int res = (hook->f)(unique,"DD",NULL);
  904. if (res == 0) return(0);
  905. hook = hook->next;
  906. }
  907. #ifdef DD_VERBOSE
  908. (void) fprintf(unique->err," done\n");
  909. #endif
  910. return(totalDeleted+totalDeletedZ);
  911. } /* end of cuddGarbageCollect */
  912. /**Function********************************************************************
  913. Synopsis [Wrapper for cuddUniqueInterZdd.]
  914. Description [Wrapper for cuddUniqueInterZdd, which applies the ZDD
  915. reduction rule. Returns a pointer to the result node under normal
  916. conditions; NULL if reordering occurred or memory was exhausted.]
  917. SideEffects [None]
  918. SeeAlso [cuddUniqueInterZdd]
  919. ******************************************************************************/
  920. DdNode *
  921. cuddZddGetNode(
  922. DdManager * zdd,
  923. int id,
  924. DdNode * T,
  925. DdNode * E)
  926. {
  927. DdNode *node;
  928. if (T == DD_ZERO(zdd))
  929. return(E);
  930. node = cuddUniqueInterZdd(zdd, id, T, E);
  931. return(node);
  932. } /* end of cuddZddGetNode */
  933. /**Function********************************************************************
  934. Synopsis [Wrapper for cuddUniqueInterZdd that is independent of variable
  935. ordering.]
  936. Description [Wrapper for cuddUniqueInterZdd that is independent of
  937. variable ordering (IVO). This function does not require parameter
  938. index to precede the indices of the top nodes of g and h in the
  939. variable order. Returns a pointer to the result node under normal
  940. conditions; NULL if reordering occurred or memory was exhausted.]
  941. SideEffects [None]
  942. SeeAlso [cuddZddGetNode cuddZddIsop]
  943. ******************************************************************************/
  944. DdNode *
  945. cuddZddGetNodeIVO(
  946. DdManager * dd,
  947. int index,
  948. DdNode * g,
  949. DdNode * h)
  950. {
  951. DdNode *f, *r, *t;
  952. DdNode *zdd_one = DD_ONE(dd);
  953. DdNode *zdd_zero = DD_ZERO(dd);
  954. f = cuddUniqueInterZdd(dd, index, zdd_one, zdd_zero);
  955. if (f == NULL) {
  956. return(NULL);
  957. }
  958. cuddRef(f);
  959. t = cuddZddProduct(dd, f, g);
  960. if (t == NULL) {
  961. Cudd_RecursiveDerefZdd(dd, f);
  962. return(NULL);
  963. }
  964. cuddRef(t);
  965. Cudd_RecursiveDerefZdd(dd, f);
  966. r = cuddZddUnion(dd, t, h);
  967. if (r == NULL) {
  968. Cudd_RecursiveDerefZdd(dd, t);
  969. return(NULL);
  970. }
  971. cuddRef(r);
  972. Cudd_RecursiveDerefZdd(dd, t);
  973. cuddDeref(r);
  974. return(r);
  975. } /* end of cuddZddGetNodeIVO */
  976. /**Function********************************************************************
  977. Synopsis [Checks the unique table for the existence of an internal node.]
  978. Description [Checks the unique table for the existence of an internal
  979. node. If it does not exist, it creates a new one. Does not
  980. modify the reference count of whatever is returned. A newly created
  981. internal node comes back with a reference count 0. For a newly
  982. created node, increments the reference counts of what T and E point
  983. to. Returns a pointer to the new node if successful; NULL if memory
  984. is exhausted or if reordering took place.]
  985. SideEffects [None]
  986. SeeAlso [cuddUniqueInterZdd]
  987. ******************************************************************************/
  988. DdNode *
  989. cuddUniqueInter(
  990. DdManager * unique,
  991. int index,
  992. DdNode * T,
  993. DdNode * E)
  994. {
  995. int pos;
  996. unsigned int level;
  997. int retval;
  998. DdNodePtr *nodelist;
  999. DdNode *looking;
  1000. DdNodePtr *previousP;
  1001. DdSubtable *subtable;
  1002. int gcNumber;
  1003. #ifdef DD_UNIQUE_PROFILE
  1004. unique->uniqueLookUps++;
  1005. #endif
  1006. if ((0x1ffffUL & (unsigned long) unique->cacheMisses) == 0) {
  1007. if (util_cpu_time() - unique->startTime > unique->timeLimit) {
  1008. unique->errorCode = CUDD_TIMEOUT_EXPIRED;
  1009. return(NULL);
  1010. }
  1011. }
  1012. if (index >= unique->size) {
  1013. int amount = ddMax(DD_DEFAULT_RESIZE,unique->size/20);
  1014. if (!ddResizeTable(unique,index,amount)) return(NULL);
  1015. }
  1016. level = unique->perm[index];
  1017. subtable = &(unique->subtables[level]);
  1018. #ifdef DD_DEBUG
  1019. assert(level < (unsigned) cuddI(unique,T->index));
  1020. assert(level < (unsigned) cuddI(unique,Cudd_Regular(E)->index));
  1021. #endif
  1022. pos = ddHash(T, E, subtable->shift);
  1023. nodelist = subtable->nodelist;
  1024. previousP = &(nodelist[pos]);
  1025. looking = *previousP;
  1026. while (T < cuddT(looking)) {
  1027. previousP = &(looking->next);
  1028. looking = *previousP;
  1029. #ifdef DD_UNIQUE_PROFILE
  1030. unique->uniqueLinks++;
  1031. #endif
  1032. }
  1033. while (T == cuddT(looking) && E < cuddE(looking)) {
  1034. previousP = &(looking->next);
  1035. looking = *previousP;
  1036. #ifdef DD_UNIQUE_PROFILE
  1037. unique->uniqueLinks++;
  1038. #endif
  1039. }
  1040. if (T == cuddT(looking) && E == cuddE(looking)) {
  1041. if (looking->ref == 0) {
  1042. cuddReclaim(unique,looking);
  1043. }
  1044. return(looking);
  1045. }
  1046. /* countDead is 0 if deads should be counted and ~0 if they should not. */
  1047. if (unique->autoDyn &&
  1048. unique->keys - (unique->dead & unique->countDead) >= unique->nextDyn &&
  1049. unique->maxReorderings > 0) {
  1050. unsigned long cpuTime;
  1051. #ifdef DD_DEBUG
  1052. retval = Cudd_DebugCheck(unique);
  1053. if (retval != 0) return(NULL);
  1054. retval = Cudd_CheckKeys(unique);
  1055. if (retval != 0) return(NULL);
  1056. #endif
  1057. retval = Cudd_ReduceHeap(unique,unique->autoMethod,10); /* 10 = whatever */
  1058. unique->maxReorderings--;
  1059. if (retval == 0) {
  1060. unique->reordered = 2;
  1061. } else if ((cpuTime = util_cpu_time()) - unique->startTime > unique->timeLimit) {
  1062. unique->errorCode = CUDD_TIMEOUT_EXPIRED;
  1063. unique->reordered = 0;
  1064. } else if (unique->timeLimit - (cpuTime - unique->startTime)
  1065. < unique->reordTime) {
  1066. unique->autoDyn = 0;
  1067. }
  1068. #ifdef DD_DEBUG
  1069. retval = Cudd_DebugCheck(unique);
  1070. if (retval != 0) unique->reordered = 2;
  1071. retval = Cudd_CheckKeys(unique);
  1072. if (retval != 0) unique->reordered = 2;
  1073. #endif
  1074. return(NULL);
  1075. }
  1076. if (subtable->keys > subtable->maxKeys) {
  1077. if (unique->gcEnabled &&
  1078. ((unique->dead > unique->minDead) ||
  1079. ((unique->dead > unique->minDead / 2) &&
  1080. (subtable->dead > subtable->keys * 0.95)))) { /* too many dead */
  1081. if (util_cpu_time() - unique->startTime > unique->timeLimit) {
  1082. unique->errorCode = CUDD_TIMEOUT_EXPIRED;
  1083. return(NULL);
  1084. }
  1085. (void) cuddGarbageCollect(unique,1);
  1086. } else {
  1087. cuddRehash(unique,(int)level);
  1088. }
  1089. /* Update pointer to insertion point. In the case of rehashing,
  1090. ** the slot may have changed. In the case of garbage collection,
  1091. ** the predecessor may have been dead. */
  1092. pos = ddHash(T, E, subtable->shift);
  1093. nodelist = subtable->nodelist;
  1094. previousP = &(nodelist[pos]);
  1095. looking = *previousP;
  1096. while (T < cuddT(looking)) {
  1097. previousP = &(looking->next);
  1098. looking = *previousP;
  1099. #ifdef DD_UNIQUE_PROFILE
  1100. unique->uniqueLinks++;
  1101. #endif
  1102. }
  1103. while (T == cuddT(looking) && E < cuddE(looking)) {
  1104. previousP = &(looking->next);
  1105. looking = *previousP;
  1106. #ifdef DD_UNIQUE_PROFILE
  1107. unique->uniqueLinks++;
  1108. #endif
  1109. }
  1110. }
  1111. gcNumber = unique->garbageCollections;
  1112. looking = cuddAllocNode(unique);
  1113. if (looking == NULL) {
  1114. return(NULL);
  1115. }
  1116. unique->keys++;
  1117. subtable->keys++;
  1118. if (gcNumber != unique->garbageCollections) {
  1119. DdNode *looking2;
  1120. pos = ddHash(T, E, subtable->shift);
  1121. nodelist = subtable->nodelist;
  1122. previousP = &(nodelist[pos]);
  1123. looking2 = *previousP;
  1124. while (T < cuddT(looking2)) {
  1125. previousP = &(looking2->next);
  1126. looking2 = *previousP;
  1127. #ifdef DD_UNIQUE_PROFILE
  1128. unique->uniqueLinks++;
  1129. #endif
  1130. }
  1131. while (T == cuddT(looking2) && E < cuddE(looking2)) {
  1132. previousP = &(looking2->next);
  1133. looking2 = *previousP;
  1134. #ifdef DD_UNIQUE_PROFILE
  1135. unique->uniqueLinks++;
  1136. #endif
  1137. }
  1138. }
  1139. looking->index = index;
  1140. cuddT(looking) = T;
  1141. cuddE(looking) = E;
  1142. looking->next = *previousP;
  1143. *previousP = looking;
  1144. cuddSatInc(T->ref); /* we know T is a regular pointer */
  1145. cuddRef(E);
  1146. #ifdef DD_DEBUG
  1147. cuddCheckCollisionOrdering(unique,level,pos);
  1148. #endif
  1149. return(looking);
  1150. } /* end of cuddUniqueInter */
  1151. /**Function********************************************************************
  1152. Synopsis [Wrapper for cuddUniqueInter that is independent of variable
  1153. ordering.]
  1154. Description [Wrapper for cuddUniqueInter that is independent of
  1155. variable ordering (IVO). This function does not require parameter
  1156. index to precede the indices of the top nodes of T and E in the
  1157. variable order. Returns a pointer to the result node under normal
  1158. conditions; NULL if reordering occurred or memory was exhausted.]
  1159. SideEffects [None]
  1160. SeeAlso [cuddUniqueInter Cudd_MakeBddFromZddCover]
  1161. ******************************************************************************/
  1162. DdNode *
  1163. cuddUniqueInterIVO(
  1164. DdManager * unique,
  1165. int index,
  1166. DdNode * T,
  1167. DdNode * E)
  1168. {
  1169. DdNode *result;
  1170. DdNode *v;
  1171. v = cuddUniqueInter(unique, index, DD_ONE(unique),
  1172. Cudd_Not(DD_ONE(unique)));
  1173. if (v == NULL)
  1174. return(NULL);
  1175. /* Since v is a projection function, we can skip the call to cuddRef. */
  1176. result = cuddBddIteRecur(unique, v, T, E);
  1177. return(result);
  1178. } /* end of cuddUniqueInterIVO */
  1179. /**Function********************************************************************
  1180. Synopsis [Checks the unique table for the existence of an internal
  1181. ZDD node.]
  1182. Description [Checks the unique table for the existence of an internal
  1183. ZDD node. If it does not exist, it creates a new one. Does not
  1184. modify the reference count of whatever is returned. A newly created
  1185. internal node comes back with a reference count 0. For a newly
  1186. created node, increments the reference counts of what T and E point
  1187. to. Returns a pointer to the new node if successful; NULL if memory
  1188. is exhausted or if reordering took place.]
  1189. SideEffects [None]
  1190. SeeAlso [cuddUniqueInter]
  1191. ******************************************************************************/
  1192. DdNode *
  1193. cuddUniqueInterZdd(
  1194. DdManager * unique,
  1195. int index,
  1196. DdNode * T,
  1197. DdNode * E)
  1198. {
  1199. int pos;
  1200. unsigned int level;
  1201. int retval;
  1202. DdNodePtr *nodelist;
  1203. DdNode *looking;
  1204. DdSubtable *subtable;
  1205. #ifdef DD_UNIQUE_PROFILE
  1206. unique->uniqueLookUps++;
  1207. #endif
  1208. if (index >= unique->sizeZ) {
  1209. if (!cuddResizeTableZdd(unique,index)) return(NULL);
  1210. }
  1211. level = unique->permZ[index];
  1212. subtable = &(unique->subtableZ[level]);
  1213. #ifdef DD_DEBUG
  1214. assert(level < (unsigned) cuddIZ(unique,T->index));
  1215. assert(level < (unsigned) cuddIZ(unique,Cudd_Regular(E)->index));
  1216. #endif
  1217. if (subtable->keys > subtable->maxKeys) {
  1218. if (unique->gcEnabled && ((unique->deadZ > unique->minDead) ||
  1219. (10 * subtable->dead > 9 * subtable->keys))) { /* too many dead */
  1220. (void) cuddGarbageCollect(unique,1);
  1221. } else {
  1222. ddRehashZdd(unique,(int)level);
  1223. }
  1224. }
  1225. pos = ddHash(T, E, subtable->shift);
  1226. nodelist = subtable->nodelist;
  1227. looking = nodelist[pos];
  1228. while (looking != NULL) {
  1229. if (cuddT(looking) == T && cuddE(looking) == E) {
  1230. if (looking->ref == 0) {
  1231. cuddReclaimZdd(unique,looking);
  1232. }
  1233. return(looking);
  1234. }
  1235. looking = looking->next;
  1236. #ifdef DD_UNIQUE_PROFILE
  1237. unique->uniqueLinks++;
  1238. #endif
  1239. }
  1240. /* countDead is 0 if deads should be counted and ~0 if they should not. */
  1241. if (unique->autoDynZ &&
  1242. unique->keysZ - (unique->deadZ & unique->countDead) >= unique->nextDyn) {
  1243. #ifdef DD_DEBUG
  1244. retval = Cudd_DebugCheck(unique);
  1245. if (retval != 0) return(NULL);
  1246. retval = Cudd_CheckKeys(unique);
  1247. if (retval != 0) return(NULL);
  1248. #endif
  1249. retval = Cudd_zddReduceHeap(unique,unique->autoMethodZ,10); /* 10 = whatever */
  1250. if (retval == 0) unique->reordered = 2;
  1251. #ifdef DD_DEBUG
  1252. retval = Cudd_DebugCheck(unique);
  1253. if (retval != 0) unique->reordered = 2;
  1254. retval = Cudd_CheckKeys(unique);
  1255. if (retval != 0) unique->reordered = 2;
  1256. #endif
  1257. return(NULL);
  1258. }
  1259. unique->keysZ++;
  1260. subtable->keys++;
  1261. looking = cuddAllocNode(unique);
  1262. if (looking == NULL) return(NULL);
  1263. looking->index = index;
  1264. cuddT(looking) = T;
  1265. cuddE(looking) = E;
  1266. looking->next = nodelist[pos];
  1267. nodelist[pos] = looking;
  1268. cuddRef(T);
  1269. cuddRef(E);
  1270. return(looking);
  1271. } /* end of cuddUniqueInterZdd */
  1272. /**Function********************************************************************
  1273. Synopsis [Checks the unique table for the existence of a constant node.]
  1274. Description [Checks the unique table for the existence of a constant node.
  1275. If it does not exist, it creates a new one. Does not
  1276. modify the reference count of whatever is returned. A newly created
  1277. internal node comes back with a reference count 0. Returns a
  1278. pointer to the new node.]
  1279. SideEffects [None]
  1280. ******************************************************************************/
  1281. DdNode *
  1282. cuddUniqueConst(
  1283. DdManager * unique,
  1284. CUDD_VALUE_TYPE value)
  1285. {
  1286. int pos;
  1287. DdNodePtr *nodelist;
  1288. DdNode *looking;
  1289. hack split;
  1290. #ifdef DD_UNIQUE_PROFILE
  1291. unique->uniqueLookUps++;
  1292. #endif
  1293. if (unique->constants.keys > unique->constants.maxKeys) {
  1294. if (unique->gcEnabled && ((unique->dead > unique->minDead) ||
  1295. (10 * unique->constants.dead > 9 * unique->constants.keys))) { /* too many dead */
  1296. (void) cuddGarbageCollect(unique,1);
  1297. } else {
  1298. cuddRehash(unique,CUDD_CONST_INDEX);
  1299. }
  1300. }
  1301. cuddAdjust(value); /* for the case of crippled infinities */
  1302. if (ddAbs(value) < unique->epsilon) {
  1303. value = 0.0;
  1304. }
  1305. split.value = value;
  1306. pos = ddHash(split.bits[0], split.bits[1], unique->constants.shift);
  1307. nodelist = unique->constants.nodelist;
  1308. looking = nodelist[pos];
  1309. /* Here we compare values both for equality and for difference less
  1310. * than epsilon. The first comparison is required when values are
  1311. * infinite, since Infinity - Infinity is NaN and NaN < X is 0 for
  1312. * every X.
  1313. */
  1314. while (looking != NULL) {
  1315. if (looking->type.value == value ||
  1316. ddEqualVal(looking->type.value,value,unique->epsilon)) {
  1317. if (looking->ref == 0) {
  1318. cuddReclaim(unique,looking);
  1319. }
  1320. return(looking);
  1321. }
  1322. looking = looking->next;
  1323. #ifdef DD_UNIQUE_PROFILE
  1324. unique->uniqueLinks++;
  1325. #endif
  1326. }
  1327. unique->keys++;
  1328. unique->constants.keys++;
  1329. looking = cuddAllocNode(unique);
  1330. if (looking == NULL) return(NULL);
  1331. looking->index = CUDD_CONST_INDEX;
  1332. looking->type.value = value;
  1333. looking->next = nodelist[pos];
  1334. nodelist[pos] = looking;
  1335. return(looking);
  1336. } /* end of cuddUniqueConst */
  1337. /**Function********************************************************************
  1338. Synopsis [Rehashes a unique subtable.]
  1339. Description [Doubles the size of a unique subtable and rehashes its
  1340. contents.]
  1341. SideEffects [None]
  1342. SeeAlso []
  1343. ******************************************************************************/
  1344. void
  1345. cuddRehash(
  1346. DdManager * unique,
  1347. int i)
  1348. {
  1349. unsigned int slots, oldslots;
  1350. int shift, oldshift;
  1351. int j, pos;
  1352. DdNodePtr *nodelist, *oldnodelist;
  1353. DdNode *node, *next;
  1354. DdNode *sentinel = &(unique->sentinel);
  1355. hack split;
  1356. extern DD_OOMFP MMoutOfMemory;
  1357. DD_OOMFP saveHandler;
  1358. if (unique->gcFrac == DD_GC_FRAC_HI && unique->slots > unique->looseUpTo) {
  1359. unique->gcFrac = DD_GC_FRAC_LO;
  1360. unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
  1361. #ifdef DD_VERBOSE
  1362. (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_LO);
  1363. (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
  1364. #endif
  1365. }
  1366. if (unique->gcFrac != DD_GC_FRAC_MIN && unique->memused > unique->maxmem) {
  1367. unique->gcFrac = DD_GC_FRAC_MIN;
  1368. unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
  1369. #ifdef DD_VERBOSE
  1370. (void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_MIN);
  1371. (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
  1372. #endif
  1373. cuddShrinkDeathRow(unique);
  1374. if (cuddGarbageCollect(unique,1) > 0) return;
  1375. }
  1376. if (i != CUDD_CONST_INDEX) {
  1377. oldslots = unique->subtables[i].slots;
  1378. oldshift = unique->subtables[i].shift;
  1379. oldnodelist = unique->subtables[i].nodelist;
  1380. /* Compute the new size of the subtable. */
  1381. slots = oldslots << 1;
  1382. shift = oldshift - 1;
  1383. saveHandler = MMoutOfMemory;
  1384. MMoutOfMemory = Cudd_OutOfMem;
  1385. nodelist = ALLOC(DdNodePtr, slots);
  1386. MMoutOfMemory = saveHandler;
  1387. if (nodelist == NULL) {
  1388. (void) fprintf(unique->err,
  1389. "Unable to resize subtable %d for lack of memory\n",
  1390. i);
  1391. /* Prevent frequent resizing attempts. */
  1392. (void) cuddGarbageCollect(unique,1);
  1393. if (unique->stash != NULL) {
  1394. FREE(unique->stash);
  1395. unique->stash = NULL;
  1396. /* Inhibit resizing of tables. */
  1397. cuddSlowTableGrowth(unique);
  1398. }
  1399. return;
  1400. }
  1401. unique->subtables[i].nodelist = nodelist;
  1402. unique->subtables[i].slots = slots;
  1403. unique->subtables[i].shift = shift;
  1404. unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
  1405. /* Move the nodes from the old table to the new table.
  1406. ** This code depends on the type of hash function.
  1407. ** It assumes that the effect of doubling the size of the table
  1408. ** is to retain one more bit of the 32-bit hash value.
  1409. ** The additional bit is the LSB. */
  1410. for (j = 0; (unsigned) j < oldslots; j++) {
  1411. DdNodePtr *evenP, *oddP;
  1412. node = oldnodelist[j];
  1413. evenP = &(nodelist[j<<1]);
  1414. oddP = &(nodelist[(j<<1)+1]);
  1415. while (node != sentinel) {
  1416. next = node->next;
  1417. pos = ddHash(cuddT(node), cuddE(node), shift);
  1418. if (pos & 1) {
  1419. *oddP = node;
  1420. oddP = &(node->next);
  1421. } else {
  1422. *evenP = node;
  1423. evenP = &(node->next);
  1424. }
  1425. node = next;
  1426. }
  1427. *evenP = *oddP = sentinel;
  1428. }
  1429. FREE(oldnodelist);
  1430. #ifdef DD_VERBOSE
  1431. (void) fprintf(unique->err,
  1432. "rehashing layer %d: keys %d dead %d new size %d\n",
  1433. i, unique->subtables[i].keys,
  1434. unique->subtables[i].dead, slots);
  1435. #endif
  1436. } else {
  1437. oldslots = unique->constants.slots;
  1438. oldshift = unique->constants.shift;
  1439. oldnodelist = unique->constants.nodelist;
  1440. /* The constant subtable is never subjected to reordering.
  1441. ** Therefore, when it is resized, it is because it has just
  1442. ** reached the maximum load. We can safely just double the size,
  1443. ** with no need for the loop we use for the other tables.
  1444. */
  1445. slots = oldslots << 1;
  1446. shift = oldshift - 1;
  1447. saveHandler = MMoutOfMemory;
  1448. MMoutOfMemory = Cudd_OutOfMem;
  1449. nodelist = ALLOC(DdNodePtr, slots);
  1450. MMoutOfMemory = saveHandler;
  1451. if (nodelist == NULL) {
  1452. (void) fprintf(unique->err,
  1453. "Unable to resize constant subtable for lack of memory\n");
  1454. (void) cuddGarbageCollect(unique,1);
  1455. for (j = 0; j < unique->size; j++) {
  1456. unique->subtables[j].maxKeys <<= 1;
  1457. }
  1458. unique->constants.maxKeys <<= 1;
  1459. return;
  1460. }
  1461. unique->constants.slots = slots;
  1462. unique->constants.shift = shift;
  1463. unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
  1464. unique->constants.nodelist = nodelist;
  1465. for (j = 0; (unsigned) j < slots; j++) {
  1466. nodelist[j] = NULL;
  1467. }
  1468. for (j = 0; (unsigned) j < oldslots; j++) {
  1469. node = oldnodelist[j];
  1470. while (node != NULL) {
  1471. next = node->next;
  1472. split.value = cuddV(node);
  1473. pos = ddHash(split.bits[0], split.bits[1], shift);
  1474. node->next = nodelist[pos];
  1475. nodelist[pos] = node;
  1476. node = next;
  1477. }
  1478. }
  1479. FREE(oldnodelist);
  1480. #ifdef DD_VERBOSE
  1481. (void) fprintf(unique->err,
  1482. "rehashing constants: keys %d dead %d new size %d\n",
  1483. unique->constants.keys,unique->constants.dead,slots);
  1484. #endif
  1485. }
  1486. /* Update global data */
  1487. unique->memused += (slots - oldslots) * sizeof(DdNodePtr);
  1488. unique->slots += (slots - oldslots);
  1489. ddFixLimits(unique);
  1490. } /* end of cuddRehash */
  1491. /**Function********************************************************************
  1492. Synopsis [Shrinks a subtable.]
  1493. Description [Shrinks a subtable.]
  1494. SideEffects [None]
  1495. SeeAlso [cuddRehash]
  1496. ******************************************************************************/
  1497. void
  1498. cuddShrinkSubtable(
  1499. DdManager *unique,
  1500. int i)
  1501. {
  1502. int j;
  1503. int shift, posn;
  1504. DdNodePtr *nodelist, *oldnodelist;
  1505. DdNode *node, *next;
  1506. DdNode *sentinel = &(unique->sentinel);
  1507. unsigned int slots, oldslots;
  1508. extern DD_OOMFP MMoutOfMemory;
  1509. DD_OOMFP saveHandler;
  1510. oldnodelist = unique->subtables[i].nodelist;
  1511. oldslots = unique->subtables[i].slots;
  1512. slots = oldslots >> 1;
  1513. saveHandler = MMoutOfMemory;
  1514. MMoutOfMemory = Cudd_OutOfMem;
  1515. nodelist = ALLOC(DdNodePtr, slots);
  1516. MMoutOfMemory = saveHandler;
  1517. if (nodelist == NULL) {
  1518. return;
  1519. }
  1520. unique->subtables[i].nodelist = nodelist;
  1521. unique->subtables[i].slots = slots;
  1522. unique->subtables[i].shift++;
  1523. unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
  1524. #ifdef DD_VERBOSE
  1525. (void) fprintf(unique->err,
  1526. "shrunk layer %d (%d keys) from %d to %d slots\n",
  1527. i, unique->subtables[i].keys, oldslots, slots);
  1528. #endif
  1529. for (j = 0; (unsigned) j < slots; j++) {
  1530. nodelist[j] = sentinel;
  1531. }
  1532. shift = unique->subtables[i].shift;
  1533. for (j = 0; (unsigned) j < oldslots; j++) {
  1534. node = oldnodelist[j];
  1535. while (node != sentinel) {
  1536. DdNode *looking, *T, *E;
  1537. DdNodePtr *previousP;
  1538. next = node->next;
  1539. posn = ddHash(cuddT(node), cuddE(node), shift);
  1540. previousP = &(nodelist[posn]);
  1541. looking = *previousP;
  1542. T = cuddT(node);
  1543. E = cuddE(node);
  1544. while (T < cuddT(looking)) {
  1545. previousP = &(looking->next);
  1546. looking = *previousP;
  1547. #ifdef DD_UNIQUE_PROFILE
  1548. unique->uniqueLinks++;
  1549. #endif
  1550. }
  1551. while (T == cuddT(looking) && E < cuddE(looking)) {
  1552. previousP = &(looking->next);
  1553. looking = *previousP;
  1554. #ifdef DD_UNIQUE_PROFILE
  1555. unique->uniqueLinks++;
  1556. #endif
  1557. }
  1558. node->next = *previousP;
  1559. *previousP = node;
  1560. node = next;
  1561. }
  1562. }
  1563. FREE(oldnodelist);
  1564. unique->memused += ((long) slots - (long) oldslots) * sizeof(DdNode *);
  1565. unique->slots += slots - oldslots;
  1566. unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
  1567. unique->cacheSlack = (int)
  1568. ddMin(unique->maxCacheHard,DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots)
  1569. - 2 * (int) unique->cacheSlots;
  1570. } /* end of cuddShrinkSubtable */
  1571. /**Function********************************************************************
  1572. Synopsis [Inserts n new subtables in a unique table at level.]
  1573. Description [Inserts n new subtables in a unique table at level.
  1574. The number n should be positive, and level should be an existing level.
  1575. Returns 1 if successful; 0 otherwise.]
  1576. SideEffects [None]
  1577. SeeAlso [cuddDestroySubtables]
  1578. ******************************************************************************/
  1579. int
  1580. cuddInsertSubtables(
  1581. DdManager * unique,
  1582. int n,
  1583. int level)
  1584. {
  1585. DdSubtable *newsubtables;
  1586. DdNodePtr *newnodelist;
  1587. DdNodePtr *newvars;
  1588. DdNode *sentinel = &(unique->sentinel);
  1589. int oldsize,newsize;
  1590. int i,j,index,reorderSave;
  1591. unsigned int numSlots = unique->initSlots;
  1592. int *newperm, *newinvperm, *newmap;
  1593. DdNode *one, *zero;
  1594. #ifdef DD_DEBUG
  1595. assert(n > 0 && level < unique->size);
  1596. #endif
  1597. oldsize = unique->size;
  1598. /* Easy case: there is still room in the current table. */
  1599. if (oldsize + n <= unique->maxSize) {
  1600. /* Shift the tables at and below level. */
  1601. for (i = oldsize - 1; i >= level; i--) {
  1602. unique->subtables[i+n].slots = unique->subtables[i].slots;
  1603. unique->subtables[i+n].shift = unique->subtables[i].shift;
  1604. unique->subtables[i+n].keys = unique->subtables[i].keys;
  1605. unique->subtables[i+n].maxKeys = unique->subtables[i].maxKeys;
  1606. unique->subtables[i+n].dead = unique->subtables[i].dead;
  1607. unique->subtables[i+n].nodelist = unique->subtables[i].nodelist;
  1608. unique->subtables[i+n].bindVar = unique->subtables[i].bindVar;
  1609. unique->subtables[i+n].varType = unique->subtables[i].varType;
  1610. unique->subtables[i+n].pairIndex = unique->subtables[i].pairIndex;
  1611. unique->subtables[i+n].varHandled = unique->subtables[i].varHandled;
  1612. unique->subtables[i+n].varToBeGrouped =
  1613. unique->subtables[i].varToBeGrouped;
  1614. index = unique->invperm[i];
  1615. unique->invperm[i+n] = index;
  1616. unique->perm[index] += n;
  1617. }
  1618. /* Create new subtables. */
  1619. for (i = 0; i < n; i++) {
  1620. unique->subtables[level+i].slots = numSlots;
  1621. unique->subtables[level+i].shift = sizeof(int) * 8 -
  1622. cuddComputeFloorLog2(numSlots);
  1623. unique->subtables[level+i].keys = 0;
  1624. unique->subtables[level+i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
  1625. unique->subtables[level+i].dead = 0;
  1626. unique->subtables[level+i].bindVar = 0;
  1627. unique->subtables[level+i].varType = CUDD_VAR_PRIMARY_INPUT;
  1628. unique->subtables[level+i].pairIndex = 0;
  1629. unique->subtables[level+i].varHandled = 0;
  1630. unique->subtables[level+i].varToBeGrouped = CUDD_LAZY_NONE;
  1631. unique->perm[oldsize+i] = level + i;
  1632. unique->invperm[level+i] = oldsize + i;
  1633. newnodelist = unique->subtables[level+i].nodelist =
  1634. ALLOC(DdNodePtr, numSlots);
  1635. if (newnodelist == NULL) {
  1636. unique->errorCode = CUDD_MEMORY_OUT;
  1637. return(0);
  1638. }
  1639. for (j = 0; (unsigned) j < numSlots; j++) {
  1640. newnodelist[j] = sentinel;
  1641. }
  1642. }
  1643. if (unique->map != NULL) {
  1644. for (i = 0; i < n; i++) {
  1645. unique->map[oldsize+i] = oldsize + i;
  1646. }
  1647. }
  1648. } else {
  1649. /* The current table is too small: we need to allocate a new,
  1650. ** larger one; move all old subtables, and initialize the new
  1651. ** subtables.
  1652. */
  1653. newsize = oldsize + n + DD_DEFAULT_RESIZE;
  1654. #ifdef DD_VERBOSE
  1655. (void) fprintf(unique->err,
  1656. "Increasing the table size from %d to %d\n",
  1657. unique->maxSize, newsize);
  1658. #endif
  1659. /* Allocate memory for new arrays (except nodelists). */
  1660. newsubtables = ALLOC(DdSubtable,newsize);
  1661. if (newsubtables == NULL) {
  1662. unique->errorCode = CUDD_MEMORY_OUT;
  1663. return(0);
  1664. }
  1665. newvars = ALLOC(DdNodePtr,newsize);
  1666. if (newvars == NULL) {
  1667. unique->errorCode = CUDD_MEMORY_OUT;
  1668. FREE(newsubtables);
  1669. return(0);
  1670. }
  1671. newperm = ALLOC(int,newsize);
  1672. if (newperm == NULL) {
  1673. unique->errorCode = CUDD_MEMORY_OUT;
  1674. FREE(newsubtables);
  1675. FREE(newvars);
  1676. return(0);
  1677. }
  1678. newinvperm = ALLOC(int,newsize);
  1679. if (newinvperm == NULL) {
  1680. unique->errorCode = CUDD_MEMORY_OUT;
  1681. FREE(newsubtables);
  1682. FREE(newvars);
  1683. FREE(newperm);
  1684. return(0);
  1685. }
  1686. if (unique->map != NULL) {
  1687. newmap = ALLOC(int,newsize);
  1688. if (newmap == NULL) {
  1689. unique->errorCode = CUDD_MEMORY_OUT;
  1690. FREE(newsubtables);
  1691. FREE(newvars);
  1692. FREE(newperm);
  1693. FREE(newinvperm);
  1694. return(0);
  1695. }
  1696. unique->memused += (newsize - unique->maxSize) * sizeof(int);
  1697. }
  1698. unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
  1699. sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
  1700. /* Copy levels before insertion points from old tables. */
  1701. for (i = 0; i < level; i++) {
  1702. newsubtables[i].slots = unique->subtables[i].slots;
  1703. newsubtables[i].shift = unique->subtables[i].shift;
  1704. newsubtables[i].keys = unique->subtables[i].keys;
  1705. newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
  1706. newsubtables[i].dead = unique->subtables[i].dead;
  1707. newsubtables[i].nodelist = unique->subtables[i].nodelist;
  1708. newsubtables[i].bindVar = unique->subtables[i].bindVar;
  1709. newsubtables[i].varType = unique->subtables[i].varType;
  1710. newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
  1711. newsubtables[i].varHandled = unique->subtables[i].varHandled;
  1712. newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
  1713. newvars[i] = unique->vars[i];
  1714. newperm[i] = unique->perm[i];
  1715. newinvperm[i] = unique->invperm[i];
  1716. }
  1717. /* Finish initializing permutation for new table to old one. */
  1718. for (i = level; i < oldsize; i++) {
  1719. newperm[i] = unique->perm[i];
  1720. }
  1721. /* Initialize new levels. */
  1722. for (i = level; i < level + n; i++) {
  1723. newsubtables[i].slots = numSlots;
  1724. newsubtables[i].shift = sizeof(int) * 8 -
  1725. cuddComputeFloorLog2(numSlots);
  1726. newsubtables[i].keys = 0;
  1727. newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
  1728. newsubtables[i].dead = 0;
  1729. newsubtables[i].bindVar = 0;
  1730. newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
  1731. newsubtables[i].pairIndex = 0;
  1732. newsubtables[i].varHandled = 0;
  1733. newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
  1734. newperm[oldsize + i - level] = i;
  1735. newinvperm[i] = oldsize + i - level;
  1736. newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
  1737. if (newnodelist == NULL) {
  1738. /* We are going to leak some memory. We should clean up. */
  1739. unique->errorCode = CUDD_MEMORY_OUT;
  1740. return(0);
  1741. }
  1742. for (j = 0; (unsigned) j < numSlots; j++) {
  1743. newnodelist[j] = sentinel;
  1744. }
  1745. }
  1746. /* Copy the old tables for levels past the insertion point. */
  1747. for (i = level; i < oldsize; i++) {
  1748. newsubtables[i+n].slots = unique->subtables[i].slots;
  1749. newsubtables[i+n].shift = unique->subtables[i].shift;
  1750. newsubtables[i+n].keys = unique->subtables[i].keys;
  1751. newsubtables[i+n].maxKeys = unique->subtables[i].maxKeys;
  1752. newsubtables[i+n].dead = unique->subtables[i].dead;
  1753. newsubtables[i+n].nodelist = unique->subtables[i].nodelist;
  1754. newsubtables[i+n].bindVar = unique->subtables[i].bindVar;
  1755. newsubtables[i+n].varType = unique->subtables[i].varType;
  1756. newsubtables[i+n].pairIndex = unique->subtables[i].pairIndex;
  1757. newsubtables[i+n].varHandled = unique->subtables[i].varHandled;
  1758. newsubtables[i+n].varToBeGrouped =
  1759. unique->subtables[i].varToBeGrouped;
  1760. newvars[i] = unique->vars[i];
  1761. index = unique->invperm[i];
  1762. newinvperm[i+n] = index;
  1763. newperm[index] += n;
  1764. }
  1765. /* Update the map. */
  1766. if (unique->map != NULL) {
  1767. for (i = 0; i < oldsize; i++) {
  1768. newmap[i] = unique->map[i];
  1769. }
  1770. for (i = oldsize; i < oldsize + n; i++) {
  1771. newmap[i] = i;
  1772. }
  1773. FREE(unique->map);
  1774. unique->map = newmap;
  1775. }
  1776. /* Install the new tables and free the old ones. */
  1777. FREE(unique->subtables);
  1778. unique->subtables = newsubtables;
  1779. unique->maxSize = newsize;
  1780. FREE(unique->vars);
  1781. unique->vars = newvars;
  1782. FREE(unique->perm);
  1783. unique->perm = newperm;
  1784. FREE(unique->invperm);
  1785. unique->invperm = newinvperm;
  1786. /* Update the stack for iterative procedures. */
  1787. if (newsize > unique->maxSizeZ) {
  1788. FREE(unique->stack);
  1789. unique->stack = ALLOC(DdNodePtr,newsize + 1);
  1790. if (unique->stack == NULL) {
  1791. unique->errorCode = CUDD_MEMORY_OUT;
  1792. return(0);
  1793. }
  1794. unique->stack[0] = NULL; /* to suppress harmless UMR */
  1795. unique->memused +=
  1796. (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
  1797. * sizeof(DdNode *);
  1798. }
  1799. }
  1800. /* Update manager parameters to account for the new subtables. */
  1801. unique->slots += n * numSlots;
  1802. ddFixLimits(unique);
  1803. unique->size += n;
  1804. /* Now that the table is in a coherent state, create the new
  1805. ** projection functions. We need to temporarily disable reordering,
  1806. ** because we cannot reorder without projection functions in place.
  1807. **/
  1808. one = unique->one;
  1809. zero = Cudd_Not(one);
  1810. reorderSave = unique->autoDyn;
  1811. unique->autoDyn = 0;
  1812. for (i = oldsize; i < oldsize + n; i++) {
  1813. unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
  1814. if (unique->vars[i] == NULL) {
  1815. unique->autoDyn = reorderSave;
  1816. /* Shift everything back so table remains coherent. */
  1817. for (j = oldsize; j < i; j++) {
  1818. Cudd_IterDerefBdd(unique,unique->vars[j]);
  1819. cuddDeallocNode(unique,unique->vars[j]);
  1820. unique->vars[j] = NULL;
  1821. }
  1822. for (j = level; j < oldsize; j++) {
  1823. unique->subtables[j].slots = unique->subtables[j+n].slots;
  1824. unique->subtables[j].slots = unique->subtables[j+n].slots;
  1825. unique->subtables[j].shift = unique->subtables[j+n].shift;
  1826. unique->subtables[j].keys = unique->subtables[j+n].keys;
  1827. unique->subtables[j].maxKeys =
  1828. unique->subtables[j+n].maxKeys;
  1829. unique->subtables[j].dead = unique->subtables[j+n].dead;
  1830. FREE(unique->subtables[j].nodelist);
  1831. unique->subtables[j].nodelist =
  1832. unique->subtables[j+n].nodelist;
  1833. unique->subtables[j+n].nodelist = NULL;
  1834. unique->subtables[j].bindVar =
  1835. unique->subtables[j+n].bindVar;
  1836. unique->subtables[j].varType =
  1837. unique->subtables[j+n].varType;
  1838. unique->subtables[j].pairIndex =
  1839. unique->subtables[j+n].pairIndex;
  1840. unique->subtables[j].varHandled =
  1841. unique->subtables[j+n].varHandled;
  1842. unique->subtables[j].varToBeGrouped =
  1843. unique->subtables[j+n].varToBeGrouped;
  1844. index = unique->invperm[j+n];
  1845. unique->invperm[j] = index;
  1846. unique->perm[index] -= n;
  1847. }
  1848. unique->size = oldsize;
  1849. unique->slots -= n * numSlots;
  1850. ddFixLimits(unique);
  1851. (void) Cudd_DebugCheck(unique);
  1852. return(0);
  1853. }
  1854. cuddRef(unique->vars[i]);
  1855. }
  1856. if (unique->tree != NULL) {
  1857. unique->tree->size += n;
  1858. unique->tree->index = unique->invperm[0];
  1859. ddPatchTree(unique,unique->tree);
  1860. }
  1861. unique->autoDyn = reorderSave;
  1862. return(1);
  1863. } /* end of cuddInsertSubtables */
  1864. /**Function********************************************************************
  1865. Synopsis [Destroys the n most recently created subtables in a unique table.]
  1866. Description [Destroys the n most recently created subtables in a unique
  1867. table. n should be positive. The subtables should not contain any live
  1868. nodes, except the (isolated) projection function. The projection
  1869. functions are freed. Returns 1 if successful; 0 otherwise.]
  1870. SideEffects [The variable map used for fast variable substitution is
  1871. destroyed if it exists. In this case the cache is also cleared.]
  1872. SeeAlso [cuddInsertSubtables Cudd_SetVarMap]
  1873. ******************************************************************************/
  1874. int
  1875. cuddDestroySubtables(
  1876. DdManager * unique,
  1877. int n)
  1878. {
  1879. DdSubtable *subtables;
  1880. DdNodePtr *nodelist;
  1881. DdNodePtr *vars;
  1882. int firstIndex, lastIndex;
  1883. int index, level, newlevel;
  1884. int lowestLevel;
  1885. int shift;
  1886. int found;
  1887. /* Sanity check and set up. */
  1888. if (n <= 0) return(0);
  1889. if (n > unique->size) n = unique->size;
  1890. subtables = unique->subtables;
  1891. vars = unique->vars;
  1892. firstIndex = unique->size - n;
  1893. lastIndex = unique->size;
  1894. /* Check for nodes labeled by the variables being destroyed
  1895. ** that may still be in use. It is allowed to destroy a variable
  1896. ** only if there are no such nodes. Also, find the lowest level
  1897. ** among the variables being destroyed. This will make further
  1898. ** processing more efficient.
  1899. */
  1900. lowestLevel = unique->size;
  1901. for (index = firstIndex; index < lastIndex; index++) {
  1902. level = unique->perm[index];
  1903. if (level < lowestLevel) lowestLevel = level;
  1904. nodelist = subtables[level].nodelist;
  1905. if (subtables[level].keys - subtables[level].dead != 1) return(0);
  1906. /* The projection function should be isolated. If the ref count
  1907. ** is 1, everything is OK. If the ref count is saturated, then
  1908. ** we need to make sure that there are no nodes pointing to it.
  1909. ** As for the external references, we assume the application is
  1910. ** responsible for them.
  1911. */
  1912. if (vars[index]->ref != 1) {
  1913. if (vars[index]->ref != DD_MAXREF) return(0);
  1914. found = cuddFindParent(unique,vars[index]);
  1915. if (found) {
  1916. return(0);
  1917. } else {
  1918. vars[index]->ref = 1;
  1919. }
  1920. }
  1921. Cudd_RecursiveDeref(unique,vars[index]);
  1922. }
  1923. /* Collect garbage, because we cannot afford having dead nodes pointing
  1924. ** to the dead nodes in the subtables being destroyed.
  1925. */
  1926. (void) cuddGarbageCollect(unique,1);
  1927. /* Here we know we can destroy our subtables. */
  1928. for (index = firstIndex; index < lastIndex; index++) {
  1929. level = unique->perm[index];
  1930. nodelist = subtables[level].nodelist;
  1931. #ifdef DD_DEBUG
  1932. assert(subtables[level].keys == 0);
  1933. #endif
  1934. FREE(nodelist);
  1935. unique->memused -= sizeof(DdNodePtr) * subtables[level].slots;
  1936. unique->slots -= subtables[level].slots;
  1937. unique->dead -= subtables[level].dead;
  1938. }
  1939. /* Here all subtables to be destroyed have their keys field == 0 and
  1940. ** their hash tables have been freed.
  1941. ** We now scan the subtables from level lowestLevel + 1 to level size - 1,
  1942. ** shifting the subtables as required. We keep a running count of
  1943. ** how many subtables have been moved, so that we know by how many
  1944. ** positions each subtable should be shifted.
  1945. */
  1946. shift = 1;
  1947. for (level = lowestLevel + 1; level < unique->size; level++) {
  1948. if (subtables[level].keys == 0) {
  1949. shift++;
  1950. continue;
  1951. }
  1952. newlevel = level - shift;
  1953. subtables[newlevel].slots = subtables[level].slots;
  1954. subtables[newlevel].shift = subtables[level].shift;
  1955. subtables[newlevel].keys = subtables[level].keys;
  1956. subtables[newlevel].maxKeys = subtables[level].maxKeys;
  1957. subtables[newlevel].dead = subtables[level].dead;
  1958. subtables[newlevel].nodelist = subtables[level].nodelist;
  1959. index = unique->invperm[level];
  1960. unique->perm[index] = newlevel;
  1961. unique->invperm[newlevel] = index;
  1962. subtables[newlevel].bindVar = subtables[level].bindVar;
  1963. subtables[newlevel].varType = subtables[level].varType;
  1964. subtables[newlevel].pairIndex = subtables[level].pairIndex;
  1965. subtables[newlevel].varHandled = subtables[level].varHandled;
  1966. subtables[newlevel].varToBeGrouped = subtables[level].varToBeGrouped;
  1967. }
  1968. /* Destroy the map. If a surviving variable is
  1969. ** mapped to a dying variable, and the map were used again,
  1970. ** an out-of-bounds access to unique->vars would result. */
  1971. if (unique->map != NULL) {
  1972. cuddCacheFlush(unique);
  1973. FREE(unique->map);
  1974. unique->map = NULL;
  1975. }
  1976. unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
  1977. unique->size -= n;
  1978. return(1);
  1979. } /* end of cuddDestroySubtables */
  1980. /**Function********************************************************************
  1981. Synopsis [Increases the number of ZDD subtables in a unique table so
  1982. that it meets or exceeds index.]
  1983. Description [Increases the number of ZDD subtables in a unique table so
  1984. that it meets or exceeds index. When new ZDD variables are created, it
  1985. is possible to preserve the functions unchanged, or it is possible to
  1986. preserve the covers unchanged, but not both. cuddResizeTableZdd preserves
  1987. the covers. Returns 1 if successful; 0 otherwise.]
  1988. SideEffects [None]
  1989. SeeAlso [ddResizeTable]
  1990. ******************************************************************************/
  1991. int
  1992. cuddResizeTableZdd(
  1993. DdManager * unique,
  1994. int index)
  1995. {
  1996. DdSubtable *newsubtables;
  1997. DdNodePtr *newnodelist;
  1998. int oldsize,newsize;
  1999. int i,j,reorderSave;
  2000. unsigned int numSlots = unique->initSlots;
  2001. int *newperm, *newinvperm;
  2002. oldsize = unique->sizeZ;
  2003. /* Easy case: there is still room in the current table. */
  2004. if (index < unique->maxSizeZ) {
  2005. for (i = oldsize; i <= index; i++) {
  2006. unique->subtableZ[i].slots = numSlots;
  2007. unique->subtableZ[i].shift = sizeof(int) * 8 -
  2008. cuddComputeFloorLog2(numSlots);
  2009. unique->subtableZ[i].keys = 0;
  2010. unique->subtableZ[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
  2011. unique->subtableZ[i].dead = 0;
  2012. unique->permZ[i] = i;
  2013. unique->invpermZ[i] = i;
  2014. newnodelist = unique->subtableZ[i].nodelist =
  2015. ALLOC(DdNodePtr, numSlots);
  2016. if (newnodelist == NULL) {
  2017. unique->errorCode = CUDD_MEMORY_OUT;
  2018. return(0);
  2019. }
  2020. for (j = 0; (unsigned) j < numSlots; j++) {
  2021. newnodelist[j] = NULL;
  2022. }
  2023. }
  2024. } else {
  2025. /* The current table is too small: we need to allocate a new,
  2026. ** larger one; move all old subtables, and initialize the new
  2027. ** subtables up to index included.
  2028. */
  2029. newsize = index + DD_DEFAULT_RESIZE;
  2030. #ifdef DD_VERBOSE
  2031. (void) fprintf(unique->err,
  2032. "Increasing the ZDD table size from %d to %d\n",
  2033. unique->maxSizeZ, newsize);
  2034. #endif
  2035. newsubtables = ALLOC(DdSubtable,newsize);
  2036. if (newsubtables == NULL) {
  2037. unique->errorCode = CUDD_MEMORY_OUT;
  2038. return(0);
  2039. }
  2040. newperm = ALLOC(int,newsize);
  2041. if (newperm == NULL) {
  2042. unique->errorCode = CUDD_MEMORY_OUT;
  2043. return(0);
  2044. }
  2045. newinvperm = ALLOC(int,newsize);
  2046. if (newinvperm == NULL) {
  2047. unique->errorCode = CUDD_MEMORY_OUT;
  2048. return(0);
  2049. }
  2050. unique->memused += (newsize - unique->maxSizeZ) * ((numSlots+1) *
  2051. sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
  2052. if (newsize > unique->maxSize) {
  2053. FREE(unique->stack);
  2054. unique->stack = ALLOC(DdNodePtr,newsize + 1);
  2055. if (unique->stack == NULL) {
  2056. unique->errorCode = CUDD_MEMORY_OUT;
  2057. return(0);
  2058. }
  2059. unique->stack[0] = NULL; /* to suppress harmless UMR */
  2060. unique->memused +=
  2061. (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
  2062. * sizeof(DdNode *);
  2063. }
  2064. for (i = 0; i < oldsize; i++) {
  2065. newsubtables[i].slots = unique->subtableZ[i].slots;
  2066. newsubtables[i].shift = unique->subtableZ[i].shift;
  2067. newsubtables[i].keys = unique->subtableZ[i].keys;
  2068. newsubtables[i].maxKeys = unique->subtableZ[i].maxKeys;
  2069. newsubtables[i].dead = unique->subtableZ[i].dead;
  2070. newsubtables[i].nodelist = unique->subtableZ[i].nodelist;
  2071. newperm[i] = unique->permZ[i];
  2072. newinvperm[i] = unique->invpermZ[i];
  2073. }
  2074. for (i = oldsize; i <= index; i++) {
  2075. newsubtables[i].slots = numSlots;
  2076. newsubtables[i].shift = sizeof(int) * 8 -
  2077. cuddComputeFloorLog2(numSlots);
  2078. newsubtables[i].keys = 0;
  2079. newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
  2080. newsubtables[i].dead = 0;
  2081. newperm[i] = i;
  2082. newinvperm[i] = i;
  2083. newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
  2084. if (newnodelist == NULL) {
  2085. unique->errorCode = CUDD_MEMORY_OUT;
  2086. return(0);
  2087. }
  2088. for (j = 0; (unsigned) j < numSlots; j++) {
  2089. newnodelist[j] = NULL;
  2090. }
  2091. }
  2092. FREE(unique->subtableZ);
  2093. unique->subtableZ = newsubtables;
  2094. unique->maxSizeZ = newsize;
  2095. FREE(unique->permZ);
  2096. unique->permZ = newperm;
  2097. FREE(unique->invpermZ);
  2098. unique->invpermZ = newinvperm;
  2099. }
  2100. unique->slots += (index + 1 - unique->sizeZ) * numSlots;
  2101. ddFixLimits(unique);
  2102. unique->sizeZ = index + 1;
  2103. /* Now that the table is in a coherent state, update the ZDD
  2104. ** universe. We need to temporarily disable reordering,
  2105. ** because we cannot reorder without universe in place.
  2106. */
  2107. reorderSave = unique->autoDynZ;
  2108. unique->autoDynZ = 0;
  2109. cuddZddFreeUniv(unique);
  2110. if (!cuddZddInitUniv(unique)) {
  2111. unique->autoDynZ = reorderSave;
  2112. return(0);
  2113. }
  2114. unique->autoDynZ = reorderSave;
  2115. return(1);
  2116. } /* end of cuddResizeTableZdd */
  2117. /**Function********************************************************************
  2118. Synopsis [Adjusts parameters of a table to slow down its growth.]
  2119. Description []
  2120. SideEffects [None]
  2121. SeeAlso []
  2122. ******************************************************************************/
  2123. void
  2124. cuddSlowTableGrowth(
  2125. DdManager *unique)
  2126. {
  2127. int i;
  2128. unique->maxCacheHard = unique->cacheSlots - 1;
  2129. unique->cacheSlack = - (int) (unique->cacheSlots + 1);
  2130. for (i = 0; i < unique->size; i++) {
  2131. unique->subtables[i].maxKeys <<= 2;
  2132. }
  2133. unique->gcFrac = DD_GC_FRAC_MIN;
  2134. unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
  2135. cuddShrinkDeathRow(unique);
  2136. (void) fprintf(unique->err,"Slowing down table growth: ");
  2137. (void) fprintf(unique->err,"GC fraction = %.2f\t", unique->gcFrac);
  2138. (void) fprintf(unique->err,"minDead = %u\n", unique->minDead);
  2139. } /* end of cuddSlowTableGrowth */
  2140. /*---------------------------------------------------------------------------*/
  2141. /* Definition of static functions */
  2142. /*---------------------------------------------------------------------------*/
  2143. /**Function********************************************************************
  2144. Synopsis [Rehashes a ZDD unique subtable.]
  2145. Description []
  2146. SideEffects [None]
  2147. SeeAlso [cuddRehash]
  2148. ******************************************************************************/
  2149. static void
  2150. ddRehashZdd(
  2151. DdManager * unique,
  2152. int i)
  2153. {
  2154. unsigned int slots, oldslots;
  2155. int shift, oldshift;
  2156. int j, pos;
  2157. DdNodePtr *nodelist, *oldnodelist;
  2158. DdNode *node, *next;
  2159. extern DD_OOMFP MMoutOfMemory;
  2160. DD_OOMFP saveHandler;
  2161. if (unique->slots > unique->looseUpTo) {
  2162. unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
  2163. #ifdef DD_VERBOSE
  2164. if (unique->gcFrac == DD_GC_FRAC_HI) {
  2165. (void) fprintf(unique->err,"GC fraction = %.2f\t",
  2166. DD_GC_FRAC_LO);
  2167. (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
  2168. }
  2169. #endif
  2170. unique->gcFrac = DD_GC_FRAC_LO;
  2171. }
  2172. assert(i != CUDD_MAXINDEX);
  2173. oldslots = unique->subtableZ[i].slots;
  2174. oldshift = unique->subtableZ[i].shift;
  2175. oldnodelist = unique->subtableZ[i].nodelist;
  2176. /* Compute the new size of the subtable. Normally, we just
  2177. ** double. However, after reordering, a table may be severely
  2178. ** overloaded. Therefore, we iterate. */
  2179. slots = oldslots;
  2180. shift = oldshift;
  2181. do {
  2182. slots <<= 1;
  2183. shift--;
  2184. } while (slots * DD_MAX_SUBTABLE_DENSITY < unique->subtableZ[i].keys);
  2185. saveHandler = MMoutOfMemory;
  2186. MMoutOfMemory = Cudd_OutOfMem;
  2187. nodelist = ALLOC(DdNodePtr, slots);
  2188. MMoutOfMemory = saveHandler;
  2189. if (nodelist == NULL) {
  2190. (void) fprintf(unique->err,
  2191. "Unable to resize ZDD subtable %d for lack of memory.\n",
  2192. i);
  2193. (void) cuddGarbageCollect(unique,1);
  2194. for (j = 0; j < unique->sizeZ; j++) {
  2195. unique->subtableZ[j].maxKeys <<= 1;
  2196. }
  2197. return;
  2198. }
  2199. unique->subtableZ[i].nodelist = nodelist;
  2200. unique->subtableZ[i].slots = slots;
  2201. unique->subtableZ[i].shift = shift;
  2202. unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
  2203. for (j = 0; (unsigned) j < slots; j++) {
  2204. nodelist[j] = NULL;
  2205. }
  2206. for (j = 0; (unsigned) j < oldslots; j++) {
  2207. node = oldnodelist[j];
  2208. while (node != NULL) {
  2209. next = node->next;
  2210. pos = ddHash(cuddT(node), cuddE(node), shift);
  2211. node->next = nodelist[pos];
  2212. nodelist[pos] = node;
  2213. node = next;
  2214. }
  2215. }
  2216. FREE(oldnodelist);
  2217. #ifdef DD_VERBOSE
  2218. (void) fprintf(unique->err,
  2219. "rehashing layer %d: keys %d dead %d new size %d\n",
  2220. i, unique->subtableZ[i].keys,
  2221. unique->subtableZ[i].dead, slots);
  2222. #endif
  2223. /* Update global data. */
  2224. unique->memused += (slots - oldslots) * sizeof(DdNode *);
  2225. unique->slots += (slots - oldslots);
  2226. ddFixLimits(unique);
  2227. } /* end of ddRehashZdd */
  2228. /**Function********************************************************************
  2229. Synopsis [Increases the number of subtables in a unique table so
  2230. that it meets or exceeds index.]
  2231. Description [Increases the number of subtables in a unique table so
  2232. that it meets or exceeds index. The parameter amount determines how
  2233. much spare space is allocated to prevent too frequent resizing. If
  2234. index is negative, the table is resized, but no new variables are
  2235. created. Returns 1 if successful; 0 otherwise.]
  2236. SideEffects [None]
  2237. SeeAlso [Cudd_Reserve cuddResizeTableZdd]
  2238. ******************************************************************************/
  2239. static int
  2240. ddResizeTable(
  2241. DdManager * unique,
  2242. int index,
  2243. int amount)
  2244. {
  2245. DdSubtable *newsubtables;
  2246. DdNodePtr *newnodelist;
  2247. DdNodePtr *newvars;
  2248. DdNode *sentinel = &(unique->sentinel);
  2249. int oldsize,newsize;
  2250. int i,j,reorderSave;
  2251. int numSlots = unique->initSlots;
  2252. int *newperm, *newinvperm, *newmap;
  2253. DdNode *one, *zero;
  2254. oldsize = unique->size;
  2255. /* Easy case: there is still room in the current table. */
  2256. if (index >= 0 && index < unique->maxSize) {
  2257. for (i = oldsize; i <= index; i++) {
  2258. unique->subtables[i].slots = numSlots;
  2259. unique->subtables[i].shift = sizeof(int) * 8 -
  2260. cuddComputeFloorLog2(numSlots);
  2261. unique->subtables[i].keys = 0;
  2262. unique->subtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
  2263. unique->subtables[i].dead = 0;
  2264. unique->subtables[i].bindVar = 0;
  2265. unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
  2266. unique->subtables[i].pairIndex = 0;
  2267. unique->subtables[i].varHandled = 0;
  2268. unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
  2269. unique->perm[i] = i;
  2270. unique->invperm[i] = i;
  2271. newnodelist = unique->subtables[i].nodelist =
  2272. ALLOC(DdNodePtr, numSlots);
  2273. if (newnodelist == NULL) {
  2274. for (j = oldsize; j < i; j++) {
  2275. FREE(unique->subtables[j].nodelist);
  2276. }
  2277. unique->errorCode = CUDD_MEMORY_OUT;
  2278. return(0);
  2279. }
  2280. for (j = 0; j < numSlots; j++) {
  2281. newnodelist[j] = sentinel;
  2282. }
  2283. }
  2284. if (unique->map != NULL) {
  2285. for (i = oldsize; i <= index; i++) {
  2286. unique->map[i] = i;
  2287. }
  2288. }
  2289. } else {
  2290. /* The current table is too small: we need to allocate a new,
  2291. ** larger one; move all old subtables, and initialize the new
  2292. ** subtables up to index included.
  2293. */
  2294. newsize = (index < 0) ? amount : index + amount;
  2295. #ifdef DD_VERBOSE
  2296. (void) fprintf(unique->err,
  2297. "Increasing the table size from %d to %d\n",
  2298. unique->maxSize, newsize);
  2299. #endif
  2300. newsubtables = ALLOC(DdSubtable,newsize);
  2301. if (newsubtables == NULL) {
  2302. unique->errorCode = CUDD_MEMORY_OUT;
  2303. return(0);
  2304. }
  2305. newvars = ALLOC(DdNodePtr,newsize);
  2306. if (newvars == NULL) {
  2307. FREE(newsubtables);
  2308. unique->errorCode = CUDD_MEMORY_OUT;
  2309. return(0);
  2310. }
  2311. newperm = ALLOC(int,newsize);
  2312. if (newperm == NULL) {
  2313. FREE(newsubtables);
  2314. FREE(newvars);
  2315. unique->errorCode = CUDD_MEMORY_OUT;
  2316. return(0);
  2317. }
  2318. newinvperm = ALLOC(int,newsize);
  2319. if (newinvperm == NULL) {
  2320. FREE(newsubtables);
  2321. FREE(newvars);
  2322. FREE(newperm);
  2323. unique->errorCode = CUDD_MEMORY_OUT;
  2324. return(0);
  2325. }
  2326. if (unique->map != NULL) {
  2327. newmap = ALLOC(int,newsize);
  2328. if (newmap == NULL) {
  2329. FREE(newsubtables);
  2330. FREE(newvars);
  2331. FREE(newperm);
  2332. FREE(newinvperm);
  2333. unique->errorCode = CUDD_MEMORY_OUT;
  2334. return(0);
  2335. }
  2336. unique->memused += (newsize - unique->maxSize) * sizeof(int);
  2337. }
  2338. unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
  2339. sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
  2340. if (newsize > unique->maxSizeZ) {
  2341. FREE(unique->stack);
  2342. unique->stack = ALLOC(DdNodePtr,newsize + 1);
  2343. if (unique->stack == NULL) {
  2344. FREE(newsubtables);
  2345. FREE(newvars);
  2346. FREE(newperm);
  2347. FREE(newinvperm);
  2348. if (unique->map != NULL) {
  2349. FREE(newmap);
  2350. }
  2351. unique->errorCode = CUDD_MEMORY_OUT;
  2352. return(0);
  2353. }
  2354. unique->stack[0] = NULL; /* to suppress harmless UMR */
  2355. unique->memused +=
  2356. (newsize - ddMax(unique->maxSize,unique->maxSizeZ))
  2357. * sizeof(DdNode *);
  2358. }
  2359. for (i = 0; i < oldsize; i++) {
  2360. newsubtables[i].slots = unique->subtables[i].slots;
  2361. newsubtables[i].shift = unique->subtables[i].shift;
  2362. newsubtables[i].keys = unique->subtables[i].keys;
  2363. newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
  2364. newsubtables[i].dead = unique->subtables[i].dead;
  2365. newsubtables[i].nodelist = unique->subtables[i].nodelist;
  2366. newsubtables[i].bindVar = unique->subtables[i].bindVar;
  2367. newsubtables[i].varType = unique->subtables[i].varType;
  2368. newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
  2369. newsubtables[i].varHandled = unique->subtables[i].varHandled;
  2370. newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
  2371. newvars[i] = unique->vars[i];
  2372. newperm[i] = unique->perm[i];
  2373. newinvperm[i] = unique->invperm[i];
  2374. }
  2375. for (i = oldsize; i <= index; i++) {
  2376. newsubtables[i].slots = numSlots;
  2377. newsubtables[i].shift = sizeof(int) * 8 -
  2378. cuddComputeFloorLog2(numSlots);
  2379. newsubtables[i].keys = 0;
  2380. newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
  2381. newsubtables[i].dead = 0;
  2382. newsubtables[i].bindVar = 0;
  2383. newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
  2384. newsubtables[i].pairIndex = 0;
  2385. newsubtables[i].varHandled = 0;
  2386. newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
  2387. newperm[i] = i;
  2388. newinvperm[i] = i;
  2389. newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
  2390. if (newnodelist == NULL) {
  2391. unique->errorCode = CUDD_MEMORY_OUT;
  2392. return(0);
  2393. }
  2394. for (j = 0; j < numSlots; j++) {
  2395. newnodelist[j] = sentinel;
  2396. }
  2397. }
  2398. if (unique->map != NULL) {
  2399. for (i = 0; i < oldsize; i++) {
  2400. newmap[i] = unique->map[i];
  2401. }
  2402. for (i = oldsize; i <= index; i++) {
  2403. newmap[i] = i;
  2404. }
  2405. FREE(unique->map);
  2406. unique->map = newmap;
  2407. }
  2408. FREE(unique->subtables);
  2409. unique->subtables = newsubtables;
  2410. unique->maxSize = newsize;
  2411. FREE(unique->vars);
  2412. unique->vars = newvars;
  2413. FREE(unique->perm);
  2414. unique->perm = newperm;
  2415. FREE(unique->invperm);
  2416. unique->invperm = newinvperm;
  2417. }
  2418. /* Now that the table is in a coherent state, create the new
  2419. ** projection functions. We need to temporarily disable reordering,
  2420. ** because we cannot reorder without projection functions in place.
  2421. **/
  2422. if (index >= 0) {
  2423. one = unique->one;
  2424. zero = Cudd_Not(one);
  2425. unique->size = index + 1;
  2426. if (unique->tree != NULL) {
  2427. unique->tree->size = ddMax(unique->tree->size, unique->size);
  2428. }
  2429. unique->slots += (index + 1 - oldsize) * numSlots;
  2430. ddFixLimits(unique);
  2431. reorderSave = unique->autoDyn;
  2432. unique->autoDyn = 0;
  2433. for (i = oldsize; i <= index; i++) {
  2434. unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
  2435. if (unique->vars[i] == NULL) {
  2436. unique->autoDyn = reorderSave;
  2437. for (j = oldsize; j < i; j++) {
  2438. Cudd_IterDerefBdd(unique,unique->vars[j]);
  2439. cuddDeallocNode(unique,unique->vars[j]);
  2440. unique->vars[j] = NULL;
  2441. }
  2442. for (j = oldsize; j <= index; j++) {
  2443. FREE(unique->subtables[j].nodelist);
  2444. unique->subtables[j].nodelist = NULL;
  2445. }
  2446. unique->size = oldsize;
  2447. unique->slots -= (index + 1 - oldsize) * numSlots;
  2448. ddFixLimits(unique);
  2449. return(0);
  2450. }
  2451. cuddRef(unique->vars[i]);
  2452. }
  2453. unique->autoDyn = reorderSave;
  2454. }
  2455. return(1);
  2456. } /* end of ddResizeTable */
  2457. /**Function********************************************************************
  2458. Synopsis [Searches the subtables above node for a parent.]
  2459. Description [Searches the subtables above node for a parent. Returns 1
  2460. as soon as one parent is found. Returns 0 is the search is fruitless.]
  2461. SideEffects [None]
  2462. SeeAlso []
  2463. ******************************************************************************/
  2464. static int
  2465. cuddFindParent(
  2466. DdManager * table,
  2467. DdNode * node)
  2468. {
  2469. int i,j;
  2470. int slots;
  2471. DdNodePtr *nodelist;
  2472. DdNode *f;
  2473. for (i = cuddI(table,node->index) - 1; i >= 0; i--) {
  2474. nodelist = table->subtables[i].nodelist;
  2475. slots = table->subtables[i].slots;
  2476. for (j = 0; j < slots; j++) {
  2477. f = nodelist[j];
  2478. while (cuddT(f) > node) {
  2479. f = f->next;
  2480. }
  2481. while (cuddT(f) == node && Cudd_Regular(cuddE(f)) > node) {
  2482. f = f->next;
  2483. }
  2484. if (cuddT(f) == node && Cudd_Regular(cuddE(f)) == node) {
  2485. return(1);
  2486. }
  2487. }
  2488. }
  2489. return(0);
  2490. } /* end of cuddFindParent */
  2491. /**Function********************************************************************
  2492. Synopsis [Adjusts the values of table limits.]
  2493. Description [Adjusts the values of table fields controlling the.
  2494. sizes of subtables and computed table. If the computed table is too small
  2495. according to the new values, it is resized.]
  2496. SideEffects [Modifies manager fields. May resize computed table.]
  2497. SeeAlso []
  2498. ******************************************************************************/
  2499. DD_INLINE
  2500. static void
  2501. ddFixLimits(
  2502. DdManager *unique)
  2503. {
  2504. unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
  2505. unique->cacheSlack = (int) ddMin(unique->maxCacheHard,
  2506. DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots) -
  2507. 2 * (int) unique->cacheSlots;
  2508. if (unique->cacheSlots < unique->slots/2 && unique->cacheSlack >= 0)
  2509. cuddCacheResize(unique);
  2510. return;
  2511. } /* end of ddFixLimits */
  2512. #ifndef DD_UNSORTED_FREE_LIST
  2513. #ifdef DD_RED_BLACK_FREE_LIST
  2514. /**Function********************************************************************
  2515. Synopsis [Inserts a DdNode in a red/black search tree.]
  2516. Description [Inserts a DdNode in a red/black search tree. Nodes from
  2517. the same "page" (defined by DD_PAGE_MASK) are linked in a LIFO list.]
  2518. SideEffects [None]
  2519. SeeAlso [cuddOrderedThread]
  2520. ******************************************************************************/
  2521. static void
  2522. cuddOrderedInsert(
  2523. DdNodePtr * root,
  2524. DdNodePtr node)
  2525. {
  2526. DdNode *scan;
  2527. DdNodePtr *scanP;
  2528. DdNodePtr *stack[DD_STACK_SIZE];
  2529. int stackN = 0;
  2530. scanP = root;
  2531. while ((scan = *scanP) != NULL) {
  2532. stack[stackN++] = scanP;
  2533. if (DD_INSERT_COMPARE(node, scan) == 0) { /* add to page list */
  2534. DD_NEXT(node) = DD_NEXT(scan);
  2535. DD_NEXT(scan) = node;
  2536. return;
  2537. }
  2538. scanP = (node < scan) ? &DD_LEFT(scan) : &DD_RIGHT(scan);
  2539. }
  2540. DD_RIGHT(node) = DD_LEFT(node) = DD_NEXT(node) = NULL;
  2541. DD_COLOR(node) = DD_RED;
  2542. *scanP = node;
  2543. stack[stackN] = &node;
  2544. cuddDoRebalance(stack,stackN);
  2545. } /* end of cuddOrderedInsert */
  2546. /**Function********************************************************************
  2547. Synopsis [Threads all the nodes of a search tree into a linear list.]
  2548. Description [Threads all the nodes of a search tree into a linear
  2549. list. For each node of the search tree, the "left" child, if non-null, has
  2550. a lower address than its parent, and the "right" child, if non-null, has a
  2551. higher address than its parent.
  2552. The list is sorted in order of increasing addresses. The search
  2553. tree is destroyed as a result of this operation. The last element of
  2554. the linear list is made to point to the address passed in list. Each
  2555. node if the search tree is a linearly-linked list of nodes from the
  2556. same memory page (as defined in DD_PAGE_MASK). When a node is added to
  2557. the linear list, all the elements of the linked list are added.]
  2558. SideEffects [The search tree is destroyed as a result of this operation.]
  2559. SeeAlso [cuddOrderedInsert]
  2560. ******************************************************************************/
  2561. static DdNode *
  2562. cuddOrderedThread(
  2563. DdNode * root,
  2564. DdNode * list)
  2565. {
  2566. DdNode *current, *next, *prev, *end;
  2567. current = root;
  2568. /* The first word in the node is used to implement a stack that holds
  2569. ** the nodes from the root of the tree to the current node. Here we
  2570. ** put the root of the tree at the bottom of the stack.
  2571. */
  2572. *((DdNodePtr *) current) = NULL;
  2573. while (current != NULL) {
  2574. if (DD_RIGHT(current) != NULL) {
  2575. /* If possible, we follow the "right" link. Eventually we'll
  2576. ** find the node with the largest address in the current tree.
  2577. ** In this phase we use the first word of a node to implemen
  2578. ** a stack of the nodes on the path from the root to "current".
  2579. ** Also, we disconnect the "right" pointers to indicate that
  2580. ** we have already followed them.
  2581. */
  2582. next = DD_RIGHT(current);
  2583. DD_RIGHT(current) = NULL;
  2584. *((DdNodePtr *)next) = current;
  2585. current = next;
  2586. } else {
  2587. /* We can't proceed along the "right" links any further.
  2588. ** Hence "current" is the largest element in the current tree.
  2589. ** We make this node the new head of "list". (Repeating this
  2590. ** operation until the tree is empty yields the desired linear
  2591. ** threading of all nodes.)
  2592. */
  2593. prev = *((DdNodePtr *) current); /* save prev node on stack in prev */
  2594. /* Traverse the linked list of current until the end. */
  2595. for (end = current; DD_NEXT(end) != NULL; end = DD_NEXT(end));
  2596. DD_NEXT(end) = list; /* attach "list" at end and make */
  2597. list = current; /* "current" the new head of "list" */
  2598. /* Now, if current has a "left" child, we push it on the stack.
  2599. ** Otherwise, we just continue with the parent of "current".
  2600. */
  2601. if (DD_LEFT(current) != NULL) {
  2602. next = DD_LEFT(current);
  2603. *((DdNodePtr *) next) = prev;
  2604. current = next;
  2605. } else {
  2606. current = prev;
  2607. }
  2608. }
  2609. }
  2610. return(list);
  2611. } /* end of cuddOrderedThread */
  2612. /**Function********************************************************************
  2613. Synopsis [Performs the left rotation for red/black trees.]
  2614. Description []
  2615. SideEffects [None]
  2616. SeeAlso [cuddRotateRight]
  2617. ******************************************************************************/
  2618. DD_INLINE
  2619. static void
  2620. cuddRotateLeft(
  2621. DdNodePtr * nodeP)
  2622. {
  2623. DdNode *newRoot;
  2624. DdNode *oldRoot = *nodeP;
  2625. *nodeP = newRoot = DD_RIGHT(oldRoot);
  2626. DD_RIGHT(oldRoot) = DD_LEFT(newRoot);
  2627. DD_LEFT(newRoot) = oldRoot;
  2628. } /* end of cuddRotateLeft */
  2629. /**Function********************************************************************
  2630. Synopsis [Performs the right rotation for red/black trees.]
  2631. Description []
  2632. SideEffects [None]
  2633. SeeAlso [cuddRotateLeft]
  2634. ******************************************************************************/
  2635. DD_INLINE
  2636. static void
  2637. cuddRotateRight(
  2638. DdNodePtr * nodeP)
  2639. {
  2640. DdNode *newRoot;
  2641. DdNode *oldRoot = *nodeP;
  2642. *nodeP = newRoot = DD_LEFT(oldRoot);
  2643. DD_LEFT(oldRoot) = DD_RIGHT(newRoot);
  2644. DD_RIGHT(newRoot) = oldRoot;
  2645. } /* end of cuddRotateRight */
  2646. /**Function********************************************************************
  2647. Synopsis [Rebalances a red/black tree.]
  2648. Description []
  2649. SideEffects [None]
  2650. SeeAlso []
  2651. ******************************************************************************/
  2652. static void
  2653. cuddDoRebalance(
  2654. DdNodePtr ** stack,
  2655. int stackN)
  2656. {
  2657. DdNodePtr *xP, *parentP, *grandpaP;
  2658. DdNode *x, *y, *parent, *grandpa;
  2659. xP = stack[stackN];
  2660. x = *xP;
  2661. /* Work our way back up, re-balancing the tree. */
  2662. while (--stackN >= 0) {
  2663. parentP = stack[stackN];
  2664. parent = *parentP;
  2665. if (DD_IS_BLACK(parent)) break;
  2666. /* Since the root is black, here a non-null grandparent exists. */
  2667. grandpaP = stack[stackN-1];
  2668. grandpa = *grandpaP;
  2669. if (parent == DD_LEFT(grandpa)) {
  2670. y = DD_RIGHT(grandpa);
  2671. if (y != NULL && DD_IS_RED(y)) {
  2672. DD_COLOR(parent) = DD_BLACK;
  2673. DD_COLOR(y) = DD_BLACK;
  2674. DD_COLOR(grandpa) = DD_RED;
  2675. x = grandpa;
  2676. stackN--;
  2677. } else {
  2678. if (x == DD_RIGHT(parent)) {
  2679. cuddRotateLeft(parentP);
  2680. DD_COLOR(x) = DD_BLACK;
  2681. } else {
  2682. DD_COLOR(parent) = DD_BLACK;
  2683. }
  2684. DD_COLOR(grandpa) = DD_RED;
  2685. cuddRotateRight(grandpaP);
  2686. break;
  2687. }
  2688. } else {
  2689. y = DD_LEFT(grandpa);
  2690. if (y != NULL && DD_IS_RED(y)) {
  2691. DD_COLOR(parent) = DD_BLACK;
  2692. DD_COLOR(y) = DD_BLACK;
  2693. DD_COLOR(grandpa) = DD_RED;
  2694. x = grandpa;
  2695. stackN--;
  2696. } else {
  2697. if (x == DD_LEFT(parent)) {
  2698. cuddRotateRight(parentP);
  2699. DD_COLOR(x) = DD_BLACK;
  2700. } else {
  2701. DD_COLOR(parent) = DD_BLACK;
  2702. }
  2703. DD_COLOR(grandpa) = DD_RED;
  2704. cuddRotateLeft(grandpaP);
  2705. }
  2706. }
  2707. }
  2708. DD_COLOR(*(stack[0])) = DD_BLACK;
  2709. } /* end of cuddDoRebalance */
  2710. #endif
  2711. #endif
  2712. /**Function********************************************************************
  2713. Synopsis [Fixes a variable tree after the insertion of new subtables.]
  2714. Description [Fixes a variable tree after the insertion of new subtables.
  2715. After such an insertion, the low fields of the tree below the insertion
  2716. point are inconsistent.]
  2717. SideEffects [None]
  2718. SeeAlso []
  2719. ******************************************************************************/
  2720. static void
  2721. ddPatchTree(
  2722. DdManager *dd,
  2723. MtrNode *treenode)
  2724. {
  2725. MtrNode *auxnode = treenode;
  2726. while (auxnode != NULL) {
  2727. auxnode->low = dd->perm[auxnode->index];
  2728. if (auxnode->child != NULL) {
  2729. ddPatchTree(dd, auxnode->child);
  2730. }
  2731. auxnode = auxnode->younger;
  2732. }
  2733. return;
  2734. } /* end of ddPatchTree */
  2735. #ifdef DD_DEBUG
  2736. /**Function********************************************************************
  2737. Synopsis [Checks whether a collision list is ordered.]
  2738. Description []
  2739. SideEffects [None]
  2740. SeeAlso []
  2741. ******************************************************************************/
  2742. static int
  2743. cuddCheckCollisionOrdering(
  2744. DdManager *unique,
  2745. int i,
  2746. int j)
  2747. {
  2748. int slots;
  2749. DdNode *node, *next;
  2750. DdNodePtr *nodelist;
  2751. DdNode *sentinel = &(unique->sentinel);
  2752. nodelist = unique->subtables[i].nodelist;
  2753. slots = unique->subtables[i].slots;
  2754. node = nodelist[j];
  2755. if (node == sentinel) return(1);
  2756. next = node->next;
  2757. while (next != sentinel) {
  2758. if (cuddT(node) < cuddT(next) ||
  2759. (cuddT(node) == cuddT(next) && cuddE(node) < cuddE(next))) {
  2760. (void) fprintf(unique->err,
  2761. "Unordered list: index %u, position %d\n", i, j);
  2762. return(0);
  2763. }
  2764. node = next;
  2765. next = node->next;
  2766. }
  2767. return(1);
  2768. } /* end of cuddCheckCollisionOrdering */
  2769. #endif
  2770. /**Function********************************************************************
  2771. Synopsis [Reports problem in garbage collection.]
  2772. Description []
  2773. SideEffects [None]
  2774. SeeAlso [cuddGarbageCollect cuddGarbageCollectZdd]
  2775. ******************************************************************************/
  2776. static void
  2777. ddReportRefMess(
  2778. DdManager *unique /* manager */,
  2779. int i /* table in which the problem occurred */,
  2780. const char *caller /* procedure that detected the problem */)
  2781. {
  2782. if (i == CUDD_CONST_INDEX) {
  2783. (void) fprintf(unique->err,
  2784. "%s: problem in constants\n", caller);
  2785. } else if (i != -1) {
  2786. (void) fprintf(unique->err,
  2787. "%s: problem in table %d\n", caller, i);
  2788. }
  2789. (void) fprintf(unique->err, " dead count != deleted\n");
  2790. (void) fprintf(unique->err, " This problem is often due to a missing \
  2791. call to Cudd_Ref\n or to an extra call to Cudd_RecursiveDeref.\n \
  2792. See the CUDD Programmer's Guide for additional details.");
  2793. abort();
  2794. } /* end of ddReportRefMess */