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? - 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.

Related

Proof of "less than or equal" transitive law in Coq

I recently started learning Coq at a university course. I have an assignment with a problem, and I got stuck. I need to demonstrate the transitivity of the <= law, which states that for all m, n and p, if m <= n and n <= p, then m <= p. I tried every basic tactic possible, and I didn't figure it out. I want to mention that I'm a beginner and any basic solution without complicated tactics would be appreciated. It should be done with induction as well. Thanks!
Inductive Nat := O : Nat | S : Nat -> Nat.
Fixpoint le_Nat (m n : Nat) : bool :=
match m with
| O => true
| S m' => match n with
| O => false
| S n' => (le_Nat m' n')
end
end.
Lemma le_Trans :
forall m n p,
le_Nat m n = true -> le_Nat n p = true -> le_Nat m p = true.
Proof.
...
Qed.
Here is a long, detailled version:
Proof.
induction m as [| m IHm]; simpl.
- reflexivity.
- destruct n; simpl.
+ intros; discriminate.
+ destruct p; simpl.
* intros; assumption.
* apply IHm.
Qed.
and a shorter one:
induction m;destruct n; destruct p; simpl; try (reflexivity || discriminate).
apply IHm.
Qed.
You may start your proof with three nested induction/case analyses.
Many sub-goals will be trivial or easy to solve.
The last sub-goal will apply the induction hypothesis.
Proof.
induction m; destruct n ; destruct p; simpl.
(* ... *)

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).

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.

Doing a double induction in Coq properly

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.

How to simplify A + 0 > 0 into A > 0?

I'm just a beginner with Coq, and I've been trying to prove a few elementary theorems about natural numbers. I've done a few already, not very elegantly, but completed nether the less. However I'm totally stuck on completing this theorem:
Theorem add_increase: (forall a b: nat, a > 0 -> a + b > b).
Proof.
intros A.
intros B.
intros H.
case B.
Entering this in, I get this output:
2 subgoals
A, B : nat
H : A > 0
______________________________________(1/2)
A + 0 > 0
______________________________________(2/2)
forall n : nat, A + S n > S n
Obviously, the first goal is pretty trivial to simplify to hypothesis H. However, I just can't figure out how to make this straightforward simplification.
One way to simplify this is to use a rather boring lemma
Lemma add_zero_r : forall n, n + 0 = n.
Proof.
intros n. induction n. reflexivity.
simpl. rewrite IHn. reflexivity.
Qed.
and next use this to rewrite your goal:
Theorem add_increase: (forall a b: nat, a > 0 -> a + b > b).
Proof.
intros A.
intros B.
intros H.
case B.
rewrite (add_zero_r A).
assumption.
To finish the other proof case I've used a little lemma and a tactic that eases the task of proving stuff with inequalities over naturals.
First, I've imported Omega library.
Require Import Omega.
Prove another boring fact.
Lemma add_succ_r : forall n m, n + (S m) = S (n + m).
Proof.
intros n m. induction n. reflexivity.
simpl. rewrite IHn. reflexivity.
Qed.
and going back to add_increase prove we have the following goal:
A, B : nat
H : A > 0
============================
forall n : nat, A + S n > S n
That can be solved by:
intros C.
rewrite (add_succ_r A C).
omega.
Again, I've used the previous proved lemma to rewrite the goal. The omega tactic is a very useful one since it is a complete decision procedure for the so called quantifier free Presburger arithmetic, and based on your context, it can solve the goal automagically.
Here's the complete solution to your proof:
Require Import Omega.
Lemma add_zero_r : forall n, n + 0 = n.
Proof.
intros n. induction n. reflexivity.
simpl. rewrite IHn. reflexivity.
Qed.
Lemma add_succ_r : forall n m, n + (S m) = S (n + m).
Proof.
intros n m. induction n. reflexivity.
simpl. rewrite IHn. reflexivity.
Qed.
Theorem add_increase: (forall a b: nat, a > 0 -> a + b > b).
Proof.
intros A.
intros B.
intros H.
case B.
rewrite (add_zero_r A).
assumption.
intros C.
rewrite (add_succ_r A C).
omega.
Qed.
Several common lemmas such as a + 0 = a etc. are put in the hint database arith. With them, auto can usually solve many simple goals of this kind, so use auto with arith.
Require Import Arith.
Theorem add_increase: (forall a b: nat, a > 0 -> a + b > b).
destruct a; intros b H.
- inversion H. (* base case, H: 0 > 0 *)
- simpl. auto with arith.
Qed.
To see which lemmas auto used, you can Print add_increase. In this case, auto used three lemmas, and they can alternatively be given explicitly to auto by auto using gt_le_S, le_lt_n_Sm, le_plus_r.
In general, when you need a lemma that you think ought to have already been proven, you can search for it with SearchAbout. Use _ as a wild card, or ?a as a named wild-card. In your case above you wanted something about adding a zero on the right, so
SearchAbout ( _ + 0 = _ ).
returns
plus_0_r: forall n : nat, n + 0 = n
NPeano.Nat.add_0_r: forall n : nat, n + 0 = n
You can even find a lemma in the library that is close to what you want to prove.
SearchAbout ( _ > _ -> _ + _ > _ ).
finds
plus_gt_compat_l: forall n m p : nat, n > m -> p + n > p + m
which is pretty close to add_increase.
Theorem add_increase: (forall a b: nat, a > 0 -> a + b > b).
intros.
pose (plus_gt_compat_l a 0 b H) as A.
repeat rewrite (plus_comm b) in A.
apply A.
Qed.
Another solution using a different natural numbers library ssrnat and the ssreflect proof language (which is needed by the library):
From mathcomp Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq.
Theorem add_increase a b : 0 < a -> b < a + b.
Proof. by rewrite -{1}[b]add0n ltn_add2r. Qed.
The ltn_add2r : (m + p < n + p) = (m < n) lemma is proved by induction on p, directly by induction on p plus commutativity and other easy properties of addition.
Note that if we're invoking the omega tactic, we could've just done:
Theorem add_increase : forall a b: nat, a > 0 -> a + b > b.
Proof. intros a b. omega. Qed.