CUDD: Quantification of ZDDs

我怕爱的太早我们不能终老 提交于 2021-01-23 05:04:24

问题


I'm working with CUDD (https://github.com/ivmai/cudd) to use bdd and zdd functionality for model checking, and am wondering how i can quantify over zdds.

For bdds there are the functions bddExistAbstract and bddUnivAbstract (see http://web.mit.edu/sage/export/tmp/y/usr/share/doc/polybori/cudd/cuddAllDet.html#Cudd_bddUnivAbstract).

The manual says that the functions universally and existentially abstracts out the given variables from the bdd (in cover form). I dont quite know what they mean with "abstracts out", and therefore im stuck on figuring out how quantification changes zdds.

Can you guys help? thanks.


回答1:


I am ready to give a long answer, however, it will probably not directly help you.

TL;DR: As far as I know, CUDD does not have implementation of ExistAbstract or any similar function for ZDDs. But, I am not a CUDD guru and may have overlooked it.

And here is the long answer. You probably want to just use the functions. So I will cover this first. Later, I will write about the implementation. Maybe, somebody is ready to add the implementation for ZDDs to CUDD?

Function bddExistAbstract (Ex) calculates existential quantification over the given Boolean function (use wikipedia, youtube, coursera, and similar references to learn all the mathematical background). In short, the existential quantification of variable v in the Boolean function F is calculated as Ex(F,v) = F|v=0 + F|v=1. In practice, if you write the Boolean function as a sum-of-products formula than the resulting formula is obtained by simply removing the quantified variable.

Example (+ is for disjunction, * is for conjuction, ~ is for negation):

F = ~a * c + a * b * ~c + a * ~b * c
Ex(F,b) = ~a * c + a * ~c + a * c = a + c

The universal quantification of variable v in the Boolean function F is calculated as Ax(F,v) = F|v=0 * F|v=1.

It is nothing wrong with implementing existential (and universal) quantification for ZDDs, but you should ask yourself, why would you need it. Are you representing Boolean functions (e.g. characteristic functions) with ZDDs? This is not recommendable because ZDDs seems to be inefficient for this or at least not more efficient than BDDs just more complicated. ZDDs are primarily used to represent sets (more precisely, the "combination sets"). With sets, existential quantification does not have any usable meaning. For example, Boolean function F in the previous example coresponds to combination set {{c},{a,b},{b,c},{a,c}} while resulting Ex(F,b) correspond to set {{c},{a,b},{b,c},{a,c},{a},{a,b,c}}.

To extend your question, observing the given example you can immediatelly think of another function that would give result for sets but in the sense of existential quantification for Boolean function. I will call it ElementAbstract (ElemAbst) and I am not aware of its usage outside of my own projects. It removes the given element from all combinations. Here is the example:

S = {{c},{a,b},{b,c},{a,c}}
ElemAbst(S,b)= {{c},{a},{c},{a,c}} = {{a},{c},{a,c}}

Now, lets talk about the implementation. I will give the simplified code from our "Biddy BDD package" which is written in C. Hopefully, I have not introduced errors by performing the simplification. Please, use our public repository to get the complete and working code (http://svn.savannah.nongnu.org/viewvc/biddy/biddyOp.c?view=markup), it includes support for complement edges)

We will start with a case, where only one variable is requested to be abstracted.

Biddy_Edge
BiddyE(Biddy_Manager MNG, Biddy_Edge f, Biddy_Variable v)
{
    Biddy_Edge e, t, r;
    Biddy_Variable fv;

    ...

    if (f == biddyZero) return biddyZero;

    if (biddyManagerType == BIDDYTYPEOBDD) {
        if (BiddyIsSmaller(v,BiddyGetVariable(f))) return f;
    }

    ...

    if (biddyManagerType == BIDDYTYPEOBDD) {
        if ((fv=BiddyGetVariable(f)) == v) {
            r = BiddyOr(MNG,BiddyGetElse(f),BiddyGetThen(f));
        }
        else {
            e = BiddyE(MNG,BiddyGetElse(f),v);
            t = BiddyE(MNG,BiddyGetThen(f),v);
            r = BiddyFoaNode(MNG,fv,e,t);
        }
    }

    if (biddyManagerType == BIDDYTYPEZBDD) {
        if ((fv=BiddyGetVariable(f)) == v) {
            r = BiddyOr(MNG,BiddyGetElse(f),BiddyGetThen(f));
            r = BiddyFoaNode(MNG,v,r,r);
        }
        else if (BiddyIsSmaller(v,fv)) {
            r = BiddyFoaNode(MNG,v,f,f);
        }
        else {
            e = BiddyE(MNG,BiddyGetElse(f),v);
            t = BiddyE(MNG,BiddyGetThen(f),v);
            r = BiddyFoaNode(MNG,fv,e,t);
        }
    }

    ...

    return r;
}

It is more usable to implement a general case where many variables are abstracted at once. This variant is included in CUDD. Variables to be abstracted are given as a cube which is a simple product of all variables to be abstracted. Biddy also includes this variant for both, BDDs and ZDDs.

Biddy_Edge
BiddyExistAbstract(Biddy_Manager MNG, Biddy_Edge f, Biddy_Edge cube)
{
    Biddy_Edge e, t, r;
    Biddy_Variable fv,cv;

    ...

    if (f == biddyZero) return biddyZero;

    ...

    if (biddyManagerType == BIDDYTYPEOBDD) {
        fv = BiddyGetVariable(f);
        cv = BiddyGetVariable(cube);
        while (!BiddyIsTerminal(cube) && BiddyIsSmaller(cv,fv)) {
            cube = BiddyGetThen(cube);
            cv = BiddyGetVariable(cube);
        }
        if (BiddyIsTerminal(cube)) {
            return f;
        }
        if (cv == fv) {
            e = BiddyExistAbstract(MNG,BiddyGetElse(f),BiddyGetThen(cube));
            t = BiddyExistAbstract(MNG,BiddyGetThen(f),BiddyGetThen(cube));
            r = BiddyOr(MNG,e,t);
        } else {
            e = BiddyExistAbstract(MNG,BiddyGetElse(f),cube);
            t = BiddyExistAbstract(MNG,BiddyGetThen(f),cube);
            r = BiddyFoaNode(MNG,fv,e,t);
        }
    }

    if (biddyManagerType == BIDDYTYPEZBDD) {
        if (BiddyIsTerminal(cube)) {
            return f;
        }
        cv = BiddyGetVariable(cube);
        fv = BiddyGetVariable(f);
        if (BiddyIsSmaller(cv,fv)) {
            r = BiddyExistAbstract(MNG,f,BiddyGetThen(cube));
            r = BiddyFoaNode(MNG,cv,r,r);
        }
        else if (cv == fv) {
            e = BiddyExistAbstract(MNG,BiddyGetElse(f),BiddyGetThen(cube));
            t = BiddyExistAbstract(MNG,BiddyGetThen(f),BiddyGetThen(cube));
            r = BiddyOr(MNG,e,t);
            r = BiddyFoaNode(MNG,cv,r,r);
        } else {
            e = BiddyExistAbstract(MNG,BiddyGetElse(f),cube);
            t = BiddyExistAbstract(MNG,BiddyGetThen(f),cube);
            r = BiddyFoaNode(MNG,fv,e,t);
        }
    }

    ...

    return r;
}

And finaly, here is the implementation for ElementAbstract for abstracting a single variable. Again, Biddy supports this function for both, BDDs and ZDDs, without asking questions whether this is useful to somebody.

Biddy_Edge
BiddyElementAbstract(Biddy_Manager MNG, Biddy_Edge f, Biddy_Variable v)
{
    Biddy_Edge e, t, r;
    Biddy_Variable fv;

    ...

    if (f == biddyZero) return biddyZero;

    if (biddyManagerType == BIDDYTYPEZBDD) {
        if (BiddyIsSmaller(v,BiddyGetVariable(f))) return f;
    }

    ...

    if (biddyManagerType == BIDDYTYPEOBDD) {
        if ((fv=BiddyGetVariable(f)) == v) {
            r = BiddyOr(MNG,BiddyGetElse(f),BiddyGetThen(f));
            r = BiddyFoaNode(MNG,v,r,biddyZero);
        }
        else if (BiddyIsSmaller(v,fv)) {
            r = BiddyFoaNode(MNG,v,f,biddyZero);
        }
        else {
            e = BiddyElementAbstract(MNG,BiddyGetElse(f),v);
            t = BiddyElementAbstract(MNG,BiddyGetThen(f),v);
            r = BiddyFoaNode(MNG,fv,e,t);
    }
    }

    if (biddyManagerType == BIDDYTYPEZBDD) {
        if ((fv=BiddyGetVariable(f)) == v) {
            r = BiddyOr(MNG,BiddyGetElse(f),BiddyGetThen(f));
        }
        else {
            e = BiddyElementAbstract(MNG,BiddyGetElse(f),v);
            t = BiddyElementAbstract(MNG,BiddyGetThen(f),v);
            r = BiddyFoaNode(MNG,fv,e,t);
        }
    }

    ...

    return r;
}



回答2:


The Python package dd implements a Cython interface to CUDD that extends the ZDD functions of CUDD with quantification. For example, to use existential quantification over ZDDs:

from dd import cudd_zdd

zdd = cudd_zdd.ZDD()  # create a ZDD manager
zdd.declare('x', 'y')  # add variables to the manager
u = zdd.add_expr('x /\ y')  # create a BDD `u` for the expression x /\ y
v = zdd.exist(['y'], u)  # quantify over variable y, i.e., compute \E y:  x /\ y
>>> zdd.to_expr(v)  # convert to an expression as string
'x'

The implementation of quantification for ZDDs can be found at:

https://github.com/tulip-control/dd/blob/24ec9eba335c173e1fe0367a9ac25ec201dee1b5/dd/cudd_zdd.pyx#L1999-L2172

and a number of implementations at the Python level also exist for development purposes:

https://github.com/tulip-control/dd/blob/24ec9eba335c173e1fe0367a9ac25ec201dee1b5/dd/cudd_zdd.pyx#L1387-L1544

The package dd can be installed from PyPI with pip install dd. This will install the CUDD bindings on Linux. On macOS the bindings to CUDD need to be compiled from the source of dd, so the installation for macOS becomes:

pip download dd --no-deps
tar xzf dd-*.tar.gz
cd dd-*/
python setup.py install --fetch --cudd --cudd_zdd

as described in the file README.md.



来源:https://stackoverflow.com/questions/63265943/cudd-quantification-of-zdds

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!