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.

1670 lines
46 KiB

2 months ago
  1. /**
  2. @file
  3. @ingroup cudd
  4. @brief Functions for symmetry-based variable reordering.
  5. @author Shipra Panda, Fabio Somenzi
  6. @copyright@parblock
  7. Copyright (c) 1995-2015, Regents of the University of Colorado
  8. All rights reserved.
  9. Redistribution and use in source and binary forms, with or without
  10. modification, are permitted provided that the following conditions
  11. are met:
  12. Redistributions of source code must retain the above copyright
  13. notice, this list of conditions and the following disclaimer.
  14. Redistributions in binary form must reproduce the above copyright
  15. notice, this list of conditions and the following disclaimer in the
  16. documentation and/or other materials provided with the distribution.
  17. Neither the name of the University of Colorado nor the names of its
  18. contributors may be used to endorse or promote products derived from
  19. this software without specific prior written permission.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  27. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  28. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  30. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  31. POSSIBILITY OF SUCH DAMAGE.
  32. @endparblock
  33. */
  34. #include "util.h"
  35. #include "cuddInt.h"
  36. /*---------------------------------------------------------------------------*/
  37. /* Constant declarations */
  38. /*---------------------------------------------------------------------------*/
  39. #define MV_OOM (Move *)1
  40. /*---------------------------------------------------------------------------*/
  41. /* Stucture declarations */
  42. /*---------------------------------------------------------------------------*/
  43. /*---------------------------------------------------------------------------*/
  44. /* Type declarations */
  45. /*---------------------------------------------------------------------------*/
  46. /*---------------------------------------------------------------------------*/
  47. /* Variable declarations */
  48. /*---------------------------------------------------------------------------*/
  49. /*---------------------------------------------------------------------------*/
  50. /* Macro declarations */
  51. /*---------------------------------------------------------------------------*/
  52. /** \cond */
  53. /*---------------------------------------------------------------------------*/
  54. /* Static function prototypes */
  55. /*---------------------------------------------------------------------------*/
  56. static int ddSymmUniqueCompare (void const *ptrX, void const *ptrY);
  57. static int ddSymmSiftingAux (DdManager *table, int x, int xLow, int xHigh);
  58. static int ddSymmSiftingConvAux (DdManager *table, int x, int xLow, int xHigh);
  59. static Move * ddSymmSiftingUp (DdManager *table, int y, int xLow);
  60. static Move * ddSymmSiftingDown (DdManager *table, int x, int xHigh);
  61. static int ddSymmGroupMove (DdManager *table, int x, int y, Move **moves);
  62. static int ddSymmGroupMoveBackward (DdManager *table, int x, int y);
  63. static int ddSymmSiftingBackward (DdManager *table, Move *moves, int size);
  64. static void ddSymmSummary (DdManager *table, int lower, int upper, int *symvars, int *symgroups);
  65. /** \endcond */
  66. /*---------------------------------------------------------------------------*/
  67. /* Definition of exported functions */
  68. /*---------------------------------------------------------------------------*/
  69. /**
  70. @brief Prints statistics on symmetric variables.
  71. @details The information is accurate only if this function is called
  72. right after reordering with methods CUDD_REORDER_SYMM_SIFT or
  73. CUDD_REORDER_SYMM_SIFT_CONV.
  74. @sideeffect None
  75. */
  76. void
  77. Cudd_SymmProfile(
  78. DdManager * table,
  79. int lower,
  80. int upper)
  81. {
  82. int i,x,gbot;
  83. int TotalSymm = 0;
  84. int TotalSymmGroups = 0;
  85. for (i = lower; i <= upper; i++) {
  86. if (table->subtables[i].next != (unsigned) i) {
  87. x = i;
  88. (void) fprintf(table->out,"Group:");
  89. do {
  90. (void) fprintf(table->out," %d",table->invperm[x]);
  91. TotalSymm++;
  92. gbot = x;
  93. x = table->subtables[x].next;
  94. } while (x != i);
  95. TotalSymmGroups++;
  96. #ifdef DD_DEBUG
  97. assert(table->subtables[gbot].next == (unsigned) i);
  98. #endif
  99. i = gbot;
  100. (void) fprintf(table->out,"\n");
  101. }
  102. }
  103. (void) fprintf(table->out,"Total Symmetric = %d\n",TotalSymm);
  104. (void) fprintf(table->out,"Total Groups = %d\n",TotalSymmGroups);
  105. } /* end of Cudd_SymmProfile */
  106. /*---------------------------------------------------------------------------*/
  107. /* Definition of internal functions */
  108. /*---------------------------------------------------------------------------*/
  109. /**
  110. @brief Checks for symmetry of x and y.
  111. @details Ignores projection functions, unless they are isolated.
  112. @return 1 in case of symmetry; 0 otherwise.
  113. @sideeffect None
  114. */
  115. int
  116. cuddSymmCheck(
  117. DdManager * table,
  118. int x,
  119. int y)
  120. {
  121. DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10;
  122. int comple; /* f0 is complemented */
  123. int xsymmy; /* x and y may be positively symmetric */
  124. int xsymmyp; /* x and y may be negatively symmetric */
  125. int arccount; /* number of arcs from layer x to layer y */
  126. int TotalRefCount; /* total reference count of layer y minus 1 */
  127. int yindex;
  128. int i;
  129. DdNodePtr *list;
  130. int slots;
  131. DdNode *sentinel = &(table->sentinel);
  132. #ifdef DD_DEBUG
  133. int xindex;
  134. #endif
  135. /* Checks that x and y are not the projection functions.
  136. ** For x it is sufficient to check whether there is only one
  137. ** node; indeed, if there is one node, it is the projection function
  138. ** and it cannot point to y. Hence, if y isn't just the projection
  139. ** function, it has one arc coming from a layer different from x.
  140. */
  141. if (table->subtables[x].keys == 1) {
  142. return(0);
  143. }
  144. yindex = table->invperm[y];
  145. if (table->subtables[y].keys == 1) {
  146. if (table->vars[yindex]->ref == 1)
  147. return(0);
  148. }
  149. xsymmy = xsymmyp = 1;
  150. arccount = 0;
  151. slots = table->subtables[x].slots;
  152. list = table->subtables[x].nodelist;
  153. for (i = 0; i < slots; i++) {
  154. f = list[i];
  155. while (f != sentinel) {
  156. /* Find f1, f0, f11, f10, f01, f00. */
  157. f1 = cuddT(f);
  158. f0 = Cudd_Regular(cuddE(f));
  159. comple = Cudd_IsComplement(cuddE(f));
  160. if ((int) f1->index == yindex) {
  161. arccount++;
  162. f11 = cuddT(f1); f10 = cuddE(f1);
  163. } else {
  164. if ((int) f0->index != yindex) {
  165. /* If f is an isolated projection function it is
  166. ** allowed to bypass layer y.
  167. */
  168. if (f1 != DD_ONE(table) || f0 != DD_ONE(table) || f->ref != 1)
  169. return(0); /* f bypasses layer y */
  170. }
  171. f11 = f10 = f1;
  172. }
  173. if ((int) f0->index == yindex) {
  174. arccount++;
  175. f01 = cuddT(f0); f00 = cuddE(f0);
  176. } else {
  177. f01 = f00 = f0;
  178. }
  179. if (comple) {
  180. f01 = Cudd_Not(f01);
  181. f00 = Cudd_Not(f00);
  182. }
  183. if (f1 != DD_ONE(table) || f0 != DD_ONE(table) || f->ref != 1) {
  184. xsymmy &= f01 == f10;
  185. xsymmyp &= f11 == f00;
  186. if ((xsymmy == 0) && (xsymmyp == 0))
  187. return(0);
  188. }
  189. f = f->next;
  190. } /* while */
  191. } /* for */
  192. /* Calculate the total reference counts of y */
  193. TotalRefCount = -1; /* -1 for projection function */
  194. slots = table->subtables[y].slots;
  195. list = table->subtables[y].nodelist;
  196. for (i = 0; i < slots; i++) {
  197. f = list[i];
  198. while (f != sentinel) {
  199. TotalRefCount += f->ref;
  200. f = f->next;
  201. }
  202. }
  203. #if defined(DD_DEBUG) && defined(DD_VERBOSE)
  204. if (arccount == TotalRefCount) {
  205. xindex = table->invperm[x];
  206. (void) fprintf(table->out,
  207. "Found symmetry! x =%d\ty = %d\tPos(%d,%d)\n",
  208. xindex,yindex,x,y);
  209. }
  210. #endif
  211. return(arccount == TotalRefCount);
  212. } /* end of cuddSymmCheck */
  213. /**
  214. @brief Symmetric sifting algorithm.
  215. @details Assumes that no dead nodes are present.
  216. <ol>
  217. <li> Order all the variables according to the number of entries in
  218. each unique subtable.
  219. <li> Sift the variable up and down, remembering each time the total
  220. size of the DD heap and grouping variables that are symmetric.
  221. <li> Select the best permutation.
  222. <li> Repeat 3 and 4 for all variables.
  223. </ol>
  224. @return 1 plus the number of symmetric variables if successful; 0
  225. otherwise.
  226. @sideeffect None
  227. @see cuddSymmSiftingConv
  228. */
  229. int
  230. cuddSymmSifting(
  231. DdManager * table,
  232. int lower,
  233. int upper)
  234. {
  235. int i;
  236. IndexKey *var;
  237. int size;
  238. int x;
  239. int result;
  240. int symvars;
  241. int symgroups;
  242. #ifdef DD_STATS
  243. int previousSize;
  244. #endif
  245. size = table->size;
  246. /* Find order in which to sift variables. */
  247. var = ALLOC(IndexKey,size);
  248. if (var == NULL) {
  249. table->errorCode = CUDD_MEMORY_OUT;
  250. goto ddSymmSiftingOutOfMem;
  251. }
  252. for (i = 0; i < size; i++) {
  253. x = table->perm[i];
  254. var[i].index = i;
  255. var[i].keys = table->subtables[x].keys;
  256. }
  257. util_qsort(var,size,sizeof(IndexKey),ddSymmUniqueCompare);
  258. /* Initialize the symmetry of each subtable to itself. */
  259. for (i = lower; i <= upper; i++) {
  260. table->subtables[i].next = i;
  261. }
  262. for (i = 0; i < ddMin(table->siftMaxVar,size); i++) {
  263. if (table->ddTotalNumberSwapping >= table->siftMaxSwap)
  264. break;
  265. if (util_cpu_time() - table->startTime > table->timeLimit) {
  266. table->autoDyn = 0; /* prevent further reordering */
  267. break;
  268. }
  269. if (table->terminationCallback != NULL &&
  270. table->terminationCallback(table->tcbArg)) {
  271. table->autoDyn = 0; /* prevent further reordering */
  272. break;
  273. }
  274. x = table->perm[var[i].index];
  275. #ifdef DD_STATS
  276. previousSize = (int) (table->keys - table->isolated);
  277. #endif
  278. if (x < lower || x > upper) continue;
  279. if (table->subtables[x].next == (unsigned) x) {
  280. result = ddSymmSiftingAux(table,x,lower,upper);
  281. if (!result) goto ddSymmSiftingOutOfMem;
  282. #ifdef DD_STATS
  283. if (table->keys < (unsigned) previousSize + table->isolated) {
  284. (void) fprintf(table->out,"-");
  285. } else if (table->keys > (unsigned) previousSize +
  286. table->isolated) {
  287. (void) fprintf(table->out,"+"); /* should never happen */
  288. } else {
  289. (void) fprintf(table->out,"=");
  290. }
  291. fflush(table->out);
  292. #endif
  293. }
  294. }
  295. FREE(var);
  296. ddSymmSummary(table, lower, upper, &symvars, &symgroups);
  297. #ifdef DD_STATS
  298. (void) fprintf(table->out, "\n#:S_SIFTING %8d: symmetric variables\n",
  299. symvars);
  300. (void) fprintf(table->out, "#:G_SIFTING %8d: symmetric groups",
  301. symgroups);
  302. #endif
  303. return(1+symvars);
  304. ddSymmSiftingOutOfMem:
  305. if (var != NULL) FREE(var);
  306. return(0);
  307. } /* end of cuddSymmSifting */
  308. /**
  309. @brief Symmetric sifting to convergence algorithm.
  310. @details Assumes that no dead nodes are present.
  311. <ol>
  312. <li> Order all the variables according to the number of entries in
  313. each unique subtable.
  314. <li> Sift the variable up and down, remembering each time the total
  315. size of the %DD heap and grouping variables that are symmetric.
  316. <li> Select the best permutation.
  317. <li> Repeat 3 and 4 for all variables.
  318. <li> Repeat 1-4 until no further improvement.
  319. </ol>
  320. @return 1 plus the number of symmetric variables if successful; 0
  321. otherwise.
  322. @sideeffect None
  323. @see cuddSymmSifting
  324. */
  325. int
  326. cuddSymmSiftingConv(
  327. DdManager * table,
  328. int lower,
  329. int upper)
  330. {
  331. int i;
  332. IndexKey *var;
  333. int size;
  334. int x;
  335. int result;
  336. int symvars;
  337. int symgroups;
  338. int classes;
  339. int initialSize;
  340. #ifdef DD_STATS
  341. int previousSize;
  342. #endif
  343. initialSize = (int) (table->keys - table->isolated);
  344. size = table->size;
  345. /* Find order in which to sift variables. */
  346. var = ALLOC(IndexKey,size);
  347. if (var == NULL) {
  348. table->errorCode = CUDD_MEMORY_OUT;
  349. goto ddSymmSiftingConvOutOfMem;
  350. }
  351. for (i = 0; i < size; i++) {
  352. x = table->perm[i];
  353. var[i].index = i;
  354. var[i].keys = table->subtables[x].keys;
  355. }
  356. util_qsort(var,size,sizeof(IndexKey),ddSymmUniqueCompare);
  357. /* Initialize the symmetry of each subtable to itself
  358. ** for first pass of converging symmetric sifting.
  359. */
  360. for (i = lower; i <= upper; i++) {
  361. table->subtables[i].next = i;
  362. }
  363. for (i = 0; i < ddMin(table->siftMaxVar, table->size); i++) {
  364. if (table->ddTotalNumberSwapping >= table->siftMaxSwap)
  365. break;
  366. if (util_cpu_time() - table->startTime > table->timeLimit) {
  367. table->autoDyn = 0; /* prevent further reordering */
  368. break;
  369. }
  370. if (table->terminationCallback != NULL &&
  371. table->terminationCallback(table->tcbArg)) {
  372. table->autoDyn = 0; /* prevent further reordering */
  373. break;
  374. }
  375. x = table->perm[var[i].index];
  376. if (x < lower || x > upper) continue;
  377. /* Only sift if not in symmetry group already. */
  378. if (table->subtables[x].next == (unsigned) x) {
  379. #ifdef DD_STATS
  380. previousSize = (int) (table->keys - table->isolated);
  381. #endif
  382. result = ddSymmSiftingAux(table,x,lower,upper);
  383. if (!result) goto ddSymmSiftingConvOutOfMem;
  384. #ifdef DD_STATS
  385. if (table->keys < (unsigned) previousSize + table->isolated) {
  386. (void) fprintf(table->out,"-");
  387. } else if (table->keys > (unsigned) previousSize +
  388. table->isolated) {
  389. (void) fprintf(table->out,"+");
  390. } else {
  391. (void) fprintf(table->out,"=");
  392. }
  393. fflush(table->out);
  394. #endif
  395. }
  396. }
  397. /* Sifting now until convergence. */
  398. while ((unsigned) initialSize > table->keys - table->isolated) {
  399. initialSize = (int) (table->keys - table->isolated);
  400. #ifdef DD_STATS
  401. (void) fprintf(table->out,"\n");
  402. #endif
  403. /* Here we consider only one representative for each symmetry class. */
  404. for (x = lower, classes = 0; x <= upper; x++, classes++) {
  405. while ((unsigned) x < table->subtables[x].next) {
  406. x = table->subtables[x].next;
  407. }
  408. /* Here x is the largest index in a group.
  409. ** Groups consist of adjacent variables.
  410. ** Hence, the next increment of x will move it to a new group.
  411. */
  412. i = table->invperm[x];
  413. var[classes].keys = table->subtables[x].keys;
  414. var[classes].index = i;
  415. }
  416. util_qsort(var,classes,sizeof(IndexKey),ddSymmUniqueCompare);
  417. /* Now sift. */
  418. for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
  419. if (table->ddTotalNumberSwapping >= table->siftMaxSwap)
  420. break;
  421. if (util_cpu_time() - table->startTime > table->timeLimit) {
  422. table->autoDyn = 0; /* prevent further reordering */
  423. break;
  424. }
  425. if (table->terminationCallback != NULL &&
  426. table->terminationCallback(table->tcbArg)) {
  427. table->autoDyn = 0; /* prevent further reordering */
  428. break;
  429. }
  430. x = table->perm[var[i].index];
  431. if ((unsigned) x >= table->subtables[x].next) {
  432. #ifdef DD_STATS
  433. previousSize = (int) (table->keys - table->isolated);
  434. #endif
  435. result = ddSymmSiftingConvAux(table,x,lower,upper);
  436. if (!result ) goto ddSymmSiftingConvOutOfMem;
  437. #ifdef DD_STATS
  438. if (table->keys < (unsigned) previousSize + table->isolated) {
  439. (void) fprintf(table->out,"-");
  440. } else if (table->keys > (unsigned) previousSize +
  441. table->isolated) {
  442. (void) fprintf(table->out,"+");
  443. } else {
  444. (void) fprintf(table->out,"=");
  445. }
  446. fflush(table->out);
  447. #endif
  448. }
  449. } /* for */
  450. }
  451. ddSymmSummary(table, lower, upper, &symvars, &symgroups);
  452. #ifdef DD_STATS
  453. (void) fprintf(table->out, "\n#:S_SIFTING %8d: symmetric variables\n",
  454. symvars);
  455. (void) fprintf(table->out, "#:G_SIFTING %8d: symmetric groups",
  456. symgroups);
  457. #endif
  458. FREE(var);
  459. return(1+symvars);
  460. ddSymmSiftingConvOutOfMem:
  461. if (var != NULL) FREE(var);
  462. return(0);
  463. } /* end of cuddSymmSiftingConv */
  464. /*---------------------------------------------------------------------------*/
  465. /* Definition of static functions */
  466. /*---------------------------------------------------------------------------*/
  467. /**
  468. @brief Comparison function used by qsort.
  469. @details Used to order the variables according to the number of keys
  470. in the subtables.
  471. @return the difference in number of keys between the two variables
  472. being compared.
  473. @sideeffect None
  474. */
  475. static int
  476. ddSymmUniqueCompare(
  477. void const * ptrX,
  478. void const * ptrY)
  479. {
  480. IndexKey const * pX = (IndexKey const *) ptrX;
  481. IndexKey const * pY = (IndexKey const *) ptrY;
  482. #if 0
  483. if (pY->keys == pX->keys) {
  484. return(pX->index - pY->index);
  485. }
  486. #endif
  487. return(pY->keys - pX->keys);
  488. } /* end of ddSymmUniqueCompare */
  489. /**
  490. @brief Given xLow <= x <= xHigh moves x up and down between the
  491. boundaries.
  492. @details Finds the best position and does the required changes.
  493. Assumes that x is not part of a symmetry group.
  494. @return 1 if successful; 0 otherwise.
  495. @sideeffect None
  496. */
  497. static int
  498. ddSymmSiftingAux(
  499. DdManager * table,
  500. int x,
  501. int xLow,
  502. int xHigh)
  503. {
  504. Move *move;
  505. Move *moveUp; /* list of up moves */
  506. Move *moveDown; /* list of down moves */
  507. int initialSize;
  508. int result;
  509. int i;
  510. int topbot; /* index to either top or bottom of symmetry group */
  511. int initGroupSize, finalGroupSize;
  512. #ifdef DD_DEBUG
  513. /* check for previously detected symmetry */
  514. assert(table->subtables[x].next == (unsigned) x);
  515. #endif
  516. initialSize = (int) (table->keys - table->isolated);
  517. moveDown = NULL;
  518. moveUp = NULL;
  519. if ((x - xLow) > (xHigh - x)) {
  520. /* Will go down first, unless x == xHigh:
  521. ** Look for consecutive symmetries above x.
  522. */
  523. for (i = x; i > xLow; i--) {
  524. if (!cuddSymmCheck(table,i-1,i))
  525. break;
  526. topbot = table->subtables[i-1].next; /* find top of i-1's group */
  527. table->subtables[i-1].next = i;
  528. table->subtables[x].next = topbot; /* x is bottom of group so its */
  529. /* next is top of i-1's group */
  530. i = topbot + 1; /* add 1 for i--; new i is top of symm group */
  531. }
  532. } else {
  533. /* Will go up first unless x == xlow:
  534. ** Look for consecutive symmetries below x.
  535. */
  536. for (i = x; i < xHigh; i++) {
  537. if (!cuddSymmCheck(table,i,i+1))
  538. break;
  539. /* find bottom of i+1's symm group */
  540. topbot = i + 1;
  541. while ((unsigned) topbot < table->subtables[topbot].next) {
  542. topbot = table->subtables[topbot].next;
  543. }
  544. table->subtables[topbot].next = table->subtables[i].next;
  545. table->subtables[i].next = i + 1;
  546. i = topbot - 1; /* subtract 1 for i++; new i is bottom of group */
  547. }
  548. }
  549. /* Now x may be in the middle of a symmetry group.
  550. ** Find bottom of x's symm group.
  551. */
  552. while ((unsigned) x < table->subtables[x].next)
  553. x = table->subtables[x].next;
  554. if (x == xLow) { /* Sift down */
  555. #ifdef DD_DEBUG
  556. /* x must be a singleton */
  557. assert((unsigned) x == table->subtables[x].next);
  558. #endif
  559. if (x == xHigh) return(1); /* just one variable */
  560. initGroupSize = 1;
  561. moveDown = ddSymmSiftingDown(table,x,xHigh);
  562. /* after this point x --> xHigh, unless early term */
  563. if (moveDown == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
  564. if (moveDown == NULL) return(1);
  565. x = moveDown->y;
  566. /* Find bottom of x's group */
  567. i = x;
  568. while ((unsigned) i < table->subtables[i].next) {
  569. i = table->subtables[i].next;
  570. }
  571. #ifdef DD_DEBUG
  572. /* x should be the top of the symmetry group and i the bottom */
  573. assert((unsigned) i >= table->subtables[i].next);
  574. assert((unsigned) x == table->subtables[i].next);
  575. #endif
  576. finalGroupSize = i - x + 1;
  577. if (initGroupSize == finalGroupSize) {
  578. /* No new symmetry groups detected, return to best position */
  579. result = ddSymmSiftingBackward(table,moveDown,initialSize);
  580. } else {
  581. initialSize = (int) (table->keys - table->isolated);
  582. moveUp = ddSymmSiftingUp(table,x,xLow);
  583. result = ddSymmSiftingBackward(table,moveUp,initialSize);
  584. }
  585. if (!result) goto ddSymmSiftingAuxOutOfMem;
  586. } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */
  587. /* Find top of x's symm group */
  588. i = x; /* bottom */
  589. x = table->subtables[x].next; /* top */
  590. if (x == xLow) return(1); /* just one big group */
  591. initGroupSize = i - x + 1;
  592. moveUp = ddSymmSiftingUp(table,x,xLow);
  593. /* after this point x --> xLow, unless early term */
  594. if (moveUp == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
  595. if (moveUp == NULL) return(1);
  596. x = moveUp->x;
  597. /* Find top of x's group */
  598. i = table->subtables[x].next;
  599. #ifdef DD_DEBUG
  600. /* x should be the bottom of the symmetry group and i the top */
  601. assert((unsigned) x >= table->subtables[x].next);
  602. assert((unsigned) i == table->subtables[x].next);
  603. #endif
  604. finalGroupSize = x - i + 1;
  605. if (initGroupSize == finalGroupSize) {
  606. /* No new symmetry groups detected, return to best position */
  607. result = ddSymmSiftingBackward(table,moveUp,initialSize);
  608. } else {
  609. initialSize = (int) (table->keys - table->isolated);
  610. moveDown = ddSymmSiftingDown(table,x,xHigh);
  611. result = ddSymmSiftingBackward(table,moveDown,initialSize);
  612. }
  613. if (!result) goto ddSymmSiftingAuxOutOfMem;
  614. } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
  615. moveDown = ddSymmSiftingDown(table,x,xHigh);
  616. /* at this point x == xHigh, unless early term */
  617. if (moveDown == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
  618. if (moveDown != NULL) {
  619. x = moveDown->y; /* x is top here */
  620. i = x;
  621. while ((unsigned) i < table->subtables[i].next) {
  622. i = table->subtables[i].next;
  623. }
  624. } else {
  625. i = x;
  626. while ((unsigned) i < table->subtables[i].next) {
  627. i = table->subtables[i].next;
  628. }
  629. x = table->subtables[i].next;
  630. }
  631. #ifdef DD_DEBUG
  632. /* x should be the top of the symmetry group and i the bottom */
  633. assert((unsigned) i >= table->subtables[i].next);
  634. assert((unsigned) x == table->subtables[i].next);
  635. #endif
  636. initGroupSize = i - x + 1;
  637. moveUp = ddSymmSiftingUp(table,x,xLow);
  638. if (moveUp == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
  639. if (moveUp != NULL) {
  640. x = moveUp->x;
  641. i = table->subtables[x].next;
  642. } else {
  643. i = x;
  644. while ((unsigned) x < table->subtables[x].next)
  645. x = table->subtables[x].next;
  646. }
  647. #ifdef DD_DEBUG
  648. /* x should be the bottom of the symmetry group and i the top */
  649. assert((unsigned) x >= table->subtables[x].next);
  650. assert((unsigned) i == table->subtables[x].next);
  651. #endif
  652. finalGroupSize = x - i + 1;
  653. if (initGroupSize == finalGroupSize) {
  654. /* No new symmetry groups detected, return to best position */
  655. result = ddSymmSiftingBackward(table,moveUp,initialSize);
  656. } else {
  657. while (moveDown != NULL) {
  658. move = moveDown->next;
  659. cuddDeallocMove(table, moveDown);
  660. moveDown = move;
  661. }
  662. initialSize = (int) (table->keys - table->isolated);
  663. moveDown = ddSymmSiftingDown(table,x,xHigh);
  664. result = ddSymmSiftingBackward(table,moveDown,initialSize);
  665. }
  666. if (!result) goto ddSymmSiftingAuxOutOfMem;
  667. } else { /* moving up first: shorter */
  668. /* Find top of x's symmetry group */
  669. x = table->subtables[x].next;
  670. moveUp = ddSymmSiftingUp(table,x,xLow);
  671. /* at this point x == xHigh, unless early term */
  672. if (moveUp == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
  673. if (moveUp != NULL) {
  674. x = moveUp->x;
  675. i = table->subtables[x].next;
  676. } else {
  677. while ((unsigned) x < table->subtables[x].next)
  678. x = table->subtables[x].next;
  679. i = table->subtables[x].next;
  680. }
  681. #ifdef DD_DEBUG
  682. /* x is bottom of the symmetry group and i is top */
  683. assert((unsigned) x >= table->subtables[x].next);
  684. assert((unsigned) i == table->subtables[x].next);
  685. #endif
  686. initGroupSize = x - i + 1;
  687. moveDown = ddSymmSiftingDown(table,x,xHigh);
  688. if (moveDown == MV_OOM) goto ddSymmSiftingAuxOutOfMem;
  689. if (moveDown != NULL) {
  690. x = moveDown->y;
  691. i = x;
  692. while ((unsigned) i < table->subtables[i].next) {
  693. i = table->subtables[i].next;
  694. }
  695. } else {
  696. i = x;
  697. x = table->subtables[x].next;
  698. }
  699. #ifdef DD_DEBUG
  700. /* x should be the top of the symmetry group and i the bottom */
  701. assert((unsigned) i >= table->subtables[i].next);
  702. assert((unsigned) x == table->subtables[i].next);
  703. #endif
  704. finalGroupSize = i - x + 1;
  705. if (initGroupSize == finalGroupSize) {
  706. /* No new symmetries detected, go back to best position */
  707. result = ddSymmSiftingBackward(table,moveDown,initialSize);
  708. } else {
  709. while (moveUp != NULL) {
  710. move = moveUp->next;
  711. cuddDeallocMove(table, moveUp);
  712. moveUp = move;
  713. }
  714. initialSize = (int) (table->keys - table->isolated);
  715. moveUp = ddSymmSiftingUp(table,x,xLow);
  716. result = ddSymmSiftingBackward(table,moveUp,initialSize);
  717. }
  718. if (!result) goto ddSymmSiftingAuxOutOfMem;
  719. }
  720. while (moveDown != NULL) {
  721. move = moveDown->next;
  722. cuddDeallocMove(table, moveDown);
  723. moveDown = move;
  724. }
  725. while (moveUp != NULL) {
  726. move = moveUp->next;
  727. cuddDeallocMove(table, moveUp);
  728. moveUp = move;
  729. }
  730. return(1);
  731. ddSymmSiftingAuxOutOfMem:
  732. if (moveDown != MV_OOM) {
  733. while (moveDown != NULL) {
  734. move = moveDown->next;
  735. cuddDeallocMove(table, moveDown);
  736. moveDown = move;
  737. }
  738. }
  739. if (moveUp != MV_OOM) {
  740. while (moveUp != NULL) {
  741. move = moveUp->next;
  742. cuddDeallocMove(table, moveUp);
  743. moveUp = move;
  744. }
  745. }
  746. return(0);
  747. } /* end of ddSymmSiftingAux */
  748. /**
  749. @brief Given xLow <= x <= xHigh moves x up and down between the
  750. boundaries.
  751. @details Finds the best position and does the required changes.
  752. Assumes that x is either an isolated variable, or it is the bottom of
  753. a symmetry group. All symmetries may not have been found, because of
  754. exceeded growth limit.
  755. @return 1 if successful; 0 otherwise.
  756. @sideeffect None
  757. */
  758. static int
  759. ddSymmSiftingConvAux(
  760. DdManager * table,
  761. int x,
  762. int xLow,
  763. int xHigh)
  764. {
  765. Move *move;
  766. Move *moveUp; /* list of up moves */
  767. Move *moveDown; /* list of down moves */
  768. int initialSize;
  769. int result;
  770. int i;
  771. int initGroupSize, finalGroupSize;
  772. initialSize = (int) (table->keys - table->isolated);
  773. moveDown = NULL;
  774. moveUp = NULL;
  775. if (x == xLow) { /* Sift down */
  776. #ifdef DD_DEBUG
  777. /* x is bottom of symmetry group */
  778. assert((unsigned) x >= table->subtables[x].next);
  779. #endif
  780. i = table->subtables[x].next;
  781. initGroupSize = x - i + 1;
  782. moveDown = ddSymmSiftingDown(table,x,xHigh);
  783. /* at this point x == xHigh, unless early term */
  784. if (moveDown == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
  785. if (moveDown == NULL) return(1);
  786. x = moveDown->y;
  787. i = x;
  788. while ((unsigned) i < table->subtables[i].next) {
  789. i = table->subtables[i].next;
  790. }
  791. #ifdef DD_DEBUG
  792. /* x should be the top of the symmetric group and i the bottom */
  793. assert((unsigned) i >= table->subtables[i].next);
  794. assert((unsigned) x == table->subtables[i].next);
  795. #endif
  796. finalGroupSize = i - x + 1;
  797. if (initGroupSize == finalGroupSize) {
  798. /* No new symmetries detected, go back to best position */
  799. result = ddSymmSiftingBackward(table,moveDown,initialSize);
  800. } else {
  801. initialSize = (int) (table->keys - table->isolated);
  802. moveUp = ddSymmSiftingUp(table,x,xLow);
  803. result = ddSymmSiftingBackward(table,moveUp,initialSize);
  804. }
  805. if (!result) goto ddSymmSiftingConvAuxOutOfMem;
  806. } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */
  807. /* Find top of x's symm group */
  808. while ((unsigned) x < table->subtables[x].next)
  809. x = table->subtables[x].next;
  810. i = x; /* bottom */
  811. x = table->subtables[x].next; /* top */
  812. if (x == xLow) return(1);
  813. initGroupSize = i - x + 1;
  814. moveUp = ddSymmSiftingUp(table,x,xLow);
  815. /* at this point x == xLow, unless early term */
  816. if (moveUp == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
  817. if (moveUp == NULL) return(1);
  818. x = moveUp->x;
  819. i = table->subtables[x].next;
  820. #ifdef DD_DEBUG
  821. /* x should be the bottom of the symmetry group and i the top */
  822. assert((unsigned) x >= table->subtables[x].next);
  823. assert((unsigned) i == table->subtables[x].next);
  824. #endif
  825. finalGroupSize = x - i + 1;
  826. if (initGroupSize == finalGroupSize) {
  827. /* No new symmetry groups detected, return to best position */
  828. result = ddSymmSiftingBackward(table,moveUp,initialSize);
  829. } else {
  830. initialSize = (int) (table->keys - table->isolated);
  831. moveDown = ddSymmSiftingDown(table,x,xHigh);
  832. result = ddSymmSiftingBackward(table,moveDown,initialSize);
  833. }
  834. if (!result)
  835. goto ddSymmSiftingConvAuxOutOfMem;
  836. } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */
  837. moveDown = ddSymmSiftingDown(table,x,xHigh);
  838. /* at this point x == xHigh, unless early term */
  839. if (moveDown == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
  840. if (moveDown != NULL) {
  841. x = moveDown->y;
  842. i = x;
  843. while ((unsigned) i < table->subtables[i].next) {
  844. i = table->subtables[i].next;
  845. }
  846. } else {
  847. while ((unsigned) x < table->subtables[x].next)
  848. x = table->subtables[x].next;
  849. i = x;
  850. x = table->subtables[x].next;
  851. }
  852. #ifdef DD_DEBUG
  853. /* x should be the top of the symmetry group and i the bottom */
  854. assert((unsigned) i >= table->subtables[i].next);
  855. assert((unsigned) x == table->subtables[i].next);
  856. #endif
  857. initGroupSize = i - x + 1;
  858. moveUp = ddSymmSiftingUp(table,x,xLow);
  859. if (moveUp == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
  860. if (moveUp != NULL) {
  861. x = moveUp->x;
  862. i = table->subtables[x].next;
  863. } else {
  864. i = x;
  865. while ((unsigned) x < table->subtables[x].next)
  866. x = table->subtables[x].next;
  867. }
  868. #ifdef DD_DEBUG
  869. /* x should be the bottom of the symmetry group and i the top */
  870. assert((unsigned) x >= table->subtables[x].next);
  871. assert((unsigned) i == table->subtables[x].next);
  872. #endif
  873. finalGroupSize = x - i + 1;
  874. if (initGroupSize == finalGroupSize) {
  875. /* No new symmetry groups detected, return to best position */
  876. result = ddSymmSiftingBackward(table,moveUp,initialSize);
  877. } else {
  878. while (moveDown != NULL) {
  879. move = moveDown->next;
  880. cuddDeallocMove(table, moveDown);
  881. moveDown = move;
  882. }
  883. initialSize = (int) (table->keys - table->isolated);
  884. moveDown = ddSymmSiftingDown(table,x,xHigh);
  885. result = ddSymmSiftingBackward(table,moveDown,initialSize);
  886. }
  887. if (!result) goto ddSymmSiftingConvAuxOutOfMem;
  888. } else { /* moving up first: shorter */
  889. /* Find top of x's symmetry group */
  890. x = table->subtables[x].next;
  891. moveUp = ddSymmSiftingUp(table,x,xLow);
  892. /* at this point x == xHigh, unless early term */
  893. if (moveUp == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
  894. if (moveUp != NULL) {
  895. x = moveUp->x;
  896. i = table->subtables[x].next;
  897. } else {
  898. i = x;
  899. while ((unsigned) x < table->subtables[x].next)
  900. x = table->subtables[x].next;
  901. }
  902. #ifdef DD_DEBUG
  903. /* x is bottom of the symmetry group and i is top */
  904. assert((unsigned) x >= table->subtables[x].next);
  905. assert((unsigned) i == table->subtables[x].next);
  906. #endif
  907. initGroupSize = x - i + 1;
  908. moveDown = ddSymmSiftingDown(table,x,xHigh);
  909. if (moveDown == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem;
  910. if (moveDown != NULL) {
  911. x = moveDown->y;
  912. i = x;
  913. while ((unsigned) i < table->subtables[i].next) {
  914. i = table->subtables[i].next;
  915. }
  916. } else {
  917. i = x;
  918. x = table->subtables[x].next;
  919. }
  920. #ifdef DD_DEBUG
  921. /* x should be the top of the symmetry group and i the bottom */
  922. assert((unsigned) i >= table->subtables[i].next);
  923. assert((unsigned) x == table->subtables[i].next);
  924. #endif
  925. finalGroupSize = i - x + 1;
  926. if (initGroupSize == finalGroupSize) {
  927. /* No new symmetries detected, go back to best position */
  928. result = ddSymmSiftingBackward(table,moveDown,initialSize);
  929. } else {
  930. while (moveUp != NULL) {
  931. move = moveUp->next;
  932. cuddDeallocMove(table, moveUp);
  933. moveUp = move;
  934. }
  935. initialSize = (int) (table->keys - table->isolated);
  936. moveUp = ddSymmSiftingUp(table,x,xLow);
  937. result = ddSymmSiftingBackward(table,moveUp,initialSize);
  938. }
  939. if (!result) goto ddSymmSiftingConvAuxOutOfMem;
  940. }
  941. while (moveDown != NULL) {
  942. move = moveDown->next;
  943. cuddDeallocMove(table, moveDown);
  944. moveDown = move;
  945. }
  946. while (moveUp != NULL) {
  947. move = moveUp->next;
  948. cuddDeallocMove(table, moveUp);
  949. moveUp = move;
  950. }
  951. return(1);
  952. ddSymmSiftingConvAuxOutOfMem:
  953. if (moveDown != MV_OOM) {
  954. while (moveDown != NULL) {
  955. move = moveDown->next;
  956. cuddDeallocMove(table, moveDown);
  957. moveDown = move;
  958. }
  959. }
  960. if (moveUp != MV_OOM) {
  961. while (moveUp != NULL) {
  962. move = moveUp->next;
  963. cuddDeallocMove(table, moveUp);
  964. moveUp = move;
  965. }
  966. }
  967. return(0);
  968. } /* end of ddSymmSiftingConvAux */
  969. /**
  970. @brief Moves x up until either it reaches the bound (xLow) or
  971. the size of the %DD heap increases too much.
  972. @details Assumes that x is the top of a symmetry group. Checks x
  973. for symmetry to the adjacent variables. If symmetry is found, the
  974. symmetry group of x is merged with the symmetry group of the other
  975. variable.
  976. @return the set of moves in case of success; MV_OOM if memory is
  977. full.
  978. @sideeffect None
  979. */
  980. static Move *
  981. ddSymmSiftingUp(
  982. DdManager * table,
  983. int y,
  984. int xLow)
  985. {
  986. Move *moves;
  987. Move *move;
  988. int x;
  989. int size;
  990. int i;
  991. int gxtop,gybot;
  992. int limitSize;
  993. int xindex, yindex;
  994. int zindex;
  995. int z;
  996. int isolated;
  997. int L; /* lower bound on DD size */
  998. #ifdef DD_DEBUG
  999. int checkL;
  1000. #endif
  1001. moves = NULL;
  1002. yindex = table->invperm[y];
  1003. /* Initialize the lower bound.
  1004. ** The part of the DD below the bottom of y' group will not change.
  1005. ** The part of the DD above y that does not interact with y will not
  1006. ** change. The rest may vanish in the best case, except for
  1007. ** the nodes at level xLow, which will not vanish, regardless.
  1008. */
  1009. limitSize = L = (int) (table->keys - table->isolated);
  1010. gybot = y;
  1011. while ((unsigned) gybot < table->subtables[gybot].next)
  1012. gybot = table->subtables[gybot].next;
  1013. for (z = xLow + 1; z <= gybot; z++) {
  1014. zindex = table->invperm[z];
  1015. if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
  1016. isolated = table->vars[zindex]->ref == 1;
  1017. L -= (int) table->subtables[z].keys - isolated;
  1018. }
  1019. }
  1020. x = cuddNextLow(table,y);
  1021. while (x >= xLow && L <= limitSize) {
  1022. #ifdef DD_DEBUG
  1023. gybot = y;
  1024. while ((unsigned) gybot < table->subtables[gybot].next)
  1025. gybot = table->subtables[gybot].next;
  1026. checkL = (int) (table->keys - table->isolated);
  1027. for (z = xLow + 1; z <= gybot; z++) {
  1028. zindex = table->invperm[z];
  1029. if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
  1030. isolated = table->vars[zindex]->ref == 1;
  1031. checkL -= (int) table->subtables[z].keys - isolated;
  1032. }
  1033. }
  1034. assert(L == checkL);
  1035. #endif
  1036. gxtop = table->subtables[x].next;
  1037. if (cuddSymmCheck(table,x,y)) {
  1038. /* Symmetry found, attach symm groups */
  1039. table->subtables[x].next = y;
  1040. i = table->subtables[y].next;
  1041. while (table->subtables[i].next != (unsigned) y)
  1042. i = table->subtables[i].next;
  1043. table->subtables[i].next = gxtop;
  1044. } else if (table->subtables[x].next == (unsigned) x &&
  1045. table->subtables[y].next == (unsigned) y) {
  1046. /* x and y have self symmetry */
  1047. xindex = table->invperm[x];
  1048. size = cuddSwapInPlace(table,x,y);
  1049. #ifdef DD_DEBUG
  1050. assert(table->subtables[x].next == (unsigned) x);
  1051. assert(table->subtables[y].next == (unsigned) y);
  1052. #endif
  1053. if (size == 0) goto ddSymmSiftingUpOutOfMem;
  1054. /* Update the lower bound. */
  1055. if (cuddTestInteract(table,xindex,yindex)) {
  1056. isolated = table->vars[xindex]->ref == 1;
  1057. L += (int) table->subtables[y].keys - isolated;
  1058. }
  1059. move = (Move *) cuddDynamicAllocNode(table);
  1060. if (move == NULL) goto ddSymmSiftingUpOutOfMem;
  1061. move->x = x;
  1062. move->y = y;
  1063. move->size = size;
  1064. move->next = moves;
  1065. moves = move;
  1066. if ((double) size > (double) limitSize * table->maxGrowth)
  1067. return(moves);
  1068. if (size < limitSize) limitSize = size;
  1069. } else { /* Group move */
  1070. size = ddSymmGroupMove(table,x,y,&moves);
  1071. if (size == 0) goto ddSymmSiftingUpOutOfMem;
  1072. /* Update the lower bound. */
  1073. z = moves->y;
  1074. do {
  1075. zindex = table->invperm[z];
  1076. if (cuddTestInteract(table,zindex,yindex)) {
  1077. isolated = table->vars[zindex]->ref == 1;
  1078. L += (int) table->subtables[z].keys - isolated;
  1079. }
  1080. z = table->subtables[z].next;
  1081. } while (z != (int) moves->y);
  1082. if ((double) size > (double) limitSize * table->maxGrowth)
  1083. return(moves);
  1084. if (size < limitSize) limitSize = size;
  1085. }
  1086. y = gxtop;
  1087. x = cuddNextLow(table,y);
  1088. }
  1089. return(moves);
  1090. ddSymmSiftingUpOutOfMem:
  1091. while (moves != NULL) {
  1092. move = moves->next;
  1093. cuddDeallocMove(table, moves);
  1094. moves = move;
  1095. }
  1096. return(MV_OOM);
  1097. } /* end of ddSymmSiftingUp */
  1098. /**
  1099. @brief Moves x down until either it reaches the bound (xHigh) or
  1100. the size of the %DD heap increases too much.
  1101. @details Assumes that x is the bottom of a symmetry group. Checks x
  1102. for symmetry to the adjacent variables. If symmetry is found, the
  1103. symmetry group of x is merged with the symmetry group of the other
  1104. variable.
  1105. @return the set of moves in case of success; MV_OOM if memory is
  1106. full.
  1107. @sideeffect None
  1108. */
  1109. static Move *
  1110. ddSymmSiftingDown(
  1111. DdManager * table,
  1112. int x,
  1113. int xHigh)
  1114. {
  1115. Move *moves;
  1116. Move *move;
  1117. int y;
  1118. int size;
  1119. int limitSize;
  1120. int gxtop,gybot;
  1121. int R; /* upper bound on node decrease */
  1122. int xindex, yindex;
  1123. int isolated;
  1124. int z;
  1125. int zindex;
  1126. #ifdef DD_DEBUG
  1127. int checkR;
  1128. #endif
  1129. moves = NULL;
  1130. /* Initialize R */
  1131. xindex = table->invperm[x];
  1132. gxtop = table->subtables[x].next;
  1133. limitSize = size = (int) (table->keys - table->isolated);
  1134. R = 0;
  1135. for (z = xHigh; z > gxtop; z--) {
  1136. zindex = table->invperm[z];
  1137. if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
  1138. isolated = table->vars[zindex]->ref == 1;
  1139. R += (int) table->subtables[z].keys - isolated;
  1140. }
  1141. }
  1142. y = cuddNextHigh(table,x);
  1143. while (y <= xHigh && size - R < limitSize) {
  1144. #ifdef DD_DEBUG
  1145. gxtop = table->subtables[x].next;
  1146. checkR = 0;
  1147. for (z = xHigh; z > gxtop; z--) {
  1148. zindex = table->invperm[z];
  1149. if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
  1150. isolated = table->vars[zindex]->ref == 1;
  1151. checkR += (int) table->subtables[z].keys - isolated;
  1152. }
  1153. }
  1154. assert(R == checkR);
  1155. #endif
  1156. gybot = table->subtables[y].next;
  1157. while (table->subtables[gybot].next != (unsigned) y)
  1158. gybot = table->subtables[gybot].next;
  1159. if (cuddSymmCheck(table,x,y)) {
  1160. /* Symmetry found, attach symm groups */
  1161. gxtop = table->subtables[x].next;
  1162. table->subtables[x].next = y;
  1163. table->subtables[gybot].next = gxtop;
  1164. } else if (table->subtables[x].next == (unsigned) x &&
  1165. table->subtables[y].next == (unsigned) y) {
  1166. /* x and y have self symmetry */
  1167. /* Update upper bound on node decrease. */
  1168. yindex = table->invperm[y];
  1169. if (cuddTestInteract(table,xindex,yindex)) {
  1170. isolated = table->vars[yindex]->ref == 1;
  1171. R -= (int) table->subtables[y].keys - isolated;
  1172. }
  1173. size = cuddSwapInPlace(table,x,y);
  1174. #ifdef DD_DEBUG
  1175. assert(table->subtables[x].next == (unsigned) x);
  1176. assert(table->subtables[y].next == (unsigned) y);
  1177. #endif
  1178. if (size == 0) goto ddSymmSiftingDownOutOfMem;
  1179. move = (Move *) cuddDynamicAllocNode(table);
  1180. if (move == NULL) goto ddSymmSiftingDownOutOfMem;
  1181. move->x = x;
  1182. move->y = y;
  1183. move->size = size;
  1184. move->next = moves;
  1185. moves = move;
  1186. if ((double) size > (double) limitSize * table->maxGrowth)
  1187. return(moves);
  1188. if (size < limitSize) limitSize = size;
  1189. } else { /* Group move */
  1190. /* Update upper bound on node decrease: first phase. */
  1191. gxtop = table->subtables[x].next;
  1192. z = gxtop + 1;
  1193. do {
  1194. zindex = table->invperm[z];
  1195. if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
  1196. isolated = table->vars[zindex]->ref == 1;
  1197. R -= (int) table->subtables[z].keys - isolated;
  1198. }
  1199. z++;
  1200. } while (z <= gybot);
  1201. size = ddSymmGroupMove(table,x,y,&moves);
  1202. if (size == 0) goto ddSymmSiftingDownOutOfMem;
  1203. if ((double) size > (double) limitSize * table->maxGrowth)
  1204. return(moves);
  1205. if (size < limitSize) limitSize = size;
  1206. /* Update upper bound on node decrease: second phase. */
  1207. gxtop = table->subtables[gybot].next;
  1208. for (z = gxtop + 1; z <= gybot; z++) {
  1209. zindex = table->invperm[z];
  1210. if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
  1211. isolated = table->vars[zindex]->ref == 1;
  1212. R += (int) table->subtables[z].keys - isolated;
  1213. }
  1214. }
  1215. }
  1216. x = gybot;
  1217. y = cuddNextHigh(table,x);
  1218. }
  1219. return(moves);
  1220. ddSymmSiftingDownOutOfMem:
  1221. while (moves != NULL) {
  1222. move = moves->next;
  1223. cuddDeallocMove(table, moves);
  1224. moves = move;
  1225. }
  1226. return(MV_OOM);
  1227. } /* end of ddSymmSiftingDown */
  1228. /**
  1229. @brief Swaps two groups.
  1230. @details x is assumed to be the bottom variable of the first
  1231. group. y is assumed to be the top variable of the second group.
  1232. Updates the list of moves.
  1233. @return the number of keys in the table if successful; 0 otherwise.
  1234. @sideeffect None
  1235. */
  1236. static int
  1237. ddSymmGroupMove(
  1238. DdManager * table,
  1239. int x,
  1240. int y,
  1241. Move ** moves)
  1242. {
  1243. Move *move;
  1244. int size = 0;
  1245. int i,j;
  1246. int xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
  1247. int swapx = 0, swapy = 0;
  1248. #ifdef DD_DEBUG
  1249. assert(x < y); /* we assume that x < y */
  1250. #endif
  1251. /* Find top, bottom, and size for the two groups. */
  1252. xbot = x;
  1253. xtop = table->subtables[x].next;
  1254. xsize = xbot - xtop + 1;
  1255. ybot = y;
  1256. while ((unsigned) ybot < table->subtables[ybot].next)
  1257. ybot = table->subtables[ybot].next;
  1258. ytop = y;
  1259. ysize = ybot - ytop + 1;
  1260. /* Sift the variables of the second group up through the first group. */
  1261. for (i = 1; i <= ysize; i++) {
  1262. for (j = 1; j <= xsize; j++) {
  1263. size = cuddSwapInPlace(table,x,y);
  1264. if (size == 0) return(0);
  1265. swapx = x; swapy = y;
  1266. y = x;
  1267. x = y - 1;
  1268. }
  1269. y = ytop + i;
  1270. x = y - 1;
  1271. }
  1272. /* fix symmetries */
  1273. y = xtop; /* ytop is now where xtop used to be */
  1274. for (i = 0; i < ysize-1 ; i++) {
  1275. table->subtables[y].next = y + 1;
  1276. y = y + 1;
  1277. }
  1278. table->subtables[y].next = xtop; /* y is bottom of its group, join */
  1279. /* its symmetry to top of its group */
  1280. x = y + 1;
  1281. newxtop = x;
  1282. for (i = 0; i < xsize - 1 ; i++) {
  1283. table->subtables[x].next = x + 1;
  1284. x = x + 1;
  1285. }
  1286. table->subtables[x].next = newxtop; /* x is bottom of its group, join */
  1287. /* its symmetry to top of its group */
  1288. /* Store group move */
  1289. move = (Move *) cuddDynamicAllocNode(table);
  1290. if (move == NULL) return(0);
  1291. move->x = swapx;
  1292. move->y = swapy;
  1293. move->size = size;
  1294. move->next = *moves;
  1295. *moves = move;
  1296. return(size);
  1297. } /* end of ddSymmGroupMove */
  1298. /**
  1299. @brief Undoes the swap of two groups.
  1300. @details x is assumed to be the bottom variable of the first
  1301. group. y is assumed to be the top variable of the second group.
  1302. @return the number of keys in the table if successful; 0 otherwise.
  1303. @sideeffect None
  1304. */
  1305. static int
  1306. ddSymmGroupMoveBackward(
  1307. DdManager * table,
  1308. int x,
  1309. int y)
  1310. {
  1311. int size = (int) (table->keys - table->isolated);
  1312. int i,j;
  1313. int xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
  1314. #ifdef DD_DEBUG
  1315. assert(x < y); /* We assume that x < y */
  1316. #endif
  1317. /* Find top, bottom, and size for the two groups. */
  1318. xbot = x;
  1319. xtop = table->subtables[x].next;
  1320. xsize = xbot - xtop + 1;
  1321. ybot = y;
  1322. while ((unsigned) ybot < table->subtables[ybot].next)
  1323. ybot = table->subtables[ybot].next;
  1324. ytop = y;
  1325. ysize = ybot - ytop + 1;
  1326. #ifdef DD_DEBUG
  1327. assert(xsize > 0);
  1328. assert(ysize > 0);
  1329. #endif
  1330. /* Sift the variables of the second group up through the first group. */
  1331. for (i = 1; i <= ysize; i++) {
  1332. for (j = 1; j <= xsize; j++) {
  1333. size = cuddSwapInPlace(table,x,y);
  1334. if (size == 0) return(0);
  1335. y = x;
  1336. x = cuddNextLow(table,y);
  1337. }
  1338. y = ytop + i;
  1339. x = y - 1;
  1340. }
  1341. /* Fix symmetries. */
  1342. y = xtop;
  1343. for (i = 0; i < ysize-1 ; i++) {
  1344. table->subtables[y].next = y + 1;
  1345. y = y + 1;
  1346. }
  1347. table->subtables[y].next = xtop; /* y is bottom of its group, join */
  1348. /* its symmetry to top of its group */
  1349. x = y + 1;
  1350. newxtop = x;
  1351. for (i = 0; i < xsize-1 ; i++) {
  1352. table->subtables[x].next = x + 1;
  1353. x = x + 1;
  1354. }
  1355. table->subtables[x].next = newxtop; /* x is bottom of its group, join */
  1356. /* its symmetry to top of its group */
  1357. return(size);
  1358. } /* end of ddSymmGroupMoveBackward */
  1359. /**
  1360. @brief Given a set of moves, returns the %DD heap to the position
  1361. giving the minimum size.
  1362. @details In case of ties, returns to the closest position giving the
  1363. minimum size.
  1364. @return 1 in case of success; 0 otherwise.
  1365. @sideeffect None
  1366. */
  1367. static int
  1368. ddSymmSiftingBackward(
  1369. DdManager * table,
  1370. Move * moves,
  1371. int size)
  1372. {
  1373. Move *move;
  1374. int res;
  1375. for (move = moves; move != NULL; move = move->next) {
  1376. if (move->size < size) {
  1377. size = move->size;
  1378. }
  1379. }
  1380. for (move = moves; move != NULL; move = move->next) {
  1381. if (move->size == size) return(1);
  1382. if (table->subtables[move->x].next == move->x && table->subtables[move->y].next == move->y) {
  1383. res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
  1384. #ifdef DD_DEBUG
  1385. assert(table->subtables[move->x].next == move->x);
  1386. assert(table->subtables[move->y].next == move->y);
  1387. #endif
  1388. } else { /* Group move necessary */
  1389. res = ddSymmGroupMoveBackward(table,(int)move->x,(int)move->y);
  1390. }
  1391. if (!res) return(0);
  1392. }
  1393. return(1);
  1394. } /* end of ddSymmSiftingBackward */
  1395. /**
  1396. @brief Counts numbers of symmetric variables and symmetry groups.
  1397. @sideeffect None
  1398. */
  1399. static void
  1400. ddSymmSummary(
  1401. DdManager * table,
  1402. int lower,
  1403. int upper,
  1404. int * symvars,
  1405. int * symgroups)
  1406. {
  1407. int i,x,gbot;
  1408. int TotalSymm = 0;
  1409. int TotalSymmGroups = 0;
  1410. for (i = lower; i <= upper; i++) {
  1411. if (table->subtables[i].next != (unsigned) i) {
  1412. TotalSymmGroups++;
  1413. x = i;
  1414. do {
  1415. TotalSymm++;
  1416. gbot = x;
  1417. x = table->subtables[x].next;
  1418. } while (x != i);
  1419. #ifdef DD_DEBUG
  1420. assert(table->subtables[gbot].next == (unsigned) i);
  1421. #endif
  1422. i = gbot;
  1423. }
  1424. }
  1425. *symvars = TotalSymm;
  1426. *symgroups = TotalSymmGroups;
  1427. return;
  1428. } /* end of ddSymmSummary */