emergency commit
[cl-cudd.git] / distr / cudd / cuddSubsetHB.c
blob43713fe2bc642bc461fe4767cb1aeba57150e22e
1 /**CFile***********************************************************************
3 FileName [cuddSubsetHB.c]
5 PackageName [cudd]
7 Synopsis [Procedure to subset the given BDD by choosing the heavier
8 branches.]
11 Description [External procedures provided by this module:
12 <ul>
13 <li> Cudd_SubsetHeavyBranch()
14 <li> Cudd_SupersetHeavyBranch()
15 </ul>
16 Internal procedures included in this module:
17 <ul>
18 <li> cuddSubsetHeavyBranch()
19 </ul>
20 Static procedures included in this module:
21 <ul>
22 <li> ResizeCountMintermPages();
23 <li> ResizeNodeDataPages()
24 <li> ResizeCountNodePages()
25 <li> SubsetCountMintermAux()
26 <li> SubsetCountMinterm()
27 <li> SubsetCountNodesAux()
28 <li> SubsetCountNodes()
29 <li> BuildSubsetBdd()
30 </ul>
33 SeeAlso [cuddSubsetSP.c]
35 Author [Kavita Ravi]
37 Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado
39 All rights reserved.
41 Redistribution and use in source and binary forms, with or without
42 modification, are permitted provided that the following conditions
43 are met:
45 Redistributions of source code must retain the above copyright
46 notice, this list of conditions and the following disclaimer.
48 Redistributions in binary form must reproduce the above copyright
49 notice, this list of conditions and the following disclaimer in the
50 documentation and/or other materials provided with the distribution.
52 Neither the name of the University of Colorado nor the names of its
53 contributors may be used to endorse or promote products derived from
54 this software without specific prior written permission.
56 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
57 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
58 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
59 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
60 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
61 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
62 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
63 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
64 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
66 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
67 POSSIBILITY OF SUCH DAMAGE.]
69 ******************************************************************************/
71 #ifdef __STDC__
72 #include <float.h>
73 #else
74 #define DBL_MAX_EXP 1024
75 #endif
76 #include "util.h"
77 #include "cuddInt.h"
79 /*---------------------------------------------------------------------------*/
80 /* Constant declarations */
81 /*---------------------------------------------------------------------------*/
83 #define DEFAULT_PAGE_SIZE 2048
84 #define DEFAULT_NODE_DATA_PAGE_SIZE 1024
85 #define INITIAL_PAGES 128
88 /*---------------------------------------------------------------------------*/
89 /* Stucture declarations */
90 /*---------------------------------------------------------------------------*/
92 /* data structure to store the information on each node. It keeps
93 * the number of minterms represented by the DAG rooted at this node
94 * in terms of the number of variables specified by the user, number
95 * of nodes in this DAG and the number of nodes of its child with
96 * lesser number of minterms that are not shared by the child with
97 * more minterms
99 struct NodeData {
100 double *mintermPointer;
101 int *nodesPointer;
102 int *lightChildNodesPointer;
105 /*---------------------------------------------------------------------------*/
106 /* Type declarations */
107 /*---------------------------------------------------------------------------*/
109 typedef struct NodeData NodeData_t;
111 /*---------------------------------------------------------------------------*/
112 /* Variable declarations */
113 /*---------------------------------------------------------------------------*/
115 #ifndef lint
116 static char rcsid[] DD_UNUSED = "$Id: cuddSubsetHB.c,v 1.37 2009/02/20 02:14:58 fabio Exp $";
117 #endif
119 static int memOut;
120 #ifdef DEBUG
121 static int num_calls;
122 #endif
124 static DdNode *zero, *one; /* constant functions */
125 static double **mintermPages; /* pointers to the pages */
126 static int **nodePages; /* pointers to the pages */
127 static int **lightNodePages; /* pointers to the pages */
128 static double *currentMintermPage; /* pointer to the current
129 page */
130 static double max; /* to store the 2^n value of the number
131 * of variables */
133 static int *currentNodePage; /* pointer to the current
134 page */
135 static int *currentLightNodePage; /* pointer to the
136 * current page */
137 static int pageIndex; /* index to next element */
138 static int page; /* index to current page */
139 static int pageSize = DEFAULT_PAGE_SIZE; /* page size */
140 static int maxPages; /* number of page pointers */
142 static NodeData_t *currentNodeDataPage; /* pointer to the current
143 page */
144 static int nodeDataPage; /* index to next element */
145 static int nodeDataPageIndex; /* index to next element */
146 static NodeData_t **nodeDataPages; /* index to current page */
147 static int nodeDataPageSize = DEFAULT_NODE_DATA_PAGE_SIZE;
148 /* page size */
149 static int maxNodeDataPages; /* number of page pointers */
152 /*---------------------------------------------------------------------------*/
153 /* Macro declarations */
154 /*---------------------------------------------------------------------------*/
156 /**AutomaticStart*************************************************************/
158 /*---------------------------------------------------------------------------*/
159 /* Static function prototypes */
160 /*---------------------------------------------------------------------------*/
162 static void ResizeNodeDataPages (void);
163 static void ResizeCountMintermPages (void);
164 static void ResizeCountNodePages (void);
165 static double SubsetCountMintermAux (DdNode *node, double max, st_table *table);
166 static st_table * SubsetCountMinterm (DdNode *node, int nvars);
167 static int SubsetCountNodesAux (DdNode *node, st_table *table, double max);
168 static int SubsetCountNodes (DdNode *node, st_table *table, int nvars);
169 static void StoreNodes (st_table *storeTable, DdManager *dd, DdNode *node);
170 static DdNode * BuildSubsetBdd (DdManager *dd, DdNode *node, int *size, st_table *visitedTable, int threshold, st_table *storeTable, st_table *approxTable);
172 /**AutomaticEnd***************************************************************/
175 /*---------------------------------------------------------------------------*/
176 /* Definition of exported functions */
177 /*---------------------------------------------------------------------------*/
179 /**Function********************************************************************
181 Synopsis [Extracts a dense subset from a BDD with the heavy branch
182 heuristic.]
184 Description [Extracts a dense subset from a BDD. This procedure
185 builds a subset by throwing away one of the children of each node,
186 starting from the root, until the result is small enough. The child
187 that is eliminated from the result is the one that contributes the
188 fewer minterms. Returns a pointer to the BDD of the subset if
189 successful. NULL if the procedure runs out of memory. The parameter
190 numVars is the maximum number of variables to be used in minterm
191 calculation and node count calculation. The optimal number should
192 be as close as possible to the size of the support of f. However,
193 it is safe to pass the value returned by Cudd_ReadSize for numVars
194 when the number of variables is under 1023. If numVars is larger
195 than 1023, it will overflow. If a 0 parameter is passed then the
196 procedure will compute a value which will avoid overflow but will
197 cause underflow with 2046 variables or more.]
199 SideEffects [None]
201 SeeAlso [Cudd_SubsetShortPaths Cudd_SupersetHeavyBranch Cudd_ReadSize]
203 ******************************************************************************/
204 DdNode *
205 Cudd_SubsetHeavyBranch(
206 DdManager * dd /* manager */,
207 DdNode * f /* function to be subset */,
208 int numVars /* number of variables in the support of f */,
209 int threshold /* maximum number of nodes in the subset */)
211 DdNode *subset;
213 memOut = 0;
214 do {
215 dd->reordered = 0;
216 subset = cuddSubsetHeavyBranch(dd, f, numVars, threshold);
217 } while ((dd->reordered == 1) && (!memOut));
219 return(subset);
221 } /* end of Cudd_SubsetHeavyBranch */
224 /**Function********************************************************************
226 Synopsis [Extracts a dense superset from a BDD with the heavy branch
227 heuristic.]
229 Description [Extracts a dense superset from a BDD. The procedure is
230 identical to the subset procedure except for the fact that it
231 receives the complement of the given function. Extracting the subset
232 of the complement function is equivalent to extracting the superset
233 of the function. This procedure builds a superset by throwing away
234 one of the children of each node starting from the root of the
235 complement function, until the result is small enough. The child
236 that is eliminated from the result is the one that contributes the
237 fewer minterms.
238 Returns a pointer to the BDD of the superset if successful. NULL if
239 intermediate result causes the procedure to run out of memory. The
240 parameter numVars is the maximum number of variables to be used in
241 minterm calculation and node count calculation. The optimal number
242 should be as close as possible to the size of the support of f.
243 However, it is safe to pass the value returned by Cudd_ReadSize for
244 numVars when the number of variables is under 1023. If numVars is
245 larger than 1023, it will overflow. If a 0 parameter is passed then
246 the procedure will compute a value which will avoid overflow but
247 will cause underflow with 2046 variables or more.]
249 SideEffects [None]
251 SeeAlso [Cudd_SubsetHeavyBranch Cudd_SupersetShortPaths Cudd_ReadSize]
253 ******************************************************************************/
254 DdNode *
255 Cudd_SupersetHeavyBranch(
256 DdManager * dd /* manager */,
257 DdNode * f /* function to be superset */,
258 int numVars /* number of variables in the support of f */,
259 int threshold /* maximum number of nodes in the superset */)
261 DdNode *subset, *g;
263 g = Cudd_Not(f);
264 memOut = 0;
265 do {
266 dd->reordered = 0;
267 subset = cuddSubsetHeavyBranch(dd, g, numVars, threshold);
268 } while ((dd->reordered == 1) && (!memOut));
270 return(Cudd_NotCond(subset, (subset != NULL)));
272 } /* end of Cudd_SupersetHeavyBranch */
275 /*---------------------------------------------------------------------------*/
276 /* Definition of internal functions */
277 /*---------------------------------------------------------------------------*/
280 /**Function********************************************************************
282 Synopsis [The main procedure that returns a subset by choosing the heavier
283 branch in the BDD.]
285 Description [Here a subset BDD is built by throwing away one of the
286 children. Starting at root, annotate each node with the number of
287 minterms (in terms of the total number of variables specified -
288 numVars), number of nodes taken by the DAG rooted at this node and
289 number of additional nodes taken by the child that has the lesser
290 minterms. The child with the lower number of minterms is thrown away
291 and a dyanmic count of the nodes of the subset is kept. Once the
292 threshold is reached the subset is returned to the calling
293 procedure.]
295 SideEffects [None]
297 SeeAlso [Cudd_SubsetHeavyBranch]
299 ******************************************************************************/
300 DdNode *
301 cuddSubsetHeavyBranch(
302 DdManager * dd /* DD manager */,
303 DdNode * f /* current DD */,
304 int numVars /* maximum number of variables */,
305 int threshold /* threshold size for the subset */)
308 int i, *size;
309 st_table *visitedTable;
310 int numNodes;
311 NodeData_t *currNodeQual;
312 DdNode *subset;
313 st_table *storeTable, *approxTable;
314 char *key, *value;
315 st_generator *stGen;
317 if (f == NULL) {
318 fprintf(dd->err, "Cannot subset, nil object\n");
319 dd->errorCode = CUDD_INVALID_ARG;
320 return(NULL);
323 one = Cudd_ReadOne(dd);
324 zero = Cudd_Not(one);
326 /* If user does not know numVars value, set it to the maximum
327 * exponent that the pow function can take. The -1 is due to the
328 * discrepancy in the value that pow takes and the value that
329 * log gives.
331 if (numVars == 0) {
332 /* set default value */
333 numVars = DBL_MAX_EXP - 1;
336 if (Cudd_IsConstant(f)) {
337 return(f);
340 max = pow(2.0, (double)numVars);
342 /* Create visited table where structures for node data are allocated and
343 stored in a st_table */
344 visitedTable = SubsetCountMinterm(f, numVars);
345 if ((visitedTable == NULL) || memOut) {
346 (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
347 dd->errorCode = CUDD_MEMORY_OUT;
348 return(0);
350 numNodes = SubsetCountNodes(f, visitedTable, numVars);
351 if (memOut) {
352 (void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
353 dd->errorCode = CUDD_MEMORY_OUT;
354 return(0);
357 if (st_lookup(visitedTable, f, &currNodeQual) == 0) {
358 fprintf(dd->err,
359 "Something is wrong, ought to be node quality table\n");
360 dd->errorCode = CUDD_INTERNAL_ERROR;
363 size = ALLOC(int, 1);
364 if (size == NULL) {
365 dd->errorCode = CUDD_MEMORY_OUT;
366 return(NULL);
368 *size = numNodes;
370 #ifdef DEBUG
371 num_calls = 0;
372 #endif
373 /* table to store nodes being created. */
374 storeTable = st_init_table(st_ptrcmp, st_ptrhash);
375 /* insert the constant */
376 cuddRef(one);
377 if (st_insert(storeTable, (char *)Cudd_ReadOne(dd), NIL(char)) ==
378 ST_OUT_OF_MEM) {
379 fprintf(dd->out, "Something wrong, st_table insert failed\n");
381 /* table to store approximations of nodes */
382 approxTable = st_init_table(st_ptrcmp, st_ptrhash);
383 subset = (DdNode *)BuildSubsetBdd(dd, f, size, visitedTable, threshold,
384 storeTable, approxTable);
385 if (subset != NULL) {
386 cuddRef(subset);
389 stGen = st_init_gen(approxTable);
390 if (stGen == NULL) {
391 st_free_table(approxTable);
392 return(NULL);
394 while(st_gen(stGen, (char **)&key, (char **)&value)) {
395 Cudd_RecursiveDeref(dd, (DdNode *)value);
397 st_free_gen(stGen); stGen = NULL;
398 st_free_table(approxTable);
400 stGen = st_init_gen(storeTable);
401 if (stGen == NULL) {
402 st_free_table(storeTable);
403 return(NULL);
405 while(st_gen(stGen, (char **)&key, (char **)&value)) {
406 Cudd_RecursiveDeref(dd, (DdNode *)key);
408 st_free_gen(stGen); stGen = NULL;
409 st_free_table(storeTable);
411 for (i = 0; i <= page; i++) {
412 FREE(mintermPages[i]);
414 FREE(mintermPages);
415 for (i = 0; i <= page; i++) {
416 FREE(nodePages[i]);
418 FREE(nodePages);
419 for (i = 0; i <= page; i++) {
420 FREE(lightNodePages[i]);
422 FREE(lightNodePages);
423 for (i = 0; i <= nodeDataPage; i++) {
424 FREE(nodeDataPages[i]);
426 FREE(nodeDataPages);
427 st_free_table(visitedTable);
428 FREE(size);
429 #if 0
430 (void) Cudd_DebugCheck(dd);
431 (void) Cudd_CheckKeys(dd);
432 #endif
434 if (subset != NULL) {
435 #ifdef DD_DEBUG
436 if (!Cudd_bddLeq(dd, subset, f)) {
437 fprintf(dd->err, "Wrong subset\n");
438 dd->errorCode = CUDD_INTERNAL_ERROR;
439 return(NULL);
441 #endif
442 cuddDeref(subset);
443 return(subset);
444 } else {
445 return(NULL);
447 } /* end of cuddSubsetHeavyBranch */
450 /*---------------------------------------------------------------------------*/
451 /* Definition of static functions */
452 /*---------------------------------------------------------------------------*/
455 /**Function********************************************************************
457 Synopsis [Resize the number of pages allocated to store the node data.]
459 Description [Resize the number of pages allocated to store the node data
460 The procedure moves the counter to the next page when the end of
461 the page is reached and allocates new pages when necessary.]
463 SideEffects [Changes the size of pages, page, page index, maximum
464 number of pages freeing stuff in case of memory out. ]
466 SeeAlso []
468 ******************************************************************************/
469 static void
470 ResizeNodeDataPages(void)
472 int i;
473 NodeData_t **newNodeDataPages;
475 nodeDataPage++;
476 /* If the current page index is larger than the number of pages
477 * allocated, allocate a new page array. Page numbers are incremented by
478 * INITIAL_PAGES
480 if (nodeDataPage == maxNodeDataPages) {
481 newNodeDataPages = ALLOC(NodeData_t *,maxNodeDataPages + INITIAL_PAGES);
482 if (newNodeDataPages == NULL) {
483 for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
484 FREE(nodeDataPages);
485 memOut = 1;
486 return;
487 } else {
488 for (i = 0; i < maxNodeDataPages; i++) {
489 newNodeDataPages[i] = nodeDataPages[i];
491 /* Increase total page count */
492 maxNodeDataPages += INITIAL_PAGES;
493 FREE(nodeDataPages);
494 nodeDataPages = newNodeDataPages;
497 /* Allocate a new page */
498 currentNodeDataPage = nodeDataPages[nodeDataPage] =
499 ALLOC(NodeData_t ,nodeDataPageSize);
500 if (currentNodeDataPage == NULL) {
501 for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
502 FREE(nodeDataPages);
503 memOut = 1;
504 return;
506 /* reset page index */
507 nodeDataPageIndex = 0;
508 return;
510 } /* end of ResizeNodeDataPages */
513 /**Function********************************************************************
515 Synopsis [Resize the number of pages allocated to store the minterm
516 counts. ]
518 Description [Resize the number of pages allocated to store the minterm
519 counts. The procedure moves the counter to the next page when the
520 end of the page is reached and allocates new pages when necessary.]
522 SideEffects [Changes the size of minterm pages, page, page index, maximum
523 number of pages freeing stuff in case of memory out. ]
525 SeeAlso []
527 ******************************************************************************/
528 static void
529 ResizeCountMintermPages(void)
531 int i;
532 double **newMintermPages;
534 page++;
535 /* If the current page index is larger than the number of pages
536 * allocated, allocate a new page array. Page numbers are incremented by
537 * INITIAL_PAGES
539 if (page == maxPages) {
540 newMintermPages = ALLOC(double *,maxPages + INITIAL_PAGES);
541 if (newMintermPages == NULL) {
542 for (i = 0; i < page; i++) FREE(mintermPages[i]);
543 FREE(mintermPages);
544 memOut = 1;
545 return;
546 } else {
547 for (i = 0; i < maxPages; i++) {
548 newMintermPages[i] = mintermPages[i];
550 /* Increase total page count */
551 maxPages += INITIAL_PAGES;
552 FREE(mintermPages);
553 mintermPages = newMintermPages;
556 /* Allocate a new page */
557 currentMintermPage = mintermPages[page] = ALLOC(double,pageSize);
558 if (currentMintermPage == NULL) {
559 for (i = 0; i < page; i++) FREE(mintermPages[i]);
560 FREE(mintermPages);
561 memOut = 1;
562 return;
564 /* reset page index */
565 pageIndex = 0;
566 return;
568 } /* end of ResizeCountMintermPages */
571 /**Function********************************************************************
573 Synopsis [Resize the number of pages allocated to store the node counts.]
575 Description [Resize the number of pages allocated to store the node counts.
576 The procedure moves the counter to the next page when the end of
577 the page is reached and allocates new pages when necessary.]
579 SideEffects [Changes the size of pages, page, page index, maximum
580 number of pages freeing stuff in case of memory out.]
582 SeeAlso []
584 ******************************************************************************/
585 static void
586 ResizeCountNodePages(void)
588 int i;
589 int **newNodePages;
591 page++;
593 /* If the current page index is larger than the number of pages
594 * allocated, allocate a new page array. The number of pages is incremented
595 * by INITIAL_PAGES.
597 if (page == maxPages) {
598 newNodePages = ALLOC(int *,maxPages + INITIAL_PAGES);
599 if (newNodePages == NULL) {
600 for (i = 0; i < page; i++) FREE(nodePages[i]);
601 FREE(nodePages);
602 for (i = 0; i < page; i++) FREE(lightNodePages[i]);
603 FREE(lightNodePages);
604 memOut = 1;
605 return;
606 } else {
607 for (i = 0; i < maxPages; i++) {
608 newNodePages[i] = nodePages[i];
610 FREE(nodePages);
611 nodePages = newNodePages;
614 newNodePages = ALLOC(int *,maxPages + INITIAL_PAGES);
615 if (newNodePages == NULL) {
616 for (i = 0; i < page; i++) FREE(nodePages[i]);
617 FREE(nodePages);
618 for (i = 0; i < page; i++) FREE(lightNodePages[i]);
619 FREE(lightNodePages);
620 memOut = 1;
621 return;
622 } else {
623 for (i = 0; i < maxPages; i++) {
624 newNodePages[i] = lightNodePages[i];
626 FREE(lightNodePages);
627 lightNodePages = newNodePages;
629 /* Increase total page count */
630 maxPages += INITIAL_PAGES;
632 /* Allocate a new page */
633 currentNodePage = nodePages[page] = ALLOC(int,pageSize);
634 if (currentNodePage == NULL) {
635 for (i = 0; i < page; i++) FREE(nodePages[i]);
636 FREE(nodePages);
637 for (i = 0; i < page; i++) FREE(lightNodePages[i]);
638 FREE(lightNodePages);
639 memOut = 1;
640 return;
642 /* Allocate a new page */
643 currentLightNodePage = lightNodePages[page] = ALLOC(int,pageSize);
644 if (currentLightNodePage == NULL) {
645 for (i = 0; i <= page; i++) FREE(nodePages[i]);
646 FREE(nodePages);
647 for (i = 0; i < page; i++) FREE(lightNodePages[i]);
648 FREE(lightNodePages);
649 memOut = 1;
650 return;
652 /* reset page index */
653 pageIndex = 0;
654 return;
656 } /* end of ResizeCountNodePages */
659 /**Function********************************************************************
661 Synopsis [Recursively counts minterms of each node in the DAG.]
663 Description [Recursively counts minterms of each node in the DAG.
664 Similar to the cuddCountMintermAux which recursively counts the
665 number of minterms for the dag rooted at each node in terms of the
666 total number of variables (max). This procedure creates the node
667 data structure and stores the minterm count as part of the node
668 data structure. ]
670 SideEffects [Creates structures of type node quality and fills the st_table]
672 SeeAlso [SubsetCountMinterm]
674 ******************************************************************************/
675 static double
676 SubsetCountMintermAux(
677 DdNode * node /* function to analyze */,
678 double max /* number of minterms of constant 1 */,
679 st_table * table /* visitedTable table */)
682 DdNode *N,*Nv,*Nnv; /* nodes to store cofactors */
683 double min,*pmin; /* minterm count */
684 double min1, min2; /* minterm count */
685 NodeData_t *dummy;
686 NodeData_t *newEntry;
687 int i;
689 #ifdef DEBUG
690 num_calls++;
691 #endif
693 /* Constant case */
694 if (Cudd_IsConstant(node)) {
695 if (node == zero) {
696 return(0.0);
697 } else {
698 return(max);
700 } else {
702 /* check if entry for this node exists */
703 if (st_lookup(table, node, &dummy)) {
704 min = *(dummy->mintermPointer);
705 return(min);
708 /* Make the node regular to extract cofactors */
709 N = Cudd_Regular(node);
711 /* store the cofactors */
712 Nv = Cudd_T(N);
713 Nnv = Cudd_E(N);
715 Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
716 Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
718 min1 = SubsetCountMintermAux(Nv, max,table)/2.0;
719 if (memOut) return(0.0);
720 min2 = SubsetCountMintermAux(Nnv,max,table)/2.0;
721 if (memOut) return(0.0);
722 min = (min1+min2);
724 /* if page index is at the bottom, then create a new page */
725 if (pageIndex == pageSize) ResizeCountMintermPages();
726 if (memOut) {
727 for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
728 FREE(nodeDataPages);
729 st_free_table(table);
730 return(0.0);
733 /* point to the correct location in the page */
734 pmin = currentMintermPage+pageIndex;
735 pageIndex++;
737 /* store the minterm count of this node in the page */
738 *pmin = min;
740 /* Note I allocate the struct here. Freeing taken care of later */
741 if (nodeDataPageIndex == nodeDataPageSize) ResizeNodeDataPages();
742 if (memOut) {
743 for (i = 0; i <= page; i++) FREE(mintermPages[i]);
744 FREE(mintermPages);
745 st_free_table(table);
746 return(0.0);
749 newEntry = currentNodeDataPage + nodeDataPageIndex;
750 nodeDataPageIndex++;
752 /* points to the correct location in the page */
753 newEntry->mintermPointer = pmin;
754 /* initialize this field of the Node Quality structure */
755 newEntry->nodesPointer = NULL;
757 /* insert entry for the node in the table */
758 if (st_insert(table,(char *)node, (char *)newEntry) == ST_OUT_OF_MEM) {
759 memOut = 1;
760 for (i = 0; i <= page; i++) FREE(mintermPages[i]);
761 FREE(mintermPages);
762 for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
763 FREE(nodeDataPages);
764 st_free_table(table);
765 return(0.0);
767 return(min);
770 } /* end of SubsetCountMintermAux */
773 /**Function********************************************************************
775 Synopsis [Counts minterms of each node in the DAG]
777 Description [Counts minterms of each node in the DAG. Similar to the
778 Cudd_CountMinterm procedure except this returns the minterm count for
779 all the nodes in the bdd in an st_table.]
781 SideEffects [none]
783 SeeAlso [SubsetCountMintermAux]
785 ******************************************************************************/
786 static st_table *
787 SubsetCountMinterm(
788 DdNode * node /* function to be analyzed */,
789 int nvars /* number of variables node depends on */)
791 st_table *table;
792 int i;
795 #ifdef DEBUG
796 num_calls = 0;
797 #endif
799 max = pow(2.0,(double) nvars);
800 table = st_init_table(st_ptrcmp,st_ptrhash);
801 if (table == NULL) goto OUT_OF_MEM;
802 maxPages = INITIAL_PAGES;
803 mintermPages = ALLOC(double *,maxPages);
804 if (mintermPages == NULL) {
805 st_free_table(table);
806 goto OUT_OF_MEM;
808 page = 0;
809 currentMintermPage = ALLOC(double,pageSize);
810 mintermPages[page] = currentMintermPage;
811 if (currentMintermPage == NULL) {
812 FREE(mintermPages);
813 st_free_table(table);
814 goto OUT_OF_MEM;
816 pageIndex = 0;
817 maxNodeDataPages = INITIAL_PAGES;
818 nodeDataPages = ALLOC(NodeData_t *, maxNodeDataPages);
819 if (nodeDataPages == NULL) {
820 for (i = 0; i <= page ; i++) FREE(mintermPages[i]);
821 FREE(mintermPages);
822 st_free_table(table);
823 goto OUT_OF_MEM;
825 nodeDataPage = 0;
826 currentNodeDataPage = ALLOC(NodeData_t ,nodeDataPageSize);
827 nodeDataPages[nodeDataPage] = currentNodeDataPage;
828 if (currentNodeDataPage == NULL) {
829 for (i = 0; i <= page ; i++) FREE(mintermPages[i]);
830 FREE(mintermPages);
831 FREE(nodeDataPages);
832 st_free_table(table);
833 goto OUT_OF_MEM;
835 nodeDataPageIndex = 0;
837 (void) SubsetCountMintermAux(node,max,table);
838 if (memOut) goto OUT_OF_MEM;
839 return(table);
841 OUT_OF_MEM:
842 memOut = 1;
843 return(NULL);
845 } /* end of SubsetCountMinterm */
848 /**Function********************************************************************
850 Synopsis [Recursively counts the number of nodes under the dag.
851 Also counts the number of nodes under the lighter child of
852 this node.]
854 Description [Recursively counts the number of nodes under the dag.
855 Also counts the number of nodes under the lighter child of
856 this node. . Note that the same dag may be the lighter child of two
857 different nodes and have different counts. As with the minterm counts,
858 the node counts are stored in pages to be space efficient and the
859 address for these node counts are stored in an st_table associated
860 to each node. ]
862 SideEffects [Updates the node data table with node counts]
864 SeeAlso [SubsetCountNodes]
866 ******************************************************************************/
867 static int
868 SubsetCountNodesAux(
869 DdNode * node /* current node */,
870 st_table * table /* table to update node count, also serves as visited table. */,
871 double max /* maximum number of variables */)
873 int tval, eval, i;
874 DdNode *N, *Nv, *Nnv;
875 double minNv, minNnv;
876 NodeData_t *dummyN, *dummyNv, *dummyNnv, *dummyNBar;
877 int *pmin, *pminBar, *val;
879 if ((node == NULL) || Cudd_IsConstant(node))
880 return(0);
882 /* if this node has been processed do nothing */
883 if (st_lookup(table, node, &dummyN) == 1) {
884 val = dummyN->nodesPointer;
885 if (val != NULL)
886 return(0);
887 } else {
888 return(0);
891 N = Cudd_Regular(node);
892 Nv = Cudd_T(N);
893 Nnv = Cudd_E(N);
895 Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
896 Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
898 /* find the minterm counts for the THEN and ELSE branches */
899 if (Cudd_IsConstant(Nv)) {
900 if (Nv == zero) {
901 minNv = 0.0;
902 } else {
903 minNv = max;
905 } else {
906 if (st_lookup(table, Nv, &dummyNv) == 1)
907 minNv = *(dummyNv->mintermPointer);
908 else {
909 return(0);
912 if (Cudd_IsConstant(Nnv)) {
913 if (Nnv == zero) {
914 minNnv = 0.0;
915 } else {
916 minNnv = max;
918 } else {
919 if (st_lookup(table, Nnv, &dummyNnv) == 1) {
920 minNnv = *(dummyNnv->mintermPointer);
922 else {
923 return(0);
928 /* recur based on which has larger minterm, */
929 if (minNv >= minNnv) {
930 tval = SubsetCountNodesAux(Nv, table, max);
931 if (memOut) return(0);
932 eval = SubsetCountNodesAux(Nnv, table, max);
933 if (memOut) return(0);
935 /* store the node count of the lighter child. */
936 if (pageIndex == pageSize) ResizeCountNodePages();
937 if (memOut) {
938 for (i = 0; i <= page; i++) FREE(mintermPages[i]);
939 FREE(mintermPages);
940 for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
941 FREE(nodeDataPages);
942 st_free_table(table);
943 return(0);
945 pmin = currentLightNodePage + pageIndex;
946 *pmin = eval; /* Here the ELSE child is lighter */
947 dummyN->lightChildNodesPointer = pmin;
949 } else {
950 eval = SubsetCountNodesAux(Nnv, table, max);
951 if (memOut) return(0);
952 tval = SubsetCountNodesAux(Nv, table, max);
953 if (memOut) return(0);
955 /* store the node count of the lighter child. */
956 if (pageIndex == pageSize) ResizeCountNodePages();
957 if (memOut) {
958 for (i = 0; i <= page; i++) FREE(mintermPages[i]);
959 FREE(mintermPages);
960 for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
961 FREE(nodeDataPages);
962 st_free_table(table);
963 return(0);
965 pmin = currentLightNodePage + pageIndex;
966 *pmin = tval; /* Here the THEN child is lighter */
967 dummyN->lightChildNodesPointer = pmin;
970 /* updating the page index for node count storage. */
971 pmin = currentNodePage + pageIndex;
972 *pmin = tval + eval + 1;
973 dummyN->nodesPointer = pmin;
975 /* pageIndex is parallel page index for count_nodes and count_lightNodes */
976 pageIndex++;
978 /* if this node has been reached first, it belongs to a heavier
979 branch. Its complement will be reached later on a lighter branch.
980 Hence the complement has zero node count. */
982 if (st_lookup(table, Cudd_Not(node), &dummyNBar) == 1) {
983 if (pageIndex == pageSize) ResizeCountNodePages();
984 if (memOut) {
985 for (i = 0; i < page; i++) FREE(mintermPages[i]);
986 FREE(mintermPages);
987 for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
988 FREE(nodeDataPages);
989 st_free_table(table);
990 return(0);
992 pminBar = currentLightNodePage + pageIndex;
993 *pminBar = 0;
994 dummyNBar->lightChildNodesPointer = pminBar;
995 /* The lighter child has less nodes than the parent.
996 * So if parent 0 then lighter child zero
998 if (pageIndex == pageSize) ResizeCountNodePages();
999 if (memOut) {
1000 for (i = 0; i < page; i++) FREE(mintermPages[i]);
1001 FREE(mintermPages);
1002 for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
1003 FREE(nodeDataPages);
1004 st_free_table(table);
1005 return(0);
1007 pminBar = currentNodePage + pageIndex;
1008 *pminBar = 0;
1009 dummyNBar->nodesPointer = pminBar ; /* maybe should point to zero */
1011 pageIndex++;
1013 return(*pmin);
1014 } /*end of SubsetCountNodesAux */
1017 /**Function********************************************************************
1019 Synopsis [Counts the nodes under the current node and its lighter child]
1021 Description [Counts the nodes under the current node and its lighter
1022 child. Calls a recursive procedure to count the number of nodes of
1023 a DAG rooted at a particular node and the number of nodes taken by its
1024 lighter child.]
1026 SideEffects [None]
1028 SeeAlso [SubsetCountNodesAux]
1030 ******************************************************************************/
1031 static int
1032 SubsetCountNodes(
1033 DdNode * node /* function to be analyzed */,
1034 st_table * table /* node quality table */,
1035 int nvars /* number of variables node depends on */)
1037 int num;
1038 int i;
1040 #ifdef DEBUG
1041 num_calls = 0;
1042 #endif
1044 max = pow(2.0,(double) nvars);
1045 maxPages = INITIAL_PAGES;
1046 nodePages = ALLOC(int *,maxPages);
1047 if (nodePages == NULL) {
1048 goto OUT_OF_MEM;
1051 lightNodePages = ALLOC(int *,maxPages);
1052 if (lightNodePages == NULL) {
1053 for (i = 0; i <= page; i++) FREE(mintermPages[i]);
1054 FREE(mintermPages);
1055 for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
1056 FREE(nodeDataPages);
1057 FREE(nodePages);
1058 goto OUT_OF_MEM;
1061 page = 0;
1062 currentNodePage = nodePages[page] = ALLOC(int,pageSize);
1063 if (currentNodePage == NULL) {
1064 for (i = 0; i <= page; i++) FREE(mintermPages[i]);
1065 FREE(mintermPages);
1066 for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
1067 FREE(nodeDataPages);
1068 FREE(lightNodePages);
1069 FREE(nodePages);
1070 goto OUT_OF_MEM;
1073 currentLightNodePage = lightNodePages[page] = ALLOC(int,pageSize);
1074 if (currentLightNodePage == NULL) {
1075 for (i = 0; i <= page; i++) FREE(mintermPages[i]);
1076 FREE(mintermPages);
1077 for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
1078 FREE(nodeDataPages);
1079 FREE(currentNodePage);
1080 FREE(lightNodePages);
1081 FREE(nodePages);
1082 goto OUT_OF_MEM;
1085 pageIndex = 0;
1086 num = SubsetCountNodesAux(node,table,max);
1087 if (memOut) goto OUT_OF_MEM;
1088 return(num);
1090 OUT_OF_MEM:
1091 memOut = 1;
1092 return(0);
1094 } /* end of SubsetCountNodes */
1097 /**Function********************************************************************
1099 Synopsis [Procedure to recursively store nodes that are retained in the subset.]
1101 Description [rocedure to recursively store nodes that are retained in the subset.]
1103 SideEffects [None]
1105 SeeAlso [StoreNodes]
1107 ******************************************************************************/
1108 static void
1109 StoreNodes(
1110 st_table * storeTable,
1111 DdManager * dd,
1112 DdNode * node)
1114 DdNode *N, *Nt, *Ne;
1115 if (Cudd_IsConstant(dd)) {
1116 return;
1118 N = Cudd_Regular(node);
1119 if (st_lookup(storeTable, (char *)N, NIL(char *))) {
1120 return;
1122 cuddRef(N);
1123 if (st_insert(storeTable, (char *)N, NIL(char)) == ST_OUT_OF_MEM) {
1124 fprintf(dd->err,"Something wrong, st_table insert failed\n");
1127 Nt = Cudd_T(N);
1128 Ne = Cudd_E(N);
1130 StoreNodes(storeTable, dd, Nt);
1131 StoreNodes(storeTable, dd, Ne);
1132 return;
1137 /**Function********************************************************************
1139 Synopsis [Builds the subset BDD using the heavy branch method.]
1141 Description [The procedure carries out the building of the subset BDD
1142 starting at the root. Using the three different counts labelling each node,
1143 the procedure chooses the heavier branch starting from the root and keeps
1144 track of the number of nodes it discards at each step, thus keeping count
1145 of the size of the subset BDD dynamically. Once the threshold is satisfied,
1146 the procedure then calls ITE to build the BDD.]
1148 SideEffects [None]
1150 SeeAlso []
1152 ******************************************************************************/
1153 static DdNode *
1154 BuildSubsetBdd(
1155 DdManager * dd /* DD manager */,
1156 DdNode * node /* current node */,
1157 int * size /* current size of the subset */,
1158 st_table * visitedTable /* visited table storing all node data */,
1159 int threshold,
1160 st_table * storeTable,
1161 st_table * approxTable)
1164 DdNode *Nv, *Nnv, *N, *topv, *neW;
1165 double minNv, minNnv;
1166 NodeData_t *currNodeQual;
1167 NodeData_t *currNodeQualT;
1168 NodeData_t *currNodeQualE;
1169 DdNode *ThenBranch, *ElseBranch;
1170 unsigned int topid;
1171 char *dummy;
1173 #ifdef DEBUG
1174 num_calls++;
1175 #endif
1176 /*If the size of the subset is below the threshold, dont do
1177 anything. */
1178 if ((*size) <= threshold) {
1179 /* store nodes below this, so we can recombine if possible */
1180 StoreNodes(storeTable, dd, node);
1181 return(node);
1184 if (Cudd_IsConstant(node))
1185 return(node);
1187 /* Look up minterm count for this node. */
1188 if (!st_lookup(visitedTable, node, &currNodeQual)) {
1189 fprintf(dd->err,
1190 "Something is wrong, ought to be in node quality table\n");
1193 /* Get children. */
1194 N = Cudd_Regular(node);
1195 Nv = Cudd_T(N);
1196 Nnv = Cudd_E(N);
1198 /* complement if necessary */
1199 Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
1200 Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
1202 if (!Cudd_IsConstant(Nv)) {
1203 /* find out minterms and nodes contributed by then child */
1204 if (!st_lookup(visitedTable, Nv, &currNodeQualT)) {
1205 fprintf(dd->out,"Something wrong, couldnt find nodes in node quality table\n");
1206 dd->errorCode = CUDD_INTERNAL_ERROR;
1207 return(NULL);
1209 else {
1210 minNv = *(((NodeData_t *)currNodeQualT)->mintermPointer);
1212 } else {
1213 if (Nv == zero) {
1214 minNv = 0;
1215 } else {
1216 minNv = max;
1219 if (!Cudd_IsConstant(Nnv)) {
1220 /* find out minterms and nodes contributed by else child */
1221 if (!st_lookup(visitedTable, Nnv, &currNodeQualE)) {
1222 fprintf(dd->out,"Something wrong, couldnt find nodes in node quality table\n");
1223 dd->errorCode = CUDD_INTERNAL_ERROR;
1224 return(NULL);
1225 } else {
1226 minNnv = *(((NodeData_t *)currNodeQualE)->mintermPointer);
1228 } else {
1229 if (Nnv == zero) {
1230 minNnv = 0;
1231 } else {
1232 minNnv = max;
1236 /* keep track of size of subset by subtracting the number of
1237 * differential nodes contributed by lighter child
1239 *size = (*(size)) - (int)*(currNodeQual->lightChildNodesPointer);
1240 if (minNv >= minNnv) { /*SubsetCountNodesAux procedure takes
1241 the Then branch in case of a tie */
1243 /* recur with the Then branch */
1244 ThenBranch = (DdNode *)BuildSubsetBdd(dd, Nv, size,
1245 visitedTable, threshold, storeTable, approxTable);
1246 if (ThenBranch == NULL) {
1247 return(NULL);
1249 cuddRef(ThenBranch);
1250 /* The Else branch is either a node that already exists in the
1251 * subset, or one whose approximation has been computed, or
1252 * Zero.
1254 if (st_lookup(storeTable, (char *)Cudd_Regular(Nnv), &dummy)) {
1255 ElseBranch = Nnv;
1256 cuddRef(ElseBranch);
1257 } else {
1258 if (st_lookup(approxTable, (char *)Nnv, &dummy)) {
1259 ElseBranch = (DdNode *)dummy;
1260 cuddRef(ElseBranch);
1261 } else {
1262 ElseBranch = zero;
1263 cuddRef(ElseBranch);
1268 else {
1269 /* recur with the Else branch */
1270 ElseBranch = (DdNode *)BuildSubsetBdd(dd, Nnv, size,
1271 visitedTable, threshold, storeTable, approxTable);
1272 if (ElseBranch == NULL) {
1273 return(NULL);
1275 cuddRef(ElseBranch);
1276 /* The Then branch is either a node that already exists in the
1277 * subset, or one whose approximation has been computed, or
1278 * Zero.
1280 if (st_lookup(storeTable, (char *)Cudd_Regular(Nv), &dummy)) {
1281 ThenBranch = Nv;
1282 cuddRef(ThenBranch);
1283 } else {
1284 if (st_lookup(approxTable, (char *)Nv, &dummy)) {
1285 ThenBranch = (DdNode *)dummy;
1286 cuddRef(ThenBranch);
1287 } else {
1288 ThenBranch = zero;
1289 cuddRef(ThenBranch);
1294 /* construct the Bdd with the top variable and the two children */
1295 topid = Cudd_NodeReadIndex(N);
1296 topv = Cudd_ReadVars(dd, topid);
1297 cuddRef(topv);
1298 neW = cuddBddIteRecur(dd, topv, ThenBranch, ElseBranch);
1299 if (neW != NULL) {
1300 cuddRef(neW);
1302 Cudd_RecursiveDeref(dd, topv);
1303 Cudd_RecursiveDeref(dd, ThenBranch);
1304 Cudd_RecursiveDeref(dd, ElseBranch);
1307 if (neW == NULL)
1308 return(NULL);
1309 else {
1310 /* store this node in the store table */
1311 if (!st_lookup(storeTable, (char *)Cudd_Regular(neW), &dummy)) {
1312 cuddRef(neW);
1313 if (!st_insert(storeTable, (char *)Cudd_Regular(neW), NIL(char)))
1314 return (NULL);
1316 /* store the approximation for this node */
1317 if (N != Cudd_Regular(neW)) {
1318 if (st_lookup(approxTable, (char *)node, &dummy)) {
1319 fprintf(dd->err, "This node should not be in the approximated table\n");
1320 } else {
1321 cuddRef(neW);
1322 if (!st_insert(approxTable, (char *)node, (char *)neW))
1323 return(NULL);
1326 cuddDeref(neW);
1327 return(neW);
1329 } /* end of BuildSubsetBdd */