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.

1365 lines
38 KiB

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