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.

2204 lines
68 KiB

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