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.

3214 lines
90 KiB

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