Z3 partial order doesn't seem to be reflexive

Question:

I am trying to learn to use the Z3 solver. In this tutorial it is explained that a partial order is best defined using the built-in PartialOrder function. It seems to me that the resulting order is not reflexive, as the following bit of code returns sat:

>>> s = Solver()
>>> R = PartialOrder(IntSort(), 0)
>>> x = Int('x')
>>> s.add(Not(R(x, x)))
>>> s.check()
sat

Am I misunderstanding something?

I checked the other properties (transitivity and antisymmetry) which seem to work as expected. Also, changing PartialOrder(IntSort(), 0) to LinearOrder(IntSort(), 0) changes the answer to unsat.

The model for the Not(R(x, x)) formula doesn’t make me any wiser:

 next = [else ->
         If(And(member(Var(0), Var(2)),
                Not(member(Var(1), Var(3)))),
            pair(cons(Var(1), fst(Var(4))),
                 cons(Var(1), snd(Var(4)))),
            Var(4))],
 partial-order = [else ->
                  Or(connected(cons(Var(0), nil),
                               Var(1),
                               cons(Var(0), nil)),
                     Var(0) == Var(1))],
 member = [else ->
           If(is(nil, Var(1)),
              False,
              If(head(Var(1)) == Var(0),
                 True,
                 member(Var(0), tail(Var(1)))))],
 connected = [else ->
              If(fst(pair(nil, Var(2))) == nil,
                 False,
                 If(member(Var(1), fst(pair(nil, Var(2)))),
                    True,
                    connected(fst(pair(nil, Var(2))),
                              Var(1),
                              snd(pair(nil, Var(2))))))]]

I’m using version 4.11.2.0.

Asked By: Wijnand

||

Answers:

z3’s PartialOrder is supposed to be reflexive. So, indeed, there seems to be something fishy going on here. I seem to recall that these sorts of relations worked on uninterpreted-sorts better, or at least finite-domains; but even then I’m seeing bizarre behavior.

For instance, this code:

from z3 import *

s = Solver()
A = DeclareSort('A')
R = PartialOrder(A, 0)
a = Const('a', A)
s.add(Not(R(a, a)))
print(s.check())

prints sat. But it’s supposed to be equivalent (i.e., same semantics, but with better performance) to the following:

from z3 import *

s = Solver()
A = DeclareSort('A')
R = Function('R', A, A, BoolSort())
x, y, z = Consts('x y z', A)
s.add(ForAll([x], R(x, x)))
s.add(ForAll([x,y], Implies(And(R(x, y), R(y, x)), x == y)))
s.add(ForAll([x,y,z], Implies(And(R(x, y), R(y, z)), R(x, z))))

a = Const('a', A)
s.add(Not(R(a, a)))
print(s.check())

which prints unsat as you’d expect.

I’d recommend filing a ticket at https://github.com/Z3Prover/z3/issues and see what the developers have to say. Please do update this question back with what you find out!

Answered By: alias
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.