我有以下问题:
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]
谢谢
答案 0 :(得分:0)
老实说,我无法具体回答z3,但我想对 A)点发表自己的看法。
通常,约束x=0 v x=1
被抽象为t1 v t2
,其中t1
是x=0
,而t2
是x=1
,位于{ {1}}引擎级别。
因此,SAT
引擎可能会在为输入公式构建可满足的真值分配期间尝试将SAT
和t1
都分配给t2
。重要的是要注意,这与true
的理论是矛盾的,但是LAR
引擎无法进行这种推理。因此,SAT
引擎在做出此决定后可能会继续搜索一段时间。
当最终调用SAT
解算器时,它将检测给定(可能是部分)真值分配的LAR不满足要求。结果,它(应该)将LAR
子句作为学习子句传递给not t1 or not t2
引擎,以阻止要再次生成的值的错误分配。
如果有很多这样的错误分配,则可能需要多次调用SAT
解算器,以便生成纠正LAR
真值分配所需的所有阻塞子句,可能最多一个对于每种不良组合。
SAT
引擎收到冲突条款后,将不得不跳回进行错误分配的地方并做出正确的决定。显然,SAT
引擎完成的所有工作都不会浪费,因为它浪费了价值的分配:在此期间学到的任何有用的子句肯定会被重用。但是,这仍然会导致某些公式的性能显着下降。
通过简单地将SAT
声明为Bool来比较所有这些来回计算的浪费:现在x
引擎知道它只能为其分配两个值之一,并赢得了胜利永远不要同时分配SAT
和x
。
在这种特定情况下,可以通过在输入公式中提供必要的阻塞子句来缓解此问题。但是,得出这始终是最佳实践并非易事:在某些情况下,明确列出所有已知的阻塞子句可能会导致公式大小爆炸,甚至在实践中甚至导致性能下降。最好的建议是在解决问题的任何特定编码之前,尝试不同的方法并进行实验评估。
免责声明::某些not x
求解器可能比其他求解器更聪明,并在解析公式时自动为SMT
变量生成适当的阻塞子句或完全避免这种情况通过其他方式(即 afaik ,基于模型的SMT求解器不应引起相同的问题)
答案 1 :(得分:0)
Patrick为此做了一个很好的解释。在实践中,您确实必须尝试看看会发生什么。由于启发式学习的时间/方式,不同的问题可能表现出不同的行为。我认为这里没有一般的经验法则。我个人的喜好是将布尔值保留为布尔值,并根据需要进行转换,但这主要是从编程/维护的角度出发,而不是效率方面。
您的“部门”被截断的问题很可能与此相同:Retrieve a value in Z3Py yields unexpected result
您可以是显性的,也可以写1.0/2.0
等。或使用:
from __future__ import division
位于程序顶部。
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)))