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.
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!
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.
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!