Library Epsilon



Require Import ClassicalEpsilon.

Set Implicit Arguments.


Lemma ex_unique_introduction :
    (A:Type)(P:AProp),
    ( x, P x) →
    ( a b, P aP ba = b)->
    ! x, P x.
Proof.
 intros.
 case (unique_existence P).
 destruct 1.
 split;auto.
 case H;intros x0 Hx0.
  x0;auto.
 case H1.
 split;auto.
Qed.

Ltac ex_unique_intro :=
    match goal with [ |- ex (unique ?P) ] ⇒
       apply ex_unique_introduction end.


Theorem epsilon_ind :
    (A:Type)(i : inhabited A)(P:AProp)
          (Q:AProp), ( x, P x)->
                       ( x : A, P xQ x) →
                       Q (epsilon i P).
Proof.
 intros A a P Q exP P_Q.
 apply P_Q.
  apply epsilon_spec; assumption.
Qed.

Theorem epsilon_equiv : (A:Type)(i : inhabited A)(P:AProp),
  ( x, P x)<-> P (epsilon i P).
Proof.
 split.
 intros; apply epsilon_ind; auto.
  (epsilon i P); auto.
Qed.


Definition tau (A:Type)(i:inhabited A)(P:AProp) :=
     epsilon i (fun y¬ (P y)).

Lemma forall_def : ( P, P ¬ P) →
                     (A:Type)(i:inhabited A)(P:AProp),
                    ( y, P y) P (tau i P).
Proof.
 intros class A a P; split.
 auto.
 intros H y .
 case (class (P y));auto.
 intro Hy.
 revert H.
 pattern (tau a P).
 unfold tau;apply epsilon_ind;auto.
  y;auto.
 tauto.
Qed.



Definition iota (A:Type)(i : inhabited A)(P: AProp) : A :=
epsilon i (unique P).

Lemma iota_e : (A:Type) (i: inhabited A) (P : AProp),
                     ex (unique P) →
                     unique P (iota i P).
Proof.
 intros A a P H; unfold iota.
 apply epsilon_ind;auto.
Qed.

Lemma iota_e_weak : (A:Type) (i: inhabited A) (P : AProp),
                     ex (unique P) →
                      P (iota i P).
Proof.
 intros.
 case (iota_e i H).
 auto.
Qed.

Theorem iota_ind :
    (A:Type)(i: inhabited A)(P:AProp)
          (Q:AProp),
                      ( b : A, unique P bQ b) →
                       ex (unique P) →
                       Q (iota i P).
Proof.
  intros A a P Q H (x,H0).
 apply H.
apply iota_e.
   x;auto.
Qed.

Theorem iota_ind_weak : (A:Type)(i: inhabited A)(P:AProp)
          (Q:AProp),
              ( b : A, P bQ b) →
              ex (unique P) →
              Q (iota i P).
Proof.
 intros.
 apply H.
 apply iota_e_weak.
 auto.
Qed.


Ltac epsilon_elim_aux :=
  match goal with [ |- (?P (epsilon (A:=?X) ?a ?Q))] ⇒
           apply epsilon_ind; auto
  end.

Ltac epsilon_elim := epsilon_elim_aux ||
  match goal with
  [ |- (?P (?k ?d))] ⇒
   (let v := eval cbv zeta beta delta [k] in (k d) in
     (match v with (epsilon ?w ?d) ⇒ change (P v); epsilon_elim_aux end))
  | [ |- (?P (?k ?arg ?arg1))] ⇒
   (let v := eval cbv zeta beta delta [k] in (k arg arg1) in
     (match v with (epsilon ?w ?d) ⇒ change (P v); epsilon_elim_aux end))
  | [ |- (?P ?k)] ⇒
   (let v := eval cbv zeta beta delta [k] in k in
     (match v with (epsilon ?w ?d) ⇒ change (P v); epsilon_elim_aux end))
  end.

Ltac iota_elim_aux :=
  match goal with [ |- (?P (iota (A:=?X) ?i ?Q))] ⇒
    apply iota_ind; auto
  end.

Ltac iota_elim := iota_elim_aux ||
  match goal with
  [ |- (?P (?k ?arg))] ⇒
   (let v := eval cbv zeta beta delta [k] in (k arg) in
     (match v with (iota ?w ?d) ⇒ change (P v); iota_elim_aux end))
 | [ |- (?P (?k ?arg ?arg1))] ⇒
   (let v := eval cbv zeta beta delta [k] in (k arg arg1) in
     (match v with (iota ?w ?d) ⇒ change (P v); iota_elim_aux end))
 | [ |- (?P ?k)] ⇒
   (let v := eval cbv zeta beta delta [k] in k in
     (match v with (iota ?w ?d) ⇒ change (P v); iota_elim_aux end))
  end.

Lemma iota_parameter_rw : (A:Type)(a b:inhabited A)(P:AProp),
  (ex (unique P)) →
   iota a P = iota b P.
Proof.
 intros.
 pattern (iota a P).
 iota_elim.
 pattern (iota b P).
 iota_elim.
 intros b0 H0 b1 H1.
 revert H;intros (x,(Hx,H')).
 transitivity x;auto.
 symmetry;auto.
 red in H1;decompose [and] H1.


 auto.
  red in H0;decompose [and] H0.
 auto.

Qed.

Structures for descriptions and specifications
The operators "some" and "the" correspond to epsilon and iota applied to the proof they expect

Definition select(A:Type)(P:AProp)(pi: x, P x)
  : A
  := proj1_sig (constructive_indefinite_description P pi).

Implicit Arguments select [A P].

Definition select_the (A:Type)(P:AProp)
                      (pi:! x, P x)
           : A
           := proj1_sig (constructive_indefinite_description (unique P) pi).

Implicit Arguments select_the [A P].

Lemma select_e : (A:Type)(P:AProp)(pi: x, P x),
                 P (select pi).
Proof.
 intros.
 unfold select.
 case (constructive_indefinite_description P pi).
 auto.
Qed.

Implicit Arguments select_e [A P].

Theorem select_ind : (A:Type)(P Q:AProp)
                 (pi: x, P x),
                 ( a, P aQ a) → Q (select pi).
Proof.
 intros.
 apply H ;apply select_e.
Qed.

Theorem select_the_e : (A:Type)(P:AProp)
                               (pi:! x, P x),
  unique P (select_the pi).
Proof.
 unfold select_the.
 intros.
 case (constructive_indefinite_description (unique P) pi);auto.
Qed.

Implicit Arguments select_the_e [A P].

Theorem select_the_ind : (A:Type)(P Q:AProp)
                               (pi:ex (unique P)),
  ( b, unique P bQ b) → Q (select_the pi).
Proof.
 intros A P Q pi H;apply H. apply select_the_e.
Qed.

Implicit Arguments select_the_ind [A P].

Theorem select_the_rw : (A:Type)(P:AProp)
                        (pi:! x, P x) b,
                 P bb= select_the pi.
Proof.
 intros A P pi b Hb.
 case pi; intros x (Px,Eqx).

 unfold select_the.
  case (constructive_indefinite_description (unique P)
        (ex_intro (unique (fun x0 : AP x0)) x (conj Px Eqx))).
 simpl;firstorder.
Qed.

Implicit Arguments select_the_rw [A P].

Ltac select_the_elim_aux :=
  match goal with [ |- (?Q (select_the ?d))] ⇒
    apply select_the_ind
  end.

Ltac select_the_elim := select_the_elim_aux ||
  match goal with [ |- (?P ?k)] ⇒
   (let v := eval cbv beta zeta delta [k] in k in
     (match v with (select_the ?d) ⇒ change (P v); select_the_elim_aux end))
  end.

Ltac select_elim_aux :=
  match goal with [ |- (?P (select ?d))] ⇒
    generalize (select d) (select_e d); simpl
  end.

Ltac select_elim := select_elim_aux ||
  match goal with [ |- (?P ?k)] ⇒
   (let v := eval cbv beta zeta delta [k] in k in
     (match v with (select ?d) ⇒ change (P v); select_elim_aux end))
  end.

Ltac hilbert_e :=
 select_the_elim || select_elim || iota_elim || epsilon_elim .

Tactic Notation "epsilon_e" constr(T) "at" integer(n) :=
       pattern T at n; hilbert_e.

Tactic Notation "epsilon_e" constr(T) :=
       pattern T ; hilbert_e.


Ltac select_i P :=
   refine (select (P:=P) _).

Ltac select_the_i P :=
   refine (select_the (P:=P) _).

Building partial functions

Definition functional(A B : Type) (R: ABProp ) :=
   x y , R x y z, R x zy = z.

Implicit Arguments functional [A B].

Section AB_fixed.
 Variables A B: Type.

description of some partial function by a Domain and a binary relation


Definition choice_fun (i : inhabited B)(DA : AProp)(R:ABProp)(a:A):=
      (epsilon i (fun (b':B) ⇒ DA a R a b')).

Definition iota_fun (b : inhabited B)(DA : AProp)(R:ABProp)(a:A):=
      (iota b (fun (b':B) ⇒ DA a R a b')).

Lemma choice_fun_e : i : inhabited B,
   (DA : AProp)(R:ABProp)(a:A),
   ( d : B, R a d) →
   DA aR a (choice_fun i DA R a).
Proof.
 intros.
 unfold choice_fun.
 pattern (epsilon i (fun b : BDA a R a b)).
 epsilon_elim.
 intros.
 case H;intuition.
  x;auto.
 tauto.
Qed.

Lemma choice_fun_ind : i : inhabited B,
   (P : AProp)(Q R:ABProp)(a x:A),
   ( d : B, R a d) → a = x
   P a → ( b, P aR a bQ a b) →
   Q x (choice_fun i P R a).
Proof.
 intros.
 subst x.
 apply H2.
 auto. apply choice_fun_e;auto.
Qed.

a partial function equipped with a proof of its partial correctness

Definition the_fun (i : inhabited B)(D : AProp)(R:ABProp)
       (pi : a, D a! b, R a b): AB :=
      fun a:Aiota i (fun (b:B) ⇒ D a R a b).

same stuff but without unicity of the result

Definition some_fun (i : inhabited B)(D : AProp)(R:ABProp)
       (pi : a, D a b: B, R a b) : AB :=
      fun a:Aepsilon i (fun (b:B) ⇒ D a R a b).

Lemma iota_fun_e : b : inhabited B,
   (DA : AProp)(R:ABProp)(a:A),
   (ex (unique (R a))) →
   DA aunique (R a) (iota_fun b DA R a).
Proof.
 intros.
 unfold iota_fun.
 pattern (iota b (fun b' : BDA a R a b')).
 iota_elim.
 case H;intros.
 case H2; auto.
 case H;intros.
 case H4;auto.
 case H;intros.
 split.
 auto.
 intros.
 case H6.
 firstorder.
 case H.
 intros x (e,u). x.
 split;auto.
 firstorder.
Qed.

Lemma iota_fun_ind : b : inhabited B,
   (P : AProp)(Q R:ABProp)(a x:A),
   a = x → (ex (unique (R a))) →
   P a → ( b, P aunique (R a) bQ a b) →
   Q x (iota_fun b P R a).
Proof.
 intros.
 subst x.
 apply H2.
 auto. apply iota_fun_e.
 case H0;intros d (Hd,Hd').
  d;auto.
 auto.
 red.
 auto.
 auto.
Qed.

Lemma iota_fun_rw : b: inhabited B,
   (P : AProp)(R:ABProp)(a:A)(b':B),
   (ex (unique ( R a))) →
   P a
   R a b'b'= (iota_fun b P R a).
Proof.
 intros.
  unfold iota_fun.
  pattern (iota b (fun b0 : BP a R a b0)).
 iota_elim.
   case H;intros d (Hd,Hd').
 intuition.
 transitivity d;auto.
 symmetry;auto.
  red in H2.
 firstorder.
 firstorder.
Qed.

Theorem the_fun_e : (b :inhabited B)(P: AProp)(R:ABProp)
(pi : a, P aex (unique (R a))) (a:A),
      P aR a (the_fun b P R pi a) .
Proof.
 intros b P R pi a H.
 unfold the_fun.
 pattern (iota b (fun b0 : BP a R a b0)).
 iota_elim.
 case (pi a H).
 intros x (Hx,H'x).
 firstorder.
 firstorder.
Qed.

Theorem some_fun_e : (i : inhabited B)(P: AProp)(R:ABProp)
(pi : a, P a b0: B, R a b0) (a:A),
      P aR a (some_fun i P R pi a) .
Proof.
 intros i P R pi a H.
 unfold some_fun.
 pattern (epsilon i (fun b0 : BP a R a b0)).
 epsilon_elim.
 case (pi a H).
 intros x Hx.
  x.
 split;auto.
 destruct 1;auto.
Qed.

Theorem the_fun_rw : (b : inhabited B)(P: AProp)(R:ABProp)
(pi : a, P aex (unique ( R a))) (a:A)(b0:B),
      P aR a b0b0= (the_fun b P R pi a) .
Proof.
 intros b P R pi a b0 H H0.
 unfold the_fun.
 pattern (iota b (fun b1 : BP a R a b1)).
 iota_elim.
 firstorder.
 case (pi a H).

 intros x (Hx,H'x).
  x.
 firstorder.
Qed.

Theorem the_fun_ind : (b : inhabited B)(P: AProp)(Q R:ABProp)
(pi : a, P aex (unique (R a))) (a x:A),
      P aa = x
( b0, P aunique (R a) b0Q a b0) →
 Q x (the_fun b P R pi a) .
Proof.
 intros.
 subst x.
 apply H1. auto.
 case (pi a H).
 destruct 1.
 split.
 eapply the_fun_e.
 auto.
 intros.
 replace x' with x.
 symmetry;apply (the_fun_rw b P R pi a);auto.
 auto.
Qed.

Theorem some_fun_ind : (i : inhabited B)(P: AProp)(Q R:ABProp)
(pi : a, P a b: B, R a b) (a x:A),
      a = xP a → ( b0, P aR a b0Q a b0) →
      Q x (some_fun i P R pi a) .
Proof.
 intros.
 subst x.
 apply H1. auto. eapply some_fun_e.
 auto.
Qed.

End AB_fixed.

tactic for building a partial function

Opaque the_fun some_fun.

Ltac the_fun_i P R:=
   refine (the_fun _ P R _).

Ltac some_fun_i P R:=
   refine (some_fun _ P R _).

Ltac the_fun_elim :=
match goal with [ |- (?Q ?a (?f ?t)) ] ⇒
 (let v := eval cbv beta zeta delta [f] in f in
       (match v with (the_fun ?i ?P ?R ?d) ⇒ change (Q a (v t));
                 apply the_fun_ind ; auto end)) end.

Ltac some_fun_elim :=
match goal with [ |- (?Q ?a (?f ?t)) ] ⇒
 (let v := eval cbv beta zeta delta [f] in f in
       (match v with (some_fun ?i ?P ?R ?d) ⇒ change (Q a (v t));
                 apply some_fun_ind ; auto end)) end.

Ltac iota_fun_elim :=
match goal with [ |- (?Q ?a (?f ?t)) ] ⇒
 (let v := eval cbv beta zeta delta [f] in f in
       (match v with (iota_fun ?i ?P ?R ) ⇒ change (Q a (v t));
                 apply iota_fun_ind ; auto end)) end.

Ltac choice_fun_elim :=
match goal with [ |- (?Q ?a (?f ?t)) ] ⇒
 (let v := eval cbv beta zeta delta [f] in f in
       (match v with (choice_fun ?i ?P ?R ) ⇒ change (Q a (v t));
                 apply choice_fun_ind ; auto end)) end.

Ltac pfun_e := choice_fun_elim || iota_fun_elim || some_fun_elim ||
              the_fun_elim.

Ltac partial_fun_e arg result := pattern arg, result;pfun_e.

Ltac iota_fun_rewrite :=
 match goal with [ |- (?f ?x = ?y) ] ⇒
    (let v := eval cbv beta zeta delta [f] in f in
           (match v with (iota_fun ?i ?P ?R ) ⇒
                         change (v x = y);symmetry; apply iota_fun_rw; auto
                          end)) end.


Ltac the_fun_rewrite :=
 match goal with [ |- (?f ?x = ?y) ] ⇒
    (let v := eval cbv beta zeta delta [f] in f in
           (match v with (the_fun ?i ?P ?R ?d ) ⇒
                         change (v x = y);symmetry; apply the_fun_rw; auto
                          end)) end.


Section definite_description.


Lemma dd'' : (A:Type)(B:AType)
                         (R: x:A, B xProp),
      ( x: A, inhabited (B x)) →
      (sigT (fun f : x:A, B x
                     ( x:A, ( y:B x, R x y) → R x (f x)))).
Proof.
 intros A B R i.
  (fun (x:A) ⇒ (epsilon (i x) (fun y ⇒ (R x y)))).
 intros x [y ry].
 apply (epsilon_ind). y; trivial.
 auto.
Qed.

Lemma dd' : (A:Type) (B:AType)
                             (R: x:A, B xProp),
      ( x, inhabited (B x)) →
      ( x:A, y : B x, R x y ) →
       sigT (fun f : x:A, B x ⇒ ( x:A, R x (f x))).
Proof.
 intros.
 case (dd'' B R H).
 intros.
  x.
 intros;apply r.
 auto.
Qed.

End definite_description.

Definition epsilon_extensionality :=
   (A:Type)(i: inhabited A)(P Q:AProp),
  ( a, P a Q a) →
  epsilon i P = epsilon i Q.


Definition restricted_epsilon_extensionality :=
   (A:Type)(i: inhabited A)(P Q:AProp),
  ( a, P a Q a) →
  ex P
  epsilon i P = epsilon i Q.

Lemma inhabited_bool : inhabited bool.
 constructor.
 exact true.
Qed.

Lemma or_to_sumbool : P Q : Prop, P Q{P}+{Q}.
Proof.
 intros P Q H.
 pose (y := epsilon inhabited_bool (fun bb=true P b=false Q)).
 case_eq y.
 intro eg.
 left.
 generalize eg;pattern y; hilbert_e.
  case H.
   true;auto.
   false;auto.
  destruct 1.
  tauto.
  case H0;intros; subst x; discriminate.
  intro eg;right.
  generalize eg;pattern y; hilbert_e.
  case H.
   true;auto.
   false;auto.
  destruct 1.
  intro; subst x.
  case H0. discriminate 1.
  tauto.
 Qed.

Lemma iota_rw : (A:Type)(a: inhabited A)(P:AProp)(x:A),
              unique P x
              iota a P = x.
Proof.
 intros.
 case H ;intros H1 H2.
 symmetry;apply H2;auto.
 epsilon_e (iota a P).
 firstorder.
  x;firstorder.
Qed.

Opaque epsilon.

Definition unspec (A:Type)(i:inhabited A) := epsilon i (fun xTrue).

Lemma quasi_classic : (A:Type), A + (AFalse).
Proof.
 intro A;case (or_to_sumbool (classic (inhabited A))).
 intro i; left;exact (epsilon i (fun aTrue)).
 intro H;right;intro a.
 case H.
 constructor.
 auto.
Qed.