Multiset proof verification in dafny - dafny

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];
}
}

Related

Dafny assertion passes but lemma fails

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.

Why is my Dafny assertion failing on both x == y and x != y?

I'm following the tutorials here and the code seems correct but when I test using assertions I get an error!
Running the program prints the correct answer, but the assertions seem to be paradoxical. When a show the counter examples it seems that -1 is considered even though it shouldn't be.
method binarySearch(a:array<int>, key:int) returns (r:int)
requires forall i,j :: 0 <= i <= j < a.Length ==> a[i] <= a[j]
ensures 0 <= r ==> r < a.Length && a[r] == key
ensures r < 0 ==> forall i :: 0 <= i < a.Length ==> a[i] != key
{
var lo, hi := 0, a.Length;
while (lo < hi)
invariant 0 <= lo <= hi <= a.Length
invariant forall i :: 0 <= i < lo ==> a[i] < key
invariant forall i :: hi <= i < a.Length ==> a[i] > key
decreases hi - lo;
{
var mid := (lo + hi) / 2;
if key < a[mid]
{
hi := mid;
}
else if key > a[mid]
{
lo := mid + 1;
}
else
{
return mid;
}
}
return -1;
}
// tests
method Main()
{
var a := new int[6][1,2,3,4,5,6];
var r := binarySearch(a, 5);
assert r == 4; // fails
assert r != 4; // also fails
}
Is this a bug or am I missing something?
Dafny uses post-condition of method to reason about result of method call.
Here post-condition is
If r is between 0 to array length, element at r is equal to key
If r is less than 0, it is not in array.
Dafny doesn't know which of these is vacuous, but you can hint it.
Guarding assert r == 4 with if r >= 0 && r < a.Length will make it verify.
Alternatively after adding assert a[4] == 5 before assert r == 4, verification will go through.
Reason for strange error is after call to binary search, these are facts known to dafny
assert (r < 0) || (0 <= r < 6)
assert (r < 0) ==> forall i :: 0 <= i < a.Length ==> a[i] != 5
assert (0 <= r < 6) ==> a[r] == 5
Using these it can neither prove r == 4 nor r != 4. Dafny doesn't seem to propagate information like assert a[0] == 1 etc by default to prover, you have to explicitly ask for it.

Dafny - Loop invariant for nested loops

I am trying to create a Dafny program that returns true if and only if, A contains no duplicates.
This is what I have so far, however the invariant invariant r <==> (forall j :: 0 <= j < i && j != i ==> A[j] != A[i]); says that it will not hold on entry.
Any advice on what I am doing wrong?
`method CheckArr1(A: array<int>) returns (r: bool)
requires A.Length > 0
ensures r <==> (forall i, j :: 0 <= i < A.Length && 0 <= j < A.Length && i != j ==> A[i] != A[j]);
{
var i := 0;
r := true;
while i < A.Length
decreases A.Length - i;
invariant i <= A.Length;
invariant r <==> (forall x, y :: 0 <= x < i && 0 <= y < i && x != y ==> A[x] != A[y]);
{
var j := 0;
while j < i
decreases i - j;
invariant j <= i;
invariant r <==> (forall j :: 0 <= j < i && j != i ==> A[j] != A[i]);
{
r := (r && (A[j] != A[i]));
j := j + 1;
}
i := i + 1;
}
}`
The "invariant doesn't hold on entry" error is for the declared invariant
r <==> (forall j :: 0 <= j < i && j != i ==> A[j] != A[i])
of the inner loop. On entry to the that loop, j is 0, so the condition that needs to hold on entry to the inner loop is
r <==> (0 <= 0 < i && 0 != i ==> A[0] != A[i])
which we can simplify to
r <==> (0 < i ==> A[0] != A[i]) // (*)
There is no reason to believe that r will hold this value on entry to the inner loop. All you know inside the body of the outer loop is that
r <==> (forall x, y :: 0 <= x < i && 0 <= y < i && x != y ==> A[x] != A[y]) // (**)
which says that r tells you whether or not there are any duplicates within the first i elements. Condition (*) says something about a[i], whereas (**) does not say anything about a[i].
From your current program, it would be easier if you changed the inner loop to use a different variable, say s, to achieve the invariant you have given. That is, use the invariant
s <==> (forall j :: 0 <= j < i ==> A[j] != A[i])
Then, after the inner loop, update r using the value you computed for s.

What invariant do I miss in the BubbleSort proof?

I think I may need additional invariants to convince Dafny the code works.
I tried a few but failed to pass.
method BubbleSort(arr: array<int>)
ensures forall k, k' :: 0 <= k < k' < arr.Length ==> arr[k] <= arr[k']
modifies arr
{
var i := arr.Length;
while i > 0
invariant 0 <= i <= arr.Length
// Violating the invariant next line
invariant forall k, k' :: i <= k < k' < arr.Length ==> arr[k] <= arr[k']
decreases i
{
var j := 0;
while j < i - 1
invariant 0 <= j < i
invariant forall k :: 0 <= k < j ==> arr[j] >= arr[k]
decreases i - j
{
if arr[j] > arr[j+1] {
arr[j], arr[j+1] := arr[j+1], arr[j];
}
j := j + 1;
}
i := i - 1;
}
}
The invariant sorted(a , i , a . Length -1) has to be maintained when i is decreased. The invariant partioned(a, i) guarantees this, since it implies a[i-1] <= a[i]. The reason that it is stronger than this is that otherwise its invariance could not be proven.
Note: partitioned(a, i) says that a[k] <= a[l] for all k <= i and i < l .
I found this example of a dafny verified bubble sort among these notes.
https://www.cs.cmu.edu/~mfredrik/15414/lectures/17-notes.pdf
predicate sorted ( a : array <int > , l : int , u : int)
reads a
{
forall i , j :: 0 <= l <= i <= j <= u < a . Length ==> a [ i ] <= a [ j ]
}
predicate partitioned ( a : array <int > , i : int)
reads a
{
forall k , k' :: 0 <= k <= i < k' < a . Length ==> a [ k ] <= a [k']
}
method BubbleSort(a: array<int>) returns (b: array<int>)
requires a.Length!=0
modifies a
ensures sorted(a,0,a.Length-1)
{
var i:=0;
var j:=0;
var temp:=0;
var n:=a.Length;
i:=n-1;
b:=a;
while i>0
invariant i<0 ==> a.Length==0
invariant -1<=i<n
invariant sorted (a , i , a . Length -1)
invariant partitioned(a,i)
{
j:=0;
while j<i
invariant 0<=j<=i
invariant 0<=i<n
invariant sorted(a , i , a . Length -1)
invariant forall k :: 0 <= k <j ==> a[j] >= a[k]
invariant partitioned(a,i)
{ if a[j]>a[j+1]
{
temp:=a[j];
a[j]:=a[j+1];
a[j+1]:=temp;
}
j:=j+1;
}
i:=i-1;
}
b:=a;
}

What to do about "Verification inconclusive" errors

I have a method that results in an error "verificaton inconclusive". It's not clear why the verification is inconclusive. It doesn't seem to be a time out and there is no indication of what verification conditions can't be proved. In short: what does this mean?
I'm using version 2.0.0. I don't recall seeing this message in version 1.9.7.
The particular method where I have the problem is.
function c( n : int, r : int ) : int
requires 0 <= r <= n
{
if( r==0 ) then 1
else if( r==n ) then 1
else c(n-1, r-1) + c( n-1, r )
}
method combinations1Row( m : array2<int>, i : int )
requires m != null
requires m.Length0 == m.Length1
requires var N := m.Length0 ; 0 <= i < N ;
requires forall n,r : int :: 0 <= r <= n < i ==> m[n,r] == c(n,r)
modifies m
ensures forall n,r : int :: 0 <= r <= n <= i ==> m[n,r] == c(n,r)
{
var N := m.Length0 ;
var j := 0 ;
while( j <= i )
invariant 0 <= j <= i+1
invariant forall n,r : int :: 0 <= r <= n < i ==> m[n,r] == c(n,r)
invariant forall r : int :: 0 <= r < j ==> m[i,r] == c(i,r)
{
if( j==0 ) { m[i,j] := 1 ; }
else if( j==i ) { m[i,j] := 1 ; }
else { m[i,j] := m[i-1,j-1] + m[i-1,j] ; }
assert m[i,j] == c(i,j) ;
assert forall r : int :: 0 <= r <= j ==> m[i,r] == c(i,r) ;
j := j+1 ;
}
assert j==i+1 ;
}

Resources