The source code and dockerfile for the GSW2024 AI Lab.
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.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

1406 lines
33 KiB

2 months ago
  1. /**
  2. @file
  3. @ingroup cudd
  4. @brief %BDD ITE function and satellites.
  5. @author Fabio Somenzi
  6. @copyright@parblock
  7. Copyright (c) 1995-2015, Regents of the University of Colorado
  8. All rights reserved.
  9. Redistribution and use in source and binary forms, with or without
  10. modification, are permitted provided that the following conditions
  11. are met:
  12. Redistributions of source code must retain the above copyright
  13. notice, this list of conditions and the following disclaimer.
  14. Redistributions in binary form must reproduce the above copyright
  15. notice, this list of conditions and the following disclaimer in the
  16. documentation and/or other materials provided with the distribution.
  17. Neither the name of the University of Colorado nor the names of its
  18. contributors may be used to endorse or promote products derived from
  19. this software without specific prior written permission.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  27. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  28. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  30. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  31. POSSIBILITY OF SUCH DAMAGE.
  32. @endparblock
  33. */
  34. #include "util.h"
  35. #include "cuddInt.h"
  36. /*---------------------------------------------------------------------------*/
  37. /* Constant declarations */
  38. /*---------------------------------------------------------------------------*/
  39. /*---------------------------------------------------------------------------*/
  40. /* Stucture declarations */
  41. /*---------------------------------------------------------------------------*/
  42. /*---------------------------------------------------------------------------*/
  43. /* Type declarations */
  44. /*---------------------------------------------------------------------------*/
  45. /*---------------------------------------------------------------------------*/
  46. /* Variable declarations */
  47. /*---------------------------------------------------------------------------*/
  48. /*---------------------------------------------------------------------------*/
  49. /* Macro declarations */
  50. /*---------------------------------------------------------------------------*/
  51. /** \cond */
  52. /*---------------------------------------------------------------------------*/
  53. /* Static function prototypes */
  54. /*---------------------------------------------------------------------------*/
  55. static void bddVarToConst (DdNode *f, DdNode **gp, DdNode **hp, DdNode *one);
  56. static int bddVarToCanonical (DdManager *dd, DdNode **fp, DdNode **gp, DdNode **hp, int *topfp, int *topgp, int *tophp);
  57. static int bddVarToCanonicalSimple (DdManager *dd, DdNode **fp, DdNode **gp, DdNode **hp, int *topfp, int *topgp, int *tophp);
  58. /** \endcond */
  59. /*---------------------------------------------------------------------------*/
  60. /* Definition of exported functions */
  61. /*---------------------------------------------------------------------------*/
  62. /**
  63. @brief Implements ITE(f,g,h).
  64. @return a pointer to the resulting %BDD if successful; NULL if the
  65. intermediate result blows up.
  66. @sideeffect None
  67. @see Cudd_addIte Cudd_bddIteConstant Cudd_bddIntersect
  68. */
  69. DdNode *
  70. Cudd_bddIte(
  71. DdManager * dd /**< manager */,
  72. DdNode * f /**< first operand */,
  73. DdNode * g /**< second operand */,
  74. DdNode * h /**< third operand */)
  75. {
  76. DdNode *res;
  77. do {
  78. dd->reordered = 0;
  79. res = cuddBddIteRecur(dd,f,g,h);
  80. } while (dd->reordered == 1);
  81. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  82. dd->timeoutHandler(dd, dd->tohArg);
  83. }
  84. return(res);
  85. } /* end of Cudd_bddIte */
  86. /**
  87. @brief Implements ITE(f,g,h) unless too many nodes are required.
  88. @return a pointer to the resulting %BDD if successful; NULL if the
  89. intermediate result blows up or more new nodes than `limit` are
  90. required.
  91. @sideeffect None
  92. @see Cudd_bddIte
  93. */
  94. DdNode *
  95. Cudd_bddIteLimit(
  96. DdManager * dd /**< manager */,
  97. DdNode * f /**< first operand */,
  98. DdNode * g /**< second operand */,
  99. DdNode * h /**< third operand */,
  100. unsigned int limit /**< maximum number of new nodes */)
  101. {
  102. DdNode *res;
  103. unsigned int saveLimit = dd->maxLive;
  104. dd->maxLive = (dd->keys - dd->dead) + (dd->keysZ - dd->deadZ) + limit;
  105. do {
  106. dd->reordered = 0;
  107. res = cuddBddIteRecur(dd,f,g,h);
  108. } while (dd->reordered == 1);
  109. dd->maxLive = saveLimit;
  110. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  111. dd->timeoutHandler(dd, dd->tohArg);
  112. }
  113. return(res);
  114. } /* end of Cudd_bddIteLimit */
  115. /**
  116. @brief Implements ITEconstant(f,g,h).
  117. @return a pointer to the resulting %BDD (which may or may not be
  118. constant) or DD_NON_CONSTANT.
  119. @details No new nodes are created.
  120. @sideeffect None
  121. @see Cudd_bddIte Cudd_bddIntersect Cudd_bddLeq Cudd_addIteConstant
  122. */
  123. DdNode *
  124. Cudd_bddIteConstant(
  125. DdManager * dd /**< manager */,
  126. DdNode * f /**< first operand */,
  127. DdNode * g /**< second operand */,
  128. DdNode * h /**< thord operand */)
  129. {
  130. DdNode *r, *Fv, *Fnv, *Gv, *Gnv, *H, *Hv, *Hnv, *t, *e;
  131. DdNode *one = DD_ONE(dd);
  132. DdNode *zero = Cudd_Not(one);
  133. int comple;
  134. int topf, topg, toph, v;
  135. statLine(dd);
  136. /* Trivial cases. */
  137. if (f == one) /* ITE(1,G,H) => G */
  138. return(g);
  139. if (f == zero) /* ITE(0,G,H) => H */
  140. return(h);
  141. /* f now not a constant. */
  142. bddVarToConst(f, &g, &h, one); /* possibly convert g or h */
  143. /* to constants */
  144. if (g == h) /* ITE(F,G,G) => G */
  145. return(g);
  146. if (Cudd_IsConstantInt(g) && Cudd_IsConstantInt(h))
  147. return(DD_NON_CONSTANT); /* ITE(F,1,0) or ITE(F,0,1) */
  148. /* => DD_NON_CONSTANT */
  149. if (g == Cudd_Not(h))
  150. return(DD_NON_CONSTANT); /* ITE(F,G,G') => DD_NON_CONSTANT */
  151. /* if F != G and F != G' */
  152. comple = bddVarToCanonical(dd, &f, &g, &h, &topf, &topg, &toph);
  153. /* Cache lookup. */
  154. r = cuddConstantLookup(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h);
  155. if (r != NULL) {
  156. return(Cudd_NotCond(r,comple && r != DD_NON_CONSTANT));
  157. }
  158. v = ddMin(topg, toph);
  159. /* ITE(F,G,H) = (v,G,H) (non constant) if F = (v,1,0), v < top(G,H). */
  160. if (topf < v && cuddT(f) == one && cuddE(f) == zero) {
  161. return(DD_NON_CONSTANT);
  162. }
  163. /* Compute cofactors. */
  164. if (topf <= v) {
  165. v = ddMin(topf, v); /* v = top_var(F,G,H) */
  166. Fv = cuddT(f); Fnv = cuddE(f);
  167. } else {
  168. Fv = Fnv = f;
  169. }
  170. if (topg == v) {
  171. Gv = cuddT(g); Gnv = cuddE(g);
  172. } else {
  173. Gv = Gnv = g;
  174. }
  175. if (toph == v) {
  176. H = Cudd_Regular(h);
  177. Hv = cuddT(H); Hnv = cuddE(H);
  178. if (Cudd_IsComplement(h)) {
  179. Hv = Cudd_Not(Hv);
  180. Hnv = Cudd_Not(Hnv);
  181. }
  182. } else {
  183. Hv = Hnv = h;
  184. }
  185. /* Recursion. */
  186. t = Cudd_bddIteConstant(dd, Fv, Gv, Hv);
  187. if (t == DD_NON_CONSTANT || !Cudd_IsConstantInt(t)) {
  188. cuddCacheInsert(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h, DD_NON_CONSTANT);
  189. return(DD_NON_CONSTANT);
  190. }
  191. e = Cudd_bddIteConstant(dd, Fnv, Gnv, Hnv);
  192. if (e == DD_NON_CONSTANT || !Cudd_IsConstantInt(e) || t != e) {
  193. cuddCacheInsert(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h, DD_NON_CONSTANT);
  194. return(DD_NON_CONSTANT);
  195. }
  196. cuddCacheInsert(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h, t);
  197. return(Cudd_NotCond(t,comple));
  198. } /* end of Cudd_bddIteConstant */
  199. /**
  200. @brief Returns a function included in the intersection of f and g.
  201. @details The function computed (if not zero) is a witness that the
  202. intersection is not empty. Cudd_bddIntersect tries to build as few
  203. new nodes as possible. If the only result of interest is whether f
  204. and g intersect, Cudd_bddLeq should be used instead.
  205. @sideeffect None
  206. @see Cudd_bddLeq Cudd_bddIteConstant
  207. */
  208. DdNode *
  209. Cudd_bddIntersect(
  210. DdManager * dd /**< manager */,
  211. DdNode * f /**< first operand */,
  212. DdNode * g /**< second operand */)
  213. {
  214. DdNode *res;
  215. do {
  216. dd->reordered = 0;
  217. res = cuddBddIntersectRecur(dd,f,g);
  218. } while (dd->reordered == 1);
  219. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  220. dd->timeoutHandler(dd, dd->tohArg);
  221. }
  222. return(res);
  223. } /* end of Cudd_bddIntersect */
  224. /**
  225. @brief Computes the conjunction of two BDDs f and g.
  226. @return a pointer to the resulting %BDD if successful; NULL if the
  227. intermediate result blows up.
  228. @sideeffect None
  229. @see Cudd_bddIte Cudd_addApply Cudd_bddAndAbstract Cudd_bddIntersect
  230. Cudd_bddOr Cudd_bddNand Cudd_bddNor Cudd_bddXor Cudd_bddXnor
  231. */
  232. DdNode *
  233. Cudd_bddAnd(
  234. DdManager * dd /**< manager */,
  235. DdNode * f /**< first operand */,
  236. DdNode * g /**< second operand */)
  237. {
  238. DdNode *res;
  239. do {
  240. dd->reordered = 0;
  241. res = cuddBddAndRecur(dd,f,g);
  242. } while (dd->reordered == 1);
  243. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  244. dd->timeoutHandler(dd, dd->tohArg);
  245. }
  246. return(res);
  247. } /* end of Cudd_bddAnd */
  248. /**
  249. @brief Computes the conjunction of two BDDs f and g unless too many
  250. nodes are required.
  251. @return a pointer to the resulting %BDD if successful; NULL if the
  252. intermediate result blows up or more new nodes than `limit` are
  253. required.
  254. @sideeffect None
  255. @see Cudd_bddAnd
  256. */
  257. DdNode *
  258. Cudd_bddAndLimit(
  259. DdManager * dd /**< manager */,
  260. DdNode * f /**< first operand */,
  261. DdNode * g /**< second operand */,
  262. unsigned int limit /**< maximum number of new nodes */)
  263. {
  264. DdNode *res;
  265. unsigned int saveLimit = dd->maxLive;
  266. dd->maxLive = (dd->keys - dd->dead) + (dd->keysZ - dd->deadZ) + limit;
  267. do {
  268. dd->reordered = 0;
  269. res = cuddBddAndRecur(dd,f,g);
  270. } while (dd->reordered == 1);
  271. dd->maxLive = saveLimit;
  272. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  273. dd->timeoutHandler(dd, dd->tohArg);
  274. }
  275. return(res);
  276. } /* end of Cudd_bddAndLimit */
  277. /**
  278. @brief Computes the disjunction of two BDDs f and g.
  279. @return a pointer to the resulting %BDD if successful; NULL if the
  280. intermediate result blows up.
  281. @sideeffect None
  282. @see Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddNand Cudd_bddNor
  283. Cudd_bddXor Cudd_bddXnor
  284. */
  285. DdNode *
  286. Cudd_bddOr(
  287. DdManager * dd /**< manager */,
  288. DdNode * f /**< first operand */,
  289. DdNode * g /**< second operand */)
  290. {
  291. DdNode *res;
  292. do {
  293. dd->reordered = 0;
  294. res = cuddBddAndRecur(dd,Cudd_Not(f),Cudd_Not(g));
  295. } while (dd->reordered == 1);
  296. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  297. dd->timeoutHandler(dd, dd->tohArg);
  298. }
  299. res = Cudd_NotCond(res,res != NULL);
  300. return(res);
  301. } /* end of Cudd_bddOr */
  302. /**
  303. @brief Computes the disjunction of two BDDs f and g unless too many
  304. nodes are required.
  305. @return a pointer to the resulting %BDD if successful; NULL if the
  306. intermediate result blows up or more new nodes than `limit` are
  307. required.
  308. @sideeffect None
  309. @see Cudd_bddOr
  310. */
  311. DdNode *
  312. Cudd_bddOrLimit(
  313. DdManager * dd /**< manager */,
  314. DdNode * f /**< first operand */,
  315. DdNode * g /**< second operand */,
  316. unsigned int limit /**< maximum number of new nodes */)
  317. {
  318. DdNode *res;
  319. unsigned int saveLimit = dd->maxLive;
  320. dd->maxLive = (dd->keys - dd->dead) + (dd->keysZ - dd->deadZ) + limit;
  321. do {
  322. dd->reordered = 0;
  323. res = cuddBddAndRecur(dd,Cudd_Not(f),Cudd_Not(g));
  324. } while (dd->reordered == 1);
  325. dd->maxLive = saveLimit;
  326. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  327. dd->timeoutHandler(dd, dd->tohArg);
  328. }
  329. res = Cudd_NotCond(res,res != NULL);
  330. return(res);
  331. } /* end of Cudd_bddOrLimit */
  332. /**
  333. @brief Computes the NAND of two BDDs f and g.
  334. @return a pointer to the resulting %BDD if successful; NULL if the
  335. intermediate result blows up.
  336. @sideeffect None
  337. @see Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddOr Cudd_bddNor
  338. Cudd_bddXor Cudd_bddXnor
  339. */
  340. DdNode *
  341. Cudd_bddNand(
  342. DdManager * dd /**< manager */,
  343. DdNode * f /**< first operand */,
  344. DdNode * g /** second operand */)
  345. {
  346. DdNode *res;
  347. do {
  348. dd->reordered = 0;
  349. res = cuddBddAndRecur(dd,f,g);
  350. } while (dd->reordered == 1);
  351. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  352. dd->timeoutHandler(dd, dd->tohArg);
  353. }
  354. res = Cudd_NotCond(res,res != NULL);
  355. return(res);
  356. } /* end of Cudd_bddNand */
  357. /**
  358. @brief Computes the NOR of two BDDs f and g.
  359. @return a pointer to the resulting %BDD if successful; NULL if the
  360. intermediate result blows up.
  361. @sideeffect None
  362. @see Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddOr Cudd_bddNand
  363. Cudd_bddXor Cudd_bddXnor
  364. */
  365. DdNode *
  366. Cudd_bddNor(
  367. DdManager * dd /**< manager */,
  368. DdNode * f /**< first operand */,
  369. DdNode * g /**< second operand */)
  370. {
  371. DdNode *res;
  372. do {
  373. dd->reordered = 0;
  374. res = cuddBddAndRecur(dd,Cudd_Not(f),Cudd_Not(g));
  375. } while (dd->reordered == 1);
  376. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  377. dd->timeoutHandler(dd, dd->tohArg);
  378. }
  379. return(res);
  380. } /* end of Cudd_bddNor */
  381. /**
  382. @brief Computes the exclusive OR of two BDDs f and g.
  383. @return a pointer to the resulting %BDD if successful; NULL if the
  384. intermediate result blows up.
  385. @sideeffect None
  386. @see Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddOr
  387. Cudd_bddNand Cudd_bddNor Cudd_bddXnor
  388. */
  389. DdNode *
  390. Cudd_bddXor(
  391. DdManager * dd /**< manager */,
  392. DdNode * f /**< first operand */,
  393. DdNode * g /**< second operand */)
  394. {
  395. DdNode *res;
  396. do {
  397. dd->reordered = 0;
  398. res = cuddBddXorRecur(dd,f,g);
  399. } while (dd->reordered == 1);
  400. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  401. dd->timeoutHandler(dd, dd->tohArg);
  402. }
  403. return(res);
  404. } /* end of Cudd_bddXor */
  405. /**
  406. @brief Computes the exclusive NOR of two BDDs f and g.
  407. @return a pointer to the resulting %BDD if successful; NULL if the
  408. intermediate result blows up.
  409. @sideeffect None
  410. @see Cudd_bddIte Cudd_addApply Cudd_bddAnd Cudd_bddOr
  411. Cudd_bddNand Cudd_bddNor Cudd_bddXor
  412. */
  413. DdNode *
  414. Cudd_bddXnor(
  415. DdManager * dd /**< manager */,
  416. DdNode * f /**< first operand */,
  417. DdNode * g /**< second operand */)
  418. {
  419. DdNode *res;
  420. do {
  421. dd->reordered = 0;
  422. res = cuddBddXorRecur(dd,f,Cudd_Not(g));
  423. } while (dd->reordered == 1);
  424. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  425. dd->timeoutHandler(dd, dd->tohArg);
  426. }
  427. return(res);
  428. } /* end of Cudd_bddXnor */
  429. /**
  430. @brief Computes the exclusive NOR of two BDDs f and g unless too
  431. many nodes are required.
  432. @return a pointer to the resulting %BDD if successful; NULL if the
  433. intermediate result blows up or more new nodes than `limit` are
  434. required.
  435. @sideeffect None
  436. @see Cudd_bddXnor
  437. */
  438. DdNode *
  439. Cudd_bddXnorLimit(
  440. DdManager * dd /**< manager */,
  441. DdNode * f /**< first operand */,
  442. DdNode * g /**< second operand */,
  443. unsigned int limit /**< maximum number of new nodes */)
  444. {
  445. DdNode *res;
  446. unsigned int saveLimit = dd->maxLive;
  447. dd->maxLive = (dd->keys - dd->dead) + (dd->keysZ - dd->deadZ) + limit;
  448. do {
  449. dd->reordered = 0;
  450. res = cuddBddXorRecur(dd,f,Cudd_Not(g));
  451. } while (dd->reordered == 1);
  452. dd->maxLive = saveLimit;
  453. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  454. dd->timeoutHandler(dd, dd->tohArg);
  455. }
  456. return(res);
  457. } /* end of Cudd_bddXnorLimit */
  458. /**
  459. @brief Checks whether f is less than or equal to g.
  460. @return 1 if f is less than or equal to g; 0 otherwise.
  461. @details No new nodes are created.
  462. @sideeffect None
  463. @see Cudd_bddIteConstant Cudd_addEvalConst
  464. */
  465. int
  466. Cudd_bddLeq(
  467. DdManager * dd /**< manager */,
  468. DdNode * f /**< first operand */,
  469. DdNode * g /**< second operand */)
  470. {
  471. DdNode *one, *zero, *tmp, *F, *fv, *fvn, *gv, *gvn;
  472. int topf, topg, res;
  473. statLine(dd);
  474. /* Terminal cases and normalization. */
  475. if (f == g) return(1);
  476. if (Cudd_IsComplement(g)) {
  477. /* Special case: if f is regular and g is complemented,
  478. ** f(1,...,1) = 1 > 0 = g(1,...,1).
  479. */
  480. if (!Cudd_IsComplement(f)) return(0);
  481. /* Both are complemented: Swap and complement because
  482. ** f <= g <=> g' <= f' and we want the second argument to be regular.
  483. */
  484. tmp = g;
  485. g = Cudd_Not(f);
  486. f = Cudd_Not(tmp);
  487. } else if (Cudd_IsComplement(f) && g < f) {
  488. tmp = g;
  489. g = Cudd_Not(f);
  490. f = Cudd_Not(tmp);
  491. }
  492. /* Now g is regular. */
  493. one = DD_ONE(dd);
  494. if (g == one) return(1); /* no need to test against zero */
  495. if (f == one) return(0); /* since at this point g != one */
  496. if (Cudd_Not(f) == g) return(0); /* because neither is constant */
  497. zero = Cudd_Not(one);
  498. if (f == zero) return(1);
  499. /* Here neither f nor g is constant. */
  500. /* Check cache. */
  501. F = Cudd_Regular(f);
  502. if (F->ref != 1 || g->ref != 1) {
  503. tmp = cuddCacheLookup2(dd,(DD_CTFP)Cudd_bddLeq,f,g);
  504. if (tmp != NULL) {
  505. return(tmp == one);
  506. }
  507. }
  508. /* Compute cofactors. */
  509. topf = dd->perm[F->index];
  510. topg = dd->perm[g->index];
  511. if (topf <= topg) {
  512. fv = cuddT(F); fvn = cuddE(F);
  513. if (f != F) {
  514. fv = Cudd_Not(fv);
  515. fvn = Cudd_Not(fvn);
  516. }
  517. } else {
  518. fv = fvn = f;
  519. }
  520. if (topg <= topf) {
  521. gv = cuddT(g); gvn = cuddE(g);
  522. } else {
  523. gv = gvn = g;
  524. }
  525. /* Recursive calls. Since we want to maximize the probability of
  526. ** the special case f(1,...,1) > g(1,...,1), we consider the negative
  527. ** cofactors first. Indeed, the complementation parity of the positive
  528. ** cofactors is the same as the one of the parent functions.
  529. */
  530. res = Cudd_bddLeq(dd,fvn,gvn) && Cudd_bddLeq(dd,fv,gv);
  531. /* Store result in cache and return. */
  532. if (F->ref !=1 || g->ref != 1)
  533. cuddCacheInsert2(dd,(DD_CTFP)Cudd_bddLeq,f,g,(res ? one : zero));
  534. return(res);
  535. } /* end of Cudd_bddLeq */
  536. /*---------------------------------------------------------------------------*/
  537. /* Definition of internal functions */
  538. /*---------------------------------------------------------------------------*/
  539. /**
  540. @brief Implements the recursive step of Cudd_bddIte.
  541. @return a pointer to the resulting %BDD. NULL if the intermediate
  542. result blows up or if reordering occurs.
  543. @sideeffect None
  544. */
  545. DdNode *
  546. cuddBddIteRecur(
  547. DdManager * dd,
  548. DdNode * f,
  549. DdNode * g,
  550. DdNode * h)
  551. {
  552. DdNode *one, *zero, *res;
  553. DdNode *r, *Fv, *Fnv, *Gv, *Gnv, *H, *Hv, *Hnv, *t, *e;
  554. int topf, topg, toph, v;
  555. unsigned int index;
  556. int comple;
  557. statLine(dd);
  558. /* Terminal cases. */
  559. /* One variable cases. */
  560. if (f == (one = DD_ONE(dd))) /* ITE(1,G,H) = G */
  561. return(g);
  562. if (f == (zero = Cudd_Not(one))) /* ITE(0,G,H) = H */
  563. return(h);
  564. /* From now on, f is known not to be a constant. */
  565. if (g == one || f == g) { /* ITE(F,F,H) = ITE(F,1,H) = F + H */
  566. if (h == zero) { /* ITE(F,1,0) = F */
  567. return(f);
  568. } else {
  569. res = cuddBddAndRecur(dd,Cudd_Not(f),Cudd_Not(h));
  570. return(Cudd_NotCond(res,res != NULL));
  571. }
  572. } else if (g == zero || f == Cudd_Not(g)) { /* ITE(F,!F,H) = ITE(F,0,H) = !F * H */
  573. if (h == one) { /* ITE(F,0,1) = !F */
  574. return(Cudd_Not(f));
  575. } else {
  576. res = cuddBddAndRecur(dd,Cudd_Not(f),h);
  577. return(res);
  578. }
  579. }
  580. if (h == zero || f == h) { /* ITE(F,G,F) = ITE(F,G,0) = F * G */
  581. res = cuddBddAndRecur(dd,f,g);
  582. return(res);
  583. } else if (h == one || f == Cudd_Not(h)) { /* ITE(F,G,!F) = ITE(F,G,1) = !F + G */
  584. res = cuddBddAndRecur(dd,f,Cudd_Not(g));
  585. return(Cudd_NotCond(res,res != NULL));
  586. }
  587. /* Check remaining one variable case. */
  588. if (g == h) { /* ITE(F,G,G) = G */
  589. return(g);
  590. } else if (g == Cudd_Not(h)) { /* ITE(F,G,!G) = F <-> G */
  591. res = cuddBddXorRecur(dd,f,h);
  592. return(res);
  593. }
  594. /* From here, there are no constants. */
  595. comple = bddVarToCanonicalSimple(dd, &f, &g, &h, &topf, &topg, &toph);
  596. /* f & g are now regular pointers */
  597. v = ddMin(topg, toph);
  598. /* A shortcut: ITE(F,G,H) = (v,G,H) if F = (v,1,0), v < top(G,H). */
  599. if (topf < v && cuddT(f) == one && cuddE(f) == zero) {
  600. r = cuddUniqueInter(dd, (int) f->index, g, h);
  601. return(Cudd_NotCond(r,comple && r != NULL));
  602. }
  603. /* Check cache. */
  604. r = cuddCacheLookup(dd, DD_BDD_ITE_TAG, f, g, h);
  605. if (r != NULL) {
  606. return(Cudd_NotCond(r,comple));
  607. }
  608. checkWhetherToGiveUp(dd);
  609. /* Compute cofactors. */
  610. index = f->index;
  611. if (topf <= v) {
  612. v = ddMin(topf, v); /* v = top_var(F,G,H) */
  613. Fv = cuddT(f); Fnv = cuddE(f);
  614. } else {
  615. Fv = Fnv = f;
  616. }
  617. if (topg == v) {
  618. index = g->index;
  619. Gv = cuddT(g); Gnv = cuddE(g);
  620. } else {
  621. Gv = Gnv = g;
  622. }
  623. if (toph == v) {
  624. H = Cudd_Regular(h);
  625. index = H->index;
  626. Hv = cuddT(H); Hnv = cuddE(H);
  627. if (Cudd_IsComplement(h)) {
  628. Hv = Cudd_Not(Hv);
  629. Hnv = Cudd_Not(Hnv);
  630. }
  631. } else {
  632. Hv = Hnv = h;
  633. }
  634. /* Recursive step. */
  635. t = cuddBddIteRecur(dd,Fv,Gv,Hv);
  636. if (t == NULL) return(NULL);
  637. cuddRef(t);
  638. e = cuddBddIteRecur(dd,Fnv,Gnv,Hnv);
  639. if (e == NULL) {
  640. Cudd_IterDerefBdd(dd,t);
  641. return(NULL);
  642. }
  643. cuddRef(e);
  644. r = (t == e) ? t : cuddUniqueInter(dd,index,t,e);
  645. if (r == NULL) {
  646. Cudd_IterDerefBdd(dd,t);
  647. Cudd_IterDerefBdd(dd,e);
  648. return(NULL);
  649. }
  650. cuddDeref(t);
  651. cuddDeref(e);
  652. cuddCacheInsert(dd, DD_BDD_ITE_TAG, f, g, h, r);
  653. return(Cudd_NotCond(r,comple));
  654. } /* end of cuddBddIteRecur */
  655. /**
  656. @brief Implements the recursive step of Cudd_bddIntersect.
  657. @sideeffect None
  658. @see Cudd_bddIntersect
  659. */
  660. DdNode *
  661. cuddBddIntersectRecur(
  662. DdManager * dd,
  663. DdNode * f,
  664. DdNode * g)
  665. {
  666. DdNode *res;
  667. DdNode *F, *G, *t, *e;
  668. DdNode *fv, *fnv, *gv, *gnv;
  669. DdNode *one, *zero;
  670. unsigned int index;
  671. int topf, topg;
  672. statLine(dd);
  673. one = DD_ONE(dd);
  674. zero = Cudd_Not(one);
  675. /* Terminal cases. */
  676. if (f == zero || g == zero || f == Cudd_Not(g)) return(zero);
  677. if (f == g || g == one) return(f);
  678. if (f == one) return(g);
  679. /* At this point f and g are not constant. */
  680. if (f > g) { DdNode *tmp = f; f = g; g = tmp; }
  681. res = cuddCacheLookup2(dd,Cudd_bddIntersect,f,g);
  682. if (res != NULL) return(res);
  683. checkWhetherToGiveUp(dd);
  684. /* Find splitting variable. Here we can skip the use of cuddI,
  685. ** because the operands are known to be non-constant.
  686. */
  687. F = Cudd_Regular(f);
  688. topf = dd->perm[F->index];
  689. G = Cudd_Regular(g);
  690. topg = dd->perm[G->index];
  691. /* Compute cofactors. */
  692. if (topf <= topg) {
  693. index = F->index;
  694. fv = cuddT(F);
  695. fnv = cuddE(F);
  696. if (Cudd_IsComplement(f)) {
  697. fv = Cudd_Not(fv);
  698. fnv = Cudd_Not(fnv);
  699. }
  700. } else {
  701. index = G->index;
  702. fv = fnv = f;
  703. }
  704. if (topg <= topf) {
  705. gv = cuddT(G);
  706. gnv = cuddE(G);
  707. if (Cudd_IsComplement(g)) {
  708. gv = Cudd_Not(gv);
  709. gnv = Cudd_Not(gnv);
  710. }
  711. } else {
  712. gv = gnv = g;
  713. }
  714. /* Compute partial results. */
  715. t = cuddBddIntersectRecur(dd,fv,gv);
  716. if (t == NULL) return(NULL);
  717. cuddRef(t);
  718. if (t != zero) {
  719. e = zero;
  720. } else {
  721. e = cuddBddIntersectRecur(dd,fnv,gnv);
  722. if (e == NULL) {
  723. Cudd_IterDerefBdd(dd, t);
  724. return(NULL);
  725. }
  726. }
  727. cuddRef(e);
  728. if (t == e) { /* both equal zero */
  729. res = t;
  730. } else if (Cudd_IsComplement(t)) {
  731. res = cuddUniqueInter(dd,(int)index,Cudd_Not(t),Cudd_Not(e));
  732. if (res == NULL) {
  733. Cudd_IterDerefBdd(dd, t);
  734. Cudd_IterDerefBdd(dd, e);
  735. return(NULL);
  736. }
  737. res = Cudd_Not(res);
  738. } else {
  739. res = cuddUniqueInter(dd,(int)index,t,e);
  740. if (res == NULL) {
  741. Cudd_IterDerefBdd(dd, t);
  742. Cudd_IterDerefBdd(dd, e);
  743. return(NULL);
  744. }
  745. }
  746. cuddDeref(e);
  747. cuddDeref(t);
  748. cuddCacheInsert2(dd,Cudd_bddIntersect,f,g,res);
  749. return(res);
  750. } /* end of cuddBddIntersectRecur */
  751. /**
  752. @brief Implements the recursive step of Cudd_bddAnd.
  753. @details Takes the conjunction of two BDDs.
  754. @return a pointer to the result is successful; NULL otherwise.
  755. @sideeffect None
  756. @see Cudd_bddAnd
  757. */
  758. DdNode *
  759. cuddBddAndRecur(
  760. DdManager * manager,
  761. DdNode * f,
  762. DdNode * g)
  763. {
  764. DdNode *F, *fv, *fnv, *G, *gv, *gnv;
  765. DdNode *one, *r, *t, *e;
  766. int topf, topg;
  767. unsigned int index;
  768. statLine(manager);
  769. one = DD_ONE(manager);
  770. /* Terminal cases. */
  771. F = Cudd_Regular(f);
  772. G = Cudd_Regular(g);
  773. if (F == G) {
  774. if (f == g) return(f);
  775. else return(Cudd_Not(one));
  776. }
  777. if (F == one) {
  778. if (f == one) return(g);
  779. else return(f);
  780. }
  781. if (G == one) {
  782. if (g == one) return(f);
  783. else return(g);
  784. }
  785. /* At this point f and g are not constant. */
  786. if (f > g) { /* Try to increase cache efficiency. */
  787. DdNode *tmp = f;
  788. f = g;
  789. g = tmp;
  790. F = Cudd_Regular(f);
  791. G = Cudd_Regular(g);
  792. }
  793. /* Check cache. */
  794. if (F->ref != 1 || G->ref != 1) {
  795. r = cuddCacheLookup2(manager, Cudd_bddAnd, f, g);
  796. if (r != NULL) return(r);
  797. }
  798. checkWhetherToGiveUp(manager);
  799. /* Here we can skip the use of cuddI, because the operands are known
  800. ** to be non-constant.
  801. */
  802. topf = manager->perm[F->index];
  803. topg = manager->perm[G->index];
  804. /* Compute cofactors. */
  805. if (topf <= topg) {
  806. index = F->index;
  807. fv = cuddT(F);
  808. fnv = cuddE(F);
  809. if (Cudd_IsComplement(f)) {
  810. fv = Cudd_Not(fv);
  811. fnv = Cudd_Not(fnv);
  812. }
  813. } else {
  814. index = G->index;
  815. fv = fnv = f;
  816. }
  817. if (topg <= topf) {
  818. gv = cuddT(G);
  819. gnv = cuddE(G);
  820. if (Cudd_IsComplement(g)) {
  821. gv = Cudd_Not(gv);
  822. gnv = Cudd_Not(gnv);
  823. }
  824. } else {
  825. gv = gnv = g;
  826. }
  827. t = cuddBddAndRecur(manager, fv, gv);
  828. if (t == NULL) return(NULL);
  829. cuddRef(t);
  830. e = cuddBddAndRecur(manager, fnv, gnv);
  831. if (e == NULL) {
  832. Cudd_IterDerefBdd(manager, t);
  833. return(NULL);
  834. }
  835. cuddRef(e);
  836. if (t == e) {
  837. r = t;
  838. } else {
  839. if (Cudd_IsComplement(t)) {
  840. r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e));
  841. if (r == NULL) {
  842. Cudd_IterDerefBdd(manager, t);
  843. Cudd_IterDerefBdd(manager, e);
  844. return(NULL);
  845. }
  846. r = Cudd_Not(r);
  847. } else {
  848. r = cuddUniqueInter(manager,(int)index,t,e);
  849. if (r == NULL) {
  850. Cudd_IterDerefBdd(manager, t);
  851. Cudd_IterDerefBdd(manager, e);
  852. return(NULL);
  853. }
  854. }
  855. }
  856. cuddDeref(e);
  857. cuddDeref(t);
  858. if (F->ref != 1 || G->ref != 1)
  859. cuddCacheInsert2(manager, Cudd_bddAnd, f, g, r);
  860. return(r);
  861. } /* end of cuddBddAndRecur */
  862. /**
  863. @brief Implements the recursive step of Cudd_bddXor.
  864. @details Takes the exclusive OR of two BDDs.
  865. @return a pointer to the result is successful; NULL otherwise.
  866. @sideeffect None
  867. @see Cudd_bddXor
  868. */
  869. DdNode *
  870. cuddBddXorRecur(
  871. DdManager * manager,
  872. DdNode * f,
  873. DdNode * g)
  874. {
  875. DdNode *fv, *fnv, *G, *gv, *gnv;
  876. DdNode *one, *zero, *r, *t, *e;
  877. int topf, topg;
  878. unsigned int index;
  879. statLine(manager);
  880. one = DD_ONE(manager);
  881. zero = Cudd_Not(one);
  882. /* Terminal cases. */
  883. if (f == g) return(zero);
  884. if (f == Cudd_Not(g)) return(one);
  885. if (f > g) { /* Try to increase cache efficiency and simplify tests. */
  886. DdNode *tmp = f;
  887. f = g;
  888. g = tmp;
  889. }
  890. if (g == zero) return(f);
  891. if (g == one) return(Cudd_Not(f));
  892. if (Cudd_IsComplement(f)) {
  893. f = Cudd_Not(f);
  894. g = Cudd_Not(g);
  895. }
  896. /* Now the first argument is regular. */
  897. if (f == one) return(Cudd_Not(g));
  898. /* At this point f and g are not constant. */
  899. /* Check cache. */
  900. r = cuddCacheLookup2(manager, Cudd_bddXor, f, g);
  901. if (r != NULL) return(r);
  902. checkWhetherToGiveUp(manager);
  903. /* Here we can skip the use of cuddI, because the operands are known
  904. ** to be non-constant.
  905. */
  906. topf = manager->perm[f->index];
  907. G = Cudd_Regular(g);
  908. topg = manager->perm[G->index];
  909. /* Compute cofactors. */
  910. if (topf <= topg) {
  911. index = f->index;
  912. fv = cuddT(f);
  913. fnv = cuddE(f);
  914. } else {
  915. index = G->index;
  916. fv = fnv = f;
  917. }
  918. if (topg <= topf) {
  919. gv = cuddT(G);
  920. gnv = cuddE(G);
  921. if (Cudd_IsComplement(g)) {
  922. gv = Cudd_Not(gv);
  923. gnv = Cudd_Not(gnv);
  924. }
  925. } else {
  926. gv = gnv = g;
  927. }
  928. t = cuddBddXorRecur(manager, fv, gv);
  929. if (t == NULL) return(NULL);
  930. cuddRef(t);
  931. e = cuddBddXorRecur(manager, fnv, gnv);
  932. if (e == NULL) {
  933. Cudd_IterDerefBdd(manager, t);
  934. return(NULL);
  935. }
  936. cuddRef(e);
  937. if (t == e) {
  938. r = t;
  939. } else {
  940. if (Cudd_IsComplement(t)) {
  941. r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e));
  942. if (r == NULL) {
  943. Cudd_IterDerefBdd(manager, t);
  944. Cudd_IterDerefBdd(manager, e);
  945. return(NULL);
  946. }
  947. r = Cudd_Not(r);
  948. } else {
  949. r = cuddUniqueInter(manager,(int)index,t,e);
  950. if (r == NULL) {
  951. Cudd_IterDerefBdd(manager, t);
  952. Cudd_IterDerefBdd(manager, e);
  953. return(NULL);
  954. }
  955. }
  956. }
  957. cuddDeref(e);
  958. cuddDeref(t);
  959. cuddCacheInsert2(manager, Cudd_bddXor, f, g, r);
  960. return(r);
  961. } /* end of cuddBddXorRecur */
  962. /*---------------------------------------------------------------------------*/
  963. /* Definition of static functions */
  964. /*---------------------------------------------------------------------------*/
  965. /**
  966. @brief Replaces variables with constants if possible.
  967. @details This function performs part of the transformation to
  968. standard form by replacing variables with constants if possible.
  969. @sideeffect None
  970. @see bddVarToCanonical bddVarToCanonicalSimple
  971. */
  972. static void
  973. bddVarToConst(
  974. DdNode * f,
  975. DdNode ** gp,
  976. DdNode ** hp,
  977. DdNode * one)
  978. {
  979. DdNode *g = *gp;
  980. DdNode *h = *hp;
  981. if (f == g) { /* ITE(F,F,H) = ITE(F,1,H) = F + H */
  982. *gp = one;
  983. } else if (f == Cudd_Not(g)) { /* ITE(F,!F,H) = ITE(F,0,H) = !F * H */
  984. *gp = Cudd_Not(one);
  985. }
  986. if (f == h) { /* ITE(F,G,F) = ITE(F,G,0) = F * G */
  987. *hp = Cudd_Not(one);
  988. } else if (f == Cudd_Not(h)) { /* ITE(F,G,!F) = ITE(F,G,1) = !F + G */
  989. *hp = one;
  990. }
  991. } /* end of bddVarToConst */
  992. /**
  993. @brief Picks unique member from equiv expressions.
  994. @details Reduces 2 variable expressions to canonical form.
  995. @sideeffect None
  996. @see bddVarToConst bddVarToCanonicalSimple
  997. */
  998. static int
  999. bddVarToCanonical(
  1000. DdManager * dd,
  1001. DdNode ** fp,
  1002. DdNode ** gp,
  1003. DdNode ** hp,
  1004. int * topfp,
  1005. int * topgp,
  1006. int * tophp)
  1007. {
  1008. DdNode *F, *G, *H, *r, *f, *g, *h;
  1009. DdNode *one = dd->one;
  1010. int topf, topg, toph;
  1011. int comple, change;
  1012. f = *fp;
  1013. g = *gp;
  1014. h = *hp;
  1015. F = Cudd_Regular(f);
  1016. G = Cudd_Regular(g);
  1017. H = Cudd_Regular(h);
  1018. topf = cuddI(dd,F->index);
  1019. topg = cuddI(dd,G->index);
  1020. toph = cuddI(dd,H->index);
  1021. change = 0;
  1022. if (G == one) { /* ITE(F,c,H) */
  1023. if ((topf > toph) || (topf == toph && f > h)) {
  1024. r = h;
  1025. h = f;
  1026. f = r; /* ITE(F,1,H) = ITE(H,1,F) */
  1027. if (g != one) { /* g == zero */
  1028. f = Cudd_Not(f); /* ITE(F,0,H) = ITE(!H,0,!F) */
  1029. h = Cudd_Not(h);
  1030. }
  1031. change = 1;
  1032. }
  1033. } else if (H == one) { /* ITE(F,G,c) */
  1034. if ((topf > topg) || (topf == topg && f > g)) {
  1035. r = g;
  1036. g = f;
  1037. f = r; /* ITE(F,G,0) = ITE(G,F,0) */
  1038. if (h == one) {
  1039. f = Cudd_Not(f); /* ITE(F,G,1) = ITE(!G,!F,1) */
  1040. g = Cudd_Not(g);
  1041. }
  1042. change = 1;
  1043. }
  1044. } else if (g == Cudd_Not(h)) { /* ITE(F,G,!G) = ITE(G,F,!F) */
  1045. if ((topf > topg) || (topf == topg && f > g)) {
  1046. r = f;
  1047. f = g;
  1048. g = r;
  1049. h = Cudd_Not(r);
  1050. change = 1;
  1051. }
  1052. }
  1053. /* adjust pointers so that the first 2 arguments to ITE are regular */
  1054. if (Cudd_IsComplement(f) != 0) { /* ITE(!F,G,H) = ITE(F,H,G) */
  1055. f = Cudd_Not(f);
  1056. r = g;
  1057. g = h;
  1058. h = r;
  1059. change = 1;
  1060. }
  1061. comple = 0;
  1062. if (Cudd_IsComplement(g) != 0) { /* ITE(F,!G,H) = !ITE(F,G,!H) */
  1063. g = Cudd_Not(g);
  1064. h = Cudd_Not(h);
  1065. change = 1;
  1066. comple = 1;
  1067. }
  1068. if (change != 0) {
  1069. *fp = f;
  1070. *gp = g;
  1071. *hp = h;
  1072. }
  1073. *topfp = cuddI(dd,f->index);
  1074. *topgp = cuddI(dd,g->index);
  1075. *tophp = cuddI(dd,Cudd_Regular(h)->index);
  1076. return(comple);
  1077. } /* end of bddVarToCanonical */
  1078. /**
  1079. @brief Picks unique member from equiv expressions.
  1080. @details Makes sure the first two pointers are regular. This
  1081. mat require the complementation of the result, which is signaled by
  1082. returning 1 instead of 0. This function is simpler than the general
  1083. case because it assumes that no two arguments are the same or
  1084. complementary, and no argument is constant.
  1085. @sideeffect None
  1086. @see bddVarToConst bddVarToCanonical
  1087. */
  1088. static int
  1089. bddVarToCanonicalSimple(
  1090. DdManager * dd,
  1091. DdNode ** fp,
  1092. DdNode ** gp,
  1093. DdNode ** hp,
  1094. int * topfp,
  1095. int * topgp,
  1096. int * tophp)
  1097. {
  1098. DdNode *r, *f, *g, *h;
  1099. int comple, change;
  1100. f = *fp;
  1101. g = *gp;
  1102. h = *hp;
  1103. change = 0;
  1104. /* adjust pointers so that the first 2 arguments to ITE are regular */
  1105. if (Cudd_IsComplement(f)) { /* ITE(!F,G,H) = ITE(F,H,G) */
  1106. f = Cudd_Not(f);
  1107. r = g;
  1108. g = h;
  1109. h = r;
  1110. change = 1;
  1111. }
  1112. comple = 0;
  1113. if (Cudd_IsComplement(g)) { /* ITE(F,!G,H) = !ITE(F,G,!H) */
  1114. g = Cudd_Not(g);
  1115. h = Cudd_Not(h);
  1116. change = 1;
  1117. comple = 1;
  1118. }
  1119. if (change) {
  1120. *fp = f;
  1121. *gp = g;
  1122. *hp = h;
  1123. }
  1124. /* Here we can skip the use of cuddI, because the operands are known
  1125. ** to be non-constant.
  1126. */
  1127. *topfp = dd->perm[f->index];
  1128. *topgp = dd->perm[g->index];
  1129. *tophp = dd->perm[Cudd_Regular(h)->index];
  1130. return(comple);
  1131. } /* end of bddVarToCanonicalSimple */