Iterative Tree Delete (Magic Wands)
Deletion of minimal tree element (VerifyThis@FM2012)
/* This example shows how magic wands can be used to specify the
* imperative version of challenge 3 from the VerifyThis@FM2012
* verification competition. Method tree_delete_min below is an
* iterative implementation of the removal of the minimal element
* in a binary search tree.
*
* The example contains two assertions (marked with "TODO") that
* help overcoming an incompleteness with respect to sequences.
*
* At present, this example uses syntax which is only supported
* by the default Viper verifier (Silicon).
*/
field v: Int
field l: Ref
field r: Ref
predicate Tree(x: Ref) {
x == null
? true
: acc(x.v)
&& acc(x.l) && acc(Tree(x.l))
&& acc(x.r) && acc(Tree(x.r))
}
function val(x: Ref): Int
requires x != null && acc(Tree(x))
{ unfolding acc(Tree(x)) in x.v }
function vals(x: Ref): Seq[Int]
requires acc(Tree(x))
{ x == null ? Seq[Int]() : unfolding acc(Tree(x)) in vals(x.l) ++ Seq(x.v) ++ vals(x.r) }
/* Deletes the minimal element of a binary tree, assuming that the
* tree is a binary search tree (which, for simplicity, is not made
* explicit in the definition of predicate Tree).
*/
method tree_delete_min(x: Ref) returns (z: Ref)
requires x != null && acc(Tree(x))
ensures acc(Tree(z)) /* POST1 */
ensures vals(z) == old(vals(x))[1..] /* POST2 */
{
var p: Ref := x
var plvs: Seq[Int]
define A(p, plvs) acc(p.l) && acc(Tree(p.l)) && vals(p.l) == plvs[1..]
define B acc(Tree(x)) && vals(x) == old(vals(x))[1..]
unfold acc(Tree(p))
plvs := vals(p.l)
if (p.l == null) {
z := p.r
assert vals(x.l) == Seq[Int]() /* TODO: Required by Silicon for POST2 */
} else {
package A(p, plvs) --* B {
fold acc(Tree(p))
}
while (unfolding acc(Tree(p.l)) in p.l.l != null)
invariant p != null && acc(p.l) && acc(Tree(p.l)) && p.l != null
invariant plvs == vals(p.l)
invariant A(p, plvs) --* B
{
var prevP: Ref := p
var prevPlvs: Seq[Int] := plvs
unfold acc(Tree(p.l))
p := p.l
plvs := vals(p.l)
package A(p, plvs) --* B {
fold Tree(p)
apply A(prevP, prevPlvs) --* B
}
}
unfold acc(Tree(p.l))
assert vals(p.l.l) == Seq[Int]() /* TODO: Required by Silicon for POST2 */
p.l := p.l.r
apply A(p, plvs) --* B
z := x
}
}