From mathcomp Require Import all_ssreflect.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
(**
----------------------------------------------------------
#
#
** Lesson 2: summary
- statements
- proofs by computation
- proofs by case split
- proofs by rewriting
#
#
#
#
----------------------------------------------------------
##
** Formal proofs
Today we learn how to state and prove theorems.
We don't do that in the void, nor without a methodology.
We work on top of the Mathematical Components library
and we follow the Small Scale Reflection approach using
the SSReflect proof language.
The Mathematical Components library can be
#
browsed online#.
The modules of interest are
#
ssrnat#
and
#
ssrbool#
(see the headers for the doc).
The SSReflect proof language
(#
reference manual#)
is covered in full details by the Mathematical Components book.
Here we just cover the basics.
#
#
#
#
----------------------------------------------------------
##
** Formal statements
Most of the statements that we consider in Mathematical
Components are equalities.
#
#
*)
Check (_ = _).
Locate "_ = _".
(**
#
#
For example, we can equate two expressions representing natural numbers.
#
#
*)
Lemma addnA: forall (m n k : nat), m + (n + k) = (m + n) + k.
Abort.
(**
#
#
Addition is defined as left-associative.
#
#
*)
Lemma addnA: forall (m n k : nat), m + (n + k) = m + n + k.
Abort.
(**
#
#
Quantifications can be set as parameters before the colon.
#
#
*)
Lemma addnA (m n k : nat) : m + (n + k) = m + n + k.
Abort.
(**
#
#
In lesson 1 we have defined many boolean tests that can
play the role of (decidable) predicates.
#
#
*)
Check 0 <= 4. (* not a statement *)
Check (0 <= 4) = true. (* a statement we can prove *)
(**
#
#
#
#
Motto: whenever possible predicates are expressed as a programs.
#
#
This choice has a deep impact on the proofs we make in lesson 2 and 3 and
the way we can form new types in lesson 4.
Booleans can be coerced into statements.
#
#
*)
Check is_true (* Definition is_true b := b = true *).
(**
#
#
Tests can be turned into statements.
#
#
*)
Check (_ <= _).
Check is_true (_ <= _).
Lemma leq0n (n : nat) : is_true (0 <= n).
Abort.
(**
#
#
the [is_true]
"coercion" is automatically inserted by Coq.
#
#
*)
Lemma leq0n (n : nat) : 0 <= n.
Abort.
(**
#
#
Equality statement between tests reads as "if and only if".
#
#
*)
Print Nat.sub.
Lemma eqn_leq (m n : nat) : m == n = (m <= n) && (n <= m).
Abort.
(**
#
#
[(_ <= _) && (_ <= _)] has a special notation [(_ <= _ <= _)]
#
#
*)
Lemma eqn_leq (m n : nat) : m == n = (m <= n <= m).
Abort.
(**
#
#
#
#
#
#
#
#
#
#
----------------------------------------------------------
##
** Proofs by computation
Our statements are programs. Hence they compute!
The [by[]] tactic solves trivial goal (mostly) by
computation.
<<
Fixpoint addn n m :=
if n is p.+1 then (addn p m).+1 else m.
>>
#
#
*)
Goal 2 + 2 = 4.
Proof. by []. Qed.
Lemma addSn m n : m.+1 + n = (m + n).+1.
Proof. by []. Qed.
(**
#
#
<<
Fixpoint subn m n : nat :=
match m, n with
| p.+1, q.+1 => subn p q
| _ , _ => m
end.
>>
#
#
*)
Goal 2 - 4 = 0.
Proof. by []. Qed.
Lemma subn0 m n : m.+1 - n.+1 = m - n.
Proof. by []. Qed.
(**
#
#
<<
Definition leq m n := m - n == 0.
>>
#
#
*)
Goal 0 <= 4.
Proof. by []. Qed.
(**
#
#
[_ < _] is just a notation for [_.+1 <= _].
#
#
*)
Goal 3 < 3 = false.
Proof. by []. Qed.
Goal 4 <= 3 = false.
Proof. by []. Qed.
Lemma leq0n n : 0 <= n.
Proof. by []. Qed.
Lemma ltn0 n : n.+1 <= 0 = false.
Proof. by []. Qed.
Lemma ltnS m n : (m.+1 <= n.+1) = (m <= n).
Proof. by []. Qed.
(**
#
#
Notice the naming convention.
#
#
*)
Print negb.
Locate "~~".
Search negb in ssr.ssrbool.
Lemma negbK (b : bool) : ~~ (~~ b) = b.
Proof. Fail by []. Abort.
(**
#
#
It is not always the case the computation solves all our
problems. In particular here there are no constructors to
consume, hence computation is stuck.
To prove [negbK] we need a case split.
#
#
#
#
#
#
#
#
----------------------------------------------------------
##
** Proofs by case analysis
The proof of [negbK] requires a case analysis: given that
[b] is of type bool, it can only be [true] or [false].
The [case: term] command performs this proof step.
#
#
*)
Lemma negbK b : ~~ (~~ b) = b.
Proof.
case: b.
by [].
by [].
Qed.
Lemma andbC (b1 b2 : bool) : b1 && b2 = b2 && b1.
Proof.
by case: b1; case: b2.
Qed.
Lemma orbN b : b || ~~ b.
Proof.
by case: b.
Qed.
(**
#
#
The constructors of [bool] have no arguments, but for
example the second constructor of [nat] has one.
In this case one has to complement the command by supplying
names for these arguments.
#
#
*)
Lemma leqn0 n : (n <= 0) = (n == 0).
Proof.
case: n => [| p].
by [].
by [].
Qed.
(**
#
#
Sometimes case analysis is not enough.
[[
Fixpoint muln (m n : nat) : nat :=
if m is p.+1 then n + muln p n else 0.
]]
#
#
*)
Lemma muln_eq0 m n :
(m * n == 0) = (m == 0) || (n == 0).
Proof.
case: m => [|p].
by [].
case: n => [|k]; last first. (* rotates the goals *)
by [].
Abort.
(**
#
#
We don't know how to prove this yet.
But maybe someone proved it already...
#
#
*)
Search _ (_ * 0) in ssrnat. (* :-( *)
Search _ muln 0 in ssrnat.
Print right_zero.
Search right_zero.
(**
#
#
The [Search] command is quite primitive but also
your best friend.
It takes a head pattern, the whildcard [_]
in the examples above, followed by term or patterns,
and finally a location, in this case the [ssrnat] library.
Our first attempt was unsuccessful because
standard properies (associativity, communtativity, ...)
are expressed in Mathematical Components using
higher order predicates.
In this way these lemmas are very consistent, but also
harder to find if one does not know that.
The second hit is what we need to complete the proof.
#
#
#
#
#
#
----------------------------------------------------------
##
** Proofs by rewriting
The [rewrite] tactic uses an equation. If offers many
more flags than the ones we will see (hint: check the
Coq user manual, SSReflect chapter).
#
#
*)
Lemma muln_eq0 m n :
(m * n == 0) = (m == 0) || (n == 0).
Proof.
case: m => [|p].
by [].
case: n => [|q].
rewrite muln0.
by [].
by [].
Qed.
(**
#
#
Let's now look at another example to learn more
about [rewrite].
#
#
*)
Lemma leq_mul2l m n1 n2 :
(m * n1 <= m * n2) = (m == 0) || (n1 <= n2).
Proof.
rewrite /leq.
(* Search _ muln subn in ssrnat. *)
rewrite -mulnBr.
rewrite muln_eq0.
by [].
Qed.
(**
#
#
#
#
#
#
#
#
----------------------------------------------------------
##
** Lesson 2: sum up
- [by []] trivial proofs (including computation)
- [case: m] case split
- [rewrite t1 -t2 /def] rewrite
#
#
*)