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.

497 lines
14 KiB

3 months ago
  1. /**
  2. @file
  3. @ingroup cudd
  4. @brief Cofactoring functions.
  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 int ddVarsAreSymmetricBefore(DdManager * dd, DdNode * f, DdNode * var1, DdNode * var2);
  56. static int ddVarsAreSymmetricBetween(DdManager * dd, DdNode * f1, DdNode * f0, DdNode * var2);
  57. /** \endcond */
  58. /*---------------------------------------------------------------------------*/
  59. /* Definition of exported functions */
  60. /*---------------------------------------------------------------------------*/
  61. /**
  62. @brief Computes the cofactor of f with respect to g.
  63. @details g must be the %BDD or the %ADD of a cube.
  64. @return a pointer to the cofactor if successful; NULL otherwise.
  65. @sideeffect None
  66. @see Cudd_bddConstrain Cudd_bddRestrict
  67. */
  68. DdNode *
  69. Cudd_Cofactor(
  70. DdManager * dd,
  71. DdNode * f,
  72. DdNode * g)
  73. {
  74. DdNode *res,*zero;
  75. zero = Cudd_Not(DD_ONE(dd));
  76. if (g == zero || g == DD_ZERO(dd)) {
  77. (void) fprintf(dd->err,"Cudd_Cofactor: Invalid restriction 1\n");
  78. dd->errorCode = CUDD_INVALID_ARG;
  79. return(NULL);
  80. }
  81. do {
  82. dd->reordered = 0;
  83. res = cuddCofactorRecur(dd,f,g);
  84. } while (dd->reordered == 1);
  85. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  86. dd->timeoutHandler(dd, dd->tohArg);
  87. }
  88. return(res);
  89. } /* end of Cudd_Cofactor */
  90. /**
  91. @brief Checks whether g is the %BDD of a cube.
  92. @details The constant 1 is a valid cube, but all other constant
  93. functions cause cuddCheckCube to return 0.
  94. @return 1 in case of success; 0 otherwise.
  95. @sideeffect None
  96. */
  97. int
  98. Cudd_CheckCube(
  99. DdManager * dd,
  100. DdNode * g)
  101. {
  102. DdNode *g1,*g0,*one,*zero;
  103. one = DD_ONE(dd);
  104. if (g == one) return(1);
  105. if (Cudd_Not(g) == one) return(0);
  106. zero = Cudd_Not(one);
  107. cuddGetBranches(g,&g1,&g0);
  108. if (g0 == zero) {
  109. return(Cudd_CheckCube(dd, g1));
  110. }
  111. if (g1 == zero) {
  112. return(Cudd_CheckCube(dd, g0));
  113. }
  114. return(0);
  115. } /* end of Cudd_CheckCube */
  116. /**
  117. @brief Checks whether two variables are symmetric in a BDD.
  118. @return 1 if the variables are symmetric; 0 if they are not.
  119. @details No nodes are built during the check.
  120. @sideeffect None
  121. */
  122. int
  123. Cudd_VarsAreSymmetric(
  124. DdManager * dd /**< manager */,
  125. DdNode * f /**< BDD whose variables are tested */,
  126. int index1 /**< index of first variable */,
  127. int index2 /**< index of second variable */)
  128. {
  129. DdNode *var1, *var2;
  130. if (index1 == index2) /* trivial case: symmetry is reflexive */
  131. return(1);
  132. if (index1 >= dd->size) {
  133. if (index2 >= dd->size) {
  134. return(1); /* f depends on neither variable */
  135. } else {
  136. /* f does not depend on var1; check whether it depends on var2 */
  137. var2 = dd->vars[index2];
  138. return ddVarsAreSymmetricBetween(dd, f, f, var2);
  139. }
  140. } else if (index2 >= dd->size) {
  141. /* f does not depend on var2; check whether it depends on var1 */
  142. var1 = dd->vars[index1];
  143. return ddVarsAreSymmetricBetween(dd, f, f, var1);
  144. }
  145. /* Make sure index1 denotes the variable currently closer to the root. */
  146. if (dd->perm[index1] < dd->perm[index2]) {
  147. var1 = dd->vars[index1];
  148. var2 = dd->vars[index2];
  149. } else {
  150. var1 = dd->vars[index2];
  151. var2 = dd->vars[index1];
  152. }
  153. return ddVarsAreSymmetricBefore(dd, f, var1, var2);
  154. } /* end of Cudd_VarsAreSymmetric */
  155. /*---------------------------------------------------------------------------*/
  156. /* Definition of internal functions */
  157. /*---------------------------------------------------------------------------*/
  158. /**
  159. @brief Computes the children of g.
  160. @sideeffect None
  161. */
  162. void
  163. cuddGetBranches(
  164. DdNode * g,
  165. DdNode ** g1,
  166. DdNode ** g0)
  167. {
  168. DdNode *G = Cudd_Regular(g);
  169. *g1 = cuddT(G);
  170. *g0 = cuddE(G);
  171. if (Cudd_IsComplement(g)) {
  172. *g1 = Cudd_Not(*g1);
  173. *g0 = Cudd_Not(*g0);
  174. }
  175. } /* end of cuddGetBranches */
  176. /**
  177. @brief Performs the recursive step of Cudd_Cofactor.
  178. @return a pointer to the cofactor if successful; NULL otherwise.
  179. @sideeffect None
  180. @see Cudd_Cofactor
  181. */
  182. DdNode *
  183. cuddCofactorRecur(
  184. DdManager * dd,
  185. DdNode * f,
  186. DdNode * g)
  187. {
  188. DdNode *one,*zero,*F,*G,*g1,*g0,*f1,*f0,*t,*e,*r;
  189. int topf,topg;
  190. int comple;
  191. statLine(dd);
  192. F = Cudd_Regular(f);
  193. if (cuddIsConstant(F)) return(f);
  194. one = DD_ONE(dd);
  195. /* The invariant g != 0 is true on entry to this procedure and is
  196. ** recursively maintained by it. Therefore it suffices to test g
  197. ** against one to make sure it is not constant.
  198. */
  199. if (g == one) return(f);
  200. /* From now on, f and g are known not to be constants. */
  201. comple = f != F;
  202. r = cuddCacheLookup2(dd,Cudd_Cofactor,F,g);
  203. if (r != NULL) {
  204. return(Cudd_NotCond(r,comple));
  205. }
  206. checkWhetherToGiveUp(dd);
  207. topf = dd->perm[F->index];
  208. G = Cudd_Regular(g);
  209. topg = dd->perm[G->index];
  210. /* We take the cofactors of F because we are going to rely on
  211. ** the fact that the cofactors of the complement are the complements
  212. ** of the cofactors to better utilize the cache. Variable comple
  213. ** remembers whether we have to complement the result or not.
  214. */
  215. if (topf <= topg) {
  216. f1 = cuddT(F); f0 = cuddE(F);
  217. } else {
  218. f1 = f0 = F;
  219. }
  220. if (topg <= topf) {
  221. g1 = cuddT(G); g0 = cuddE(G);
  222. if (g != G) { g1 = Cudd_Not(g1); g0 = Cudd_Not(g0); }
  223. } else {
  224. g1 = g0 = g;
  225. }
  226. zero = Cudd_Not(one);
  227. if (topf >= topg) {
  228. if (g0 == zero || g0 == DD_ZERO(dd)) {
  229. r = cuddCofactorRecur(dd, f1, g1);
  230. } else if (g1 == zero || g1 == DD_ZERO(dd)) {
  231. r = cuddCofactorRecur(dd, f0, g0);
  232. } else {
  233. (void) fprintf(dd->err,
  234. "Cudd_Cofactor: Invalid restriction 2\n");
  235. dd->errorCode = CUDD_INVALID_ARG;
  236. return(NULL);
  237. }
  238. if (r == NULL) return(NULL);
  239. } else /* if (topf < topg) */ {
  240. t = cuddCofactorRecur(dd, f1, g);
  241. if (t == NULL) return(NULL);
  242. cuddRef(t);
  243. e = cuddCofactorRecur(dd, f0, g);
  244. if (e == NULL) {
  245. Cudd_RecursiveDeref(dd, t);
  246. return(NULL);
  247. }
  248. cuddRef(e);
  249. if (t == e) {
  250. r = t;
  251. } else if (Cudd_IsComplement(t)) {
  252. r = cuddUniqueInter(dd,(int)F->index,Cudd_Not(t),Cudd_Not(e));
  253. if (r != NULL)
  254. r = Cudd_Not(r);
  255. } else {
  256. r = cuddUniqueInter(dd,(int)F->index,t,e);
  257. }
  258. if (r == NULL) {
  259. Cudd_RecursiveDeref(dd ,e);
  260. Cudd_RecursiveDeref(dd ,t);
  261. return(NULL);
  262. }
  263. cuddDeref(t);
  264. cuddDeref(e);
  265. }
  266. cuddCacheInsert2(dd,Cudd_Cofactor,F,g,r);
  267. return(Cudd_NotCond(r,comple));
  268. } /* end of cuddCofactorRecur */
  269. /*---------------------------------------------------------------------------*/
  270. /* Definition of static functions */
  271. /*---------------------------------------------------------------------------*/
  272. /**
  273. @brief Implements the upper recursive step of Cudd_VarsAreSymmetric().
  274. @details The assumption is made that the level of index1 is less
  275. than the level of index2.
  276. @return 1 if the variables are symmetric for the given function;
  277. 0 if they are not.
  278. @see Cudd_VarsAreSymmetric ddVarsAreSymmetricBetween
  279. */
  280. static int
  281. ddVarsAreSymmetricBefore(
  282. DdManager * dd,
  283. DdNode * f,
  284. DdNode * var1,
  285. DdNode * var2)
  286. {
  287. DdNode *F, *ft, *fe, *r;
  288. int top, res, level1;
  289. statLine(dd);
  290. F = Cudd_Regular(f);
  291. if (cuddIsConstant(F)) /* f depends on neither variable */
  292. return(1);
  293. top = dd->perm[F->index];
  294. if (top > dd->perm[var2->index])
  295. return(1); /* f depends on neither variable */
  296. /* Cache lookup. We take advantage of the observation that
  297. * var1 and var2 are symmetric in f iff they are symmetric in
  298. * the complement of f. */
  299. r = cuddCacheLookup(dd, DD_VARS_SYMM_BEFORE_TAG, F, var1, var2);
  300. if (r != NULL) {
  301. return(r == DD_ONE(dd) ? 1 : 0);
  302. }
  303. level1 = dd->perm[var1->index];
  304. if (top > level1)
  305. /* Check whether f1 depends on the variable currently at level2. */
  306. return ddVarsAreSymmetricBetween(dd, f, f, var2);
  307. ft = cuddT(F);
  308. fe = cuddE(F);
  309. if (F != f) {
  310. ft = Cudd_Not(ft);
  311. fe = Cudd_Not(fe);
  312. }
  313. if (top < level1) {
  314. res = ddVarsAreSymmetricBefore(dd, ft, var1, var2);
  315. if (res)
  316. res = ddVarsAreSymmetricBefore(dd, fe, var1, var2);
  317. } else {
  318. res = ddVarsAreSymmetricBetween(dd, ft, fe, var2);
  319. }
  320. /* Cache insertion. */
  321. cuddCacheInsert(dd, DD_VARS_SYMM_BEFORE_TAG, F, var1, var2,
  322. res ? DD_ONE(dd) : Cudd_Not(DD_ONE(dd)));
  323. return(res);
  324. } /* end of ddVarsAreSymmetricBefore */
  325. /**
  326. @brief Implements the lower recursive step of Cudd_VarsAreSymmetric().
  327. @return 1 if the negative cofactor of the first argument w.r.t. the variable
  328. currently at level2 is the same as the positive cofactor of the second
  329. argument; 0 if the two cofactors are not the same.
  330. @see Cudd_VarsAreSymmetric ddVarsAreSymmetricBefore
  331. */
  332. static int
  333. ddVarsAreSymmetricBetween(
  334. DdManager * dd,
  335. DdNode * f1,
  336. DdNode * f0,
  337. DdNode * var2)
  338. {
  339. DdNode *F1, *F0, *f1t, *f1e, *f0t, *f0e, *r;
  340. int topf1, topf0, top, res;
  341. int level2 = dd->perm[var2->index];
  342. statLine(dd);
  343. F1 = Cudd_Regular(f1);
  344. F0 = Cudd_Regular(f0);
  345. if (cuddIsConstant(F1) && cuddIsConstant(F0))
  346. return f1 == f0;
  347. /* Here we know that one of f1 and f0 is not constant. Hence the
  348. * least index is that of a variable. */
  349. if (cuddIsConstant(F1))
  350. topf1 = CUDD_CONST_INDEX;
  351. else
  352. topf1 = dd->perm[F1->index];
  353. if (cuddIsConstant(F0))
  354. topf0 = CUDD_CONST_INDEX;
  355. else
  356. topf0 = dd->perm[F0->index];
  357. if (topf0 > level2 && topf1 > level2)
  358. return(f1 == f0);
  359. /* Cache lookup. */
  360. r = cuddCacheLookup(dd, DD_VARS_SYMM_BETWEEN_TAG, f1, f0, var2);
  361. if (r != NULL) {
  362. return(r == DD_ONE(dd) ? 1 : 0);
  363. }
  364. /* Compute cofactors and find top level. */
  365. if (topf1 <= topf0) {
  366. top = topf1;
  367. f1t = cuddT(F1);
  368. f1e = cuddE(F1);
  369. if (F1 != f1) {
  370. f1t = Cudd_Not(f1t);
  371. f1e = Cudd_Not(f1e);
  372. }
  373. } else {
  374. top = topf0;
  375. f1t = f1e = f1;
  376. }
  377. if (topf0 <= topf1) {
  378. f0t = cuddT(F0);
  379. f0e = cuddE(F0);
  380. if (F0 != f0) {
  381. f0t = Cudd_Not(f0t);
  382. f0e = Cudd_Not(f0e);
  383. }
  384. } else {
  385. f0t = f0e = f0;
  386. }
  387. if (top < level2) {
  388. res = ddVarsAreSymmetricBetween(dd, f1t, f0t, var2);
  389. if (res)
  390. res = ddVarsAreSymmetricBetween(dd, f1e, f0e, var2);
  391. } else {
  392. assert(top == level2);
  393. res = f1e == f0t;
  394. }
  395. /* Cache insertion. */
  396. cuddCacheInsert(dd, DD_VARS_SYMM_BETWEEN_TAG, f1, f0, var2,
  397. res ? DD_ONE(dd) : Cudd_Not(DD_ONE(dd)));
  398. return(res);
  399. } /* end of ddVarsAreSymmetricBetween */