The source code and dockerfile for the GSW2024 AI Lab.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

1302 lines
35 KiB

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