Lecture 4: Proofs about programs

(credits: Assia Mahboubi and Yves Bertot)

Proofs of programs in Coq

Now : We will see how to write specifications of programs written in Coq and how to prove them.

4  Coq programs can be seen as models of realistic programs and its formal proof as a dynamic documentation.

4  Coq programs can be translated (extracted) to realistic programming languages.

4  Coq programs can be executed efficiently, and this is a proof automation technique.

And there exist tools too to prove even imperative programs but it is much more intricate a problem.

Proofs about computation

4 Reason about functional correctness

4 State properties about computation results

4 Show consistency between several computations

4 Use the same tactics as for usual logical connectives

4 Add tactics to control computations and observation of data

4 Follow the structure of functions

4 Proving is akin to symbolic debugging

4 A proof is a guarantee that all cases have been covered

4 It is much stronger than a test!

First examples

Controlling execution

4  Replace formulas containing functions with other formulas

4  Manually with direct Coq control:

4change f1 with f2

4 Really checks that f1 and f2 are the same modulo computation

4  Manually with indirect control

4replace f1 with f2

4 Produces a side goal with the equality f1 = f2

4  Simply expand definitions

4unfold f, unfold f at 2

Functions and specifications

4 Each function should come with theorems about it.

4 In this course, sometimes called companion theorems.

4 They should be usable directly through apply when the conclusion of the goal fits.

4 Otherwise, they can be brought in the context using assert, e.g., assert (H := th a b c H1).

Reasoning about pattern-matching constructs

4  Pattern-matching typically describes alternative behaviors.

4  Reasoning on these functions goes by covering all cases.

4  Companion theorems describe the non trivial identities.

Examples with natural numbers

Tools

4 case is the basic constructs

4 generates one goal per constructor

4 the expression is replaced by constructor-values, in the conclusion

4 the argument to S becomes a universally quantified variable

4 destruct is more advanced and covers the context

4 like case, but nesting is authorized

4 the context is also modified

4 case_eq remembers in which case we are

4 the context is not modified (as in case)

4 remembering can be crucial

How to find Companion theorems

4 Search is your friend.

4 In general Search commands are your friends.

4 Search: use a predicate name
Search le.

4 SearchRewrite: use patterns of expressions searchRewrite (_ + 0).

4 SearchPattern: use a pattern of the conclusion of the theorem

(type Prop, usually)

SearchPattern (_ * _ <= _ * _).

Recursive functions and induction

4  When a function is recursive, calls are usually made on direct subterms.

4  Companion theorems do not already exist, but have to be stated and proved by the user.

4  Induction hypotheses make up for the missing theorems.

4  The structure of the proof is imposed by the data-type.

Examples on recursive functions

Proofs on functions on lists

4  Tactics case, destruct, case_eq also work

4  Induction on lists works like induction on natural numbers

4 nil plays the same role as 0: base case of proofs by induction

4 a::tl plays the same role as S

4  Induction hypothesis on tl

4  Fits with recursive calls on tl

Example proof on lists

A trick to control recursion

4  Add one-step unfolding theorems to recursive functions

4  Associate any definition

Fixpoint f x1 ...xn := body

with a (trivial) theorem f_step

forall x1 ...xn, f x1 ...xn =body

4  Use rewrite f_step instead of change, replace, or simpl

4  This provides a better control than simpl.

4  More concise than replace or change.

4  Note that unfold is not well-suited for recursive functions.