l3lab/ntp-mathlib huggingface dataset:
@[reassoc (attr := simp)]
theorem inr_inl_pushoutAssoc_hom [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inr ≫ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom = pushout.inl ≫ pushout.inr := by
  trans f₂ ≫ l₁
  · congr 1
    

Proof state:
case e_a
C : Type u
inst✝⁵ : Category.{v, u} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom =
    pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr)

Next tactic:
exact
      (pushoutPushoutLeftIsPushout g₁ g₂ g₃ g₄).comp_coconePointUniqueUpToIso_hom _
        WalkingCospan.left
@[reassoc (attr := simp)]
theorem inr_inl_pushoutAssoc_hom [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inr ≫ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom = pushout.inl ≫ pushout.inr := by
  trans f₂ ≫ l₁
  · congr 1
    exact
      (pushoutPushoutLeftIsPushout g₁ g₂ g₃ g₄).comp_coconePointUniqueUpToIso_hom _
        WalkingCospan.left
  · 

Proof state:
C : Type u
inst✝⁵ : Category.{v, u} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inr ≫
      pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr) =
    pushout.inl ≫ pushout.inr

Next tactic:
exact pushout.inr_desc _ _ _
@[reassoc (attr := simp)]
theorem inr_inr_pushoutAssoc_inv [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inr ≫ pushout.inr ≫ (pushoutAssoc g₁ g₂ g₃ g₄).inv = pushout.inr := by
  

Proof state:
C : Type u
inst✝⁵ : Category.{v, u} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inr ≫ pushout.inr ≫ (pushoutAssoc g₁ g₂ g₃ g₄).inv = pushout.inr

Next tactic:
trans f₄ ≫ l₂'
@[reassoc (attr := simp)]
theorem inr_inr_pushoutAssoc_inv [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inr ≫ pushout.inr ≫ (pushoutAssoc g₁ g₂ g₃ g₄).inv = pushout.inr := by
  trans f₄ ≫ l₂'
  · 

Proof state:
C : Type u
inst✝⁵ : Category.{v, u} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inr ≫ pushout.inr ≫ (pushoutAssoc g₁ g₂ g₃ g₄).inv =
    pushout.inr ≫
      pushout.desc (pushout.inr ≫ pushout.inl) pushout.inr (_ : g₃ ≫ pushout.inr ≫ pushout.inl = g₄ ≫ pushout.inr)

Next tactic:
congr 1
@[reassoc (attr := simp)]
theorem inr_inr_pushoutAssoc_inv [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inr ≫ pushout.inr ≫ (pushoutAssoc g₁ g₂ g₃ g₄).inv = pushout.inr := by
  trans f₄ ≫ l₂'
  · congr 1
    

Proof state:
case e_a
C : Type u
inst✝⁵ : Category.{v, u} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inr ≫ (pushoutAssoc g₁ g₂ g₃ g₄).inv =
    pushout.desc (pushout.inr ≫ pushout.inl) pushout.inr (_ : g₃ ≫ pushout.inr ≫ pushout.inl = g₄ ≫ pushout.inr)

Next tactic:
exact
      (pushoutPushoutLeftIsPushout g₁ g₂ g₃ g₄).comp_coconePointUniqueUpToIso_inv
        (pushoutPushoutRightIsPushout g₁ g₂ g₃ g₄) WalkingCospan.right
@[reassoc (attr := simp)]
theorem inr_inr_pushoutAssoc_inv [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inr ≫ pushout.inr ≫ (pushoutAssoc g₁ g₂ g₃ g₄).inv = pushout.inr := by
  trans f₄ ≫ l₂'
  · congr 1
    exact
      (pushoutPushoutLeftIsPushout g₁ g₂ g₃ g₄).comp_coconePointUniqueUpToIso_inv
        (pushoutPushoutRightIsPushout g₁ g₂ g₃ g₄) WalkingCospan.right
  · 

Proof state:
C : Type u
inst✝⁵ : Category.{v, u} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inr ≫
      pushout.desc (pushout.inr ≫ pushout.inl) pushout.inr (_ : g₃ ≫ pushout.inr ≫ pushout.inl = g₄ ≫ pushout.inr) =
    pushout.inr

Next tactic:
exact pushout.inr_desc _ _ _
@[reassoc (attr := simp)]
theorem inl_pushoutAssoc_inv [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).inv = pushout.inl ≫ pushout.inl := by
  

Proof state:
C : Type u
inst✝⁵ : Category.{v, u} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).inv = pushout.inl ≫ pushout.inl

Next tactic:
rw [Iso.comp_inv_eq, Category.assoc, inl_inl_pushoutAssoc_hom]
@[reassoc (attr := simp)]
theorem inl_inr_pushoutAssoc_inv [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inl ≫ pushout.inr ≫ (pushoutAssoc g₁ g₂ g₃ g₄).inv = pushout.inr ≫ pushout.inl := by
  

Proof state:
C : Type u
inst✝⁵ : Category.{v, u} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inl ≫ pushout.inr ≫ (pushoutAssoc g₁ g₂ g₃ g₄).inv = pushout.inr ≫ pushout.inl

Next tactic:
rw [← Category.assoc, Iso.comp_inv_eq, Category.assoc, inr_inl_pushoutAssoc_hom]
@[reassoc (attr := simp)]
theorem inr_pushoutAssoc_hom [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inr ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom = pushout.inr ≫ pushout.inr := by
  

Proof state:
C : Type u
inst✝⁵ : Category.{v, u} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inr ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom = pushout.inr ≫ pushout.inr

Next tactic:
rw [← Iso.eq_comp_inv, Category.assoc, inr_inr_pushoutAssoc_inv]
/-- Having wide pullback at any universe level implies having binary pullbacks. -/
instance (priority := 100) hasPullbacks_of_hasWidePullbacks (D : Type u) [h : Category.{v} D]
    [h' : HasWidePullbacks.{w} D] : HasPullbacks.{v,u} D := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D✝ : Type u₂
inst✝ : Category.{v₂, u₂} D✝
W X Y Z : C
D : Type u
h : Category.{v, u} D
h' : HasWidePullbacks D
⊢ HasPullbacks D

Next tactic:
haveI I := @hasWidePullbacks_shrink.{0, w} D h h'
/-- Having wide pullback at any universe level implies having binary pullbacks. -/
instance (priority := 100) hasPullbacks_of_hasWidePullbacks (D : Type u) [h : Category.{v} D]
    [h' : HasWidePullbacks.{w} D] : HasPullbacks.{v,u} D := by
  haveI I := @hasWidePullbacks_shrink.{0, w} D h h'
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D✝ : Type u₂
inst✝ : Category.{v₂, u₂} D✝
W X Y Z : C
D : Type u
h : Category.{v, u} D
h' : HasWidePullbacks D
I : HasWidePullbacks D
⊢ HasPullbacks D

Next tactic:
infer_instance
/-- Having wide pushout at any universe level implies having binary pushouts. -/
instance (priority := 100) hasPushouts_of_hasWidePushouts (D : Type u) [h : Category.{v} D]
    [h' : HasWidePushouts.{w} D] : HasPushouts.{v,u} D := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D✝ : Type u₂
inst✝ : Category.{v₂, u₂} D✝
W X Y Z : C
D : Type u
h : Category.{v, u} D
h' : HasWidePushouts D
⊢ HasPushouts D

Next tactic:
haveI I := @hasWidePushouts_shrink.{0, w} D h h'
/-- Having wide pushout at any universe level implies having binary pushouts. -/
instance (priority := 100) hasPushouts_of_hasWidePushouts (D : Type u) [h : Category.{v} D]
    [h' : HasWidePushouts.{w} D] : HasPushouts.{v,u} D := by
  haveI I := @hasWidePushouts_shrink.{0, w} D h h'
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D✝ : Type u₂
inst✝ : Category.{v₂, u₂} D✝
W X Y Z : C
D : Type u
h : Category.{v, u} D
h' : HasWidePushouts D
I : HasWidePushouts D
⊢ HasPushouts D

Next tactic:
infer_instance
/-- Given a morphism `f : X ⟶ Y`, we can take morphisms over `Y` to morphisms over `X` via
pullbacks. This is right adjoint to `over.map` (TODO) -/
@[simps! (config := { simpRhs := true}) obj_left obj_hom map_left]
def baseChange [HasPullbacks C] {X Y : C} (f : X ⟶ Y) : Over Y ⥤ Over X where
  obj g := Over.mk (pullback.snd : pullback g.hom f ⟶ _)
  map i := Over.homMk (pullback.map _ _ _ _ i.left (𝟙 _) (𝟙 _) (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X✝¹ Y✝¹ Z : C
inst✝ : HasPullbacks C
X Y : C
f : X ⟶ Y
X✝ Y✝ : Over Y
i : X✝ ⟶ Y✝
⊢ X✝.hom ≫ 𝟙 ((Functor.fromPUnit Y).obj X✝.right) = i.left ≫ Y✝.hom

Next tactic:
simp
/-- Given a morphism `f : X ⟶ Y`, we can take morphisms over `Y` to morphisms over `X` via
pullbacks. This is right adjoint to `over.map` (TODO) -/
@[simps! (config := { simpRhs := true}) obj_left obj_hom map_left]
def baseChange [HasPullbacks C] {X Y : C} (f : X ⟶ Y) : Over Y ⥤ Over X where
  obj g := Over.mk (pullback.snd : pullback g.hom f ⟶ _)
  map i := Over.homMk (pullback.map _ _ _ _ i.left (𝟙 _) (𝟙 _) (by simp) (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X✝¹ Y✝¹ Z : C
inst✝ : HasPullbacks C
X Y : C
f : X ⟶ Y
X✝ Y✝ : Over Y
i : X✝ ⟶ Y✝
⊢ f ≫ 𝟙 ((Functor.fromPUnit Y).obj X✝.right) = 𝟙 X ≫ f

Next tactic:
simp
/-- Given a morphism `f : X ⟶ Y`, we can take morphisms over `Y` to morphisms over `X` via
pullbacks. This is right adjoint to `over.map` (TODO) -/
@[simps! (config := { simpRhs := true}) obj_left obj_hom map_left]
def baseChange [HasPullbacks C] {X Y : C} (f : X ⟶ Y) : Over Y ⥤ Over X where
  obj g := Over.mk (pullback.snd : pullback g.hom f ⟶ _)
  map i := Over.homMk (pullback.map _ _ _ _ i.left (𝟙 _) (𝟙 _) (by simp) (by simp))
  map_id Z := by
    

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X✝ Y✝ Z✝ : C
inst✝ : HasPullbacks C
X Y : C
f : X ⟶ Y
Z : Over Y
⊢ { obj := fun g => Over.mk pullback.snd,
          map := fun {X_1 Y_1} i =>
            Over.homMk
              (pullback.map X_1.hom f Y_1.hom f i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f ≫ 𝟙 Y = 𝟙 X ≫ f)) }.map
      (𝟙 Z) =
    𝟙
      ({ obj := fun g => Over.mk pullback.snd,
            map := fun {X_1 Y_1} i =>
              Over.homMk
                (pullback.map X_1.hom f Y_1.hom f i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                  (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f ≫ 𝟙 Y = 𝟙 X ≫ f)) }.obj
        Z)

Next tactic:
apply Over.OverMorphism.ext
/-- Given a morphism `f : X ⟶ Y`, we can take morphisms over `Y` to morphisms over `X` via
pullbacks. This is right adjoint to `over.map` (TODO) -/
@[simps! (config := { simpRhs := true}) obj_left obj_hom map_left]
def baseChange [HasPullbacks C] {X Y : C} (f : X ⟶ Y) : Over Y ⥤ Over X where
  obj g := Over.mk (pullback.snd : pullback g.hom f ⟶ _)
  map i := Over.homMk (pullback.map _ _ _ _ i.left (𝟙 _) (𝟙 _) (by simp) (by simp))
  map_id Z := by
    apply Over.OverMorphism.ext; 

Proof state:
case h
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X✝ Y✝ Z✝ : C
inst✝ : HasPullbacks C
X Y : C
f : X ⟶ Y
Z : Over Y
⊢ ({ obj := fun g => Over.mk pullback.snd,
            map := fun {X_1 Y_1} i =>
              Over.homMk
                (pullback.map X_1.hom f Y_1.hom f i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                  (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f ≫ 𝟙 Y = 𝟙 X ≫ f)) }.map
        (𝟙 Z)).left =
    (𝟙
        ({ obj := fun g => Over.mk pullback.snd,
              map := fun {X_1 Y_1} i =>
                Over.homMk
                  (pullback.map X_1.hom f Y_1.hom f i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                    (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f ≫ 𝟙 Y = 𝟙 X ≫ f)) }.obj
          Z)).left

Next tactic:
apply pullback.hom_ext
/-- Given a morphism `f : X ⟶ Y`, we can take morphisms over `Y` to morphisms over `X` via
pullbacks. This is right adjoint to `over.map` (TODO) -/
@[simps! (config := { simpRhs := true}) obj_left obj_hom map_left]
def baseChange [HasPullbacks C] {X Y : C} (f : X ⟶ Y) : Over Y ⥤ Over X where
  obj g := Over.mk (pullback.snd : pullback g.hom f ⟶ _)
  map i := Over.homMk (pullback.map _ _ _ _ i.left (𝟙 _) (𝟙 _) (by simp) (by simp))
  map_id Z := by
    apply Over.OverMorphism.ext; apply pullback.hom_ext
    · 

Proof state:
case h.h₀
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X✝ Y✝ Z✝ : C
inst✝ : HasPullbacks C
X Y : C
f : X ⟶ Y
Z : Over Y
⊢ ({ obj := fun g => Over.mk pullback.snd,
              map := fun {X_1 Y_1} i =>
                Over.homMk
                  (pullback.map X_1.hom f Y_1.hom f i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                    (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f ≫ 𝟙 Y = 𝟙 X ≫ f)) }.map
          (𝟙 Z)).left ≫
      pullback.fst =
    (𝟙
          ({ obj := fun g => Over.mk pullback.snd,
                map := fun {X_1 Y_1} i =>
                  Over.homMk
                    (pullback.map X_1.hom f Y_1.hom f i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                      (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f ≫ 𝟙 Y = 𝟙 X ≫ f)) }.obj
            Z)).left ≫
      pullback.fst

Next tactic:
dsimp
/-- Given a morphism `f : X ⟶ Y`, we can take morphisms over `Y` to morphisms over `X` via
pullbacks. This is right adjoint to `over.map` (TODO) -/
@[simps! (config := { simpRhs := true}) obj_left obj_hom map_left]
def baseChange [HasPullbacks C] {X Y : C} (f : X ⟶ Y) : Over Y ⥤ Over X where
  obj g := Over.mk (pullback.snd : pullback g.hom f ⟶ _)
  map i := Over.homMk (pullback.map _ _ _ _ i.left (𝟙 _) (𝟙 _) (by simp) (by simp))
  map_id Z := by
    apply Over.OverMorphism.ext; apply pullback.hom_ext
    · dsimp; 

Proof state:
case h.h₀
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X✝ Y✝ Z✝ : C
inst✝ : HasPullbacks C
X Y : C
f : X ⟶ Y
Z : Over Y
⊢ pullback.map Z.hom f Z.hom f (𝟙 Z.left) (𝟙 X) (𝟙 Y) (_ : Z.hom ≫ 𝟙 Y = 𝟙 Z.left ≫ Z.hom) (_ : f ≫ 𝟙 Y = 𝟙 X ≫ f) ≫
      pullback.fst =
    𝟙 (pullback Z.hom f) ≫ pullback.fst

Next tactic:
simp
/-- Given a morphism `f : X ⟶ Y`, we can take morphisms over `Y` to morphisms over `X` via
pullbacks. This is right adjoint to `over.map` (TODO) -/
@[simps! (config := { simpRhs := true}) obj_left obj_hom map_left]
def baseChange [HasPullbacks C] {X Y : C} (f : X ⟶ Y) : Over Y ⥤ Over X where
  obj g := Over.mk (pullback.snd : pullback g.hom f ⟶ _)
  map i := Over.homMk (pullback.map _ _ _ _ i.left (𝟙 _) (𝟙 _) (by simp) (by simp))
  map_id Z := by
    apply Over.OverMorphism.ext; apply pullback.hom_ext
    · dsimp; simp
    · 

Proof state:
case h.h₁
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X✝ Y✝ Z✝ : C
inst✝ : HasPullbacks C
X Y : C
f : X ⟶ Y
Z : Over Y
⊢ ({ obj := fun g => Over.mk pullback.snd,
              map := fun {X_1 Y_1} i =>
                Over.homMk
                  (pullback.map X_1.hom f Y_1.hom f i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                    (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f ≫ 𝟙 Y = 𝟙 X ≫ f)) }.map
          (𝟙 Z)).left ≫
      pullback.snd =
    (𝟙
          ({ obj := fun g => Over.mk pullback.snd,
                map := fun {X_1 Y_1} i =>
                  Over.homMk
                    (pullback.map X_1.hom f Y_1.hom f i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                      (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f ≫ 𝟙 Y = 𝟙 X ≫ f)) }.obj
            Z)).left ≫
      pullback.snd

Next tactic:
dsimp
/-- Given a morphism `f : X ⟶ Y`, we can take morphisms over `Y` to morphisms over `X` via
pullbacks. This is right adjoint to `over.map` (TODO) -/
@[simps! (config := { simpRhs := true}) obj_left obj_hom map_left]
def baseChange [HasPullbacks C] {X Y : C} (f : X ⟶ Y) : Over Y ⥤ Over X where
  obj g := Over.mk (pullback.snd : pullback g.hom f ⟶ _)
  map i := Over.homMk (pullback.map _ _ _ _ i.left (𝟙 _) (𝟙 _) (by simp) (by simp))
  map_id Z := by
    apply Over.OverMorphism.ext; apply pullback.hom_ext
    · dsimp; simp
    · dsimp; 

Proof state:
case h.h₁
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X✝ Y✝ Z✝ : C
inst✝ : HasPullbacks C
X Y : C
f : X ⟶ Y
Z : Over Y
⊢ pullback.map Z.hom f Z.hom f (𝟙 Z.left) (𝟙 X) (𝟙 Y) (_ : Z.hom ≫ 𝟙 Y = 𝟙 Z.left ≫ Z.hom) (_ : f ≫ 𝟙 Y = 𝟙 X ≫ f) ≫
      pullback.snd =
    𝟙 (pullback Z.hom f) ≫ pullback.snd

Next tactic:
simp
/-- Given a morphism `f : X ⟶ Y`, we can take morphisms over `Y` to morphisms over `X` via
pullbacks. This is right adjoint to `over.map` (TODO) -/
@[simps! (config := { simpRhs := true}) obj_left obj_hom map_left]
def baseChange [HasPullbacks C] {X Y : C} (f : X ⟶ Y) : Over Y ⥤ Over X where
  obj g := Over.mk (pullback.snd : pullback g.hom f ⟶ _)
  map i := Over.homMk (pullback.map _ _ _ _ i.left (𝟙 _) (𝟙 _) (by simp) (by simp))
  map_id Z := by
    apply Over.OverMorphism.ext; apply pullback.hom_ext
    · dsimp; simp
    · dsimp; simp
  map_comp f g := by
    

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X✝¹ Y✝¹ Z : C
inst✝ : HasPullbacks C
X Y : C
f✝ : X ⟶ Y
X✝ Y✝ Z✝ : Over Y
f : X✝ ⟶ Y✝
g : Y✝ ⟶ Z✝
⊢ { obj := fun g => Over.mk pullback.snd,
          map := fun {X_1 Y_1} i =>
            Over.homMk
              (pullback.map X_1.hom f✝ Y_1.hom f✝ i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f✝ ≫ 𝟙 Y = 𝟙 X ≫ f✝)) }.map
      (f ≫ g) =
    { obj := fun g => Over.mk pullback.snd,
            map := fun {X_1 Y_1} i =>
              Over.homMk
                (pullback.map X_1.hom f✝ Y_1.hom f✝ i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                  (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f✝ ≫ 𝟙 Y = 𝟙 X ≫ f✝)) }.map
        f ≫
      { obj := fun g => Over.mk pullback.snd,
            map := fun {X_1 Y_1} i =>
              Over.homMk
                (pullback.map X_1.hom f✝ Y_1.hom f✝ i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                  (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f✝ ≫ 𝟙 Y = 𝟙 X ≫ f✝)) }.map
        g

Next tactic:
apply Over.OverMorphism.ext
/-- Given a morphism `f : X ⟶ Y`, we can take morphisms over `Y` to morphisms over `X` via
pullbacks. This is right adjoint to `over.map` (TODO) -/
@[simps! (config := { simpRhs := true}) obj_left obj_hom map_left]
def baseChange [HasPullbacks C] {X Y : C} (f : X ⟶ Y) : Over Y ⥤ Over X where
  obj g := Over.mk (pullback.snd : pullback g.hom f ⟶ _)
  map i := Over.homMk (pullback.map _ _ _ _ i.left (𝟙 _) (𝟙 _) (by simp) (by simp))
  map_id Z := by
    apply Over.OverMorphism.ext; apply pullback.hom_ext
    · dsimp; simp
    · dsimp; simp
  map_comp f g := by
    apply Over.OverMorphism.ext; 

Proof state:
case h
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X✝¹ Y✝¹ Z : C
inst✝ : HasPullbacks C
X Y : C
f✝ : X ⟶ Y
X✝ Y✝ Z✝ : Over Y
f : X✝ ⟶ Y✝
g : Y✝ ⟶ Z✝
⊢ ({ obj := fun g => Over.mk pullback.snd,
            map := fun {X_1 Y_1} i =>
              Over.homMk
                (pullback.map X_1.hom f✝ Y_1.hom f✝ i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                  (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f✝ ≫ 𝟙 Y = 𝟙 X ≫ f✝)) }.map
        (f ≫ g)).left =
    ({ obj := fun g => Over.mk pullback.snd,
              map := fun {X_1 Y_1} i =>
                Over.homMk
                  (pullback.map X_1.hom f✝ Y_1.hom f✝ i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                    (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f✝ ≫ 𝟙 Y = 𝟙 X ≫ f✝)) }.map
          f ≫
        { obj := fun g => Over.mk pullback.snd,
              map := fun {X_1 Y_1} i =>
                Over.homMk
                  (pullback.map X_1.hom f✝ Y_1.hom f✝ i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                    (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f✝ ≫ 𝟙 Y = 𝟙 X ≫ f✝)) }.map
          g).left

Next tactic:
apply pullback.hom_ext
/-- Given a morphism `f : X ⟶ Y`, we can take morphisms over `Y` to morphisms over `X` via
pullbacks. This is right adjoint to `over.map` (TODO) -/
@[simps! (config := { simpRhs := true}) obj_left obj_hom map_left]
def baseChange [HasPullbacks C] {X Y : C} (f : X ⟶ Y) : Over Y ⥤ Over X where
  obj g := Over.mk (pullback.snd : pullback g.hom f ⟶ _)
  map i := Over.homMk (pullback.map _ _ _ _ i.left (𝟙 _) (𝟙 _) (by simp) (by simp))
  map_id Z := by
    apply Over.OverMorphism.ext; apply pullback.hom_ext
    · dsimp; simp
    · dsimp; simp
  map_comp f g := by
    apply Over.OverMorphism.ext; apply pullback.hom_ext
    · 

Proof state:
case h.h₀
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X✝¹ Y✝¹ Z : C
inst✝ : HasPullbacks C
X Y : C
f✝ : X ⟶ Y
X✝ Y✝ Z✝ : Over Y
f : X✝ ⟶ Y✝
g : Y✝ ⟶ Z✝
⊢ ({ obj := fun g => Over.mk pullback.snd,
              map := fun {X_1 Y_1} i =>
                Over.homMk
                  (pullback.map X_1.hom f✝ Y_1.hom f✝ i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                    (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f✝ ≫ 𝟙 Y = 𝟙 X ≫ f✝)) }.map
          (f ≫ g)).left ≫
      pullback.fst =
    ({ obj := fun g => Over.mk pullback.snd,
                map := fun {X_1 Y_1} i =>
                  Over.homMk
                    (pullback.map X_1.hom f✝ Y_1.hom f✝ i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                      (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f✝ ≫ 𝟙 Y = 𝟙 X ≫ f✝)) }.map
            f ≫
          { obj := fun g => Over.mk pullback.snd,
                map := fun {X_1 Y_1} i =>
                  Over.homMk
                    (pullback.map X_1.hom f✝ Y_1.hom f✝ i.left (𝟙 X) (𝟙 ((Functor.fromPUnit Y).obj X_1.right))
                      (_ : X_1.hom ≫ 𝟙 Y = i.left ≫ Y_1.hom) (_ : f✝ ≫ 𝟙 Y = 𝟙 X ≫ f✝)) }.map
            g).left ≫
      pullback.fst

Next tactic:
dsimp