3

假设我有以下布尔函数:

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))

现在我想用它们构建一个二元决策图。我浏览了几篇论文,但还没有找到如何从像这样的嵌套逻辑公式中构造它们。

据说布尔函数是有根有向无环图。它有几个非终端和终端节点。然后它说每个非终端节点都由一个布尔变量(不是函数)标记,该变量有两个子节点。我不知道上面的函数定义中的布尔变量是什么。从节点到子节点的边a或分别b代表节点分配为 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
}

但接下来的问题是如何从这些函数foobar和构建图形baz

4

3 回答 3

2

基本逻辑运算 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))
  • 缓存结果

“创建节点”当然应该对自身进行重复数据删除,以满足“减少”的要求。3 种情况下的拆分处理了订购要求。

作为简单操作树的复杂函数可以通过自下而上地应用到 BDD 中,每次只执行 BDD 的简单组合。这当然会产生不属于最终结果的节点。变量和常量具有微不足道的 BDD。

例如,通过and(x, or(y, z))深度优先进入该树,为变量(一个x普通节点(x, 0, 1),操作是) 在表示and的 BDD 上执行,然后对结果和表示变量的 BDD 执行。确切的结果取决于您选择的变量排序。yzORORyzANDx

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

于 2018-05-29T23:17:12.587 回答
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从根开始的 a 总是会导致叶子,因此0您可以跳过后面的决定:

x0 -0-> 0
...

请注意,必须使用要在以下图形边缘上分配的变量名称来标记节点。该算法并不是很复杂(当然存在更有效的算法),但我希望它可以将策略可视化。

于 2018-05-29T22:59:10.617 回答
0

用于存储 BDD 的数据结构可以基于以下形式的三元组:(level, u, v)u变量 atlevel为 FALSE时,v布尔函数是什么的节点,当变量 atlevel是 TRUE 时,布尔函数是什么的节点。

所描述的示例可以使用 Python 包进行编程ddpip install dd以安装纯 Python 实现)。代码是

from dd import autoref as _bdd

bdd = _bdd.BDD()
bdd.declare('x', 'y', 'z', 'a')
x_or_y = bdd.add_expr(r'x \/ y')
x_and_y = bdd.add_expr(r'x /\ y')
not_x = bdd.add_expr('~ x')

# variable renaming: x to y, y to z
let = dict(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(r'x /\ (y \/ z)')
assert foo == foo_

# using the string representation of BDD node references
foo_ = bdd.add_expr(rf'x /\ {y_or_z}')
assert foo == foo_

bar = bdd.apply('or', foo, ~ bdd.var('a'))
bar_ = bdd.add_expr(rf'{foo} \/ ~ a')

assert bar == bar_

let = dict(y= ~ bdd.var('y'))
baz = bdd.let(let, x_and_y)
baz_ = bdd.add_expr(r'x /\ ~ y')
assert baz == baz_
# plotting of the diagram using GraphViz
bdd.dump('foo.png', [foo])

此示例包括在 BDD 之间直接应用运算符(使用BDD.apply调用这些运算符的方法或解析布尔公式)和表示为 BDD 的函数的函数组合(使用BDD.let重命名变量和用 BDD 替换变量的方法,以及f'{u}'对 BDD 节点的引用的字符串表示的语法)。

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

绘制 foo 的结果

于 2020-02-23T00:23:28.567 回答