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.

1606 lines
52 KiB

2 months ago
  1. /**
  2. @file
  3. @ingroup cudd
  4. @brief Procedure to subset the given %BDD choosing the shortest paths
  5. (largest cubes) in the %BDD.
  6. @see cuddSubsetHB.c
  7. @author Kavita Ravi
  8. @copyright@parblock
  9. Copyright (c) 1995-2015, Regents of the University of Colorado
  10. All rights reserved.
  11. Redistribution and use in source and binary forms, with or without
  12. modification, are permitted provided that the following conditions
  13. are met:
  14. Redistributions of source code must retain the above copyright
  15. notice, this list of conditions and the following disclaimer.
  16. Redistributions in binary form must reproduce the above copyright
  17. notice, this list of conditions and the following disclaimer in the
  18. documentation and/or other materials provided with the distribution.
  19. Neither the name of the University of Colorado nor the names of its
  20. contributors may be used to endorse or promote products derived from
  21. this software without specific prior written permission.
  22. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  25. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  26. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  27. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  28. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  29. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  30. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  32. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33. POSSIBILITY OF SUCH DAMAGE.
  34. @endparblock
  35. */
  36. #include "util.h"
  37. #include "cuddInt.h"
  38. /*---------------------------------------------------------------------------*/
  39. /* Constant declarations */
  40. /*---------------------------------------------------------------------------*/
  41. #define DEFAULT_PAGE_SIZE 2048 /* page size to store the BFS queue element type */
  42. #define DEFAULT_NODE_DIST_PAGE_SIZE 2048 /* page size to store NodeDist_t type */
  43. #define MAXSHORTINT ((DdHalfWord) ~0) /* constant defined to store
  44. * maximum distance of a node
  45. * from the root or the constant
  46. */
  47. #define INITIAL_PAGES 128 /* number of initial pages for the
  48. * queue/NodeDist_t type */
  49. /*---------------------------------------------------------------------------*/
  50. /* Stucture declarations */
  51. /*---------------------------------------------------------------------------*/
  52. /**
  53. * @brief structure created to store subset results for each node and
  54. * distances with odd and even parity of the node from the root and
  55. * sink.
  56. *
  57. * Main data structure in this procedure.
  58. */
  59. struct NodeDist {
  60. DdHalfWord oddTopDist;
  61. DdHalfWord evenTopDist;
  62. DdHalfWord oddBotDist;
  63. DdHalfWord evenBotDist;
  64. DdNode *regResult;
  65. DdNode *compResult;
  66. };
  67. /**
  68. @brief assorted information needed by the BuildSubsetBdd procedure.
  69. */
  70. struct AssortedInfo {
  71. unsigned int maxpath;
  72. int findShortestPath;
  73. int thresholdReached;
  74. st_table *maxpathTable;
  75. int threshold;
  76. };
  77. /**
  78. * @brief Bookkeeping data structure for subsetting algorithm.
  79. */
  80. struct GlobalInfo {
  81. struct NodeDist **nodeDistPages; /**< pointers to the pages */
  82. int nodeDistPageIndex; /**< index to next element */
  83. int nodeDistPage; /**< index to current page */
  84. int nodeDistPageSize; /**< page size */
  85. int maxNodeDistPages; /**< number of page pointers */
  86. struct NodeDist *currentNodeDistPage; /**< current page */
  87. DdNode ***queuePages; /**< pointers to the pages */
  88. int queuePageIndex; /**< index to next element */
  89. int queuePage; /**< index to current page */
  90. int queuePageSize; /**< page size */
  91. int maxQueuePages; /**< number of page pointers */
  92. DdNode **currentQueuePage; /**< current page */
  93. #ifdef DD_DEBUG
  94. int numCalls;
  95. int hits;
  96. int thishit;
  97. #endif
  98. };
  99. /*---------------------------------------------------------------------------*/
  100. /* Type declarations */
  101. /*---------------------------------------------------------------------------*/
  102. typedef struct NodeDist NodeDist_t;
  103. typedef struct GlobalInfo GlobalInfo_t;
  104. /*---------------------------------------------------------------------------*/
  105. /* Variable declarations */
  106. /*---------------------------------------------------------------------------*/
  107. /*---------------------------------------------------------------------------*/
  108. /* Macro declarations */
  109. /*---------------------------------------------------------------------------*/
  110. /** \cond */
  111. /*---------------------------------------------------------------------------*/
  112. /* Static function prototypes */
  113. /*---------------------------------------------------------------------------*/
  114. static void ResizeNodeDistPages (DdManager *dd, GlobalInfo_t *gInfo);
  115. static void ResizeQueuePages (DdManager *dd, GlobalInfo_t *gInfo);
  116. static void CreateTopDist (DdManager *dd, GlobalInfo_t *gInfo, st_table *pathTable, int parentPage, int parentQueueIndex, int topLen, DdNode **childPage, int childQueueIndex, int numParents, FILE *fp);
  117. static int CreateBotDist (DdNode *node, st_table *pathTable, unsigned int *pathLengthArray, FILE *fp);
  118. static st_table * CreatePathTable (DdManager *dd, GlobalInfo_t *gInfo, DdNode *node, unsigned int *pathLengthArray, FILE *fp);
  119. static unsigned int AssessPathLength (unsigned int *pathLengthArray, int threshold, int numVars, unsigned int *excess, FILE *fp);
  120. static DdNode * BuildSubsetBdd (DdManager *dd, GlobalInfo_t *gInfo, st_table *pathTable, DdNode *node, struct AssortedInfo *info, st_table *subsetNodeTable);
  121. static enum st_retval stPathTableDdFree (void *key, void *value, void *arg);
  122. /** \endcond */
  123. /*---------------------------------------------------------------------------*/
  124. /* Definition of Exported functions */
  125. /*---------------------------------------------------------------------------*/
  126. /**
  127. @brief Extracts a dense subset from a %BDD with the shortest paths
  128. heuristic.
  129. @details This procedure tries to preserve the shortest paths of the
  130. input %BDD, because they give many minterms and contribute few nodes.
  131. This procedure may increase the number of nodes in trying to create
  132. the subset or reduce the number of nodes due to recombination as
  133. compared to the original %BDD. Hence the threshold may not be
  134. strictly adhered to. In practice, recombination overshadows the
  135. increase in the number of nodes and results in small BDDs as
  136. compared to the threshold. The hardlimit specifies whether threshold
  137. needs to be strictly adhered to. If it is set to 1, the procedure
  138. ensures that result is never larger than the specified limit but may
  139. be considerably less than the threshold. The value for numVars
  140. should be as close as possible to the size of the support of f for
  141. better efficiency. However, it is safe to pass the value returned by
  142. Cudd_ReadSize for numVars. If 0 is passed, then the value returned
  143. by Cudd_ReadSize is used.
  144. @return a pointer to the %BDD for the subset if successful; NULL
  145. otherwise.
  146. @sideeffect None
  147. @see Cudd_SupersetShortPaths Cudd_SubsetHeavyBranch Cudd_ReadSize
  148. */
  149. DdNode *
  150. Cudd_SubsetShortPaths(
  151. DdManager * dd /**< manager */,
  152. DdNode * f /**< function to be subset */,
  153. int numVars /**< number of variables in the support of f */,
  154. int threshold /**< maximum number of nodes in the subset */,
  155. int hardlimit /**< flag: 1 if threshold is a hard limit */)
  156. {
  157. DdNode *subset;
  158. do {
  159. dd->reordered = 0;
  160. subset = cuddSubsetShortPaths(dd, f, numVars, threshold, hardlimit);
  161. } while(dd->reordered == 1);
  162. return(subset);
  163. } /* end of Cudd_SubsetShortPaths */
  164. /**
  165. @brief Extracts a dense superset from a %BDD with the shortest paths
  166. heuristic.
  167. @details The procedure is identical to the subset procedure except
  168. for the fact that it receives the complement of the given
  169. function. Extracting the subset of the complement function is
  170. equivalent to extracting the superset of the function. This
  171. procedure tries to preserve the shortest paths of the complement
  172. %BDD, because they give many minterms and contribute few nodes. This
  173. procedure may increase the number of nodes in trying to create the
  174. superset or reduce the number of nodes due to recombination as
  175. compared to the original %BDD. Hence the threshold may not be
  176. strictly adhered to. In practice, recombination overshadows the
  177. increase in the number of nodes and results in small BDDs as
  178. compared to the threshold. The hardlimit specifies whether
  179. threshold needs to be strictly adhered to. If it is set to 1, the
  180. procedure ensures that result is never larger than the specified
  181. limit but may be considerably less than the threshold. The value
  182. for numVars should be as close as possible to the size of the
  183. support of f for better efficiency. However, it is safe to pass the
  184. value returned by Cudd_ReadSize for numVar. If 0 is passed, then
  185. the value returned by Cudd_ReadSize is used.
  186. @return a pointer to the %BDD for the superset if successful; NULL
  187. otherwise.
  188. @sideeffect None
  189. @see Cudd_SubsetShortPaths Cudd_SupersetHeavyBranch Cudd_ReadSize
  190. */
  191. DdNode *
  192. Cudd_SupersetShortPaths(
  193. DdManager * dd /**< manager */,
  194. DdNode * f /**< function to be superset */,
  195. int numVars /**< number of variables in the support of f */,
  196. int threshold /**< maximum number of nodes in the subset */,
  197. int hardlimit /**< flag: 1 if threshold is a hard limit */)
  198. {
  199. DdNode *subset, *g;
  200. g = Cudd_Not(f);
  201. do {
  202. dd->reordered = 0;
  203. subset = cuddSubsetShortPaths(dd, g, numVars, threshold, hardlimit);
  204. } while(dd->reordered == 1);
  205. return(Cudd_NotCond(subset, (subset != NULL)));
  206. } /* end of Cudd_SupersetShortPaths */
  207. /*---------------------------------------------------------------------------*/
  208. /* Definition of internal functions */
  209. /*---------------------------------------------------------------------------*/
  210. /**
  211. @brief The outermost procedure to return a subset of the given %BDD
  212. with the shortest path lengths.
  213. @details The path lengths are calculated, the maximum allowable path
  214. length is determined and the number of nodes of this path length
  215. that can be used to build a subset. If the threshold is larger than
  216. the size of the original %BDD, the original %BDD is returned.
  217. @sideeffect None
  218. @see Cudd_SubsetShortPaths
  219. */
  220. DdNode *
  221. cuddSubsetShortPaths(
  222. DdManager * dd /**< %DD manager */,
  223. DdNode * f /**< function to be subset */,
  224. int numVars /**< total number of variables in consideration */,
  225. int threshold /**< maximum number of nodes allowed in the subset */,
  226. int hardlimit /**< flag determining whether threshold should be respected strictly */)
  227. {
  228. GlobalInfo_t gInfo;
  229. st_table *pathTable;
  230. DdNode *N, *subset;
  231. unsigned int *pathLengthArray;
  232. unsigned int maxpath, oddLen, evenLen, pathLength, *excess;
  233. int i;
  234. NodeDist_t *nodeStat;
  235. struct AssortedInfo *info;
  236. st_table *subsetNodeTable;
  237. gInfo.nodeDistPageSize = DEFAULT_NODE_DIST_PAGE_SIZE;
  238. gInfo.queuePageSize = DEFAULT_PAGE_SIZE;
  239. if (numVars == 0) {
  240. /* set default value */
  241. numVars = Cudd_ReadSize(dd);
  242. }
  243. if (threshold > numVars) {
  244. threshold = threshold - numVars;
  245. }
  246. if (f == NULL) {
  247. fprintf(dd->err, "Cannot partition, nil object\n");
  248. dd->errorCode = CUDD_INVALID_ARG;
  249. return(NULL);
  250. }
  251. if (Cudd_IsConstantInt(f))
  252. return (f);
  253. pathLengthArray = ALLOC(unsigned int, numVars+1);
  254. for (i = 0; i < numVars+1; i++) pathLengthArray[i] = 0;
  255. #ifdef DD_DEBUG
  256. gInfo.numCalls = 0;
  257. #endif
  258. pathTable = CreatePathTable(dd, &gInfo, f, pathLengthArray, dd->err);
  259. if ((pathTable == NULL) || (dd->errorCode == CUDD_MEMORY_OUT)) {
  260. if (pathTable != NULL)
  261. st_free_table(pathTable);
  262. FREE(pathLengthArray);
  263. return (NIL(DdNode));
  264. }
  265. excess = ALLOC(unsigned int, 1);
  266. *excess = 0;
  267. maxpath = AssessPathLength(pathLengthArray, threshold, numVars, excess,
  268. dd->err);
  269. if (maxpath != (unsigned) (numVars + 1)) {
  270. info = ALLOC(struct AssortedInfo, 1);
  271. info->maxpath = maxpath;
  272. info->findShortestPath = 0;
  273. info->thresholdReached = *excess;
  274. info->maxpathTable = st_init_table(st_ptrcmp, st_ptrhash);
  275. info->threshold = threshold;
  276. #ifdef DD_DEBUG
  277. (void) fprintf(dd->out, "Path length array\n");
  278. for (i = 0; i < (numVars+1); i++) {
  279. if (pathLengthArray[i])
  280. (void) fprintf(dd->out, "%d ",i);
  281. }
  282. (void) fprintf(dd->out, "\n");
  283. for (i = 0; i < (numVars+1); i++) {
  284. if (pathLengthArray[i])
  285. (void) fprintf(dd->out, "%d ",pathLengthArray[i]);
  286. }
  287. (void) fprintf(dd->out, "\n");
  288. (void) fprintf(dd->out, "Maxpath = %d, Thresholdreached = %d\n",
  289. maxpath, info->thresholdReached);
  290. #endif
  291. N = Cudd_Regular(f);
  292. if (!st_lookup(pathTable, N, (void **) &nodeStat)) {
  293. fprintf(dd->err, "Something wrong, root node must be in table\n");
  294. dd->errorCode = CUDD_INTERNAL_ERROR;
  295. FREE(excess);
  296. FREE(info);
  297. return(NULL);
  298. } else {
  299. if ((nodeStat->oddTopDist != MAXSHORTINT) &&
  300. (nodeStat->oddBotDist != MAXSHORTINT))
  301. oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
  302. else
  303. oddLen = MAXSHORTINT;
  304. if ((nodeStat->evenTopDist != MAXSHORTINT) &&
  305. (nodeStat->evenBotDist != MAXSHORTINT))
  306. evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
  307. else
  308. evenLen = MAXSHORTINT;
  309. pathLength = (oddLen <= evenLen) ? oddLen : evenLen;
  310. if (pathLength > maxpath) {
  311. (void) fprintf(dd->err, "All computations are bogus, since root has path length greater than max path length within threshold %u, %u\n", maxpath, pathLength);
  312. dd->errorCode = CUDD_INTERNAL_ERROR;
  313. return(NULL);
  314. }
  315. }
  316. #ifdef DD_DEBUG
  317. gInfo.numCalls = 0;
  318. gInfo.hits = 0;
  319. gInfo.thishit = 0;
  320. #endif
  321. /* initialize a table to store computed nodes */
  322. if (hardlimit) {
  323. subsetNodeTable = st_init_table(st_ptrcmp, st_ptrhash);
  324. } else {
  325. subsetNodeTable = NIL(st_table);
  326. }
  327. subset = BuildSubsetBdd(dd, &gInfo, pathTable, f, info, subsetNodeTable);
  328. if (subset != NULL) {
  329. cuddRef(subset);
  330. }
  331. /* record the number of times a computed result for a node is hit */
  332. #ifdef DD_DEBUG
  333. (void) fprintf(dd->out, "Hits = %d, New==Node = %d, NumCalls = %d\n",
  334. gInfo.hits, gInfo.thishit, gInfo.numCalls);
  335. #endif
  336. if (subsetNodeTable != NIL(st_table)) {
  337. st_free_table(subsetNodeTable);
  338. }
  339. st_free_table(info->maxpathTable);
  340. st_foreach(pathTable, stPathTableDdFree, (void *)dd);
  341. FREE(info);
  342. } else {/* if threshold larger than size of dd */
  343. subset = f;
  344. cuddRef(subset);
  345. }
  346. FREE(excess);
  347. st_free_table(pathTable);
  348. FREE(pathLengthArray);
  349. for (i = 0; i <= gInfo.nodeDistPage; i++) FREE(gInfo.nodeDistPages[i]);
  350. FREE(gInfo.nodeDistPages);
  351. #ifdef DD_DEBUG
  352. /* check containment of subset in f */
  353. if (subset != NULL) {
  354. if (!Cudd_bddLeq(dd, subset, f)) {
  355. (void) fprintf(dd->err, "Wrong partition\n");
  356. dd->errorCode = CUDD_INTERNAL_ERROR;
  357. return(NULL);
  358. }
  359. }
  360. #endif
  361. if (subset != NULL) {
  362. cuddDeref(subset);
  363. return(subset);
  364. } else {
  365. return(NULL);
  366. }
  367. } /* end of cuddSubsetShortPaths */
  368. /*---------------------------------------------------------------------------*/
  369. /* Definition of static functions */
  370. /*---------------------------------------------------------------------------*/
  371. /**
  372. @brief Resize the number of pages allocated to store the distances
  373. related to each node.
  374. @details The procedure moves the counter to the next page when the
  375. end of the page is reached and allocates new pages when necessary.
  376. @sideeffect Changes the size of pages, page, page index, maximum
  377. number of pages freeing stuff in case of memory out.
  378. */
  379. static void
  380. ResizeNodeDistPages(
  381. DdManager *dd /**< %DD manager */,
  382. GlobalInfo_t *gInfo /**< global information */)
  383. {
  384. int i;
  385. NodeDist_t **newNodeDistPages;
  386. /* move to next page */
  387. gInfo->nodeDistPage++;
  388. /* If the current page index is larger than the number of pages
  389. * allocated, allocate a new page array. Page numbers are incremented by
  390. * INITIAL_PAGES
  391. */
  392. if (gInfo->nodeDistPage == gInfo->maxNodeDistPages) {
  393. newNodeDistPages = ALLOC(NodeDist_t *,gInfo->maxNodeDistPages + INITIAL_PAGES);
  394. if (newNodeDistPages == NULL) {
  395. for (i = 0; i < gInfo->nodeDistPage; i++) FREE(gInfo->nodeDistPages[i]);
  396. FREE(gInfo->nodeDistPages);
  397. dd->errorCode = CUDD_MEMORY_OUT;
  398. return;
  399. } else {
  400. for (i = 0; i < gInfo->maxNodeDistPages; i++) {
  401. newNodeDistPages[i] = gInfo->nodeDistPages[i];
  402. }
  403. /* Increase total page count */
  404. gInfo->maxNodeDistPages += INITIAL_PAGES;
  405. FREE(gInfo->nodeDistPages);
  406. gInfo->nodeDistPages = newNodeDistPages;
  407. }
  408. }
  409. /* Allocate a new page */
  410. gInfo->currentNodeDistPage = gInfo->nodeDistPages[gInfo->nodeDistPage] =
  411. ALLOC(NodeDist_t, gInfo->nodeDistPageSize);
  412. if (gInfo->currentNodeDistPage == NULL) {
  413. for (i = 0; i < gInfo->nodeDistPage; i++) FREE(gInfo->nodeDistPages[i]);
  414. FREE(gInfo->nodeDistPages);
  415. dd->errorCode = CUDD_MEMORY_OUT;
  416. return;
  417. }
  418. /* reset page index */
  419. gInfo->nodeDistPageIndex = 0;
  420. return;
  421. } /* end of ResizeNodeDistPages */
  422. /**
  423. @brief Resize the number of pages allocated to store nodes in the BFS
  424. traversal of the %BDD.
  425. @details The procedure moves the counter to the next page when the
  426. end of the page is reached and allocates new pages when necessary.
  427. @sideeffect Changes the size of pages, page, page index, maximum
  428. number of pages freeing stuff in case of memory out.
  429. */
  430. static void
  431. ResizeQueuePages(
  432. DdManager *dd /**< %DD manager */,
  433. GlobalInfo_t *gInfo /**< global information */)
  434. {
  435. int i;
  436. DdNode ***newQueuePages;
  437. gInfo->queuePage++;
  438. /* If the current page index is larger than the number of pages
  439. * allocated, allocate a new page array. Page numbers are incremented by
  440. * INITIAL_PAGES
  441. */
  442. if (gInfo->queuePage == gInfo->maxQueuePages) {
  443. newQueuePages = ALLOC(DdNode **,gInfo->maxQueuePages + INITIAL_PAGES);
  444. if (newQueuePages == NULL) {
  445. for (i = 0; i < gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
  446. FREE(gInfo->queuePages);
  447. dd->errorCode = CUDD_MEMORY_OUT;
  448. return;
  449. } else {
  450. for (i = 0; i < gInfo->maxQueuePages; i++) {
  451. newQueuePages[i] = gInfo->queuePages[i];
  452. }
  453. /* Increase total page count */
  454. gInfo->maxQueuePages += INITIAL_PAGES;
  455. FREE(gInfo->queuePages);
  456. gInfo->queuePages = newQueuePages;
  457. }
  458. }
  459. /* Allocate a new page */
  460. gInfo->currentQueuePage = gInfo->queuePages[gInfo->queuePage] =
  461. ALLOC(DdNode *,gInfo->queuePageSize);
  462. if (gInfo->currentQueuePage == NULL) {
  463. for (i = 0; i < gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
  464. FREE(gInfo->queuePages);
  465. dd->errorCode = CUDD_MEMORY_OUT;
  466. return;
  467. }
  468. /* reset page index */
  469. gInfo->queuePageIndex = 0;
  470. return;
  471. } /* end of ResizeQueuePages */
  472. /**
  473. @brief Labels each node with its shortest distance from the root.
  474. @details This is done in a BFS search of the %BDD. The nodes are
  475. processed in a queue implemented as pages(array) to reduce memory
  476. fragmentation. An entry is created for each node visited. The
  477. distance from the root to the node with the corresponding parity is
  478. updated. The procedure is called recursively each recusion level
  479. handling nodes at a given level from the root.
  480. @sideeffect Creates entries in the pathTable
  481. @see CreatePathTable CreateBotDist
  482. */
  483. static void
  484. CreateTopDist(
  485. DdManager *dd /**< %DD manager */,
  486. GlobalInfo_t *gInfo /**< global information */,
  487. st_table * pathTable /**< hash table to store path lengths */,
  488. int parentPage /**< the pointer to the page on which the first parent in the queue is to be found. */,
  489. int parentQueueIndex /**< pointer to the first parent on the page */,
  490. int topLen /**< current distance from the root */,
  491. DdNode ** childPage /**< pointer to the page on which the first child is to be added. */,
  492. int childQueueIndex /**< pointer to the first child */,
  493. int numParents /**< number of parents to process in this recursive call */,
  494. FILE *fp /**< where to write messages */)
  495. {
  496. NodeDist_t *nodeStat;
  497. DdNode *N, *Nv, *Nnv, *node, *child, *regChild;
  498. int i;
  499. int processingDone, childrenCount;
  500. #ifdef DD_DEBUG
  501. gInfo->numCalls++;
  502. /* assume this procedure comes in with only the root node*/
  503. /* set queue index to the next available entry for addition */
  504. /* set queue page to page of addition */
  505. if ((gInfo->queuePages[parentPage] == childPage) && (parentQueueIndex ==
  506. childQueueIndex)) {
  507. fprintf(fp, "Should not happen that they are equal\n");
  508. }
  509. assert(gInfo->queuePageIndex == childQueueIndex);
  510. assert(gInfo->currentQueuePage == childPage);
  511. #endif
  512. /* number children added to queue is initialized , needed for
  513. * numParents in the next call
  514. */
  515. childrenCount = 0;
  516. /* process all the nodes in this level */
  517. while (numParents) {
  518. numParents--;
  519. if (parentQueueIndex == gInfo->queuePageSize) {
  520. parentPage++;
  521. parentQueueIndex = 0;
  522. }
  523. /* a parent to process */
  524. node = *(gInfo->queuePages[parentPage] + parentQueueIndex);
  525. parentQueueIndex++;
  526. /* get its children */
  527. N = Cudd_Regular(node);
  528. Nv = Cudd_T(N);
  529. Nnv = Cudd_E(N);
  530. Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
  531. Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
  532. processingDone = 2;
  533. while (processingDone) {
  534. /* processing the THEN and the ELSE children, the THEN
  535. * child first
  536. */
  537. if (processingDone == 2) {
  538. child = Nv;
  539. } else {
  540. child = Nnv;
  541. }
  542. regChild = Cudd_Regular(child);
  543. /* dont process if the child is a constant */
  544. if (!Cudd_IsConstantInt(child)) {
  545. /* check is already visited, if not add a new entry in
  546. * the path Table
  547. */
  548. if (!st_lookup(pathTable, regChild, (void **) &nodeStat)) {
  549. /* if not in table, has never been visited */
  550. /* create entry for table */
  551. if (gInfo->nodeDistPageIndex == gInfo->nodeDistPageSize)
  552. ResizeNodeDistPages(dd, gInfo);
  553. if (dd->errorCode == CUDD_MEMORY_OUT) {
  554. for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
  555. FREE(gInfo->queuePages);
  556. st_free_table(pathTable);
  557. return;
  558. }
  559. /* New entry for child in path Table is created here */
  560. nodeStat = gInfo->currentNodeDistPage + gInfo->nodeDistPageIndex;
  561. gInfo->nodeDistPageIndex++;
  562. /* Initialize fields of the node data */
  563. nodeStat->oddTopDist = MAXSHORTINT;
  564. nodeStat->evenTopDist = MAXSHORTINT;
  565. nodeStat->evenBotDist = MAXSHORTINT;
  566. nodeStat->oddBotDist = MAXSHORTINT;
  567. nodeStat->regResult = NULL;
  568. nodeStat->compResult = NULL;
  569. /* update the table entry element, the distance keeps
  570. * track of the parity of the path from the root
  571. */
  572. if (Cudd_IsComplement(child)) {
  573. nodeStat->oddTopDist = (DdHalfWord) topLen + 1;
  574. } else {
  575. nodeStat->evenTopDist = (DdHalfWord) topLen + 1;
  576. }
  577. /* insert entry element for child in the table */
  578. if (st_insert(pathTable, regChild,
  579. nodeStat) == ST_OUT_OF_MEM) {
  580. dd->errorCode = CUDD_MEMORY_OUT;
  581. for (i = 0; i <= gInfo->nodeDistPage; i++)
  582. FREE(gInfo->nodeDistPages[i]);
  583. FREE(gInfo->nodeDistPages);
  584. for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
  585. FREE(gInfo->queuePages);
  586. st_free_table(pathTable);
  587. return;
  588. }
  589. /* Create list element for this child to process its children.
  590. * If this node has been processed already, then it appears
  591. * in the path table and hence is never added to the list
  592. * again.
  593. */
  594. if (gInfo->queuePageIndex == gInfo->queuePageSize) ResizeQueuePages(dd, gInfo);
  595. if (dd->errorCode == CUDD_MEMORY_OUT) {
  596. for (i = 0; i <= gInfo->nodeDistPage; i++)
  597. FREE(gInfo->nodeDistPages[i]);
  598. FREE(gInfo->nodeDistPages);
  599. st_free_table(pathTable);
  600. return;
  601. }
  602. *(gInfo->currentQueuePage + gInfo->queuePageIndex) = child;
  603. gInfo->queuePageIndex++;
  604. childrenCount++;
  605. } else {
  606. /* if not been met in a path with this parity before */
  607. /* put in list */
  608. if (((Cudd_IsComplement(child)) && (nodeStat->oddTopDist ==
  609. MAXSHORTINT)) || ((!Cudd_IsComplement(child)) &&
  610. (nodeStat->evenTopDist == MAXSHORTINT))) {
  611. if (gInfo->queuePageIndex == gInfo->queuePageSize) ResizeQueuePages(dd, gInfo);
  612. if (dd->errorCode == CUDD_MEMORY_OUT) {
  613. for (i = 0; i <= gInfo->nodeDistPage; i++)
  614. FREE(gInfo->nodeDistPages[i]);
  615. FREE(gInfo->nodeDistPages);
  616. st_free_table(pathTable);
  617. return;
  618. }
  619. *(gInfo->currentQueuePage + gInfo->queuePageIndex) = child;
  620. gInfo->queuePageIndex++;
  621. /* update the distance with the appropriate parity */
  622. if (Cudd_IsComplement(child)) {
  623. nodeStat->oddTopDist = (DdHalfWord) topLen + 1;
  624. } else {
  625. nodeStat->evenTopDist = (DdHalfWord) topLen + 1;
  626. }
  627. childrenCount++;
  628. }
  629. } /* end of else (not found in st_table) */
  630. } /*end of if Not constant child */
  631. processingDone--;
  632. } /*end of while processing Nv, Nnv */
  633. } /*end of while numParents */
  634. #ifdef DD_DEBUG
  635. assert(gInfo->queuePages[parentPage] == childPage);
  636. assert(parentQueueIndex == childQueueIndex);
  637. #endif
  638. if (childrenCount != 0) {
  639. topLen++;
  640. childPage = gInfo->currentQueuePage;
  641. childQueueIndex = gInfo->queuePageIndex;
  642. CreateTopDist(dd, gInfo, pathTable, parentPage, parentQueueIndex, topLen,
  643. childPage, childQueueIndex, childrenCount, fp);
  644. }
  645. return;
  646. } /* end of CreateTopDist */
  647. /**
  648. @brief Labels each node with the shortest distance from the constant.
  649. @details This is done in a DFS search of the %BDD. Each node has an
  650. odd and even parity distance from the sink (since there exists paths
  651. to both zero and one) which is less than MAXSHORTINT. At each node
  652. these distances are updated using the minimum distance of its
  653. children from the constant. SInce now both the length from the root
  654. and child is known, the minimum path length(length of the shortest
  655. path between the root and the constant that this node lies on) of
  656. this node can be calculated and used to update the pathLengthArray.
  657. @sideeffect Updates Path Table and path length array
  658. @see CreatePathTable CreateTopDist AssessPathLength
  659. */
  660. static int
  661. CreateBotDist(
  662. DdNode * node /* current node */,
  663. st_table * pathTable /* path table with path lengths */,
  664. unsigned int * pathLengthArray /* array that stores number of nodes belonging to a particular path length. */,
  665. FILE *fp /* where to write messages */)
  666. {
  667. DdNode *N, *Nv, *Nnv;
  668. DdNode *realChild;
  669. DdNode *child, *regChild;
  670. NodeDist_t *nodeStat, *nodeStatChild;
  671. unsigned int oddLen, evenLen, pathLength;
  672. DdHalfWord botDist;
  673. int processingDone;
  674. if (Cudd_IsConstantInt(node))
  675. return(1);
  676. N = Cudd_Regular(node);
  677. /* each node has one table entry */
  678. /* update as you go down the min dist of each node from
  679. the root in each (odd and even) parity */
  680. if (!st_lookup(pathTable, N, (void **) &nodeStat)) {
  681. fprintf(fp, "Something wrong, the entry doesn't exist\n");
  682. return(0);
  683. }
  684. /* compute length of odd parity distances */
  685. if ((nodeStat->oddTopDist != MAXSHORTINT) &&
  686. (nodeStat->oddBotDist != MAXSHORTINT))
  687. oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
  688. else
  689. oddLen = MAXSHORTINT;
  690. /* compute length of even parity distances */
  691. if (!((nodeStat->evenTopDist == MAXSHORTINT) ||
  692. (nodeStat->evenBotDist == MAXSHORTINT)))
  693. evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
  694. else
  695. evenLen = MAXSHORTINT;
  696. /* assign pathlength to minimum of the two */
  697. pathLength = (oddLen <= evenLen) ? oddLen : evenLen;
  698. Nv = Cudd_T(N);
  699. Nnv = Cudd_E(N);
  700. /* process each child */
  701. processingDone = 0;
  702. while (processingDone != 2) {
  703. if (!processingDone) {
  704. child = Nv;
  705. } else {
  706. child = Nnv;
  707. }
  708. realChild = Cudd_NotCond(child, Cudd_IsComplement(node));
  709. regChild = Cudd_Regular(child);
  710. if (Cudd_IsConstantInt(realChild)) {
  711. /* Found a minterm; count parity and shortest distance
  712. ** from the constant.
  713. */
  714. if (Cudd_IsComplement(child))
  715. nodeStat->oddBotDist = 1;
  716. else
  717. nodeStat->evenBotDist = 1;
  718. } else {
  719. /* If node not in table, recur. */
  720. if (!st_lookup(pathTable, regChild, (void **) &nodeStatChild)) {
  721. fprintf(fp, "Something wrong, node in table should have been created in top dist proc.\n");
  722. return(0);
  723. }
  724. if (nodeStatChild->oddBotDist == MAXSHORTINT) {
  725. if (nodeStatChild->evenBotDist == MAXSHORTINT) {
  726. if (!CreateBotDist(realChild, pathTable, pathLengthArray, fp))
  727. return(0);
  728. } else {
  729. fprintf(fp, "Something wrong, both bot nodeStats should be there\n");
  730. return(0);
  731. }
  732. }
  733. /* Update shortest distance from the constant depending on
  734. ** parity. */
  735. if (Cudd_IsComplement(child)) {
  736. /* If parity on the edge then add 1 to even distance
  737. ** of child to get odd parity distance and add 1 to
  738. ** odd distance of child to get even parity
  739. ** distance. Change distance of current node only if
  740. ** the calculated distance is less than existing
  741. ** distance. */
  742. if (nodeStatChild->oddBotDist != MAXSHORTINT)
  743. botDist = nodeStatChild->oddBotDist + 1;
  744. else
  745. botDist = MAXSHORTINT;
  746. if (nodeStat->evenBotDist > botDist )
  747. nodeStat->evenBotDist = botDist;
  748. if (nodeStatChild->evenBotDist != MAXSHORTINT)
  749. botDist = nodeStatChild->evenBotDist + 1;
  750. else
  751. botDist = MAXSHORTINT;
  752. if (nodeStat->oddBotDist > botDist)
  753. nodeStat->oddBotDist = botDist;
  754. } else {
  755. /* If parity on the edge then add 1 to even distance
  756. ** of child to get even parity distance and add 1 to
  757. ** odd distance of child to get odd parity distance.
  758. ** Change distance of current node only if the
  759. ** calculated distance is lesser than existing
  760. ** distance. */
  761. if (nodeStatChild->evenBotDist != MAXSHORTINT)
  762. botDist = nodeStatChild->evenBotDist + 1;
  763. else
  764. botDist = MAXSHORTINT;
  765. if (nodeStat->evenBotDist > botDist)
  766. nodeStat->evenBotDist = botDist;
  767. if (nodeStatChild->oddBotDist != MAXSHORTINT)
  768. botDist = nodeStatChild->oddBotDist + 1;
  769. else
  770. botDist = MAXSHORTINT;
  771. if (nodeStat->oddBotDist > botDist)
  772. nodeStat->oddBotDist = botDist;
  773. }
  774. } /* end of else (if not constant child ) */
  775. processingDone++;
  776. } /* end of while processing Nv, Nnv */
  777. /* Compute shortest path length on the fly. */
  778. if ((nodeStat->oddTopDist != MAXSHORTINT) &&
  779. (nodeStat->oddBotDist != MAXSHORTINT))
  780. oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
  781. else
  782. oddLen = MAXSHORTINT;
  783. if ((nodeStat->evenTopDist != MAXSHORTINT) &&
  784. (nodeStat->evenBotDist != MAXSHORTINT))
  785. evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
  786. else
  787. evenLen = MAXSHORTINT;
  788. /* Update path length array that has number of nodes of a particular
  789. ** path length. */
  790. if (oddLen < pathLength ) {
  791. if (pathLength != MAXSHORTINT)
  792. pathLengthArray[pathLength]--;
  793. if (oddLen != MAXSHORTINT)
  794. pathLengthArray[oddLen]++;
  795. pathLength = oddLen;
  796. }
  797. if (evenLen < pathLength ) {
  798. if (pathLength != MAXSHORTINT)
  799. pathLengthArray[pathLength]--;
  800. if (evenLen != MAXSHORTINT)
  801. pathLengthArray[evenLen]++;
  802. }
  803. return(1);
  804. } /*end of CreateBotDist */
  805. /**
  806. @brief The outer procedure to label each node with its shortest
  807. distance from the root and constant
  808. @details Calls CreateTopDist and CreateBotDist. The basis for
  809. computing the distance between root and constant is that the
  810. distance may be the sum of even distances from the node to the root
  811. and constant or the sum of odd distances from the node to the root
  812. and constant. Both CreateTopDist and CreateBotDist create the odd
  813. and even parity distances from the root and constant respectively.
  814. @sideeffect None
  815. @see CreateTopDist CreateBotDist
  816. */
  817. static st_table *
  818. CreatePathTable(
  819. DdManager *dd /**< %DD manager */,
  820. GlobalInfo_t *gInfo /**< global information */,
  821. DdNode * node /**< root of function */,
  822. unsigned int * pathLengthArray /**< array of path lengths to store nodes labeled with the various path lengths */,
  823. FILE *fp /**< where to write messages */)
  824. {
  825. st_table *pathTable;
  826. NodeDist_t *nodeStat;
  827. DdHalfWord topLen;
  828. DdNode *N;
  829. int i, numParents;
  830. int insertValue;
  831. DdNode **childPage;
  832. int parentPage;
  833. int childQueueIndex, parentQueueIndex;
  834. /* Creating path table for storing data about nodes */
  835. pathTable = st_init_table(st_ptrcmp,st_ptrhash);
  836. /* Initializing pages for info about each node */
  837. gInfo->maxNodeDistPages = INITIAL_PAGES;
  838. gInfo->nodeDistPages = ALLOC(NodeDist_t *, gInfo->maxNodeDistPages);
  839. if (gInfo->nodeDistPages == NULL) {
  840. goto OUT_OF_MEM;
  841. }
  842. assert(gInfo->nodeDistPageSize > 0);
  843. gInfo->nodeDistPage = 0;
  844. gInfo->currentNodeDistPage = gInfo->nodeDistPages[gInfo->nodeDistPage] =
  845. ALLOC(NodeDist_t, gInfo->nodeDistPageSize);
  846. if (gInfo->currentNodeDistPage == NULL) {
  847. for (i = 0; i <= gInfo->nodeDistPage; i++) FREE(gInfo->nodeDistPages[i]);
  848. FREE(gInfo->nodeDistPages);
  849. goto OUT_OF_MEM;
  850. }
  851. gInfo->nodeDistPageIndex = 0;
  852. /* Initializing pages for the BFS search queue, implemented as an array. */
  853. gInfo->maxQueuePages = INITIAL_PAGES;
  854. gInfo->queuePages = ALLOC(DdNode **, gInfo->maxQueuePages);
  855. if (gInfo->queuePages == NULL) {
  856. goto OUT_OF_MEM;
  857. }
  858. assert(gInfo->queuePageSize > 0);
  859. gInfo->queuePage = 0;
  860. gInfo->currentQueuePage = gInfo->queuePages[gInfo->queuePage] =
  861. ALLOC(DdNode *, gInfo->queuePageSize);
  862. if (gInfo->currentQueuePage == NULL) {
  863. for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
  864. FREE(gInfo->queuePages);
  865. goto OUT_OF_MEM;
  866. }
  867. gInfo->queuePageIndex = 0;
  868. /* Enter the root node into the queue to start with. */
  869. parentPage = gInfo->queuePage;
  870. parentQueueIndex = gInfo->queuePageIndex;
  871. topLen = 0;
  872. *(gInfo->currentQueuePage + gInfo->queuePageIndex) = node;
  873. gInfo->queuePageIndex++;
  874. childPage = gInfo->currentQueuePage;
  875. childQueueIndex = gInfo->queuePageIndex;
  876. N = Cudd_Regular(node);
  877. if (gInfo->nodeDistPageIndex == gInfo->nodeDistPageSize)
  878. ResizeNodeDistPages(dd, gInfo);
  879. if (dd->errorCode == CUDD_MEMORY_OUT) {
  880. if (gInfo->nodeDistPages != NULL) {
  881. for (i = 0; i <= gInfo->nodeDistPage; i++)
  882. FREE(gInfo->nodeDistPages[i]);
  883. FREE(gInfo->nodeDistPages);
  884. }
  885. for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
  886. FREE(gInfo->queuePages);
  887. st_free_table(pathTable);
  888. goto OUT_OF_MEM;
  889. }
  890. nodeStat = gInfo->currentNodeDistPage + gInfo->nodeDistPageIndex;
  891. gInfo->nodeDistPageIndex++;
  892. nodeStat->oddTopDist = MAXSHORTINT;
  893. nodeStat->evenTopDist = MAXSHORTINT;
  894. nodeStat->evenBotDist = MAXSHORTINT;
  895. nodeStat->oddBotDist = MAXSHORTINT;
  896. nodeStat->regResult = NULL;
  897. nodeStat->compResult = NULL;
  898. insertValue = st_insert(pathTable, N, nodeStat);
  899. if (insertValue == ST_OUT_OF_MEM) {
  900. dd->errorCode = CUDD_MEMORY_OUT;
  901. for (i = 0; i <= gInfo->nodeDistPage; i++) FREE(gInfo->nodeDistPages[i]);
  902. FREE(gInfo->nodeDistPages);
  903. for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
  904. FREE(gInfo->queuePages);
  905. st_free_table(pathTable);
  906. goto OUT_OF_MEM;
  907. } else if (insertValue == 1) {
  908. fprintf(fp, "Something wrong, the entry exists but didnt show up in st_lookup\n");
  909. return(NULL);
  910. }
  911. if (Cudd_IsComplement(node)) {
  912. nodeStat->oddTopDist = 0;
  913. } else {
  914. nodeStat->evenTopDist = 0;
  915. }
  916. numParents = 1;
  917. /* call the function that counts the distance of each node from the
  918. * root
  919. */
  920. #ifdef DD_DEBUG
  921. gInfo->numCalls = 0;
  922. #endif
  923. CreateTopDist(dd, gInfo, pathTable, parentPage, parentQueueIndex, (int) topLen,
  924. childPage, childQueueIndex, numParents, fp);
  925. if (dd->errorCode == CUDD_MEMORY_OUT) {
  926. fprintf(fp, "Out of Memory and cant count path lengths\n");
  927. goto OUT_OF_MEM;
  928. }
  929. #ifdef DD_DEBUG
  930. gInfo->numCalls = 0;
  931. #endif
  932. /* call the function that counts the distance of each node from the
  933. * constant
  934. */
  935. if (!CreateBotDist(node, pathTable, pathLengthArray, fp)) return(NULL);
  936. /* free BFS queue pages as no longer required */
  937. for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
  938. FREE(gInfo->queuePages);
  939. return(pathTable);
  940. OUT_OF_MEM:
  941. (void) fprintf(fp, "Out of Memory, cannot allocate pages\n");
  942. dd->errorCode = CUDD_MEMORY_OUT;
  943. return(NULL);
  944. } /*end of CreatePathTable */
  945. /**
  946. @brief Chooses the maximum allowable path length of nodes under the
  947. threshold.
  948. @details The corner cases are when the threshold is larger than the
  949. number of nodes in the %BDD iself, in which case 'numVars + 1' is
  950. returned. If all nodes of a particular path length are needed, then
  951. the maxpath returned is the next one with excess nodes = 0.
  952. @sideeffect None
  953. */
  954. static unsigned int
  955. AssessPathLength(
  956. unsigned int * pathLengthArray /* array determining number of nodes belonging to the different path lengths */,
  957. int threshold /* threshold to determine maximum allowable nodes in the subset */,
  958. int numVars /* maximum number of variables */,
  959. unsigned int * excess /* number of nodes labeled maxpath required in the subset */,
  960. FILE *fp /* where to write messages */)
  961. {
  962. unsigned int i, maxpath;
  963. int temp;
  964. temp = threshold;
  965. i = 0;
  966. maxpath = 0;
  967. /* quit loop if i reaches max number of variables or if temp reaches
  968. * below zero
  969. */
  970. while ((i < (unsigned) numVars+1) && (temp > 0)) {
  971. if (pathLengthArray[i] > 0) {
  972. maxpath = i;
  973. temp = temp - pathLengthArray[i];
  974. }
  975. i++;
  976. }
  977. /* if all nodes of max path are needed */
  978. if (temp >= 0) {
  979. maxpath++; /* now maxpath becomes the next maxppath or max number
  980. of variables */
  981. *excess = 0;
  982. } else { /* normal case when subset required is less than size of
  983. original BDD */
  984. *excess = temp + pathLengthArray[maxpath];
  985. }
  986. if (maxpath == 0) {
  987. fprintf(fp, "Path Length array seems to be all zeroes, check\n");
  988. }
  989. return(maxpath);
  990. } /* end of AssessPathLength */
  991. /**
  992. @brief Builds the %BDD with nodes labeled with path length less than
  993. or equal to maxpath.
  994. @details Builds the %BDD with nodes labeled with path length
  995. under maxpath and as many nodes labeled maxpath as determined by the
  996. threshold. The procedure uses the path table to determine which nodes
  997. in the original bdd need to be retained. This procedure picks a
  998. shortest path (tie break decided by taking the child with the shortest
  999. distance to the constant) and recurs down the path till it reaches the
  1000. constant. the procedure then starts building the subset upward from
  1001. the constant. All nodes labeled by path lengths less than the given
  1002. maxpath are used to build the subset. However, in the case of nodes
  1003. that have label equal to maxpath, as many are chosen as required by
  1004. the threshold. This number is stored in the info structure in the
  1005. field thresholdReached. This field is decremented whenever a node
  1006. labeled maxpath is encountered and the nodes labeled maxpath are
  1007. aggregated in a maxpath table. As soon as the thresholdReached count
  1008. goes to 0, the shortest path from this node to the constant is found.
  1009. The extraction of nodes with the above labeling is based on the fact
  1010. that each node, labeled with a path length, P, has at least one child
  1011. labeled P or less. So extracting all nodes labeled a given path length
  1012. P ensures complete paths between the root and the constant. Extraction
  1013. of a partial number of nodes with a given path length may result in
  1014. incomplete paths and hence the additional number of nodes are grabbed
  1015. to complete the path. Since the Bdd is built bottom-up, other nodes
  1016. labeled maxpath do lie on complete paths. The procedure may cause the
  1017. subset to have a larger or smaller number of nodes than the specified
  1018. threshold. The increase in the number of nodes is caused by the
  1019. building of a subset and the reduction by recombination. However in
  1020. most cases, the recombination overshadows the increase and the
  1021. procedure returns a result with lower number of nodes than specified.
  1022. The subsetNodeTable is NIL when there is no hard limit on the number
  1023. of nodes. Further efforts towards keeping the subset closer to the
  1024. threshold number were abandoned in favour of keeping the procedure
  1025. simple and fast.
  1026. @sideeffect SubsetNodeTable is changed if it is not NIL.
  1027. */
  1028. static DdNode *
  1029. BuildSubsetBdd(
  1030. DdManager * dd /**< %DD manager */,
  1031. GlobalInfo_t *gInfo /**< global information */,
  1032. st_table * pathTable /**< path table with path lengths and computed results */,
  1033. DdNode * node /**< current node */,
  1034. struct AssortedInfo * info /**< assorted information structure */,
  1035. st_table * subsetNodeTable /**< table storing computed results */)
  1036. {
  1037. DdNode *N, *Nv, *Nnv;
  1038. DdNode *ThenBranch, *ElseBranch, *childBranch;
  1039. DdNode *child = NULL, *regChild = NULL, *regNnv = NULL, *regNv = NULL;
  1040. NodeDist_t *nodeStatNv, *nodeStat, *nodeStatNnv;
  1041. DdNode *neW, *topv, *regNew;
  1042. char *entry;
  1043. int topid;
  1044. unsigned int childPathLength, oddLen, evenLen;
  1045. unsigned int NnvPathLength = 0, NvPathLength = 0;
  1046. unsigned int NvBotDist, NnvBotDist;
  1047. int tiebreakChild;
  1048. int processingDone, thenDone;
  1049. DdNode *zero = Cudd_Not(DD_ONE(dd));
  1050. #ifdef DD_DEBUG
  1051. gInfo->numCalls++;
  1052. #endif
  1053. if (Cudd_IsConstantInt(node))
  1054. return(node);
  1055. N = Cudd_Regular(node);
  1056. /* Find node in table. */
  1057. if (!st_lookup(pathTable, N, (void **) &nodeStat)) {
  1058. (void) fprintf(dd->err, "Something wrong, node must be in table \n");
  1059. dd->errorCode = CUDD_INTERNAL_ERROR;
  1060. return(NULL);
  1061. }
  1062. /* If the node in the table has been visited, then return the corresponding
  1063. ** Dd. Since a node can become a subset of itself, its
  1064. ** complement (that is te same node reached by a different parity) will
  1065. ** become a superset of the original node and result in some minterms
  1066. ** that were not in the original set. Hence two different results are
  1067. ** maintained, corresponding to the odd and even parities.
  1068. */
  1069. /* If this node is reached with an odd parity, get odd parity results. */
  1070. if (Cudd_IsComplement(node)) {
  1071. if (nodeStat->compResult != NULL) {
  1072. #ifdef DD_DEBUG
  1073. gInfo->hits++;
  1074. #endif
  1075. return(nodeStat->compResult);
  1076. }
  1077. } else {
  1078. /* if this node is reached with an even parity, get even parity
  1079. * results
  1080. */
  1081. if (nodeStat->regResult != NULL) {
  1082. #ifdef DD_DEBUG
  1083. gInfo->hits++;
  1084. #endif
  1085. return(nodeStat->regResult);
  1086. }
  1087. }
  1088. /* get children */
  1089. Nv = Cudd_T(N);
  1090. Nnv = Cudd_E(N);
  1091. Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
  1092. Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
  1093. /* no child processed */
  1094. processingDone = 0;
  1095. /* then child not processed */
  1096. thenDone = 0;
  1097. ThenBranch = NULL;
  1098. /* else child not processed */
  1099. ElseBranch = NULL;
  1100. /* if then child constant, branch is the child */
  1101. if (Cudd_IsConstantInt(Nv)) {
  1102. /*shortest path found */
  1103. if ((Nv == DD_ONE(dd)) && (info->findShortestPath)) {
  1104. info->findShortestPath = 0;
  1105. }
  1106. ThenBranch = Nv;
  1107. cuddRef(ThenBranch);
  1108. if (ThenBranch == NULL) {
  1109. return(NULL);
  1110. }
  1111. thenDone++;
  1112. processingDone++;
  1113. NvBotDist = MAXSHORTINT;
  1114. } else {
  1115. /* Derive regular child for table lookup. */
  1116. regNv = Cudd_Regular(Nv);
  1117. /* Get node data for shortest path length. */
  1118. if (!st_lookup(pathTable, regNv, (void **) &nodeStatNv) ) {
  1119. (void) fprintf(dd->err, "Something wrong, node must be in table\n");
  1120. dd->errorCode = CUDD_INTERNAL_ERROR;
  1121. return(NULL);
  1122. }
  1123. /* Derive shortest path length for child. */
  1124. if ((nodeStatNv->oddTopDist != MAXSHORTINT) &&
  1125. (nodeStatNv->oddBotDist != MAXSHORTINT)) {
  1126. oddLen = (nodeStatNv->oddTopDist + nodeStatNv->oddBotDist);
  1127. } else {
  1128. oddLen = MAXSHORTINT;
  1129. }
  1130. if ((nodeStatNv->evenTopDist != MAXSHORTINT) &&
  1131. (nodeStatNv->evenBotDist != MAXSHORTINT)) {
  1132. evenLen = (nodeStatNv->evenTopDist +nodeStatNv->evenBotDist);
  1133. } else {
  1134. evenLen = MAXSHORTINT;
  1135. }
  1136. NvPathLength = (oddLen <= evenLen) ? oddLen : evenLen;
  1137. NvBotDist = (oddLen <= evenLen) ? nodeStatNv->oddBotDist:
  1138. nodeStatNv->evenBotDist;
  1139. }
  1140. /* if else child constant, branch is the child */
  1141. if (Cudd_IsConstantInt(Nnv)) {
  1142. /*shortest path found */
  1143. if ((Nnv == DD_ONE(dd)) && (info->findShortestPath)) {
  1144. info->findShortestPath = 0;
  1145. }
  1146. ElseBranch = Nnv;
  1147. cuddRef(ElseBranch);
  1148. if (ElseBranch == NULL) {
  1149. return(NULL);
  1150. }
  1151. processingDone++;
  1152. NnvBotDist = MAXSHORTINT;
  1153. } else {
  1154. /* Derive regular child for table lookup. */
  1155. regNnv = Cudd_Regular(Nnv);
  1156. /* Get node data for shortest path length. */
  1157. if (!st_lookup(pathTable, regNnv, (void **) &nodeStatNnv) ) {
  1158. (void) fprintf(dd->err, "Something wrong, node must be in table\n");
  1159. dd->errorCode = CUDD_INTERNAL_ERROR;
  1160. return(NULL);
  1161. }
  1162. /* Derive shortest path length for child. */
  1163. if ((nodeStatNnv->oddTopDist != MAXSHORTINT) &&
  1164. (nodeStatNnv->oddBotDist != MAXSHORTINT)) {
  1165. oddLen = (nodeStatNnv->oddTopDist + nodeStatNnv->oddBotDist);
  1166. } else {
  1167. oddLen = MAXSHORTINT;
  1168. }
  1169. if ((nodeStatNnv->evenTopDist != MAXSHORTINT) &&
  1170. (nodeStatNnv->evenBotDist != MAXSHORTINT)) {
  1171. evenLen = (nodeStatNnv->evenTopDist +nodeStatNnv->evenBotDist);
  1172. } else {
  1173. evenLen = MAXSHORTINT;
  1174. }
  1175. NnvPathLength = (oddLen <= evenLen) ? oddLen : evenLen;
  1176. NnvBotDist = (oddLen <= evenLen) ? nodeStatNnv->oddBotDist :
  1177. nodeStatNnv->evenBotDist;
  1178. }
  1179. tiebreakChild = (NvBotDist <= NnvBotDist) ? 1 : 0;
  1180. /* while both children not processed */
  1181. while (processingDone != 2) {
  1182. if (!processingDone) {
  1183. /* if no child processed */
  1184. /* pick the child with shortest path length and record which one
  1185. * picked
  1186. */
  1187. if ((NvPathLength < NnvPathLength) ||
  1188. ((NvPathLength == NnvPathLength) && (tiebreakChild == 1))) {
  1189. child = Nv;
  1190. regChild = regNv;
  1191. thenDone = 1;
  1192. childPathLength = NvPathLength;
  1193. } else {
  1194. child = Nnv;
  1195. regChild = regNnv;
  1196. childPathLength = NnvPathLength;
  1197. } /* then path length less than else path length */
  1198. } else {
  1199. /* if one child processed, process the other */
  1200. if (thenDone) {
  1201. child = Nnv;
  1202. regChild = regNnv;
  1203. childPathLength = NnvPathLength;
  1204. } else {
  1205. child = Nv;
  1206. regChild = regNv;
  1207. thenDone = 1;
  1208. childPathLength = NvPathLength;
  1209. } /* end of else pick the Then child if ELSE child processed */
  1210. } /* end of else one child has been processed */
  1211. /* ignore (replace with constant 0) all nodes which lie on paths larger
  1212. * than the maximum length of the path required
  1213. */
  1214. if (childPathLength > info->maxpath) {
  1215. /* record nodes visited */
  1216. childBranch = zero;
  1217. } else {
  1218. if (childPathLength < info->maxpath) {
  1219. if (info->findShortestPath) {
  1220. info->findShortestPath = 0;
  1221. }
  1222. childBranch = BuildSubsetBdd(dd, gInfo, pathTable, child, info,
  1223. subsetNodeTable);
  1224. } else { /* Case: path length of node = maxpath */
  1225. /* If the node labeled with maxpath is found in the
  1226. ** maxpathTable, use it to build the subset BDD. */
  1227. if (st_lookup(info->maxpathTable, regChild, (void **) &entry)) {
  1228. /* When a node that is already been chosen is hit,
  1229. ** the quest for a complete path is over. */
  1230. if (info->findShortestPath) {
  1231. info->findShortestPath = 0;
  1232. }
  1233. childBranch = BuildSubsetBdd(dd, gInfo, pathTable, child, info,
  1234. subsetNodeTable);
  1235. } else {
  1236. /* If node is not found in the maxpathTable and
  1237. ** the threshold has been reached, then if the
  1238. ** path needs to be completed, continue. Else
  1239. ** replace the node with a zero. */
  1240. if (info->thresholdReached <= 0) {
  1241. if (info->findShortestPath) {
  1242. if (st_insert(info->maxpathTable, regChild,
  1243. NULL) == ST_OUT_OF_MEM) {
  1244. dd->errorCode = CUDD_MEMORY_OUT;
  1245. (void) fprintf(dd->err, "OUT of memory\n");
  1246. info->thresholdReached = 0;
  1247. childBranch = zero;
  1248. } else {
  1249. info->thresholdReached--;
  1250. childBranch = BuildSubsetBdd(dd, gInfo, pathTable,
  1251. child, info,subsetNodeTable);
  1252. }
  1253. } else { /* not find shortest path, we dont need this
  1254. node */
  1255. childBranch = zero;
  1256. }
  1257. } else { /* Threshold hasn't been reached,
  1258. ** need the node. */
  1259. if (st_insert(info->maxpathTable, regChild,
  1260. NULL) == ST_OUT_OF_MEM) {
  1261. dd->errorCode = CUDD_MEMORY_OUT;
  1262. (void) fprintf(dd->err, "OUT of memory\n");
  1263. info->thresholdReached = 0;
  1264. childBranch = zero;
  1265. } else {
  1266. info->thresholdReached--;
  1267. if (info->thresholdReached <= 0) {
  1268. info->findShortestPath = 1;
  1269. }
  1270. childBranch = BuildSubsetBdd(dd, gInfo, pathTable,
  1271. child, info, subsetNodeTable);
  1272. } /* end of st_insert successful */
  1273. } /* end of threshold hasnt been reached yet */
  1274. } /* end of else node not found in maxpath table */
  1275. } /* end of if (path length of node = maxpath) */
  1276. } /* end if !(childPathLength > maxpath) */
  1277. if (childBranch == NULL) {
  1278. /* deref other stuff incase reordering has taken place */
  1279. if (ThenBranch != NULL) {
  1280. Cudd_RecursiveDeref(dd, ThenBranch);
  1281. ThenBranch = NULL;
  1282. }
  1283. if (ElseBranch != NULL) {
  1284. Cudd_RecursiveDeref(dd, ElseBranch);
  1285. ElseBranch = NULL;
  1286. }
  1287. return(NULL);
  1288. }
  1289. cuddRef(childBranch);
  1290. if (child == Nv) {
  1291. ThenBranch = childBranch;
  1292. } else {
  1293. ElseBranch = childBranch;
  1294. }
  1295. processingDone++;
  1296. } /*end of while processing Nv, Nnv */
  1297. info->findShortestPath = 0;
  1298. topid = Cudd_NodeReadIndex(N);
  1299. topv = Cudd_ReadVars(dd, topid);
  1300. cuddRef(topv);
  1301. neW = cuddBddIteRecur(dd, topv, ThenBranch, ElseBranch);
  1302. if (neW != NULL) {
  1303. cuddRef(neW);
  1304. }
  1305. Cudd_RecursiveDeref(dd, topv);
  1306. Cudd_RecursiveDeref(dd, ThenBranch);
  1307. Cudd_RecursiveDeref(dd, ElseBranch);
  1308. if (neW == NULL) {
  1309. return(NULL);
  1310. } else {
  1311. /* Hard Limit of threshold has been imposed */
  1312. if (subsetNodeTable != NIL(st_table)) {
  1313. /* check if a new node is created */
  1314. regNew = Cudd_Regular(neW);
  1315. /* subset node table keeps all new nodes that have been created to
  1316. * keep a running count of how many nodes have been built in the
  1317. * subset.
  1318. */
  1319. if (!st_lookup(subsetNodeTable, regNew, (void **) &entry)) {
  1320. if (!Cudd_IsConstantInt(regNew)) {
  1321. if (st_insert(subsetNodeTable, regNew,
  1322. NULL) == ST_OUT_OF_MEM) {
  1323. (void) fprintf(dd->err, "Out of memory\n");
  1324. return (NULL);
  1325. }
  1326. if (st_count(subsetNodeTable) > info->threshold) {
  1327. info->thresholdReached = 0;
  1328. }
  1329. }
  1330. }
  1331. }
  1332. /*store computed result in regular form*/
  1333. if (Cudd_IsComplement(node)) {
  1334. nodeStat->compResult = neW;
  1335. cuddRef(nodeStat->compResult);
  1336. /* if the new node is the same as the corresponding node in the
  1337. * original bdd then its complement need not be computed as it
  1338. * cannot be larger than the node itself
  1339. */
  1340. if (neW == node) {
  1341. #ifdef DD_DEBUG
  1342. gInfo->thishit++;
  1343. #endif
  1344. /* if a result for the node has already been computed, then
  1345. * it can only be smaller than teh node itself. hence store
  1346. * the node result in order not to break recombination
  1347. */
  1348. if (nodeStat->regResult != NULL) {
  1349. Cudd_RecursiveDeref(dd, nodeStat->regResult);
  1350. }
  1351. nodeStat->regResult = Cudd_Not(neW);
  1352. cuddRef(nodeStat->regResult);
  1353. }
  1354. } else {
  1355. nodeStat->regResult = neW;
  1356. cuddRef(nodeStat->regResult);
  1357. if (neW == node) {
  1358. #ifdef DD_DEBUG
  1359. gInfo->thishit++;
  1360. #endif
  1361. if (nodeStat->compResult != NULL) {
  1362. Cudd_RecursiveDeref(dd, nodeStat->compResult);
  1363. }
  1364. nodeStat->compResult = Cudd_Not(neW);
  1365. cuddRef(nodeStat->compResult);
  1366. }
  1367. }
  1368. cuddDeref(neW);
  1369. return(neW);
  1370. } /* end of else i.e. Subset != NULL */
  1371. } /* end of BuildSubsetBdd */
  1372. /**
  1373. @brief Procedure to free the result dds stored in the NodeDist pages.
  1374. @sideeffect None
  1375. */
  1376. static enum st_retval
  1377. stPathTableDdFree(
  1378. void * key,
  1379. void * value,
  1380. void * arg)
  1381. {
  1382. NodeDist_t *nodeStat = (NodeDist_t *) value;
  1383. DdManager *dd = (DdManager *) arg;
  1384. (void) key; /* avoid warning */
  1385. if (nodeStat->regResult != NULL) {
  1386. Cudd_RecursiveDeref(dd, nodeStat->regResult);
  1387. }
  1388. if (nodeStat->compResult != NULL) {
  1389. Cudd_RecursiveDeref(dd, nodeStat->compResult);
  1390. }
  1391. return(ST_CONTINUE);
  1392. } /* end of stPathTableFree */