我对量词有疑问。
假设我有一个数组,我想为这个数组计算数组索引0,1和2 -
(declare-const cpuA (Array Int Int))
(assert (or (= (select cpuA 0) 0) (= (select cpuA 0) 1)))
(assert (or (= (select cpuA 1) 0) (= (select cpuA 1) 1)))
(assert (or (= (select cpuA 2) 0) (= (select cpuA 2) 1)))
或者我可以使用forall构造指定相同的 -
(assert (forall ((x Int)) (=> (and (>= x 0) (<= x 2)) (or (= (select cpuA x) 0) (= (select cpuA x) 1)))))
现在我想了解其中两个之间的区别。 第一种方法快速执行,并提供简单易读的模型。 相比之下,第二个选项的代码大小非常少,但程序需要时间来执行。而且解决方案也很复杂。
我想使用第二种方法,因为我的代码会变小。 但是,我想找一个可读的简单模型。
答案 0 :(得分:3)
量词推理通常非常昂贵。在您的示例中,量化公式等同于您提供的三个断言。 然而,这不是Z3决定/解决你的公式的方式。 Z3使用称为基于模型的量化实例化(MBQI)的技术来解决您的公式。 这种技术可以决定许多片段(见http://rise4fun.com/Z3/tutorial/guide)。它主要对本指南中描述的碎片有效。 它支持未解释的函数,算术和位向量理论。它对数组和数据类型的支持也有限。 这足以解决您的示例。 Z3生成的模型看起来更复杂,因为使用相同的引擎来决定更复杂的碎片。 该模型应该看起来像一个小功能程序。您可以在以下文章中找到有关此方法如何工作的更多信息:
请注意,数组理论主要用于表示/建模无界或大数组。也就是说,阵列的实际大小未知或太大。大,我的意思是公式中的数组访问次数(即selects
)远小于数组的实际大小。我们应该问自己:“我们真的需要数组来建模/解决问题X吗?”。您可以考虑以下备选方案:
(未解释)函数而不是数组。您的示例也可以编码为:
(declare-fun cpuA(Int)Int)
(断言(或(=(cpuA 0)0)(=(cpuA 0)1)))
(断言(或(=(cpuA 1)0)(=(cpuA 1)1)))
(断言(或(=(cpuA 2)0)(=(cpuA 2)1)))
程序化API。我们已经看到很多使用数组(和函数)来提供紧凑编码的例子。紧凑而优雅的编码不一定更容易解决。实际上,通常是相反的方式。使用Z3的编程API,您可以实现两全其美(性能和紧凑性)。在下面的链接中,我使用一个“变量”为“数组”的每个位置编码您的示例。宏/函数用于编码约束,例如:表达式为0
或1
。
http://rise4fun.com/Z3Py/JF