summaryrefslogtreecommitdiffstats
path: root/src/bdd/cudd/cuddGenCof.c
diff options
context:
space:
mode:
authorAlan Mishchenko <alanmi@berkeley.edu>2005-07-29 08:01:00 -0700
committerAlan Mishchenko <alanmi@berkeley.edu>2005-07-29 08:01:00 -0700
commit888e5bed5d7f56a5d86d91a6e8e88f3e5a3454dc (patch)
tree11d48c9e9069f54dc300c3571ae63c744c802c50 /src/bdd/cudd/cuddGenCof.c
parent7f94414388cce67bd3cc1a6d6269f0ed31ed0d06 (diff)
downloadabc-888e5bed5d7f56a5d86d91a6e8e88f3e5a3454dc.tar.gz
abc-888e5bed5d7f56a5d86d91a6e8e88f3e5a3454dc.tar.bz2
abc-888e5bed5d7f56a5d86d91a6e8e88f3e5a3454dc.zip
Version abc50729
Diffstat (limited to 'src/bdd/cudd/cuddGenCof.c')
-rw-r--r--src/bdd/cudd/cuddGenCof.c1968
1 files changed, 1968 insertions, 0 deletions
diff --git a/src/bdd/cudd/cuddGenCof.c b/src/bdd/cudd/cuddGenCof.c
new file mode 100644
index 00000000..59ae55d7
--- /dev/null
+++ b/src/bdd/cudd/cuddGenCof.c
@@ -0,0 +1,1968 @@
+/**CFile***********************************************************************
+
+ FileName [cuddGenCof.c]
+
+ PackageName [cudd]
+
+ Synopsis [Generalized cofactors for BDDs and ADDs.]
+
+ Description [External procedures included in this module:
+ <ul>
+ <li> Cudd_bddConstrain()
+ <li> Cudd_bddRestrict()
+ <li> Cudd_addConstrain()
+ <li> Cudd_bddConstrainDecomp()
+ <li> Cudd_addRestrict()
+ <li> Cudd_bddCharToVect()
+ <li> Cudd_bddLICompaction()
+ <li> Cudd_bddSqueeze()
+ <li> Cudd_SubsetCompress()
+ <li> Cudd_SupersetCompress()
+ </ul>
+ Internal procedures included in this module:
+ <ul>
+ <li> cuddBddConstrainRecur()
+ <li> cuddBddRestrictRecur()
+ <li> cuddAddConstrainRecur()
+ <li> cuddAddRestrictRecur()
+ <li> cuddBddLICompaction()
+ </ul>
+ Static procedures included in this module:
+ <ul>
+ <li> cuddBddConstrainDecomp()
+ <li> cuddBddCharToVect()
+ <li> cuddBddLICMarkEdges()
+ <li> cuddBddLICBuildResult()
+ <li> cuddBddSqueeze()
+ </ul>
+ ]
+
+ Author [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.h"
+#include "cuddInt.h"
+
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Codes for edge markings in Cudd_bddLICompaction. The codes are defined
+** so that they can be bitwise ORed to implement the code priority scheme.
+*/
+#define DD_LIC_DC 0
+#define DD_LIC_1 1
+#define DD_LIC_0 2
+#define DD_LIC_NL 3
+
+/*---------------------------------------------------------------------------*/
+/* Stucture declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+/* Key for the cache used in the edge marking phase. */
+typedef struct MarkCacheKey {
+ DdNode *f;
+ DdNode *c;
+} MarkCacheKey;
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+#ifndef lint
+static char rcsid[] DD_UNUSED = "$Id: cuddGenCof.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static int cuddBddConstrainDecomp ARGS((DdManager *dd, DdNode *f, DdNode **decomp));
+static DdNode * cuddBddCharToVect ARGS((DdManager *dd, DdNode *f, DdNode *x));
+static int cuddBddLICMarkEdges ARGS((DdManager *dd, DdNode *f, DdNode *c, st_table *table, st_table *cache));
+static DdNode * cuddBddLICBuildResult ARGS((DdManager *dd, DdNode *f, st_table *cache, st_table *table));
+static int MarkCacheHash ARGS((char *ptr, int modulus));
+static int MarkCacheCompare ARGS((const char *ptr1, const char *ptr2));
+static enum st_retval MarkCacheCleanUp ARGS((char *key, char *value, char *arg));
+static DdNode * cuddBddSqueeze ARGS((DdManager *dd, DdNode *l, DdNode *u));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes f constrain c.]
+
+ Description [Computes f constrain c (f @ c).
+ Uses a canonical form: (f' @ c) = ( f @ c)'. (Note: this is not true
+ for c.) List of special cases:
+ <ul>
+ <li> f @ 0 = 0
+ <li> f @ 1 = f
+ <li> 0 @ c = 0
+ <li> 1 @ c = 1
+ <li> f @ f = 1
+ <li> f @ f'= 0
+ </ul>
+ Returns a pointer to the result if successful; NULL otherwise. Note that if
+ F=(f1,...,fn) and reordering takes place while computing F @ c, then the
+ image restriction property (Img(F,c) = Img(F @ c)) is lost.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict Cudd_addConstrain]
+
+******************************************************************************/
+DdNode *
+Cudd_bddConstrain(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddConstrainRecur(dd,f,c);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddConstrain */
+
+
+/**Function********************************************************************
+
+ Synopsis [BDD restrict according to Coudert and Madre's algorithm
+ (ICCAD90).]
+
+ Description [BDD restrict according to Coudert and Madre's algorithm
+ (ICCAD90). Returns the restricted BDD if successful; otherwise NULL.
+ If application of restrict results in a BDD larger than the input
+ BDD, the input BDD is returned.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain Cudd_addRestrict]
+
+******************************************************************************/
+DdNode *
+Cudd_bddRestrict(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *suppF, *suppC, *commonSupport;
+ DdNode *cplus, *res;
+ int retval;
+ int sizeF, sizeRes;
+
+ /* Check terminal cases here to avoid computing supports in trivial cases.
+ ** This also allows us notto check later for the case c == 0, in which
+ ** there is no common support. */
+ if (c == Cudd_Not(DD_ONE(dd))) return(Cudd_Not(DD_ONE(dd)));
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(DD_ONE(dd));
+ if (f == Cudd_Not(c)) return(Cudd_Not(DD_ONE(dd)));
+
+ /* Check if supports intersect. */
+ retval = Cudd_ClassifySupport(dd,f,c,&commonSupport,&suppF,&suppC);
+ if (retval == 0) {
+ return(NULL);
+ }
+ cuddRef(commonSupport); cuddRef(suppF); cuddRef(suppC);
+ Cudd_IterDerefBdd(dd,suppF);
+
+ if (commonSupport == DD_ONE(dd)) {
+ Cudd_IterDerefBdd(dd,commonSupport);
+ Cudd_IterDerefBdd(dd,suppC);
+ return(f);
+ }
+ Cudd_IterDerefBdd(dd,commonSupport);
+
+ /* Abstract from c the variables that do not appear in f. */
+ cplus = Cudd_bddExistAbstract(dd, c, suppC);
+ if (cplus == NULL) {
+ Cudd_IterDerefBdd(dd,suppC);
+ return(NULL);
+ }
+ cuddRef(cplus);
+ Cudd_IterDerefBdd(dd,suppC);
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddRestrictRecur(dd, f, cplus);
+ } while (dd->reordered == 1);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd,cplus);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,cplus);
+ /* Make restric safe by returning the smaller of the input and the
+ ** result. */
+ sizeF = Cudd_DagSize(f);
+ sizeRes = Cudd_DagSize(res);
+ if (sizeF <= sizeRes) {
+ Cudd_IterDerefBdd(dd, res);
+ return(f);
+ } else {
+ cuddDeref(res);
+ return(res);
+ }
+
+} /* end of Cudd_bddRestrict */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes f constrain c for ADDs.]
+
+ Description [Computes f constrain c (f @ c), for f an ADD and c a 0-1
+ ADD. List of special cases:
+ <ul>
+ <li> F @ 0 = 0
+ <li> F @ 1 = F
+ <li> 0 @ c = 0
+ <li> 1 @ c = 1
+ <li> F @ F = 1
+ </ul>
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain]
+
+******************************************************************************/
+DdNode *
+Cudd_addConstrain(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddAddConstrainRecur(dd,f,c);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_addConstrain */
+
+
+/**Function********************************************************************
+
+ Synopsis [BDD conjunctive decomposition as in McMillan's CAV96 paper.]
+
+ Description [BDD conjunctive decomposition as in McMillan's CAV96
+ paper. The decomposition is canonical only for a given variable
+ order. If canonicity is required, variable ordering must be disabled
+ after the decomposition has been computed. Returns an array with one
+ entry for each BDD variable in the manager if successful; otherwise
+ NULL. The components of the solution have their reference counts
+ already incremented (unlike the results of most other functions in
+ the package.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain Cudd_bddExistAbstract]
+
+******************************************************************************/
+DdNode **
+Cudd_bddConstrainDecomp(
+ DdManager * dd,
+ DdNode * f)
+{
+ DdNode **decomp;
+ int res;
+ int i;
+
+ /* Create an initialize decomposition array. */
+ decomp = ALLOC(DdNode *,dd->size);
+ if (decomp == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < dd->size; i++) {
+ decomp[i] = NULL;
+ }
+ do {
+ dd->reordered = 0;
+ /* Clean up the decomposition array in case reordering took place. */
+ for (i = 0; i < dd->size; i++) {
+ if (decomp[i] != NULL) {
+ Cudd_IterDerefBdd(dd, decomp[i]);
+ decomp[i] = NULL;
+ }
+ }
+ res = cuddBddConstrainDecomp(dd,f,decomp);
+ } while (dd->reordered == 1);
+ if (res == 0) {
+ FREE(decomp);
+ return(NULL);
+ }
+ /* Missing components are constant ones. */
+ for (i = 0; i < dd->size; i++) {
+ if (decomp[i] == NULL) {
+ decomp[i] = DD_ONE(dd);
+ cuddRef(decomp[i]);
+ }
+ }
+ return(decomp);
+
+} /* end of Cudd_bddConstrainDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [ADD restrict according to Coudert and Madre's algorithm
+ (ICCAD90).]
+
+ Description [ADD restrict according to Coudert and Madre's algorithm
+ (ICCAD90). Returns the restricted ADD if successful; otherwise NULL.
+ If application of restrict results in an ADD larger than the input
+ ADD, the input ADD is returned.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addConstrain Cudd_bddRestrict]
+
+******************************************************************************/
+DdNode *
+Cudd_addRestrict(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *supp_f, *supp_c;
+ DdNode *res, *commonSupport;
+ int intersection;
+ int sizeF, sizeRes;
+
+ /* Check if supports intersect. */
+ supp_f = Cudd_Support(dd, f);
+ if (supp_f == NULL) {
+ return(NULL);
+ }
+ cuddRef(supp_f);
+ supp_c = Cudd_Support(dd, c);
+ if (supp_c == NULL) {
+ Cudd_RecursiveDeref(dd,supp_f);
+ return(NULL);
+ }
+ cuddRef(supp_c);
+ commonSupport = Cudd_bddLiteralSetIntersection(dd, supp_f, supp_c);
+ if (commonSupport == NULL) {
+ Cudd_RecursiveDeref(dd,supp_f);
+ Cudd_RecursiveDeref(dd,supp_c);
+ return(NULL);
+ }
+ cuddRef(commonSupport);
+ Cudd_RecursiveDeref(dd,supp_f);
+ Cudd_RecursiveDeref(dd,supp_c);
+ intersection = commonSupport != DD_ONE(dd);
+ Cudd_RecursiveDeref(dd,commonSupport);
+
+ if (intersection) {
+ do {
+ dd->reordered = 0;
+ res = cuddAddRestrictRecur(dd, f, c);
+ } while (dd->reordered == 1);
+ sizeF = Cudd_DagSize(f);
+ sizeRes = Cudd_DagSize(res);
+ if (sizeF <= sizeRes) {
+ cuddRef(res);
+ Cudd_RecursiveDeref(dd, res);
+ return(f);
+ } else {
+ return(res);
+ }
+ } else {
+ return(f);
+ }
+
+} /* end of Cudd_addRestrict */
+
+
+/**Function********************************************************************
+
+ Synopsis [Computes a vector whose image equals a non-zero function.]
+
+ Description [Computes a vector of BDDs whose image equals a non-zero
+ function.
+ The result depends on the variable order. The i-th component of the vector
+ depends only on the first i variables in the order. Each BDD in the vector
+ is not larger than the BDD of the given characteristic function. This
+ function is based on the description of char-to-vect in "Verification of
+ Sequential Machines Using Boolean Functional Vectors" by O. Coudert, C.
+ Berthet and J. C. Madre.
+ Returns a pointer to an array containing the result if successful; NULL
+ otherwise. The size of the array equals the number of variables in the
+ manager. The components of the solution have their reference counts
+ already incremented (unlike the results of most other functions in
+ the package.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain]
+
+******************************************************************************/
+DdNode **
+Cudd_bddCharToVect(
+ DdManager * dd,
+ DdNode * f)
+{
+ int i, j;
+ DdNode **vect;
+ DdNode *res = NULL;
+
+ if (f == Cudd_Not(DD_ONE(dd))) return(NULL);
+
+ vect = ALLOC(DdNode *, dd->size);
+ if (vect == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ do {
+ dd->reordered = 0;
+ for (i = 0; i < dd->size; i++) {
+ res = cuddBddCharToVect(dd,f,dd->vars[dd->invperm[i]]);
+ if (res == NULL) {
+ /* Clean up the vector array in case reordering took place. */
+ for (j = 0; j < i; j++) {
+ Cudd_IterDerefBdd(dd, vect[dd->invperm[j]]);
+ }
+ break;
+ }
+ cuddRef(res);
+ vect[dd->invperm[i]] = res;
+ }
+ } while (dd->reordered == 1);
+ if (res == NULL) {
+ FREE(vect);
+ return(NULL);
+ }
+ return(vect);
+
+} /* end of Cudd_bddCharToVect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs safe minimization of a BDD.]
+
+ Description [Performs safe minimization of a BDD. Given the BDD
+ <code>f</code> of a function to be minimized and a BDD
+ <code>c</code> representing the care set, Cudd_bddLICompaction
+ produces the BDD of a function that agrees with <code>f</code>
+ wherever <code>c</code> is 1. Safe minimization means that the size
+ of the result is guaranteed not to exceed the size of
+ <code>f</code>. This function is based on the DAC97 paper by Hong et
+ al.. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict]
+
+******************************************************************************/
+DdNode *
+Cudd_bddLICompaction(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be minimized */,
+ DdNode * c /* constraint (care set) */)
+{
+ DdNode *res;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddLICompaction(dd,f,c);
+ } while (dd->reordered == 1);
+ return(res);
+
+} /* end of Cudd_bddLICompaction */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a small BDD in a function interval.]
+
+ Description [Finds a small BDD in a function interval. Given BDDs
+ <code>l</code> and <code>u</code>, representing the lower bound and
+ upper bound of a function interval, Cudd_bddSqueeze produces the BDD
+ of a function within the interval with a small BDD. Returns a
+ pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict Cudd_bddLICompaction]
+
+******************************************************************************/
+DdNode *
+Cudd_bddSqueeze(
+ DdManager * dd /* manager */,
+ DdNode * l /* lower bound */,
+ DdNode * u /* upper bound */)
+{
+ DdNode *res;
+ int sizeRes, sizeL, sizeU;
+
+ do {
+ dd->reordered = 0;
+ res = cuddBddSqueeze(dd,l,u);
+ } while (dd->reordered == 1);
+ if (res == NULL) return(NULL);
+ /* We now compare the result with the bounds and return the smallest.
+ ** We first compare to u, so that in case l == 0 and u == 1, we return
+ ** 0 as in other minimization algorithms. */
+ sizeRes = Cudd_DagSize(res);
+ sizeU = Cudd_DagSize(u);
+ if (sizeU <= sizeRes) {
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,res);
+ res = u;
+ sizeRes = sizeU;
+ }
+ sizeL = Cudd_DagSize(l);
+ if (sizeL <= sizeRes) {
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,res);
+ res = l;
+ sizeRes = sizeL;
+ }
+ return(res);
+
+} /* end of Cudd_bddSqueeze */
+
+
+/**Function********************************************************************
+
+ Synopsis [Finds a small BDD that agrees with <code>f</code> over
+ <code>c</code>.]
+
+ Description [Finds a small BDD that agrees with <code>f</code> over
+ <code>c</code>. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict Cudd_bddLICompaction Cudd_bddSqueeze]
+
+******************************************************************************/
+DdNode *
+Cudd_bddMinimize(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *cplus, *res;
+
+ if (c == Cudd_Not(DD_ONE(dd))) return(c);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(DD_ONE(dd));
+ if (f == Cudd_Not(c)) return(Cudd_Not(DD_ONE(dd)));
+
+ cplus = Cudd_RemapOverApprox(dd,c,0,0,1.0);
+ if (cplus == NULL) return(NULL);
+ cuddRef(cplus);
+ res = Cudd_bddLICompaction(dd,f,cplus);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd,cplus);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,cplus);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_bddMinimize */
+
+
+/**Function********************************************************************
+
+ Synopsis [Find a dense subset of BDD <code>f</code>.]
+
+ Description [Finds a dense subset of BDD <code>f</code>. Density is
+ the ratio of number of minterms to number of nodes. Uses several
+ techniques in series. It is more expensive than other subsetting
+ procedures, but often produces better results. See
+ Cudd_SubsetShortPaths for a description of the threshold and nvars
+ parameters. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetRemap Cudd_SubsetShortPaths Cudd_SubsetHeavyBranch
+ Cudd_bddSqueeze]
+
+******************************************************************************/
+DdNode *
+Cudd_SubsetCompress(
+ DdManager * dd /* manager */,
+ DdNode * f /* BDD whose subset is sought */,
+ int nvars /* number of variables in the support of f */,
+ int threshold /* maximum number of nodes in the subset */)
+{
+ DdNode *res, *tmp1, *tmp2;
+
+ tmp1 = Cudd_SubsetShortPaths(dd, f, nvars, threshold, 0);
+ if (tmp1 == NULL) return(NULL);
+ cuddRef(tmp1);
+ tmp2 = Cudd_RemapUnderApprox(dd,tmp1,nvars,0,1.0);
+ if (tmp2 == NULL) {
+ Cudd_IterDerefBdd(dd,tmp1);
+ return(NULL);
+ }
+ cuddRef(tmp2);
+ Cudd_IterDerefBdd(dd,tmp1);
+ res = Cudd_bddSqueeze(dd,tmp2,f);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd,tmp2);
+ return(NULL);
+ }
+ cuddRef(res);
+ Cudd_IterDerefBdd(dd,tmp2);
+ cuddDeref(res);
+ return(res);
+
+} /* end of Cudd_SubsetCompress */
+
+
+/**Function********************************************************************
+
+ Synopsis [Find a dense superset of BDD <code>f</code>.]
+
+ Description [Finds a dense superset of BDD <code>f</code>. Density is
+ the ratio of number of minterms to number of nodes. Uses several
+ techniques in series. It is more expensive than other supersetting
+ procedures, but often produces better results. See
+ Cudd_SupersetShortPaths for a description of the threshold and nvars
+ parameters. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_SubsetCompress Cudd_SupersetRemap Cudd_SupersetShortPaths
+ Cudd_SupersetHeavyBranch Cudd_bddSqueeze]
+
+******************************************************************************/
+DdNode *
+Cudd_SupersetCompress(
+ DdManager * dd /* manager */,
+ DdNode * f /* BDD whose superset is sought */,
+ int nvars /* number of variables in the support of f */,
+ int threshold /* maximum number of nodes in the superset */)
+{
+ DdNode *subset;
+
+ subset = Cudd_SubsetCompress(dd, Cudd_Not(f),nvars,threshold);
+
+ return(Cudd_NotCond(subset, (subset != NULL)));
+
+} /* end of Cudd_SupersetCompress */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddConstrain.]
+
+ Description [Performs the recursive step of Cudd_bddConstrain.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrain]
+
+******************************************************************************/
+DdNode *
+cuddBddConstrainRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r;
+ DdNode *one, *zero;
+ unsigned int topf, topc;
+ int index;
+ int comple = 0;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Trivial cases. */
+ if (c == one) return(f);
+ if (c == zero) return(zero);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(one);
+ if (f == Cudd_Not(c)) return(zero);
+
+ /* Make canonical to increase the utilization of the cache. */
+ if (Cudd_IsComplement(f)) {
+ f = Cudd_Not(f);
+ comple = 1;
+ }
+ /* Now f is a regular pointer to a non-constant node; c is also
+ ** non-constant, but may be complemented.
+ */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_bddConstrain, f, c);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ /* Recursive step. */
+ topf = dd->perm[f->index];
+ topc = dd->perm[Cudd_Regular(c)->index];
+ if (topf <= topc) {
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ index = Cudd_Regular(c)->index;
+ Fv = Fnv = f;
+ }
+ if (topc <= topf) {
+ Cv = cuddT(Cudd_Regular(c)); Cnv = cuddE(Cudd_Regular(c));
+ if (Cudd_IsComplement(c)) {
+ Cv = Cudd_Not(Cv);
+ Cnv = Cudd_Not(Cnv);
+ }
+ } else {
+ Cv = Cnv = c;
+ }
+
+ if (!Cudd_IsConstant(Cv)) {
+ t = cuddBddConstrainRecur(dd, Fv, Cv);
+ if (t == NULL)
+ return(NULL);
+ } else if (Cv == one) {
+ t = Fv;
+ } else { /* Cv == zero: return Fnv @ Cnv */
+ if (Cnv == one) {
+ r = Fnv;
+ } else {
+ r = cuddBddConstrainRecur(dd, Fnv, Cnv);
+ if (r == NULL)
+ return(NULL);
+ }
+ return(Cudd_NotCond(r,comple));
+ }
+ cuddRef(t);
+
+ if (!Cudd_IsConstant(Cnv)) {
+ e = cuddBddConstrainRecur(dd, Fnv, Cnv);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ } else if (Cnv == one) {
+ e = Fnv;
+ } else { /* Cnv == zero: return Fv @ Cv previously computed */
+ cuddDeref(t);
+ return(Cudd_NotCond(t,comple));
+ }
+ cuddRef(e);
+
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert2(dd, Cudd_bddConstrain, f, c, r);
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddConstrainRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddRestrict.]
+
+ Description [Performs the recursive step of Cudd_bddRestrict.
+ Returns the restricted BDD if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddRestrict]
+
+******************************************************************************/
+DdNode *
+cuddBddRestrictRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r, *one, *zero;
+ unsigned int topf, topc;
+ int index;
+ int comple = 0;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Trivial cases */
+ if (c == one) return(f);
+ if (c == zero) return(zero);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(one);
+ if (f == Cudd_Not(c)) return(zero);
+
+ /* Make canonical to increase the utilization of the cache. */
+ if (Cudd_IsComplement(f)) {
+ f = Cudd_Not(f);
+ comple = 1;
+ }
+ /* Now f is a regular pointer to a non-constant node; c is also
+ ** non-constant, but may be complemented.
+ */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_bddRestrict, f, c);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ topf = dd->perm[f->index];
+ topc = dd->perm[Cudd_Regular(c)->index];
+
+ if (topc < topf) { /* abstract top variable from c */
+ DdNode *d, *s1, *s2;
+
+ /* Find complements of cofactors of c. */
+ if (Cudd_IsComplement(c)) {
+ s1 = cuddT(Cudd_Regular(c));
+ s2 = cuddE(Cudd_Regular(c));
+ } else {
+ s1 = Cudd_Not(cuddT(c));
+ s2 = Cudd_Not(cuddE(c));
+ }
+ /* Take the OR by applying DeMorgan. */
+ d = cuddBddAndRecur(dd, s1, s2);
+ if (d == NULL) return(NULL);
+ d = Cudd_Not(d);
+ cuddRef(d);
+ r = cuddBddRestrictRecur(dd, f, d);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, d);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_IterDerefBdd(dd, d);
+ cuddCacheInsert2(dd, Cudd_bddRestrict, f, c, r);
+ cuddDeref(r);
+ return(Cudd_NotCond(r,comple));
+ }
+
+ /* Recursive step. Here topf <= topc. */
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ if (topc == topf) {
+ Cv = cuddT(Cudd_Regular(c)); Cnv = cuddE(Cudd_Regular(c));
+ if (Cudd_IsComplement(c)) {
+ Cv = Cudd_Not(Cv);
+ Cnv = Cudd_Not(Cnv);
+ }
+ } else {
+ Cv = Cnv = c;
+ }
+
+ if (!Cudd_IsConstant(Cv)) {
+ t = cuddBddRestrictRecur(dd, Fv, Cv);
+ if (t == NULL) return(NULL);
+ } else if (Cv == one) {
+ t = Fv;
+ } else { /* Cv == zero: return(Fnv @ Cnv) */
+ if (Cnv == one) {
+ r = Fnv;
+ } else {
+ r = cuddBddRestrictRecur(dd, Fnv, Cnv);
+ if (r == NULL) return(NULL);
+ }
+ return(Cudd_NotCond(r,comple));
+ }
+ cuddRef(t);
+
+ if (!Cudd_IsConstant(Cnv)) {
+ e = cuddBddRestrictRecur(dd, Fnv, Cnv);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ } else if (Cnv == one) {
+ e = Fnv;
+ } else { /* Cnv == zero: return (Fv @ Cv) previously computed */
+ cuddDeref(t);
+ return(Cudd_NotCond(t,comple));
+ }
+ cuddRef(e);
+
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert2(dd, Cudd_bddRestrict, f, c, r);
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddRestrictRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addConstrain.]
+
+ Description [Performs the recursive step of Cudd_addConstrain.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addConstrain]
+
+******************************************************************************/
+DdNode *
+cuddAddConstrainRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r;
+ DdNode *one, *zero;
+ unsigned int topf, topc;
+ int index;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+
+ /* Trivial cases. */
+ if (c == one) return(f);
+ if (c == zero) return(zero);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(one);
+
+ /* Now f and c are non-constant. */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_addConstrain, f, c);
+ if (r != NULL) {
+ return(r);
+ }
+
+ /* Recursive step. */
+ topf = dd->perm[f->index];
+ topc = dd->perm[c->index];
+ if (topf <= topc) {
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ index = c->index;
+ Fv = Fnv = f;
+ }
+ if (topc <= topf) {
+ Cv = cuddT(c); Cnv = cuddE(c);
+ } else {
+ Cv = Cnv = c;
+ }
+
+ if (!Cudd_IsConstant(Cv)) {
+ t = cuddAddConstrainRecur(dd, Fv, Cv);
+ if (t == NULL)
+ return(NULL);
+ } else if (Cv == one) {
+ t = Fv;
+ } else { /* Cv == zero: return Fnv @ Cnv */
+ if (Cnv == one) {
+ r = Fnv;
+ } else {
+ r = cuddAddConstrainRecur(dd, Fnv, Cnv);
+ if (r == NULL)
+ return(NULL);
+ }
+ return(r);
+ }
+ cuddRef(t);
+
+ if (!Cudd_IsConstant(Cnv)) {
+ e = cuddAddConstrainRecur(dd, Fnv, Cnv);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ } else if (Cnv == one) {
+ e = Fnv;
+ } else { /* Cnv == zero: return Fv @ Cv previously computed */
+ cuddDeref(t);
+ return(t);
+ }
+ cuddRef(e);
+
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert2(dd, Cudd_addConstrain, f, c, r);
+ return(r);
+
+} /* end of cuddAddConstrainRecur */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_addRestrict.]
+
+ Description [Performs the recursive step of Cudd_addRestrict.
+ Returns the restricted ADD if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_addRestrict]
+
+******************************************************************************/
+DdNode *
+cuddAddRestrictRecur(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *r, *one, *zero;
+ unsigned int topf, topc;
+ int index;
+
+ statLine(dd);
+ one = DD_ONE(dd);
+ zero = DD_ZERO(dd);
+
+ /* Trivial cases */
+ if (c == one) return(f);
+ if (c == zero) return(zero);
+ if (Cudd_IsConstant(f)) return(f);
+ if (f == c) return(one);
+
+ /* Now f and c are non-constant. */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_addRestrict, f, c);
+ if (r != NULL) {
+ return(r);
+ }
+
+ topf = dd->perm[f->index];
+ topc = dd->perm[c->index];
+
+ if (topc < topf) { /* abstract top variable from c */
+ DdNode *d, *s1, *s2;
+
+ /* Find cofactors of c. */
+ s1 = cuddT(c);
+ s2 = cuddE(c);
+ /* Take the OR by applying DeMorgan. */
+ d = cuddAddApplyRecur(dd, Cudd_addOr, s1, s2);
+ if (d == NULL) return(NULL);
+ cuddRef(d);
+ r = cuddAddRestrictRecur(dd, f, d);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, d);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDeref(dd, d);
+ cuddCacheInsert2(dd, Cudd_addRestrict, f, c, r);
+ cuddDeref(r);
+ return(r);
+ }
+
+ /* Recursive step. Here topf <= topc. */
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ if (topc == topf) {
+ Cv = cuddT(c); Cnv = cuddE(c);
+ } else {
+ Cv = Cnv = c;
+ }
+
+ if (!Cudd_IsConstant(Cv)) {
+ t = cuddAddRestrictRecur(dd, Fv, Cv);
+ if (t == NULL) return(NULL);
+ } else if (Cv == one) {
+ t = Fv;
+ } else { /* Cv == zero: return(Fnv @ Cnv) */
+ if (Cnv == one) {
+ r = Fnv;
+ } else {
+ r = cuddAddRestrictRecur(dd, Fnv, Cnv);
+ if (r == NULL) return(NULL);
+ }
+ return(r);
+ }
+ cuddRef(t);
+
+ if (!Cudd_IsConstant(Cnv)) {
+ e = cuddAddRestrictRecur(dd, Fnv, Cnv);
+ if (e == NULL) {
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ } else if (Cnv == one) {
+ e = Fnv;
+ } else { /* Cnv == zero: return (Fv @ Cv) previously computed */
+ cuddDeref(t);
+ return(t);
+ }
+ cuddRef(e);
+
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(dd, e);
+ Cudd_RecursiveDeref(dd, t);
+ return(NULL);
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ cuddCacheInsert2(dd, Cudd_addRestrict, f, c, r);
+ return(r);
+
+} /* end of cuddAddRestrictRecur */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs safe minimization of a BDD.]
+
+ Description [Performs safe minimization of a BDD. Given the BDD
+ <code>f</code> of a function to be minimized and a BDD
+ <code>c</code> representing the care set, Cudd_bddLICompaction
+ produces the BDD of a function that agrees with <code>f</code>
+ wherever <code>c</code> is 1. Safe minimization means that the size
+ of the result is guaranteed not to exceed the size of
+ <code>f</code>. This function is based on the DAC97 paper by Hong et
+ al.. Returns a pointer to the result if successful; NULL
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction]
+
+******************************************************************************/
+DdNode *
+cuddBddLICompaction(
+ DdManager * dd /* manager */,
+ DdNode * f /* function to be minimized */,
+ DdNode * c /* constraint (care set) */)
+{
+ st_table *marktable, *markcache, *buildcache;
+ DdNode *res, *zero;
+
+ zero = Cudd_Not(DD_ONE(dd));
+ if (c == zero) return(zero);
+
+ /* We need to use local caches for both steps of this operation.
+ ** The results of the edge marking step are only valid as long as the
+ ** edge markings themselves are available. However, the edge markings
+ ** are lost at the end of one invocation of Cudd_bddLICompaction.
+ ** Hence, the cache entries for the edge marking step must be
+ ** invalidated at the end of this function.
+ ** For the result of the building step we argue as follows. The result
+ ** for a node and a given constrain depends on the BDD in which the node
+ ** appears. Hence, the same node and constrain may give different results
+ ** in successive invocations.
+ */
+ marktable = st_init_table(st_ptrcmp,st_ptrhash);
+ if (marktable == NULL) {
+ return(NULL);
+ }
+ markcache = st_init_table(MarkCacheCompare,MarkCacheHash);
+ if (markcache == NULL) {
+ st_free_table(marktable);
+ return(NULL);
+ }
+ if (cuddBddLICMarkEdges(dd,f,c,marktable,markcache) == CUDD_OUT_OF_MEM) {
+ st_foreach(markcache, MarkCacheCleanUp, NULL);
+ st_free_table(marktable);
+ st_free_table(markcache);
+ return(NULL);
+ }
+ st_foreach(markcache, MarkCacheCleanUp, NULL);
+ st_free_table(markcache);
+ buildcache = st_init_table(st_ptrcmp,st_ptrhash);
+ if (buildcache == NULL) {
+ st_free_table(marktable);
+ return(NULL);
+ }
+ res = cuddBddLICBuildResult(dd,f,buildcache,marktable);
+ st_free_table(buildcache);
+ st_free_table(marktable);
+ return(res);
+
+} /* end of cuddBddLICompaction */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddConstrainDecomp.]
+
+ Description [Performs the recursive step of Cudd_bddConstrainDecomp.
+ Returns f super (i) if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddConstrainDecomp]
+
+******************************************************************************/
+static int
+cuddBddConstrainDecomp(
+ DdManager * dd,
+ DdNode * f,
+ DdNode ** decomp)
+{
+ DdNode *F, *fv, *fvn;
+ DdNode *fAbs;
+ DdNode *result;
+ int ok;
+
+ if (Cudd_IsConstant(f)) return(1);
+ /* Compute complements of cofactors. */
+ F = Cudd_Regular(f);
+ fv = cuddT(F);
+ fvn = cuddE(F);
+ if (F == f) {
+ fv = Cudd_Not(fv);
+ fvn = Cudd_Not(fvn);
+ }
+ /* Compute abstraction of top variable. */
+ fAbs = cuddBddAndRecur(dd, fv, fvn);
+ if (fAbs == NULL) {
+ return(0);
+ }
+ cuddRef(fAbs);
+ fAbs = Cudd_Not(fAbs);
+ /* Recursively find the next abstraction and the components of the
+ ** decomposition. */
+ ok = cuddBddConstrainDecomp(dd, fAbs, decomp);
+ if (ok == 0) {
+ Cudd_IterDerefBdd(dd,fAbs);
+ return(0);
+ }
+ /* Compute the component of the decomposition corresponding to the
+ ** top variable and store it in the decomposition array. */
+ result = cuddBddConstrainRecur(dd, f, fAbs);
+ if (result == NULL) {
+ Cudd_IterDerefBdd(dd,fAbs);
+ return(0);
+ }
+ cuddRef(result);
+ decomp[F->index] = result;
+ Cudd_IterDerefBdd(dd, fAbs);
+ return(1);
+
+} /* end of cuddBddConstrainDecomp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddCharToVect.]
+
+ Description [Performs the recursive step of Cudd_bddCharToVect.
+ This function maintains the invariant that f is non-zero.
+ Returns the i-th component of the vector if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddCharToVect]
+
+******************************************************************************/
+static DdNode *
+cuddBddCharToVect(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * x)
+{
+ unsigned int topf;
+ unsigned int level;
+ int comple;
+
+ DdNode *one, *zero, *res, *F, *fT, *fE, *T, *E;
+
+ statLine(dd);
+ /* Check the cache. */
+ res = cuddCacheLookup2(dd, cuddBddCharToVect, f, x);
+ if (res != NULL) {
+ return(res);
+ }
+
+ F = Cudd_Regular(f);
+
+ topf = cuddI(dd,F->index);
+ level = dd->perm[x->index];
+
+ if (topf > level) return(x);
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ comple = F != f;
+ fT = Cudd_NotCond(cuddT(F),comple);
+ fE = Cudd_NotCond(cuddE(F),comple);
+
+ if (topf == level) {
+ if (fT == zero) return(zero);
+ if (fE == zero) return(one);
+ return(x);
+ }
+
+ /* Here topf < level. */
+ if (fT == zero) return(cuddBddCharToVect(dd, fE, x));
+ if (fE == zero) return(cuddBddCharToVect(dd, fT, x));
+
+ T = cuddBddCharToVect(dd, fT, x);
+ if (T == NULL) {
+ return(NULL);
+ }
+ cuddRef(T);
+ E = cuddBddCharToVect(dd, fE, x);
+ if (E == NULL) {
+ Cudd_IterDerefBdd(dd,T);
+ return(NULL);
+ }
+ cuddRef(E);
+ res = cuddBddIteRecur(dd, dd->vars[F->index], T, E);
+ if (res == NULL) {
+ Cudd_IterDerefBdd(dd,T);
+ Cudd_IterDerefBdd(dd,E);
+ return(NULL);
+ }
+ cuddDeref(T);
+ cuddDeref(E);
+ cuddCacheInsert2(dd, cuddBddCharToVect, f, x, res);
+ return(res);
+
+} /* end of cuddBddCharToVect */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the edge marking step of Cudd_bddLICompaction.]
+
+ Description [Performs the edge marking step of Cudd_bddLICompaction.
+ Returns the LUB of the markings of the two outgoing edges of <code>f</code>
+ if successful; otherwise CUDD_OUT_OF_MEM.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction cuddBddLICBuildResult]
+
+******************************************************************************/
+static int
+cuddBddLICMarkEdges(
+ DdManager * dd,
+ DdNode * f,
+ DdNode * c,
+ st_table * table,
+ st_table * cache)
+{
+ DdNode *Fv, *Fnv, *Cv, *Cnv;
+ DdNode *one, *zero;
+ unsigned int topf, topc;
+ int index;
+ int comple;
+ int resT, resE, res, retval;
+ char **slot;
+ MarkCacheKey *key;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ /* Terminal cases. */
+ if (c == zero) return(DD_LIC_DC);
+ if (f == one) return(DD_LIC_1);
+ if (f == zero) return(DD_LIC_0);
+
+ /* Make canonical to increase the utilization of the cache. */
+ comple = Cudd_IsComplement(f);
+ f = Cudd_Regular(f);
+ /* Now f is a regular pointer to a non-constant node; c may be
+ ** constant, or it may be complemented.
+ */
+
+ /* Check the cache. */
+ key = ALLOC(MarkCacheKey, 1);
+ if (key == NULL) {
+ dd->errorCode = CUDD_MEMORY_OUT;
+ return(CUDD_OUT_OF_MEM);
+ }
+ key->f = f; key->c = c;
+ if (st_lookup(cache, (char *)key, (char **)&res)) {
+ FREE(key);
+ if (comple) {
+ if (res == DD_LIC_0) res = DD_LIC_1;
+ else if (res == DD_LIC_1) res = DD_LIC_0;
+ }
+ return(res);
+ }
+
+ /* Recursive step. */
+ topf = dd->perm[f->index];
+ topc = cuddI(dd,Cudd_Regular(c)->index);
+ if (topf <= topc) {
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+ } else {
+ index = Cudd_Regular(c)->index;
+ Fv = Fnv = f;
+ }
+ if (topc <= topf) {
+ /* We know that c is not constant because f is not. */
+ Cv = cuddT(Cudd_Regular(c)); Cnv = cuddE(Cudd_Regular(c));
+ if (Cudd_IsComplement(c)) {
+ Cv = Cudd_Not(Cv);
+ Cnv = Cudd_Not(Cnv);
+ }
+ } else {
+ Cv = Cnv = c;
+ }
+
+ resT = cuddBddLICMarkEdges(dd, Fv, Cv, table, cache);
+ if (resT == CUDD_OUT_OF_MEM) {
+ FREE(key);
+ return(CUDD_OUT_OF_MEM);
+ }
+ resE = cuddBddLICMarkEdges(dd, Fnv, Cnv, table, cache);
+ if (resE == CUDD_OUT_OF_MEM) {
+ FREE(key);
+ return(CUDD_OUT_OF_MEM);
+ }
+
+ /* Update edge markings. */
+ if (topf <= topc) {
+ retval = st_find_or_add(table, (char *)f, (char ***)&slot);
+ if (retval == 0) {
+ *slot = (char *) (ptrint)((resT << 2) | resE);
+ } else if (retval == 1) {
+ *slot = (char *) (ptrint)((int)((ptrint) *slot) | (resT << 2) | resE);
+ } else {
+ FREE(key);
+ return(CUDD_OUT_OF_MEM);
+ }
+ }
+
+ /* Cache result. */
+ res = resT | resE;
+ if (st_insert(cache, (char *)key, (char *)(ptrint)res) == ST_OUT_OF_MEM) {
+ FREE(key);
+ return(CUDD_OUT_OF_MEM);
+ }
+
+ /* Take into account possible complementation. */
+ if (comple) {
+ if (res == DD_LIC_0) res = DD_LIC_1;
+ else if (res == DD_LIC_1) res = DD_LIC_0;
+ }
+ return(res);
+
+} /* end of cuddBddLICMarkEdges */
+
+
+/**Function********************************************************************
+
+ Synopsis [Builds the result of Cudd_bddLICompaction.]
+
+ Description [Builds the results of Cudd_bddLICompaction.
+ Returns a pointer to the minimized BDD if successful; otherwise NULL.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction cuddBddLICMarkEdges]
+
+******************************************************************************/
+static DdNode *
+cuddBddLICBuildResult(
+ DdManager * dd,
+ DdNode * f,
+ st_table * cache,
+ st_table * table)
+{
+ DdNode *Fv, *Fnv, *r, *t, *e;
+ DdNode *one, *zero;
+ unsigned int topf;
+ int index;
+ int comple;
+ int markT, markE, markings;
+
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+
+ if (Cudd_IsConstant(f)) return(f);
+ /* Make canonical to increase the utilization of the cache. */
+ comple = Cudd_IsComplement(f);
+ f = Cudd_Regular(f);
+
+ /* Check the cache. */
+ if (st_lookup(cache, (char *)f, (char **)&r)) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ /* Retrieve the edge markings. */
+ if (st_lookup(table, (char *)f, (char **)&markings) == 0)
+ return(NULL);
+ markT = markings >> 2;
+ markE = markings & 3;
+
+ topf = dd->perm[f->index];
+ index = f->index;
+ Fv = cuddT(f); Fnv = cuddE(f);
+
+ if (markT == DD_LIC_NL) {
+ t = cuddBddLICBuildResult(dd,Fv,cache,table);
+ if (t == NULL) {
+ return(NULL);
+ }
+ } else if (markT == DD_LIC_1) {
+ t = one;
+ } else {
+ t = zero;
+ }
+ cuddRef(t);
+ if (markE == DD_LIC_NL) {
+ e = cuddBddLICBuildResult(dd,Fnv,cache,table);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd,t);
+ return(NULL);
+ }
+ } else if (markE == DD_LIC_1) {
+ e = one;
+ } else {
+ e = zero;
+ }
+ cuddRef(e);
+
+ if (markT == DD_LIC_DC && markE != DD_LIC_DC) {
+ r = e;
+ } else if (markT != DD_LIC_DC && markE == DD_LIC_DC) {
+ r = t;
+ } else {
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+ if (st_insert(cache, (char *)f, (char *)r) == ST_OUT_OF_MEM) {
+ cuddRef(r);
+ Cudd_IterDerefBdd(dd,r);
+ return(NULL);
+ }
+
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddLICBuildResult */
+
+
+/**Function********************************************************************
+
+ Synopsis [Hash function for the computed table of cuddBddLICMarkEdges.]
+
+ Description [Hash function for the computed table of
+ cuddBddLICMarkEdges. Returns the bucket number.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction]
+
+******************************************************************************/
+static int
+MarkCacheHash(
+ char * ptr,
+ int modulus)
+{
+ int val = 0;
+ MarkCacheKey *entry;
+
+ entry = (MarkCacheKey *) ptr;
+
+ val = (int) (ptrint) entry->f;
+ val = val * 997 + (int) (ptrint) entry->c;
+
+ return ((val < 0) ? -val : val) % modulus;
+
+} /* end of MarkCacheHash */
+
+
+/**Function********************************************************************
+
+ Synopsis [Comparison function for the computed table of
+ cuddBddLICMarkEdges.]
+
+ Description [Comparison function for the computed table of
+ cuddBddLICMarkEdges. Returns 0 if the two nodes of the key are equal; 1
+ otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction]
+
+******************************************************************************/
+static int
+MarkCacheCompare(
+ const char * ptr1,
+ const char * ptr2)
+{
+ MarkCacheKey *entry1, *entry2;
+
+ entry1 = (MarkCacheKey *) ptr1;
+ entry2 = (MarkCacheKey *) ptr2;
+
+ return((entry1->f != entry2->f) || (entry1->c != entry2->c));
+
+} /* end of MarkCacheCompare */
+
+
+
+/**Function********************************************************************
+
+ Synopsis [Frees memory associated with computed table of
+ cuddBddLICMarkEdges.]
+
+ Description [Frees memory associated with computed table of
+ cuddBddLICMarkEdges. Returns ST_CONTINUE.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddLICompaction]
+
+******************************************************************************/
+static enum st_retval
+MarkCacheCleanUp(
+ char * key,
+ char * value,
+ char * arg)
+{
+ MarkCacheKey *entry;
+
+ entry = (MarkCacheKey *) key;
+ FREE(entry);
+ return ST_CONTINUE;
+
+} /* end of MarkCacheCleanUp */
+
+
+/**Function********************************************************************
+
+ Synopsis [Performs the recursive step of Cudd_bddSqueeze.]
+
+ Description [Performs the recursive step of Cudd_bddSqueeze. This
+ procedure exploits the fact that if we complement and swap the
+ bounds of the interval we obtain a valid solution by taking the
+ complement of the solution to the original problem. Therefore, we
+ can enforce the condition that the upper bound is always regular.
+ Returns a pointer to the result if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso [Cudd_bddSqueeze]
+
+******************************************************************************/
+static DdNode *
+cuddBddSqueeze(
+ DdManager * dd,
+ DdNode * l,
+ DdNode * u)
+{
+ DdNode *one, *zero, *r, *lt, *le, *ut, *ue, *t, *e;
+#if 0
+ DdNode *ar;
+#endif
+ int comple = 0;
+ unsigned int topu, topl;
+ int index;
+
+ statLine(dd);
+ if (l == u) {
+ return(l);
+ }
+ one = DD_ONE(dd);
+ zero = Cudd_Not(one);
+ /* The only case when l == zero && u == one is at the top level,
+ ** where returning either one or zero is OK. In all other cases
+ ** the procedure will detect such a case and will perform
+ ** remapping. Therefore the order in which we test l and u at this
+ ** point is immaterial. */
+ if (l == zero) return(l);
+ if (u == one) return(u);
+
+ /* Make canonical to increase the utilization of the cache. */
+ if (Cudd_IsComplement(u)) {
+ DdNode *temp;
+ temp = Cudd_Not(l);
+ l = Cudd_Not(u);
+ u = temp;
+ comple = 1;
+ }
+ /* At this point u is regular and non-constant; l is non-constant, but
+ ** may be complemented. */
+
+ /* Here we could check the relative sizes. */
+
+ /* Check the cache. */
+ r = cuddCacheLookup2(dd, Cudd_bddSqueeze, l, u);
+ if (r != NULL) {
+ return(Cudd_NotCond(r,comple));
+ }
+
+ /* Recursive step. */
+ topu = dd->perm[u->index];
+ topl = dd->perm[Cudd_Regular(l)->index];
+ if (topu <= topl) {
+ index = u->index;
+ ut = cuddT(u); ue = cuddE(u);
+ } else {
+ index = Cudd_Regular(l)->index;
+ ut = ue = u;
+ }
+ if (topl <= topu) {
+ lt = cuddT(Cudd_Regular(l)); le = cuddE(Cudd_Regular(l));
+ if (Cudd_IsComplement(l)) {
+ lt = Cudd_Not(lt);
+ le = Cudd_Not(le);
+ }
+ } else {
+ lt = le = l;
+ }
+
+ /* If one interval is contained in the other, use the smaller
+ ** interval. This corresponds to one-sided matching. */
+ if ((lt == zero || Cudd_bddLeq(dd,lt,le)) &&
+ (ut == one || Cudd_bddLeq(dd,ue,ut))) { /* remap */
+ r = cuddBddSqueeze(dd, le, ue);
+ if (r == NULL)
+ return(NULL);
+ return(Cudd_NotCond(r,comple));
+ } else if ((le == zero || Cudd_bddLeq(dd,le,lt)) &&
+ (ue == one || Cudd_bddLeq(dd,ut,ue))) { /* remap */
+ r = cuddBddSqueeze(dd, lt, ut);
+ if (r == NULL)
+ return(NULL);
+ return(Cudd_NotCond(r,comple));
+ } else if ((le == zero || Cudd_bddLeq(dd,le,Cudd_Not(ut))) &&
+ (ue == one || Cudd_bddLeq(dd,Cudd_Not(lt),ue))) { /* c-remap */
+ t = cuddBddSqueeze(dd, lt, ut);
+ cuddRef(t);
+ if (Cudd_IsComplement(t)) {
+ r = cuddUniqueInter(dd, index, Cudd_Not(t), t);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = cuddUniqueInter(dd, index, t, Cudd_Not(t));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ if (r == NULL)
+ return(NULL);
+ cuddCacheInsert2(dd, Cudd_bddSqueeze, l, u, r);
+ return(Cudd_NotCond(r,comple));
+ } else if ((lt == zero || Cudd_bddLeq(dd,lt,Cudd_Not(ue))) &&
+ (ut == one || Cudd_bddLeq(dd,Cudd_Not(le),ut))) { /* c-remap */
+ e = cuddBddSqueeze(dd, le, ue);
+ cuddRef(e);
+ if (Cudd_IsComplement(e)) {
+ r = cuddUniqueInter(dd, index, Cudd_Not(e), e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ return(NULL);
+ }
+ } else {
+ r = cuddUniqueInter(dd, index, e, Cudd_Not(e));
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ }
+ cuddDeref(e);
+ if (r == NULL)
+ return(NULL);
+ cuddCacheInsert2(dd, Cudd_bddSqueeze, l, u, r);
+ return(Cudd_NotCond(r,comple));
+ }
+
+#if 0
+ /* If the two intervals intersect, take a solution from
+ ** the intersection of the intervals. This guarantees that the
+ ** splitting variable will not appear in the result.
+ ** This approach corresponds to two-sided matching, and is very
+ ** expensive. */
+ if (Cudd_bddLeq(dd,lt,ue) && Cudd_bddLeq(dd,le,ut)) {
+ DdNode *au, *al;
+ au = cuddBddAndRecur(dd,ut,ue);
+ if (au == NULL)
+ return(NULL);
+ cuddRef(au);
+ al = cuddBddAndRecur(dd,Cudd_Not(lt),Cudd_Not(le));
+ if (al == NULL) {
+ Cudd_IterDerefBdd(dd,au);
+ return(NULL);
+ }
+ cuddRef(al);
+ al = Cudd_Not(al);
+ ar = cuddBddSqueeze(dd, al, au);
+ if (ar == NULL) {
+ Cudd_IterDerefBdd(dd,au);
+ Cudd_IterDerefBdd(dd,al);
+ return(NULL);
+ }
+ cuddRef(ar);
+ Cudd_IterDerefBdd(dd,au);
+ Cudd_IterDerefBdd(dd,al);
+ } else {
+ ar = NULL;
+ }
+#endif
+
+ t = cuddBddSqueeze(dd, lt, ut);
+ if (t == NULL) {
+ return(NULL);
+ }
+ cuddRef(t);
+ e = cuddBddSqueeze(dd, le, ue);
+ if (e == NULL) {
+ Cudd_IterDerefBdd(dd,t);
+ return(NULL);
+ }
+ cuddRef(e);
+
+ if (Cudd_IsComplement(t)) {
+ t = Cudd_Not(t);
+ e = Cudd_Not(e);
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ r = Cudd_Not(r);
+ } else {
+ r = (t == e) ? t : cuddUniqueInter(dd, index, t, e);
+ if (r == NULL) {
+ Cudd_IterDerefBdd(dd, e);
+ Cudd_IterDerefBdd(dd, t);
+ return(NULL);
+ }
+ }
+ cuddDeref(t);
+ cuddDeref(e);
+
+#if 0
+ /* Check whether there is a result obtained by abstraction and whether
+ ** it is better than the one obtained by recursion. */
+ cuddRef(r);
+ if (ar != NULL) {
+ if (Cudd_DagSize(ar) <= Cudd_DagSize(r)) {
+ Cudd_IterDerefBdd(dd, r);
+ r = ar;
+ } else {
+ Cudd_IterDerefBdd(dd, ar);
+ }
+ }
+ cuddDeref(r);
+#endif
+
+ cuddCacheInsert2(dd, Cudd_bddSqueeze, l, u, r);
+ return(Cudd_NotCond(r,comple));
+
+} /* end of cuddBddSqueeze */