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.

1664 lines
44 KiB

  1. /**CFile***********************************************************************
  2. FileName [cuddZddReord.c]
  3. PackageName [cudd]
  4. Synopsis [Procedures for dynamic variable ordering of ZDDs.]
  5. Description [External procedures included in this module:
  6. <ul>
  7. <li> Cudd_zddReduceHeap()
  8. <li> Cudd_zddShuffleHeap()
  9. </ul>
  10. Internal procedures included in this module:
  11. <ul>
  12. <li> cuddZddAlignToBdd()
  13. <li> cuddZddNextHigh()
  14. <li> cuddZddNextLow()
  15. <li> cuddZddUniqueCompare()
  16. <li> cuddZddSwapInPlace()
  17. <li> cuddZddSwapping()
  18. <li> cuddZddSifting()
  19. </ul>
  20. Static procedures included in this module:
  21. <ul>
  22. <li> zddSwapAny()
  23. <li> cuddZddSiftingAux()
  24. <li> cuddZddSiftingUp()
  25. <li> cuddZddSiftingDown()
  26. <li> cuddZddSiftingBackward()
  27. <li> zddReorderPreprocess()
  28. <li> zddReorderPostprocess()
  29. <li> zddShuffle()
  30. <li> zddSiftUp()
  31. </ul>
  32. ]
  33. SeeAlso []
  34. Author [Hyong-Kyoon Shin, In-Ho Moon]
  35. Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
  36. All rights reserved.
  37. Redistribution and use in source and binary forms, with or without
  38. modification, are permitted provided that the following conditions
  39. are met:
  40. Redistributions of source code must retain the above copyright
  41. notice, this list of conditions and the following disclaimer.
  42. Redistributions in binary form must reproduce the above copyright
  43. notice, this list of conditions and the following disclaimer in the
  44. documentation and/or other materials provided with the distribution.
  45. Neither the name of the University of Colorado nor the names of its
  46. contributors may be used to endorse or promote products derived from
  47. this software without specific prior written permission.
  48. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  49. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  50. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  51. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  52. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  53. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  54. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  55. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  56. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  57. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  58. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  59. POSSIBILITY OF SUCH DAMAGE.]
  60. ******************************************************************************/
  61. #include "util.h"
  62. #include "cuddInt.h"
  63. /*---------------------------------------------------------------------------*/
  64. /* Constant declarations */
  65. /*---------------------------------------------------------------------------*/
  66. #define DD_MAX_SUBTABLE_SPARSITY 8
  67. #define DD_SHRINK_FACTOR 2
  68. /*---------------------------------------------------------------------------*/
  69. /* Stucture declarations */
  70. /*---------------------------------------------------------------------------*/
  71. /*---------------------------------------------------------------------------*/
  72. /* Type declarations */
  73. /*---------------------------------------------------------------------------*/
  74. /*---------------------------------------------------------------------------*/
  75. /* Variable declarations */
  76. /*---------------------------------------------------------------------------*/
  77. #ifndef lint
  78. static char rcsid[] DD_UNUSED = "$Id: cuddZddReord.c,v 1.49 2012/02/05 01:07:19 fabio Exp $";
  79. #endif
  80. int *zdd_entry;
  81. int zddTotalNumberSwapping;
  82. static DdNode *empty;
  83. /*---------------------------------------------------------------------------*/
  84. /* Macro declarations */
  85. /*---------------------------------------------------------------------------*/
  86. /**AutomaticStart*************************************************************/
  87. /*---------------------------------------------------------------------------*/
  88. /* Static function prototypes */
  89. /*---------------------------------------------------------------------------*/
  90. static Move * zddSwapAny (DdManager *table, int x, int y);
  91. static int cuddZddSiftingAux (DdManager *table, int x, int x_low, int x_high);
  92. static Move * cuddZddSiftingUp (DdManager *table, int x, int x_low, int initial_size);
  93. static Move * cuddZddSiftingDown (DdManager *table, int x, int x_high, int initial_size);
  94. static int cuddZddSiftingBackward (DdManager *table, Move *moves, int size);
  95. static void zddReorderPreprocess (DdManager *table);
  96. static int zddReorderPostprocess (DdManager *table);
  97. static int zddShuffle (DdManager *table, int *permutation);
  98. static int zddSiftUp (DdManager *table, int x, int xLow);
  99. static void zddFixTree (DdManager *table, MtrNode *treenode);
  100. /**AutomaticEnd***************************************************************/
  101. /*---------------------------------------------------------------------------*/
  102. /* Definition of exported functions */
  103. /*---------------------------------------------------------------------------*/
  104. /**Function********************************************************************
  105. Synopsis [Main dynamic reordering routine for ZDDs.]
  106. Description [Main dynamic reordering routine for ZDDs.
  107. Calls one of the possible reordering procedures:
  108. <ul>
  109. <li>Swapping
  110. <li>Sifting
  111. <li>Symmetric Sifting
  112. </ul>
  113. For sifting and symmetric sifting it is possible to request reordering
  114. to convergence.<p>
  115. The core of all methods is the reordering procedure
  116. cuddZddSwapInPlace() which swaps two adjacent variables.
  117. Returns 1 in case of success; 0 otherwise. In the case of symmetric
  118. sifting (with and without convergence) returns 1 plus the number of
  119. symmetric variables, in case of success.]
  120. SideEffects [Changes the variable order for all ZDDs and clears
  121. the cache.]
  122. ******************************************************************************/
  123. int
  124. Cudd_zddReduceHeap(
  125. DdManager * table /* DD manager */,
  126. Cudd_ReorderingType heuristic /* method used for reordering */,
  127. int minsize /* bound below which no reordering occurs */)
  128. {
  129. DdHook *hook;
  130. int result;
  131. unsigned int nextDyn;
  132. #ifdef DD_STATS
  133. unsigned int initialSize;
  134. unsigned int finalSize;
  135. #endif
  136. unsigned long localTime;
  137. /* Don't reorder if there are too many dead nodes. */
  138. if (table->keysZ - table->deadZ < (unsigned) minsize)
  139. return(1);
  140. if (heuristic == CUDD_REORDER_SAME) {
  141. heuristic = table->autoMethodZ;
  142. }
  143. if (heuristic == CUDD_REORDER_NONE) {
  144. return(1);
  145. }
  146. /* This call to Cudd_zddReduceHeap does initiate reordering. Therefore
  147. ** we count it.
  148. */
  149. table->reorderings++;
  150. empty = table->zero;
  151. localTime = util_cpu_time();
  152. /* Run the hook functions. */
  153. hook = table->preReorderingHook;
  154. while (hook != NULL) {
  155. int res = (hook->f)(table, "ZDD", (void *)heuristic);
  156. if (res == 0) return(0);
  157. hook = hook->next;
  158. }
  159. /* Clear the cache and collect garbage. */
  160. zddReorderPreprocess(table);
  161. zddTotalNumberSwapping = 0;
  162. #ifdef DD_STATS
  163. initialSize = table->keysZ;
  164. switch(heuristic) {
  165. case CUDD_REORDER_RANDOM:
  166. case CUDD_REORDER_RANDOM_PIVOT:
  167. (void) fprintf(table->out,"#:I_RANDOM ");
  168. break;
  169. case CUDD_REORDER_SIFT:
  170. case CUDD_REORDER_SIFT_CONVERGE:
  171. case CUDD_REORDER_SYMM_SIFT:
  172. case CUDD_REORDER_SYMM_SIFT_CONV:
  173. (void) fprintf(table->out,"#:I_SIFTING ");
  174. break;
  175. case CUDD_REORDER_LINEAR:
  176. case CUDD_REORDER_LINEAR_CONVERGE:
  177. (void) fprintf(table->out,"#:I_LINSIFT ");
  178. break;
  179. default:
  180. (void) fprintf(table->err,"Unsupported ZDD reordering method\n");
  181. return(0);
  182. }
  183. (void) fprintf(table->out,"%8d: initial size",initialSize);
  184. #endif
  185. result = cuddZddTreeSifting(table,heuristic);
  186. #ifdef DD_STATS
  187. (void) fprintf(table->out,"\n");
  188. finalSize = table->keysZ;
  189. (void) fprintf(table->out,"#:F_REORDER %8d: final size\n",finalSize);
  190. (void) fprintf(table->out,"#:T_REORDER %8g: total time (sec)\n",
  191. ((double)(util_cpu_time() - localTime)/1000.0));
  192. (void) fprintf(table->out,"#:N_REORDER %8d: total swaps\n",
  193. zddTotalNumberSwapping);
  194. #endif
  195. if (result == 0)
  196. return(0);
  197. if (!zddReorderPostprocess(table))
  198. return(0);
  199. if (table->realignZ) {
  200. if (!cuddBddAlignToZdd(table))
  201. return(0);
  202. }
  203. nextDyn = table->keysZ * DD_DYN_RATIO;
  204. if (table->reorderings < 20 || nextDyn > table->nextDyn)
  205. table->nextDyn = nextDyn;
  206. else
  207. table->nextDyn += 20;
  208. table->reordered = 1;
  209. /* Run hook functions. */
  210. hook = table->postReorderingHook;
  211. while (hook != NULL) {
  212. int res = (hook->f)(table, "ZDD", (void *)localTime);
  213. if (res == 0) return(0);
  214. hook = hook->next;
  215. }
  216. /* Update cumulative reordering time. */
  217. table->reordTime += util_cpu_time() - localTime;
  218. return(result);
  219. } /* end of Cudd_zddReduceHeap */
  220. /**Function********************************************************************
  221. Synopsis [Reorders ZDD variables according to given permutation.]
  222. Description [Reorders ZDD variables according to given permutation.
  223. The i-th entry of the permutation array contains the index of the variable
  224. that should be brought to the i-th level. The size of the array should be
  225. equal or greater to the number of variables currently in use.
  226. Returns 1 in case of success; 0 otherwise.]
  227. SideEffects [Changes the ZDD variable order for all diagrams and clears
  228. the cache.]
  229. SeeAlso [Cudd_zddReduceHeap]
  230. ******************************************************************************/
  231. int
  232. Cudd_zddShuffleHeap(
  233. DdManager * table /* DD manager */,
  234. int * permutation /* required variable permutation */)
  235. {
  236. int result;
  237. empty = table->zero;
  238. zddReorderPreprocess(table);
  239. result = zddShuffle(table,permutation);
  240. if (!zddReorderPostprocess(table)) return(0);
  241. return(result);
  242. } /* end of Cudd_zddShuffleHeap */
  243. /*---------------------------------------------------------------------------*/
  244. /* Definition of internal functions */
  245. /*---------------------------------------------------------------------------*/
  246. /**Function********************************************************************
  247. Synopsis [Reorders ZDD variables according to the order of the BDD
  248. variables.]
  249. Description [Reorders ZDD variables according to the order of the
  250. BDD variables. This function can be called at the end of BDD
  251. reordering to insure that the order of the ZDD variables is
  252. consistent with the order of the BDD variables. The number of ZDD
  253. variables must be a multiple of the number of BDD variables. Let
  254. <code>M</code> be the ratio of the two numbers. cuddZddAlignToBdd
  255. then considers the ZDD variables from <code>M*i</code> to
  256. <code>(M+1)*i-1</code> as corresponding to BDD variable
  257. <code>i</code>. This function should be normally called from
  258. Cudd_ReduceHeap, which clears the cache. Returns 1 in case of
  259. success; 0 otherwise.]
  260. SideEffects [Changes the ZDD variable order for all diagrams and performs
  261. garbage collection of the ZDD unique table.]
  262. SeeAlso [Cudd_zddShuffleHeap Cudd_ReduceHeap]
  263. ******************************************************************************/
  264. int
  265. cuddZddAlignToBdd(
  266. DdManager * table /* DD manager */)
  267. {
  268. int *invpermZ; /* permutation array */
  269. int M; /* ratio of ZDD variables to BDD variables */
  270. int i,j; /* loop indices */
  271. int result; /* return value */
  272. /* We assume that a ratio of 0 is OK. */
  273. if (table->sizeZ == 0)
  274. return(1);
  275. empty = table->zero;
  276. M = table->sizeZ / table->size;
  277. /* Check whether the number of ZDD variables is a multiple of the
  278. ** number of BDD variables.
  279. */
  280. if (M * table->size != table->sizeZ)
  281. return(0);
  282. /* Create and initialize the inverse permutation array. */
  283. invpermZ = ALLOC(int,table->sizeZ);
  284. if (invpermZ == NULL) {
  285. table->errorCode = CUDD_MEMORY_OUT;
  286. return(0);
  287. }
  288. for (i = 0; i < table->size; i++) {
  289. int index = table->invperm[i];
  290. int indexZ = index * M;
  291. int levelZ = table->permZ[indexZ];
  292. levelZ = (levelZ / M) * M;
  293. for (j = 0; j < M; j++) {
  294. invpermZ[M * i + j] = table->invpermZ[levelZ + j];
  295. }
  296. }
  297. /* Eliminate dead nodes. Do not scan the cache again, because we
  298. ** assume that Cudd_ReduceHeap has already cleared it.
  299. */
  300. cuddGarbageCollect(table,0);
  301. result = zddShuffle(table, invpermZ);
  302. FREE(invpermZ);
  303. /* Fix the ZDD variable group tree. */
  304. zddFixTree(table,table->treeZ);
  305. return(result);
  306. } /* end of cuddZddAlignToBdd */
  307. /**Function********************************************************************
  308. Synopsis [Finds the next subtable with a larger index.]
  309. Description [Finds the next subtable with a larger index. Returns the
  310. index.]
  311. SideEffects [None]
  312. SeeAlso []
  313. ******************************************************************************/
  314. int
  315. cuddZddNextHigh(
  316. DdManager * table,
  317. int x)
  318. {
  319. return(x + 1);
  320. } /* end of cuddZddNextHigh */
  321. /**Function********************************************************************
  322. Synopsis [Finds the next subtable with a smaller index.]
  323. Description [Finds the next subtable with a smaller index. Returns the
  324. index.]
  325. SideEffects [None]
  326. SeeAlso []
  327. ******************************************************************************/
  328. int
  329. cuddZddNextLow(
  330. DdManager * table,
  331. int x)
  332. {
  333. return(x - 1);
  334. } /* end of cuddZddNextLow */
  335. /**Function********************************************************************
  336. Synopsis [Comparison function used by qsort.]
  337. Description [Comparison function used by qsort to order the
  338. variables according to the number of keys in the subtables.
  339. Returns the difference in number of keys between the two
  340. variables being compared.]
  341. SideEffects [None]
  342. SeeAlso []
  343. ******************************************************************************/
  344. int
  345. cuddZddUniqueCompare(
  346. int * ptr_x,
  347. int * ptr_y)
  348. {
  349. return(zdd_entry[*ptr_y] - zdd_entry[*ptr_x]);
  350. } /* end of cuddZddUniqueCompare */
  351. /**Function********************************************************************
  352. Synopsis [Swaps two adjacent variables.]
  353. Description [Swaps two adjacent variables. It assumes that no dead
  354. nodes are present on entry to this procedure. The procedure then
  355. guarantees that no dead nodes will be present when it terminates.
  356. cuddZddSwapInPlace assumes that x &lt; y. Returns the number of keys in
  357. the table if successful; 0 otherwise.]
  358. SideEffects [None]
  359. SeeAlso []
  360. ******************************************************************************/
  361. int
  362. cuddZddSwapInPlace(
  363. DdManager * table,
  364. int x,
  365. int y)
  366. {
  367. DdNodePtr *xlist, *ylist;
  368. int xindex, yindex;
  369. int xslots, yslots;
  370. int xshift, yshift;
  371. int oldxkeys, oldykeys;
  372. int newxkeys, newykeys;
  373. int i;
  374. int posn;
  375. DdNode *f, *f1, *f0, *f11, *f10, *f01, *f00;
  376. DdNode *newf1, *newf0, *next;
  377. DdNodePtr g, *lastP, *previousP;
  378. #ifdef DD_DEBUG
  379. assert(x < y);
  380. assert(cuddZddNextHigh(table,x) == y);
  381. assert(table->subtableZ[x].keys != 0);
  382. assert(table->subtableZ[y].keys != 0);
  383. assert(table->subtableZ[x].dead == 0);
  384. assert(table->subtableZ[y].dead == 0);
  385. #endif
  386. zddTotalNumberSwapping++;
  387. /* Get parameters of x subtable. */
  388. xindex = table->invpermZ[x];
  389. xlist = table->subtableZ[x].nodelist;
  390. oldxkeys = table->subtableZ[x].keys;
  391. xslots = table->subtableZ[x].slots;
  392. xshift = table->subtableZ[x].shift;
  393. newxkeys = 0;
  394. yindex = table->invpermZ[y];
  395. ylist = table->subtableZ[y].nodelist;
  396. oldykeys = table->subtableZ[y].keys;
  397. yslots = table->subtableZ[y].slots;
  398. yshift = table->subtableZ[y].shift;
  399. newykeys = oldykeys;
  400. /* The nodes in the x layer that don't depend on y directly
  401. ** will stay there; the others are put in a chain.
  402. ** The chain is handled as a FIFO; g points to the beginning and
  403. ** last points to the end.
  404. */
  405. g = NULL;
  406. lastP = &g;
  407. for (i = 0; i < xslots; i++) {
  408. previousP = &(xlist[i]);
  409. f = *previousP;
  410. while (f != NULL) {
  411. next = f->next;
  412. f1 = cuddT(f); f0 = cuddE(f);
  413. if ((f1->index != (DdHalfWord) yindex) &&
  414. (f0->index != (DdHalfWord) yindex)) { /* stays */
  415. newxkeys++;
  416. *previousP = f;
  417. previousP = &(f->next);
  418. } else {
  419. f->index = yindex;
  420. *lastP = f;
  421. lastP = &(f->next);
  422. }
  423. f = next;
  424. } /* while there are elements in the collision chain */
  425. *previousP = NULL;
  426. } /* for each slot of the x subtable */
  427. *lastP = NULL;
  428. #ifdef DD_COUNT
  429. table->swapSteps += oldxkeys - newxkeys;
  430. #endif
  431. /* Take care of the x nodes that must be re-expressed.
  432. ** They form a linked list pointed by g. Their index has been
  433. ** changed to yindex already.
  434. */
  435. f = g;
  436. while (f != NULL) {
  437. next = f->next;
  438. /* Find f1, f0, f11, f10, f01, f00. */
  439. f1 = cuddT(f);
  440. if ((int) f1->index == yindex) {
  441. f11 = cuddT(f1); f10 = cuddE(f1);
  442. } else {
  443. f11 = empty; f10 = f1;
  444. }
  445. f0 = cuddE(f);
  446. if ((int) f0->index == yindex) {
  447. f01 = cuddT(f0); f00 = cuddE(f0);
  448. } else {
  449. f01 = empty; f00 = f0;
  450. }
  451. /* Decrease ref count of f1. */
  452. cuddSatDec(f1->ref);
  453. /* Create the new T child. */
  454. if (f11 == empty) {
  455. if (f01 != empty) {
  456. newf1 = f01;
  457. cuddSatInc(newf1->ref);
  458. }
  459. /* else case was already handled when finding nodes
  460. ** with both children below level y
  461. */
  462. } else {
  463. /* Check xlist for triple (xindex, f11, f01). */
  464. posn = ddHash(f11, f01, xshift);
  465. /* For each element newf1 in collision list xlist[posn]. */
  466. newf1 = xlist[posn];
  467. while (newf1 != NULL) {
  468. if (cuddT(newf1) == f11 && cuddE(newf1) == f01) {
  469. cuddSatInc(newf1->ref);
  470. break; /* match */
  471. }
  472. newf1 = newf1->next;
  473. } /* while newf1 */
  474. if (newf1 == NULL) { /* no match */
  475. newf1 = cuddDynamicAllocNode(table);
  476. if (newf1 == NULL)
  477. goto zddSwapOutOfMem;
  478. newf1->index = xindex; newf1->ref = 1;
  479. cuddT(newf1) = f11;
  480. cuddE(newf1) = f01;
  481. /* Insert newf1 in the collision list xlist[pos];
  482. ** increase the ref counts of f11 and f01
  483. */
  484. newxkeys++;
  485. newf1->next = xlist[posn];
  486. xlist[posn] = newf1;
  487. cuddSatInc(f11->ref);
  488. cuddSatInc(f01->ref);
  489. }
  490. }
  491. cuddT(f) = newf1;
  492. /* Do the same for f0. */
  493. /* Decrease ref count of f0. */
  494. cuddSatDec(f0->ref);
  495. /* Create the new E child. */
  496. if (f10 == empty) {
  497. newf0 = f00;
  498. cuddSatInc(newf0->ref);
  499. } else {
  500. /* Check xlist for triple (xindex, f10, f00). */
  501. posn = ddHash(f10, f00, xshift);
  502. /* For each element newf0 in collision list xlist[posn]. */
  503. newf0 = xlist[posn];
  504. while (newf0 != NULL) {
  505. if (cuddT(newf0) == f10 && cuddE(newf0) == f00) {
  506. cuddSatInc(newf0->ref);
  507. break; /* match */
  508. }
  509. newf0 = newf0->next;
  510. } /* while newf0 */
  511. if (newf0 == NULL) { /* no match */
  512. newf0 = cuddDynamicAllocNode(table);
  513. if (newf0 == NULL)
  514. goto zddSwapOutOfMem;
  515. newf0->index = xindex; newf0->ref = 1;
  516. cuddT(newf0) = f10; cuddE(newf0) = f00;
  517. /* Insert newf0 in the collision list xlist[posn];
  518. ** increase the ref counts of f10 and f00.
  519. */
  520. newxkeys++;
  521. newf0->next = xlist[posn];
  522. xlist[posn] = newf0;
  523. cuddSatInc(f10->ref);
  524. cuddSatInc(f00->ref);
  525. }
  526. }
  527. cuddE(f) = newf0;
  528. /* Insert the modified f in ylist.
  529. ** The modified f does not already exists in ylist.
  530. ** (Because of the uniqueness of the cofactors.)
  531. */
  532. posn = ddHash(newf1, newf0, yshift);
  533. newykeys++;
  534. f->next = ylist[posn];
  535. ylist[posn] = f;
  536. f = next;
  537. } /* while f != NULL */
  538. /* GC the y layer. */
  539. /* For each node f in ylist. */
  540. for (i = 0; i < yslots; i++) {
  541. previousP = &(ylist[i]);
  542. f = *previousP;
  543. while (f != NULL) {
  544. next = f->next;
  545. if (f->ref == 0) {
  546. cuddSatDec(cuddT(f)->ref);
  547. cuddSatDec(cuddE(f)->ref);
  548. cuddDeallocNode(table, f);
  549. newykeys--;
  550. } else {
  551. *previousP = f;
  552. previousP = &(f->next);
  553. }
  554. f = next;
  555. } /* while f */
  556. *previousP = NULL;
  557. } /* for i */
  558. /* Set the appropriate fields in table. */
  559. table->subtableZ[x].nodelist = ylist;
  560. table->subtableZ[x].slots = yslots;
  561. table->subtableZ[x].shift = yshift;
  562. table->subtableZ[x].keys = newykeys;
  563. table->subtableZ[x].maxKeys = yslots * DD_MAX_SUBTABLE_DENSITY;
  564. table->subtableZ[y].nodelist = xlist;
  565. table->subtableZ[y].slots = xslots;
  566. table->subtableZ[y].shift = xshift;
  567. table->subtableZ[y].keys = newxkeys;
  568. table->subtableZ[y].maxKeys = xslots * DD_MAX_SUBTABLE_DENSITY;
  569. table->permZ[xindex] = y; table->permZ[yindex] = x;
  570. table->invpermZ[x] = yindex; table->invpermZ[y] = xindex;
  571. table->keysZ += newxkeys + newykeys - oldxkeys - oldykeys;
  572. /* Update univ section; univ[x] remains the same. */
  573. table->univ[y] = cuddT(table->univ[x]);
  574. return (table->keysZ);
  575. zddSwapOutOfMem:
  576. (void) fprintf(table->err, "Error: cuddZddSwapInPlace out of memory\n");
  577. return (0);
  578. } /* end of cuddZddSwapInPlace */
  579. /**Function********************************************************************
  580. Synopsis [Reorders variables by a sequence of (non-adjacent) swaps.]
  581. Description [Implementation of Plessier's algorithm that reorders
  582. variables by a sequence of (non-adjacent) swaps.
  583. <ol>
  584. <li> Select two variables (RANDOM or HEURISTIC).
  585. <li> Permute these variables.
  586. <li> If the nodes have decreased accept the permutation.
  587. <li> Otherwise reconstruct the original heap.
  588. <li> Loop.
  589. </ol>
  590. Returns 1 in case of success; 0 otherwise.]
  591. SideEffects [None]
  592. SeeAlso []
  593. ******************************************************************************/
  594. int
  595. cuddZddSwapping(
  596. DdManager * table,
  597. int lower,
  598. int upper,
  599. Cudd_ReorderingType heuristic)
  600. {
  601. int i, j;
  602. int max, keys;
  603. int nvars;
  604. int x, y;
  605. int iterate;
  606. int previousSize;
  607. Move *moves, *move;
  608. int pivot;
  609. int modulo;
  610. int result;
  611. #ifdef DD_DEBUG
  612. /* Sanity check */
  613. assert(lower >= 0 && upper < table->sizeZ && lower <= upper);
  614. #endif
  615. nvars = upper - lower + 1;
  616. iterate = nvars;
  617. for (i = 0; i < iterate; i++) {
  618. if (heuristic == CUDD_REORDER_RANDOM_PIVOT) {
  619. /* Find pivot <= id with maximum keys. */
  620. for (max = -1, j = lower; j <= upper; j++) {
  621. if ((keys = table->subtableZ[j].keys) > max) {
  622. max = keys;
  623. pivot = j;
  624. }
  625. }
  626. modulo = upper - pivot;
  627. if (modulo == 0) {
  628. y = pivot; /* y = nvars-1 */
  629. } else {
  630. /* y = random # from {pivot+1 .. nvars-1} */
  631. y = pivot + 1 + (int) (Cudd_Random() % modulo);
  632. }
  633. modulo = pivot - lower - 1;
  634. if (modulo < 1) { /* if pivot = 1 or 0 */
  635. x = lower;
  636. } else {
  637. do { /* x = random # from {0 .. pivot-2} */
  638. x = (int) Cudd_Random() % modulo;
  639. } while (x == y);
  640. /* Is this condition really needed, since x and y
  641. are in regions separated by pivot? */
  642. }
  643. } else {
  644. x = (int) (Cudd_Random() % nvars) + lower;
  645. do {
  646. y = (int) (Cudd_Random() % nvars) + lower;
  647. } while (x == y);
  648. }
  649. previousSize = table->keysZ;
  650. moves = zddSwapAny(table, x, y);
  651. if (moves == NULL)
  652. goto cuddZddSwappingOutOfMem;
  653. result = cuddZddSiftingBackward(table, moves, previousSize);
  654. if (!result)
  655. goto cuddZddSwappingOutOfMem;
  656. while (moves != NULL) {
  657. move = moves->next;
  658. cuddDeallocMove(table, moves);
  659. moves = move;
  660. }
  661. #ifdef DD_STATS
  662. if (table->keysZ < (unsigned) previousSize) {
  663. (void) fprintf(table->out,"-");
  664. } else if (table->keysZ > (unsigned) previousSize) {
  665. (void) fprintf(table->out,"+"); /* should never happen */
  666. } else {
  667. (void) fprintf(table->out,"=");
  668. }
  669. fflush(table->out);
  670. #endif
  671. }
  672. return(1);
  673. cuddZddSwappingOutOfMem:
  674. while (moves != NULL) {
  675. move = moves->next;
  676. cuddDeallocMove(table, moves);
  677. moves = move;
  678. }
  679. return(0);
  680. } /* end of cuddZddSwapping */
  681. /**Function********************************************************************
  682. Synopsis [Implementation of Rudell's sifting algorithm.]
  683. Description [Implementation of Rudell's sifting algorithm.
  684. Assumes that no dead nodes are present.
  685. <ol>
  686. <li> Order all the variables according to the number of entries
  687. in each unique table.
  688. <li> Sift the variable up and down, remembering each time the
  689. total size of the DD heap.
  690. <li> Select the best permutation.
  691. <li> Repeat 3 and 4 for all variables.
  692. </ol>
  693. Returns 1 if successful; 0 otherwise.]
  694. SideEffects [None]
  695. SeeAlso []
  696. ******************************************************************************/
  697. int
  698. cuddZddSifting(
  699. DdManager * table,
  700. int lower,
  701. int upper)
  702. {
  703. int i;
  704. int *var;
  705. int size;
  706. int x;
  707. int result;
  708. #ifdef DD_STATS
  709. int previousSize;
  710. #endif
  711. size = table->sizeZ;
  712. /* Find order in which to sift variables. */
  713. var = NULL;
  714. zdd_entry = ALLOC(int, size);
  715. if (zdd_entry == NULL) {
  716. table->errorCode = CUDD_MEMORY_OUT;
  717. goto cuddZddSiftingOutOfMem;
  718. }
  719. var = ALLOC(int, size);
  720. if (var == NULL) {
  721. table->errorCode = CUDD_MEMORY_OUT;
  722. goto cuddZddSiftingOutOfMem;
  723. }
  724. for (i = 0; i < size; i++) {
  725. x = table->permZ[i];
  726. zdd_entry[i] = table->subtableZ[x].keys;
  727. var[i] = i;
  728. }
  729. qsort((void *)var, size, sizeof(int), (DD_QSFP)cuddZddUniqueCompare);
  730. /* Now sift. */
  731. for (i = 0; i < ddMin(table->siftMaxVar, size); i++) {
  732. if (zddTotalNumberSwapping >= table->siftMaxSwap)
  733. break;
  734. if (util_cpu_time() - table->startTime > table->timeLimit) {
  735. table->autoDynZ = 0; /* prevent further reordering */
  736. break;
  737. }
  738. x = table->permZ[var[i]];
  739. if (x < lower || x > upper) continue;
  740. #ifdef DD_STATS
  741. previousSize = table->keysZ;
  742. #endif
  743. result = cuddZddSiftingAux(table, x, lower, upper);
  744. if (!result)
  745. goto cuddZddSiftingOutOfMem;
  746. #ifdef DD_STATS
  747. if (table->keysZ < (unsigned) previousSize) {
  748. (void) fprintf(table->out,"-");
  749. } else if (table->keysZ > (unsigned) previousSize) {
  750. (void) fprintf(table->out,"+"); /* should never happen */
  751. (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ , var[i]);
  752. } else {
  753. (void) fprintf(table->out,"=");
  754. }
  755. fflush(table->out);
  756. #endif
  757. }
  758. FREE(var);
  759. FREE(zdd_entry);
  760. return(1);
  761. cuddZddSiftingOutOfMem:
  762. if (zdd_entry != NULL) FREE(zdd_entry);
  763. if (var != NULL) FREE(var);
  764. return(0);
  765. } /* end of cuddZddSifting */
  766. /*---------------------------------------------------------------------------*/
  767. /* Definition of static functions */
  768. /*---------------------------------------------------------------------------*/
  769. /**Function********************************************************************
  770. Synopsis [Swaps any two variables.]
  771. Description [Swaps any two variables. Returns the set of moves.]
  772. SideEffects [None]
  773. SeeAlso []
  774. ******************************************************************************/
  775. static Move *
  776. zddSwapAny(
  777. DdManager * table,
  778. int x,
  779. int y)
  780. {
  781. Move *move, *moves;
  782. int tmp, size;
  783. int x_ref, y_ref;
  784. int x_next, y_next;
  785. int limit_size;
  786. if (x > y) { /* make x precede y */
  787. tmp = x; x = y; y = tmp;
  788. }
  789. x_ref = x; y_ref = y;
  790. x_next = cuddZddNextHigh(table, x);
  791. y_next = cuddZddNextLow(table, y);
  792. moves = NULL;
  793. limit_size = table->keysZ;
  794. for (;;) {
  795. if (x_next == y_next) { /* x < x_next = y_next < y */
  796. size = cuddZddSwapInPlace(table, x, x_next);
  797. if (size == 0)
  798. goto zddSwapAnyOutOfMem;
  799. move = (Move *) cuddDynamicAllocNode(table);
  800. if (move == NULL)
  801. goto zddSwapAnyOutOfMem;
  802. move->x = x;
  803. move->y = x_next;
  804. move->size = size;
  805. move->next = moves;
  806. moves = move;
  807. size = cuddZddSwapInPlace(table, y_next, y);
  808. if (size == 0)
  809. goto zddSwapAnyOutOfMem;
  810. move = (Move *)cuddDynamicAllocNode(table);
  811. if (move == NULL)
  812. goto zddSwapAnyOutOfMem;
  813. move->x = y_next;
  814. move->y = y;
  815. move->size = size;
  816. move->next = moves;
  817. moves = move;
  818. size = cuddZddSwapInPlace(table, x, x_next);
  819. if (size == 0)
  820. goto zddSwapAnyOutOfMem;
  821. move = (Move *)cuddDynamicAllocNode(table);
  822. if (move == NULL)
  823. goto zddSwapAnyOutOfMem;
  824. move->x = x;
  825. move->y = x_next;
  826. move->size = size;
  827. move->next = moves;
  828. moves = move;
  829. tmp = x; x = y; y = tmp;
  830. } else if (x == y_next) { /* x = y_next < y = x_next */
  831. size = cuddZddSwapInPlace(table, x, x_next);
  832. if (size == 0)
  833. goto zddSwapAnyOutOfMem;
  834. move = (Move *)cuddDynamicAllocNode(table);
  835. if (move == NULL)
  836. goto zddSwapAnyOutOfMem;
  837. move->x = x;
  838. move->y = x_next;
  839. move->size = size;
  840. move->next = moves;
  841. moves = move;
  842. tmp = x; x = y; y = tmp;
  843. } else {
  844. size = cuddZddSwapInPlace(table, x, x_next);
  845. if (size == 0)
  846. goto zddSwapAnyOutOfMem;
  847. move = (Move *)cuddDynamicAllocNode(table);
  848. if (move == NULL)
  849. goto zddSwapAnyOutOfMem;
  850. move->x = x;
  851. move->y = x_next;
  852. move->size = size;
  853. move->next = moves;
  854. moves = move;
  855. size = cuddZddSwapInPlace(table, y_next, y);
  856. if (size == 0)
  857. goto zddSwapAnyOutOfMem;
  858. move = (Move *)cuddDynamicAllocNode(table);
  859. if (move == NULL)
  860. goto zddSwapAnyOutOfMem;
  861. move->x = y_next;
  862. move->y = y;
  863. move->size = size;
  864. move->next = moves;
  865. moves = move;
  866. x = x_next; y = y_next;
  867. }
  868. x_next = cuddZddNextHigh(table, x);
  869. y_next = cuddZddNextLow(table, y);
  870. if (x_next > y_ref)
  871. break; /* if x == y_ref */
  872. if ((double) size > table->maxGrowth * (double) limit_size)
  873. break;
  874. if (size < limit_size)
  875. limit_size = size;
  876. }
  877. if (y_next >= x_ref) {
  878. size = cuddZddSwapInPlace(table, y_next, y);
  879. if (size == 0)
  880. goto zddSwapAnyOutOfMem;
  881. move = (Move *)cuddDynamicAllocNode(table);
  882. if (move == NULL)
  883. goto zddSwapAnyOutOfMem;
  884. move->x = y_next;
  885. move->y = y;
  886. move->size = size;
  887. move->next = moves;
  888. moves = move;
  889. }
  890. return(moves);
  891. zddSwapAnyOutOfMem:
  892. while (moves != NULL) {
  893. move = moves->next;
  894. cuddDeallocMove(table, moves);
  895. moves = move;
  896. }
  897. return(NULL);
  898. } /* end of zddSwapAny */
  899. /**Function********************************************************************
  900. Synopsis [Given xLow <= x <= xHigh moves x up and down between the
  901. boundaries.]
  902. Description [Given xLow <= x <= xHigh moves x up and down between the
  903. boundaries. Finds the best position and does the required changes.
  904. Returns 1 if successful; 0 otherwise.]
  905. SideEffects [None]
  906. SeeAlso []
  907. ******************************************************************************/
  908. static int
  909. cuddZddSiftingAux(
  910. DdManager * table,
  911. int x,
  912. int x_low,
  913. int x_high)
  914. {
  915. Move *move;
  916. Move *moveUp; /* list of up move */
  917. Move *moveDown; /* list of down move */
  918. int initial_size;
  919. int result;
  920. initial_size = table->keysZ;
  921. #ifdef DD_DEBUG
  922. assert(table->subtableZ[x].keys > 0);
  923. #endif
  924. moveDown = NULL;
  925. moveUp = NULL;
  926. if (x == x_low) {
  927. moveDown = cuddZddSiftingDown(table, x, x_high, initial_size);
  928. /* after that point x --> x_high */
  929. if (moveDown == NULL)
  930. goto cuddZddSiftingAuxOutOfMem;
  931. result = cuddZddSiftingBackward(table, moveDown,
  932. initial_size);
  933. /* move backward and stop at best position */
  934. if (!result)
  935. goto cuddZddSiftingAuxOutOfMem;
  936. }
  937. else if (x == x_high) {
  938. moveUp = cuddZddSiftingUp(table, x, x_low, initial_size);
  939. /* after that point x --> x_low */
  940. if (moveUp == NULL)
  941. goto cuddZddSiftingAuxOutOfMem;
  942. result = cuddZddSiftingBackward(table, moveUp, initial_size);
  943. /* move backward and stop at best position */
  944. if (!result)
  945. goto cuddZddSiftingAuxOutOfMem;
  946. }
  947. else if ((x - x_low) > (x_high - x)) {
  948. /* must go down first:shorter */
  949. moveDown = cuddZddSiftingDown(table, x, x_high, initial_size);
  950. /* after that point x --> x_high */
  951. if (moveDown == NULL)
  952. goto cuddZddSiftingAuxOutOfMem;
  953. moveUp = cuddZddSiftingUp(table, moveDown->y, x_low,
  954. initial_size);
  955. if (moveUp == NULL)
  956. goto cuddZddSiftingAuxOutOfMem;
  957. result = cuddZddSiftingBackward(table, moveUp, initial_size);
  958. /* move backward and stop at best position */
  959. if (!result)
  960. goto cuddZddSiftingAuxOutOfMem;
  961. }
  962. else {
  963. moveUp = cuddZddSiftingUp(table, x, x_low, initial_size);
  964. /* after that point x --> x_high */
  965. if (moveUp == NULL)
  966. goto cuddZddSiftingAuxOutOfMem;
  967. moveDown = cuddZddSiftingDown(table, moveUp->x, x_high,
  968. initial_size);
  969. /* then move up */
  970. if (moveDown == NULL)
  971. goto cuddZddSiftingAuxOutOfMem;
  972. result = cuddZddSiftingBackward(table, moveDown,
  973. initial_size);
  974. /* move backward and stop at best position */
  975. if (!result)
  976. goto cuddZddSiftingAuxOutOfMem;
  977. }
  978. while (moveDown != NULL) {
  979. move = moveDown->next;
  980. cuddDeallocMove(table, moveDown);
  981. moveDown = move;
  982. }
  983. while (moveUp != NULL) {
  984. move = moveUp->next;
  985. cuddDeallocMove(table, moveUp);
  986. moveUp = move;
  987. }
  988. return(1);
  989. cuddZddSiftingAuxOutOfMem:
  990. while (moveDown != NULL) {
  991. move = moveDown->next;
  992. cuddDeallocMove(table, moveDown);
  993. moveDown = move;
  994. }
  995. while (moveUp != NULL) {
  996. move = moveUp->next;
  997. cuddDeallocMove(table, moveUp);
  998. moveUp = move;
  999. }
  1000. return(0);
  1001. } /* end of cuddZddSiftingAux */
  1002. /**Function********************************************************************
  1003. Synopsis [Sifts a variable up.]
  1004. Description [Sifts a variable up. Moves y up until either it reaches
  1005. the bound (x_low) or the size of the ZDD heap increases too much.
  1006. Returns the set of moves in case of success; NULL if memory is full.]
  1007. SideEffects [None]
  1008. SeeAlso []
  1009. ******************************************************************************/
  1010. static Move *
  1011. cuddZddSiftingUp(
  1012. DdManager * table,
  1013. int x,
  1014. int x_low,
  1015. int initial_size)
  1016. {
  1017. Move *moves;
  1018. Move *move;
  1019. int y;
  1020. int size;
  1021. int limit_size = initial_size;
  1022. moves = NULL;
  1023. y = cuddZddNextLow(table, x);
  1024. while (y >= x_low) {
  1025. size = cuddZddSwapInPlace(table, y, x);
  1026. if (size == 0)
  1027. goto cuddZddSiftingUpOutOfMem;
  1028. move = (Move *)cuddDynamicAllocNode(table);
  1029. if (move == NULL)
  1030. goto cuddZddSiftingUpOutOfMem;
  1031. move->x = y;
  1032. move->y = x;
  1033. move->size = size;
  1034. move->next = moves;
  1035. moves = move;
  1036. if ((double)size > (double)limit_size * table->maxGrowth)
  1037. break;
  1038. if (size < limit_size)
  1039. limit_size = size;
  1040. x = y;
  1041. y = cuddZddNextLow(table, x);
  1042. }
  1043. return(moves);
  1044. cuddZddSiftingUpOutOfMem:
  1045. while (moves != NULL) {
  1046. move = moves->next;
  1047. cuddDeallocMove(table, moves);
  1048. moves = move;
  1049. }
  1050. return(NULL);
  1051. } /* end of cuddZddSiftingUp */
  1052. /**Function********************************************************************
  1053. Synopsis [Sifts a variable down.]
  1054. Description [Sifts a variable down. Moves x down until either it
  1055. reaches the bound (x_high) or the size of the ZDD heap increases too
  1056. much. Returns the set of moves in case of success; NULL if memory is
  1057. full.]
  1058. SideEffects [None]
  1059. SeeAlso []
  1060. ******************************************************************************/
  1061. static Move *
  1062. cuddZddSiftingDown(
  1063. DdManager * table,
  1064. int x,
  1065. int x_high,
  1066. int initial_size)
  1067. {
  1068. Move *moves;
  1069. Move *move;
  1070. int y;
  1071. int size;
  1072. int limit_size = initial_size;
  1073. moves = NULL;
  1074. y = cuddZddNextHigh(table, x);
  1075. while (y <= x_high) {
  1076. size = cuddZddSwapInPlace(table, x, y);
  1077. if (size == 0)
  1078. goto cuddZddSiftingDownOutOfMem;
  1079. move = (Move *)cuddDynamicAllocNode(table);
  1080. if (move == NULL)
  1081. goto cuddZddSiftingDownOutOfMem;
  1082. move->x = x;
  1083. move->y = y;
  1084. move->size = size;
  1085. move->next = moves;
  1086. moves = move;
  1087. if ((double)size > (double)limit_size * table->maxGrowth)
  1088. break;
  1089. if (size < limit_size)
  1090. limit_size = size;
  1091. x = y;
  1092. y = cuddZddNextHigh(table, x);
  1093. }
  1094. return(moves);
  1095. cuddZddSiftingDownOutOfMem:
  1096. while (moves != NULL) {
  1097. move = moves->next;
  1098. cuddDeallocMove(table, moves);
  1099. moves = move;
  1100. }
  1101. return(NULL);
  1102. } /* end of cuddZddSiftingDown */
  1103. /**Function********************************************************************
  1104. Synopsis [Given a set of moves, returns the ZDD heap to the position
  1105. giving the minimum size.]
  1106. Description [Given a set of moves, returns the ZDD heap to the
  1107. position giving the minimum size. In case of ties, returns to the
  1108. closest position giving the minimum size. Returns 1 in case of
  1109. success; 0 otherwise.]
  1110. SideEffects [None]
  1111. SeeAlso []
  1112. ******************************************************************************/
  1113. static int
  1114. cuddZddSiftingBackward(
  1115. DdManager * table,
  1116. Move * moves,
  1117. int size)
  1118. {
  1119. int i;
  1120. int i_best;
  1121. Move *move;
  1122. int res;
  1123. /* Find the minimum size among moves. */
  1124. i_best = -1;
  1125. for (move = moves, i = 0; move != NULL; move = move->next, i++) {
  1126. if (move->size < size) {
  1127. i_best = i;
  1128. size = move->size;
  1129. }
  1130. }
  1131. for (move = moves, i = 0; move != NULL; move = move->next, i++) {
  1132. if (i == i_best)
  1133. break;
  1134. res = cuddZddSwapInPlace(table, move->x, move->y);
  1135. if (!res)
  1136. return(0);
  1137. if (i_best == -1 && res == size)
  1138. break;
  1139. }
  1140. return(1);
  1141. } /* end of cuddZddSiftingBackward */
  1142. /**Function********************************************************************
  1143. Synopsis [Prepares the ZDD heap for dynamic reordering.]
  1144. Description [Prepares the ZDD heap for dynamic reordering. Does
  1145. garbage collection, to guarantee that there are no dead nodes;
  1146. and clears the cache, which is invalidated by dynamic reordering.]
  1147. SideEffects [None]
  1148. ******************************************************************************/
  1149. static void
  1150. zddReorderPreprocess(
  1151. DdManager * table)
  1152. {
  1153. /* Clear the cache. */
  1154. cuddCacheFlush(table);
  1155. /* Eliminate dead nodes. Do not scan the cache again. */
  1156. cuddGarbageCollect(table,0);
  1157. return;
  1158. } /* end of ddReorderPreprocess */
  1159. /**Function********************************************************************
  1160. Synopsis [Shrinks almost empty ZDD subtables at the end of reordering
  1161. to guarantee that they have a reasonable load factor.]
  1162. Description [Shrinks almost empty subtables at the end of reordering to
  1163. guarantee that they have a reasonable load factor. However, if there many
  1164. nodes are being reclaimed, then no resizing occurs. Returns 1 in case of
  1165. success; 0 otherwise.]
  1166. SideEffects [None]
  1167. ******************************************************************************/
  1168. static int
  1169. zddReorderPostprocess(
  1170. DdManager * table)
  1171. {
  1172. int i, j, posn;
  1173. DdNodePtr *nodelist, *oldnodelist;
  1174. DdNode *node, *next;
  1175. unsigned int slots, oldslots;
  1176. extern DD_OOMFP MMoutOfMemory;
  1177. DD_OOMFP saveHandler;
  1178. #ifdef DD_VERBOSE
  1179. (void) fflush(table->out);
  1180. #endif
  1181. /* If we have very many reclaimed nodes, we do not want to shrink
  1182. ** the subtables, because this will lead to more garbage
  1183. ** collections. More garbage collections mean shorter mean life for
  1184. ** nodes with zero reference count; hence lower probability of finding
  1185. ** a result in the cache.
  1186. */
  1187. if (table->reclaimed > table->allocated * 0.5) return(1);
  1188. /* Resize subtables. */
  1189. for (i = 0; i < table->sizeZ; i++) {
  1190. int shift;
  1191. oldslots = table->subtableZ[i].slots;
  1192. if (oldslots < table->subtableZ[i].keys * DD_MAX_SUBTABLE_SPARSITY ||
  1193. oldslots <= table->initSlots) continue;
  1194. oldnodelist = table->subtableZ[i].nodelist;
  1195. slots = oldslots >> 1;
  1196. saveHandler = MMoutOfMemory;
  1197. MMoutOfMemory = Cudd_OutOfMem;
  1198. nodelist = ALLOC(DdNodePtr, slots);
  1199. MMoutOfMemory = saveHandler;
  1200. if (nodelist == NULL) {
  1201. return(1);
  1202. }
  1203. table->subtableZ[i].nodelist = nodelist;
  1204. table->subtableZ[i].slots = slots;
  1205. table->subtableZ[i].shift++;
  1206. table->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
  1207. #ifdef DD_VERBOSE
  1208. (void) fprintf(table->err,
  1209. "shrunk layer %d (%d keys) from %d to %d slots\n",
  1210. i, table->subtableZ[i].keys, oldslots, slots);
  1211. #endif
  1212. for (j = 0; (unsigned) j < slots; j++) {
  1213. nodelist[j] = NULL;
  1214. }
  1215. shift = table->subtableZ[i].shift;
  1216. for (j = 0; (unsigned) j < oldslots; j++) {
  1217. node = oldnodelist[j];
  1218. while (node != NULL) {
  1219. next = node->next;
  1220. posn = ddHash(cuddT(node), cuddE(node), shift);
  1221. node->next = nodelist[posn];
  1222. nodelist[posn] = node;
  1223. node = next;
  1224. }
  1225. }
  1226. FREE(oldnodelist);
  1227. table->memused += (slots - oldslots) * sizeof(DdNode *);
  1228. table->slots += slots - oldslots;
  1229. table->minDead = (unsigned) (table->gcFrac * (double) table->slots);
  1230. table->cacheSlack = (int) ddMin(table->maxCacheHard,
  1231. DD_MAX_CACHE_TO_SLOTS_RATIO*table->slots) -
  1232. 2 * (int) table->cacheSlots;
  1233. }
  1234. /* We don't look at the constant subtable, because it is not
  1235. ** affected by reordering.
  1236. */
  1237. return(1);
  1238. } /* end of zddReorderPostprocess */
  1239. /**Function********************************************************************
  1240. Synopsis [Reorders ZDD variables according to a given permutation.]
  1241. Description [Reorders ZDD variables according to a given permutation.
  1242. The i-th permutation array contains the index of the variable that
  1243. should be brought to the i-th level. zddShuffle assumes that no
  1244. dead nodes are present. The reordering is achieved by a series of
  1245. upward sifts. Returns 1 if successful; 0 otherwise.]
  1246. SideEffects [None]
  1247. SeeAlso []
  1248. ******************************************************************************/
  1249. static int
  1250. zddShuffle(
  1251. DdManager * table,
  1252. int * permutation)
  1253. {
  1254. int index;
  1255. int level;
  1256. int position;
  1257. int numvars;
  1258. int result;
  1259. #ifdef DD_STATS
  1260. unsigned long localTime;
  1261. int initialSize;
  1262. int finalSize;
  1263. int previousSize;
  1264. #endif
  1265. zddTotalNumberSwapping = 0;
  1266. #ifdef DD_STATS
  1267. localTime = util_cpu_time();
  1268. initialSize = table->keysZ;
  1269. (void) fprintf(table->out,"#:I_SHUFFLE %8d: initial size\n",
  1270. initialSize);
  1271. #endif
  1272. numvars = table->sizeZ;
  1273. for (level = 0; level < numvars; level++) {
  1274. index = permutation[level];
  1275. position = table->permZ[index];
  1276. #ifdef DD_STATS
  1277. previousSize = table->keysZ;
  1278. #endif
  1279. result = zddSiftUp(table,position,level);
  1280. if (!result) return(0);
  1281. #ifdef DD_STATS
  1282. if (table->keysZ < (unsigned) previousSize) {
  1283. (void) fprintf(table->out,"-");
  1284. } else if (table->keysZ > (unsigned) previousSize) {
  1285. (void) fprintf(table->out,"+"); /* should never happen */
  1286. } else {
  1287. (void) fprintf(table->out,"=");
  1288. }
  1289. fflush(table->out);
  1290. #endif
  1291. }
  1292. #ifdef DD_STATS
  1293. (void) fprintf(table->out,"\n");
  1294. finalSize = table->keysZ;
  1295. (void) fprintf(table->out,"#:F_SHUFFLE %8d: final size\n",finalSize);
  1296. (void) fprintf(table->out,"#:T_SHUFFLE %8g: total time (sec)\n",
  1297. ((double)(util_cpu_time() - localTime)/1000.0));
  1298. (void) fprintf(table->out,"#:N_SHUFFLE %8d: total swaps\n",
  1299. zddTotalNumberSwapping);
  1300. #endif
  1301. return(1);
  1302. } /* end of zddShuffle */
  1303. /**Function********************************************************************
  1304. Synopsis [Moves one ZDD variable up.]
  1305. Description [Takes a ZDD variable from position x and sifts it up to
  1306. position xLow; xLow should be less than or equal to x.
  1307. Returns 1 if successful; 0 otherwise]
  1308. SideEffects [None]
  1309. SeeAlso []
  1310. ******************************************************************************/
  1311. static int
  1312. zddSiftUp(
  1313. DdManager * table,
  1314. int x,
  1315. int xLow)
  1316. {
  1317. int y;
  1318. int size;
  1319. y = cuddZddNextLow(table,x);
  1320. while (y >= xLow) {
  1321. size = cuddZddSwapInPlace(table,y,x);
  1322. if (size == 0) {
  1323. return(0);
  1324. }
  1325. x = y;
  1326. y = cuddZddNextLow(table,x);
  1327. }
  1328. return(1);
  1329. } /* end of zddSiftUp */
  1330. /**Function********************************************************************
  1331. Synopsis [Fixes the ZDD variable group tree after a shuffle.]
  1332. Description [Fixes the ZDD variable group tree after a
  1333. shuffle. Assumes that the order of the variables in a terminal node
  1334. has not been changed.]
  1335. SideEffects [Changes the ZDD variable group tree.]
  1336. SeeAlso []
  1337. ******************************************************************************/
  1338. static void
  1339. zddFixTree(
  1340. DdManager * table,
  1341. MtrNode * treenode)
  1342. {
  1343. if (treenode == NULL) return;
  1344. treenode->low = ((int) treenode->index < table->sizeZ) ?
  1345. table->permZ[treenode->index] : treenode->index;
  1346. if (treenode->child != NULL) {
  1347. zddFixTree(table, treenode->child);
  1348. }
  1349. if (treenode->younger != NULL)
  1350. zddFixTree(table, treenode->younger);
  1351. if (treenode->parent != NULL && treenode->low < treenode->parent->low) {
  1352. treenode->parent->low = treenode->low;
  1353. treenode->parent->index = treenode->index;
  1354. }
  1355. return;
  1356. } /* end of zddFixTree */