For some reason dafny reports that the ensure condition for PreorderTraversalChildrenAreLater might not always hold even though the quantified expression always holds... later on in the same lemma. Ideally, once I've shown the existence k, I was attempting to show that all child elements of the root.repr will appear later in the PreorderTraversal.
ensures forall k :: 0 <= k < |PreorderTraversal(root)| ==> forall child :: child in PreorderTraversal(root)[k].repr && child != PreorderTraversal(root)[k] ==> exists j :: k < j < |PreorderTraversal(root)| && PreorderTraversal(root)[j] == child
function PreorderTraversal(root: TreeNode): seq<TreeNode>
reads root.repr
requires root.Valid()
ensures forall x :: x in root.repr ==> x in PreorderTraversal(root)
ensures forall k :: 0 <= k < |PreorderTraversal(root)| ==> PreorderTraversal(root)[k] in root.repr && PreorderTraversal(root)[k].Valid()
// ensures forall k :: 0 <= k < |PreorderTraversal(root)| ==> PreorderTraversal(root)[k] in root.repr
{
if root.left != null && root.right != null then [root]+PreorderTraversal(root.left)+PreorderTraversal(root.right) else if root.left != null then [root]+PreorderTraversal(root.left) else if root.right != null then [root]+PreorderTraversal(root.right) else [root]
}
lemma {:verify true} PreorderTraversalChildrenAreLater(root: TreeNode)
requires root.Valid()
//the following does not verify
ensures forall x :: x in root.repr ==> exists k: nat :: 0 <= k < |PreorderTraversal(root)| && PreorderTraversal(root)[k] == x
{
// var what := PreorderTraversal(root);
assert forall x :: x in root.repr ==> x in PreorderTraversal(root);
forall x | x in root.repr
ensures exists k: nat :: 0 <= k < |PreorderTraversal(root)| && PreorderTraversal(root)[k] == x
{
assert x in PreorderTraversal(root);
seqbusiness(PreorderTraversal(root), x);
}
// but it verifies here, at least I get the green checkmark
assert forall x :: x in root.repr ==> exists k: nat :: 0 <= k < |PreorderTraversal(root)| && PreorderTraversal(root)[k] == x;
}
lemma seqbusiness<A>(s: seq<A>, elem: A)
requires elem in s
ensures exists k:nat :: 0 <= k < |s| && s[k] == elem
{
}
class TreeNode {
var val: int;
var left: TreeNode?;
var right: TreeNode?;
ghost var repr: set<TreeNode>;
constructor(val: int, left: TreeNode?, right: TreeNode?)
requires left != null ==> left.Valid()
requires right != null ==> right.Valid()
requires left != null && right != null ==> left.repr !! right.repr
ensures this.val == val
ensures this.left == left
ensures this.right == right
ensures left != null ==> this !in left.repr
ensures right != null ==> this !in right.repr
ensures Valid()
{
this.val := val;
this.left := left;
this.right := right;
var leftRepr := if left != null then {left}+left.repr else {};
var rightRepr := if right != null then {right}+right.repr else {};
this.repr := {this} + leftRepr + rightRepr;
}
predicate Valid()
reads this, repr
decreases repr
{
this in repr &&
(this.left != null ==>
(this.left in repr
&& this !in this.left.repr
&& this.left.repr < repr
&& this.left.Valid()
))
&& (this.right != null ==>
(this.right in repr
&& this !in this.right.repr
&& this.right.repr < repr
&& this.right.Valid())) &&
(this.left != null && this.right != null ==> this.left.repr !! this.right.repr && this.repr == {this} + this.left.repr + this.right.repr)
&& (this.left != null && this.right == null ==> this.repr == {this} + this.left.repr)
&& (this.right != null && this.left == null ==> this.repr == {this} + this.right.repr)
&& (this.right == null && this.left == null ==> this.repr == {this})
}
}
I agree it doesn't verify as is and its not clear why. However, I did manage to get it to go through by lifting out a predicate as follows:
predicate WithinRootPreorder(root:TreeNode, x: TreeNode)
reads root.repr
requires root.Valid()
requires x in root.repr {
exists k: nat :: 0 <= k < |PreorderTraversal(root)| && PreorderTraversal(root)[k] == x
}
lemma {:verify true} PreorderTraversalChildrenAreLater(root: TreeNode)
//reads root.repr
requires root.Valid()
ensures root.repr == old(root.repr)
//the following does not verify
ensures forall x :: x in root.repr ==> WithinRootPreorder(root,x)
{
...
assert forall x :: x in root.repr ==> WithinRootPreorder(root,x);
}
That seemed to work for me.
Trying to setup a few functions for a quicksort implementation I got stuck on the following lemmas, filterLemmaExtra and filterLemmaSizes.
function filter<T(==)>(xs: seq<T>, p: (T) -> bool): seq<T>
ensures forall x: T :: x in xs && p(x) ==> x in filter(xs, p)
ensures forall x: T :: x !in xs && p(x) ==> x !in filter(xs, p)
ensures forall x: T :: x in filter(xs, p) ==> p(x)
ensures forall x: T :: x in filter(xs, p) ==> x in xs[0..|xs|]
ensures forall x: T :: x in filter(xs, p) ==> x in xs
ensures forall x: T :: x in xs && !p(x) ==> x !in filter(xs, p)
ensures forall i: nat :: i < |filter(xs, p)| ==> filter(xs, p)[i] in xs
{
if xs == [] then [] else if p(xs[0]) then [xs[0]] + filter(xs[1..], p) else filter(xs[1..], p)
}
lemma filterLemmaSizes<T(==)>(xs: seq<T>, fxs: seq<T>, p: (T) -> bool)
requires fxs == filter(xs, p)
ensures forall x: T :: x in xs && p(x) ==> multiset(xs)[x] == multiset(fxs)[x]
ensures multiset(filter(xs,p)) <= multiset(xs)
{
}
lemma filterLemmaExtra<T(==)>(xs: seq<T>, p: (T) -> bool, i: nat)
requires 0 <= i <= |xs|
ensures filter(xs, p) == filter(xs[0..i], p) + filter(xs[i..], p)
{
}
predicate isNegatedBooleanFn<T(==)>(xs: seq<T>, p: (T) -> bool, q: (T) -> bool) {
forall x: T :: x in xs && p(x) ==> !q(x)
}
function filter_mset<T(==)>(ms: multiset<T>, p: (T) -> bool): multiset<T>
ensures forall x :: x in ms && p(x) ==> x in filter_mset(ms, p) && ms[x] == filter_mset(ms, p)[x]
ensures forall x :: x in filter_mset(ms, p) ==> p(x)
ensures forall x :: x in filter_mset(ms, p) ==> x in ms
{
if ms == multiset{} then multiset{} else
var x :| x in ms; if p(x) then var result := multiset{}; result[x := ms[x]] + filter_mset(ms[x := 0], p) else filter_mset(ms[x := 0], p)
}
lemma filterAndFilterMset<T(==)>(ms: seq<T>, p: (T) -> bool)
ensures multiset(filter(ms, p)) == filter_mset(multiset(ms), p)
{
assert forall x :: x in filter(ms, p) ==> x in multiset(filter(ms, p)) && p(x);
assert forall x :: x in filter(ms, p) ==> x in filter_mset(multiset(ms), p);
assert forall x :: x in filter_mset(multiset(ms), p) ==> x in filter(ms, p);
filterLemmaSizes(ms, filter(ms, p), p);
assert forall x :: x in filter(ms, p) ==> multiset(filter(ms, p))[x] == filter_mset(multiset(ms), p)[x];
}
lemma filterMS<T(==)>(xs: seq<T>, p: (T) -> bool)
ensures exists q: (T) -> bool :: isNegatedBooleanFn(xs, p, q)
{
var q: (T) -> bool := y => !p(y);
forall x | x in xs
ensures x in xs && p(x) ==> !q(x)
{
if p(x) {
assert !q(x);
}
}
assert isNegatedBooleanFn(xs, p, q);
// assert forall x: T :: x in xs && p(x) ==> !q(x);
}
lemma filterMsetAndSum<T(==)>(xs: seq<T>, ms: multiset<T>, p: (T) -> bool)
requires ms == multiset(xs)
ensures exists Q: (T) -> bool :: isNegatedBooleanFn(xs, p, Q) && (filter_mset(ms, p) + filter_mset(ms, Q)) == ms
{
filterMS(xs, p);
var Q :| isNegatedBooleanFn(xs, p, Q);
var sum_ms := filter_mset(ms, p) + filter_mset(ms, Q);
forall x | x in ms
ensures ms[x] == sum_ms[x]
{
if p(x) {
assert x in filter_mset(ms, p);
assert filter_mset(ms, p)[x] == ms[x];
assert x in sum_ms;
assert sum_ms[x] == ms[x];
}else {
assert x in filter_mset(ms, Q);
assert filter_mset(ms, Q)[x] == ms[x];
assert x in sum_ms;
assert sum_ms[x] == ms[x];
}
}
assert sum_ms == ms;
}
My initial implementation of filterLemmaExtra gets bogged down when I try to assert the indices of the concatenated sequences are equal to the filter.
lemma filterLemmaExtra<T(==)>(xs: seq<T>, p: (T) -> bool, i: nat)
requires 0 <= i <= |xs|
ensures filter(xs, p) == filter(xs[0..i], p) + filter(xs[i..], p)
{
assert xs == xs[0..i] + xs[i..];
var allxs := set x | x in xs && p(x);
var leftxs := set x | x in xs[0..i] && p(x);
var rightxs := set x | x in xs[i..] && p(x);
assert allxs == leftxs + rightxs;
forall x | x in filter(xs, p)
ensures x in filter(xs[0..i], p) || x in filter(xs[i..], p)
{
assert x in xs ==> x in xs[0..i] || x in xs[i..];
}
var all := filter(xs[0..i], p) + filter(xs[i..], p);
assert |filter(xs, p)| == |all|;
// forall i: nat | i < |filter(xs,p)| //explodes
// ensures filter(xs, p)[i] == (filter(xs[0..i], p) + filter(xs[i..], p))[i]
// {
// }
}
For the filterLemmaSizes I thought of two approaches. Initially trying to break down the seqences and the filtered sequence but apart from the case that the first element in both sequences match I can't see how to do induction on the rest of the cases.
Then I thought maybe that I could try to do a proof by negation on the multiset values but I'm not sure of how to write those statements. It seems you should be able to assert that that if multiset(xs)[x] == #non-zero number then there exist that many indices in the original array that satisfy p(x) and so they should also be in filter(xs, p);.
lemma filterLemmaSizes<T(==)>(xs: seq<T>, fxs: seq<T>, p: (T) -> bool)
requires fxs == filter(xs, p)
ensures forall x: T :: x in xs && p(x) ==> multiset(xs)[x] == multiset(fxs)[x]
ensures multiset(filter(xs,p)) <= multiset(xs)
{
forall x | x in xs && p(x)
ensures multiset(xs)[x] == multiset(fxs)[x]
{
assert x in multiset(xs);
assert x in xs[0..|xs|];
assert x in multiset(fxs);
assert x in fxs[0..|fxs|];
if multiset(xs)[x] != multiset(fxs)[x] && multiset(xs)[x] < multiset(filter(xs, p))[x] {
} else if multiset(xs)[x] != multiset(fxs)[x] && multiset(xs)[x] > multiset(filter(xs, p))[x] {
}
// if xs != [] && p(xs[0]) && x == xs[0] {
// assert xs == [xs[0]] + xs[1..];
// assert multiset(xs) == multiset{xs[0]} + multiset(xs[1..]);
// assert multiset(xs)[x] == multiset{xs[0]}[x] + multiset(xs[1..])[x];
// assert multiset(xs)[x] == multiset{xs[0]}[x] + multiset(xs[1..])[x];
// assert xs[0] == fxs[0];
// assert multiset(fxs) == multiset{xs[0]} + multiset(filter(xs[1..],p));
// assert x in xs;
// if x in xs[1..] {
// calc {
// multiset(xs)[x];
// ==
// multiset{x}[x] + multiset(xs[1..])[x];
// == {assert 1 == multiset{xs[0]}[x];}
// 1 + multiset(xs[1..])[x];
// == { filterLemmaSizes(xs[1..], filter(xs[1..],p), p); }
// 1 + multiset(filter(xs[1..], p))[x];
// ==
// multiset{xs[0]}[x] + multiset(filter(xs[1..],p))[x];
// ==
// multiset(fxs)[x];
// }
// } else{
// assert multiset(xs[1..])[x] == 0;
// assert multiset(filter(xs[1..], p))[x] == 0;
// }
// assert multiset(xs)[xs[0]] == multiset(fxs)[xs[0]];
// } else if xs != [] && x != xs[0] {
// assert xs[0] == fxs[0];
// } else{
// }
}
}
Proving both lemma need appeal to induction. See the code snippet below, I have n't proved first post condition in second lemma but it should be doable using induction too.
function filter<T>(s: seq<T>, p: T -> bool) : seq<T>
{
if s == [] then []
else if p(s[0]) then [s[0]] + filter(s[1..], p)
else filter(s[1..], p)
}
lemma filterSplit<T>(s: seq<T>, p: T -> bool, idx: nat)
requires 0 <= idx <= |s|
ensures filter(s, p) == filter(s[..idx], p) + filter(s[idx..], p)
{
if idx == 0 {
}
else {
filterSplit(s[1..], p, idx-1);
assert filter(s[1..], p) == filter(s[1..][..(idx-1)], p) + filter(s[1..][(idx-1)..], p);
if p(s[0]) {
calc {
filter(s, p);
[s[0]] + filter(s[1..], p);
[s[0]] + filter(s[1..][..(idx-1)], p) + filter(s[1..][(idx-1)..], p);
{
assert s[..idx] == [s[0]] + s[1..idx];
assert s[1..idx] == s[1..][..(idx-1)];
}
filter(s[..idx], p) + filter(s[1..][(idx-1)..], p);
{
assert s[1..][(idx-1)..] == s[idx..];
}
filter(s[..idx], p) + filter(s[idx..], p);
}
}
else {}
}
}
lemma filterMultiSet<T>(s: seq<T>, p: T -> bool)
ensures multiset(filter(s, p)) <= multiset(s)
{
if s == [] {
}
else {
filterMultiSet(s[1..], p);
calc <= {
multiset(filter(s, p));
multiset([s[0]]) + multiset(filter(s[1..], p));
multiset([s[0]]) + multiset(s[1..]);
{
assert s == [s[0]] + s[1..];
}
multiset(s);
}
}
}
Update : See code snippet below for first postcondition of second lemma
function filter<T>(s: seq<T>, p: T -> bool) : seq<T>
ensures forall x :: x !in s ==> x !in filter(s, p)
{
if s == [] then []
else if p(s[0]) then [s[0]] + filter(s[1..], p)
else filter(s[1..], p)
}
lemma filterIncludeMultiSet<T>(s: seq<T>, p: T -> bool)
ensures forall x :: x in s && p(x) ==> multiset(s)[x] == multiset(filter(s, p))[x]
{
if s == [] {}
else {
var rs := s[1..];
filterIncludeMultiSet(rs, p);
assert forall x :: x in rs && p(x) ==> multiset(rs)[x] == multiset(filter(rs, p))[x];
forall x | x in s && p(x) ensures multiset(s)[x] == multiset(filter(s, p))[x] {
if x == s[0] {
if x in rs {
calc {
multiset(s)[x];
{
assert s == [s[0]] + rs;
assert multiset(s) == multiset([s[0]]) + multiset(rs);
}
multiset([s[0]])[x] + multiset(rs)[x];
1 + multiset(filter(rs, p))[x];
}
}
else {
calc {
multiset(s)[x];
{
assert s == [s[0]] + rs;
assert multiset(s) == multiset([s[0]]) + multiset(rs);
}
multiset([s[0]])[x] + multiset(rs)[x];
1;
}
calc {
multiset(filter(s, p))[x];
multiset([s[0]] + filter(rs, p))[x];
multiset([s[0]])[x] + multiset(filter(rs, p))[x];
1;
}
}
}
else {
calc {
multiset(s)[x];
{
assert s == [s[0]] + rs;
assert multiset(s) == multiset([s[0]]) + multiset(rs);
}
multiset([s[0]])[x] + multiset(rs)[x];
multiset(rs)[x];
multiset(filter(rs, p))[x];
}
}
}
}
I found another way to verify the filterLemmaSizes.
lemma filterLemmaSizes<T(!new)>(xs: seq<T>, fxs: seq<T>, p: (T) -> bool)
requires fxs == filter(xs, p)
ensures forall x: T :: x in xs && p(x) ==> multiset(xs)[x] == multiset(fxs)[x]
{
if xs == [] {
} else {
assert xs == [xs[0]] + xs[1..];
filterLemmaSizes(xs[1..], filter(xs[1..], p), p);
if p(xs[0]) {
calc {
multiset(fxs)[xs[0]];
==
multiset(filter(xs[..1], p))[xs[0]] + multiset(filter(xs[1..], p))[xs[0]];
==
multiset(filter([xs[0]], p))[xs[0]] + multiset(filter(xs[1..], p))[xs[0]];
==
multiset([xs[0]])[xs[0]] + multiset(filter(xs[1..], p))[xs[0]];
==
1 + multiset(filter(xs[1..], p))[xs[0]];
==
multiset{xs[0]}[xs[0]] + multiset(xs[1..])[xs[0]];
==
multiset(xs)[xs[0]];
}
} else{
assert xs[0] !in filter(xs, p);
}
}
}
I'm trying to prove a little lemma for a larger proof, the lemma definition is below:
lemma LoopLemma(a: seq<int>, b: seq<int>, c: seq<int>, k:int, i:int, j:int)
requires 0 <= i < |a| && 0<= j < |b| && 0 <= k < |c| && i +j ==k && |a| + |b| == |c|
requires Sorted(c[..k]) && Sorted(b) && Sorted(a)
requires multiset(c[..k]) == multiset(a[..i]+b[..j])
ensures Sorted(c[..k]+[b[j]]) && Sorted(c[..k]+[a[i]])
{
assert multiset(c[..k]) == multiset(a[..i]+b[..j]);
var q:=a[..i]+b[..j];
var c1 := c[..k];
assert Sorted(c1);
assert multiset(c1) == multiset(q);
assert |q| == i + j;
assert |c1| == k == i + j;
calc {
multiset(c1) == multiset(q);
==
forall l :: l in multiset(c1) ==> l in multiset(q);
== {assert forall l :: l in multiset(q) ==> exists r :: 0 <= r <|q| && l == q[r]; assert forall l :: l in multiset(c1) ==> exists r :: 0 <= r <|c1| && l == c1[r];}
forall l :: 0<=l <|c1| ==> exists r :: 0 <= r < |q| && q[r] == c1[l];
}
}
I get "the calculation step between the previous line and this line might not hold" for the last step, and I don't understand why.
All I'm saying there is that if the multisets of two sequences are equal, for any entry in the first sequence exists an entry in the second sequence with the same value.
I tried some simpler examples (where I define the sequences explicitly) and it worked. Maybe I don't understand something about multisets?
Any suggestions will help.
Additional hint that needed here is every element in sequence is in multiset i.e forall i :: 0 <= i < |c[..k]| ==> c[..k][i] in multiset(c[..k]) (hint in forward direction of reasoning). Following snippet verifies.
predicate Sorted(a: seq<int>)
{
if |a| <= 1 then true else (a[0] <= a[1]) && Sorted(a[1..])
}
lemma LoopLemma(a: seq<int>, b: seq<int>, c: seq<int>, k: int, i: int, j: int)
requires 0 <= i < |a| && 0 <= j < |b| && 0 <= k < |c| && i + j == k && |a| + |b| == |c|
requires Sorted(c[..k]) && Sorted(a) && Sorted(b)
requires multiset(c[..k]) == multiset(a[..i] + b[..j])
{
var s := a[..i] + b[..j];
calc {
multiset(c[..k]) == multiset(s);
forall e :: e in multiset(c[..k]) ==> e in multiset(s);
{
assert forall e :: e in multiset(c[..k]) ==>
exists r :: 0 <= r < |s| && s[r] == e;
// assert forall e :: e in multiset(c[..k]) ==>
// exists r :: 0 <= r < |c[..k]| && c[..k][r] == e;
assert forall i :: 0 <= i < |c[..k]| ==> c[..k][i] in multiset(c[..k]);
}
forall i :: 0 <= i < |c[..k]| ==> exists r :: 0 <= r < |s| && s[r] == c[..k][i];
}
}
Right, so I am trying to verify the following fill() method. Currently the first and third invariant clauses fail, and I'm not entirely surely why. Any thoughts appreciated!
class List {
var data : int;
var next : List?;
ghost var rep : set<List>;
constructor(d : int)
ensures this.valid();
{
this.data := d;
this.next := null;
this.rep := {this};
}
predicate valid()
reads this, rep;
decreases rep + {this};
{
this in rep
&& (next != null ==> (
next in rep
&& next.rep <= rep
&& this !in next.rep
&& next.valid()
))
}
}
method fill(ol : List, on : int)
requires ol.valid();
requires on >= 0;
modifies ol.rep;
{
assert ol in ol.rep;
var n := on;
var l : List? := ol;
//
//
while(n >= 0 && l != null)
invariant ol.valid();
invariant (l != null) ==> l.valid();
invariant (l != null) ==> (l in ol.rep);
modifies l.rep;
{
l.data := n;
l := l.next;
n := n - 1;
}
}
Here's one way to do it.
class List {
var data : int;
var next : List?;
ghost var rep : set<List>;
constructor(d : int)
ensures valid()
{
data := d;
next := null;
rep := {this};
}
predicate valid()
reads this, rep
decreases rep + {this}
{
&& this in rep
&& (next != null ==>
&& next in rep
&& next.rep <= rep
&& this !in next.rep
&& next.valid())
}
static twostate lemma valid_frame(a: List)
requires old(a.valid())
requires forall x | x in old(a.rep) :: unchanged(x`next)
requires forall x | x in old(a.rep) :: unchanged(x`rep)
decreases old(a.rep)
ensures a.valid()
{}
}
method fill(ol : List, on : int)
requires ol.valid()
requires on >= 0
modifies ol.rep
ensures ol.valid()
{
var n := on;
var l : List? := ol;
label L:
while(n >= 0 && l != null)
invariant l != null ==> l.valid()
invariant l != null ==> l.rep <= old(ol.rep)
modifies ol.rep`data
{
l.data := n;
l := l.next;
n := n - 1;
}
List.valid_frame#L(ol);
}
The basic idea of this proof is that the valid predicate only depends on the next and rep fields of List. Since fill only writes to the data field, it must preserve validity.
To implement the idea, we can use a twostate lemma in Dafny. The way to "pass" a particular old state to such a lemma uses a combination of the label feature and #.
Given the following axioms:
A>=0
forall n :: n>=0 && n<N1 ==> n < A
N1 >= A
We want to prove that N1==A using Dafny.
I have tried following Dafny program:
function N1(n: int,A: int):bool
requires A>=0 && n>=0
{
if n==0 && A<=n
then true else
if n>0
&& A<=n
&& forall k::
(if 0<=k && k<n
then A>k else true)
then true
else false
}
lemma Theorem(n: int,A: int)
requires A>=0 && n>=0 && N1(n,A)
ensures n==A;
{ }
But Dafny fails to prove that. Is there a way to N1==A from the given axioms?
Dafny can prove it just fine, but it needs a bit more help:
predicate P(n:int, N1:int)
{
n >= 0 && n < N1
}
lemma Lem(A:int, N1:int)
requires A>=0
requires forall n :: P(n, N1) ==> n < A
requires N1 >= A
ensures N1 == A
{
if(N1 > A)
{
assert A >= 0 && A < N1;
assert P(A, N1);
assert A < A;
assert false;
}
assert N1 <= A;
}
The proof proceeds by contradiction, and is quite standard. The only Dafny specific bit of the proof is that we have to give a name to the property that n >= 0 && n < N1. We give the property the name P by introducing it as a predicate. The requirement to introduce P comes from the interaction of Dafny with some details of how quantifier instantiation (trigger matching) works in the underlying SMT solver (Z3).
You may alternatively prefer to write the lemma this way:
lemma Lem(A:int, N1:int)
requires A>=0
requires forall n :: P(n, N1) ==> n < A
requires N1 >= A
ensures N1 == A
{
calc ==>
{
N1 > A;
{assert P(A, N1);}
A < A;
false;
}
assert N1 <= A;
}