使用 z3/python Web 界面,如果我询问:
x = Real ('x') solve(x * x == 2, show=True)
我很好地得到了:
Problem: [x·x = 2] Solution: [x = -1.4142135623?]
我认为以下 smt-lib2 脚本会有相同的解决方案:
(set-option :produce-models true) (declare-fun s0 () Real) (assert (= 2.0 (* s0 s0))) (check-sat)
唉,我得到了unknownz3 (v3.2)。
unknown
我怀疑问题出在非线性项上(* s0 s0),而 Python 接口不知何故没有受到该项的影响。有没有办法在 smt-lib2 中编写相同的代码来获取模型?
(* s0 s0)
在 SMT-LIB 2 中,问题出在如何求解非线性方程时,z3 默认的求解方法与 Python 接口中可能使用的数值求解方法不同。z3 的标准求解器不总是能处理非线性方程,特别是在使用 *(乘法)时,像 (* s0 s0) 这样的表达式可能被认为是一个非线性方程,这可能会导致 z3 返回 unknown,因为默认的求解器并不擅长处理这种类型的问题。
SMT-LIB 2
z3
*
为了让 z3 能够处理这种非线性方程并且返回模型,您需要显式地启用一个能够处理非线性方程的求解器。
启用 non-linear 求解器: 可以通过设置 :arith 选项来启用处理非线性方程的求解器。对于 z3,通常会使用 NRA(非线性实数算术)来处理此类问题。
non-linear
:arith
NRA
修改 SMT-LIB 脚本: 将求解器切换到支持非线性算术的版本,并添加 :produce-models 选项来确保返回模型。
:produce-models
(set-option :produce-models true) ; 确保返回模型 (set-option :solver-log-level 2) ; 可选:帮助诊断问题 (set-option :timeout 5000) ; 可选:设置超时时间 (declare-fun s0 () Real) ; 声明变量 s0 (assert (= 2.0 (* s0 s0))) ; 非线性方程 s0^2 = 2 ; 启用非线性实数求解器 (set-option :solver 'nra) (check-sat) ; 检查可满足性 (get-model) ; 获取模型
:produce-models true
:solver 'nra'
s0 * s0
get-model
这段代码在 z3 中应该返回类似以下的解:
sat (model (define s0 (- 1.4142135623)) )
nra