Proving increasing iota in Coq
Question
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.
I use 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).
And we want to prove:
forall n : nat, In n (iota n) -> False
So far, I have managed to the following:
forall n : nat, In n (iota n) -> Falseforall n : nat, In n (iota n) -> Falsen: nat
H: In n (iota n)FalseH: In 0 (iota 0)Falsen: nat
H: In (S n) (iota (S n))
IHn: In n (iota n) -> FalseFalseH: In 0 (iota 0)Falsecontradiction.H: FalseFalsen: nat
H: In (S n) (iota (S n))
IHn: In n (iota n) -> FalseFalsen: nat
H: In (S n) (iota n ++ [n])
IHn: In n (iota n) -> FalseFalsen: nat
H: In (S n) (iota n)
IHn: In n (iota n) -> FalseFalsen: nat
H: In (S n) (iota n ++ [n])
IHn: In n (iota n) -> False~ In (S n) [n]n: nat
H: In (S n) (iota n ++ [n])
IHn: In n (iota n) -> False~ In (S n) [n]n: nat
H: In (S n) (iota n ++ [n])
IHn: In n (iota n) -> FalseIn (S n) [n] -> Falsen: nat
H: In (S n) (iota n ++ [n])
IHn: In n (iota n) -> False
H0: In (S n) [n]Falsen: nat
H: In (S n) (iota n ++ [n])
IHn: In n (iota n) -> False
H0: n = S n \/ FalseFalsen: nat
H: In (S n) (iota n ++ [n])
IHn: In n (iota n) -> False
H0: n = S nFalsen: nat
H: In (S n) (iota n ++ [n])
IHn: In n (iota n) -> False
H0: FalseFalsen: nat
H: In (S n) (iota n ++ [n])
IHn: In n (iota n) -> False
H0: n = S nFalsecontradiction.n: nat
H: In (S n) (iota n ++ [n])
IHn: In n (iota n) -> False
H0: n = S n
H1: n <> S nFalseapply H0.n: nat
H: In (S n) (iota n ++ [n])
IHn: In n (iota n) -> False
H0: FalseFalsen: nat
H: In (S n) (iota n)
IHn: In n (iota n) -> FalseFalsen: nat
H: In (S n) (iota n)
IHn: In n (iota n) -> FalseFalseAbort.n: nat
H: In (S n) (iota n)
IHn: In n (iota n) -> FalseIn n (iota n)
However, I am completely stuck, I need to somehow show that: In n (iota n) assuming In (S n) (iota n).
Answer
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:
forall n k : nat, n <= k -> In k (iota n) -> Falseforall n k : nat, n <= k -> In k (iota n) -> Falsek: nat
nlek: 0 <= k
kin: In k (iota 0)Falsen: nat
IHn: forall k : nat, n <= k -> In k (iota n) -> False
k: nat
nlek: S n <= k
kin: In k (iota (S n))Falsecbn in kin; contradiction.k: nat
nlek: 0 <= k
kin: In k (iota 0)Falsen: nat
IHn: forall k : nat, n <= k -> In k (iota n) -> False
k: nat
nlek: S n <= k
kin: In k (iota (S n))Falsen: nat
IHn: forall k : nat, n <= k -> In k (iota n) -> False
k: nat
nlek: S n <= k
kin: In k (iota n)Falsen: nat
IHn: forall k : nat, n <= k -> In k (iota n) -> False
k: nat
nlek: S n <= k
kin: In k (iota n ++ [n])~ In k [n]n: nat
IHn: forall k : nat, n <= k -> In k (iota n) -> False
k: nat
nlek: S n <= k
kin: In k (iota n)Falsen: nat
IHn: forall k : nat, n <= k -> In k (iota n) -> False
k: nat
nlek: S n <= k
kin: In k (iota n)n <= kn: nat
IHn: forall k : nat, n <= k -> In k (iota n) -> False
k: nat
nlek: S n <= k
kin: In k (iota n)In k (iota n)transitivity (S n); eauto.n: nat
IHn: forall k : nat, n <= k -> In k (iota n) -> False
k: nat
nlek: S n <= k
kin: In k (iota n)n <= kassumption.n: nat
IHn: forall k : nat, n <= k -> In k (iota n) -> False
k: nat
nlek: S n <= k
kin: In k (iota n)In k (iota n)n: nat
IHn: forall k : nat, n <= k -> In k (iota n) -> False
k: nat
nlek: S n <= k
kin: In k (iota n ++ [n])~ In k [n]k: nat
H: In k [k]
kin: In k (iota k ++ [k])
nlek: S k <= k
IHn: forall k0 : nat, k <= k0 -> In k0 (iota k) -> FalseFalsen: nat
IHn: forall k : nat, n <= k -> In k (iota n) -> False
k: nat
nlek: S n <= k
kin: In k (iota n ++ [n])
H: In k [n]
H0: In k []Falseapply (Nat.nle_succ_diag_l _ nlek).k: nat
H: In k [k]
kin: In k (iota k ++ [k])
nlek: S k <= k
IHn: forall k0 : nat, k <= k0 -> In k0 (iota k) -> FalseFalsecontradiction. Qed.n: nat
IHn: forall k : nat, n <= k -> In k (iota n) -> False
k: nat
nlek: S n <= k
kin: In k (iota n ++ [n])
H: In k [n]
H0: In k []False
from which you can derive t1 as a corollary:
intro n; apply (t n n); reflexivity. Qed.forall n : nat, In n (iota n) -> False
If you want to peek at the proof of t, you can have a look at this self-contained gist
Q: Interesting - how does one get the intuition for when something's impossible to prove with its current formulation - is it that either some of the assumptions or the inductive hypothesis would be directly (or indirectly) in contradiction with the conclusion? Or is there a notion of "not sufficient / strong" enough inductive hypothesis? How can one tell? (This is obvious once you show me, but figuring this out myself...)
A: Experience mostly. But whenever two things are in lockstep or one value is fixed to be a constant and that prevents you from using the induction hypothesis, that's a strong smell that you may want to look for a more general statement. This blog post sets up a number of exercises where you have to generalize the induction hypothesis to make it work. You may want to look into it.