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.

2188 lines
62 KiB

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