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.

2177 lines
64 KiB

  1. /**
  2. @file
  3. @ingroup cudd
  4. @brief Procedures to approximate a given %BDD.
  5. @see cuddSubsetHB.c cuddSubsetSP.c cuddGenCof.c
  6. @author Fabio Somenzi
  7. @copyright@parblock
  8. Copyright (c) 1995-2015, Regents of the University of Colorado
  9. All rights reserved.
  10. Redistribution and use in source and binary forms, with or without
  11. modification, are permitted provided that the following conditions
  12. are met:
  13. Redistributions of source code must retain the above copyright
  14. notice, this list of conditions and the following disclaimer.
  15. Redistributions in binary form must reproduce the above copyright
  16. notice, this list of conditions and the following disclaimer in the
  17. documentation and/or other materials provided with the distribution.
  18. Neither the name of the University of Colorado nor the names of its
  19. contributors may be used to endorse or promote products derived from
  20. this software without specific prior written permission.
  21. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  28. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  29. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. POSSIBILITY OF SUCH DAMAGE.
  33. @endparblock
  34. */
  35. #ifdef __STDC__
  36. #include <float.h>
  37. #else
  38. #define DBL_MAX_EXP 1024
  39. #endif
  40. #include "util.h"
  41. #include "cuddInt.h"
  42. /*---------------------------------------------------------------------------*/
  43. /* Constant declarations */
  44. /*---------------------------------------------------------------------------*/
  45. #define NOTHING 0
  46. #define REPLACE_T 1
  47. #define REPLACE_E 2
  48. #define REPLACE_N 3
  49. #define REPLACE_TT 4
  50. #define REPLACE_TE 5
  51. #define DONT_CARE 0
  52. #define CARE 1
  53. #define TOTAL_CARE 2
  54. #define CARE_ERROR 3
  55. /*---------------------------------------------------------------------------*/
  56. /* Stucture declarations */
  57. /*---------------------------------------------------------------------------*/
  58. /*---------------------------------------------------------------------------*/
  59. /* Type declarations */
  60. /*---------------------------------------------------------------------------*/
  61. /**
  62. ** @brief Data structure to store the information on each node.
  63. **
  64. ** @details It keeps the number of minterms of the function rooted at
  65. ** this node in terms of the number of variables specified by the
  66. ** user; the number of minterms of the complement; the impact of the
  67. ** number of minterms of this function on the number of minterms of
  68. ** the root function; the reference count of the node from within the
  69. ** root function; the flag that says whether the node intersects the
  70. ** care set; the flag that says whether the node should be replaced
  71. ** and how; the results of subsetting in both phases.
  72. */
  73. typedef struct NodeData {
  74. double mintermsP; /**< minterms for the regular node */
  75. double mintermsN; /**< minterms for the complemented node */
  76. int functionRef; /**< references from within this function */
  77. char care; /**< node intersects care set */
  78. char replace; /**< replacement decision */
  79. short int parity; /**< 1: even; 2: odd; 3: both */
  80. DdNode *resultP; /**< result for even parity */
  81. DdNode *resultN; /**< result for odd parity */
  82. } NodeData;
  83. /**
  84. ** @brief Main bookkeeping data structure for approximation algorithms.
  85. */
  86. typedef struct ApproxInfo {
  87. DdNode *one; /**< one constant */
  88. DdNode *zero; /**< %BDD zero constant */
  89. NodeData *page; /**< per-node information */
  90. DdHashTable *table; /**< hash table to access the per-node info */
  91. int index; /**< index of the current node */
  92. double max; /**< max number of minterms */
  93. int size; /**< how many nodes are left */
  94. double minterms; /**< how many minterms are left */
  95. } ApproxInfo;
  96. /**
  97. ** @brief Item of the queue used in the levelized traversal of the %BDD.
  98. */
  99. typedef struct GlobalQueueItem {
  100. struct GlobalQueueItem *next;
  101. struct GlobalQueueItem *cnext;
  102. DdNode *node;
  103. double impactP;
  104. double impactN;
  105. } GlobalQueueItem;
  106. /**
  107. ** @brief Type of the item of the local queue.
  108. */
  109. typedef struct LocalQueueItem {
  110. struct LocalQueueItem *next;
  111. struct LocalQueueItem *cnext;
  112. DdNode *node;
  113. int localRef;
  114. } LocalQueueItem;
  115. /*---------------------------------------------------------------------------*/
  116. /* Variable declarations */
  117. /*---------------------------------------------------------------------------*/
  118. /*---------------------------------------------------------------------------*/
  119. /* Macro declarations */
  120. /*---------------------------------------------------------------------------*/
  121. /** \cond */
  122. /*---------------------------------------------------------------------------*/
  123. /* Static function prototypes */
  124. /*---------------------------------------------------------------------------*/
  125. static void updateParity (DdNode *node, ApproxInfo *info, int newparity);
  126. static NodeData * gatherInfoAux (DdNode *node, ApproxInfo *info, int parity);
  127. static ApproxInfo * gatherInfo (DdManager *dd, DdNode *node, int numVars, int parity);
  128. static int computeSavings (DdManager *dd, DdNode *f, DdNode *skip, ApproxInfo *info, DdLevelQueue *queue);
  129. static int updateRefs (DdManager *dd, DdNode *f, DdNode *skip, ApproxInfo *info, DdLevelQueue *queue);
  130. static int UAmarkNodes (DdManager *dd, DdNode *f, ApproxInfo *info, int threshold, int safe, double quality);
  131. static DdNode * UAbuildSubset (DdManager *dd, DdNode *node, ApproxInfo *info);
  132. static int RAmarkNodes (DdManager *dd, DdNode *f, ApproxInfo *info, int threshold, double quality);
  133. static int BAmarkNodes (DdManager *dd, DdNode *f, ApproxInfo *info, int threshold, double quality1, double quality0);
  134. static DdNode * RAbuildSubset (DdManager *dd, DdNode *node, ApproxInfo *info);
  135. static int BAapplyBias (DdManager *dd, DdNode *f, DdNode *b, ApproxInfo *info, DdHashTable *cache);
  136. /** \endcond */
  137. /*---------------------------------------------------------------------------*/
  138. /* Definition of exported functions */
  139. /*---------------------------------------------------------------------------*/
  140. /**
  141. @brief Extracts a dense subset from a %BDD with Shiple's
  142. underapproximation method.
  143. @details This procedure uses a variant of Tom Shiple's
  144. underapproximation method. The main difference from the original
  145. method is that density is used as cost function. The parameter
  146. numVars is the maximum number of variables to be used in minterm
  147. calculation. The optimal number should be as close as possible to
  148. the size of the support of f. However, it is safe to pass the value
  149. returned by Cudd_ReadSize for numVars when the number of variables
  150. is under 1023. If numVars is larger than 1023, it will cause
  151. overflow. If a 0 parameter is passed then the procedure will compute
  152. a value which will avoid overflow but will cause underflow with 2046
  153. variables or more.
  154. @return a pointer to the %BDD of the subset if successful; NULL if
  155. the procedure runs out of memory.
  156. @sideeffect None
  157. @see Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch Cudd_ReadSize
  158. */
  159. DdNode *
  160. Cudd_UnderApprox(
  161. DdManager * dd /**< manager */,
  162. DdNode * f /**< function to be subset */,
  163. int numVars /**< number of variables in the support of f */,
  164. int threshold /**< when to stop approximation */,
  165. int safe /**< enforce safe approximation */,
  166. double quality /**< minimum improvement for accepted changes */)
  167. {
  168. DdNode *subset;
  169. do {
  170. dd->reordered = 0;
  171. subset = cuddUnderApprox(dd, f, numVars, threshold, safe, quality);
  172. } while (dd->reordered == 1);
  173. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  174. dd->timeoutHandler(dd, dd->tohArg);
  175. }
  176. return(subset);
  177. } /* end of Cudd_UnderApprox */
  178. /**
  179. @brief Extracts a dense superset from a %BDD with Shiple's
  180. underapproximation method.
  181. @details The procedure is identical to the underapproximation
  182. procedure except for the fact that it works on the complement of the
  183. given function. Extracting the subset of the complement function is
  184. equivalent to extracting the superset of the function. The
  185. parameter numVars is the maximum number of variables to be used in
  186. minterm calculation. The optimal number should be as close as
  187. possible to the size of the support of f. However, it is safe to
  188. pass the value returned by Cudd_ReadSize for numVars when the number
  189. of variables is under 1023. If numVars is larger than 1023, it will
  190. overflow. If a 0 parameter is passed then the procedure will compute
  191. a value which will avoid overflow but will cause underflow with 2046
  192. variables or more.
  193. @return a pointer to the %BDD of the superset if successful. NULL if
  194. intermediate result causes the procedure to run out of memory.
  195. @sideeffect None
  196. @see Cudd_SupersetHeavyBranch Cudd_SupersetShortPaths Cudd_ReadSize
  197. */
  198. DdNode *
  199. Cudd_OverApprox(
  200. DdManager * dd /**< manager */,
  201. DdNode * f /**< function to be superset */,
  202. int numVars /**< number of variables in the support of f */,
  203. int threshold /**< when to stop approximation */,
  204. int safe /**< enforce safe approximation */,
  205. double quality /**< minimum improvement for accepted changes */)
  206. {
  207. DdNode *subset, *g;
  208. g = Cudd_Not(f);
  209. do {
  210. dd->reordered = 0;
  211. subset = cuddUnderApprox(dd, g, numVars, threshold, safe, quality);
  212. } while (dd->reordered == 1);
  213. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  214. dd->timeoutHandler(dd, dd->tohArg);
  215. }
  216. return(Cudd_NotCond(subset, (subset != NULL)));
  217. } /* end of Cudd_OverApprox */
  218. /**
  219. @brief Extracts a dense subset from a %BDD with the remapping
  220. underapproximation method.
  221. @details This procedure uses a remapping technique and density as
  222. the cost function. The parameter numVars is the maximum number of
  223. variables to be used in minterm calculation. The optimal number
  224. should be as close as possible to the size of the support of f.
  225. However, it is safe to pass the value returned by Cudd_ReadSize for
  226. numVars when the number of variables is under 1023. If numVars is
  227. larger than 1023, it will cause overflow. If a 0 parameter is passed
  228. then the procedure will compute a value which will avoid overflow
  229. but will cause underflow with 2046 variables or more.
  230. @return a pointer to the %BDD of the subset if successful. NULL if
  231. the procedure runs out of memory.
  232. @sideeffect None
  233. @see Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch Cudd_UnderApprox Cudd_ReadSize
  234. */
  235. DdNode *
  236. Cudd_RemapUnderApprox(
  237. DdManager * dd /**< manager */,
  238. DdNode * f /**< function to be subset */,
  239. int numVars /**< number of variables in the support of f */,
  240. int threshold /**< when to stop approximation */,
  241. double quality /**< minimum improvement for accepted changes */)
  242. {
  243. DdNode *subset;
  244. do {
  245. dd->reordered = 0;
  246. subset = cuddRemapUnderApprox(dd, f, numVars, threshold, quality);
  247. } while (dd->reordered == 1);
  248. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  249. dd->timeoutHandler(dd, dd->tohArg);
  250. }
  251. return(subset);
  252. } /* end of Cudd_RemapUnderApprox */
  253. /**
  254. @brief Extracts a dense superset from a %BDD with the remapping
  255. underapproximation method.
  256. @details The procedure is identical to the underapproximation
  257. procedure except for the fact that it works on the complement of the
  258. given function. Extracting the subset of the complement function is
  259. equivalent to extracting the superset of the function. The parameter
  260. numVars is the maximum number of variables to be used in minterm
  261. calculation. The optimal number should be as close as possible to
  262. the size of the support of f. However, it is safe to pass the value
  263. returned by Cudd_ReadSize for numVars when the number of variables
  264. is under 1023. If numVars is larger than 1023, it will overflow. If
  265. a 0 parameter is passed then the procedure will compute a value
  266. which will avoid overflow but will cause underflow with 2046
  267. variables or more.
  268. @return a pointer to the %BDD of the superset if successful. NULL if
  269. intermediate result causes the procedure to run out of memory.
  270. @sideeffect None
  271. @see Cudd_SupersetHeavyBranch Cudd_SupersetShortPaths Cudd_ReadSize
  272. */
  273. DdNode *
  274. Cudd_RemapOverApprox(
  275. DdManager * dd /**< manager */,
  276. DdNode * f /**< function to be superset */,
  277. int numVars /**< number of variables in the support of f */,
  278. int threshold /**< when to stop approximation */,
  279. double quality /**< minimum improvement for accepted changes */)
  280. {
  281. DdNode *subset, *g;
  282. g = Cudd_Not(f);
  283. do {
  284. dd->reordered = 0;
  285. subset = cuddRemapUnderApprox(dd, g, numVars, threshold, quality);
  286. } while (dd->reordered == 1);
  287. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  288. dd->timeoutHandler(dd, dd->tohArg);
  289. }
  290. return(Cudd_NotCond(subset, (subset != NULL)));
  291. } /* end of Cudd_RemapOverApprox */
  292. /**
  293. @brief Extracts a dense subset from a %BDD with the biased
  294. underapproximation method.
  295. @details This procedure uses a biased remapping technique and
  296. density as the cost function. The bias is a function. This procedure
  297. tries to approximate where the bias is 0 and preserve the given
  298. function where the bias is 1. The parameter numVars is the maximum
  299. number of variables to be used in minterm calculation. The optimal
  300. number should be as close as possible to the size of the support of
  301. f. However, it is safe to pass the value returned by Cudd_ReadSize
  302. for numVars when the number of variables is under 1023. If numVars
  303. is larger than 1023, it will cause overflow. If a 0 parameter is
  304. passed then the procedure will compute a value which will avoid
  305. overflow but will cause underflow with 2046 variables or more.
  306. @return a pointer to the %BDD of the subset if successful. NULL if
  307. the procedure runs out of memory.
  308. @sideeffect None
  309. @see Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch Cudd_UnderApprox
  310. Cudd_RemapUnderApprox Cudd_ReadSize
  311. */
  312. DdNode *
  313. Cudd_BiasedUnderApprox(
  314. DdManager *dd /**< manager */,
  315. DdNode *f /**< function to be subset */,
  316. DdNode *b /**< bias function */,
  317. int numVars /**< number of variables in the support of f */,
  318. int threshold /**< when to stop approximation */,
  319. double quality1 /**< minimum improvement for accepted changes when b=1 */,
  320. double quality0 /**< minimum improvement for accepted changes when b=0 */)
  321. {
  322. DdNode *subset;
  323. do {
  324. dd->reordered = 0;
  325. subset = cuddBiasedUnderApprox(dd, f, b, numVars, threshold, quality1,
  326. quality0);
  327. } while (dd->reordered == 1);
  328. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  329. dd->timeoutHandler(dd, dd->tohArg);
  330. }
  331. return(subset);
  332. } /* end of Cudd_BiasedUnderApprox */
  333. /**
  334. @brief Extracts a dense superset from a %BDD with the biased
  335. underapproximation method.
  336. @details The procedure is identical to the underapproximation
  337. procedure except for the fact that it works on the complement of the
  338. given function. Extracting the subset of the complement function is
  339. equivalent to extracting the superset of the function. The
  340. parameter numVars is the maximum number of variables to be used in
  341. minterm calculation. The optimal number should be as close as
  342. possible to the size of the support of f. However, it is safe to
  343. pass the value returned by Cudd_ReadSize for numVars when the number
  344. of variables is under 1023. If numVars is larger than 1023, it will
  345. overflow. If a 0 parameter is passed then the procedure will compute
  346. a value which will avoid overflow but will cause underflow with 2046
  347. variables or more.
  348. @return a pointer to the %BDD of the superset if successful. NULL if
  349. intermediate result causes the procedure to run out of memory.
  350. @sideeffect None
  351. @see Cudd_SupersetHeavyBranch Cudd_SupersetShortPaths
  352. Cudd_RemapOverApprox Cudd_BiasedUnderApprox Cudd_ReadSize
  353. */
  354. DdNode *
  355. Cudd_BiasedOverApprox(
  356. DdManager *dd /**< manager */,
  357. DdNode *f /**< function to be superset */,
  358. DdNode *b /**< bias function */,
  359. int numVars /**< number of variables in the support of f */,
  360. int threshold /**< when to stop approximation */,
  361. double quality1 /**< minimum improvement for accepted changes when b=1*/,
  362. double quality0 /**< minimum improvement for accepted changes when b=0 */)
  363. {
  364. DdNode *subset, *g;
  365. g = Cudd_Not(f);
  366. do {
  367. dd->reordered = 0;
  368. subset = cuddBiasedUnderApprox(dd, g, b, numVars, threshold, quality1,
  369. quality0);
  370. } while (dd->reordered == 1);
  371. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  372. dd->timeoutHandler(dd, dd->tohArg);
  373. }
  374. return(Cudd_NotCond(subset, (subset != NULL)));
  375. } /* end of Cudd_BiasedOverApprox */
  376. /*---------------------------------------------------------------------------*/
  377. /* Definition of internal functions */
  378. /*---------------------------------------------------------------------------*/
  379. /**
  380. @brief Applies Tom Shiple's underappoximation algorithm.
  381. @details Proceeds in three phases:
  382. <ul>
  383. <li> collect information on each node in the %BDD; this is done via DFS.
  384. <li> traverse the %BDD in top-down fashion and compute for each node
  385. whether its elimination increases density.
  386. <li> traverse the %BDD via DFS and actually perform the elimination.
  387. </ul>
  388. @return the approximated %BDD if successful; NULL otherwise.
  389. @sideeffect None
  390. @see Cudd_UnderApprox
  391. */
  392. DdNode *
  393. cuddUnderApprox(
  394. DdManager * dd /**< %DD manager */,
  395. DdNode * f /**< current %DD */,
  396. int numVars /**< maximum number of variables */,
  397. int threshold /**< threshold under which approximation stops */,
  398. int safe /**< enforce safe approximation */,
  399. double quality /**< minimum improvement for accepted changes */)
  400. {
  401. ApproxInfo *info;
  402. DdNode *subset;
  403. int result;
  404. if (f == NULL) {
  405. fprintf(dd->err, "Cannot subset, nil object\n");
  406. return(NULL);
  407. }
  408. if (Cudd_IsConstantInt(f)) {
  409. return(f);
  410. }
  411. /* Create table where node data are accessible via a hash table. */
  412. info = gatherInfo(dd, f, numVars, safe);
  413. if (info == NULL) {
  414. (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
  415. dd->errorCode = CUDD_MEMORY_OUT;
  416. return(NULL);
  417. }
  418. /* Mark nodes that should be replaced by zero. */
  419. result = UAmarkNodes(dd, f, info, threshold, safe, quality);
  420. if (result == 0) {
  421. (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
  422. FREE(info->page);
  423. cuddHashTableGenericQuit(info->table);
  424. FREE(info);
  425. dd->errorCode = CUDD_MEMORY_OUT;
  426. return(NULL);
  427. }
  428. /* Build the result. */
  429. subset = UAbuildSubset(dd, f, info);
  430. #if 1
  431. if (subset && info->size < Cudd_DagSize(subset))
  432. (void) fprintf(dd->err, "Wrong prediction: %d versus actual %d\n",
  433. info->size, Cudd_DagSize(subset));
  434. #endif
  435. FREE(info->page);
  436. cuddHashTableGenericQuit(info->table);
  437. FREE(info);
  438. #ifdef DD_DEBUG
  439. if (subset != NULL) {
  440. cuddRef(subset);
  441. #if 0
  442. (void) Cudd_DebugCheck(dd);
  443. (void) Cudd_CheckKeys(dd);
  444. #endif
  445. if (!Cudd_bddLeq(dd, subset, f)) {
  446. (void) fprintf(dd->err, "Wrong subset\n");
  447. dd->errorCode = CUDD_INTERNAL_ERROR;
  448. }
  449. cuddDeref(subset);
  450. }
  451. #endif
  452. return(subset);
  453. } /* end of cuddUnderApprox */
  454. /**
  455. @brief Applies the remapping underappoximation algorithm.
  456. @details Proceeds in three phases:
  457. <ul>
  458. <li> collect information on each node in the %BDD; this is done via DFS.
  459. <li> traverse the %BDD in top-down fashion and compute for each node
  460. whether remapping increases density.
  461. <li> traverse the %BDD via DFS and actually perform the elimination.
  462. </ul>
  463. @return the approximated %BDD if successful; NULL otherwise.
  464. @sideeffect None
  465. @see Cudd_RemapUnderApprox
  466. */
  467. DdNode *
  468. cuddRemapUnderApprox(
  469. DdManager * dd /**< %DD manager */,
  470. DdNode * f /**< current %DD */,
  471. int numVars /**< maximum number of variables */,
  472. int threshold /**< threshold under which approximation stops */,
  473. double quality /**< minimum improvement for accepted changes */)
  474. {
  475. ApproxInfo *info;
  476. DdNode *subset;
  477. int result;
  478. if (f == NULL) {
  479. fprintf(dd->err, "Cannot subset, nil object\n");
  480. dd->errorCode = CUDD_INVALID_ARG;
  481. return(NULL);
  482. }
  483. if (Cudd_IsConstantInt(f)) {
  484. return(f);
  485. }
  486. /* Create table where node data are accessible via a hash table. */
  487. info = gatherInfo(dd, f, numVars, CUDD_TRUE);
  488. if (info == NULL) {
  489. (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
  490. dd->errorCode = CUDD_MEMORY_OUT;
  491. return(NULL);
  492. }
  493. /* Mark nodes that should be replaced by zero. */
  494. result = RAmarkNodes(dd, f, info, threshold, quality);
  495. if (result == 0) {
  496. (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
  497. FREE(info->page);
  498. cuddHashTableGenericQuit(info->table);
  499. FREE(info);
  500. dd->errorCode = CUDD_MEMORY_OUT;
  501. return(NULL);
  502. }
  503. /* Build the result. */
  504. subset = RAbuildSubset(dd, f, info);
  505. #if 1
  506. if (subset && info->size < Cudd_DagSize(subset))
  507. (void) fprintf(dd->err, "Wrong prediction: %d versus actual %d\n",
  508. info->size, Cudd_DagSize(subset));
  509. #endif
  510. FREE(info->page);
  511. cuddHashTableGenericQuit(info->table);
  512. FREE(info);
  513. #ifdef DD_DEBUG
  514. if (subset != NULL) {
  515. cuddRef(subset);
  516. #if 0
  517. (void) Cudd_DebugCheck(dd);
  518. (void) Cudd_CheckKeys(dd);
  519. #endif
  520. if (!Cudd_bddLeq(dd, subset, f)) {
  521. (void) fprintf(dd->err, "Wrong subset\n");
  522. }
  523. cuddDeref(subset);
  524. dd->errorCode = CUDD_INTERNAL_ERROR;
  525. }
  526. #endif
  527. return(subset);
  528. } /* end of cuddRemapUnderApprox */
  529. /**
  530. @brief Applies the biased remapping underappoximation algorithm.
  531. @details Proceeds in three phases:
  532. <ul>
  533. <li> collect information on each node in the %BDD; this is done via DFS.
  534. <li> traverse the %BDD in top-down fashion and compute for each node
  535. whether remapping increases density.
  536. <li> traverse the %BDD via DFS and actually perform the elimination.
  537. </ul>
  538. @return the approximated %BDD if successful; NULL otherwise.
  539. @sideeffect None
  540. @see Cudd_BiasedUnderApprox
  541. */
  542. DdNode *
  543. cuddBiasedUnderApprox(
  544. DdManager *dd /**< %DD manager */,
  545. DdNode *f /**< current %DD */,
  546. DdNode *b /**< bias function */,
  547. int numVars /**< maximum number of variables */,
  548. int threshold /**< threshold under which approximation stops */,
  549. double quality1 /**< minimum improvement for accepted changes when b=1 */,
  550. double quality0 /**< minimum improvement for accepted changes when b=0 */)
  551. {
  552. ApproxInfo *info;
  553. DdNode *subset;
  554. int result;
  555. DdHashTable *cache;
  556. if (f == NULL) {
  557. fprintf(dd->err, "Cannot subset, nil object\n");
  558. dd->errorCode = CUDD_INVALID_ARG;
  559. return(NULL);
  560. }
  561. if (Cudd_IsConstantInt(f)) {
  562. return(f);
  563. }
  564. /* Create table where node data are accessible via a hash table. */
  565. info = gatherInfo(dd, f, numVars, CUDD_TRUE);
  566. if (info == NULL) {
  567. (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
  568. dd->errorCode = CUDD_MEMORY_OUT;
  569. return(NULL);
  570. }
  571. cache = cuddHashTableInit(dd,2,2);
  572. result = BAapplyBias(dd, Cudd_Regular(f), b, info, cache);
  573. if (result == CARE_ERROR) {
  574. (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
  575. cuddHashTableQuit(cache);
  576. FREE(info->page);
  577. cuddHashTableGenericQuit(info->table);
  578. FREE(info);
  579. dd->errorCode = CUDD_MEMORY_OUT;
  580. return(NULL);
  581. }
  582. cuddHashTableQuit(cache);
  583. /* Mark nodes that should be replaced by zero. */
  584. result = BAmarkNodes(dd, f, info, threshold, quality1, quality0);
  585. if (result == 0) {
  586. (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
  587. FREE(info->page);
  588. cuddHashTableGenericQuit(info->table);
  589. FREE(info);
  590. dd->errorCode = CUDD_MEMORY_OUT;
  591. return(NULL);
  592. }
  593. /* Build the result. */
  594. subset = RAbuildSubset(dd, f, info);
  595. #if 1
  596. if (subset && info->size < Cudd_DagSize(subset))
  597. (void) fprintf(dd->err, "Wrong prediction: %d versus actual %d\n",
  598. info->size, Cudd_DagSize(subset));
  599. #endif
  600. FREE(info->page);
  601. cuddHashTableGenericQuit(info->table);
  602. FREE(info);
  603. #ifdef DD_DEBUG
  604. if (subset != NULL) {
  605. cuddRef(subset);
  606. #if 0
  607. (void) Cudd_DebugCheck(dd);
  608. (void) Cudd_CheckKeys(dd);
  609. #endif
  610. if (!Cudd_bddLeq(dd, subset, f)) {
  611. (void) fprintf(dd->err, "Wrong subset\n");
  612. }
  613. cuddDeref(subset);
  614. dd->errorCode = CUDD_INTERNAL_ERROR;
  615. }
  616. #endif
  617. return(subset);
  618. } /* end of cuddBiasedUnderApprox */
  619. /*---------------------------------------------------------------------------*/
  620. /* Definition of static functions */
  621. /*---------------------------------------------------------------------------*/
  622. /**
  623. @brief Recursively update the parity of the paths reaching a node.
  624. @details Assumes that node is regular and propagates the invariant.
  625. @sideeffect None
  626. @see gatherInfoAux
  627. */
  628. static void
  629. updateParity(
  630. DdNode * node /**< function to analyze */,
  631. ApproxInfo * info /**< info on %BDD */,
  632. int newparity /**< new parity for node */)
  633. {
  634. NodeData *infoN;
  635. DdNode *E;
  636. if ((infoN = (NodeData *) cuddHashTableGenericLookup(info->table, node)) == NULL)
  637. return;
  638. if ((infoN->parity & newparity) != 0) return;
  639. infoN->parity |= (short) newparity;
  640. if (Cudd_IsConstantInt(node)) return;
  641. updateParity(cuddT(node),info,newparity);
  642. E = cuddE(node);
  643. if (Cudd_IsComplement(E)) {
  644. updateParity(Cudd_Not(E),info,3-newparity);
  645. } else {
  646. updateParity(E,info,newparity);
  647. }
  648. return;
  649. } /* end of updateParity */
  650. /**
  651. @brief Recursively counts minterms and computes reference counts
  652. of each node in the %BDD.
  653. @details Similar to the cuddCountMintermAux which recursively counts
  654. the number of minterms for the dag rooted at each node in terms of
  655. the total number of variables (max). It assumes that the node
  656. pointer passed to it is regular and it maintains the invariant.
  657. @sideeffect None
  658. @see gatherInfo
  659. */
  660. static NodeData *
  661. gatherInfoAux(
  662. DdNode * node /**< function to analyze */,
  663. ApproxInfo * info /**< info on %BDD */,
  664. int parity /**< gather parity information */)
  665. {
  666. DdNode *N, *Nt, *Ne;
  667. NodeData *infoN, *infoT, *infoE;
  668. N = Cudd_Regular(node);
  669. /* Check whether entry for this node exists. */
  670. if ((infoN = (NodeData *) cuddHashTableGenericLookup(info->table, N)) != NULL) {
  671. if (parity) {
  672. /* Update parity and propagate. */
  673. updateParity(N, info, 1 + (int) Cudd_IsComplement(node));
  674. }
  675. return(infoN);
  676. }
  677. /* Compute the cofactors. */
  678. Nt = Cudd_NotCond(cuddT(N), N != node);
  679. Ne = Cudd_NotCond(cuddE(N), N != node);
  680. infoT = gatherInfoAux(Nt, info, parity);
  681. if (infoT == NULL) return(NULL);
  682. infoE = gatherInfoAux(Ne, info, parity);
  683. if (infoE == NULL) return(NULL);
  684. infoT->functionRef++;
  685. infoE->functionRef++;
  686. /* Point to the correct location in the page. */
  687. infoN = &(info->page[info->index++]);
  688. infoN->parity |= (short) (1 + Cudd_IsComplement(node));
  689. infoN->mintermsP = infoT->mintermsP/2;
  690. infoN->mintermsN = infoT->mintermsN/2;
  691. if (Cudd_IsComplement(Ne) ^ Cudd_IsComplement(node)) {
  692. infoN->mintermsP += infoE->mintermsN/2;
  693. infoN->mintermsN += infoE->mintermsP/2;
  694. } else {
  695. infoN->mintermsP += infoE->mintermsP/2;
  696. infoN->mintermsN += infoE->mintermsN/2;
  697. }
  698. /* Insert entry for the node in the table. */
  699. if (cuddHashTableGenericInsert(info->table, N, infoN) == 0) {
  700. return(NULL);
  701. }
  702. return(infoN);
  703. } /* end of gatherInfoAux */
  704. /**
  705. @brief Gathers information about each node.
  706. @details Counts minterms and computes reference counts of each
  707. node in the %BDD. The minterm count is separately computed for the
  708. node and its complement. This is to avoid cancellation
  709. errors.
  710. @return a pointer to the data structure holding the information
  711. gathered if successful; NULL otherwise.
  712. @sideeffect None
  713. @see cuddUnderApprox gatherInfoAux
  714. */
  715. static ApproxInfo *
  716. gatherInfo(
  717. DdManager * dd /* manager */,
  718. DdNode * node /* function to be analyzed */,
  719. int numVars /* number of variables node depends on */,
  720. int parity /* gather parity information */)
  721. {
  722. ApproxInfo * info;
  723. NodeData * infoTop;
  724. /* If user did not give numVars value, set it to the maximum
  725. ** exponent that the pow function can take. The -1 is due to the
  726. ** discrepancy in the value that pow takes and the value that
  727. ** log gives.
  728. */
  729. if (numVars == 0) {
  730. numVars = DBL_MAX_EXP - 1;
  731. }
  732. info = ALLOC(ApproxInfo,1);
  733. if (info == NULL) {
  734. dd->errorCode = CUDD_MEMORY_OUT;
  735. return(NULL);
  736. }
  737. info->max = pow(2.0,(double) numVars);
  738. info->one = DD_ONE(dd);
  739. info->zero = Cudd_Not(info->one);
  740. info->size = Cudd_DagSize(node);
  741. /* All the information gathered will be stored in a contiguous
  742. ** piece of memory, which is allocated here. This can be done
  743. ** efficiently because we have counted the number of nodes of the
  744. ** BDD. info->index points to the next available entry in the array
  745. ** that stores the per-node information. */
  746. info->page = ALLOC(NodeData,info->size);
  747. if (info->page == NULL) {
  748. dd->errorCode = CUDD_MEMORY_OUT;
  749. FREE(info);
  750. return(NULL);
  751. }
  752. memset(info->page, 0, info->size * sizeof(NodeData)); /* clear all page */
  753. info->table = cuddHashTableInit(dd,1,info->size);
  754. if (info->table == NULL) {
  755. FREE(info->page);
  756. FREE(info);
  757. return(NULL);
  758. }
  759. /* We visit the DAG in post-order DFS. Hence, the constant node is
  760. ** in first position, and the root of the DAG is in last position. */
  761. /* Info for the constant node: Initialize only fields different from 0. */
  762. if (cuddHashTableGenericInsert(info->table, info->one, info->page) == 0) {
  763. FREE(info->page);
  764. cuddHashTableGenericQuit(info->table);
  765. FREE(info);
  766. return(NULL);
  767. }
  768. info->page[0].mintermsP = info->max;
  769. info->index = 1;
  770. infoTop = gatherInfoAux(node,info,parity);
  771. if (infoTop == NULL) {
  772. FREE(info->page);
  773. cuddHashTableGenericQuit(info->table);
  774. FREE(info);
  775. return(NULL);
  776. }
  777. if (Cudd_IsComplement(node)) {
  778. info->minterms = infoTop->mintermsN;
  779. } else {
  780. info->minterms = infoTop->mintermsP;
  781. }
  782. infoTop->functionRef = 1;
  783. return(info);
  784. } /* end of gatherInfo */
  785. /**
  786. @brief Counts the nodes that would be eliminated if a given node
  787. were replaced by zero.
  788. @details This procedure uses a queue passed by the caller for
  789. efficiency: since the queue is left empty at the endof the search,
  790. it can be reused as is by the next search.
  791. @return the count (always striclty positive) if successful; 0
  792. otherwise.
  793. @sideeffect None
  794. @see UAmarkNodes RAmarkNodes BAmarkNodes
  795. */
  796. static int
  797. computeSavings(
  798. DdManager * dd,
  799. DdNode * f,
  800. DdNode * skip,
  801. ApproxInfo * info,
  802. DdLevelQueue * queue)
  803. {
  804. NodeData *infoN;
  805. LocalQueueItem *item;
  806. DdNode *node;
  807. int savings = 0;
  808. node = Cudd_Regular(f);
  809. if (node == NULL) return(0);
  810. skip = Cudd_Regular(skip);
  811. /* Insert the given node in the level queue. Its local reference
  812. ** count is set equal to the function reference count so that the
  813. ** search will continue from it when it is retrieved. */
  814. item = (LocalQueueItem *)
  815. cuddLevelQueueFirst(queue,node,cuddI(dd,node->index));
  816. if (item == NULL)
  817. return(0);
  818. infoN = (NodeData *) cuddHashTableGenericLookup(info->table, node);
  819. item->localRef = infoN->functionRef;
  820. /* Process the queue. */
  821. while ((item = (LocalQueueItem *) queue->first) != NULL) {
  822. node = item->node;
  823. if (node != skip) {
  824. infoN = (NodeData *) cuddHashTableGenericLookup(info->table,node);
  825. if (item->localRef == infoN->functionRef) {
  826. /* This node is not shared. */
  827. DdNode *nodeT, *nodeE;
  828. savings++;
  829. nodeT = cuddT(node);
  830. if (!cuddIsConstant(nodeT)) {
  831. item = (LocalQueueItem *)
  832. cuddLevelQueueEnqueue(queue,nodeT,cuddI(dd,nodeT->index));
  833. if (item == NULL) return(0);
  834. item->localRef++;
  835. }
  836. nodeE = Cudd_Regular(cuddE(node));
  837. if (!cuddIsConstant(nodeE)) {
  838. item = (LocalQueueItem *)
  839. cuddLevelQueueEnqueue(queue,nodeE,cuddI(dd,nodeE->index));
  840. if (item == NULL) return(0);
  841. item->localRef++;
  842. }
  843. }
  844. }
  845. cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
  846. }
  847. #ifdef DD_DEBUG
  848. /* At the end of a local search the queue should be empty. */
  849. assert(queue->size == 0);
  850. #endif
  851. return(savings);
  852. } /* end of computeSavings */
  853. /**
  854. @brief Update function reference counts to account for replacement.
  855. @return the number of nodes saved if successful; 0 otherwise.
  856. @sideeffect None
  857. @see UAmarkNodes RAmarkNodes BAmarkNodes
  858. */
  859. static int
  860. updateRefs(
  861. DdManager * dd,
  862. DdNode * f,
  863. DdNode * skip,
  864. ApproxInfo * info,
  865. DdLevelQueue * queue)
  866. {
  867. NodeData *infoN;
  868. LocalQueueItem *item;
  869. DdNode *node;
  870. int savings = 0;
  871. node = Cudd_Regular(f);
  872. /* Insert the given node in the level queue. Its function reference
  873. ** count is set equal to 0 so that the search will continue from it
  874. ** when it is retrieved. */
  875. item = (LocalQueueItem *) cuddLevelQueueFirst(queue,node,cuddI(dd,node->index));
  876. if (item == NULL)
  877. return(0);
  878. infoN = (NodeData *) cuddHashTableGenericLookup(info->table, node);
  879. infoN->functionRef = 0;
  880. if (skip != NULL) {
  881. /* Increase the function reference count of the node to be skipped
  882. ** by 1 to account for the node pointing to it that will be created. */
  883. skip = Cudd_Regular(skip);
  884. infoN = (NodeData *) cuddHashTableGenericLookup(info->table, skip);
  885. infoN->functionRef++;
  886. }
  887. /* Process the queue. */
  888. while ((item = (LocalQueueItem *) queue->first) != NULL) {
  889. node = item->node;
  890. infoN = (NodeData *) cuddHashTableGenericLookup(info->table,node);
  891. if (infoN->functionRef == 0) {
  892. /* This node is not shared or to be be skipped. */
  893. DdNode *nodeT, *nodeE;
  894. savings++;
  895. nodeT = cuddT(node);
  896. if (!cuddIsConstant(nodeT)) {
  897. item = (LocalQueueItem *)
  898. cuddLevelQueueEnqueue(queue,nodeT,cuddI(dd,nodeT->index));
  899. if (item == NULL) return(0);
  900. infoN = (NodeData *) cuddHashTableGenericLookup(info->table,nodeT);
  901. infoN->functionRef--;
  902. }
  903. nodeE = Cudd_Regular(cuddE(node));
  904. if (!cuddIsConstant(nodeE)) {
  905. item = (LocalQueueItem *)
  906. cuddLevelQueueEnqueue(queue,nodeE,cuddI(dd,nodeE->index));
  907. if (item == NULL) return(0);
  908. infoN = (NodeData *) cuddHashTableGenericLookup(info->table,nodeE);
  909. infoN->functionRef--;
  910. }
  911. }
  912. cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
  913. }
  914. #ifdef DD_DEBUG
  915. /* At the end of a local search the queue should be empty. */
  916. assert(queue->size == 0);
  917. #endif
  918. return(savings);
  919. } /* end of updateRefs */
  920. /**
  921. @brief Marks nodes for replacement by zero.
  922. @return 1 if successful; 0 otherwise.
  923. @sideeffect None
  924. @see cuddUnderApprox
  925. */
  926. static int
  927. UAmarkNodes(
  928. DdManager * dd /**< manager */,
  929. DdNode * f /**< function to be analyzed */,
  930. ApproxInfo * info /**< info on %BDD */,
  931. int threshold /**< when to stop approximating */,
  932. int safe /**< enforce safe approximation */,
  933. double quality /**< minimum improvement for accepted changes */)
  934. {
  935. DdLevelQueue *queue;
  936. DdLevelQueue *localQueue;
  937. NodeData *infoN;
  938. GlobalQueueItem *item;
  939. DdNode *node;
  940. double numOnset;
  941. double impactP, impactN;
  942. int savings;
  943. #if 0
  944. (void) printf("initial size = %d initial minterms = %g\n",
  945. info->size, info->minterms);
  946. #endif
  947. queue = cuddLevelQueueInit(dd->size,sizeof(GlobalQueueItem),info->size,dd);
  948. if (queue == NULL) {
  949. return(0);
  950. }
  951. localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
  952. dd->initSlots,dd);
  953. if (localQueue == NULL) {
  954. cuddLevelQueueQuit(queue);
  955. return(0);
  956. }
  957. node = Cudd_Regular(f);
  958. item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
  959. if (item == NULL) {
  960. cuddLevelQueueQuit(queue);
  961. cuddLevelQueueQuit(localQueue);
  962. return(0);
  963. }
  964. if (Cudd_IsComplement(f)) {
  965. item->impactP = 0.0;
  966. item->impactN = 1.0;
  967. } else {
  968. item->impactP = 1.0;
  969. item->impactN = 0.0;
  970. }
  971. while (queue->first != NULL) {
  972. /* If the size of the subset is below the threshold, quit. */
  973. if (info->size <= threshold)
  974. break;
  975. item = (GlobalQueueItem *) queue->first;
  976. node = item->node;
  977. node = Cudd_Regular(node);
  978. infoN = (NodeData *) cuddHashTableGenericLookup(info->table, node);
  979. if (safe && infoN->parity == 3) {
  980. cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
  981. continue;
  982. }
  983. impactP = item->impactP;
  984. impactN = item->impactN;
  985. numOnset = infoN->mintermsP * impactP + infoN->mintermsN * impactN;
  986. savings = computeSavings(dd,node,NULL,info,localQueue);
  987. if (savings == 0) {
  988. cuddLevelQueueQuit(queue);
  989. cuddLevelQueueQuit(localQueue);
  990. return(0);
  991. }
  992. cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
  993. #if 0
  994. (void) printf("node %p: impact = %g/%g numOnset = %g savings %d\n",
  995. node, impactP, impactN, numOnset, savings);
  996. #endif
  997. if ((1 - numOnset / info->minterms) >
  998. quality * (1 - (double) savings / info->size)) {
  999. infoN->replace = CUDD_TRUE;
  1000. info->size -= savings;
  1001. info->minterms -=numOnset;
  1002. #if 0
  1003. (void) printf("replace: new size = %d new minterms = %g\n",
  1004. info->size, info->minterms);
  1005. #endif
  1006. savings -= updateRefs(dd,node,NULL,info,localQueue);
  1007. assert(savings == 0);
  1008. continue;
  1009. }
  1010. if (!cuddIsConstant(cuddT(node))) {
  1011. item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
  1012. cuddI(dd,cuddT(node)->index));
  1013. item->impactP += impactP/2.0;
  1014. item->impactN += impactN/2.0;
  1015. }
  1016. if (!Cudd_IsConstantInt(cuddE(node))) {
  1017. item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
  1018. cuddI(dd,Cudd_Regular(cuddE(node))->index));
  1019. if (Cudd_IsComplement(cuddE(node))) {
  1020. item->impactP += impactN/2.0;
  1021. item->impactN += impactP/2.0;
  1022. } else {
  1023. item->impactP += impactP/2.0;
  1024. item->impactN += impactN/2.0;
  1025. }
  1026. }
  1027. }
  1028. cuddLevelQueueQuit(queue);
  1029. cuddLevelQueueQuit(localQueue);
  1030. return(1);
  1031. } /* end of UAmarkNodes */
  1032. /**
  1033. @brief Builds the subset %BDD.
  1034. @details Based on the info table, replaces selected nodes by zero.
  1035. @return a pointer to the result if successful; NULL otherwise.
  1036. @sideeffect None
  1037. @see cuddUnderApprox
  1038. */
  1039. static DdNode *
  1040. UAbuildSubset(
  1041. DdManager * dd /**< %DD manager */,
  1042. DdNode * node /**< current node */,
  1043. ApproxInfo * info /**< node info */)
  1044. {
  1045. DdNode *Nt, *Ne, *N, *t, *e, *r;
  1046. NodeData *infoN;
  1047. if (Cudd_IsConstantInt(node))
  1048. return(node);
  1049. N = Cudd_Regular(node);
  1050. if ((infoN = (NodeData *) cuddHashTableGenericLookup(info->table, N)) != NULL) {
  1051. if (infoN->replace == CUDD_TRUE) {
  1052. return(info->zero);
  1053. }
  1054. if (N == node ) {
  1055. if (infoN->resultP != NULL) {
  1056. return(infoN->resultP);
  1057. }
  1058. } else {
  1059. if (infoN->resultN != NULL) {
  1060. return(infoN->resultN);
  1061. }
  1062. }
  1063. } else {
  1064. (void) fprintf(dd->err,
  1065. "Something is wrong, ought to be in info table\n");
  1066. dd->errorCode = CUDD_INTERNAL_ERROR;
  1067. return(NULL);
  1068. }
  1069. Nt = Cudd_NotCond(cuddT(N), Cudd_IsComplement(node));
  1070. Ne = Cudd_NotCond(cuddE(N), Cudd_IsComplement(node));
  1071. t = UAbuildSubset(dd, Nt, info);
  1072. if (t == NULL) {
  1073. return(NULL);
  1074. }
  1075. cuddRef(t);
  1076. e = UAbuildSubset(dd, Ne, info);
  1077. if (e == NULL) {
  1078. Cudd_RecursiveDeref(dd,t);
  1079. return(NULL);
  1080. }
  1081. cuddRef(e);
  1082. if (Cudd_IsComplement(t)) {
  1083. t = Cudd_Not(t);
  1084. e = Cudd_Not(e);
  1085. r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
  1086. if (r == NULL) {
  1087. Cudd_RecursiveDeref(dd, e);
  1088. Cudd_RecursiveDeref(dd, t);
  1089. return(NULL);
  1090. }
  1091. r = Cudd_Not(r);
  1092. } else {
  1093. r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
  1094. if (r == NULL) {
  1095. Cudd_RecursiveDeref(dd, e);
  1096. Cudd_RecursiveDeref(dd, t);
  1097. return(NULL);
  1098. }
  1099. }
  1100. cuddDeref(t);
  1101. cuddDeref(e);
  1102. if (N == node) {
  1103. infoN->resultP = r;
  1104. } else {
  1105. infoN->resultN = r;
  1106. }
  1107. return(r);
  1108. } /* end of UAbuildSubset */
  1109. /**
  1110. @brief Marks nodes for remapping.
  1111. @return 1 if successful; 0 otherwise.
  1112. @sideeffect None
  1113. @see cuddRemapUnderApprox
  1114. */
  1115. static int
  1116. RAmarkNodes(
  1117. DdManager * dd /**< manager */,
  1118. DdNode * f /**< function to be analyzed */,
  1119. ApproxInfo * info /**< info on %BDD */,
  1120. int threshold /**< when to stop approximating */,
  1121. double quality /**< minimum improvement for accepted changes */)
  1122. {
  1123. DdLevelQueue *queue;
  1124. DdLevelQueue *localQueue;
  1125. NodeData *infoN, *infoT, *infoE;
  1126. GlobalQueueItem *item;
  1127. DdNode *node, *T, *E;
  1128. DdNode *shared; /* grandchild shared by the two children of node */
  1129. double numOnset;
  1130. double impact, impactP, impactN;
  1131. double minterms;
  1132. int savings;
  1133. int replace;
  1134. #if 0
  1135. (void) fprintf(dd->out,"initial size = %d initial minterms = %g\n",
  1136. info->size, info->minterms);
  1137. #endif
  1138. queue = cuddLevelQueueInit(dd->size,sizeof(GlobalQueueItem),info->size,dd);
  1139. if (queue == NULL) {
  1140. return(0);
  1141. }
  1142. localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
  1143. dd->initSlots,dd);
  1144. if (localQueue == NULL) {
  1145. cuddLevelQueueQuit(queue);
  1146. return(0);
  1147. }
  1148. /* Enqueue regular pointer to root and initialize impact. */
  1149. node = Cudd_Regular(f);
  1150. item = (GlobalQueueItem *)
  1151. cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
  1152. if (item == NULL) {
  1153. cuddLevelQueueQuit(queue);
  1154. cuddLevelQueueQuit(localQueue);
  1155. return(0);
  1156. }
  1157. if (Cudd_IsComplement(f)) {
  1158. item->impactP = 0.0;
  1159. item->impactN = 1.0;
  1160. } else {
  1161. item->impactP = 1.0;
  1162. item->impactN = 0.0;
  1163. }
  1164. /* The nodes retrieved here are guaranteed to be non-terminal.
  1165. ** The initial node is not terminal because constant nodes are
  1166. ** dealt with in the calling procedure. Subsequent nodes are inserted
  1167. ** only if they are not terminal. */
  1168. while ((item = (GlobalQueueItem *) queue->first) != NULL) {
  1169. /* If the size of the subset is below the threshold, quit. */
  1170. if (info->size <= threshold)
  1171. break;
  1172. node = item->node;
  1173. #ifdef DD_DEBUG
  1174. assert(item->impactP >= 0 && item->impactP <= 1.0);
  1175. assert(item->impactN >= 0 && item->impactN <= 1.0);
  1176. assert(!Cudd_IsComplement(node));
  1177. assert(!Cudd_IsConstantInt(node));
  1178. #endif
  1179. if ((infoN = (NodeData *) cuddHashTableGenericLookup(info->table, node)) == NULL) {
  1180. cuddLevelQueueQuit(queue);
  1181. cuddLevelQueueQuit(localQueue);
  1182. return(0);
  1183. }
  1184. #ifdef DD_DEBUG
  1185. assert(infoN->parity >= 1 && infoN->parity <= 3);
  1186. #endif
  1187. if (infoN->parity == 3) {
  1188. /* This node can be reached through paths of different parity.
  1189. ** It is not safe to replace it, because remapping will give
  1190. ** an incorrect result, while replacement by 0 may cause node
  1191. ** splitting. */
  1192. cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
  1193. continue;
  1194. }
  1195. T = cuddT(node);
  1196. E = cuddE(node);
  1197. shared = NULL;
  1198. impactP = item->impactP;
  1199. impactN = item->impactN;
  1200. if (Cudd_bddLeq(dd,T,E)) {
  1201. /* Here we know that E is regular. */
  1202. #ifdef DD_DEBUG
  1203. assert(!Cudd_IsComplement(E));
  1204. #endif
  1205. infoT = (NodeData *) cuddHashTableGenericLookup(info->table, T);
  1206. infoE = (NodeData *) cuddHashTableGenericLookup(info->table, E);
  1207. if (infoN->parity == 1) {
  1208. impact = impactP;
  1209. minterms = infoE->mintermsP/2.0 - infoT->mintermsP/2.0;
  1210. if (infoE->functionRef == 1 && !cuddIsConstant(E)) {
  1211. savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
  1212. if (savings == 1) {
  1213. cuddLevelQueueQuit(queue);
  1214. cuddLevelQueueQuit(localQueue);
  1215. return(0);
  1216. }
  1217. } else {
  1218. savings = 1;
  1219. }
  1220. replace = REPLACE_E;
  1221. } else {
  1222. #ifdef DD_DEBUG
  1223. assert(infoN->parity == 2);
  1224. #endif
  1225. impact = impactN;
  1226. minterms = infoT->mintermsN/2.0 - infoE->mintermsN/2.0;
  1227. if (infoT->functionRef == 1 && !cuddIsConstant(T)) {
  1228. savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
  1229. if (savings == 1) {
  1230. cuddLevelQueueQuit(queue);
  1231. cuddLevelQueueQuit(localQueue);
  1232. return(0);
  1233. }
  1234. } else {
  1235. savings = 1;
  1236. }
  1237. replace = REPLACE_T;
  1238. }
  1239. numOnset = impact * minterms;
  1240. } else if (Cudd_bddLeq(dd,E,T)) {
  1241. /* Here E may be complemented. */
  1242. DdNode *Ereg = Cudd_Regular(E);
  1243. infoT = (NodeData *) cuddHashTableGenericLookup(info->table, T);
  1244. infoE = (NodeData *) cuddHashTableGenericLookup(info->table, Ereg);
  1245. if (infoN->parity == 1) {
  1246. impact = impactP;
  1247. minterms = infoT->mintermsP/2.0 -
  1248. ((E == Ereg) ? infoE->mintermsP : infoE->mintermsN)/2.0;
  1249. if (infoT->functionRef == 1 && !cuddIsConstant(T)) {
  1250. savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
  1251. if (savings == 1) {
  1252. cuddLevelQueueQuit(queue);
  1253. cuddLevelQueueQuit(localQueue);
  1254. return(0);
  1255. }
  1256. } else {
  1257. savings = 1;
  1258. }
  1259. replace = REPLACE_T;
  1260. } else {
  1261. #ifdef DD_DEBUG
  1262. assert(infoN->parity == 2);
  1263. #endif
  1264. impact = impactN;
  1265. minterms = ((E == Ereg) ? infoE->mintermsN :
  1266. infoE->mintermsP)/2.0 - infoT->mintermsN/2.0;
  1267. if (infoE->functionRef == 1 && !cuddIsConstant(Ereg)) {
  1268. savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
  1269. if (savings == 1) {
  1270. cuddLevelQueueQuit(queue);
  1271. cuddLevelQueueQuit(localQueue);
  1272. return(0);
  1273. }
  1274. } else {
  1275. savings = 1;
  1276. }
  1277. replace = REPLACE_E;
  1278. }
  1279. numOnset = impact * minterms;
  1280. } else {
  1281. DdNode *Ereg = Cudd_Regular(E);
  1282. DdNode *TT = cuddT(T);
  1283. DdNode *ET = Cudd_NotCond(cuddT(Ereg), Cudd_IsComplement(E));
  1284. if (T->index == Ereg->index && TT == ET) {
  1285. shared = TT;
  1286. replace = REPLACE_TT;
  1287. } else {
  1288. DdNode *TE = cuddE(T);
  1289. DdNode *EE = Cudd_NotCond(cuddE(Ereg), Cudd_IsComplement(E));
  1290. if (T->index == Ereg->index && TE == EE) {
  1291. shared = TE;
  1292. replace = REPLACE_TE;
  1293. } else {
  1294. replace = REPLACE_N;
  1295. }
  1296. }
  1297. numOnset = infoN->mintermsP * impactP + infoN->mintermsN * impactN;
  1298. savings = computeSavings(dd,node,shared,info,localQueue);
  1299. if (shared != NULL) {
  1300. NodeData *infoS;
  1301. infoS = (NodeData *) cuddHashTableGenericLookup(info->table, Cudd_Regular(shared));
  1302. if (Cudd_IsComplement(shared)) {
  1303. numOnset -= (infoS->mintermsN * impactP +
  1304. infoS->mintermsP * impactN)/2.0;
  1305. } else {
  1306. numOnset -= (infoS->mintermsP * impactP +
  1307. infoS->mintermsN * impactN)/2.0;
  1308. }
  1309. savings--;
  1310. }
  1311. }
  1312. cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
  1313. #if 0
  1314. if (replace == REPLACE_T || replace == REPLACE_E)
  1315. (void) printf("node %p: impact = %g numOnset = %g savings %d\n",
  1316. node, impact, numOnset, savings);
  1317. else
  1318. (void) printf("node %p: impact = %g/%g numOnset = %g savings %d\n",
  1319. node, impactP, impactN, numOnset, savings);
  1320. #endif
  1321. if ((1 - numOnset / info->minterms) >
  1322. quality * (1 - (double) savings / info->size)) {
  1323. infoN->replace = (char) replace;
  1324. info->size -= savings;
  1325. info->minterms -=numOnset;
  1326. #if 0
  1327. (void) printf("remap(%d): new size = %d new minterms = %g\n",
  1328. replace, info->size, info->minterms);
  1329. #endif
  1330. if (replace == REPLACE_N) {
  1331. savings -= updateRefs(dd,node,NULL,info,localQueue);
  1332. } else if (replace == REPLACE_T) {
  1333. savings -= updateRefs(dd,node,E,info,localQueue);
  1334. } else if (replace == REPLACE_E) {
  1335. savings -= updateRefs(dd,node,T,info,localQueue);
  1336. } else {
  1337. #ifdef DD_DEBUG
  1338. assert(replace == REPLACE_TT || replace == REPLACE_TE);
  1339. #endif
  1340. savings -= updateRefs(dd,node,shared,info,localQueue) - 1;
  1341. }
  1342. assert(savings == 0);
  1343. } else {
  1344. replace = NOTHING;
  1345. }
  1346. if (replace == REPLACE_N) continue;
  1347. if ((replace == REPLACE_E || replace == NOTHING) &&
  1348. !cuddIsConstant(cuddT(node))) {
  1349. item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
  1350. cuddI(dd,cuddT(node)->index));
  1351. if (replace == REPLACE_E) {
  1352. item->impactP += impactP;
  1353. item->impactN += impactN;
  1354. } else {
  1355. item->impactP += impactP/2.0;
  1356. item->impactN += impactN/2.0;
  1357. }
  1358. }
  1359. if ((replace == REPLACE_T || replace == NOTHING) &&
  1360. !Cudd_IsConstantInt(cuddE(node))) {
  1361. item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
  1362. cuddI(dd,Cudd_Regular(cuddE(node))->index));
  1363. if (Cudd_IsComplement(cuddE(node))) {
  1364. if (replace == REPLACE_T) {
  1365. item->impactP += impactN;
  1366. item->impactN += impactP;
  1367. } else {
  1368. item->impactP += impactN/2.0;
  1369. item->impactN += impactP/2.0;
  1370. }
  1371. } else {
  1372. if (replace == REPLACE_T) {
  1373. item->impactP += impactP;
  1374. item->impactN += impactN;
  1375. } else {
  1376. item->impactP += impactP/2.0;
  1377. item->impactN += impactN/2.0;
  1378. }
  1379. }
  1380. }
  1381. if ((replace == REPLACE_TT || replace == REPLACE_TE) &&
  1382. !Cudd_IsConstantInt(shared)) {
  1383. item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(shared),
  1384. cuddI(dd,Cudd_Regular(shared)->index));
  1385. if (Cudd_IsComplement(shared)) {
  1386. item->impactP += impactN;
  1387. item->impactN += impactP;
  1388. } else {
  1389. item->impactP += impactP;
  1390. item->impactN += impactN;
  1391. }
  1392. }
  1393. }
  1394. cuddLevelQueueQuit(queue);
  1395. cuddLevelQueueQuit(localQueue);
  1396. return(1);
  1397. } /* end of RAmarkNodes */
  1398. /**
  1399. @brief Marks nodes for remapping.
  1400. @return 1 if successful; 0 otherwise.
  1401. @sideeffect None
  1402. @see cuddBiasedUnderApprox
  1403. */
  1404. static int
  1405. BAmarkNodes(
  1406. DdManager *dd /**< manager */,
  1407. DdNode *f /**< function to be analyzed */,
  1408. ApproxInfo *info /**< info on %BDD */,
  1409. int threshold /**< when to stop approximating */,
  1410. double quality1 /**< minimum improvement for accepted changes when b=1 */,
  1411. double quality0 /**< minimum improvement for accepted changes when b=0 */)
  1412. {
  1413. DdLevelQueue *queue;
  1414. DdLevelQueue *localQueue;
  1415. NodeData *infoN, *infoT, *infoE;
  1416. GlobalQueueItem *item;
  1417. DdNode *node, *T, *E;
  1418. DdNode *shared; /* grandchild shared by the two children of node */
  1419. double numOnset;
  1420. double impact, impactP, impactN;
  1421. double minterms;
  1422. double quality;
  1423. int savings;
  1424. int replace;
  1425. #if 0
  1426. (void) fprintf(dd->out,"initial size = %d initial minterms = %g\n",
  1427. info->size, info->minterms);
  1428. #endif
  1429. queue = cuddLevelQueueInit(dd->size,sizeof(GlobalQueueItem),info->size,dd);
  1430. if (queue == NULL) {
  1431. return(0);
  1432. }
  1433. localQueue = cuddLevelQueueInit(dd->size,sizeof(LocalQueueItem),
  1434. dd->initSlots,dd);
  1435. if (localQueue == NULL) {
  1436. cuddLevelQueueQuit(queue);
  1437. return(0);
  1438. }
  1439. /* Enqueue regular pointer to root and initialize impact. */
  1440. node = Cudd_Regular(f);
  1441. item = (GlobalQueueItem *)
  1442. cuddLevelQueueEnqueue(queue,node,cuddI(dd,node->index));
  1443. if (item == NULL) {
  1444. cuddLevelQueueQuit(queue);
  1445. cuddLevelQueueQuit(localQueue);
  1446. return(0);
  1447. }
  1448. if (Cudd_IsComplement(f)) {
  1449. item->impactP = 0.0;
  1450. item->impactN = 1.0;
  1451. } else {
  1452. item->impactP = 1.0;
  1453. item->impactN = 0.0;
  1454. }
  1455. /* The nodes retrieved here are guaranteed to be non-terminal.
  1456. ** The initial node is not terminal because constant nodes are
  1457. ** dealt with in the calling procedure. Subsequent nodes are inserted
  1458. ** only if they are not terminal. */
  1459. while (queue->first != NULL) {
  1460. /* If the size of the subset is below the threshold, quit. */
  1461. if (info->size <= threshold)
  1462. break;
  1463. item = (GlobalQueueItem *) queue->first;
  1464. node = item->node;
  1465. #ifdef DD_DEBUG
  1466. assert(item->impactP >= 0 && item->impactP <= 1.0);
  1467. assert(item->impactN >= 0 && item->impactN <= 1.0);
  1468. assert(!Cudd_IsComplement(node));
  1469. assert(!Cudd_IsConstantInt(node));
  1470. #endif
  1471. if ((infoN = (NodeData *) cuddHashTableGenericLookup(info->table, node)) == NULL) {
  1472. cuddLevelQueueQuit(queue);
  1473. cuddLevelQueueQuit(localQueue);
  1474. return(0);
  1475. }
  1476. quality = infoN->care ? quality1 : quality0;
  1477. #ifdef DD_DEBUG
  1478. assert(infoN->parity >= 1 && infoN->parity <= 3);
  1479. #endif
  1480. if (infoN->parity == 3) {
  1481. /* This node can be reached through paths of different parity.
  1482. ** It is not safe to replace it, because remapping will give
  1483. ** an incorrect result, while replacement by 0 may cause node
  1484. ** splitting. */
  1485. cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
  1486. continue;
  1487. }
  1488. T = cuddT(node);
  1489. E = cuddE(node);
  1490. shared = NULL;
  1491. impactP = item->impactP;
  1492. impactN = item->impactN;
  1493. if (Cudd_bddLeq(dd,T,E)) {
  1494. /* Here we know that E is regular. */
  1495. #ifdef DD_DEBUG
  1496. assert(!Cudd_IsComplement(E));
  1497. #endif
  1498. infoT = (NodeData *) cuddHashTableGenericLookup(info->table, T);
  1499. infoE = (NodeData *) cuddHashTableGenericLookup(info->table, E);
  1500. if (infoN->parity == 1) {
  1501. impact = impactP;
  1502. minterms = infoE->mintermsP/2.0 - infoT->mintermsP/2.0;
  1503. if (infoE->functionRef == 1 && !Cudd_IsConstantInt(E)) {
  1504. savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
  1505. if (savings == 1) {
  1506. cuddLevelQueueQuit(queue);
  1507. cuddLevelQueueQuit(localQueue);
  1508. return(0);
  1509. }
  1510. } else {
  1511. savings = 1;
  1512. }
  1513. replace = REPLACE_E;
  1514. } else {
  1515. #ifdef DD_DEBUG
  1516. assert(infoN->parity == 2);
  1517. #endif
  1518. impact = impactN;
  1519. minterms = infoT->mintermsN/2.0 - infoE->mintermsN/2.0;
  1520. if (infoT->functionRef == 1 && !Cudd_IsConstantInt(T)) {
  1521. savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
  1522. if (savings == 1) {
  1523. cuddLevelQueueQuit(queue);
  1524. cuddLevelQueueQuit(localQueue);
  1525. return(0);
  1526. }
  1527. } else {
  1528. savings = 1;
  1529. }
  1530. replace = REPLACE_T;
  1531. }
  1532. numOnset = impact * minterms;
  1533. } else if (Cudd_bddLeq(dd,E,T)) {
  1534. /* Here E may be complemented. */
  1535. DdNode *Ereg = Cudd_Regular(E);
  1536. infoT = (NodeData *) cuddHashTableGenericLookup(info->table, T);
  1537. infoE = (NodeData *) cuddHashTableGenericLookup(info->table, Ereg);
  1538. if (infoN->parity == 1) {
  1539. impact = impactP;
  1540. minterms = infoT->mintermsP/2.0 -
  1541. ((E == Ereg) ? infoE->mintermsP : infoE->mintermsN)/2.0;
  1542. if (infoT->functionRef == 1 && !Cudd_IsConstantInt(T)) {
  1543. savings = 1 + computeSavings(dd,T,NULL,info,localQueue);
  1544. if (savings == 1) {
  1545. cuddLevelQueueQuit(queue);
  1546. cuddLevelQueueQuit(localQueue);
  1547. return(0);
  1548. }
  1549. } else {
  1550. savings = 1;
  1551. }
  1552. replace = REPLACE_T;
  1553. } else {
  1554. #ifdef DD_DEBUG
  1555. assert(infoN->parity == 2);
  1556. #endif
  1557. impact = impactN;
  1558. minterms = ((E == Ereg) ? infoE->mintermsN :
  1559. infoE->mintermsP)/2.0 - infoT->mintermsN/2.0;
  1560. if (infoE->functionRef == 1 && !Cudd_IsConstantInt(E)) {
  1561. savings = 1 + computeSavings(dd,E,NULL,info,localQueue);
  1562. if (savings == 1) {
  1563. cuddLevelQueueQuit(queue);
  1564. cuddLevelQueueQuit(localQueue);
  1565. return(0);
  1566. }
  1567. } else {
  1568. savings = 1;
  1569. }
  1570. replace = REPLACE_E;
  1571. }
  1572. numOnset = impact * minterms;
  1573. } else {
  1574. DdNode *Ereg = Cudd_Regular(E);
  1575. DdNode *TT = cuddT(T);
  1576. DdNode *ET = Cudd_NotCond(cuddT(Ereg), Cudd_IsComplement(E));
  1577. if (T->index == Ereg->index && TT == ET) {
  1578. shared = TT;
  1579. replace = REPLACE_TT;
  1580. } else {
  1581. DdNode *TE = cuddE(T);
  1582. DdNode *EE = Cudd_NotCond(cuddE(Ereg), Cudd_IsComplement(E));
  1583. if (T->index == Ereg->index && TE == EE) {
  1584. shared = TE;
  1585. replace = REPLACE_TE;
  1586. } else {
  1587. replace = REPLACE_N;
  1588. }
  1589. }
  1590. numOnset = infoN->mintermsP * impactP + infoN->mintermsN * impactN;
  1591. savings = computeSavings(dd,node,shared,info,localQueue);
  1592. if (shared != NULL) {
  1593. NodeData *infoS;
  1594. infoS = (NodeData *) cuddHashTableGenericLookup(info->table, Cudd_Regular(shared));
  1595. if (Cudd_IsComplement(shared)) {
  1596. numOnset -= (infoS->mintermsN * impactP +
  1597. infoS->mintermsP * impactN)/2.0;
  1598. } else {
  1599. numOnset -= (infoS->mintermsP * impactP +
  1600. infoS->mintermsN * impactN)/2.0;
  1601. }
  1602. savings--;
  1603. }
  1604. }
  1605. cuddLevelQueueDequeue(queue,cuddI(dd,node->index));
  1606. #if 0
  1607. if (replace == REPLACE_T || replace == REPLACE_E)
  1608. (void) printf("node %p: impact = %g numOnset = %g savings %d\n",
  1609. node, impact, numOnset, savings);
  1610. else
  1611. (void) printf("node %p: impact = %g/%g numOnset = %g savings %d\n",
  1612. node, impactP, impactN, numOnset, savings);
  1613. #endif
  1614. if ((1 - numOnset / info->minterms) >
  1615. quality * (1 - (double) savings / info->size)) {
  1616. infoN->replace = (char) replace;
  1617. info->size -= savings;
  1618. info->minterms -=numOnset;
  1619. #if 0
  1620. (void) printf("remap(%d): new size = %d new minterms = %g\n",
  1621. replace, info->size, info->minterms);
  1622. #endif
  1623. if (replace == REPLACE_N) {
  1624. savings -= updateRefs(dd,node,NULL,info,localQueue);
  1625. } else if (replace == REPLACE_T) {
  1626. savings -= updateRefs(dd,node,E,info,localQueue);
  1627. } else if (replace == REPLACE_E) {
  1628. savings -= updateRefs(dd,node,T,info,localQueue);
  1629. } else {
  1630. #ifdef DD_DEBUG
  1631. assert(replace == REPLACE_TT || replace == REPLACE_TE);
  1632. #endif
  1633. savings -= updateRefs(dd,node,shared,info,localQueue) - 1;
  1634. }
  1635. assert(savings == 0);
  1636. } else {
  1637. replace = NOTHING;
  1638. }
  1639. if (replace == REPLACE_N) continue;
  1640. if ((replace == REPLACE_E || replace == NOTHING) &&
  1641. !cuddIsConstant(cuddT(node))) {
  1642. item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,cuddT(node),
  1643. cuddI(dd,cuddT(node)->index));
  1644. if (replace == REPLACE_E) {
  1645. item->impactP += impactP;
  1646. item->impactN += impactN;
  1647. } else {
  1648. item->impactP += impactP/2.0;
  1649. item->impactN += impactN/2.0;
  1650. }
  1651. }
  1652. if ((replace == REPLACE_T || replace == NOTHING) &&
  1653. !Cudd_IsConstantInt(cuddE(node))) {
  1654. item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(cuddE(node)),
  1655. cuddI(dd,Cudd_Regular(cuddE(node))->index));
  1656. if (Cudd_IsComplement(cuddE(node))) {
  1657. if (replace == REPLACE_T) {
  1658. item->impactP += impactN;
  1659. item->impactN += impactP;
  1660. } else {
  1661. item->impactP += impactN/2.0;
  1662. item->impactN += impactP/2.0;
  1663. }
  1664. } else {
  1665. if (replace == REPLACE_T) {
  1666. item->impactP += impactP;
  1667. item->impactN += impactN;
  1668. } else {
  1669. item->impactP += impactP/2.0;
  1670. item->impactN += impactN/2.0;
  1671. }
  1672. }
  1673. }
  1674. if ((replace == REPLACE_TT || replace == REPLACE_TE) &&
  1675. !Cudd_IsConstantInt(shared)) {
  1676. item = (GlobalQueueItem *) cuddLevelQueueEnqueue(queue,Cudd_Regular(shared),
  1677. cuddI(dd,Cudd_Regular(shared)->index));
  1678. if (Cudd_IsComplement(shared)) {
  1679. if (replace == REPLACE_T) {
  1680. item->impactP += impactN;
  1681. item->impactN += impactP;
  1682. } else {
  1683. item->impactP += impactN/2.0;
  1684. item->impactN += impactP/2.0;
  1685. }
  1686. } else {
  1687. if (replace == REPLACE_T) {
  1688. item->impactP += impactP;
  1689. item->impactN += impactN;
  1690. } else {
  1691. item->impactP += impactP/2.0;
  1692. item->impactN += impactN/2.0;
  1693. }
  1694. }
  1695. }
  1696. }
  1697. cuddLevelQueueQuit(queue);
  1698. cuddLevelQueueQuit(localQueue);
  1699. return(1);
  1700. } /* end of BAmarkNodes */
  1701. /**
  1702. @brief Builds the subset %BDD for cuddRemapUnderApprox.
  1703. @details Based on the info table, performs remapping or replacement
  1704. at selected nodes.
  1705. @return a pointer to the result if successful; NULL otherwise.
  1706. @sideeffect None
  1707. @see cuddRemapUnderApprox
  1708. */
  1709. static DdNode *
  1710. RAbuildSubset(
  1711. DdManager * dd /**< %DD manager */,
  1712. DdNode * node /**< current node */,
  1713. ApproxInfo * info /**< node info */)
  1714. {
  1715. DdNode *Nt, *Ne, *N, *t, *e, *r;
  1716. NodeData *infoN;
  1717. if (Cudd_IsConstantInt(node))
  1718. return(node);
  1719. N = Cudd_Regular(node);
  1720. Nt = Cudd_NotCond(cuddT(N), Cudd_IsComplement(node));
  1721. Ne = Cudd_NotCond(cuddE(N), Cudd_IsComplement(node));
  1722. if ((infoN = (NodeData *) cuddHashTableGenericLookup(info->table, N)) != NULL) {
  1723. if (N == node ) {
  1724. if (infoN->resultP != NULL) {
  1725. return(infoN->resultP);
  1726. }
  1727. } else {
  1728. if (infoN->resultN != NULL) {
  1729. return(infoN->resultN);
  1730. }
  1731. }
  1732. if (infoN->replace == REPLACE_T) {
  1733. r = RAbuildSubset(dd, Ne, info);
  1734. return(r);
  1735. } else if (infoN->replace == REPLACE_E) {
  1736. r = RAbuildSubset(dd, Nt, info);
  1737. return(r);
  1738. } else if (infoN->replace == REPLACE_N) {
  1739. return(info->zero);
  1740. } else if (infoN->replace == REPLACE_TT) {
  1741. DdNode *Ntt = Cudd_NotCond(cuddT(cuddT(N)),
  1742. Cudd_IsComplement(node));
  1743. int index = cuddT(N)->index;
  1744. e = info->zero;
  1745. t = RAbuildSubset(dd, Ntt, info);
  1746. if (t == NULL) {
  1747. return(NULL);
  1748. }
  1749. cuddRef(t);
  1750. if (Cudd_IsComplement(t)) {
  1751. t = Cudd_Not(t);
  1752. e = Cudd_Not(e);
  1753. r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
  1754. if (r == NULL) {
  1755. Cudd_RecursiveDeref(dd, t);
  1756. return(NULL);
  1757. }
  1758. r = Cudd_Not(r);
  1759. } else {
  1760. r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
  1761. if (r == NULL) {
  1762. Cudd_RecursiveDeref(dd, t);
  1763. return(NULL);
  1764. }
  1765. }
  1766. cuddDeref(t);
  1767. return(r);
  1768. } else if (infoN->replace == REPLACE_TE) {
  1769. DdNode *Nte = Cudd_NotCond(cuddE(cuddT(N)),
  1770. Cudd_IsComplement(node));
  1771. unsigned int index = cuddT(N)->index;
  1772. t = info->one;
  1773. e = RAbuildSubset(dd, Nte, info);
  1774. if (e == NULL) {
  1775. return(NULL);
  1776. }
  1777. cuddRef(e);
  1778. e = Cudd_Not(e);
  1779. r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
  1780. if (r == NULL) {
  1781. Cudd_RecursiveDeref(dd, e);
  1782. return(NULL);
  1783. }
  1784. r =Cudd_Not(r);
  1785. cuddDeref(e);
  1786. return(r);
  1787. }
  1788. } else {
  1789. (void) fprintf(dd->err,
  1790. "Something is wrong, ought to be in info table\n");
  1791. dd->errorCode = CUDD_INTERNAL_ERROR;
  1792. return(NULL);
  1793. }
  1794. t = RAbuildSubset(dd, Nt, info);
  1795. if (t == NULL) {
  1796. return(NULL);
  1797. }
  1798. cuddRef(t);
  1799. e = RAbuildSubset(dd, Ne, info);
  1800. if (e == NULL) {
  1801. Cudd_RecursiveDeref(dd,t);
  1802. return(NULL);
  1803. }
  1804. cuddRef(e);
  1805. if (Cudd_IsComplement(t)) {
  1806. t = Cudd_Not(t);
  1807. e = Cudd_Not(e);
  1808. r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
  1809. if (r == NULL) {
  1810. Cudd_RecursiveDeref(dd, e);
  1811. Cudd_RecursiveDeref(dd, t);
  1812. return(NULL);
  1813. }
  1814. r = Cudd_Not(r);
  1815. } else {
  1816. r = (t == e) ? t : cuddUniqueInter(dd, N->index, t, e);
  1817. if (r == NULL) {
  1818. Cudd_RecursiveDeref(dd, e);
  1819. Cudd_RecursiveDeref(dd, t);
  1820. return(NULL);
  1821. }
  1822. }
  1823. cuddDeref(t);
  1824. cuddDeref(e);
  1825. if (N == node) {
  1826. infoN->resultP = r;
  1827. } else {
  1828. infoN->resultN = r;
  1829. }
  1830. return(r);
  1831. } /* end of RAbuildSubset */
  1832. /**
  1833. @brief Finds don't care nodes by traversing f and b in parallel.
  1834. @return the care status of the visited f node if successful;
  1835. CARE_ERROR otherwise.
  1836. @sideeffect None
  1837. @see cuddBiasedUnderApprox
  1838. */
  1839. static int
  1840. BAapplyBias(
  1841. DdManager *dd,
  1842. DdNode *f,
  1843. DdNode *b,
  1844. ApproxInfo *info,
  1845. DdHashTable *cache)
  1846. {
  1847. DdNode *one, *zero, *res;
  1848. DdNode *Ft, *Fe, *B, *Bt, *Be;
  1849. int topf, topb;
  1850. NodeData *infoF;
  1851. int careT, careE;
  1852. one = DD_ONE(dd);
  1853. zero = Cudd_Not(one);
  1854. if ((infoF = (NodeData *) cuddHashTableGenericLookup(info->table, f)) == NULL)
  1855. return(CARE_ERROR);
  1856. if (f == one) return(TOTAL_CARE);
  1857. if (b == zero) return(infoF->care);
  1858. if (infoF->care == TOTAL_CARE) return(TOTAL_CARE);
  1859. if ((f->ref != 1 || Cudd_Regular(b)->ref != 1) &&
  1860. (res = cuddHashTableLookup2(cache,f,b)) != NULL) {
  1861. if (res->ref == 0) {
  1862. cache->manager->dead++;
  1863. cache->manager->constants.dead++;
  1864. }
  1865. return(infoF->care);
  1866. }
  1867. topf = dd->perm[f->index];
  1868. B = Cudd_Regular(b);
  1869. topb = cuddI(dd,B->index);
  1870. if (topf <= topb) {
  1871. Ft = cuddT(f); Fe = cuddE(f);
  1872. } else {
  1873. Ft = Fe = f;
  1874. }
  1875. if (topb <= topf) {
  1876. /* We know that b is not constant because f is not. */
  1877. Bt = cuddT(B); Be = cuddE(B);
  1878. if (Cudd_IsComplement(b)) {
  1879. Bt = Cudd_Not(Bt);
  1880. Be = Cudd_Not(Be);
  1881. }
  1882. } else {
  1883. Bt = Be = b;
  1884. }
  1885. careT = BAapplyBias(dd, Ft, Bt, info, cache);
  1886. if (careT == CARE_ERROR)
  1887. return(CARE_ERROR);
  1888. careE = BAapplyBias(dd, Cudd_Regular(Fe), Be, info, cache);
  1889. if (careE == CARE_ERROR)
  1890. return(CARE_ERROR);
  1891. if (careT == TOTAL_CARE && careE == TOTAL_CARE) {
  1892. infoF->care = TOTAL_CARE;
  1893. } else {
  1894. infoF->care = CARE;
  1895. }
  1896. if (f->ref != 1 || Cudd_Regular(b)->ref != 1) {
  1897. ptrint fanout = (ptrint) f->ref * Cudd_Regular(b)->ref;
  1898. cuddSatDec(fanout);
  1899. if (!cuddHashTableInsert2(cache,f,b,one,fanout)) {
  1900. return(CARE_ERROR);
  1901. }
  1902. }
  1903. return(infoF->care);
  1904. } /* end of BAapplyBias */