Logic: evenb_double_conv - coq

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.

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

even_Sn_not_even_n - apply 1 hypothesis in another

Unfortunately I got stuck again:
Inductive even : nat > Prop :=
| ev_0 : even 0
| ev_SS (n : nat) (H : even n) : even (S (S n)).
Lemma even_Sn_not_even_n : forall n,
even (S n) <-> not (even n).
Proof.
intros n. split.
+ intros H. unfold not. intros H1. induction H1 as [|n' E' IHn].
- inversion H.
- inversion_clear H. apply IHn in H0. apply H0.
+ intros H. induction n as [|n' IHn].
- exfalso. apply H. apply ev_0.
- apply evSS_inv'.
Here is the result:
1 subgoal (ID 179)
n' : nat
H : ~ even (S n')
IHn : ~ even n' -> even (S n')
============================
even n'
As far I could prove it in words:
(n' + 1) is not even according to H. Therefore according to IHn, it is not true that n' is not even (double negation):
IHn : ~ ~ even n'
Unfolding double negation, we conclude that n' is even.
But how to write it in coq?
The usual way to strip double negation is to introduce the "excluded middle" axiom, which is defined under the name classic in Coq.Logic.Classical_Prop, and apply the lemma NNPP.
However, in this particular case, you can use the technique called reflection by showing that the Prop is consistent with a boolean function (you might remember the evenb function introduced earlier in the book).
(Assuming you're at the beginning of IndProp) You'll soon see the following definition later in that chapter:
Inductive reflect (P : Prop) : bool -> Prop :=
| ReflectT (H : P) : reflect P true
| ReflectF (H : ~ P) : reflect P false.
You can prove the statement
Lemma even_reflect : forall n : nat, reflect (even n) (evenb n).
and then use it to move between a Prop and a boolean (which contain the same information i.e. the (non-)evenness of n) at the same time. This also means that you can do classical reasoning on that particular property without using the classic axiom.
I suggest to complete the exercises under Reflection section in IndProp, and then try the following exercises. (Edit: I uploaded the full answer here.)
(* Since `evenb` has a nontrivial recursion structure, you need the following lemma: *)
Lemma nat_ind2 :
forall P : nat -> Prop,
P 0 -> P 1 -> (forall n : nat, P n -> P (S (S n))) -> forall n : nat, P n.
Proof. fix IH 5. intros. destruct n as [| [| ]]; auto.
apply H1. apply IH; auto. Qed.
(* This is covered in an earlier chapter *)
Lemma negb_involutive : forall x : bool, negb (negb x) = x.
Proof. intros []; auto. Qed.
(* This one too. *)
Lemma evenb_S : forall n : nat, evenb (S n) = negb (evenb n).
Proof. induction n.
- auto.
- rewrite IHn. simpl. destruct (evenb n); auto. Qed.
(* Exercises. *)
Lemma evenb_even : forall n : nat, evenb n = true -> even n.
Proof. induction n using nat_ind2.
(* Fill in here *) Admitted.
Lemma evenb_odd : forall n : nat, evenb n = false -> ~ (even n).
Proof. induction n using nat_ind2.
(* Fill in here *) Admitted.
Lemma even_reflect : forall n : nat, reflect (even n) (evenb n).
Proof. (* Fill in here. Hint: You don't need induction. *) Admitted.
Lemma even_iff_evenb : forall n, even n <-> evenb n = true.
Proof. (* Fill in here. Hint: use `reflect_iff` from IndProp. *) Admitted.
Theorem reflect_iff_false : forall P b, reflect P b -> (~ P <-> b = false).
Proof. (* Fill in here. *) Admitted.
Lemma n_even_iff_evenb : forall n, ~ (even n) <-> evenb n = false.
Proof. (* Fill in here. *) Admitted.
Lemma even_Sn_not_even_n : forall n,
even (S n) <-> not (even n).
Proof. (* Fill in here.
Hint: Now you can convert all the (non-)evenness properties to booleans,
and then work with boolean logic! *) Admitted.

Induction on evidence for the "less than" relation in coq

I am working on the proof of the following theorem Sn_le_Sm__n_le_m in IndProp.v of Software Foundations (Vol 1: Logical Foundations).
Theorem Sn_le_Sm__n_le_m : ∀n m,
S n ≤ S m → n ≤ m.
Proof.
intros n m HS.
induction HS as [ | m' Hm' IHm'].
- (* le_n *) (* Failed Here *)
- (* le_S *) apply IHSm'.
Admitted.
where, the definition of le (i.e., ≤) is:
Inductive le : nat → nat → Prop :=
| le_n n : le n n
| le_S n m (H : le n m) : le n (S m).
Notation "m ≤ n" := (le m n).
Before induction HS, the context as well as the goal is as follows:
n, m : nat
HS : S n <= S m
______________________________________(1/1)
n <= m
At the point of the first bullet -, the context as well as the goal is:
n, m : nat
______________________________________(1/1)
n <= m
where we have to prove n <= m without any context, which is obviously impossible.
Why does it not generate S n = S m (and then n = m) for the le_n case in induction HS?
The main problem here -I think- is it is impossible to prove the Theorem using induction on HS as there is no way to say something about n with only hypothesis about S n because non of the constructors of le do not change the value of n. But anyway the reason that after first bullet - there is no assumption is because calling induction has the effect of replacing all occurrences of the property argument by the values that correspond to each constructor and it doesn't help in this case since the term that gets replaced S n is not mentioned anywhere. There are some tricks to avoid this. for example you can replace n with pred(S n) as follows.
Theorem Sn_le_Sm__n_le_m : forall n m,
S n <= S m -> n <= m.
Proof.
intros n m HS.
assert(Hn: n=pred (S n)). reflexivity. rewrite Hn.
assert(Hm: m=pred (S m)). reflexivity. rewrite Hm.
induction HS.
- (* le_n *) apply le_n.
- (* le_S *) (* Stucks! *) Abort.
But as I mentioned above it is impossible to go further. Another way is to use inversion which is smarter but in some cases it may not help since induction hypothesis would be necessary. But it worth to know about it.
Theorem Sn_le_Sm__n_le_m : forall n m,
S n <= S m -> n <= m.
Proof.
intros n m HS.
inversion HS.
- (* le_n *) apply le_n.
- (* le_S *) (* Stucks! *) Abort.
Best way to solve the problem is use of remember tactic as follows.
Theorem Sn_le_Sm__n_le_m : forall n m,
S n <= S m -> n <= m.
Proof.
intros n m HS.
remember (S n) as Sn.
remember (S m) as Sm.
induction HS as [ n' | n' m' H IH].
- (* le_n *)
rewrite HeqSn in HeqSm. injection HeqSm as Heq.
rewrite <- Heq. apply le_n.
- (* le_S *) (* Stucks! *) Abort.
According to Software Foundations (Vol 1: Logical Foundations)
The tactic remember e as x causes Coq to (1) replace all occurrences
of the expression e by the variable x, and (2) add an equation x = e
to the context.
Anyway, although it is impossible to prove the fact using induction on HS -imo-, performing an induction on m will solve the case. (Note the use of inversion.)
Theorem Sn_le_Sm__n_le_m : forall n m,
S n <= S m -> n <= m.
Proof.
intros n.
induction m as [|m' IHm'].
- intros H. inversion H as [Hn | n' contra Hn'].
+ apply le_n.
+ inversion contra.
- intros H. inversion H as [HnSm' | n' HSnSm' Heq].
+ apply le_n.
+ apply le_S. apply IHm'. apply HSnSm'.
Qed.
Just more examples of Kamyar's answer.
Well, let's take a look of le induction scheme :
Compute le_ind.
forall (n : nat) (P : nat -> Prop),
P n ->
(forall m : nat, n <= m -> P m -> P (S m)) ->
forall n0 : nat, n <= n0 -> P n0
P is some proposition that holds one natural number, which means in the case of le_n, our preposition n <= m will be reduced to forall n, n <= m. Indeed, it's the same lemma that we want to prove, however unprovable because there is no premise.
An easy to solve this is doing induction where le_ind doesn't do.
For example :
Theorem Sn_le_Sm__n_le_m' : forall m n,
S n <= S m -> n <= m.
elim.
by intros; apply : Gt.gt_S_le .
intros; inversion H0.
by subst.
by subst; apply : le_Sn_le.
Qed.
Notice that we doing induction by m, and using inversion to generates the two possible construction of le ({x = y} + {x < y}). Optionally, you can use le decidability.
Theorem Sn_le_Sm__n_le_m : forall n m,
S n <= S m -> n <= m.
intros.
generalize dependent n.
elim.
auto with arith.
intros.
have : n <= m.
by apply : H; apply : le_Sn_le.
move => H'.
destruct m.
auto with arith.
destruct (le_lt_eq_dec _ _ H').
assumption.
subst.
(* just prove that there is no S m <= m *)
Qed.
For the sake of your time, coq has the tactic dependent induction that easily solves your goal :
Theorem Sn_le_Sm__n_le_m'' : forall n m,
S n <= S m -> n <= m.
intros.
dependent induction H.
auto.
by apply : (le_Sn_le _ _ H).
Qed.