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.

832 lines
23 KiB

3 months ago
  1. /**
  2. @file
  3. @ingroup cplusplus
  4. @brief Test program for the C++ object-oriented encapsulation of CUDD.
  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 "cuddObj.hh"
  35. #include <math.h>
  36. #include <iostream>
  37. #include <sstream>
  38. #include <cassert>
  39. #include <stdexcept>
  40. using namespace std;
  41. /*---------------------------------------------------------------------------*/
  42. /* Variable declarations */
  43. /*---------------------------------------------------------------------------*/
  44. /*---------------------------------------------------------------------------*/
  45. /* Static function prototypes */
  46. /*---------------------------------------------------------------------------*/
  47. static void testBdd(Cudd& mgr, int verbosity);
  48. static void testAdd(Cudd& mgr, int verbosity);
  49. static void testAdd2(Cudd& mgr, int verbosity);
  50. static void testZdd(Cudd& mgr, int verbosity);
  51. static void testBdd2(Cudd& mgr, int verbosity);
  52. static void testBdd3(Cudd& mgr, int verbosity);
  53. static void testZdd2(Cudd& mgr, int verbosity);
  54. static void testBdd4(Cudd& mgr, int verbosity);
  55. static void testBdd5(Cudd& mgr, int verbosity);
  56. static void testInterpolation(Cudd& mgr, int verbosity);
  57. static void testErrorHandling(Cudd& mgr, int verbosity);
  58. /*---------------------------------------------------------------------------*/
  59. /* Definition of exported functions */
  60. /*---------------------------------------------------------------------------*/
  61. /**
  62. @brief Main program for testobj.
  63. */
  64. int
  65. main(int argc, char **argv)
  66. {
  67. int verbosity = 0;
  68. if (argc == 2) {
  69. int cnt;
  70. int retval = sscanf(argv[1], "%d %n", &verbosity, &cnt);
  71. if (retval != 1 || argv[1][cnt])
  72. return 1;
  73. } else if (argc != 1) {
  74. return 1;
  75. }
  76. Cudd mgr(0,2);
  77. if (verbosity > 2) mgr.makeVerbose(); // trace constructors and destructors
  78. testBdd(mgr,verbosity);
  79. testAdd(mgr,verbosity);
  80. testAdd2(mgr,verbosity);
  81. testZdd(mgr,verbosity);
  82. testBdd2(mgr,verbosity);
  83. testBdd3(mgr,verbosity);
  84. testZdd2(mgr,verbosity);
  85. testBdd4(mgr,verbosity);
  86. testBdd5(mgr,verbosity);
  87. testInterpolation(mgr,verbosity);
  88. testErrorHandling(mgr,verbosity);
  89. if (verbosity) mgr.info();
  90. return 0;
  91. } // main
  92. /**
  93. @brief Test basic operators on BDDs.
  94. @details The function returns void
  95. because it relies on the error handling done by the interface. The
  96. default error handler causes program termination.
  97. @sideeffect Creates BDD variables in the manager.
  98. @see testBdd2 testBdd3 testBdd4 testBdd5
  99. */
  100. static void
  101. testBdd(
  102. Cudd& mgr,
  103. int verbosity)
  104. {
  105. if (verbosity) cout << "Entering testBdd\n";
  106. // Create two new variables in the manager. If testBdd is called before
  107. // any variable is created in mgr, then x gets index 0 and y gets index 1.
  108. BDD x = mgr.bddVar();
  109. BDD y = mgr.bddVar();
  110. BDD f = x * y;
  111. if (verbosity) cout << "f"; f.print(2,verbosity);
  112. BDD g = y + !x;
  113. if (verbosity) cout << "g"; g.print(2,verbosity);
  114. if (verbosity)
  115. cout << "f and g are" << (f == !g ? "" : " not") << " complementary\n";
  116. if (verbosity)
  117. cout << "f is" << (f <= g ? "" : " not") << " less than or equal to g\n";
  118. g = f | ~g;
  119. if (verbosity) cout << "g"; g.print(2,verbosity);
  120. BDD h = f = y;
  121. if (verbosity) cout << "h"; h.print(2,verbosity);
  122. if (verbosity) cout << "x + h has " << (x+h).nodeCount() << " nodes\n";
  123. h += x;
  124. if (verbosity) cout << "h"; h.print(2,verbosity);
  125. } // testBdd
  126. /**
  127. @brief Test basic operators on ADDs.
  128. @details The function returns void because it relies on the error
  129. handling done by the interface. The default error handler causes
  130. program termination.
  131. @sideeffect May create ADD variables in the manager.
  132. @see testAdd2
  133. */
  134. static void
  135. testAdd(
  136. Cudd& mgr,
  137. int verbosity)
  138. {
  139. if (verbosity) cout << "Entering testAdd\n";
  140. // Create two ADD variables. If we called method addVar without an
  141. // argument, we would get two new indices. If testAdd is indeed called
  142. // after testBdd, then those indices would be 2 and 3. By specifying the
  143. // arguments, on the other hand, we avoid creating new unnecessary BDD
  144. // variables.
  145. ADD p = mgr.addVar(0);
  146. ADD q = mgr.addVar(1);
  147. // Test arithmetic operators.
  148. ADD r = p + q;
  149. if (verbosity) cout << "r"; r.print(2,verbosity);
  150. // CUDD_VALUE_TYPE is double.
  151. ADD s = mgr.constant(3.0);
  152. s *= p * q;
  153. if (verbosity) cout << "s"; s.print(2,verbosity);
  154. s += mgr.plusInfinity();
  155. if (verbosity) cout << "s"; s.print(2,verbosity);
  156. // Test relational operators.
  157. if (verbosity)
  158. cout << "p is" << (p <= r ? "" : " not") << " less than or equal to r\n";
  159. // Test logical operators.
  160. r = p | q;
  161. if (verbosity) cout << "r"; r.print(2,verbosity);
  162. } // testAdd
  163. /**
  164. @brief Test some more operators on ADDs.
  165. @details The function returns void because it relies on the error
  166. handling done by the interface. The default error handler causes
  167. program termination.
  168. @sideeffect May create ADD variables in the manager.
  169. @see testAdd
  170. */
  171. static void
  172. testAdd2(
  173. Cudd& mgr,
  174. int verbosity)
  175. {
  176. if (verbosity) cout << "Entering testAdd2\n";
  177. // Create two ADD variables. If we called method addVar without an
  178. // argument, we would get two new indices.
  179. vector<ADD> x(2);
  180. for (size_t i = 0; i < 2; ++i) {
  181. x[i] = mgr.addVar((int) i);
  182. }
  183. // Build a probability density function: [0.1, 0.2, 0.3, 0.4].
  184. ADD f0 = x[1].Ite(mgr.constant(0.2), mgr.constant(0.1));
  185. ADD f1 = x[1].Ite(mgr.constant(0.4), mgr.constant(0.3));
  186. ADD f = x[0].Ite(f1, f0);
  187. if (verbosity) cout << "f"; f.print(2,verbosity);
  188. // Compute the entropy.
  189. ADD l = f.Log();
  190. if (verbosity) cout << "l"; l.print(2,verbosity);
  191. ADD r = f * l;
  192. if (verbosity) cout << "r"; r.print(2,verbosity);
  193. ADD e = r.MatrixMultiply(mgr.constant(-1.0/log(2.0)),x);
  194. if (verbosity) cout << "e"; e.print(2,verbosity);
  195. } // testAdd2
  196. /**
  197. @brief Test basic operators on ZDDs.
  198. @details The function returns void because it relies on the error
  199. handling done by the interface. The default error handler causes
  200. program termination.
  201. @sideeffect May create ZDD variables in the manager.
  202. @see testZdd2
  203. */
  204. static void
  205. testZdd(
  206. Cudd& mgr,
  207. int verbosity)
  208. {
  209. if (verbosity) cout << "Entering testZdd\n";
  210. ZDD v = mgr.zddVar(0);
  211. ZDD w = mgr.zddVar(1);
  212. ZDD s = v + w;
  213. if (verbosity) cout << "s"; s.print(2,verbosity);
  214. if (verbosity) cout << "v is" << (v < s ? "" : " not") << " less than s\n";
  215. s -= v;
  216. if (verbosity) cout << "s"; s.print(2,verbosity);
  217. } // testZdd
  218. /**
  219. @brief Test vector operators on BDDs.
  220. @details The function returns void because it relies on the error
  221. handling done by the interface. The default error handler causes
  222. program termination.
  223. @sideeffect May create BDD variables in the manager.
  224. @see testBdd testBdd3 testBdd4 testBdd5
  225. */
  226. static void
  227. testBdd2(
  228. Cudd& mgr,
  229. int verbosity)
  230. {
  231. if (verbosity) cout << "Entering testBdd2\n";
  232. vector<BDD> x(4);
  233. for (size_t i = 0; i < 4; ++i) {
  234. x[i] = mgr.bddVar((int) i);
  235. }
  236. // Create the BDD for the Achilles' Heel function.
  237. BDD p1 = x[0] * x[2];
  238. BDD p2 = x[1] * x[3];
  239. BDD f = p1 + p2;
  240. const char* inames[] = {"x0", "x1", "x2", "x3"};
  241. if (verbosity) {
  242. cout << "f"; f.print(4,verbosity);
  243. cout << "Irredundant cover of f:" << endl; f.PrintCover();
  244. cout << "Number of minterms (arbitrary precision): "; f.ApaPrintMinterm(4);
  245. cout << "Number of minterms (extended precision): "; f.EpdPrintMinterm(4);
  246. cout << "Two-literal clauses of f:" << endl;
  247. f.PrintTwoLiteralClauses((char **)inames); cout << endl;
  248. }
  249. vector<BDD> vect = f.CharToVect();
  250. if (verbosity) {
  251. for (size_t i = 0; i < vect.size(); i++) {
  252. cout << "vect[" << i << "]" << endl; vect[i].PrintCover();
  253. }
  254. }
  255. // v0,...,v3 suffice if testBdd2 is called before testBdd3.
  256. if (verbosity) {
  257. const char* onames[] = {"v0", "v1", "v2", "v3", "v4", "v5"};
  258. mgr.DumpDot(vect, (char **)inames,(char **)onames);
  259. }
  260. } // testBdd2
  261. /**
  262. @brief Test additional operators on BDDs.
  263. @details The function returns void because it relies on the error
  264. handling done by the interface. The default error handler causes
  265. program termination.
  266. @sideeffect May create BDD variables in the manager.
  267. @see testBdd testBdd2 testBdd4 testBdd5
  268. */
  269. static void
  270. testBdd3(
  271. Cudd& mgr,
  272. int verbosity)
  273. {
  274. if (verbosity) cout << "Entering testBdd3\n";
  275. vector<BDD> x(6);
  276. for (size_t i = 0; i < 6; ++i) {
  277. x[i] = mgr.bddVar((int) i);
  278. }
  279. BDD G = x[4] + !x[5];
  280. BDD H = x[4] * x[5];
  281. BDD E = x[3].Ite(G,!x[5]);
  282. BDD F = x[3] + !H;
  283. BDD D = x[2].Ite(F,!H);
  284. BDD C = x[2].Ite(E,!F);
  285. BDD B = x[1].Ite(C,!F);
  286. BDD A = x[0].Ite(B,!D);
  287. BDD f = !A;
  288. if (verbosity) cout << "f"; f.print(6,verbosity);
  289. BDD f1 = f.RemapUnderApprox(6);
  290. if (verbosity) cout << "f1"; f1.print(6,verbosity);
  291. if (verbosity)
  292. cout << "f1 is" << (f1 <= f ? "" : " not") << " less than or equal to f\n";
  293. BDD g;
  294. BDD h;
  295. f.GenConjDecomp(&g,&h);
  296. if (verbosity) {
  297. cout << "g"; g.print(6,verbosity);
  298. cout << "h"; h.print(6,verbosity);
  299. cout << "g * h " << (g * h == f ? "==" : "!=") << " f\n";
  300. }
  301. } // testBdd3
  302. /**
  303. @brief Test cover manipulation with BDDs and ZDDs.
  304. @details The function returns void because it relies on the error
  305. handling done by the interface. The default error handler causes
  306. program termination. This function builds the BDDs for a
  307. transformed adder: one in which the inputs are transformations of
  308. the original inputs. It then creates ZDDs for the covers from the
  309. BDDs.
  310. @sideeffect May create BDD and ZDD variables in the manager.
  311. @see testZdd
  312. */
  313. static void
  314. testZdd2(
  315. Cudd& mgr,
  316. int verbosity)
  317. {
  318. if (verbosity) cout << "Entering testZdd2\n";
  319. size_t N = 3; // number of bits
  320. // Create variables.
  321. vector<BDD> a(N);
  322. vector<BDD> b(N);
  323. vector<BDD> c(N+1);
  324. for (size_t i = 0; i < N; ++i) {
  325. a[N-1-i] = mgr.bddVar(2*(int)i);
  326. b[N-1-i] = mgr.bddVar(2*(int)i+1);
  327. }
  328. c[0] = mgr.bddVar(2*(int)N);
  329. // Build functions.
  330. vector<BDD> s(N);
  331. for (size_t i = 0; i < N; ++i) {
  332. s[i] = a[i].Xnor(c[i]);
  333. c[i+1] = a[i].Ite(b[i],c[i]);
  334. }
  335. // Create array of outputs and print it.
  336. vector<BDD> p(N+1);
  337. for (size_t i = 0; i < N; ++i) {
  338. p[i] = s[i];
  339. }
  340. p[N] = c[N];
  341. if (verbosity) {
  342. for (size_t i = 0; i < p.size(); ++i) {
  343. cout << "p[" << i << "]"; p[i].print(2*(int)N+1,verbosity);
  344. }
  345. }
  346. const char* onames[] = {"s0", "s1", "s2", "c3"};
  347. if (verbosity) {
  348. const char* inames[] = {"a2", "b2", "a1", "b1", "a0", "b0", "c0"};
  349. mgr.DumpDot(p, (char **)inames,(char **)onames);
  350. }
  351. // Create ZDD variables and build ZDD covers from BDDs.
  352. mgr.zddVarsFromBddVars(2);
  353. vector<ZDD> z(N+1);
  354. for (size_t i = 0; i < N+1; ++i) {
  355. ZDD temp;
  356. BDD dummy = p[i].zddIsop(p[i],&temp);
  357. z[i] = temp;
  358. }
  359. // Print out covers.
  360. if (verbosity) {
  361. DdGen *gen;
  362. int *path;
  363. for (size_t i = 0; i < z.size(); i++) {
  364. cout << "z[" << i << "]"; z[i].print(4*(int)N+2,verbosity);
  365. }
  366. // Print cover in two different ways: with PrintCover and with
  367. // enumeration over the paths. The only difference should be
  368. // a reversal in the order of the cubes.
  369. for (size_t i = 0; i < z.size(); i++) {
  370. cout << "z[" << i << "]\n"; z[i].PrintCover();
  371. cout << "z[" << i << "]\n";
  372. DdNode *f = Cudd_Not(z[i].getNode());
  373. Cudd_zddForeachPath(z[i].manager(), f, gen, path) {
  374. for (size_t q = 0; q < 4*N+2; q += 2) {
  375. int v = path[q] * 4 + path[q+1];
  376. switch (v) {
  377. case 0:
  378. case 2:
  379. case 8:
  380. case 10:
  381. cout << "-";
  382. break;
  383. case 1:
  384. case 9:
  385. cout << "0";
  386. break;
  387. case 6:
  388. cout << "1";
  389. break;
  390. default:
  391. cout << "?";
  392. }
  393. }
  394. cout << " 1\n";
  395. }
  396. }
  397. const char* znames[] = {"a2+", "a2-", "b2+", "b2-", "a1+", "a1-", "b1+",
  398. "b1-", "a0+", "a0-", "b0+", "b0-", "c0+", "c0-"};
  399. mgr.DumpDot(z, (char **)znames,(char **)onames);
  400. }
  401. } // testZdd2
  402. /**
  403. @brief Test transfer between BDD managers.
  404. @details The function returns void because it relies on the error
  405. handling done by the interface. The default error handler causes
  406. program termination.
  407. @sideeffect May create BDD variables in the manager.
  408. @see testBdd testBdd2 testBdd3 testBdd5
  409. */
  410. static void
  411. testBdd4(
  412. Cudd& mgr,
  413. int verbosity)
  414. {
  415. if (verbosity) cout << "Entering testBdd4\n";
  416. BDD x = mgr.bddVar(0);
  417. BDD y = mgr.bddVar(1);
  418. BDD z = mgr.bddVar(2);
  419. BDD f = (~x & ~y & ~z) | (x & y);
  420. if (verbosity) cout << "f"; f.print(3,verbosity);
  421. Cudd otherMgr(0,0);
  422. BDD g = f.Transfer(otherMgr);
  423. if (verbosity) cout << "g"; g.print(3,verbosity);
  424. BDD h = g.Transfer(mgr);
  425. if (verbosity)
  426. cout << "f and h are" << (f == h ? "" : " not") << " identical\n";
  427. } // testBdd4
  428. /**
  429. @brief Test maximal expansion of cubes.
  430. @details The function returns void because it relies on the error
  431. handling done by the interface. The default error handler causes
  432. program termination.
  433. @sideeffect May create BDD variables in the manager.
  434. @see testBdd testBdd2 testBdd3 testBdd4
  435. */
  436. static void
  437. testBdd5(
  438. Cudd& mgr,
  439. int verbosity)
  440. {
  441. if (verbosity) cout << "Entering testBdd5\n";
  442. vector<BDD> x;
  443. x.reserve(4);
  444. for (int i = 0; i < 4; i++) {
  445. x.push_back(mgr.bddVar(i));
  446. }
  447. const char* inames[] = {"a", "b", "c", "d"};
  448. BDD f = (x[1] & x[3]) | (x[0] & ~x[2] & x[3]) | (~x[0] & x[1] & ~x[2]);
  449. BDD lb = x[1] & ~x[2] & x[3];
  450. BDD ub = x[3];
  451. BDD primes = lb.MaximallyExpand(ub,f);
  452. assert(primes == (x[1] & x[3]));
  453. BDD lprime = primes.LargestPrimeUnate(lb);
  454. assert(lprime == primes);
  455. if (verbosity) {
  456. const char * onames[] = {"lb", "ub", "f", "primes", "lprime"};
  457. vector<BDD> z;
  458. z.reserve(5);
  459. z.push_back(lb);
  460. z.push_back(ub);
  461. z.push_back(f);
  462. z.push_back(primes);
  463. z.push_back(lprime);
  464. mgr.DumpDot(z, (char **)inames, (char **)onames);
  465. cout << "primes(1)"; primes.print(4,verbosity);
  466. }
  467. lb = ~x[0] & x[2] & x[3];
  468. primes = lb.MaximallyExpand(ub,f);
  469. assert(primes == mgr.bddZero());
  470. if (verbosity) {
  471. cout << "primes(2)"; primes.print(4,verbosity);
  472. }
  473. lb = x[0] & ~x[2] & x[3];
  474. primes = lb.MaximallyExpand(ub,f);
  475. assert(primes == lb);
  476. lprime = primes.LargestPrimeUnate(lb);
  477. assert(lprime == primes);
  478. if (verbosity) {
  479. cout << "primes(3)"; primes.print(4,verbosity);
  480. }
  481. lb = ~x[0] & x[1] & ~x[2] & x[3];
  482. ub = mgr.bddOne();
  483. primes = lb.MaximallyExpand(ub,f);
  484. assert(primes == ((x[1] & x[3]) | (~x[0] & x[1] & ~x[2])));
  485. lprime = primes.LargestPrimeUnate(lb);
  486. assert(lprime == (x[1] & x[3]));
  487. if (verbosity) {
  488. cout << "primes(4)"; primes.print(4,1); primes.PrintCover();
  489. }
  490. ub = ~x[0] & x[3];
  491. primes = lb.MaximallyExpand(ub,f);
  492. assert(primes == (~x[0] & x[1] & x[3]));
  493. lprime = primes.LargestPrimeUnate(lb);
  494. assert(lprime == primes);
  495. if (verbosity) {
  496. cout << "primes(5)"; primes.print(4,verbosity);
  497. }
  498. } // testBdd5
  499. /**
  500. @brief Test BDD interpolation.
  501. */
  502. static void
  503. testInterpolation(
  504. Cudd& mgr,
  505. int verbosity)
  506. {
  507. BDD a = mgr.bddVar(0);
  508. BDD b = mgr.bddVar(1);
  509. BDD c = mgr.bddVar(2);
  510. BDD d = mgr.bddVar(3);
  511. BDD l1 = (a | d) & b & c;
  512. BDD u1 = (~a & ~b & ~c) | ((a | b) & c);
  513. BDD ip1 = l1.Interpolate(u1);
  514. if (verbosity) {
  515. cout << "l1"; l1.print(4,verbosity);
  516. cout << "u1"; u1.print(4,verbosity);
  517. cout << "interpolant1"; ip1.print(4,verbosity);
  518. }
  519. BDD l2 = (~a | ~b) & (a | c) & (b | c) & (a | ~b | ~d);
  520. BDD u2 = (~b & ~d) | (~b & c & d) | (b & c & ~d);
  521. BDD ip2 = l2.Interpolate(u2);
  522. if (verbosity) {
  523. cout << "l2"; l2.print(4,verbosity);
  524. cout << "u2"; u2.print(4,verbosity);
  525. cout << "interpolant2"; ip2.print(4,verbosity);
  526. }
  527. BDD l3 = ~a & ~b & d;
  528. BDD u3 = ~b & d;
  529. BDD ip3 = l3.Interpolate(u3);
  530. if (verbosity) {
  531. cout << "l3"; l3.print(4,verbosity);
  532. cout << "u3"; u3.print(4,verbosity);
  533. cout << "interpolant3"; ip3.print(4,verbosity);
  534. }
  535. } // testInterpolation
  536. /**
  537. @brief Basic test of error handling.
  538. @details This function also illustrates the use of the overloading of the
  539. stream insertion operator (operator<<) for BDDs.
  540. */
  541. static void
  542. testErrorHandling(
  543. Cudd& mgr,
  544. int verbosity)
  545. {
  546. // Setup.
  547. if (verbosity) cout << "Entering testErrorHandling\n";
  548. FILE *savefp = 0;
  549. if (verbosity == 0) {
  550. // Suppress error messages coming from CUDD.
  551. savefp = mgr.ReadStderr();
  552. #ifndef _WIN32
  553. FILE * devnull = fopen("/dev/null", "w");
  554. #else
  555. FILE * devnull = fopen("NUL", "w");
  556. #endif
  557. if (devnull)
  558. mgr.SetStderr(devnull);
  559. }
  560. size_t const N = 60;
  561. vector<BDD> vars;
  562. vars.reserve(N);
  563. for (size_t i = 0; i < N; ++i) {
  564. vars.push_back(mgr.bddVar((int) i));
  565. }
  566. // It is necessary to give names to all the BDD variables in the manager
  567. // for the names to be used by operator<<.
  568. for (int i = 0; i < mgr.ReadSize(); ++i) {
  569. ostringstream os;
  570. os << "var[" << i << "]";
  571. mgr.pushVariableName(os.str());
  572. }
  573. // Tests.
  574. // Trying to print the expression of an empty BDD.
  575. try {
  576. BDD empty;
  577. if (verbosity > 0)
  578. cout << "Oops! ";
  579. cout << empty << endl;
  580. } catch (logic_error const & e) {
  581. if (verbosity > 0)
  582. cerr << "Caught: " << e.what() << endl;
  583. }
  584. // Trying to extract a minterm from the zero BDD.
  585. try {
  586. BDD zero = mgr.bddZero();
  587. BDD minterm = zero.PickOneMinterm(vars);
  588. } catch (logic_error const & e) {
  589. if (verbosity > 0)
  590. cerr << "Caught: " << e.what() << endl;
  591. mgr.ClearErrorCode();
  592. }
  593. // Passing a non-cube second argument to Cofactor.
  594. try {
  595. BDD f = vars.at(1) | (vars.at(2) & vars.at(3));
  596. if (verbosity > 0)
  597. cout << "f = " << f << endl;
  598. BDD notAcube = vars.at(0) | vars.at(1);
  599. if (verbosity > 0)
  600. cout << notAcube << " is not a cube" << endl;
  601. BDD fc = f.Cofactor(notAcube);
  602. if (verbosity > 0) {
  603. cout << "The cofactor is: "; fc.summary(3);
  604. }
  605. } catch (logic_error const & e) {
  606. if (verbosity > 0)
  607. cerr << "Caught: " << e.what() << endl;
  608. mgr.ClearErrorCode();
  609. }
  610. #if 0
  611. // This attempt to allocate over 100 GB may succeed on machines with
  612. // enough memory; hence we exclude it from "make check."
  613. // Failing malloc.
  614. // Don't let the memory manager kill the program if malloc fails.
  615. DD_OOMFP saveHandler = mgr.InstallOutOfMemoryHandler(Cudd_OutOfMemSilent);
  616. try {
  617. mgr.Reserve(2000000000);
  618. } catch (logic_error const & e) {
  619. if (verbosity > 0)
  620. cerr << "Caught: " << e.what() << endl;
  621. mgr.ClearErrorCode();
  622. }
  623. (void) mgr.InstallOutOfMemoryHandler(saveHandler);
  624. #endif
  625. // Forgetting to check for empty result when setting a limit on
  626. // the number of new nodes.
  627. try {
  628. BDD f = mgr.bddOne();
  629. BDD g = f;
  630. for (size_t i = 0; i < N/2; i += 4) {
  631. f &= vars.at(i) | vars.at(i+N/2);
  632. g &= vars.at(i+1) | vars.at(i+N/2+1);
  633. }
  634. if (verbosity > 0) {
  635. cout << "f "; f.summary(N);
  636. cout << "g "; g.summary(N);
  637. }
  638. BDD h = f.And(g, /* max new nodes */ 1);
  639. if (verbosity > 0) {
  640. cout << "h "; h.summary(N);
  641. }
  642. } catch (logic_error const & e) {
  643. if (verbosity > 0)
  644. cerr << "Caught: " << e.what() << endl;
  645. mgr.ClearErrorCode();
  646. }
  647. // Using more memory than the set limit.
  648. size_t saveLimit = mgr.SetMaxMemory((size_t) 1);
  649. try {
  650. // The limit is ridiculously low (1 byte), but CUDD is resourceful.
  651. // Therefore we can still create a few BDDs.
  652. BDD f = mgr.Interval(vars, 122346345U, 348353453U);
  653. if (verbosity > 0) {
  654. cout << "f "; f.summary(N);
  655. }
  656. BDD g = mgr.Interval(vars, 34234U, 3143534534U);
  657. if (verbosity > 0) {
  658. cout << "g "; g.summary(N);
  659. }
  660. BDD h = f ^ g;
  661. if (verbosity > 0) {
  662. cout << "h "; h.summary(N);
  663. }
  664. // But if we really insist...
  665. BDD extra = mgr.bddVar(60000);
  666. // Here we would have to fix the variable names.
  667. } catch (logic_error const & e) {
  668. if (verbosity > 0)
  669. cerr << "Caught: " << e.what() << endl;
  670. mgr.ClearErrorCode();
  671. }
  672. (void) mgr.SetMaxMemory(saveLimit);
  673. // Timing out.
  674. unsigned long saveTl = mgr.SetTimeLimit(1UL); // 1 ms
  675. try {
  676. BDD f = mgr.bddOne();
  677. for (size_t i = 0; i < N/2; ++i) {
  678. f &= vars.at(i) | vars.at(i+N/2);
  679. }
  680. } catch (logic_error const & e) {
  681. if (verbosity > 0)
  682. cerr << "Caught: " << e.what() << endl;
  683. mgr.ClearErrorCode();
  684. }
  685. (void) mgr.SetTimeLimit(saveTl);
  686. // Let's clean up after ourselves.
  687. mgr.clearVariableNames();
  688. if (verbosity == 0) {
  689. mgr.SetStderr(savefp);
  690. }
  691. } // testErrorHandling