\import Category
\import Category.Functor
\import Category.Limit
\import Equiv
\import Function.Meta
\import Logic
\import Meta
\import Paths
\import Paths.Meta
\record Adjunction (C : Precat) (D : Precat) {
| LAdj : Functor C D
| RAdj : Functor D C
| eta : NatTrans Id (Comp RAdj LAdj)
| epsilon : NatTrans (Comp LAdj RAdj) Id
| eta_epsilon-left {Y : D} : RAdj.Func (epsilon Y) ∘ eta (RAdj Y) = id
| eta_epsilon-right {X : C} : epsilon (LAdj X) ∘ LAdj.Func (eta X) = id
\lemma eta_epsilon-equiv {X : C} {Y : D} : QEquiv {Hom (LAdj X) Y} {Hom X (RAdj Y)} (Func __ ∘ eta X) (epsilon Y ∘ LAdj.Func __) \cowith
| ret_f f => pmap (_ ∘) LAdj.Func-o *> inv o-assoc *> pmap (∘ _) (epsilon.natural f) *> o-assoc *> pmap (f ∘) eta_epsilon-right *> id-right
| f_sec g => pmap (∘ _) Func-o *> o-assoc *> pmap (_ ∘) (inv (eta.natural g)) *> inv o-assoc *> pmap (∘ g) eta_epsilon-left *> id-left
\lemma eta_Iso {Y : D} (e : Iso (eta (RAdj Y))) : Func (epsilon Y) = e.hinv
=> Iso.hinv-unique (\new SplitMono e.f {
| hinv => Func (epsilon Y)
| hinv_f => eta_epsilon-left
}) e idp
\lemma preservesLimits {J : Precat} {G : Functor J D} : PreservesLimit RAdj G
=> \lam c cl z => IsEquiv.rightFactor (inP eta_epsilon-equiv) $ transport IsEquiv (ext \lam h => exts \lam j => pmap (∘ _) Func-o *> o-assoc) $
IsEquiv.trans (cl (LAdj z)) {\lam c' => conePullback {J} {_} {Comp RAdj G} (Cone.map RAdj c') z (eta z)} $ later $ inP \new QEquiv {
| ret c' => \new Cone {
| coneMap j => epsilon (G j) ∘ LAdj.Func (c'.coneMap j)
| coneCoh h => inv o-assoc *> pmap (∘ _) (inv (epsilon.natural _)) *> o-assoc *> pmap (_ ∘) (inv LAdj.Func-o) *> pmap (_ ∘ LAdj.Func __) (c'.coneCoh h)
}
| ret_f c' => exts \lam j => eta_epsilon-equiv.ret_f _
| f_sec c' => exts \lam j => eta_epsilon-equiv.f_ret _
}
} \where {
\func comp {C D E : Precat} (A1 : Adjunction C D) (A2 : Adjunction D E) : Adjunction C E \cowith
| LAdj => Comp A2.LAdj A1.LAdj
| RAdj => Comp A1.RAdj A2.RAdj
| eta => NatTrans.Comp-right A1.RAdj (NatTrans.Comp-left A2.eta A1.LAdj) ∘ A1.eta
| epsilon => A2.epsilon ∘ NatTrans.Comp-right A2.LAdj (NatTrans.Comp-left A1.epsilon A2.RAdj)
| eta_epsilon-left => inv o-assoc *> pmap (∘ _) (inv Func-o *> pmap A1.RAdj.Func (pmap (∘ _) Func-o *> o-assoc *> pmap (_ ∘) (inv (A2.eta.natural _)) *> inv o-assoc *> pmap (∘ _) A2.eta_epsilon-left *> id-left)) *> A1.eta_epsilon-left
| eta_epsilon-right => o-assoc *> pmap (_ ∘) (inv Func-o *> pmap A2.LAdj.Func (pmap (_ ∘) Func-o *> inv o-assoc *> pmap (∘ _) (A1.epsilon.natural _) *> o-assoc *> pmap (_ ∘) A1.eta_epsilon-right *> id-right)) *> A2.eta_epsilon-right
\func rightFactor {C D E : Precat} (G1 : FullyFaithfulFunctor D E) (G2 : Functor C D) (adj : Adjunction E C { | RAdj => Comp G1 G2 }) : Adjunction D C \cowith
| LAdj => Comp adj.LAdj G1
| RAdj => G2
| eta {
| trans Y => G1.inverse (adj.eta (G1 Y))
| natural h => run {
IsEquiv.isInj G1.isFullyFaithful,
repeat {2} (rewrite G1.Func-o),
repeat {2} (rewrite G1.inverse-right),
adj.eta.natural (G1.Func h)
}
}
| epsilon => adj.epsilon
| eta_epsilon-left => G1.isFaithful $ G1.Func-o *> pmap (_ ∘) (IsEquiv.f_ret G1.isFullyFaithful) *> adj.eta_epsilon-left *> inv G1.Func-id
| eta_epsilon-right => pmap (_ ∘ Func __) (IsEquiv.f_ret G1.isFullyFaithful) *> adj.eta_epsilon-right
\class FromReflector \extends Adjunction
| LOb : C -> D
| etaMap {X : C} : Hom X (RAdj (LOb X))
| eta-adjoint {X : C} {Y : D} : IsEquiv {Hom (LOb X) Y} {Hom X (RAdj Y)} (RAdj.Func __ ∘ etaMap)
| LAdj {
| F => LOb
| Func f => IsEquiv.ret eta-adjoint (etaMap ∘ f)
| Func-id => inv $ IsEquiv.adjoint eta-adjoint $ pmap (∘ _) RAdj.Func-id *> id-left *> inv id-right
| Func-o => inv $ IsEquiv.adjoint eta-adjoint $ pmap (∘ _) RAdj.Func-o *> o-assoc *> pmap (_ ∘) (IsEquiv.f_ret eta-adjoint) *> inv o-assoc *> pmap (∘ _) (IsEquiv.f_ret eta-adjoint) *> o-assoc
}
| eta {
| trans X => etaMap
| natural f => inv (IsEquiv.f_ret eta-adjoint)
}
| epsilon {
| trans X => IsEquiv.ret eta-adjoint id
| natural f => IsEquiv.isInj eta-adjoint $ pmap (∘ _) RAdj.Func-o *> o-assoc *> pmap (_ ∘) (IsEquiv.f_ret eta-adjoint) *> inv o-assoc *> pmap (∘ _) (IsEquiv.f_ret eta-adjoint) *> id-left *> inv (pmap (∘ _) RAdj.Func-o *> o-assoc *> pmap (_ ∘) (IsEquiv.f_ret eta-adjoint) *> id-right)
}
| eta_epsilon-left => IsEquiv.f_ret eta-adjoint
| eta_epsilon-right => IsEquiv.isInj eta-adjoint $ rewrite (RAdj.Func-id, RAdj.Func-o, o-assoc, inv (eta.natural _), inv o-assoc, IsEquiv.f_ret eta-adjoint) idp
\class FromCoreflector \extends Adjunction
| ROb : D -> C
| epsilonMap {Y : D} : Hom (LAdj (ROb Y)) Y
| epsilon-adjoint {X : C} {Y : D} : IsEquiv {Hom X (ROb Y)} {Hom (LAdj X) Y} (epsilonMap ∘ LAdj.Func __)
| RAdj {
| F => ROb
| Func f => IsEquiv.ret epsilon-adjoint (f ∘ epsilonMap)
| Func-id => inv $ IsEquiv.adjoint epsilon-adjoint $ pmap (_ ∘) LAdj.Func-id *> id-right *> inv id-left
| Func-o => inv $ IsEquiv.adjoint epsilon-adjoint $ pmap (_ ∘) LAdj.Func-o *> inv o-assoc *> pmap (∘ _) (IsEquiv.f_ret epsilon-adjoint) *> o-assoc *> pmap (_ ∘) (IsEquiv.f_ret epsilon-adjoint) *> inv o-assoc
}
| epsilon {
| trans Y => epsilonMap
| natural f => IsEquiv.f_ret epsilon-adjoint
}
| eta {
| trans X => IsEquiv.ret epsilon-adjoint id
| natural f => IsEquiv.isInj epsilon-adjoint $ pmap (_ ∘) LAdj.Func-o *> inv o-assoc *> pmap (∘ _) (IsEquiv.f_ret epsilon-adjoint) *> id-left *>
inv (pmap (_ ∘) LAdj.Func-o *> inv o-assoc *> pmap (∘ _) (epsilon.natural _) *> o-assoc *> pmap (_ ∘) (IsEquiv.f_ret epsilon-adjoint) *> id-right)
}
| eta_epsilon-left => IsEquiv.isInj epsilon-adjoint $ pmap (_ ∘) LAdj.Func-o *> inv o-assoc *> pmap (∘ _) (epsilon.natural _) *> o-assoc *> pmap (_ ∘) (IsEquiv.f_ret epsilon-adjoint) *> inv (pmap (_ ∘) LAdj.Func-id)
| eta_epsilon-right => IsEquiv.f_ret epsilon-adjoint
}
\class CatEquiv \extends Adjunction {
\field eta-iso {X : C} : Iso (eta X)
\field epsilon-iso {Y : D} : Iso (epsilon Y)
\lemma RAdj-FF {X Y : D} : IsEquiv (RAdj.Func {X} {Y}) => inP \new QEquiv {
| ret g => epsilon _ ∘ LAdj.Func g ∘ hinv {epsilon-iso}
| ret_f f => pmap (∘ _) (epsilon.natural f) *> o-assoc *> pmap (f ∘) epsilon-iso.f_hinv *> id-right
| f_sec g => Func-o *> pmap (∘ _) (Func-o *> pmap (∘ _) (eta_Iso eta-iso) *> natural {eta.iso-inv eta-iso} g) *> o-assoc *> pmap (g ∘) (Iso.hinv-unique (oIso eta-iso (RAdj.Func-iso epsilon-iso)) idIso eta_epsilon-left) *> id-right
}
\protected \func op : CatEquiv C.op D.op \cowith
| LAdj => LAdj.op
| RAdj => RAdj.op
| eta => (eta.iso-inv eta-iso).op
| epsilon => (epsilon.iso-inv epsilon-iso).op
| eta_epsilon-left => Iso.hinv-unique (oIso eta-iso (RAdj.Func-iso epsilon-iso)) idIso eta_epsilon-left
| eta_epsilon-right => Iso.hinv-unique (oIso (LAdj.Func-iso eta-iso) epsilon-iso) idIso eta_epsilon-right
| eta-iso => eta-iso.op.reverse
| epsilon-iso => epsilon-iso.op.reverse
\func reverse : CatEquiv D C \cowith
| LAdj => RAdj
| RAdj => LAdj
| eta => epsilon.iso-inv epsilon-iso
| epsilon => eta.iso-inv eta-iso
| eta_epsilon-left => Iso.hinv-unique (oIso (LAdj.Func-iso eta-iso) epsilon-iso) idIso eta_epsilon-right
| eta_epsilon-right => Iso.hinv-unique (oIso eta-iso (RAdj.Func-iso epsilon-iso)) idIso eta_epsilon-left
| eta-iso => epsilon-iso.reverse
| epsilon-iso => eta-iso.reverse
}