包是多次出现的元素的集合。动作时间逻辑 (TLA+)Bags
中的标准模块包含与袋子相对应的数学定义。
为了将二元决策图的图形转换为公式,我使用了下面的代码。来自 OP 的第一个 BDD 的答案是:
/\ b \in 0 .. 7
/\ x \in 0 .. 1
/\ y \in 0 .. 1
/\ z \in 0 .. 1
/\ \/ (b = 0) /\ (y = 1)
\/ (b = 3) /\ (x = 1)
\/ (b = 6) /\ (z = 1)
此表达式是用 TLA+ 编写的。
上面实际上不是包,因为包包含每个元素至少出现一次(因此没有出现y
意味着这不是包;省略y
应该将其变成与包对应的 BDD)。包是否适合产品系列是一个单独的问题,我不会讨论。
您可以修改代码以确认第二张图中显示的 BDD 的公式。
下面的代码使用 Python 包omega == 0.1.1
和dd == 0.5.1
(注意:我是它们的作者)。这些在纯 Python 中工作,足以满足这种大小的 BDD(否则构建dd.cudd
将允许您使用CUDD
——当然,对于小到可以手动编写的 BDD 没有区别)。
#!/usr/bin/env python
"""Convert from a BDD figure to a formula."""
from omega.symbolic import fol
# "bare" BDDs (without integers) can be used also
# via the package `dd`
# from dd import autoref as _bdd
# bdd = _bdd.BDD()
ctx = fol.Context()
ctx.declare(x=(0, 1), y=(0, 1), z=(0, 1), b=(0, 7))
bdd = ctx.bdd
# bdd.declare('x', 'y', 'z', 'b1', 'b2', 'b3')
# level of b3
u1 = bdd.add_expr('b_2')
u2 = bdd.add_expr('~ b_2')
# level of b2
u3 = bdd.add_expr(f'ite(b_1, {u1}, FALSE)')
u4 = bdd.add_expr(f'ite(b_1, FALSE, {u2})')
u5 = bdd.add_expr(f'ite(b_1, {u1}, {u2})')
u6 = bdd.add_expr(f'ite(b_1, {u2}, FALSE)')
# level of b1
u7 = bdd.add_expr(f'ite(b_0, FALSE, {u3})')
u8 = bdd.add_expr(f'ite(b_0, FALSE, {u4})')
u9 = bdd.add_expr(f'ite(b_0, FALSE, {u5})')
u10 = bdd.add_expr(f'ite(b_0, {u6}, {u3})')
u11 = bdd.add_expr(f'ite(b_0, {u6}, FALSE)')
u12 = bdd.add_expr(f'ite(b_0, {u6}, {u4})')
u13 = bdd.add_expr(f'ite(b_0, {u6}, {u5})')
# level of z
u14 = bdd.add_expr(f'ite(z_0, {u7}, FALSE)')
u15 = bdd.add_expr(f'ite(z_0, {u9}, {u8})')
u16 = bdd.add_expr(f'ite(z_0, {u10}, {u11})')
u17 = bdd.add_expr(f'ite(z_0, {u13}, {u12})')
# level of y
u18 = bdd.add_expr(f'ite(y_0, {u15}, {u14})')
u19 = bdd.add_expr(f'ite(y_0, {u17}, {u16})')
# level of x
from_fig = bdd.add_expr(f'ite(x_0, {u19}, {u18})')
# the variable order from the first figure in the OP
levels = dict(x_0=0, y_0=1, z_0=2, b_0=3, b_1=4, b_2=5)
fol._bdd.reorder(bdd, levels)
bdd.dump('foo_1.png', [from_fig])
# a better variable order
levels = dict(b_0=0, b_1=1, b_2=2, x_0=3, y_0=4, z_0=5)
fol._bdd.reorder(bdd, levels)
bdd.dump('foo_2.png', [from_fig])
# Create the BDD directly from an expression
s = r'''
\/ (b = 3 /\ x = 1)
\/ (b = 0 /\ y = 1)
\/ (b = 6 /\ z = 1)
'''
from_formula = ctx.add_expr(s)
assert from_formula == from_fig
# print a minimal formula in disjunctive normal form
# use this to covert BDDs to expressions
print(ctx.to_expr(from_fig, show_dom=True))
可以使用以下方式安装依赖项pip
:
pip install dd==0.5.6
pip install omega==0.3.1
通过按照上述代码重新排序变量的级别,我们可以获得更小的 (RO)BDD:
上面的 BDD 使用否定边表示,本教程中对 BDD进行了解释。