Proof Process busy on combine_split - coq

I'm doing the Software foundations exercises and doing the combine_split exercise I'm running into a wall when trying to prove an auxiliary lemma.
When applying reflexivity within the assert the Proof Process just hangs there despite the equation just being (x, y) = (x, y) which is obviously true.
Here is the implementation
Theorem combine_split : forall X Y (l : list (X * Y)) l1 l2,
split l = (l1, l2) ->
combine l1 l2 = l.
Proof.
intros X Y.
intros l.
induction l as [| n l' IHl'].
- simpl. intros l1 l2 H. injection H as H1 H2. rewrite <- H1, <-H2. reflexivity.
- destruct n as [n1 n2]. simpl. destruct (split l').
intros l1 l2 H. injection H as H1 H2.
rewrite <- H1, <- H2. simpl.
assert ( Hc : combine x y = l'). { apply IHl'. reflexivity.}
apply Hc.
Qed.
Why is this happening?

Looks like a parsing bug in Proof General, in its sentence splitting. It appears to be sending reflexivity.} to Coq based on the highlighting when you wanted it split into reflexivity. and then } as a separate command. In any case coqc doesn't lex this as desired, interpreting .} as a single (unknown) token. (I'm actually confused why if it's sending reflexivity.} you don't get that lexing error.)
You can fix this by adding a space: reflexivity. }

Related

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

How to prove theorem about list of pairs

I tried to continue proving this practice example that is about list of pairs, but it seems impossible. How should I continue to solve this theorem?
Require Import List.
Fixpoint split (A B:Set)(x:list (A*B)) : (list A)*(list B) :=
match x with
|nil => (nil, nil)
|cons (a,b) x1 => let (ta, tb) := split A B x1 in (a::ta, b::tb)
end.
Theorem split_eq_len :
forall (A B:Set)(x:list (A*B))(y:list A)(z:list B),(split A B x)=(y,z) ->
length y = length z.
Proof.
intros A B x.
elim x.
simpl.
intros y z.
intros H.
injection H.
intros H1 H2.
rewrite <- H1.
rewrite <- H2.
reflexivity.
intros hx.
elim hx.
intros a b tx H y z.
simpl.
intro.
destruct (split A B tx).
I don't want to just give you a proof, but here's one hint:
Your proof will be a bit simpler if you use inversion H instead of injection H and subst instead of rewriting with equalities (subst takes any equality v = expr where v is a variable and substitutes expr for v everywhere; it then clears out the variable v).
Let me show you a couple of steps you can take to advance your proof.
You have ended up in this proof state:
H0 : (a :: l, b :: l0) = (y, z)
============================
length y = length z
At this point it should be obvious that y and z are some non-empty lists. So injection H0. (or inversion H0. as suggested by Tej Chajed) helps you with this.
Then you can change your goal into
length l = length l0
using a combination of simplifications and rewrites (it depends on the exact tactic you use, inversion makes it simpler). You may also find the f_equal tactic very useful. At this point you are almost done because you can now use your induction hypothesis.

Using "rewrite [hypothesis with implication]"

Working through CIS 500 Software Foundations courseCIS 500 Software Foundations course. Currently on MoreCoq. I don't understand the rewrite IHl1 part. How is it working? Why does this not work when used before simpl?
Definition split_combine_statement : Prop := forall X Y (l1 : list X) (l2 : list Y),
length l1 = length l2 -> split (combine l1 l2) = (l1,l2).
Theorem split_combine : split_combine_statement.
Proof. unfold split_combine_statement. intros. generalize dependent Y. induction l1.
Case "l = []". simpl. intros. destruct l2.
SCase "l2 = []". reflexivity.
SCase "l2 = y :: l2". inversion H.
Case "l = x :: l1". intros. destruct l2.
SCase "l2 = []". inversion H.
SCase "l2 = y :: l2". simpl. rewrite IHl1.
Your hypothesis IHl1 is:
IHl1 : forall (Y : Type) (l2 : list Y),
length l1 = length l2 -> split (combine l1 l2) = (l1, l2)
So in order to rewrite it, you need to instantiate the Y type and l2 list. Next, you need to provide the equality length l1 = length l2 to rewrite
split (combine l1 l2) = (l1,l2). The whole solution is:
Definition split_combine_statement : Prop := forall X Y (l1 : list X) (l2 : list Y),
length l1 = length l2 -> split (combine l1 l2) = (l1,l2).
Theorem split_combine : split_combine_statement.
Proof.
unfold split_combine_statement.
intros. generalize dependent Y. induction l1.
simpl. intros. destruct l2.
reflexivity.
inversion H.
intros. destruct l2.
inversion H.
simpl. inversion H. rewrite (IHl1 Y l2 H1). reflexivity.
Qed.
Note that to rewrite IHl1, we need to instantiate the universal quantifiers (passing adequate values for its variables) and to provide a left hand side for the implication. In Coq words: rewrite (IHl1 Y l2 H1) is passing the type Y to instantiate the forall (Y : Type) in IHl1. The same holds for l2.

How do you determine which terms to call intros on in coq

I am a beginner with coq, so this may be a trivial question. Sometimes I can't figure out which terms I need to call intros on, when writing a Theorem. A simple example,
Theorem silly1 : forall (n m o p : nat),
n = m ->
[n;o] = [n;p] ->
[n;o] = [m;p].
Proof.
intros n m o p eq1 eq2.
rewrite <- eq1.
apply eq2. Qed.
I know based on the goal, that I will probably need to call intros on (n m o p), but why do I need to use it on eq1 and eq2.
Also, in some other Theorems, you may need to use intros on the type parameter, the hypothesis, or the inductive hypothesis. Example
Theorem trans_eq : forall (X:Type) (n m o : X),
n = m -> m = o -> n = o.
Proof.
intros X n m o eq1 eq2. rewrite -> eq1. rewrite -> eq2.
reflexivity. Qed.
Theorem silly3' : forall (n : nat),
(beq_nat n 5 = true -> beq_nat (S (S n)) 7 = true) ->
true = beq_nat n 5 ->
true = beq_nat (S (S n)) 7.
Proof.
intros n eq H.
symmetry in H. apply eq in H. symmetry in H.
apply H. Qed.
So I guess what I'm asking is...when I start proving a theorem, how should I go about reasoning through the goals, to determine which terms I need to call intros on?
An example of what gallais is refering to is this.
Theorem example_1 : forall A B, (A -> B) -> A -> B.
Proof. intros ? ? H1. apply H1. Qed.
Theorem example_2 : forall A B, (A -> B) -> A -> B.
Proof. intros ? ? H1 H2. apply H1. apply H2. Qed.
Print example_1.
Print example_2.
Another example of when it can be problematic is using introduction before using induction. This makes the induction hypothesis different.
Fixpoint reverse_helper {A : Type} (l1 l2 : list A) : list A :=
match l1 with
| nil => l2
| cons x l1 => reverse_helper l1 (cons x l2)
end.
Theorem example_3 : forall A (l1 l2 : list A), reverse_helper l1 l2 = app (reverse_helper l1 nil) l2.
Proof. intros. induction l1. simpl. reflexivity. simpl. try rewrite IHl1. Abort.
Theorem example_4 : forall A (l1 l2 : list A), reverse_helper l1 l2 = app (reverse_helper l1 nil) l2.
Proof. induction l1. intros. simpl. reflexivity. intros. simpl. rewrite (IHl1 (cons a l2)). rewrite (IHl1 (cons a nil)). Admitted.
Otherwise, you should use introduction whenever you can. You won't be able to use whatever is being quantified over or the antecedents of an implication until you do.
By the way
H1 : A1
...
Hn : An
___
B
is equivalent to
H1: A1, ..., Hn: An ⊢ B.
When you prove something interactively, you're using a sequent calculus starting from the conclusion and working your way back to the hypotheses.