2022-11-21 13:47:52 +00:00
|
|
|
// Dafny coursework tasks
|
|
|
|
// Autumn term, 2022
|
|
|
|
//
|
|
|
|
// Authors: John Wickerson
|
|
|
|
|
|
|
|
method countsquares(n:nat) returns (result:nat)
|
2022-11-21 13:50:18 +00:00
|
|
|
ensures result == (n * (n + 1) * (2 * n + 1)) / 6;
|
2022-11-21 13:47:52 +00:00
|
|
|
{
|
|
|
|
var i := 0;
|
|
|
|
result := 0;
|
2022-11-21 13:50:18 +00:00
|
|
|
while i < n
|
|
|
|
invariant 0 <= i <= n;
|
|
|
|
decreases n - i;
|
|
|
|
invariant result == (i * (i + 1) * (2 * i + 1)) / 6;
|
|
|
|
{
|
2022-11-21 13:47:52 +00:00
|
|
|
i := i + 1;
|
|
|
|
result := result + i * i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
method countsquares2(n:nat) returns (result:nat)
|
2022-11-21 13:50:18 +00:00
|
|
|
ensures result == (n * (n + 1) * (2 * n + 1)) / 6;
|
2022-11-21 13:47:52 +00:00
|
|
|
{
|
|
|
|
var i := n;
|
|
|
|
result := 0;
|
2022-11-21 13:50:18 +00:00
|
|
|
while i > 0
|
|
|
|
invariant 0 <= i <= n;
|
|
|
|
decreases i;
|
|
|
|
invariant result == ((n * (n + 1) * (2 * n + 1)) / 6) - ((i * (i + 1) * (2 * i + 1)) / 6);
|
|
|
|
{
|
2022-11-21 13:47:52 +00:00
|
|
|
result := result + i * i;
|
|
|
|
i := i - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-16 14:01:53 +00:00
|
|
|
// countsquares was easier to verify than countsquares2 as the loop invariant
|
|
|
|
// was the same as the post-condition of the function, as the value of result
|
|
|
|
// after each loop iteration is simply the result of the function call with a
|
|
|
|
// smaller input value n.
|
|
|
|
|
2022-11-21 13:47:52 +00:00
|
|
|
predicate sorted(A:array<int>)
|
2022-11-21 13:51:44 +00:00
|
|
|
reads A;
|
2022-11-21 13:47:52 +00:00
|
|
|
{
|
2022-11-21 13:51:44 +00:00
|
|
|
forall m,n :: 0 <= m < n < A.Length ==> A[m] <= A[n]
|
2022-11-21 13:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
method binarysearch_between(A:array<int>, v:int, lo:int, hi:int) returns (result:bool)
|
2022-11-21 13:51:44 +00:00
|
|
|
requires sorted(A);
|
|
|
|
requires 0 <= lo <= hi <= A.Length;
|
|
|
|
decreases hi - lo;
|
|
|
|
ensures (exists j :: lo <= j < hi && A[j] == v) <==> result;
|
2022-11-21 13:47:52 +00:00
|
|
|
{
|
|
|
|
if lo == hi {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
var mid:int := (lo + hi) / 2;
|
|
|
|
if v == A[mid] {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if v < A[mid] {
|
|
|
|
result := binarysearch_between(A, v, lo, mid);
|
|
|
|
}
|
|
|
|
if v > A[mid] {
|
|
|
|
result := binarysearch_between(A, v, mid+1, hi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
method binarysearch(A:array<int>, v:int) returns (result:bool)
|
2022-11-21 13:51:44 +00:00
|
|
|
requires sorted(A);
|
|
|
|
ensures (exists j :: 0 <= j < A.Length && A[j] == v) <==> result;
|
2022-11-21 13:47:52 +00:00
|
|
|
{
|
2022-11-21 13:51:44 +00:00
|
|
|
result := binarysearch_between(A, v, 0, A.Length); // call with lo and hi to cover full array
|
2022-11-21 13:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
method binarysearch_iter(A:array<int>, v:int) returns (result:bool)
|
2022-11-21 13:51:44 +00:00
|
|
|
requires sorted(A);
|
|
|
|
ensures (exists j :: 0 <= j < A.Length && A[j] == v) <==> result;
|
2022-11-21 13:47:52 +00:00
|
|
|
{
|
2022-11-21 13:51:44 +00:00
|
|
|
result := false;
|
|
|
|
var lo := 0;
|
|
|
|
var hi := A.Length;
|
|
|
|
while lo < hi
|
|
|
|
invariant 0 <= lo <= hi <= A.Length;
|
2022-11-21 18:33:48 +00:00
|
|
|
invariant forall j :: (0 <= j < lo || hi <= j < A.Length) ==> A[j] != v;
|
2022-11-21 13:51:44 +00:00
|
|
|
decreases hi - lo;
|
|
|
|
{
|
|
|
|
var mid := (lo + hi) / 2;
|
|
|
|
if A[mid] > v {
|
|
|
|
hi := mid;
|
|
|
|
} else if A[mid] < v {
|
|
|
|
lo := mid + 1;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2022-11-21 13:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
method partition(A:array<int>, lo:int, hi:int) returns (pivot:int)
|
2022-11-21 18:33:48 +00:00
|
|
|
requires 0 <= lo < hi <= A.Length;
|
|
|
|
ensures 0 <= lo <= pivot < hi <= A.Length;
|
2022-11-28 10:26:36 +00:00
|
|
|
requires hi < A.Length ==> forall k :: lo <= k < hi ==> A[k] < A[hi];
|
|
|
|
ensures hi < A.Length ==> forall k :: lo <= k < hi ==> A[k] < A[hi];
|
|
|
|
requires 0 < lo ==> forall k :: lo <= k < hi ==> A[lo-1] <= A[k];
|
|
|
|
ensures 0 < lo ==> forall k :: lo <= k < hi ==> A[lo-1] <= A[k];
|
2022-11-21 18:33:48 +00:00
|
|
|
ensures forall k :: (0 <= k < lo || hi <= k < A.Length) ==> old(A[k]) == A[k];
|
2022-11-28 10:26:36 +00:00
|
|
|
ensures forall k :: lo <= k < pivot ==> A[k] < A[pivot];
|
|
|
|
ensures forall k :: pivot < k < hi ==> A[pivot] <= A[k];
|
2022-11-21 18:33:48 +00:00
|
|
|
modifies A;
|
2022-11-21 13:47:52 +00:00
|
|
|
{
|
|
|
|
pivot := lo;
|
|
|
|
var i := lo+1;
|
|
|
|
while i < hi
|
2022-11-28 10:26:36 +00:00
|
|
|
invariant 0 <= lo <= pivot < i <= hi;
|
|
|
|
invariant forall k :: (0 <= k < lo || hi <= k < A.Length) ==> old(A[k]) == A[k];
|
|
|
|
invariant forall k :: (lo <= k < pivot) ==> A[k] < A[pivot];
|
|
|
|
invariant forall k :: (pivot < k < i) ==> A[pivot] <= A[k];
|
|
|
|
invariant hi < A.Length ==> forall k :: lo <= k < hi ==> A[k] < A[hi];
|
|
|
|
invariant 0 < lo ==> forall k :: lo <= k < hi ==> A[lo-1] <= A[k];
|
2022-11-21 13:47:52 +00:00
|
|
|
{
|
|
|
|
if A[i] < A[pivot] {
|
|
|
|
var j := i-1;
|
|
|
|
var tmp := A[i];
|
|
|
|
A[i] := A[j];
|
|
|
|
while pivot < j
|
2022-11-28 10:26:36 +00:00
|
|
|
invariant forall k :: (0 <= k < lo || hi <= k < A.Length) ==> old(A[k]) == A[k];
|
|
|
|
invariant forall k :: (pivot < k <= i) ==> A[pivot] <= A[k];
|
|
|
|
invariant forall k :: (lo <= k < pivot) ==> A[k] < A[pivot];
|
|
|
|
invariant A[pivot] > tmp;
|
|
|
|
invariant hi < A.Length ==> forall k :: lo <= k < hi ==> A[k] < A[hi];
|
|
|
|
invariant 0 < lo ==> forall k :: lo <= k < hi ==> A[lo-1] <= A[k];
|
2022-11-21 13:47:52 +00:00
|
|
|
{
|
|
|
|
A[j+1] := A[j];
|
|
|
|
j := j-1;
|
|
|
|
}
|
|
|
|
A[pivot+1] := A[pivot];
|
|
|
|
A[pivot] := tmp;
|
|
|
|
pivot := pivot+1;
|
|
|
|
}
|
|
|
|
i := i+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-28 10:26:36 +00:00
|
|
|
predicate sorted_between(A: array<int>, lo: int, hi: int)
|
|
|
|
reads A;
|
|
|
|
requires 0 <= lo <= hi <= A.Length;
|
2022-11-21 18:33:48 +00:00
|
|
|
{
|
2022-11-28 10:26:36 +00:00
|
|
|
forall m, n :: lo <= m < n < hi ==> A[m] <= A[n]
|
2022-11-21 18:33:48 +00:00
|
|
|
}
|
|
|
|
|
2022-11-21 13:47:52 +00:00
|
|
|
method quicksort_between(A:array<int>, lo:int, hi:int)
|
2022-11-21 18:33:48 +00:00
|
|
|
requires 0 <= lo <= hi <= A.Length;
|
2022-11-28 10:26:36 +00:00
|
|
|
requires hi < A.Length ==> forall k :: lo <= k < hi ==> A[k] < A[hi];
|
|
|
|
ensures hi < A.Length ==> forall k :: lo <= k < hi ==> A[k] < A[hi];
|
|
|
|
requires 0 < lo ==> forall k :: lo <= k < hi ==> A[lo-1] <= A[k];
|
|
|
|
ensures 0 < lo ==> forall k :: lo <= k < hi ==> A[lo-1] <= A[k];
|
2022-11-21 18:33:48 +00:00
|
|
|
ensures forall k :: (0 <= k < lo || hi <= k < A.Length) ==> old(A[k]) == A[k];
|
|
|
|
// old(A[k]) evaluates to the value of A[k] on entry to the method, so this
|
|
|
|
// checkes that only values in A[lo..hi] can be modified by this method
|
2022-11-28 10:26:36 +00:00
|
|
|
ensures sorted_between(A, lo, hi);
|
2022-11-21 18:33:48 +00:00
|
|
|
modifies A;
|
|
|
|
decreases hi - lo;
|
2022-11-21 13:47:52 +00:00
|
|
|
{
|
|
|
|
if lo+1 >= hi { return; }
|
|
|
|
var pivot := partition(A, lo, hi);
|
|
|
|
quicksort_between(A, lo, pivot);
|
|
|
|
quicksort_between(A, pivot+1, hi);
|
|
|
|
}
|
|
|
|
|
|
|
|
method quicksort(A:array<int>)
|
2022-11-21 18:33:48 +00:00
|
|
|
modifies A;
|
2022-11-28 10:26:36 +00:00
|
|
|
ensures sorted(A);
|
2022-11-21 13:47:52 +00:00
|
|
|
{
|
|
|
|
quicksort_between(A, 0, A.Length);
|
|
|
|
}
|
|
|
|
|
|
|
|
method Main() {
|
2022-11-28 10:26:36 +00:00
|
|
|
var A:array<int> := new int[7] [4,0,1,9,7,1,2];
|
|
|
|
print "Before: ", A[0], A[1], A[2], A[3], A[4], A[5], A[6], "\n";
|
2022-11-21 13:47:52 +00:00
|
|
|
quicksort(A);
|
2022-11-28 10:26:36 +00:00
|
|
|
print "After: ", A[0], A[1], A[2], A[3], A[4], A[5], A[6], "\n";
|
2022-11-21 13:47:52 +00:00
|
|
|
}
|