小能豆

z3/python 实数

py

使用 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)。

我怀疑问题出在非线性项上(* s0 s0),而 Python 接口不知何故没有受到该项的影响。有没有办法在 smt-lib2 中编写相同的代码来获取模型?


阅读 16

收藏
2024-12-09

共1个答案

小能豆

SMT-LIB 2 中,问题出在如何求解非线性方程时,z3 默认的求解方法与 Python 接口中可能使用的数值求解方法不同。z3 的标准求解器不总是能处理非线性方程,特别是在使用 *(乘法)时,像 (* s0 s0) 这样的表达式可能被认为是一个非线性方程,这可能会导致 z3 返回 unknown,因为默认的求解器并不擅长处理这种类型的问题。

解决方案

为了让 z3 能够处理这种非线性方程并且返回模型,您需要显式地启用一个能够处理非线性方程的求解器。

  1. 启用 non-linear 求解器
    可以通过设置 :arith 选项来启用处理非线性方程的求解器。对于 z3,通常会使用 NRA(非线性实数算术)来处理此类问题。

  2. 修改 SMT-LIB 脚本
    将求解器切换到支持非线性算术的版本,并添加 :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)                         ; 获取模型

解释:

  1. :produce-models true 确保你能够获得模型(解)。
  2. :solver 'nra' 显式启用了非线性实数算术求解器,它能够处理类似 s0 * s0 这种非线性表达式。
  3. get-model 命令用来获取最终的模型,显示解。

结果

这段代码在 z3 中应该返回类似以下的解:

sat
(model 
  (define s0 (- 1.4142135623))
)

注意:

  • nra 求解器是专门设计来处理非线性实数问题的,如果你不设置这个选项,z3 将默认使用线性求解器,这会导致 unknown
  • 如果你遇到性能问题,可能需要进一步优化或改变求解策略。
2024-12-09