Doing a double induction in Coq properly - coq

I am trying to prove the plus_n_Sm theorem from the Induction chapter in Software Foundations
Theorem succ_is_plus_1: forall n: nat, S n = n + 1.
Proof.
induction n as [| n' ind_hyp].
- simpl. reflexivity.
- simpl. rewrite <- ind_hyp. reflexivity.
Qed.
Theorem plus_n_Sm : forall n m : nat,
S (n + m) = n + (S m).
Proof.
induction n as [| n' ind_hyp ].
- induction m as [| m' ind_m ].
+ simpl. reflexivity.
+ simpl. reflexivity.
- induction m as [| m' ind_m2 ].
+ rewrite -> succ_is_plus_1 . rewrite <- plus_n_O. reflexivity.
+ rewrite -> succ_is_plus_1. rewrite <- ind_m2.
The output at this point is
1 subgoal
n' : nat
ind_hyp : forall m : nat, S (n' + m) = n' + S m
m' : nat
ind_m2 : S (S n' + m') = S n' + S m'
______________________________________(1/1)
S (S n' + m') + 1 = S n' + S (S m')
I'm stuck here. What am I doing wrong? What is the proper way of thinking for finding the induction proof on two variables?

As the first comment said, the key is that an induction on n suffices, m can be a constant. Then the proof is straightforward.

Related

Proving S (n + m) = n + (S m), how to rewrite n+1 = S(n)?

Theorem add_0_r : forall n:nat, n + 0 = n.
Proof.
intros n. induction n as [| n' IHn'].
- (* n = 0 *) reflexivity.
- (* n = S n' *) simpl. rewrite -> IHn'. reflexivity. Qed.
Theorem plus_n_Sm : forall n m : nat,
S (n + m) = n + (S m).
Proof.
intros n m. induction m as [| m' IHn']. rewrite -> add_0_r. rewrite <- sum.
The last tactic rewirte <- sum does not work. This is the goal:
n: ℕ
-------------
S(n) = n + 1
I don't know how to rewrite n+1 as S(n). I think that n+1 is just a notation for S(n), right?
If you look at the definition of + as follows, you can see that it is defined by induction on its first argument:
Locate "+". (* to obtain the name Nat.add *)
Print Nat.add.
(*
Nat.add =
fix add (n m : nat) {struct n} : nat :=
match n with
| 0 => m
| S p => S (add p m)
end
: nat -> nat -> nat
*)
As a result 1 + n is indeed convertible to S n (you can see that using Eval cbn in 1 + ?[n].) but not n + 1 (if you unfold Nat.add. you will obtain a pattern match stuck on the variable n).
For your proof, that specific definition of + means that you might reconsider your approach and try to do your proof by induction on n rather than m (paying attention to have the right induction hypothesis).
If you are using the nat type from the standard library, then n+1 is not a notation for S n, but a notation for the function Nat.add. In that case n+1 is not apparently equal to S n. You need to prove it by an induction on n.
By the way, if you are using Nat.nat, you need to use induction on n rather than m. Because Nat.add is defined by a match on the first argument. In this case, your first subgoal of the induction can be proved simply by reflexivity. (Coq is able to simplify S (0 + m) and 0 + S m, but not S (n + 0) and n + 1).
Was able to prove with the following:
Theorem plus_n_Sm : forall n m : nat,
S (n + m) = n + (S m).
Proof.
intros n m. induction n as [| n' IHn'].
- simpl. reflexivity.
- simpl. rewrite -> IHn'. reflexivity.
Qed.

How to write intermediate proof statements inside Coq - similar to how in Isar one has `have Statement using Lemma1, Lemma2 by auto` but in Coq?

I wanted to write intermediate lemmas inside Coq proof scripts, e.g., inside SCRIPT in Proof. SCRIPT Qed. itself - similar to how one would do in Isar. How does one do this in Coq? e.g.:
have Lemma using Lemma1, Lemma2 by auto.
I am aware of the exact statement and wonder if that is it...but I'd like to have the proof for the statement too like in Isar we have have by auto or using Proof. LEMMA_PROOF Qed.
To make it concrete, I was trying to do these very simple proofs:
Module small_example.
Theorem add_easy_induct_1:
forall n:nat,
n + 0 = n.
Proof.
intros.
induction n as [| n' IH].
- simpl. reflexivity.
- simpl. rewrite -> IH. reflexivity.
Qed.
Theorem plus_n_Sm :
forall n m : nat,
S (n + m) = n + (S m).
Proof.
intros n m.
induction n as [| n' IH].
- simpl. reflexivity.
- simpl. rewrite -> IH. reflexivity.
Qed.
Theorem add_comm :
forall n m : nat,
n + m = m + n.
Proof.
intros.
induction n as [| n' IH].
- simpl. rewrite -> add_easy_induct_1. reflexivity.
- simpl. rewrite -> IH. simpl. rewrite <- plus_n_Sm. reflexivity.
Qed.
End small_example
but I wasn't sure how and it wasn't working too well.
I'm also interested in shows in Coq e.g.
shows T using lemmas by hammer.
Current answers are good in showing that the have and by statements exist in Coq. However, what is crucially missing is 1) the shows statement and 2) the using statements. I'd like to see similar constructs with those in Coq proofs -- especially the using one that works with shows's and have's.
What Isabelle seems to be good at is declaring statements as true given a proof and a list of hypothesis. So for example have name: L using l1 by metis. would create the lemma L as a new fact, give it name name but prove it using the tactic metis but crucially depending on the fact l1 as something given for that statement to succeed. So I want to be able to declare things and be checked by a tactic/ATP in Coq.
Related:
I am aware of Czar (https://coq.discourse.group/t/what-is-the-difference-between-ssreflect-and-czar/824) but that is no longer supported in Coq afaik.
You can write assert <lem> to prove an intermediate result <lem> in the middle of a proof. Other variants are assert <lem> by <tactic> to immediately prove <lem> using <tactic>, or assert (<lemname> : <lem>) to give a name to the lemma. Example:
Theorem add_comm :
forall n m : nat,
n + m = m + n.
Proof.
intros.
induction n as [| n' IH].
- simpl.
assert (add_easy_induct_1 : forall n, n + 0 = n) by (induction n; auto).
rewrite -> add_easy_induct_1. reflexivity.
- simpl.
assert (plus_n_Sm : forall n m, S (n + m) = n + S m) by (induction n; auto).
rewrite -> IH. simpl. rewrite <- plus_n_Sm. reflexivity.
Qed.
Documentation on assert: https://coq.inria.fr/distrib/current/refman/proof-engine/tactics.html#coq:tacn.assert
You can use the have: construct in the ssreflect language of tactics for Coq, with pretty much the same semantics you want, plus a couple of additional nice features related to how this lemma can be used right away (e.g., for rewriting) instead of being given a name.
For a concrete code example, see https://stackoverflow.com/a/71428239/1601580
To provide an example to https://stackoverflow.com/a/70326508/1601580 answer, here is some code example for have:
Theorem n_plus_zero_eq_n:
forall n:nat,
n + 0 = n.
Proof.
intros.
induction n as [| n' IH].
- simpl. reflexivity.
- simpl. rewrite -> IH. reflexivity.
Qed.
Theorem Sn_plus_m_eq_n_plus_Sm:
forall n m : nat,
S (n + m) = n + (S m).
Proof.
intros n m.
induction n as [| n' IH].
- auto.
- simpl. rewrite <- IH. reflexivity.
Qed.
Theorem add_comm :
forall n m : nat,
n + m = m + n.
Proof.
intros.
induction n as [| n' IH].
- simpl. rewrite -> n_plus_zero_eq_n. reflexivity.
- simpl. rewrite -> IH. rewrite -> Sn_plus_m_eq_n_plus_Sm. reflexivity.
Qed.
(* have proof *)
From Coq Require Import ssreflect ssrfun ssrbool.
Theorem add_comm_have:
forall n m : nat,
n + m = m + n.
Proof.
intros. induction n.
- simpl.
have: (forall n, n+0 = n) by (apply n_plus_zero_eq_n). move=> H.
rewrite -> H. by reflexivity.
- simpl. rewrite IHn.
have: (forall n m: nat, S (n + m) = n + (S m)) by (apply Sn_plus_m_eq_n_plus_Sm). move=> H'.
rewrite -> H'. by reflexivity.
Qed.
second example based on comment:
From Coq Require Import ssreflect ssrfun ssrbool.
Theorem add_comm_have':
forall n m : nat,
n + m = m + n.
Proof.
intros. induction n.
- simpl.
have -> //: forall n, n+0 = n by (apply n_plus_zero_eq_n).
- simpl. rewrite IHn.
have -> //: forall n m: nat, S (n + m) = n + (S m) by (apply Sn_plus_m_eq_n_plus_Sm).
Qed.

How does one properly simplify a coq goal with a previous lemma?

Why doesn't the last line of my proof shed a successor instead of adding one.
Note: i'm doing these excercises outside of a classroom setting and don't condone people using it to cheat on hw, I just don't know where else to ask it.
From the tactics chapter in Pierce.
Theorem plus_n_n_injective : forall n m,
n + n = m + m ->
n = m.
Proof.
intros n. induction n as [| n'].
intros.
simpl in H.
destruct m.
reflexivity.
discriminate.
intros.
rewrite <- plus_n_Sm in H.
destruct m.
discriminate.
rewrite <- plus_n_Sm in H.
apply S_injective in H.
simpl in H.
apply S_injective in H.
apply S_injective.
where these auxiliary lemmas are used
Theorem S_injective : forall (n m : nat),
S n = S m ->
n = m.
Proof.
intros n m H1.
assert (H2: n = pred (S n)). { reflexivity. }
rewrite H2. rewrite H1. reflexivity.
Qed.
Theorem plus_n_Sm : forall n m : nat,
S (n + m) = n + (S m).
Proof.
intros n m. induction n as [| n' IHn'].
simpl.
reflexivity.
simpl.
rewrite -> IHn'.
reflexivity.
Qed.
If you have a look at the statement of S_injective:
Theorem S_injective : forall (n m : nat),
S n = S m ->
n = m.
you will see it says that to prove n = m it is enough to prove S n = S m.
Before you apply it, you have to prove S n' = S m, and then you say you only need to prove S (S n') = S (S m). It's because apply in the goal is doing some backward thinking.
What you want instead is being able to say n = m -> S n = S m. You can prove the lemma by hand like you did, or you can use the f_equal tactic which works in general to prove f n = f m from n = m for any f (roughly).

Coq: Proving simple theorem using Fixpoints and Induction

I am learning to use Coq right now and I have stumbled on a theorem I can't seem to prove. Below is the theorem and my current attempt.
Fixpoint nateq (n m : nat) : bool :=
match n with
| O => match m with
| O => true
| S _ => false
end
| S n' => match m with
| O => false
| S m' => nateq n' m'
end
end.
Theorem nateq_is_eq : ∀ n m : nat, nateq n m = true → n = m.
Proof.
admit.
Admitted.
My attempt
Theorem nateq_is_eq : ∀ n m : nat, nateq n m = true → n = m.
Proof.
intros n m H.
induction n as [| n' IHn'].
- induction m as [| m' IHm'].
+ reflexivity.
+ inversion H.
- induction m as [| m' IHm'].
+ inversion H.
+
Admitted.
My problem is in the final inductive step. The current state of my subgoals says the following:
1 subgoal
n', m' : nat
H : nateq (S n') (S m') = true
IHn' : nateq n' (S m') = true → n' = S m'
IHm' : nateq (S n') m' = true → (nateq n' m' = true → n' = m') → S n' = m'
______________________________________(1/1)
S n' = S m'
This all seems a bit convoluted. I would really appreciate any advice in the right direction.
Your induction hypothesis on n' is not general enough: to get the proof to go through, it needs to work for arbitrary m. The generalize dependent tactic can be used to solve this problem:
Require Import Coq.Unicode.Utf8.
Fixpoint nateq (n m : nat) : bool :=
match n with
| O => match m with
| O => true
| S _ => false
end
| S n' => match m with
| O => false
| S m' => nateq n' m'
end
end.
Theorem nateq_is_eq : ∀ n m : nat, nateq n m = true → n = m.
Proof.
intros n m H.
generalize dependent m.
induction n as [|n IH].
- destruct m; easy.
- destruct m as [|m]; try easy.
simpl. intros H. specialize (IH _ H). congruence.
Qed.
In this case, you can avoid the problem altogether simply by leaving m on the context:
Theorem nateq_is_eq' : ∀ n m : nat, nateq n m = true → n = m.
Proof.
intros n. induction n as [|n IH].
- destruct m; easy.
- destruct m as [|m]; try easy.
simpl. intros H. specialize (IH _ H). congruence.
Qed.
The Software Foundations book has a more detailed explanation on the generalize dependent tactic.

Logic: evenb_double_conv

Theorem evenb_double_conv : forall n,
exists k, n = if evenb n then double k
else S (double k).
Proof.
(* Hint: Use the [evenb_S] lemma from [Induction.v]. *)
intros n. induction n as [|n' IHn'].
- simpl. exists O. simpl. reflexivity.
- rewrite -> evenb_S. destruct (evenb n') as [H1 | H2].
+ simpl.
Here I am stuck:
n' : nat
IHn' : exists k : nat, n' = double k
============================
exists k : nat, S n' = S (double k)
We can either rewrite (double k) to n' using inductive hypothesis or use injection upon the goal and then apply induction hypothesis.
But I can do none of these because of exists.
rewrite <- IHn' gives:
Error: Cannot find an homogeneous relation to rewrite.
injection gives:
Error: Ltac call to "injection" failed.
Not a negated primitive equality.
What to do?
We need to break exists in hypothesis with destruct: destruct IHn' as [k HE].
Theorem evenb_double_conv : forall n,
exists k, n = if evenb n then double k
else S (double k).
Proof.
(* Hint: Use the [evenb_S] lemma from [Induction.v]. *)
intros n. induction n as [|n' IHn'].
- simpl. exists O. simpl. reflexivity.
- rewrite -> evenb_S. destruct IHn' as [k HE]. destruct (evenb n').
(* Now find out which k we need to insert into the goal for every branch *)
Injection doesn't work here, because it works only in hypothesis.