### Induction, Recursion, Iteration

#### From Specification to Implementation

Let’s review the material from last week, linking induction, recursion and iteration.

We have developed a correct implementation in three steps.

1. Describe the mathematical concepts necessary to express required program properties
2. Create a (recursive) specification that is easy to understand (and validate)
3. Implement an efficient solution for the specification

We document clearly what is implemented by specifying it in mathematical terms. We document clearly why the implementation is correct by supplying a proof. Instead of a proof we also accept other evidence of correctness such as successful tests.

Today we make preparations for systematic testing of loops and recursive functions.

But first let’s refresh our memory of induction, recursion and iteration.

#### Example: Multiplication by Repeated Addition

We can express multiplication of two natural numbers by repeated addition. `m * n = (n + n + ... + n)` <- `n` times The repeated addition on the right-hand side can be expressed recursively.

``````0 * n = 0
m' n = m * n + n
``````

Using the recursive definition of multiplication we can calculate:

``````3 * 1
= 2 * 1 + 1
= 1 * 1 + 1 + 1
= 0 * 1 + 1 + 1 + 1
= 0 + 1 + 1 + 1
``````

Let’s specify it in Slang

#### Multiplication by Repeated Addition in Slang

We specify `mult_spec` using the inductive definition of the natural numbers.

 ``````1 2 3 4 `````` ``````@strictpure def mult_spec(m: Z, n: Z): Z = m match { case 0 => 0 case k => mult_spec(k - 1, n) + n } ``````

where `k - 1` denotes the predecessor of natural number `k`.

Induction rules for `mult_spec`:

Base case (`m == 0`):

 ``````1 2 3 4 5 `````` ``````@pure def mult_spec_0(n: Z) { Contract( Ensures(mult_spec(0, n) == 0) ) } ``````

Inductive case (`m > 0`):

 ``````1 2 3 4 5 6 `````` ``````@pure def mult_spec_step(m: Z, n: Z) { Contract( Requires(m > 0), Ensures(mult_spec(m, n) == mult_spec(m - 1, n) + n) ) } ``````

Logika applies these rules automatically.

#### Program Specification

We can write a specification for a multiplication function:

 `````` 1 2 3 4 5 6 7 8 9 10 11 `````` ``````@pure def mult_rec(m: Z, n: Z): Z = { Contract( Requires(m >= 0), Ensures(Res == mult_spec(m, n)) ) if (m == 0) { return 0 } else { return mult_rec(m - 1, n) + n } } ``````

Of course, in this simple example the structure of the recursive specification resembles closely that of the mathematical definition. As a consequence, Logika proves the post-condition fully-automatically.

#### Program Implementation

We can implement the program using a while loop.

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 `````` ``````def mult_it(m: Z, n: Z): Z = { Contract( Requires(m >= 0), Ensures(Res == mult_rec(m, n)) ) var i: Z = m var k: Z = 0 while (i > 0) { Invariant( ... ) ... } return k } ``````

where variables `i` and `k` are modified until `k` contains the product.

#### Exercise 1

1. Implement function `mult_it`
2. Formulate an invariant
• Hint: Use backward conjecture to find a candidate for the invariant
3. Insert deductions that document why the program is correct
4. Prove and document that the function terminates
 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 `````` ``````def mult_it(m: Z, n: Z): Z = { Contract( Requires(m >= 0), Ensures(Res == mult_rec(m, n)) ) var i: Z = m var k: Z = 0 while (i > 0) { Invariant( ... ) ... } return k } ``````

### Recursion Unfolding

#### Example: Counting Down Recursively

We can specify counting down recursively as follows.

 ``````1 2 3 4 5 `````` ``````cd(k) = if k == 0 k else cd(k-1) ``````

We can calculate `cd(2)` observing the value of the parameter `k` at each invocation.

 ``````1 2 3 4 5 6 7 `````` ``````cd(2) { k == 2 and k != 0 } = cd(2 - 1) { k == 2 - 1 and k != 0} = cd(2 - 1 - 1) { k == 2 - 1 - 1 and k == 0 } = 0 ``````

Let’s rename `k` at each invocation to clarify what’s going on.

We rename `k` into `k0, k1, k2, ...` counting upwards.

 ``````1 2 3 4 5 6 7 `````` ``````cd(2) { k0 == 2 and k0 !=0 } = cd(2 - 1) { k1 == 2 - 1 and k1 != 0 } = cd(2 - 1 - 1 - 1) { k2 == 2 - 1 - 1 and k2 == 0 } = 0 ``````

Now, let’s replace sub-expressions by the names of the parameters holding those values.

Using `k0, k1, k2` we get:

 ``````1 2 3 4 5 6 7 `````` ``````cd(k0) { k0 == 2 and k0 != 0 } = cd(k0 - 1) { k1 == k0 - 1 and k1 != 0 } = cd(k1 -1) { k2 == k1 - 1 and k2 == 0 } = k2 ``````

Only focusing on the value of the parameter and ignoring the initial value `2`, we observe:

 ``````1 2 3 `````` ``````k0 != 0 k1 == k0 - 1 and k1 != 0 k2 == k1 - 1 and k2 == 0 ``````

#### Recursively Unfolding Counting Down

The observation

 ``````1 2 3 `````` ``````k0 != 0 k1 == k0 - 1 and k1 != 0 k2 == k1 - 1 and k2 == 0 ``````

describes the computation starting with the call `cd(2)` in terms of the parameter values. Note, the final `k2 == 0` which determines that the first branch is chosen and `k2` is returned. We can read the function definition as an equation.

`cd(k) == if(k == 0) k else cd(k - 1)`, (FP1)

Using lambda notation,

`cd == λk * if(k == 0) k else cd(k - 1)`, (FP2)

Theses two equations are called a fix-point equations. Replacing the left-hand side by the right-hand side in either (FP1) or (FP2) is called unfolding. Let’s consider (FP2) first and then apply what we’ve learned to (FP1).

#### Recursively Unfolding Lambda Using (FP2)

Unfolding is a calculation that the function itself as a value.

``````cd
= λk · if (k == 0) k else cd(k − 1)
= λk · if (k == 0) k else (λk · if (k == 0) k else cd(k − 1))(k − 1)
= λk · if (k == 0) k else (λk · if (k == 0) k else (λk · if (k == 0) k else cd(k − 1))(k − 1))(k − 1)
``````
• Let’s colour the different k’s bound by the lambdas

`cd2 = λk · if (k == 0) k else (λk · if (k == 0) k else (λk · if (k == 0) k else cd(k − 1))(k − 1))(k − 1) `

• Let’s call this function cd2
• Now let `k0, k1 == k0 − 1, k2 == k1 − 1` be given, and calculate
``````cd2(k0)
= if (k0 == 0) k0 else (λk · if (k == 0) k else (λk · if (k == 0) k else cd(k − 1))(k − 1))(k0 − 1)
= if (k0 == 0) k0 else (λk · if (k == 0) k else (λk · if (k == 0) k else cd(k − 1))(k − 1))(k1)
= if (k0 == 0) k0 else if (k1 == 0) k1 else (λk · if (k == 0) k else cd(k − 1))(k1 − 1)
= if (k0 == 0) k0 else if (k1 == 0) k1 else (λk · if (k == 0) k else cd(k − 1))(k2)
= if (k0 == 0) k0 else if (k1 == 0) k1 else if (k2 == 0) k2 else cd(k2 − 1)
``````
• Let’s compare this to our initial observation for the computation of cd(2)

#### Recursive Unfolding Vs Direct Calculation

Given `k0, k1 == k0 − 1, k2 == k1 − 1`, we have
`if (k0 == 0) k0 else if (k1 == 0) k1 else if (k2 == 0) k2 else cd(k2 − 1) (1)`
The observation

``````k0 != 0
k1 == k0 − 1 and k1 != 0
k2 == k1 − 1 and k2 == 0
``````

describes the situation where expression (1) returns `k2`
This is the case when `k0 == 2`
In other words, when `cd(2)` is called
Next let’s consider the fix-point equation `cd(k) == if (k == 0) k else cd(k − 1)`
We begin by unfolding it

#### Unfolding with Parameters using (FP1)

Using `cd(k) == if (k == 0) k else cd(k − 1)`, we calculate

``````cd(k0)
= if (k0 == 0) k0 else cd(k0 − 1)
``````
• Letting k1 == k0 − 1
``````= if (k0 == 0) k0 else cd(k1)
= if (k0 == 0) k0 else if (k1 == 0) k1 else cd(k1 − 1)
``````
• Letting k2 == k1 − 1
``````= if (k0 == 0) k0 else if (k1 == 0) k1 else cd(k2)
= if (k0 == 0) k0 else if (k1 == 0) k1 else if (k2 == 0) k2 else cd(k2 − 1)
``````

Fix-point equation version (FP2) describes a function as its solution
This function can be used to observe computations via unfolding
Fix-point equation version (FP1) can be used directly for unfolding and observation
It hides the steps involving lambda abstraction and application
To keep track of consecutive parameter values we introduce new variables at each call

#### Unfolded Recursive Programs as Facts

Let’s state the expression `if (k0 == 0) k0 else if (k1 == 0) k1 else if (k2 == 0) k2 else cd(k2 − 1)` as a statement where the result value is assigned to a variable Res

``````if (k0 == 0)
Res = k0        (k0 == 0 => Res == k0) &                                call cd(0)
else            (k0 != 0 => k1 == k0 − 1) &
if (k1 == 0)
Res = k1        (k0 != 0 & k1 == 0 => Res == k1) &                      call cd(1)
else            (k0 != 0 & k1 != 0 => k2 == k1 − 1) &
if (k2 == 0)
Res = k2        (k0 != 0 & k1 != 0 & k2 == 0 => Res = k2)
else            &
Res = cd(k2 − 1)(k0 != 0 & k1 != 0 & k2 != 0 => Res == cd(k2 − 1))
``````

Within the fact for the unfolded function we also discover our original observation for `cd(2)` The two shorter cases deal with the calls `cd(0)` and `cd(1)`

#### Slang Examples: Counting Down and the Factorial Function

The count-down function in Slang:

 ``````1 2 3 4 5 6 7 `````` ``````@pure def count0(k: Z): Z = { if (k == 0) { return k } else { return count0(k - 1) } } ``````

With a separate function specifying its correctness:

 ``````1 2 3 4 5 6 `````` ``````@pure def count0_0(k: Z): Unit = { Contract( Requires(k >= 0), Ensures(count0(k) == 0) ) } ``````

We can unfold function `count0` in Slang. We do it within the body of the function.

The function itself:

 ``````1 2 3 4 5 6 7 `````` ``````@pure def count0(k0: Z): Z = { if (k0 == 0) { return k0 } else { return count0(k0 - 1) } } ``````

First Unfolding:

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 `````` ``````@pure def count0(k0: Z): Z = { if (k0 == 0) { return k0 } else { k1 = k0 - 1 if (k1 == 0) { return k1 } else { return count0(k1 - 1) } } } ``````

Second Unfolding:

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 `````` ``````@pure def count0(k0: Z): Z = { if (k0 == 0) { return k0 } else { k1 = k0 - 1 if (k1 == 0) { return k1 } else { k2 = k1 - 1 if (k2 == 0) { return k2 } else { return count0(k2 - 1) } } } } ``````

We can see the effect of recursive unfolding in Slang. It occurs when inter-procedural check is chosen.

#### Recursive Counting Down and Unfolding in Logika

Let’s inter-procedurally check the post-condition `count0(k) == 0`.

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 `````` ``````@pure def count0(k: Z): Z = { if (k == 0) { return k } else { return count0(k - 1) } } @pure def count0_0(k: Z): Unit = { Contract( Requires(k >= 0), Ensures(count0(k) == 0) ) } ``````

of function `count0_0`.

Unfolded if-branch

Unfolded else-branch

#### Exercise 2: Recursive Factorial Unfolding

Unfold function `fac_rec` two times. Write down the fact for the unfolded function. Inter-procedurally check the post-condition `fac_rec(n) == fac_rec_spec(n)`.

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 `````` ``````@pure def fac_rec(n: Z): Z = { if (n == 0) { return 1 } else { return n * fac_rec(n - 1) } } @pure def fac_rec_lemma(n: Z) { Contract( Requires(n >= 0), Ensures(fac_rec(n) == fac_rec_spec(n)) ) } ``````

of function `fac_rec_lemma`.

### Iteration Unfolding

#### Example: Counting Down Iteratively

We can specify counting down recursively as follows.

``````cd(k) =
m = k
while m > 0
m = m − 1
m
``````

Where the tailing `m` is the returned result. We can calculate `cd(2)` observing the value of the local variable \$m\$ at each iteration.

``````cd(2)
{ m == 2 and m > 0 }
{ m == 2 − 1 and m > 0 }
{ m == 2 − 1 − 1 and m <= 0 }
= 0
``````

It would be convenient if we could observe iterative programs similarly to recursive programs. Recall the similarity between tail-recursion and while-loops.

We rename k into `m0, m1, m2, . . .` counting upwards.

``````cd(2)
{ m0 == 2 and m0 > 0 }
{ m1 == 2 − 1 and m1 > 0 }
{ m2 == 2 − 1 − 1 and m2 <= 0 }
= 0
``````

and replace sub-expressions by variable names.

``````cd(2)
{ m0 == 2 and m0 > 0 }
{ m1 == m0 − 1 and m1 > 0 }
{ m2 == m1 − 0 and m2 <= 0 }
= 0
``````

This is exactly the same pattern we have observed for recursion. Let’s look for a fix-point equation.

We focus on the iterative part of the body of function cd.

``````m = k
while m > 0
m = m − 1
``````

To observe one step of the execution of the loop we consider the following. If the condition `m > 0` is true, we execute the loop body and the execute the loop again. `m = m − 1; while (m > 0) m = m − 1` If the condition is false, the loop is exited (and the statement following the loop may be executed). The above describes a conditional with an empty else-branch.
We have (in italics): while (m > 0) m = m − 1 == if (m > 0) { m = m − 1; while (m > 0) m = m − 1 } (FP3) The loop is a solution of fix-point equation (FP3). We can use it for unfolding while-loops.

#### Loop Unfolding using (FP3)

Using `while (m > 0) m = m − 1 == if (m > 0) { m = m − 1; while (m > 0) m = m − 1 }`, abbreviating `while (m > 0) m = m − 1` with `W`, we calculate.

``````while (m > 0) m = m − 1
= if (m > 0) { m = m − 1; W }
= if (m > 0) { m = m − 1; if (m > 0) { m = m − 1; W } }
= if (m > 0) { m = m − 1; if (m > 0) { m = m − 1; if (m > 0) { m = m − 1; W } } }

More readable this is           . . . and as a fact
if (m > 0)                      (m0 <= 0 => m == m0) &
m = m − 1                     (m0 > 0 => m1 == m0 − 1) &
if (m > 0)                  (m0 > 0 & m1 <= 0 => m == m1) &
m = m − 1                 (m0 > 0 & m1 > 0 => m2 = m1 − 1) &
if (m > 0)              (m0 > 0 & m1 > 0 & m1 <= 0 => m == m2) &
m = m − 1             . . .
W
``````

The complete body of the loop unfolded twice:

``````m0 == k
(m0 <= 0 => m == m0) &
(m0 > 0 => m1 == m0 − 1) &
(m0 > 0 & m1 <= 0 => m == m1) &
(m0 > 0 & m1 > 0 => m2 = m1 − 1) &
(m0 > 0 & m1 > 0 & m1 <= 0 => m == m2) &
Res == m
``````

Note the similarity of the structure of the formula. with respect to the variables m0, m1, m2 in the iterative case. and the variables k0, k1, k2 in the recursive case. In the iterative case the variables occur as a consequence of consecutive assignments. In the recursive case they occur as a consequence of consecutive parameter passing.

#### Unfolding the Iterative Slang Counting Down Function

The function itself:

 ``````1 2 3 4 5 6 7 `````` ``````@pure def while0(k: Z): Z = { var m: Z = k while (m > 0) { m = m - 1 } return m } ``````

First Unfolding:

 `````` 1 2 3 4 5 6 7 8 9 10 `````` ``````@pure def while0(k: Z): Z = { var m: Z = k if (m > 0) { m = m - 1 while (m > 0) { m = m - 1 } } return m } ``````

Second Unfolding:

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 `````` ``````@pure def while0(k: Z): Z = { var m: Z = k if (m > 0) { m = m - 1 if (m > 0) { m = m - 1 while (m > 0) { m = m - 1 } } } return m } ``````

We can see the effect of recursive unfolding in Slang. It occurs when inter-procedural check is chosen.

#### Recursive Counting Down and Unfolding in Logika

Let’s inter-procedurally check the post-condition `count0(k) == 0`

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 `````` ``````@pure def while0(k: Z): Z = { var m: Z = k while (m > 0) { m = m - 1 } return m } @pure def while0_0(k: Z) { Contract( Requires(k >= 0), Ensures(while0(k) == 0) ) } ``````

of function `while0_0`.

Second Unfolding

#### Exercise 3: Iterative Factorial Unfolding

1. Unfold the loop of the function `fac_it` two times
2. Write down the fact for the unfolded function
3. Inter-procedurally check the post-condition `fac_it(n) == fac_rec(n)`
 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 `````` ``````@pure def fac_it(n: Z): Z = { var x: Z = 1 var m: Z = 0; while (m < n) { m = m + 1 x = x * m } return x } @pure def fac_it_rec_lemma(n: Z) { Contract( Requires(n >= 0), Ensures(fac_it(n) == fac_rec(n)) ) } ``````

of function `fac_it_rec_lemma`.

### Symbolic Execution with Unfolding

#### Symbolic Execution with Recursion

 ``````1 2 3 4 5 6 7 `````` ``````def count0(k: Z): Z = { if (k == 0) { return k // Res = k } else { return count0(k - 1) } } ``````
• Executing `count0(k)` yields (`k: K0`), (PC: `true`)

• Executing `if (k == 0) {` yields (`k: K0`), (PC: `K0 == 0`)

• Executing `return k` yields (`k: K0, Res: K0`), (PC: `K0 == 0`)

• Executing `count0(k)` yields (`k: K0`), (PC: `true`)

• Executing `} else {` yields (`k: K0`), (PC: `K0 != 0`)

• Executing `return count0(k - 1)` yields (`k: K1`), (PC: `K0 != 0, K1 == K0 - 1`)

• Executing `if (k == 0) {` yields (`k: K1`), (PC: `K0 != 0, K1 == K0 - 1, K1 == 0`)

• Executing `return k` yields (`k: K1, Res: K1`), (PC: `K0 != 0, K1 == K0 - 1, K1 == 0`)

### Symbolic Execution with Iteratio

 ``````1 2 3 4 5 6 7 `````` ``````def while0(k: Z): Z = { var m: Z = k while (m > 0) { m = m - 1 } return m // Res = m } ``````
• Executing `while0(k)` yields (`k: K`), (PC: `true`)

• Executing `var m: Z = k` yields (`k: K, m: K`), (PC: `true`)

• Executing `}` yields (`k: K, m: K`), (PC: `K <= 0`)

• Executing `return m` yields (`k: K, m: K, Res: K`), (PC: `K <= 0`)

• Executing `while0(k)` yields (`k: K`), (PC: `true`)

• Executing `var m: Z = k` yields (`k: K, m: K`), (PC: `true`)

• Executing `while (m > 0) {` yields (`k: K, m: K`), (PC: `K > 0`)

• Executing `m = m - 1` yields (`k: K, m: M1`), (PC: `K > 0, M1 > K - 1`)

• Executing `}` yields (`k: K, m: M1`), (PC: `K > 0, M1 > K - 1, M1 <= 0`)

• Executing `return m` yields (`k: K, m: M1, Res: M1`), (PC: `K > 0, M1 > K - 1, M1 <= 0`)

### Slang Examples

Count Int Loop Rec

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 `````` ``````// #Sireum #Logika import org.sireum._ @pure def while0(k: Z): Z = { var m: Z = k while (m > 0) { m = m - 1 } return m } @pure def while0_0(k: Z) { Contract( Requires(k >= 0), Ensures(while0(k) == 0) ) } @pure def count0(k: Z): Z = { if (k == 0) { return k } else { return count0(k - 1) } } @pure def count0_0(k: Z) { Contract( Requires(k >= 0), Ensures(count0(k) == 0) ) } ``````

Fac Function Loop Rec Unfolding

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 `````` ``````// #Sireum #Logika import org.sireum._ // mathematically oriented specification of the factorial function @strictpure def fac_rec_spec(n: Z): Z = n match { case 0 => 1 case m => m * fac_rec_spec(m - 1) } // recursive implementation of the factorial function @pure def fac_rec(n: Z): Z = { // no contract: we will instead verify/test using a refinement approach if (n == 0) { return 1 } else { return n * fac_rec(n - 1) } } // iterative/imperative implementation of the factorial function @pure def fac_it(n: Z): Z = { // no contract: we will instead verify/test using a refinement approach var x: Z = 1 var m: Z = 0; while (m < n) { m = m + 1 x = x * m } return x } // Refinement specification: // For all n >= Z, // fac_it(n) refines (conforms to) fac_rec_spec(n) // i.e., // fac_it(n) == fac_rec_spec(n) @pure def fac_imp_spec_refinement(n: Z) { Contract( Requires(n >= 0) ) assert(fac_it(n) == fac_rec_spec(n)) } // Refinement specification: // For all n >= Z, // fac_it(n) refines (conforms to) fac_rec(n) // i.e., // fac_it(n) == fac_rec(n) @pure def fac_imp_rec_refinement(n: Z) { Contract( Requires(n >= 0) ) assert(fac_it(n) == fac_rec(n)) } // Refinement specification: // For all n >= Z, // fac_rec(n) refines (conforms to) fac_rec_spec(n) // i.e., // fac_it(n) == fac_rec(n) @pure def fac_rec_spec_refinement(n: Z) { Contract( Requires(n >= 0) ) assert(fac_rec(n) == fac_rec_spec(n)) } ``````

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 `````` ``````// #Sireum #Logika import org.sireum._ // Inductive definition of multiplication @strictpure def mult_spec(m: Z, n: Z): Z = m match { case 0 => 0 case k => mult_spec(k - 1, n) + n } // Induction rules @pure def mult_spec_0(n: Z) { Contract( Ensures(mult_spec(0, n) == 0) ) } @pure def mult_spec_step(m: Z, n: Z) { Contract( Requires(m > 0), Ensures(mult_spec(m, n) == mult_spec(m - 1, n) + n) ) Deduce(|- (m != 0)) } @pure def mult_rec(m: Z, n: Z): Z = { Contract( Requires(m >= 0), Ensures(Res == mult_spec(m, n)) ) if (m == 0) { return 0 } else { return mult_rec(m - 1, n) + n } } def mult_it(m: Z, n: Z): Z = { Contract( Requires(m >= 0), Ensures(Res == mult_rec(m, n)) ) var i: Z = m var k: Z = 0 Deduce(|- (k == mult_rec(m - i, n))) while (i > 0) { Invariant( Modifies(k, i), (i >= 0), (k == mult_rec(m - i, n)) ) Deduce(|- (k == mult_rec(m - i, n))) Deduce(|- (k + n == mult_rec(m - i, n) + n)) Deduce(|- (k + n == mult_rec(m - i + 1, n))) Deduce(|- (k + n == mult_rec(m - (i - 1), n))) k = k + n Deduce(|- (k == mult_rec(m - (i - 1), n))) i = i - 1 Deduce(|- (k == mult_rec(m - i, n))) } Deduce(|- (i <= 0)) Deduce(|- (i == 0)) Deduce(|- (k == mult_rec(m - i, n))) Deduce(|- (k == mult_rec(m - 0, n))) Deduce(|- (k == mult_rec(m, n))) return k } def mult_it_term(m: Z, n: Z): Z = { Contract( Requires(m >= 0), Ensures(Res == mult_rec(m, n)) ) var i: Z = m var k: Z = 0 while (i > 0) { // decreases i Invariant( Modifies(k, i), (i >= 0), (k == mult_rec(m - i, n)) ) val measure_i_pre = i Deduce(|- (measure_i_pre >= 0)) k = k + n i = i - 1 val measure_i_post = i Deduce(|- (measure_i_post < measure_i_pre)) } return k } ``````