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.

1796 lines
46 KiB

4 weeks ago
  1. /**
  2. @file
  3. @ingroup cudd
  4. @brief Functions for the solution of satisfiability related problems.
  5. @author Seh-Woong Jeong, 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. #define DD_BIGGY 100000000
  40. /*---------------------------------------------------------------------------*/
  41. /* Stucture declarations */
  42. /*---------------------------------------------------------------------------*/
  43. /*---------------------------------------------------------------------------*/
  44. /* Type declarations */
  45. /*---------------------------------------------------------------------------*/
  46. /**
  47. @brief Type of item stored in memoization table.
  48. */
  49. typedef struct cuddPathPair {
  50. int pos;
  51. int neg;
  52. } cuddPathPair;
  53. /*---------------------------------------------------------------------------*/
  54. /* Variable declarations */
  55. /*---------------------------------------------------------------------------*/
  56. /*---------------------------------------------------------------------------*/
  57. /* Macro declarations */
  58. /*---------------------------------------------------------------------------*/
  59. #define WEIGHT(weight, col) ((weight) == NULL ? 1 : weight[col])
  60. /** \cond */
  61. /*---------------------------------------------------------------------------*/
  62. /* Static function prototypes */
  63. /*---------------------------------------------------------------------------*/
  64. static enum st_retval freePathPair (void *key, void *value, void *arg);
  65. static cuddPathPair getShortest (DdManager *dd, DdNode *root, int *cost, int *support, st_table *visited);
  66. static DdNode * getPath (DdManager *manager, st_table *visited, DdNode *f, int *weight, int cost);
  67. static cuddPathPair getLargest (DdManager *dd, DdNode *root, st_table *visited);
  68. static DdNode * getCube (DdManager *manager, st_table *visited, DdNode *f, int cost);
  69. static DdNode * ddBddMaximallyExpand(DdManager *dd, DdNode *lb, DdNode *ub, DdNode *f);
  70. static int ddBddShortestPathUnate(DdManager *dd, DdNode *f, int *phases, st_table *table);
  71. static DdNode * ddGetLargestCubeUnate(DdManager *dd, DdNode *f, int *phases, st_table *table);
  72. /** \endcond */
  73. /*---------------------------------------------------------------------------*/
  74. /* Definition of exported functions */
  75. /*---------------------------------------------------------------------------*/
  76. /**
  77. @brief Returns the value of a %DD for a given variable assignment.
  78. @details The variable assignment is passed in an array of int's,
  79. that should specify a zero or a one for each variable in the support
  80. of the function.
  81. @return a pointer to a constant node. No new nodes are produced.
  82. @sideeffect None
  83. @see Cudd_bddLeq Cudd_addEvalConst
  84. */
  85. DdNode *
  86. Cudd_Eval(
  87. DdManager * dd,
  88. DdNode * f,
  89. int * inputs)
  90. {
  91. int comple;
  92. DdNode *ptr;
  93. (void) dd; /* avoid warning */
  94. comple = Cudd_IsComplement(f);
  95. ptr = Cudd_Regular(f);
  96. while (!cuddIsConstant(ptr)) {
  97. if (inputs[ptr->index] == 1) {
  98. ptr = cuddT(ptr);
  99. } else {
  100. comple ^= Cudd_IsComplement(cuddE(ptr));
  101. ptr = Cudd_Regular(cuddE(ptr));
  102. }
  103. }
  104. return(Cudd_NotCond(ptr,comple));
  105. } /* end of Cudd_Eval */
  106. /**
  107. @brief Finds a shortest path in a %DD.
  108. @details f is the %DD we want to get the shortest path for;
  109. weight\[i\] is the weight of the THEN arc coming from the node whose
  110. index is i. If weight is NULL, then unit weights are assumed for all
  111. THEN arcs. All ELSE arcs have 0 weight. If non-NULL, both weight
  112. and support should point to arrays with at least as many entries as
  113. there are variables in the manager.
  114. @return the shortest path as the %BDD of a cube.
  115. @sideeffect support contains on return the true support of f.
  116. If support is NULL on entry, then Cudd_ShortestPath does not compute
  117. the true support info. length contains the length of the path.
  118. @see Cudd_ShortestLength Cudd_LargestCube
  119. */
  120. DdNode *
  121. Cudd_ShortestPath(
  122. DdManager * manager,
  123. DdNode * f,
  124. int * weight,
  125. int * support,
  126. int * length)
  127. {
  128. DdNode *F;
  129. st_table *visited;
  130. DdNode *sol;
  131. cuddPathPair *rootPair;
  132. int complement, cost;
  133. int i;
  134. DdNode *one = DD_ONE(manager);
  135. DdNode *zero = DD_ZERO(manager);
  136. /* Initialize support. Support does not depend on variable order.
  137. ** Hence, it does not need to be reinitialized if reordering occurs.
  138. */
  139. if (support) {
  140. for (i = 0; i < manager->size; i++) {
  141. support[i] = 0;
  142. }
  143. }
  144. if (f == Cudd_Not(one) || f == zero) {
  145. *length = DD_BIGGY;
  146. return(Cudd_Not(one));
  147. }
  148. /* From this point on, a path exists. */
  149. do {
  150. manager->reordered = 0;
  151. /* Initialize visited table. */
  152. visited = st_init_table(st_ptrcmp, st_ptrhash);
  153. /* Now get the length of the shortest path(s) from f to 1. */
  154. (void) getShortest(manager, f, weight, support, visited);
  155. complement = Cudd_IsComplement(f);
  156. F = Cudd_Regular(f);
  157. if (!st_lookup(visited, F, (void **) &rootPair)) return(NULL);
  158. if (complement) {
  159. cost = rootPair->neg;
  160. } else {
  161. cost = rootPair->pos;
  162. }
  163. /* Recover an actual shortest path. */
  164. sol = getPath(manager,visited,f,weight,cost);
  165. st_foreach(visited, freePathPair, NULL);
  166. st_free_table(visited);
  167. } while (manager->reordered == 1);
  168. if (manager->errorCode == CUDD_TIMEOUT_EXPIRED && manager->timeoutHandler) {
  169. manager->timeoutHandler(manager, manager->tohArg);
  170. }
  171. *length = cost;
  172. return(sol);
  173. } /* end of Cudd_ShortestPath */
  174. /**
  175. @brief Finds a largest cube in a %DD.
  176. @details f is the %DD we want to get the largest cube for. The
  177. problem is translated into the one of finding a shortest path in f,
  178. when both THEN and ELSE arcs are assumed to have unit length. This
  179. yields a largest cube in the disjoint cover corresponding to the
  180. %DD. Therefore, it is not necessarily the largest implicant of f.
  181. @return the largest cube as a %BDD.
  182. @sideeffect The number of literals of the cube is returned in the location
  183. pointed by length if it is non-null.
  184. @see Cudd_ShortestPath
  185. */
  186. DdNode *
  187. Cudd_LargestCube(
  188. DdManager * manager,
  189. DdNode * f,
  190. int * length)
  191. {
  192. DdNode *F;
  193. st_table *visited;
  194. DdNode *sol;
  195. cuddPathPair *rootPair;
  196. int complement, cost;
  197. DdNode *one = DD_ONE(manager);
  198. DdNode *zero = DD_ZERO(manager);
  199. if (f == Cudd_Not(one) || f == zero) {
  200. if (length != NULL) {
  201. *length = DD_BIGGY;
  202. }
  203. return(Cudd_Not(one));
  204. }
  205. /* From this point on, a path exists. */
  206. do {
  207. manager->reordered = 0;
  208. /* Initialize visited table. */
  209. visited = st_init_table(st_ptrcmp, st_ptrhash);
  210. /* Now get the length of the shortest path(s) from f to 1. */
  211. (void) getLargest(manager, f, visited);
  212. complement = Cudd_IsComplement(f);
  213. F = Cudd_Regular(f);
  214. if (!st_lookup(visited, F, (void **) &rootPair)) return(NULL);
  215. if (complement) {
  216. cost = rootPair->neg;
  217. } else {
  218. cost = rootPair->pos;
  219. }
  220. /* Recover an actual shortest path. */
  221. sol = getCube(manager,visited,f,cost);
  222. st_foreach(visited, freePathPair, NULL);
  223. st_free_table(visited);
  224. } while (manager->reordered == 1);
  225. if (length != NULL) {
  226. *length = cost;
  227. }
  228. if (manager->errorCode == CUDD_TIMEOUT_EXPIRED && manager->timeoutHandler) {
  229. manager->timeoutHandler(manager, manager->tohArg);
  230. }
  231. return(sol);
  232. } /* end of Cudd_LargestCube */
  233. /**
  234. @brief Find the length of the shortest path(s) in a %DD.
  235. @details f is the %DD we want to get the shortest path for;
  236. weight\[i\] is the weight of the THEN edge coming from the node
  237. whose index is i. All ELSE edges have 0 weight.
  238. @return the length of the shortest path(s) if such a path is found;
  239. a large number if the function is identically 0, and CUDD_OUT_OF_MEM
  240. in case of failure.
  241. @sideeffect None
  242. @see Cudd_ShortestPath
  243. */
  244. int
  245. Cudd_ShortestLength(
  246. DdManager * manager,
  247. DdNode * f,
  248. int * weight)
  249. {
  250. DdNode *F;
  251. st_table *visited;
  252. cuddPathPair *my_pair;
  253. int complement, cost;
  254. DdNode *one = DD_ONE(manager);
  255. DdNode *zero = DD_ZERO(manager);
  256. if (f == Cudd_Not(one) || f == zero) {
  257. return(DD_BIGGY);
  258. }
  259. /* From this point on, a path exists. */
  260. /* Initialize visited table and support. */
  261. visited = st_init_table(st_ptrcmp, st_ptrhash);
  262. /* Now get the length of the shortest path(s) from f to 1. */
  263. (void) getShortest(manager, f, weight, NULL, visited);
  264. complement = Cudd_IsComplement(f);
  265. F = Cudd_Regular(f);
  266. if (!st_lookup(visited, F, (void **) &my_pair)) return(CUDD_OUT_OF_MEM);
  267. if (complement) {
  268. cost = my_pair->neg;
  269. } else {
  270. cost = my_pair->pos;
  271. }
  272. st_foreach(visited, freePathPair, NULL);
  273. st_free_table(visited);
  274. return(cost);
  275. } /* end of Cudd_ShortestLength */
  276. /**
  277. @brief Checks whether a %BDD is negative unate in a
  278. variable.
  279. @details Determines whether the function represented by %BDD f is
  280. negative unate (monotonic decreasing) in variable i. This function
  281. does not generate any new nodes.
  282. @return the constant one is f is unate and the (logical) constant
  283. zero if it is not.
  284. @sideeffect None
  285. @see Cudd_Increasing
  286. */
  287. DdNode *
  288. Cudd_Decreasing(
  289. DdManager * dd,
  290. DdNode * f,
  291. int i)
  292. {
  293. int topf, level;
  294. DdNode *F, *fv, *fvn, *res;
  295. DD_CTFP cacheOp;
  296. statLine(dd);
  297. #ifdef DD_DEBUG
  298. assert(0 <= i && i < dd->size);
  299. #endif
  300. F = Cudd_Regular(f);
  301. topf = cuddI(dd,F->index);
  302. /* Check terminal case. If topf > i, f does not depend on var.
  303. ** Therefore, f is unate in i.
  304. */
  305. level = (unsigned) dd->perm[i];
  306. if (topf > level) {
  307. return(DD_ONE(dd));
  308. }
  309. /* From now on, f is not constant. */
  310. /* Check cache. */
  311. cacheOp = (DD_CTFP) Cudd_Decreasing;
  312. res = cuddCacheLookup2(dd,cacheOp,f,dd->vars[i]);
  313. if (res != NULL) {
  314. return(res);
  315. }
  316. checkWhetherToGiveUp(dd);
  317. /* Compute cofactors. */
  318. fv = cuddT(F); fvn = cuddE(F);
  319. if (F != f) {
  320. fv = Cudd_Not(fv);
  321. fvn = Cudd_Not(fvn);
  322. }
  323. if (topf == level) {
  324. /* Special case: if fv is regular, fv(1,...,1) = 1;
  325. ** If in addition fvn is complemented, fvn(1,...,1) = 0.
  326. ** But then f(1,1,...,1) > f(0,1,...,1). Hence f is not
  327. ** monotonic decreasing in i.
  328. */
  329. if (!Cudd_IsComplement(fv) && Cudd_IsComplement(fvn)) {
  330. return(Cudd_Not(DD_ONE(dd)));
  331. }
  332. res = Cudd_bddLeq(dd,fv,fvn) ? DD_ONE(dd) : Cudd_Not(DD_ONE(dd));
  333. } else {
  334. res = Cudd_Decreasing(dd,fv,i);
  335. if (res == DD_ONE(dd)) {
  336. res = Cudd_Decreasing(dd,fvn,i);
  337. }
  338. }
  339. cuddCacheInsert2(dd,cacheOp,f,dd->vars[i],res);
  340. return(res);
  341. } /* end of Cudd_Decreasing */
  342. /**
  343. @brief Checks whether a %BDD is positive unate in a variable.
  344. @details Determines whether the function represented by %BDD f is
  345. positive unate (monotonic increasing) in variable i. It is based on
  346. Cudd_Decreasing and the fact that f is monotonic increasing in i if
  347. and only if its complement is monotonic decreasing in i.
  348. @sideeffect None
  349. @see Cudd_Decreasing
  350. */
  351. DdNode *
  352. Cudd_Increasing(
  353. DdManager * dd,
  354. DdNode * f,
  355. int i)
  356. {
  357. return(Cudd_Decreasing(dd,Cudd_Not(f),i));
  358. } /* end of Cudd_Increasing */
  359. /**
  360. @brief Tells whether F and G are identical wherever D is 0.
  361. @details F and G are either two ADDs or two BDDs. D is either a 0-1
  362. %ADD or a %BDD. No new nodes are created.
  363. @return 1 if F and G are equivalent, and 0 otherwise.
  364. @sideeffect None
  365. @see Cudd_bddLeqUnless
  366. */
  367. int
  368. Cudd_EquivDC(
  369. DdManager * dd,
  370. DdNode * F,
  371. DdNode * G,
  372. DdNode * D)
  373. {
  374. DdNode *tmp, *One, *Gr, *Dr;
  375. DdNode *Fv, *Fvn, *Gv, *Gvn, *Dv, *Dvn;
  376. int res;
  377. int flevel, glevel, dlevel, top;
  378. One = DD_ONE(dd);
  379. statLine(dd);
  380. /* Check terminal cases. */
  381. if (D == One || F == G) return(1);
  382. if (D == Cudd_Not(One) || D == DD_ZERO(dd) || F == Cudd_Not(G)) return(0);
  383. /* From now on, D is non-constant. */
  384. /* Normalize call to increase cache efficiency. */
  385. if (F > G) {
  386. tmp = F;
  387. F = G;
  388. G = tmp;
  389. }
  390. if (Cudd_IsComplement(F)) {
  391. F = Cudd_Not(F);
  392. G = Cudd_Not(G);
  393. }
  394. /* From now on, F is regular. */
  395. /* Check cache. */
  396. tmp = cuddCacheLookup(dd,DD_EQUIV_DC_TAG,F,G,D);
  397. if (tmp != NULL) return(tmp == One);
  398. /* Find splitting variable. */
  399. flevel = cuddI(dd,F->index);
  400. Gr = Cudd_Regular(G);
  401. glevel = cuddI(dd,Gr->index);
  402. top = ddMin(flevel,glevel);
  403. Dr = Cudd_Regular(D);
  404. dlevel = dd->perm[Dr->index];
  405. top = ddMin(top,dlevel);
  406. /* Compute cofactors. */
  407. if (top == flevel) {
  408. Fv = cuddT(F);
  409. Fvn = cuddE(F);
  410. } else {
  411. Fv = Fvn = F;
  412. }
  413. if (top == glevel) {
  414. Gv = cuddT(Gr);
  415. Gvn = cuddE(Gr);
  416. if (G != Gr) {
  417. Gv = Cudd_Not(Gv);
  418. Gvn = Cudd_Not(Gvn);
  419. }
  420. } else {
  421. Gv = Gvn = G;
  422. }
  423. if (top == dlevel) {
  424. Dv = cuddT(Dr);
  425. Dvn = cuddE(Dr);
  426. if (D != Dr) {
  427. Dv = Cudd_Not(Dv);
  428. Dvn = Cudd_Not(Dvn);
  429. }
  430. } else {
  431. Dv = Dvn = D;
  432. }
  433. /* Solve recursively. */
  434. res = Cudd_EquivDC(dd,Fv,Gv,Dv);
  435. if (res != 0) {
  436. res = Cudd_EquivDC(dd,Fvn,Gvn,Dvn);
  437. }
  438. cuddCacheInsert(dd,DD_EQUIV_DC_TAG,F,G,D,(res) ? One : Cudd_Not(One));
  439. return(res);
  440. } /* end of Cudd_EquivDC */
  441. /**
  442. @brief Tells whether f is less than of equal to G unless D is 1.
  443. @details f, g, and D are BDDs. No new nodes are created.
  444. @return 1 if f is less than of equal to G, and 0 otherwise.
  445. @sideeffect None
  446. @see Cudd_EquivDC Cudd_bddLeq Cudd_bddIteConstant
  447. */
  448. int
  449. Cudd_bddLeqUnless(
  450. DdManager *dd,
  451. DdNode *f,
  452. DdNode *g,
  453. DdNode *D)
  454. {
  455. DdNode *tmp, *One, *F, *G;
  456. DdNode *Ft, *Fe, *Gt, *Ge, *Dt, *De;
  457. int res;
  458. int flevel, glevel, dlevel, top;
  459. statLine(dd);
  460. One = DD_ONE(dd);
  461. /* Check terminal cases. */
  462. if (f == g || g == One || f == Cudd_Not(One) || D == One ||
  463. D == f || D == Cudd_Not(g)) return(1);
  464. /* Check for two-operand cases. */
  465. if (D == Cudd_Not(One) || D == g || D == Cudd_Not(f))
  466. return(Cudd_bddLeq(dd,f,g));
  467. if (g == Cudd_Not(One) || g == Cudd_Not(f)) return(Cudd_bddLeq(dd,f,D));
  468. if (f == One) return(Cudd_bddLeq(dd,Cudd_Not(g),D));
  469. /* From now on, f, g, and D are non-constant, distinct, and
  470. ** non-complementary. */
  471. /* Normalize call to increase cache efficiency. We rely on the
  472. ** fact that f <= g unless D is equivalent to not(g) <= not(f)
  473. ** unless D and to f <= D unless g. We make sure that D is
  474. ** regular, and that at most one of f and g is complemented. We also
  475. ** ensure that when two operands can be swapped, the one with the
  476. ** lowest address comes first. */
  477. if (Cudd_IsComplement(D)) {
  478. if (Cudd_IsComplement(g)) {
  479. /* Special case: if f is regular and g is complemented,
  480. ** f(1,...,1) = 1 > 0 = g(1,...,1). If D(1,...,1) = 0, return 0.
  481. */
  482. if (!Cudd_IsComplement(f)) return(0);
  483. /* !g <= D unless !f or !D <= g unless !f */
  484. tmp = D;
  485. D = Cudd_Not(f);
  486. if (g < tmp) {
  487. f = Cudd_Not(g);
  488. g = tmp;
  489. } else {
  490. f = Cudd_Not(tmp);
  491. }
  492. } else {
  493. if (Cudd_IsComplement(f)) {
  494. /* !D <= !f unless g or !D <= g unless !f */
  495. tmp = f;
  496. f = Cudd_Not(D);
  497. if (tmp < g) {
  498. D = g;
  499. g = Cudd_Not(tmp);
  500. } else {
  501. D = Cudd_Not(tmp);
  502. }
  503. } else {
  504. /* f <= D unless g or !D <= !f unless g */
  505. tmp = D;
  506. D = g;
  507. if (tmp < f) {
  508. g = Cudd_Not(f);
  509. f = Cudd_Not(tmp);
  510. } else {
  511. g = tmp;
  512. }
  513. }
  514. }
  515. } else {
  516. if (Cudd_IsComplement(g)) {
  517. if (Cudd_IsComplement(f)) {
  518. /* !g <= !f unless D or !g <= D unless !f */
  519. tmp = f;
  520. f = Cudd_Not(g);
  521. if (D < tmp) {
  522. g = D;
  523. D = Cudd_Not(tmp);
  524. } else {
  525. g = Cudd_Not(tmp);
  526. }
  527. } else {
  528. /* f <= g unless D or !g <= !f unless D */
  529. if (g < f) {
  530. tmp = g;
  531. g = Cudd_Not(f);
  532. f = Cudd_Not(tmp);
  533. }
  534. }
  535. } else {
  536. /* f <= g unless D or f <= D unless g */
  537. if (D < g) {
  538. tmp = D;
  539. D = g;
  540. g = tmp;
  541. }
  542. }
  543. }
  544. /* From now on, D is regular. */
  545. /* Check cache. */
  546. tmp = cuddCacheLookup(dd,DD_BDD_LEQ_UNLESS_TAG,f,g,D);
  547. if (tmp != NULL) return(tmp == One);
  548. /* Find splitting variable. */
  549. F = Cudd_Regular(f);
  550. flevel = dd->perm[F->index];
  551. G = Cudd_Regular(g);
  552. glevel = dd->perm[G->index];
  553. top = ddMin(flevel,glevel);
  554. dlevel = dd->perm[D->index];
  555. top = ddMin(top,dlevel);
  556. /* Compute cofactors. */
  557. if (top == flevel) {
  558. Ft = cuddT(F);
  559. Fe = cuddE(F);
  560. if (F != f) {
  561. Ft = Cudd_Not(Ft);
  562. Fe = Cudd_Not(Fe);
  563. }
  564. } else {
  565. Ft = Fe = f;
  566. }
  567. if (top == glevel) {
  568. Gt = cuddT(G);
  569. Ge = cuddE(G);
  570. if (G != g) {
  571. Gt = Cudd_Not(Gt);
  572. Ge = Cudd_Not(Ge);
  573. }
  574. } else {
  575. Gt = Ge = g;
  576. }
  577. if (top == dlevel) {
  578. Dt = cuddT(D);
  579. De = cuddE(D);
  580. } else {
  581. Dt = De = D;
  582. }
  583. /* Solve recursively. */
  584. res = Cudd_bddLeqUnless(dd,Ft,Gt,Dt);
  585. if (res != 0) {
  586. res = Cudd_bddLeqUnless(dd,Fe,Ge,De);
  587. }
  588. cuddCacheInsert(dd,DD_BDD_LEQ_UNLESS_TAG,f,g,D,Cudd_NotCond(One,!res));
  589. return(res);
  590. } /* end of Cudd_bddLeqUnless */
  591. /**
  592. @brief Compares two ADDs for equality within tolerance.
  593. @details Two ADDs are reported to be equal if the maximum difference
  594. between them (the sup norm of their difference) is less than or
  595. equal to the tolerance parameter. If parameter <code>pr</code> is
  596. positive the first failure is reported to the standard output.
  597. @return 1 if the two ADDs are equal (within tolerance); 0 otherwise.
  598. @sideeffect None
  599. */
  600. int
  601. Cudd_EqualSupNorm(
  602. DdManager * dd /**< manager */,
  603. DdNode * f /**< first %ADD */,
  604. DdNode * g /**< second %ADD */,
  605. CUDD_VALUE_TYPE tolerance /**< maximum allowed difference */,
  606. int pr /**< verbosity level */)
  607. {
  608. DdNode *fv, *fvn, *gv, *gvn, *r;
  609. int topf, topg;
  610. statLine(dd);
  611. /* Check terminal cases. */
  612. if (f == g) return(1);
  613. if (cuddIsConstant(f) && cuddIsConstant(g)) {
  614. if (ddEqualVal(cuddV(f),cuddV(g),tolerance)) {
  615. return(1);
  616. } else {
  617. if (pr>0) {
  618. (void) fprintf(dd->out,"Offending nodes:\n");
  619. (void) fprintf(dd->out,
  620. "f: address = %p\t value = %40.30f\n",
  621. (void *) f, cuddV(f));
  622. (void) fprintf(dd->out,
  623. "g: address = %p\t value = %40.30f\n",
  624. (void *) g, cuddV(g));
  625. }
  626. return(0);
  627. }
  628. }
  629. /* We only insert the result in the cache if the comparison is
  630. ** successful. Therefore, if we hit we return 1. */
  631. r = cuddCacheLookup2(dd,(DD_CTFP)Cudd_EqualSupNorm,f,g);
  632. if (r != NULL) {
  633. return(1);
  634. }
  635. /* Compute the cofactors and solve the recursive subproblems. */
  636. topf = cuddI(dd,f->index);
  637. topg = cuddI(dd,g->index);
  638. if (topf <= topg) {fv = cuddT(f); fvn = cuddE(f);} else {fv = fvn = f;}
  639. if (topg <= topf) {gv = cuddT(g); gvn = cuddE(g);} else {gv = gvn = g;}
  640. if (!Cudd_EqualSupNorm(dd,fv,gv,tolerance,pr)) return(0);
  641. if (!Cudd_EqualSupNorm(dd,fvn,gvn,tolerance,pr)) return(0);
  642. cuddCacheInsert2(dd,(DD_CTFP)Cudd_EqualSupNorm,f,g,DD_ONE(dd));
  643. return(1);
  644. } /* end of Cudd_EqualSupNorm */
  645. /**Function********************************************************************
  646. Synopsis [Compares two ADDs for equality within tolerance.]
  647. Description [Same as Cudd_EqualSupNorm but tests for max _relative_ difference
  648. i.e. (f-g/f)<e instead of (f-g)<e ]
  649. SideEffects [None]
  650. SeeAlso []
  651. ******************************************************************************/
  652. int
  653. Cudd_EqualSupNormRel(
  654. DdManager * dd /* manager */,
  655. DdNode * f /* first ADD */,
  656. DdNode * g /* second ADD */,
  657. CUDD_VALUE_TYPE tolerance /* maximum allowed difference */,
  658. int pr /* verbosity level */)
  659. {
  660. DdNode *fv, *fvn, *gv, *gvn, *r;
  661. unsigned int topf, topg;
  662. statLine(dd);
  663. /* Check terminal cases. */
  664. if (f == g) return(1);
  665. if (Cudd_IsConstant(f) && Cudd_IsConstant(g)) {
  666. CUDD_VALUE_TYPE absDiff = ddAbs((cuddV(f) - cuddV(g)));
  667. if (absDiff/cuddV(f) < tolerance || absDiff < Cudd_ReadEpsilon(dd)) {
  668. return(1);
  669. } else {
  670. if (pr>0) {
  671. (void) fprintf(dd->out,"Offending nodes (wrt. precision %0.30f) with diff %0.30f:\n", Cudd_ReadEpsilon(dd), absDiff);
  672. (void) fprintf(dd->out,
  673. "f: address = %p\t value = %40.30f\n",
  674. (void *) f, cuddV(f));
  675. (void) fprintf(dd->out,
  676. "g: address = %p\t value = %40.30f\n",
  677. (void *) g, cuddV(g));
  678. }
  679. return(0);
  680. }
  681. }
  682. /* We only insert the result in the cache if the comparison is
  683. ** successful. Therefore, if we hit we return 1. */
  684. r = cuddCacheLookup2(dd,(DD_CTFP)Cudd_EqualSupNormRel,f,g);
  685. if (r != NULL) {
  686. return(1);
  687. }
  688. /* Compute the cofactors and solve the recursive subproblems. */
  689. topf = cuddI(dd,f->index);
  690. topg = cuddI(dd,g->index);
  691. if (topf <= topg) {fv = cuddT(f); fvn = cuddE(f);} else {fv = fvn = f;}
  692. if (topg <= topf) {gv = cuddT(g); gvn = cuddE(g);} else {gv = gvn = g;}
  693. if (!Cudd_EqualSupNormRel(dd,fv,gv,tolerance,pr)) return(0);
  694. if (!Cudd_EqualSupNormRel(dd,fvn,gvn,tolerance,pr)) return(0);
  695. cuddCacheInsert2(dd,(DD_CTFP)Cudd_EqualSupNormRel,f,g,DD_ONE(dd));
  696. return(1);
  697. } /* end of Cudd_EqualSupNormRel */
  698. /**
  699. @brief Expands cube to a prime implicant of f.
  700. @return the prime if successful; NULL otherwise. In particular,
  701. NULL is returned if cube is not a real cube or is not an implicant
  702. of f.
  703. @sideeffect None
  704. @see Cudd_bddMaximallyExpand
  705. */
  706. DdNode *
  707. Cudd_bddMakePrime(
  708. DdManager *dd /**< manager */,
  709. DdNode *cube /**< cube to be expanded */,
  710. DdNode *f /**< function of which the cube is to be made a prime */)
  711. {
  712. DdNode *res;
  713. if (!Cudd_bddLeq(dd,cube,f)) return(NULL);
  714. do {
  715. dd->reordered = 0;
  716. res = cuddBddMakePrime(dd,cube,f);
  717. } while (dd->reordered == 1);
  718. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  719. dd->timeoutHandler(dd, dd->tohArg);
  720. }
  721. return(res);
  722. } /* end of Cudd_bddMakePrime */
  723. /**
  724. @brief Expands lb to prime implicants of (f and ub).
  725. @details Expands lb to all prime implicants of (f and ub) that
  726. contain lb. Assumes that lb is contained in ub.
  727. @return the disjunction of the primes if lb is contained in f;
  728. returns the zero %BDD if lb is not contained in f; returns NULL in
  729. case of failure. In particular, NULL is returned if cube is not a
  730. real cube or is not an implicant of f. Returning the disjunction of
  731. all prime implicants works because the resulting function is unate.
  732. @sideeffect None
  733. @see Cudd_bddMakePrime
  734. */
  735. DdNode *
  736. Cudd_bddMaximallyExpand(
  737. DdManager *dd /**< manager */,
  738. DdNode *lb /**< cube to be expanded */,
  739. DdNode *ub /**< upper bound cube */,
  740. DdNode *f /**< function against which to expand */)
  741. {
  742. DdNode *res;
  743. if (!Cudd_bddLeq(dd,lb,ub)) return(NULL);
  744. do {
  745. dd->reordered = 0;
  746. res = ddBddMaximallyExpand(dd,lb,ub,f);
  747. } while (dd->reordered == 1);
  748. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  749. dd->timeoutHandler(dd, dd->tohArg);
  750. }
  751. return(res);
  752. } /* end of Cudd_bddMaximallyExpand */
  753. /**
  754. @brief Find a largest prime implicant of a unate function.
  755. @details The behavior is undefined if f is not unate. The third
  756. argument is used to determine whether f is unate positive
  757. (increasing) or negative (decreasing) in each of the variables in
  758. its support.
  759. @return the %BDD for the prime if succesful; NULL otherwise.
  760. @sideeffect None
  761. @see Cudd_bddMaximallyExpand
  762. */
  763. DdNode *
  764. Cudd_bddLargestPrimeUnate(
  765. DdManager *dd /**< manager */,
  766. DdNode *f /**< unate function */,
  767. DdNode *phaseBdd /**< cube of the phases */)
  768. {
  769. DdNode *res;
  770. int *phases;
  771. int retval;
  772. st_table *table;
  773. /* Extract phase vector for quick access. */
  774. phases = ALLOC(int, dd->size);
  775. if (phases == NULL) return(NULL);
  776. retval = Cudd_BddToCubeArray(dd, phaseBdd, phases);
  777. if (retval == 0) {
  778. FREE(phases);
  779. return(NULL);
  780. }
  781. do {
  782. dd->reordered = 0;
  783. table = st_init_table(st_ptrcmp,st_ptrhash);
  784. if (table == NULL) {
  785. FREE(phases);
  786. return(NULL);
  787. }
  788. (void) ddBddShortestPathUnate(dd, f, phases, table);
  789. res = ddGetLargestCubeUnate(dd, f, phases, table);
  790. st_free_table(table);
  791. } while (dd->reordered == 1);
  792. FREE(phases);
  793. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  794. dd->timeoutHandler(dd, dd->tohArg);
  795. }
  796. return(res);
  797. } /* end of Cudd_bddLargestPrimeUnate */
  798. /*---------------------------------------------------------------------------*/
  799. /* Definition of internal functions */
  800. /*---------------------------------------------------------------------------*/
  801. /**
  802. @brief Performs the recursive step of Cudd_bddMakePrime.
  803. @return the prime if successful; NULL otherwise.
  804. @sideeffect None
  805. */
  806. DdNode *
  807. cuddBddMakePrime(
  808. DdManager *dd /**< manager */,
  809. DdNode *cube /**< cube to be expanded */,
  810. DdNode *f /**< function of which the cube is to be made a prime */)
  811. {
  812. DdNode *scan;
  813. DdNode *t, *e;
  814. DdNode *res = cube;
  815. DdNode *lzero = Cudd_Not(DD_ONE(dd));
  816. Cudd_Ref(res);
  817. scan = cube;
  818. while (!Cudd_IsConstantInt(scan)) {
  819. DdNode *reg = Cudd_Regular(scan);
  820. DdNode *var = dd->vars[reg->index];
  821. DdNode *expanded = Cudd_bddExistAbstract(dd,res,var);
  822. if (expanded == NULL) {
  823. Cudd_RecursiveDeref(dd,res);
  824. return(NULL);
  825. }
  826. Cudd_Ref(expanded);
  827. if (Cudd_bddLeq(dd,expanded,f)) {
  828. Cudd_RecursiveDeref(dd,res);
  829. res = expanded;
  830. } else {
  831. Cudd_RecursiveDeref(dd,expanded);
  832. }
  833. cuddGetBranches(scan,&t,&e);
  834. if (t == lzero) {
  835. scan = e;
  836. } else if (e == lzero) {
  837. scan = t;
  838. } else {
  839. Cudd_RecursiveDeref(dd,res);
  840. return(NULL); /* cube is not a cube */
  841. }
  842. }
  843. if (scan == DD_ONE(dd)) {
  844. Cudd_Deref(res);
  845. return(res);
  846. } else {
  847. Cudd_RecursiveDeref(dd,res);
  848. return(NULL);
  849. }
  850. } /* end of cuddBddMakePrime */
  851. /*---------------------------------------------------------------------------*/
  852. /* Definition of static functions */
  853. /*---------------------------------------------------------------------------*/
  854. /**
  855. @brief Frees the entries of the visited symbol table.
  856. @return ST_CONTINUE.
  857. @sideeffect None
  858. */
  859. static enum st_retval
  860. freePathPair(
  861. void * key,
  862. void * value,
  863. void * arg)
  864. {
  865. cuddPathPair *pair = (cuddPathPair *) value;
  866. (void) key; /* avoid warning */
  867. (void) arg; /* avoid warning */
  868. FREE(pair);
  869. return(ST_CONTINUE);
  870. } /* end of freePathPair */
  871. /**
  872. @brief Finds the length of the shortest path(s) in a %DD.
  873. @details Uses a local symbol table to store the lengths for each
  874. node. Only the lengths for the regular nodes are entered in the
  875. table, because those for the complement nodes are simply obtained by
  876. swapping the two lenghts.
  877. @return a pair of lengths: the length of the shortest path to 1; and
  878. the length of the shortest path to 0. This is done so as to take
  879. complement arcs into account.
  880. @sideeffect Accumulates the support of the %DD in support.
  881. */
  882. static cuddPathPair
  883. getShortest(
  884. DdManager * dd,
  885. DdNode * root,
  886. int * cost,
  887. int * support,
  888. st_table * visited)
  889. {
  890. cuddPathPair *my_pair, res_pair, pair_T, pair_E;
  891. DdNode *my_root, *T, *E;
  892. int weight;
  893. DdNode *zero = DD_ZERO(dd);
  894. my_root = Cudd_Regular(root);
  895. if (st_lookup(visited, my_root, (void **) &my_pair)) {
  896. if (Cudd_IsComplement(root)) {
  897. res_pair.pos = my_pair->neg;
  898. res_pair.neg = my_pair->pos;
  899. } else {
  900. res_pair.pos = my_pair->pos;
  901. res_pair.neg = my_pair->neg;
  902. }
  903. return(res_pair);
  904. }
  905. /* In the case of a BDD the following test is equivalent to
  906. ** testing whether the BDD is the constant 1. This formulation,
  907. ** however, works for ADDs as well, by assuming the usual
  908. ** dichotomy of 0 and != 0.
  909. */
  910. if (cuddIsConstant(my_root)) {
  911. if (my_root != zero) {
  912. res_pair.pos = 0;
  913. res_pair.neg = DD_BIGGY;
  914. } else {
  915. res_pair.pos = DD_BIGGY;
  916. res_pair.neg = 0;
  917. }
  918. } else {
  919. T = cuddT(my_root);
  920. E = cuddE(my_root);
  921. pair_T = getShortest(dd, T, cost, support, visited);
  922. pair_E = getShortest(dd, E, cost, support, visited);
  923. weight = WEIGHT(cost, my_root->index);
  924. res_pair.pos = ddMin(pair_T.pos+weight, pair_E.pos);
  925. res_pair.neg = ddMin(pair_T.neg+weight, pair_E.neg);
  926. /* Update support. */
  927. if (support != NULL) {
  928. support[my_root->index] = 1;
  929. }
  930. }
  931. my_pair = ALLOC(cuddPathPair, 1);
  932. if (my_pair == NULL) {
  933. if (Cudd_IsComplement(root)) {
  934. int tmp = res_pair.pos;
  935. res_pair.pos = res_pair.neg;
  936. res_pair.neg = tmp;
  937. }
  938. return(res_pair);
  939. }
  940. my_pair->pos = res_pair.pos;
  941. my_pair->neg = res_pair.neg;
  942. st_insert(visited, my_root, my_pair);
  943. if (Cudd_IsComplement(root)) {
  944. res_pair.pos = my_pair->neg;
  945. res_pair.neg = my_pair->pos;
  946. } else {
  947. res_pair.pos = my_pair->pos;
  948. res_pair.neg = my_pair->neg;
  949. }
  950. return(res_pair);
  951. } /* end of getShortest */
  952. /**
  953. @brief Build a %BDD for a shortest path of f.
  954. @details Given the minimum length from the root, and the minimum
  955. lengths for each node (in visited), apply triangulation at each
  956. node. Of the two children of each node on a shortest path, at least
  957. one is on a shortest path. In case of ties the procedure chooses the
  958. THEN children.
  959. @return a pointer to the cube %BDD representing the path if
  960. successful; NULL otherwise.
  961. @sideeffect None
  962. */
  963. static DdNode *
  964. getPath(
  965. DdManager * manager,
  966. st_table * visited,
  967. DdNode * f,
  968. int * weight,
  969. int cost)
  970. {
  971. DdNode *sol, *tmp;
  972. DdNode *my_dd, *T, *E;
  973. cuddPathPair *T_pair, *E_pair;
  974. int Tcost, Ecost;
  975. int complement;
  976. my_dd = Cudd_Regular(f);
  977. complement = Cudd_IsComplement(f);
  978. sol = DD_ONE(manager);
  979. cuddRef(sol);
  980. while (!cuddIsConstant(my_dd)) {
  981. Tcost = cost - WEIGHT(weight, my_dd->index);
  982. Ecost = cost;
  983. T = cuddT(my_dd);
  984. E = cuddE(my_dd);
  985. if (complement) {T = Cudd_Not(T); E = Cudd_Not(E);}
  986. st_lookup(visited, Cudd_Regular(T), (void **) &T_pair);
  987. if ((Cudd_IsComplement(T) && T_pair->neg == Tcost) ||
  988. (!Cudd_IsComplement(T) && T_pair->pos == Tcost)) {
  989. tmp = cuddBddAndRecur(manager,manager->vars[my_dd->index],sol);
  990. if (tmp == NULL) {
  991. Cudd_RecursiveDeref(manager,sol);
  992. return(NULL);
  993. }
  994. cuddRef(tmp);
  995. Cudd_RecursiveDeref(manager,sol);
  996. sol = tmp;
  997. complement = Cudd_IsComplement(T);
  998. my_dd = Cudd_Regular(T);
  999. cost = Tcost;
  1000. continue;
  1001. }
  1002. st_lookup(visited, Cudd_Regular(E), (void **) &E_pair);
  1003. if ((Cudd_IsComplement(E) && E_pair->neg == Ecost) ||
  1004. (!Cudd_IsComplement(E) && E_pair->pos == Ecost)) {
  1005. tmp = cuddBddAndRecur(manager,Cudd_Not(manager->vars[my_dd->index]),sol);
  1006. if (tmp == NULL) {
  1007. Cudd_RecursiveDeref(manager,sol);
  1008. return(NULL);
  1009. }
  1010. cuddRef(tmp);
  1011. Cudd_RecursiveDeref(manager,sol);
  1012. sol = tmp;
  1013. complement = Cudd_IsComplement(E);
  1014. my_dd = Cudd_Regular(E);
  1015. cost = Ecost;
  1016. continue;
  1017. }
  1018. (void) fprintf(manager->err,"We shouldn't be here!!\n");
  1019. manager->errorCode = CUDD_INTERNAL_ERROR;
  1020. return(NULL);
  1021. }
  1022. cuddDeref(sol);
  1023. return(sol);
  1024. } /* end of getPath */
  1025. /**
  1026. @brief Finds the size of the largest cube(s) in a %DD.
  1027. @details This problem is translated into finding the shortest paths
  1028. from a node when both THEN and ELSE arcs have unit lengths. Uses a
  1029. local symbol table to store the lengths for each node. Only the
  1030. lengths for the regular nodes are entered in the table, because
  1031. those for the complement nodes are simply obtained by swapping the
  1032. two lenghts.
  1033. @return a pair of lengths: the length of the shortest path to 1; and
  1034. the length of the shortest path to 0. This is done so as to take
  1035. complement arcs into account.
  1036. @sideeffect none
  1037. */
  1038. static cuddPathPair
  1039. getLargest(
  1040. DdManager * dd,
  1041. DdNode * root,
  1042. st_table * visited)
  1043. {
  1044. cuddPathPair *my_pair, res_pair, pair_T, pair_E;
  1045. DdNode *my_root, *T, *E;
  1046. DdNode *zero = DD_ZERO(dd);
  1047. my_root = Cudd_Regular(root);
  1048. if (st_lookup(visited, my_root, (void **) &my_pair)) {
  1049. if (Cudd_IsComplement(root)) {
  1050. res_pair.pos = my_pair->neg;
  1051. res_pair.neg = my_pair->pos;
  1052. } else {
  1053. res_pair.pos = my_pair->pos;
  1054. res_pair.neg = my_pair->neg;
  1055. }
  1056. return(res_pair);
  1057. }
  1058. /* In the case of a BDD the following test is equivalent to
  1059. ** testing whether the BDD is the constant 1. This formulation,
  1060. ** however, works for ADDs as well, by assuming the usual
  1061. ** dichotomy of 0 and != 0.
  1062. */
  1063. if (cuddIsConstant(my_root)) {
  1064. if (my_root != zero) {
  1065. res_pair.pos = 0;
  1066. res_pair.neg = DD_BIGGY;
  1067. } else {
  1068. res_pair.pos = DD_BIGGY;
  1069. res_pair.neg = 0;
  1070. }
  1071. } else {
  1072. T = cuddT(my_root);
  1073. E = cuddE(my_root);
  1074. pair_T = getLargest(dd, T, visited);
  1075. pair_E = getLargest(dd, E, visited);
  1076. res_pair.pos = ddMin(pair_T.pos, pair_E.pos) + 1;
  1077. res_pair.neg = ddMin(pair_T.neg, pair_E.neg) + 1;
  1078. }
  1079. my_pair = ALLOC(cuddPathPair, 1);
  1080. if (my_pair == NULL) { /* simply do not cache this result */
  1081. if (Cudd_IsComplement(root)) {
  1082. int tmp = res_pair.pos;
  1083. res_pair.pos = res_pair.neg;
  1084. res_pair.neg = tmp;
  1085. }
  1086. return(res_pair);
  1087. }
  1088. my_pair->pos = res_pair.pos;
  1089. my_pair->neg = res_pair.neg;
  1090. /* Caching may fail without affecting correctness. */
  1091. st_insert(visited, my_root, my_pair);
  1092. if (Cudd_IsComplement(root)) {
  1093. res_pair.pos = my_pair->neg;
  1094. res_pair.neg = my_pair->pos;
  1095. } else {
  1096. res_pair.pos = my_pair->pos;
  1097. res_pair.neg = my_pair->neg;
  1098. }
  1099. return(res_pair);
  1100. } /* end of getLargest */
  1101. /**
  1102. @brief Build a %BDD for a largest cube of f.
  1103. @details Given the minimum length from the root, and the minimum
  1104. lengths for each node (in visited), apply triangulation at each
  1105. node. Of the two children of each node on a shortest path, at least
  1106. one is on a shortest path. In case of ties the procedure chooses the
  1107. THEN children.
  1108. @return a pointer to the cube %BDD representing the path if
  1109. successful; NULL otherwise.
  1110. @sideeffect None
  1111. */
  1112. static DdNode *
  1113. getCube(
  1114. DdManager * manager,
  1115. st_table * visited,
  1116. DdNode * f,
  1117. int cost)
  1118. {
  1119. DdNode *sol, *tmp;
  1120. DdNode *my_dd, *T, *E;
  1121. cuddPathPair *T_pair, *E_pair;
  1122. int Tcost, Ecost;
  1123. int complement;
  1124. my_dd = Cudd_Regular(f);
  1125. complement = Cudd_IsComplement(f);
  1126. sol = DD_ONE(manager);
  1127. cuddRef(sol);
  1128. while (!cuddIsConstant(my_dd)) {
  1129. Tcost = cost - 1;
  1130. Ecost = cost - 1;
  1131. T = cuddT(my_dd);
  1132. E = cuddE(my_dd);
  1133. if (complement) {T = Cudd_Not(T); E = Cudd_Not(E);}
  1134. if (!st_lookup(visited, Cudd_Regular(T), (void **)&T_pair)) return(NULL);
  1135. if ((Cudd_IsComplement(T) && T_pair->neg == Tcost) ||
  1136. (!Cudd_IsComplement(T) && T_pair->pos == Tcost)) {
  1137. tmp = cuddBddAndRecur(manager,manager->vars[my_dd->index],sol);
  1138. if (tmp == NULL) {
  1139. Cudd_RecursiveDeref(manager,sol);
  1140. return(NULL);
  1141. }
  1142. cuddRef(tmp);
  1143. Cudd_RecursiveDeref(manager,sol);
  1144. sol = tmp;
  1145. complement = Cudd_IsComplement(T);
  1146. my_dd = Cudd_Regular(T);
  1147. cost = Tcost;
  1148. continue;
  1149. }
  1150. if (!st_lookup(visited, Cudd_Regular(E), (void **)&E_pair)) return(NULL);
  1151. if ((Cudd_IsComplement(E) && E_pair->neg == Ecost) ||
  1152. (!Cudd_IsComplement(E) && E_pair->pos == Ecost)) {
  1153. tmp = cuddBddAndRecur(manager,Cudd_Not(manager->vars[my_dd->index]),sol);
  1154. if (tmp == NULL) {
  1155. Cudd_RecursiveDeref(manager,sol);
  1156. return(NULL);
  1157. }
  1158. cuddRef(tmp);
  1159. Cudd_RecursiveDeref(manager,sol);
  1160. sol = tmp;
  1161. complement = Cudd_IsComplement(E);
  1162. my_dd = Cudd_Regular(E);
  1163. cost = Ecost;
  1164. continue;
  1165. }
  1166. (void) fprintf(manager->err,"We shouldn't be here!\n");
  1167. manager->errorCode = CUDD_INTERNAL_ERROR;
  1168. return(NULL);
  1169. }
  1170. cuddDeref(sol);
  1171. return(sol);
  1172. } /* end of getCube */
  1173. /**
  1174. @brief Performs the recursive step of Cudd_bddMaximallyExpand.
  1175. @details On entry to this function, ub and lb should be different
  1176. from the zero %BDD. The function then maintains this invariant.
  1177. @return set of primes or zero %BDD if successful; NULL otherwise.
  1178. @sideeffect None
  1179. */
  1180. static DdNode *
  1181. ddBddMaximallyExpand(
  1182. DdManager *dd /**< manager */,
  1183. DdNode *lb /**< cube to be expanded */,
  1184. DdNode *ub /**< upper bound cube */,
  1185. DdNode *f /**< function against which to expand */)
  1186. {
  1187. DdNode *lone, *lzero, *lbv, *lbvn, *lbnx, *ubv, *ubvn, *fv, *fvn, *res;
  1188. DdNode *F, *UB, *LB, *t, *e;
  1189. int top, toplb, topub, topf;
  1190. unsigned int index;
  1191. statLine(dd);
  1192. /* Terminal cases. */
  1193. lone = DD_ONE(dd);
  1194. lzero = Cudd_Not(lone);
  1195. assert(ub != lzero && lb != lzero);
  1196. /** There are three major terminal cases in theory:
  1197. ** ub -> f : return ub
  1198. ** lb == f : return lb
  1199. ** not(lb -> f): return zero
  1200. ** Only the second case can be checked exactly in constant time.
  1201. ** For the others, we check for sufficient conditions.
  1202. */
  1203. if (ub == f || f == lone) return(ub);
  1204. if (lb == f) return(lb);
  1205. if (f == lzero || ub == Cudd_Not(f) || lb == lone || lb == Cudd_Not(f))
  1206. return(lzero);
  1207. if (!Cudd_IsComplement(lb) && Cudd_IsComplement(f)) return(lzero);
  1208. /* Here lb and f are not constant. */
  1209. /* Check cache. Since lb and ub are cubes, their local reference counts
  1210. ** are always 1. Hence, we only check the reference count of f.
  1211. */
  1212. F = Cudd_Regular(f);
  1213. if (F->ref != 1) {
  1214. DdNode *tmp = cuddCacheLookup(dd, DD_BDD_MAX_EXP_TAG, lb, ub, f);
  1215. if (tmp != NULL) {
  1216. return(tmp);
  1217. }
  1218. }
  1219. checkWhetherToGiveUp(dd);
  1220. /* Compute cofactors. For lb we use the non-zero one in
  1221. ** both branches of the recursion.
  1222. */
  1223. LB = Cudd_Regular(lb);
  1224. UB = Cudd_Regular(ub);
  1225. topf = dd->perm[F->index];
  1226. toplb = dd->perm[LB->index];
  1227. topub = (ub == lone) ? CUDD_CONST_INDEX : (unsigned int) dd->perm[UB->index];
  1228. assert(toplb <= topub);
  1229. top = ddMin(topf,toplb);
  1230. if (toplb == top) {
  1231. index = LB->index;
  1232. lbv = cuddT(LB);
  1233. lbvn = cuddE(LB);
  1234. if (lb != LB) {
  1235. lbv = Cudd_Not(lbv);
  1236. lbvn = Cudd_Not(lbvn);
  1237. }
  1238. if (lbv == lzero) {
  1239. lbnx = lbvn;
  1240. } else {
  1241. lbnx = lbv;
  1242. }
  1243. } else {
  1244. index = F->index;
  1245. lbnx = lbv = lbvn = lb;
  1246. }
  1247. if (topub == top) {
  1248. ubv = cuddT(UB);
  1249. ubvn = cuddE(UB);
  1250. if (ub != UB) {
  1251. ubv = Cudd_Not(ubv);
  1252. ubvn = Cudd_Not(ubvn);
  1253. }
  1254. } else {
  1255. ubv = ubvn = ub;
  1256. }
  1257. if (topf == top) {
  1258. fv = cuddT(F);
  1259. fvn = cuddE(F);
  1260. if (f != F) {
  1261. fv = Cudd_Not(fv);
  1262. fvn = Cudd_Not(fvn);
  1263. }
  1264. } else {
  1265. fv = fvn = f;
  1266. }
  1267. /* Recursive calls. */
  1268. if (ubv != lzero) {
  1269. t = ddBddMaximallyExpand(dd, lbnx, ubv, fv);
  1270. if (t == NULL) return(NULL);
  1271. } else {
  1272. assert(topub == toplb && topub == top && lbv == lzero);
  1273. t = lzero;
  1274. }
  1275. cuddRef(t);
  1276. /* If the top variable appears only in lb, the positive and negative
  1277. ** cofactors of each operand are the same. We want to avoid a
  1278. ** needless recursive call, which would force us to give up the
  1279. ** cache optimization trick based on reference counts.
  1280. */
  1281. if (ubv == ubvn && fv == fvn) {
  1282. res = t;
  1283. } else {
  1284. if (ubvn != lzero) {
  1285. e = ddBddMaximallyExpand(dd, lbnx, ubvn, fvn);
  1286. if (e == NULL) {
  1287. Cudd_IterDerefBdd(dd,t);
  1288. return(NULL);
  1289. }
  1290. } else {
  1291. assert(topub == toplb && topub == top && lbvn == lzero);
  1292. e = lzero;
  1293. }
  1294. if (t == e) {
  1295. res = t;
  1296. } else {
  1297. cuddRef(e);
  1298. if (toplb == top) {
  1299. if (lbv == lzero) {
  1300. /* Top variable appears in negative phase. */
  1301. if (t != lone) {
  1302. DdNode *newT;
  1303. if (Cudd_IsComplement(t)) {
  1304. newT = cuddUniqueInter(dd, index, Cudd_Not(t), lzero);
  1305. if (newT == NULL) {
  1306. Cudd_IterDerefBdd(dd,t);
  1307. Cudd_IterDerefBdd(dd,e);
  1308. return(NULL);
  1309. }
  1310. newT = Cudd_Not(newT);
  1311. } else {
  1312. newT = cuddUniqueInter(dd, index, t, lone);
  1313. if (newT == NULL) {
  1314. Cudd_IterDerefBdd(dd,t);
  1315. Cudd_IterDerefBdd(dd,e);
  1316. return(NULL);
  1317. }
  1318. }
  1319. cuddRef(newT);
  1320. cuddDeref(t);
  1321. t = newT;
  1322. }
  1323. } else if (lbvn == lzero) {
  1324. /* Top variable appears in positive phase. */
  1325. if (e != lone) {
  1326. DdNode *newE;
  1327. newE = cuddUniqueInter(dd, index, lone, e);
  1328. if (newE == NULL) {
  1329. Cudd_IterDerefBdd(dd,t);
  1330. Cudd_IterDerefBdd(dd,e);
  1331. return(NULL);
  1332. }
  1333. cuddRef(newE);
  1334. cuddDeref(e);
  1335. e = newE;
  1336. }
  1337. } else {
  1338. /* Not a cube. */
  1339. Cudd_IterDerefBdd(dd,t);
  1340. Cudd_IterDerefBdd(dd,e);
  1341. return(NULL);
  1342. }
  1343. }
  1344. /* Combine results. */
  1345. res = cuddBddAndRecur(dd, t, e);
  1346. if (res == NULL) {
  1347. Cudd_IterDerefBdd(dd,t);
  1348. Cudd_IterDerefBdd(dd,e);
  1349. return(NULL);
  1350. }
  1351. cuddRef(res);
  1352. Cudd_IterDerefBdd(dd,t);
  1353. Cudd_IterDerefBdd(dd,e);
  1354. }
  1355. }
  1356. /* Cache result and return. */
  1357. if (F->ref != 1) {
  1358. cuddCacheInsert(dd, DD_BDD_MAX_EXP_TAG, lb, ub, f, res);
  1359. }
  1360. cuddDeref(res);
  1361. return(res);
  1362. } /* end of ddBddMaximallyExpand */
  1363. /**
  1364. @brief Performs shortest path computation on a unate function.
  1365. @details This function is based on the observation that in the %BDD
  1366. of a unate function no node except the constant is reachable from
  1367. the root via paths of different parity.
  1368. @return the length of the shortest path to one if successful;
  1369. CUDD_OUT_OF_MEM otherwise.
  1370. @sideeffect None
  1371. @see getShortest
  1372. */
  1373. static int
  1374. ddBddShortestPathUnate(
  1375. DdManager *dd,
  1376. DdNode *f,
  1377. int *phases,
  1378. st_table *table)
  1379. {
  1380. int positive, l, lT, lE;
  1381. DdNode *lone = DD_ONE(dd);
  1382. DdNode *lzero = Cudd_Not(lone);
  1383. DdNode *F, *fv, *fvn;
  1384. if (st_lookup_int(table, f, &l)) {
  1385. return(l);
  1386. }
  1387. if (f == lone) {
  1388. l = 0;
  1389. } else if (f == lzero) {
  1390. l = DD_BIGGY;
  1391. } else {
  1392. F = Cudd_Regular(f);
  1393. fv = cuddT(F);
  1394. fvn = cuddE(F);
  1395. if (f != F) {
  1396. fv = Cudd_Not(fv);
  1397. fvn = Cudd_Not(fvn);
  1398. }
  1399. lT = ddBddShortestPathUnate(dd, fv, phases, table);
  1400. lE = ddBddShortestPathUnate(dd, fvn, phases, table);
  1401. positive = phases[F->index];
  1402. l = positive ? ddMin(lT+1, lE) : ddMin(lT, lE+1);
  1403. }
  1404. if (st_insert(table, f, (void *)(ptrint) l) == ST_OUT_OF_MEM) {
  1405. return(CUDD_OUT_OF_MEM);
  1406. }
  1407. return(l);
  1408. } /* end of ddShortestPathUnate */
  1409. /**
  1410. @brief Extracts largest prime of a unate function.
  1411. @return the %BDD of the prime if successful; NULL otherwise.
  1412. @sideeffect None
  1413. @see getPath
  1414. */
  1415. static DdNode *
  1416. ddGetLargestCubeUnate(
  1417. DdManager *dd,
  1418. DdNode *f,
  1419. int *phases,
  1420. st_table *table)
  1421. {
  1422. DdNode *res, *scan;
  1423. int cost;
  1424. res = DD_ONE(dd);
  1425. cuddRef(res);
  1426. scan = f;
  1427. st_lookup_int(table, scan, &cost);
  1428. while (!Cudd_IsConstantInt(scan)) {
  1429. int Pcost, Ncost, Tcost;
  1430. DdNode *tmp, *T, *E;
  1431. DdNode *rscan = Cudd_Regular(scan);
  1432. unsigned int index = rscan->index;
  1433. assert(phases[index] == 0 || phases[index] == 1);
  1434. int positive = phases[index] == 1;
  1435. Pcost = positive ? cost - 1 : cost;
  1436. Ncost = positive ? cost : cost - 1;
  1437. T = cuddT(rscan);
  1438. E = cuddE(rscan);
  1439. if (rscan != scan) {
  1440. T = Cudd_Not(T);
  1441. E = Cudd_Not(E);
  1442. }
  1443. tmp = res;
  1444. st_lookup_int(table, T, &Tcost);
  1445. if (Tcost == Pcost) {
  1446. cost = Pcost;
  1447. scan = T;
  1448. if (positive) {
  1449. tmp = cuddBddAndRecur(dd, dd->vars[index], res);
  1450. }
  1451. } else {
  1452. cost = Ncost;
  1453. scan = E;
  1454. if (!positive) {
  1455. tmp = cuddBddAndRecur(dd, Cudd_Not(dd->vars[index]), res);
  1456. }
  1457. }
  1458. if (tmp == NULL) {
  1459. Cudd_IterDerefBdd(dd, res);
  1460. return(NULL);
  1461. }
  1462. cuddRef(tmp);
  1463. Cudd_IterDerefBdd(dd, res);
  1464. res = tmp;
  1465. }
  1466. cuddDeref(res);
  1467. return(res);
  1468. } /* end of ddGetLargestCubeUnate */