\import Algebra.Meta
\import Category.Functor
\import Equiv(Equiv, QEquiv, Retraction, transEquiv)
\import Equiv.Path
\import Function.Meta ($)
\import Logic
\import Meta
\import Paths
\import Paths.Meta
\import Set
\plevels obj >= hom
\class Precat (Ob : \hType obj) {
| Hom : Ob -> Ob -> \Set hom
| id (X : Ob) : Hom X X
| \fixl 8 o \alias \infixl 8 ∘ {X Y Z : Ob} : Hom Y Z -> Hom X Y -> Hom X Z
| id-left {X Y : Ob} {f : Hom X Y} : id Y ∘ f = f
| id-right {X Y : Ob} {f : Hom X Y} : f ∘ id X = f
| o-assoc {X Y Z W : Ob} {h : Hom Z W} {g : Hom Y Z} {f : Hom X Y} : (h ∘ g) ∘ f = h ∘ (g ∘ f)
\func \infixl 8 >> {x y z : Ob} (f : Hom x y) (g : Hom y z) => g ∘ f
\func op : Precat \cowith
| Ob => Ob
| Hom x y => Hom y x
| id x => id x
| o g f => o f g
| id-left => id-right
| id-right => id-left
| o-assoc => inv o-assoc
\func idtoiso {a b : Ob} (p : a = b) : Iso {_} {a} {b} \elim p
| idp => idIso
}
\meta SmallPrecat => Precat \lp
\open Precat (>>)
\record Map {C : Precat} {dom cod : C} (\coerce f : Hom dom cod)
\record Mono \extends Map
| isMono {x : C} {g h : Hom x dom} : f ∘ g = f ∘ h -> g = h
\where {
\func comp {C : Precat} {x y z : C} (g : Mono {C} {y} {z}) (f : Mono {C} {x} {y}) : Mono {C} {x} {z} (g.f ∘ f) \cowith
| isMono p => f.isMono (g.isMono (inv o-assoc *> p *> o-assoc))
}
\func isEpi {C : Precat} {x y : C} (f : Hom x y) => \Pi {z : C} {g h : Hom y z} -> g ∘ f = h ∘ f -> g = h
\record SplitMono \extends Mono {
| hinv : Hom cod dom
| hinv_f : hinv ∘ f = id dom
| isMono {_} {g} {h} gf=hf =>
g ==< inv id-left >==
g >> id dom ==< pmap (g >>) (inv hinv_f) >==
g >> (f >> hinv) ==< o-assoc >==
(g >> f) >> hinv ==< pmap (o hinv) gf=hf >==
(h >> f) >> hinv ==< inv o-assoc >==
h >> (f >> hinv) ==< pmap (h >>) hinv_f >==
h >> id dom ==< id-left >==
h `qed
\lemma adjoint {z : C} {g : Hom z dom} {h : Hom z cod} (p : f ∘ g = h) : g = hinv ∘ h
=> inv id-left *> pmap (`∘ g) (inv hinv_f) *> o-assoc *> pmap (hinv ∘) p
}
\record Iso \extends SplitMono {
| f_hinv : f ∘ hinv = id cod
\lemma adjointInv {z : C} {g : Hom z dom} {h : Hom z cod} (p : g = hinv ∘ h) : f ∘ g = h
=> pmap (f ∘) p *> inv o-assoc *> pmap (`∘ h) f_hinv *> id-left
\lemma adjoint' {z : C} {g : Hom cod z} {h : Hom dom z} (p : g ∘ f = h) : g = h ∘ hinv
=> inv id-right *> pmap (g ∘) (inv f_hinv) *> inv o-assoc *> pmap (`∘ hinv) p
\lemma -o_Equiv {z : C} : Equiv {Hom cod z} {Hom dom z} (__ ∘ f)
=> \new QEquiv {
| ret h => h ∘ hinv
| ret_f h => o-assoc *> pmap (h ∘) f_hinv *> id-right
| f_sec h => o-assoc *> pmap (h ∘) hinv_f *> id-right
}
\lemma o-_Equiv {z : C} : Equiv {Hom z dom} {Hom z cod} (f ∘ __)
=> \new QEquiv {
| ret h => hinv ∘ h
| ret_f h => inv o-assoc *> pmap (`∘ _) hinv_f *> id-left
| f_sec h => inv o-assoc *> pmap (`∘ _) f_hinv *> id-left
}
\func reverse : Iso => \new Iso hinv f f_hinv hinv_f
\func op : Iso => \new Iso {C.op} f hinv f_hinv hinv_f
} \where {
\func equals {C : Precat} {x y : C} (e e' : Iso {C} {x} {y}) (p : e.f = e'.f) : e = e'
=> ext (p, isMono {e} (e.f_hinv *> inv e'.f_hinv *> inv (pmap (e'.hinv >>) p)))
\use \level levelProp {C : Precat} {x y : C} (f : Hom x y) (e e' : Iso f) => equals e e' idp
\lemma rightFactor {C : Precat} {x y z : C} (f : Hom x y) (e2 : Mono {C} {y} {z}) (e3 : Iso (e2.f ∘ f)) : Iso f \cowith
| hinv => e3.hinv ∘ e2
| hinv_f => o-assoc *> e3.hinv_f
| f_hinv => e2.isMono (rewriteEq e3.f_hinv (inv (rewriteEq id-right idp)))
\lemma leftFactor {C : Precat} {x y z : C} {f : Hom x y} (e : isEpi f) (g : Hom y z) (e3 : Iso (g ∘ f)) : Iso g
=> op {rightFactor {C.op} g (\new Mono f e) e3.op}
\lemma composite {C : Precat} {x y z : C} (f : Iso {C} {x} {y}) (g : Iso {C} {y} {z}) : Iso (g.f ∘ f.f) \cowith
| hinv => f.hinv ∘ g.hinv
| hinv_f => rewriteEq g.hinv_f (rewriteEq f.hinv_f idp)
| f_hinv => rewriteEq f.f_hinv (rewriteEq g.f_hinv idp)
}
\func idIso {C : Precat} {x : C} : Iso (id x) \cowith
| hinv => id x
| f_hinv => id-left
| hinv_f => id-right
\class Cat \extends Precat {
| univalence {a b : Ob} : Equiv (idtoiso {_} {a} {b})
\func op : Cat \cowith
| Precat => Precat.op
| univalence => univalenceFromEquiv {Precat.op} (\lam {a} {b} => transEquiv univalence $ later \new QEquiv {
| f (e : Iso) => e.op.reverse
| ret (e : Iso) => e.op.reverse
| ret_f => idpe
| f_sec => idpe
}) (\lam {c} => idp)
\func isotoid {a b : Ob} (e : Iso {\this} {a} {b}) : a = b
=> univalence.ret e
\lemma transport_iso (e : Iso {\this}) : transport (Hom e.dom) (isotoid e) (id e.dom) = e
=> Jl (\lam b p => transport (Hom e.dom) p (id e.dom) = idtoiso p) idp (isotoid e) *> path (\lam i => Iso.f {univalence.f_ret e i})
\func univalenceToTransport (e : Iso {\this}) : \Sigma (p : e.dom = e.cod) (transport (Hom e.dom) p (id e.dom) = e)
=> (isotoid e, transport_iso e)
\lemma transport_Hom {x1 y1 x2 y2 : Ob} (p1 : x1 = y1) (p2 : x2 = y2) {g : Hom x1 x2} {f : Hom y1 y2}
(h : g >> transport (Hom x2) p2 (id x2) = transport (Hom x1) p1 (id x1) >> f)
: coe (\lam i => Hom (p1 @ i) (p2 @ i)) g right = f \elim p1, p2
| idp, idp => inv id-left *> h *> id-right
\lemma transport_Hom-left {x y z : Ob} (p : x = y) {g : Hom x z} {f : Hom y z} (h : g = transport (Hom x) p (id x) >> f) : transport (`Hom z) p g = f \elim p
| idp => h *> id-right
\lemma transport_Hom-right {x y z : Ob} (p : x = y) {g : Hom z x} {f : Hom z y} (h : g >> transport (Hom x) p (id x) = f) : transport (Hom z) p g = f \elim p
| idp => inv id-left *> h
\lemma transport_Hom_iso (e1 e2 : Iso {\this}) {g : Hom e1.dom e2.dom} {f : Hom e1.cod e2.cod}
(h : g >> e2.f = e1.f >> f)
: coe (\lam i => Hom (isotoid e1 @ i) (isotoid e2 @ i)) g right = f
=> transport_Hom (isotoid e1) (isotoid e2) (pmap (g >>) (transport_iso e2) *> h *> pmap (`>> f) (inv (transport_iso e1)))
\lemma transport_Hom_iso-left (e : Iso {\this}) {z : Ob} (g : Hom e.dom z) {f : Hom e.cod z} (h : g = e.f >> f) : transport (`Hom z) (isotoid e) g = f
=> transport_Hom-left (isotoid e) (h *> pmap (`>> f) (inv (transport_iso e)))
\lemma transport_Hom_iso-right (e : Iso {\this}) {z : Ob} (g : Hom z e.dom) {f : Hom z e.cod} (h : g >> e.f = f) : transport (Hom z) (isotoid e) g = f
=> transport_Hom-right (isotoid e) (pmap (g >>) (transport_iso e) *> h)
} \where {
\lemma univalenceFromEquiv {C : Precat} (e : \Pi {a b : C} -> Equiv {a = b} {Iso {C} {a} {b}}) (i : \Pi {a : C} -> Iso.f {e (idpe a)} = id a) {a b : C} : Equiv (idtoiso {C} {a} {b})
=> \let t : e.f = idtoiso {C} {a} {b} => ext (\case \elim b, \elim __ \with {
| b, idp => Iso.equals _ _ i
}) \in transport (Equiv __) t e
\lemma makeUnivalence {C : Precat} (c : \Pi (e : Iso {C}) -> \Sigma (p : e.dom = e.cod) (transport (Hom e.dom) p (id e.dom) = e)) {a b : C} : Equiv (idtoiso {C} {a} {b})
=> pathEquiv (\lam a b => Iso {C} {a} {b}) (\lam {a} {b} => \new Retraction {
| f => idtoiso
| sec e => (c e).1
| f_sec (e : Iso) => Iso.equals _ _ (Jl (\lam b p => Iso.f {idtoiso p} = transport (Hom e.dom) p (id e.dom)) idp (c e).1 *> (c e).2)
})
\lemma transport_Hom_Func {C D E : Precat} {x1 y1 : C} (p1 : x1 = y1) {x2 y2 : D} (p2 : x2 = y2) (F : Functor C E) (G : Functor D E) {g : Hom (F x1) (G x2)} {f : Hom (F y1) (G y2)}
(h : transport (Hom (G x2)) (pmap G p2) (id (G x2)) ∘ g = f ∘ transport (Hom (F x1)) (pmap F p1) (id (F x1)))
: coe (\lam i => Hom (F (p1 @ i)) (G (p2 @ i))) g right = f \elim p1, p2
| idp, idp => inv id-left *> h *> id-right
\lemma transport_Hom_Func-right {C D : Precat} {x y : C} (p : x = y) {z : D} (F : Functor C D) {g : Hom z (F x)}
: transport (Hom z) (pmap F p) g = F.Func (transport (Hom x) p (id x)) ∘ g \elim p
| idp => inv (pmap (`∘ g) Func-id *> id-left)
\lemma transport_Hom_Func_iso-right {C : Cat} {D : Precat} (e : Iso {C}) {z : D} (F : Functor C D) {g : Hom z (F e.dom)}
: transport (Hom z) (pmap F (isotoid e)) g = F.Func e.f ∘ g
=> transport_Hom_Func-right (isotoid e) F *> cong (transport_iso e)
\lemma transport_Hom_Func_iso {C D : Cat} {E : Precat} (e1 : Iso {C}) (e2 : Iso {D}) (F : Functor C E) (G : Functor D E) {g : Hom (F e1.dom) (G e2.dom)} {f : Hom (F e1.cod) (G e2.cod)}
(h : G.Func e2.f ∘ g = f ∘ F.Func e1.f)
: coe (\lam i => Hom (F (isotoid e1 @ i)) (G (isotoid e2 @ i))) g right = f
=> transport_Hom_Func (isotoid e1) (isotoid e2) F G (pmap (`∘ g) (transport_Hom_Func_iso-right e2 G *> id-right) *> h *> pmap (f ∘) (inv (transport_Hom_Func_iso-right e1 F *> id-right)))
}
\meta SmallCat => Cat \lp
\func DiscretePrecat (X : \Type) : Precat X \cowith
| Hom x y => Trunc0 (x = y)
| id x => in0 idp
| o {x y z : X} (t : Trunc0 (y = z)) (s : Trunc0 (x = y)) : Trunc0 (x = z) \elim t, s {
| in0 y=z, in0 x=y => in0 (x=y *> y=z)
}
| id-left {_} {_} {p} => cases p idp
| id-right {_} {_} {p} => cases p (pmap in0 (idp_*> _))
| o-assoc {_} {_} {_} {_} {p} {q} {r} => cases (p,q,r) (pmap in0 (inv (*>-assoc _ _ _)))
\where {
\func map {X : \Type} {D : Precat} (f : X -> D) {x y : X} (h : Hom {DiscretePrecat X} x y) : Hom (f x) (f y) \elim h
| in0 idp => id _
}
\sfunc SIP (C : Cat) (Str : C -> \hType (\suc \lp)) (isHom : \Pi {x y : C} -> Str x -> Str y -> Hom x y -> \hType (\suc \lp))
(st : \Pi {X : C} {S1 S2 : Str X} -> isHom S1 S2 (id X) -> isHom S2 S1 (id X) -> S1 = S2)
{X Y : C} (e : Iso {C} {X} {Y}) (S1 : Str X) (S2 : Str Y) (p : isHom S1 S2 e) (q : isHom S2 S1 e.hinv)
: \Sigma (p : X = Y) (Path (\lam i => Str (p @ i)) S1 S2) (transport (Hom X) p (id X) = e)
=> \case \elim Y, \elim e, \elim S2, p, q, Cat.univalenceToTransport e \with {
| Y, e : Iso, S2, p, q, (idp,s) => (idp, st (transportInv (isHom S1 S2) s p) (transport (isHom S2 S1) (inv id-right *> pmap (∘ e.hinv) s *> e.hinv_f) q), s)
}
\class Graph (\coerce V : \Set) (E : V -> V -> \Set) {
\data Paths (x y : V)
| empty (x = y)
| cons {z : V} (E x z) (Paths z y)
\func concat {x y z : V} (p : Paths x y) (q : Paths y z) : Paths x z \elim p
| empty idp => q
| cons e p => cons e (concat p q)
\lemma concat_idp {x y : V} {p : Paths x y} : concat p (empty idp) = p \elim p
| empty idp => idp
| cons e p => pmap (cons e) concat_idp
\lemma concat-assoc {x y z w : V} {p : Paths x y} {q : Paths y z} {r : Paths z w} : concat (concat p q) r = concat p (concat q r) \elim p
| empty idp => idp
| cons e p => pmap (cons e) concat-assoc
\func FreeCat : Cat V \cowith
| Hom => Paths
| id x => empty idp
| o q p => concat p q
| id-left => concat_idp
| id-right => idp
| o-assoc => inv concat-assoc
| univalence => Cat.makeUnivalence $ later \case \elim __ \with {
| (x, y, empty idp, _, _, _) => (idp,idp)
| (x, y, cons e p, _, (), _)
}
}
\func TrivialCat : Cat => Graph.FreeCat {\new Graph (\Sigma) (\lam _ _ => Empty)}