I'm new to Coq. I'm confused about the proof below:
Lemma nth_eq : forall {A} (l1 l2 : list A),
length l1 = length l2 ->
(forall d k, nth k l1 d = nth k l2 d) ->l1 = l2.
Proof.
intros.
The result shows:
1 subgoal
A : Type
l1, l2 : list A
H : length l1 = length l2
H0 : forall (d : A) (k : nat), nth k l1 d = nth k l2 d
______________________________________(1/1)
l1 = l2
The inference is obvious by using H0 and H but I don't know how to use H0 to finish the proof. Thank you very much for your help!
Since it's been a while and the OP hasn't responded to the comment by gallais, I'll put a solution here which should hopefully be easy to follow stepping through the proof in an IDE.
Require Import List.
Lemma nth_eq : forall {A} (l1 l2 : list A),
length l1 = length l2 ->
(forall d k, nth k l1 d = nth k l2 d) ->l1 = l2.
Proof.
(* shortcut to the below:
induction l1; destruct l2; try discriminate 1.
will eliminate two of the cases for you *)
induction l1; destruct l2.
+ reflexivity.
+ discriminate 1.
+ discriminate 1.
+ intros. f_equal.
- specialize H0 with (d := a) (k := 0). simpl in H0. assumption.
- apply IHl1.
* simpl in H. injection H. trivial.
* intros. specialize H0 with (d := d) (k := S k). simpl in H0.
assumption.
Qed.
Related
I tried following proof,
Require Import List Omega.
Import ListNotations.
Variable X : Type.
Lemma length_n_nth_app_error_same : forall (n:nat) (x:X) (l:list X),
n <= length l -> 0 < n -> nth_error l n = nth_error (l ++ [x]) n .
Proof.
intros.
induction l eqn:eqHl.
- unfold length in H. omega.
-
but I'm stuck, as what I have is only
1 subgoal
n : nat
x : X
l : list X
a : X
l0 : list X
eqHl : l = a :: l0
H : n <= length (a :: l0)
H0 : 0 < n
IHl0 : l = l0 ->
n <= length l0 ->
nth_error l0 n = nth_error (l0 ++ [x]) n
______________________________________(1/1)
nth_error (a :: l0) n = nth_error ((a :: l0) ++ [x]) n
I've met some similar cases also for other proofs on lists.
I don't know if the usual induction would be useful here.
How should I prove this?
Should I use generalize?
Your theorem is wrong. Maybe your understanding of nth_error is incorrect.
Specifically, when n = length l, nth_error l n returns None while nth_error (l ++ [x]) n returns Some x.
Require Import List Omega.
Import ListNotations.
Lemma length_n_nth_app_error_not_always_same :
(forall (n:nat) (X:Type) (x:X) (l:list X),
n <= length l -> 0 < n -> nth_error l n = nth_error (l ++ [x]) n)
-> False.
Proof.
intros.
assert (1 <= 1) by omega. assert (0 < 1) by omega.
specialize (H 1 nat 2 [1] H0 H1). simpl in H. inversion H. Qed.
On the other hand, proving a similar theorem with fixed inequality is easy:
Lemma length_n_nth_app_error_same : forall (n:nat) (X:Type) (x:X) (l:list X),
n < length l -> nth_error l n = nth_error (l ++ [x]) n .
Proof.
induction n; intros.
- simpl. destruct l; simpl in *.
+ omega.
+ reflexivity.
- simpl. destruct l; simpl in *.
+ omega.
+ apply IHn. omega. Qed.
Note that I used induction n instead of induction l. It is mainly because nth_error does recursive calls on decreasing n.
Also, if you felt like an induction hypothesis is not general enough, it is probably because your order of intros and induction was wrong. The rule of thumb is to start the proof by induction, and then intros the variables. If it is still not enough, you can revert dependent all the variables other than the one to do induction, and then induction x; intros.
I am stuck on a goal.
Assume we have the following definition:
Fixpoint iota (n : nat) : list nat :=
match n with
| 0 => []
| S k => iota k ++ [k]
end.
And we want to prove:
Theorem t1 : forall n, In n (iota n) -> False.
So far, I have managed to the following:
Theorem t1 : forall n, In n (iota n) -> False.
Proof.
intros.
induction n.
- cbn in H. contradiction.
- cbn in H. apply app_split in H.
Focus 2. unfold not. intros.
unfold In in H0. destruct H0. assert (~(n = S n)) by now apply s_inj.
contradiction.
apply H0.
apply IHn.
I used these two lemmas, proofs omitted:
Axiom app_split : forall A x (l l2 : list A), In x (l ++ l2) -> not (In x l2) -> In x l.
Axiom s_inj : forall n, ~(n = S n).
However, I am completely stuck, I need to somehow show that: In n (iota n) assuming In (S n) (iota n).
As you've observed the fact that the n in In n and the one in iota n are in lockstep in your statement makes the induction hypothesis hard to invoke (if not completely useless).
The trick here is to prove a more general statement than the one you are actually interested in which breaks this dependency between the two ns. I would suggest:
Theorem t : forall n k, n <= k -> In k (iota n) -> False.
from which you can derive t1 as a corollary:
Corollary t1 : forall n, In n (iota n) -> False.
intro n; apply (t n n); reflexivity.
Qed.
If you want to peek at the proof of t, you can have a look at this self-contained gist
I am doing an exercise in Coq and trying to prove if a list equals to its reverse, it's a palindrome. Here is how I define palindromes:
Inductive pal {X : Type} : list X -> Prop :=
| emptypal : pal []
| singlpal : forall x, pal [x]
| inducpal : forall x l, pal l -> pal (x :: l ++ [x]).
Here is the theorem:
Theorem palindrome3 : forall {X : Type} (l : list X),
l = rev l -> pal l.
According to my definition, I will need to do the induction my extracting the front and tail element but apparently coq won't let me do it, and if I force it to do so, it gives an induction result that definitely doesn't make any sense:
Proof.
intros X l H. remember (rev l) as rl. induction l, rl.
- apply emptypal.
- inversion H.
- inversion H.
- (* stuck *)
context:
1 subgoals
X : Type
x : X
l : list X
x0 : X
rl : list X
Heqrl : x0 :: rl = rev (x :: l)
H : x :: l = x0 :: rl
IHl : x0 :: rl = rev l -> l = x0 :: rl -> pal l
______________________________________(1/1)
pal (x :: l)
aparently the inductive context is terribly wrong. is there any way I can fix the induction?
The solution I propose here is probably not the shortest one, but I think it is rather natural.
My solution consists in defining an induction principle on list specialized to your problem.
Consider natural numbers. There is not only the standard induction nat_ind where you prove P 0 and forall n, P n -> P (S n). But there are other induction schemes, e.g., the strong induction lt_wf_ind, or the two-step induction where you prove P 0, P 1 and forall n, P n -> P (S (S n)). If the standard induction scheme is not strong enough to prove the property you want, you can try another one.
We can do the same for lists. If the standard induction scheme list_ind is not enough, we can write another one that works. In this idea, we define for lists an induction principle similar to the two-step induction on nat (and we will prove the validity of this induction scheme using the two-step induction on nat), where we need to prove three cases: P [], forall x, P [x] and forall x l x', P l -> P (x :: l ++ [x']). The proof of this scheme is the difficult part. Applying it to deduce your theorem is quite straightforward.
I don't know if the two-step induction scheme is part of the standard library, so I introduce it as an axiom.
Axiom nat_ind2 : forall P : nat -> Prop, P 0 -> P 1 ->
(forall n : nat, P n -> P (S (S n))) -> forall n : nat, P n.
Then we prove the induction scheme we want.
Lemma list_ind2 : forall {A} (P : list A -> Prop) (P_nil : P [])
(P_single : forall x, P [x])
(P_cons_snoc : forall x l x', P l -> P (x :: l ++ [x'])),
forall l, P l.
Proof.
intros. remember (length l) as n. symmetry in Heqn. revert dependent l.
induction n using nat_ind2; intros.
- apply length_zero_iff_nil in Heqn. subst l. apply P_nil.
- destruct l; [discriminate|]. simpl in Heqn. inversion Heqn; subst.
apply length_zero_iff_nil in H0. subst l. apply P_single.
- destruct l; [discriminate|]. simpl in Heqn.
inversion Heqn; subst. pose proof (rev_involutive l) as Hinv.
destruct (rev l). destruct l; discriminate. simpl in Hinv. subst l.
rewrite app_length in H0.
rewrite PeanoNat.Nat.add_comm in H0. simpl in H0. inversion H0.
apply P_cons_snoc. apply IHn. assumption.
Qed.
You should be able to conclude quite easily using this induction principle.
Theorem palindrome3 : forall {X : Type} (l : list X),
l = rev l -> pal l.
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.
I'm new to Coq, but with some effort I was able to prove various inductive lemmas. However I get stuck on all exercises that uses the following inductive definition:
Inductive In (A:Type) (y:A) : list A -> Prop :=
| InHead : forall xs:list A, In y (cons y xs)
| InTail : forall (x:A) (xs:list A), In y xs -> In y (cons x xs).
The furthest i got was with the following lemma:
Lemma my_In_rev : forall (A:Type) (x:A) (l:list A), In x l -> In x (rev l).
Proof.
induction l.
simpl.
trivial.
simpl.
intros.
The following two lemmas I cant get past the first steps, because I get stuck on the exists goal right after using intros.
Lemma my_In_map : forall (A B:Type) (y:B) (f:A->B) (l:list A), In y (map f l) -> exists x : A, In x l /\ y = f x.
Lemma my_In_split : forall (A:Type) (x:A) (l : list A), In x l -> exists l1, exists l2, l = l1 ++ (x::l2).
Proof.
Any help would be appreciated!
For your first lemma, I added two simple sublemmas (that you can find in the list library).
The two others are more straightforward.
Require Import List.
Lemma In_concat_l: forall (A: Type) (l1 l2: list A) (x:A),
In x l1 -> In x (l1 ++ l2).
Proof.
intros A.
induction l1 as [ | hd tl hi ]; intros l2 x hIn; simpl in *.
- contradiction.
- destruct hIn.
+ left; assumption.
+ right; now apply hi.
Qed.
Lemma In_concat_r: forall (A: Type) (l1 l2: list A) (x:A),
In x l2 -> In x (l1 ++ l2).
intros A.
induction l1 as [ | hd tl hi ]; intros l2 x hIn; simpl in *.
- assumption.
- right; now apply hi.
Qed.
Lemma my_In_rev : forall (A:Type) (x:A) (l:list A), In x l -> In x (rev l).
Proof.
intros A x l.
induction l as [ | hd tl hi ]; intros hIn; simpl in *.
- contradiction.
- destruct hIn.
+ apply In_concat_r.
rewrite H.
now constructor.
+ apply In_concat_l.
now apply hi.
Qed.
Lemma my_In_map : forall (A B:Type) (y:B) (f:A->B) (l:list A), In y (map f l) -> exists x : A, In x l /\ y = f x.
Proof.
intros A B y f l.
induction l as [ | hd tl hi]; intros hIn; simpl in *.
- contradiction.
- destruct hIn.
+ exists hd; split.
left; reflexivity.
symmetry; assumption.
+ destruct (hi H) as [x0 [ h1 h2]].
exists x0; split.
right; assumption.
assumption.
Qed.
Lemma my_In_split : forall (A:Type) (x:A) (l : list A), In x l -> exists l1, exists l2, l = l1 ++ (x::l2).
Proof.
intros A x l.
induction l as [ | hd tl hi]; intros hIn; simpl in *.
- contradiction.
- destruct hIn.
rewrite H.
exists nil; exists tl; simpl; reflexivity.
destruct (hi H) as [ l1 [ l2 h ]].
exists (hd :: l1); exists l2.
rewrite <- app_comm_cons; rewrite h.
reflexivity.
Qed.
I won't say it's less complex than Rui's answer, but I find this solution a little bit easier to understand. But in the end, they are relatively close.
Cheers,
V.
When the goal is existentially quantified, you have to give a concrete example of an object with the stated property, and when a hypothesis is existentially quantified, you're allowed to assume one such object exists and introduce it. See FAQs 47, 53, and 54. By the way, an In predicate is already defined in Coq.Lists.List. Check it out here. A reference for Coq tactics is here.
A proof of the first lemma:
Require Import Coq.Lists.List.
Require Import Coq.Setoids.Setoid.
Inductive In {A : Type} (y : A) : list A -> Prop :=
| InHead : forall xs : list A, In y (cons y xs)
| InTail : forall (x : A) (xs : list A), In y xs -> In y (cons x xs).
Lemma L1 : forall (t1 : Type) (l1 : list t1) (o1 o2 : t1),
In o1 (o2 :: l1) <-> o1 = o2 \/ In o1 l1.
Proof.
intros t1 l1 o1 o2. split.
intros H1. inversion H1 as [l2 [H3 H4] | o3 l2 H2 [H3 H4]].
left. reflexivity.
right. apply H2.
intros H1. inversion H1 as [H2 | H2].
rewrite H2. apply InHead.
apply InTail. apply H2.
Qed.
Lemma my_In_map : forall (A B : Type) (l : list A) (y : B) (f : A -> B),
In y (map f l) -> exists x : A, In x l /\ y = f x.
Proof.
intros A B. induction l as [| z l H1].
intros y f H2. simpl in *. inversion H2.
intros y f H2. simpl in *. rewrite L1 in H2. inversion H2 as [H3 | H3].
exists z. split.
apply InHead.
apply H3.
assert (H4 := H1 _ _ H3). inversion H4 as [x [H5 H6]]. exists x. split.
rewrite L1. right. apply H5.
apply H6.
Qed.