Uninterpreted functions: postconditions vs axioms
fpoli opened this issue · 2 comments
Related to #479, I found that the first program below does not work, but the second does. Is the semantics of the two encodings of rd()
the same? I'm wondering if the postcondition and the domain axiom are encoded in semantically different ways or if the difference is just because of heuristics of Z3. If the latter is more reliable we might e.g. switch to it in Prusti.
Not working:
field f: Ref
function rd(): Perm
ensures none < result && result < write
ensures none < result * result && result * result < result // Workaround for Silicon issue #479
predicate Q(self: Ref)
predicate P(self: Ref) {
acc(self.f, rd()) && Q(self.f)
}
method test(x: Ref)
requires acc(P(x), rd())
{
unfold acc(P(x), rd()) // ERROR: Unfolding P(x) might fail. There might be insufficient permission to access self.f
inhale acc(x.f, rd() - rd() * rd())
assert perm(x.f) == rd()
}
Working:
field f: Ref
domain MyPermissions {
function rd(): Perm
axiom { none < rd() && rd() < write }
axiom { none < rd() * rd() && rd() * rd() < rd() } // Workaround for Silicon issue #479
}
predicate Q(self: Ref)
predicate P(self: Ref) {
acc(self.f, rd()) && Q(self.f)
}
method test(x: Ref)
requires acc(P(x), rd())
{
unfold acc(P(x), rd())
inhale acc(x.f, rd() - rd() * rd())
assert perm(x.f) == rd()
}
The first version is encoded to something that is essentially equivalent to this:
domain Snap {
function Snap_unit(): Snap
}
domain Internal {
function rd_limited(s: Snap): Perm
function rd_pre(s: Snap): Bool
axiom {
forall s: Snap :: { rd_limited(s) } rd_pre(s) ==>
let result == (rd_limited(s)) in none < result && result < write && none < result * result && result * result < result
}
}
Then, wherever rd()
is used in the Viper program, Silicon first emits the assumption rd_pre(Snap_unit())
and then encodes rd()
as rd_limited(Snap_unit())
.
So: There is a difference in the encoding; when using the non-domain function, Z3 will have to instantiate a quantifier to learn the postcondition. However, that quantifier is definitely triggered, and Z3 gets the same information. But I guess it's easy to imagine that some Z3 heuristics have an easier time dealing with the first scenario.
Thanks! Running Z3 on the SMT2 log of the non-domain formulation, Z3 version 4.8.12 manages to prove the property while Z3 version 4.8.7 does not.