CSCI 2041

ADVANCED PROGRAMMING PRINCIPLES

Reasoning about programs:

Induction

Correctness

How can we convince ourselves (and others) that a program is correct?

let sum_to n =
  let rec tr_sum i acc =
     if i=0 then acc
     else tr_sum i-1 acc+i in
  tr_sum n 0
let fib n =
  let rec tr_fib i f0 f1 =
    if i=0 then f0
    else tr_fib (i-1) f1 (f1+f0) in
  tr_fib n 0 1

How can we convince ourselves that sum_to and fib are correct?

We can test any specific input, but for many programs, there are infinitely many possible inputs…


Principle of Natural Induction: Let P(n) be a property of natural numbers. (i.e. for each natural number n, either P(n) is true or P(n) is false.) If the following hold:

P(0) and ∀𝓃, P(𝓃) ⇒ P(𝓃+1)

Then it must be true that for all n, P(n).

CSci 2011 example: proving that ∀n, ∑i≤n i = n(n+1)/2

let rec sum_to n =
 if n = 0 then 0 else n + (sum_to (n-1))

Prove: for all 𝓃 ≥ 0, sum_to 𝓃 ≡ ∑i≤𝓃 i.

Here P(𝓃) = sum_to 𝓃 ≡ ∑i≤𝓃 i, so we need to prove:

  1. Base Case: sum_to 0 ≡ 0 [✓, eval. sum_to]
  2. Inductive (step) Case:
    if sum_to 𝓃 ≡ ∑i≤𝓃 i ( Inductive Hypothesis )
    then sum_to (𝓃+1) ≡ ∑i≤(𝓃+1) i ( Inductive Conclusion ):

sum_to (𝓃+1) ≡ (𝓃+1) + (sum_to 𝓃)       [eval. sum_to]
             ≡ (𝓃+1) +i≤𝓃 i                              [I.H.]
             ≡i≤(𝓃+1) i                                               [✓, algebra]

using lemmas

let sum_to n =
  let rec tr_sum i acc =
     if i=0 then acc
     else tr_sum i-1 acc+i in
  tr_sum n 0

In order to prove that for all 𝓃, (sum_to 𝓃) ≡ ∑i≤𝓃i, we need to prove a lemma about tr_sum:

For all 𝓃≥0, for all 𝒶, tr_sum 𝓃 𝒶 ≡ 𝒶 + ∑i≤𝓃i.

  let rec tr_sum i acc =
     if i=0 then acc
     else tr_sum i-1 acc+i
For all 𝓃≥0, for all 𝒶, tr_sum 𝓃 𝒶 ≡ 𝒶 + ∑i≤𝓃i.
  • Base case: for all 𝒶, tr_sum 0 𝒶 ≡ 𝒶 ≡ 𝒶 + 0.

  • Inductive case: notice tr_sum (𝓃+1) 𝒶 ≡ tr_sum 𝓃 (𝒶+(𝓃+1)).

    if for all 𝒶, (tr_sum 𝓃 𝒶) ≡ 𝒶 + ∑i≤𝓃i, (IH) then we also have

    (tr_sum 𝓃 (𝒶+(𝓃+1))) ≡ (𝒶 + (𝓃+1)) + ∑i≤𝓃i,

    so tr_sum (𝓃+1) 𝒶 ≡ tr_sum 𝓃 (𝒶+(𝓃+1)) [eval tr_sum]

    ≡ (𝒶 + (𝓃+1)) + ∑i≤𝓃i = 𝒶 + ∑i≤(𝓃+1)i. [✓, algebra]

let fib n =
  let rec tr_fib i f0 f1 =
    if i=0 then f0
    else tr_fib (i-1) f1 (f1+f0) in
  tr_fib n 0 1

In order to prove that for all n, fib n ≡ Fn, we prove a lemma about tr_fib:

For all i≥0, for all n, tr_fib i Fn-i Fn-i+1 ≡ Fn
  let rec tr_fib i f0 f1 =
    if i=0 then f0
    else tr_fib (i-1) f1 (f1+f0) in
For all i≥0, for all n, tr_fib i Fn-i Fn-i+1 ≡ Fn

Base Case: tr_fib 0 Fn Fn+1 ≡ Fn, by evaluation.

Inductive Case:

tr_fib (i+1) Fn-i-1 Fn-i

tr_fib i Fn-i (Fn-i + Fn-i-1)    [eval. tr_fib]

tr_fib i Fn-i F(n-i)+1≡ Fn     [✓, algebra, IH]

Referential Transparency

In these proofs, we often replace one expression with another equivalent expression.

We are using the fact that OCaml expressions have referential transparency: if two expressions evaluate to the same normal form, then this is true in any context.

Alternatively, referential transparency means that evaluating an expression does not change the bindings (values) of variables.

For the substitution to be valid, evaluating both expressions should result in the same termination behavior in any context.

cs2041.org

// reveal.js plugins