Error in Passing Boolean Expression in CUDD (Working in BuDDy) - binary-decision-diagram

I am trying to find total no of nodes in a Shared-BDD using CUDD.
I have already written C Code using BuDDy-2.4 and it is running fine But when i am using CUDD instead of BuDDy, My program is showing error.
My BuDDY C File is:
//BuDDY_C Code for Node Count:
#define X1 (a&b&c&d)|(!c&d&f)|(g&!g) //Define Function-1 here
#define X2 (a&b&d&!c)|(!c&!c&d)^(g) //Define Function-2 here
#include<bdd.h>
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
bdd z[2],a,b,c,d,e,f,g,h;
int i,INPUT=8,node_count,order[8]={2,5,1,6,0,4,3,7};
printf("\nGiven Variable Order:\t ");
for(i=0;i<INPUT;i++)
printf("%d \t",order[i]);
bdd_init(1000,100);
bdd_setvarnum(INPUT);
a = bdd_ithvar(order[0]); //Assign Variable order stored in order[0] to a
b = bdd_ithvar(order[1]); //Assign Variable order stored in order[1] to b
c = bdd_ithvar(order[2]); //Assign Variable order stored in order[2] to c
d = bdd_ithvar(order[3]); //Assign Variable order stored in order[3] to d
e = bdd_ithvar(order[4]); //Assign Variable order stored in order[4] to e
f = bdd_ithvar(order[5]); //Assign Variable order stored in order[5] to f
g = bdd_ithvar(order[6]); //Assign Variable order stored in order[6] to g
h = bdd_ithvar(order[7]); //Assign Variable order stored in order[7] to h
z[0]=X1;
z[1]=X2;
node_count=bdd_anodecount(z,2);
bdd_done();
printf("\n Total no of nodes are %d\n",node_count);
return 0;
}
My CUDD C Program is:
//CUDD_C Code for Node Count
#define X1 (a&b&c&d)|(!c&d&f)|(g&!g) //Define Function-1 here
#define X2 (a&b&d&!c)|(!c&!c&d)^(g) //Define Function-2 here
#include <stdio.h>
#include <stdlib.h>
#include "cudd.h"
int main(void) {
DdNode *z[2],*a,*b,*c,*d,*e,*f,*g,*h;
int i,INPUT=8,node_count,order[8]={2,5,1,6,0,4,3,7};
printf("\nGiven Variable Order:\t ");
for(i=0;i<INPUT;i++)
printf("%d \t",order[i]);
DdManager * mgr = Cudd_Init(INPUT,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0);
a = Cudd_bddIthVar(mgr, order[0]); //Assign Variable order stored in order[0] to a
b = Cudd_bddIthVar(mgr, order[1]); //Assign Variable order stored in order[0] to b
c = Cudd_bddIthVar(mgr, order[2]); //Assign Variable order stored in order[0] to c
d = Cudd_bddIthVar(mgr, order[3]); //Assign Variable order stored in order[0] to d
e = Cudd_bddIthVar(mgr, order[4]); //Assign Variable order stored in order[0] to e
f = Cudd_bddIthVar(mgr, order[5]); //Assign Variable order stored in order[0] to f
g = Cudd_bddIthVar(mgr, order[6]); //Assign Variable order stored in order[0] to g
h = Cudd_bddIthVar(mgr, order[7]); //Assign Variable order stored in order[0] to h
z[0]=X1;
z[1]=X2;
Cudd_Ref(z[0]);
Cudd_Ref(z[1]);
/*-----Calculate no of nodes and number of shared nodes*/
node_count= Cudd_SharingSize( z, 2);
printf("\n Total no of nodes are %d\n",node_count);
int err = Cudd_CheckZeroRef(mgr);
Cudd_Quit(mgr);
return err;
}
But this CUDD C program is showing Error
balal#balal-HP-H710:~/Desktop/cudd-3.0.0$ g++ -o test test2_cudd.c -lbdd
test2_cudd.c: In function ‘int main()’:
test2_cudd.c:2:14: error: invalid operands of types ‘DdNode*’ and ‘DdNode*’ to binary ‘operator&’
#define X1 (a&b&c&d)|(!c&d&f)|(g&!g) //Define Function-1 here
~^~
test2_cudd.c:30:7: note: in expansion of macro ‘X1’
z[0]=X1;
^~
test2_cudd.c:2:25: error: invalid operands of types ‘bool’ and ‘DdNode*’ to binary ‘operator&’
#define X1 (a&b&c&d)|(!c&d&f)|(g&!g) //Define Function-1 here
~~^~
test2_cudd.c:30:7: note: in expansion of macro ‘X1’
z[0]=X1;
^~
test2_cudd.c:2:33: error: invalid operands of types ‘DdNode*’ and ‘bool’ to binary ‘operator&’
#define X1 (a&b&c&d)|(!c&d&f)|(g&!g) //Define Function-1 here
~^~~
test2_cudd.c:30:7: note: in expansion of macro ‘X1’
z[0]=X1;
^~
test2_cudd.c:3:14: error: invalid operands of types ‘DdNode*’ and ‘DdNode*’ to binary ‘operator&’
#define X2 (a&b&d&!c)|(!c&!c&d)^(g) //Define Function-2 here
~^~
test2_cudd.c:31:7: note: in expansion of macro ‘X2’
z[1]=X2;
^~
test2_cudd.c:3:29: error: invalid operands of types ‘int’ and ‘DdNode*’ to binary ‘operator&’
#define X2 (a&b&d&!c)|(!c&!c&d)^(g) //Define Function-2 here
~~~~~^~
test2_cudd.c:31:7: note: in expansion of macro ‘X2’
z[1]=X2;
^~
balal#balal-HP-H710:~/Desktop/cudd-3.0.0$

You are trying to use the "&" operator on BDD nodes while writing your program in C. Since C does not support operator overloading, this won't work because the "&" operator could at most mean to take the bitwise AND of the addresses, which is not what you want.
In order to compute the AND of two BDDs, you have to use the Cudd_bddAnd function. See, for instance, here for an example. Note that your macros will become a lot longer in this way and need to include local variables apart from scopes.
The alternative is to use the C++ interface to CUDD, where BDDs can be encapsulated into objects that support operator overloading.
Note that
z[0]=X1;
z[1]=X2;
Cudd_Ref(z[0]);
Cudd_Ref(z[1]);
can also potentially cause trouble. In CUDD, nodes have to be referenced with Cudd_Ref(...) before any other CUDD function is called that can create new nodes. Since your X2 macro includes operations over BDDs, this can happen. So it's best practice to Cudd_Ref(...) BDDs immediately. The following looks better:
z[0]=X1;
Cudd_Ref(z[0]);
z[1]=X2;
Cudd_Ref(z[1]);
Note that your Buddy code is also wrong for the same reason. However, since the BDD type there is defined as "typedef int BDD;" the compiler used bitwise AND and OR on the BDD node numbers instead, which is why it compiled to code that produces wrong results.

Another possibility is to use the Cython interface to CUDD that is included in the Python package dd. Installation of dd with the module dd.cudd is described here and could be summarized as
pip download dd --no-deps
tar -xzf dd-*.tar.gz
cd dd-*/
python setup.py install --fetch --cudd
This will download and build CUDD, and build and install the Cython bindings of dd to CUDD. dd has Cython bindings also to BuDDy, and those could be built similarly, with the user downloading and building BuDDy, and passing --buddy to the script setup.py.
The example code could be translated to the following Python code.
from dd import cudd as _bdd
bdd = _bdd.BDD()
bdd.declare('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h')
# /\ is conjunction in TLA+, \/ disjunction, ~ negation
X1 = bdd.add_expr('(a /\ b /\ c /\ d) \/ (~ c /\ d /\ f) \/ (g /\ ~ g)')
# note that g /\ ~ g is FALSE
X2 = bdd.add_expr('(a /\ b /\ d /\ ~ c) \/ ((~ c /\ ~ c /\ d) ^ g)')
# note that ~ c /\ ~ c is ~ c
# using the operators &, |, ! for conjunction, disjunction, and negation
X1_ = bdd.add_expr('(a & b & c & d) \/ (!c & d & f) \/ (g & !g)')
X2_ = bdd.add_expr('(a & b & d & !c) \/ ((!c & !c & d) ^ g)')
assert X1 == X1_, (X1, X1_)
assert X2 == X2_, (X2, X2_)
def descendants(roots):
"""Return nodes reachable from `roots`.
Nodes in `roots` are included.
"""
if not roots:
return set()
visited = set()
for u in roots:
_descendants(u, visited)
assert set(roots).issubset(visited), (roots, visited)
return visited
def _descendants(u, visited):
v, w = u.low, u.high
# terminal node or visited ?
if u.low is None or u in visited:
return
_descendants(v, visited)
_descendants(w, visited)
visited.add(u)
r = descendants([X1, X2])
print(len(r))
# plot diagrams of the results using GraphViz
bdd.dump('X1.pdf', [X1])
bdd.dump('X2.pdf', [X2])
The function descendants computes the set of nodes reachable from the given nodes (the nodes referenced by X1 and X2), including the given nodes. The answer for the variable order in my run is 16 nodes. The diagrams for the BDDs of the Boolean functions X1 and X2 are the following.
BDD of Boolean function X1
BDD of Boolean function X2

Related

Is there a way to work around the (SET_ADD) error in in numba given here?

I have a snippet of python code as a function here. The purpose of the code is to use the combinations tool of itertools and turn a list of pairs into a list of triplets by matching items that correlate with each other. Due to the time consuming nature of the function, I have been trying to get it to work using a GPU through numba. Here is the function followed by me calling it:
#jit(target_backend='cuda')
def combinator(size, theuniquegenes, thetuplelist):
limiter = size+1
lengths = [l + 1 for l in range(len(theuniquegenes)) if (l + 1 > 2) and (l + 1 < limiter)]
new_combs = {c for l in lengths for c in combinations(theuniquegenes, l)}
correlations = {x for x in new_combs if all([c in thetuplelist for c in combinations(x, 2)])}
print(len(correlations))
tuplelist = thetuplelist + list(correlations)
print(len(tuplelist))
return tuplelist
tuplelist = combinator(3, uniquegenes, tuplelist)
Unfortunately, I keep encountering the following error message:
numba.core.errors.UnsupportedError: Failed in object mode pipeline (step: inline calls to locally defined closures)
Use of unsupported opcode (SET_ADD) found
new_combs = {c for l in lengths for c in combinations(theuniquegenes, l)}
^
How can I rewrite this line to work?

Second order combinatoric probabilities

Let say I have a set of symbols s = {a,b,c, ... } and a corpus1 :
a b g k.
o p a r b.
......
by simple counting I can calculate probabilities p(sym), p(sym1,sym2), p(sym1|sym2)
will use upper-case for set S and CORPUS2 and PROBABILITIES related to them
now I create Set 'S' of all combinations of 's', S = { ab,ac,ad,bc,bd,... }, such that I create CORPUS2 from corpus1 in the following manner :
ab ag ak, bg bk, gk.
op oa or ob, pa pr pb, ar ab, rb.
......
i.e all pairs combinations, order does not matter ab == ba. Commas are for visual purpose.
My question : Is it possible to express probabilities P(SYM), P(SYM1,SYM2), P(SYM1|SYM2) via p(sym), p(sym1,sym2), p(sym1|sym2) i.e. have a formula
PS> In my thinking I'm stuck at the following dilema ...
p(sym) = count(sym) / n
but to calculate P(SYM) w/o materializing CORPUS2 there seems to be no way, because it depends on p(sub-sym1),p(sub-sym2) multiplied by the lenght of the sequences they participate in. SYM = sub-sym1:sub-sym2
may be : ~P(SYM) = p(sub-sym1,sub-sym2) * p(sub-sym1) * p(sub-sym2) * avg-seq-len
P(SYM) = for seq in corpus1 :
total += ( len(seq) * (len(seq)+1)) / 2
for sub-sym1 and sub-sym2 in combinations(seq,2) :
if sub-sym1 and sub-sym2 == SYM :
count += 1
return count/total
there is a condition and hidden/random parameter/length involved ..
P(SYM1,SYM2), P(SYM1|SYM2) ??
Probabilities are defined/calculated in the usual way by counting .. for lower case symbols using corpus1 and for upper case symbols using CORPUS2.

Substitute numerical constants with symbols in sympy

I have a question similar to this one: How to substitute multiple symbols in an expression in sympy? but in reverse.
I have a sympy expression with numerical values and symbols alike. I would like to substitute all numerical values with symbolic constants. I appreciate that such query is uncommon for sympy. What can I try next?
For example, I have:
-0.5967695*sin(0.15280747*x0 + 0.89256966) + 0.5967695*sin(sin(0.004289882*x0 - 1.5390939)) and would like to replace all numbers with a, b, c etc. ideally in a batch type of way.
The goal is to then apply trig identities to simplify the expression.
I'm not sure if there is already such a function. If there is not, it's quite easy to build one. For example:
import string
def num2symbols(expr):
# wild symbol to select all numbers
w = Wild("w", properties=[lambda t: isinstance(t, Number)])
# extract the numbers from the expression
n = expr.find(w)
# get a lowercase alphabet
alphabet = list(string.ascii_lowercase)
# create a symbol for each number
s = symbols(" ".join(alphabet[:len(n)]))
# create a dictionary mapping a number to a symbol
d = {k: v for k, v in zip(n, s)}
return d, expr.subs(d)
x0 = symbols("x0")
expr = -0.5967695*sin(0.15280747*x0 + 0.89256966) + 0.5967695*sin(sin(0.004289882*x0 - 1.5390939))
d, new_expr = num2symbols(expr)
print(new_expr)
# out: b*sin(c + d*x0) - b*sin(sin(a + f*x0))
print(d):
# {-1.53909390000000: a, -0.596769500000000: b, 0.892569660000000: c, 0.152807470000000: d, 0.596769500000000: e, 0.00428988200000000: f}
I feel like dict.setdefault was made for this purpose in Python :-)
>>> c = numbered_symbols('c',cls=Dummy)
>>> d = {}
>>> econ = expr.replace(lambda x:x.is_Float, lambda x: sign(x)*d.setdefault(abs(x),next(c)))
>>> undo = {v:k for k,v in d.items()}
Do what you want with econ and when done (after saving results to econ)
>>> econ.xreplace(undo) == expr
True
(But if you change econ the exact equivalence may no longer hold.) This uses abs to store symbols so if the expression has constants that differ by a sign they will appear in econ with +/-ci instead of ci and cj.

CUDD: Access BDD childs

I'm working with CUDD C++ interface.
I'm finding not much information about this library.
How can I get the two children of a BDD?
For example:
Cudd mgr;
BDD x = mgr.bddVar();
BDD y = mgr.bddVar();
BDD f = x * y;
Now, with f, I want to get its then child and else child.
The documentation says that DdNode has this children but I don't know how to access them.
Thank you.
You can access the then and else children of a Cudd BDD node as follows:
DdNode *t = Cudd_T(f.getNode());
DdNode *e = Cudd_E(f.getNode());
This gives DdNode pointer, which is the data structure used to refer to BDDs when using the plain C interface. You can get C++ objects again by:
BDD tb = BDD(mgr,t);
Note that the above only works if f is not a complemented node. Otherwise, you have to run the result of calling "getNode" function through the Cudd_Regular function. Note that this inverts the meaning of the BDD.
You could also treat the BDDs like as if CuDD did not use inverted nodes. For this case, you would get then- and else-successors as follows:
BDD t;
BDD e;
if (Cudd_IsComplement(f.getNode())) {
t = !BDD(manager,Cudd_Regular(Cudd_T(f.getNode())));
e = !BDD(manager,Cudd_Regular(Cudd_E(f.getNode())));
} else {
t = BDD(manager,Cudd_T(f.getNode()));
e = BDD(manager,Cudd_E(f.getNode()));
}
Accessing the successors of a BDD node is also possible using the Cython bindings to CUDD of the Python package dd.
from dd import cudd as _bdd
bdd = _bdd.BDD()
bdd.declare('x', 'y')
u = bdd.add_expr(r'x /\ y')
# "else" successor of node `u`
v = u.low
# "then" successor of node `u`
w = u.high
u_ = bdd.add_expr(rf'(~ x /\ {v}) \/ (x /\ {w})')
assert u == u_, (u, u_)
Installation of dd with the module dd.cudd is described here

Regular expression puzzle

This is not homework, but an old exam question. I am curious to see the answer.
We are given an alphabet S={0,1,2,3,4,5,6,7,8,9,+}. Define the language L as the set of strings w from this alphabet such that w is in L if:
a) w is a number such as 42 or w is the (finite) sum of numbers such as 34 + 16 or 34 + 2 + 10
and
b) The number represented by w is divisible by 3.
Write a regular expression (and a DFA) for L.
This should work:
^(?:0|(?:(?:[369]|[147](?:0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0\+)*[147]0*(?:\+?(?:0\
+)*[369]0*)*\+?(?:0\+)*[258])*(?:0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0\+)*[258]|0*(?:
\+?(?:0\+)*[369]0*)*\+?(?:0\+)*[147]0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0\+)*[147])|[
258](?:0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0\+)*[258]0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0
\+)*[147])*(?:0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0\+)*[147]|0*(?:\+?(?:0\+)*[369]0*)
*\+?(?:0\+)*[258]0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0\+)*[258]))0*)+)(?:\+(?:0|(?:(?
:[369]|[147](?:0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0\+)*[147]0*(?:\+?(?:0\+)*[369]0*)
*\+?(?:0\+)*[258])*(?:0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0\+)*[258]|0*(?:\+?(?:0\+)*
[369]0*)*\+?(?:0\+)*[147]0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0\+)*[147])|[258](?:0*(?
:\+?(?:0\+)*[369]0*)*\+?(?:0\+)*[258]0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0\+)*[147])*
(?:0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0\+)*[147]|0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0\+)
*[258]0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0\+)*[258]))0*)+))*$
It works by having three states representing the sum of the digits so far modulo 3. It disallows leading zeros on numbers, and plus signs at the start and end of the string, as well as two consecutive plus signs.
Generation of regular expression and test bed:
a = r'0*(?:\+?(?:0\+)*[369]0*)*\+?(?:0\+)*'
b = r'a[147]'
c = r'a[258]'
r1 = '[369]|[147](?:bc)*(?:c|bb)|[258](?:cb)*(?:b|cc)'
r2 = '(?:0|(?:(?:' + r1 + ')0*)+)'
r3 = '^' + r2 + r'(?:\+' + r2 + ')*$'
r = r3.replace('b', b).replace('c', c).replace('a', a)
print r
# Test on 10000 examples.
import random, re
random.seed(1)
r = re.compile(r)
for _ in range(10000):
x = ''.join(random.choice('0123456789+') for j in range(random.randint(1,50)))
if re.search(r'(?:\+|^)(?:\+|0[0-9])|\+$', x):
valid = False
else:
valid = eval(x) % 3 == 0
result = re.match(r, x) is not None
if result != valid:
print 'Failed for ' + x
Note that my memory of DFA syntax is woefully out of date, so my answer is undoubtedly a little broken. Hopefully this gives you a general idea. I've chosen to ignore + completely. As AmirW states, abc+def and abcdef are the same for divisibility purposes.
Accept state is C.
A=1,4,7,BB,AC,CA
B=2,5,8,AA,BC,CB
C=0,3,6,9,AB,BA,CC
Notice that the above language uses all 9 possible ABC pairings. It will always end at either A,B,or C, and the fact that every variable use is paired means that each iteration of processing will shorten the string of variables.
Example:
1490 = AACC = BCC = BC = B (Fail)
1491 = AACA = BCA = BA = C (Success)
Not a full solution, just an idea:
(B) alone: The "plus" signs don't matter here. abc + def is the same as abcdef for the sake of divisibility by 3. For the latter case, there is a regexp here: http://blog.vkistudios.com/index.cfm/2008/12/30/Regular-Expression-to-determine-if-a-base-10-number-is-divisible-by-3
to combine this with requirement (A), we can take the solution of (B) and modify it:
First read character must be in 0..9 (not a plus)
Input must not end with a plus, so: Duplicate each state (will use S for the original state and S' for the duplicate to distinguish between them). If we're in state S and we read a plus we'll move to S'.
When reading a number we'll go to the new state as if we were in S. S' states cannot accept (another) plus.
Also, S' is not "accept state" even if S is. (because input must not end with a plus).