/**CFile*********************************************************************** FileName [cuddSat.c] PackageName [cudd] Synopsis [Functions for the solution of satisfiability related problems.] Description [External procedures included in this file:
pr
is positive
the first failure is reported to the standard output.]
SideEffects [None]
SeeAlso []
******************************************************************************/
int
Cudd_EqualSupNorm(
DdManager * dd /* manager */,
DdNode * f /* first ADD */,
DdNode * g /* second ADD */,
CUDD_VALUE_TYPE tolerance /* maximum allowed difference */,
int pr /* verbosity level */)
{
DdNode *fv, *fvn, *gv, *gvn, *r;
unsigned int topf, topg;
statLine(dd);
/* Check terminal cases. */
if (f == g) return(1);
if (Cudd_IsConstant(f) && Cudd_IsConstant(g)) {
if (ddEqualVal(cuddV(f),cuddV(g),tolerance)) {
return(1);
} else {
if (pr>0) {
(void) fprintf(dd->out,"Offending nodes:\n");
#if SIZEOF_VOID_P == 8
(void) fprintf(dd->out,
"f: address = %lx\t value = %40.30f\n",
(unsigned long) f, cuddV(f));
(void) fprintf(dd->out,
"g: address = %lx\t value = %40.30f\n",
(unsigned long) g, cuddV(g));
#else
(void) fprintf(dd->out,
"f: address = %x\t value = %40.30f\n",
(unsigned) f, cuddV(f));
(void) fprintf(dd->out,
"g: address = %x\t value = %40.30f\n",
(unsigned) g, cuddV(g));
#endif
}
return(0);
}
}
/* We only insert the result in the cache if the comparison is
** successful. Therefore, if we hit we return 1. */
r = cuddCacheLookup2(dd,(DdNode * (*)(DdManager *, DdNode *, DdNode *))Cudd_EqualSupNorm,f,g);
if (r != NULL) {
return(1);
}
/* Compute the cofactors and solve the recursive subproblems. */
topf = cuddI(dd,f->index);
topg = cuddI(dd,g->index);
if (topf <= topg) {fv = cuddT(f); fvn = cuddE(f);} else {fv = fvn = f;}
if (topg <= topf) {gv = cuddT(g); gvn = cuddE(g);} else {gv = gvn = g;}
if (!Cudd_EqualSupNorm(dd,fv,gv,tolerance,pr)) return(0);
if (!Cudd_EqualSupNorm(dd,fvn,gvn,tolerance,pr)) return(0);
cuddCacheInsert2(dd,(DdNode * (*)(DdManager *, DdNode *, DdNode *))Cudd_EqualSupNorm,f,g,DD_ONE(dd));
return(1);
} /* end of Cudd_EqualSupNorm */
/**Function********************************************************************
Synopsis [Expands cube to a prime implicant of f.]
Description [Expands cube to a prime implicant of f. Returns the prime
if successful; NULL otherwise. In particular, NULL is returned if cube
is not a real cube or is not an implicant of f.]
SideEffects [None]
SeeAlso []
******************************************************************************/
DdNode *
Cudd_bddMakePrime(
DdManager *dd /* manager */,
DdNode *cube /* cube to be expanded */,
DdNode *f /* function of which the cube is to be made a prime */)
{
DdNode *res;
if (!Cudd_bddLeq(dd,cube,f)) return(NULL);
do {
dd->reordered = 0;
res = cuddBddMakePrime(dd,cube,f);
} while (dd->reordered == 1);
return(res);
} /* end of Cudd_bddMakePrime */
/*---------------------------------------------------------------------------*/
/* Definition of internal functions */
/*---------------------------------------------------------------------------*/
/**Function********************************************************************
Synopsis [Performs the recursive step of Cudd_bddMakePrime.]
Description [Performs the recursive step of Cudd_bddMakePrime.
Returns the prime if successful; NULL otherwise.]
SideEffects [None]
SeeAlso []
******************************************************************************/
DdNode *
cuddBddMakePrime(
DdManager *dd /* manager */,
DdNode *cube /* cube to be expanded */,
DdNode *f /* function of which the cube is to be made a prime */)
{
DdNode *scan;
DdNode *t, *e;
DdNode *res = cube;
DdNode *zero = Cudd_Not(DD_ONE(dd));
Cudd_Ref(res);
scan = cube;
while (!Cudd_IsConstant(scan)) {
DdNode *reg = Cudd_Regular(scan);
DdNode *var = dd->vars[reg->index];
DdNode *expanded = Cudd_bddExistAbstract(dd,res,var);
if (expanded == NULL) {
return(NULL);
}
Cudd_Ref(expanded);
if (Cudd_bddLeq(dd,expanded,f)) {
Cudd_RecursiveDeref(dd,res);
res = expanded;
} else {
Cudd_RecursiveDeref(dd,expanded);
}
cuddGetBranches(scan,&t,&e);
if (t == zero) {
scan = e;
} else if (e == zero) {
scan = t;
} else {
Cudd_RecursiveDeref(dd,res);
return(NULL); /* cube is not a cube */
}
}
if (scan == DD_ONE(dd)) {
Cudd_Deref(res);
return(res);
} else {
Cudd_RecursiveDeref(dd,res);
return(NULL);
}
} /* end of cuddBddMakePrime */
/*---------------------------------------------------------------------------*/
/* Definition of static functions */
/*---------------------------------------------------------------------------*/
/**Function********************************************************************
Synopsis [Frees the entries of the visited symbol table.]
Description [Frees the entries of the visited symbol table. Returns
ST_CONTINUE.]
SideEffects [None]
******************************************************************************/
static enum st_retval
freePathPair(
char * key,
char * value,
char * arg)
{
cuddPathPair *pair;
pair = (cuddPathPair *) value;
FREE(pair);
return(ST_CONTINUE);
} /* end of freePathPair */
/**Function********************************************************************
Synopsis [Finds the length of the shortest path(s) in a DD.]
Description [Finds the length of the shortest path(s) in a DD.
Uses a local symbol table to store the lengths for each
node. Only the lengths for the regular nodes are entered in the table,
because those for the complement nodes are simply obtained by swapping
the two lenghts.
Returns a pair of lengths: the length of the shortest path to 1;
and the length of the shortest path to 0. This is done so as to take
complement arcs into account.]
SideEffects [Accumulates the support of the DD in support.]
SeeAlso []
******************************************************************************/
static cuddPathPair
getShortest(
DdNode * root,
int * cost,
int * support,
st_table * visited)
{
cuddPathPair *my_pair, res_pair, pair_T, pair_E;
DdNode *my_root, *T, *E;
int weight;
my_root = Cudd_Regular(root);
if (st_lookup(visited, (char *)my_root, (char **)&my_pair)) {
if (Cudd_IsComplement(root)) {
res_pair.pos = my_pair->neg;
res_pair.neg = my_pair->pos;
} else {
res_pair.pos = my_pair->pos;
res_pair.neg = my_pair->neg;
}
return(res_pair);
}
/* In the case of a BDD the following test is equivalent to
** testing whether the BDD is the constant 1. This formulation,
** however, works for ADDs as well, by assuming the usual
** dichotomy of 0 and != 0.
*/
if (cuddIsConstant(my_root)) {
if (my_root != zero) {
res_pair.pos = 0;
res_pair.neg = DD_BIGGY;
} else {
res_pair.pos = DD_BIGGY;
res_pair.neg = 0;
}
} else {
T = cuddT(my_root);
E = cuddE(my_root);
pair_T = getShortest(T, cost, support, visited);
pair_E = getShortest(E, cost, support, visited);
weight = WEIGHT(cost, my_root->index);
res_pair.pos = ddMin(pair_T.pos+weight, pair_E.pos);
res_pair.neg = ddMin(pair_T.neg+weight, pair_E.neg);
/* Update support. */
if (support != NULL) {
support[my_root->index] = 1;
}
}
my_pair = ALLOC(cuddPathPair, 1);
if (my_pair == NULL) {
if (Cudd_IsComplement(root)) {
int tmp = res_pair.pos;
res_pair.pos = res_pair.neg;
res_pair.neg = tmp;
}
return(res_pair);
}
my_pair->pos = res_pair.pos;
my_pair->neg = res_pair.neg;
st_insert(visited, (char *)my_root, (char *)my_pair);
if (Cudd_IsComplement(root)) {
res_pair.pos = my_pair->neg;
res_pair.neg = my_pair->pos;
} else {
res_pair.pos = my_pair->pos;
res_pair.neg = my_pair->neg;
}
return(res_pair);
} /* end of getShortest */
/**Function********************************************************************
Synopsis [Build a BDD for a shortest path of f.]
Description [Build a BDD for a shortest path of f.
Given the minimum length from the root, and the minimum
lengths for each node (in visited), apply triangulation at each node.
Of the two children of each node on a shortest path, at least one is
on a shortest path. In case of ties the procedure chooses the THEN
children.
Returns a pointer to the cube BDD representing the path if
successful; NULL otherwise.]
SideEffects [None]
SeeAlso []
******************************************************************************/
static DdNode *
getPath(
DdManager * manager,
st_table * visited,
DdNode * f,
int * weight,
int cost)
{
DdNode *sol, *tmp;
DdNode *my_dd, *T, *E;
cuddPathPair *T_pair, *E_pair;
int Tcost, Ecost;
int complement;
my_dd = Cudd_Regular(f);
complement = Cudd_IsComplement(f);
sol = one;
cuddRef(sol);
while (!cuddIsConstant(my_dd)) {
Tcost = cost - WEIGHT(weight, my_dd->index);
Ecost = cost;
T = cuddT(my_dd);
E = cuddE(my_dd);
if (complement) {T = Cudd_Not(T); E = Cudd_Not(E);}
st_lookup(visited, (char *)Cudd_Regular(T), (char **)&T_pair);
if ((Cudd_IsComplement(T) && T_pair->neg == Tcost) ||
(!Cudd_IsComplement(T) && T_pair->pos == Tcost)) {
tmp = cuddBddAndRecur(manager,manager->vars[my_dd->index],sol);
if (tmp == NULL) {
Cudd_RecursiveDeref(manager,sol);
return(NULL);
}
cuddRef(tmp);
Cudd_RecursiveDeref(manager,sol);
sol = tmp;
complement = Cudd_IsComplement(T);
my_dd = Cudd_Regular(T);
cost = Tcost;
continue;
}
st_lookup(visited, (char *)Cudd_Regular(E), (char **)&E_pair);
if ((Cudd_IsComplement(E) && E_pair->neg == Ecost) ||
(!Cudd_IsComplement(E) && E_pair->pos == Ecost)) {
tmp = cuddBddAndRecur(manager,Cudd_Not(manager->vars[my_dd->index]),sol);
if (tmp == NULL) {
Cudd_RecursiveDeref(manager,sol);
return(NULL);
}
cuddRef(tmp);
Cudd_RecursiveDeref(manager,sol);
sol = tmp;
complement = Cudd_IsComplement(E);
my_dd = Cudd_Regular(E);
cost = Ecost;
continue;
}
(void) fprintf(manager->err,"We shouldn't be here!!\n");
manager->errorCode = CUDD_INTERNAL_ERROR;
return(NULL);
}
cuddDeref(sol);
return(sol);
} /* end of getPath */
/**Function********************************************************************
Synopsis [Finds the size of the largest cube(s) in a DD.]
Description [Finds the size of the largest cube(s) in a DD.
This problem is translated into finding the shortest paths from a node
when both THEN and ELSE arcs have unit lengths.
Uses a local symbol table to store the lengths for each
node. Only the lengths for the regular nodes are entered in the table,
because those for the complement nodes are simply obtained by swapping
the two lenghts.
Returns a pair of lengths: the length of the shortest path to 1;
and the length of the shortest path to 0. This is done so as to take
complement arcs into account.]
SideEffects [none]
SeeAlso []
******************************************************************************/
static cuddPathPair
getLargest(
DdNode * root,
st_table * visited)
{
cuddPathPair *my_pair, res_pair, pair_T, pair_E;
DdNode *my_root, *T, *E;
my_root = Cudd_Regular(root);
if (st_lookup(visited, (char *)my_root, (char **)&my_pair)) {
if (Cudd_IsComplement(root)) {
res_pair.pos = my_pair->neg;
res_pair.neg = my_pair->pos;
} else {
res_pair.pos = my_pair->pos;
res_pair.neg = my_pair->neg;
}
return(res_pair);
}
/* In the case of a BDD the following test is equivalent to
** testing whether the BDD is the constant 1. This formulation,
** however, works for ADDs as well, by assuming the usual
** dichotomy of 0 and != 0.
*/
if (cuddIsConstant(my_root)) {
if (my_root != zero) {
res_pair.pos = 0;
res_pair.neg = DD_BIGGY;
} else {
res_pair.pos = DD_BIGGY;
res_pair.neg = 0;
}
} else {
T = cuddT(my_root);
E = cuddE(my_root);
pair_T = getLargest(T, visited);
pair_E = getLargest(E, visited);
res_pair.pos = ddMin(pair_T.pos, pair_E.pos) + 1;
res_pair.neg = ddMin(pair_T.neg, pair_E.neg) + 1;
}
my_pair = ALLOC(cuddPathPair, 1);
if (my_pair == NULL) { /* simlpy do not cache this result */
if (Cudd_IsComplement(root)) {
int tmp = res_pair.pos;
res_pair.pos = res_pair.neg;
res_pair.neg = tmp;
}
return(res_pair);
}
my_pair->pos = res_pair.pos;
my_pair->neg = res_pair.neg;
st_insert(visited, (char *)my_root, (char *)my_pair);
if (Cudd_IsComplement(root)) {
res_pair.pos = my_pair->neg;
res_pair.neg = my_pair->pos;
} else {
res_pair.pos = my_pair->pos;
res_pair.neg = my_pair->neg;
}
return(res_pair);
} /* end of getLargest */
/**Function********************************************************************
Synopsis [Build a BDD for a largest cube of f.]
Description [Build a BDD for a largest cube of f.
Given the minimum length from the root, and the minimum
lengths for each node (in visited), apply triangulation at each node.
Of the two children of each node on a shortest path, at least one is
on a shortest path. In case of ties the procedure chooses the THEN
children.
Returns a pointer to the cube BDD representing the path if
successful; NULL otherwise.]
SideEffects [None]
SeeAlso []
******************************************************************************/
static DdNode *
getCube(
DdManager * manager,
st_table * visited,
DdNode * f,
int cost)
{
DdNode *sol, *tmp;
DdNode *my_dd, *T, *E;
cuddPathPair *T_pair, *E_pair;
int Tcost, Ecost;
int complement;
my_dd = Cudd_Regular(f);
complement = Cudd_IsComplement(f);
sol = one;
cuddRef(sol);
while (!cuddIsConstant(my_dd)) {
Tcost = cost - 1;
Ecost = cost - 1;
T = cuddT(my_dd);
E = cuddE(my_dd);
if (complement) {T = Cudd_Not(T); E = Cudd_Not(E);}
st_lookup(visited, (char *)Cudd_Regular(T), (char **)&T_pair);
if ((Cudd_IsComplement(T) && T_pair->neg == Tcost) ||
(!Cudd_IsComplement(T) && T_pair->pos == Tcost)) {
tmp = cuddBddAndRecur(manager,manager->vars[my_dd->index],sol);
if (tmp == NULL) {
Cudd_RecursiveDeref(manager,sol);
return(NULL);
}
cuddRef(tmp);
Cudd_RecursiveDeref(manager,sol);
sol = tmp;
complement = Cudd_IsComplement(T);
my_dd = Cudd_Regular(T);
cost = Tcost;
continue;
}
st_lookup(visited, (char *)Cudd_Regular(E), (char **)&E_pair);
if ((Cudd_IsComplement(E) && E_pair->neg == Ecost) ||
(!Cudd_IsComplement(E) && E_pair->pos == Ecost)) {
tmp = cuddBddAndRecur(manager,Cudd_Not(manager->vars[my_dd->index]),sol);
if (tmp == NULL) {
Cudd_RecursiveDeref(manager,sol);
return(NULL);
}
cuddRef(tmp);
Cudd_RecursiveDeref(manager,sol);
sol = tmp;
complement = Cudd_IsComplement(E);
my_dd = Cudd_Regular(E);
cost = Ecost;
continue;
}
(void) fprintf(manager->err,"We shouldn't be here!\n");
manager->errorCode = CUDD_INTERNAL_ERROR;
return(NULL);
}
cuddDeref(sol);
return(sol);
} /* end of getCube */