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.

2096 lines
56 KiB

2 months ago
  1. /**
  2. @file
  3. @ingroup cudd
  4. @brief Functions for group sifting.
  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 "mtrInt.h"
  36. #include "cuddInt.h"
  37. /*---------------------------------------------------------------------------*/
  38. /* Constant declarations */
  39. /*---------------------------------------------------------------------------*/
  40. /* Constants for lazy sifting */
  41. #define DD_NORMAL_SIFT 0
  42. #define DD_LAZY_SIFT 1
  43. /* Constants for sifting up and down */
  44. #define DD_SIFT_DOWN 0
  45. #define DD_SIFT_UP 1
  46. /*---------------------------------------------------------------------------*/
  47. /* Stucture declarations */
  48. /*---------------------------------------------------------------------------*/
  49. /*---------------------------------------------------------------------------*/
  50. /* Type declarations */
  51. /*---------------------------------------------------------------------------*/
  52. typedef int (*DD_CHKFP)(DdManager *, int, int);
  53. /*---------------------------------------------------------------------------*/
  54. /* Variable declarations */
  55. /*---------------------------------------------------------------------------*/
  56. /*---------------------------------------------------------------------------*/
  57. /* Macro declarations */
  58. /*---------------------------------------------------------------------------*/
  59. /** \cond */
  60. /*---------------------------------------------------------------------------*/
  61. /* Static function prototypes */
  62. /*---------------------------------------------------------------------------*/
  63. static int ddTreeSiftingAux (DdManager *table, MtrNode *treenode, Cudd_ReorderingType method);
  64. #ifdef DD_STATS
  65. static int ddCountInternalMtrNodes (DdManager *table, MtrNode *treenode);
  66. #endif
  67. static int ddReorderChildren (DdManager *table, MtrNode *treenode, Cudd_ReorderingType method);
  68. static void ddFindNodeHiLo (DdManager *table, MtrNode *treenode, int *lower, int *upper);
  69. static int ddUniqueCompareGroup (void const *ptrX, void const *ptrY);
  70. static int ddGroupSifting (DdManager *table, int lower, int upper, DD_CHKFP checkFunction, int lazyFlag);
  71. static void ddCreateGroup (DdManager *table, int x, int y);
  72. static int ddGroupSiftingAux (DdManager *table, int x, int xLow, int xHigh, DD_CHKFP checkFunction, int lazyFlag);
  73. static int ddGroupSiftingUp (DdManager *table, int y, int xLow, DD_CHKFP checkFunction, Move **moves);
  74. static int ddGroupSiftingDown (DdManager *table, int x, int xHigh, DD_CHKFP checkFunction, Move **moves);
  75. static int ddGroupMove (DdManager *table, int x, int y, Move **moves);
  76. static int ddGroupMoveBackward (DdManager *table, int x, int y);
  77. static int ddGroupSiftingBackward (DdManager *table, Move *moves, int size, int upFlag, int lazyFlag);
  78. static void ddMergeGroups (DdManager *table, MtrNode *treenode, int low, int high);
  79. static void ddDissolveGroup (DdManager *table, int x, int y);
  80. static int ddNoCheck (DdManager *table, int x, int y);
  81. static int ddSecDiffCheck (DdManager *table, int x, int y);
  82. static int ddExtSymmCheck (DdManager *table, int x, int y);
  83. static int ddVarGroupCheck (DdManager * table, int x, int y);
  84. static int ddSetVarHandled (DdManager *dd, int index);
  85. static int ddResetVarHandled (DdManager *dd, int index);
  86. static int ddIsVarHandled (DdManager *dd, int index);
  87. /** \endcond */
  88. /*---------------------------------------------------------------------------*/
  89. /* Definition of exported functions */
  90. /*---------------------------------------------------------------------------*/
  91. /**
  92. @brief Creates a new variable group.
  93. @details The group starts at variable low and contains size
  94. variables. The parameter low is the index of the first variable. If
  95. the variable already exists, its current position in the order is
  96. known to the manager. If the variable does not exist yet, the
  97. position is assumed to be the same as the index. The group tree is
  98. created if it does not exist yet.
  99. @return a pointer to the group if successful; NULL otherwise.
  100. @sideeffect The variable tree is changed.
  101. @see Cudd_MakeZddTreeNode
  102. */
  103. MtrNode *
  104. Cudd_MakeTreeNode(
  105. DdManager * dd /**< manager */,
  106. unsigned int low /**< index of the first group variable */,
  107. unsigned int size /**< number of variables in the group */,
  108. unsigned int type /**< MTR_DEFAULT or MTR_FIXED */)
  109. {
  110. MtrNode *group;
  111. MtrNode *tree;
  112. unsigned int level;
  113. /* If the variable does not exist yet, the position is assumed to be
  114. ** the same as the index. Therefore, applications that rely on
  115. ** Cudd_bddNewVarAtLevel or Cudd_addNewVarAtLevel to create new
  116. ** variables have to create the variables before they group them.
  117. */
  118. level = (low < (unsigned int) dd->size) ? (unsigned int) dd->perm[low] : low;
  119. if (level + size - 1> (int) MTR_MAXHIGH)
  120. return(NULL);
  121. /* If the tree does not exist yet, create it. */
  122. tree = dd->tree;
  123. if (tree == NULL) {
  124. dd->tree = tree = Mtr_InitGroupTree(0, dd->size);
  125. if (tree == NULL)
  126. return(NULL);
  127. tree->index = dd->size == 0 ? 0 : dd->invperm[0];
  128. }
  129. /* Extend the upper bound of the tree if necessary. This allows the
  130. ** application to create groups even before the variables are created.
  131. */
  132. tree->size = ddMax(tree->size, ddMax(level + size, (unsigned) dd->size));
  133. /* Create the group. */
  134. group = Mtr_MakeGroup(tree, level, size, type);
  135. if (group == NULL)
  136. return(NULL);
  137. /* Initialize the index field to the index of the variable currently
  138. ** in position low. This field will be updated by the reordering
  139. ** procedure to provide a handle to the group once it has been moved.
  140. */
  141. group->index = (MtrHalfWord) low;
  142. return(group);
  143. } /* end of Cudd_MakeTreeNode */
  144. /*---------------------------------------------------------------------------*/
  145. /* Definition of internal functions */
  146. /*---------------------------------------------------------------------------*/
  147. /**
  148. @brief Tree sifting algorithm.
  149. @details Assumes that a tree representing a group hierarchy is
  150. passed as a parameter. It then reorders each group in postorder
  151. fashion by calling ddTreeSiftingAux. Assumes that no dead nodes are
  152. present.
  153. @return 1 if successful; 0 otherwise.
  154. @sideeffect None
  155. */
  156. int
  157. cuddTreeSifting(
  158. DdManager * table /**< %DD table */,
  159. Cudd_ReorderingType method /**< reordering method for the groups of leaves */)
  160. {
  161. int i;
  162. int nvars;
  163. int result;
  164. int tempTree;
  165. /* If no tree is provided we create a temporary one in which all
  166. ** variables are in a single group. After reordering this tree is
  167. ** destroyed.
  168. */
  169. tempTree = table->tree == NULL;
  170. if (tempTree) {
  171. table->tree = Mtr_InitGroupTree(0,table->size);
  172. table->tree->index = table->invperm[0];
  173. }
  174. nvars = table->size;
  175. #ifdef DD_DEBUG
  176. if (table->enableExtraDebug > 0 && !tempTree)
  177. (void) fprintf(table->out,"cuddTreeSifting:");
  178. Mtr_PrintGroups(table->tree,table->enableExtraDebug <= 0);
  179. #endif
  180. #ifdef DD_STATS
  181. table->extsymmcalls = 0;
  182. table->extsymm = 0;
  183. table->secdiffcalls = 0;
  184. table->secdiff = 0;
  185. table->secdiffmisfire = 0;
  186. (void) fprintf(table->out,"\n");
  187. if (!tempTree)
  188. (void) fprintf(table->out,"#:IM_NODES %8d: group tree nodes\n",
  189. ddCountInternalMtrNodes(table,table->tree));
  190. #endif
  191. /* Initialize the group of each subtable to itself. Initially
  192. ** there are no groups. Groups are created according to the tree
  193. ** structure in postorder fashion.
  194. */
  195. for (i = 0; i < nvars; i++)
  196. table->subtables[i].next = i;
  197. /* Reorder. */
  198. result = ddTreeSiftingAux(table, table->tree, method);
  199. #ifdef DD_STATS /* print stats */
  200. if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
  201. (table->groupcheck == CUDD_GROUP_CHECK7 ||
  202. table->groupcheck == CUDD_GROUP_CHECK5)) {
  203. (void) fprintf(table->out,"\nextsymmcalls = %d\n",table->extsymmcalls);
  204. (void) fprintf(table->out,"extsymm = %d",table->extsymm);
  205. }
  206. if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
  207. table->groupcheck == CUDD_GROUP_CHECK7) {
  208. (void) fprintf(table->out,"\nsecdiffcalls = %d\n",table->secdiffcalls);
  209. (void) fprintf(table->out,"secdiff = %d\n",table->secdiff);
  210. (void) fprintf(table->out,"secdiffmisfire = %d",table->secdiffmisfire);
  211. }
  212. #endif
  213. if (tempTree)
  214. Cudd_FreeTree(table);
  215. else
  216. Mtr_ReorderGroups(table->tree, table->perm);
  217. return(result);
  218. } /* end of cuddTreeSifting */
  219. /*---------------------------------------------------------------------------*/
  220. /* Definition of static functions */
  221. /*---------------------------------------------------------------------------*/
  222. /**
  223. @brief Visits the group tree and reorders each group.
  224. @details Recursively visits the group tree and reorders each
  225. group in postorder fashion.
  226. @return 1 if successful; 0 otherwise.
  227. @sideeffect None
  228. */
  229. static int
  230. ddTreeSiftingAux(
  231. DdManager * table,
  232. MtrNode * treenode,
  233. Cudd_ReorderingType method)
  234. {
  235. MtrNode *auxnode;
  236. int res;
  237. Cudd_AggregationType saveCheck;
  238. #ifdef DD_DEBUG
  239. Mtr_PrintGroups(treenode,1);
  240. #endif
  241. auxnode = treenode;
  242. while (auxnode != NULL) {
  243. if (auxnode->child != NULL) {
  244. if (!ddTreeSiftingAux(table, auxnode->child, method))
  245. return(0);
  246. saveCheck = table->groupcheck;
  247. table->groupcheck = CUDD_NO_CHECK;
  248. if (method != CUDD_REORDER_LAZY_SIFT)
  249. res = ddReorderChildren(table, auxnode, CUDD_REORDER_GROUP_SIFT);
  250. else
  251. res = ddReorderChildren(table, auxnode, CUDD_REORDER_LAZY_SIFT);
  252. table->groupcheck = saveCheck;
  253. if (res == 0)
  254. return(0);
  255. } else if (auxnode->size > 1) {
  256. if (!ddReorderChildren(table, auxnode, method))
  257. return(0);
  258. }
  259. auxnode = auxnode->younger;
  260. }
  261. return(1);
  262. } /* end of ddTreeSiftingAux */
  263. #ifdef DD_STATS
  264. /**
  265. @brief Counts the number of internal nodes of the group tree.
  266. @return the count.
  267. @sideeffect None
  268. */
  269. static int
  270. ddCountInternalMtrNodes(
  271. DdManager * table,
  272. MtrNode * treenode)
  273. {
  274. MtrNode *auxnode;
  275. int count,nodeCount;
  276. nodeCount = 0;
  277. auxnode = treenode;
  278. while (auxnode != NULL) {
  279. if (!(MTR_TEST(auxnode,MTR_TERMINAL))) {
  280. nodeCount++;
  281. count = ddCountInternalMtrNodes(table,auxnode->child);
  282. nodeCount += count;
  283. }
  284. auxnode = auxnode->younger;
  285. }
  286. return(nodeCount);
  287. } /* end of ddCountInternalMtrNodes */
  288. #endif
  289. /**
  290. @brief Reorders the children of a group tree node according to
  291. the options.
  292. @details After reordering puts all the variables in the group and/or
  293. its descendents in a single group. This allows hierarchical
  294. reordering. If the variables in the group do not exist yet, simply
  295. does nothing.
  296. @return 1 if successful; 0 otherwise.
  297. @sideeffect None
  298. */
  299. static int
  300. ddReorderChildren(
  301. DdManager * table,
  302. MtrNode * treenode,
  303. Cudd_ReorderingType method)
  304. {
  305. int lower;
  306. int upper = 0;
  307. int result;
  308. unsigned int initialSize;
  309. ddFindNodeHiLo(table,treenode,&lower,&upper);
  310. /* If upper == -1 these variables do not exist yet. */
  311. if (upper == -1)
  312. return(1);
  313. if (treenode->flags == MTR_FIXED) {
  314. result = 1;
  315. } else {
  316. #ifdef DD_STATS
  317. (void) fprintf(table->out," ");
  318. #endif
  319. switch (method) {
  320. case CUDD_REORDER_RANDOM:
  321. case CUDD_REORDER_RANDOM_PIVOT:
  322. result = cuddSwapping(table,lower,upper,method);
  323. break;
  324. case CUDD_REORDER_SIFT:
  325. result = cuddSifting(table,lower,upper);
  326. break;
  327. case CUDD_REORDER_SIFT_CONVERGE:
  328. do {
  329. initialSize = table->keys - table->isolated;
  330. result = cuddSifting(table,lower,upper);
  331. if (initialSize <= table->keys - table->isolated)
  332. break;
  333. #ifdef DD_STATS
  334. else
  335. (void) fprintf(table->out,"\n");
  336. #endif
  337. } while (result != 0);
  338. break;
  339. case CUDD_REORDER_SYMM_SIFT:
  340. result = cuddSymmSifting(table,lower,upper);
  341. break;
  342. case CUDD_REORDER_SYMM_SIFT_CONV:
  343. result = cuddSymmSiftingConv(table,lower,upper);
  344. break;
  345. case CUDD_REORDER_GROUP_SIFT:
  346. if (table->groupcheck == CUDD_NO_CHECK) {
  347. result = ddGroupSifting(table,lower,upper,ddNoCheck,
  348. DD_NORMAL_SIFT);
  349. } else if (table->groupcheck == CUDD_GROUP_CHECK5) {
  350. result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
  351. DD_NORMAL_SIFT);
  352. } else if (table->groupcheck == CUDD_GROUP_CHECK7) {
  353. result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
  354. DD_NORMAL_SIFT);
  355. } else {
  356. (void) fprintf(table->err,
  357. "Unknown group ckecking method\n");
  358. result = 0;
  359. }
  360. break;
  361. case CUDD_REORDER_GROUP_SIFT_CONV:
  362. do {
  363. initialSize = table->keys - table->isolated;
  364. if (table->groupcheck == CUDD_NO_CHECK) {
  365. (void) ddGroupSifting(table,lower,upper,ddNoCheck,
  366. DD_NORMAL_SIFT);
  367. } else if (table->groupcheck == CUDD_GROUP_CHECK5) {
  368. (void) ddGroupSifting(table,lower,upper,ddExtSymmCheck,
  369. DD_NORMAL_SIFT);
  370. } else if (table->groupcheck == CUDD_GROUP_CHECK7) {
  371. (void) ddGroupSifting(table,lower,upper,ddExtSymmCheck,
  372. DD_NORMAL_SIFT);
  373. } else {
  374. (void) fprintf(table->err,
  375. "Unknown group ckecking method\n");
  376. }
  377. #ifdef DD_STATS
  378. (void) fprintf(table->out,"\n");
  379. #endif
  380. result = cuddWindowReorder(table,lower,upper,
  381. CUDD_REORDER_WINDOW4);
  382. if (initialSize <= table->keys - table->isolated)
  383. break;
  384. #ifdef DD_STATS
  385. else
  386. (void) fprintf(table->out,"\n");
  387. #endif
  388. } while (result != 0);
  389. break;
  390. case CUDD_REORDER_WINDOW2:
  391. case CUDD_REORDER_WINDOW3:
  392. case CUDD_REORDER_WINDOW4:
  393. case CUDD_REORDER_WINDOW2_CONV:
  394. case CUDD_REORDER_WINDOW3_CONV:
  395. case CUDD_REORDER_WINDOW4_CONV:
  396. result = cuddWindowReorder(table,lower,upper,method);
  397. break;
  398. case CUDD_REORDER_ANNEALING:
  399. result = cuddAnnealing(table,lower,upper);
  400. break;
  401. case CUDD_REORDER_GENETIC:
  402. result = cuddGa(table,lower,upper);
  403. break;
  404. case CUDD_REORDER_LINEAR:
  405. result = cuddLinearAndSifting(table,lower,upper);
  406. break;
  407. case CUDD_REORDER_LINEAR_CONVERGE:
  408. do {
  409. initialSize = table->keys - table->isolated;
  410. result = cuddLinearAndSifting(table,lower,upper);
  411. if (initialSize <= table->keys - table->isolated)
  412. break;
  413. #ifdef DD_STATS
  414. else
  415. (void) fprintf(table->out,"\n");
  416. #endif
  417. } while (result != 0);
  418. break;
  419. case CUDD_REORDER_EXACT:
  420. result = cuddExact(table,lower,upper);
  421. break;
  422. case CUDD_REORDER_LAZY_SIFT:
  423. result = ddGroupSifting(table,lower,upper,ddVarGroupCheck,
  424. DD_LAZY_SIFT);
  425. break;
  426. default:
  427. return(0);
  428. }
  429. }
  430. /* Create a single group for all the variables that were sifted,
  431. ** so that they will be treated as a single block by successive
  432. ** invocations of ddGroupSifting.
  433. */
  434. ddMergeGroups(table,treenode,lower,upper);
  435. #ifdef DD_DEBUG
  436. if (table->enableExtraDebug > 0)
  437. (void) fprintf(table->out,"ddReorderChildren:");
  438. #endif
  439. return(result);
  440. } /* end of ddReorderChildren */
  441. /**
  442. @brief Finds the lower and upper bounds of the group represented
  443. by treenode.
  444. @details From the index and size fields we need to derive the
  445. current positions, and find maximum and minimum.
  446. @sideeffect The bounds are returned as side effects.
  447. */
  448. static void
  449. ddFindNodeHiLo(
  450. DdManager * table,
  451. MtrNode * treenode,
  452. int * lower,
  453. int * upper)
  454. {
  455. int low;
  456. int high;
  457. /* Check whether no variables in this group already exist.
  458. ** If so, return immediately. The calling procedure will know from
  459. ** the values of upper that no reordering is needed.
  460. */
  461. if ((int) treenode->low >= table->size) {
  462. *lower = table->size;
  463. *upper = -1;
  464. return;
  465. }
  466. *lower = low = (unsigned int) table->perm[treenode->index];
  467. high = (int) (low + treenode->size - 1);
  468. if (high >= table->size) {
  469. /* This is the case of a partially existing group. The aim is to
  470. ** reorder as many variables as safely possible. If the tree
  471. ** node is terminal, we just reorder the subset of the group
  472. ** that is currently in existence. If the group has
  473. ** subgroups, then we only reorder those subgroups that are
  474. ** fully instantiated. This way we avoid breaking up a group.
  475. */
  476. MtrNode *auxnode = treenode->child;
  477. if (auxnode == NULL) {
  478. *upper = (unsigned int) table->size - 1;
  479. } else {
  480. /* Search the subgroup that strands the table->size line.
  481. ** If the first group starts at 0 and goes past table->size
  482. ** upper will get -1, thus correctly signaling that no reordering
  483. ** should take place.
  484. */
  485. while (auxnode != NULL) {
  486. int thisLower = table->perm[auxnode->low];
  487. int thisUpper = thisLower + auxnode->size - 1;
  488. if (thisUpper >= table->size && thisLower < table->size)
  489. *upper = (unsigned int) thisLower - 1;
  490. auxnode = auxnode->younger;
  491. }
  492. }
  493. } else {
  494. /* Normal case: All the variables of the group exist. */
  495. *upper = (unsigned int) high;
  496. }
  497. #ifdef DD_DEBUG
  498. /* Make sure that all variables in group are contiguous. */
  499. assert(treenode->size >= (MtrHalfWord) (*upper - *lower + 1));
  500. #endif
  501. return;
  502. } /* end of ddFindNodeHiLo */
  503. /**
  504. @brief Comparison function used by qsort.
  505. @details Comparison function used by qsort to order the variables
  506. according to the number of keys in the subtables.
  507. @return the difference in number of keys between the two variables
  508. being compared.
  509. @sideeffect None
  510. */
  511. static int
  512. ddUniqueCompareGroup(
  513. void const * ptrX,
  514. void const * ptrY)
  515. {
  516. IndexKey const * pX = (IndexKey const *) ptrX;
  517. IndexKey const * pY = (IndexKey const *) ptrY;
  518. #if 0
  519. if (pY->keys == pX->keys) {
  520. return(pX->index - pY->index);
  521. }
  522. #endif
  523. return(pY->keys - pX->keys);
  524. } /* end of ddUniqueCompareGroup */
  525. /**
  526. @brief Sifts from treenode->low to treenode->high.
  527. @details If croupcheck == CUDD_GROUP_CHECK7, it checks for group
  528. creation at the end of the initial sifting. If a group is created,
  529. it is then sifted again. After sifting one variable, the group that
  530. contains it is dissolved.
  531. @return 1 in case of success; 0 otherwise.
  532. @sideeffect None
  533. */
  534. static int
  535. ddGroupSifting(
  536. DdManager * table,
  537. int lower,
  538. int upper,
  539. DD_CHKFP checkFunction,
  540. int lazyFlag)
  541. {
  542. IndexKey *var;
  543. int i,j,x,xInit;
  544. int nvars;
  545. int classes;
  546. int result;
  547. int *sifted;
  548. int merged;
  549. int dissolve;
  550. #ifdef DD_STATS
  551. unsigned previousSize;
  552. #endif
  553. int xindex;
  554. nvars = table->size;
  555. /* Order variables to sift. */
  556. sifted = NULL;
  557. var = ALLOC(IndexKey,nvars);
  558. if (var == NULL) {
  559. table->errorCode = CUDD_MEMORY_OUT;
  560. goto ddGroupSiftingOutOfMem;
  561. }
  562. sifted = ALLOC(int,nvars);
  563. if (sifted == NULL) {
  564. table->errorCode = CUDD_MEMORY_OUT;
  565. goto ddGroupSiftingOutOfMem;
  566. }
  567. /* Here we consider only one representative for each group. */
  568. for (i = 0, classes = 0; i < nvars; i++) {
  569. sifted[i] = 0;
  570. x = table->perm[i];
  571. if ((unsigned) x >= table->subtables[x].next) {
  572. var[classes].index = i;
  573. var[classes].keys = table->subtables[x].keys;
  574. classes++;
  575. }
  576. }
  577. util_qsort(var, classes, sizeof(IndexKey), ddUniqueCompareGroup);
  578. if (lazyFlag) {
  579. for (i = 0; i < nvars; i ++) {
  580. ddResetVarHandled(table, i);
  581. }
  582. }
  583. /* Now sift. */
  584. for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
  585. if (table->ddTotalNumberSwapping >= table->siftMaxSwap)
  586. break;
  587. if (util_cpu_time() - table->startTime + table->reordTime
  588. > table->timeLimit) {
  589. table->autoDyn = 0; /* prevent further reordering */
  590. break;
  591. }
  592. if (table->terminationCallback != NULL &&
  593. table->terminationCallback(table->tcbArg)) {
  594. table->autoDyn = 0; /* prevent further reordering */
  595. break;
  596. }
  597. xindex = var[i].index;
  598. if (sifted[xindex] == 1) /* variable already sifted as part of group */
  599. continue;
  600. x = table->perm[xindex]; /* find current level of this variable */
  601. if (x < lower || x > upper || table->subtables[x].bindVar == 1)
  602. continue;
  603. #ifdef DD_STATS
  604. previousSize = table->keys - table->isolated;
  605. #endif
  606. #ifdef DD_DEBUG
  607. /* x is bottom of group */
  608. assert((unsigned) x >= table->subtables[x].next);
  609. #endif
  610. if ((unsigned) x == table->subtables[x].next) {
  611. dissolve = 1;
  612. result = ddGroupSiftingAux(table,x,lower,upper,checkFunction,
  613. lazyFlag);
  614. } else {
  615. dissolve = 0;
  616. result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag);
  617. }
  618. if (!result) goto ddGroupSiftingOutOfMem;
  619. /* check for aggregation */
  620. merged = 0;
  621. if (lazyFlag == 0 && table->groupcheck == CUDD_GROUP_CHECK7) {
  622. x = table->perm[xindex]; /* find current level */
  623. if ((unsigned) x == table->subtables[x].next) { /* not part of a group */
  624. if (x != upper && sifted[table->invperm[x+1]] == 0 &&
  625. (unsigned) x+1 == table->subtables[x+1].next) {
  626. if (ddSecDiffCheck(table,x,x+1)) {
  627. merged =1;
  628. ddCreateGroup(table,x,x+1);
  629. }
  630. }
  631. if (x != lower && sifted[table->invperm[x-1]] == 0 &&
  632. (unsigned) x-1 == table->subtables[x-1].next) {
  633. if (ddSecDiffCheck(table,x-1,x)) {
  634. merged =1;
  635. ddCreateGroup(table,x-1,x);
  636. }
  637. }
  638. }
  639. }
  640. if (merged) { /* a group was created */
  641. /* move x to bottom of group */
  642. while ((unsigned) x < table->subtables[x].next)
  643. x = table->subtables[x].next;
  644. /* sift */
  645. result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag);
  646. if (!result) goto ddGroupSiftingOutOfMem;
  647. #ifdef DD_STATS
  648. if (table->keys < previousSize + table->isolated) {
  649. (void) fprintf(table->out,"_");
  650. } else if (table->keys > previousSize + table->isolated) {
  651. (void) fprintf(table->out,"^");
  652. } else {
  653. (void) fprintf(table->out,"*");
  654. }
  655. fflush(table->out);
  656. } else {
  657. if (table->keys < previousSize + table->isolated) {
  658. (void) fprintf(table->out,"-");
  659. } else if (table->keys > previousSize + table->isolated) {
  660. (void) fprintf(table->out,"+");
  661. } else {
  662. (void) fprintf(table->out,"=");
  663. }
  664. fflush(table->out);
  665. #endif
  666. }
  667. /* Mark variables in the group just sifted. */
  668. x = table->perm[xindex];
  669. if ((unsigned) x != table->subtables[x].next) {
  670. xInit = x;
  671. do {
  672. j = table->invperm[x];
  673. sifted[j] = 1;
  674. x = table->subtables[x].next;
  675. } while (x != xInit);
  676. /* Dissolve the group if it was created. */
  677. if (lazyFlag == 0 && dissolve) {
  678. do {
  679. j = table->subtables[x].next;
  680. table->subtables[x].next = x;
  681. x = j;
  682. } while (x != xInit);
  683. }
  684. }
  685. #ifdef DD_DEBUG
  686. if (table->enableExtraDebug > 0)
  687. (void) fprintf(table->out,"ddGroupSifting:");
  688. #endif
  689. if (lazyFlag) ddSetVarHandled(table, xindex);
  690. } /* for */
  691. FREE(sifted);
  692. FREE(var);
  693. return(1);
  694. ddGroupSiftingOutOfMem:
  695. if (var != NULL) FREE(var);
  696. if (sifted != NULL) FREE(sifted);
  697. return(0);
  698. } /* end of ddGroupSifting */
  699. /**
  700. @brief Creates a group encompassing variables from x to y in the
  701. %DD table.
  702. @details In the current implementation it must be y == x+1.
  703. @sideeffect None
  704. */
  705. static void
  706. ddCreateGroup(
  707. DdManager * table,
  708. int x,
  709. int y)
  710. {
  711. int gybot;
  712. #ifdef DD_DEBUG
  713. assert(y == x+1);
  714. #endif
  715. /* Find bottom of second group. */
  716. gybot = y;
  717. while ((unsigned) gybot < table->subtables[gybot].next)
  718. gybot = table->subtables[gybot].next;
  719. /* Link groups. */
  720. table->subtables[x].next = y;
  721. table->subtables[gybot].next = x;
  722. return;
  723. } /* ddCreateGroup */
  724. /**
  725. @brief Sifts one variable up and down until it has taken all
  726. positions. Checks for aggregation.
  727. @details There may be at most two sweeps, even if the group grows.
  728. Assumes that x is either an isolated variable, or it is the bottom
  729. of a group. All groups may not have been found. The variable being
  730. moved is returned to the best position seen during sifting.
  731. @return 1 in case of success; 0 otherwise.
  732. @sideeffect None
  733. */
  734. static int
  735. ddGroupSiftingAux(
  736. DdManager * table,
  737. int x,
  738. int xLow,
  739. int xHigh,
  740. DD_CHKFP checkFunction,
  741. int lazyFlag)
  742. {
  743. Move *move;
  744. Move *moves; /* list of moves */
  745. int initialSize;
  746. int result;
  747. int y;
  748. int topbot;
  749. #ifdef DD_DEBUG
  750. if (table->enableExtraDebug > 0)
  751. (void) fprintf(table->out,
  752. "ddGroupSiftingAux from %d to %d\n",xLow,xHigh);
  753. assert((unsigned) x >= table->subtables[x].next); /* x is bottom of group */
  754. #endif
  755. table->originalSize = (table->keys - table->isolated);
  756. initialSize = (int) table->originalSize;
  757. moves = NULL;
  758. /* If we have a singleton, we check for aggregation in both
  759. ** directions before we sift.
  760. */
  761. if ((unsigned) x == table->subtables[x].next) {
  762. /* Will go down first, unless x == xHigh:
  763. ** Look for aggregation above x.
  764. */
  765. for (y = x; y > xLow; y--) {
  766. if (!checkFunction(table,y-1,y))
  767. break;
  768. topbot = table->subtables[y-1].next; /* find top of y-1's group */
  769. table->subtables[y-1].next = y;
  770. table->subtables[x].next = topbot; /* x is bottom of group so its */
  771. /* next is top of y-1's group */
  772. y = topbot + 1; /* add 1 for y--; new y is top of group */
  773. }
  774. /* Will go up first unless x == xlow:
  775. ** Look for aggregation below x.
  776. */
  777. for (y = x; y < xHigh; y++) {
  778. if (!checkFunction(table,y,y+1))
  779. break;
  780. /* find bottom of y+1's group */
  781. topbot = y + 1;
  782. while ((unsigned) topbot < table->subtables[topbot].next) {
  783. topbot = table->subtables[topbot].next;
  784. }
  785. table->subtables[topbot].next = table->subtables[y].next;
  786. table->subtables[y].next = y + 1;
  787. y = topbot - 1; /* subtract 1 for y++; new y is bottom of group */
  788. }
  789. }
  790. /* Now x may be in the middle of a group.
  791. ** Find bottom of x's group.
  792. */
  793. while ((unsigned) x < table->subtables[x].next)
  794. x = table->subtables[x].next;
  795. if (x == xLow) { /* Sift down */
  796. #ifdef DD_DEBUG
  797. /* x must be a singleton */
  798. assert((unsigned) x == table->subtables[x].next);
  799. #endif
  800. if (x == xHigh) return(1); /* just one variable */
  801. if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
  802. goto ddGroupSiftingAuxOutOfMem;
  803. /* at this point x == xHigh, unless early term */
  804. /* move backward and stop at best position */
  805. result = ddGroupSiftingBackward(table,moves,initialSize,
  806. DD_SIFT_DOWN,lazyFlag);
  807. #ifdef DD_DEBUG
  808. assert(table->keys - table->isolated <= (unsigned) initialSize);
  809. #endif
  810. if (!result) goto ddGroupSiftingAuxOutOfMem;
  811. } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */
  812. #ifdef DD_DEBUG
  813. /* x is bottom of group */
  814. assert((unsigned) x >= table->subtables[x].next);
  815. #endif
  816. /* Find top of x's group */
  817. x = table->subtables[x].next;
  818. if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
  819. goto ddGroupSiftingAuxOutOfMem;
  820. /* at this point x == xLow, unless early term */
  821. /* move backward and stop at best position */
  822. result = ddGroupSiftingBackward(table,moves,initialSize,
  823. DD_SIFT_UP,lazyFlag);
  824. #ifdef DD_DEBUG
  825. assert(table->keys - table->isolated <= (unsigned) initialSize);
  826. #endif
  827. if (!result) goto ddGroupSiftingAuxOutOfMem;
  828. } else if (x - xLow > xHigh - x) { /* must go down first: shorter */
  829. if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
  830. goto ddGroupSiftingAuxOutOfMem;
  831. /* at this point x == xHigh, unless early term */
  832. /* Find top of group */
  833. if (moves) {
  834. x = moves->y;
  835. }
  836. while ((unsigned) x < table->subtables[x].next)
  837. x = table->subtables[x].next;
  838. x = table->subtables[x].next;
  839. #ifdef DD_DEBUG
  840. /* x should be the top of a group */
  841. assert((unsigned) x <= table->subtables[x].next);
  842. #endif
  843. if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
  844. goto ddGroupSiftingAuxOutOfMem;
  845. /* move backward and stop at best position */
  846. result = ddGroupSiftingBackward(table,moves,initialSize,
  847. DD_SIFT_UP,lazyFlag);
  848. #ifdef DD_DEBUG
  849. assert(table->keys - table->isolated <= (unsigned) initialSize);
  850. #endif
  851. if (!result) goto ddGroupSiftingAuxOutOfMem;
  852. } else { /* moving up first: shorter */
  853. /* Find top of x's group */
  854. x = table->subtables[x].next;
  855. if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
  856. goto ddGroupSiftingAuxOutOfMem;
  857. /* at this point x == xHigh, unless early term */
  858. if (moves) {
  859. x = moves->x;
  860. }
  861. while ((unsigned) x < table->subtables[x].next)
  862. x = table->subtables[x].next;
  863. #ifdef DD_DEBUG
  864. /* x is bottom of a group */
  865. assert((unsigned) x >= table->subtables[x].next);
  866. #endif
  867. if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
  868. goto ddGroupSiftingAuxOutOfMem;
  869. /* move backward and stop at best position */
  870. result = ddGroupSiftingBackward(table,moves,initialSize,
  871. DD_SIFT_DOWN,lazyFlag);
  872. #ifdef DD_DEBUG
  873. assert(table->keys - table->isolated <= (unsigned) initialSize);
  874. #endif
  875. if (!result) goto ddGroupSiftingAuxOutOfMem;
  876. }
  877. while (moves != NULL) {
  878. move = moves->next;
  879. cuddDeallocMove(table, moves);
  880. moves = move;
  881. }
  882. return(1);
  883. ddGroupSiftingAuxOutOfMem:
  884. while (moves != NULL) {
  885. move = moves->next;
  886. cuddDeallocMove(table, moves);
  887. moves = move;
  888. }
  889. return(0);
  890. } /* end of ddGroupSiftingAux */
  891. /**
  892. @brief Sifts up a variable until either it reaches position xLow
  893. or the size of the %DD heap increases too much.
  894. @details Assumes that y is the top of a group (or a singleton).
  895. Checks y for aggregation to the adjacent variables. Records all the
  896. moves that are appended to the list of moves received as input and
  897. returned as a side effect.
  898. @return 1 in case of success; 0 otherwise.
  899. @sideeffect None
  900. */
  901. static int
  902. ddGroupSiftingUp(
  903. DdManager * table,
  904. int y,
  905. int xLow,
  906. DD_CHKFP checkFunction,
  907. Move ** moves)
  908. {
  909. Move *move;
  910. int x;
  911. int size;
  912. int i;
  913. int gxtop,gybot;
  914. int limitSize;
  915. int xindex, yindex;
  916. int zindex;
  917. int z;
  918. unsigned int isolated;
  919. int L; /* lower bound on DD size */
  920. #ifdef DD_DEBUG
  921. int checkL;
  922. #endif
  923. yindex = table->invperm[y];
  924. /* Initialize the lower bound.
  925. ** The part of the DD below the bottom of y's group will not change.
  926. ** The part of the DD above y that does not interact with any
  927. ** variable of y's group will not change.
  928. ** The rest may vanish in the best case, except for
  929. ** the nodes at level xLow, which will not vanish, regardless.
  930. ** What we use here is not really a lower bound, because we ignore
  931. ** the interactions with all variables except y.
  932. */
  933. limitSize = L = (int) (table->keys - table->isolated);
  934. gybot = y;
  935. while ((unsigned) gybot < table->subtables[gybot].next)
  936. gybot = table->subtables[gybot].next;
  937. for (z = xLow + 1; z <= gybot; z++) {
  938. zindex = table->invperm[z];
  939. if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
  940. isolated = table->vars[zindex]->ref == 1;
  941. L -= table->subtables[z].keys - isolated;
  942. }
  943. }
  944. x = cuddNextLow(table,y);
  945. while (x >= xLow && L <= limitSize) {
  946. #ifdef DD_DEBUG
  947. gybot = y;
  948. while ((unsigned) gybot < table->subtables[gybot].next)
  949. gybot = table->subtables[gybot].next;
  950. checkL = table->keys - table->isolated;
  951. for (z = xLow + 1; z <= gybot; z++) {
  952. zindex = table->invperm[z];
  953. if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
  954. isolated = table->vars[zindex]->ref == 1;
  955. checkL -= table->subtables[z].keys - isolated;
  956. }
  957. }
  958. if (table->enableExtraDebug > 0 && L != checkL) {
  959. (void) fprintf(table->out,
  960. "Inaccurate lower bound: L = %d checkL = %d\n",
  961. L, checkL);
  962. }
  963. #endif
  964. gxtop = table->subtables[x].next;
  965. if (checkFunction(table,x,y)) {
  966. /* Group found, attach groups */
  967. table->subtables[x].next = y;
  968. i = table->subtables[y].next;
  969. while (table->subtables[i].next != (unsigned) y)
  970. i = table->subtables[i].next;
  971. table->subtables[i].next = gxtop;
  972. move = (Move *)cuddDynamicAllocNode(table);
  973. if (move == NULL) goto ddGroupSiftingUpOutOfMem;
  974. move->x = x;
  975. move->y = y;
  976. move->flags = MTR_NEWNODE;
  977. move->size = (int) (table->keys - table->isolated);
  978. move->next = *moves;
  979. *moves = move;
  980. } else if (table->subtables[x].next == (unsigned) x &&
  981. table->subtables[y].next == (unsigned) y) {
  982. /* x and y are self groups */
  983. xindex = table->invperm[x];
  984. size = cuddSwapInPlace(table,x,y);
  985. #ifdef DD_DEBUG
  986. assert(table->subtables[x].next == (unsigned) x);
  987. assert(table->subtables[y].next == (unsigned) y);
  988. #endif
  989. if (size == 0) goto ddGroupSiftingUpOutOfMem;
  990. /* Update the lower bound. */
  991. if (cuddTestInteract(table,xindex,yindex)) {
  992. isolated = table->vars[xindex]->ref == 1;
  993. L += table->subtables[y].keys - isolated;
  994. }
  995. move = (Move *)cuddDynamicAllocNode(table);
  996. if (move == NULL) goto ddGroupSiftingUpOutOfMem;
  997. move->x = x;
  998. move->y = y;
  999. move->flags = MTR_DEFAULT;
  1000. move->size = size;
  1001. move->next = *moves;
  1002. *moves = move;
  1003. #ifdef DD_DEBUG
  1004. if (table->enableExtraDebug > 0)
  1005. (void) fprintf(table->out,
  1006. "ddGroupSiftingUp (2 single groups):\n");
  1007. #endif
  1008. if ((double) size > (double) limitSize * table->maxGrowth)
  1009. return(1);
  1010. if (size < limitSize) limitSize = size;
  1011. } else { /* Group move */
  1012. size = ddGroupMove(table,x,y,moves);
  1013. if (size == 0) goto ddGroupSiftingUpOutOfMem;
  1014. /* Update the lower bound. */
  1015. z = (*moves)->y;
  1016. do {
  1017. zindex = table->invperm[z];
  1018. if (cuddTestInteract(table,zindex,yindex)) {
  1019. isolated = table->vars[zindex]->ref == 1;
  1020. L += table->subtables[z].keys - isolated;
  1021. }
  1022. z = table->subtables[z].next;
  1023. } while (z != (int) (*moves)->y);
  1024. if ((double) size > (double) limitSize * table->maxGrowth)
  1025. return(1);
  1026. if (size < limitSize) limitSize = size;
  1027. }
  1028. y = gxtop;
  1029. x = cuddNextLow(table,y);
  1030. }
  1031. return(1);
  1032. ddGroupSiftingUpOutOfMem:
  1033. while (*moves != NULL) {
  1034. move = (*moves)->next;
  1035. cuddDeallocMove(table, *moves);
  1036. *moves = move;
  1037. }
  1038. return(0);
  1039. } /* end of ddGroupSiftingUp */
  1040. /**
  1041. @brief Sifts down a variable until it reaches position xHigh.
  1042. @details Assumes that x is the bottom of a group (or a singleton).
  1043. Records all the moves.
  1044. @return 1 in case of success; 0 otherwise.
  1045. @sideeffect None
  1046. */
  1047. static int
  1048. ddGroupSiftingDown(
  1049. DdManager * table,
  1050. int x,
  1051. int xHigh,
  1052. DD_CHKFP checkFunction,
  1053. Move ** moves)
  1054. {
  1055. Move *move;
  1056. int y;
  1057. int size;
  1058. int limitSize;
  1059. int gxtop,gybot;
  1060. int R; /* upper bound on node decrease */
  1061. int xindex, yindex;
  1062. unsigned isolated;
  1063. int allVars;
  1064. int z;
  1065. int zindex;
  1066. #ifdef DD_DEBUG
  1067. int checkR;
  1068. #endif
  1069. /* If the group consists of simple variables, there is no point in
  1070. ** sifting it down. This check is redundant if the projection functions
  1071. ** do not have external references, because the computation of the
  1072. ** lower bound takes care of the problem. It is necessary otherwise to
  1073. ** prevent the sifting down of simple variables. */
  1074. y = x;
  1075. allVars = 1;
  1076. do {
  1077. if (table->subtables[y].keys != 1) {
  1078. allVars = 0;
  1079. break;
  1080. }
  1081. y = table->subtables[y].next;
  1082. } while (table->subtables[y].next != (unsigned) x);
  1083. if (allVars)
  1084. return(1);
  1085. /* Initialize R. */
  1086. xindex = table->invperm[x];
  1087. gxtop = table->subtables[x].next;
  1088. limitSize = size = (int) (table->keys - table->isolated);
  1089. R = 0;
  1090. for (z = xHigh; z > gxtop; z--) {
  1091. zindex = table->invperm[z];
  1092. if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
  1093. isolated = table->vars[zindex]->ref == 1;
  1094. R += table->subtables[z].keys - isolated;
  1095. }
  1096. }
  1097. y = cuddNextHigh(table,x);
  1098. while (y <= xHigh && size - R < limitSize) {
  1099. #ifdef DD_DEBUG
  1100. gxtop = table->subtables[x].next;
  1101. checkR = 0;
  1102. for (z = xHigh; z > gxtop; z--) {
  1103. zindex = table->invperm[z];
  1104. if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
  1105. isolated = table->vars[zindex]->ref == 1;
  1106. checkR += table->subtables[z].keys - isolated;
  1107. }
  1108. }
  1109. assert(R >= checkR);
  1110. #endif
  1111. /* Find bottom of y group. */
  1112. gybot = table->subtables[y].next;
  1113. while (table->subtables[gybot].next != (unsigned) y)
  1114. gybot = table->subtables[gybot].next;
  1115. if (checkFunction(table,x,y)) {
  1116. /* Group found: attach groups and record move. */
  1117. gxtop = table->subtables[x].next;
  1118. table->subtables[x].next = y;
  1119. table->subtables[gybot].next = gxtop;
  1120. move = (Move *)cuddDynamicAllocNode(table);
  1121. if (move == NULL) goto ddGroupSiftingDownOutOfMem;
  1122. move->x = x;
  1123. move->y = y;
  1124. move->flags = MTR_NEWNODE;
  1125. move->size = (int) (table->keys - table->isolated);
  1126. move->next = *moves;
  1127. *moves = move;
  1128. } else if (table->subtables[x].next == (unsigned) x &&
  1129. table->subtables[y].next == (unsigned) y) {
  1130. /* x and y are self groups */
  1131. /* Update upper bound on node decrease. */
  1132. yindex = table->invperm[y];
  1133. if (cuddTestInteract(table,xindex,yindex)) {
  1134. isolated = table->vars[yindex]->ref == 1;
  1135. R -= table->subtables[y].keys - isolated;
  1136. }
  1137. size = cuddSwapInPlace(table,x,y);
  1138. #ifdef DD_DEBUG
  1139. assert(table->subtables[x].next == (unsigned) x);
  1140. assert(table->subtables[y].next == (unsigned) y);
  1141. #endif
  1142. if (size == 0) goto ddGroupSiftingDownOutOfMem;
  1143. /* Record move. */
  1144. move = (Move *) cuddDynamicAllocNode(table);
  1145. if (move == NULL) goto ddGroupSiftingDownOutOfMem;
  1146. move->x = x;
  1147. move->y = y;
  1148. move->flags = MTR_DEFAULT;
  1149. move->size = size;
  1150. move->next = *moves;
  1151. *moves = move;
  1152. #ifdef DD_DEBUG
  1153. if (table->enableExtraDebug > 0)
  1154. (void) fprintf(table->out,
  1155. "ddGroupSiftingDown (2 single groups):\n");
  1156. #endif
  1157. if ((double) size > (double) limitSize * table->maxGrowth)
  1158. return(1);
  1159. if (size < limitSize) limitSize = size;
  1160. } else { /* Group move */
  1161. /* Update upper bound on node decrease: first phase. */
  1162. gxtop = table->subtables[x].next;
  1163. z = gxtop + 1;
  1164. do {
  1165. zindex = table->invperm[z];
  1166. if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
  1167. isolated = table->vars[zindex]->ref == 1;
  1168. R -= table->subtables[z].keys - isolated;
  1169. }
  1170. z++;
  1171. } while (z <= gybot);
  1172. size = ddGroupMove(table,x,y,moves);
  1173. if (size == 0) goto ddGroupSiftingDownOutOfMem;
  1174. if ((double) size > (double) limitSize * table->maxGrowth)
  1175. return(1);
  1176. if (size < limitSize) limitSize = size;
  1177. /* Update upper bound on node decrease: second phase. */
  1178. gxtop = table->subtables[gybot].next;
  1179. for (z = gxtop + 1; z <= gybot; z++) {
  1180. zindex = table->invperm[z];
  1181. if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
  1182. isolated = table->vars[zindex]->ref == 1;
  1183. R += table->subtables[z].keys - isolated;
  1184. }
  1185. }
  1186. }
  1187. x = gybot;
  1188. y = cuddNextHigh(table,x);
  1189. }
  1190. return(1);
  1191. ddGroupSiftingDownOutOfMem:
  1192. while (*moves != NULL) {
  1193. move = (*moves)->next;
  1194. cuddDeallocMove(table, *moves);
  1195. *moves = move;
  1196. }
  1197. return(0);
  1198. } /* end of ddGroupSiftingDown */
  1199. /**
  1200. @brief Swaps two groups and records the move.
  1201. @return the number of keys in the %DD table in case of success; 0
  1202. otherwise.
  1203. @sideeffect None
  1204. */
  1205. static int
  1206. ddGroupMove(
  1207. DdManager * table,
  1208. int x,
  1209. int y,
  1210. Move ** moves)
  1211. {
  1212. Move *move;
  1213. int size;
  1214. int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
  1215. int swapx = 0, swapy = 0;
  1216. #if defined(DD_DEBUG) && defined(DD_VERBOSE)
  1217. int initialSize,bestSize;
  1218. #endif
  1219. #ifdef DD_DEBUG
  1220. /* We assume that x < y */
  1221. assert(x < y);
  1222. #endif
  1223. /* Find top, bottom, and size for the two groups. */
  1224. xbot = x;
  1225. xtop = table->subtables[x].next;
  1226. xsize = xbot - xtop + 1;
  1227. ybot = y;
  1228. while ((unsigned) ybot < table->subtables[ybot].next)
  1229. ybot = table->subtables[ybot].next;
  1230. ytop = y;
  1231. ysize = ybot - ytop + 1;
  1232. #if defined(DD_DEBUG) && defined(DD_VERBOSE)
  1233. initialSize = bestSize = table->keys - table->isolated;
  1234. #endif
  1235. /* Sift the variables of the second group up through the first group */
  1236. for (i = 1; i <= ysize; i++) {
  1237. for (j = 1; j <= xsize; j++) {
  1238. size = cuddSwapInPlace(table,x,y);
  1239. if (size == 0) goto ddGroupMoveOutOfMem;
  1240. #if defined(DD_DEBUG) && defined(DD_VERBOSE)
  1241. if (size < bestSize)
  1242. bestSize = size;
  1243. #endif
  1244. swapx = x; swapy = y;
  1245. y = x;
  1246. x = cuddNextLow(table,y);
  1247. }
  1248. y = ytop + i;
  1249. x = cuddNextLow(table,y);
  1250. }
  1251. #if defined(DD_DEBUG) && defined(DD_VERBOSE)
  1252. if ((bestSize < initialSize) && (bestSize < size))
  1253. (void) fprintf(table->out,"Missed local minimum: initialSize:%d bestSize:%d finalSize:%d\n",initialSize,bestSize,size);
  1254. #endif
  1255. /* fix groups */
  1256. y = xtop; /* ytop is now where xtop used to be */
  1257. for (i = 0; i < ysize - 1; i++) {
  1258. table->subtables[y].next = cuddNextHigh(table,y);
  1259. y = cuddNextHigh(table,y);
  1260. }
  1261. table->subtables[y].next = xtop; /* y is bottom of its group, join */
  1262. /* it to top of its group */
  1263. x = cuddNextHigh(table,y);
  1264. newxtop = x;
  1265. for (i = 0; i < xsize - 1; i++) {
  1266. table->subtables[x].next = cuddNextHigh(table,x);
  1267. x = cuddNextHigh(table,x);
  1268. }
  1269. table->subtables[x].next = newxtop; /* x is bottom of its group, join */
  1270. /* it to top of its group */
  1271. #ifdef DD_DEBUG
  1272. if (table->enableExtraDebug > 0)
  1273. (void) fprintf(table->out,"ddGroupMove:\n");
  1274. #endif
  1275. /* Store group move */
  1276. move = (Move *) cuddDynamicAllocNode(table);
  1277. if (move == NULL) goto ddGroupMoveOutOfMem;
  1278. move->x = swapx;
  1279. move->y = swapy;
  1280. move->flags = MTR_DEFAULT;
  1281. move->size = (int) (table->keys - table->isolated);
  1282. move->next = *moves;
  1283. *moves = move;
  1284. return((int)(table->keys - table->isolated));
  1285. ddGroupMoveOutOfMem:
  1286. while (*moves != NULL) {
  1287. move = (*moves)->next;
  1288. cuddDeallocMove(table, *moves);
  1289. *moves = move;
  1290. }
  1291. return(0);
  1292. } /* end of ddGroupMove */
  1293. /**
  1294. @brief Undoes the swap two groups.
  1295. @return 1 in case of success; 0 otherwise.
  1296. @sideeffect None
  1297. */
  1298. static int
  1299. ddGroupMoveBackward(
  1300. DdManager * table,
  1301. int x,
  1302. int y)
  1303. {
  1304. int size;
  1305. int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
  1306. #ifdef DD_DEBUG
  1307. /* We assume that x < y */
  1308. assert(x < y);
  1309. #endif
  1310. /* Find top, bottom, and size for the two groups. */
  1311. xbot = x;
  1312. xtop = table->subtables[x].next;
  1313. xsize = xbot - xtop + 1;
  1314. ybot = y;
  1315. while ((unsigned) ybot < table->subtables[ybot].next)
  1316. ybot = table->subtables[ybot].next;
  1317. ytop = y;
  1318. ysize = ybot - ytop + 1;
  1319. /* Sift the variables of the second group up through the first group */
  1320. for (i = 1; i <= ysize; i++) {
  1321. for (j = 1; j <= xsize; j++) {
  1322. size = cuddSwapInPlace(table,x,y);
  1323. if (size == 0)
  1324. return(0);
  1325. y = x;
  1326. x = cuddNextLow(table,y);
  1327. }
  1328. y = ytop + i;
  1329. x = cuddNextLow(table,y);
  1330. }
  1331. /* fix groups */
  1332. y = xtop;
  1333. for (i = 0; i < ysize - 1; i++) {
  1334. table->subtables[y].next = cuddNextHigh(table,y);
  1335. y = cuddNextHigh(table,y);
  1336. }
  1337. table->subtables[y].next = xtop; /* y is bottom of its group, join */
  1338. /* to its top */
  1339. x = cuddNextHigh(table,y);
  1340. newxtop = x;
  1341. for (i = 0; i < xsize - 1; i++) {
  1342. table->subtables[x].next = cuddNextHigh(table,x);
  1343. x = cuddNextHigh(table,x);
  1344. }
  1345. table->subtables[x].next = newxtop; /* x is bottom of its group, join */
  1346. /* to its top */
  1347. #ifdef DD_DEBUG
  1348. if (table->enableExtraDebug > 0)
  1349. (void) fprintf(table->out,"ddGroupMoveBackward:\n");
  1350. #endif
  1351. return(1);
  1352. } /* end of ddGroupMoveBackward */
  1353. /**
  1354. @brief Determines the best position for a variables and returns
  1355. it there.
  1356. @return 1 in case of success; 0 otherwise.
  1357. @sideeffect None
  1358. */
  1359. static int
  1360. ddGroupSiftingBackward(
  1361. DdManager * table,
  1362. Move * moves,
  1363. int size,
  1364. int upFlag,
  1365. int lazyFlag)
  1366. {
  1367. Move *move;
  1368. int res;
  1369. Move *end_move = NULL;
  1370. int diff, tmp_diff;
  1371. int index;
  1372. unsigned int pairlev;
  1373. if (lazyFlag) {
  1374. end_move = NULL;
  1375. /* Find the minimum size, and the earliest position at which it
  1376. ** was achieved. */
  1377. for (move = moves; move != NULL; move = move->next) {
  1378. if (move->size < size) {
  1379. size = move->size;
  1380. end_move = move;
  1381. } else if (move->size == size) {
  1382. if (end_move == NULL) end_move = move;
  1383. }
  1384. }
  1385. /* Find among the moves that give minimum size the one that
  1386. ** minimizes the distance from the corresponding variable. */
  1387. if (moves != NULL) {
  1388. diff = Cudd_ReadSize(table) + 1;
  1389. index = (upFlag == 1) ?
  1390. table->invperm[moves->x] : table->invperm[moves->y];
  1391. pairlev =
  1392. (unsigned) table->perm[Cudd_bddReadPairIndex(table, index)];
  1393. for (move = moves; move != NULL; move = move->next) {
  1394. if (move->size == size) {
  1395. if (upFlag == 1) {
  1396. tmp_diff = (move->x > pairlev) ?
  1397. move->x - pairlev : pairlev - move->x;
  1398. } else {
  1399. tmp_diff = (move->y > pairlev) ?
  1400. move->y - pairlev : pairlev - move->y;
  1401. }
  1402. if (tmp_diff < diff) {
  1403. diff = tmp_diff;
  1404. end_move = move;
  1405. }
  1406. }
  1407. }
  1408. }
  1409. } else {
  1410. /* Find the minimum size. */
  1411. for (move = moves; move != NULL; move = move->next) {
  1412. if (move->size < size) {
  1413. size = move->size;
  1414. }
  1415. }
  1416. }
  1417. /* In case of lazy sifting, end_move identifies the position at
  1418. ** which we want to stop. Otherwise, we stop as soon as we meet
  1419. ** the minimum size. */
  1420. for (move = moves; move != NULL; move = move->next) {
  1421. if (lazyFlag) {
  1422. if (move == end_move) return(1);
  1423. } else {
  1424. if (move->size == size) return(1);
  1425. }
  1426. if ((table->subtables[move->x].next == move->x) &&
  1427. (table->subtables[move->y].next == move->y)) {
  1428. res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
  1429. if (!res) return(0);
  1430. #ifdef DD_DEBUG
  1431. if (table->enableExtraDebug > 0)
  1432. (void) fprintf(table->out,"ddGroupSiftingBackward:\n");
  1433. assert(table->subtables[move->x].next == move->x);
  1434. assert(table->subtables[move->y].next == move->y);
  1435. #endif
  1436. } else { /* Group move necessary */
  1437. if (move->flags == MTR_NEWNODE) {
  1438. ddDissolveGroup(table,(int)move->x,(int)move->y);
  1439. } else {
  1440. res = ddGroupMoveBackward(table,(int)move->x,(int)move->y);
  1441. if (!res) return(0);
  1442. }
  1443. }
  1444. }
  1445. return(1);
  1446. } /* end of ddGroupSiftingBackward */
  1447. /**
  1448. @brief Merges groups in the %DD table.
  1449. @details Creates a single group from low to high and adjusts the
  1450. index field of the tree node.
  1451. @sideeffect None
  1452. */
  1453. static void
  1454. ddMergeGroups(
  1455. DdManager * table,
  1456. MtrNode * treenode,
  1457. int low,
  1458. int high)
  1459. {
  1460. int i;
  1461. MtrNode *auxnode;
  1462. int saveindex;
  1463. int newindex;
  1464. /* Merge all variables from low to high in one group, unless
  1465. ** this is the topmost group. In such a case we do not merge lest
  1466. ** we lose the symmetry information. */
  1467. if (treenode != table->tree) {
  1468. for (i = low; i < high; i++)
  1469. table->subtables[i].next = i+1;
  1470. table->subtables[high].next = low;
  1471. }
  1472. /* Adjust the index fields of the tree nodes. If a node is the
  1473. ** first child of its parent, then the parent may also need adjustment. */
  1474. saveindex = treenode->index;
  1475. newindex = table->invperm[low];
  1476. auxnode = treenode;
  1477. do {
  1478. auxnode->index = newindex;
  1479. if (auxnode->parent == NULL ||
  1480. (int) auxnode->parent->index != saveindex)
  1481. break;
  1482. auxnode = auxnode->parent;
  1483. } while (1);
  1484. return;
  1485. } /* end of ddMergeGroups */
  1486. /**
  1487. @brief Dissolves a group in the %DD table.
  1488. @details x and y are variables in a group to be cut in two. The cut
  1489. is to pass between x and y.
  1490. @sideeffect None
  1491. */
  1492. static void
  1493. ddDissolveGroup(
  1494. DdManager * table,
  1495. int x,
  1496. int y)
  1497. {
  1498. int topx;
  1499. int boty;
  1500. /* find top and bottom of the two groups */
  1501. boty = y;
  1502. while ((unsigned) boty < table->subtables[boty].next)
  1503. boty = table->subtables[boty].next;
  1504. topx = table->subtables[boty].next;
  1505. table->subtables[boty].next = y;
  1506. table->subtables[x].next = topx;
  1507. return;
  1508. } /* end of ddDissolveGroup */
  1509. /**
  1510. @brief Pretends to check two variables for aggregation.
  1511. @return always 0.
  1512. @sideeffect None
  1513. */
  1514. static int
  1515. ddNoCheck(
  1516. DdManager * table,
  1517. int x,
  1518. int y)
  1519. {
  1520. (void) table; /* avoid warning */
  1521. (void) x; /* avoid warning */
  1522. (void) y; /* avoid warning */
  1523. return(0);
  1524. } /* end of ddNoCheck */
  1525. /**
  1526. @brief Checks two variables for aggregation.
  1527. @details The check is based on the second difference of the number
  1528. of nodes as a function of the layer. If the second difference is
  1529. lower than a given threshold (typically negative) then the two
  1530. variables should be aggregated.
  1531. @return 1 if the two variables pass the test; 0 otherwise.
  1532. @sideeffect None
  1533. */
  1534. static int
  1535. ddSecDiffCheck(
  1536. DdManager * table,
  1537. int x,
  1538. int y)
  1539. {
  1540. double Nx,Nx_1;
  1541. double Sx;
  1542. double threshold;
  1543. int xindex,yindex;
  1544. if (x==0) return(0);
  1545. #ifdef DD_STATS
  1546. table->secdiffcalls++;
  1547. #endif
  1548. Nx = (double) table->subtables[x].keys;
  1549. Nx_1 = (double) table->subtables[x-1].keys;
  1550. Sx = (table->subtables[y].keys/Nx) - (Nx/Nx_1);
  1551. threshold = table->recomb / 100.0;
  1552. if (Sx < threshold) {
  1553. xindex = table->invperm[x];
  1554. yindex = table->invperm[y];
  1555. if (cuddTestInteract(table,xindex,yindex)) {
  1556. #if defined(DD_DEBUG) && defined(DD_VERBOSE)
  1557. (void) fprintf(table->out,
  1558. "Second difference for %d = %g Pos(%d)\n",
  1559. table->invperm[x],Sx,x);
  1560. #endif
  1561. #ifdef DD_STATS
  1562. table->secdiff++;
  1563. #endif
  1564. return(1);
  1565. } else {
  1566. #ifdef DD_STATS
  1567. table->secdiffmisfire++;
  1568. #endif
  1569. return(0);
  1570. }
  1571. }
  1572. return(0);
  1573. } /* end of ddSecDiffCheck */
  1574. /**
  1575. @brief Checks for extended symmetry of x and y.
  1576. @return 1 in case of extended symmetry; 0 otherwise.
  1577. @sideeffect None
  1578. */
  1579. static int
  1580. ddExtSymmCheck(
  1581. DdManager * table,
  1582. int x,
  1583. int y)
  1584. {
  1585. DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10;
  1586. DdNode *one;
  1587. int comple; /* f0 is complemented */
  1588. int notproj; /* f is not a projection function */
  1589. int arccount; /* number of arcs from layer x to layer y */
  1590. int TotalRefCount; /* total reference count of layer y minus 1 */
  1591. int counter; /* number of nodes of layer x that are allowed */
  1592. /* to violate extended symmetry conditions */
  1593. int arccounter; /* number of arcs into layer y that are allowed */
  1594. /* to come from layers other than x */
  1595. int i;
  1596. int xindex;
  1597. int yindex;
  1598. int res;
  1599. int slots;
  1600. DdNodePtr *list;
  1601. DdNode *sentinel = &(table->sentinel);
  1602. xindex = table->invperm[x];
  1603. yindex = table->invperm[y];
  1604. /* If the two variables do not interact, we do not want to merge them. */
  1605. if (!cuddTestInteract(table,xindex,yindex))
  1606. return(0);
  1607. #ifdef DD_DEBUG
  1608. /* Checks that x and y do not contain just the projection functions.
  1609. ** With the test on interaction, these test become redundant,
  1610. ** because an isolated projection function does not interact with
  1611. ** any other variable.
  1612. */
  1613. if (table->subtables[x].keys == 1) {
  1614. assert(table->vars[xindex]->ref != 1);
  1615. }
  1616. if (table->subtables[y].keys == 1) {
  1617. assert(table->vars[yindex]->ref != 1);
  1618. }
  1619. #endif
  1620. #ifdef DD_STATS
  1621. table->extsymmcalls++;
  1622. #endif
  1623. arccount = 0;
  1624. counter = (int) (table->subtables[x].keys *
  1625. (table->symmviolation/100.0) + 0.5);
  1626. one = DD_ONE(table);
  1627. slots = table->subtables[x].slots;
  1628. list = table->subtables[x].nodelist;
  1629. for (i = 0; i < slots; i++) {
  1630. f = list[i];
  1631. while (f != sentinel) {
  1632. /* Find f1, f0, f11, f10, f01, f00. */
  1633. f1 = cuddT(f);
  1634. f0 = Cudd_Regular(cuddE(f));
  1635. comple = Cudd_IsComplement(cuddE(f));
  1636. notproj = f1 != one || f0 != one || f->ref != (DdHalfWord) 1;
  1637. if (f1->index == (unsigned) yindex) {
  1638. arccount++;
  1639. f11 = cuddT(f1); f10 = cuddE(f1);
  1640. } else {
  1641. if ((int) f0->index != yindex) {
  1642. /* If f is an isolated projection function it is
  1643. ** allowed to bypass layer y.
  1644. */
  1645. if (notproj) {
  1646. if (counter == 0)
  1647. return(0);
  1648. counter--; /* f bypasses layer y */
  1649. }
  1650. }
  1651. f11 = f10 = f1;
  1652. }
  1653. if ((int) f0->index == yindex) {
  1654. arccount++;
  1655. f01 = cuddT(f0); f00 = cuddE(f0);
  1656. } else {
  1657. f01 = f00 = f0;
  1658. }
  1659. if (comple) {
  1660. f01 = Cudd_Not(f01);
  1661. f00 = Cudd_Not(f00);
  1662. }
  1663. /* Unless we are looking at a projection function
  1664. ** without external references except the one from the
  1665. ** table, we insist that f01 == f10 or f11 == f00
  1666. */
  1667. if (notproj) {
  1668. if (f01 != f10 && f11 != f00) {
  1669. if (counter == 0)
  1670. return(0);
  1671. counter--;
  1672. }
  1673. }
  1674. f = f->next;
  1675. } /* while */
  1676. } /* for */
  1677. /* Calculate the total reference counts of y */
  1678. TotalRefCount = -1; /* -1 for projection function */
  1679. slots = table->subtables[y].slots;
  1680. list = table->subtables[y].nodelist;
  1681. for (i = 0; i < slots; i++) {
  1682. f = list[i];
  1683. while (f != sentinel) {
  1684. TotalRefCount += f->ref;
  1685. f = f->next;
  1686. }
  1687. }
  1688. arccounter = (int) (table->subtables[y].keys *
  1689. (table->arcviolation/100.0) + 0.5);
  1690. res = arccount >= TotalRefCount - arccounter;
  1691. #if defined(DD_DEBUG) && defined(DD_VERBOSE)
  1692. if (res) {
  1693. (void) fprintf(table->out,
  1694. "Found extended symmetry! x = %d\ty = %d\tPos(%d,%d)\n",
  1695. xindex,yindex,x,y);
  1696. }
  1697. #endif
  1698. #ifdef DD_STATS
  1699. if (res)
  1700. table->extsymm++;
  1701. #endif
  1702. return(res);
  1703. } /* end ddExtSymmCheck */
  1704. /**
  1705. @brief Checks for grouping of x and y.
  1706. @details This function is used for lazy sifting.
  1707. @return 1 in case of grouping; 0 otherwise.
  1708. @sideeffect None
  1709. */
  1710. static int
  1711. ddVarGroupCheck(
  1712. DdManager * table,
  1713. int x,
  1714. int y)
  1715. {
  1716. int xindex = table->invperm[x];
  1717. int yindex = table->invperm[y];
  1718. if (Cudd_bddIsVarToBeUngrouped(table, xindex)) return(0);
  1719. if (Cudd_bddReadPairIndex(table, xindex) == yindex) {
  1720. if (ddIsVarHandled(table, xindex) ||
  1721. ddIsVarHandled(table, yindex)) {
  1722. if (Cudd_bddIsVarToBeGrouped(table, xindex) ||
  1723. Cudd_bddIsVarToBeGrouped(table, yindex) ) {
  1724. if (table->keys - table->isolated <= table->originalSize) {
  1725. return(1);
  1726. }
  1727. }
  1728. }
  1729. }
  1730. return(0);
  1731. } /* end of ddVarGroupCheck */
  1732. /**
  1733. @brief Sets a variable to already handled.
  1734. @details This function is used for lazy sifting.
  1735. @sideeffect none
  1736. */
  1737. static int
  1738. ddSetVarHandled(
  1739. DdManager *dd,
  1740. int index)
  1741. {
  1742. if (index >= dd->size || index < 0) return(0);
  1743. dd->subtables[dd->perm[index]].varHandled = 1;
  1744. return(1);
  1745. } /* end of ddSetVarHandled */
  1746. /**
  1747. @brief Resets a variable to be processed.
  1748. @details This function is used for lazy sifting.
  1749. @sideeffect none
  1750. */
  1751. static int
  1752. ddResetVarHandled(
  1753. DdManager *dd,
  1754. int index)
  1755. {
  1756. if (index >= dd->size || index < 0) return(0);
  1757. dd->subtables[dd->perm[index]].varHandled = 0;
  1758. return(1);
  1759. } /* end of ddResetVarHandled */
  1760. /**
  1761. @brief Checks whether a variables is already handled.
  1762. @details This function is used for lazy sifting.
  1763. @sideeffect none
  1764. */
  1765. static int
  1766. ddIsVarHandled(
  1767. DdManager *dd,
  1768. int index)
  1769. {
  1770. if (index >= dd->size || index < 0) return(-1);
  1771. return dd->subtables[dd->perm[index]].varHandled;
  1772. } /* end of ddIsVarHandled */