Double induction in Coq - double

Basically, I would like to prove that following result:
Lemma nat_ind_2 (P: nat -> Prop): P 0 -> P 1 -> (forall n, P n -> P (2+n)) ->
forall n, P n.
that is the recurrence scheme of the so called double induction.
I tried to prove it applying induction two times, but I am not sure that I will get anywhere this way. Indeed, I got stuck at that point:
Proof.
intros. elim n.
exact H.
intros. elim n0.
exact H0.
intros. apply (H1 n1).

Actually, there's a much simpler solution. A fix allows recursion (aka induction) on any subterm while nat_rect only allows recursion on the immediate subterm of a nat. nat_rect itself is defined with a fix, and nat_ind is just a special case of nat_rect.
Definition nat_rect_2 (P : nat -> Type) (f1 : P 0) (f2 : P 1)
(f3 : forall n, P n -> P (S (S n))) : forall n, P n :=
fix nat_rect_2 n :=
match n with
| 0 => f1
| 1 => f2
| S (S m) => f3 m (nat_rect_2 m)
end.

#Rui's fix solution is quite general. Here is an alternative solution that uses the following observation: when proving this lemma mentally, you use somewhat stronger induction principle. For example if P holds for two consecutive numbers it becomes easy to make it hold for the next pair:
Lemma nat_ind_2 (P: nat -> Prop): P 0 -> P 1 -> (forall n, P n -> P (2+n)) ->
forall n, P n.
Proof.
intros P0 P1 H.
assert (G: forall n, P n /\ P (S n)).
induction n as [ | n [Pn PSn]]; auto.
split; try apply H; auto.
apply G.
Qed.
Here G proves something redundant, yet calling the induction tactic for it brings sufficient context for near-trivial proof.

I think well-founded induction is necessary for that.
Require Import Arith.
Theorem nat_rect_3 : forall P,
(forall n1, (forall n2, n2 < n1 -> P n2) -> P n1) ->
forall n, P n.
Proof.
intros P H1 n1.
apply Acc_rect with (R := lt).
info_eauto.
induction n1 as [| n1 H2].
apply Acc_intro. intros n2 H3. Check lt_n_0. Check (lt_n_0 _). Check (lt_n_0 _ H3). destruct (lt_n_0 _ H3).
destruct H2 as [H2]. apply Acc_intro. intros n2 H3. apply Acc_intro. intros n3 H4. apply H2. info_eauto with *.
Defined.
Theorem nat_rect_2 : forall P,
P 0 ->
P 1 ->
(forall n, P n -> P (S (S n))) ->
forall n, P n.
Proof.
intros ? H1 H2 H3.
induction n as [n H4] using nat_rect_3.
destruct n as [| [| n]].
info_eauto with *.
info_eauto with *.
info_eauto with *.
Defined.

A fun observation: Rui's answer is the fixpoint translation of NonNumeric's answer, which is the generalization of user1861759's answer for any n, not just n = 2.
In other words, these answers are all fine, and actually deeply related to one another, by the correspondence between terminating fixpoints and generalized induction.

Related

Proving increasing iota in Coq

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

How to do induction differently?

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.

COQ gets wrong by proving "forall n:nat, ( n <= 0) -> n=0"

Can someone explain me the following - apparently wrong - COQ derivation?
Theorem test: forall n:nat, ( n <= 0) -> n=0.
intros n H.
elim H.
auto.
COQ answer:
1 subgoal
n : nat
H : n <= 0
=================
forall m : nat, n <= m -> n = m -> n = S m
le (<=) has two constructors. In n <= 0 both (somehow) could apply:
Inductive le (n : nat) : nat -> Prop :=
le_n : n <= n
| le_S : forall m : nat, n <= m -> n <= S m
auto in your proof solves the first goal / case. The second is unprovable. You should do induction on n to prove the theorem:
Theorem test: forall n, n <= 0 -> n = 0.
intros n H.
induction n.
reflexivity.
inversion H. Qed.
or you could use inversion H tactic (not elim):
Theorem test: forall n, n <= 0 -> n = 0.
intros n H.
inversion H.
auto. Qed.
When using induction on a predicate, you usually need to make sure the arguments to the predicate are variables and not terms. You do so by adding some equations. You also usually need to make sure those variables are distinct and that there aren't any unnecessary hypotheses or quantifiers before the predicate.
Goal forall n1, n1 <= 0 -> n1 = 0.
assert (H1 : forall n1 n2, n1 <= n2 -> n2 = 0 -> n1 = 0).
induction 1 as [| n2 H1 H2].
intros H1.
eapply H1.
intros H3.
discriminate.
intros n1 H2.
eapply H1.
eapply H2.
eapply eq_refl.
Qed.
It's the other way around: your original goal doesn't imply the unprovable goal; it's the unprovable goal that implies the original.
The goal
A : B
_____
C
is equivalent to the sequent
A : B |- C.
When proving something interactively in Coq, you are building a sequent tree from bottom to top. Here's an example.
-------------------- apply H
P : Prop, H : P |- P
-------------------- intro H
P : Prop |- P -> P
-------------------------- intro P
|- forall P : Prop, P -> P
Of course, when moving backwards to a proof, you can make a wrong move.
?
------------- ?
P : Prop |- P
-------------------- clear H
P : Prop, H : P |- P
-------------------- intro H
P : Prop |- P -> P
-------------------------- intro P
|- forall P : Prop, P -> P
You can learn more about sequent calculus from all over the internet.

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.

Inductive Predicate for Addition in Coq

I'm new to inductive predicates in Coq. I have learned how to define simple inductive predicates such as "even" (as in adam.chlipala.net/cpdt/html/Predicates.html) or "last" (as in http://www.cse.chalmers.se/research/group/logic/TypesSS05/resources/coq/CoqArt/inductive-prop-chap/SRC/last.v).
Now I wanted to try something slightly more complicated: to define addition as an inductive predicate, but I got stuck. I did the following:
Inductive N : Type :=
| z : N (* zero *)
| s : N -> N. (* successor *)
Inductive Add: N -> N -> N -> Prop :=
| add_z: forall n, (Add n z n)
| add_s: forall m n r, (Add m n r) -> (Add m (s n) (s r)).
Fixpoint plus (x y : N) :=
match y with
| z => x
| (s n) => (s (plus x n))
end.
And I would like to prove a simple theorem (analogously to what has been done for last and last_fun in www.cse.chalmers.se/research/group/logic/TypesSS05/resources/coq/CoqArt/inductive-prop-chap/SRC/last.v):
Theorem T1: forall x y r, (plus x y) = r -> (Add x y r).
Proof.
intros x y r. induction y.
simpl. intro H. rewrite H. apply add_z.
case r.
simpl. intro H. discriminate H.
???
But then I get stuck. The induction hypothesis seems strange. I don't know if I defined Add wrongly, or if I am just using wrong tactics. Could you please help me, by either correcting my inductive Add or telling me how to complete this proof?
You introduced r before using induction on y. In general you'll want to use induction before introducing anything so the induction hypothesis is as general as possible.
Conjecture injectivity : forall n m, s n = s m -> n = m.
Theorem T1: forall x y r, (plus x y) = r -> (Add x y r).
Proof.
intros x y. induction y.
simpl. intros r H. rewrite H. apply add_z.
intro r. case r.
simpl. intro H. discriminate H.
simpl. intros n H. apply add_s. apply IHy. apply injectivity. apply H.
Qed.