I am pretty sure it has something to do with the python API. Is there a way to get back a partial model from z3 even when the status is unknown
?
I am trying to get a model out of z3 even when the status returns unknown
result. It fails with raising an exception
for model not available
. Any suggestions what can be done?
I converted the assertions to smt-lib format using sexpr()
method from the z3 Solver
interface and it returns a partial model even when the status is unknown
. I have attached example below.
# -*- 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())
In SMMT-LIB Format
(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)
I am running this file like this from the command line (terminal)
$ z3 example.py
Output :
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)
)
Any suggestions on how to get this model via the python interface directly?
The exception which z3 raises after model()
call on unknown
status.
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
Thanks
You cannot rely on the model if the solver returned unknown
. That is, the model you get is not "partial" by any means: It may or may not satisfy some of the constraints, but otherwise, there's not much you can do with it. It's at best a representation of the internal state of the solver. But in general, it is not guaranteed to be a representation of anything.
Also, when I run your SMTLib script with z3, I get:
unknown
(error "line 21 column 10: model is not available")
and I've z3 built from their github master about a week ago. I gather you've an old version, I'd strongly recommend you upgrade.
For reference, when you get unknown as an answer, the only valid thing to do is to ask the solver why the result is unknown. This is typically done with code like:
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)
For your Python program, I get:
smt tactic failed to show goal to be sat/unsat (incomplete quantifiers)
and that's really the only information you have at this point: Any "extraction" of model values would be simply wrong if the solver state is unknown
.
(A related question is also about "interrupting" the computation during a call to z3's optimizing solver. The "model" you get if you interrupt the solver will not be a "best" so far by any means, it may or may not satisfy the existing constraints. Long story short, unless solver reports sat
, do not count on the model you get: z3 is doing the right thing here and telling you there's no viable model available.)