array<T>, where
T is another type.
a.LengthExercise: Specify the first requirement of
Find: if the algorithm returns an index (i.e.
non-negative integer), then the key should be
present at that index.
Use the following signature for your method:
method Find(a: array<int>, key: int) returns (index: int)
Exercise: Implement Find in a way that satisfies your specification.
method Find(a: array<int>, key: int) returns (index: int)
ensures 0 <= index ==> index < a.Length && a[index] == key
{
// ...
}
forall k :: k < k + 1
forall k :: 0 <= k < a.length ==> 0 <= a[k]
exists k :: 0 <= k < a.length ==> 0 <= a[k]
Exercise: Use quantifiers to specify that the method
Find returns a negative number whenever the searched key is not
present in the array.
method Find(a: array<int>, key: int) returns (index: int)
ensures 0 <= index ==> index < a.Length && a[index] == key
{
// ...
}
predicate sorted(a: array<int>)
requires a != null
{
forall j, k :: 0 <= j < k < a.Length ==> a[j] <= a[k]
}
Write this predicate in Dafny. Try to explain the error message that appears.
predicate sorted(a: array<int>)
requires a != null
reads a
{
forall j, k ::
0 <= j < k < a.Length ==>
a[j] <= a[k]
}
modifies annotation. Example:
method m3(a: array<int>)
requires 1 <= a.Length
modifies a
{
a[0] := 42;
}Exercise: Write a verified implementation of binary search. Use the following signature:
method BinarySearch(a: array<int>, key: int)
returns (index: int)
requires a != null && sorted(a)
ensures ...
{
...
}
datatype Colour = Red | White | Blue
datatype Nat = Zero | Succ(n: Nat)
Zero, Succ(Zero),
Succ(Succ(Zero)), etc.Zero < Succ(Zero) < Succ(Succ(Zero))function add(n1: Nat, n2: Nat): Nat
{
match n1
case Zero => n2
case Succ(n) => Succ(add(n, n2))
}
lemma add_unit(n: Nat)
ensures add(n, Zero) == n
ensures add(Zero, n) == n
{}
lemma add_succ(n1: Nat, n2: Nat)
ensures Succ(add(n1,n2)) == add(n1, Succ(n2))
{}
{},
then it's an axiom (i.e., we assume it to
be true).
lemma add_commutative(n1: Nat, n2: Nat)
ensures add(n1, n2) == add(n2, n1)
{}
lemma {:induction n1} add_commutative(n1: Nat, n2: Nat)
ensures add(n1, n2) == add(n2, n1)
{
match n1
case Zero =>
calc {
add(Zero, n2);
== // def. add
n2;
== { add_unit(n2); }
add(n2, Zero);
}
case Succ(n) => // Inductive hypothesis: add(n, n2) == add(n2, n)
}
case Succ(n) => // Inductive hypothesis: add(n, n2) == add(n2, n)
calc {
add(n1, n2);
== // n1 == Succ(n)
add(Succ(n), n2);
== // def. add
Succ(add(n,n2));
== // IH: add(n, n2) == add(n2, n)
Succ(add(n2,n));
== { add_succ(n2, n); }
add(n2, Succ(n));
== // Succ(n) == n1
add(n2, n1);
}
datatype List = Nil | Cons (head: T, tail: List)
List, we prove:
lemma reverse_append<T>(l1: List<T>, l2: List<T>)
ensures reverse(append(l1, l2)) ==
append(reverse(l2), reverse(l1))
Nil
reverse(append(Nil, l2)) == append(reverse(l2), reverse(Nil))Cons(h,x)
reverse(append(Cons(h,x), l2)) ==
append(reverse(l2), reverse(Cons(h,x)))x
reverse(append(x, l2)) == append(reverse(l2), reverse(x))