IndProp: prove that Prop is not provable - coq

The task.
Suppose we give Coq the following definition:
Inductive R2 : nat -> list nat -> Prop :=
| c1 : R2 0 []
| c2 : forall n l, R2 n l -> R2 (S n) (n :: l)
| c3 : forall n l, R2 (S n) l -> R2 n l.
Which of the following propositions are provable?
I proved 2 out of 3.
Example Example_R21 : R2 2 [1;0].
Proof.
apply c2. apply c2. apply c1.
Qed.
Example Example_R22 : R2 1 [1;2;1;0].
Proof.
repeat constructor.
Qed.
The 3-rd is not provable, because c3 will only increase n, and it will never be equal to the head of list + 1. But how to formally prove that it is not provable?
Example Example_R23 : not (R2 6 [3;2;1;0]).
Proof.
Qed.
Update 1
Fixpoint gen (n: nat) : list nat :=
match n with
| 0 => []
| S n' => (n' :: gen n')
end.
Lemma R2_gen : forall (n : nat) (l : list nat), R2 n l -> l = gen n.
Proof.
intros n l H. induction H.
- simpl. reflexivity.
- simpl. rewrite IHR2. reflexivity.
- simpl in IHR2. ?

You have to proceed by induction on the R2. Basically, if you have R2 6 (3 :: _), then it must be a c3 (no other constructor fits), so it contains an R2 7 (3 :: _), which must also be c3, which contains R2 8 (3 :: _), etc. This chain is infinite, so you'll never reach the end. Therefore, you can use False as the goal of the induction and you will never reach the base case where you actually have to produce False. It is not enough to just use inversion. Inversion is really just one step of the needed induction, and induction on any of the other things in the context doesn't help.
During the induction, the first parameter will vary. Specifically, it will always be more than S 3 (that's what lets us rule out the other constructors), so we need to generalize with respect to k where the first parameter is always 5 + k (starting with k = 1 for our case where we have 6).
Example Example_R23 : not (R2 6 [3;2;1;0]).
Proof.
set (xs := [2; 1; 0]).
change 6 with (5 + 1).
set (x := 3). (* sets are not strictly needed, but help clean things up *)
generalize 1 as k.
intros k.
(* Everything up to here is just generalizing over k *)
remember (S (S x) + k) as n eqn:prf_n.
remember (x :: xs) as l eqn:prf_l.
intros no.
revert k prf_n prf_l.
induction no as [ | n' l' _ _ | n' l' _ rec_no]
; intros k prf_n prf_l.
- discriminate.
- injection prf_l as -> ->.
discriminate.
- subst.
(* Everything up to here is combined inversion and induction *)
eapply rec_no.
+ apply plus_n_Sm.
+ reflexivity.
Defined.
We can reduce this proof immensely by using the experimental dependent induction tactic, which replaces the middle, inversiony part.
Example Example_R23 : not (R2 6 [3;2;1;0]).
Proof.
set (xs := [2; 1; 0]).
change 6 with (5 + 1).
set (x := 3).
generalize 1 as k.
intros k no.
dependent induction no generalizing k.
eapply IHno.
- apply plus_n_Sm.
- reflexivity.
Defined.
Another form of cleanup would be extracting the generalized proof out into a lemma:
Lemma R2_head x k xs : ~R2 (S (S x) + k) (x :: xs).
Proof.
intros no.
dependent induction no generalizing k.
- clear no IHno. (* Another "infinite chain" contradiction *)
rename x into prf_x, x0 into x.
induction x as [ | x rec_x].
+ discriminate.
+ injection prf_x.
apply rec_x.
- eapply IHno.
+ apply plus_n_Sm.
+ reflexivity.
Defined.
Example Example_R232 : not (R2 6 [3;2;1;0]) := R2_head 3 _ _.

Here is a simple proof that uses the goal generalization technique.
First, we prove a more general property than we actually are posed with.
From Coq Require Import Lia.
Lemma R2_len n l : R2 n l -> n <= length l.
Proof. induction 1; simpl; lia. Qed.
Now our example is a simple concrete instance of the more general property.
Example Example_R23 : not (R2 6 [3;2;1;0]).
Proof. intros H%R2_len; simpl in H; lia. Qed.

This is equivalent to #HTNW's proof
Lemma R2_head' {a n l}: R2 a (n::l) -> a <= S n.
intros H; dependent induction H;
try pose proof (IHR2 _ _ eq_refl); lia.
Qed.
Example Example_R23 : not (R2 6 [3;2;1;0]).
Proof. intros C; pose proof (R2_head' C); lia. Qed.

not A is A -> False. You should introduce the absurd hypothesis and reason by cases on it (see the inversion tactic).

You could write a function to generate the list from the nat parameter (let's call it gen) and prove R2 n l -> l = gen n. From that, you can prove your proposition by showing that l <> gen n.

Related

Addition of natural numbers in Coq

Coq's standard libraries give the Peano natural numbers and addition:
Inductive nat : Set :=
| O : nat
| S : nat -> nat.
Fixpoint add n m :=
match n with
| 0 => m
| S p => S (add p m)
end.
I am curious if I change the fix_definition of addition like
Fixpoint add n m :=
match n with
| 0 => m
| S p => add p (S m)
end.
Is the new addition equivalent to the old one? I tried to prove their equivalence by proving forall n m, add (S n) m = S (add n m) but failed.
In order to proof your helper lemma, you need to be careful what to introduce. If you don't introduce m, you get a more general induction hypothesis as in:
Require Import Nat.
Print add.
Fixpoint my_add n m :=
match n with
| 0 => m
| S p => my_add p (S m)
end.
Lemma my_add_S_r: forall n m, my_add n (S m) = S (my_add n m).
Proof.
(* Note: don't introduce m here - you get a more general induction hypothesis this way *)
intros n.
induction n.
- intros; reflexivity.
- intros; cbn. rewrite IHn. reflexivity.
Qed.
Lemma my_add_equiv: forall n m, add n m = my_add n m.
intros.
induction n.
- reflexivity.
- cbn. rewrite my_add_S_r. rewrite IHn. reflexivity.
Qed.
Yes both additions are equivalent, you can prove it using the lemma plus_n_Sm : forall n m : nat, S (n + m) = n + S m from the standard library (found using Search "+" (S _).) and an adequate induction hypothesis (for instance P(n) := forall m, n + m = add n m).

Proof irrelevance for boolean equality

I'm trying to prove group axioms for Z_3 type:
Require Import Coq.Arith.PeanoNat.
Record Z_3 : Type := Z3
{
n :> nat;
proof : (Nat.ltb n 3) = true
}.
Proposition lt_0_3 : (0 <? 3) = true.
Proof.
simpl. reflexivity.
Qed.
Definition z3_0 : Z_3 := (Z3 0 lt_0_3).
Proposition lt_1_3 : (1 <? 3) = true.
Proof.
reflexivity.
Qed.
Definition z3_1 : Z_3 := (Z3 1 lt_1_3).
Proposition lt_2_3 : (2 <? 3) = true.
Proof.
reflexivity.
Qed.
Definition z3_2 : Z_3 := (Z3 2 lt_2_3).
Proposition three_ne_0 : 3 <> 0.
Proof.
discriminate.
Qed.
Lemma mod_upper_bound_bool : forall (a b : nat), (not (eq b O)) -> (Nat.ltb (a mod b) b) = true.
Proof.
intros a b H. apply (Nat.mod_upper_bound a b) in H. case Nat.ltb_spec0.
- reflexivity.
- intros Hcontr. contradiction.
Qed.
Definition Z3_op (x y: Z_3) : Z_3 :=
let a := (x + y) mod 3 in
Z3 a (mod_upper_bound_bool _ 3 three_ne_0).
Lemma Z3_eq n m p q : n = m -> Z3 n p = Z3 m q.
Proof.
intros H. revert p q. rewrite H. clear H. intros. apply f_equal.
We are almost done:
1 subgoal (ID 41)
n, m : nat
p, q : (m <? 3) = true
============================
p = q
What theorem should I use to prove that p = q?
Update 1
Theorem bool_dec :
(forall x y: bool, {x = y} + {x <> y}).
Proof.
intros x y. destruct x.
- destruct y.
+ left. reflexivity.
+ right. intro. discriminate H.
- destruct y.
+ right. intro. discriminate H.
+ left. reflexivity.
Qed.
Lemma Z3_eq n m p q : n = m -> Z3 n p = Z3 m q.
Proof.
intros H. revert p q. rewrite H. clear H. intros. apply f_equal. apply UIP_dec. apply bool_dec.
Qed.
You are probably interested in knowing that every two proofs of a decidable equality are equal. This is explained and proved here: https://coq.inria.fr/library/Coq.Logic.Eqdep_dec.html
You are interested in particular in the lemma UIP_dec: https://coq.inria.fr/library/Coq.Logic.Eqdep_dec.html#UIP_dec
Theorem UIP_dec :
forall (A:Type),
(forall x y:A, {x = y} + {x <> y}) ->
forall (x y:A) (p1 p2:x = y), p1 = p2.
You will have then to prove that equalities of booleans are decidable (i.e. that you can write a function which says whether two given booleans are equal or not) which you should also be able to find in the standard library but which should be easily provable by hand as well.
This is a different question but since you asked: bool_dec exists and even has that name!
The easy way to find it is to use the command
Search sumbool bool.
It will turn up several lemmata, including pretty early:
Bool.bool_dec: forall b1 b2 : bool, {b1 = b2} + {b1 <> b2}
Why did I search sumbool? sumbool is the type which is written above:
{ A } + { B } := sumbool A B
You can find it using the very nice Locate command:
Locate "{".
will turn up
"{ A } + { B }" := sumbool A B : type_scope (default interpretation)
(and other notations involving "{").

Z_3: left id proof

I am close to ending the proof for Z_3 left id. Here is what I have so far
Require Import Coq.Arith.PeanoNat.
Require Import Coq.Bool.Bool.
Require Import Coq.Logic.Eqdep_dec.
Record Z_3 : Type := Z3
{
n :> nat;
proof : (Nat.ltb n 3) = true
}.
Proposition lt_0_3 : (0 <? 3) = true.
Proof.
simpl. reflexivity.
Qed.
Definition z3_0 : Z_3 := (Z3 0 lt_0_3).
Proposition lt_1_3 : (1 <? 3) = true.
Proof.
reflexivity.
Qed.
Definition z3_1 : Z_3 := (Z3 1 lt_1_3).
Proposition lt_2_3 : (2 <? 3) = true.
Proof.
reflexivity.
Qed.
Definition z3_2 : Z_3 := (Z3 2 lt_2_3).
Proposition three_ne_0 : 3 <> 0.
Proof.
discriminate.
Qed.
Lemma mod_upper_bound_bool : forall (a b : nat), b <> O -> (a mod b <? b) = true.
Proof.
intros a b H. apply (Nat.mod_upper_bound a b) in H. case Nat.ltb_spec0.
- reflexivity.
- intros Hcontr. contradiction.
Qed.
Definition Z3_op (x y: Z_3) : Z_3 :=
let a := (x + y) mod 3 in
Z3 a (mod_upper_bound_bool _ 3 three_ne_0).
Lemma Z3_eq n m p q : n = m -> Z3 n p = Z3 m q.
Proof.
intros H. revert p q. rewrite H. clear H. intros. apply f_equal. apply UIP_dec. apply bool_dec.
Qed.
Proposition Z3_left_id' : forall x: Z_3, (Z3_op z3_0 x) = x.
Proof.
intro. unfold Z3_op. destruct x as [n proof]. apply Z3_eq.
Result:
1 subgoal (ID 46)
n : nat
proof : (n <? 3) = true
============================
(z3_0 + {| n := n; proof := proof |}) mod 3 = n
I found the following theorems that could be useful:
Nat.ltb_spec0
: forall x y : nat, reflect (x < y) (x <? y)
Nat.mod_small: forall a b : nat, a < b -> a mod b = a
Is it possible to get rid of profs in the goal, convert proof from bool to Prop, and then use Nat.mod_small?
Update
Proposition Z3_left_id' : forall x: Z_3, (Z3_op z3_0 x) = x.
Proof.
intro. unfold Z3_op. destruct x as [vx proof]. apply Z3_eq. unfold n, z3_0. rewrite plus_O_n. apply Nat.mod_small.
1 subgoal (ID 67)
vx : nat
proof : (vx <? 3) = true
============================
vx < 3
You need the coercion to execute. Unfortunately,
by naming the bound variable of your proof n and the projection from Z_3 to nat n, you painted yourself in a corner.
Here are four solutions:
1/ this one I mention just for the record: you can talk about the constant n that was defined in this file by using the file name as a module qualifier.
unfold user4035_oct_16.n.
user4035_oct_16 is the name of the current file, this is ugly.
2/ you could call a computation function that computes everything, however computation of modulo leaves unsightly terms in the goal, so you could decide to not compute that particular part.
cbn -[Nat.modulo].
I like this one, but it requires that you spend sometime learning how to use cbn.
3/ You can avoid the name clash by renaming variables in the goal.
rename n into m.
unfold n, Z3_0.
Not very nice either.
4/ Just go back in your script and replace destruct x as [n proof] with destruct x as [vx proof], then you can type:
unfold n, z3_0.
you will be able to use the lemmas you suggest.
Proof:
Proposition Z3_left_id : forall x: Z_3, (Z3_op z3_0 x) = x.
Proof.
intro. unfold Z3_op. destruct x as [vx proof]. apply Z3_eq. unfold n, z3_0. rewrite plus_O_n. apply Nat.mod_small. apply Nat.ltb_lt in proof. assumption.
Qed.

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.