Python Z3 API 查询:当求解器 returns 状态未知时,我们能否使用 z3 python API 获得部分模型

Python Z3 API Query : Can we get a partial model using the z3 python API when solver returns unkown status

我很确定它与 python API 有关。即使状态为 unknown,是否有办法从 z3 取回部分模型?

即使结果为 returns unknown,我也在尝试从 z3 中获取模型。它因 model not available 引发 exception 而失败。有什么建议可以做什么?

我使用 z3 Solver 接口中的 sexpr() 方法将断言转换为 smt-lib 格式,它 returns 即使状态为 unknown 也是部分模型。我在下面附上了例子。

# -*- coding: utf-8 -*-
​
from z3 import *
​
x, y, z = Reals('x y z')
m, n, l = Reals('m n l')
u, v = Ints('u v')
​
S = SolverFor("NRA")
​
S.add(x >= 0)
S.add(y >= 30, z <= 50)
S.add(m >= 5, n >= 5)
S.add(m * x + n * y + l > 300)
​
S.add(ForAll([u, v], Implies(m * u + n * v + l > 300, u + v + z <= 50)))
​
print(S.check())
print(S.sexpr())

采用 SMMT-LIB 格式

(set-option :print-success true) 
(set-option :produce-unsat-cores true) ; enable generation of unsat cores
(set-option :produce-models true) ; enable model generation
(set-option :produce-proofs true) ; enable proof generation
(declare-fun x () Real)
(declare-fun y () Real)
(declare-fun z () Real)
(declare-fun m () Real)
(declare-fun n () Real)
(declare-fun l () Real)
(assert (>= x 0.0))
(assert (>= y 30.0))
(assert (<= z 50.0))
(assert (>= m 5.0))
(assert (>= n 5.0))
(assert (not (<= (+ (* m x) (* n y) l) 300.0)))
(assert (forall ((u Int) (v Int))
  (let ((a!1 (<= (+ (* m (to_real u)) (* n (to_real v)) l) 300.0)))
    (or (<= (+ (to_real u) (to_real v) z) 50.0) a!1))))
(check-sat)
(get-model)

我在命令行(终端)运行 这个文件是这样的

$ z3 example.py

输出:

success
success
success
success
success
success
success
success
success
success
success
success
success
success
success
success
success
unknown
(model 
  (define-fun z () Real
    20.0)
  (define-fun y () Real
    30.0)
  (define-fun l () Real
    145.0)
  (define-fun x () Real
    0.0)
  (define-fun n () Real
    5.0)
  (define-fun m () Real
    5.0)
)

关于如何直接通过 python 界面获取此模型有什么建议吗?

z3 在 model() 调用 unknown 状态后引发的异常。

unknown
Traceback (most recent call last):

  File "C:\Python38\Lib\site-packages\z3\z3.py", line 6696, in model
    return ModelRef(Z3_solver_get_model(self.ctx.ref(), self.solver), self.ctx)

  File "C:\Python38\Lib\site-packages\z3\z3core.py", line 3759, in Z3_solver_get_model
    _elems.Check(a0)

  File "C:\Python38\Lib\site-packages\z3\z3core.py", line 1385, in Check
    raise self.Exception(self.get_error_message(ctx, err))

Z3Exception: b'there is no current model'


During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File "C:\Users\lahir\Documents\GitHub\codersguild\Research\tangram-solve\z3_tryouts.py", line 19, in <module>
    print(S.model())

  File "C:\Python38\Lib\site-packages\z3\z3.py", line 6698, in model
    raise Z3Exception("model is not available")

Z3Exception: model is not available

谢谢

除了我上面提到的那个,我还没有找到替代品。

如果求解器返回 unknown,则不能依赖该模型。也就是说,您获得的模型无论如何都不是“部分”的:它可能满足也可能不满足某些约束,但除此之外,您无能为力。它充其量只是求解器内部状态的表示。但总的来说,不能保证代表任何东西。

此外,当我 运行 使用 z3 的 SMTLib 脚本时,我得到:

unknown
(error "line 21 column 10: model is not available")

我大约一周前从他们的 github 大师那里构建了 z3。我发现你的版本太旧了,我强烈建议你升级。

作为参考,当您得到未知答案时,唯一有效的做法是询问求解器为什么结果未知。这通常使用如下代码完成:

r = S.check()
if r == sat:
    print(S.model())
elif r == unknown:
    print("Unknown, reason: %s" % S.reason_unknown())
else:
    print("Solver said: %s" % r)

对于您的 Python 程序,我得到:

smt tactic failed to show goal to be sat/unsat (incomplete quantifiers)

这确实是您此时拥有的唯一信息:如果求解器状态为 unknown

,则模型值的任何“提取”都是错误的

(一个相关的问题也是关于在调用 z3 的优化求解器期间“中断”计算。如果您中断求解器,您得到的“模型”将不是到目前为止“最好”无论如何,它可能满足也可能不满足现有的约束。长话短说,除非求解器报告 sat,不要指望你得到的模型:z3 在这里做正确的事情并告诉你没有可用的可行模型。)