You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
986 lines
23 KiB
986 lines
23 KiB
/**
|
|
@file
|
|
|
|
@ingroup cudd
|
|
|
|
@brief Translation from %BDD to %ADD and vice versa and transfer
|
|
between different managers.
|
|
|
|
@author Fabio Somenzi
|
|
|
|
@copyright@parblock
|
|
Copyright (c) 1995-2015, Regents of the University of Colorado
|
|
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
Neither the name of the University of Colorado nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
@endparblock
|
|
|
|
*/
|
|
|
|
#include "util.h"
|
|
#include "cuddInt.h"
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Constant declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Stucture declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Type declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Variable declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Macro declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/** \cond */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Static function prototypes */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static DdNode * addBddDoThreshold (DdManager *dd, DdNode *f, DdNode *val);
|
|
static DdNode * addBddDoStrictThreshold (DdManager *dd, DdNode *f, DdNode *val);
|
|
static DdNode * addBddDoInterval (DdManager *dd, DdNode *f, DdNode *l, DdNode *u);
|
|
static DdNode * addBddDoIthBit (DdManager *dd, DdNode *f, DdNode *index);
|
|
static DdNode * ddBddToAddRecur (DdManager *dd, DdNode *B);
|
|
static DdNode * cuddBddTransferRecur (DdManager *ddS, DdManager *ddD, DdNode *f, st_table *table);
|
|
|
|
/** \endcond */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of exported functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**
|
|
@brief Converts an %ADD to a %BDD.
|
|
|
|
@details Replaces all discriminants greater than or equal to value
|
|
with 1, and all other discriminants with 0.
|
|
|
|
@return a pointer to the resulting %BDD if successful; NULL
|
|
otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_addBddInterval Cudd_addBddPattern Cudd_BddToAdd
|
|
Cudd_addBddStrictThreshold
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_addBddThreshold(
|
|
DdManager * dd,
|
|
DdNode * f,
|
|
CUDD_VALUE_TYPE value)
|
|
{
|
|
DdNode *res;
|
|
DdNode *val;
|
|
|
|
val = cuddUniqueConst(dd,value);
|
|
if (val == NULL) return(NULL);
|
|
cuddRef(val);
|
|
|
|
do {
|
|
dd->reordered = 0;
|
|
res = addBddDoThreshold(dd, f, val);
|
|
} while (dd->reordered == 1);
|
|
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, val);
|
|
if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
|
|
dd->timeoutHandler(dd, dd->tohArg);
|
|
}
|
|
return(NULL);
|
|
}
|
|
cuddRef(res);
|
|
Cudd_RecursiveDeref(dd, val);
|
|
cuddDeref(res);
|
|
return(res);
|
|
|
|
} /* end of Cudd_addBddThreshold */
|
|
|
|
|
|
/**
|
|
@brief Converts an %ADD to a %BDD.
|
|
|
|
@details Replaces all discriminants STRICTLY greater than value with
|
|
1, and all other discriminants with 0.
|
|
|
|
@return a pointer to the resulting %BDD if successful; NULL
|
|
otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_addBddInterval Cudd_addBddPattern Cudd_BddToAdd
|
|
Cudd_addBddThreshold
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_addBddStrictThreshold(
|
|
DdManager * dd,
|
|
DdNode * f,
|
|
CUDD_VALUE_TYPE value)
|
|
{
|
|
DdNode *res;
|
|
DdNode *val;
|
|
|
|
val = cuddUniqueConst(dd,value);
|
|
if (val == NULL) return(NULL);
|
|
cuddRef(val);
|
|
|
|
do {
|
|
dd->reordered = 0;
|
|
res = addBddDoStrictThreshold(dd, f, val);
|
|
} while (dd->reordered == 1);
|
|
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, val);
|
|
if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
|
|
dd->timeoutHandler(dd, dd->tohArg);
|
|
}
|
|
return(NULL);
|
|
}
|
|
cuddRef(res);
|
|
Cudd_RecursiveDeref(dd, val);
|
|
cuddDeref(res);
|
|
return(res);
|
|
|
|
} /* end of Cudd_addBddStrictThreshold */
|
|
|
|
|
|
/**
|
|
@brief Converts an %ADD to a %BDD.
|
|
|
|
@details Replaces all discriminants greater than or equal to lower
|
|
and less than or equal to upper with 1, and all other discriminants
|
|
with 0.
|
|
|
|
@return a pointer to the resulting %BDD if successful; NULL
|
|
otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_addBddThreshold Cudd_addBddStrictThreshold
|
|
Cudd_addBddPattern Cudd_BddToAdd
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_addBddInterval(
|
|
DdManager * dd,
|
|
DdNode * f,
|
|
CUDD_VALUE_TYPE lower,
|
|
CUDD_VALUE_TYPE upper)
|
|
{
|
|
DdNode *res;
|
|
DdNode *l;
|
|
DdNode *u;
|
|
|
|
/* Create constant nodes for the interval bounds, so that we can use
|
|
** the global cache.
|
|
*/
|
|
l = cuddUniqueConst(dd,lower);
|
|
if (l == NULL) return(NULL);
|
|
cuddRef(l);
|
|
u = cuddUniqueConst(dd,upper);
|
|
if (u == NULL) {
|
|
Cudd_RecursiveDeref(dd,l);
|
|
return(NULL);
|
|
}
|
|
cuddRef(u);
|
|
|
|
do {
|
|
dd->reordered = 0;
|
|
res = addBddDoInterval(dd, f, l, u);
|
|
} while (dd->reordered == 1);
|
|
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, l);
|
|
Cudd_RecursiveDeref(dd, u);
|
|
if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
|
|
dd->timeoutHandler(dd, dd->tohArg);
|
|
}
|
|
return(NULL);
|
|
}
|
|
cuddRef(res);
|
|
Cudd_RecursiveDeref(dd, l);
|
|
Cudd_RecursiveDeref(dd, u);
|
|
cuddDeref(res);
|
|
return(res);
|
|
|
|
} /* end of Cudd_addBddInterval */
|
|
|
|
|
|
/**
|
|
@brief Converts an %ADD to a %BDD by extracting the i-th bit from
|
|
the leaves.
|
|
|
|
@details Converts an %ADD to a %BDD by replacing all
|
|
discriminants whose i-th bit is equal to 1 with 1, and all other
|
|
discriminants with 0. The i-th bit refers to the integer
|
|
representation of the leaf value. If the value has a fractional
|
|
part, it is ignored. Repeated calls to this procedure allow one to
|
|
transform an integer-valued %ADD into an array of BDDs, one for each
|
|
bit of the leaf values.
|
|
|
|
@return a pointer to the resulting %BDD if successful; NULL
|
|
otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_addBddInterval Cudd_addBddPattern Cudd_BddToAdd
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_addBddIthBit(
|
|
DdManager * dd,
|
|
DdNode * f,
|
|
int bit)
|
|
{
|
|
DdNode *res;
|
|
DdNode *index;
|
|
|
|
index = cuddUniqueConst(dd,(CUDD_VALUE_TYPE) bit);
|
|
if (index == NULL) return(NULL);
|
|
cuddRef(index);
|
|
|
|
do {
|
|
dd->reordered = 0;
|
|
res = addBddDoIthBit(dd, f, index);
|
|
} while (dd->reordered == 1);
|
|
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, index);
|
|
if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
|
|
dd->timeoutHandler(dd, dd->tohArg);
|
|
}
|
|
return(NULL);
|
|
}
|
|
cuddRef(res);
|
|
Cudd_RecursiveDeref(dd, index);
|
|
cuddDeref(res);
|
|
return(res);
|
|
|
|
} /* end of Cudd_addBddIthBit */
|
|
|
|
|
|
/**
|
|
@brief Converts a %BDD to a 0-1 %ADD.
|
|
|
|
@return a pointer to the resulting %ADD if successful; NULL
|
|
otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_addBddPattern Cudd_addBddThreshold Cudd_addBddInterval
|
|
Cudd_addBddStrictThreshold
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_BddToAdd(
|
|
DdManager * dd,
|
|
DdNode * B)
|
|
{
|
|
DdNode *res;
|
|
|
|
do {
|
|
dd->reordered = 0;
|
|
res = ddBddToAddRecur(dd, B);
|
|
} while (dd->reordered ==1);
|
|
return(res);
|
|
|
|
} /* end of Cudd_BddToAdd */
|
|
|
|
|
|
/**
|
|
@brief Converts an %ADD to a %BDD.
|
|
|
|
@details Replaces all discriminants different from 0 with 1.
|
|
|
|
@return a pointer to the resulting %BDD if successful; NULL
|
|
otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_BddToAdd Cudd_addBddThreshold Cudd_addBddInterval
|
|
Cudd_addBddStrictThreshold
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_addBddPattern(
|
|
DdManager * dd,
|
|
DdNode * f)
|
|
{
|
|
DdNode *res;
|
|
|
|
do {
|
|
dd->reordered = 0;
|
|
res = cuddAddBddDoPattern(dd, f);
|
|
} while (dd->reordered == 1);
|
|
if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
|
|
dd->timeoutHandler(dd, dd->tohArg);
|
|
}
|
|
return(res);
|
|
|
|
} /* end of Cudd_addBddPattern */
|
|
|
|
|
|
/**
|
|
@brief Convert a %BDD from a manager to another one.
|
|
|
|
@details The orders of the variables in the two managers may be
|
|
different.
|
|
|
|
@return a pointer to the %BDD in the destination manager if
|
|
successful; NULL otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_bddTransfer(
|
|
DdManager * ddSource,
|
|
DdManager * ddDestination,
|
|
DdNode * f)
|
|
{
|
|
DdNode *res;
|
|
do {
|
|
ddDestination->reordered = 0;
|
|
res = cuddBddTransfer(ddSource, ddDestination, f);
|
|
} while (ddDestination->reordered == 1);
|
|
if (ddDestination->errorCode == CUDD_TIMEOUT_EXPIRED &&
|
|
ddDestination->timeoutHandler) {
|
|
ddDestination->timeoutHandler(ddDestination, ddDestination->tohArg);
|
|
}
|
|
return(res);
|
|
|
|
} /* end of Cudd_bddTransfer */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of internal functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**
|
|
@brief Convert a %BDD from a manager to another one.
|
|
|
|
@return a pointer to the %BDD in the destination manager if
|
|
successful; NULL otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_bddTransfer
|
|
|
|
*/
|
|
DdNode *
|
|
cuddBddTransfer(
|
|
DdManager * ddS,
|
|
DdManager * ddD,
|
|
DdNode * f)
|
|
{
|
|
DdNode *res;
|
|
st_table *table = NULL;
|
|
st_generator *gen = NULL;
|
|
DdNode *key, *value;
|
|
|
|
table = st_init_table(st_ptrcmp,st_ptrhash);
|
|
if (table == NULL) goto failure;
|
|
res = cuddBddTransferRecur(ddS, ddD, f, table);
|
|
if (res != NULL) cuddRef(res);
|
|
|
|
/* Dereference all elements in the table and dispose of the table.
|
|
** This must be done also if res is NULL to avoid leaks in case of
|
|
** reordering. */
|
|
gen = st_init_gen(table);
|
|
if (gen == NULL) goto failure;
|
|
while (st_gen(gen, (void **) &key, (void **) &value)) {
|
|
Cudd_RecursiveDeref(ddD, value);
|
|
}
|
|
st_free_gen(gen); gen = NULL;
|
|
st_free_table(table); table = NULL;
|
|
|
|
if (res != NULL) cuddDeref(res);
|
|
return(res);
|
|
|
|
failure:
|
|
/* No need to free gen because it is always NULL here. */
|
|
if (table != NULL) st_free_table(table);
|
|
return(NULL);
|
|
|
|
} /* end of cuddBddTransfer */
|
|
|
|
|
|
/**
|
|
@brief Performs the recursive step for Cudd_addBddPattern.
|
|
|
|
@return a pointer to the resulting %BDD if successful; NULL
|
|
otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
DdNode *
|
|
cuddAddBddDoPattern(
|
|
DdManager * dd,
|
|
DdNode * f)
|
|
{
|
|
DdNode *res, *T, *E;
|
|
DdNode *fv, *fvn;
|
|
unsigned int v;
|
|
|
|
statLine(dd);
|
|
/* Check terminal case. */
|
|
if (cuddIsConstant(f)) {
|
|
return(Cudd_NotCond(DD_ONE(dd),f == DD_ZERO(dd)));
|
|
}
|
|
|
|
/* Check cache. */
|
|
res = cuddCacheLookup1(dd,Cudd_addBddPattern,f);
|
|
if (res != NULL) return(res);
|
|
|
|
checkWhetherToGiveUp(dd);
|
|
|
|
/* Recursive step. */
|
|
v = f->index;
|
|
fv = cuddT(f); fvn = cuddE(f);
|
|
|
|
T = cuddAddBddDoPattern(dd,fv);
|
|
if (T == NULL) return(NULL);
|
|
cuddRef(T);
|
|
|
|
E = cuddAddBddDoPattern(dd,fvn);
|
|
if (E == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
return(NULL);
|
|
}
|
|
cuddRef(E);
|
|
if (Cudd_IsComplement(T)) {
|
|
res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
Cudd_RecursiveDeref(dd, E);
|
|
return(NULL);
|
|
}
|
|
res = Cudd_Not(res);
|
|
} else {
|
|
res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
Cudd_RecursiveDeref(dd, E);
|
|
return(NULL);
|
|
}
|
|
}
|
|
cuddDeref(T);
|
|
cuddDeref(E);
|
|
|
|
/* Store result. */
|
|
cuddCacheInsert1(dd,Cudd_addBddPattern,f,res);
|
|
|
|
return(res);
|
|
|
|
} /* end of cuddAddBddDoPattern */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of static functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**
|
|
@brief Performs the recursive step for Cudd_addBddThreshold.
|
|
|
|
@return a pointer to the %BDD if successful; NULL otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see addBddDoStrictThreshold
|
|
|
|
*/
|
|
static DdNode *
|
|
addBddDoThreshold(
|
|
DdManager * dd,
|
|
DdNode * f,
|
|
DdNode * val)
|
|
{
|
|
DdNode *res, *T, *E;
|
|
DdNode *fv, *fvn;
|
|
unsigned int v;
|
|
|
|
statLine(dd);
|
|
/* Check terminal case. */
|
|
if (cuddIsConstant(f)) {
|
|
return(Cudd_NotCond(DD_ONE(dd),cuddV(f) < cuddV(val)));
|
|
}
|
|
|
|
/* Check cache. */
|
|
res = cuddCacheLookup2(dd,addBddDoThreshold,f,val);
|
|
if (res != NULL) return(res);
|
|
|
|
checkWhetherToGiveUp(dd);
|
|
|
|
/* Recursive step. */
|
|
v = f->index;
|
|
fv = cuddT(f); fvn = cuddE(f);
|
|
|
|
T = addBddDoThreshold(dd,fv,val);
|
|
if (T == NULL) return(NULL);
|
|
cuddRef(T);
|
|
|
|
E = addBddDoThreshold(dd,fvn,val);
|
|
if (E == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
return(NULL);
|
|
}
|
|
cuddRef(E);
|
|
if (Cudd_IsComplement(T)) {
|
|
res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
Cudd_RecursiveDeref(dd, E);
|
|
return(NULL);
|
|
}
|
|
res = Cudd_Not(res);
|
|
} else {
|
|
res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
Cudd_RecursiveDeref(dd, E);
|
|
return(NULL);
|
|
}
|
|
}
|
|
cuddDeref(T);
|
|
cuddDeref(E);
|
|
|
|
/* Store result. */
|
|
cuddCacheInsert2(dd,addBddDoThreshold,f,val,res);
|
|
|
|
return(res);
|
|
|
|
} /* end of addBddDoThreshold */
|
|
|
|
|
|
/**
|
|
@brief Performs the recursive step for Cudd_addBddStrictThreshold.
|
|
|
|
@return a pointer to the %BDD if successful; NULL otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see addBddDoThreshold
|
|
|
|
*/
|
|
static DdNode *
|
|
addBddDoStrictThreshold(
|
|
DdManager * dd,
|
|
DdNode * f,
|
|
DdNode * val)
|
|
{
|
|
DdNode *res, *T, *E;
|
|
DdNode *fv, *fvn;
|
|
unsigned int v;
|
|
|
|
statLine(dd);
|
|
/* Check terminal case. */
|
|
if (cuddIsConstant(f)) {
|
|
return(Cudd_NotCond(DD_ONE(dd),cuddV(f) <= cuddV(val)));
|
|
}
|
|
|
|
/* Check cache. */
|
|
res = cuddCacheLookup2(dd,addBddDoStrictThreshold,f,val);
|
|
if (res != NULL) return(res);
|
|
|
|
checkWhetherToGiveUp(dd);
|
|
|
|
/* Recursive step. */
|
|
v = f->index;
|
|
fv = cuddT(f); fvn = cuddE(f);
|
|
|
|
T = addBddDoStrictThreshold(dd,fv,val);
|
|
if (T == NULL) return(NULL);
|
|
cuddRef(T);
|
|
|
|
E = addBddDoStrictThreshold(dd,fvn,val);
|
|
if (E == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
return(NULL);
|
|
}
|
|
cuddRef(E);
|
|
if (Cudd_IsComplement(T)) {
|
|
res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
Cudd_RecursiveDeref(dd, E);
|
|
return(NULL);
|
|
}
|
|
res = Cudd_Not(res);
|
|
} else {
|
|
res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
Cudd_RecursiveDeref(dd, E);
|
|
return(NULL);
|
|
}
|
|
}
|
|
cuddDeref(T);
|
|
cuddDeref(E);
|
|
|
|
/* Store result. */
|
|
cuddCacheInsert2(dd,addBddDoStrictThreshold,f,val,res);
|
|
|
|
return(res);
|
|
|
|
} /* end of addBddDoStrictThreshold */
|
|
|
|
|
|
/**
|
|
@brief Performs the recursive step for Cudd_addBddInterval.
|
|
|
|
@return a pointer to the %BDD if successful; NULL otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see addBddDoThreshold addBddDoStrictThreshold
|
|
|
|
*/
|
|
static DdNode *
|
|
addBddDoInterval(
|
|
DdManager * dd,
|
|
DdNode * f,
|
|
DdNode * l,
|
|
DdNode * u)
|
|
{
|
|
DdNode *res, *T, *E;
|
|
DdNode *fv, *fvn;
|
|
unsigned int v;
|
|
|
|
statLine(dd);
|
|
/* Check terminal case. */
|
|
if (cuddIsConstant(f)) {
|
|
return(Cudd_NotCond(DD_ONE(dd),cuddV(f) < cuddV(l) || cuddV(f) > cuddV(u)));
|
|
}
|
|
|
|
/* Check cache. */
|
|
res = cuddCacheLookup(dd,DD_ADD_BDD_DO_INTERVAL_TAG,f,l,u);
|
|
if (res != NULL) return(res);
|
|
|
|
checkWhetherToGiveUp(dd);
|
|
|
|
/* Recursive step. */
|
|
v = f->index;
|
|
fv = cuddT(f); fvn = cuddE(f);
|
|
|
|
T = addBddDoInterval(dd,fv,l,u);
|
|
if (T == NULL) return(NULL);
|
|
cuddRef(T);
|
|
|
|
E = addBddDoInterval(dd,fvn,l,u);
|
|
if (E == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
return(NULL);
|
|
}
|
|
cuddRef(E);
|
|
if (Cudd_IsComplement(T)) {
|
|
res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
Cudd_RecursiveDeref(dd, E);
|
|
return(NULL);
|
|
}
|
|
res = Cudd_Not(res);
|
|
} else {
|
|
res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
Cudd_RecursiveDeref(dd, E);
|
|
return(NULL);
|
|
}
|
|
}
|
|
cuddDeref(T);
|
|
cuddDeref(E);
|
|
|
|
/* Store result. */
|
|
cuddCacheInsert(dd,DD_ADD_BDD_DO_INTERVAL_TAG,f,l,u,res);
|
|
|
|
return(res);
|
|
|
|
} /* end of addBddDoInterval */
|
|
|
|
|
|
/**
|
|
@brief Performs the recursive step for Cudd_addBddIthBit.
|
|
|
|
@return a pointer to the %BDD if successful; NULL otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
static DdNode *
|
|
addBddDoIthBit(
|
|
DdManager * dd,
|
|
DdNode * f,
|
|
DdNode * index)
|
|
{
|
|
DdNode *res, *T, *E;
|
|
DdNode *fv, *fvn;
|
|
int mask, value;
|
|
unsigned int v;
|
|
|
|
statLine(dd);
|
|
/* Check terminal case. */
|
|
if (cuddIsConstant(f)) {
|
|
mask = 1 << ((int) cuddV(index));
|
|
value = (int) cuddV(f);
|
|
return(Cudd_NotCond(DD_ONE(dd),(value & mask) == 0));
|
|
}
|
|
|
|
/* Check cache. */
|
|
res = cuddCacheLookup2(dd,addBddDoIthBit,f,index);
|
|
if (res != NULL) return(res);
|
|
|
|
checkWhetherToGiveUp(dd);
|
|
|
|
/* Recursive step. */
|
|
v = f->index;
|
|
fv = cuddT(f); fvn = cuddE(f);
|
|
|
|
T = addBddDoIthBit(dd,fv,index);
|
|
if (T == NULL) return(NULL);
|
|
cuddRef(T);
|
|
|
|
E = addBddDoIthBit(dd,fvn,index);
|
|
if (E == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
return(NULL);
|
|
}
|
|
cuddRef(E);
|
|
if (Cudd_IsComplement(T)) {
|
|
res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E));
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
Cudd_RecursiveDeref(dd, E);
|
|
return(NULL);
|
|
}
|
|
res = Cudd_Not(res);
|
|
} else {
|
|
res = (T == E) ? T : cuddUniqueInter(dd,v,T,E);
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
Cudd_RecursiveDeref(dd, E);
|
|
return(NULL);
|
|
}
|
|
}
|
|
cuddDeref(T);
|
|
cuddDeref(E);
|
|
|
|
/* Store result. */
|
|
cuddCacheInsert2(dd,addBddDoIthBit,f,index,res);
|
|
|
|
return(res);
|
|
|
|
} /* end of addBddDoIthBit */
|
|
|
|
|
|
/**
|
|
@brief Performs the recursive step for Cudd_BddToAdd.
|
|
|
|
@return a pointer to the resulting %ADD if successful; NULL
|
|
otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
static DdNode *
|
|
ddBddToAddRecur(
|
|
DdManager * dd,
|
|
DdNode * B)
|
|
{
|
|
DdNode *one;
|
|
DdNode *res, *res1, *T, *E, *Bt, *Be;
|
|
int complement = 0;
|
|
|
|
statLine(dd);
|
|
one = DD_ONE(dd);
|
|
|
|
if (Cudd_IsConstantInt(B)) {
|
|
if (B == one) {
|
|
res = one;
|
|
} else {
|
|
res = DD_ZERO(dd);
|
|
}
|
|
return(res);
|
|
}
|
|
/* Check visited table */
|
|
res = cuddCacheLookup1(dd,ddBddToAddRecur,B);
|
|
if (res != NULL) return(res);
|
|
|
|
checkWhetherToGiveUp(dd);
|
|
|
|
if (Cudd_IsComplement(B)) {
|
|
complement = 1;
|
|
Bt = cuddT(Cudd_Regular(B));
|
|
Be = cuddE(Cudd_Regular(B));
|
|
} else {
|
|
Bt = cuddT(B);
|
|
Be = cuddE(B);
|
|
}
|
|
|
|
T = ddBddToAddRecur(dd, Bt);
|
|
if (T == NULL) return(NULL);
|
|
cuddRef(T);
|
|
|
|
E = ddBddToAddRecur(dd, Be);
|
|
if (E == NULL) {
|
|
Cudd_RecursiveDeref(dd, T);
|
|
return(NULL);
|
|
}
|
|
cuddRef(E);
|
|
|
|
/* No need to check for T == E, because it is guaranteed not to happen. */
|
|
res = cuddUniqueInter(dd, (int) Cudd_Regular(B)->index, T, E);
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd ,T);
|
|
Cudd_RecursiveDeref(dd ,E);
|
|
return(NULL);
|
|
}
|
|
cuddDeref(T);
|
|
cuddDeref(E);
|
|
|
|
if (complement) {
|
|
cuddRef(res);
|
|
res1 = cuddAddCmplRecur(dd, res);
|
|
if (res1 == NULL) {
|
|
Cudd_RecursiveDeref(dd, res);
|
|
return(NULL);
|
|
}
|
|
cuddRef(res1);
|
|
Cudd_RecursiveDeref(dd, res);
|
|
res = res1;
|
|
cuddDeref(res);
|
|
}
|
|
|
|
/* Store result. */
|
|
cuddCacheInsert1(dd,ddBddToAddRecur,B,res);
|
|
|
|
return(res);
|
|
|
|
} /* end of ddBddToAddRecur */
|
|
|
|
|
|
/**
|
|
@brief Performs the recursive step of Cudd_bddTransfer.
|
|
|
|
@return a pointer to the result if successful; NULL otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see cuddBddTransfer
|
|
|
|
*/
|
|
static DdNode *
|
|
cuddBddTransferRecur(
|
|
DdManager * ddS,
|
|
DdManager * ddD,
|
|
DdNode * f,
|
|
st_table * table)
|
|
{
|
|
DdNode *ft, *fe, *t, *e, *var, *res;
|
|
DdNode *one, *zero;
|
|
unsigned int index;
|
|
int comple = 0;
|
|
|
|
statLine(ddD);
|
|
one = DD_ONE(ddD);
|
|
comple = Cudd_IsComplement(f);
|
|
|
|
/* Trivial cases. */
|
|
if (Cudd_IsConstantInt(f)) return(Cudd_NotCond(one, comple));
|
|
|
|
/* Make canonical to increase the utilization of the cache. */
|
|
f = Cudd_NotCond(f,comple);
|
|
/* Now f is a regular pointer to a non-constant node. */
|
|
|
|
/* Check the cache. */
|
|
if (st_lookup(table, f, (void **) &res))
|
|
return(Cudd_NotCond(res,comple));
|
|
|
|
/* Recursive step. */
|
|
index = f->index;
|
|
ft = cuddT(f); fe = cuddE(f);
|
|
|
|
t = cuddBddTransferRecur(ddS, ddD, ft, table);
|
|
if (t == NULL) {
|
|
return(NULL);
|
|
}
|
|
cuddRef(t);
|
|
|
|
e = cuddBddTransferRecur(ddS, ddD, fe, table);
|
|
if (e == NULL) {
|
|
Cudd_RecursiveDeref(ddD, t);
|
|
return(NULL);
|
|
}
|
|
cuddRef(e);
|
|
|
|
zero = Cudd_Not(one);
|
|
var = cuddUniqueInter(ddD,index,one,zero);
|
|
if (var == NULL) {
|
|
Cudd_RecursiveDeref(ddD, t);
|
|
Cudd_RecursiveDeref(ddD, e);
|
|
return(NULL);
|
|
}
|
|
res = cuddBddIteRecur(ddD,var,t,e);
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(ddD, t);
|
|
Cudd_RecursiveDeref(ddD, e);
|
|
return(NULL);
|
|
}
|
|
cuddRef(res);
|
|
Cudd_RecursiveDeref(ddD, t);
|
|
Cudd_RecursiveDeref(ddD, e);
|
|
|
|
if (st_add_direct(table, f, res) == ST_OUT_OF_MEM) {
|
|
Cudd_RecursiveDeref(ddD, res);
|
|
return(NULL);
|
|
}
|
|
return(Cudd_NotCond(res,comple));
|
|
|
|
} /* end of cuddBddTransferRecur */
|
|
|