Z3:如何最好地编码“a”;开关语句";?
我想创建一个表达式,它选择给定表达式集中的一个。给定一个表达式数组Z3:如何最好地编码“a”;开关语句";?,z3,smt,Z3,Smt,我想创建一个表达式,它选择给定表达式集中的一个。给定一个表达式数组 Expr[] availableExprs = ...; 对于静态已知长度,我希望Z3选择其中任何一个(如switch语句)。如果问题是SAT,我需要一种方法来找出在模型中选择了哪一个(它在数组中的索引) 最快的编码方式是什么 到目前为止,我考虑了以下方法: 将整数限制为[0,arrayLength),并使用ITE选择其中一个表达式。模型允许我提取此整数。不幸的是,这将整数理论引入了模型(以前根本不使用整数) 为每个可能的选择
Expr[] availableExprs = ...;
对于静态已知长度,我希望Z3选择其中任何一个(如switch语句)。如果问题是SAT,我需要一种方法来找出在模型中选择了哪一个(它在数组中的索引)
最快的编码方式是什么
到目前为止,我考虑了以下方法:
[0,arrayLength)
,并使用ITE选择其中一个表达式。模型允许我提取此整数。不幸的是,这将整数理论引入了模型(以前根本不使用整数)显然,所有这些都是有效的,但它们似乎都有缺点。最佳策略是什么?我想你应该确保每个表达式都是无量词的,并且只使用公式中已经存在的函数和谓词。如果不是这样,那么为每个索引引入一个新的命题变量p_I,并断言ctx.MkIff(p_i,availableExprs[i])到解算器。
当Z3生成一个模型时,使用model.Eval(p_i)并检查结果是否为表达式“True”。如果您只想编码一个元素v在有限集合{e1,…,en}(使用sort U)中,您可以使用smtlib2执行此操作,如下所示:
(declare-fun v () U)
(declare-fun p1 () Bool)
...
(assert (= p1 (= v e1)))
(assert (= p2 (= v e2)))
...
(assert (= pn (= v en)))
(assert (or p1 ... pn))
变量v将等于{e1…en}的“数组”中的一个元素。如果选择变量v等于ei,则pi必须为真。这基本上是对尼古拉建议的重述,但为任意排序而重铸
请注意,由于不保证ei!=ej,多个pi可能被设置为true。如果需要确保没有两个元素同时被选中,则需要确定所需的语义。如果{e1…en}已被限定为不同的,则无需添加任何内容。如果“数组”您可以断言,元素必须是不同的,但尚未被限定为不同的
(assert (distinct e1 ... en))
(这可能会在内部扩展为n的二次型。)
相反,您可以说没有两个p变量可以一次为真。请注意,这是一个较弱的语句。要看到这一点,假设v=e1=1,e2=e3=0。然后p1=true,p2=p3=false。这些约束的明显编码是二次编码:
(assert (or (not pi) (not pj))) ; for all i < j
(断言(或(非pi)(非pj));对于所有i
如果您需要更好的编码,请尝试了解如何编码“p1+…+pn MkIff与MkEq相同,对吗?
availableExprs[i]
可以有任何类型(不一定是布尔型)。我不明白为什么我要断言“索引布尔型”“等于开关值。你能澄清一下吗?我将研究伪布尔约束和你提供的技巧。它们看起来是很好的研究方法。我将断言只有一个pn是真的,而不是区分输入(这在语义上是错误的).我正在合成程序,从另一个位向量计算一个位向量(如位计数程序).程序是一系列二进制运算符,每个运算符应用于以前计算的任何结果。我需要为运算符的每个输入选择任何可用的表达式,我需要知道它是哪一个,以便找出Z3程序合成的内容。顺便说一句,我同时尝试了我在问题中提出的所有策略。数组w最快的是布尔值,最慢的是布尔值。在我看来,嵌套得很深的ite链是有害的。您的断言技巧允许我绕过这一点。谢谢。(declare datatypes()((U e1 e2…en))
不应该做同样的事情吗?