我有这种树数据类型,我希望能够在这里上下移动。但实际上,任何结构都可以工作,只要我能得到一个节点的父/左子/右子。
Tree = Datatype('Tree')
Tree.declare('nil')
Tree.declare('node', ('label', IntSort()), ('left', Tree), ('up', Tree), ('right', Tree))
Tree = Tree.create()
但我不知道如何填充数据结构......我想我可以像下面一样一次创建一个节点,但这似乎是错误的方式。
trees = [Const('t' + str(i), Tree) for i in range(3)]
Tree.up(trees[0]) = Tree.nil
Tree.left(trees[0]) = trees[1]
Tree.right(trees[0]) = trees[2]
Tree.up(trees[1]) = trees[0]
Tree.up(trees[2]) = trees[0]
感谢您的帮助。
答案 0 :(得分:2)
我觉得你对这些数据结构的工作原理有些误解。 Z3的语言,也就是Z3py,是一阶逻辑(模理论)的语言,其中只存在假设/事实。命令式编程语言的主要区别之一是,您没有破坏性更新*,即您无法更新实体的价值。
在您的代码中,您尝试通过基本上操纵指针,以命令式方式构建数据结构,例如:例如,通过(尝试)转让
Tree.up(trees[0]) = Tree.nil
您可能想到的是"使trees[0].up
指向nil
"。但是,由于破坏性更新不是一阶语言的一部分,因此您必须“思考功能性”,即“假设up(trees[0]) == nil
"”。添加这些假设可以按如下方式进行({4}上升{4}}:
s = Solver()
s.add(
Tree.up(trees[0]) == Tree.nil,
Tree.left(trees[0]) == trees[1],
Tree.right(trees[0]) == trees[2],
Tree.up(trees[1]) == trees[0],
Tree.up(trees[2]) == trees[0]
)
print s.check() # sat -> your constraints are satisfiable
没有破坏性更新的结果是您无法以命令式编程语言的典型方式修改数据结构。通过此类更新,可以修改树,例如trees[1].up.left != trees[1]
,例如,通过作业trees[1].up.left = trees[2]
(对于trees[1] != trees[2]
)。但是,如果添加相应的假设
s.add(
trees[1] != trees[2],
Tree.left(Tree.up(trees[1])) == trees[2]
)
print s.check() # unsat
你会发现你的约束不再令人满意,因为旧的和新的假设都是矛盾的。
顺便说一句,您对Tree
数据类型的定义使得可以假设Tree.up(nil) == someTree
。假设t1 != t2
是树的叶子而left(t1) == right(t1) == nil
与t2
类似,那么如果up(nil) == t1
和up(nil) == t2
,您就会产生矛盾。但是,我不知道如何在Z3级别上防止这种情况。
*可以添加破坏性更新作为语法糖,因为它们可以通过所谓的 passification 转换转换为假设。例如,这是使用中间验证语言online完成的。