Library HoTT.HIT.epi

Require Import Basics.
Require Import Types.
Require Import TruncType.
Require Import ReflectiveSubuniverse.
Require Import Colimits.Pushout Truncations.Core HIT.SetCone.

Local Open Scope path_scope.

Section AssumingUA.
Context `{ua:Univalence}.

We will now prove that for sets, epis and surjections are equivalent.
Definition isepi {X Y} `(f:XY) := Z: HSet,
   g h: Y Z, g o f = h o f g = h.

Definition isepi_funext {X Y : Type} (f : X Y)
  := Z : HSet, g0 g1 : Y Z, g0 o f == g1 o f g0 == g1.

Definition isepi' {X Y} `(f : X Y) :=
   (Z : HSet) (g : Y Z), Contr { h : Y Z | g o f = h o f }.

Lemma equiv_isepi_isepi' {X Y} f : @isepi X Y f <~> @isepi' X Y f.
Proof.
  unfold isepi, isepi'.
  apply (@equiv_functor_forall' _ _ _ _ _ (equiv_idmap _)); intro Z.
  apply (@equiv_functor_forall' _ _ _ _ _ (equiv_idmap _)); intro g.
  unfold equiv_idmap; simpl.
  refine (transitivity (@equiv_sig_ind _ (fun h : Y Zg o f = h o f) (fun hg = h.1)) _).
TODO(JasonGross): Can we do this entirely by chaining equivalences?
  apply equiv_iff_hprop.
  { intro hepi.
    nrapply (Build_Contr _ (g; idpath)).
    intro xy; specialize (hepi xy).
    apply path_sigma_uncurried.
     hepi.
    apply path_ishprop. }
  { intros hepi xy.
    exact (ap pr1 ((contr (g; 1))^ @ contr xy)). }
Defined.

Definition equiv_isepi_isepi_funext {X Y : Type} (f : X Y)
  : isepi f <~> isepi_funext f.
Proof.
  apply equiv_iff_hprop.
  - intros e ? g0 g1 h.
    apply equiv_path_arrow.
    apply e.
    by apply path_arrow.
  - intros e ? g0 g1 p.
    apply path_arrow.
    apply e.
    by apply equiv_path_arrow.
Defined.

Section cones.
  Lemma isepi'_contr_cone `{Funext} {A B : HSet} (f : A B) : isepi' f Contr (setcone f).
  Proof.
    intros hepi.
    apply (Build_Contr _ (setcone_point _)).
    pose (alpha1 := @pglue A B Unit f (const_tt _)).
    pose (tot:= { h : B setcone f & tr o push o inl o f = h o f }).
    transparent assert (l : tot).
    { simple refine (tr o _ o inl; _).
      { refine push. }
      { refine idpath. } }
    pose (r := (@const B (setcone f) (setcone_point _); (ap (fun f ⇒ @tr 0 _ o f) (path_forall _ _ alpha1))) : tot).
    subst tot.
    assert (X : l = r).
      { let lem := constr:(fun X push'hepi (Build_HSet (setcone f)) (tr o push' o @inl _ X)) in
        pose (lem _ push).
        refine (path_contr l r). }
    subst l r.

    pose (I0 b := ap10 (X ..1) b).
    refine (Trunc_ind _ _).
    pose (fun a : B + Unit ⇒ (match a as a return setcone_point _ = tr (push a) with
                                 | inl a'(I0 a')^
                                 | inr ttidpath
                               end)) as I0f.
    refine (Pushout_ind _ (fun a'I0f (inl a')) (fun u ⇒ (I0f (inr u))) _).

    simpl. subst alpha1. intros.
    unfold setcone_point.
    subst I0. simpl.
    pose (X..2) as p. simpl in p.
    rewrite (transport_precompose f _ _ X..1) in p.
    assert (H':=concat (ap (fun xap10 x a) p) (ap10_ap_postcompose tr (path_arrow (pushl o f) (pushr o const_tt _) pglue) _)).
    rewrite ap10_path_arrow in H'.
    clear p.
Apparently pose; clearbody is only ~.8 seconds, while pose proof is ~4 seconds?
    pose (concat (ap10_ap_precompose f (X ..1) a)^ H') as p.
    clearbody p.
    simpl in p.
    rewrite p.
    rewrite transport_paths_Fr.
    apply concat_Vp.
  Qed.
End cones.

Lemma issurj_isepi {X Y} (f:XY): IsSurjection f isepi f.
Proof.
intros sur ? ? ? ep. apply path_forall. intro y.
specialize (sur y). pose (center (merely (hfiber f y))).
apply (Trunc_rec (n:=-1) (A:=(sig (fun x : Xf x = y))));
  try assumption.
intros [x p]. set (p0:=apD10 ep x).
transitivity (g (f x)).
- by apply ap.
- transitivity (h (f x));auto with path_hints. by apply ap.
Qed.

Corollary issurj_isepi_funext {X Y} (f:XY) : IsSurjection f isepi_funext f.
Proof.
  intro s.
  apply equiv_isepi_isepi_funext.
  by apply issurj_isepi.
Defined.

Old-style proof using polymorphic Omega. Needs resizing for the isepi proof to live in the same universe as X and Y (the Z quantifier is instantiated with an HSet at a level higher)
Lemma isepi_issurj {X Y} (f:X->Y): isepi f -> issurj f.
Proof.
  intros epif y.
  set (g :=fun _:Y => Unit_hp).
  set (h:=(fun y:Y => (hp (hexists (fun _ : Unit => {x:X & y = (f x)})) _ ))).
  assert (X1: g o f = h o f ).
  - apply path_forall. intro x. apply path_equiv_biimp_rec;[|done].
    intros _ . apply min1. exists tt. by (exists x).
  - specialize (epif _ g h).
    specialize (epif X1). clear X1.
    set (p:=apD10 epif y).
    apply (@minus1Trunc_map (sig (fun _ : Unit => sig (fun x : X => y = f x)))).
    + intros [ _ [x eq]].
      exists x.
        by symmetry.
    + apply (transport hproptype p tt).
Defined.

Section isepi_issurj.
  Context {X Y : HSet} (f : X Y) (Hisepi : isepi f).
  Definition epif := equiv_isepi_isepi' _ Hisepi.
  Definition fam (c : setcone f) : HProp.
  Proof.
    pose (fib y := hexists (fun x : Xf x = y)).
    apply (fun f ⇒ @Trunc_rec _ _ HProp _ f c).
    refine (Pushout_rec HProp fib (fun _Unit_hp) (fun x_)).
Prove that the truncated sigma is equivalent to Unit
    pose (contr_inhabited_hprop (fib (f x)) (tr (x; idpath))) as i.
    apply path_hprop. simpl. simpl in i.
    apply (equiv_contr_unit).
  Defined.

  Lemma isepi_issurj : IsSurjection f.
  Proof.
    intros y.
    pose (i := isepi'_contr_cone _ epif).

    assert (X0 : x : setcone f, fam x = fam (setcone_point f)).
    { intros. apply contr_dom_equiv. apply i. }
    specialize (X0 (tr (push (inl y)))). simpl in X0.
    unfold IsConnected.
    refine (transport (fun AContr A) (ap trunctype_type X0)^ _); exact _.
  Defined.
End isepi_issurj.

Lemma isepi_isequiv X Y (f : X Y) `{IsEquiv _ _ f}
: isepi f.
Proof.
  intros ? g h H'.
  apply ap10 in H'.
  apply path_forall.
  intro x.
  transitivity (g (f (f^-1 x))).
  - by rewrite eisretr.
  - transitivity (h (f (f^-1 x))).
    × apply H'.
    × by rewrite eisretr.
Qed.
End AssumingUA.