open import Cat.Functor.Equivalence
open import Cat.Functor.Properties
open import Cat.Diagram.Pullback
open import Cat.Diagram.Initial
open import Cat.Functor.Compose
open import Cat.Instances.Comma
open import Cat.Instances.Slice
open import Cat.Prelude

import Cat.Reasoning

module Cat.Functor.Pullback
{o β} {C : Precategory o β}
where

open Cat.Reasoning C
open is-pullback
open Pullback
open Initial
open Functor
open _=>_
open /-Obj
open /-Hom


# Base changeπ

Let be a category with all pullbacks, and a morphism in Then we have a functor called the base change, where the action on objects is given by pulling back along

On objects, the functor maps as in the diagram below. Itβs a bit busy, so look at it in parts: On the left we have the object of and on the right we have the whole pullback diagram, showing how the parts fit together. The actual object of the functor gives is the vertical arrow

module _ (pullbacks : β {X Y Z} f g β Pullback C {X} {Y} {Z} f g) {X Y : Ob} (f : Hom Y X) where
Base-change : Functor (Slice C X) (Slice C Y)
Base-change .Fβ x = ob where
ob : /-Obj Y
ob .domain = pullbacks (x .map) f .apex
ob .map    = pullbacks (x .map) f .pβ


On morphisms, we use the universal property of the pullback to obtain a map by observing that the square diagram below is a cone over

  Base-change .Fβ {x} {y} dh = dh' where
module ypb = Pullback (pullbacks (y .map) f)
module xpb = Pullback (pullbacks (x .map) f)
dh' : /-Hom _ _
dh' .map = ypb.universal {pβ' = dh .map β xpb.pβ}
(pulll (dh .commutes) β xpb.square)
dh' .commutes = ypb.pββuniversal

The properties of pullbacks also guarantee that this operation is functorial, but the details are not particularly enlightening.
  Base-change .F-id {x} = ext (sym (xpb.unique id-comm (idr _)))
where module xpb = Pullback (pullbacks (x .map) f)

Base-change .F-β {x} {y} {z} am bm =
ext (sym (zpb.unique
(pulll zpb.pββuniversal β pullr ypb.pββuniversal β assoc _ _ _)
(pulll zpb.pββuniversal β ypb.pββuniversal)))
where
module ypb = Pullback (pullbacks (y .map) f)
module zpb = Pullback (pullbacks (z .map) f)


## Propertiesπ

The base change functor is a right adjoint. We construct the left adjoint directly, then give the unit and counit, and finally prove the triangle identities.

The left adjoint, called dependent sum and written is given on objects by precomposition with and on morphisms by what is essentially the identity function β only the witness of commutativity must change.

module _ {X Y : Ob} (f : Hom Y X) where
Ξ£f : Functor (Slice C Y) (Slice C X)
Ξ£f .Fβ o = cut (f β o .map)
Ξ£f .Fβ dh = record { map = dh .map ; commutes = pullr (dh .commutes) }
Ξ£f .F-id = trivial!
Ξ£f .F-β f g = trivial!

open _β£_

Ξ£-iso-equiv
: {X Y : Ob} {f : Hom Y X}
β Cat.Reasoning.is-invertible C f
β is-equivalence (Ξ£f f)
Ξ£-iso-equiv {X} {f = f} isom = ff+split-esoβis-equivalence Ξ£-ff Ξ£-seso where
module Sl = Cat.Reasoning (Slice C X)
module isom = is-invertible isom

func = Ξ£f f
Ξ£-ff : β {x y} β is-equiv (func .Fβ {x} {y})
Ξ£-ff = is-isoβis-equiv (iso βinv (Ξ» x β trivial!) Ξ» x β trivial!) where
βinv : /-Hom _ _ β /-Hom _ _
βinv o .map = o .map
βinv o .commutes = invertibleβmonic isom _ _ (assoc _ _ _ β o .commutes)

Ξ£-seso : is-split-eso func
Ξ£-seso y = cut (isom.inv β y .map)
, Sl.make-iso into from' (ext (eliml refl)) (ext (eliml refl))
where
into : /-Hom _ _
into .map = id
into .commutes = id-comm β sym (pulll isom.invl)

from' : /-Hom _ _
from' .map = id
from' .commutes = elimr refl β cancell isom.invl


The adjunction unit and counit are given by the universal properties of pullbacks. β οΈ WIP β οΈ

module _ (pullbacks : β {X Y Z} f g β Pullback C {X} {Y} {Z} f g) {X Y : Ob} (f : Hom Y X) where
open _β£_
open _=>_

Ξ£fβ£f* : Ξ£f f β£ Base-change pullbacks f
Ξ£fβ£f* .unit .Ξ· obj = dh where
module pb = Pullback (pullbacks (f β obj .map) f)
dh : /-Hom _ _
dh .map = pb.universal {pβ' = id} {pβ' = obj .map} (idr _)
dh .commutes = pb.pββuniversal
Ξ£fβ£f* .unit .is-natural x y g =
ext (pb.uniqueβ
{p = (f β y .map) β id β g .map β‘β¨ cat! C β©β‘ f β y .map β g .map β}
(pulll pb.pββuniversal)
(pulll pb.pββuniversal)
(pulll pb.pββuniversal β pullr pb'.pββuniversal β id-comm)
(pulll pb.pββuniversal β pb'.pββuniversal β sym (g .commutes)))
where
module pb = Pullback (pullbacks (f β y .map) f)
module pb' = Pullback (pullbacks (f β x .map) f)

Ξ£fβ£f* .counit .Ξ· obj = dh where
module pb = Pullback (pullbacks (obj .map) f)
dh : /-Hom _ _
dh .map = pb.pβ
dh .commutes = pb.square
Ξ£fβ£f* .counit .is-natural x y g = ext pb.pββuniversal
where module pb = Pullback (pullbacks (y .map) f)

Ξ£fβ£f* .zig {A} = ext pb.pββuniversal
where module pb = Pullback (pullbacks (f β A .map) f)

Ξ£fβ£f* .zag {B} = ext
(sym (pb.uniqueβ {p = pb.square}
(idr _) (idr _)
(pulll pb.pββuniversal β pullr pb'.pββuniversal β idr _)
(pulll pb.pββuniversal β pb'.pββuniversal))) where
module pb = Pullback (pullbacks (B .map) f)
module pb' = Pullback (pullbacks (f β pb.pβ) f)


## Equifibred natural transformationsπ

A natural transformation is called equifibred, or cartesian, if each of its naturality squares is a pullback:

is-equifibred
: β {oj βj} {J : Precategory oj βj} {F G : Functor J C}
β F => G β Type _
is-equifibred {J = J} {F} {G} Ξ± =
β {x y} (f : J .Precategory.Hom x y)
β is-pullback C (F .Fβ f) (Ξ± .Ξ· y) (Ξ± .Ξ· x) (G .Fβ f)


An easy property of equifibered transformations is that they are closed under pre-whiskering:

β-equifibred
: β {oj βj ok βk} {J : Precategory oj βj} {K : Precategory ok βk}
β {F G : Functor J C} (H : Functor K J) (Ξ± : F => G)
β is-equifibred Ξ± β is-equifibred (Ξ± β H)
β-equifibred H Ξ± eq f = eq (H .Fβ f)