Z3Prover / z3

The Z3 Theorem Prover

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Missing universes for uninterpreted sorts

wintersteiger opened this issue · comments

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.