如何将布尔函数转换为二元决策图

时间:2018-05-29 22:06:38

标签: algorithm data-structures logic graph-theory binary-decision-diagram

说我有以下布尔函数:

or(x, y) := x || y
and(x, y) := x && y
not(x) := !x
foo(x, y, z) := and(x, or(y, z))
bar(x, y, z, a) := or(foo(x, y, z), not(a))
baz(x, y) := and(x, not(y))

现在我想从他们那里构建一个Binary Decision Diagram。我查看了几篇论文,但是还没有找到如何从这些嵌套逻辑公式构造它们。

据说布尔函数是有根的,有向的非循环图。它有几个非终端和终端节点。然后它说每个非终结节点都用布尔变量(不是函数)标记,它有两个子节点。我不知道上面的函数定义中的布尔变量是什么。从节点到子ab的边缘分别表示节点的 assigment 为0或1。如果同构子图已合并,则称为简化,并删除两个子同构的节点。这是一个简化有序二元决策图(ROBDD)。

由此以及我遇到的所有资源,我无法弄清楚如何将这些功能转换为BDD / ROBDD:

foo(1, 0, 1)
bar(1, 0, 1, 0)
baz(1, 0)

或者也许这些需要转换:

foo(x, y, z)
bar(x, y, z, a)
baz(x, y)

寻求帮助解释我需要做什么才能使其成为有根的,有向的非循环图。了解数据结构的外观也会有所帮助。看起来就是这样:

var nonterminal = {
  a: child,
  b: child,
  v: some variable, not sure what
}

但接下来的问题是如何从这些函数构建图表foobarbaz

3 个答案:

答案 0 :(得分:1)

您可以通过评估所有变量分配来完成此操作,例如在

的情况下
foo(0,0,0) = 0
foo(0,0,1) = 0
foo(0,1,0) = 0
...

然后创建图形,从根开始。每个函数参数都有一个用其赋值标记的边,叶节点用结果值标记:

x0 -0-> y0 -0-> z0 -0-> 0
x0 -0-> y1 -0-> z1 -1-> 0
x0 -0-> y2 -1-> z2 -0-> 0
...

合并节点(y0 = y1 = y2,z0 = z1):

x0 -0-> y0 -0-> z0 -0-> 0
x0 -0-> y0 -0-> z0 -1-> 0
x0 -0-> y0 -1-> z1 -0-> 0
...

减少节点(有一些规则允许加入节点或跳过节点)。例如。由于来自根的0始终指向叶0,因此您可以跳过后面的决定:

x0 -0-> 0
...

请注意,必须使用要在以下图形边上指定的变量名标记节点。该算法并不是非常复杂(当然存在更高效的算法),但我希望它可视化策略。

答案 1 :(得分:1)

基本逻辑运算AND,OR,XOR等都可以在BDD表示中的函数之间计算,以在BDD表示中产生新函数。这些算法除了处理终端之外都是类似的,大致如下:

  • 如果结果是终端,则返回该终端。
  • 如果缓存(op, A, B),则返回缓存的结果。
  • 区分3个案例(实际上你可以概括一下......)

    1. A.var == B.var,创建一个节点(A.var, OP(A.lo, B.lo), OP(A.hi, B.hi)),其中OP表示递归调用此过程。
    2. A.var < B.var,创建一个节点(A.var, OP(A.lo, B), OP(A.hi, B))
    3. A.var > B.var,创建一个节点(B.var, OP(A, B.lo), OP(A, B.hi))
  • 缓存结果

&#34;创建节点&#34;当然应该重复删除自己,以实现减少&#34;减少&#34;需求。 3个案例中的分割处理了订购要求。

作为简单操作树的复杂函数可以通过自下而上的方式在BDD中转换,每次只进行BDD的简单组合。这当然确实会生成不属于最终结果的节点。变量和常量都有微不足道的BDD。

例如,and(x, or(y, z))是通过深度优先到该树创建的,为变量x(一个普通节点,(x, 0, 1))创建BDD,然后为{{1 }和y,在代表{{1}的BDD上执行z(上述算法的一个实例,其中只有第一步真正关心操作是OR) }和OR,然后对结果执行y,BDD代表变量z。确切的结果取决于您对变量排序的选择。

评估其他函数内部的函数需要函数组合(如果已经表示BDD已调用的函数),这可能与BDD有关,但有一些糟糕的最坏情况,或者只是内联被调用函数的定义。

答案 2 :(得分:0)

用于存储BDD的数据结构可以基于(level, u, v)形式的三元组,其中ulevel处的变量为FALSE时布尔函数所在的节点,而{ {1}处的变量为TRUE时,布尔函数为{1}}的节点。

可以使用Python软件包ddv来安装纯Python实现)对所述示例进行编程。代码是

level

此示例包括在BDD之间直接应用运算符(使用方法pip install dd或解析调用这些运算符的布尔公式)以及表示为BDD的函数的函数组成(使用方法from dd import autoref as _bdd bdd = _bdd.BDD() bdd.declare('x', 'y', 'z', 'a') x_or_y = bdd.add_expr('x \/ y') x_and_y = bdd.add_expr('x /\ y') not_x = bdd.add_expr('~ x') # variable renaming: x to y, y to z let = {'x': 'y', 'y': 'z'} y_or_z = bdd.let(let, x_or_y) # using the method `BDD.apply` foo = bdd.apply('and', bdd.var('x'), y_or_z) # using a formula foo_ = bdd.add_expr('x /\ (y \/ z)') assert foo == foo_ # using the string representation of BDD node references foo_ = bdd.add_expr('x /\ {u}'.format(u=y_or_z)) assert foo == foo_ bar = bdd.apply('or', foo, ~ bdd.var('a')) bar_ = bdd.add_expr('{u} \/ ~ a'.format(u=foo)) assert bar == bar_ let = {'y': ~ bdd.var('y')} baz = bdd.let(let, x_and_y) baz_ = bdd.add_expr('x /\ ~ y') assert baz == baz_ # plotting of the diagram using GraphViz bdd.dump('foo.png', [foo]) 用于重命名变量和用BDD代替变量,以及语法BDD.apply表示对BDD节点的引用的字符串表示形式。)

绘制布尔函数foo的结果如下所示(由上面的代码中的BDD.let语句产生)。

The result of plotting foo