澄清SMT类型;错误的截断错误?允许Bool * Int

时间:2018-07-28 16:00:10

标签: z3 smt z3py

我有以下问题:

A。如果我有一个变量x,则将其声明为(情况1)为Bool(情况2)为Int并断言x = 0或将x = 1(情况3)为Int并断言0 <= x <= 1。在每种情况下,Z3或更普遍地在SMT中会发生什么?因为情况发生在SAT而不是SMT级别,是否(案例1)是所需要的?这里有参考书吗?

B。我在Python中有以下声明(用于使用Z3 Python API)

    tmp.append(sum([self.a[i * self.nrVM + k] * componentsRequirements[i][1] for i 
    in range(self.nrComp)]) <= self.MemProv[k])

其中a被声明为Z3 Int变量(0或1),componentsRequirements是一个Python变量,被视为float,self.MemProv被声明为Z3 Real变量。

奇怪的是,对于componentsRequirements的float值,例如0.5,求解器建立的约束将其视为0,而不是0.5。例如:

    (assert (<= (to_real (+ 0 (* 0 C1_VM2)
            (* 0 C2_VM2)
            (* 2 C3_VM2)
            (* 2 C4_VM2)
            (* 3 C5_VM2)
            (* 1 C6_VM2)
            (* 0 C7_VM2)
            (* 2 C8_VM2)
            (* 1 C9_VM2)
            (* 2 C10_VM2)))
StorageProv2))

上面的0应该实际上是0.5。当将a更改为Real值时,会考虑使用浮点数,但是由于a的语义,我们对此表示认可。我尝试在和组件需求之间使用可交换性,但没有成功。

C。如果我想使用x作为Bool类型并将其乘以一个Int,我当然会在Z3中得到一个错误(不允许使用Bool * Real / Int)。除了保留两个乘数的类型外,是否有办法克服此问题?上面的例子就是这样(a-Bool,componentsRequirements-实数/整数):         a [i * self.nrVM + k] * componentsRequirements [i] [1]

谢谢

2 个答案:

答案 0 :(得分:0)

老实说,我无法具体回答z3,但我想对 A)点发表自己的看法。

通常,约束x=0 v x=1被抽象为t1 v t2,其中t1x=0,而t2x=1,位于{ {1}}引擎级别。

因此,SAT引擎可能会在为输入公式构建可满足的真值分配期间尝试将SATt1都分配给t2。重要的是要注意,这与true的理论是矛盾的,但是LAR引擎无法进行这种推理。因此,SAT引擎在做出此决定后可能会继续搜索一段时间。

当最终调用SAT解算器时,它将检测给定(可能是部分)真值分配的LAR不满足要求。结果,它(应该)将LAR子句作为学习子句传递给not t1 or not t2引擎,以阻止要再次生成的值的错误分配。

如果有很多这样的错误分配,则可能需要多次调用SAT解算器,以便生成纠正LAR真值分配所需的所有阻塞子句,可能最多一个对于每种不良组合。

SAT引擎收到冲突条款后,将不得不跳回进行错误分配的地方并做出正确的决定。显然,SAT引擎完成的所有工作都不会浪费,因为它浪费了价值的分配:在此期间学到的任何有用的子句肯定会被重用。但是,这仍然会导致某些公式的性能显着下降。

通过简单地将SAT声明为Bool来比较所有这些来回计算的浪费:现在x引擎知道它只能为其分配两个值之一,并赢得了胜利永远不要同时分配SATx

在这种特定情况下,可以通过在输入公式中提供必要的阻塞子句来缓解此问题。但是,得出这始终是最佳实践并非易事:在某些情况下,明确列出所有已知的阻塞子句可能会导致公式大小爆炸,甚至在实践中甚至导致性能下降。最好的建议是在解决问题的任何特定编码之前,尝试不同的方法并进行实验评估。


免责声明::某些not x求解器可能比其他求解器更聪明,并在解析公式时自动为SMT变量生成适当的阻塞子句或完全避免这种情况通过其他方式(即 afaik ,基于模型的SMT求解器不应引起相同的问题)

答案 1 :(得分:0)

关于A

Patrick为此做了一个很好的解释。在实践中,您确实必须尝试看看会发生什么。由于启发式学习的时间/方式,不同的问题可能表现出不同的行为。我认为这里没有一般的经验法则。我个人的喜好是将布尔值保留为布尔值,并根据需要进行转换,但这主要是从编程/维护的角度出发,而不是效率方面。

关于B

您的“部门”被截断的问题很可能与此相同:Retrieve a value in Z3Py yields unexpected result

您可以是显性的,也可以写1.0/2.0等。或使用:

 from __future__ import division

位于程序顶部。

关于C

SMTLib是一种强类型语言;你不能乘以布尔。您必须先将其转换为数字。类似(* (ite b 1 0) x),其中b是您的布尔值。或者,您可以编写一个为您执行此操作的自定义函数,然后调用该函数。像这样:

(define-fun mul_bool_int ((b Bool) (i Int)) Int (ite b i 0))
(assert (= 0 (mul_bool_int false 5)))
(assert (= 5 (mul_bool_int true 5)))