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.

1703 lines
44 KiB

3 months ago
  1. /**
  2. @file
  3. @ingroup cudd
  4. @brief Functional composition and variable permutation of DDs.
  5. @details The permutation functions use a local cache because the
  6. results to be remembered depend on the permutation being applied.
  7. Since the permutation is just an array, it cannot be stored in the
  8. global cache. There are different procedured for BDDs and ADDs. This
  9. is because bddPermuteRecur uses cuddBddIteRecur. If this were
  10. changed, the procedures could be merged.
  11. @author Fabio Somenzi and Kavita Ravi
  12. @copyright@parblock
  13. Copyright (c) 1995-2015, Regents of the University of Colorado
  14. All rights reserved.
  15. Redistribution and use in source and binary forms, with or without
  16. modification, are permitted provided that the following conditions
  17. are met:
  18. Redistributions of source code must retain the above copyright
  19. notice, this list of conditions and the following disclaimer.
  20. Redistributions in binary form must reproduce the above copyright
  21. notice, this list of conditions and the following disclaimer in the
  22. documentation and/or other materials provided with the distribution.
  23. Neither the name of the University of Colorado nor the names of its
  24. contributors may be used to endorse or promote products derived from
  25. this software without specific prior written permission.
  26. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  27. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  28. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  29. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  30. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  31. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  32. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  33. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  34. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  35. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  36. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37. POSSIBILITY OF SUCH DAMAGE.
  38. @endparblock
  39. */
  40. #include "util.h"
  41. #include "cuddInt.h"
  42. /*---------------------------------------------------------------------------*/
  43. /* Constant declarations */
  44. /*---------------------------------------------------------------------------*/
  45. /*---------------------------------------------------------------------------*/
  46. /* Stucture declarations */
  47. /*---------------------------------------------------------------------------*/
  48. /*---------------------------------------------------------------------------*/
  49. /* Type declarations */
  50. /*---------------------------------------------------------------------------*/
  51. /*---------------------------------------------------------------------------*/
  52. /* Variable declarations */
  53. /*---------------------------------------------------------------------------*/
  54. /*---------------------------------------------------------------------------*/
  55. /* Macro declarations */
  56. /*---------------------------------------------------------------------------*/
  57. /** \cond */
  58. /*---------------------------------------------------------------------------*/
  59. /* Static function prototypes */
  60. /*---------------------------------------------------------------------------*/
  61. static DdNode * cuddAddPermuteRecur (DdManager *manager, DdHashTable *table, DdNode *node, int *permut);
  62. static DdNode * cuddBddPermuteRecur (DdManager *manager, DdHashTable *table, DdNode *node, int *permut);
  63. static DdNode * cuddBddVarMapRecur (DdManager *manager, DdNode *f);
  64. static DdNode * cuddAddVectorComposeRecur (DdManager *dd, DdHashTable *table, DdNode *f, DdNode **vector, int deepest);
  65. static DdNode * cuddAddNonSimComposeRecur (DdManager *dd, DdNode *f, DdNode **vector, DdNode *key, DdNode *cube, int lastsub);
  66. static DdNode * cuddBddVectorComposeRecur (DdManager *dd, DdHashTable *table, DdNode *f, DdNode **vector, int deepest);
  67. static int ddIsIthAddVar (DdManager *dd, DdNode *f, unsigned int i);
  68. static DdNode * cuddAddGeneralVectorComposeRecur (DdManager *dd, DdHashTable *table, DdNode *f, DdNode **vectorOn, DdNode **vectorOff, int deepest);
  69. static int ddIsIthAddVarPair (DdManager *dd, DdNode *f, DdNode *g, unsigned int i);
  70. /** \endcond */
  71. /*---------------------------------------------------------------------------*/
  72. /* Definition of exported functions */
  73. /*---------------------------------------------------------------------------*/
  74. /**
  75. @brief Substitutes g for x_v in the %BDD for f.
  76. @details v is the index of the variable to be substituted.
  77. Cudd_bddCompose passes the corresponding projection function to the
  78. recursive procedure, so that the cache may be used.
  79. @return the composed %BDD if successful; NULL otherwise.
  80. @sideeffect None
  81. @see Cudd_addCompose
  82. */
  83. DdNode *
  84. Cudd_bddCompose(
  85. DdManager * dd,
  86. DdNode * f,
  87. DdNode * g,
  88. int v)
  89. {
  90. DdNode *proj, *res;
  91. /* Sanity check. */
  92. if (v < 0 || v >= dd->size) return(NULL);
  93. proj = dd->vars[v];
  94. do {
  95. dd->reordered = 0;
  96. res = cuddBddComposeRecur(dd,f,g,proj);
  97. } while (dd->reordered == 1);
  98. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  99. dd->timeoutHandler(dd, dd->tohArg);
  100. }
  101. return(res);
  102. } /* end of Cudd_bddCompose */
  103. /**
  104. @brief Substitutes g for x_v in the %ADD for f.
  105. @details v is the index of the variable to be substituted. g must be
  106. a 0-1 %ADD. Cudd_bddCompose passes the corresponding projection
  107. function to the recursive procedure, so that the cache may be used.
  108. @return the composed %ADD if successful; NULL otherwise.
  109. @sideeffect None
  110. @see Cudd_bddCompose
  111. */
  112. DdNode *
  113. Cudd_addCompose(
  114. DdManager * dd,
  115. DdNode * f,
  116. DdNode * g,
  117. int v)
  118. {
  119. DdNode *proj, *res;
  120. /* Sanity check. */
  121. if (v < 0 || v >= dd->size) return(NULL);
  122. proj = dd->vars[v];
  123. do {
  124. dd->reordered = 0;
  125. res = cuddAddComposeRecur(dd,f,g,proj);
  126. } while (dd->reordered == 1);
  127. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  128. dd->timeoutHandler(dd, dd->tohArg);
  129. }
  130. return(res);
  131. } /* end of Cudd_addCompose */
  132. /**
  133. @brief Permutes the variables of an %ADD.
  134. @details Given a permutation in array permut, creates a new %ADD
  135. with permuted variables. There should be an entry in array permut
  136. for each variable in the manager. The i-th entry of permut holds the
  137. index of the variable that is to substitute the i-th
  138. variable.
  139. @return a pointer to the resulting %ADD if successful; NULL
  140. otherwise.
  141. @sideeffect None
  142. @see Cudd_bddPermute Cudd_addSwapVariables
  143. */
  144. DdNode *
  145. Cudd_addPermute(
  146. DdManager * manager,
  147. DdNode * node,
  148. int * permut)
  149. {
  150. DdHashTable *table;
  151. DdNode *res;
  152. do {
  153. manager->reordered = 0;
  154. table = cuddHashTableInit(manager,1,2);
  155. if (table == NULL) return(NULL);
  156. /* Recursively solve the problem. */
  157. res = cuddAddPermuteRecur(manager,table,node,permut);
  158. if (res != NULL) cuddRef(res);
  159. /* Dispose of local cache. */
  160. cuddHashTableQuit(table);
  161. } while (manager->reordered == 1);
  162. if (res != NULL) cuddDeref(res);
  163. if (manager->errorCode == CUDD_TIMEOUT_EXPIRED && manager->timeoutHandler) {
  164. manager->timeoutHandler(manager, manager->tohArg);
  165. }
  166. return(res);
  167. } /* end of Cudd_addPermute */
  168. /**
  169. @brief Swaps two sets of variables of the same size (x and y) in
  170. the %ADD f.
  171. @details The size is given by n. The two sets of variables are
  172. assumed to be disjoint.
  173. @return a pointer to the resulting %ADD if successful; NULL
  174. otherwise.
  175. @sideeffect None
  176. @see Cudd_addPermute Cudd_bddSwapVariables
  177. */
  178. DdNode *
  179. Cudd_addSwapVariables(
  180. DdManager * dd,
  181. DdNode * f,
  182. DdNode ** x,
  183. DdNode ** y,
  184. int n)
  185. {
  186. DdNode *swapped;
  187. int i, j, k;
  188. int *permut;
  189. permut = ALLOC(int,dd->size);
  190. if (permut == NULL) {
  191. dd->errorCode = CUDD_MEMORY_OUT;
  192. return(NULL);
  193. }
  194. for (i = 0; i < dd->size; i++) permut[i] = i;
  195. for (i = 0; i < n; i++) {
  196. j = x[i]->index;
  197. k = y[i]->index;
  198. permut[j] = k;
  199. permut[k] = j;
  200. }
  201. swapped = Cudd_addPermute(dd,f,permut);
  202. FREE(permut);
  203. return(swapped);
  204. } /* end of Cudd_addSwapVariables */
  205. /**
  206. @brief Permutes the variables of a %BDD.
  207. @details Given a permutation in array permut, creates a new %BDD
  208. with permuted variables. There should be an entry in array permut
  209. for each variable in the manager. The i-th entry of permut holds the
  210. index of the variable that is to substitute the i-th variable.
  211. @return a pointer to the resulting %BDD if successful; NULL
  212. otherwise.
  213. @sideeffect None
  214. @see Cudd_addPermute Cudd_bddSwapVariables
  215. */
  216. DdNode *
  217. Cudd_bddPermute(
  218. DdManager * manager,
  219. DdNode * node,
  220. int * permut)
  221. {
  222. DdHashTable *table;
  223. DdNode *res;
  224. do {
  225. manager->reordered = 0;
  226. table = cuddHashTableInit(manager,1,2);
  227. if (table == NULL) return(NULL);
  228. res = cuddBddPermuteRecur(manager,table,node,permut);
  229. if (res != NULL) cuddRef(res);
  230. /* Dispose of local cache. */
  231. cuddHashTableQuit(table);
  232. } while (manager->reordered == 1);
  233. if (res != NULL) cuddDeref(res);
  234. if (manager->errorCode == CUDD_TIMEOUT_EXPIRED && manager->timeoutHandler) {
  235. manager->timeoutHandler(manager, manager->tohArg);
  236. }
  237. return(res);
  238. } /* end of Cudd_bddPermute */
  239. /**
  240. @brief Remaps the variables of a %BDD using the default variable map.
  241. @details A typical use of this function is to swap two sets of
  242. variables. The variable map must be registered with Cudd_SetVarMap.
  243. @return a pointer to the resulting %BDD if successful; NULL
  244. otherwise.
  245. @sideeffect None
  246. @see Cudd_bddPermute Cudd_bddSwapVariables Cudd_SetVarMap
  247. */
  248. DdNode *
  249. Cudd_bddVarMap(
  250. DdManager * manager /**< %DD manager */,
  251. DdNode * f /**< function in which to remap variables */)
  252. {
  253. DdNode *res;
  254. if (manager->map == NULL) return(NULL);
  255. do {
  256. manager->reordered = 0;
  257. res = cuddBddVarMapRecur(manager, f);
  258. } while (manager->reordered == 1);
  259. if (manager->errorCode == CUDD_TIMEOUT_EXPIRED && manager->timeoutHandler) {
  260. manager->timeoutHandler(manager, manager->tohArg);
  261. }
  262. return(res);
  263. } /* end of Cudd_bddVarMap */
  264. /**
  265. @brief Registers a variable mapping with the manager.
  266. @details Registers with the manager a variable mapping described
  267. by two sets of variables. This variable mapping is then used by
  268. functions like Cudd_bddVarMap. This function is convenient for
  269. those applications that perform the same mapping several times.
  270. However, if several different permutations are used, it may be more
  271. efficient not to rely on the registered mapping, because changing
  272. mapping causes the cache to be cleared. (The initial setting,
  273. however, does not clear the cache.) The two sets of variables (x and
  274. y) must have the same size (x and y). The size is given by n. The
  275. two sets of variables are normally disjoint, but this restriction is
  276. not imposeded by the function. When new variables are created, the
  277. map is automatically extended (each new variable maps to
  278. itself). The typical use, however, is to wait until all variables
  279. are created, and then create the map.
  280. @return 1 if the mapping is successfully registered with the
  281. manager; 0 otherwise.
  282. @sideeffect Modifies the manager. May clear the cache.
  283. @see Cudd_bddVarMap Cudd_bddPermute Cudd_bddSwapVariables
  284. */
  285. int
  286. Cudd_SetVarMap (
  287. DdManager *manager /**< %DD manager */,
  288. DdNode **x /**< first array of variables */,
  289. DdNode **y /**< second array of variables */,
  290. int n /**< length of both arrays */)
  291. {
  292. int i;
  293. if (manager->map != NULL) {
  294. cuddCacheFlush(manager);
  295. } else {
  296. manager->map = ALLOC(int,manager->maxSize);
  297. if (manager->map == NULL) {
  298. manager->errorCode = CUDD_MEMORY_OUT;
  299. return(0);
  300. }
  301. manager->memused += sizeof(int) * manager->maxSize;
  302. }
  303. /* Initialize the map to the identity. */
  304. for (i = 0; i < manager->size; i++) {
  305. manager->map[i] = i;
  306. }
  307. /* Create the map. */
  308. for (i = 0; i < n; i++) {
  309. manager->map[x[i]->index] = y[i]->index;
  310. manager->map[y[i]->index] = x[i]->index;
  311. }
  312. return(1);
  313. } /* end of Cudd_SetVarMap */
  314. /**
  315. @brief Swaps two sets of variables of the same size (x and y) in
  316. the %BDD f.
  317. @details The size is given by n. The two sets of variables are
  318. assumed to be disjoint.
  319. @return a pointer to the resulting %BDD if successful; NULL
  320. otherwise.
  321. @sideeffect None
  322. @see Cudd_bddPermute Cudd_addSwapVariables
  323. */
  324. DdNode *
  325. Cudd_bddSwapVariables(
  326. DdManager * dd,
  327. DdNode * f,
  328. DdNode ** x,
  329. DdNode ** y,
  330. int n)
  331. {
  332. DdNode *swapped;
  333. int i, j, k;
  334. int *permut;
  335. permut = ALLOC(int,dd->size);
  336. if (permut == NULL) {
  337. dd->errorCode = CUDD_MEMORY_OUT;
  338. return(NULL);
  339. }
  340. for (i = 0; i < dd->size; i++) permut[i] = i;
  341. for (i = 0; i < n; i++) {
  342. j = x[i]->index;
  343. k = y[i]->index;
  344. permut[j] = k;
  345. permut[k] = j;
  346. }
  347. swapped = Cudd_bddPermute(dd,f,permut);
  348. FREE(permut);
  349. return(swapped);
  350. } /* end of Cudd_bddSwapVariables */
  351. /**
  352. @brief Rearranges a set of variables in the %BDD B.
  353. @details The size of the set is given by n. This procedure is
  354. intended for the `randomization' of the priority functions.
  355. @return a pointer to the %BDD if successful; NULL otherwise.
  356. @sideeffect None
  357. @see Cudd_bddPermute Cudd_bddSwapVariables
  358. Cudd_Dxygtdxz Cudd_Dxygtdyz Cudd_PrioritySelect
  359. */
  360. DdNode *
  361. Cudd_bddAdjPermuteX(
  362. DdManager * dd,
  363. DdNode * B,
  364. DdNode ** x,
  365. int n)
  366. {
  367. DdNode *swapped;
  368. int i, j, k;
  369. int *permut;
  370. permut = ALLOC(int,dd->size);
  371. if (permut == NULL) {
  372. dd->errorCode = CUDD_MEMORY_OUT;
  373. return(NULL);
  374. }
  375. for (i = 0; i < dd->size; i++) permut[i] = i;
  376. for (i = 0; i < n-2; i += 3) {
  377. j = x[i]->index;
  378. k = x[i+1]->index;
  379. permut[j] = k;
  380. permut[k] = j;
  381. }
  382. swapped = Cudd_bddPermute(dd,B,permut);
  383. FREE(permut);
  384. return(swapped);
  385. } /* end of Cudd_bddAdjPermuteX */
  386. /**
  387. @brief Composes an %ADD with a vector of 0-1 ADDs.
  388. @details Given a vector of 0-1 ADDs, creates a new %ADD by
  389. substituting the 0-1 ADDs for the variables of the %ADD f. There
  390. should be an entry in vector for each variable in the manager.
  391. If no substitution is sought for a given variable, the corresponding
  392. projection function should be specified in the vector.
  393. This function implements simultaneous composition.
  394. @return a pointer to the resulting %ADD if successful; NULL
  395. otherwise.
  396. @sideeffect None
  397. @see Cudd_addNonSimCompose Cudd_addPermute Cudd_addCompose
  398. Cudd_bddVectorCompose
  399. */
  400. DdNode *
  401. Cudd_addVectorCompose(
  402. DdManager * dd,
  403. DdNode * f,
  404. DdNode ** vector)
  405. {
  406. DdHashTable *table;
  407. DdNode *res;
  408. int deepest;
  409. int i;
  410. do {
  411. dd->reordered = 0;
  412. /* Initialize local cache. */
  413. table = cuddHashTableInit(dd,1,2);
  414. if (table == NULL) return(NULL);
  415. /* Find deepest real substitution. */
  416. for (deepest = dd->size - 1; deepest >= 0; deepest--) {
  417. i = dd->invperm[deepest];
  418. if (!ddIsIthAddVar(dd,vector[i],i)) {
  419. break;
  420. }
  421. }
  422. /* Recursively solve the problem. */
  423. res = cuddAddVectorComposeRecur(dd,table,f,vector,deepest);
  424. if (res != NULL) cuddRef(res);
  425. /* Dispose of local cache. */
  426. cuddHashTableQuit(table);
  427. } while (dd->reordered == 1);
  428. if (res != NULL) cuddDeref(res);
  429. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  430. dd->timeoutHandler(dd, dd->tohArg);
  431. }
  432. return(res);
  433. } /* end of Cudd_addVectorCompose */
  434. /**
  435. @brief Composes an %ADD with a vector of ADDs.
  436. @details Given a vector of ADDs, creates a new %ADD by substituting the
  437. ADDs for the variables of the %ADD f. vectorOn contains ADDs to be substituted
  438. for the x_v and vectorOff the ADDs to be substituted for x_v'. There should
  439. be an entry in vector for each variable in the manager. If no substitution
  440. is sought for a given variable, the corresponding projection function should
  441. be specified in the vector. This function implements simultaneous
  442. composition.
  443. @return a pointer to the resulting %ADD if successful; NULL
  444. otherwise.
  445. @sideeffect None
  446. @see Cudd_addVectorCompose Cudd_addNonSimCompose Cudd_addPermute
  447. Cudd_addCompose Cudd_bddVectorCompose
  448. */
  449. DdNode *
  450. Cudd_addGeneralVectorCompose(
  451. DdManager * dd,
  452. DdNode * f,
  453. DdNode ** vectorOn,
  454. DdNode ** vectorOff)
  455. {
  456. DdHashTable *table;
  457. DdNode *res;
  458. int deepest;
  459. int i;
  460. do {
  461. dd->reordered = 0;
  462. /* Initialize local cache. */
  463. table = cuddHashTableInit(dd,1,2);
  464. if (table == NULL) return(NULL);
  465. /* Find deepest real substitution. */
  466. for (deepest = dd->size - 1; deepest >= 0; deepest--) {
  467. i = dd->invperm[deepest];
  468. if (!ddIsIthAddVarPair(dd,vectorOn[i],vectorOff[i],i)) {
  469. break;
  470. }
  471. }
  472. /* Recursively solve the problem. */
  473. res = cuddAddGeneralVectorComposeRecur(dd,table,f,vectorOn,
  474. vectorOff,deepest);
  475. if (res != NULL) cuddRef(res);
  476. /* Dispose of local cache. */
  477. cuddHashTableQuit(table);
  478. } while (dd->reordered == 1);
  479. if (res != NULL) cuddDeref(res);
  480. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  481. dd->timeoutHandler(dd, dd->tohArg);
  482. }
  483. return(res);
  484. } /* end of Cudd_addGeneralVectorCompose */
  485. /**
  486. @brief Composes an %ADD with a vector of 0-1 ADDs.
  487. @details Given a vector of 0-1 ADDs, creates a new %ADD by
  488. substituting the 0-1 ADDs for the variables of the %ADD f. There
  489. should be an entry in vector for each variable in the manager.
  490. This function implements non-simultaneous composition. If any of the
  491. functions being composed depends on any of the variables being
  492. substituted, then the result depends on the order of composition,
  493. which in turn depends on the variable order: The variables farther from
  494. the roots in the order are substituted first.
  495. @return a pointer to the resulting %ADD if successful; NULL
  496. otherwise.
  497. @sideeffect None
  498. @see Cudd_addVectorCompose Cudd_addPermute Cudd_addCompose
  499. */
  500. DdNode *
  501. Cudd_addNonSimCompose(
  502. DdManager * dd,
  503. DdNode * f,
  504. DdNode ** vector)
  505. {
  506. DdNode *cube, *key, *var, *tmp, *piece;
  507. DdNode *res;
  508. int i, lastsub;
  509. /* The cache entry for this function is composed of three parts:
  510. ** f itself, the replacement relation, and the cube of the
  511. ** variables being substituted.
  512. ** The replacement relation is the product of the terms (yi EXNOR gi).
  513. ** This apporach allows us to use the global cache for this function,
  514. ** with great savings in memory with respect to using arrays for the
  515. ** cache entries.
  516. ** First we build replacement relation and cube of substituted
  517. ** variables from the vector specifying the desired composition.
  518. */
  519. key = DD_ONE(dd);
  520. cuddRef(key);
  521. cube = DD_ONE(dd);
  522. cuddRef(cube);
  523. for (i = (int) dd->size - 1; i >= 0; i--) {
  524. if (ddIsIthAddVar(dd,vector[i],(unsigned int)i)) {
  525. continue;
  526. }
  527. var = Cudd_addIthVar(dd,i);
  528. if (var == NULL) {
  529. Cudd_RecursiveDeref(dd,key);
  530. Cudd_RecursiveDeref(dd,cube);
  531. return(NULL);
  532. }
  533. cuddRef(var);
  534. /* Update cube. */
  535. tmp = Cudd_addApply(dd,Cudd_addTimes,var,cube);
  536. if (tmp == NULL) {
  537. Cudd_RecursiveDeref(dd,key);
  538. Cudd_RecursiveDeref(dd,cube);
  539. Cudd_RecursiveDeref(dd,var);
  540. return(NULL);
  541. }
  542. cuddRef(tmp);
  543. Cudd_RecursiveDeref(dd,cube);
  544. cube = tmp;
  545. /* Update replacement relation. */
  546. piece = Cudd_addApply(dd,Cudd_addXnor,var,vector[i]);
  547. if (piece == NULL) {
  548. Cudd_RecursiveDeref(dd,key);
  549. Cudd_RecursiveDeref(dd,var);
  550. return(NULL);
  551. }
  552. cuddRef(piece);
  553. Cudd_RecursiveDeref(dd,var);
  554. tmp = Cudd_addApply(dd,Cudd_addTimes,key,piece);
  555. if (tmp == NULL) {
  556. Cudd_RecursiveDeref(dd,key);
  557. Cudd_RecursiveDeref(dd,piece);
  558. return(NULL);
  559. }
  560. cuddRef(tmp);
  561. Cudd_RecursiveDeref(dd,key);
  562. Cudd_RecursiveDeref(dd,piece);
  563. key = tmp;
  564. }
  565. /* Now try composition, until no reordering occurs. */
  566. do {
  567. /* Find real substitution with largest index. */
  568. for (lastsub = dd->size - 1; lastsub >= 0; lastsub--) {
  569. if (!ddIsIthAddVar(dd,vector[lastsub],(unsigned int)lastsub)) {
  570. break;
  571. }
  572. }
  573. /* Recursively solve the problem. */
  574. dd->reordered = 0;
  575. res = cuddAddNonSimComposeRecur(dd,f,vector,key,cube,lastsub+1);
  576. if (res != NULL) cuddRef(res);
  577. } while (dd->reordered == 1);
  578. Cudd_RecursiveDeref(dd,key);
  579. Cudd_RecursiveDeref(dd,cube);
  580. if (res != NULL) cuddDeref(res);
  581. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  582. dd->timeoutHandler(dd, dd->tohArg);
  583. }
  584. return(res);
  585. } /* end of Cudd_addNonSimCompose */
  586. /**
  587. @brief Composes a %BDD with a vector of BDDs.
  588. @details Given a vector of BDDs, creates a new %BDD by
  589. substituting the BDDs for the variables of the %BDD f. There
  590. should be an entry in vector for each variable in the manager.
  591. If no substitution is sought for a given variable, the corresponding
  592. projection function should be specified in the vector.
  593. This function implements simultaneous composition.
  594. @return a pointer to the resulting %BDD if successful; NULL
  595. otherwise.
  596. @sideeffect None
  597. @see Cudd_bddPermute Cudd_bddCompose Cudd_addVectorCompose
  598. */
  599. DdNode *
  600. Cudd_bddVectorCompose(
  601. DdManager * dd,
  602. DdNode * f,
  603. DdNode ** vector)
  604. {
  605. DdHashTable *table;
  606. DdNode *res;
  607. int deepest;
  608. int i;
  609. do {
  610. dd->reordered = 0;
  611. /* Initialize local cache. */
  612. table = cuddHashTableInit(dd,1,2);
  613. if (table == NULL) return(NULL);
  614. /* Find deepest real substitution. */
  615. for (deepest = dd->size - 1; deepest >= 0; deepest--) {
  616. i = dd->invperm[deepest];
  617. if (vector[i] != dd->vars[i]) {
  618. break;
  619. }
  620. }
  621. /* Recursively solve the problem. */
  622. res = cuddBddVectorComposeRecur(dd,table,f,vector, deepest);
  623. if (res != NULL) cuddRef(res);
  624. /* Dispose of local cache. */
  625. cuddHashTableQuit(table);
  626. } while (dd->reordered == 1);
  627. if (res != NULL) cuddDeref(res);
  628. if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
  629. dd->timeoutHandler(dd, dd->tohArg);
  630. }
  631. return(res);
  632. } /* end of Cudd_bddVectorCompose */
  633. /*---------------------------------------------------------------------------*/
  634. /* Definition of internal functions */
  635. /*---------------------------------------------------------------------------*/
  636. /**
  637. @brief Performs the recursive step of Cudd_bddCompose.
  638. @details Exploits the fact that the composition of f' with g
  639. produces the complement of the composition of f with g to better
  640. utilize the cache.
  641. @return the composed %BDD if successful; NULL otherwise.
  642. @sideeffect None
  643. @see Cudd_bddCompose
  644. */
  645. DdNode *
  646. cuddBddComposeRecur(
  647. DdManager * dd,
  648. DdNode * f,
  649. DdNode * g,
  650. DdNode * proj)
  651. {
  652. DdNode *F, *G, *f1, *f0, *g1, *g0, *r, *t, *e;
  653. unsigned int topindex;
  654. int topf, topg, v;
  655. int comple;
  656. statLine(dd);
  657. v = dd->perm[proj->index];
  658. F = Cudd_Regular(f);
  659. topf = cuddI(dd,F->index);
  660. /* Terminal case. Subsumes the test for constant f. */
  661. if (topf > v) return(f);
  662. /* We solve the problem for a regular pointer, and then complement
  663. ** the result if the pointer was originally complemented.
  664. */
  665. comple = Cudd_IsComplement(f);
  666. /* Check cache. */
  667. r = cuddCacheLookup(dd,DD_BDD_COMPOSE_RECUR_TAG,F,g,proj);
  668. if (r != NULL) {
  669. return(Cudd_NotCond(r,comple));
  670. }
  671. checkWhetherToGiveUp(dd);
  672. if (topf == v) {
  673. /* Compose. */
  674. f1 = cuddT(F);
  675. f0 = cuddE(F);
  676. r = cuddBddIteRecur(dd, g, f1, f0);
  677. if (r == NULL) return(NULL);
  678. } else {
  679. /* Compute cofactors of f and g. Remember the index of the top
  680. ** variable.
  681. */
  682. G = Cudd_Regular(g);
  683. topg = cuddI(dd,G->index);
  684. if (topf > topg) {
  685. topindex = G->index;
  686. f1 = f0 = F;
  687. } else {
  688. topindex = F->index;
  689. f1 = cuddT(F);
  690. f0 = cuddE(F);
  691. }
  692. if (topg > topf) {
  693. g1 = g0 = g;
  694. } else {
  695. g1 = cuddT(G);
  696. g0 = cuddE(G);
  697. if (g != G) {
  698. g1 = Cudd_Not(g1);
  699. g0 = Cudd_Not(g0);
  700. }
  701. }
  702. /* Recursive step. */
  703. t = cuddBddComposeRecur(dd, f1, g1, proj);
  704. if (t == NULL) return(NULL);
  705. cuddRef(t);
  706. e = cuddBddComposeRecur(dd, f0, g0, proj);
  707. if (e == NULL) {
  708. Cudd_IterDerefBdd(dd, t);
  709. return(NULL);
  710. }
  711. cuddRef(e);
  712. r = cuddBddIteRecur(dd, dd->vars[topindex], t, e);
  713. if (r == NULL) {
  714. Cudd_IterDerefBdd(dd, t);
  715. Cudd_IterDerefBdd(dd, e);
  716. return(NULL);
  717. }
  718. cuddRef(r);
  719. Cudd_IterDerefBdd(dd, t); /* t & e not necessarily part of r */
  720. Cudd_IterDerefBdd(dd, e);
  721. cuddDeref(r);
  722. }
  723. cuddCacheInsert(dd,DD_BDD_COMPOSE_RECUR_TAG,F,g,proj,r);
  724. return(Cudd_NotCond(r,comple));
  725. } /* end of cuddBddComposeRecur */
  726. /**
  727. @brief Performs the recursive step of Cudd_addCompose.
  728. @return the composed %BDD if successful; NULL otherwise.
  729. @sideeffect None
  730. @see Cudd_addCompose
  731. */
  732. DdNode *
  733. cuddAddComposeRecur(
  734. DdManager * dd,
  735. DdNode * f,
  736. DdNode * g,
  737. DdNode * proj)
  738. {
  739. DdNode *f1, *f0, *g1, *g0, *r, *t, *e;
  740. int v;
  741. int topf, topg;
  742. unsigned int topindex;
  743. statLine(dd);
  744. v = dd->perm[proj->index];
  745. topf = cuddI(dd,f->index);
  746. /* Terminal case. Subsumes the test for constant f. */
  747. if (topf > v) return(f);
  748. /* Check cache. */
  749. r = cuddCacheLookup(dd,DD_ADD_COMPOSE_RECUR_TAG,f,g,proj);
  750. if (r != NULL) {
  751. return(r);
  752. }
  753. checkWhetherToGiveUp(dd);
  754. if (topf == v) {
  755. /* Compose. */
  756. f1 = cuddT(f);
  757. f0 = cuddE(f);
  758. r = cuddAddIteRecur(dd, g, f1, f0);
  759. if (r == NULL) return(NULL);
  760. } else {
  761. /* Compute cofactors of f and g. Remember the index of the top
  762. ** variable.
  763. */
  764. topg = cuddI(dd,g->index);
  765. if (topf > topg) {
  766. topindex = g->index;
  767. f1 = f0 = f;
  768. } else {
  769. topindex = f->index;
  770. f1 = cuddT(f);
  771. f0 = cuddE(f);
  772. }
  773. if (topg > topf) {
  774. g1 = g0 = g;
  775. } else {
  776. g1 = cuddT(g);
  777. g0 = cuddE(g);
  778. }
  779. /* Recursive step. */
  780. t = cuddAddComposeRecur(dd, f1, g1, proj);
  781. if (t == NULL) return(NULL);
  782. cuddRef(t);
  783. e = cuddAddComposeRecur(dd, f0, g0, proj);
  784. if (e == NULL) {
  785. Cudd_RecursiveDeref(dd, t);
  786. return(NULL);
  787. }
  788. cuddRef(e);
  789. if (t == e) {
  790. r = t;
  791. } else {
  792. r = cuddUniqueInter(dd, (int) topindex, t, e);
  793. if (r == NULL) {
  794. Cudd_RecursiveDeref(dd, t);
  795. Cudd_RecursiveDeref(dd, e);
  796. return(NULL);
  797. }
  798. }
  799. cuddDeref(t);
  800. cuddDeref(e);
  801. }
  802. cuddCacheInsert(dd,DD_ADD_COMPOSE_RECUR_TAG,f,g,proj,r);
  803. return(r);
  804. } /* end of cuddAddComposeRecur */
  805. /*---------------------------------------------------------------------------*/
  806. /* Definition of static functions */
  807. /*---------------------------------------------------------------------------*/
  808. /**
  809. @brief Implements the recursive step of Cudd_addPermute.
  810. @details Recursively puts the %ADD in the order given in the
  811. array permut. Checks for trivial cases to terminate recursion, then
  812. splits on the children of this node. Once the solutions for the
  813. children are obtained, it puts into the current position the node
  814. from the rest of the %ADD that should be here. Then returns this %ADD.
  815. The key here is that the node being visited is NOT put in its proper
  816. place by this instance, but rather is switched when its proper
  817. position is reached in the recursion tree.<p>
  818. The DdNode * that is returned is the same %ADD as passed in as node,
  819. but in the new order.
  820. @sideeffect None
  821. @see Cudd_addPermute cuddBddPermuteRecur
  822. */
  823. static DdNode *
  824. cuddAddPermuteRecur(
  825. DdManager * manager /**< %DD manager */,
  826. DdHashTable * table /**< computed table */,
  827. DdNode * node /**< %ADD to be reordered */,
  828. int * permut /**< permutation array */)
  829. {
  830. DdNode *T,*E;
  831. DdNode *res,*var;
  832. int index;
  833. statLine(manager);
  834. /* Check for terminal case of constant node. */
  835. if (cuddIsConstant(node)) {
  836. return(node);
  837. }
  838. /* If problem already solved, look up answer and return. */
  839. if (node->ref != 1 && (res = cuddHashTableLookup1(table,node)) != NULL) {
  840. #ifdef DD_DEBUG
  841. manager->addPermuteRecurHits++;
  842. #endif
  843. return(res);
  844. }
  845. /* Split and recur on children of this node. */
  846. T = cuddAddPermuteRecur(manager,table,cuddT(node),permut);
  847. if (T == NULL) return(NULL);
  848. cuddRef(T);
  849. E = cuddAddPermuteRecur(manager,table,cuddE(node),permut);
  850. if (E == NULL) {
  851. Cudd_RecursiveDeref(manager, T);
  852. return(NULL);
  853. }
  854. cuddRef(E);
  855. /* Move variable that should be in this position to this position
  856. ** by creating a single var ADD for that variable, and calling
  857. ** cuddAddIteRecur with the T and E we just created.
  858. */
  859. index = permut[node->index];
  860. var = cuddUniqueInter(manager,index,DD_ONE(manager),DD_ZERO(manager));
  861. if (var == NULL) return(NULL);
  862. cuddRef(var);
  863. res = cuddAddIteRecur(manager,var,T,E);
  864. if (res == NULL) {
  865. Cudd_RecursiveDeref(manager,var);
  866. Cudd_RecursiveDeref(manager, T);
  867. Cudd_RecursiveDeref(manager, E);
  868. return(NULL);
  869. }
  870. cuddRef(res);
  871. Cudd_RecursiveDeref(manager,var);
  872. Cudd_RecursiveDeref(manager, T);
  873. Cudd_RecursiveDeref(manager, E);
  874. /* Do not keep the result if the reference count is only 1, since
  875. ** it will not be visited again.
  876. */
  877. if (node->ref != 1) {
  878. ptrint fanout = (ptrint) node->ref;
  879. cuddSatDec(fanout);
  880. if (!cuddHashTableInsert1(table,node,res,fanout)) {
  881. Cudd_RecursiveDeref(manager, res);
  882. return(NULL);
  883. }
  884. }
  885. cuddDeref(res);
  886. return(res);
  887. } /* end of cuddAddPermuteRecur */
  888. /**
  889. @brief Implements the recursive step of Cudd_bddPermute.
  890. @details Recursively puts the %BDD in the order given in the array permut.
  891. Checks for trivial cases to terminate recursion, then splits on the
  892. children of this node. Once the solutions for the children are
  893. obtained, it puts into the current position the node from the rest of
  894. the %BDD that should be here. Then returns this %BDD.
  895. The key here is that the node being visited is NOT put in its proper
  896. place by this instance, but rather is switched when its proper position
  897. is reached in the recursion tree.<p>
  898. The DdNode * that is returned is the same %BDD as passed in as node,
  899. but in the new order.
  900. @sideeffect None
  901. @see Cudd_bddPermute cuddAddPermuteRecur
  902. */
  903. static DdNode *
  904. cuddBddPermuteRecur(
  905. DdManager * manager /**< %DD manager */,
  906. DdHashTable * table /**< computed table */,
  907. DdNode * node /**< %BDD to be reordered */,
  908. int * permut /**< permutation array */)
  909. {
  910. DdNode *N,*T,*E;
  911. DdNode *res;
  912. int index;
  913. statLine(manager);
  914. N = Cudd_Regular(node);
  915. /* Check for terminal case of constant node. */
  916. if (cuddIsConstant(N)) {
  917. return(node);
  918. }
  919. /* If problem already solved, look up answer and return. */
  920. if (N->ref != 1 && (res = cuddHashTableLookup1(table,N)) != NULL) {
  921. #ifdef DD_DEBUG
  922. manager->bddPermuteRecurHits++;
  923. #endif
  924. return(Cudd_NotCond(res,N != node));
  925. }
  926. /* Split and recur on children of this node. */
  927. T = cuddBddPermuteRecur(manager,table,cuddT(N),permut);
  928. if (T == NULL) return(NULL);
  929. cuddRef(T);
  930. E = cuddBddPermuteRecur(manager,table,cuddE(N),permut);
  931. if (E == NULL) {
  932. Cudd_IterDerefBdd(manager, T);
  933. return(NULL);
  934. }
  935. cuddRef(E);
  936. /* Move variable that should be in this position to this position
  937. ** by retrieving the single var BDD for that variable, and calling
  938. ** cuddBddIteRecur with the T and E we just created.
  939. */
  940. index = permut[N->index];
  941. res = cuddBddIteRecur(manager,manager->vars[index],T,E);
  942. if (res == NULL) {
  943. Cudd_IterDerefBdd(manager, T);
  944. Cudd_IterDerefBdd(manager, E);
  945. return(NULL);
  946. }
  947. cuddRef(res);
  948. Cudd_IterDerefBdd(manager, T);
  949. Cudd_IterDerefBdd(manager, E);
  950. /* Do not keep the result if the reference count is only 1, since
  951. ** it will not be visited again.
  952. */
  953. if (N->ref != 1) {
  954. ptrint fanout = (ptrint) N->ref;
  955. cuddSatDec(fanout);
  956. if (!cuddHashTableInsert1(table,N,res,fanout)) {
  957. Cudd_IterDerefBdd(manager, res);
  958. return(NULL);
  959. }
  960. }
  961. cuddDeref(res);
  962. return(Cudd_NotCond(res,N != node));
  963. } /* end of cuddBddPermuteRecur */
  964. /**
  965. @brief Implements the recursive step of Cudd_bddVarMap.
  966. @return a pointer to the result if successful; NULL otherwise.
  967. @sideeffect None
  968. @see Cudd_bddVarMap
  969. */
  970. static DdNode *
  971. cuddBddVarMapRecur(
  972. DdManager *manager /**< %DD manager */,
  973. DdNode *f /**< %BDD to be remapped */)
  974. {
  975. DdNode *F, *T, *E;
  976. DdNode *res;
  977. int index;
  978. statLine(manager);
  979. F = Cudd_Regular(f);
  980. /* Check for terminal case of constant node. */
  981. if (cuddIsConstant(F)) {
  982. return(f);
  983. }
  984. /* If problem already solved, look up answer and return. */
  985. if (F->ref != 1 &&
  986. (res = cuddCacheLookup1(manager,Cudd_bddVarMap,F)) != NULL) {
  987. return(Cudd_NotCond(res,F != f));
  988. }
  989. checkWhetherToGiveUp(manager);
  990. /* Split and recur on children of this node. */
  991. T = cuddBddVarMapRecur(manager,cuddT(F));
  992. if (T == NULL) return(NULL);
  993. cuddRef(T);
  994. E = cuddBddVarMapRecur(manager,cuddE(F));
  995. if (E == NULL) {
  996. Cudd_IterDerefBdd(manager, T);
  997. return(NULL);
  998. }
  999. cuddRef(E);
  1000. /* Move variable that should be in this position to this position
  1001. ** by retrieving the single var BDD for that variable, and calling
  1002. ** cuddBddIteRecur with the T and E we just created.
  1003. */
  1004. index = manager->map[F->index];
  1005. res = cuddBddIteRecur(manager,manager->vars[index],T,E);
  1006. if (res == NULL) {
  1007. Cudd_IterDerefBdd(manager, T);
  1008. Cudd_IterDerefBdd(manager, E);
  1009. return(NULL);
  1010. }
  1011. cuddRef(res);
  1012. Cudd_IterDerefBdd(manager, T);
  1013. Cudd_IterDerefBdd(manager, E);
  1014. /* Do not keep the result if the reference count is only 1, since
  1015. ** it will not be visited again.
  1016. */
  1017. if (F->ref != 1) {
  1018. cuddCacheInsert1(manager,Cudd_bddVarMap,F,res);
  1019. }
  1020. cuddDeref(res);
  1021. return(Cudd_NotCond(res,F != f));
  1022. } /* end of cuddBddVarMapRecur */
  1023. /**
  1024. @brief Performs the recursive step of Cudd_addVectorCompose.
  1025. @sideeffect None
  1026. */
  1027. static DdNode *
  1028. cuddAddVectorComposeRecur(
  1029. DdManager * dd /**< %DD manager */,
  1030. DdHashTable * table /**< computed table */,
  1031. DdNode * f /**< %ADD in which to compose */,
  1032. DdNode ** vector /**< functions to substitute */,
  1033. int deepest /**< depth of deepest substitution */)
  1034. {
  1035. DdNode *T,*E;
  1036. DdNode *res;
  1037. statLine(dd);
  1038. /* If we are past the deepest substitution, return f. */
  1039. if (cuddI(dd,f->index) > deepest) {
  1040. return(f);
  1041. }
  1042. if ((res = cuddHashTableLookup1(table,f)) != NULL) {
  1043. #ifdef DD_DEBUG
  1044. dd->addVectorComposeHits++;
  1045. #endif
  1046. return(res);
  1047. }
  1048. /* Split and recur on children of this node. */
  1049. T = cuddAddVectorComposeRecur(dd,table,cuddT(f),vector,deepest);
  1050. if (T == NULL) return(NULL);
  1051. cuddRef(T);
  1052. E = cuddAddVectorComposeRecur(dd,table,cuddE(f),vector,deepest);
  1053. if (E == NULL) {
  1054. Cudd_RecursiveDeref(dd, T);
  1055. return(NULL);
  1056. }
  1057. cuddRef(E);
  1058. /* Retrieve the 0-1 ADD for the current top variable and call
  1059. ** cuddAddIteRecur with the T and E we just created.
  1060. */
  1061. res = cuddAddIteRecur(dd,vector[f->index],T,E);
  1062. if (res == NULL) {
  1063. Cudd_RecursiveDeref(dd, T);
  1064. Cudd_RecursiveDeref(dd, E);
  1065. return(NULL);
  1066. }
  1067. cuddRef(res);
  1068. Cudd_RecursiveDeref(dd, T);
  1069. Cudd_RecursiveDeref(dd, E);
  1070. /* Do not keep the result if the reference count is only 1, since
  1071. ** it will not be visited again
  1072. */
  1073. if (f->ref != 1) {
  1074. ptrint fanout = (ptrint) f->ref;
  1075. cuddSatDec(fanout);
  1076. if (!cuddHashTableInsert1(table,f,res,fanout)) {
  1077. Cudd_RecursiveDeref(dd, res);
  1078. return(NULL);
  1079. }
  1080. }
  1081. cuddDeref(res);
  1082. return(res);
  1083. } /* end of cuddAddVectorComposeRecur */
  1084. /**
  1085. @brief Performs the recursive step of Cudd_addGeneralVectorCompose.
  1086. @sideeffect None
  1087. */
  1088. static DdNode *
  1089. cuddAddGeneralVectorComposeRecur(
  1090. DdManager * dd /**< %DD manager */,
  1091. DdHashTable * table /**< computed table */,
  1092. DdNode * f /**< %ADD in which to compose */,
  1093. DdNode ** vectorOn /**< functions to substitute for x_i */,
  1094. DdNode ** vectorOff /**< functions to substitute for x_i' */,
  1095. int deepest /**< depth of deepest substitution */)
  1096. {
  1097. DdNode *T,*E,*t,*e;
  1098. DdNode *res;
  1099. /* If we are past the deepest substitution, return f. */
  1100. if (cuddI(dd,f->index) > deepest) {
  1101. return(f);
  1102. }
  1103. if ((res = cuddHashTableLookup1(table,f)) != NULL) {
  1104. #ifdef DD_DEBUG
  1105. dd->addGeneralVectorComposeHits++;
  1106. #endif
  1107. return(res);
  1108. }
  1109. /* Split and recur on children of this node. */
  1110. T = cuddAddGeneralVectorComposeRecur(dd,table,cuddT(f),
  1111. vectorOn,vectorOff,deepest);
  1112. if (T == NULL) return(NULL);
  1113. cuddRef(T);
  1114. E = cuddAddGeneralVectorComposeRecur(dd,table,cuddE(f),
  1115. vectorOn,vectorOff,deepest);
  1116. if (E == NULL) {
  1117. Cudd_RecursiveDeref(dd, T);
  1118. return(NULL);
  1119. }
  1120. cuddRef(E);
  1121. /* Retrieve the compose ADDs for the current top variable and call
  1122. ** cuddAddApplyRecur with the T and E we just created.
  1123. */
  1124. t = cuddAddApplyRecur(dd,Cudd_addTimes,vectorOn[f->index],T);
  1125. if (t == NULL) {
  1126. Cudd_RecursiveDeref(dd,T);
  1127. Cudd_RecursiveDeref(dd,E);
  1128. return(NULL);
  1129. }
  1130. cuddRef(t);
  1131. e = cuddAddApplyRecur(dd,Cudd_addTimes,vectorOff[f->index],E);
  1132. if (e == NULL) {
  1133. Cudd_RecursiveDeref(dd,T);
  1134. Cudd_RecursiveDeref(dd,E);
  1135. Cudd_RecursiveDeref(dd,t);
  1136. return(NULL);
  1137. }
  1138. cuddRef(e);
  1139. res = cuddAddApplyRecur(dd,Cudd_addPlus,t,e);
  1140. if (res == NULL) {
  1141. Cudd_RecursiveDeref(dd,T);
  1142. Cudd_RecursiveDeref(dd,E);
  1143. Cudd_RecursiveDeref(dd,t);
  1144. Cudd_RecursiveDeref(dd,e);
  1145. return(NULL);
  1146. }
  1147. cuddRef(res);
  1148. Cudd_RecursiveDeref(dd,T);
  1149. Cudd_RecursiveDeref(dd,E);
  1150. Cudd_RecursiveDeref(dd,t);
  1151. Cudd_RecursiveDeref(dd,e);
  1152. /* Do not keep the result if the reference count is only 1, since
  1153. ** it will not be visited again
  1154. */
  1155. if (f->ref != 1) {
  1156. ptrint fanout = (ptrint) f->ref;
  1157. cuddSatDec(fanout);
  1158. if (!cuddHashTableInsert1(table,f,res,fanout)) {
  1159. Cudd_RecursiveDeref(dd, res);
  1160. return(NULL);
  1161. }
  1162. }
  1163. cuddDeref(res);
  1164. return(res);
  1165. } /* end of cuddAddGeneralVectorComposeRecur */
  1166. /**
  1167. @brief Performs the recursive step of Cudd_addNonSimCompose.
  1168. @sideeffect None
  1169. */
  1170. static DdNode *
  1171. cuddAddNonSimComposeRecur(
  1172. DdManager * dd,
  1173. DdNode * f,
  1174. DdNode ** vector,
  1175. DdNode * key,
  1176. DdNode * cube,
  1177. int lastsub)
  1178. {
  1179. DdNode *f1, *f0, *key1, *key0, *cube1, *var;
  1180. DdNode *T,*E;
  1181. DdNode *r;
  1182. int top, topf, topk, topc;
  1183. unsigned int index;
  1184. int i;
  1185. DdNode **vect1;
  1186. DdNode **vect0;
  1187. statLine(dd);
  1188. /* If we are past the deepest substitution, return f. */
  1189. if (cube == DD_ONE(dd) || cuddIsConstant(f)) {
  1190. return(f);
  1191. }
  1192. /* If problem already solved, look up answer and return. */
  1193. r = cuddCacheLookup(dd,DD_ADD_NON_SIM_COMPOSE_TAG,f,key,cube);
  1194. if (r != NULL) {
  1195. return(r);
  1196. }
  1197. checkWhetherToGiveUp(dd);
  1198. /* Find top variable. we just need to look at f, key, and cube,
  1199. ** because all the varibles in the gi are in key.
  1200. */
  1201. topf = cuddI(dd,f->index);
  1202. topk = cuddI(dd,key->index);
  1203. top = ddMin(topf,topk);
  1204. topc = cuddI(dd,cube->index);
  1205. top = ddMin(top,topc);
  1206. index = dd->invperm[top];
  1207. /* Compute the cofactors. */
  1208. if (topf == top) {
  1209. f1 = cuddT(f);
  1210. f0 = cuddE(f);
  1211. } else {
  1212. f1 = f0 = f;
  1213. }
  1214. if (topc == top) {
  1215. cube1 = cuddT(cube);
  1216. /* We want to eliminate vector[index] from key. Otherwise
  1217. ** cache performance is severely affected. Hence we
  1218. ** existentially quantify the variable with index "index" from key.
  1219. */
  1220. var = Cudd_addIthVar(dd, (int) index);
  1221. if (var == NULL) {
  1222. return(NULL);
  1223. }
  1224. cuddRef(var);
  1225. key1 = cuddAddExistAbstractRecur(dd, key, var);
  1226. if (key1 == NULL) {
  1227. Cudd_RecursiveDeref(dd,var);
  1228. return(NULL);
  1229. }
  1230. cuddRef(key1);
  1231. Cudd_RecursiveDeref(dd,var);
  1232. key0 = key1;
  1233. } else {
  1234. cube1 = cube;
  1235. if (topk == top) {
  1236. key1 = cuddT(key);
  1237. key0 = cuddE(key);
  1238. } else {
  1239. key1 = key0 = key;
  1240. }
  1241. cuddRef(key1);
  1242. }
  1243. /* Allocate two new vectors for the cofactors of vector. */
  1244. vect1 = ALLOC(DdNode *,lastsub);
  1245. if (vect1 == NULL) {
  1246. dd->errorCode = CUDD_MEMORY_OUT;
  1247. Cudd_RecursiveDeref(dd,key1);
  1248. return(NULL);
  1249. }
  1250. vect0 = ALLOC(DdNode *,lastsub);
  1251. if (vect0 == NULL) {
  1252. dd->errorCode = CUDD_MEMORY_OUT;
  1253. Cudd_RecursiveDeref(dd,key1);
  1254. FREE(vect1);
  1255. return(NULL);
  1256. }
  1257. /* Cofactor the gi. Eliminate vect1[index] and vect0[index], because
  1258. ** we do not need them.
  1259. */
  1260. for (i = 0; i < lastsub; i++) {
  1261. DdNode *gi = vector[i];
  1262. if (gi == NULL) {
  1263. vect1[i] = vect0[i] = NULL;
  1264. } else if (gi->index == index) {
  1265. vect1[i] = cuddT(gi);
  1266. vect0[i] = cuddE(gi);
  1267. } else {
  1268. vect1[i] = vect0[i] = gi;
  1269. }
  1270. }
  1271. vect1[index] = vect0[index] = NULL;
  1272. /* Recur on children. */
  1273. T = cuddAddNonSimComposeRecur(dd,f1,vect1,key1,cube1,lastsub);
  1274. FREE(vect1);
  1275. if (T == NULL) {
  1276. Cudd_RecursiveDeref(dd,key1);
  1277. FREE(vect0);
  1278. return(NULL);
  1279. }
  1280. cuddRef(T);
  1281. E = cuddAddNonSimComposeRecur(dd,f0,vect0,key0,cube1,lastsub);
  1282. FREE(vect0);
  1283. if (E == NULL) {
  1284. Cudd_RecursiveDeref(dd,key1);
  1285. Cudd_RecursiveDeref(dd,T);
  1286. return(NULL);
  1287. }
  1288. cuddRef(E);
  1289. Cudd_RecursiveDeref(dd,key1);
  1290. /* Retrieve the 0-1 ADD for the current top variable from vector,
  1291. ** and call cuddAddIteRecur with the T and E we just created.
  1292. */
  1293. r = cuddAddIteRecur(dd,vector[index],T,E);
  1294. if (r == NULL) {
  1295. Cudd_RecursiveDeref(dd,T);
  1296. Cudd_RecursiveDeref(dd,E);
  1297. return(NULL);
  1298. }
  1299. cuddRef(r);
  1300. Cudd_RecursiveDeref(dd,T);
  1301. Cudd_RecursiveDeref(dd,E);
  1302. cuddDeref(r);
  1303. /* Store answer to trim recursion. */
  1304. cuddCacheInsert(dd,DD_ADD_NON_SIM_COMPOSE_TAG,f,key,cube,r);
  1305. return(r);
  1306. } /* end of cuddAddNonSimComposeRecur */
  1307. /**
  1308. @brief Performs the recursive step of Cudd_bddVectorCompose.
  1309. @sideeffect None
  1310. */
  1311. static DdNode *
  1312. cuddBddVectorComposeRecur(
  1313. DdManager * dd /**< %DD manager */,
  1314. DdHashTable * table /**< computed table */,
  1315. DdNode * f /**< %BDD in which to compose */,
  1316. DdNode ** vector /**< functions to be composed */,
  1317. int deepest /**< depth of the deepest substitution */)
  1318. {
  1319. DdNode *F,*T,*E;
  1320. DdNode *res;
  1321. statLine(dd);
  1322. F = Cudd_Regular(f);
  1323. /* If we are past the deepest substitution, return f. */
  1324. if (cuddI(dd,F->index) > deepest) {
  1325. return(f);
  1326. }
  1327. /* If problem already solved, look up answer and return. */
  1328. if ((res = cuddHashTableLookup1(table,F)) != NULL) {
  1329. #ifdef DD_DEBUG
  1330. dd->bddVectorComposeHits++;
  1331. #endif
  1332. return(Cudd_NotCond(res,F != f));
  1333. }
  1334. /* Split and recur on children of this node. */
  1335. T = cuddBddVectorComposeRecur(dd,table,cuddT(F),vector, deepest);
  1336. if (T == NULL) return(NULL);
  1337. cuddRef(T);
  1338. E = cuddBddVectorComposeRecur(dd,table,cuddE(F),vector, deepest);
  1339. if (E == NULL) {
  1340. Cudd_IterDerefBdd(dd, T);
  1341. return(NULL);
  1342. }
  1343. cuddRef(E);
  1344. /* Call cuddBddIteRecur with the BDD that replaces the current top
  1345. ** variable and the T and E we just created.
  1346. */
  1347. res = cuddBddIteRecur(dd,vector[F->index],T,E);
  1348. if (res == NULL) {
  1349. Cudd_IterDerefBdd(dd, T);
  1350. Cudd_IterDerefBdd(dd, E);
  1351. return(NULL);
  1352. }
  1353. cuddRef(res);
  1354. Cudd_IterDerefBdd(dd, T);
  1355. Cudd_IterDerefBdd(dd, E);
  1356. /* Do not keep the result if the reference count is only 1, since
  1357. ** it will not be visited again.
  1358. */
  1359. if (F->ref != 1) {
  1360. ptrint fanout = (ptrint) F->ref;
  1361. cuddSatDec(fanout);
  1362. if (!cuddHashTableInsert1(table,F,res,fanout)) {
  1363. Cudd_IterDerefBdd(dd, res);
  1364. return(NULL);
  1365. }
  1366. }
  1367. cuddDeref(res);
  1368. return(Cudd_NotCond(res,F != f));
  1369. } /* end of cuddBddVectorComposeRecur */
  1370. /**
  1371. @brief Comparison of a function to the i-th %ADD variable.
  1372. @return 1 if the function is the i-th %ADD variable; 0 otherwise.
  1373. @sideeffect None
  1374. */
  1375. static int
  1376. ddIsIthAddVar(
  1377. DdManager * dd,
  1378. DdNode * f,
  1379. unsigned int i)
  1380. {
  1381. return(f->index == i && cuddT(f) == DD_ONE(dd) && cuddE(f) == DD_ZERO(dd));
  1382. } /* end of ddIsIthAddVar */
  1383. /**
  1384. @brief Comparison of a pair of functions to the i-th %ADD variable.
  1385. @return 1 if the functions are the i-th %ADD variable and its
  1386. complement; 0 otherwise.
  1387. @sideeffect None
  1388. */
  1389. static int
  1390. ddIsIthAddVarPair(
  1391. DdManager * dd,
  1392. DdNode * f,
  1393. DdNode * g,
  1394. unsigned int i)
  1395. {
  1396. return(f->index == i && g->index == i &&
  1397. cuddT(f) == DD_ONE(dd) && cuddE(f) == DD_ZERO(dd) &&
  1398. cuddT(g) == DD_ZERO(dd) && cuddE(g) == DD_ONE(dd));
  1399. } /* end of ddIsIthAddVarPair */