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.
1996 lines
54 KiB
1996 lines
54 KiB
/**
|
|
@file
|
|
|
|
@ingroup cudd
|
|
|
|
@brief Priority functions.
|
|
|
|
@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 int cuddMinHammingDistRecur (DdNode * f, int *minterm, DdHashTable * table, int upperBound);
|
|
static DdNode * separateCube (DdManager *dd, DdNode *f, CUDD_VALUE_TYPE *distance);
|
|
static DdNode * createResult (DdManager *dd, unsigned int index, unsigned int phase, DdNode *cube, CUDD_VALUE_TYPE distance);
|
|
|
|
/** \endcond */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of exported functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**
|
|
@brief Selects pairs from R using a priority function.
|
|
|
|
@details Selects pairs from a relation R(x,y) (given as a %BDD)
|
|
in such a way that a given x appears in one pair only. Uses a
|
|
priority function to determine which y should be paired to a given x.
|
|
Three of the arguments--x, y, and z--are vectors of %BDD variables.
|
|
The first two are the variables on which R depends. The third vector
|
|
is a vector of auxiliary variables, used during the computation. This
|
|
vector is optional. If a NULL value is passed instead,
|
|
Cudd_PrioritySelect will create the working variables on the fly.
|
|
The sizes of x and y (and z if it is not NULL) should equal n.
|
|
The priority function Pi can be passed as a %BDD, or can be built by
|
|
Cudd_PrioritySelect. If NULL is passed instead of a DdNode *,
|
|
parameter Pifunc is used by Cudd_PrioritySelect to build a %BDD for the
|
|
priority function. (Pifunc is a pointer to a C function.) If Pi is not
|
|
NULL, then Pifunc is ignored. Pifunc should have the same interface as
|
|
the standard priority functions (e.g., Cudd_Dxygtdxz).
|
|
Cudd_PrioritySelect and Cudd_CProjection can sometimes be used
|
|
interchangeably. Specifically, calling Cudd_PrioritySelect with
|
|
Cudd_Xgty as Pifunc produces the same result as calling
|
|
Cudd_CProjection with the all-zero minterm as reference minterm.
|
|
However, depending on the application, one or the other may be
|
|
preferable:
|
|
<ul>
|
|
<li> When extracting representatives from an equivalence relation,
|
|
Cudd_CProjection has the advantage of nor requiring the auxiliary
|
|
variables.
|
|
<li> When computing matchings in general bipartite graphs,
|
|
Cudd_PrioritySelect normally obtains better results because it can use
|
|
more powerful matching schemes (e.g., Cudd_Dxygtdxz).
|
|
</ul>
|
|
|
|
@return a pointer to the selected function if successful; NULL
|
|
otherwise.
|
|
|
|
@sideeffect If called with z == NULL, will create new variables in
|
|
the manager.
|
|
|
|
@see Cudd_Dxygtdxz Cudd_Dxygtdyz Cudd_Xgty
|
|
Cudd_bddAdjPermuteX Cudd_CProjection
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_PrioritySelect(
|
|
DdManager * dd /**< manager */,
|
|
DdNode * R /**< %BDD of the relation */,
|
|
DdNode ** x /**< array of x variables */,
|
|
DdNode ** y /**< array of y variables */,
|
|
DdNode ** z /**< array of z variables (optional: may be NULL) */,
|
|
DdNode * Pi /**< %BDD of the priority function (optional: may be NULL) */,
|
|
int n /**< size of x, y, and z */,
|
|
DD_PRFP Pifunc /**< function used to build Pi if it is NULL */)
|
|
{
|
|
DdNode *res = NULL;
|
|
DdNode *zcube = NULL;
|
|
DdNode *Rxz, *Q;
|
|
int createdZ = 0;
|
|
int createdPi = 0;
|
|
int i;
|
|
|
|
/* Create z variables if needed. */
|
|
if (z == NULL) {
|
|
if (Pi != NULL) return(NULL);
|
|
z = ALLOC(DdNode *,n);
|
|
if (z == NULL) {
|
|
dd->errorCode = CUDD_MEMORY_OUT;
|
|
return(NULL);
|
|
}
|
|
createdZ = 1;
|
|
for (i = 0; i < n; i++) {
|
|
if (dd->size >= (int) CUDD_MAXINDEX - 1) goto endgame;
|
|
z[i] = cuddUniqueInter(dd,dd->size,dd->one,Cudd_Not(dd->one));
|
|
if (z[i] == NULL) goto endgame;
|
|
}
|
|
}
|
|
|
|
/* Create priority function BDD if needed. */
|
|
if (Pi == NULL) {
|
|
Pi = Pifunc(dd,n,x,y,z);
|
|
if (Pi == NULL) goto endgame;
|
|
createdPi = 1;
|
|
cuddRef(Pi);
|
|
}
|
|
|
|
/* Initialize abstraction cube. */
|
|
zcube = DD_ONE(dd);
|
|
cuddRef(zcube);
|
|
for (i = n - 1; i >= 0; i--) {
|
|
DdNode *tmpp;
|
|
tmpp = Cudd_bddAnd(dd,z[i],zcube);
|
|
if (tmpp == NULL) goto endgame;
|
|
cuddRef(tmpp);
|
|
Cudd_RecursiveDeref(dd,zcube);
|
|
zcube = tmpp;
|
|
}
|
|
|
|
/* Compute subset of (x,y) pairs. */
|
|
Rxz = Cudd_bddSwapVariables(dd,R,y,z,n);
|
|
if (Rxz == NULL) goto endgame;
|
|
cuddRef(Rxz);
|
|
Q = Cudd_bddAndAbstract(dd,Rxz,Pi,zcube);
|
|
if (Q == NULL) {
|
|
Cudd_RecursiveDeref(dd,Rxz);
|
|
goto endgame;
|
|
}
|
|
cuddRef(Q);
|
|
Cudd_RecursiveDeref(dd,Rxz);
|
|
res = Cudd_bddAnd(dd,R,Cudd_Not(Q));
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd,Q);
|
|
goto endgame;
|
|
}
|
|
cuddRef(res);
|
|
Cudd_RecursiveDeref(dd,Q);
|
|
|
|
endgame:
|
|
if (zcube != NULL) Cudd_RecursiveDeref(dd,zcube);
|
|
if (createdZ) {
|
|
FREE(z);
|
|
}
|
|
if (createdPi) {
|
|
Cudd_RecursiveDeref(dd,Pi);
|
|
}
|
|
if (res != NULL) cuddDeref(res);
|
|
return(res);
|
|
|
|
} /* Cudd_PrioritySelect */
|
|
|
|
|
|
/**
|
|
@brief Generates a %BDD for the function x > y.
|
|
|
|
@details This function generates a %BDD for the function x > y.
|
|
Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and
|
|
y\[0\] y\[1\] ... y\[N-1\], with 0 the most significant bit.
|
|
The %BDD is built bottom-up.
|
|
It has 3*N-1 internal nodes, if the variables are ordered as follows:
|
|
x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\].
|
|
Argument z is not used by Cudd_Xgty: it is included to make it
|
|
call-compatible to Cudd_Dxygtdxz and Cudd_Dxygtdyz.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_PrioritySelect Cudd_Dxygtdxz Cudd_Dxygtdyz
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_Xgty(
|
|
DdManager * dd /**< %DD manager */,
|
|
int N /**< number of x and y variables */,
|
|
DdNode ** z /**< array of z variables: unused */,
|
|
DdNode ** x /**< array of x variables */,
|
|
DdNode ** y /**< array of y variables */)
|
|
{
|
|
DdNode *u, *v, *w;
|
|
int i;
|
|
|
|
(void) z; /* avoid warning */
|
|
/* Build bottom part of BDD outside loop. */
|
|
u = Cudd_bddAnd(dd, x[N-1], Cudd_Not(y[N-1]));
|
|
if (u == NULL) return(NULL);
|
|
cuddRef(u);
|
|
|
|
/* Loop to build the rest of the BDD. */
|
|
for (i = N-2; i >= 0; i--) {
|
|
v = Cudd_bddAnd(dd, y[i], Cudd_Not(u));
|
|
if (v == NULL) {
|
|
Cudd_RecursiveDeref(dd, u);
|
|
return(NULL);
|
|
}
|
|
cuddRef(v);
|
|
w = Cudd_bddAnd(dd, Cudd_Not(y[i]), u);
|
|
if (w == NULL) {
|
|
Cudd_RecursiveDeref(dd, u);
|
|
Cudd_RecursiveDeref(dd, v);
|
|
return(NULL);
|
|
}
|
|
cuddRef(w);
|
|
Cudd_RecursiveDeref(dd, u);
|
|
u = Cudd_bddIte(dd, x[i], Cudd_Not(v), w);
|
|
if (u == NULL) {
|
|
Cudd_RecursiveDeref(dd, v);
|
|
Cudd_RecursiveDeref(dd, w);
|
|
return(NULL);
|
|
}
|
|
cuddRef(u);
|
|
Cudd_RecursiveDeref(dd, v);
|
|
Cudd_RecursiveDeref(dd, w);
|
|
|
|
}
|
|
cuddDeref(u);
|
|
return(u);
|
|
|
|
} /* end of Cudd_Xgty */
|
|
|
|
|
|
/**
|
|
@brief Generates a %BDD for the function x==y.
|
|
|
|
@details This function generates a %BDD for the function x==y.
|
|
Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and
|
|
y\[0\] y\[1\] ... y\[N-1\]. The %BDD is built bottom-up.
|
|
It has 3*N-1 internal nodes, if the variables are ordered as follows:
|
|
x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\].
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_addXeqy
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_Xeqy(
|
|
DdManager * dd /**< %DD manager */,
|
|
int N /**< number of x and y variables */,
|
|
DdNode ** x /**< array of x variables */,
|
|
DdNode ** y /**< array of y variables */)
|
|
{
|
|
DdNode *u, *v, *w;
|
|
int i;
|
|
|
|
/* Build bottom part of BDD outside loop. */
|
|
u = Cudd_bddIte(dd, x[N-1], y[N-1], Cudd_Not(y[N-1]));
|
|
if (u == NULL) return(NULL);
|
|
cuddRef(u);
|
|
|
|
/* Loop to build the rest of the BDD. */
|
|
for (i = N-2; i >= 0; i--) {
|
|
v = Cudd_bddAnd(dd, y[i], u);
|
|
if (v == NULL) {
|
|
Cudd_RecursiveDeref(dd, u);
|
|
return(NULL);
|
|
}
|
|
cuddRef(v);
|
|
w = Cudd_bddAnd(dd, Cudd_Not(y[i]), u);
|
|
if (w == NULL) {
|
|
Cudd_RecursiveDeref(dd, u);
|
|
Cudd_RecursiveDeref(dd, v);
|
|
return(NULL);
|
|
}
|
|
cuddRef(w);
|
|
Cudd_RecursiveDeref(dd, u);
|
|
u = Cudd_bddIte(dd, x[i], v, w);
|
|
if (u == NULL) {
|
|
Cudd_RecursiveDeref(dd, v);
|
|
Cudd_RecursiveDeref(dd, w);
|
|
return(NULL);
|
|
}
|
|
cuddRef(u);
|
|
Cudd_RecursiveDeref(dd, v);
|
|
Cudd_RecursiveDeref(dd, w);
|
|
}
|
|
cuddDeref(u);
|
|
return(u);
|
|
|
|
} /* end of Cudd_Xeqy */
|
|
|
|
|
|
/**
|
|
@brief Generates an %ADD for the function x==y.
|
|
|
|
@details This function generates an %ADD for the function x==y.
|
|
Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and
|
|
y\[0\] y\[1\] ... y\[N-1\]. The %ADD is built bottom-up.
|
|
It has 3*N-1 internal nodes, if the variables are ordered as follows:
|
|
x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\].
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_Xeqy
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_addXeqy(
|
|
DdManager * dd /**< %DD manager */,
|
|
int N /**< number of x and y variables */,
|
|
DdNode ** x /**< array of x variables */,
|
|
DdNode ** y /**< array of y variables */)
|
|
{
|
|
DdNode *one, *zero;
|
|
DdNode *u, *v, *w;
|
|
int i;
|
|
|
|
one = DD_ONE(dd);
|
|
zero = DD_ZERO(dd);
|
|
|
|
/* Build bottom part of ADD outside loop. */
|
|
v = Cudd_addIte(dd, y[N-1], one, zero);
|
|
if (v == NULL) return(NULL);
|
|
cuddRef(v);
|
|
w = Cudd_addIte(dd, y[N-1], zero, one);
|
|
if (w == NULL) {
|
|
Cudd_RecursiveDeref(dd, v);
|
|
return(NULL);
|
|
}
|
|
cuddRef(w);
|
|
u = Cudd_addIte(dd, x[N-1], v, w);
|
|
if (u == NULL) {
|
|
Cudd_RecursiveDeref(dd, v);
|
|
Cudd_RecursiveDeref(dd, w);
|
|
return(NULL);
|
|
}
|
|
cuddRef(u);
|
|
Cudd_RecursiveDeref(dd, v);
|
|
Cudd_RecursiveDeref(dd, w);
|
|
|
|
/* Loop to build the rest of the ADD. */
|
|
for (i = N-2; i >= 0; i--) {
|
|
v = Cudd_addIte(dd, y[i], u, zero);
|
|
if (v == NULL) {
|
|
Cudd_RecursiveDeref(dd, u);
|
|
return(NULL);
|
|
}
|
|
cuddRef(v);
|
|
w = Cudd_addIte(dd, y[i], zero, u);
|
|
if (w == NULL) {
|
|
Cudd_RecursiveDeref(dd, u);
|
|
Cudd_RecursiveDeref(dd, v);
|
|
return(NULL);
|
|
}
|
|
cuddRef(w);
|
|
Cudd_RecursiveDeref(dd, u);
|
|
u = Cudd_addIte(dd, x[i], v, w);
|
|
if (w == NULL) {
|
|
Cudd_RecursiveDeref(dd, v);
|
|
Cudd_RecursiveDeref(dd, w);
|
|
return(NULL);
|
|
}
|
|
cuddRef(u);
|
|
Cudd_RecursiveDeref(dd, v);
|
|
Cudd_RecursiveDeref(dd, w);
|
|
}
|
|
cuddDeref(u);
|
|
return(u);
|
|
|
|
} /* end of Cudd_addXeqy */
|
|
|
|
|
|
/**
|
|
@brief Generates a %BDD for the function d(x,y) > d(x,z).
|
|
|
|
@details This function generates a %BDD for the function d(x,y)
|
|
> d(x,z);
|
|
x, y, and z are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\],
|
|
y\[0\] y\[1\] ... y\[N-1\], and z\[0\] z\[1\] ... z\[N-1\],
|
|
with 0 the most significant bit.
|
|
The distance d(x,y) is defined as:
|
|
\f$\sum_{i=0}^{N-1}(|x_i - y_i| \cdot 2^{N-i-1})\f$.
|
|
The %BDD is built bottom-up.
|
|
It has 7*N-3 internal nodes, if the variables are ordered as follows:
|
|
x\[0\] y\[0\] z\[0\] x\[1\] y\[1\] z\[1\] ... x\[N-1\] y\[N-1\] z\[N-1\].
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_PrioritySelect Cudd_Dxygtdyz Cudd_Xgty Cudd_bddAdjPermuteX
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_Dxygtdxz(
|
|
DdManager * dd /**< %DD manager */,
|
|
int N /**< number of x, y, and z variables */,
|
|
DdNode ** x /**< array of x variables */,
|
|
DdNode ** y /**< array of y variables */,
|
|
DdNode ** z /**< array of z variables */)
|
|
{
|
|
DdNode *one, *zero;
|
|
DdNode *z1, *z2, *z3, *z4, *y1_, *y2, *x1;
|
|
int i;
|
|
|
|
one = DD_ONE(dd);
|
|
zero = Cudd_Not(one);
|
|
|
|
/* Build bottom part of BDD outside loop. */
|
|
y1_ = Cudd_bddIte(dd, y[N-1], one, Cudd_Not(z[N-1]));
|
|
if (y1_ == NULL) return(NULL);
|
|
cuddRef(y1_);
|
|
y2 = Cudd_bddIte(dd, y[N-1], z[N-1], one);
|
|
if (y2 == NULL) {
|
|
Cudd_RecursiveDeref(dd, y1_);
|
|
return(NULL);
|
|
}
|
|
cuddRef(y2);
|
|
x1 = Cudd_bddIte(dd, x[N-1], y1_, y2);
|
|
if (x1 == NULL) {
|
|
Cudd_RecursiveDeref(dd, y1_);
|
|
Cudd_RecursiveDeref(dd, y2);
|
|
return(NULL);
|
|
}
|
|
cuddRef(x1);
|
|
Cudd_RecursiveDeref(dd, y1_);
|
|
Cudd_RecursiveDeref(dd, y2);
|
|
|
|
/* Loop to build the rest of the BDD. */
|
|
for (i = N-2; i >= 0; i--) {
|
|
z1 = Cudd_bddIte(dd, z[i], one, Cudd_Not(x1));
|
|
if (z1 == NULL) {
|
|
Cudd_RecursiveDeref(dd, x1);
|
|
return(NULL);
|
|
}
|
|
cuddRef(z1);
|
|
z2 = Cudd_bddIte(dd, z[i], x1, one);
|
|
if (z2 == NULL) {
|
|
Cudd_RecursiveDeref(dd, x1);
|
|
Cudd_RecursiveDeref(dd, z1);
|
|
return(NULL);
|
|
}
|
|
cuddRef(z2);
|
|
z3 = Cudd_bddIte(dd, z[i], one, x1);
|
|
if (z3 == NULL) {
|
|
Cudd_RecursiveDeref(dd, x1);
|
|
Cudd_RecursiveDeref(dd, z1);
|
|
Cudd_RecursiveDeref(dd, z2);
|
|
return(NULL);
|
|
}
|
|
cuddRef(z3);
|
|
z4 = Cudd_bddIte(dd, z[i], x1, zero);
|
|
if (z4 == NULL) {
|
|
Cudd_RecursiveDeref(dd, x1);
|
|
Cudd_RecursiveDeref(dd, z1);
|
|
Cudd_RecursiveDeref(dd, z2);
|
|
Cudd_RecursiveDeref(dd, z3);
|
|
return(NULL);
|
|
}
|
|
cuddRef(z4);
|
|
Cudd_RecursiveDeref(dd, x1);
|
|
y1_ = Cudd_bddIte(dd, y[i], z2, Cudd_Not(z1));
|
|
if (y1_ == NULL) {
|
|
Cudd_RecursiveDeref(dd, z1);
|
|
Cudd_RecursiveDeref(dd, z2);
|
|
Cudd_RecursiveDeref(dd, z3);
|
|
Cudd_RecursiveDeref(dd, z4);
|
|
return(NULL);
|
|
}
|
|
cuddRef(y1_);
|
|
y2 = Cudd_bddIte(dd, y[i], z4, z3);
|
|
if (y2 == NULL) {
|
|
Cudd_RecursiveDeref(dd, z1);
|
|
Cudd_RecursiveDeref(dd, z2);
|
|
Cudd_RecursiveDeref(dd, z3);
|
|
Cudd_RecursiveDeref(dd, z4);
|
|
Cudd_RecursiveDeref(dd, y1_);
|
|
return(NULL);
|
|
}
|
|
cuddRef(y2);
|
|
Cudd_RecursiveDeref(dd, z1);
|
|
Cudd_RecursiveDeref(dd, z2);
|
|
Cudd_RecursiveDeref(dd, z3);
|
|
Cudd_RecursiveDeref(dd, z4);
|
|
x1 = Cudd_bddIte(dd, x[i], y1_, y2);
|
|
if (x1 == NULL) {
|
|
Cudd_RecursiveDeref(dd, y1_);
|
|
Cudd_RecursiveDeref(dd, y2);
|
|
return(NULL);
|
|
}
|
|
cuddRef(x1);
|
|
Cudd_RecursiveDeref(dd, y1_);
|
|
Cudd_RecursiveDeref(dd, y2);
|
|
}
|
|
cuddDeref(x1);
|
|
return(Cudd_Not(x1));
|
|
|
|
} /* end of Cudd_Dxygtdxz */
|
|
|
|
|
|
/**
|
|
@brief Generates a %BDD for the function d(x,y) > d(y,z).
|
|
|
|
@details This function generates a %BDD for the function d(x,y)
|
|
> d(y,z);
|
|
x, y, and z are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\],
|
|
y\[0\] y\[1\] ... y\[N-1\], and z\[0\] z\[1\] ... z\[N-1\],
|
|
with 0 the most significant bit.
|
|
The distance d(x,y) is defined as:
|
|
\f$\sum_{i=0}^{N-1}(|x_i - y_i| \cdot 2^{N-i-1})\f$.
|
|
The %BDD is built bottom-up.
|
|
It has 7*N-3 internal nodes, if the variables are ordered as follows:
|
|
x\[0\] y\[0\] z\[0\] x\[1\] y\[1\] z\[1\] ... x\[N-1\] y\[N-1\] z\[N-1\].
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_PrioritySelect Cudd_Dxygtdxz Cudd_Xgty Cudd_bddAdjPermuteX
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_Dxygtdyz(
|
|
DdManager * dd /**< %DD manager */,
|
|
int N /**< number of x, y, and z variables */,
|
|
DdNode ** x /**< array of x variables */,
|
|
DdNode ** y /**< array of y variables */,
|
|
DdNode ** z /**< array of z variables */)
|
|
{
|
|
DdNode *one, *zero;
|
|
DdNode *z1, *z2, *z3, *z4, *y1_, *y2, *x1;
|
|
int i;
|
|
|
|
one = DD_ONE(dd);
|
|
zero = Cudd_Not(one);
|
|
|
|
/* Build bottom part of BDD outside loop. */
|
|
y1_ = Cudd_bddIte(dd, y[N-1], one, z[N-1]);
|
|
if (y1_ == NULL) return(NULL);
|
|
cuddRef(y1_);
|
|
y2 = Cudd_bddIte(dd, y[N-1], z[N-1], zero);
|
|
if (y2 == NULL) {
|
|
Cudd_RecursiveDeref(dd, y1_);
|
|
return(NULL);
|
|
}
|
|
cuddRef(y2);
|
|
x1 = Cudd_bddIte(dd, x[N-1], y1_, Cudd_Not(y2));
|
|
if (x1 == NULL) {
|
|
Cudd_RecursiveDeref(dd, y1_);
|
|
Cudd_RecursiveDeref(dd, y2);
|
|
return(NULL);
|
|
}
|
|
cuddRef(x1);
|
|
Cudd_RecursiveDeref(dd, y1_);
|
|
Cudd_RecursiveDeref(dd, y2);
|
|
|
|
/* Loop to build the rest of the BDD. */
|
|
for (i = N-2; i >= 0; i--) {
|
|
z1 = Cudd_bddIte(dd, z[i], x1, zero);
|
|
if (z1 == NULL) {
|
|
Cudd_RecursiveDeref(dd, x1);
|
|
return(NULL);
|
|
}
|
|
cuddRef(z1);
|
|
z2 = Cudd_bddIte(dd, z[i], x1, one);
|
|
if (z2 == NULL) {
|
|
Cudd_RecursiveDeref(dd, x1);
|
|
Cudd_RecursiveDeref(dd, z1);
|
|
return(NULL);
|
|
}
|
|
cuddRef(z2);
|
|
z3 = Cudd_bddIte(dd, z[i], one, x1);
|
|
if (z3 == NULL) {
|
|
Cudd_RecursiveDeref(dd, x1);
|
|
Cudd_RecursiveDeref(dd, z1);
|
|
Cudd_RecursiveDeref(dd, z2);
|
|
return(NULL);
|
|
}
|
|
cuddRef(z3);
|
|
z4 = Cudd_bddIte(dd, z[i], one, Cudd_Not(x1));
|
|
if (z4 == NULL) {
|
|
Cudd_RecursiveDeref(dd, x1);
|
|
Cudd_RecursiveDeref(dd, z1);
|
|
Cudd_RecursiveDeref(dd, z2);
|
|
Cudd_RecursiveDeref(dd, z3);
|
|
return(NULL);
|
|
}
|
|
cuddRef(z4);
|
|
Cudd_RecursiveDeref(dd, x1);
|
|
y1_ = Cudd_bddIte(dd, y[i], z2, z1);
|
|
if (y1_ == NULL) {
|
|
Cudd_RecursiveDeref(dd, z1);
|
|
Cudd_RecursiveDeref(dd, z2);
|
|
Cudd_RecursiveDeref(dd, z3);
|
|
Cudd_RecursiveDeref(dd, z4);
|
|
return(NULL);
|
|
}
|
|
cuddRef(y1_);
|
|
y2 = Cudd_bddIte(dd, y[i], z4, Cudd_Not(z3));
|
|
if (y2 == NULL) {
|
|
Cudd_RecursiveDeref(dd, z1);
|
|
Cudd_RecursiveDeref(dd, z2);
|
|
Cudd_RecursiveDeref(dd, z3);
|
|
Cudd_RecursiveDeref(dd, z4);
|
|
Cudd_RecursiveDeref(dd, y1_);
|
|
return(NULL);
|
|
}
|
|
cuddRef(y2);
|
|
Cudd_RecursiveDeref(dd, z1);
|
|
Cudd_RecursiveDeref(dd, z2);
|
|
Cudd_RecursiveDeref(dd, z3);
|
|
Cudd_RecursiveDeref(dd, z4);
|
|
x1 = Cudd_bddIte(dd, x[i], y1_, Cudd_Not(y2));
|
|
if (x1 == NULL) {
|
|
Cudd_RecursiveDeref(dd, y1_);
|
|
Cudd_RecursiveDeref(dd, y2);
|
|
return(NULL);
|
|
}
|
|
cuddRef(x1);
|
|
Cudd_RecursiveDeref(dd, y1_);
|
|
Cudd_RecursiveDeref(dd, y2);
|
|
}
|
|
cuddDeref(x1);
|
|
return(Cudd_Not(x1));
|
|
|
|
} /* end of Cudd_Dxygtdyz */
|
|
|
|
|
|
/**
|
|
@brief Generates a %BDD for the function x - y ≥ c.
|
|
|
|
@details This function generates a %BDD for the function x -y ≥ c.
|
|
Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and
|
|
y\[0\] y\[1\] ... y\[N-1\], with 0 the most significant bit.
|
|
The %BDD is built bottom-up.
|
|
It has a linear number of nodes if the variables are ordered as follows:
|
|
x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\].
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_Xgty
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_Inequality(
|
|
DdManager * dd /**< %DD manager */,
|
|
int N /**< number of x and y variables */,
|
|
int c /**< right-hand side constant */,
|
|
DdNode ** x /**< array of x variables */,
|
|
DdNode ** y /**< array of y variables */)
|
|
{
|
|
/* The nodes at level i represent values of the difference that are
|
|
** multiples of 2^i. We use variables with names starting with k
|
|
** to denote the multipliers of 2^i in such multiples. */
|
|
int kTrue = c;
|
|
int kFalse = c - 1;
|
|
/* Mask used to compute the ceiling function. Since we divide by 2^i,
|
|
** we want to know whether the dividend is a multiple of 2^i. If it is,
|
|
** then ceiling and floor coincide; otherwise, they differ by one. */
|
|
int mask = 1;
|
|
int i;
|
|
|
|
DdNode *f = NULL; /* the eventual result */
|
|
DdNode *one = DD_ONE(dd);
|
|
DdNode *zero = Cudd_Not(one);
|
|
|
|
/* Two x-labeled nodes are created at most at each iteration. They are
|
|
** stored, along with their k values, in these variables. At each level,
|
|
** the old nodes are freed and the new nodes are copied into the old map.
|
|
*/
|
|
DdNode *map[2] = {NULL, NULL};
|
|
int invalidIndex = 1 << (N-1);
|
|
int index[2] = {invalidIndex, invalidIndex};
|
|
|
|
/* This should never happen. */
|
|
if (N < 0) return(NULL);
|
|
|
|
/* If there are no bits, both operands are 0. The result depends on c. */
|
|
if (N == 0) {
|
|
if (c >= 0) return(one);
|
|
else return(zero);
|
|
}
|
|
|
|
/* The maximum or the minimum difference comparing to c can generate the terminal case */
|
|
if ((1 << N) - 1 < c) return(zero);
|
|
else if ((-(1 << N) + 1) >= c) return(one);
|
|
|
|
/* Build the result bottom up. */
|
|
for (i = 1; i <= N; i++) {
|
|
int kTrueLower, kFalseLower;
|
|
int leftChild, middleChild, rightChild;
|
|
DdNode *g0, *g1, *fplus, *fequal, *fminus;
|
|
int j;
|
|
DdNode *newMap[2] = {NULL, NULL};
|
|
int newIndex[2];
|
|
|
|
kTrueLower = kTrue;
|
|
kFalseLower = kFalse;
|
|
/* kTrue = ceiling((c-1)/2^i) + 1 */
|
|
kTrue = ((c-1) >> i) + ((c & mask) != 1) + 1;
|
|
mask = (mask << 1) | 1;
|
|
/* kFalse = floor(c/2^i) - 1 */
|
|
kFalse = (c >> i) - 1;
|
|
newIndex[0] = invalidIndex;
|
|
newIndex[1] = invalidIndex;
|
|
|
|
for (j = kFalse + 1; j < kTrue; j++) {
|
|
/* Skip if node is not reachable from top of BDD. */
|
|
if ((j >= (1 << (N - i))) || (j <= -(1 << (N -i)))) continue;
|
|
|
|
/* Find f- */
|
|
leftChild = (j << 1) - 1;
|
|
if (leftChild >= kTrueLower) {
|
|
fminus = one;
|
|
} else if (leftChild <= kFalseLower) {
|
|
fminus = zero;
|
|
} else {
|
|
assert(leftChild == index[0] || leftChild == index[1]);
|
|
if (leftChild == index[0]) {
|
|
fminus = map[0];
|
|
} else {
|
|
fminus = map[1];
|
|
}
|
|
}
|
|
|
|
/* Find f= */
|
|
middleChild = j << 1;
|
|
if (middleChild >= kTrueLower) {
|
|
fequal = one;
|
|
} else if (middleChild <= kFalseLower) {
|
|
fequal = zero;
|
|
} else {
|
|
assert(middleChild == index[0] || middleChild == index[1]);
|
|
if (middleChild == index[0]) {
|
|
fequal = map[0];
|
|
} else {
|
|
fequal = map[1];
|
|
}
|
|
}
|
|
|
|
/* Find f+ */
|
|
rightChild = (j << 1) + 1;
|
|
if (rightChild >= kTrueLower) {
|
|
fplus = one;
|
|
} else if (rightChild <= kFalseLower) {
|
|
fplus = zero;
|
|
} else {
|
|
assert(rightChild == index[0] || rightChild == index[1]);
|
|
if (rightChild == index[0]) {
|
|
fplus = map[0];
|
|
} else {
|
|
fplus = map[1];
|
|
}
|
|
}
|
|
|
|
/* Build new nodes. */
|
|
g1 = Cudd_bddIte(dd, y[N - i], fequal, fplus);
|
|
if (g1 == NULL) {
|
|
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
|
|
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
|
|
if (newIndex[0] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[0]);
|
|
if (newIndex[1] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[1]);
|
|
return(NULL);
|
|
}
|
|
cuddRef(g1);
|
|
g0 = Cudd_bddIte(dd, y[N - i], fminus, fequal);
|
|
if (g0 == NULL) {
|
|
Cudd_IterDerefBdd(dd, g1);
|
|
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
|
|
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
|
|
if (newIndex[0] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[0]);
|
|
if (newIndex[1] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[1]);
|
|
return(NULL);
|
|
}
|
|
cuddRef(g0);
|
|
f = Cudd_bddIte(dd, x[N - i], g1, g0);
|
|
if (f == NULL) {
|
|
Cudd_IterDerefBdd(dd, g1);
|
|
Cudd_IterDerefBdd(dd, g0);
|
|
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
|
|
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
|
|
if (newIndex[0] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[0]);
|
|
if (newIndex[1] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[1]);
|
|
return(NULL);
|
|
}
|
|
cuddRef(f);
|
|
Cudd_IterDerefBdd(dd, g1);
|
|
Cudd_IterDerefBdd(dd, g0);
|
|
|
|
/* Save newly computed node in map. */
|
|
assert(newIndex[0] == invalidIndex || newIndex[1] == invalidIndex);
|
|
if (newIndex[0] == invalidIndex) {
|
|
newIndex[0] = j;
|
|
newMap[0] = f;
|
|
} else {
|
|
newIndex[1] = j;
|
|
newMap[1] = f;
|
|
}
|
|
}
|
|
|
|
/* Copy new map to map. */
|
|
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
|
|
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
|
|
map[0] = newMap[0];
|
|
map[1] = newMap[1];
|
|
index[0] = newIndex[0];
|
|
index[1] = newIndex[1];
|
|
}
|
|
|
|
cuddDeref(f);
|
|
return(f);
|
|
|
|
} /* end of Cudd_Inequality */
|
|
|
|
|
|
/**
|
|
@brief Generates a %BDD for the function x - y != c.
|
|
|
|
@details This function generates a %BDD for the function x -y != c.
|
|
Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and
|
|
y\[0\] y\[1\] ... y\[N-1\], with 0 the most significant bit.
|
|
The %BDD is built bottom-up.
|
|
It has a linear number of nodes if the variables are ordered as follows:
|
|
x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\].
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_Xgty
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_Disequality(
|
|
DdManager * dd /**< %DD manager */,
|
|
int N /**< number of x and y variables */,
|
|
int c /**< right-hand side constant */,
|
|
DdNode ** x /**< array of x variables */,
|
|
DdNode ** y /**< array of y variables */)
|
|
{
|
|
/* The nodes at level i represent values of the difference that are
|
|
** multiples of 2^i. We use variables with names starting with k
|
|
** to denote the multipliers of 2^i in such multiples. */
|
|
int kTrueLb = c + 1;
|
|
int kTrueUb = c - 1;
|
|
int kFalse = c;
|
|
/* Mask used to compute the ceiling function. Since we divide by 2^i,
|
|
** we want to know whether the dividend is a multiple of 2^i. If it is,
|
|
** then ceiling and floor coincide; otherwise, they differ by one. */
|
|
int mask = 1;
|
|
int i;
|
|
|
|
DdNode *f = NULL; /* the eventual result */
|
|
DdNode *one = DD_ONE(dd);
|
|
DdNode *zero = Cudd_Not(one);
|
|
|
|
/* Two x-labeled nodes are created at most at each iteration. They are
|
|
** stored, along with their k values, in these variables. At each level,
|
|
** the old nodes are freed and the new nodes are copied into the old map.
|
|
*/
|
|
DdNode *map[2] = {NULL, NULL};
|
|
int invalidIndex = 1 << (N-1);
|
|
int index[2] = {invalidIndex, invalidIndex};
|
|
|
|
/* This should never happen. */
|
|
if (N < 0) return(NULL);
|
|
|
|
/* If there are no bits, both operands are 0. The result depends on c. */
|
|
if (N == 0) {
|
|
if (c != 0) return(one);
|
|
else return(zero);
|
|
}
|
|
|
|
/* The maximum or the minimum difference comparing to c can generate the terminal case */
|
|
if ((1 << N) - 1 < c || (-(1 << N) + 1) > c) return(one);
|
|
|
|
/* Build the result bottom up. */
|
|
for (i = 1; i <= N; i++) {
|
|
int kTrueLbLower, kTrueUbLower;
|
|
int leftChild, middleChild, rightChild;
|
|
DdNode *g0, *g1, *fplus, *fequal, *fminus;
|
|
int j;
|
|
DdNode *newMap[2] = {NULL, NULL};
|
|
int newIndex[2];
|
|
|
|
kTrueLbLower = kTrueLb;
|
|
kTrueUbLower = kTrueUb;
|
|
/* kTrueLb = floor((c-1)/2^i) + 2 */
|
|
kTrueLb = ((c-1) >> i) + 2;
|
|
/* kTrueUb = ceiling((c+1)/2^i) - 2 */
|
|
kTrueUb = ((c+1) >> i) + (((c+2) & mask) != 1) - 2;
|
|
mask = (mask << 1) | 1;
|
|
newIndex[0] = invalidIndex;
|
|
newIndex[1] = invalidIndex;
|
|
|
|
for (j = kTrueUb + 1; j < kTrueLb; j++) {
|
|
/* Skip if node is not reachable from top of BDD. */
|
|
if ((j >= (1 << (N - i))) || (j <= -(1 << (N -i)))) continue;
|
|
|
|
/* Find f- */
|
|
leftChild = (j << 1) - 1;
|
|
if (leftChild >= kTrueLbLower || leftChild <= kTrueUbLower) {
|
|
fminus = one;
|
|
} else if (i == 1 && leftChild == kFalse) {
|
|
fminus = zero;
|
|
} else {
|
|
assert(leftChild == index[0] || leftChild == index[1]);
|
|
if (leftChild == index[0]) {
|
|
fminus = map[0];
|
|
} else {
|
|
fminus = map[1];
|
|
}
|
|
}
|
|
|
|
/* Find f= */
|
|
middleChild = j << 1;
|
|
if (middleChild >= kTrueLbLower || middleChild <= kTrueUbLower) {
|
|
fequal = one;
|
|
} else if (i == 1 && middleChild == kFalse) {
|
|
fequal = zero;
|
|
} else {
|
|
assert(middleChild == index[0] || middleChild == index[1]);
|
|
if (middleChild == index[0]) {
|
|
fequal = map[0];
|
|
} else {
|
|
fequal = map[1];
|
|
}
|
|
}
|
|
|
|
/* Find f+ */
|
|
rightChild = (j << 1) + 1;
|
|
if (rightChild >= kTrueLbLower || rightChild <= kTrueUbLower) {
|
|
fplus = one;
|
|
} else if (i == 1 && rightChild == kFalse) {
|
|
fplus = zero;
|
|
} else {
|
|
assert(rightChild == index[0] || rightChild == index[1]);
|
|
if (rightChild == index[0]) {
|
|
fplus = map[0];
|
|
} else {
|
|
fplus = map[1];
|
|
}
|
|
}
|
|
|
|
/* Build new nodes. */
|
|
g1 = Cudd_bddIte(dd, y[N - i], fequal, fplus);
|
|
if (g1 == NULL) {
|
|
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
|
|
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
|
|
if (newIndex[0] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[0]);
|
|
if (newIndex[1] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[1]);
|
|
return(NULL);
|
|
}
|
|
cuddRef(g1);
|
|
g0 = Cudd_bddIte(dd, y[N - i], fminus, fequal);
|
|
if (g0 == NULL) {
|
|
Cudd_IterDerefBdd(dd, g1);
|
|
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
|
|
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
|
|
if (newIndex[0] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[0]);
|
|
if (newIndex[1] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[1]);
|
|
return(NULL);
|
|
}
|
|
cuddRef(g0);
|
|
f = Cudd_bddIte(dd, x[N - i], g1, g0);
|
|
if (f == NULL) {
|
|
Cudd_IterDerefBdd(dd, g1);
|
|
Cudd_IterDerefBdd(dd, g0);
|
|
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
|
|
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
|
|
if (newIndex[0] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[0]);
|
|
if (newIndex[1] != invalidIndex) Cudd_IterDerefBdd(dd, newMap[1]);
|
|
return(NULL);
|
|
}
|
|
cuddRef(f);
|
|
Cudd_IterDerefBdd(dd, g1);
|
|
Cudd_IterDerefBdd(dd, g0);
|
|
|
|
/* Save newly computed node in map. */
|
|
assert(newIndex[0] == invalidIndex || newIndex[1] == invalidIndex);
|
|
if (newIndex[0] == invalidIndex) {
|
|
newIndex[0] = j;
|
|
newMap[0] = f;
|
|
} else {
|
|
newIndex[1] = j;
|
|
newMap[1] = f;
|
|
}
|
|
}
|
|
|
|
/* Copy new map to map. */
|
|
if (index[0] != invalidIndex) Cudd_IterDerefBdd(dd, map[0]);
|
|
if (index[1] != invalidIndex) Cudd_IterDerefBdd(dd, map[1]);
|
|
map[0] = newMap[0];
|
|
map[1] = newMap[1];
|
|
index[0] = newIndex[0];
|
|
index[1] = newIndex[1];
|
|
}
|
|
|
|
cuddDeref(f);
|
|
return(f);
|
|
|
|
} /* end of Cudd_Disequality */
|
|
|
|
|
|
/**
|
|
@brief Generates a %BDD for the function lowerB ≤ x ≤ upperB.
|
|
|
|
@details This function generates a %BDD for the function
|
|
lowerB ≤ x ≤ upperB, where x is an N-bit number,
|
|
x\[0\] x\[1\] ... x\[N-1\], with 0 the most significant bit (important!).
|
|
The number of variables N should be sufficient to represent the bounds;
|
|
otherwise, the bounds are truncated to their N least significant bits.
|
|
Two BDDs are built bottom-up for lowerB ≤ x and x ≤ upperB, and they
|
|
are finally conjoined.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_Xgty
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_bddInterval(
|
|
DdManager * dd /**< %DD manager */,
|
|
int N /**< number of x variables */,
|
|
DdNode ** x /**< array of x variables */,
|
|
unsigned int lowerB /**< lower bound */,
|
|
unsigned int upperB /**< upper bound */)
|
|
{
|
|
DdNode *one, *zero;
|
|
DdNode *r, *rl, *ru;
|
|
int i;
|
|
|
|
one = DD_ONE(dd);
|
|
zero = Cudd_Not(one);
|
|
|
|
rl = one;
|
|
cuddRef(rl);
|
|
ru = one;
|
|
cuddRef(ru);
|
|
|
|
/* Loop to build the rest of the BDDs. */
|
|
for (i = N-1; i >= 0; i--) {
|
|
DdNode *vl, *vu;
|
|
vl = Cudd_bddIte(dd, x[i],
|
|
lowerB&1 ? rl : one,
|
|
lowerB&1 ? zero : rl);
|
|
if (vl == NULL) {
|
|
Cudd_IterDerefBdd(dd, rl);
|
|
Cudd_IterDerefBdd(dd, ru);
|
|
return(NULL);
|
|
}
|
|
cuddRef(vl);
|
|
Cudd_IterDerefBdd(dd, rl);
|
|
rl = vl;
|
|
lowerB >>= 1;
|
|
vu = Cudd_bddIte(dd, x[i],
|
|
upperB&1 ? ru : zero,
|
|
upperB&1 ? one : ru);
|
|
if (vu == NULL) {
|
|
Cudd_IterDerefBdd(dd, rl);
|
|
Cudd_IterDerefBdd(dd, ru);
|
|
return(NULL);
|
|
}
|
|
cuddRef(vu);
|
|
Cudd_IterDerefBdd(dd, ru);
|
|
ru = vu;
|
|
upperB >>= 1;
|
|
}
|
|
|
|
/* Conjoin the two bounds. */
|
|
r = Cudd_bddAnd(dd, rl, ru);
|
|
if (r == NULL) {
|
|
Cudd_IterDerefBdd(dd, rl);
|
|
Cudd_IterDerefBdd(dd, ru);
|
|
return(NULL);
|
|
}
|
|
cuddRef(r);
|
|
Cudd_IterDerefBdd(dd, rl);
|
|
Cudd_IterDerefBdd(dd, ru);
|
|
cuddDeref(r);
|
|
return(r);
|
|
|
|
} /* end of Cudd_bddInterval */
|
|
|
|
|
|
/**
|
|
@brief Computes the compatible projection of R w.r.t. cube Y.
|
|
|
|
@details Computes the compatible projection of relation R with
|
|
respect to cube Y. For a comparison between Cudd_CProjection and
|
|
Cudd_PrioritySelect, see the documentation of the latter.
|
|
|
|
@return a pointer to the c-projection if successful; NULL otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_PrioritySelect
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_CProjection(
|
|
DdManager * dd,
|
|
DdNode * R,
|
|
DdNode * Y)
|
|
{
|
|
DdNode *res;
|
|
DdNode *support;
|
|
|
|
if (Cudd_CheckCube(dd,Y) == 0) {
|
|
(void) fprintf(dd->err,
|
|
"Error: The third argument of Cudd_CProjection should be a cube\n");
|
|
dd->errorCode = CUDD_INVALID_ARG;
|
|
return(NULL);
|
|
}
|
|
|
|
/* Compute the support of Y, which is used by the abstraction step
|
|
** in cuddCProjectionRecur.
|
|
*/
|
|
support = Cudd_Support(dd,Y);
|
|
if (support == NULL) return(NULL);
|
|
cuddRef(support);
|
|
|
|
do {
|
|
dd->reordered = 0;
|
|
res = cuddCProjectionRecur(dd,R,Y,support);
|
|
} while (dd->reordered == 1);
|
|
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd,support);
|
|
if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
|
|
dd->timeoutHandler(dd, dd->tohArg);
|
|
}
|
|
return(NULL);
|
|
}
|
|
cuddRef(res);
|
|
Cudd_RecursiveDeref(dd,support);
|
|
cuddDeref(res);
|
|
|
|
return(res);
|
|
|
|
} /* end of Cudd_CProjection */
|
|
|
|
|
|
/**
|
|
@brief Computes the Hamming distance %ADD.
|
|
|
|
@details The two vectors xVars and yVars identify the variables that
|
|
form the two arguments.
|
|
|
|
@return an %ADD that gives the Hamming distance between its two
|
|
arguments if successful; NULL otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_addHamming(
|
|
DdManager * dd,
|
|
DdNode ** xVars,
|
|
DdNode ** yVars,
|
|
int nVars)
|
|
{
|
|
DdNode *result,*tempBdd;
|
|
DdNode *tempAdd,*temp;
|
|
int i;
|
|
|
|
result = DD_ZERO(dd);
|
|
cuddRef(result);
|
|
|
|
for (i = 0; i < nVars; i++) {
|
|
tempBdd = Cudd_bddIte(dd,xVars[i],Cudd_Not(yVars[i]),yVars[i]);
|
|
if (tempBdd == NULL) {
|
|
Cudd_RecursiveDeref(dd,result);
|
|
return(NULL);
|
|
}
|
|
cuddRef(tempBdd);
|
|
tempAdd = Cudd_BddToAdd(dd,tempBdd);
|
|
if (tempAdd == NULL) {
|
|
Cudd_RecursiveDeref(dd,tempBdd);
|
|
Cudd_RecursiveDeref(dd,result);
|
|
return(NULL);
|
|
}
|
|
cuddRef(tempAdd);
|
|
Cudd_RecursiveDeref(dd,tempBdd);
|
|
temp = Cudd_addApply(dd,Cudd_addPlus,tempAdd,result);
|
|
if (temp == NULL) {
|
|
Cudd_RecursiveDeref(dd,tempAdd);
|
|
Cudd_RecursiveDeref(dd,result);
|
|
return(NULL);
|
|
}
|
|
cuddRef(temp);
|
|
Cudd_RecursiveDeref(dd,tempAdd);
|
|
Cudd_RecursiveDeref(dd,result);
|
|
result = temp;
|
|
}
|
|
|
|
cuddDeref(result);
|
|
return(result);
|
|
|
|
} /* end of Cudd_addHamming */
|
|
|
|
|
|
/**
|
|
@brief Returns the minimum Hamming distance between f and minterm.
|
|
|
|
@details Returns the minimum Hamming distance between the
|
|
minterms of a function f and a reference minterm. The function is
|
|
given as a %BDD; the minterm is given as an array of integers, one
|
|
for each variable in the manager.
|
|
|
|
@return the minimum distance if it is less than the upper bound; the
|
|
upper bound if the minimum distance is at least as large;
|
|
CUDD_OUT_OF_MEM in case of failure.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_addHamming Cudd_bddClosestCube
|
|
|
|
*/
|
|
int
|
|
Cudd_MinHammingDist(
|
|
DdManager *dd /**< %DD manager */,
|
|
DdNode *f /**< function to examine */,
|
|
int *minterm /**< reference minterm */,
|
|
int upperBound /**< distance above which an approximate answer is OK */)
|
|
{
|
|
DdHashTable *table;
|
|
CUDD_VALUE_TYPE epsilon;
|
|
int res;
|
|
|
|
table = cuddHashTableInit(dd,1,2);
|
|
if (table == NULL) {
|
|
return(CUDD_OUT_OF_MEM);
|
|
}
|
|
epsilon = Cudd_ReadEpsilon(dd);
|
|
Cudd_SetEpsilon(dd,(CUDD_VALUE_TYPE)0.0);
|
|
res = cuddMinHammingDistRecur(f,minterm,table,upperBound);
|
|
cuddHashTableQuit(table);
|
|
Cudd_SetEpsilon(dd,epsilon);
|
|
|
|
return(res);
|
|
|
|
} /* end of Cudd_MinHammingDist */
|
|
|
|
|
|
/**
|
|
@brief Finds a cube of f at minimum Hamming distance from the minterms of g.
|
|
|
|
@details All the minterms of the cube are at the minimum distance.
|
|
If the distance is 0, the cube belongs to the intersection of f and
|
|
g.
|
|
|
|
@return the cube if successful; NULL otherwise.
|
|
|
|
@sideeffect The distance is returned as a side effect.
|
|
|
|
@see Cudd_MinHammingDist
|
|
|
|
*/
|
|
DdNode *
|
|
Cudd_bddClosestCube(
|
|
DdManager *dd,
|
|
DdNode * f,
|
|
DdNode *g,
|
|
int *distance)
|
|
{
|
|
DdNode *res, *acube;
|
|
CUDD_VALUE_TYPE rdist;
|
|
|
|
/* Compute the cube and distance as a single ADD. */
|
|
do {
|
|
dd->reordered = 0;
|
|
res = cuddBddClosestCube(dd,f,g,CUDD_CONST_INDEX + 1.0);
|
|
} while (dd->reordered == 1);
|
|
if (res == NULL) {
|
|
if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
|
|
dd->timeoutHandler(dd, dd->tohArg);
|
|
}
|
|
return(NULL);
|
|
}
|
|
cuddRef(res);
|
|
|
|
/* Unpack distance and cube. */
|
|
do {
|
|
dd->reordered = 0;
|
|
acube = separateCube(dd, res, &rdist);
|
|
} while (dd->reordered == 1);
|
|
if (acube == NULL) {
|
|
Cudd_RecursiveDeref(dd, res);
|
|
if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
|
|
dd->timeoutHandler(dd, dd->tohArg);
|
|
}
|
|
return(NULL);
|
|
}
|
|
cuddRef(acube);
|
|
Cudd_RecursiveDeref(dd, res);
|
|
|
|
/* Convert cube from ADD to BDD. */
|
|
do {
|
|
dd->reordered = 0;
|
|
res = cuddAddBddDoPattern(dd, acube);
|
|
} while (dd->reordered == 1);
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, acube);
|
|
if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
|
|
dd->timeoutHandler(dd, dd->tohArg);
|
|
}
|
|
return(NULL);
|
|
}
|
|
cuddRef(res);
|
|
Cudd_RecursiveDeref(dd, acube);
|
|
|
|
*distance = (int) rdist;
|
|
cuddDeref(res);
|
|
return(res);
|
|
|
|
} /* end of Cudd_bddClosestCube */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of internal functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**
|
|
@brief Performs the recursive step of Cudd_CProjection.
|
|
|
|
@return the projection if successful; NULL otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_CProjection
|
|
|
|
*/
|
|
DdNode *
|
|
cuddCProjectionRecur(
|
|
DdManager * dd,
|
|
DdNode * R,
|
|
DdNode * Y,
|
|
DdNode * Ysupp)
|
|
{
|
|
DdNode *res, *res1, *res2, *resA;
|
|
DdNode *r, *y, *RT, *RE, *YT, *YE, *Yrest, *Ra, *Ran, *Gamma, *Alpha;
|
|
int topR, topY, top;
|
|
unsigned int index;
|
|
DdNode *one = DD_ONE(dd);
|
|
|
|
statLine(dd);
|
|
if (Y == one) return(R);
|
|
|
|
#ifdef DD_DEBUG
|
|
assert(!Cudd_IsConstantInt(Y));
|
|
#endif
|
|
|
|
if (R == Cudd_Not(one)) return(R);
|
|
|
|
res = cuddCacheLookup2(dd, Cudd_CProjection, R, Y);
|
|
if (res != NULL) return(res);
|
|
|
|
checkWhetherToGiveUp(dd);
|
|
|
|
r = Cudd_Regular(R);
|
|
topR = cuddI(dd,r->index);
|
|
y = Cudd_Regular(Y);
|
|
topY = cuddI(dd,y->index);
|
|
|
|
top = ddMin(topR, topY);
|
|
|
|
/* Compute the cofactors of R */
|
|
index = r->index;
|
|
if (topR == top) {
|
|
RT = cuddT(r);
|
|
RE = cuddE(r);
|
|
if (r != R) {
|
|
RT = Cudd_Not(RT); RE = Cudd_Not(RE);
|
|
}
|
|
} else {
|
|
RT = RE = R;
|
|
}
|
|
|
|
if (topY > top) {
|
|
/* Y does not depend on the current top variable.
|
|
** We just need to compute the results on the two cofactors of R
|
|
** and make them the children of a node labeled r->index.
|
|
*/
|
|
res1 = cuddCProjectionRecur(dd,RT,Y,Ysupp);
|
|
if (res1 == NULL) return(NULL);
|
|
cuddRef(res1);
|
|
res2 = cuddCProjectionRecur(dd,RE,Y,Ysupp);
|
|
if (res2 == NULL) {
|
|
Cudd_RecursiveDeref(dd,res1);
|
|
return(NULL);
|
|
}
|
|
cuddRef(res2);
|
|
res = cuddBddIteRecur(dd, dd->vars[index], res1, res2);
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd,res1);
|
|
Cudd_RecursiveDeref(dd,res2);
|
|
return(NULL);
|
|
}
|
|
/* If we have reached this point, res1 and res2 are now
|
|
** incorporated in res. cuddDeref is therefore sufficient.
|
|
*/
|
|
cuddDeref(res1);
|
|
cuddDeref(res2);
|
|
} else {
|
|
/* Compute the cofactors of Y */
|
|
index = y->index;
|
|
YT = cuddT(y);
|
|
YE = cuddE(y);
|
|
if (y != Y) {
|
|
YT = Cudd_Not(YT); YE = Cudd_Not(YE);
|
|
}
|
|
if (YT == Cudd_Not(one)) {
|
|
Alpha = Cudd_Not(dd->vars[index]);
|
|
Yrest = YE;
|
|
Ra = RE;
|
|
Ran = RT;
|
|
} else {
|
|
Alpha = dd->vars[index];
|
|
Yrest = YT;
|
|
Ra = RT;
|
|
Ran = RE;
|
|
}
|
|
Gamma = cuddBddExistAbstractRecur(dd,Ra,cuddT(Ysupp));
|
|
if (Gamma == NULL) return(NULL);
|
|
if (Gamma == one) {
|
|
res1 = cuddCProjectionRecur(dd,Ra,Yrest,cuddT(Ysupp));
|
|
if (res1 == NULL) return(NULL);
|
|
cuddRef(res1);
|
|
res = cuddBddAndRecur(dd, Alpha, res1);
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd,res1);
|
|
return(NULL);
|
|
}
|
|
cuddDeref(res1);
|
|
} else if (Gamma == Cudd_Not(one)) {
|
|
res1 = cuddCProjectionRecur(dd,Ran,Yrest,cuddT(Ysupp));
|
|
if (res1 == NULL) return(NULL);
|
|
cuddRef(res1);
|
|
res = cuddBddAndRecur(dd, Cudd_Not(Alpha), res1);
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd,res1);
|
|
return(NULL);
|
|
}
|
|
cuddDeref(res1);
|
|
} else {
|
|
cuddRef(Gamma);
|
|
resA = cuddCProjectionRecur(dd,Ran,Yrest,cuddT(Ysupp));
|
|
if (resA == NULL) {
|
|
Cudd_RecursiveDeref(dd,Gamma);
|
|
return(NULL);
|
|
}
|
|
cuddRef(resA);
|
|
res2 = cuddBddAndRecur(dd, Cudd_Not(Gamma), resA);
|
|
if (res2 == NULL) {
|
|
Cudd_RecursiveDeref(dd,Gamma);
|
|
Cudd_RecursiveDeref(dd,resA);
|
|
return(NULL);
|
|
}
|
|
cuddRef(res2);
|
|
Cudd_RecursiveDeref(dd,Gamma);
|
|
Cudd_RecursiveDeref(dd,resA);
|
|
res1 = cuddCProjectionRecur(dd,Ra,Yrest,cuddT(Ysupp));
|
|
if (res1 == NULL) {
|
|
Cudd_RecursiveDeref(dd,res2);
|
|
return(NULL);
|
|
}
|
|
cuddRef(res1);
|
|
res = cuddBddIteRecur(dd, Alpha, res1, res2);
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd,res1);
|
|
Cudd_RecursiveDeref(dd,res2);
|
|
return(NULL);
|
|
}
|
|
cuddDeref(res1);
|
|
cuddDeref(res2);
|
|
}
|
|
}
|
|
|
|
cuddCacheInsert2(dd,Cudd_CProjection,R,Y,res);
|
|
|
|
return(res);
|
|
|
|
} /* end of cuddCProjectionRecur */
|
|
|
|
|
|
/**
|
|
@brief Performs the recursive step of Cudd_bddClosestCube.
|
|
|
|
@details@parblock
|
|
The procedure uses a four-way recursion to examine all four combinations
|
|
of cofactors of <code>f</code> and <code>g</code> according to the
|
|
following formula.
|
|
|
|
H(f,g) = min(H(ft,gt), H(fe,ge), H(ft,ge)+1, H(fe,gt)+1)
|
|
|
|
Bounding is based on the following observations.
|
|
<ul>
|
|
<li> If we already found two points at distance 0, there is no point in
|
|
continuing. Furthermore,
|
|
<li> If F == not(G) then the best we can hope for is a minimum distance
|
|
of 1. If we have already found two points at distance 1, there is
|
|
no point in continuing. (Indeed, H(F,G) == 1 in this case. We
|
|
have to continue, though, to find the cube.)
|
|
</ul>
|
|
The variable <code>bound</code> is set at the largest value of the distance
|
|
that we are still interested in. Therefore, we desist when
|
|
|
|
(bound == -1) and (F != not(G)) or (bound == 0) and (F == not(G)).
|
|
|
|
If we were maximally aggressive in using the bound, we would always
|
|
set the bound to the minimum distance seen thus far minus one. That
|
|
is, we would maintain the invariant
|
|
|
|
bound < minD,
|
|
|
|
except at the very beginning, when we have no value for
|
|
<code>minD</code>.
|
|
|
|
However, we do not use <code>bound < minD</code> when examining the
|
|
two negative cofactors, because we try to find a large cube at
|
|
minimum distance. To do so, we try to find a cube in the negative
|
|
cofactors at the same or smaller distance from the cube found in the
|
|
positive cofactors.
|
|
|
|
When we compute <code>H(ft,ge)</code> and <code>H(fe,gt)</code> we
|
|
know that we are going to add 1 to the result of the recursive call
|
|
to account for the difference in the splitting variable. Therefore,
|
|
we decrease the bound correspondingly.
|
|
|
|
Another important observation concerns the need of examining all
|
|
four pairs of cofators only when both <code>f</code> and
|
|
<code>g</code> depend on the top variable.
|
|
|
|
Suppose <code>gt == ge == g</code>. (That is, <code>g</code> does
|
|
not depend on the top variable.) Then
|
|
|
|
H(f,g) = min(H(ft,g), H(fe,g), H(ft,g)+1, H(fe,g)+1)
|
|
= min(H(ft,g), H(fe,g)) .
|
|
|
|
Therefore, under these circumstances, we skip the two "cross" cases.
|
|
|
|
An interesting feature of this function is the scheme used for
|
|
caching the results in the global computed table. Since we have a
|
|
cube and a distance, we combine them to form an %ADD. The
|
|
combination replaces the zero child of the top node of the cube with
|
|
the negative of the distance. (The use of the negative is to avoid
|
|
ambiguity with 1.) The degenerate cases (zero and one) are treated
|
|
specially because the distance is known (0 for one, and infinity for
|
|
zero).
|
|
@endparblock
|
|
|
|
@return the cube if succesful; NULL otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_bddClosestCube
|
|
|
|
*/
|
|
DdNode *
|
|
cuddBddClosestCube(
|
|
DdManager *dd,
|
|
DdNode *f,
|
|
DdNode *g,
|
|
CUDD_VALUE_TYPE bound)
|
|
{
|
|
DdNode *res, *F, *G, *ft, *fe, *gt, *ge, *tt, *ee;
|
|
DdNode *ctt, *cee, *cte, *cet;
|
|
CUDD_VALUE_TYPE minD, dtt, dee, dte, det;
|
|
DdNode *one = DD_ONE(dd);
|
|
DdNode *lzero = Cudd_Not(one);
|
|
DdNode *azero = DD_ZERO(dd);
|
|
int topf, topg;
|
|
unsigned int index;
|
|
|
|
statLine(dd);
|
|
if (bound < (f == Cudd_Not(g))) return(azero);
|
|
/* Terminal cases. */
|
|
if (g == lzero || f == lzero) return(azero);
|
|
if (f == one && g == one) return(one);
|
|
|
|
/* Check cache. */
|
|
F = Cudd_Regular(f);
|
|
G = Cudd_Regular(g);
|
|
if (F->ref != 1 || G->ref != 1) {
|
|
res = cuddCacheLookup2(dd,(DD_CTFP) Cudd_bddClosestCube, f, g);
|
|
if (res != NULL) return(res);
|
|
}
|
|
|
|
checkWhetherToGiveUp(dd);
|
|
|
|
topf = cuddI(dd,F->index);
|
|
topg = cuddI(dd,G->index);
|
|
|
|
/* Compute cofactors. */
|
|
if (topf <= topg) {
|
|
index = F->index;
|
|
ft = cuddT(F);
|
|
fe = cuddE(F);
|
|
if (Cudd_IsComplement(f)) {
|
|
ft = Cudd_Not(ft);
|
|
fe = Cudd_Not(fe);
|
|
}
|
|
} else {
|
|
index = G->index;
|
|
ft = fe = f;
|
|
}
|
|
|
|
if (topg <= topf) {
|
|
gt = cuddT(G);
|
|
ge = cuddE(G);
|
|
if (Cudd_IsComplement(g)) {
|
|
gt = Cudd_Not(gt);
|
|
ge = Cudd_Not(ge);
|
|
}
|
|
} else {
|
|
gt = ge = g;
|
|
}
|
|
|
|
tt = cuddBddClosestCube(dd,ft,gt,bound);
|
|
if (tt == NULL) return(NULL);
|
|
cuddRef(tt);
|
|
ctt = separateCube(dd,tt,&dtt);
|
|
if (ctt == NULL) {
|
|
Cudd_RecursiveDeref(dd, tt);
|
|
return(NULL);
|
|
}
|
|
cuddRef(ctt);
|
|
Cudd_RecursiveDeref(dd, tt);
|
|
minD = dtt;
|
|
bound = ddMin(bound,minD);
|
|
|
|
ee = cuddBddClosestCube(dd,fe,ge,bound);
|
|
if (ee == NULL) {
|
|
Cudd_RecursiveDeref(dd, ctt);
|
|
return(NULL);
|
|
}
|
|
cuddRef(ee);
|
|
cee = separateCube(dd,ee,&dee);
|
|
if (cee == NULL) {
|
|
Cudd_RecursiveDeref(dd, ctt);
|
|
Cudd_RecursiveDeref(dd, ee);
|
|
return(NULL);
|
|
}
|
|
cuddRef(cee);
|
|
Cudd_RecursiveDeref(dd, ee);
|
|
minD = ddMin(dtt, dee);
|
|
if (minD <= CUDD_CONST_INDEX) bound = ddMin(bound,minD-1);
|
|
|
|
if (minD > 0 && topf == topg) {
|
|
DdNode *te = cuddBddClosestCube(dd,ft,ge,bound-1);
|
|
if (te == NULL) {
|
|
Cudd_RecursiveDeref(dd, ctt);
|
|
Cudd_RecursiveDeref(dd, cee);
|
|
return(NULL);
|
|
}
|
|
cuddRef(te);
|
|
cte = separateCube(dd,te,&dte);
|
|
if (cte == NULL) {
|
|
Cudd_RecursiveDeref(dd, ctt);
|
|
Cudd_RecursiveDeref(dd, cee);
|
|
Cudd_RecursiveDeref(dd, te);
|
|
return(NULL);
|
|
}
|
|
cuddRef(cte);
|
|
Cudd_RecursiveDeref(dd, te);
|
|
dte += 1.0;
|
|
minD = ddMin(minD, dte);
|
|
} else {
|
|
cte = azero;
|
|
cuddRef(cte);
|
|
dte = CUDD_CONST_INDEX + 1.0;
|
|
}
|
|
if (minD <= CUDD_CONST_INDEX) bound = ddMin(bound,minD-1);
|
|
|
|
if (minD > 0 && topf == topg) {
|
|
DdNode *et = cuddBddClosestCube(dd,fe,gt,bound-1);
|
|
if (et == NULL) {
|
|
Cudd_RecursiveDeref(dd, ctt);
|
|
Cudd_RecursiveDeref(dd, cee);
|
|
Cudd_RecursiveDeref(dd, cte);
|
|
return(NULL);
|
|
}
|
|
cuddRef(et);
|
|
cet = separateCube(dd,et,&det);
|
|
if (cet == NULL) {
|
|
Cudd_RecursiveDeref(dd, ctt);
|
|
Cudd_RecursiveDeref(dd, cee);
|
|
Cudd_RecursiveDeref(dd, cte);
|
|
Cudd_RecursiveDeref(dd, et);
|
|
return(NULL);
|
|
}
|
|
cuddRef(cet);
|
|
Cudd_RecursiveDeref(dd, et);
|
|
det += 1.0;
|
|
minD = ddMin(minD, det);
|
|
} else {
|
|
cet = azero;
|
|
cuddRef(cet);
|
|
det = CUDD_CONST_INDEX + 1.0;
|
|
}
|
|
|
|
if (minD == dtt) {
|
|
if (dtt == dee && ctt == cee) {
|
|
res = createResult(dd,CUDD_CONST_INDEX,1,ctt,dtt);
|
|
} else {
|
|
res = createResult(dd,index,1,ctt,dtt);
|
|
}
|
|
} else if (minD == dee) {
|
|
res = createResult(dd,index,0,cee,dee);
|
|
} else if (minD == dte) {
|
|
#ifdef DD_DEBUG
|
|
assert(topf == topg);
|
|
#endif
|
|
res = createResult(dd,index,1,cte,dte);
|
|
} else {
|
|
#ifdef DD_DEBUG
|
|
assert(topf == topg);
|
|
#endif
|
|
res = createResult(dd,index,0,cet,det);
|
|
}
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, ctt);
|
|
Cudd_RecursiveDeref(dd, cee);
|
|
Cudd_RecursiveDeref(dd, cte);
|
|
Cudd_RecursiveDeref(dd, cet);
|
|
return(NULL);
|
|
}
|
|
cuddRef(res);
|
|
Cudd_RecursiveDeref(dd, ctt);
|
|
Cudd_RecursiveDeref(dd, cee);
|
|
Cudd_RecursiveDeref(dd, cte);
|
|
Cudd_RecursiveDeref(dd, cet);
|
|
|
|
/* Only cache results that are different from azero to avoid
|
|
** storing results that depend on the value of the bound. */
|
|
if ((F->ref != 1 || G->ref != 1) && res != azero)
|
|
cuddCacheInsert2(dd,(DD_CTFP) Cudd_bddClosestCube, f, g, res);
|
|
|
|
cuddDeref(res);
|
|
return(res);
|
|
|
|
} /* end of cuddBddClosestCube */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of static functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**
|
|
@brief Performs the recursive step of Cudd_MinHammingDist.
|
|
|
|
@details It is based on the following identity. Let H(f) be the
|
|
minimum Hamming distance of the minterms of f from the reference
|
|
minterm. Then:
|
|
|
|
H(f) = min(H(f0)+h0,H(f1)+h1)
|
|
|
|
where f0 and f1 are the two cofactors of f with respect to its top
|
|
variable; h0 is 1 if the minterm assigns 1 to the top variable of f;
|
|
h1 is 1 if the minterm assigns 0 to the top variable of f.
|
|
The upper bound on the distance is used to bound the depth of the
|
|
recursion.
|
|
|
|
@return the minimum distance unless it exceeds the upper bound or
|
|
computation fails.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_MinHammingDist
|
|
|
|
*/
|
|
static int
|
|
cuddMinHammingDistRecur(
|
|
DdNode * f,
|
|
int *minterm,
|
|
DdHashTable * table,
|
|
int upperBound)
|
|
{
|
|
DdNode *F, *Ft, *Fe;
|
|
double h, hT, hE;
|
|
DdNode *zero, *res;
|
|
DdManager *dd = table->manager;
|
|
|
|
statLine(dd);
|
|
if (upperBound == 0) return(0);
|
|
|
|
F = Cudd_Regular(f);
|
|
|
|
if (cuddIsConstant(F)) {
|
|
zero = Cudd_Not(DD_ONE(dd));
|
|
if (f == dd->background || f == zero) {
|
|
return(upperBound);
|
|
} else {
|
|
return(0);
|
|
}
|
|
}
|
|
if ((res = cuddHashTableLookup1(table,f)) != NULL) {
|
|
h = cuddV(res);
|
|
if (res->ref == 0) {
|
|
dd->dead++;
|
|
dd->constants.dead++;
|
|
}
|
|
return((int) h);
|
|
}
|
|
|
|
Ft = cuddT(F); Fe = cuddE(F);
|
|
if (Cudd_IsComplement(f)) {
|
|
Ft = Cudd_Not(Ft); Fe = Cudd_Not(Fe);
|
|
}
|
|
if (minterm[F->index] == 0) {
|
|
DdNode *temp = Ft;
|
|
Ft = Fe; Fe = temp;
|
|
}
|
|
|
|
hT = cuddMinHammingDistRecur(Ft,minterm,table,upperBound);
|
|
if (hT == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM);
|
|
if (hT == 0) {
|
|
hE = upperBound;
|
|
} else {
|
|
hE = cuddMinHammingDistRecur(Fe,minterm,table,upperBound - 1);
|
|
if (hE == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM);
|
|
}
|
|
h = ddMin(hT, hE + 1);
|
|
|
|
if (F->ref != 1) {
|
|
ptrint fanout = (ptrint) F->ref;
|
|
cuddSatDec(fanout);
|
|
res = cuddUniqueConst(dd, (CUDD_VALUE_TYPE) h);
|
|
if (!cuddHashTableInsert1(table,f,res,fanout)) {
|
|
cuddRef(res); Cudd_RecursiveDeref(dd, res);
|
|
return(CUDD_OUT_OF_MEM);
|
|
}
|
|
}
|
|
|
|
return((int) h);
|
|
|
|
} /* end of cuddMinHammingDistRecur */
|
|
|
|
|
|
/**
|
|
@brief Separates cube from distance.
|
|
|
|
@return the cube if successful; NULL otherwise.
|
|
|
|
@sideeffect The distance is returned as a side effect.
|
|
|
|
@see cuddBddClosestCube createResult
|
|
|
|
*/
|
|
static DdNode *
|
|
separateCube(
|
|
DdManager *dd,
|
|
DdNode *f,
|
|
CUDD_VALUE_TYPE *distance)
|
|
{
|
|
DdNode *cube, *t;
|
|
|
|
/* One and zero are special cases because the distance is implied. */
|
|
if (Cudd_IsConstantInt(f)) {
|
|
*distance = (f == DD_ONE(dd)) ? 0.0 :
|
|
(1.0 + (CUDD_VALUE_TYPE) CUDD_CONST_INDEX);
|
|
return(f);
|
|
}
|
|
|
|
/* Find out which branch points to the distance and replace the top
|
|
** node with one pointing to zero instead. */
|
|
t = cuddT(f);
|
|
if (Cudd_IsConstantInt(t) && cuddV(t) <= 0) {
|
|
#ifdef DD_DEBUG
|
|
assert(!Cudd_IsConstantInt(cuddE(f)) || cuddE(f) == DD_ONE(dd));
|
|
#endif
|
|
*distance = -cuddV(t);
|
|
cube = cuddUniqueInter(dd, f->index, DD_ZERO(dd), cuddE(f));
|
|
} else {
|
|
#ifdef DD_DEBUG
|
|
assert(!Cudd_IsConstantInt(t) || t == DD_ONE(dd));
|
|
#endif
|
|
*distance = -cuddV(cuddE(f));
|
|
cube = cuddUniqueInter(dd, f->index, t, DD_ZERO(dd));
|
|
}
|
|
|
|
return(cube);
|
|
|
|
} /* end of separateCube */
|
|
|
|
|
|
/**
|
|
@brief Builds a result for cache storage.
|
|
|
|
@return a pointer to the resulting %ADD if successful; NULL
|
|
otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see cuddBddClosestCube separateCube
|
|
|
|
*/
|
|
static DdNode *
|
|
createResult(
|
|
DdManager *dd,
|
|
unsigned int index,
|
|
unsigned int phase,
|
|
DdNode *cube,
|
|
CUDD_VALUE_TYPE distance)
|
|
{
|
|
DdNode *res, *constant;
|
|
|
|
/* Special case. The cube is either one or zero, and we do not
|
|
** add any variables. Hence, the result is also one or zero,
|
|
** and the distance remains implied by the value of the constant. */
|
|
if (index == CUDD_CONST_INDEX && Cudd_IsConstantInt(cube)) return(cube);
|
|
|
|
constant = cuddUniqueConst(dd,-distance);
|
|
if (constant == NULL) return(NULL);
|
|
cuddRef(constant);
|
|
|
|
if (index == CUDD_CONST_INDEX) {
|
|
/* Replace the top node. */
|
|
if (cuddT(cube) == DD_ZERO(dd)) {
|
|
res = cuddUniqueInter(dd,cube->index,constant,cuddE(cube));
|
|
} else {
|
|
res = cuddUniqueInter(dd,cube->index,cuddT(cube),constant);
|
|
}
|
|
} else {
|
|
/* Add a new top node. */
|
|
#ifdef DD_DEBUG
|
|
assert(cuddI(dd,index) < cuddI(dd,cube->index));
|
|
#endif
|
|
if (phase) {
|
|
res = cuddUniqueInter(dd,index,cube,constant);
|
|
} else {
|
|
res = cuddUniqueInter(dd,index,constant,cube);
|
|
}
|
|
}
|
|
if (res == NULL) {
|
|
Cudd_RecursiveDeref(dd, constant);
|
|
return(NULL);
|
|
}
|
|
cuddDeref(constant); /* safe because constant is part of res */
|
|
|
|
return(res);
|
|
|
|
} /* end of createResult */
|