\import Algebra.Meta
\import Data.Or
\import Equiv
\import Equiv.Path
\import Equiv.Sigma
\import Function
\import Function.Meta
\import Homotopy.Cube
\import Homotopy.Localization.Modality
\import Homotopy.Localization.Universe
\import Homotopy.Pushout
\import Logic
\import Paths
\func famUniverse.{u} {fam : Family.{u}} : ReflUniverse \cowith
| Universe => universe
| localization A => \new Localization {
| S' {
| S => LData {famHat} A
| local j => inP \new QEquiv {
| ret => ext {famHat} {A} {inl j}
| ret_f g =>
\have p s => path (isExt {famHat} {A} {inr j} (rec (ext {famHat} {A} {inl j} (g `o` F j)) g (\lam x => path (isExt {famHat} {A} {inl j} (g `o` F j) x))) s)
\in path (\lam i y => (inv (p (pinl y)) *> p (pinr y)) @ i)
| f_sec f => path (\lam i x => isExt {famHat} {A} {inl j} f x i)
}
}
| inL => alpha {famHat}
| local-univ Z => alpha-equiv {famHat} {A} {\new Local {universe {famHat}} Z
\case \elim __ \with {
| inl j => local {Z} j
| inr j => transport IsEquiv (inv (path (\lam i g d => rec.map g id id (\lam x => idpe (F j x)) d @ i)))
(IsEquiv.trans (Embedding.diag-equiv (Embedding.fromIsEquiv (Z.local j))) (pushout_pullback-equiv (F j)))
}}
}
\where {
\open PushoutData
\class Family.{u}
| J : \Type u
| X : J -> \Type u
| Y : J -> \Type u
| F : \Pi (j : J) -> X j -> Y j
\instance universe.{u} {fam : Family.{u}} : Universe.{u} \cowith
| isLocal Z => \Pi (j : J) -> IsEquiv {Y j -> Z} {X j -> Z} (o F j)
\data LData.{u} {fam : Family.{u}} (A : \Type u)
| alpha A
| ext {j : J} (X j -> LData A) (Y j)
| isExt {j : J} (f : X j -> LData A) (x : X j) : ext f (F j x) = f x
\func dataExt.{u} {fam : Family.{u}} {A : \Type u} {Z : Local.{u}} (h : A -> Z) (d : LData A) : Z \elim d
| alpha a => h a
| ext {j} f y => IsEquiv.ret (Z.local j) (\lam x => dataExt h (f x)) y
| isExt {j} f x i => (IsEquiv.f_ret (Z.local j) {\lam x => dataExt h (f x)} i) x
\func dataExt-unique.{u} {fam : Family.{u}} {A : \Type u} {Z : Local.{u}} (H1 H2 : LData A -> Z) (K : \Pi (a : A) -> H1 (alpha a) = H2 (alpha a)) (d : LData A) : H1 d = H2 d \elim d
| alpha a => K a
| ext {j} f y =>
\have p x => path (\lam i => H1 (isExt f x i)) <* dataExt-unique H1 H2 K (f x) *> inv (path (\lam i => H2 (isExt f x i)))
\in path (\lam i => IsEquiv.ret (pmapIsEquiv (Z.local j) {H1 `o` ext f} {H2 `o` ext f}) (path (\lam i' x => p x i')) i y)
| isExt {j} f x i =>
\let | p x => path (\lam i => H1 (isExt f x i)) <* dataExt-unique H1 H2 K (f x) *> inv (path (\lam i => H2 (isExt f x i)))
| e => pmapIsEquiv (Z.local j) {H1 `o` ext f} {H2 `o` ext f}
| q => path (\lam i => IsEquiv.ret e (path (\lam i' x => p x i')) i (F j x))
| s : q = p x => path (\lam k => path (\lam i => IsEquiv.f_ret e k i x))
\in Cube2.map _ _ _ _ s i
\lemma alpha-equiv.{u} {fam : Family.{u}} {A : \Type u} {Z : Local.{u}} : IsEquiv {LData A -> Z} {A -> Z} (-o alpha)
=> inP \new QEquiv {
| ret => dataExt
| ret_f h => path (\lam i d => dataExt-unique (dataExt (h `o` alpha)) h (\lam _ => idp) d i)
| f_sec _ => idp
}
\func DHat.{u} {fam : Family.{u}} (k : J `Or` J) : \Type u \elim k
| inl j => X j
| inr j => PushoutData (F j) (F j)
\func CHat.{u} {fam : Family.{u}} (k : J `Or` J) : \Type u \elim k
| inl j => Y j
| inr j => Y j
\func FHat.{u} {fam : Family.{u}} (k : J `Or` J) (d : DHat k) : CHat k \elim k
| inl j => F j d
| inr j => rec id id (\lam _ => idp) d
\func famHat.{u} {fam : Family.{u}}
=> \new Family (J `Or` J) DHat CHat FHat
\lemma pushout_pullback-equiv {X Y Z : \Type} (f : X -> Y)
: IsEquiv {\Sigma (g1 g2 : Y -> Z) (g1 `o` f = g2 `o` f)}
{PushoutData f f -> Z}
(\lam t => rec t.1 t.2 (\lam x => path ((t.3 @ __) x)))
=> inP \new QEquiv {
| ret m => (m `o` pinl, m `o` pinr, path (\lam i x => m (pglue x i)))
| ret_f t => idp
| f_sec m => path (\lam i d => (\case \elim d \return rec (m `o` pinl) (m `o` pinr) (\lam x => path (\lam i => m (pglue x i))) d = m d \with {
| pinl y => idp
| pinr y => idp
| pglue x i => idp
}) @ i)
}
}
\func nullFamUniverse.{u} {J : \Type u} (X : J -> \Type u) : Modality \cowith
| ReflUniverse => famUniverse {\new famUniverse.Family J X (\lam _ => \Sigma) (\lam _ _ => ())}
| isModality A B => \new Local {
| local j => inP $ equation
(\Sigma -> \Sigma (a : A) (B a)) {\new QEquiv { | B => \Sigma (f : \Sigma -> A) (\Sigma -> B (f ())) | f g => (\lam _ => (g ()).1, \lam _ => (g ()).2) | ret p _ => (p.1 (), p.2 ()) | ret_f g => idp | f_sec p => idp }}
(\Sigma (f : \Sigma -> A) (\Sigma -> B (f ()))) {sigma-right {\Sigma -> A} $ \lam f => IsEquiv.toQEquiv $ (B (f ())).local j}
(\Sigma (f : \Sigma -> A) (X j -> B (f ()))) {sigma-left $ IsEquiv.toQEquiv (A.local j)}
(\Sigma (f : X j -> A) (\Pi (x : X j) -> B (f x))) {\new QEquiv { | B => X j -> \Sigma (a : A) (B a) | f p x => (p.1 x, p.2 x) | ret g => ((g __).1, (g __).2) | ret_f p => idp | f_sec g => idp }}
(X j -> \Sigma (a : A) (B a))
}
\where {
\lemma localDesc.{u} {J : \Type u} {X : J -> \Type u} (Z : \Type u) : (nullFamUniverse X).isLocal Z = (\Pi (j : J) -> IsEquiv {Z} {X j -> Z} (\lam z _ => z))
=> path \lam i => \Pi (j : J) -> IsEquiv {QEquiv_= (unit-func Z) i} {X j -> Z} (\lam t _ => coe2 (QEquiv_= (unit-func Z)) i t right)
}
\func nullTypeUniverse.{u} (M : \Type u) : Modality => nullFamUniverse {\Sigma} (\lam _ => M)
\where {
\lemma localDesc.{u} (M Z : \Type u) : (nullTypeUniverse M).isLocal Z = IsEquiv {Z} {M -> Z} (\lam z _ => z)
=> nullFamUniverse.localDesc Z *> QEquiv_= (unit-func (IsEquiv {Z} {M -> Z} (\lam z _ => z)))
}