z3 icon indicating copy to clipboard operation
z3 copied to clipboard

Missing universes for uninterpreted sorts

Open wintersteiger opened this issue 10 months ago • 2 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!

wintersteiger avatar Apr 08 '24 19:04 wintersteiger

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.

NikolajBjorner avatar Apr 10 '24 02:04 NikolajBjorner

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.

wintersteiger avatar Apr 10 '24 11:04 wintersteiger