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.

1134 lines
31 KiB

  1. /**
  2. @file
  3. @ingroup cudd
  4. @brief Sanity check tests for some CUDD functions.
  5. @details testcudd reads a matrix with real coefficients and
  6. transforms it into an %ADD. It then performs various operations on
  7. the %ADD and on the %BDD corresponding to the ADD pattern. Finally,
  8. testcudd tests functions relate to Walsh matrices and matrix
  9. multiplication.
  10. @author Fabio Somenzi
  11. @copyright@parblock
  12. Copyright (c) 1995-2015, Regents of the University of Colorado
  13. All rights reserved.
  14. Redistribution and use in source and binary forms, with or without
  15. modification, are permitted provided that the following conditions
  16. are met:
  17. Redistributions of source code must retain the above copyright
  18. notice, this list of conditions and the following disclaimer.
  19. Redistributions in binary form must reproduce the above copyright
  20. notice, this list of conditions and the following disclaimer in the
  21. documentation and/or other materials provided with the distribution.
  22. Neither the name of the University of Colorado nor the names of its
  23. contributors may be used to endorse or promote products derived from
  24. this software without specific prior written permission.
  25. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  26. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  27. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  28. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  29. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  30. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  31. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  32. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  33. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  35. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. POSSIBILITY OF SUCH DAMAGE.
  37. @endparblock
  38. */
  39. #include "util.h"
  40. #include "cuddInt.h"
  41. /*---------------------------------------------------------------------------*/
  42. /* Constant declarations */
  43. /*---------------------------------------------------------------------------*/
  44. #define TESTCUDD_VERSION "TestCudd Version #1.0, Release date 3/17/01"
  45. /*---------------------------------------------------------------------------*/
  46. /* Variable declarations */
  47. /*---------------------------------------------------------------------------*/
  48. static const char *onames[] = { "C", "M" }; /* names of functions to be dumped */
  49. /** \cond */
  50. /*---------------------------------------------------------------------------*/
  51. /* Static function prototypes */
  52. /*---------------------------------------------------------------------------*/
  53. static void usage (char * prog);
  54. static FILE *open_file (char *filename, const char *mode);
  55. static int testIterators (DdManager *dd, DdNode *M, DdNode *C, int pr);
  56. static int testXor (DdManager *dd, DdNode *f, int pr, int nvars);
  57. static int testHamming (DdManager *dd, DdNode *f, int pr);
  58. static int testWalsh (DdManager *dd, int N, int cmu, int approach, int pr);
  59. static int testSupport(DdManager *dd, DdNode *f, DdNode *g, int pr);
  60. /** \endcond */
  61. /**
  62. @brief Main function for testcudd.
  63. @sideeffect None
  64. */
  65. int
  66. main(int argc, char * const *argv)
  67. {
  68. FILE *fp; /* pointer to input file */
  69. char *file = (char *) ""; /* input file name */
  70. FILE *dfp = NULL; /* pointer to dump file */
  71. FILE *savefp = NULL;/* pointer to save current manager's stdout setting */
  72. char *dfile; /* file for DD dump */
  73. DdNode *dfunc[2]; /* addresses of the functions to be dumped */
  74. DdManager *dd; /* pointer to DD manager */
  75. DdNode *one; /* fast access to constant function */
  76. DdNode *M;
  77. DdNode **x; /* pointers to variables */
  78. DdNode **y; /* pointers to variables */
  79. DdNode **xn; /* complements of row variables */
  80. DdNode **yn_; /* complements of column variables */
  81. DdNode **xvars;
  82. DdNode **yvars;
  83. DdNode *C; /* result of converting from ADD to BDD */
  84. DdNode *ess; /* cube of essential variables */
  85. DdNode *shortP; /* BDD cube of shortest path */
  86. DdNode *largest; /* BDD of largest cube */
  87. DdNode *shortA; /* ADD cube of shortest path */
  88. DdNode *constN; /* value returned by evaluation of ADD */
  89. DdNode *ycube; /* cube of the negated y vars for c-proj */
  90. DdNode *CP; /* C-Projection of C */
  91. DdNode *CPr; /* C-Selection of C */
  92. int length; /* length of the shortest path */
  93. int nx; /* number of variables */
  94. int ny;
  95. int maxnx;
  96. int maxny;
  97. int m;
  98. int n;
  99. int N;
  100. int cmu; /* use CMU multiplication */
  101. int pr; /* verbose printout level */
  102. int harwell;
  103. int multiple; /* read multiple matrices */
  104. int ok;
  105. int approach; /* reordering approach */
  106. int autodyn; /* automatic reordering */
  107. int groupcheck; /* option for group sifting */
  108. int profile; /* print heap and cache profile if != 0 */
  109. int keepperm; /* keep track of permutation */
  110. int clearcache; /* clear the cache after each matrix */
  111. int blifOrDot; /* dump format: 0 -> dot, 1 -> blif, ... */
  112. int retval; /* return value */
  113. int i; /* loop index */
  114. unsigned long startTime; /* initial time */
  115. unsigned long lapTime = 0;
  116. int size;
  117. unsigned int cacheSize, maxMemory;
  118. unsigned int nvars,nslots;
  119. int optidx;
  120. startTime = util_cpu_time();
  121. approach = CUDD_REORDER_NONE;
  122. autodyn = 0;
  123. pr = 0;
  124. harwell = 0;
  125. multiple = 0;
  126. profile = 0;
  127. keepperm = 0;
  128. cmu = 0;
  129. N = 4;
  130. nvars = 4;
  131. cacheSize = 2048;
  132. maxMemory = 0;
  133. nslots = CUDD_UNIQUE_SLOTS;
  134. clearcache = 0;
  135. groupcheck = CUDD_GROUP_CHECK7;
  136. dfile = NULL;
  137. blifOrDot = 0; /* dot format */
  138. /* Parse command line. */
  139. for (optidx = 1; optidx < argc; optidx++) {
  140. if (argv[optidx][0] == '-') {
  141. switch(argv[optidx][1]) {
  142. case 'C':
  143. cmu = 1;
  144. break;
  145. case 'D':
  146. autodyn = 1;
  147. break;
  148. case 'H':
  149. harwell = 1;
  150. break;
  151. case 'M':
  152. /* NOOP: retained for backward compatibility. */
  153. break;
  154. case 'P':
  155. profile = 1;
  156. break;
  157. case 'S':
  158. if (++optidx == argc) usage(argv[0]);
  159. nslots = atoi(argv[optidx]);
  160. break;
  161. case 'X':
  162. if (++optidx == argc) usage(argv[0]);
  163. maxMemory = atoi(argv[optidx]);
  164. break;
  165. case 'a':
  166. if (++optidx == argc) usage(argv[0]);
  167. approach = atoi(argv[optidx]);
  168. break;
  169. case 'b':
  170. blifOrDot = 1; /* blif format */
  171. break;
  172. case 'c':
  173. clearcache = 1;
  174. break;
  175. case 'd':
  176. if (++optidx == argc) usage(argv[0]);
  177. dfile = argv[optidx];
  178. break;
  179. case 'g':
  180. if (++optidx == argc) usage(argv[0]);
  181. groupcheck = atoi(argv[optidx]);
  182. break;
  183. case 'k':
  184. keepperm = 1;
  185. break;
  186. case 'm':
  187. multiple = 1;
  188. break;
  189. case 'n':
  190. if (++optidx == argc) usage(argv[0]);
  191. N = atoi(argv[optidx]);
  192. break;
  193. case 'p':
  194. if (++optidx == argc) usage(argv[0]);
  195. pr = atoi(argv[optidx]);
  196. break;
  197. case 'v':
  198. if (++optidx == argc) usage(argv[0]);
  199. nvars = atoi(argv[optidx]);
  200. break;
  201. case 'x':
  202. if (++optidx == argc) usage(argv[0]);
  203. cacheSize = atoi(argv[optidx]);
  204. break;
  205. case 'h':
  206. default:
  207. usage(argv[0]);
  208. break;
  209. }
  210. } else if (argc - optidx == 1) {
  211. file = argv[optidx];
  212. } else {
  213. usage(argv[0]);
  214. }
  215. }
  216. if ((approach<0) || (approach>17)) {
  217. (void) fprintf(stderr,"Invalid approach: %d \n",approach);
  218. usage(argv[0]);
  219. }
  220. if (pr > 0) {
  221. (void) printf("# %s\n", TESTCUDD_VERSION);
  222. /* Echo command line and arguments. */
  223. (void) printf("#");
  224. for (i = 0; i < argc; i++) {
  225. (void) printf(" %s", argv[i]);
  226. }
  227. (void) printf("\n");
  228. (void) fflush(stdout);
  229. }
  230. /* Initialize manager and provide easy reference to terminals. */
  231. dd = Cudd_Init(nvars,0,nslots,cacheSize,maxMemory);
  232. one = DD_ONE(dd);
  233. dd->groupcheck = (Cudd_AggregationType) groupcheck;
  234. if (autodyn) Cudd_AutodynEnable(dd,CUDD_REORDER_SAME);
  235. /* Open input file. */
  236. fp = open_file(file, "r");
  237. /* Open dump file if requested */
  238. if (dfile != NULL) {
  239. dfp = open_file(dfile, "w");
  240. }
  241. x = y = xn = yn_ = NULL;
  242. do {
  243. /* We want to start anew for every matrix. */
  244. maxnx = maxny = 0;
  245. nx = maxnx; ny = maxny;
  246. if (pr>0) lapTime = util_cpu_time();
  247. if (harwell) {
  248. if (pr > 0) (void) printf(":name: ");
  249. ok = Cudd_addHarwell(fp, dd, &M, &x, &y, &xn, &yn_, &nx, &ny,
  250. &m, &n, 0, 2, 1, 2, pr);
  251. } else {
  252. ok = Cudd_addRead(fp, dd, &M, &x, &y, &xn, &yn_, &nx, &ny,
  253. &m, &n, 0, 2, 1, 2);
  254. if (pr > 0)
  255. (void) printf(":name: %s: %d rows %d columns\n", file, m, n);
  256. }
  257. if (!ok) {
  258. (void) fprintf(stderr, "Error reading matrix\n");
  259. return(1);
  260. }
  261. if (nx > maxnx) maxnx = nx;
  262. if (ny > maxny) maxny = ny;
  263. /* Build cube of negated y's. */
  264. ycube = DD_ONE(dd);
  265. Cudd_Ref(ycube);
  266. for (i = maxny - 1; i >= 0; i--) {
  267. DdNode *tmpp;
  268. tmpp = Cudd_bddAnd(dd,Cudd_Not(dd->vars[y[i]->index]),ycube);
  269. if (tmpp == NULL) return(2);
  270. Cudd_Ref(tmpp);
  271. Cudd_RecursiveDeref(dd,ycube);
  272. ycube = tmpp;
  273. }
  274. /* Initialize vectors of BDD variables used by priority func. */
  275. xvars = ALLOC(DdNode *, nx);
  276. if (xvars == NULL) return(2);
  277. for (i = 0; i < nx; i++) {
  278. xvars[i] = dd->vars[x[i]->index];
  279. }
  280. yvars = ALLOC(DdNode *, ny);
  281. if (yvars == NULL) return(2);
  282. for (i = 0; i < ny; i++) {
  283. yvars[i] = dd->vars[y[i]->index];
  284. }
  285. /* Clean up */
  286. for (i=0; i < maxnx; i++) {
  287. Cudd_RecursiveDeref(dd, x[i]);
  288. Cudd_RecursiveDeref(dd, xn[i]);
  289. }
  290. FREE(x);
  291. FREE(xn);
  292. for (i=0; i < maxny; i++) {
  293. Cudd_RecursiveDeref(dd, y[i]);
  294. Cudd_RecursiveDeref(dd, yn_[i]);
  295. }
  296. FREE(y);
  297. FREE(yn_);
  298. if (pr>0) {(void) printf(":1: M"); Cudd_PrintDebug(dd,M,nx+ny,pr);}
  299. if (pr>0) (void) printf(":2: time to read the matrix = %s\n",
  300. util_print_time(util_cpu_time() - lapTime));
  301. C = Cudd_addBddPattern(dd, M);
  302. if (C == 0) return(2);
  303. Cudd_Ref(C);
  304. if (pr>0) {(void) printf(":3: C"); Cudd_PrintDebug(dd,C,nx+ny,pr);}
  305. /* Test iterators. */
  306. retval = testIterators(dd,M,C,pr);
  307. if (retval == 0) return(2);
  308. if (profile != 0 && pr > 0)
  309. cuddCacheProfile(dd,stdout);
  310. /* Test XOR */
  311. retval = testXor(dd,C,pr,nx+ny);
  312. if (retval == 0) return(2);
  313. /* Test Hamming distance functions. */
  314. retval = testHamming(dd,C,pr);
  315. if (retval == 0) return(2);
  316. /* Test selection functions. */
  317. CP = Cudd_CProjection(dd,C,ycube);
  318. if (CP == NULL) return(2);
  319. Cudd_Ref(CP);
  320. if (pr>0) {(void) printf("ycube"); Cudd_PrintDebug(dd,ycube,nx+ny,pr);}
  321. if (pr>0) {(void) printf("CP"); Cudd_PrintDebug(dd,CP,nx+ny,pr);}
  322. if (nx == ny) {
  323. CPr = Cudd_PrioritySelect(dd,C,xvars,yvars,(DdNode **)NULL,
  324. (DdNode *)NULL,ny,Cudd_Xgty);
  325. if (CPr == NULL) return(2);
  326. Cudd_Ref(CPr);
  327. if (pr>0) {(void) printf(":4: CPr"); Cudd_PrintDebug(dd,CPr,nx+ny,pr);}
  328. if (CP != CPr) {
  329. (void) printf("CP != CPr!\n");
  330. }
  331. Cudd_RecursiveDeref(dd, CPr);
  332. }
  333. /* Test inequality generator. */
  334. {
  335. int Nmin = ddMin(nx,ny);
  336. int q;
  337. DdGen *gen;
  338. int *cube;
  339. DdNode *f = Cudd_Inequality(dd,Nmin,2,xvars,yvars);
  340. if (f == NULL) return(2);
  341. Cudd_Ref(f);
  342. if (pr>0) {
  343. (void) printf(":4: ineq");
  344. Cudd_PrintDebug(dd,f,nx+ny,pr);
  345. if (pr>1) {
  346. Cudd_ForeachPrime(dd,Cudd_Not(f),Cudd_Not(f),gen,cube) {
  347. for (q = 0; q < dd->size; q++) {
  348. switch (cube[q]) {
  349. case 0:
  350. (void) printf("1");
  351. break;
  352. case 1:
  353. (void) printf("0");
  354. break;
  355. case 2:
  356. (void) printf("-");
  357. break;
  358. default:
  359. (void) printf("?");
  360. }
  361. }
  362. (void) printf(" 1\n");
  363. }
  364. (void) printf("\n");
  365. }
  366. }
  367. Cudd_IterDerefBdd(dd, f);
  368. }
  369. FREE(xvars); FREE(yvars);
  370. Cudd_RecursiveDeref(dd, CP);
  371. /* Test functions for essential variables. */
  372. ess = Cudd_FindEssential(dd,C);
  373. if (ess == NULL) return(2);
  374. Cudd_Ref(ess);
  375. if (pr>0) {(void) printf(":4: ess"); Cudd_PrintDebug(dd,ess,nx+ny,pr);}
  376. Cudd_RecursiveDeref(dd, ess);
  377. /* Test functions for shortest paths. */
  378. shortP = Cudd_ShortestPath(dd, M, NULL, NULL, &length);
  379. if (shortP == NULL) return(2);
  380. Cudd_Ref(shortP);
  381. if (pr>0) {
  382. (void) printf(":5: shortP"); Cudd_PrintDebug(dd,shortP,nx+ny,pr);
  383. }
  384. /* Test functions for largest cubes. */
  385. largest = Cudd_LargestCube(dd, Cudd_Not(C), &length);
  386. if (largest == NULL) return(2);
  387. Cudd_Ref(largest);
  388. if (pr>0) {
  389. (void) printf(":5b: largest");
  390. Cudd_PrintDebug(dd,largest,nx+ny,pr);
  391. }
  392. Cudd_RecursiveDeref(dd, largest);
  393. /* Test Cudd_addEvalConst and Cudd_addIteConstant. */
  394. shortA = Cudd_BddToAdd(dd,shortP);
  395. if (shortA == NULL) return(2);
  396. Cudd_Ref(shortA);
  397. Cudd_RecursiveDeref(dd, shortP);
  398. constN = Cudd_addEvalConst(dd,shortA,M);
  399. if (constN == DD_NON_CONSTANT) return(2);
  400. if (Cudd_addIteConstant(dd,shortA,M,constN) != constN) return(2);
  401. if (pr>0) {(void) printf("The value of M along the chosen shortest path is %g\n", cuddV(constN));}
  402. Cudd_RecursiveDeref(dd, shortA);
  403. shortP = Cudd_ShortestPath(dd, C, NULL, NULL, &length);
  404. if (shortP == NULL) return(2);
  405. Cudd_Ref(shortP);
  406. if (pr>0) {
  407. (void) printf(":6: shortP"); Cudd_PrintDebug(dd,shortP,nx+ny,pr);
  408. }
  409. /* Test Cudd_bddIteConstant and Cudd_bddLeq. */
  410. if (!Cudd_bddLeq(dd,shortP,C)) return(2);
  411. if (Cudd_bddIteConstant(dd,Cudd_Not(shortP),one,C) != one) return(2);
  412. Cudd_RecursiveDeref(dd, shortP);
  413. /* Experiment with support functions. */
  414. if (!testSupport(dd,M,ycube,pr)) {
  415. return(2);
  416. }
  417. Cudd_RecursiveDeref(dd, ycube);
  418. if (profile) {
  419. retval = cuddHeapProfile(dd);
  420. if (retval == 0) {
  421. (void) fprintf(stderr,"Error reported by cuddHeapProfile\n");
  422. return(2);
  423. }
  424. }
  425. size = dd->size;
  426. if (pr>0) {
  427. (void) printf("Average distance: %g\n", Cudd_AverageDistance(dd));
  428. }
  429. /* Reorder if so requested. */
  430. if (approach != CUDD_REORDER_NONE) {
  431. #ifndef DD_STATS
  432. retval = Cudd_EnableReorderingReporting(dd);
  433. if (retval == 0) {
  434. (void) fprintf(stderr,"Error reported by Cudd_EnableReorderingReporting\n");
  435. return(3);
  436. }
  437. #endif
  438. #ifdef DD_DEBUG
  439. retval = Cudd_DebugCheck(dd);
  440. if (retval != 0) {
  441. (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
  442. return(3);
  443. }
  444. retval = Cudd_CheckKeys(dd);
  445. if (retval != 0) {
  446. (void) fprintf(stderr,"Error reported by Cudd_CheckKeys\n");
  447. return(3);
  448. }
  449. #endif
  450. retval = Cudd_ReduceHeap(dd,(Cudd_ReorderingType)approach,5);
  451. if (retval == 0) {
  452. (void) fprintf(stderr,"Error reported by Cudd_ReduceHeap\n");
  453. return(3);
  454. }
  455. #ifndef DD_STATS
  456. retval = Cudd_DisableReorderingReporting(dd);
  457. if (retval == 0) {
  458. (void) fprintf(stderr,"Error reported by Cudd_DisableReorderingReporting\n");
  459. return(3);
  460. }
  461. #endif
  462. #ifdef DD_DEBUG
  463. retval = Cudd_DebugCheck(dd);
  464. if (retval != 0) {
  465. (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
  466. return(3);
  467. }
  468. retval = Cudd_CheckKeys(dd);
  469. if (retval != 0) {
  470. (void) fprintf(stderr,"Error reported by Cudd_CheckKeys\n");
  471. return(3);
  472. }
  473. #endif
  474. if (approach == CUDD_REORDER_SYMM_SIFT ||
  475. approach == CUDD_REORDER_SYMM_SIFT_CONV) {
  476. Cudd_SymmProfile(dd,0,dd->size-1);
  477. }
  478. if (pr>0) {
  479. (void) printf("Average distance: %g\n", Cudd_AverageDistance(dd));
  480. }
  481. if (keepperm) {
  482. /* Print variable permutation. */
  483. (void) printf("Variable Permutation:");
  484. for (i=0; i<size; i++) {
  485. if (i%20 == 0) (void) printf("\n");
  486. (void) printf("%d ", dd->invperm[i]);
  487. }
  488. (void) printf("\n");
  489. (void) printf("Inverse Permutation:");
  490. for (i=0; i<size; i++) {
  491. if (i%20 == 0) (void) printf("\n");
  492. (void) printf("%d ", dd->perm[i]);
  493. }
  494. (void) printf("\n");
  495. }
  496. if (pr>0) {(void) printf("M"); Cudd_PrintDebug(dd,M,nx+ny,pr);}
  497. if (profile) {
  498. retval = cuddHeapProfile(dd);
  499. if (retval == 0) {
  500. (void) fprintf(stderr,"Error reported by cuddHeapProfile\n");
  501. return(2);
  502. }
  503. }
  504. }
  505. /* Dump DDs of C and M if so requested. */
  506. if (dfile != NULL) {
  507. dfunc[0] = C;
  508. dfunc[1] = M;
  509. if (blifOrDot == 1) {
  510. /* Only dump C because blif cannot handle ADDs */
  511. retval = Cudd_DumpBlif(dd,1,dfunc,NULL,
  512. (char const * const *)onames,NULL,dfp,0);
  513. } else {
  514. retval = Cudd_DumpDot(dd,2,dfunc,NULL,
  515. (char const * const *)onames,dfp);
  516. }
  517. if (retval != 1) {
  518. (void) fprintf(stderr,"abnormal termination\n");
  519. return(2);
  520. }
  521. }
  522. Cudd_RecursiveDeref(dd, C);
  523. Cudd_RecursiveDeref(dd, M);
  524. if (clearcache) {
  525. if (pr>0) {(void) printf("Clearing the cache... ");}
  526. for (i = dd->cacheSlots - 1; i>=0; i--) {
  527. dd->cache[i].data = NULL;
  528. }
  529. if (pr>0) {(void) printf("done\n");}
  530. }
  531. if (pr>0) {
  532. (void) printf("Number of variables = %6d\t",dd->size);
  533. (void) printf("Number of slots = %6u\n",dd->slots);
  534. (void) printf("Number of keys = %6u\t",dd->keys);
  535. (void) printf("Number of min dead = %6u\n",dd->minDead);
  536. }
  537. } while (multiple && !feof(fp));
  538. fclose(fp);
  539. if (dfile != NULL) {
  540. fclose(dfp);
  541. }
  542. /* Second phase: experiment with Walsh matrices. */
  543. if (!testWalsh(dd,N,cmu,approach,pr)) {
  544. return(2);
  545. }
  546. /* Check variable destruction. */
  547. assert(cuddDestroySubtables(dd,3));
  548. if (pr == 0) {
  549. savefp = Cudd_ReadStdout(dd);
  550. Cudd_SetStdout(dd,fopen("/dev/null","a"));
  551. }
  552. assert(Cudd_DebugCheck(dd) == 0);
  553. assert(Cudd_CheckKeys(dd) == 0);
  554. if (pr == 0) {
  555. fclose(Cudd_ReadStdout(dd));
  556. Cudd_SetStdout(dd,savefp);
  557. }
  558. retval = Cudd_CheckZeroRef(dd);
  559. ok = retval != 0; /* ok == 0 means O.K. */
  560. if (retval != 0) {
  561. (void) fprintf(stderr,
  562. "%d non-zero DD reference counts after dereferencing\n", retval);
  563. }
  564. if (pr > 0) {
  565. (void) Cudd_PrintInfo(dd,stdout);
  566. }
  567. Cudd_Quit(dd);
  568. if (pr>0) (void) printf("total time = %s\n",
  569. util_print_time(util_cpu_time() - startTime));
  570. if (pr > 0) util_print_cpu_stats(stdout);
  571. return ok;
  572. } /* end of main */
  573. /*---------------------------------------------------------------------------*/
  574. /* Definition of static functions */
  575. /*---------------------------------------------------------------------------*/
  576. /**
  577. @brief Prints usage info for testcudd.
  578. @sideeffect None
  579. */
  580. static void
  581. usage(char *prog)
  582. {
  583. (void) fprintf(stderr, "usage: %s [options] [file]\n", prog);
  584. (void) fprintf(stderr, " -C\t\tuse CMU multiplication algorithm\n");
  585. (void) fprintf(stderr, " -D\t\tenable automatic dynamic reordering\n");
  586. (void) fprintf(stderr, " -H\t\tread matrix in Harwell format\n");
  587. (void) fprintf(stderr, " -P\t\tprint BDD heap and cache profile\n");
  588. (void) fprintf(stderr, " -S n\t\tnumber of slots for each subtable\n");
  589. (void) fprintf(stderr, " -X n\t\ttarget maximum memory in bytes\n");
  590. (void) fprintf(stderr, " -a n\t\tchoose reordering approach (0-13)\n");
  591. (void) fprintf(stderr, " \t\t\t0: same as autoMethod\n");
  592. (void) fprintf(stderr, " \t\t\t1: no reordering (default)\n");
  593. (void) fprintf(stderr, " \t\t\t2: random\n");
  594. (void) fprintf(stderr, " \t\t\t3: pivot\n");
  595. (void) fprintf(stderr, " \t\t\t4: sifting\n");
  596. (void) fprintf(stderr, " \t\t\t5: sifting to convergence\n");
  597. (void) fprintf(stderr, " \t\t\t6: symmetric sifting\n");
  598. (void) fprintf(stderr, " \t\t\t7: symmetric sifting to convergence\n");
  599. (void) fprintf(stderr, " \t\t\t8-10: window of size 2-4\n");
  600. (void) fprintf(stderr, " \t\t\t11-13: window of size 2-4 to conv.\n");
  601. (void) fprintf(stderr, " \t\t\t14: group sifting\n");
  602. (void) fprintf(stderr, " \t\t\t15: group sifting to convergence\n");
  603. (void) fprintf(stderr, " \t\t\t16: simulated annealing\n");
  604. (void) fprintf(stderr, " \t\t\t17: genetic algorithm\n");
  605. (void) fprintf(stderr, " -b\t\tuse blif as format for dumps\n");
  606. (void) fprintf(stderr, " -c\t\tclear the cache after each matrix\n");
  607. (void) fprintf(stderr, " -d file\tdump DDs to file\n");
  608. (void) fprintf(stderr, " -g\t\tselect aggregation criterion (0,5,7)\n");
  609. (void) fprintf(stderr, " -h\t\tprints this message\n");
  610. (void) fprintf(stderr, " -k\t\tprint the variable permutation\n");
  611. (void) fprintf(stderr, " -m\t\tread multiple matrices (only with -H)\n");
  612. (void) fprintf(stderr, " -n n\t\tnumber of variables\n");
  613. (void) fprintf(stderr, " -p n\t\tcontrol verbosity\n");
  614. (void) fprintf(stderr, " -v n\t\tinitial variables in the unique table\n");
  615. (void) fprintf(stderr, " -x n\t\tinitial size of the cache\n");
  616. exit(2);
  617. } /* end of usage */
  618. /**
  619. @brief Opens a file.
  620. @details Opens a file, or fails with an error message and exits.
  621. Allows '-' as a synonym for standard input.
  622. @sideeffect None
  623. */
  624. static FILE *
  625. open_file(char *filename, const char *mode)
  626. {
  627. FILE *fp;
  628. if (strcmp(filename, "-") == 0) {
  629. return mode[0] == 'r' ? stdin : stdout;
  630. } else if ((fp = fopen(filename, mode)) == NULL) {
  631. perror(filename);
  632. exit(1);
  633. }
  634. return fp;
  635. } /* end of open_file */
  636. /**
  637. @brief Tests Walsh matrix multiplication.
  638. @return 1 if successful; 0 otherwise.
  639. @sideeffect May create new variables in the manager.
  640. */
  641. static int
  642. testWalsh(
  643. DdManager *dd /* manager */,
  644. int N /* number of variables */,
  645. int cmu /* use CMU approach to matrix multiplication */,
  646. int approach /* reordering approach */,
  647. int pr /* verbosity level */)
  648. {
  649. DdNode *walsh1, *walsh2, *wtw;
  650. DdNode **x, **v, **z;
  651. int i, retval;
  652. DdNode *one = DD_ONE(dd);
  653. DdNode *zero = DD_ZERO(dd);
  654. if (N > 3) {
  655. x = ALLOC(DdNode *,N);
  656. v = ALLOC(DdNode *,N);
  657. z = ALLOC(DdNode *,N);
  658. for (i = N-1; i >= 0; i--) {
  659. Cudd_Ref(x[i]=cuddUniqueInter(dd,3*i,one,zero));
  660. Cudd_Ref(v[i]=cuddUniqueInter(dd,3*i+1,one,zero));
  661. Cudd_Ref(z[i]=cuddUniqueInter(dd,3*i+2,one,zero));
  662. }
  663. Cudd_Ref(walsh1 = Cudd_addWalsh(dd,v,z,N));
  664. if (pr>0) {(void) printf("walsh1"); Cudd_PrintDebug(dd,walsh1,2*N,pr);}
  665. Cudd_Ref(walsh2 = Cudd_addWalsh(dd,x,v,N));
  666. if (cmu) {
  667. Cudd_Ref(wtw = Cudd_addTimesPlus(dd,walsh2,walsh1,v,N));
  668. } else {
  669. Cudd_Ref(wtw = Cudd_addMatrixMultiply(dd,walsh2,walsh1,v,N));
  670. }
  671. if (pr>0) {(void) printf("wtw"); Cudd_PrintDebug(dd,wtw,2*N,pr);}
  672. if (approach != CUDD_REORDER_NONE) {
  673. #ifdef DD_DEBUG
  674. retval = Cudd_DebugCheck(dd);
  675. if (retval != 0) {
  676. (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
  677. return(0);
  678. }
  679. #endif
  680. retval = Cudd_ReduceHeap(dd,(Cudd_ReorderingType)approach,5);
  681. if (retval == 0) {
  682. (void) fprintf(stderr,"Error reported by Cudd_ReduceHeap\n");
  683. return(0);
  684. }
  685. #ifdef DD_DEBUG
  686. retval = Cudd_DebugCheck(dd);
  687. if (retval != 0) {
  688. (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
  689. return(0);
  690. }
  691. #endif
  692. if (approach == CUDD_REORDER_SYMM_SIFT ||
  693. approach == CUDD_REORDER_SYMM_SIFT_CONV) {
  694. Cudd_SymmProfile(dd,0,dd->size-1);
  695. }
  696. }
  697. /* Clean up. */
  698. Cudd_RecursiveDeref(dd, wtw);
  699. Cudd_RecursiveDeref(dd, walsh1);
  700. Cudd_RecursiveDeref(dd, walsh2);
  701. for (i=0; i < N; i++) {
  702. Cudd_RecursiveDeref(dd, x[i]);
  703. Cudd_RecursiveDeref(dd, v[i]);
  704. Cudd_RecursiveDeref(dd, z[i]);
  705. }
  706. FREE(x);
  707. FREE(v);
  708. FREE(z);
  709. }
  710. return(1);
  711. } /* end of testWalsh */
  712. /**
  713. @brief Tests iterators on cubes and nodes.
  714. @sideeffect None
  715. */
  716. static int
  717. testIterators(
  718. DdManager *dd,
  719. DdNode *M,
  720. DdNode *C,
  721. int pr)
  722. {
  723. int *cube;
  724. CUDD_VALUE_TYPE value;
  725. DdGen *gen;
  726. int q;
  727. /* Test iterator for cubes. */
  728. if (pr>1) {
  729. (void) printf("Testing iterator on cubes:\n");
  730. Cudd_ForeachCube(dd,M,gen,cube,value) {
  731. for (q = 0; q < dd->size; q++) {
  732. switch (cube[q]) {
  733. case 0:
  734. (void) printf("0");
  735. break;
  736. case 1:
  737. (void) printf("1");
  738. break;
  739. case 2:
  740. (void) printf("-");
  741. break;
  742. default:
  743. (void) printf("?");
  744. }
  745. }
  746. (void) printf(" %g\n",value);
  747. }
  748. (void) printf("\n");
  749. }
  750. if (pr>1) {
  751. (void) printf("Testing prime expansion of cubes:\n");
  752. if (!Cudd_bddPrintCover(dd,C,C)) return(0);
  753. }
  754. if (pr>1) {
  755. (void) printf("Testing iterator on primes (CNF):\n");
  756. Cudd_ForeachPrime(dd,Cudd_Not(C),Cudd_Not(C),gen,cube) {
  757. for (q = 0; q < dd->size; q++) {
  758. switch (cube[q]) {
  759. case 0:
  760. (void) printf("1");
  761. break;
  762. case 1:
  763. (void) printf("0");
  764. break;
  765. case 2:
  766. (void) printf("-");
  767. break;
  768. default:
  769. (void) printf("?");
  770. }
  771. }
  772. (void) printf(" 1\n");
  773. }
  774. (void) printf("\n");
  775. }
  776. /* Test iterator on nodes. */
  777. if (pr>2) {
  778. DdNode *node;
  779. (void) printf("Testing iterator on nodes:\n");
  780. Cudd_ForeachNode(dd,M,gen,node) {
  781. if (Cudd_IsConstant(node)) {
  782. (void) printf("ID = 0x%"PRIxPTR"\tvalue = %-9g\n",
  783. (ptruint) node / (ptruint) sizeof(DdNode),
  784. Cudd_V(node));
  785. } else {
  786. (void) printf("ID = 0x%"PRIxPTR"\tindex = %u\tr = %u\n",
  787. (ptruint) node / (ptruint) sizeof(DdNode),
  788. node->index, node->ref);
  789. }
  790. }
  791. (void) printf("\n");
  792. }
  793. return(1);
  794. } /* end of testIterators */
  795. /**
  796. @brief Tests the functions related to the exclusive OR.
  797. @details Builds the boolean difference of the given function in
  798. three different ways and checks that the results is the same.
  799. @return 1 if successful; 0 otherwise.
  800. @sideeffect None
  801. */
  802. static int
  803. testXor(DdManager *dd, DdNode *f, int pr, int nvars)
  804. {
  805. DdNode *f1, *f0, *res1, *res2;
  806. int x;
  807. /* Extract cofactors w.r.t. mid variable. */
  808. x = nvars / 2;
  809. f1 = Cudd_Cofactor(dd,f,dd->vars[x]);
  810. if (f1 == NULL) return(0);
  811. Cudd_Ref(f1);
  812. f0 = Cudd_Cofactor(dd,f,Cudd_Not(dd->vars[x]));
  813. if (f0 == NULL) {
  814. Cudd_RecursiveDeref(dd,f1);
  815. return(0);
  816. }
  817. Cudd_Ref(f0);
  818. /* Compute XOR of cofactors with ITE. */
  819. res1 = Cudd_bddIte(dd,f1,Cudd_Not(f0),f0);
  820. if (res1 == NULL) return(0);
  821. Cudd_Ref(res1);
  822. if (pr>0) {(void) printf("xor1"); Cudd_PrintDebug(dd,res1,nvars,pr);}
  823. /* Compute XOR of cofactors with XOR. */
  824. res2 = Cudd_bddXor(dd,f1,f0);
  825. if (res2 == NULL) {
  826. Cudd_RecursiveDeref(dd,res1);
  827. return(0);
  828. }
  829. Cudd_Ref(res2);
  830. if (res1 != res2) {
  831. if (pr>0) {(void) printf("xor2"); Cudd_PrintDebug(dd,res2,nvars,pr);}
  832. Cudd_RecursiveDeref(dd,res1);
  833. Cudd_RecursiveDeref(dd,res2);
  834. return(0);
  835. }
  836. Cudd_RecursiveDeref(dd,res1);
  837. Cudd_RecursiveDeref(dd,f1);
  838. Cudd_RecursiveDeref(dd,f0);
  839. /* Compute boolean difference directly. */
  840. res1 = Cudd_bddBooleanDiff(dd,f,x);
  841. if (res1 == NULL) {
  842. Cudd_RecursiveDeref(dd,res2);
  843. return(0);
  844. }
  845. Cudd_Ref(res1);
  846. if (res1 != res2) {
  847. if (pr>0) {(void) printf("xor3"); Cudd_PrintDebug(dd,res1,nvars,pr);}
  848. Cudd_RecursiveDeref(dd,res1);
  849. Cudd_RecursiveDeref(dd,res2);
  850. return(0);
  851. }
  852. Cudd_RecursiveDeref(dd,res1);
  853. Cudd_RecursiveDeref(dd,res2);
  854. return(1);
  855. } /* end of testXor */
  856. /**
  857. @brief Tests the Hamming distance functions.
  858. @return 1 if successful; 0 otherwise.
  859. @sideeffect None
  860. */
  861. static int
  862. testHamming(
  863. DdManager *dd,
  864. DdNode *f,
  865. int pr)
  866. {
  867. DdNode **vars, *minBdd, *zero, *scan;
  868. int i;
  869. int d;
  870. int *minterm;
  871. int size = Cudd_ReadSize(dd);
  872. vars = ALLOC(DdNode *, size);
  873. if (vars == NULL) return(0);
  874. for (i = 0; i < size; i++) {
  875. vars[i] = Cudd_bddIthVar(dd,i);
  876. }
  877. minBdd = Cudd_bddPickOneMinterm(dd,Cudd_Not(f),vars,size);
  878. Cudd_Ref(minBdd);
  879. if (pr > 0) {
  880. (void) printf("Chosen minterm for Hamming distance test: ");
  881. Cudd_PrintDebug(dd,minBdd,size,pr);
  882. }
  883. minterm = ALLOC(int,size);
  884. if (minterm == NULL) {
  885. FREE(vars);
  886. Cudd_RecursiveDeref(dd,minBdd);
  887. return(0);
  888. }
  889. scan = minBdd;
  890. zero = Cudd_Not(DD_ONE(dd));
  891. while (!Cudd_IsConstant(scan)) {
  892. DdNode *R = Cudd_Regular(scan);
  893. DdNode *T = Cudd_T(R);
  894. DdNode *E = Cudd_E(R);
  895. if (R != scan) {
  896. T = Cudd_Not(T);
  897. E = Cudd_Not(E);
  898. }
  899. if (T == zero) {
  900. minterm[R->index] = 0;
  901. scan = E;
  902. } else {
  903. minterm[R->index] = 1;
  904. scan = T;
  905. }
  906. }
  907. Cudd_RecursiveDeref(dd,minBdd);
  908. d = Cudd_MinHammingDist(dd,f,minterm,size);
  909. if (pr > 0)
  910. (void) printf("Minimum Hamming distance = %d\n", d);
  911. FREE(vars);
  912. FREE(minterm);
  913. return(1);
  914. } /* end of testHamming */
  915. /**
  916. @brief Tests the support functions.
  917. @return 1 if successful; 0 otherwise.
  918. @sideeffect None
  919. */
  920. static int
  921. testSupport(
  922. DdManager *dd,
  923. DdNode *f,
  924. DdNode *g,
  925. int pr)
  926. {
  927. DdNode *sb, *common, *onlyF, *onlyG;
  928. DdNode *F[2];
  929. int *support;
  930. int ret, ssize;
  931. int size = Cudd_ReadSize(dd);
  932. sb = Cudd_Support(dd, f);
  933. if (sb == NULL) return(0);
  934. Cudd_Ref(sb);
  935. if (pr > 0) {
  936. (void) printf("Support of f: ");
  937. Cudd_PrintDebug(dd,sb,size,pr);
  938. }
  939. Cudd_RecursiveDeref(dd, sb);
  940. ssize = Cudd_SupportIndices(dd, f, &support);
  941. if (ssize == CUDD_OUT_OF_MEM) return(0);
  942. if (pr > 0) {
  943. (void) printf("Size of the support of f: %d\n", ssize);
  944. }
  945. FREE(support);
  946. ssize = Cudd_SupportSize(dd, f);
  947. if (pr > 0) {
  948. (void) printf("Size of the support of f: %d\n", ssize);
  949. }
  950. F[0] = f;
  951. F[1] = g;
  952. sb = Cudd_VectorSupport(dd, F, 2);
  953. if (sb == NULL) return(0);
  954. Cudd_Ref(sb);
  955. if (pr > 0) {
  956. (void) printf("Support of f and g: ");
  957. Cudd_PrintDebug(dd,sb,size,pr);
  958. }
  959. Cudd_RecursiveDeref(dd, sb);
  960. ssize = Cudd_VectorSupportIndices(dd, F, 2, &support);
  961. if (ssize == CUDD_OUT_OF_MEM) return(0);
  962. if (pr > 0) {
  963. (void) printf("Size of the support of f and g: %d\n", ssize);
  964. }
  965. FREE(support);
  966. ssize = Cudd_VectorSupportSize(dd, F, 2);
  967. if (pr > 0) {
  968. (void) printf("Size of the support of f and g: %d\n", ssize);
  969. }
  970. ret = Cudd_ClassifySupport(dd, f, g, &common, &onlyF, &onlyG);
  971. if (ret == 0) return(0);
  972. Cudd_Ref(common); Cudd_Ref(onlyF); Cudd_Ref(onlyG);
  973. if (pr > 0) {
  974. (void) printf("Support common to f and g: ");
  975. Cudd_PrintDebug(dd,common,size,pr);
  976. (void) printf("Support private to f: ");
  977. Cudd_PrintDebug(dd,onlyF,size,pr);
  978. (void) printf("Support private to g: ");
  979. Cudd_PrintDebug(dd,onlyG,size,pr);
  980. }
  981. Cudd_RecursiveDeref(dd, common);
  982. Cudd_RecursiveDeref(dd, onlyF);
  983. Cudd_RecursiveDeref(dd, onlyG);
  984. return(1);
  985. } /* end of testSupport */