我想创建一个表达式,选择一组给定的表达式。给出一系列表达式
Expr[] availableExprs = ...;
具有静态已知长度,我希望Z3选择其中任何一个(如switch语句)。如果问题是SAT,我需要一种方法来找出在模型中选择了哪些(它在数组中的索引)。
对此进行编码的最快方法是什么?
到目前为止,我考虑过这些方法:
[0, arrayLength)
并使用ITE选择其中一个表达式。该模型允许我提取此整数。不幸的是,这将整数理论引入模型(之前根本没有使用整数)。答案 0 :(得分:3)
如果您想要编码的是元素v是有限集合{e1,...,en}(使用排序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必须为真。这基本上是对尼古拉的建议的重述,但重铸任意种类。
请注意,多个pi可能设置为true,因为无法保证ei!= ej。如果您需要确保没有选择两个元素,您需要确定您想要的语义。如果{e1 ... en}已经必须是不同的,则不需要添加任何内容。如果“数组”元素必须是不同的但不是必须区分,则可以断言
(assert (distinct e1 ... en))
(这可能会在内部扩展到n中的二次方。) 你可以说没有2个p变量可以一次为真。请注意,这是一个较弱的陈述。为了看到这一点,假设v = e1 = 1且e2 = e3 = 0.那么p1 =真,p2 = p3 =假。这些约束的明显编码是二次的:
(assert (or (not pi) (not pj))) ; for all i < j
如果您需要更好的编码,请尝试查看如何在Translating Pseudo-Boolean Constraints into SAT部分5.3中编码“p1 + ... + pn&lt; = 1”。如果明显的编码失败,我只会尝试这个。
答案 1 :(得分:1)
我认为您希望确保每个表达式都是无量词的,并且仅使用公式中已存在的函数和谓词。如果不是这种情况,则为每个索引引入一个新的命题变量p_i,并向解算器断言ctx.MkIff(p_i,availableExprs [i])。 当Z3生成模型时,使用model.Eval(p_i)并检查结果是否为“True”表达式。