According to Homotopy Type Theory (page 49), this is the full induction principle for equality :
Definition path_induction (A : Type) (C : forall x y : A, (x = y) -> Type)
(c : forall x : A, C x x eq_refl) (x y : A) (prEq : x = y)
: C x y prEq :=
match prEq with
| eq_refl => c x
end.
I don't understand much about HoTT, but I do see path induction is stronger than eq_rect :
Lemma path_ind_stronger : forall (A : Type) (x y : A) (P : A -> Type)
(prX : P x) (prEq : x = y),
eq_rect x P prX y prEq =
path_induction A (fun x y pr => P x -> P y) (fun x pr => pr) x y prEq prX.
Proof.
intros. destruct prEq. reflexivity.
Qed.
Conversely, I failed to construct path_induction from eq_rect. Is it possible ? If not, what is the correct induction principle for equality ? I thought those principles were mechanically derived from the Inductive type definitions.
EDIT
Thanks to the answer below, the full induction principle on equality can be generated by
Scheme eq_rect_full := Induction for eq Sort Prop.
Then we get the converse,
Lemma eq_rect_full_works : forall (A : Type) (C : forall x y : A, (x = y) -> Prop)
(c : forall x : A, C x x eq_refl) (x y : A)
(prEq : x = y),
path_induction A C c x y prEq
= eq_rect_full A x (fun y => C x y) (c x) y prEq.
Proof.
intros. destruct prEq. reflexivity.
Qed.
I think you are referring to the fact that the result type of path_induction mentions the path that is being destructed, whereas the one of eq_rect does not. This omission is the default for inductive propositions (as opposed to what happens with Type), because the extra argument is not usually used in proof-irrelevant developments. Nevertheless, you can instruct Coq to generate more complete induction principles with the Scheme command: https://coq.inria.fr/distrib/current/refman/user-extensions/proof-schemes.html?highlight=minimality. (The Minimality variant is the one used for propositions by default.)
Related
I have a problem in proving trivial proposition.
First, We define a composition of function with general domain and codomain:
Definition fun_comp {X Y Z W}
(f : X -> Y) (g : Z -> W) (H : Y = Z) : X -> W.
destruct H. refine (fun x => g (f x)). Defined.
We will now try to prove a trivial lemma:
Lemma compose_trivial {X Y Z} (f : X -> Y) (g : Y -> Z) (H : Y = Y)
: forall x, fun_comp f g H x = g (f x).
Proof.
intros x. revert f g. destruct H.
But destruct H. fails with an error message:
Cannot instantiate metavariable P of type
"forall a : Type, Y = a -> Prop" with abstraction
"fun (Y : Type) (H : Y = Y) =>
forall (f : X -> Y) (g : Y -> Z), fun_comp f g H x = g (f x)"
of incompatible type
"forall Y : Type, Y = Y -> Prop".
If it is able to generalize Y in the right hand side of H independently, the destruct tactic would work, but it would contradict to the right hand side of the goal g (f x).
Is it possible to prove trivial_compose? If possible, how can I?
This is not trivial at all. This has to do with uniqueness of identity proof that is not provable in Coq. You need an extra axiom.
For example,
Require Import ProofIrrelevance.
Lemma compose_trivial {X Y Z} (f : X -> Y) (g : Y -> Z) (H : Y = Y)
: forall x, fun_comp f g H x = g (f x).
Proof.
intros x.
now rewrite <- (proof_irrelevance _ (eq_refl Y) H).
Qed.
Consider the situation described by the code below, wherein I have a "piecewise" function h behaving differently (like f, or like g) depending on some (decidable) property condition of its input (h is defined using case_eq). Assume that I can prove that a property is guaranteed of the image of any x after application of either of the partial functions f or g; I should be able to prove that the entire function h guarantees property using a simple case_eq proof, no? Yet the following code rejects the rewrite step:
Section Error.
Variables X Y : Type.
Variables n m : Y.
Variable condition : X -> bool.
Variable property : Y -> Prop.
Definition type1 (x : X) : Prop := condition x = true.
Definition type2 (x : X) : Prop := condition x = false.
Variable f : {x:X | type1 x} -> Y.
Variable g : {x:X | type2 x} -> Y.
Definition h : X -> Y. intro x. case_eq (condition x); intro.
- exact (f (exist type1 x H)).
- exact (g (exist type2 x H)).
Defined.
Hypothesis Hf : forall x, property (f x).
Hypothesis Hg : forall x, property (g x).
Theorem hRange : forall x, property (h x).
Proof. intro. case_eq (condition x); intro.
- unfold h. rewrite H.
with the error
Abstracting over the term "condition x" leads to a term
fun b : bool =>
property
((if b as b0 return (b = b0 -> Y)
then fun H0 : b = true => f (exist type1 x H0)
else fun H0 : b = false => g (exist type2 x H0)) eq_refl)
which is ill-typed.
Reason is: Illegal application:
The term "exist" of type "forall (A : Type) (P : A -> Prop) (x : A), P x -> {x : A | P x}"
cannot be applied to the terms
"X" : "Type"
"type1" : "X -> Prop"
"x" : "X"
"H0" : "b = true"
The 4th term has type "b = true" which should be coercible to "type1 x".
Of course, I wish it would eliminate the if clause, rewriting the goal to property (f (exist type1 x H)) but Coq doesn't like this. Why not?
I feel Coq wouldn't behave like this if the hypothesis generated by case_eq in the definition of h wasn't implicated in the result (in this case, I could've rewritten h with a match clause, and those cause me no issue. In the present situation, just assume that the hypothesis is crucial to constructing some "non-computational" part of either f x or g x, e.g. if Y is itself a sig-type). I've read other threads like this and this, but to the short extent that I understand them, they don't help me understand my situation.
This problem occurs when you try to destruct or rewrite all the occurrences of a subterm. Here, you've rewritten condition x in the type of H0, which causes exist type1 x H0 to be ill-typed (can you see why?).
The solution is to restrict the destruct or rewrite to only some of the subterms. This might require you to generalize part of your goal. For example:
From Coq Require Import ssreflect.
Section Error.
Variables X Y : Type.
Variables n m : Y.
Variable condition : X -> bool.
Variable property : Y -> Prop.
Definition type1 (x : X) : Prop := condition x = true.
Definition type2 (x : X) : Prop := condition x = false.
Variable f : {x:X | type1 x} -> Y.
Variable g : {x:X | type2 x} -> Y.
Definition h : X -> Y. intro x. case_eq (condition x); intro.
- exact (f (exist type1 x H)).
- exact (g (exist type2 x H)).
Defined.
Hypothesis Hf : forall x, property (f x).
Hypothesis Hg : forall x, property (g x).
Theorem hRange : forall x, property (h x).
Proof.
intro; unfold h; generalize (eq_refl (condition x)).
case: {2 3}(condition x).
- intros H. apply Hf.
- intros H. apply Hg.
Qed.
End Error.
After generalizing eq_refl, the goal looks like this:
1 subgoal (ID 16)
X, Y : Type
n, m : Y
condition : X -> bool
property : Y -> Prop
f : {x : X | type1 x} -> Y
g : {x : X | type2 x} -> Y
Hf : forall x : {x : X | type1 x}, property (f x)
Hg : forall x : {x : X | type2 x}, property (g x)
x : X
============================
forall e : condition x = condition x,
property
((if condition x as b return (condition x = b -> Y)
then fun H : condition x = true => f (exist type1 x H)
else fun H : condition x = false => g (exist type2 x H)) e)
The tactic case: {2 3}..., which was imported from ssreflect, says that condition x should only be destructed on the RHS of e and on the condition of the if.
I am trying to implement/specify the permutation groups (symmetric groups) in coq. This went well for a bit, until I tried to prove that the identity is actually the identity. My proof gets stuck on proving that the proposition "x is invertible" is exactly the same as the proposition "id * x is invertible".
Are these two propositions actually the same? Am I trying to prove something that is not true? Is there a better way of specifying the permutation group (as a type)?
(* The permutation group on X contains all functions between X and X that are bijective/invertible *)
Inductive G {X : Type} : Type :=
| function (f: X -> X) (H: exists g: X -> X, forall x : X, f (g x) = x /\ g (f x) = x).
(* Composing two functions preserves invertibility *)
Lemma invertible_composition {X : Type} (f g: X -> X) :
(exists f' : X -> X, forall x : X, f (f' x) = x /\ f' (f x) = x) ->
(exists g' : X -> X, forall x : X, g (g' x) = x /\ g' (g x) = x) ->
exists h : X -> X, forall x : X, (fun x => f (g x)) (h x) = x /\ h ((fun x => f (g x)) x) = x.
Admitted.
(* The group operation is composition *)
Definition op {X : Type} (a b : G) : G :=
match a, b with
| function f H, function g H' => function (fun x => f (g x)) (#invertible_composition X f g H H')
end.
Definition id' {X : Type} (x : X) : X := x.
(* The identity function is invertible *)
Lemma id_invertible {X : Type} : exists g : X -> X, forall x : X, id' (g x) = x /\ g (id' x) = x.
Admitted.
Definition id {X : Type} : (#G X) := function id' id_invertible.
(* The part on which I get stuck: proving that composition with the identity does not change elements. *)
Lemma identity {X: Type} : forall x : G, op id x = x /\ #op X x id = x.
Proof.
intros.
split.
- destruct x.
simpl.
apply f_equal.
Abort.
I believe that your statement cannot be proved without assuming extra axioms:
proof_irrelevance:
forall (P : Prop) (p q : P), p = q.
You need this axiom to show that two elements of G are equal when the underlying functions are:
Require Import Coq.Logic.ProofIrrelevance.
Inductive G X : Type :=
| function (f: X -> X) (H: exists g: X -> X, forall x : X, f (g x) = x /\ g (f x) = x).
Arguments function {X} _ _.
Definition fun_of_G {X} (f : G X) : X -> X :=
match f with function f _ => f end.
Lemma fun_of_G_inj {X} (f g : G X) : fun_of_G f = fun_of_G g -> f = g.
Proof.
destruct f as [f fP], g as [g gP].
simpl.
intros e.
destruct e.
f_equal.
apply proof_irrelevance.
Qed.
(As a side note, it is usually better to declare the X parameter of G explicitly, rather than implicitly. It is rarely the case that Coq can figure out what X should be on its own.)
With fun_of_G_inj, it should be possible to show identity simply by applying it to each equality, because fun a => (fun x => x) (g a) is equal to g for any g.
If you want to use this representation for groups, you'll probably also need the axiom of functional extensionality eventually:
functional_extensionality:
forall X Y (f g : X -> Y), (forall x, f x = g x) -> f = g.
This axiom is available in the Coq.Logic.FunctionalExtensionality module.
If you want to define the inverse element as a function, you probably also need some form of the axiom of choice: it is necessary for extracting the inverse element g from the existence proof.
If you don't want to assume extra axioms, you have to place restrictions on your permutation group. For instance, you can restrict your attention to elements with finite support -- that is, permutation that fix all elements of X, except for a finite set. There are multiple libraries that allow you to work with permutations this way, including my own extensional structures.
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.
split.
- generalize dependent y.
generalize dependent f.
induction l.
+ intros. inversion H.
+ intros.
simpl.
simpl in H.
destruct H.
* exists x.
split.
apply H.
left. reflexivity.
*
1 subgoal
A : Type
B : Type
x : A
l : list A
IHl : forall (f : A -> B) (y : B),
In y (map f l) -> exists x : A, f x = y /\ In x l
f : A -> B
y : B
H : In y (map f l)
______________________________________(1/1)
exists x0 : A, f x0 = y /\ (x = x0 \/ In x0 l)
Since proving exists x0 : A, f x0 = y /\ (x = x0 \/ In x0 l) is the same as proving exists x0 : A, f x0 = y /\ In x0 l, I want to eliminate x = x0 inside the goal here so I can apply the inductive hypothesis, but I am not sure how to do this. I've tried left in (x = x0 \/ In x0 l) and various other things, but I haven't been successful in making it happen. As it turns out, defining a helper function of type forall a b c, (a /\ c) -> a /\ (b \/ c) to do the rewriting does not work for terms under an existential either.
How could this be done?
Note that the above is one of the SF book exercises.
You can get access to the components of your inductive hypothesis with any of the following:
specialize (IHl f y h); destruct IHl
destruct (IHl f y H)
edestruct IHl
You can then use exists and split to manipulate the goal into a form that is easier to work with.
As it turns out, it is necessary to define a helper.
Lemma In_map_iff_helper : forall (X : Type) (a b c : X -> Prop),
(exists q, (a q /\ c q)) -> (exists q, a q /\ (b q \/ c q)).
Proof.
intros.
destruct H.
exists x.
destruct H.
split.
apply H.
right.
apply H0.
Qed.
This does the rewriting that is needed right off the bat. I made a really dumb error thinking that I needed a tactic rather than an auxiliary lemma. I should have studied the preceding examples more closely - if I did, I'd have realized that existentials need to be accounted for.
I would like to prove that termination implies existence of normal form. These are my definitions:
Section Forms.
Require Import Classical_Prop.
Require Import Classical_Pred_Type.
Context {A : Type}
Variable R : A -> A -> Prop.
Definition Inverse (Rel : A -> A -> Prop) := fun x y => Rel y x.
Inductive ReflexiveTransitiveClosure : Relation A A :=
| rtc_into (x y : A) : R x y -> ReflexiveTransitiveClosure x y
| rtc_trans (x y z : A) : R x y -> ReflexiveTransitiveClosure y z ->
ReflexiveTransitiveClosure x z
| rtc_refl (x y : A) : x = y -> ReflexiveTransitiveClosure x y.
Definition redc (x : A) := exists y, R x y.
Definition nf (x : A) := ~(redc x).
Definition nfo (x y : A) := ReflexiveTransitiveClosure R x y /\ nf y.
Definition terminating := forall x, Acc (Inverse R) x.
Definition normalizing := forall x, (exists y, nfo x y).
End Forms.
I'd like to prove:
Lemma terminating_impl_normalizing (T : terminating):
normalizing.
I have been banging my head against the wall for a couple of hours now, and I've made almost no progress. I can show:
Lemma terminating_not_inf_forall (T : terminating) :
forall f : nat -> A, ~ (forall n, R (f n) (f (S n))).
which I believe should help (this is also true without classic).
Here is a proof using the excluded middle. I reformulated the problem to replace custom definitions by standard ones (note by the way that in your definition of the closure, the rtc_into is redundant with the other ones). I also reformulated terminating using well_founded.
Require Import Classical_Prop.
Require Import Relations.
Section Forms.
Context {A : Type} (R:relation A).
Definition inverse := fun x y => R y x.
Definition redc (x : A) := exists y, R x y.
Definition nf (x : A) := ~(redc x).
Definition nfo (x y : A) := clos_refl_trans _ R x y /\ nf y.
Definition terminating := well_founded inverse. (* forall x, Acc inverse x. *)
Definition normalizing := forall x, (exists y, nfo x y).
Lemma terminating_impl_normalizing (T : terminating):
normalizing.
Proof.
unfold normalizing.
apply (well_founded_ind T). intros.
destruct (classic (redc x)).
- destruct H0 as [y H0]. pose proof (H _ H0).
destruct H1 as [y' H1]. exists y'. unfold nfo.
destruct H1.
split.
+ apply rt_trans with (y:=y). apply rt_step. assumption. assumption.
+ assumption.
- exists x. unfold nfo. split. apply rt_refl. assumption.
Qed.
End Forms.
The proof is not very complicated but here are the main ideas:
use well founded induction
thanks to the excluded middle principle, separate the case where x is not in normal form and the case where it is
if x is not in normal form, use the induction hypothesis and use the transitivity of the closure to conclude
if x is already in normal form, we are done