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.

1491 lines
46 KiB

  1. /**
  2. @file
  3. @ingroup cudd
  4. @brief Export functions.
  5. @author Fabio Somenzi
  6. @copyright@parblock
  7. Copyright (c) 1995-2015, Regents of the University of Colorado
  8. All rights reserved.
  9. Redistribution and use in source and binary forms, with or without
  10. modification, are permitted provided that the following conditions
  11. are met:
  12. Redistributions of source code must retain the above copyright
  13. notice, this list of conditions and the following disclaimer.
  14. Redistributions in binary form must reproduce the above copyright
  15. notice, this list of conditions and the following disclaimer in the
  16. documentation and/or other materials provided with the distribution.
  17. Neither the name of the University of Colorado nor the names of its
  18. contributors may be used to endorse or promote products derived from
  19. this software without specific prior written permission.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  27. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  28. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  30. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  31. POSSIBILITY OF SUCH DAMAGE.
  32. @endparblock
  33. */
  34. #include "util.h"
  35. #include "cstringstream.h"
  36. #include "cuddInt.h"
  37. /*---------------------------------------------------------------------------*/
  38. /* Constant declarations */
  39. /*---------------------------------------------------------------------------*/
  40. /*---------------------------------------------------------------------------*/
  41. /* Stucture declarations */
  42. /*---------------------------------------------------------------------------*/
  43. /*---------------------------------------------------------------------------*/
  44. /* Type declarations */
  45. /*---------------------------------------------------------------------------*/
  46. /*---------------------------------------------------------------------------*/
  47. /* Variable declarations */
  48. /*---------------------------------------------------------------------------*/
  49. /*---------------------------------------------------------------------------*/
  50. /* Macro declarations */
  51. /*---------------------------------------------------------------------------*/
  52. /** \cond */
  53. /*---------------------------------------------------------------------------*/
  54. /* Static function prototypes */
  55. /*---------------------------------------------------------------------------*/
  56. static int ddDoDumpBlif (DdManager *dd, DdNode *f, FILE *fp, st_table *visited, char const * const *names, int mv);
  57. static int ddDoDumpDaVinci (DdManager *dd, DdNode *f, FILE *fp, st_table *visited, char const * const *names, ptruint mask);
  58. static int ddDoDumpDDcal (DdManager *dd, DdNode *f, FILE *fp, st_table *visited, char const * const *names, ptruint mask);
  59. static int ddDoDumpFactoredForm (DdManager *dd, DdNode *f, FILE *fp, char const * const *names);
  60. static int ddDoFactoredFormString(DdManager * dd, DdNode *f, cstringstream stream, char const * const * names);
  61. /** \endcond */
  62. /*---------------------------------------------------------------------------*/
  63. /* Definition of exported functions */
  64. /*---------------------------------------------------------------------------*/
  65. /**
  66. @brief Writes a blif file representing the argument BDDs.
  67. @details Each %BDD is written as a network of multiplexers.
  68. Cudd_DumpBlif does not close the file: This is the caller
  69. responsibility. Cudd_DumpBlif uses a minimal unique subset of the
  70. hexadecimal address of a node as name for it. If the argument
  71. inames is non-null, it is assumed to hold the pointers to the names
  72. of the inputs. Similarly for onames.
  73. @return 1 in case of success; 0 otherwise (e.g., out-of-memory, file
  74. system full, or an %ADD with constants different from 0 and 1).
  75. @sideeffect None
  76. @see Cudd_DumpBlifBody Cudd_DumpDot Cudd_PrintDebug Cudd_DumpDDcal
  77. Cudd_DumpDaVinci Cudd_DumpFactoredForm
  78. */
  79. int
  80. Cudd_DumpBlif(
  81. DdManager * dd /**< manager */,
  82. int n /**< number of output nodes to be dumped */,
  83. DdNode ** f /**< array of output nodes to be dumped */,
  84. char const * const * inames /**< array of input names (or NULL) */,
  85. char const * const * onames /**< array of output names (or NULL) */,
  86. char * mname /**< model name (or NULL) */,
  87. FILE * fp /**< pointer to the dump file */,
  88. int mv /**< 0: blif, 1: blif-MV */)
  89. {
  90. DdNode *support = NULL;
  91. DdNode *scan;
  92. int *sorted = NULL;
  93. int nvars = dd->size;
  94. int retval;
  95. int i;
  96. /* Build a bit array with the support of f. */
  97. sorted = ALLOC(int,nvars);
  98. if (sorted == NULL) {
  99. dd->errorCode = CUDD_MEMORY_OUT;
  100. goto failure;
  101. }
  102. for (i = 0; i < nvars; i++) sorted[i] = 0;
  103. /* Take the union of the supports of each output function. */
  104. support = Cudd_VectorSupport(dd,f,n);
  105. if (support == NULL) goto failure;
  106. cuddRef(support);
  107. scan = support;
  108. while (!cuddIsConstant(scan)) {
  109. sorted[scan->index] = 1;
  110. scan = cuddT(scan);
  111. }
  112. Cudd_RecursiveDeref(dd,support);
  113. support = NULL; /* so that we do not try to free it in case of failure */
  114. /* Write the header (.model .inputs .outputs). */
  115. if (mname == NULL) {
  116. retval = fprintf(fp,".model DD\n.inputs");
  117. } else {
  118. retval = fprintf(fp,".model %s\n.inputs",mname);
  119. }
  120. if (retval == EOF) {
  121. FREE(sorted);
  122. return(0);
  123. }
  124. /* Write the input list by scanning the support array. */
  125. for (i = 0; i < nvars; i++) {
  126. if (sorted[i]) {
  127. if (inames == NULL) {
  128. retval = fprintf(fp," %d", i);
  129. } else {
  130. retval = fprintf(fp," %s", inames[i]);
  131. }
  132. if (retval == EOF) goto failure;
  133. }
  134. }
  135. FREE(sorted);
  136. sorted = NULL;
  137. /* Write the .output line. */
  138. retval = fprintf(fp,"\n.outputs");
  139. if (retval == EOF) goto failure;
  140. for (i = 0; i < n; i++) {
  141. if (onames == NULL) {
  142. retval = fprintf(fp," f%d", i);
  143. } else {
  144. retval = fprintf(fp," %s", onames[i]);
  145. }
  146. if (retval == EOF) goto failure;
  147. }
  148. retval = fprintf(fp,"\n");
  149. if (retval == EOF) goto failure;
  150. retval = Cudd_DumpBlifBody(dd, n, f, inames, onames, fp, mv);
  151. if (retval == 0) goto failure;
  152. /* Write trailer and return. */
  153. retval = fprintf(fp,".end\n");
  154. if (retval == EOF) goto failure;
  155. return(1);
  156. failure:
  157. if (sorted != NULL) FREE(sorted);
  158. if (support != NULL) Cudd_RecursiveDeref(dd,support);
  159. return(0);
  160. } /* end of Cudd_DumpBlif */
  161. /**
  162. @brief Writes a blif body representing the argument BDDs.
  163. @details Each %BDD is written as a network of multiplexers. No
  164. header (.model, .inputs, and .outputs) and footer (.end) are
  165. produced by this function. One multiplexer is written for each %BDD
  166. node. Cudd_DumpBlifBody does not close the file: This is the caller
  167. responsibility. Cudd_DumpBlifBody uses a minimal unique subset of
  168. the hexadecimal address of a node as name for it. If the argument
  169. inames is non-null, it is assumed to hold the pointers to the names
  170. of the inputs. Similarly for onames. This function prints out only
  171. .names part.
  172. @return 1 in case of success; 0 otherwise (e.g., out-of-memory, file
  173. system full, or an %ADD with constants different from 0 and 1).
  174. @sideeffect None
  175. @see Cudd_DumpBlif Cudd_DumpDot Cudd_PrintDebug Cudd_DumpDDcal
  176. Cudd_DumpDaVinci Cudd_DumpFactoredForm
  177. */
  178. int
  179. Cudd_DumpBlifBody(
  180. DdManager * dd /**< manager */,
  181. int n /**< number of output nodes to be dumped */,
  182. DdNode ** f /**< array of output nodes to be dumped */,
  183. char const * const * inames /**< array of input names (or NULL) */,
  184. char const * const * onames /**< array of output names (or NULL) */,
  185. FILE * fp /**< pointer to the dump file */,
  186. int mv /**< 0: blif, 1: blif-MV */)
  187. {
  188. st_table *visited = NULL;
  189. int retval;
  190. int i;
  191. /* Initialize symbol table for visited nodes. */
  192. visited = st_init_table(st_ptrcmp, st_ptrhash);
  193. if (visited == NULL) goto failure;
  194. /* Call the function that really gets the job done. */
  195. for (i = 0; i < n; i++) {
  196. retval = ddDoDumpBlif(dd,Cudd_Regular(f[i]),fp,visited,inames,mv);
  197. if (retval == 0) goto failure;
  198. }
  199. /* To account for the possible complement on the root,
  200. ** we put either a buffer or an inverter at the output of
  201. ** the multiplexer representing the top node.
  202. */
  203. for (i = 0; i < n; i++) {
  204. if (onames == NULL) {
  205. retval = fprintf(fp, ".names %" PRIxPTR " f%d\n",
  206. (ptruint) f[i] / (ptruint) sizeof(DdNode), i);
  207. } else {
  208. retval = fprintf(fp, ".names %" PRIxPTR " %s\n",
  209. (ptruint) f[i] / (ptruint) sizeof(DdNode), onames[i]);
  210. }
  211. if (retval == EOF) goto failure;
  212. if (Cudd_IsComplement(f[i])) {
  213. retval = fprintf(fp,"%s0 1\n", mv ? ".def 0\n" : "");
  214. } else {
  215. retval = fprintf(fp,"%s1 1\n", mv ? ".def 0\n" : "");
  216. }
  217. if (retval == EOF) goto failure;
  218. }
  219. st_free_table(visited);
  220. return(1);
  221. failure:
  222. if (visited != NULL) st_free_table(visited);
  223. return(0);
  224. } /* end of Cudd_DumpBlifBody */
  225. /**
  226. @brief Writes a dot file representing the argument DDs.
  227. @details Writes a file representing the argument DDs in a format
  228. suitable for the graph drawing program dot.
  229. Cudd_DumpDot does not close the file: This is the caller
  230. responsibility. Cudd_DumpDot uses a minimal unique subset of the
  231. hexadecimal address of a node as name for it.
  232. If the argument inames is non-null, it is assumed to hold the pointers
  233. to the names of the inputs. Similarly for onames.
  234. Cudd_DumpDot uses the following convention to draw arcs:
  235. <ul>
  236. <li> solid line: THEN arcs;
  237. <li> dotted line: complement arcs;
  238. <li> dashed line: regular ELSE arcs.
  239. </ul>
  240. The dot options are chosen so that the drawing fits on a letter-size
  241. sheet.
  242. @return 1 in case of success; 0 otherwise (e.g., out-of-memory, file
  243. system full).
  244. @sideeffect None
  245. @see Cudd_DumpBlif Cudd_PrintDebug Cudd_DumpDDcal
  246. Cudd_DumpDaVinci Cudd_DumpFactoredForm
  247. */
  248. int
  249. Cudd_DumpDot(
  250. DdManager * dd /**< manager */,
  251. int n /**< number of output nodes to be dumped */,
  252. DdNode ** f /**< array of output nodes to be dumped */,
  253. char const * const * inames /**< array of input names (or NULL) */,
  254. char const * const * onames /**< array of output names (or NULL) */,
  255. FILE * fp /**< pointer to the dump file */)
  256. {
  257. DdNode *support = NULL;
  258. DdNode *scan;
  259. int *sorted = NULL;
  260. int nvars = dd->size;
  261. st_table *visited = NULL;
  262. st_generator *gen = NULL;
  263. int retval;
  264. int i, j;
  265. int slots;
  266. DdNodePtr *nodelist;
  267. ptruint refAddr, diff, mask = 0;
  268. /* Build a bit array with the support of f. */
  269. sorted = ALLOC(int,nvars);
  270. if (sorted == NULL) {
  271. dd->errorCode = CUDD_MEMORY_OUT;
  272. goto failure;
  273. }
  274. for (i = 0; i < nvars; i++) sorted[i] = 0;
  275. /* Take the union of the supports of each output function. */
  276. support = Cudd_VectorSupport(dd,f,n);
  277. if (support == NULL) goto failure;
  278. cuddRef(support);
  279. scan = support;
  280. while (!cuddIsConstant(scan)) {
  281. sorted[scan->index] = 1;
  282. scan = cuddT(scan);
  283. }
  284. Cudd_RecursiveDeref(dd,support);
  285. support = NULL; /* so that we do not try to free it in case of failure */
  286. /* Initialize symbol table for visited nodes. */
  287. visited = st_init_table(st_ptrcmp, st_ptrhash);
  288. if (visited == NULL) goto failure;
  289. /* Collect all the nodes of this DD in the symbol table. */
  290. for (i = 0; i < n; i++) {
  291. retval = cuddCollectNodes(Cudd_Regular(f[i]),visited);
  292. if (retval == 0) goto failure;
  293. }
  294. /* Find how many most significant hex digits are identical
  295. ** in the addresses of all the nodes. Build a mask based
  296. ** on this knowledge, so that digits that carry no information
  297. ** will not be printed. This is done in two steps.
  298. ** 1. We scan the symbol table to find the bits that differ
  299. ** in at least 2 addresses.
  300. ** 2. We choose one of the possible masks. There are 8 possible
  301. ** masks for 32-bit integer, and 16 possible masks for 64-bit
  302. ** integers.
  303. */
  304. /* Find the bits that are different. */
  305. refAddr = (ptruint) Cudd_Regular(f[0]);
  306. diff = 0;
  307. gen = st_init_gen(visited);
  308. if (gen == NULL) goto failure;
  309. while (st_gen(gen, (void **) &scan, NULL)) {
  310. diff |= refAddr ^ (ptruint) scan;
  311. }
  312. st_free_gen(gen); gen = NULL;
  313. /* Choose the mask. */
  314. for (i = 0; (unsigned) i < 8 * sizeof(ptruint); i += 4) {
  315. mask = ((ptruint) 1 << i) - 1;
  316. if (diff <= mask) break;
  317. }
  318. /* Write the header and the global attributes. */
  319. retval = fprintf(fp,"digraph \"DD\" {\n");
  320. if (retval == EOF) return(0);
  321. retval = fprintf(fp,
  322. "size = \"7.5,10\"\ncenter = true;\nedge [dir = none];\n");
  323. if (retval == EOF) return(0);
  324. /* Write the input name subgraph by scanning the support array. */
  325. retval = fprintf(fp,"{ node [shape = plaintext];\n");
  326. if (retval == EOF) goto failure;
  327. retval = fprintf(fp," edge [style = invis];\n");
  328. if (retval == EOF) goto failure;
  329. /* We use a name ("CONST NODES") with an embedded blank, because
  330. ** it is unlikely to appear as an input name.
  331. */
  332. retval = fprintf(fp," \"CONST NODES\" [style = invis];\n");
  333. if (retval == EOF) goto failure;
  334. for (i = 0; i < nvars; i++) {
  335. if (sorted[dd->invperm[i]]) {
  336. if (inames == NULL || inames[dd->invperm[i]] == NULL) {
  337. retval = fprintf(fp,"\" %d \" -> ", dd->invperm[i]);
  338. } else {
  339. retval = fprintf(fp,"\" %s \" -> ", inames[dd->invperm[i]]);
  340. }
  341. if (retval == EOF) goto failure;
  342. }
  343. }
  344. retval = fprintf(fp,"\"CONST NODES\"; \n}\n");
  345. if (retval == EOF) goto failure;
  346. /* Write the output node subgraph. */
  347. retval = fprintf(fp,"{ rank = same; node [shape = box]; edge [style = invis];\n");
  348. if (retval == EOF) goto failure;
  349. for (i = 0; i < n; i++) {
  350. if (onames == NULL) {
  351. retval = fprintf(fp,"\"F%d\"", i);
  352. } else {
  353. retval = fprintf(fp,"\" %s \"", onames[i]);
  354. }
  355. if (retval == EOF) goto failure;
  356. if (i == n - 1) {
  357. retval = fprintf(fp,"; }\n");
  358. } else {
  359. retval = fprintf(fp," -> ");
  360. }
  361. if (retval == EOF) goto failure;
  362. }
  363. /* Write rank info: All nodes with the same index have the same rank. */
  364. for (i = 0; i < nvars; i++) {
  365. if (sorted[dd->invperm[i]]) {
  366. retval = fprintf(fp,"{ rank = same; ");
  367. if (retval == EOF) goto failure;
  368. if (inames == NULL || inames[dd->invperm[i]] == NULL) {
  369. retval = fprintf(fp,"\" %d \";\n", dd->invperm[i]);
  370. } else {
  371. retval = fprintf(fp,"\" %s \";\n", inames[dd->invperm[i]]);
  372. }
  373. if (retval == EOF) goto failure;
  374. nodelist = dd->subtables[i].nodelist;
  375. slots = dd->subtables[i].slots;
  376. for (j = 0; j < slots; j++) {
  377. scan = nodelist[j];
  378. while (scan != NULL) {
  379. if (st_is_member(visited,scan)) {
  380. // retval = fprintf(fp,"\"%#" PRIxPTR "\";\n",
  381. // ((mask & (ptruint) scan) / sizeof(DdNode)));
  382. retval = fprintf(fp,"\"%p\";\n", (ptruint) scan);
  383. if (retval == EOF) goto failure;
  384. }
  385. scan = scan->next;
  386. }
  387. }
  388. retval = fprintf(fp,"}\n");
  389. if (retval == EOF) goto failure;
  390. }
  391. }
  392. /* All constants have the same rank. */
  393. retval = fprintf(fp,
  394. "{ rank = same; \"CONST NODES\";\n{ node [shape = box]; ");
  395. if (retval == EOF) goto failure;
  396. nodelist = dd->constants.nodelist;
  397. slots = dd->constants.slots;
  398. for (j = 0; j < slots; j++) {
  399. scan = nodelist[j];
  400. while (scan != NULL) {
  401. if (st_is_member(visited,scan)) {
  402. // retval = fprintf(fp,"\"%#" PRIxPTR "\";\n",
  403. // ((mask & (ptruint) scan) / sizeof(DdNode)));
  404. retval = fprintf(fp,"\"%p\";\n", Cudd_Regular(scan));
  405. if (retval == EOF) goto failure;
  406. }
  407. scan = scan->next;
  408. }
  409. }
  410. retval = fprintf(fp,"}\n}\n");
  411. if (retval == EOF) goto failure;
  412. /* Write edge info. */
  413. /* Edges from the output nodes. */
  414. for (i = 0; i < n; i++) {
  415. if (onames == NULL) {
  416. retval = fprintf(fp,"\"F%d\"", i);
  417. } else {
  418. retval = fprintf(fp,"\" %s \"", onames[i]);
  419. }
  420. if (retval == EOF) goto failure;
  421. /* Account for the possible complement on the root. */
  422. if (Cudd_IsComplement(f[i])) {
  423. // retval = fprintf(fp," -> \"%#" PRIxPTR "\" [style = dotted];\n",
  424. // ((mask & (ptruint) f[i]) / sizeof(DdNode)));
  425. retval = fprintf(fp," -> \"%p\" [style = dotted];\n", (ptruint)Cudd_Regular(f[i]));
  426. } else {
  427. // retval = fprintf(fp," -> \"%p#" PRIxPTR "\" [style = solid];\n",
  428. // ((mask & (ptruint) f[i]) / sizeof(DdNode)));
  429. retval = fprintf(fp," -> \"%p\" [style = solid];\n", (ptruint)Cudd_Regular(f[i]));
  430. }
  431. if (retval == EOF) goto failure;
  432. }
  433. /* Edges from internal nodes. */
  434. for (i = 0; i < nvars; i++) {
  435. if (sorted[dd->invperm[i]]) {
  436. nodelist = dd->subtables[i].nodelist;
  437. slots = dd->subtables[i].slots;
  438. for (j = 0; j < slots; j++) {
  439. scan = nodelist[j];
  440. while (scan != NULL) {
  441. if (st_is_member(visited,scan)) {
  442. // retval = fprintf(fp,
  443. // "\"%#" PRIxPTR "\" -> \"%#" PRIxPTR "\";\n",
  444. // ((mask & (ptruint) scan) / sizeof(DdNode)),
  445. // ((mask & (ptruint) cuddT(scan)) / sizeof(DdNode)));
  446. retval = fprintf(fp, "\"%p\" -> \"%p\";\n", (ptruint)Cudd_Regular(scan), (ptruint)Cudd_Regular(cuddT(scan)));
  447. if (retval == EOF) goto failure;
  448. if (Cudd_IsComplement(cuddE(scan))) {
  449. // retval = fprintf(fp,
  450. // "\"%#" PRIxPTR "\" -> \"%#" PRIxPTR
  451. // "\" [style = dotted];\n",
  452. // ((mask & (ptruint) scan) / sizeof(DdNode)),
  453. // ((mask & (ptruint) cuddE(scan)) /
  454. // sizeof(DdNode)));
  455. retval = fprintf(fp, "\"%p\" -> \"%p\" [style = dotted];\n", (ptruint)Cudd_Regular(scan), (ptruint)Cudd_Regular(cuddE(scan)));
  456. } else {
  457. // retval = fprintf(fp,
  458. // "\"%#" PRIxPTR "\" -> \"%#" PRIxPTR
  459. // "\" [style = dashed];\n",
  460. // ((mask & (ptruint) scan) / sizeof(DdNode)),
  461. // ((mask & (ptruint) cuddE(scan)) /
  462. // sizeof(DdNode)));
  463. retval = fprintf(fp, "\"%p\" -> \"%p\" [style = dashed];\n", (ptruint)Cudd_Regular(scan), (ptruint)Cudd_Regular(cuddE(scan)));
  464. }
  465. if (retval == EOF) goto failure;
  466. }
  467. scan = scan->next;
  468. }
  469. }
  470. }
  471. }
  472. /* Write constant labels. */
  473. nodelist = dd->constants.nodelist;
  474. slots = dd->constants.slots;
  475. for (j = 0; j < slots; j++) {
  476. scan = nodelist[j];
  477. while (scan != NULL) {
  478. if (st_is_member(visited,scan)) {
  479. // retval = fprintf(fp,"\"%#" PRIxPTR "\" [label = \"%g\"];\n",
  480. // ((mask & (ptruint) scan) / sizeof(DdNode)), cuddV(scan));
  481. retval = fprintf(fp,"\"%p\" [label = \"%g\"];\n", (ptruint)Cudd_Regular(scan), cuddV(scan));
  482. if (retval == EOF) goto failure;
  483. }
  484. scan = scan->next;
  485. }
  486. }
  487. /* Write trailer and return. */
  488. retval = fprintf(fp,"}\n");
  489. if (retval == EOF) goto failure;
  490. st_free_table(visited);
  491. FREE(sorted);
  492. return(1);
  493. failure:
  494. if (sorted != NULL) FREE(sorted);
  495. if (support != NULL) Cudd_RecursiveDeref(dd,support);
  496. if (visited != NULL) st_free_table(visited);
  497. return(0);
  498. } /* end of Cudd_DumpDot */
  499. /**
  500. @brief Writes a daVinci file representing the argument BDDs.
  501. @details Writes a daVinci file representing the argument BDDs.
  502. Cudd_DumpDaVinci does not close the file: This is the caller
  503. responsibility. Cudd_DumpDaVinci uses a minimal unique subset of the
  504. hexadecimal address of a node as name for it. If the argument
  505. inames is non-null, it is assumed to hold the pointers to the names
  506. of the inputs. Similarly for onames.
  507. @return 1 in case of success; 0 otherwise (e.g., out-of-memory or
  508. file system full).
  509. @sideeffect None
  510. @see Cudd_DumpDot Cudd_PrintDebug Cudd_DumpBlif Cudd_DumpDDcal
  511. Cudd_DumpFactoredForm
  512. */
  513. int
  514. Cudd_DumpDaVinci(
  515. DdManager * dd /**< manager */,
  516. int n /**< number of output nodes to be dumped */,
  517. DdNode ** f /**< array of output nodes to be dumped */,
  518. char const * const * inames /**< array of input names (or NULL) */,
  519. char const * const * onames /**< array of output names (or NULL) */,
  520. FILE * fp /**< pointer to the dump file */)
  521. {
  522. DdNode *support = NULL;
  523. DdNode *scan;
  524. st_table *visited = NULL;
  525. int retval;
  526. int i;
  527. st_generator *gen;
  528. ptruint refAddr, diff, mask = 0;
  529. /* Initialize symbol table for visited nodes. */
  530. visited = st_init_table(st_ptrcmp, st_ptrhash);
  531. if (visited == NULL) goto failure;
  532. /* Collect all the nodes of this DD in the symbol table. */
  533. for (i = 0; i < n; i++) {
  534. retval = cuddCollectNodes(Cudd_Regular(f[i]),visited);
  535. if (retval == 0) goto failure;
  536. }
  537. /* Find how many most significant hex digits are identical
  538. ** in the addresses of all the nodes. Build a mask based
  539. ** on this knowledge, so that digits that carry no information
  540. ** will not be printed. This is done in two steps.
  541. ** 1. We scan the symbol table to find the bits that differ
  542. ** in at least 2 addresses.
  543. ** 2. We choose one of the possible masks. There are 8 possible
  544. ** masks for 32-bit integer, and 16 possible masks for 64-bit
  545. ** integers.
  546. */
  547. /* Find the bits that are different. */
  548. refAddr = (ptruint) Cudd_Regular(f[0]);
  549. diff = 0;
  550. gen = st_init_gen(visited);
  551. while (st_gen(gen, (void **) &scan, NULL)) {
  552. diff |= refAddr ^ (ptruint) scan;
  553. }
  554. st_free_gen(gen);
  555. /* Choose the mask. */
  556. for (i = 0; (unsigned) i < 8 * sizeof(ptruint); i += 4) {
  557. mask = ((ptruint) 1 << i) - 1;
  558. if (diff <= mask) break;
  559. }
  560. st_free_table(visited);
  561. /* Initialize symbol table for visited nodes. */
  562. visited = st_init_table(st_ptrcmp, st_ptrhash);
  563. if (visited == NULL) goto failure;
  564. retval = fprintf(fp, "[");
  565. if (retval == EOF) goto failure;
  566. /* Call the function that really gets the job done. */
  567. for (i = 0; i < n; i++) {
  568. if (onames == NULL) {
  569. retval = fprintf(fp,
  570. "l(\"f%d\",n(\"root\",[a(\"OBJECT\",\"f%d\")],",
  571. i,i);
  572. } else {
  573. retval = fprintf(fp,
  574. "l(\"%s\",n(\"root\",[a(\"OBJECT\",\"%s\")],",
  575. onames[i], onames[i]);
  576. }
  577. if (retval == EOF) goto failure;
  578. retval = fprintf(fp, "[e(\"edge\",[a(\"EDGECOLOR\",\"%s\"),a(\"_DIR\",\"none\")],",
  579. Cudd_IsComplement(f[i]) ? "red" : "blue");
  580. if (retval == EOF) goto failure;
  581. retval = ddDoDumpDaVinci(dd,Cudd_Regular(f[i]),fp,visited,inames,mask);
  582. if (retval == 0) goto failure;
  583. retval = fprintf(fp, ")]))%s", i == n-1 ? "" : ",");
  584. if (retval == EOF) goto failure;
  585. }
  586. /* Write trailer and return. */
  587. retval = fprintf(fp, "]\n");
  588. if (retval == EOF) goto failure;
  589. st_free_table(visited);
  590. return(1);
  591. failure:
  592. if (support != NULL) Cudd_RecursiveDeref(dd,support);
  593. if (visited != NULL) st_free_table(visited);
  594. return(0);
  595. } /* end of Cudd_DumpDaVinci */
  596. /**
  597. @brief Writes a DDcal file representing the argument BDDs.
  598. @details Writes a DDcal file representing the argument BDDs.
  599. Cudd_DumpDDcal does not close the file: This is the caller
  600. responsibility. Cudd_DumpDDcal uses a minimal unique subset of the
  601. hexadecimal address of a node as name for it. If the argument
  602. inames is non-null, it is assumed to hold the pointers to the names
  603. of the inputs. Similarly for onames.
  604. @return 1 in case of success; 0 otherwise (e.g., out-of-memory or
  605. file system full).
  606. @sideeffect None
  607. @see Cudd_DumpDot Cudd_PrintDebug Cudd_DumpBlif Cudd_DumpDaVinci
  608. Cudd_DumpFactoredForm
  609. */
  610. int
  611. Cudd_DumpDDcal(
  612. DdManager * dd /**< manager */,
  613. int n /**< number of output nodes to be dumped */,
  614. DdNode ** f /**< array of output nodes to be dumped */,
  615. char const * const * inames /**< array of input names (or NULL) */,
  616. char const * const * onames /**< array of output names (or NULL) */,
  617. FILE * fp /**< pointer to the dump file */)
  618. {
  619. DdNode *support = NULL;
  620. DdNode *scan;
  621. int *sorted = NULL;
  622. int nvars = dd->size;
  623. st_table *visited = NULL;
  624. int retval;
  625. int i;
  626. st_generator *gen;
  627. ptruint refAddr, diff, mask = 0;
  628. /* Initialize symbol table for visited nodes. */
  629. visited = st_init_table(st_ptrcmp, st_ptrhash);
  630. if (visited == NULL) goto failure;
  631. /* Collect all the nodes of this DD in the symbol table. */
  632. for (i = 0; i < n; i++) {
  633. retval = cuddCollectNodes(Cudd_Regular(f[i]),visited);
  634. if (retval == 0) goto failure;
  635. }
  636. /* Find how many most significant hex digits are identical
  637. ** in the addresses of all the nodes. Build a mask based
  638. ** on this knowledge, so that digits that carry no information
  639. ** will not be printed. This is done in two steps.
  640. ** 1. We scan the symbol table to find the bits that differ
  641. ** in at least 2 addresses.
  642. ** 2. We choose one of the possible masks. There are 8 possible
  643. ** masks for 32-bit integer, and 16 possible masks for 64-bit
  644. ** integers.
  645. */
  646. /* Find the bits that are different. */
  647. refAddr = (ptruint) Cudd_Regular(f[0]);
  648. diff = 0;
  649. gen = st_init_gen(visited);
  650. while (st_gen(gen, (void **) &scan, NULL)) {
  651. diff |= refAddr ^ (ptruint) scan;
  652. }
  653. st_free_gen(gen);
  654. /* Choose the mask. */
  655. for (i = 0; (unsigned) i < 8 * sizeof(ptruint); i += 4) {
  656. mask = ((ptruint) 1 << i) - 1;
  657. if (diff <= mask) break;
  658. }
  659. st_free_table(visited);
  660. /* Build a bit array with the support of f. */
  661. sorted = ALLOC(int,nvars);
  662. if (sorted == NULL) {
  663. dd->errorCode = CUDD_MEMORY_OUT;
  664. goto failure;
  665. }
  666. for (i = 0; i < nvars; i++) sorted[i] = 0;
  667. /* Take the union of the supports of each output function. */
  668. support = Cudd_VectorSupport(dd,f,n);
  669. if (support == NULL) goto failure;
  670. cuddRef(support);
  671. scan = support;
  672. while (!cuddIsConstant(scan)) {
  673. sorted[scan->index] = 1;
  674. scan = cuddT(scan);
  675. }
  676. Cudd_RecursiveDeref(dd,support);
  677. support = NULL; /* so that we do not try to free it in case of failure */
  678. for (i = 0; i < nvars; i++) {
  679. if (sorted[dd->invperm[i]]) {
  680. if (inames == NULL || inames[dd->invperm[i]] == NULL) {
  681. retval = fprintf(fp,"v%d", dd->invperm[i]);
  682. } else {
  683. retval = fprintf(fp,"%s", inames[dd->invperm[i]]);
  684. }
  685. if (retval == EOF) goto failure;
  686. }
  687. retval = fprintf(fp,"%s", i == nvars - 1 ? "\n" : " * ");
  688. if (retval == EOF) goto failure;
  689. }
  690. FREE(sorted);
  691. sorted = NULL;
  692. /* Initialize symbol table for visited nodes. */
  693. visited = st_init_table(st_ptrcmp, st_ptrhash);
  694. if (visited == NULL) goto failure;
  695. /* Call the function that really gets the job done. */
  696. for (i = 0; i < n; i++) {
  697. retval = ddDoDumpDDcal(dd,Cudd_Regular(f[i]),fp,visited,inames,mask);
  698. if (retval == 0) goto failure;
  699. if (onames == NULL) {
  700. retval = fprintf(fp, "f%d = ", i);
  701. } else {
  702. retval = fprintf(fp, "%s = ", onames[i]);
  703. }
  704. if (retval == EOF) goto failure;
  705. retval = fprintf(fp, "n%#" PRIxPTR "%s\n",
  706. (((ptruint) f[i] & mask) / sizeof(DdNode)),
  707. Cudd_IsComplement(f[i]) ? "'" : "");
  708. if (retval == EOF) goto failure;
  709. }
  710. /* Write trailer and return. */
  711. retval = fprintf(fp, "[");
  712. if (retval == EOF) goto failure;
  713. for (i = 0; i < n; i++) {
  714. if (onames == NULL) {
  715. retval = fprintf(fp, "f%d", i);
  716. } else {
  717. retval = fprintf(fp, "%s", onames[i]);
  718. }
  719. if (retval == EOF) goto failure;
  720. retval = fprintf(fp, "%s", i == n-1 ? "" : " ");
  721. if (retval == EOF) goto failure;
  722. }
  723. retval = fprintf(fp, "]\n");
  724. if (retval == EOF) goto failure;
  725. st_free_table(visited);
  726. return(1);
  727. failure:
  728. if (sorted != NULL) FREE(sorted);
  729. if (support != NULL) Cudd_RecursiveDeref(dd,support);
  730. if (visited != NULL) st_free_table(visited);
  731. return(0);
  732. } /* end of Cudd_DumpDDcal */
  733. /**
  734. @brief Writes factored forms representing the argument BDDs.
  735. @details Writes factored forms representing the argument BDDs. The
  736. format of the factored form is the one used in the genlib files for
  737. technology mapping in sis. Cudd_DumpFactoredForm does not close the
  738. file: This is the caller responsibility. Caution must be exercised
  739. because a factored form may be exponentially larger than the
  740. argument %BDD. If the argument inames is non-null, it is assumed to
  741. hold the pointers to the names of the inputs. Similarly for onames.
  742. If the number of output nodes is 0, it is interpreted as 1, but no
  743. output name followed by equal sign is printed before the factored
  744. form.
  745. @return 1 in case of success; 0 otherwise (e.g., file system full).
  746. @sideeffect None
  747. @see Cudd_DumpDot Cudd_PrintDebug Cudd_DumpBlif Cudd_DumpDaVinci
  748. Cudd_DumpDDcal
  749. */
  750. int
  751. Cudd_DumpFactoredForm(
  752. DdManager * dd /**< manager */,
  753. int n /**< number of output nodes to be dumped */,
  754. DdNode ** f /**< array of output nodes to be dumped */,
  755. char const * const * inames /**< array of input names (or NULL) */,
  756. char const * const * onames /**< array of output names (or NULL) */,
  757. FILE * fp /**< pointer to the dump file */)
  758. {
  759. int retval = 0;
  760. int i;
  761. int printName = n != 0;
  762. if (!printName) n = 1;
  763. /* Call the function that really gets the job done. */
  764. for (i = 0; i < n; i++) {
  765. if (printName) {
  766. if (onames == NULL) {
  767. retval = fprintf(fp, "f%d = ", i);
  768. } else {
  769. retval = fprintf(fp, "%s = ", onames[i]);
  770. }
  771. }
  772. if (retval == EOF) return(0);
  773. if (f[i] == DD_ONE(dd)) {
  774. retval = fprintf(fp, "CONST1");
  775. if (retval == EOF) return(0);
  776. } else if (f[i] == Cudd_Not(DD_ONE(dd)) || f[i] == DD_ZERO(dd)) {
  777. retval = fprintf(fp, "CONST0");
  778. if (retval == EOF) return(0);
  779. } else {
  780. retval = fprintf(fp, "%s", Cudd_IsComplement(f[i]) ? (Cudd_bddIsVar(dd, Cudd_Regular(f[i])) ? "!" : "!(") : "");
  781. if (retval == EOF) return(0);
  782. retval = ddDoDumpFactoredForm(dd,Cudd_Regular(f[i]),fp,inames);
  783. if (retval == 0) return(0);
  784. retval = fprintf(fp, "%s", Cudd_IsComplement(f[i]) && !Cudd_bddIsVar(dd, Cudd_Regular(f[i])) ? ")" : "");
  785. if (retval == EOF) return(0);
  786. }
  787. retval = fprintf(fp, "%s", i == n-1 ? "" : "\n");
  788. if (retval == EOF) return(0);
  789. }
  790. return(1);
  791. } /* end of Cudd_DumpFactoredForm */
  792. /**
  793. @brief Returns a string with the factored form of the argument BDDs
  794. @details The factored form uses & for conjunction, | for disjunction
  795. and ! for negation. Caution must be exercised because a factored
  796. form may be exponentially larger than the argument %BDD. If the
  797. argument inames is non-null, it is assumed to hold the pointers to
  798. the names of the inputs.
  799. @return a string in case of success; NULL otherwise.
  800. @sideeffect None
  801. @see Cudd_DumpDot Cudd_PrintDebug Cudd_DumpBlif Cudd_DumpDaVinci
  802. Cudd_DumpDDcal Cudd_DumpFactoredForm
  803. */
  804. char *
  805. Cudd_FactoredFormString(
  806. DdManager *dd,
  807. DdNode *f,
  808. char const * const * inames)
  809. {
  810. cstringstream stream = newStringStream();
  811. int err, retval;
  812. char * str;
  813. if (!stream) {
  814. return(0);
  815. }
  816. /* Call the function that really gets the job done. */
  817. if (f == DD_ONE(dd)) {
  818. err = appendStringStringStream(stream, "true");
  819. if (err) {
  820. deleteStringStream(stream);
  821. return(0);
  822. }
  823. } else if (f == Cudd_Not(DD_ONE(dd)) || f == DD_ZERO(dd)) {
  824. err = appendStringStringStream(stream, "false");
  825. if (err) {
  826. deleteStringStream(stream);
  827. return(0);
  828. }
  829. } else {
  830. err = appendStringStringStream(
  831. stream, Cudd_IsComplement(f) ?
  832. (Cudd_bddIsVar(dd, Cudd_Regular(f)) ? "!" : "!(") : "");
  833. if (err) {
  834. deleteStringStream(stream);
  835. return(0);
  836. }
  837. retval = ddDoFactoredFormString(dd,Cudd_Regular(f),stream,inames);
  838. if (retval == 0) {
  839. deleteStringStream(stream);
  840. return(0);
  841. }
  842. err = appendStringStringStream(
  843. stream, Cudd_IsComplement(f) &&
  844. !Cudd_bddIsVar(dd, Cudd_Regular(f)) ? ")" : "");
  845. if (err) {
  846. deleteStringStream(stream);
  847. return(0);
  848. }
  849. }
  850. str = stringFromStringStream(stream);
  851. deleteStringStream(stream);
  852. return(str);
  853. } /* end of Cudd_FactoredFormString */
  854. /*---------------------------------------------------------------------------*/
  855. /* Definition of internal functions */
  856. /*---------------------------------------------------------------------------*/
  857. /*---------------------------------------------------------------------------*/
  858. /* Definition of static functions */
  859. /*---------------------------------------------------------------------------*/
  860. /**
  861. @brief Performs the recursive step of Cudd_DumpBlif.
  862. @details Traverses the %BDD f and writes a multiplexer-network
  863. description to the file pointed by fp in blif format. f is assumed
  864. to be a regular pointer and ddDoDumpBlif guarantees this assumption
  865. in the recursive calls.
  866. @sideeffect None
  867. */
  868. static int
  869. ddDoDumpBlif(
  870. DdManager * dd,
  871. DdNode * f,
  872. FILE * fp,
  873. st_table * visited,
  874. char const * const * names,
  875. int mv)
  876. {
  877. DdNode *T, *E;
  878. int retval;
  879. #ifdef DD_DEBUG
  880. assert(!Cudd_IsComplement(f));
  881. #endif
  882. /* If already visited, nothing to do. */
  883. if (st_is_member(visited, f) == 1)
  884. return(1);
  885. /* Check for abnormal condition that should never happen. */
  886. if (f == NULL)
  887. return(0);
  888. /* Mark node as visited. */
  889. if (st_insert(visited, f, NULL) == ST_OUT_OF_MEM)
  890. return(0);
  891. /* Check for special case: If constant node, generate constant 1. */
  892. if (f == DD_ONE(dd)) {
  893. retval = fprintf(fp, ".names %" PRIxPTR "\n1\n",(ptruint) f / (ptruint) sizeof(DdNode));
  894. if (retval == EOF) {
  895. return(0);
  896. } else {
  897. return(1);
  898. }
  899. }
  900. /* Check whether this is an ADD. We deal with 0-1 ADDs, but not
  901. ** with the general case.
  902. */
  903. if (f == DD_ZERO(dd)) {
  904. retval = fprintf(fp, ".names %" PRIxPTR "\n%s",
  905. (ptruint) f / (ptruint) sizeof(DdNode),
  906. mv ? "0\n" : "");
  907. if (retval == EOF) {
  908. return(0);
  909. } else {
  910. return(1);
  911. }
  912. }
  913. if (cuddIsConstant(f))
  914. return(0);
  915. /* Recursive calls. */
  916. T = cuddT(f);
  917. retval = ddDoDumpBlif(dd,T,fp,visited,names,mv);
  918. if (retval != 1) return(retval);
  919. E = Cudd_Regular(cuddE(f));
  920. retval = ddDoDumpBlif(dd,E,fp,visited,names,mv);
  921. if (retval != 1) return(retval);
  922. /* Write multiplexer taking complement arc into account. */
  923. if (names != NULL) {
  924. retval = fprintf(fp,".names %s", names[f->index]);
  925. } else {
  926. #if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
  927. retval = fprintf(fp,".names %u", f->index);
  928. #else
  929. retval = fprintf(fp,".names %hu", f->index);
  930. #endif
  931. }
  932. if (retval == EOF)
  933. return(0);
  934. if (mv) {
  935. if (Cudd_IsComplement(cuddE(f))) {
  936. retval = fprintf(fp," %" PRIxPTR " %" PRIxPTR " %" PRIxPTR "\n.def 0\n1 1 - 1\n0 - 0 1\n",
  937. (ptruint) T / (ptruint) sizeof(DdNode),
  938. (ptruint) E / (ptruint) sizeof(DdNode),
  939. (ptruint) f / (ptruint) sizeof(DdNode));
  940. } else {
  941. retval = fprintf(fp," %" PRIxPTR " %" PRIxPTR " %" PRIxPTR "\n.def 0\n1 1 - 1\n0 - 1 1\n",
  942. (ptruint) T / (ptruint) sizeof(DdNode),
  943. (ptruint) E / (ptruint) sizeof(DdNode),
  944. (ptruint) f / (ptruint) sizeof(DdNode));
  945. }
  946. } else {
  947. if (Cudd_IsComplement(cuddE(f))) {
  948. retval = fprintf(fp," %" PRIxPTR " %" PRIxPTR " %" PRIxPTR "\n11- 1\n0-0 1\n",
  949. (ptruint) T / (ptruint) sizeof(DdNode),
  950. (ptruint) E / (ptruint) sizeof(DdNode),
  951. (ptruint) f / (ptruint) sizeof(DdNode));
  952. } else {
  953. retval = fprintf(fp," %" PRIxPTR " %" PRIxPTR " %" PRIxPTR "\n11- 1\n0-1 1\n",
  954. (ptruint) T / (ptruint) sizeof(DdNode),
  955. (ptruint) E / (ptruint) sizeof(DdNode),
  956. (ptruint) f / (ptruint) sizeof(DdNode));
  957. }
  958. }
  959. if (retval == EOF) {
  960. return(0);
  961. } else {
  962. return(1);
  963. }
  964. } /* end of ddDoDumpBlif */
  965. /**
  966. @brief Performs the recursive step of Cudd_DumpDaVinci.
  967. @details Traverses the %BDD f and writes a term expression to the
  968. file pointed by fp in daVinci format. f is assumed to be a regular
  969. pointer and ddDoDumpDaVinci guarantees this assumption in the
  970. recursive calls.
  971. @sideeffect None
  972. */
  973. static int
  974. ddDoDumpDaVinci(
  975. DdManager * dd,
  976. DdNode * f,
  977. FILE * fp,
  978. st_table * visited,
  979. char const * const * names,
  980. ptruint mask)
  981. {
  982. DdNode *T, *E;
  983. int retval;
  984. ptruint id;
  985. #ifdef DD_DEBUG
  986. assert(!Cudd_IsComplement(f));
  987. #endif
  988. id = ((ptruint) f & mask) / sizeof(DdNode);
  989. /* If already visited, insert a reference. */
  990. if (st_is_member(visited, f) == 1) {
  991. retval = fprintf(fp,"r(\"%#" PRIxPTR "\")", id);
  992. if (retval == EOF) {
  993. return(0);
  994. } else {
  995. return(1);
  996. }
  997. }
  998. /* Check for abnormal condition that should never happen. */
  999. if (f == NULL)
  1000. return(0);
  1001. /* Mark node as visited. */
  1002. if (st_insert(visited, f, NULL) == ST_OUT_OF_MEM)
  1003. return(0);
  1004. /* Check for special case: If constant node, generate constant 1. */
  1005. if (Cudd_IsConstantInt(f)) {
  1006. retval = fprintf(fp,
  1007. "l(\"%#" PRIxPTR
  1008. "\",n(\"constant\",[a(\"OBJECT\",\"%g\")],[]))",
  1009. id, cuddV(f));
  1010. if (retval == EOF) {
  1011. return(0);
  1012. } else {
  1013. return(1);
  1014. }
  1015. }
  1016. /* Recursive calls. */
  1017. if (names != NULL) {
  1018. retval = fprintf(fp, "l(\"%#" PRIxPTR
  1019. "\",n(\"internal\",[a(\"OBJECT\",\"%s\"),",
  1020. id, names[f->index]);
  1021. } else {
  1022. #if SIZEOF_VOID_P == 8
  1023. retval = fprintf(fp, "l(\"%#" PRIxPTR
  1024. "\",n(\"internal\",[a(\"OBJECT\",\"%u\"),",
  1025. id, f->index);
  1026. #else
  1027. retval = fprintf(fp, "l(\"%#"PRIxPTR
  1028. "\",n(\"internal\",[a(\"OBJECT\",\"%hu\"),",
  1029. id, f->index);
  1030. #endif
  1031. }
  1032. if (retval == EOF) return(0);
  1033. retval = fprintf(fp, "a(\"_GO\",\"ellipse\")],[e(\"then\",[a(\"EDGECOLOR\",\"blue\"),a(\"_DIR\",\"none\")],");
  1034. if (retval == EOF) return(0);
  1035. T = cuddT(f);
  1036. retval = ddDoDumpDaVinci(dd,T,fp,visited,names,mask);
  1037. if (retval != 1) return(retval);
  1038. retval = fprintf(fp, "),e(\"else\",[a(\"EDGECOLOR\",\"%s\"),a(\"_DIR\",\"none\")],",
  1039. Cudd_IsComplement(cuddE(f)) ? "red" : "green");
  1040. if (retval == EOF) return(0);
  1041. E = Cudd_Regular(cuddE(f));
  1042. retval = ddDoDumpDaVinci(dd,E,fp,visited,names,mask);
  1043. if (retval != 1) return(retval);
  1044. retval = fprintf(fp,")]))");
  1045. if (retval == EOF) {
  1046. return(0);
  1047. } else {
  1048. return(1);
  1049. }
  1050. } /* end of ddDoDumpDaVinci */
  1051. /**
  1052. @brief Performs the recursive step of Cudd_DumpDDcal.
  1053. @details Traverses the %BDD f and writes a line for each node to the
  1054. file pointed by fp in DDcal format. f is assumed to be a regular
  1055. pointer and ddDoDumpDDcal guarantees this assumption in the
  1056. recursive calls.
  1057. @sideeffect None
  1058. */
  1059. static int
  1060. ddDoDumpDDcal(
  1061. DdManager * dd,
  1062. DdNode * f,
  1063. FILE * fp,
  1064. st_table * visited,
  1065. char const * const * names,
  1066. ptruint mask)
  1067. {
  1068. DdNode *T, *E;
  1069. int retval;
  1070. ptruint id, idT, idE;
  1071. #ifdef DD_DEBUG
  1072. assert(!Cudd_IsComplement(f));
  1073. #endif
  1074. id = ((ptruint) f & mask) / sizeof(DdNode);
  1075. /* If already visited, do nothing. */
  1076. if (st_is_member(visited, f) == 1) {
  1077. return(1);
  1078. }
  1079. /* Check for abnormal condition that should never happen. */
  1080. if (f == NULL)
  1081. return(0);
  1082. /* Mark node as visited. */
  1083. if (st_insert(visited, f, NULL) == ST_OUT_OF_MEM)
  1084. return(0);
  1085. /* Check for special case: If constant node, assign constant. */
  1086. if (Cudd_IsConstantInt(f)) {
  1087. if (f != DD_ONE(dd) && f != DD_ZERO(dd))
  1088. return(0);
  1089. retval = fprintf(fp, "n%#" PRIxPTR" = %g\n", id, cuddV(f));
  1090. if (retval == EOF) {
  1091. return(0);
  1092. } else {
  1093. return(1);
  1094. }
  1095. }
  1096. /* Recursive calls. */
  1097. T = cuddT(f);
  1098. retval = ddDoDumpDDcal(dd,T,fp,visited,names,mask);
  1099. if (retval != 1) return(retval);
  1100. E = Cudd_Regular(cuddE(f));
  1101. retval = ddDoDumpDDcal(dd,E,fp,visited,names,mask);
  1102. if (retval != 1) return(retval);
  1103. idT = ((ptruint) T & mask) / sizeof(DdNode);
  1104. idE = ((ptruint) E & mask) / sizeof(DdNode);
  1105. if (names != NULL) {
  1106. retval = fprintf(fp, "n%#" PRIxPTR " = %s * n%#" PRIxPTR
  1107. " + %s' * n%#" PRIxPTR "%s\n",
  1108. id, names[f->index], idT, names[f->index],
  1109. idE, Cudd_IsComplement(cuddE(f)) ? "'" : "");
  1110. } else {
  1111. #if SIZEOF_VOID_P == 8
  1112. retval = fprintf(fp, "n%#" PRIxPTR " = v%u * n%#" PRIxPTR
  1113. " + v%u' * n%#" PRIxPTR "%s\n",
  1114. id, f->index, idT, f->index,
  1115. idE, Cudd_IsComplement(cuddE(f)) ? "'" : "");
  1116. #else
  1117. retval = fprintf(fp, "n%#"PRIxPTR" = v%hu * n%#"PRIxPTR
  1118. " + v%hu' * n%#"PRIxPTR"%s\n",
  1119. id, f->index, idT, f->index,
  1120. idE, Cudd_IsComplement(cuddE(f)) ? "'" : "");
  1121. #endif
  1122. }
  1123. if (retval == EOF) {
  1124. return(0);
  1125. } else {
  1126. return(1);
  1127. }
  1128. } /* end of ddDoDumpDDcal */
  1129. /**
  1130. @brief Performs the recursive step of Cudd_DumpFactoredForm.
  1131. @details Traverses the %BDD f and writes a factored form for each
  1132. node to the file pointed by fp in terms of the factored forms of the
  1133. children. Constants are propagated, and absorption is applied. f is
  1134. assumed to be a regular pointer and ddDoDumpFActoredForm guarantees
  1135. this assumption in the recursive calls.
  1136. @sideeffect None
  1137. @see Cudd_DumpFactoredForm
  1138. */
  1139. static int
  1140. ddDoDumpFactoredForm(
  1141. DdManager * dd,
  1142. DdNode * f,
  1143. FILE * fp,
  1144. char const * const * names)
  1145. {
  1146. DdNode *T, *E;
  1147. int retval;
  1148. #ifdef DD_DEBUG
  1149. assert(!Cudd_IsComplement(f));
  1150. assert(!cuddIsConstant(f));
  1151. #endif
  1152. /* Check for abnormal condition that should never happen. */
  1153. if (f == NULL)
  1154. return(0);
  1155. /* Recursive calls. */
  1156. T = cuddT(f);
  1157. E = cuddE(f);
  1158. if (T != DD_ZERO(dd)) {
  1159. if (E != DD_ONE(dd)) {
  1160. if (names != NULL) {
  1161. retval = fprintf(fp, "%s", names[f->index]);
  1162. } else {
  1163. #if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
  1164. retval = fprintf(fp, "x%u", f->index);
  1165. #else
  1166. retval = fprintf(fp, "x%hu", f->index);
  1167. #endif
  1168. }
  1169. if (retval == EOF) return(0);
  1170. }
  1171. if (T != DD_ONE(dd)) {
  1172. // retval = fprintf(fp, "%s(", E != DD_ONE(dd) ? " * " : "");
  1173. retval = fprintf(fp, "%s%s", E != DD_ONE(dd) ? " * " : "", Cudd_bddIsVar(dd, T) ? "" : "(");
  1174. if (retval == EOF) return(0);
  1175. retval = ddDoDumpFactoredForm(dd,T,fp,names);
  1176. if (retval != 1) return(retval);
  1177. retval = fprintf(fp, "%s", Cudd_bddIsVar(dd, T) ? "" : ")");
  1178. if (retval == EOF) return(0);
  1179. }
  1180. if (E == Cudd_Not(DD_ONE(dd)) || E == DD_ZERO(dd)) return(1);
  1181. retval = fprintf(fp, " + ");
  1182. if (retval == EOF) return(0);
  1183. }
  1184. E = Cudd_Regular(E);
  1185. if (T != DD_ONE(dd)) {
  1186. if (names != NULL) {
  1187. retval = fprintf(fp, "!%s", names[f->index]);
  1188. } else {
  1189. #if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
  1190. retval = fprintf(fp, "!x%u", f->index);
  1191. #else
  1192. retval = fprintf(fp, "!x%hu", f->index);
  1193. #endif
  1194. }
  1195. if (retval == EOF) return(0);
  1196. }
  1197. if (E != DD_ONE(dd)) {
  1198. retval = fprintf(fp, "%s%s%s", T != DD_ONE(dd) ? " * " : "",
  1199. E != cuddE(f) ? "!" : "", Cudd_bddIsVar(dd, E) ? "" : "(");
  1200. if (retval == EOF) return(0);
  1201. retval = ddDoDumpFactoredForm(dd,E,fp,names);
  1202. if (retval != 1) return(retval);
  1203. retval = fprintf(fp, "%s", Cudd_bddIsVar(dd, E) ? "" : "(");
  1204. if (retval == EOF) return(0);
  1205. }
  1206. return(1);
  1207. } /* end of ddDoDumpFactoredForm */
  1208. /**
  1209. @brief Performs the recursive step of Cudd_DumpFactoredForm.
  1210. @details Traverses the %BDD f and writes a factored form for each
  1211. node to the file pointed by fp in terms of the factored forms of the
  1212. children. Constants are propagated, and absorption is applied. f is
  1213. assumed to be a regular pointer and ddDoDumpFActoredForm guarantees
  1214. this assumption in the recursive calls.
  1215. @sideeffect None
  1216. @see Cudd_DumpFactoredForm
  1217. */
  1218. static int
  1219. ddDoFactoredFormString(
  1220. DdManager * dd,
  1221. DdNode * f,
  1222. cstringstream stream,
  1223. char const * const * names)
  1224. {
  1225. DdNode *T, *E;
  1226. int retval, err;
  1227. #ifdef DD_DEBUG
  1228. assert(!Cudd_IsComplement(f));
  1229. assert(!cuddIsConstant(f));
  1230. #endif
  1231. /* Check for abnormal condition that should never happen. */
  1232. if (f == NULL)
  1233. return(0);
  1234. /* Recursive calls. */
  1235. T = cuddT(f);
  1236. E = cuddE(f);
  1237. if (T != DD_ZERO(dd)) {
  1238. if (E != DD_ONE(dd)) {
  1239. if (names != NULL) {
  1240. err = appendStringStringStream(stream, names[f->index]);
  1241. } else {
  1242. err = appendCharStringStream(stream, 'x');
  1243. if (err) return(0);
  1244. err = appendUnsignedStringStream(stream, (unsigned) f->index);
  1245. }
  1246. if (err) return(0);
  1247. }
  1248. if (T != DD_ONE(dd)) {
  1249. err = appendStringStringStream(stream, E != DD_ONE(dd) ? " & " : "");
  1250. if (err) return(0);
  1251. err = appendStringStringStream(stream, Cudd_bddIsVar(dd, T) ? "" : "(");
  1252. if (err) return(0);
  1253. retval = ddDoFactoredFormString(dd,T,stream,names);
  1254. if (retval != 1) return(retval);
  1255. err = appendStringStringStream(stream, Cudd_bddIsVar(dd, T) ? "" : ")");
  1256. if (err) return(0);
  1257. }
  1258. if (E == Cudd_Not(DD_ONE(dd)) || E == DD_ZERO(dd)) return(1);
  1259. err = appendStringStringStream(stream, " | ");
  1260. if (err) return(0);
  1261. }
  1262. E = Cudd_Regular(E);
  1263. if (T != DD_ONE(dd)) {
  1264. err = appendCharStringStream(stream, '!');
  1265. if (err) return(0);
  1266. if (names != NULL) {
  1267. err = appendStringStringStream(stream, names[f->index]);
  1268. } else {
  1269. err = appendCharStringStream(stream, 'x');
  1270. if (err) return(0);
  1271. err = appendUnsignedStringStream(stream, (unsigned) f->index);
  1272. }
  1273. if (err) return(0);
  1274. }
  1275. if (E != DD_ONE(dd)) {
  1276. err = appendStringStringStream(stream, T != DD_ONE(dd) ? " & " : "");
  1277. if (err) return(0);
  1278. err = appendStringStringStream(stream, E != cuddE(f) ? "!" : "");
  1279. if (err) return(0);
  1280. err = appendStringStringStream(stream, Cudd_bddIsVar(dd, E) ? "" : "(");
  1281. if (err) return(0);
  1282. retval = ddDoFactoredFormString(dd,E,stream,names);
  1283. if (retval != 1) return(retval);
  1284. err = appendStringStringStream(stream, Cudd_bddIsVar(dd, E) ? "" : ")");
  1285. if (err) return(0);
  1286. }
  1287. return(1);
  1288. } /* end of ddDoFactoredFormString */