Martin Escardo 1st May 2020.
This is ported from the Midlands Graduate School 2019 lecture notes
 https://www.cs.bham.ac.uk/~mhe/HoTT-UF.in-Agda-Lecture-Notes/HoTT-UF-Agda.html
 https://github.com/martinescardo/HoTT-UF.Agda-Lecture-Notes
\begin{code}
{-# OPTIONS --safe --without-K #-}
module MGS.FunExt-from-Univalence where
open import MGS.Equivalence-Induction public
funext : β π€ π₯ β (π€ β π₯)βΊ Μ
funext π€ π₯ = {X : π€ Μ } {Y : π₯ Μ } {f g : X β Y} β f βΌ g β f οΌ g
precomp-is-equiv : is-univalent π€
                 β (X Y : π€ Μ ) (f : X β Y)
                 β is-equiv f
                 β (Z : π€ Μ ) β is-equiv (Ξ» (g : Y β Z) β g β f)
precomp-is-equiv {π€} ua =
   π-equiv ua
     (Ξ» X Y (f : X β Y) β (Z : π€ Μ ) β is-equiv (Ξ» g β g β f))
     (Ξ» X Z β id-is-equiv (X β Z))
univalence-gives-funext : is-univalent π€ β funext π₯ π€
univalence-gives-funext {π€} {π₯} ua {X} {Y} {fβ} {fβ} = Ξ³
 where
  Ξ : π€ Μ
  Ξ = Ξ£ yβ κ Y , Ξ£ yβ κ Y , yβ οΌ yβ
  Ξ΄ : Y β Ξ
  Ξ΄ y = (y , y , refl y)
  Οβ Οβ : Ξ β Y
  Οβ (yβ , yβ , p) = yβ
  Οβ (yβ , yβ , p) = yβ
  Ξ΄-is-equiv : is-equiv Ξ΄
  Ξ΄-is-equiv = invertibles-are-equivs Ξ΄ (Οβ , Ξ· , Ξ΅)
   where
    Ξ· : (y : Y) β Οβ (Ξ΄ y) οΌ y
    Ξ· y = refl y
    Ξ΅ : (d : Ξ) β Ξ΄ (Οβ d) οΌ d
    Ξ΅ (y , y , refl y) = refl (y , y , refl y)
  Ο : (Ξ β Y) β (Y β Y)
  Ο Ο = Ο β Ξ΄
  Ο-is-equiv : is-equiv Ο
  Ο-is-equiv = precomp-is-equiv ua Y Ξ Ξ΄ Ξ΄-is-equiv Y
  p : Ο Οβ οΌ Ο Οβ
  p = refl (ππ Y)
  q : Οβ οΌ Οβ
  q = equivs-are-lc Ο Ο-is-equiv p
  Ξ³ : fβ βΌ fβ β fβ οΌ fβ
  Ξ³ h = ap (Ξ» Ο x β Ο (fβ x , fβ x , h x)) q
  Ξ³' : fβ βΌ fβ β fβ οΌ fβ
  Ξ³' h = fβ                             οΌβ¨ refl _ β©
         (Ξ» x β fβ x)                   οΌβ¨ refl _ β©
         (Ξ» x β Οβ (fβ x , fβ x , h x)) οΌβ¨ ap (Ξ» - x β - (fβ x , fβ x , h x)) q β©
         (Ξ» x β Οβ (fβ x , fβ x , h x)) οΌβ¨ refl _ β©
         (Ξ» x β fβ x)                   οΌβ¨ refl _ β©
         fβ                             β
dfunext : β π€ π₯ β (π€ β π₯)βΊ Μ
dfunext π€ π₯ = {X : π€ Μ } {A : X β π₯ Μ } {f g : Ξ  A} β f βΌ g β f οΌ g
happly : {X : π€ Μ } {A : X β π₯ Μ } (f g : Ξ  A) β f οΌ g β f βΌ g
happly f g p x = ap (Ξ» - β - x) p
hfunext : β π€ π₯ β (π€ β π₯)βΊ Μ
hfunext π€ π₯ = {X : π€ Μ } {A : X β π₯ Μ } (f g : Ξ  A) β is-equiv (happly f g)
hfunext-gives-dfunext : hfunext π€ π₯ β dfunext π€ π₯
hfunext-gives-dfunext hfe {X} {A} {f} {g} = inverse (happly f g) (hfe f g)
vvfunext : β π€ π₯ β (π€ β π₯)βΊ Μ
vvfunext π€ π₯ = {X : π€ Μ } {A : X β π₯ Μ }
             β ((x : X) β is-singleton (A x))
             β is-singleton (Ξ  A)
dfunext-gives-vvfunext : dfunext π€ π₯ β vvfunext π€ π₯
dfunext-gives-vvfunext fe {X} {A} i = Ξ³
 where
  f : Ξ  A
  f x = center (A x) (i x)
  c : (g : Ξ  A) β f οΌ g
  c g = fe (Ξ» (x : X) β centrality (A x) (i x) (g x))
  Ξ³ : is-singleton (Ξ  A)
  Ξ³ = f , c
postcomp-invertible : {X : π€ Μ } {Y : π₯ Μ } {A : π¦ Μ }
                    β funext π¦ π€
                    β funext π¦ π₯
                    β (f : X β Y)
                    β invertible f
                    β invertible (Ξ» (h : A β X) β f β h)
postcomp-invertible {π€} {π₯} {π¦} {X} {Y} {A} nfe nfe' f (g , Ξ· , Ξ΅) = Ξ³
 where
  f' : (A β X) β (A β Y)
  f' h = f β h
  g' : (A β Y) β (A β X)
  g' k = g β k
  Ξ·' : (h : A β X) β g' (f' h) οΌ h
  Ξ·' h = nfe (Ξ· β h)
  Ξ΅' : (k : A β Y) β f' (g' k) οΌ k
  Ξ΅' k = nfe' (Ξ΅ β k)
  Ξ³ : invertible f'
  Ξ³ = (g' , Ξ·' , Ξ΅')
postcomp-is-equiv : {X : π€ Μ } {Y : π₯ Μ } {A : π¦ Μ }
                  β funext π¦ π€
                  β funext π¦ π₯
                  β (f : X β Y)
                  β is-equiv f
                  β is-equiv (Ξ» (h : A β X) β f β h)
postcomp-is-equiv fe fe' f e =
 invertibles-are-equivs
  (Ξ» h β f β h)
  (postcomp-invertible fe fe' f (equivs-are-invertible f e))
vvfunext-gives-hfunext : vvfunext π€ π₯ β hfunext π€ π₯
vvfunext-gives-hfunext vfe {X} {Y} f = Ξ³
 where
  a : (x : X) β is-singleton (Ξ£ y κ Y x , f x οΌ y)
  a x = singleton-types'-are-singletons (Y x) (f x)
  c : is-singleton (Ξ  x κ X , Ξ£ y κ Y x , f x οΌ y)
  c = vfe a
  Ο : (Ξ£ g κ Ξ  Y , f βΌ g) β (Ξ  x κ X , Ξ£ y κ Y x , f x οΌ y)
  Ο = β-gives-β· Ξ Ξ£-distr-β
  d : is-singleton (Ξ£ g κ Ξ  Y , f βΌ g)
  d = retract-of-singleton Ο c
  e : (Ξ£ g κ Ξ  Y , f οΌ g) β (Ξ£ g κ Ξ  Y , f βΌ g)
  e = NatΞ£ (happly f)
  i : is-equiv e
  i = maps-of-singletons-are-equivs e (singleton-types'-are-singletons (Ξ  Y) f) d
  Ξ³ : (g : Ξ  Y) β is-equiv (happly f g)
  Ξ³ = NatΞ£-equiv-gives-fiberwise-equiv (happly f) i
funext-gives-vvfunext : funext π€ (π€ β π₯) β funext π€ π€ β vvfunext π€ π₯
funext-gives-vvfunext {π€} {π₯} fe fe' {X} {A} Ο = Ξ³
 where
  f : Ξ£ A β X
  f = prβ
  f-is-equiv : is-equiv f
  f-is-equiv = prβ-equiv Ο
  g : (X β Ξ£ A) β (X β X)
  g h = f β h
  e : is-equiv g
  e = postcomp-is-equiv fe fe' f f-is-equiv
  i : is-singleton (Ξ£ h κ (X β Ξ£ A), f β h οΌ ππ X)
  i = e (ππ X)
  r : (Ξ£ h κ (X β Ξ£ A), f β h οΌ ππ X) β Ξ  A
  r (h , p) x = transport A (happly (f β h) (ππ X) p x) (prβ (h x))
  s : Ξ  A β (Ξ£ h κ (X β Ξ£ A), f β h οΌ ππ X)
  s Ο = (Ξ» x β x , Ο x) , refl (ππ X)
  Ξ· : β Ο β r (s Ο) οΌ Ο
  Ξ· Ο = refl (r (s Ο))
  Ξ³ : is-singleton (Ξ  A)
  Ξ³ = retract-of-singleton (r , s , Ξ·) i
abstract
 funext-gives-hfunext       : funext π€ (π€ β π₯) β funext π€ π€ β hfunext π€ π₯
 dfunext-gives-hfunext      : dfunext π€ π₯ β hfunext π€ π₯
 funext-gives-dfunext       : funext π€ (π€ β π₯) β funext π€ π€ β dfunext π€ π₯
 univalence-gives-dfunext'  : is-univalent π€ β is-univalent (π€ β π₯) β dfunext π€ π₯
 univalence-gives-hfunext'  : is-univalent π€ β is-univalent (π€ β π₯) β hfunext π€ π₯
 univalence-gives-vvfunext' : is-univalent π€ β is-univalent (π€ β π₯) β vvfunext π€ π₯
 univalence-gives-hfunext   : is-univalent π€ β hfunext π€ π€
 univalence-gives-dfunext   : is-univalent π€ β dfunext π€ π€
 univalence-gives-vvfunext  : is-univalent π€ β vvfunext π€ π€
 funext-gives-hfunext fe fe' = vvfunext-gives-hfunext (funext-gives-vvfunext fe fe')
 funext-gives-dfunext fe fe' = hfunext-gives-dfunext (funext-gives-hfunext fe fe')
 dfunext-gives-hfunext fe = vvfunext-gives-hfunext (dfunext-gives-vvfunext fe)
 univalence-gives-dfunext' ua ua' = funext-gives-dfunext
                                     (univalence-gives-funext ua')
                                     (univalence-gives-funext ua)
 univalence-gives-hfunext' ua ua' = funext-gives-hfunext
                                      (univalence-gives-funext ua')
                                      (univalence-gives-funext ua)
 univalence-gives-vvfunext' ua ua' = funext-gives-vvfunext
                                      (univalence-gives-funext ua')
                                      (univalence-gives-funext ua)
 univalence-gives-hfunext ua = univalence-gives-hfunext' ua ua
 univalence-gives-dfunext ua = univalence-gives-dfunext' ua ua
 univalence-gives-vvfunext ua = univalence-gives-vvfunext' ua ua
\end{code}