z3
z3 copied to clipboard
Missing universes for uninterpreted sorts
A new variation of #7121 has cropped up:
from z3 import *
z3.set_param("model", True)
z3.set_param("model.completion", True)
z3.set_param("verbose", 10)
ctx = z3.Context(model=True)
slvr = z3.Solver(ctx=ctx)
slvr.set("model", True)
slvr.set("model.completion", True)
S = z3.DeclareSort("mysort", ctx)
x = z3.Const("x", S)
slvr.append(~(x != x))
print("Solver: " + str(slvr))
print("Result: " + str(slvr.check()))
model = slvr.model()
print("Model: " + str(model))
print("Sorts: " + str(model.sorts()))
print("Universe: " + str(model.get_universe(S)))
print("Eval: " + str(model.eval(x, True)))
says
Solver: [Not(x != x)]
(simplifier :num-exprs 0 :num-asts 157 :time 0.00 :before-memory 20.99 :after-memory 20.99)
Result: sat
Model: []
Sorts: []
Universe: None
Eval: mysort!val!
where the list of sorts and the universe are empty. This time it's the simplifier that solves the problem. TIA!
this is different from the other case because there is no reference to x in the model. x gets simplified away. Only the universes for sorts used in the model would be determined.
That's right, but it doesn't change the fact that the model is incomplete with model.completion
enabled. It is complete when using the binary:
$ cat tst.smt2
(declare-sort S 0)
(declare-const x S)
(assert (not (not (= x x))))
(check-sat)
(get-model)
$ z3 tst.smt2
sat
(
(define-fun x () S
S!val!0)
)
$ z3 tst.smt2 model.completion=true
sat
(
;; universe for S:
;; S!val!0
;; -----------
;; definitions for universe elements:
(declare-fun S!val!0 () S)
;; cardinality constraint:
(forall ((x S)) (= x S!val!0))
;; -----------
(define-fun x () S
S!val!0)
)
Some thoughts:
-
When a user-sort doesn't have a universe in the model, can I always assume that it has size exactly 1?
-
If we make up new sort elements when querying for a model value, we could also make up the entire universe at the same time. (I believe we actually do, it's just not accessible.)
-
For cases where the variables appear in the solver assertions, we could just splice in a model converter that collects all the unassigned decls from the constraints and inserts
get_some_value()
terms into the model where they are missing. This is cheap and easy and takes only a tiny amount of additional time when model completion is enabled. -
For things that don't appear in either the assertions or the model, I totally agree, we can just throw a hard error or return zero.