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.

1297 lines
34 KiB

2 months ago
  1. /**
  2. @file
  3. @ingroup cudd
  4. @brief Functions for %BDD and %ADD reduction by linear
  5. transformations.
  6. @author Fabio Somenzi
  7. @copyright@parblock
  8. Copyright (c) 1995-2015, Regents of the University of Colorado
  9. All rights reserved.
  10. Redistribution and use in source and binary forms, with or without
  11. modification, are permitted provided that the following conditions
  12. are met:
  13. Redistributions of source code must retain the above copyright
  14. notice, this list of conditions and the following disclaimer.
  15. Redistributions in binary form must reproduce the above copyright
  16. notice, this list of conditions and the following disclaimer in the
  17. documentation and/or other materials provided with the distribution.
  18. Neither the name of the University of Colorado nor the names of its
  19. contributors may be used to endorse or promote products derived from
  20. this software without specific prior written permission.
  21. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  28. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  29. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. POSSIBILITY OF SUCH DAMAGE.
  33. @endparblock
  34. */
  35. #include "util.h"
  36. #include "cuddInt.h"
  37. /*---------------------------------------------------------------------------*/
  38. /* Constant declarations */
  39. /*---------------------------------------------------------------------------*/
  40. #define CUDD_SWAP_MOVE 0
  41. #define CUDD_LINEAR_TRANSFORM_MOVE 1
  42. #define CUDD_INVERSE_TRANSFORM_MOVE 2
  43. #if SIZEOF_VOID_P == 8
  44. #define BPL 64
  45. #define LOGBPL 6
  46. #else
  47. #define BPL 32
  48. #define LOGBPL 5
  49. #endif
  50. /*---------------------------------------------------------------------------*/
  51. /* Stucture declarations */
  52. /*---------------------------------------------------------------------------*/
  53. /*---------------------------------------------------------------------------*/
  54. /* Type declarations */
  55. /*---------------------------------------------------------------------------*/
  56. /*---------------------------------------------------------------------------*/
  57. /* Variable declarations */
  58. /*---------------------------------------------------------------------------*/
  59. /*---------------------------------------------------------------------------*/
  60. /* Macro declarations */
  61. /*---------------------------------------------------------------------------*/
  62. /** \cond */
  63. /*---------------------------------------------------------------------------*/
  64. /* Static function prototypes */
  65. /*---------------------------------------------------------------------------*/
  66. static int ddLinearUniqueCompare (void const *ptrX, void const *ptrY);
  67. static int ddLinearAndSiftingAux (DdManager *table, int x, int xLow, int xHigh);
  68. static Move * ddLinearAndSiftingUp (DdManager *table, int y, int xLow, Move *prevMoves);
  69. static Move * ddLinearAndSiftingDown (DdManager *table, int x, int xHigh, Move *prevMoves);
  70. static int ddLinearAndSiftingBackward (DdManager *table, int size, Move *moves);
  71. static Move* ddUndoMoves (DdManager *table, Move *moves);
  72. static void cuddXorLinear (DdManager *table, int x, int y);
  73. /** \endcond */
  74. /*---------------------------------------------------------------------------*/
  75. /* Definition of exported functions */
  76. /*---------------------------------------------------------------------------*/
  77. /**
  78. @brief Prints the linear transform matrix.
  79. @return 1 in case of success; 0 otherwise.
  80. @sideeffect none
  81. */
  82. int
  83. Cudd_PrintLinear(
  84. DdManager * table)
  85. {
  86. int i,j,k;
  87. int retval;
  88. int nvars = table->linearSize;
  89. int wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
  90. ptruint word;
  91. for (i = 0; i < nvars; i++) {
  92. for (j = 0; j < wordsPerRow; j++) {
  93. word = table->linear[i*wordsPerRow + j];
  94. for (k = 0; k < BPL; k++) {
  95. retval = fprintf(table->out,"%" PRIuPTR,word & (ptruint) 1);
  96. if (retval == 0) return(0);
  97. word >>= 1;
  98. }
  99. }
  100. retval = fprintf(table->out,"\n");
  101. if (retval == 0) return(0);
  102. }
  103. return(1);
  104. } /* end of Cudd_PrintLinear */
  105. /**
  106. @brief Reads an entry of the linear transform matrix.
  107. @sideeffect none
  108. */
  109. int
  110. Cudd_ReadLinear(
  111. DdManager * table /**< CUDD manager */,
  112. int x /**< row index */,
  113. int y /**< column index */)
  114. {
  115. int nvars = table->size;
  116. ptruint wordsPerRow = ((ptruint)(nvars - 1) >> LOGBPL) + 1;
  117. ptruint word;
  118. int bit;
  119. int result;
  120. assert(table->size == table->linearSize);
  121. word = wordsPerRow * (ptruint) x + ((ptruint) y >> LOGBPL);
  122. bit = y & (BPL-1);
  123. result = (int) ((table->linear[word] >> bit) & (ptruint) 1);
  124. return(result);
  125. } /* end of Cudd_ReadLinear */
  126. /*---------------------------------------------------------------------------*/
  127. /* Definition of internal functions */
  128. /*---------------------------------------------------------------------------*/
  129. /**
  130. @brief %BDD reduction based on combination of sifting and linear
  131. transformations.
  132. @details Assumes that no dead nodes are present.
  133. <ol>
  134. <li> Order all the variables according to the number of entries
  135. in each unique table.
  136. <li> Sift the variable up and down, remembering each time the
  137. total size of the %DD heap. At each position, linear transformation
  138. of the two adjacent variables is tried and is accepted if it reduces
  139. the size of the %DD.
  140. <li> Select the best permutation.
  141. <li> Repeat 3 and 4 for all variables.
  142. </ol>
  143. @return 1 if successful; 0 otherwise.
  144. @sideeffect None
  145. */
  146. int
  147. cuddLinearAndSifting(
  148. DdManager * table,
  149. int lower,
  150. int upper)
  151. {
  152. int i;
  153. IndexKey *var;
  154. int size;
  155. int x;
  156. int result;
  157. #ifdef DD_STATS
  158. int previousSize;
  159. #endif
  160. #ifdef DD_STATS
  161. table->totalNumberLinearTr = 0;
  162. #endif
  163. size = table->size;
  164. var = NULL;
  165. if (table->linear == NULL) {
  166. result = cuddInitLinear(table);
  167. if (result == 0) goto cuddLinearAndSiftingOutOfMem;
  168. #if 0
  169. (void) fprintf(table->out,"\n");
  170. result = Cudd_PrintLinear(table);
  171. if (result == 0) goto cuddLinearAndSiftingOutOfMem;
  172. #endif
  173. } else if (table->size != table->linearSize) {
  174. result = cuddResizeLinear(table);
  175. if (result == 0) goto cuddLinearAndSiftingOutOfMem;
  176. #if 0
  177. (void) fprintf(table->out,"\n");
  178. result = Cudd_PrintLinear(table);
  179. if (result == 0) goto cuddLinearAndSiftingOutOfMem;
  180. #endif
  181. }
  182. /* Find order in which to sift variables. */
  183. var = ALLOC(IndexKey,size);
  184. if (var == NULL) {
  185. table->errorCode = CUDD_MEMORY_OUT;
  186. goto cuddLinearAndSiftingOutOfMem;
  187. }
  188. for (i = 0; i < size; i++) {
  189. x = table->perm[i];
  190. var[i].index = i;
  191. var[i].keys = table->subtables[x].keys;
  192. }
  193. util_qsort(var,size,sizeof(IndexKey),ddLinearUniqueCompare);
  194. /* Now sift. */
  195. for (i = 0; i < ddMin(table->siftMaxVar,size); i++) {
  196. x = table->perm[var[i].index];
  197. if (x < lower || x > upper) continue;
  198. #ifdef DD_STATS
  199. previousSize = (int) (table->keys - table->isolated);
  200. #endif
  201. result = ddLinearAndSiftingAux(table,x,lower,upper);
  202. if (!result) goto cuddLinearAndSiftingOutOfMem;
  203. #ifdef DD_STATS
  204. if (table->keys < (unsigned) previousSize + table->isolated) {
  205. (void) fprintf(table->out,"-");
  206. } else if (table->keys > (unsigned) previousSize + table->isolated) {
  207. (void) fprintf(table->out,"+"); /* should never happen */
  208. (void) fprintf(table->out,"\nSize increased from %d to %u while sifting variable %d\n", previousSize, table->keys - table->isolated, var[i].index);
  209. } else {
  210. (void) fprintf(table->out,"=");
  211. }
  212. fflush(table->out);
  213. #endif
  214. #ifdef DD_DEBUG
  215. (void) Cudd_DebugCheck(table);
  216. #endif
  217. }
  218. FREE(var);
  219. #ifdef DD_STATS
  220. (void) fprintf(table->out,"\n#:L_LINSIFT %8d: linear trans.",
  221. table->totalNumberLinearTr);
  222. #endif
  223. return(1);
  224. cuddLinearAndSiftingOutOfMem:
  225. if (var != NULL) FREE(var);
  226. return(0);
  227. } /* end of cuddLinearAndSifting */
  228. /**
  229. @brief Linearly combines two adjacent variables.
  230. @details Specifically, replaces the top variable with the exclusive
  231. nor of the two variables. It assumes that no dead nodes are present
  232. on entry to this procedure. The procedure then guarantees that no
  233. dead nodes will be present when it terminates. cuddLinearInPlace
  234. assumes that x &lt; y.
  235. @return the number of keys in the table if successful; 0 otherwise.
  236. @sideeffect The two subtables corrresponding to variables x and y are
  237. modified. The global counters of the unique table are also affected.
  238. @see cuddSwapInPlace
  239. */
  240. int
  241. cuddLinearInPlace(
  242. DdManager * table,
  243. int x,
  244. int y)
  245. {
  246. DdNodePtr *xlist, *ylist;
  247. int xindex, yindex;
  248. int xslots, yslots;
  249. int xshift, yshift;
  250. #if defined(DD_COUNT) || defined(DD_DEBUG)
  251. int oldxkeys;
  252. #endif
  253. int oldykeys;
  254. int newxkeys, newykeys;
  255. int comple, newcomplement;
  256. int i;
  257. int posn;
  258. int isolated;
  259. DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10,*newf1,*newf0;
  260. DdNode *g,*next,*last=NULL;
  261. DdNodePtr *previousP;
  262. DdNode *tmp;
  263. DdNode *sentinel = &(table->sentinel);
  264. #ifdef DD_DEBUG
  265. int count, idcheck;
  266. #endif
  267. #ifdef DD_DEBUG
  268. assert(x < y);
  269. assert(cuddNextHigh(table,x) == y);
  270. assert(table->subtables[x].keys != 0);
  271. assert(table->subtables[y].keys != 0);
  272. assert(table->subtables[x].dead == 0);
  273. assert(table->subtables[y].dead == 0);
  274. #endif
  275. xindex = table->invperm[x];
  276. yindex = table->invperm[y];
  277. if (cuddTestInteract(table,xindex,yindex)) {
  278. #ifdef DD_STATS
  279. table->totalNumberLinearTr++;
  280. #endif
  281. /* Get parameters of x subtable. */
  282. xlist = table->subtables[x].nodelist;
  283. #if defined(DD_COUNT) || defined(DD_DEBUG)
  284. oldxkeys = table->subtables[x].keys;
  285. #endif
  286. xslots = table->subtables[x].slots;
  287. xshift = table->subtables[x].shift;
  288. /* Get parameters of y subtable. */
  289. ylist = table->subtables[y].nodelist;
  290. oldykeys = table->subtables[y].keys;
  291. yslots = table->subtables[y].slots;
  292. yshift = table->subtables[y].shift;
  293. newxkeys = 0;
  294. newykeys = oldykeys;
  295. /* Check whether the two projection functions involved in this
  296. ** swap are isolated. At the end, we'll be able to tell how many
  297. ** isolated projection functions are there by checking only these
  298. ** two functions again. This is done to eliminate the isolated
  299. ** projection functions from the node count.
  300. */
  301. isolated = - ((table->vars[xindex]->ref == 1) +
  302. (table->vars[yindex]->ref == 1));
  303. /* The nodes in the x layer are put in a chain.
  304. ** The chain is handled as a FIFO; g points to the beginning and
  305. ** last points to the end.
  306. */
  307. g = NULL;
  308. #ifdef DD_DEBUG
  309. last = NULL;
  310. #endif
  311. for (i = 0; i < xslots; i++) {
  312. f = xlist[i];
  313. if (f == sentinel) continue;
  314. xlist[i] = sentinel;
  315. if (g == NULL) {
  316. g = f;
  317. } else {
  318. last->next = f;
  319. }
  320. while ((next = f->next) != sentinel) {
  321. f = next;
  322. } /* while there are elements in the collision chain */
  323. last = f;
  324. } /* for each slot of the x subtable */
  325. #ifdef DD_DEBUG
  326. /* last is always assigned in the for loop because there is at
  327. ** least one key */
  328. assert(last != NULL);
  329. #endif
  330. last->next = NULL;
  331. #ifdef DD_COUNT
  332. table->swapSteps += oldxkeys;
  333. #endif
  334. /* Take care of the x nodes that must be re-expressed.
  335. ** They form a linked list pointed by g.
  336. */
  337. f = g;
  338. while (f != NULL) {
  339. next = f->next;
  340. /* Find f1, f0, f11, f10, f01, f00. */
  341. f1 = cuddT(f);
  342. #ifdef DD_DEBUG
  343. assert(!(Cudd_IsComplement(f1)));
  344. #endif
  345. if ((int) f1->index == yindex) {
  346. f11 = cuddT(f1); f10 = cuddE(f1);
  347. } else {
  348. f11 = f10 = f1;
  349. }
  350. #ifdef DD_DEBUG
  351. assert(!(Cudd_IsComplement(f11)));
  352. #endif
  353. f0 = cuddE(f);
  354. comple = Cudd_IsComplement(f0);
  355. f0 = Cudd_Regular(f0);
  356. if ((int) f0->index == yindex) {
  357. f01 = cuddT(f0); f00 = cuddE(f0);
  358. } else {
  359. f01 = f00 = f0;
  360. }
  361. if (comple) {
  362. f01 = Cudd_Not(f01);
  363. f00 = Cudd_Not(f00);
  364. }
  365. /* Decrease ref count of f1. */
  366. cuddSatDec(f1->ref);
  367. /* Create the new T child. */
  368. if (f11 == f00) {
  369. newf1 = f11;
  370. cuddSatInc(newf1->ref);
  371. } else {
  372. /* Check ylist for triple (yindex,f11,f00). */
  373. posn = ddHash(f11, f00, yshift);
  374. /* For each element newf1 in collision list ylist[posn]. */
  375. previousP = &(ylist[posn]);
  376. newf1 = *previousP;
  377. while (f11 < cuddT(newf1)) {
  378. previousP = &(newf1->next);
  379. newf1 = *previousP;
  380. }
  381. while (f11 == cuddT(newf1) && f00 < cuddE(newf1)) {
  382. previousP = &(newf1->next);
  383. newf1 = *previousP;
  384. }
  385. if (cuddT(newf1) == f11 && cuddE(newf1) == f00) {
  386. cuddSatInc(newf1->ref);
  387. } else { /* no match */
  388. newf1 = cuddDynamicAllocNode(table);
  389. if (newf1 == NULL)
  390. goto cuddLinearOutOfMem;
  391. newf1->index = yindex; newf1->ref = 1;
  392. cuddT(newf1) = f11;
  393. cuddE(newf1) = f00;
  394. /* Insert newf1 in the collision list ylist[posn];
  395. ** increase the ref counts of f11 and f00.
  396. */
  397. newykeys++;
  398. newf1->next = *previousP;
  399. *previousP = newf1;
  400. cuddSatInc(f11->ref);
  401. tmp = Cudd_Regular(f00);
  402. cuddSatInc(tmp->ref);
  403. }
  404. }
  405. cuddT(f) = newf1;
  406. #ifdef DD_DEBUG
  407. assert(!(Cudd_IsComplement(newf1)));
  408. #endif
  409. /* Do the same for f0, keeping complement dots into account. */
  410. /* decrease ref count of f0 */
  411. tmp = Cudd_Regular(f0);
  412. cuddSatDec(tmp->ref);
  413. /* create the new E child */
  414. if (f01 == f10) {
  415. newf0 = f01;
  416. tmp = Cudd_Regular(newf0);
  417. cuddSatInc(tmp->ref);
  418. } else {
  419. /* make sure f01 is regular */
  420. newcomplement = Cudd_IsComplement(f01);
  421. if (newcomplement) {
  422. f01 = Cudd_Not(f01);
  423. f10 = Cudd_Not(f10);
  424. }
  425. /* Check ylist for triple (yindex,f01,f10). */
  426. posn = ddHash(f01, f10, yshift);
  427. /* For each element newf0 in collision list ylist[posn]. */
  428. previousP = &(ylist[posn]);
  429. newf0 = *previousP;
  430. while (f01 < cuddT(newf0)) {
  431. previousP = &(newf0->next);
  432. newf0 = *previousP;
  433. }
  434. while (f01 == cuddT(newf0) && f10 < cuddE(newf0)) {
  435. previousP = &(newf0->next);
  436. newf0 = *previousP;
  437. }
  438. if (cuddT(newf0) == f01 && cuddE(newf0) == f10) {
  439. cuddSatInc(newf0->ref);
  440. } else { /* no match */
  441. newf0 = cuddDynamicAllocNode(table);
  442. if (newf0 == NULL)
  443. goto cuddLinearOutOfMem;
  444. newf0->index = yindex; newf0->ref = 1;
  445. cuddT(newf0) = f01;
  446. cuddE(newf0) = f10;
  447. /* Insert newf0 in the collision list ylist[posn];
  448. ** increase the ref counts of f01 and f10.
  449. */
  450. newykeys++;
  451. newf0->next = *previousP;
  452. *previousP = newf0;
  453. cuddSatInc(f01->ref);
  454. tmp = Cudd_Regular(f10);
  455. cuddSatInc(tmp->ref);
  456. }
  457. if (newcomplement) {
  458. newf0 = Cudd_Not(newf0);
  459. }
  460. }
  461. cuddE(f) = newf0;
  462. /* Re-insert the modified f in xlist.
  463. ** The modified f does not already exists in xlist.
  464. ** (Because of the uniqueness of the cofactors.)
  465. */
  466. posn = ddHash(newf1, newf0, xshift);
  467. newxkeys++;
  468. previousP = &(xlist[posn]);
  469. tmp = *previousP;
  470. while (newf1 < cuddT(tmp)) {
  471. previousP = &(tmp->next);
  472. tmp = *previousP;
  473. }
  474. while (newf1 == cuddT(tmp) && newf0 < cuddE(tmp)) {
  475. previousP = &(tmp->next);
  476. tmp = *previousP;
  477. }
  478. f->next = *previousP;
  479. *previousP = f;
  480. f = next;
  481. } /* while f != NULL */
  482. /* GC the y layer. */
  483. /* For each node f in ylist. */
  484. for (i = 0; i < yslots; i++) {
  485. previousP = &(ylist[i]);
  486. f = *previousP;
  487. while (f != sentinel) {
  488. next = f->next;
  489. if (f->ref == 0) {
  490. tmp = cuddT(f);
  491. cuddSatDec(tmp->ref);
  492. tmp = Cudd_Regular(cuddE(f));
  493. cuddSatDec(tmp->ref);
  494. cuddDeallocNode(table,f);
  495. newykeys--;
  496. } else {
  497. *previousP = f;
  498. previousP = &(f->next);
  499. }
  500. f = next;
  501. } /* while f */
  502. *previousP = sentinel;
  503. } /* for every collision list */
  504. #ifdef DD_DEBUG
  505. #if 0
  506. (void) fprintf(table->out,"Linearly combining %d and %d\n",x,y);
  507. #endif
  508. count = 0;
  509. idcheck = 0;
  510. for (i = 0; i < yslots; i++) {
  511. f = ylist[i];
  512. while (f != sentinel) {
  513. count++;
  514. if (f->index != (DdHalfWord) yindex)
  515. idcheck++;
  516. f = f->next;
  517. }
  518. }
  519. if (count != newykeys) {
  520. fprintf(table->err,"Error in finding newykeys\toldykeys = %d\tnewykeys = %d\tactual = %d\n",oldykeys,newykeys,count);
  521. }
  522. if (idcheck != 0)
  523. fprintf(table->err,"Error in id's of ylist\twrong id's = %d\n",idcheck);
  524. count = 0;
  525. idcheck = 0;
  526. for (i = 0; i < xslots; i++) {
  527. f = xlist[i];
  528. while (f != sentinel) {
  529. count++;
  530. if (f->index != (DdHalfWord) xindex)
  531. idcheck++;
  532. f = f->next;
  533. }
  534. }
  535. if (count != newxkeys || newxkeys != oldxkeys) {
  536. fprintf(table->err,"Error in finding newxkeys\toldxkeys = %d \tnewxkeys = %d \tactual = %d\n",oldxkeys,newxkeys,count);
  537. }
  538. if (idcheck != 0)
  539. fprintf(table->err,"Error in id's of xlist\twrong id's = %d\n",idcheck);
  540. #endif
  541. isolated += (table->vars[xindex]->ref == 1) +
  542. (table->vars[yindex]->ref == 1);
  543. table->isolated += (unsigned int) isolated;
  544. /* Set the appropriate fields in table. */
  545. table->subtables[y].keys = newykeys;
  546. /* Here we should update the linear combination table
  547. ** to record that x <- x EXNOR y. This is done by complementing
  548. ** the (x,y) entry of the table.
  549. */
  550. table->keys += newykeys - oldykeys;
  551. cuddXorLinear(table,xindex,yindex);
  552. }
  553. #ifdef DD_DEBUG
  554. if (table->enableExtraDebug) {
  555. (void) Cudd_DebugCheck(table);
  556. }
  557. #endif
  558. return((int) (table->keys - table->isolated));
  559. cuddLinearOutOfMem:
  560. (void) fprintf(table->err,"Error: cuddLinearInPlace out of memory\n");
  561. return (0);
  562. } /* end of cuddLinearInPlace */
  563. /**
  564. @brief Updates the interaction matrix.
  565. @sideeffect none
  566. */
  567. void
  568. cuddUpdateInteractionMatrix(
  569. DdManager * table,
  570. int xindex,
  571. int yindex)
  572. {
  573. int i;
  574. for (i = 0; i < yindex; i++) {
  575. if (i != xindex && cuddTestInteract(table,i,yindex)) {
  576. if (i < xindex) {
  577. cuddSetInteract(table,i,xindex);
  578. } else {
  579. cuddSetInteract(table,xindex,i);
  580. }
  581. }
  582. }
  583. for (i = yindex+1; i < table->size; i++) {
  584. if (i != xindex && cuddTestInteract(table,yindex,i)) {
  585. if (i < xindex) {
  586. cuddSetInteract(table,i,xindex);
  587. } else {
  588. cuddSetInteract(table,xindex,i);
  589. }
  590. }
  591. }
  592. } /* end of cuddUpdateInteractionMatrix */
  593. /**
  594. @brief Initializes the linear transform matrix.
  595. @return 1 if successful; 0 otherwise.
  596. @sideeffect none
  597. */
  598. int
  599. cuddInitLinear(
  600. DdManager * table)
  601. {
  602. int words;
  603. int wordsPerRow;
  604. int nvars;
  605. int word;
  606. int bit;
  607. int i;
  608. ptruint *linear;
  609. nvars = table->size;
  610. wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
  611. words = wordsPerRow * nvars;
  612. table->linear = linear = ALLOC(ptruint,words);
  613. if (linear == NULL) {
  614. table->errorCode = CUDD_MEMORY_OUT;
  615. return(0);
  616. }
  617. table->memused += words * sizeof(ptruint);
  618. table->linearSize = nvars;
  619. for (i = 0; i < words; i++) linear[i] = 0;
  620. for (i = 0; i < nvars; i++) {
  621. word = wordsPerRow * i + (i >> LOGBPL);
  622. bit = i & (BPL-1);
  623. linear[word] = (ptruint) 1 << bit;
  624. }
  625. return(1);
  626. } /* end of cuddInitLinear */
  627. /**
  628. @brief Resizes the linear transform matrix.
  629. @return 1 if successful; 0 otherwise.
  630. @sideeffect none
  631. */
  632. int
  633. cuddResizeLinear(
  634. DdManager * table)
  635. {
  636. int words,oldWords;
  637. int wordsPerRow,oldWordsPerRow;
  638. int nvars,oldNvars;
  639. int word,oldWord;
  640. int bit;
  641. int i,j;
  642. ptruint *linear,*oldLinear;
  643. oldNvars = table->linearSize;
  644. oldWordsPerRow = ((oldNvars - 1) >> LOGBPL) + 1;
  645. oldWords = oldWordsPerRow * oldNvars;
  646. oldLinear = table->linear;
  647. nvars = table->size;
  648. wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
  649. words = wordsPerRow * nvars;
  650. table->linear = linear = ALLOC(ptruint,words);
  651. if (linear == NULL) {
  652. table->errorCode = CUDD_MEMORY_OUT;
  653. return(0);
  654. }
  655. table->memused += (words - oldWords) * sizeof(ptruint);
  656. for (i = 0; i < words; i++) linear[i] = 0;
  657. /* Copy old matrix. */
  658. for (i = 0; i < oldNvars; i++) {
  659. for (j = 0; j < oldWordsPerRow; j++) {
  660. oldWord = oldWordsPerRow * i + j;
  661. word = wordsPerRow * i + j;
  662. linear[word] = oldLinear[oldWord];
  663. }
  664. }
  665. FREE(oldLinear);
  666. /* Add elements to the diagonal. */
  667. for (i = oldNvars; i < nvars; i++) {
  668. word = wordsPerRow * i + (i >> LOGBPL);
  669. bit = i & (BPL-1);
  670. linear[word] = (ptruint) 1 << bit;
  671. }
  672. table->linearSize = nvars;
  673. return(1);
  674. } /* end of cuddResizeLinear */
  675. /*---------------------------------------------------------------------------*/
  676. /* Definition of static functions */
  677. /*---------------------------------------------------------------------------*/
  678. /**
  679. @brief Comparison function used by qsort.
  680. @details Comparison function used by qsort to order the
  681. variables according to the number of keys in the subtables.
  682. @return the difference in number of keys between the two variables
  683. being compared.
  684. @sideeffect None
  685. */
  686. static int
  687. ddLinearUniqueCompare(
  688. void const * ptrX,
  689. void const * ptrY)
  690. {
  691. IndexKey const * pX = (IndexKey const *) ptrX;
  692. IndexKey const * pY = (IndexKey const *) ptrY;
  693. #if 0
  694. if (pY->keys == pX->keys) {
  695. return(pX->index - pY->index);
  696. }
  697. #endif
  698. return(pY->keys - pX->keys);
  699. } /* end of ddLinearUniqueCompare */
  700. /**
  701. @brief Given xLow <= x <= xHigh moves x up and down between the
  702. boundaries.
  703. @details At each step a linear transformation is tried, and, if it
  704. decreases the size of the %DD, it is accepted. Finds the best position
  705. and does the required changes.
  706. @return 1 if successful; 0 otherwise.
  707. @sideeffect None
  708. */
  709. static int
  710. ddLinearAndSiftingAux(
  711. DdManager * table,
  712. int x,
  713. int xLow,
  714. int xHigh)
  715. {
  716. Move *move;
  717. Move *moveUp; /* list of up moves */
  718. Move *moveDown; /* list of down moves */
  719. int initialSize;
  720. int result;
  721. initialSize = (int) (table->keys - table->isolated);
  722. moveDown = NULL;
  723. moveUp = NULL;
  724. if (x == xLow) {
  725. moveDown = ddLinearAndSiftingDown(table,x,xHigh,NULL);
  726. /* At this point x --> xHigh unless bounding occurred. */
  727. if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
  728. /* Move backward and stop at best position. */
  729. result = ddLinearAndSiftingBackward(table,initialSize,moveDown);
  730. if (!result) goto ddLinearAndSiftingAuxOutOfMem;
  731. } else if (x == xHigh) {
  732. moveUp = ddLinearAndSiftingUp(table,x,xLow,NULL);
  733. /* At this point x --> xLow unless bounding occurred. */
  734. if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
  735. /* Move backward and stop at best position. */
  736. result = ddLinearAndSiftingBackward(table,initialSize,moveUp);
  737. if (!result) goto ddLinearAndSiftingAuxOutOfMem;
  738. } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
  739. moveDown = ddLinearAndSiftingDown(table,x,xHigh,NULL);
  740. /* At this point x --> xHigh unless bounding occurred. */
  741. if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
  742. moveUp = ddUndoMoves(table,moveDown);
  743. #ifdef DD_DEBUG
  744. assert(moveUp == NULL || moveUp->x == (DdHalfWord) x);
  745. #endif
  746. moveUp = ddLinearAndSiftingUp(table,x,xLow,moveUp);
  747. if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
  748. /* Move backward and stop at best position. */
  749. result = ddLinearAndSiftingBackward(table,initialSize,moveUp);
  750. if (!result) goto ddLinearAndSiftingAuxOutOfMem;
  751. } else { /* must go up first: shorter */
  752. moveUp = ddLinearAndSiftingUp(table,x,xLow,NULL);
  753. /* At this point x --> xLow unless bounding occurred. */
  754. if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
  755. moveDown = ddUndoMoves(table,moveUp);
  756. #ifdef DD_DEBUG
  757. assert(moveDown == NULL || moveDown->y == (DdHalfWord) x);
  758. #endif
  759. moveDown = ddLinearAndSiftingDown(table,x,xHigh,moveDown);
  760. if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto ddLinearAndSiftingAuxOutOfMem;
  761. /* Move backward and stop at best position. */
  762. result = ddLinearAndSiftingBackward(table,initialSize,moveDown);
  763. if (!result) goto ddLinearAndSiftingAuxOutOfMem;
  764. }
  765. while (moveDown != NULL) {
  766. move = moveDown->next;
  767. cuddDeallocMove(table, moveDown);
  768. moveDown = move;
  769. }
  770. while (moveUp != NULL) {
  771. move = moveUp->next;
  772. cuddDeallocMove(table, moveUp);
  773. moveUp = move;
  774. }
  775. return(1);
  776. ddLinearAndSiftingAuxOutOfMem:
  777. while (moveDown != NULL) {
  778. move = moveDown->next;
  779. cuddDeallocMove(table, moveDown);
  780. moveDown = move;
  781. }
  782. while (moveUp != NULL) {
  783. move = moveUp->next;
  784. cuddDeallocMove(table, moveUp);
  785. moveUp = move;
  786. }
  787. return(0);
  788. } /* end of ddLinearAndSiftingAux */
  789. /**
  790. @brief Sifts a variable up and applies linear transformations.
  791. @details Moves y up until either it reaches the bound (xLow) or the
  792. size of the %DD heap increases too much.
  793. @return the set of moves in case of success; NULL if memory is full.
  794. @sideeffect None
  795. */
  796. static Move *
  797. ddLinearAndSiftingUp(
  798. DdManager * table,
  799. int y,
  800. int xLow,
  801. Move * prevMoves)
  802. {
  803. Move *moves;
  804. Move *move;
  805. int x;
  806. int size, newsize;
  807. int limitSize;
  808. int xindex, yindex;
  809. int isolated;
  810. int L; /* lower bound on DD size */
  811. #ifdef DD_DEBUG
  812. int checkL;
  813. int z;
  814. int zindex;
  815. #endif
  816. moves = prevMoves;
  817. yindex = table->invperm[y];
  818. /* Initialize the lower bound.
  819. ** The part of the DD below y will not change.
  820. ** The part of the DD above y that does not interact with y will not
  821. ** change. The rest may vanish in the best case, except for
  822. ** the nodes at level xLow, which will not vanish, regardless.
  823. */
  824. limitSize = L = (int) (table->keys - table->isolated);
  825. for (x = xLow + 1; x < y; x++) {
  826. xindex = table->invperm[x];
  827. if (cuddTestInteract(table,xindex,yindex)) {
  828. isolated = table->vars[xindex]->ref == 1;
  829. L -= (int) table->subtables[x].keys - isolated;
  830. }
  831. }
  832. isolated = table->vars[yindex]->ref == 1;
  833. L -= (int) table->subtables[y].keys - isolated;
  834. x = cuddNextLow(table,y);
  835. while (x >= xLow && L <= limitSize) {
  836. xindex = table->invperm[x];
  837. #ifdef DD_DEBUG
  838. checkL = table->keys - table->isolated;
  839. for (z = xLow + 1; z < y; z++) {
  840. zindex = table->invperm[z];
  841. if (cuddTestInteract(table,zindex,yindex)) {
  842. isolated = table->vars[zindex]->ref == 1;
  843. checkL -= table->subtables[z].keys - isolated;
  844. }
  845. }
  846. isolated = table->vars[yindex]->ref == 1;
  847. checkL -= table->subtables[y].keys - isolated;
  848. if (L != checkL) {
  849. (void) fprintf(table->out, "checkL(%d) != L(%d)\n",checkL,L);
  850. }
  851. #endif
  852. size = cuddSwapInPlace(table,x,y);
  853. if (size == 0) goto ddLinearAndSiftingUpOutOfMem;
  854. newsize = cuddLinearInPlace(table,x,y);
  855. if (newsize == 0) goto ddLinearAndSiftingUpOutOfMem;
  856. move = (Move *) cuddDynamicAllocNode(table);
  857. if (move == NULL) goto ddLinearAndSiftingUpOutOfMem;
  858. move->x = x;
  859. move->y = y;
  860. move->next = moves;
  861. moves = move;
  862. move->flags = CUDD_SWAP_MOVE;
  863. if (newsize >= size) {
  864. /* Undo transformation. The transformation we apply is
  865. ** its own inverse. Hence, we just apply the transformation
  866. ** again.
  867. */
  868. newsize = cuddLinearInPlace(table,x,y);
  869. if (newsize == 0) goto ddLinearAndSiftingUpOutOfMem;
  870. #ifdef DD_DEBUG
  871. if (newsize != size) {
  872. (void) fprintf(table->out,"Change in size after identity transformation! From %d to %d\n",size,newsize);
  873. }
  874. #endif
  875. } else if (cuddTestInteract(table,xindex,yindex)) {
  876. size = newsize;
  877. move->flags = CUDD_LINEAR_TRANSFORM_MOVE;
  878. cuddUpdateInteractionMatrix(table,xindex,yindex);
  879. }
  880. move->size = size;
  881. /* Update the lower bound. */
  882. if (cuddTestInteract(table,xindex,yindex)) {
  883. isolated = table->vars[xindex]->ref == 1;
  884. L += (int) table->subtables[y].keys - isolated;
  885. }
  886. if ((double) size > (double) limitSize * table->maxGrowth) break;
  887. if (size < limitSize) limitSize = size;
  888. y = x;
  889. x = cuddNextLow(table,y);
  890. }
  891. return(moves);
  892. ddLinearAndSiftingUpOutOfMem:
  893. while (moves != NULL) {
  894. move = moves->next;
  895. cuddDeallocMove(table, moves);
  896. moves = move;
  897. }
  898. return((Move *) CUDD_OUT_OF_MEM);
  899. } /* end of ddLinearAndSiftingUp */
  900. /**
  901. @brief Sifts a variable down and applies linear transformations.
  902. @details Moves x down until either it reaches the bound (xHigh) or
  903. the size of the %DD heap increases too much.
  904. @return the set of moves in case of success; NULL if memory is full.
  905. @sideeffect None
  906. */
  907. static Move *
  908. ddLinearAndSiftingDown(
  909. DdManager * table,
  910. int x,
  911. int xHigh,
  912. Move * prevMoves)
  913. {
  914. Move *moves;
  915. Move *move;
  916. int y;
  917. int size, newsize;
  918. int R; /* upper bound on node decrease */
  919. int limitSize;
  920. int xindex, yindex;
  921. int isolated;
  922. #ifdef DD_DEBUG
  923. int checkR;
  924. int z;
  925. int zindex;
  926. #endif
  927. moves = prevMoves;
  928. /* Initialize R */
  929. xindex = table->invperm[x];
  930. limitSize = size = table->keys - table->isolated;
  931. R = 0;
  932. for (y = xHigh; y > x; y--) {
  933. yindex = table->invperm[y];
  934. if (cuddTestInteract(table,xindex,yindex)) {
  935. isolated = table->vars[yindex]->ref == 1;
  936. R += table->subtables[y].keys - isolated;
  937. }
  938. }
  939. y = cuddNextHigh(table,x);
  940. while (y <= xHigh && size - R < limitSize) {
  941. #ifdef DD_DEBUG
  942. checkR = 0;
  943. for (z = xHigh; z > x; z--) {
  944. zindex = table->invperm[z];
  945. if (cuddTestInteract(table,xindex,zindex)) {
  946. isolated = table->vars[zindex]->ref == 1;
  947. checkR += (int) table->subtables[z].keys - isolated;
  948. }
  949. }
  950. if (R != checkR) {
  951. (void) fprintf(table->out, "checkR(%d) != R(%d)\n",checkR,R);
  952. }
  953. #endif
  954. /* Update upper bound on node decrease. */
  955. yindex = table->invperm[y];
  956. if (cuddTestInteract(table,xindex,yindex)) {
  957. isolated = table->vars[yindex]->ref == 1;
  958. R -= (int) table->subtables[y].keys - isolated;
  959. }
  960. size = cuddSwapInPlace(table,x,y);
  961. if (size == 0) goto ddLinearAndSiftingDownOutOfMem;
  962. newsize = cuddLinearInPlace(table,x,y);
  963. if (newsize == 0) goto ddLinearAndSiftingDownOutOfMem;
  964. move = (Move *) cuddDynamicAllocNode(table);
  965. if (move == NULL) goto ddLinearAndSiftingDownOutOfMem;
  966. move->x = x;
  967. move->y = y;
  968. move->next = moves;
  969. moves = move;
  970. move->flags = CUDD_SWAP_MOVE;
  971. if (newsize >= size) {
  972. /* Undo transformation. The transformation we apply is
  973. ** its own inverse. Hence, we just apply the transformation
  974. ** again.
  975. */
  976. newsize = cuddLinearInPlace(table,x,y);
  977. if (newsize == 0) goto ddLinearAndSiftingDownOutOfMem;
  978. if (newsize != size) {
  979. (void) fprintf(table->out,"Change in size after identity transformation! From %d to %d\n",size,newsize);
  980. }
  981. } else if (cuddTestInteract(table,xindex,yindex)) {
  982. size = newsize;
  983. move->flags = CUDD_LINEAR_TRANSFORM_MOVE;
  984. cuddUpdateInteractionMatrix(table,xindex,yindex);
  985. }
  986. move->size = size;
  987. if ((double) size > (double) limitSize * table->maxGrowth) break;
  988. if (size < limitSize) limitSize = size;
  989. x = y;
  990. y = cuddNextHigh(table,x);
  991. }
  992. return(moves);
  993. ddLinearAndSiftingDownOutOfMem:
  994. while (moves != NULL) {
  995. move = moves->next;
  996. cuddDeallocMove(table, moves);
  997. moves = move;
  998. }
  999. return((Move *) CUDD_OUT_OF_MEM);
  1000. } /* end of ddLinearAndSiftingDown */
  1001. /**
  1002. @brief Given a set of moves, returns the %DD heap to the order
  1003. giving the minimum size.
  1004. @details In case of ties, returns to the closest position giving the
  1005. minimum size.
  1006. @return 1 in case of success; 0 otherwise.
  1007. @sideeffect None
  1008. */
  1009. static int
  1010. ddLinearAndSiftingBackward(
  1011. DdManager * table,
  1012. int size,
  1013. Move * moves)
  1014. {
  1015. Move *move;
  1016. int res;
  1017. for (move = moves; move != NULL; move = move->next) {
  1018. if (move->size < size) {
  1019. size = move->size;
  1020. }
  1021. }
  1022. for (move = moves; move != NULL; move = move->next) {
  1023. if (move->size == size) return(1);
  1024. if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) {
  1025. res = cuddLinearInPlace(table,(int)move->x,(int)move->y);
  1026. if (!res) return(0);
  1027. }
  1028. res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
  1029. if (!res) return(0);
  1030. if (move->flags == CUDD_INVERSE_TRANSFORM_MOVE) {
  1031. res = cuddLinearInPlace(table,(int)move->x,(int)move->y);
  1032. if (!res) return(0);
  1033. }
  1034. }
  1035. return(1);
  1036. } /* end of ddLinearAndSiftingBackward */
  1037. /**
  1038. @brief Given a set of moves, returns the %DD heap to the order
  1039. in effect before the moves.
  1040. @return 1 in case of success; 0 otherwise.
  1041. @sideeffect None
  1042. */
  1043. static Move*
  1044. ddUndoMoves(
  1045. DdManager * table,
  1046. Move * moves)
  1047. {
  1048. Move *invmoves = NULL;
  1049. Move *move;
  1050. Move *invmove;
  1051. int size;
  1052. for (move = moves; move != NULL; move = move->next) {
  1053. invmove = (Move *) cuddDynamicAllocNode(table);
  1054. if (invmove == NULL) goto ddUndoMovesOutOfMem;
  1055. invmove->x = move->x;
  1056. invmove->y = move->y;
  1057. invmove->next = invmoves;
  1058. invmoves = invmove;
  1059. if (move->flags == CUDD_SWAP_MOVE) {
  1060. invmove->flags = CUDD_SWAP_MOVE;
  1061. size = cuddSwapInPlace(table,(int)move->x,(int)move->y);
  1062. if (!size) goto ddUndoMovesOutOfMem;
  1063. } else if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) {
  1064. invmove->flags = CUDD_INVERSE_TRANSFORM_MOVE;
  1065. size = cuddLinearInPlace(table,(int)move->x,(int)move->y);
  1066. if (!size) goto ddUndoMovesOutOfMem;
  1067. size = cuddSwapInPlace(table,(int)move->x,(int)move->y);
  1068. if (!size) goto ddUndoMovesOutOfMem;
  1069. } else { /* must be CUDD_INVERSE_TRANSFORM_MOVE */
  1070. #ifdef DD_DEBUG
  1071. (void) fprintf(table->err,"Unforseen event in ddUndoMoves!\n");
  1072. #endif
  1073. invmove->flags = CUDD_LINEAR_TRANSFORM_MOVE;
  1074. size = cuddSwapInPlace(table,(int)move->x,(int)move->y);
  1075. if (!size) goto ddUndoMovesOutOfMem;
  1076. size = cuddLinearInPlace(table,(int)move->x,(int)move->y);
  1077. if (!size) goto ddUndoMovesOutOfMem;
  1078. }
  1079. invmove->size = size;
  1080. }
  1081. return(invmoves);
  1082. ddUndoMovesOutOfMem:
  1083. while (invmoves != NULL) {
  1084. move = invmoves->next;
  1085. cuddDeallocMove(table, invmoves);
  1086. invmoves = move;
  1087. }
  1088. return((Move *) CUDD_OUT_OF_MEM);
  1089. } /* end of ddUndoMoves */
  1090. /**
  1091. @brief XORs two rows of the linear transform matrix.
  1092. @details Replaces the first row with the result.
  1093. @sideeffect none
  1094. */
  1095. static void
  1096. cuddXorLinear(
  1097. DdManager * table,
  1098. int x,
  1099. int y)
  1100. {
  1101. int i;
  1102. int nvars = table->size;
  1103. int wordsPerRow = ((nvars - 1) >> LOGBPL) + 1;
  1104. int xstart = wordsPerRow * x;
  1105. int ystart = wordsPerRow * y;
  1106. ptruint *linear = table->linear;
  1107. for (i = 0; i < wordsPerRow; i++) {
  1108. linear[xstart+i] ^= linear[ystart+i];
  1109. }
  1110. } /* end of cuddXorLinear */