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.

1340 lines
38 KiB

  1. /**CFile***********************************************************************
  2. FileName [cuddZddGroup.c]
  3. PackageName [cudd]
  4. Synopsis [Functions for ZDD group sifting.]
  5. Description [External procedures included in this file:
  6. <ul>
  7. <li> Cudd_MakeZddTreeNode()
  8. </ul>
  9. Internal procedures included in this file:
  10. <ul>
  11. <li> cuddZddTreeSifting()
  12. </ul>
  13. Static procedures included in this module:
  14. <ul>
  15. <li> zddTreeSiftingAux()
  16. <li> zddCountInternalMtrNodes()
  17. <li> zddReorderChildren()
  18. <li> zddFindNodeHiLo()
  19. <li> zddUniqueCompareGroup()
  20. <li> zddGroupSifting()
  21. <li> zddGroupSiftingAux()
  22. <li> zddGroupSiftingUp()
  23. <li> zddGroupSiftingDown()
  24. <li> zddGroupMove()
  25. <li> zddGroupMoveBackward()
  26. <li> zddGroupSiftingBackward()
  27. <li> zddMergeGroups()
  28. </ul>]
  29. Author [Fabio Somenzi]
  30. Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
  31. All rights reserved.
  32. Redistribution and use in source and binary forms, with or without
  33. modification, are permitted provided that the following conditions
  34. are met:
  35. Redistributions of source code must retain the above copyright
  36. notice, this list of conditions and the following disclaimer.
  37. Redistributions in binary form must reproduce the above copyright
  38. notice, this list of conditions and the following disclaimer in the
  39. documentation and/or other materials provided with the distribution.
  40. Neither the name of the University of Colorado nor the names of its
  41. contributors may be used to endorse or promote products derived from
  42. this software without specific prior written permission.
  43. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  44. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  45. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  46. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  47. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  48. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  49. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  50. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  51. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  52. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  53. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  54. POSSIBILITY OF SUCH DAMAGE.]
  55. ******************************************************************************/
  56. #include "util.h"
  57. #include "cuddInt.h"
  58. /*---------------------------------------------------------------------------*/
  59. /* Constant declarations */
  60. /*---------------------------------------------------------------------------*/
  61. /*---------------------------------------------------------------------------*/
  62. /* Stucture declarations */
  63. /*---------------------------------------------------------------------------*/
  64. /*---------------------------------------------------------------------------*/
  65. /* Type declarations */
  66. /*---------------------------------------------------------------------------*/
  67. /*---------------------------------------------------------------------------*/
  68. /* Variable declarations */
  69. /*---------------------------------------------------------------------------*/
  70. #ifndef lint
  71. static char rcsid[] DD_UNUSED = "$Id: cuddZddGroup.c,v 1.22 2012/02/05 01:07:19 fabio Exp $";
  72. #endif
  73. static int *entry;
  74. extern int zddTotalNumberSwapping;
  75. #ifdef DD_STATS
  76. static int extsymmcalls;
  77. static int extsymm;
  78. static int secdiffcalls;
  79. static int secdiff;
  80. static int secdiffmisfire;
  81. #endif
  82. #ifdef DD_DEBUG
  83. static int pr = 0; /* flag to enable printing while debugging */
  84. /* by depositing a 1 into it */
  85. #endif
  86. /*---------------------------------------------------------------------------*/
  87. /* Macro declarations */
  88. /*---------------------------------------------------------------------------*/
  89. /**AutomaticStart*************************************************************/
  90. /*---------------------------------------------------------------------------*/
  91. /* Static function prototypes */
  92. /*---------------------------------------------------------------------------*/
  93. static int zddTreeSiftingAux (DdManager *table, MtrNode *treenode, Cudd_ReorderingType method);
  94. #ifdef DD_STATS
  95. static int zddCountInternalMtrNodes (DdManager *table, MtrNode *treenode);
  96. #endif
  97. static int zddReorderChildren (DdManager *table, MtrNode *treenode, Cudd_ReorderingType method);
  98. static void zddFindNodeHiLo (DdManager *table, MtrNode *treenode, int *lower, int *upper);
  99. static int zddUniqueCompareGroup (int *ptrX, int *ptrY);
  100. static int zddGroupSifting (DdManager *table, int lower, int upper);
  101. static int zddGroupSiftingAux (DdManager *table, int x, int xLow, int xHigh);
  102. static int zddGroupSiftingUp (DdManager *table, int y, int xLow, Move **moves);
  103. static int zddGroupSiftingDown (DdManager *table, int x, int xHigh, Move **moves);
  104. static int zddGroupMove (DdManager *table, int x, int y, Move **moves);
  105. static int zddGroupMoveBackward (DdManager *table, int x, int y);
  106. static int zddGroupSiftingBackward (DdManager *table, Move *moves, int size);
  107. static void zddMergeGroups (DdManager *table, MtrNode *treenode, int low, int high);
  108. /**AutomaticEnd***************************************************************/
  109. /*---------------------------------------------------------------------------*/
  110. /* Definition of exported functions */
  111. /*---------------------------------------------------------------------------*/
  112. /**Function********************************************************************
  113. Synopsis [Creates a new ZDD variable group.]
  114. Description [Creates a new ZDD variable group. The group starts at
  115. variable and contains size variables. The parameter low is the index
  116. of the first variable. If the variable already exists, its current
  117. position in the order is known to the manager. If the variable does
  118. not exist yet, the position is assumed to be the same as the index.
  119. The group tree is created if it does not exist yet.
  120. Returns a pointer to the group if successful; NULL otherwise.]
  121. SideEffects [The ZDD variable tree is changed.]
  122. SeeAlso [Cudd_MakeTreeNode]
  123. ******************************************************************************/
  124. MtrNode *
  125. Cudd_MakeZddTreeNode(
  126. DdManager * dd /* manager */,
  127. unsigned int low /* index of the first group variable */,
  128. unsigned int size /* number of variables in the group */,
  129. unsigned int type /* MTR_DEFAULT or MTR_FIXED */)
  130. {
  131. MtrNode *group;
  132. MtrNode *tree;
  133. unsigned int level;
  134. /* If the variable does not exist yet, the position is assumed to be
  135. ** the same as the index. Therefore, applications that rely on
  136. ** Cudd_bddNewVarAtLevel or Cudd_addNewVarAtLevel to create new
  137. ** variables have to create the variables before they group them.
  138. */
  139. level = (low < (unsigned int) dd->sizeZ) ? dd->permZ[low] : low;
  140. if (level + size - 1> (int) MTR_MAXHIGH)
  141. return(NULL);
  142. /* If the tree does not exist yet, create it. */
  143. tree = dd->treeZ;
  144. if (tree == NULL) {
  145. dd->treeZ = tree = Mtr_InitGroupTree(0, dd->sizeZ);
  146. if (tree == NULL)
  147. return(NULL);
  148. tree->index = dd->invpermZ[0];
  149. }
  150. /* Extend the upper bound of the tree if necessary. This allows the
  151. ** application to create groups even before the variables are created.
  152. */
  153. tree->size = ddMax(tree->size, level + size);
  154. /* Create the group. */
  155. group = Mtr_MakeGroup(tree, level, size, type);
  156. if (group == NULL)
  157. return(NULL);
  158. /* Initialize the index field to the index of the variable currently
  159. ** in position low. This field will be updated by the reordering
  160. ** procedure to provide a handle to the group once it has been moved.
  161. */
  162. group->index = (MtrHalfWord) low;
  163. return(group);
  164. } /* end of Cudd_MakeZddTreeNode */
  165. /*---------------------------------------------------------------------------*/
  166. /* Definition of internal functions */
  167. /*---------------------------------------------------------------------------*/
  168. /**Function********************************************************************
  169. Synopsis [Tree sifting algorithm for ZDDs.]
  170. Description [Tree sifting algorithm for ZDDs. Assumes that a tree
  171. representing a group hierarchy is passed as a parameter. It then
  172. reorders each group in postorder fashion by calling
  173. zddTreeSiftingAux. Assumes that no dead nodes are present. Returns
  174. 1 if successful; 0 otherwise.]
  175. SideEffects [None]
  176. ******************************************************************************/
  177. int
  178. cuddZddTreeSifting(
  179. DdManager * table /* DD table */,
  180. Cudd_ReorderingType method /* reordering method for the groups of leaves */)
  181. {
  182. int i;
  183. int nvars;
  184. int result;
  185. int tempTree;
  186. /* If no tree is provided we create a temporary one in which all
  187. ** variables are in a single group. After reordering this tree is
  188. ** destroyed.
  189. */
  190. tempTree = table->treeZ == NULL;
  191. if (tempTree) {
  192. table->treeZ = Mtr_InitGroupTree(0,table->sizeZ);
  193. table->treeZ->index = table->invpermZ[0];
  194. }
  195. nvars = table->sizeZ;
  196. #ifdef DD_DEBUG
  197. if (pr > 0 && !tempTree)
  198. (void) fprintf(table->out,"cuddZddTreeSifting:");
  199. Mtr_PrintGroups(table->treeZ,pr <= 0);
  200. #endif
  201. #if 0
  202. /* Debugging code. */
  203. if (table->tree && table->treeZ) {
  204. (void) fprintf(table->out,"\n");
  205. Mtr_PrintGroups(table->tree, 0);
  206. cuddPrintVarGroups(table,table->tree,0,0);
  207. for (i = 0; i < table->size; i++) {
  208. (void) fprintf(table->out,"%s%d",
  209. (i == 0) ? "" : ",", table->invperm[i]);
  210. }
  211. (void) fprintf(table->out,"\n");
  212. for (i = 0; i < table->size; i++) {
  213. (void) fprintf(table->out,"%s%d",
  214. (i == 0) ? "" : ",", table->perm[i]);
  215. }
  216. (void) fprintf(table->out,"\n\n");
  217. Mtr_PrintGroups(table->treeZ,0);
  218. cuddPrintVarGroups(table,table->treeZ,1,0);
  219. for (i = 0; i < table->sizeZ; i++) {
  220. (void) fprintf(table->out,"%s%d",
  221. (i == 0) ? "" : ",", table->invpermZ[i]);
  222. }
  223. (void) fprintf(table->out,"\n");
  224. for (i = 0; i < table->sizeZ; i++) {
  225. (void) fprintf(table->out,"%s%d",
  226. (i == 0) ? "" : ",", table->permZ[i]);
  227. }
  228. (void) fprintf(table->out,"\n");
  229. }
  230. /* End of debugging code. */
  231. #endif
  232. #ifdef DD_STATS
  233. extsymmcalls = 0;
  234. extsymm = 0;
  235. secdiffcalls = 0;
  236. secdiff = 0;
  237. secdiffmisfire = 0;
  238. (void) fprintf(table->out,"\n");
  239. if (!tempTree)
  240. (void) fprintf(table->out,"#:IM_NODES %8d: group tree nodes\n",
  241. zddCountInternalMtrNodes(table,table->treeZ));
  242. #endif
  243. /* Initialize the group of each subtable to itself. Initially
  244. ** there are no groups. Groups are created according to the tree
  245. ** structure in postorder fashion.
  246. */
  247. for (i = 0; i < nvars; i++)
  248. table->subtableZ[i].next = i;
  249. /* Reorder. */
  250. result = zddTreeSiftingAux(table, table->treeZ, method);
  251. #ifdef DD_STATS /* print stats */
  252. if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
  253. (table->groupcheck == CUDD_GROUP_CHECK7 ||
  254. table->groupcheck == CUDD_GROUP_CHECK5)) {
  255. (void) fprintf(table->out,"\nextsymmcalls = %d\n",extsymmcalls);
  256. (void) fprintf(table->out,"extsymm = %d",extsymm);
  257. }
  258. if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
  259. table->groupcheck == CUDD_GROUP_CHECK7) {
  260. (void) fprintf(table->out,"\nsecdiffcalls = %d\n",secdiffcalls);
  261. (void) fprintf(table->out,"secdiff = %d\n",secdiff);
  262. (void) fprintf(table->out,"secdiffmisfire = %d",secdiffmisfire);
  263. }
  264. #endif
  265. if (tempTree)
  266. Cudd_FreeZddTree(table);
  267. return(result);
  268. } /* end of cuddZddTreeSifting */
  269. /*---------------------------------------------------------------------------*/
  270. /* Definition of static functions */
  271. /*---------------------------------------------------------------------------*/
  272. /**Function********************************************************************
  273. Synopsis [Visits the group tree and reorders each group.]
  274. Description [Recursively visits the group tree and reorders each
  275. group in postorder fashion. Returns 1 if successful; 0 otherwise.]
  276. SideEffects [None]
  277. ******************************************************************************/
  278. static int
  279. zddTreeSiftingAux(
  280. DdManager * table,
  281. MtrNode * treenode,
  282. Cudd_ReorderingType method)
  283. {
  284. MtrNode *auxnode;
  285. int res;
  286. #ifdef DD_DEBUG
  287. Mtr_PrintGroups(treenode,1);
  288. #endif
  289. auxnode = treenode;
  290. while (auxnode != NULL) {
  291. if (auxnode->child != NULL) {
  292. if (!zddTreeSiftingAux(table, auxnode->child, method))
  293. return(0);
  294. res = zddReorderChildren(table, auxnode, CUDD_REORDER_GROUP_SIFT);
  295. if (res == 0)
  296. return(0);
  297. } else if (auxnode->size > 1) {
  298. if (!zddReorderChildren(table, auxnode, method))
  299. return(0);
  300. }
  301. auxnode = auxnode->younger;
  302. }
  303. return(1);
  304. } /* end of zddTreeSiftingAux */
  305. #ifdef DD_STATS
  306. /**Function********************************************************************
  307. Synopsis [Counts the number of internal nodes of the group tree.]
  308. Description [Counts the number of internal nodes of the group tree.
  309. Returns the count.]
  310. SideEffects [None]
  311. ******************************************************************************/
  312. static int
  313. zddCountInternalMtrNodes(
  314. DdManager * table,
  315. MtrNode * treenode)
  316. {
  317. MtrNode *auxnode;
  318. int count,nodeCount;
  319. nodeCount = 0;
  320. auxnode = treenode;
  321. while (auxnode != NULL) {
  322. if (!(MTR_TEST(auxnode,MTR_TERMINAL))) {
  323. nodeCount++;
  324. count = zddCountInternalMtrNodes(table,auxnode->child);
  325. nodeCount += count;
  326. }
  327. auxnode = auxnode->younger;
  328. }
  329. return(nodeCount);
  330. } /* end of zddCountInternalMtrNodes */
  331. #endif
  332. /**Function********************************************************************
  333. Synopsis [Reorders the children of a group tree node according to
  334. the options.]
  335. Description [Reorders the children of a group tree node according to
  336. the options. After reordering puts all the variables in the group
  337. and/or its descendents in a single group. This allows hierarchical
  338. reordering. If the variables in the group do not exist yet, simply
  339. does nothing. Returns 1 if successful; 0 otherwise.]
  340. SideEffects [None]
  341. ******************************************************************************/
  342. static int
  343. zddReorderChildren(
  344. DdManager * table,
  345. MtrNode * treenode,
  346. Cudd_ReorderingType method)
  347. {
  348. int lower;
  349. int upper;
  350. int result;
  351. unsigned int initialSize;
  352. zddFindNodeHiLo(table,treenode,&lower,&upper);
  353. /* If upper == -1 these variables do not exist yet. */
  354. if (upper == -1)
  355. return(1);
  356. if (treenode->flags == MTR_FIXED) {
  357. result = 1;
  358. } else {
  359. #ifdef DD_STATS
  360. (void) fprintf(table->out," ");
  361. #endif
  362. switch (method) {
  363. case CUDD_REORDER_RANDOM:
  364. case CUDD_REORDER_RANDOM_PIVOT:
  365. result = cuddZddSwapping(table,lower,upper,method);
  366. break;
  367. case CUDD_REORDER_SIFT:
  368. result = cuddZddSifting(table,lower,upper);
  369. break;
  370. case CUDD_REORDER_SIFT_CONVERGE:
  371. do {
  372. initialSize = table->keysZ;
  373. result = cuddZddSifting(table,lower,upper);
  374. if (initialSize <= table->keysZ)
  375. break;
  376. #ifdef DD_STATS
  377. else
  378. (void) fprintf(table->out,"\n");
  379. #endif
  380. } while (result != 0);
  381. break;
  382. case CUDD_REORDER_SYMM_SIFT:
  383. result = cuddZddSymmSifting(table,lower,upper);
  384. break;
  385. case CUDD_REORDER_SYMM_SIFT_CONV:
  386. result = cuddZddSymmSiftingConv(table,lower,upper);
  387. break;
  388. case CUDD_REORDER_GROUP_SIFT:
  389. result = zddGroupSifting(table,lower,upper);
  390. break;
  391. case CUDD_REORDER_LINEAR:
  392. result = cuddZddLinearSifting(table,lower,upper);
  393. break;
  394. case CUDD_REORDER_LINEAR_CONVERGE:
  395. do {
  396. initialSize = table->keysZ;
  397. result = cuddZddLinearSifting(table,lower,upper);
  398. if (initialSize <= table->keysZ)
  399. break;
  400. #ifdef DD_STATS
  401. else
  402. (void) fprintf(table->out,"\n");
  403. #endif
  404. } while (result != 0);
  405. break;
  406. default:
  407. return(0);
  408. }
  409. }
  410. /* Create a single group for all the variables that were sifted,
  411. ** so that they will be treated as a single block by successive
  412. ** invocations of zddGroupSifting.
  413. */
  414. zddMergeGroups(table,treenode,lower,upper);
  415. #ifdef DD_DEBUG
  416. if (pr > 0) (void) fprintf(table->out,"zddReorderChildren:");
  417. #endif
  418. return(result);
  419. } /* end of zddReorderChildren */
  420. /**Function********************************************************************
  421. Synopsis [Finds the lower and upper bounds of the group represented
  422. by treenode.]
  423. Description [Finds the lower and upper bounds of the group represented
  424. by treenode. The high and low fields of treenode are indices. From
  425. those we need to derive the current positions, and find maximum and
  426. minimum.]
  427. SideEffects [The bounds are returned as side effects.]
  428. SeeAlso []
  429. ******************************************************************************/
  430. static void
  431. zddFindNodeHiLo(
  432. DdManager * table,
  433. MtrNode * treenode,
  434. int * lower,
  435. int * upper)
  436. {
  437. int low;
  438. int high;
  439. /* Check whether no variables in this group already exist.
  440. ** If so, return immediately. The calling procedure will know from
  441. ** the values of upper that no reordering is needed.
  442. */
  443. if ((int) treenode->low >= table->sizeZ) {
  444. *lower = table->sizeZ;
  445. *upper = -1;
  446. return;
  447. }
  448. *lower = low = (unsigned int) table->permZ[treenode->index];
  449. high = (int) (low + treenode->size - 1);
  450. if (high >= table->sizeZ) {
  451. /* This is the case of a partially existing group. The aim is to
  452. ** reorder as many variables as safely possible. If the tree
  453. ** node is terminal, we just reorder the subset of the group
  454. ** that is currently in existence. If the group has
  455. ** subgroups, then we only reorder those subgroups that are
  456. ** fully instantiated. This way we avoid breaking up a group.
  457. */
  458. MtrNode *auxnode = treenode->child;
  459. if (auxnode == NULL) {
  460. *upper = (unsigned int) table->sizeZ - 1;
  461. } else {
  462. /* Search the subgroup that strands the table->sizeZ line.
  463. ** If the first group starts at 0 and goes past table->sizeZ
  464. ** upper will get -1, thus correctly signaling that no reordering
  465. ** should take place.
  466. */
  467. while (auxnode != NULL) {
  468. int thisLower = table->permZ[auxnode->low];
  469. int thisUpper = thisLower + auxnode->size - 1;
  470. if (thisUpper >= table->sizeZ && thisLower < table->sizeZ)
  471. *upper = (unsigned int) thisLower - 1;
  472. auxnode = auxnode->younger;
  473. }
  474. }
  475. } else {
  476. /* Normal case: All the variables of the group exist. */
  477. *upper = (unsigned int) high;
  478. }
  479. #ifdef DD_DEBUG
  480. /* Make sure that all variables in group are contiguous. */
  481. assert(treenode->size >= *upper - *lower + 1);
  482. #endif
  483. return;
  484. } /* end of zddFindNodeHiLo */
  485. /**Function********************************************************************
  486. Synopsis [Comparison function used by qsort.]
  487. Description [Comparison function used by qsort to order the variables
  488. according to the number of keys in the subtables. Returns the
  489. difference in number of keys between the two variables being
  490. compared.]
  491. SideEffects [None]
  492. ******************************************************************************/
  493. static int
  494. zddUniqueCompareGroup(
  495. int * ptrX,
  496. int * ptrY)
  497. {
  498. #if 0
  499. if (entry[*ptrY] == entry[*ptrX]) {
  500. return((*ptrX) - (*ptrY));
  501. }
  502. #endif
  503. return(entry[*ptrY] - entry[*ptrX]);
  504. } /* end of zddUniqueCompareGroup */
  505. /**Function********************************************************************
  506. Synopsis [Sifts from treenode->low to treenode->high.]
  507. Description [Sifts from treenode->low to treenode->high. If
  508. croupcheck == CUDD_GROUP_CHECK7, it checks for group creation at the
  509. end of the initial sifting. If a group is created, it is then sifted
  510. again. After sifting one variable, the group that contains it is
  511. dissolved. Returns 1 in case of success; 0 otherwise.]
  512. SideEffects [None]
  513. ******************************************************************************/
  514. static int
  515. zddGroupSifting(
  516. DdManager * table,
  517. int lower,
  518. int upper)
  519. {
  520. int *var;
  521. int i,j,x,xInit;
  522. int nvars;
  523. int classes;
  524. int result;
  525. int *sifted;
  526. #ifdef DD_STATS
  527. unsigned previousSize;
  528. #endif
  529. int xindex;
  530. nvars = table->sizeZ;
  531. /* Order variables to sift. */
  532. entry = NULL;
  533. sifted = NULL;
  534. var = ALLOC(int,nvars);
  535. if (var == NULL) {
  536. table->errorCode = CUDD_MEMORY_OUT;
  537. goto zddGroupSiftingOutOfMem;
  538. }
  539. entry = ALLOC(int,nvars);
  540. if (entry == NULL) {
  541. table->errorCode = CUDD_MEMORY_OUT;
  542. goto zddGroupSiftingOutOfMem;
  543. }
  544. sifted = ALLOC(int,nvars);
  545. if (sifted == NULL) {
  546. table->errorCode = CUDD_MEMORY_OUT;
  547. goto zddGroupSiftingOutOfMem;
  548. }
  549. /* Here we consider only one representative for each group. */
  550. for (i = 0, classes = 0; i < nvars; i++) {
  551. sifted[i] = 0;
  552. x = table->permZ[i];
  553. if ((unsigned) x >= table->subtableZ[x].next) {
  554. entry[i] = table->subtableZ[x].keys;
  555. var[classes] = i;
  556. classes++;
  557. }
  558. }
  559. qsort((void *)var,classes,sizeof(int),(DD_QSFP)zddUniqueCompareGroup);
  560. /* Now sift. */
  561. for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
  562. if (zddTotalNumberSwapping >= table->siftMaxSwap)
  563. break;
  564. if (util_cpu_time() - table->startTime > table->timeLimit) {
  565. table->autoDynZ = 0; /* prevent further reordering */
  566. break;
  567. }
  568. xindex = var[i];
  569. if (sifted[xindex] == 1) /* variable already sifted as part of group */
  570. continue;
  571. x = table->permZ[xindex]; /* find current level of this variable */
  572. if (x < lower || x > upper)
  573. continue;
  574. #ifdef DD_STATS
  575. previousSize = table->keysZ;
  576. #endif
  577. #ifdef DD_DEBUG
  578. /* x is bottom of group */
  579. assert((unsigned) x >= table->subtableZ[x].next);
  580. #endif
  581. result = zddGroupSiftingAux(table,x,lower,upper);
  582. if (!result) goto zddGroupSiftingOutOfMem;
  583. #ifdef DD_STATS
  584. if (table->keysZ < previousSize) {
  585. (void) fprintf(table->out,"-");
  586. } else if (table->keysZ > previousSize) {
  587. (void) fprintf(table->out,"+");
  588. } else {
  589. (void) fprintf(table->out,"=");
  590. }
  591. fflush(table->out);
  592. #endif
  593. /* Mark variables in the group just sifted. */
  594. x = table->permZ[xindex];
  595. if ((unsigned) x != table->subtableZ[x].next) {
  596. xInit = x;
  597. do {
  598. j = table->invpermZ[x];
  599. sifted[j] = 1;
  600. x = table->subtableZ[x].next;
  601. } while (x != xInit);
  602. }
  603. #ifdef DD_DEBUG
  604. if (pr > 0) (void) fprintf(table->out,"zddGroupSifting:");
  605. #endif
  606. } /* for */
  607. FREE(sifted);
  608. FREE(var);
  609. FREE(entry);
  610. return(1);
  611. zddGroupSiftingOutOfMem:
  612. if (entry != NULL) FREE(entry);
  613. if (var != NULL) FREE(var);
  614. if (sifted != NULL) FREE(sifted);
  615. return(0);
  616. } /* end of zddGroupSifting */
  617. /**Function********************************************************************
  618. Synopsis [Sifts one variable up and down until it has taken all
  619. positions. Checks for aggregation.]
  620. Description [Sifts one variable up and down until it has taken all
  621. positions. Checks for aggregation. There may be at most two sweeps,
  622. even if the group grows. Assumes that x is either an isolated
  623. variable, or it is the bottom of a group. All groups may not have
  624. been found. The variable being moved is returned to the best position
  625. seen during sifting. Returns 1 in case of success; 0 otherwise.]
  626. SideEffects [None]
  627. ******************************************************************************/
  628. static int
  629. zddGroupSiftingAux(
  630. DdManager * table,
  631. int x,
  632. int xLow,
  633. int xHigh)
  634. {
  635. Move *move;
  636. Move *moves; /* list of moves */
  637. int initialSize;
  638. int result;
  639. #ifdef DD_DEBUG
  640. if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingAux from %d to %d\n",xLow,xHigh);
  641. assert((unsigned) x >= table->subtableZ[x].next); /* x is bottom of group */
  642. #endif
  643. initialSize = table->keysZ;
  644. moves = NULL;
  645. if (x == xLow) { /* Sift down */
  646. #ifdef DD_DEBUG
  647. /* x must be a singleton */
  648. assert((unsigned) x == table->subtableZ[x].next);
  649. #endif
  650. if (x == xHigh) return(1); /* just one variable */
  651. if (!zddGroupSiftingDown(table,x,xHigh,&moves))
  652. goto zddGroupSiftingAuxOutOfMem;
  653. /* at this point x == xHigh, unless early term */
  654. /* move backward and stop at best position */
  655. result = zddGroupSiftingBackward(table,moves,initialSize);
  656. #ifdef DD_DEBUG
  657. assert(table->keysZ <= (unsigned) initialSize);
  658. #endif
  659. if (!result) goto zddGroupSiftingAuxOutOfMem;
  660. } else if (cuddZddNextHigh(table,x) > xHigh) { /* Sift up */
  661. #ifdef DD_DEBUG
  662. /* x is bottom of group */
  663. assert((unsigned) x >= table->subtableZ[x].next);
  664. #endif
  665. /* Find top of x's group */
  666. x = table->subtableZ[x].next;
  667. if (!zddGroupSiftingUp(table,x,xLow,&moves))
  668. goto zddGroupSiftingAuxOutOfMem;
  669. /* at this point x == xLow, unless early term */
  670. /* move backward and stop at best position */
  671. result = zddGroupSiftingBackward(table,moves,initialSize);
  672. #ifdef DD_DEBUG
  673. assert(table->keysZ <= (unsigned) initialSize);
  674. #endif
  675. if (!result) goto zddGroupSiftingAuxOutOfMem;
  676. } else if (x - xLow > xHigh - x) { /* must go down first: shorter */
  677. if (!zddGroupSiftingDown(table,x,xHigh,&moves))
  678. goto zddGroupSiftingAuxOutOfMem;
  679. /* at this point x == xHigh, unless early term */
  680. /* Find top of group */
  681. if (moves) {
  682. x = moves->y;
  683. }
  684. while ((unsigned) x < table->subtableZ[x].next)
  685. x = table->subtableZ[x].next;
  686. x = table->subtableZ[x].next;
  687. #ifdef DD_DEBUG
  688. /* x should be the top of a group */
  689. assert((unsigned) x <= table->subtableZ[x].next);
  690. #endif
  691. if (!zddGroupSiftingUp(table,x,xLow,&moves))
  692. goto zddGroupSiftingAuxOutOfMem;
  693. /* move backward and stop at best position */
  694. result = zddGroupSiftingBackward(table,moves,initialSize);
  695. #ifdef DD_DEBUG
  696. assert(table->keysZ <= (unsigned) initialSize);
  697. #endif
  698. if (!result) goto zddGroupSiftingAuxOutOfMem;
  699. } else { /* moving up first: shorter */
  700. /* Find top of x's group */
  701. x = table->subtableZ[x].next;
  702. if (!zddGroupSiftingUp(table,x,xLow,&moves))
  703. goto zddGroupSiftingAuxOutOfMem;
  704. /* at this point x == xHigh, unless early term */
  705. if (moves) {
  706. x = moves->x;
  707. }
  708. while ((unsigned) x < table->subtableZ[x].next)
  709. x = table->subtableZ[x].next;
  710. #ifdef DD_DEBUG
  711. /* x is bottom of a group */
  712. assert((unsigned) x >= table->subtableZ[x].next);
  713. #endif
  714. if (!zddGroupSiftingDown(table,x,xHigh,&moves))
  715. goto zddGroupSiftingAuxOutOfMem;
  716. /* move backward and stop at best position */
  717. result = zddGroupSiftingBackward(table,moves,initialSize);
  718. #ifdef DD_DEBUG
  719. assert(table->keysZ <= (unsigned) initialSize);
  720. #endif
  721. if (!result) goto zddGroupSiftingAuxOutOfMem;
  722. }
  723. while (moves != NULL) {
  724. move = moves->next;
  725. cuddDeallocMove(table, moves);
  726. moves = move;
  727. }
  728. return(1);
  729. zddGroupSiftingAuxOutOfMem:
  730. while (moves != NULL) {
  731. move = moves->next;
  732. cuddDeallocMove(table, moves);
  733. moves = move;
  734. }
  735. return(0);
  736. } /* end of zddGroupSiftingAux */
  737. /**Function********************************************************************
  738. Synopsis [Sifts up a variable until either it reaches position xLow
  739. or the size of the DD heap increases too much.]
  740. Description [Sifts up a variable until either it reaches position
  741. xLow or the size of the DD heap increases too much. Assumes that y is
  742. the top of a group (or a singleton). Checks y for aggregation to the
  743. adjacent variables. Records all the moves that are appended to the
  744. list of moves received as input and returned as a side effect.
  745. Returns 1 in case of success; 0 otherwise.]
  746. SideEffects [None]
  747. ******************************************************************************/
  748. static int
  749. zddGroupSiftingUp(
  750. DdManager * table,
  751. int y,
  752. int xLow,
  753. Move ** moves)
  754. {
  755. Move *move;
  756. int x;
  757. int size;
  758. int gxtop;
  759. int limitSize;
  760. limitSize = table->keysZ;
  761. x = cuddZddNextLow(table,y);
  762. while (x >= xLow) {
  763. gxtop = table->subtableZ[x].next;
  764. if (table->subtableZ[x].next == (unsigned) x &&
  765. table->subtableZ[y].next == (unsigned) y) {
  766. /* x and y are self groups */
  767. size = cuddZddSwapInPlace(table,x,y);
  768. #ifdef DD_DEBUG
  769. assert(table->subtableZ[x].next == (unsigned) x);
  770. assert(table->subtableZ[y].next == (unsigned) y);
  771. #endif
  772. if (size == 0) goto zddGroupSiftingUpOutOfMem;
  773. move = (Move *)cuddDynamicAllocNode(table);
  774. if (move == NULL) goto zddGroupSiftingUpOutOfMem;
  775. move->x = x;
  776. move->y = y;
  777. move->flags = MTR_DEFAULT;
  778. move->size = size;
  779. move->next = *moves;
  780. *moves = move;
  781. #ifdef DD_DEBUG
  782. if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingUp (2 single groups):\n");
  783. #endif
  784. if ((double) size > (double) limitSize * table->maxGrowth)
  785. return(1);
  786. if (size < limitSize) limitSize = size;
  787. } else { /* group move */
  788. size = zddGroupMove(table,x,y,moves);
  789. if (size == 0) goto zddGroupSiftingUpOutOfMem;
  790. if ((double) size > (double) limitSize * table->maxGrowth)
  791. return(1);
  792. if (size < limitSize) limitSize = size;
  793. }
  794. y = gxtop;
  795. x = cuddZddNextLow(table,y);
  796. }
  797. return(1);
  798. zddGroupSiftingUpOutOfMem:
  799. while (*moves != NULL) {
  800. move = (*moves)->next;
  801. cuddDeallocMove(table, *moves);
  802. *moves = move;
  803. }
  804. return(0);
  805. } /* end of zddGroupSiftingUp */
  806. /**Function********************************************************************
  807. Synopsis [Sifts down a variable until it reaches position xHigh.]
  808. Description [Sifts down a variable until it reaches position xHigh.
  809. Assumes that x is the bottom of a group (or a singleton). Records
  810. all the moves. Returns 1 in case of success; 0 otherwise.]
  811. SideEffects [None]
  812. ******************************************************************************/
  813. static int
  814. zddGroupSiftingDown(
  815. DdManager * table,
  816. int x,
  817. int xHigh,
  818. Move ** moves)
  819. {
  820. Move *move;
  821. int y;
  822. int size;
  823. int limitSize;
  824. int gybot;
  825. /* Initialize R */
  826. limitSize = size = table->keysZ;
  827. y = cuddZddNextHigh(table,x);
  828. while (y <= xHigh) {
  829. /* Find bottom of y group. */
  830. gybot = table->subtableZ[y].next;
  831. while (table->subtableZ[gybot].next != (unsigned) y)
  832. gybot = table->subtableZ[gybot].next;
  833. if (table->subtableZ[x].next == (unsigned) x &&
  834. table->subtableZ[y].next == (unsigned) y) {
  835. /* x and y are self groups */
  836. size = cuddZddSwapInPlace(table,x,y);
  837. #ifdef DD_DEBUG
  838. assert(table->subtableZ[x].next == (unsigned) x);
  839. assert(table->subtableZ[y].next == (unsigned) y);
  840. #endif
  841. if (size == 0) goto zddGroupSiftingDownOutOfMem;
  842. /* Record move. */
  843. move = (Move *) cuddDynamicAllocNode(table);
  844. if (move == NULL) goto zddGroupSiftingDownOutOfMem;
  845. move->x = x;
  846. move->y = y;
  847. move->flags = MTR_DEFAULT;
  848. move->size = size;
  849. move->next = *moves;
  850. *moves = move;
  851. #ifdef DD_DEBUG
  852. if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingDown (2 single groups):\n");
  853. #endif
  854. if ((double) size > (double) limitSize * table->maxGrowth)
  855. return(1);
  856. if (size < limitSize) limitSize = size;
  857. x = y;
  858. y = cuddZddNextHigh(table,x);
  859. } else { /* Group move */
  860. size = zddGroupMove(table,x,y,moves);
  861. if (size == 0) goto zddGroupSiftingDownOutOfMem;
  862. if ((double) size > (double) limitSize * table->maxGrowth)
  863. return(1);
  864. if (size < limitSize) limitSize = size;
  865. }
  866. x = gybot;
  867. y = cuddZddNextHigh(table,x);
  868. }
  869. return(1);
  870. zddGroupSiftingDownOutOfMem:
  871. while (*moves != NULL) {
  872. move = (*moves)->next;
  873. cuddDeallocMove(table, *moves);
  874. *moves = move;
  875. }
  876. return(0);
  877. } /* end of zddGroupSiftingDown */
  878. /**Function********************************************************************
  879. Synopsis [Swaps two groups and records the move.]
  880. Description [Swaps two groups and records the move. Returns the
  881. number of keys in the DD table in case of success; 0 otherwise.]
  882. SideEffects [None]
  883. ******************************************************************************/
  884. static int
  885. zddGroupMove(
  886. DdManager * table,
  887. int x,
  888. int y,
  889. Move ** moves)
  890. {
  891. Move *move;
  892. int size;
  893. int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
  894. int swapx,swapy;
  895. #if defined(DD_DEBUG) && defined(DD_VERBOSE)
  896. int initialSize,bestSize;
  897. #endif
  898. #ifdef DD_DEBUG
  899. /* We assume that x < y */
  900. assert(x < y);
  901. #endif
  902. /* Find top, bottom, and size for the two groups. */
  903. xbot = x;
  904. xtop = table->subtableZ[x].next;
  905. xsize = xbot - xtop + 1;
  906. ybot = y;
  907. while ((unsigned) ybot < table->subtableZ[ybot].next)
  908. ybot = table->subtableZ[ybot].next;
  909. ytop = y;
  910. ysize = ybot - ytop + 1;
  911. #if defined(DD_DEBUG) && defined(DD_VERBOSE)
  912. initialSize = bestSize = table->keysZ;
  913. #endif
  914. /* Sift the variables of the second group up through the first group */
  915. for (i = 1; i <= ysize; i++) {
  916. for (j = 1; j <= xsize; j++) {
  917. size = cuddZddSwapInPlace(table,x,y);
  918. if (size == 0) goto zddGroupMoveOutOfMem;
  919. #if defined(DD_DEBUG) && defined(DD_VERBOSE)
  920. if (size < bestSize)
  921. bestSize = size;
  922. #endif
  923. swapx = x; swapy = y;
  924. y = x;
  925. x = cuddZddNextLow(table,y);
  926. }
  927. y = ytop + i;
  928. x = cuddZddNextLow(table,y);
  929. }
  930. #if defined(DD_DEBUG) && defined(DD_VERBOSE)
  931. if ((bestSize < initialSize) && (bestSize < size))
  932. (void) fprintf(table->out,"Missed local minimum: initialSize:%d bestSize:%d finalSize:%d\n",initialSize,bestSize,size);
  933. #endif
  934. /* fix groups */
  935. y = xtop; /* ytop is now where xtop used to be */
  936. for (i = 0; i < ysize - 1; i++) {
  937. table->subtableZ[y].next = cuddZddNextHigh(table,y);
  938. y = cuddZddNextHigh(table,y);
  939. }
  940. table->subtableZ[y].next = xtop; /* y is bottom of its group, join */
  941. /* it to top of its group */
  942. x = cuddZddNextHigh(table,y);
  943. newxtop = x;
  944. for (i = 0; i < xsize - 1; i++) {
  945. table->subtableZ[x].next = cuddZddNextHigh(table,x);
  946. x = cuddZddNextHigh(table,x);
  947. }
  948. table->subtableZ[x].next = newxtop; /* x is bottom of its group, join */
  949. /* it to top of its group */
  950. #ifdef DD_DEBUG
  951. if (pr > 0) (void) fprintf(table->out,"zddGroupMove:\n");
  952. #endif
  953. /* Store group move */
  954. move = (Move *) cuddDynamicAllocNode(table);
  955. if (move == NULL) goto zddGroupMoveOutOfMem;
  956. move->x = swapx;
  957. move->y = swapy;
  958. move->flags = MTR_DEFAULT;
  959. move->size = table->keysZ;
  960. move->next = *moves;
  961. *moves = move;
  962. return(table->keysZ);
  963. zddGroupMoveOutOfMem:
  964. while (*moves != NULL) {
  965. move = (*moves)->next;
  966. cuddDeallocMove(table, *moves);
  967. *moves = move;
  968. }
  969. return(0);
  970. } /* end of zddGroupMove */
  971. /**Function********************************************************************
  972. Synopsis [Undoes the swap two groups.]
  973. Description [Undoes the swap two groups. Returns 1 in case of
  974. success; 0 otherwise.]
  975. SideEffects [None]
  976. ******************************************************************************/
  977. static int
  978. zddGroupMoveBackward(
  979. DdManager * table,
  980. int x,
  981. int y)
  982. {
  983. int size;
  984. int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
  985. #ifdef DD_DEBUG
  986. /* We assume that x < y */
  987. assert(x < y);
  988. #endif
  989. /* Find top, bottom, and size for the two groups. */
  990. xbot = x;
  991. xtop = table->subtableZ[x].next;
  992. xsize = xbot - xtop + 1;
  993. ybot = y;
  994. while ((unsigned) ybot < table->subtableZ[ybot].next)
  995. ybot = table->subtableZ[ybot].next;
  996. ytop = y;
  997. ysize = ybot - ytop + 1;
  998. /* Sift the variables of the second group up through the first group */
  999. for (i = 1; i <= ysize; i++) {
  1000. for (j = 1; j <= xsize; j++) {
  1001. size = cuddZddSwapInPlace(table,x,y);
  1002. if (size == 0)
  1003. return(0);
  1004. y = x;
  1005. x = cuddZddNextLow(table,y);
  1006. }
  1007. y = ytop + i;
  1008. x = cuddZddNextLow(table,y);
  1009. }
  1010. /* fix groups */
  1011. y = xtop;
  1012. for (i = 0; i < ysize - 1; i++) {
  1013. table->subtableZ[y].next = cuddZddNextHigh(table,y);
  1014. y = cuddZddNextHigh(table,y);
  1015. }
  1016. table->subtableZ[y].next = xtop; /* y is bottom of its group, join */
  1017. /* to its top */
  1018. x = cuddZddNextHigh(table,y);
  1019. newxtop = x;
  1020. for (i = 0; i < xsize - 1; i++) {
  1021. table->subtableZ[x].next = cuddZddNextHigh(table,x);
  1022. x = cuddZddNextHigh(table,x);
  1023. }
  1024. table->subtableZ[x].next = newxtop; /* x is bottom of its group, join */
  1025. /* to its top */
  1026. #ifdef DD_DEBUG
  1027. if (pr > 0) (void) fprintf(table->out,"zddGroupMoveBackward:\n");
  1028. #endif
  1029. return(1);
  1030. } /* end of zddGroupMoveBackward */
  1031. /**Function********************************************************************
  1032. Synopsis [Determines the best position for a variables and returns
  1033. it there.]
  1034. Description [Determines the best position for a variables and returns
  1035. it there. Returns 1 in case of success; 0 otherwise.]
  1036. SideEffects [None]
  1037. ******************************************************************************/
  1038. static int
  1039. zddGroupSiftingBackward(
  1040. DdManager * table,
  1041. Move * moves,
  1042. int size)
  1043. {
  1044. Move *move;
  1045. int res;
  1046. for (move = moves; move != NULL; move = move->next) {
  1047. if (move->size < size) {
  1048. size = move->size;
  1049. }
  1050. }
  1051. for (move = moves; move != NULL; move = move->next) {
  1052. if (move->size == size) return(1);
  1053. if ((table->subtableZ[move->x].next == move->x) &&
  1054. (table->subtableZ[move->y].next == move->y)) {
  1055. res = cuddZddSwapInPlace(table,(int)move->x,(int)move->y);
  1056. if (!res) return(0);
  1057. #ifdef DD_DEBUG
  1058. if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingBackward:\n");
  1059. assert(table->subtableZ[move->x].next == move->x);
  1060. assert(table->subtableZ[move->y].next == move->y);
  1061. #endif
  1062. } else { /* Group move necessary */
  1063. res = zddGroupMoveBackward(table,(int)move->x,(int)move->y);
  1064. if (!res) return(0);
  1065. }
  1066. }
  1067. return(1);
  1068. } /* end of zddGroupSiftingBackward */
  1069. /**Function********************************************************************
  1070. Synopsis [Merges groups in the DD table.]
  1071. Description [Creates a single group from low to high and adjusts the
  1072. idex field of the tree node.]
  1073. SideEffects [None]
  1074. ******************************************************************************/
  1075. static void
  1076. zddMergeGroups(
  1077. DdManager * table,
  1078. MtrNode * treenode,
  1079. int low,
  1080. int high)
  1081. {
  1082. int i;
  1083. MtrNode *auxnode;
  1084. int saveindex;
  1085. int newindex;
  1086. /* Merge all variables from low to high in one group, unless
  1087. ** this is the topmost group. In such a case we do not merge lest
  1088. ** we lose the symmetry information. */
  1089. if (treenode != table->treeZ) {
  1090. for (i = low; i < high; i++)
  1091. table->subtableZ[i].next = i+1;
  1092. table->subtableZ[high].next = low;
  1093. }
  1094. /* Adjust the index fields of the tree nodes. If a node is the
  1095. ** first child of its parent, then the parent may also need adjustment. */
  1096. saveindex = treenode->index;
  1097. newindex = table->invpermZ[low];
  1098. auxnode = treenode;
  1099. do {
  1100. auxnode->index = newindex;
  1101. if (auxnode->parent == NULL ||
  1102. (int) auxnode->parent->index != saveindex)
  1103. break;
  1104. auxnode = auxnode->parent;
  1105. } while (1);
  1106. return;
  1107. } /* end of zddMergeGroups */