/**CFile*********************************************************************** FileName [cuddDecomp.c] PackageName [cudd] Synopsis [Functions for BDD decomposition.] Description [External procedures included in this file:
f
is the function of the BDD and
x
is the variable, the decomposition is
(f+x)(f+x')
. 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 = ABC_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 = ABC_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 = ABC_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 = ABC_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 f
is the function of the
BDD and x
is the variable, the decomposition is
f*x + f*x'
. 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, (const 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 = ABC_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, (const 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 = ABC_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);
ABC_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 = ABC_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) {
ABC_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 = ABC_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) {
ABC_FREE(factors);
return(NULL);
}
}
} else {
value = 1;
if ( st__insert(ghTable, (char *)Cudd_Regular(factors->g),
(char *)(long)value) == st__OUT_OF_MEM) {
ABC_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) {
ABC_FREE(factors);
return(NULL);
}
}
} else {
value = 2;
if ( st__insert(ghTable, (char *)Cudd_Regular(factors->h),
(char *)(long)value) == st__OUT_OF_MEM) {
ABC_FREE(factors);
return(NULL);
}
}
}
/* Store factors in cache table for later use. */
if ( st__insert(cacheTable, (char *)node, (char *)factors) ==
st__OUT_OF_MEM) {
ABC_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 = ABC_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;
ABC_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;
ABC_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;
ABC_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;
ABC_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;
ABC_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;
ABC_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;
ABC_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;
ABC_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;
ABC_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;
ABC_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;
ABC_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;
ABC_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;
ABC_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 = ABC_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);
ABC_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 = ABC_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);
ABC_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 = NULL, *factorsNnv = NULL, *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 = ABC_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, (const 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, (const 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 = ABC_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;
ABC_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;
ABC_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, (const 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, (const 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) ABC_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) ABC_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) ABC_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) ABC_FREE(factorsNv);
if (freeNnv) ABC_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) ABC_FREE(factorsNv);
if (freeNnv) ABC_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) ABC_FREE(factorsNv);
if (freeNnv) ABC_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) ABC_FREE(factorsNv);
if (freeNnv) ABC_FREE(factorsNnv);
return(NULL);
}
cuddRef(h2);
Cudd_RecursiveDeref(dd, factorsNv->h);
Cudd_RecursiveDeref(dd, factorsNnv->g);
if (freeNv) ABC_FREE(factorsNv);
if (freeNnv) ABC_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 = ABC_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, (const char **)&key, (char **)&value)) {
ABC_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, (const 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, (const char **)&key, (char **)&value)) {
ABC_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, (const char **)&key, (char **)&value)) {
ABC_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) ABC_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, (const 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, (const char **)&key, (char **)&value)) {
ABC_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, (const char **)&key, (char **)&value)) {
ABC_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, (const 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 */
ABC_NAMESPACE_IMPL_END