summaryrefslogtreecommitdiffstats
path: root/src/bdd/cudd/cuddDecomp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bdd/cudd/cuddDecomp.c')
-rw-r--r--src/bdd/cudd/cuddDecomp.c2150
1 files changed, 2150 insertions, 0 deletions
diff --git a/src/bdd/cudd/cuddDecomp.c b/src/bdd/cudd/cuddDecomp.c
new file mode 100644
index 00000000..4fde7392
--- /dev/null
+++ b/src/bdd/cudd/cuddDecomp.c
@@ -0,0 +1,2150 @@
+/**CFile***********************************************************************
+
+ FileName [cuddDecomp.c]
+
+ PackageName [cudd]
+
+ Synopsis [Functions for BDD decomposition.]
+
+ Description [External procedures included in this file:
+ <ul>
+ <li> Cudd_bddApproxConjDecomp()
+ <li> Cudd_bddApproxDisjDecomp()
+ <li> Cudd_bddIterConjDecomp()
+ <li> Cudd_bddIterDisjDecomp()
+ <li> Cudd_bddGenConjDecomp()
+ <li> Cudd_bddGenDisjDecomp()
+ <li> Cudd_bddVarConjDecomp()
+ <li> Cudd_bddVarDisjDecomp()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddConjunctsAux()
+ <li> CreateBotDist()
+ <li> BuildConjuncts()
+ <li> ConjunctsFree()
+ </ul>]
+
+ Author [Kavita Ravi, Fabio Somenzi]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util_hack.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+#define DEPTH 5
+#define THRESHOLD 10
+#define NONE 0
+#define PAIR_ST 1
+#define PAIR_CR 2
+#define G_ST 3
+#define G_CR 4
+#define H_ST 5
+#define H_CR 6
+#define BOTH_G 7
+#define BOTH_H 8
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+typedef struct Conjuncts {
+ DdNode *g;
+ DdNode *h;
+} Conjuncts;
+
+typedef struct NodeStat {
+ int distance;
+ int localRef;
+} NodeStat;
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddDecomp.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $";
+#endif
+
+static DdNode *one, *zero;
+long lastTimeG;
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+#define FactorsNotStored(factors) ((int)((long)(factors) & 01))
+
+#define FactorsComplement(factors) ((Conjuncts *)((long)(factors) | 01))
+
+#define FactorsUncomplement(factors) ((Conjuncts *)((long)(factors) ^ 01))
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static NodeStat * CreateBotDist ARGS((DdNode * node, st_table * distanceTable));
+static double CountMinterms ARGS((DdNode * node, double max, st_table * mintermTable, FILE *fp));
+static void ConjunctsFree ARGS((DdManager * dd, Conjuncts * factors));
+static int PairInTables ARGS((DdNode * g, DdNode * h, st_table * ghTable));
+static Conjuncts * CheckTablesCacheAndReturn ARGS((DdNode * node, DdNode * g, DdNode * h, st_table * ghTable, st_table * cacheTable));
+static Conjuncts * PickOnePair ARGS((DdNode * node, DdNode * g1, DdNode * h1, DdNode * g2, DdNode * h2, st_table * ghTable, st_table * cacheTable));
+static Conjuncts * CheckInTables ARGS((DdNode * node, DdNode * g1, DdNode * h1, DdNode * g2, DdNode * h2, st_table * ghTable, st_table * cacheTable, int * outOfMem));
+static Conjuncts * ZeroCase ARGS((DdManager * dd, DdNode * node, Conjuncts * factorsNv, st_table * ghTable, st_table * cacheTable, int switched));
+static Conjuncts * BuildConjuncts ARGS((DdManager * dd, DdNode * node, st_table * distanceTable, st_table * cacheTable, int approxDistance, int maxLocalRef, st_table * ghTable, st_table * mintermTable));
+static int cuddConjunctsAux ARGS((DdManager * dd, DdNode * f, DdNode ** c1, DdNode ** c2));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way conjunctive decomposition of a BDD.]
+
+ Description [Performs two-way conjunctive decomposition of a
+ BDD. This procedure owes its name to the use of supersetting to
+ obtain an initial factor of the given function. Returns the number
+ of conjuncts produced, that is, 2 if successful; 1 if no meaningful
+ decomposition was found; 0 otherwise. The conjuncts produced by this
+ procedure tend to be imbalanced.]
+
+ SideEffects [The factors are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the conjuncts are already
+ referenced. If the function returns 0, the array for the conjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddApproxDisjDecomp Cudd_bddIterConjDecomp
+ Cudd_bddGenConjDecomp Cudd_bddVarConjDecomp Cudd_RemapOverApprox
+ Cudd_bddSqueeze Cudd_bddLICompaction]
+
+******************************************************************************/
+int
+Cudd_bddApproxConjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** conjuncts /* address of the first factor */)
+{
+ DdNode *superset1, *superset2, *glocal, *hlocal;
+ int nvars = Cudd_SupportSize(dd,f);
+
+ /* Find a tentative first factor by overapproximation and minimization. */
+ superset1 = Cudd_RemapOverApprox(dd,f,nvars,0,1.0);
+ if (superset1 == NULL) return(0);
+ cuddRef(superset1);
+ superset2 = Cudd_bddSqueeze(dd,f,superset1);
+ if (superset2 == NULL) {
+ Cudd_RecursiveDeref(dd,superset1);
+ return(0);
+ }
+ cuddRef(superset2);
+ Cudd_RecursiveDeref(dd,superset1);
+
+ /* Compute the second factor by minimization. */
+ hlocal = Cudd_bddLICompaction(dd,f,superset2);
+ if (hlocal == NULL) {
+ Cudd_RecursiveDeref(dd,superset2);
+ return(0);
+ }
+ cuddRef(hlocal);
+
+ /* Refine the first factor by minimization. If h turns out to be f, this
+ ** step guarantees that g will be 1. */
+ glocal = Cudd_bddLICompaction(dd,superset2,hlocal);
+ if (glocal == NULL) {
+ Cudd_RecursiveDeref(dd,superset2);
+ Cudd_RecursiveDeref(dd,hlocal);
+ return(0);
+ }
+ cuddRef(glocal);
+ Cudd_RecursiveDeref(dd,superset2);
+
+ if (glocal != DD_ONE(dd)) {
+ if (hlocal != DD_ONE(dd)) {
+ *conjuncts = ALLOC(DdNode *,2);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ (*conjuncts)[1] = hlocal;
+ return(2);
+ } else {
+ Cudd_RecursiveDeref(dd,hlocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ return(1);
+ }
+ } else {
+ Cudd_RecursiveDeref(dd,glocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = hlocal;
+ return(1);
+ }
+
+} /* end of Cudd_bddApproxConjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way disjunctive decomposition of a BDD.]
+
+ Description [Performs two-way disjunctive decomposition of a BDD.
+ Returns the number of disjuncts produced, that is, 2 if successful;
+ 1 if no meaningful decomposition was found; 0 otherwise. The
+ disjuncts produced by this procedure tend to be imbalanced.]
+
+ SideEffects [The two disjuncts are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the disjuncts are already
+ referenced. If the function returns 0, the array for the disjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddApproxConjDecomp Cudd_bddIterDisjDecomp
+ Cudd_bddGenDisjDecomp Cudd_bddVarDisjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddApproxDisjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** disjuncts /* address of the array of the disjuncts */)
+{
+ int result, i;
+
+ result = Cudd_bddApproxConjDecomp(dd,Cudd_Not(f),disjuncts);
+ for (i = 0; i < result; i++) {
+ (*disjuncts)[i] = Cudd_Not((*disjuncts)[i]);
+ }
+ return(result);
+
+} /* end of Cudd_bddApproxDisjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way conjunctive decomposition of a BDD.]
+
+ Description [Performs two-way conjunctive decomposition of a
+ BDD. This procedure owes its name to the iterated use of
+ supersetting to obtain a factor of the given function. Returns the
+ number of conjuncts produced, that is, 2 if successful; 1 if no
+ meaningful decomposition was found; 0 otherwise. The conjuncts
+ produced by this procedure tend to be imbalanced.]
+
+ SideEffects [The factors are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the conjuncts are already
+ referenced. If the function returns 0, the array for the conjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddIterDisjDecomp Cudd_bddApproxConjDecomp
+ Cudd_bddGenConjDecomp Cudd_bddVarConjDecomp Cudd_RemapOverApprox
+ Cudd_bddSqueeze Cudd_bddLICompaction]
+
+******************************************************************************/
+int
+Cudd_bddIterConjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** conjuncts /* address of the array of conjuncts */)
+{
+ DdNode *superset1, *superset2, *old[2], *res[2];
+ int sizeOld, sizeNew;
+ int nvars = Cudd_SupportSize(dd,f);
+
+ old[0] = DD_ONE(dd);
+ cuddRef(old[0]);
+ old[1] = f;
+ cuddRef(old[1]);
+ sizeOld = Cudd_SharingSize(old,2);
+
+ do {
+ /* Find a tentative first factor by overapproximation and
+ ** minimization. */
+ superset1 = Cudd_RemapOverApprox(dd,old[1],nvars,0,1.0);
+ if (superset1 == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ return(0);
+ }
+ cuddRef(superset1);
+ superset2 = Cudd_bddSqueeze(dd,old[1],superset1);
+ if (superset2 == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ Cudd_RecursiveDeref(dd,superset1);
+ return(0);
+ }
+ cuddRef(superset2);
+ Cudd_RecursiveDeref(dd,superset1);
+ res[0] = Cudd_bddAnd(dd,old[0],superset2);
+ if (res[0] == NULL) {
+ Cudd_RecursiveDeref(dd,superset2);
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ return(0);
+ }
+ cuddRef(res[0]);
+ Cudd_RecursiveDeref(dd,superset2);
+ if (res[0] == old[0]) {
+ Cudd_RecursiveDeref(dd,res[0]);
+ break; /* avoid infinite loop */
+ }
+
+ /* Compute the second factor by minimization. */
+ res[1] = Cudd_bddLICompaction(dd,old[1],res[0]);
+ if (res[1] == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ return(0);
+ }
+ cuddRef(res[1]);
+
+ sizeNew = Cudd_SharingSize(res,2);
+ if (sizeNew <= sizeOld) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ old[0] = res[0];
+ Cudd_RecursiveDeref(dd,old[1]);
+ old[1] = res[1];
+ sizeOld = sizeNew;
+ } else {
+ Cudd_RecursiveDeref(dd,res[0]);
+ Cudd_RecursiveDeref(dd,res[1]);
+ break;
+ }
+
+ } while (1);
+
+ /* Refine the first factor by minimization. If h turns out to
+ ** be f, this step guarantees that g will be 1. */
+ superset1 = Cudd_bddLICompaction(dd,old[0],old[1]);
+ if (superset1 == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ return(0);
+ }
+ cuddRef(superset1);
+ Cudd_RecursiveDeref(dd,old[0]);
+ old[0] = superset1;
+
+ if (old[0] != DD_ONE(dd)) {
+ if (old[1] != DD_ONE(dd)) {
+ *conjuncts = ALLOC(DdNode *,2);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ Cudd_RecursiveDeref(dd,old[1]);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = old[0];
+ (*conjuncts)[1] = old[1];
+ return(2);
+ } else {
+ Cudd_RecursiveDeref(dd,old[1]);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,old[0]);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = old[0];
+ return(1);
+ }
+ } else {
+ Cudd_RecursiveDeref(dd,old[0]);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,old[1]);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = old[1];
+ return(1);
+ }
+
+} /* end of Cudd_bddIterConjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way disjunctive decomposition of a BDD.]
+
+ Description [Performs two-way disjunctive decomposition of a BDD.
+ Returns the number of disjuncts produced, that is, 2 if successful;
+ 1 if no meaningful decomposition was found; 0 otherwise. The
+ disjuncts produced by this procedure tend to be imbalanced.]
+
+ SideEffects [The two disjuncts are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the disjuncts are already
+ referenced. If the function returns 0, the array for the disjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddIterConjDecomp Cudd_bddApproxDisjDecomp
+ Cudd_bddGenDisjDecomp Cudd_bddVarDisjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddIterDisjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** disjuncts /* address of the array of the disjuncts */)
+{
+ int result, i;
+
+ result = Cudd_bddIterConjDecomp(dd,Cudd_Not(f),disjuncts);
+ for (i = 0; i < result; i++) {
+ (*disjuncts)[i] = Cudd_Not((*disjuncts)[i]);
+ }
+ return(result);
+
+} /* end of Cudd_bddIterDisjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way conjunctive decomposition of a BDD.]
+
+ Description [Performs two-way conjunctive decomposition of a
+ BDD. This procedure owes its name to the fact tht it generalizes the
+ decomposition based on the cofactors with respect to one
+ variable. Returns the number of conjuncts produced, that is, 2 if
+ successful; 1 if no meaningful decomposition was found; 0
+ otherwise. The conjuncts produced by this procedure tend to be
+ balanced.]
+
+ SideEffects [The two factors are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the conjuncts are already
+ referenced. If the function returns 0, the array for the conjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddGenDisjDecomp Cudd_bddApproxConjDecomp
+ Cudd_bddIterConjDecomp Cudd_bddVarConjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddGenConjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** conjuncts /* address of the array of conjuncts */)
+{
+ int result;
+ DdNode *glocal, *hlocal;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ do {
+ dd->reordered = 0;
+ result = cuddConjunctsAux(dd, f, &glocal, &hlocal);
+ } while (dd->reordered == 1);
+
+ if (result == 0) {
+ return(0);
+ }
+
+ if (glocal != one) {
+ if (hlocal != one) {
+ *conjuncts = ALLOC(DdNode *,2);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ (*conjuncts)[1] = hlocal;
+ return(2);
+ } else {
+ Cudd_RecursiveDeref(dd,hlocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ return(1);
+ }
+ } else {
+ Cudd_RecursiveDeref(dd,glocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = hlocal;
+ return(1);
+ }
+
+} /* end of Cudd_bddGenConjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way disjunctive decomposition of a BDD.]
+
+ Description [Performs two-way disjunctive decomposition of a BDD.
+ Returns the number of disjuncts produced, that is, 2 if successful;
+ 1 if no meaningful decomposition was found; 0 otherwise. The
+ disjuncts produced by this procedure tend to be balanced.]
+
+ SideEffects [The two disjuncts are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the disjuncts are already
+ referenced. If the function returns 0, the array for the disjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddGenConjDecomp Cudd_bddApproxDisjDecomp
+ Cudd_bddIterDisjDecomp Cudd_bddVarDisjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddGenDisjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** disjuncts /* address of the array of the disjuncts */)
+{
+ int result, i;
+
+ result = Cudd_bddGenConjDecomp(dd,Cudd_Not(f),disjuncts);
+ for (i = 0; i < result; i++) {
+ (*disjuncts)[i] = Cudd_Not((*disjuncts)[i]);
+ }
+ return(result);
+
+} /* end of Cudd_bddGenDisjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way conjunctive decomposition of a BDD.]
+
+ Description [Conjunctively decomposes one BDD according to a
+ variable. If <code>f</code> is the function of the BDD and
+ <code>x</code> is the variable, the decomposition is
+ <code>(f+x)(f+x')</code>. The variable is chosen so as to balance
+ the sizes of the two conjuncts and to keep them small. Returns the
+ number of conjuncts produced, that is, 2 if successful; 1 if no
+ meaningful decomposition was found; 0 otherwise.]
+
+ SideEffects [The two factors are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the conjuncts are already
+ referenced. If the function returns 0, the array for the conjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddVarDisjDecomp Cudd_bddGenConjDecomp
+ Cudd_bddApproxConjDecomp Cudd_bddIterConjDecomp]
+
+*****************************************************************************/
+int
+Cudd_bddVarConjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** conjuncts /* address of the array of conjuncts */)
+{
+ int best;
+ int min;
+ DdNode *support, *scan, *var, *glocal, *hlocal;
+
+ /* Find best cofactoring variable. */
+ support = Cudd_Support(dd,f);
+ if (support == NULL) return(0);
+ if (Cudd_IsConstant(support)) {
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = f;
+ cuddRef((*conjuncts)[0]);
+ return(1);
+ }
+ cuddRef(support);
+ min = 1000000000;
+ best = -1;
+ scan = support;
+ while (!Cudd_IsConstant(scan)) {
+ int i = scan->index;
+ int est1 = Cudd_EstimateCofactor(dd,f,i,1);
+ int est0 = Cudd_EstimateCofactor(dd,f,i,0);
+ /* Minimize the size of the larger of the two cofactors. */
+ int est = (est1 > est0) ? est1 : est0;
+ if (est < min) {
+ min = est;
+ best = i;
+ }
+ scan = cuddT(scan);
+ }
+#ifdef DD_DEBUG
+ assert(best >= 0 && best < dd->size);
+#endif
+ Cudd_RecursiveDeref(dd,support);
+
+ var = Cudd_bddIthVar(dd,best);
+ glocal = Cudd_bddOr(dd,f,var);
+ if (glocal == NULL) {
+ return(0);
+ }
+ cuddRef(glocal);
+ hlocal = Cudd_bddOr(dd,f,Cudd_Not(var));
+ if (hlocal == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ return(0);
+ }
+ cuddRef(hlocal);
+
+ if (glocal != DD_ONE(dd)) {
+ if (hlocal != DD_ONE(dd)) {
+ *conjuncts = ALLOC(DdNode *,2);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ (*conjuncts)[1] = hlocal;
+ return(2);
+ } else {
+ Cudd_RecursiveDeref(dd,hlocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,glocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = glocal;
+ return(1);
+ }
+ } else {
+ Cudd_RecursiveDeref(dd,glocal);
+ *conjuncts = ALLOC(DdNode *,1);
+ if (*conjuncts == NULL) {
+ Cudd_RecursiveDeref(dd,hlocal);
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+ }
+ (*conjuncts)[0] = hlocal;
+ return(1);
+ }
+
+} /* end of Cudd_bddVarConjDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs two-way disjunctive decomposition of a BDD.]
+
+ Description [Performs two-way disjunctive decomposition of a BDD
+ according to a variable. If <code>f</code> is the function of the
+ BDD and <code>x</code> is the variable, the decomposition is
+ <code>f*x + f*x'</code>. The variable is chosen so as to balance
+ the sizes of the two disjuncts and to keep them small. Returns the
+ number of disjuncts produced, that is, 2 if successful; 1 if no
+ meaningful decomposition was found; 0 otherwise.]
+
+ SideEffects [The two disjuncts are returned in an array as side effects.
+ The array is allocated by this function. It is the caller's responsibility
+ to free it. On successful completion, the disjuncts are already
+ referenced. If the function returns 0, the array for the disjuncts is
+ not allocated. If the function returns 1, the only factor equals the
+ function to be decomposed.]
+
+ SeeAlso [Cudd_bddVarConjDecomp Cudd_bddApproxDisjDecomp
+ Cudd_bddIterDisjDecomp Cudd_bddGenDisjDecomp]
+
+******************************************************************************/
+int
+Cudd_bddVarDisjDecomp(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be decomposed */,
+ DdNode *** disjuncts /* address of the array of the disjuncts */)
+{
+ int result, i;
+
+ result = Cudd_bddVarConjDecomp(dd,Cudd_Not(f),disjuncts);
+ for (i = 0; i < result; i++) {
+ (*disjuncts)[i] = Cudd_Not((*disjuncts)[i]);
+ }
+ return(result);
+
+} /* end of Cudd_bddVarDisjDecomp */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Get longest distance of node from constant.]
+
+ Description [Get longest distance of node from constant. Returns the
+ distance of the root from the constant if successful; CUDD_OUT_OF_MEM
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static NodeStat *
+CreateBotDist(
+ DdNode * node,
+ st_table * distanceTable)
+{
+ DdNode *N, *Nv, *Nnv;
+ int distance, distanceNv, distanceNnv;
+ NodeStat *nodeStat, *nodeStatNv, *nodeStatNnv;
+
+#if 0
+ if (Cudd_IsConstant(node)) {
+ return(0);
+ }
+#endif
+
+ /* Return the entry in the table if found. */
+ N = Cudd_Regular(node);
+ if (st_lookup(distanceTable, (char *)N, (char **)&nodeStat)) {
+ nodeStat->localRef++;
+ return(nodeStat);
+ }
+
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ /* Recur on the children. */
+ nodeStatNv = CreateBotDist(Nv, distanceTable);
+ if (nodeStatNv == NULL) return(NULL);
+ distanceNv = nodeStatNv->distance;
+
+ nodeStatNnv = CreateBotDist(Nnv, distanceTable);
+ if (nodeStatNnv == NULL) return(NULL);
+ distanceNnv = nodeStatNnv->distance;
+ /* Store max distance from constant; note sometimes this distance
+ ** may be to 0.
+ */
+ distance = (distanceNv > distanceNnv) ? (distanceNv+1) : (distanceNnv + 1);
+
+ nodeStat = ALLOC(NodeStat, 1);
+ if (nodeStat == NULL) {
+ return(0);
+ }
+ nodeStat->distance = distance;
+ nodeStat->localRef = 1;
+
+ if (st_insert(distanceTable, (char *)N, (char *)nodeStat) ==
+ ST_OUT_OF_MEM) {
+ return(0);
+
+ }
+ return(nodeStat);
+
+} /* end of CreateBotDist */
+
+
+/**Function********************************************************************
+
+ Synopsis [Count the number of minterms of each node ina a BDD and
+ store it in a hash table.]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static double
+CountMinterms(
+ DdNode * node,
+ double max,
+ st_table * mintermTable,
+ FILE *fp)
+{
+ DdNode *N, *Nv, *Nnv;
+ double min, minNv, minNnv;
+ double *dummy;
+
+ N = Cudd_Regular(node);
+
+ if (cuddIsConstant(N)) {
+ if (node == zero) {
+ return(0);
+ } else {
+ return(max);
+ }
+ }
+
+ /* Return the entry in the table if found. */
+ if (st_lookup(mintermTable, (char *)node, (char **)&dummy)) {
+ min = *dummy;
+ return(min);
+ }
+
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ /* Recur on the children. */
+ minNv = CountMinterms(Nv, max, mintermTable, fp);
+ if (minNv == -1.0) return(-1.0);
+ minNnv = CountMinterms(Nnv, max, mintermTable, fp);
+ if (minNnv == -1.0) return(-1.0);
+ min = minNv / 2.0 + minNnv / 2.0;
+ /* store
+ */
+
+ dummy = ALLOC(double, 1);
+ if (dummy == NULL) return(-1.0);
+ *dummy = min;
+ if (st_insert(mintermTable, (char *)node, (char *)dummy) == ST_OUT_OF_MEM) {
+ (void) fprintf(fp, "st table insert failed\n");
+ }
+ return(min);
+
+} /* end of CountMinterms */
+
+
+/**Function********************************************************************
+
+ Synopsis [Free factors structure]
+
+ Description []
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+static void
+ConjunctsFree(
+ DdManager * dd,
+ Conjuncts * factors)
+{
+ Cudd_RecursiveDeref(dd, factors->g);
+ Cudd_RecursiveDeref(dd, factors->h);
+ FREE(factors);
+ return;
+
+} /* end of ConjunctsFree */
+
+
+/**Function********************************************************************
+
+ Synopsis [Check whether the given pair is in the tables.]
+
+ Description [.Check whether the given pair is in the tables. gTable
+ and hTable are combined.
+ absence in both is indicated by 0,
+ presence in gTable is indicated by 1,
+ presence in hTable by 2 and
+ presence in both by 3.
+ The values returned by this function are PAIR_ST,
+ PAIR_CR, G_ST, G_CR, H_ST, H_CR, BOTH_G, BOTH_H, NONE.
+ PAIR_ST implies g in gTable and h in hTable
+ PAIR_CR implies g in hTable and h in gTable
+ G_ST implies g in gTable and h not in any table
+ G_CR implies g in hTable and h not in any table
+ H_ST implies h in hTable and g not in any table
+ H_CR implies h in gTable and g not in any table
+ BOTH_G implies both in gTable
+ BOTH_H implies both in hTable
+ NONE implies none in table; ]
+
+ SideEffects []
+
+ SeeAlso [CheckTablesCacheAndReturn CheckInTables]
+
+******************************************************************************/
+static int
+PairInTables(
+ DdNode * g,
+ DdNode * h,
+ st_table * ghTable)
+{
+ int valueG, valueH, gPresent, hPresent;
+
+ valueG = valueH = gPresent = hPresent = 0;
+
+ gPresent = st_lookup_int(ghTable, (char *)Cudd_Regular(g), &valueG);
+ hPresent = st_lookup_int(ghTable, (char *)Cudd_Regular(h), &valueH);
+
+ if (!gPresent && !hPresent) return(NONE);
+
+ if (!hPresent) {
+ if (valueG & 1) return(G_ST);
+ if (valueG & 2) return(G_CR);
+ }
+ if (!gPresent) {
+ if (valueH & 1) return(H_CR);
+ if (valueH & 2) return(H_ST);
+ }
+ /* both in tables */
+ if ((valueG & 1) && (valueH & 2)) return(PAIR_ST);
+ if ((valueG & 2) && (valueH & 1)) return(PAIR_CR);
+
+ if (valueG & 1) {
+ return(BOTH_G);
+ } else {
+ return(BOTH_H);
+ }
+
+} /* end of PairInTables */
+
+
+/**Function********************************************************************
+
+ Synopsis [Check the tables for the existence of pair and return one
+ combination, cache the result.]
+
+ Description [Check the tables for the existence of pair and return
+ one combination, cache the result. The assumption is that one of the
+ conjuncts is already in the tables.]
+
+ SideEffects [g and h referenced for the cache]
+
+ SeeAlso [ZeroCase]
+
+******************************************************************************/
+static Conjuncts *
+CheckTablesCacheAndReturn(
+ DdNode * node,
+ DdNode * g,
+ DdNode * h,
+ st_table * ghTable,
+ st_table * cacheTable)
+{
+ int pairValue;
+ int value;
+ Conjuncts *factors;
+
+ value = 0;
+ /* check tables */
+ pairValue = PairInTables(g, h, ghTable);
+ assert(pairValue != NONE);
+ /* if both dont exist in table, we know one exists(either g or h).
+ * Therefore store the other and proceed
+ */
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) return(NULL);
+ if ((pairValue == BOTH_H) || (pairValue == H_ST)) {
+ if (g != one) {
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(g), &value)) {
+ value |= 1;
+ } else {
+ value = 1;
+ }
+ if (st_insert(ghTable, (char *)Cudd_Regular(g),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ return(NULL);
+ }
+ }
+ factors->g = g;
+ factors->h = h;
+ } else if ((pairValue == BOTH_G) || (pairValue == G_ST)) {
+ if (h != one) {
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(h), &value)) {
+ value |= 2;
+ } else {
+ value = 2;
+ }
+ if (st_insert(ghTable, (char *)Cudd_Regular(h),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ return(NULL);
+ }
+ }
+ factors->g = g;
+ factors->h = h;
+ } else if (pairValue == H_CR) {
+ if (g != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ return(NULL);
+ }
+ }
+ factors->g = h;
+ factors->h = g;
+ } else if (pairValue == G_CR) {
+ if (h != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ return(NULL);
+ }
+ }
+ factors->g = h;
+ factors->h = g;
+ } else if (pairValue == PAIR_CR) {
+ /* pair exists in table */
+ factors->g = h;
+ factors->h = g;
+ } else if (pairValue == PAIR_ST) {
+ factors->g = g;
+ factors->h = h;
+ }
+
+ /* cache the result for this node */
+ if (st_insert(cacheTable, (char *)node, (char *)factors) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+
+ return(factors);
+
+} /* end of CheckTablesCacheAndReturn */
+
+/**Function********************************************************************
+
+ Synopsis [Check the tables for the existence of pair and return one
+ combination, store in cache.]
+
+ Description [Check the tables for the existence of pair and return
+ one combination, store in cache. The pair that has more pointers to
+ it is picked. An approximation of the number of local pointers is
+ made by taking the reference count of the pairs sent. ]
+
+ SideEffects []
+
+ SeeAlso [ZeroCase BuildConjuncts]
+
+******************************************************************************/
+static Conjuncts *
+PickOnePair(
+ DdNode * node,
+ DdNode * g1,
+ DdNode * h1,
+ DdNode * g2,
+ DdNode * h2,
+ st_table * ghTable,
+ st_table * cacheTable)
+{
+ int value;
+ Conjuncts *factors;
+ int oneRef, twoRef;
+
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) return(NULL);
+
+ /* count the number of pointers to pair 2 */
+ if (h2 == one) {
+ twoRef = (Cudd_Regular(g2))->ref;
+ } else if (g2 == one) {
+ twoRef = (Cudd_Regular(h2))->ref;
+ } else {
+ twoRef = ((Cudd_Regular(g2))->ref + (Cudd_Regular(h2))->ref)/2;
+ }
+
+ /* count the number of pointers to pair 1 */
+ if (h1 == one) {
+ oneRef = (Cudd_Regular(g1))->ref;
+ } else if (g1 == one) {
+ oneRef = (Cudd_Regular(h1))->ref;
+ } else {
+ oneRef = ((Cudd_Regular(g1))->ref + (Cudd_Regular(h1))->ref)/2;
+ }
+
+ /* pick the pair with higher reference count */
+ if (oneRef >= twoRef) {
+ factors->g = g1;
+ factors->h = h1;
+ } else {
+ factors->g = g2;
+ factors->h = h2;
+ }
+
+ /*
+ * Store computed factors in respective tables to encourage
+ * recombination.
+ */
+ if (factors->g != one) {
+ /* insert g in htable */
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(factors->g), &value)) {
+ if (value == 2) {
+ value |= 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(factors->g),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(factors->g),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ }
+
+ if (factors->h != one) {
+ /* insert h in htable */
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(factors->h), &value)) {
+ if (value == 1) {
+ value |= 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(factors->h),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(factors->h),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ }
+
+ /* Store factors in cache table for later use. */
+ if (st_insert(cacheTable, (char *)node, (char *)factors) ==
+ ST_OUT_OF_MEM) {
+ FREE(factors);
+ return(NULL);
+ }
+
+ return(factors);
+
+} /* end of PickOnePair */
+
+
+/**Function********************************************************************
+
+ Synopsis [Check if the two pairs exist in the table, If any of the
+ conjuncts do exist, store in the cache and return the corresponding pair.]
+
+ Description [Check if the two pairs exist in the table. If any of
+ the conjuncts do exist, store in the cache and return the
+ corresponding pair.]
+
+ SideEffects []
+
+ SeeAlso [ZeroCase BuildConjuncts]
+
+******************************************************************************/
+static Conjuncts *
+CheckInTables(
+ DdNode * node,
+ DdNode * g1,
+ DdNode * h1,
+ DdNode * g2,
+ DdNode * h2,
+ st_table * ghTable,
+ st_table * cacheTable,
+ int * outOfMem)
+{
+ int pairValue1, pairValue2;
+ Conjuncts *factors;
+ int value;
+
+ *outOfMem = 0;
+
+ /* check existence of pair in table */
+ pairValue1 = PairInTables(g1, h1, ghTable);
+ pairValue2 = PairInTables(g2, h2, ghTable);
+
+ /* if none of the 4 exist in the gh tables, return NULL */
+ if ((pairValue1 == NONE) && (pairValue2 == NONE)) {
+ return NULL;
+ }
+
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ *outOfMem = 1;
+ return NULL;
+ }
+
+ /* pairs that already exist in the table get preference. */
+ if (pairValue1 == PAIR_ST) {
+ factors->g = g1;
+ factors->h = h1;
+ } else if (pairValue2 == PAIR_ST) {
+ factors->g = g2;
+ factors->h = h2;
+ } else if (pairValue1 == PAIR_CR) {
+ factors->g = h1;
+ factors->h = g1;
+ } else if (pairValue2 == PAIR_CR) {
+ factors->g = h2;
+ factors->h = g2;
+ } else if (pairValue1 == G_ST) {
+ /* g exists in the table, h is not found in either table */
+ factors->g = g1;
+ factors->h = h1;
+ if (h1 != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == BOTH_G) {
+ /* g and h are found in the g table */
+ factors->g = g1;
+ factors->h = h1;
+ if (h1 != one) {
+ value = 3;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == H_ST) {
+ /* h exists in the table, g is not found in either table */
+ factors->g = g1;
+ factors->h = h1;
+ if (g1 != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == BOTH_H) {
+ /* g and h are found in the h table */
+ factors->g = g1;
+ factors->h = h1;
+ if (g1 != one) {
+ value = 3;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == G_ST) {
+ /* g exists in the table, h is not found in either table */
+ factors->g = g2;
+ factors->h = h2;
+ if (h2 != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == BOTH_G) {
+ /* g and h are found in the g table */
+ factors->g = g2;
+ factors->h = h2;
+ if (h2 != one) {
+ value = 3;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == H_ST) {
+ /* h exists in the table, g is not found in either table */
+ factors->g = g2;
+ factors->h = h2;
+ if (g2 != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == BOTH_H) {
+ /* g and h are found in the h table */
+ factors->g = g2;
+ factors->h = h2;
+ if (g2 != one) {
+ value = 3;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == G_CR) {
+ /* g found in h table and h in none */
+ factors->g = h1;
+ factors->h = g1;
+ if (h1 != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue1 == H_CR) {
+ /* h found in g table and g in none */
+ factors->g = h1;
+ factors->h = g1;
+ if (g1 != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g1),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == G_CR) {
+ /* g found in h table and h in none */
+ factors->g = h2;
+ factors->h = g2;
+ if (h2 != one) {
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(h2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ } else if (pairValue2 == H_CR) {
+ /* h found in g table and g in none */
+ factors->g = h2;
+ factors->h = g2;
+ if (g2 != one) {
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(g2),
+ (char *)(long)value) == ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ }
+ }
+
+ /* Store factors in cache table for later use. */
+ if (st_insert(cacheTable, (char *)node, (char *)factors) ==
+ ST_OUT_OF_MEM) {
+ *outOfMem = 1;
+ FREE(factors);
+ return(NULL);
+ }
+ return factors;
+} /* end of CheckInTables */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [If one child is zero, do explicitly what Restrict does or better]
+
+ Description [If one child is zero, do explicitly what Restrict does or better.
+ First separate a variable and its child in the base case. In case of a cube
+ times a function, separate the cube and function. As a last resort, look in
+ tables.]
+
+ SideEffects [Frees the BDDs in factorsNv. factorsNv itself is not freed
+ because it is freed above.]
+
+ SeeAlso [BuildConjuncts]
+
+******************************************************************************/
+static Conjuncts *
+ZeroCase(
+ DdManager * dd,
+ DdNode * node,
+ Conjuncts * factorsNv,
+ st_table * ghTable,
+ st_table * cacheTable,
+ int switched)
+{
+ int topid;
+ DdNode *g, *h, *g1, *g2, *h1, *h2, *x, *N, *G, *H, *Gv, *Gnv;
+ DdNode *Hv, *Hnv;
+ int value;
+ int outOfMem;
+ Conjuncts *factors;
+
+ /* get var at this node */
+ N = Cudd_Regular(node);
+ topid = N->index;
+ x = dd->vars[topid];
+ x = (switched) ? Cudd_Not(x): x;
+ cuddRef(x);
+
+ /* Seprate variable and child */
+ if (factorsNv->g == one) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, x);
+ return(NULL);
+ }
+ factors->g = x;
+ factors->h = factorsNv->h;
+ /* cache the result*/
+ if (st_insert(cacheTable, (char *)node, (char *)factors) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, x);
+ FREE(factors);
+ return NULL;
+ }
+
+ /* store x in g table, the other node is already in the table */
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(x), &value)) {
+ value |= 1;
+ } else {
+ value = 1;
+ }
+ if (st_insert(ghTable, (char *)Cudd_Regular(x), (char *)(long)value) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return NULL;
+ }
+ return(factors);
+ }
+
+ /* Seprate variable and child */
+ if (factorsNv->h == one) {
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, x);
+ return(NULL);
+ }
+ factors->g = factorsNv->g;
+ factors->h = x;
+ /* cache the result. */
+ if (st_insert(cacheTable, (char *)node, (char *)factors) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, x);
+ FREE(factors);
+ return(NULL);
+ }
+ /* store x in h table, the other node is already in the table */
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(x), &value)) {
+ value |= 2;
+ } else {
+ value = 2;
+ }
+ if (st_insert(ghTable, (char *)Cudd_Regular(x), (char *)(long)value) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return NULL;
+ }
+ return(factors);
+ }
+
+ G = Cudd_Regular(factorsNv->g);
+ Gv = cuddT(G);
+ Gnv = cuddE(G);
+ Gv = Cudd_NotCond(Gv, Cudd_IsComplement(node));
+ Gnv = Cudd_NotCond(Gnv, Cudd_IsComplement(node));
+ /* if the child below is a variable */
+ if ((Gv == zero) || (Gnv == zero)) {
+ h = factorsNv->h;
+ g = cuddBddAndRecur(dd, x, factorsNv->g);
+ if (g != NULL) cuddRef(g);
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, x);
+ if (g == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ return NULL;
+ }
+ /* CheckTablesCacheAndReturn responsible for allocating
+ * factors structure., g,h referenced for cache store the
+ */
+ factors = CheckTablesCacheAndReturn(node,
+ g,
+ h,
+ ghTable,
+ cacheTable);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g);
+ Cudd_RecursiveDeref(dd, h);
+ }
+ return(factors);
+ }
+
+ H = Cudd_Regular(factorsNv->h);
+ Hv = cuddT(H);
+ Hnv = cuddE(H);
+ Hv = Cudd_NotCond(Hv, Cudd_IsComplement(node));
+ Hnv = Cudd_NotCond(Hnv, Cudd_IsComplement(node));
+ /* if the child below is a variable */
+ if ((Hv == zero) || (Hnv == zero)) {
+ g = factorsNv->g;
+ h = cuddBddAndRecur(dd, x, factorsNv->h);
+ if (h!= NULL) cuddRef(h);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, x);
+ if (h == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ return NULL;
+ }
+ /* CheckTablesCacheAndReturn responsible for allocating
+ * factors structure.g,h referenced for table store
+ */
+ factors = CheckTablesCacheAndReturn(node,
+ g,
+ h,
+ ghTable,
+ cacheTable);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g);
+ Cudd_RecursiveDeref(dd, h);
+ }
+ return(factors);
+ }
+
+ /* build g1 = x*g; h1 = h */
+ /* build g2 = g; h2 = x*h */
+ Cudd_RecursiveDeref(dd, x);
+ h1 = factorsNv->h;
+ g1 = cuddBddAndRecur(dd, x, factorsNv->g);
+ if (g1 != NULL) cuddRef(g1);
+ if (g1 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ return NULL;
+ }
+
+ g2 = factorsNv->g;
+ h2 = cuddBddAndRecur(dd, x, factorsNv->h);
+ if (h2 != NULL) cuddRef(h2);
+ if (h2 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ return NULL;
+ }
+
+ /* check whether any pair is in tables */
+ factors = CheckInTables(node, g1, h1, g2, h2, ghTable, cacheTable, &outOfMem);
+ if (outOfMem) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ return NULL;
+ }
+ if (factors != NULL) {
+ if ((factors->g == g1) || (factors->g == h1)) {
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ }
+ return factors;
+ }
+
+ /* check for each pair in tables and choose one */
+ factors = PickOnePair(node,g1, h1, g2, h2, ghTable, cacheTable);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ /* now free what was created and not used */
+ if ((factors->g == g1) || (factors->g == h1)) {
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ }
+ }
+
+ return(factors);
+} /* end of ZeroCase */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the conjuncts recursively, bottom up.]
+
+ Description [Builds the conjuncts recursively, bottom up. Constants
+ are returned as (f, f). The cache is checked for previously computed
+ result. The decomposition points are determined by the local
+ reference count of this node and the longest distance from the
+ constant. At the decomposition point, the factors returned are (f,
+ 1). Recur on the two children. The order is determined by the
+ heavier branch. Combine the factors of the two children and pick the
+ one that already occurs in the gh table. Occurence in g is indicated
+ by value 1, occurence in h by 2, occurence in both 3.]
+
+ SideEffects []
+
+ SeeAlso [cuddConjunctsAux]
+
+******************************************************************************/
+static Conjuncts *
+BuildConjuncts(
+ DdManager * dd,
+ DdNode * node,
+ st_table * distanceTable,
+ st_table * cacheTable,
+ int approxDistance,
+ int maxLocalRef,
+ st_table * ghTable,
+ st_table * mintermTable)
+{
+ int topid, distance;
+ Conjuncts *factorsNv, *factorsNnv, *factors;
+ Conjuncts *dummy;
+ DdNode *N, *Nv, *Nnv, *temp, *g1, *g2, *h1, *h2, *topv;
+ double minNv = 0.0, minNnv = 0.0;
+ double *doubleDummy;
+ int switched =0;
+ int outOfMem;
+ int freeNv = 0, freeNnv = 0, freeTemp;
+ NodeStat *nodeStat;
+ int value;
+
+ /* if f is constant, return (f,f) */
+ if (Cudd_IsConstant(node)) {
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ factors->g = node;
+ factors->h = node;
+ return(FactorsComplement(factors));
+ }
+
+ /* If result (a pair of conjuncts) in cache, return the factors. */
+ if (st_lookup(cacheTable, (char *)node, (char **)&dummy)) {
+ factors = dummy;
+ return(factors);
+ }
+
+ /* check distance and local reference count of this node */
+ N = Cudd_Regular(node);
+ if (!st_lookup(distanceTable, (char *)N, (char **)&nodeStat)) {
+ (void) fprintf(dd->err, "Not in table, Something wrong\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ distance = nodeStat->distance;
+
+ /* at or below decomposition point, return (f, 1) */
+ if (((nodeStat->localRef > maxLocalRef*2/3) &&
+ (distance < approxDistance*2/3)) ||
+ (distance <= approxDistance/4)) {
+ factors = ALLOC(Conjuncts, 1);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ /* alternate assigning (f,1) */
+ value = 0;
+ if (st_lookup_int(ghTable, (char *)Cudd_Regular(node), &value)) {
+ if (value == 3) {
+ if (!lastTimeG) {
+ factors->g = node;
+ factors->h = one;
+ lastTimeG = 1;
+ } else {
+ factors->g = one;
+ factors->h = node;
+ lastTimeG = 0;
+ }
+ } else if (value == 1) {
+ factors->g = node;
+ factors->h = one;
+ } else {
+ factors->g = one;
+ factors->h = node;
+ }
+ } else if (!lastTimeG) {
+ factors->g = node;
+ factors->h = one;
+ lastTimeG = 1;
+ value = 1;
+ if (st_insert(ghTable, (char *)Cudd_Regular(node), (char *)(long)value) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(factors);
+ return NULL;
+ }
+ } else {
+ factors->g = one;
+ factors->h = node;
+ lastTimeG = 0;
+ value = 2;
+ if (st_insert(ghTable, (char *)Cudd_Regular(node), (char *)(long)value) == ST_OUT_OF_MEM) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ FREE(factors);
+ return NULL;
+ }
+ }
+ return(FactorsComplement(factors));
+ }
+
+ /* get the children and recur */
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
+ Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
+
+ /* Choose which subproblem to solve first based on the number of
+ * minterms. We go first where there are more minterms.
+ */
+ if (!Cudd_IsConstant(Nv)) {
+ if (!st_lookup(mintermTable, (char *)Nv, (char **)&doubleDummy)) {
+ (void) fprintf(dd->err, "Not in table: Something wrong\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ minNv = *doubleDummy;
+ }
+
+ if (!Cudd_IsConstant(Nnv)) {
+ if (!st_lookup(mintermTable, (char *)Nnv, (char **)&doubleDummy)) {
+ (void) fprintf(dd->err, "Not in table: Something wrong\n");
+ dd->errorCode = CUDD_INTERNAL_ERROR;
+ return(NULL);
+ }
+ minNnv = *doubleDummy;
+ }
+
+ if (minNv < minNnv) {
+ temp = Nv;
+ Nv = Nnv;
+ Nnv = temp;
+ switched = 1;
+ }
+
+ /* build gt, ht recursively */
+ if (Nv != zero) {
+ factorsNv = BuildConjuncts(dd, Nv, distanceTable,
+ cacheTable, approxDistance, maxLocalRef,
+ ghTable, mintermTable);
+ if (factorsNv == NULL) return(NULL);
+ freeNv = FactorsNotStored(factorsNv);
+ factorsNv = (freeNv) ? FactorsUncomplement(factorsNv) : factorsNv;
+ cuddRef(factorsNv->g);
+ cuddRef(factorsNv->h);
+
+ /* Deal with the zero case */
+ if (Nnv == zero) {
+ /* is responsible for freeing factorsNv */
+ factors = ZeroCase(dd, node, factorsNv, ghTable,
+ cacheTable, switched);
+ if (freeNv) FREE(factorsNv);
+ return(factors);
+ }
+ }
+
+ /* build ge, he recursively */
+ if (Nnv != zero) {
+ factorsNnv = BuildConjuncts(dd, Nnv, distanceTable,
+ cacheTable, approxDistance, maxLocalRef,
+ ghTable, mintermTable);
+ if (factorsNnv == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ if (freeNv) FREE(factorsNv);
+ return(NULL);
+ }
+ freeNnv = FactorsNotStored(factorsNnv);
+ factorsNnv = (freeNnv) ? FactorsUncomplement(factorsNnv) : factorsNnv;
+ cuddRef(factorsNnv->g);
+ cuddRef(factorsNnv->h);
+
+ /* Deal with the zero case */
+ if (Nv == zero) {
+ /* is responsible for freeing factorsNv */
+ factors = ZeroCase(dd, node, factorsNnv, ghTable,
+ cacheTable, switched);
+ if (freeNnv) FREE(factorsNnv);
+ return(factors);
+ }
+ }
+
+ /* construct the 2 pairs */
+ /* g1 = x*gt + x'*ge; h1 = x*ht + x'*he; */
+ /* g2 = x*gt + x'*he; h2 = x*ht + x'*ge */
+ if (switched) {
+ factors = factorsNnv;
+ factorsNnv = factorsNv;
+ factorsNv = factors;
+ freeTemp = freeNv;
+ freeNv = freeNnv;
+ freeNnv = freeTemp;
+ }
+
+ /* Build the factors for this node. */
+ topid = N->index;
+ topv = dd->vars[topid];
+
+ g1 = cuddBddIteRecur(dd, topv, factorsNv->g, factorsNnv->g);
+ if (g1 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+ return(NULL);
+ }
+
+ cuddRef(g1);
+
+ h1 = cuddBddIteRecur(dd, topv, factorsNv->h, factorsNnv->h);
+ if (h1 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+ Cudd_RecursiveDeref(dd, g1);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+ return(NULL);
+ }
+
+ cuddRef(h1);
+
+ g2 = cuddBddIteRecur(dd, topv, factorsNv->g, factorsNnv->h);
+ if (g2 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+ return(NULL);
+ }
+ cuddRef(g2);
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+
+ h2 = cuddBddIteRecur(dd, topv, factorsNv->h, factorsNnv->g);
+ if (h2 == NULL) {
+ Cudd_RecursiveDeref(dd, factorsNv->g);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ Cudd_RecursiveDeref(dd, factorsNnv->h);
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+ return(NULL);
+ }
+ cuddRef(h2);
+ Cudd_RecursiveDeref(dd, factorsNv->h);
+ Cudd_RecursiveDeref(dd, factorsNnv->g);
+ if (freeNv) FREE(factorsNv);
+ if (freeNnv) FREE(factorsNnv);
+
+ /* check for each pair in tables and choose one */
+ factors = CheckInTables(node, g1, h1, g2, h2, ghTable, cacheTable, &outOfMem);
+ if (outOfMem) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ return(NULL);
+ }
+ if (factors != NULL) {
+ if ((factors->g == g1) || (factors->g == h1)) {
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ }
+ return(factors);
+ }
+
+ /* if not in tables, pick one pair */
+ factors = PickOnePair(node,g1, h1, g2, h2, ghTable, cacheTable);
+ if (factors == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ /* now free what was created and not used */
+ if ((factors->g == g1) || (factors->g == h1)) {
+ Cudd_RecursiveDeref(dd, g2);
+ Cudd_RecursiveDeref(dd, h2);
+ } else {
+ Cudd_RecursiveDeref(dd, g1);
+ Cudd_RecursiveDeref(dd, h1);
+ }
+ }
+
+ return(factors);
+
+} /* end of BuildConjuncts */
+
+
+/**Function********************************************************************
+
+ Synopsis [Procedure to compute two conjunctive factors of f and place in *c1 and *c2.]
+
+ Description [Procedure to compute two conjunctive factors of f and
+ place in *c1 and *c2. Sets up the required data - table of distances
+ from the constant and local reference count. Also minterm table. ]
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+static int
+cuddConjunctsAux(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** c1,
+ DdNode ** c2)
+{
+ st_table *distanceTable = NULL;
+ st_table *cacheTable = NULL;
+ st_table *mintermTable = NULL;
+ st_table *ghTable = NULL;
+ st_generator *stGen;
+ char *key, *value;
+ Conjuncts *factors;
+ int distance, approxDistance;
+ double max, minterms;
+ int freeFactors;
+ NodeStat *nodeStat;
+ int maxLocalRef;
+
+ /* initialize */
+ *c1 = NULL;
+ *c2 = NULL;
+
+ /* initialize distances table */
+ distanceTable = st_init_table(st_ptrcmp,st_ptrhash);
+ if (distanceTable == NULL) goto outOfMem;
+
+ /* make the entry for the constant */
+ nodeStat = ALLOC(NodeStat, 1);
+ if (nodeStat == NULL) goto outOfMem;
+ nodeStat->distance = 0;
+ nodeStat->localRef = 1;
+ if (st_insert(distanceTable, (char *)one, (char *)nodeStat) == ST_OUT_OF_MEM) {
+ goto outOfMem;
+ }
+
+ /* Count node distances from constant. */
+ nodeStat = CreateBotDist(f, distanceTable);
+ if (nodeStat == NULL) goto outOfMem;
+
+ /* set the distance for the decomposition points */
+ approxDistance = (DEPTH < nodeStat->distance) ? nodeStat->distance : DEPTH;
+ distance = nodeStat->distance;
+
+ if (distance < approxDistance) {
+ /* Too small to bother. */
+ *c1 = f;
+ *c2 = DD_ONE(dd);
+ cuddRef(*c1); cuddRef(*c2);
+ stGen = st_init_gen(distanceTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(distanceTable);
+ return(1);
+ }
+
+ /* record the maximum local reference count */
+ maxLocalRef = 0;
+ stGen = st_init_gen(distanceTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ nodeStat = (NodeStat *)value;
+ maxLocalRef = (nodeStat->localRef > maxLocalRef) ?
+ nodeStat->localRef : maxLocalRef;
+ }
+ st_free_gen(stGen); stGen = NULL;
+
+
+ /* Count minterms for each node. */
+ max = pow(2.0, (double)Cudd_SupportSize(dd,f)); /* potential overflow */
+ mintermTable = st_init_table(st_ptrcmp,st_ptrhash);
+ if (mintermTable == NULL) goto outOfMem;
+ minterms = CountMinterms(f, max, mintermTable, dd->err);
+ if (minterms == -1.0) goto outOfMem;
+
+ lastTimeG = Cudd_Random() & 1;
+ cacheTable = st_init_table(st_ptrcmp, st_ptrhash);
+ if (cacheTable == NULL) goto outOfMem;
+ ghTable = st_init_table(st_ptrcmp, st_ptrhash);
+ if (ghTable == NULL) goto outOfMem;
+
+ /* Build conjuncts. */
+ factors = BuildConjuncts(dd, f, distanceTable, cacheTable,
+ approxDistance, maxLocalRef, ghTable, mintermTable);
+ if (factors == NULL) goto outOfMem;
+
+ /* free up tables */
+ stGen = st_init_gen(distanceTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(distanceTable); distanceTable = NULL;
+ st_free_table(ghTable); ghTable = NULL;
+
+ stGen = st_init_gen(mintermTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(mintermTable); mintermTable = NULL;
+
+ freeFactors = FactorsNotStored(factors);
+ factors = (freeFactors) ? FactorsUncomplement(factors) : factors;
+ if (factors != NULL) {
+ *c1 = factors->g;
+ *c2 = factors->h;
+ cuddRef(*c1);
+ cuddRef(*c2);
+ if (freeFactors) FREE(factors);
+
+#if 0
+ if ((*c1 == f) && (!Cudd_IsConstant(f))) {
+ assert(*c2 == one);
+ }
+ if ((*c2 == f) && (!Cudd_IsConstant(f))) {
+ assert(*c1 == one);
+ }
+
+ if ((*c1 != one) && (!Cudd_IsConstant(f))) {
+ assert(!Cudd_bddLeq(dd, *c2, *c1));
+ }
+ if ((*c2 != one) && (!Cudd_IsConstant(f))) {
+ assert(!Cudd_bddLeq(dd, *c1, *c2));
+ }
+#endif
+ }
+
+ stGen = st_init_gen(cacheTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ ConjunctsFree(dd, (Conjuncts *)value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+
+ st_free_table(cacheTable); cacheTable = NULL;
+
+ return(1);
+
+outOfMem:
+ if (distanceTable != NULL) {
+ stGen = st_init_gen(distanceTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(distanceTable); distanceTable = NULL;
+ }
+ if (mintermTable != NULL) {
+ stGen = st_init_gen(mintermTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ FREE(value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(mintermTable); mintermTable = NULL;
+ }
+ if (ghTable != NULL) st_free_table(ghTable);
+ if (cacheTable != NULL) {
+ stGen = st_init_gen(cacheTable);
+ if (stGen == NULL) goto outOfMem;
+ while(st_gen(stGen, (char **)&key, (char **)&value)) {
+ ConjunctsFree(dd, (Conjuncts *)value);
+ }
+ st_free_gen(stGen); stGen = NULL;
+ st_free_table(cacheTable); cacheTable = NULL;
+ }
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(0);
+
+} /* end of cuddConjunctsAux */