How to prove decidability of a partial order inductive predicate? - coq

Context
I am trying to define the partial order A ≤ B ≤ C with a relation le in Coq and prove that it is decidable: forall x y, {le x y} + {~le x y}.
I succeeded to do it through an equivalent boolean function leb but cannot find a way to prove it directly (or le_antisym for that mater). I get stuck in situations like the following:
1 subgoal
H : le C A
______________________________________(1/1)
False
Questions
How can I prove, that le C A is a false premise?
Is there an other other proof strategy that I should use?
Should I define my predicate le differently?
Minimal executable example
Require Import Setoid.
Ltac inv H := inversion H; clear H; subst.
Inductive t : Set := A | B | C.
Ltac destruct_ts :=
repeat match goal with
| [ x : t |- _ ] => destruct x
end.
Inductive le : t -> t -> Prop :=
| le_refl : forall x, le x x
| le_trans : forall x y z, le x y -> le y z -> le x z
| le_A_B : le A B
| le_B_C : le B C .
Definition leb (x y : t) : bool :=
match x, y with
| A, _ => true
| _, C => true
| B, B => true
| _, _ => false
end.
Theorem le_iff_leb : forall x y,
le x y <-> leb x y = true.
Proof.
intros x y. split; intro H.
- induction H; destruct_ts; simpl in *; congruence.
- destruct_ts; eauto using le; simpl in *; congruence.
Qed.
Theorem le_antisym : forall x y,
le x y -> le y x -> x = y.
Proof.
intros x y H1 H2.
rewrite le_iff_leb in *. (* How to prove that without using [leb]? *)
destruct x, y; simpl in *; congruence.
Qed.
Theorem le_dec : forall x y, { le x y } + { ~le x y }.
intros x y.
destruct x, y; eauto using le.
- apply right.
intros H. (* Stuck here *)
inv H.
rewrite le_iff_leb in *.
destruct y; simpl in *; congruence.
- apply right.
intros H; inv H. (* Same thing *)
rewrite le_iff_leb in *.
destruct y; simpl in *; congruence.
- apply right.
intros H; inv H. (* Same thing *)
rewrite le_iff_leb in *.
destruct y; simpl in *; congruence.
Qed.

The problem with le is the transitivity constructor: when doing inversion or induction on a proof of le x y, we know nothing about the middle point that comes out of the transitivity case, which often leads to failed proof attempts. You can prove your result with an alternative (but still inductive) characterization of the relation:
Require Import Setoid.
Ltac inv H := inversion H; clear H; subst.
Inductive t : Set := A | B | C.
Inductive le : t -> t -> Prop :=
| le_refl : forall x, le x x
| le_trans : forall x y z, le x y -> le y z -> le x z
| le_A_B : le A B
| le_B_C : le B C .
Inductive le' : t -> t -> Prop :=
| le'_refl : forall x, le' x x
| le'_A_B : le' A B
| le'_B_C : le' B C
| le'_A_C : le' A C.
Lemma le_le' x y : le x y <-> le' x y.
Proof.
split.
- intros H.
induction H as [x|x y z xy IHxy yz IHyz| | ]; try now constructor.
inv IHxy; inv IHyz; constructor.
- intros H; inv H; eauto using le.
Qed.
Theorem le_antisym : forall x y,
le x y -> le y x -> x = y.
Proof.
intros x y.
rewrite 2!le_le'.
intros []; trivial; intros H; inv H.
Qed.
Theorem le_dec : forall x y, { le x y } + { ~le x y }.
intros x y.
destruct x, y; eauto using le; right; rewrite le_le';
intros H; inv H.
Qed.
In this case, however, I think that using an inductive characterization of le is not a good idea, because the boolean version is more useful. Naturally, there are occasions where you would like two characterizations of a relation: for instance, sometimes you would like a boolean test for equality on a type, but would like to use = for rewriting. The ssreflect proof language makes it easy to work in this style. For instance, here is another version of your first proof attempt. (The reflect P b predicate means that the proposition P is equivalent to the assertion b = true.)
From mathcomp Require Import ssreflect ssrfun ssrbool.
Inductive t : Set := A | B | C.
Inductive le : t -> t -> Prop :=
| le_refl : forall x, le x x
| le_trans : forall x y z, le x y -> le y z -> le x z
| le_A_B : le A B
| le_B_C : le B C .
Definition leb (x y : t) : bool :=
match x, y with
| A, _ => true
| _, C => true
| B, B => true
| _, _ => false
end.
Theorem leP x y : reflect (le x y) (leb x y).
Proof.
apply/(iffP idP); first by case: x; case y=> //=; eauto using le.
by elim=> [[]| | |] //= [] [] [].
Qed.
Theorem le_antisym x y : le x y -> le y x -> x = y.
Proof. by case: x; case: y; move=> /leP ? /leP ?. Qed.
Theorem le_dec : forall x y, { le x y } + { ~le x y }.
Proof. by move=> x y; case: (leP x y); eauto. Qed.

I'd also go with Arthur's solution. But let me demonstrate another approach.
First, we'll need a couple of supporting lemmas:
Lemma not_leXA x : x <> A -> ~ le x A.
Proof. remember A; intros; induction 1; subst; firstorder congruence. Qed.
Lemma not_leCX x : x <> C -> ~ le C x.
Proof. remember C; intros; induction 1; subst; firstorder congruence. Qed.
Now we can define le_dec:
Definition le_dec x y : { le x y } + { ~le x y }.
Proof.
destruct x, y; try (left; abstract constructor).
- left; abstract (eapply le_trans; constructor).
- right; abstract now apply not_leXA.
- right; abstract now apply not_leCX.
- right; abstract now apply not_leCX.
Defined.
Notice that I used Defined instead of Qed -- now you can calculate with le_dec, which is usually the point of using the sumbool type.
I also used abstract to conceal the proof terms from the evaluator. E.g. let's imagine I defined a le_dec' function which is the same as le_dec, but with all abstract removed, then we would get the following results when trying to compute le_dec B A / le_dec' B A :
Compute le_dec B A.
(* ==> right le_dec_subproof5 *)
and
Compute le_dec' B A.
(* ==> right
(not_leXA B
(fun x : B = A =>
match x in (_ = x0) return (x0 = A -> False) with
| eq_refl =>
fun x0 : B = A =>
match
match
x0 in (_ = x1)
return match x1 with
| B => True
| _ => False
end
with
| eq_refl => I
end return False
with
end
end eq_refl)) *)

Note that you can make use of the definitions in Relations to define your order relation. For instance, it contains a definition of reflexive and transitive closure named clos_refl_trans. The resulting proofs are similar to those based on your definitions (cf. #Anton's answer).
Require Import Relations.
Inductive t : Set := A | B | C.
Inductive le : t -> t -> Prop :=
| le_A_B : le A B
| le_B_C : le B C.
Definition le' := clos_refl_trans _ le.
Lemma A_minimal : forall x, x <> A -> ~ le' x A.
Proof.
intros. intros contra. remember A as a. induction contra; subst.
- inversion H0.
- contradiction.
- destruct y; apply IHcontra2 + apply IHcontra1; congruence.
Qed.
Lemma C_maximal : forall x, x <> C -> ~ le' C x.
Proof.
intros. intros contra. remember C as c. induction contra; subst.
- inversion H0.
- contradiction.
- destruct y; apply IHcontra2 + apply IHcontra1; congruence.
Qed.
Lemma le'_antisym : forall x y,
le' x y -> le' y x -> x = y.
Proof.
intros. induction H.
- destruct H.
+ apply A_minimal in H0; try discriminate. contradiction.
+ apply C_maximal in H0; try discriminate. contradiction.
- reflexivity.
- fold le' in *. rewrite IHclos_refl_trans1 by (eapply rt_trans; eassumption).
apply IHclos_refl_trans2; (eapply rt_trans; eassumption).
Qed.

Related

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

Implementing SKI conversion - prove that returning value has promised type

I'm trying to implement a function extract which takes an expression like (f (g x y)) together with a variable e.g. y and produces a function y --> (f (g x y)) with SKI combinators. In this case, the result should be (S (K f) (g x)).
In some sense, I'm doing a conversion from lambda term to its SKI version.
I'm trying to do a typed version of this and I'm having hard times.
Set up
Types in these expressions are represented by the following inductive type
Inductive type : Type :=
| base_type : forall (n : nat), type
| arrow_type : type -> type -> type.
Basically, I have some basic types indexed by integers(base_type) and also I can create function types between them (arrow_type)
Introduce notation for function types
Notation "A --> B" := (arrow_type A B) (at level 30, right associativity).
Expression are represented by the following inductive type
Inductive term : type -> Type :=
| var : forall (n : nat) (A : type), term A
| eval : forall {A B : type}, term (A-->B) -> term A -> term B
| I : forall (A : type) , term (A --> A)
| K : forall (A B : type) , term (A --> (B --> A))
| S : forall (A X Y : type), term ((A --> X --> Y) --> (A --> X) --> A --> Y).
Here, I have again set of basic variables indexed by integers n : nat and a type A : type (not Type!)
Thus, a variable x : term X is an expression with type X.
To reduce eyesore, let's introduce notation for function evaluation
Notation "f [ x ]" := (eval f x) (at level 25, left associativity).
Introductory example
The original question can be stated more precisely as follows.
Let's start with defining with some types
Notation X := (base_type 0).
Notation Y := (base_type 1).
Define variables x y and functions f g (they can be all indexed with 0 because they all have different type)
Notation x := (var 0 X).
Notation y := (var 0 Y).
Notation g := (var 0 (X --> Y --> X)).
Notation f := (var 0 (X --> Y)).
The type of the resulting expression is Y.
Check f[g[x][y]].
My goal is to produce a function extract such that
extract f[g[x][y]] y
produces
S[K[f]][g[x]]
with type filled in
(S Y X Y)[(K (X-->Y) Y)[f]][g[x]]
Equality on type and term
To proceed with an attempt to define extract I need to define equality on type and term.
Require Import Arith.EqNat.
Open Scope bool_scope.
Fixpoint eq_type (A B : type) : bool :=
match A, B with
| base_type n, base_type m => beq_nat n m
| arrow_type X Y, arrow_type X' Y' => (eq_type X X') && (eq_type Y Y')
| _, _ => false
end.
Fixpoint eq_term {A B : type} (a : term A) (b : term B) : bool :=
match a, b with
| var n X , var n' X' => (beq_nat n n') && (eq_type X X')
| eval X Y f x , eval X' Y' f' x' => (eq_type X X') && (eq_type Y Y') && (eq_term f f') && (eq_term x x')
| I X , I X' => (eq_type X X')
| K X Y , K X' Y' => (eq_type X X') && (eq_type Y Y')
| S Z X Y , S Z' X' Y' => (eq_type X X') && (eq_type Y Y') && (eq_type Z Z')
| _ , _ => false
end.
Attempt at implementing extract
The 'implementation' is quite straightforward
Fixpoint extract {A B : type} (expr : term B) (val : term A) : term (A-->B) :=
if (eq_term expr val)
then (I A)
else
match expr with
| eval X Y f x => (S A X Y)[extract f val][extract x val]
| _ => (K B A)[expr]
end.
There are two problems
When returning I A: type of I A is A --> A not A --> B as promised, but in that particular case I should be able to prove that B and A are the same.
When returning (S A X Y)[...: the returning value is A --> Y and not A --> B, but again I should be able to prove that Y is equal to B.
How can I prove B=A and Y=B in those particular cases such that the function definition is accepted?
What you can do is turn eq_type and eq_term from boolean functions into decision procedures for equality. Currently, as far as I can tell, your equality is entirely syntactic. So you could simply use Coq's notion of equality to talk about equality of terms and types. Then, you can write:
Definition eq_type_dec (A B : type) : { A = B } + { A <> B }.
You pretty much do the pattern match on A and B, then return left eq_refl for the cases of equality, and right ... in the other cases, where ... is whatever you need to do to prove disequality.
Do the same and define eq_term_dec. You have two choices here, either making the equality of types intrinsic or extrinsic:
Definition eq_term_dec (A B : type) (a : A) (b : B) :
{ (A = B) * (existT (fun t => t) A a = existT (fun t => t) B b) }
+
{ (A <> B) + (existT (fun t => t) A a <> existT (fun t => t) B b) }.
or:
Definition eq_term_dec (A : type) (a b : term A) : { a = b } + { a <> b }.
The first one seems pretty awful to write, but gives you more flexibility. I'd probably favor the latter, and use it under a eq_type_check when dealing with possibly-unequal types.
Once you have those, you can turn your if into a dependent match:
Fixpoint extract {A B : type} (expr : term B) (val : term A) : term (A-->B) :=
match eq_type_dec A B with
| left eqAB =>
match eqAB
in eq _ B1
return term B1 -> term (A --> B1)
with
| eq_refl => fun expr1 => (* now expr1 : A *)
match eq_expr_dec _ _ expr1 val with
| left eqab => I A
| right neqab => (* ... *)
end
end expr (* note here we pass the values that must change type *)
| right neqAB => (* ... *)
end.
There might still be quite a bit of work in the branches I have elided. You might look at different ways of doing such dependently-typed programming, either manually like I have shown here, or using dependent elimination tactics, or using the recursors of those types.
EDIT
To answer your comment, here are twp ways I know of writing eq_term_dec. One way is to use the Program extension of Coq, which adds one axiom and becomes much more capable of dealing with dependent types:
Require Import Program.Equality.
Fixpoint eq_term_dec (A : type) (a b : term A) : { a = b } + { a <> b }.
dependent induction a; dependent induction b; try (right ; congruence).
- destruct (PeanoNat.Nat.eq_dec n n0); [ left | right ]; congruence.
The other way is to actually figure out the dependently-typed term you need. There has to be a way of doing so using tactics, but I'm not quite sure how to proceed, however, I know how to write the term. It is not for the faint of heart, and I don't expect you to understand what's going on until after you have become familiar with dependent pattern-matching and the "convoy pattern". Here it is if you want to see what this looks like:
Fixpoint eq_term_dec (A : type) (a b : term A) : { a = b } + { a <> b }.
revert b.
destruct a.
{
destruct b; try (right ; congruence).
destruct (PeanoNat.Nat.eq_dec n n0) ; [ left | right ] ; congruence.
}
{ destruct b; admit. (* skipping this, it's easy *) }
{
(* Here is the complication: *)
(* `b` has type `term (A -> A)` *)
(* If you abstract over its type, the goal is ill-typed, because the equality *)
(* `I A = b` is at type `A -> A`. *)
intros b.
refine (
(fun (T : type) (ia : term T) (b : term T) =>
match b
as b1
in term T1
return forall (ia0 : term T1),
match T1 as T2 return term T2 -> term T2 -> Type with
| arrow_type Foo Bar => fun ia1 b2 => {ia1 = b2} + {ia1 <> b2}
| _ => fun _ _ => True
end ia0 b1
with
| var n a => fun b => _
| eval h a => fun b => _
| I A => fun b => _
| K A B => fun b => _
| S A B C => fun b => _
end ia
) (A --> A) (I A) b
).
(* from now on it's easy to proceed *)
destruct a.
easy.
destruct b; try ( right ; congruence ).
destruct (PeanoNat.Nat.eq_dec n n0) ; [ left | right ] ; congruence.
(* one more to show it's easy *)
destruct t0.
easy.
destruct b; try ( right ; congruence ).
(* etc... *)
I have a solution, it is not pretty but it seems to work. Especially, the proof of eq_term_dec is super long and ugly.
If anyone is interested, my solution:
Inductive type : Type :=
| base_type : forall (n : nat), type
| arrow_type : type -> type -> type.
Notation "A --> B" := (arrow_type A B) (at level 30, right associativity).
Inductive term : type -> Type :=
| var : forall (n : nat) (A : type), term A
| eval : forall {A B : type}, term (A-->B) -> term A -> term B
| I : forall {A : type} , term (A --> A)
| K : forall {A B : type} , term (A --> (B --> A))
| S : forall {A X Y : type}, term ((A --> X --> Y) --> ((A --> X) --> (A --> Y))).
(* Coercion term : type >-> Sortclass. *)
Notation "n :: A" := (var n A).
Notation "f [ x ]" := (eval f x) (at level 25, left associativity).
Fixpoint eq_type_dec (A B : type) : {A = B} + {A <> B}.
Proof.
decide equality.
decide equality.
Defined.
Require Import Coq.Logic.Eqdep.
Fixpoint eq_term_dec {A B : type} (a : term A) (b : term B) :
( (A = B) * (existT (fun T : type => term T) A a = existT (fun T : type => term T) B b) )
+
( (A <> B) + (existT (fun T : type => term T) A a <> existT (fun T : type => term T) B b) ).
Proof.
case a as [n X| X Y f x | X | X Y | Z X Y], b as [n' X'| X' Y' f' x' | X' | X' Y' | Z' X' Y'].
(* var n X ? var n' X'*)
- assert (ndec : {n=n'} + {n<>n'}) by decide equality.
pose (Xdec := eq_type_dec X X').
destruct ndec as [eqn | neqn], Xdec as [eqX | neqX].
left.
rewrite eqn.
rewrite eqX.
split; reflexivity.
right; left. apply neqX.
right; right.
intro H; inversion H as [H1]. auto.
right; left. apply neqX.
- right; right; intro H; inversion H. (* n ? f[x] *)
- right; right; intro H; inversion H. (* n ? I *)
- right; right; intro H; inversion H. (* n ? K *)
- right; right; intro H; inversion H. (* n ? S *)
- right; right; intro H; inversion H. (* f[x] ? n *)
- pose (xdec := eq_term_dec _ _ x x').
pose (fdec := eq_term_dec _ _ f f').
destruct xdec, fdec.
(* x = x' && f = f' *)
left.
split.
apply fst in p0.
inversion p0.
auto.
apply snd in p0.
inversion p0.
revert dependent x.
revert dependent f.
rewrite H0.
rewrite H1.
intros.
apply snd in p.
assert (x=x'). apply inj_pair2; apply p.
assert (f=f'). apply inj_pair2; apply p0.
rewrite H, H3. auto.
right.
destruct s.
left. intro.
apply fst in p.
assert (X-->Y = X' --> Y').
rewrite H, p.
auto. auto.
right. intro.
inversion H.
apply n.
revert dependent x.
revert dependent f.
rewrite H1.
rewrite H2.
intros.
apply inj_pair2 in H4.
apply inj_pair2 in H4.
rewrite H4.
auto.
right.
destruct s.
inversion p.
inversion H.
auto.
inversion p.
inversion H0.
revert dependent x.
revert dependent f.
rewrite H2.
rewrite H3.
intros.
apply inj_pair2 in H0.
rewrite H0.
right.
intro.
apply inj_pair2 in H1.
inversion H1. auto.
destruct s, s0.
right. right.
intro. inversion H. auto.
right. right.
intro. inversion H. auto.
right. right.
intro. inversion H. auto.
right. right.
intro. inversion H. auto.
- right; right; intro H; inversion H. (* f[x] ? I *)
- right; right; intro H; inversion H. (* f[x] ? K *)
- right; right; intro H; inversion H. (* f[x] ? S *)
- right; right; intro H; inversion H. (* I ? n *)
- right; right; intro H; inversion H. (* I ? f[x] *)
- pose (Xdec := eq_type_dec X X'). (* I ? I *)
destruct Xdec.
left; split; rewrite e; auto.
right; left. intro. inversion H. auto.
- right; right; intro H; inversion H. (* I ? K *)
- right; right; intro H; inversion H. (* I ? S *)
- right; right; intro H; inversion H. (* K ? n *)
- right; right; intro H; inversion H. (* K ? f[x] *)
- right; right; intro H; inversion H. (* K ? I *)
- pose (Xdec := eq_type_dec X X').
pose (Ydec := eq_type_dec Y Y').
destruct Xdec, Ydec.
left; split; rewrite e; rewrite e0; auto.
right; left; intro; inversion H; auto.
right; left; intro; inversion H; auto.
right; left; intro; inversion H; auto.
- right; right; intro H; inversion H. (* K ? S *)
- right; right; intro H; inversion H. (* S ? n *)
- right; right; intro H; inversion H. (* S ? f[x] *)
- right; right; intro H; inversion H. (* S ? I *)
- right; right; intro H; inversion H. (* S ? K *)
- pose (Xdec := eq_type_dec X X').
pose (Ydec := eq_type_dec Y Y').
pose (Zdec := eq_type_dec Z Z').
destruct Xdec, Ydec, Zdec.
left; split; rewrite e; rewrite e0; rewrite e1; auto.
right; left; intro; inversion H; auto.
right; left; intro; inversion H; auto.
right; left; intro; inversion H; auto.
right; left; intro; inversion H; auto.
right; left; intro; inversion H; auto.
right; left; intro; inversion H; auto.
right; left; intro; inversion H; auto.
Defined.
Fixpoint extract {A B : type} (expr : term B) (val : term A) : term (A-->B).
Proof.
pose (ab_dec := eq_term_dec expr val).
destruct ab_dec.
(* expr is equal to val *)
apply fst in p; rewrite p; apply I.
(* expr is not equal to val *)
inversion expr as [n X | X Y f x | X | X Y | Z X Y].
(* expr is just a constant, i.e. expr = var n X *)
apply (K[expr]).
(* expr is a function evaluation, i.e. expr = f[x]*)
apply (S[extract _ _ f val][extract _ _ x val]).
(* expr is identity, i.e. expr = I *)
rewrite H; apply (K[expr]).
(* expr is constant function, i.e. expr = K *)
rewrite H; apply (K[expr]).
(* expr is constant function, i.e. expr = S *)
rewrite H; apply (K[expr]).
Defined.
Notation X := (base_type 0).
Notation Y := (base_type 1).
Notation x := (var 0 X).
Notation y := (var 0 Y).
Notation f := (var 0 (X --> Y --> X)).
Compute extract (f[x]) x. (* => S [K [f]] [I] *)
Compute extract (f[x][y]) x. (* => S [S [K [f]] [I]] [K [y]] *)

Coq beginner - Prove a basic lemma

I'm a beginner with Coq so maybe my question will seems to be a dumb question, but here is my problem :
I defined a simple module in which I defined a type T and a function "my_custom_equal" :
Definition T := nat.
Fixpoint my_custom_equal (x y : T) :=
match x, y with
| O, O => true
| O, S _ => false
| S _, O => false
| S sub_x, S sub_y => my_custom_equal sub_x sub_y
end.
Lemma my_custom_reflex : forall x : T, my_custom_equal x x = true.
Proof.
intros.
induction x.
simpl.
reflexivity.
simpl.
rewrite IHx.
reflexivity.
Qed.
Lemma my_custom_unicite : forall x y : T, my_custom_equal x y = true -> x = y.
Proof.
intros.
induction x.
induction y.
reflexivity.
discriminate.
Qed.
As you can see, it is not really complicated but I still got stuck on the my_custom_unicite proof, I always reach the point where I need to prove that "S x = y" and my hypothesis are only :
y : nat
H : my_custom_equal 0 (S y) = true
IHy : my_custom_equal 0 y = true -> 0 = y
______________________________________(1/1)
S x = y
I don't understand how to achieve this proof, could you help me ?
Thanks!
This is a typical trap for beginners. The problem is that you performed induction on x when y was already introduced in your context. Because of that, the induction hypothesis that you obtain is not sufficiently general: what you really want is to have something like
forall y, my_custom_equal x y = true -> x = y
Notice the extra forall. The solution is to put y back into your goal:
Lemma my_custom_unicite : forall x y, my_custom_equal x y = true -> x = y.
Proof.
intros x y. revert y.
induction x as [|x IH].
- intros []; easy.
- intros [|y]; try easy.
simpl.
intros H.
rewrite (IH y H).
reflexivity.
Qed.
Try running this proof interactively and check how the induction hypothesis changes when you reach the second case.

How to deal with a function with an exists on the right side?

I am not sure whether I am using the right words in the question title, so here is the code:
Lemma In_map_iff :
forall (A B : Type) (f : A -> B) (l : list A) (y : B),
In y (map f l) <->
exists x, f x = y /\ In x l.
Proof.
intros A B f l y.
split.
- intros.
induction l.
+ intros. inversion H.
+ exists x.
simpl.
simpl in H.
destruct H.
* split.
{ apply H. }
{ left. reflexivity. }
* split.
A : Type
B : Type
f : A -> B
x : A
l : list A
y : B
H : In y (map f l)
IHl : In y (map f l) -> exists x : A, f x = y /\ In x l
============================
f x = y
Basically, there is not much to go on with this proof, I can only really use induction on l and after substituting for x in the goal I get the above form. If IHl had a forall instead of exists maybe I could substitute something there, but I am not sure at all what to do here.
I've been stuck on this one for a while now, but unlike the other problems where that has happened, I could not find the solution online for this one. This is a problem as I am going through the book on my own, so have nobody to ask except in places like SO.
I'd appreciate a few hints. Thank you.
Lemma In_map_iff :
forall (A B : Type) (f : A -> B) (l : list A) (y : B),
In y (map f l) <->
exists x, f x = y /\ In x l.
Proof.
intros A B f l y.
split.
- intros.
induction l.
+ intros. inversion H.
+ simpl.
simpl in H.
destruct H.
* exists x.
split.
{ apply H. }
{ left. reflexivity. }
* destruct IHl.
-- apply H.
-- exists x0.
destruct H0.
++ split.
** apply H0.
** right. apply H1.
- intros.
inversion H.
induction l.
+ intros.
inversion H.
inversion H1.
inversion H3.
+ simpl.
right.
apply IHl.
* inversion H.
inversion H0.
inversion H2.
exists x.
split.
-- reflexivity.
-- destruct H3.
A : Type
B : Type
f : A -> B
x0 : A
l : list A
y : B
H : exists x : A, f x = y /\ In x (x0 :: l)
x : A
H0 : f x = y /\ In x (x0 :: l)
IHl : (exists x : A, f x = y /\ In x l) ->
f x = y /\ In x l -> In y (map f l)
x1 : A
H1 : f x1 = y /\ In x1 (x0 :: l)
H2 : f x = y
H3 : x0 = x
H4 : f x = y
============================
In x l
I managed to do one case, but am now stuck in the other. To be honest, since I've already spent 5 hours on a problem that should need like 15 minutes, I am starting to think that maybe I should consider genetic programming at this point.
H can be true on two different ways, try destruct H. From that, the proof follows easily I think, but be careful on the order you destruct H and instantiate the existential thou.
Here is a proof that has the same structure as would have a pen-and-paper proof (at least the first -> part). When you see <tactic>... it means ; intuition (because of Proof with intuition. declaration), i.e. apply the intuition tactic to all the subgoals generated by <tactic>. intuition enables us not to do tedious logical deductions and can be replaced by a sequence of apply and rewrite tactics, utilizing some logical lemmas.
As #ejgallego pointed out the key here is that while proving you can destruct existential hypotheses and get inhabitants of some types out of them. Which is crucial when trying to prove existential goals.
Require Import Coq.Lists.List.
Lemma some_SF_lemma :
forall (A B : Type) (f : A -> B) (l : list A) (y : B),
In y (map f l) <->
exists x, f x = y /\ In x l.
Proof with intuition.
intros A B f l y. split; intro H.
- (* -> *)
induction l as [ | h l'].
+ (* l = [] *)
contradiction.
+ (* l = h :: l' *)
destruct H.
* exists h...
* destruct (IHl' H) as [x H'].
exists x...
- (* <- *)
admit.
Admitted.

Rewriting a match in Coq

In Coq, suppose I have a fixpoint function f whose matching definition on (g x), and I want to use a hypothesis in the form (g x = ...) in a proof. The following is a minimal working example (in reality f, g would be more complicated):
Definition g (x:nat) := x.
Fixpoint f (x:nat) :=
match g x with
| O => O
| S y => match x with
| O => S O
| S z => f z
end
end.
Lemma test : forall (x : nat), g x = O -> f x = O.
Proof.
intros.
unfold f.
rewrite H. (*fails*)
The message shows where Coq gets stuck:
(fix f (x0 : nat) : nat :=
match g x0 with
| 0 => 0
| S _ => match x0 with
| 0 => 1
| S z0 => f z0
end
end) x = 0
Error: Found no subterm matching "g x" in the current goal.
But, the commands unfold f. rewrite H. does not work.
How do I get Coq to unfold f and then use H ?
Parameter g: nat -> nat.
(* You could restructure f in one of two ways: *)
(* 1. Use a helper then prove an unrolling lemma: *)
Definition fhelp fhat (x:nat) :=
match g x with
| O => O
| S y => match x with
| O => S O
| S z => fhat z
end
end.
Fixpoint f (x:nat) := fhelp f x.
Lemma funroll : forall x, f x = fhelp f x.
destruct x; simpl; reflexivity.
Qed.
Lemma test : forall (x : nat), g x = O -> f x = O.
Proof.
intros.
rewrite funroll.
unfold fhelp.
rewrite H.
reflexivity.
Qed.
(* 2. Use Coq's "Function": *)
Function f2 (x:nat) :=
match g x with
| O => O
| S y => match x with
| O => S O
| S z => f2 z
end
end.
Check f2_equation.
Lemma test2 : forall (x : nat), g x = O -> f2 x = O.
Proof.
intros.
rewrite f2_equation.
rewrite H.
reflexivity.
Qed.
I'm not sure if this would solve the general problem, but in your particular case (since g is so simple), this works:
Lemma test : forall (x : nat), g x = O -> f x = O.
Proof.
unfold g.
intros ? H. rewrite H. reflexivity.
Qed.
Here is another solution, but of course for this trivial example. Perhaps will give you some idea.
Lemma test2 : forall (x : nat), g x = O -> f x = O.
Proof.
=>intros;
pattern x;
unfold g in H;
rewrite H;
trivial.
Qed.