// Revisiting examples from the previous lectures method ex1(input: int) returns (result: int) requires input > -1/2 requires input != 0 ensures result > 0 { result := (1 / input) + 2; } method ex2(input: int) returns (result: int) requires input > 5/2 ensures result > 0 { var x := input * 2; var y := x * 2 - 10; result := y / 2; } method ex3(input: int) returns (result: int) requires input > 5/2 ensures result >= 0 // ^^ this might seem surprising (instead of >) // the verifier knows that this is integer divison, so // (N>0)/(N>0) --> N >= 0 { var x := input * 2; // we can use assert to check what the verifier knows at each step // so we can trace the goal backwards like we did in class assert(x >= 5); var y := ex3_f(x); assert(y > 0); result := y / 2; assert(result >= 0); } method ex3_f(x: int) returns (result: int) requires x > 5 ensures result > 0 { result := x * 2 - 10; } method loop_ex1(input: int) returns (result: int) requires 0 <= input ensures result == input { var i := 0; // These are the two implications that capture the correctness of the loop // exactly from the while rule we saw in class assert (((0 <= i <= input) && (i >= input)) ==> i == input); assert (((0 <= i <= input) && (i < input)) ==> 0 <= i +1 <= input); while (i < input) invariant 0 <= i <= input { i := i + 1; } result := i; } method loop_ex2(input: int) returns (result: int) requires 0 <= input ensures result == input*input { var i := 0; var acc := 0; assert 0 <= i <= input && acc == i * input && i >= input ==> acc == input*input; assert 0 <= i <= input && acc == i * input && i < input ==> 0 <= i + 1 <= input && acc + input == (i + 1)*input; while (i < input) invariant 0 <= i <= input invariant acc == i * input { acc := acc + input; i := i + 1; } result := acc; } // New examples in the lecture function abs(x: int): int { if (x < 0) then -x else x } method Abs(x: int) returns (result: int) ensures result >= 0 // This is one way to write the spec //ensures x < 0 ==> result == -x //ensures x >= 0 ==> result == x // Can also use a dafny `function`, which only exists for verification ensures result == abs(x) { if (x < 0) { result := -x; } else { result := x; } } // Can also have `function method`s, which are both functions for verification // and methods function method smaller(n: nat, m: nat): (result: nat) ensures result <= n && result <= m ensures result == n || result == m { if (n < m) then n else m } Remember the WP rule for loops, it will help design the loop and invariant: // {pre-body} body {I} // --------------------------------------------------------------------- // {I ∧ (I ∧ ¬ C ⇒ goal) ∧ (I ∧ C ⇒ pre-body)} while (C) {I} body {goal} // gcd with weak spec method some_CD(n: nat, m: nat) returns (result: nat) requires n > 0 requires m > 0 ensures 0 < result <= n; ensures 0 < result <= m; ensures n % result == 0 && m % result == 0; { var i := smaller(n, m); // Picking a good loop condition and invariant: // you want the first assertion here, which we derived from the loop rule, to be clearly true. // IOW, the condition being false and the invariant being true should pretty directly give the goal. assert (1 <= i <= smaller(n, m)) && ! (i > 1 && (n % i != 0 || m % i != 0)) ==> (n % i == 0 && m % i == 0); assert (1 <= i <= smaller(n, m)) && (i > 1 && (n % i != 0 || m % i != 0)) ==> (1 <= i - 1 <= smaller(n, m)); while (i > 1 && (n % i != 0 || m % i != 0)) invariant 1 <= i <= smaller(n, m); { i := i - 1; } assert (n % i == 0 && m % i == 0); result := i; } method GCD(n: nat, m: nat) returns (result: nat) requires n > 0 requires m > 0 ensures 0 < result <= n; ensures 0 < result <= m; ensures n % result == 0 && m % result == 0; ensures forall i : nat | result < i <= smaller(n, m) :: n % i != 0 || m % i != 0; { var i := smaller(n, m); assert (1 <= i <= smaller(n, m)) && (forall p : nat | i+1 <= p <= smaller(n, m) :: n % p != 0 || m % p != 0) && ! (i > 1 && (n % i != 0 || m % i != 0)) ==> (n % i == 0 && m % i == 0) && (forall p : nat | i < p <= smaller(n, m) :: n % p != 0 || m % p != 0); assert (1 <= i <= smaller(n, m)) && (forall p : nat | i+1 <= p <= smaller(n, m) :: n % p != 0 || m % p != 0) && (i > 1 && (n % i != 0 || m % i != 0)) ==> (1 <= i - 1 <= smaller(n, m)) && (forall p : nat | i <= p <= smaller(n, m) :: n % p != 0 || m % p != 0); while (i > 1 && (n % i != 0 || m % i != 0)) invariant 1 <= i <= smaller(n, m) // again the invariant matches the goal, modulo the body's update invariant forall p : nat | i+1 <= p <= smaller(n, m) :: n % p != 0 || m % p != 0 { i := i - 1; } assert (n % i == 0 && m % i == 0); assert forall p : nat | i < p <= smaller(n, m) :: n % p != 0 || m % p != 0; result := i; } // You need a Main method with this signature to run the program method Main() { // Verify, compile, and run your program with: // /path/to/dafny /compile:3 my-program.dfy // You can skip verification with: // /path/to/dafny /compile:4 my-program.dfy // some static tests with assert // assert checks that the verifier can prove a proposition var ex1 := Abs(5); print "ex1 is ", ex1, "\n"; assert (ex1 == 5); var ex2 := Abs(-5); assert (ex2 == 5); var ex3 := Abs(0); assert (ex3 == 0); var fib1 := Fib(0); var fib2 := Fib(2); var fib5 := Fib(5); assert fib1 == 1; assert fib2 == 2; assert fib5 == 8; // some unit tests with expect // expect inserts a dynamic check of a proposition, and then lets the verifier assume it is true var ex4 := Abs(-500); expect ex4 == 500; var fib6 := Fib(6); expect fib6 == 13; }