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. (** #
# #


# #

(notes)
# This slide corresponds to section 2.1 of #the Mathematical Components book# #
# #


# #

# ---------------------------------------------------------- #
# ** 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. #


# #

(notes)
# This slide corresponds to section 2.2.1 of #the Mathematical Components book# #
# #


# #

# ---------------------------------------------------------- #
# ** 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. #
(notes)
# This slide corresponds to sections 2.2.2 and 2.5 of #the Mathematical Components book# #
# #


# #

# ---------------------------------------------------------- #
# ** 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. (** #
# #
(notes)
# This slide corresponds to section 2.2.3 of #the Mathematical Components book# #
# #


# #

# ---------------------------------------------------------- #
# ** Lesson 2: sum up - [by []] trivial proofs (including computation) - [case: m] case split - [rewrite t1 -t2 /def] rewrite #
# *)