l3lab/ntp-mathlib huggingface dataset:
/-- The evaluation map is not generally multiplicative when the coefficient ring is noncommutative,
but nevertheless any polynomial of the form `p * (X - monomial 0 r)` is sent to zero
when evaluated at `r`.

This is the key step in our proof of the Cayley-Hamilton theorem.
-/
theorem eval_mul_X_sub_C {p : R[X]} (r : R) : (p * (X - C r)).eval r = 0 := by
  simp only [eval, eval₂_eq_sum, RingHom.id_apply]
  have bound :=
    calc
      (p * (X - C r)).natDegree ≤ p.natDegree + (X - C r).natDegree := natDegree_mul_le
      _ ≤ p.natDegree + 1 := (add_le_add_left (natDegree_X_sub_C_le _) _)
      _ < p.natDegree + 2 := lt_add_one _
  rw [sum_over_range' _ _ (p.natDegree + 2) bound]
  swap
  · simp
  rw [sum_range_succ']
  conv_lhs =>
    congr
    arg 2
    simp [coeff_mul_X_sub_C, sub_mul, mul_assoc, ← pow_succ]
  rw [sum_range_sub']
  

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝ : Ring R
p : R[X]
r : R
bound : natDegree (p * (X - C r)) < natDegree p + 2
⊢ coeff p 0 * r ^ (0 + 1) - coeff p (natDegree p + 1) * r ^ (natDegree p + 1 + 1) + coeff (p * (X - C r)) 0 * r ^ 0 = 0

Next tactic:
simp [coeff_monomial]
theorem not_isUnit_X_sub_C [Nontrivial R] (r : R) : ¬IsUnit (X - C r) :=
  fun ⟨⟨_, g, _hfg, hgf⟩, rfl⟩ => zero_ne_one' R <| by 

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
inst✝¹ : Ring R
inst✝ : Nontrivial R
r : R
x✝ : IsUnit (X - C r)
g : R[X]
_hfg : (X - C r) * g = 1
hgf : g * (X - C r) = 1
⊢ 0 = 1

Next tactic:
erw [← eval_mul_X_sub_C, hgf, eval_one]
theorem aeval_endomorphism {M : Type*} [CommRing R] [AddCommGroup M] [Module R M] (f : M →ₗ[R] M)
    (v : M) (p : R[X]) : aeval f p v = p.sum fun n b => b • (f ^ n) v := by
  

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
M : Type u_3
inst✝² : CommRing R
inst✝¹ : AddCommGroup M
inst✝ : Module R M
f : M →ₗ[R] M
v : M
p : R[X]
⊢ ((aeval f) p) v = sum p fun n b => b • (f ^ n) v

Next tactic:
rw [aeval_def, eval₂_eq_sum]
theorem aeval_endomorphism {M : Type*} [CommRing R] [AddCommGroup M] [Module R M] (f : M →ₗ[R] M)
    (v : M) (p : R[X]) : aeval f p v = p.sum fun n b => b • (f ^ n) v := by
  rw [aeval_def, eval₂_eq_sum]
  

Proof state:
R : Type u
S : Type v
T : Type w
A : Type z
A' : Type u_1
B : Type u_2
a b : R
n : ℕ
M : Type u_3
inst✝² : CommRing R
inst✝¹ : AddCommGroup M
inst✝ : Module R M
f : M →ₗ[R] M
v : M
p : R[X]
⊢ (sum p fun e a => (algebraMap R (M →ₗ[R] M)) a * f ^ e) v = sum p fun n b => b • (f ^ n) v

Next tactic:
exact map_sum (LinearMap.applyₗ v) _ _
theorem mulN_coeff (n : ℕ) (x : 𝕎 R) (k : ℕ) :
    (x * n).coeff k = aeval x.coeff (wittMulN p n k) := by
  

Proof state:
p : ℕ
R : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R
n : ℕ
x : 𝕎 R
k : ℕ
⊢ coeff (x * ↑n) k = (aeval x.coeff) (wittMulN p n k)

Next tactic:
induction' n with n ih generalizing k
theorem mulN_coeff (n : ℕ) (x : 𝕎 R) (k : ℕ) :
    (x * n).coeff k = aeval x.coeff (wittMulN p n k) := by
  induction' n with n ih generalizing k
  · 

Proof state:
case zero
p : ℕ
R : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R
x : 𝕎 R
k : ℕ
⊢ coeff (x * ↑Nat.zero) k = (aeval x.coeff) (wittMulN p Nat.zero k)

Next tactic:
simp only [Nat.zero_eq, Nat.cast_zero, mul_zero, zero_coeff, wittMulN,
      AlgHom.map_zero, Pi.zero_apply]
theorem mulN_coeff (n : ℕ) (x : 𝕎 R) (k : ℕ) :
    (x * n).coeff k = aeval x.coeff (wittMulN p n k) := by
  induction' n with n ih generalizing k
  · simp only [Nat.zero_eq, Nat.cast_zero, mul_zero, zero_coeff, wittMulN,
      AlgHom.map_zero, Pi.zero_apply]
  · 

Proof state:
case succ
p : ℕ
R : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R
x : 𝕎 R
n : ℕ
ih : ∀ (k : ℕ), coeff (x * ↑n) k = (aeval x.coeff) (wittMulN p n k)
k : ℕ
⊢ coeff (x * ↑(Nat.succ n)) k = (aeval x.coeff) (wittMulN p (Nat.succ n) k)

Next tactic:
rw [wittMulN, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one, mul_add, mul_one, aeval_bind₁,
      add_coeff]
theorem mulN_coeff (n : ℕ) (x : 𝕎 R) (k : ℕ) :
    (x * n).coeff k = aeval x.coeff (wittMulN p n k) := by
  induction' n with n ih generalizing k
  · simp only [Nat.zero_eq, Nat.cast_zero, mul_zero, zero_coeff, wittMulN,
      AlgHom.map_zero, Pi.zero_apply]
  · rw [wittMulN, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one, mul_add, mul_one, aeval_bind₁,
      add_coeff]
    

Proof state:
case succ
p : ℕ
R : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R
x : 𝕎 R
n : ℕ
ih : ∀ (k : ℕ), coeff (x * ↑n) k = (aeval x.coeff) (wittMulN p n k)
k : ℕ
⊢ peval (wittAdd p k) ![(x * ↑n).coeff, x.coeff] =
    (aeval fun i => (aeval x.coeff) (Function.uncurry ![wittMulN p n, X] i)) (wittAdd p k)

Next tactic:
apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
theorem mulN_coeff (n : ℕ) (x : 𝕎 R) (k : ℕ) :
    (x * n).coeff k = aeval x.coeff (wittMulN p n k) := by
  induction' n with n ih generalizing k
  · simp only [Nat.zero_eq, Nat.cast_zero, mul_zero, zero_coeff, wittMulN,
      AlgHom.map_zero, Pi.zero_apply]
  · rw [wittMulN, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one, mul_add, mul_one, aeval_bind₁,
      add_coeff]
    apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
    

Proof state:
p : ℕ
R : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R
x : 𝕎 R
n : ℕ
ih : ∀ (k : ℕ), coeff (x * ↑n) k = (aeval x.coeff) (wittMulN p n k)
k : ℕ
⊢ Function.uncurry ![(x * ↑n).coeff, x.coeff] = fun i => (aeval x.coeff) (Function.uncurry ![wittMulN p n, X] i)

Next tactic:
ext1 ⟨b, i⟩
theorem mulN_coeff (n : ℕ) (x : 𝕎 R) (k : ℕ) :
    (x * n).coeff k = aeval x.coeff (wittMulN p n k) := by
  induction' n with n ih generalizing k
  · simp only [Nat.zero_eq, Nat.cast_zero, mul_zero, zero_coeff, wittMulN,
      AlgHom.map_zero, Pi.zero_apply]
  · rw [wittMulN, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one, mul_add, mul_one, aeval_bind₁,
      add_coeff]
    apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
    ext1 ⟨b, i⟩
    

Proof state:
case h.mk
p : ℕ
R : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R
x : 𝕎 R
n : ℕ
ih : ∀ (k : ℕ), coeff (x * ↑n) k = (aeval x.coeff) (wittMulN p n k)
k : ℕ
b : Fin 2
i : ℕ
⊢ Function.uncurry ![(x * ↑n).coeff, x.coeff] (b, i) = (aeval x.coeff) (Function.uncurry ![wittMulN p n, X] (b, i))

Next tactic:
fin_cases b
theorem mulN_coeff (n : ℕ) (x : 𝕎 R) (k : ℕ) :
    (x * n).coeff k = aeval x.coeff (wittMulN p n k) := by
  induction' n with n ih generalizing k
  · simp only [Nat.zero_eq, Nat.cast_zero, mul_zero, zero_coeff, wittMulN,
      AlgHom.map_zero, Pi.zero_apply]
  · rw [wittMulN, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one, mul_add, mul_one, aeval_bind₁,
      add_coeff]
    apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
    ext1 ⟨b, i⟩
    fin_cases b
    · 

Proof state:
case h.mk.head
p : ℕ
R : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R
x : 𝕎 R
n : ℕ
ih : ∀ (k : ℕ), coeff (x * ↑n) k = (aeval x.coeff) (wittMulN p n k)
k i : ℕ
⊢ Function.uncurry ![(x * ↑n).coeff, x.coeff] ({ val := 0, isLt := (_ : 0 < 2) }, i) =
    (aeval x.coeff) (Function.uncurry ![wittMulN p n, X] ({ val := 0, isLt := (_ : 0 < 2) }, i))

Next tactic:
simp [Function.uncurry, Matrix.cons_val_zero, ih]
theorem mulN_coeff (n : ℕ) (x : 𝕎 R) (k : ℕ) :
    (x * n).coeff k = aeval x.coeff (wittMulN p n k) := by
  induction' n with n ih generalizing k
  · simp only [Nat.zero_eq, Nat.cast_zero, mul_zero, zero_coeff, wittMulN,
      AlgHom.map_zero, Pi.zero_apply]
  · rw [wittMulN, Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one, mul_add, mul_one, aeval_bind₁,
      add_coeff]
    apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
    ext1 ⟨b, i⟩
    fin_cases b
    · simp [Function.uncurry, Matrix.cons_val_zero, ih]
    · 

Proof state:
case h.mk.tail.head
p : ℕ
R : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R
x : 𝕎 R
n : ℕ
ih : ∀ (k : ℕ), coeff (x * ↑n) k = (aeval x.coeff) (wittMulN p n k)
k i : ℕ
⊢ Function.uncurry ![(x * ↑n).coeff, x.coeff] ({ val := 1, isLt := (_ : (fun a => a < 2) 1) }, i) =
    (aeval x.coeff) (Function.uncurry ![wittMulN p n, X] ({ val := 1, isLt := (_ : (fun a => a < 2) 1) }, i))

Next tactic:
simp [Function.uncurry, Matrix.cons_val_one, Matrix.head_cons, aeval_X]
/-- Multiplication by `n` is a polynomial function. -/
@[is_poly]
theorem mulN_isPoly (n : ℕ) : IsPoly p fun R _Rcr x => x * n :=
  ⟨⟨wittMulN p n, fun R _Rcr x => by 

Proof state:
p : ℕ
R✝ : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R✝
n : ℕ
R : Type u_2
_Rcr : CommRing R
x : 𝕎 R
⊢ (x * ↑n).coeff = fun n_1 => (aeval x.coeff) (wittMulN p n n_1)

Next tactic:
funext k
/-- Multiplication by `n` is a polynomial function. -/
@[is_poly]
theorem mulN_isPoly (n : ℕ) : IsPoly p fun R _Rcr x => x * n :=
  ⟨⟨wittMulN p n, fun R _Rcr x => by funext k; 

Proof state:
case h
p : ℕ
R✝ : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R✝
n : ℕ
R : Type u_2
_Rcr : CommRing R
x : 𝕎 R
k : ℕ
⊢ coeff (x * ↑n) k = (aeval x.coeff) (wittMulN p n k)

Next tactic:
exact mulN_coeff n x k
@[simp]
theorem bind₁_wittMulN_wittPolynomial (n k : ℕ) :
    bind₁ (wittMulN p n) (wittPolynomial p ℤ k) = n * wittPolynomial p ℤ k := by
  

Proof state:
p : ℕ
R : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R
n k : ℕ
⊢ (bind₁ (wittMulN p n)) (wittPolynomial p ℤ k) = ↑n * wittPolynomial p ℤ k

Next tactic:
induction' n with n ih
@[simp]
theorem bind₁_wittMulN_wittPolynomial (n k : ℕ) :
    bind₁ (wittMulN p n) (wittPolynomial p ℤ k) = n * wittPolynomial p ℤ k := by
  induction' n with n ih
  · 

Proof state:
case zero
p : ℕ
R : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R
k : ℕ
⊢ (bind₁ (wittMulN p Nat.zero)) (wittPolynomial p ℤ k) = ↑Nat.zero * wittPolynomial p ℤ k

Next tactic:
simp [wittMulN, Nat.cast_zero, zero_mul, bind₁_zero_wittPolynomial]
@[simp]
theorem bind₁_wittMulN_wittPolynomial (n k : ℕ) :
    bind₁ (wittMulN p n) (wittPolynomial p ℤ k) = n * wittPolynomial p ℤ k := by
  induction' n with n ih
  · simp [wittMulN, Nat.cast_zero, zero_mul, bind₁_zero_wittPolynomial]
  · 

Proof state:
case succ
p : ℕ
R : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R
k n : ℕ
ih : (bind₁ (wittMulN p n)) (wittPolynomial p ℤ k) = ↑n * wittPolynomial p ℤ k
⊢ (bind₁ (wittMulN p (Nat.succ n))) (wittPolynomial p ℤ k) = ↑(Nat.succ n) * wittPolynomial p ℤ k

Next tactic:
rw [wittMulN, ← bind₁_bind₁, wittAdd, wittStructureInt_prop]
@[simp]
theorem bind₁_wittMulN_wittPolynomial (n k : ℕ) :
    bind₁ (wittMulN p n) (wittPolynomial p ℤ k) = n * wittPolynomial p ℤ k := by
  induction' n with n ih
  · simp [wittMulN, Nat.cast_zero, zero_mul, bind₁_zero_wittPolynomial]
  · rw [wittMulN, ← bind₁_bind₁, wittAdd, wittStructureInt_prop]
    

Proof state:
case succ
p : ℕ
R : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R
k n : ℕ
ih : (bind₁ (wittMulN p n)) (wittPolynomial p ℤ k) = ↑n * wittPolynomial p ℤ k
⊢ (bind₁ (Function.uncurry ![wittMulN p n, X]))
      ((bind₁ fun i => (rename (Prod.mk i)) (wittPolynomial p ℤ k)) (X 0 + X 1)) =
    ↑(Nat.succ n) * wittPolynomial p ℤ k

Next tactic:
simp only [AlgHom.map_add, Nat.cast_succ, bind₁_X_right]
@[simp]
theorem bind₁_wittMulN_wittPolynomial (n k : ℕ) :
    bind₁ (wittMulN p n) (wittPolynomial p ℤ k) = n * wittPolynomial p ℤ k := by
  induction' n with n ih
  · simp [wittMulN, Nat.cast_zero, zero_mul, bind₁_zero_wittPolynomial]
  · rw [wittMulN, ← bind₁_bind₁, wittAdd, wittStructureInt_prop]
    simp only [AlgHom.map_add, Nat.cast_succ, bind₁_X_right]
    

Proof state:
case succ
p : ℕ
R : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R
k n : ℕ
ih : (bind₁ (wittMulN p n)) (wittPolynomial p ℤ k) = ↑n * wittPolynomial p ℤ k
⊢ (bind₁ (Function.uncurry ![wittMulN p n, X])) ((rename (Prod.mk 0)) (wittPolynomial p ℤ k)) +
      (bind₁ (Function.uncurry ![wittMulN p n, X])) ((rename (Prod.mk 1)) (wittPolynomial p ℤ k)) =
    (↑n + 1) * wittPolynomial p ℤ k

Next tactic:
rw [add_mul, one_mul, bind₁_rename, bind₁_rename]
@[simp]
theorem bind₁_wittMulN_wittPolynomial (n k : ℕ) :
    bind₁ (wittMulN p n) (wittPolynomial p ℤ k) = n * wittPolynomial p ℤ k := by
  induction' n with n ih
  · simp [wittMulN, Nat.cast_zero, zero_mul, bind₁_zero_wittPolynomial]
  · rw [wittMulN, ← bind₁_bind₁, wittAdd, wittStructureInt_prop]
    simp only [AlgHom.map_add, Nat.cast_succ, bind₁_X_right]
    rw [add_mul, one_mul, bind₁_rename, bind₁_rename]
    

Proof state:
case succ
p : ℕ
R : Type u_1
hp : Fact (Nat.Prime p)
inst✝ : CommRing R
k n : ℕ
ih : (bind₁ (wittMulN p n)) (wittPolynomial p ℤ k) = ↑n * wittPolynomial p ℤ k
⊢ (bind₁ (Function.uncurry ![wittMulN p n, X] ∘ Prod.mk 0)) (wittPolynomial p ℤ k) +
      (bind₁ (Function.uncurry ![wittMulN p n, X] ∘ Prod.mk 1)) (wittPolynomial p ℤ k) =
    ↑n * wittPolynomial p ℤ k + wittPolynomial p ℤ k

Next tactic:
simp only [ih, Function.uncurry, Function.comp, bind₁_X_left, AlgHom.id_apply,
      Matrix.cons_val_zero, Matrix.head_cons, Matrix.cons_val_one]
/-- Given an adjunction `F ⊣ G`, this provides the natural adjunction
  `(whiskeringRight C _ _).obj F ⊣ (whiskeringRight C _ _).obj G`. -/
@[simps! unit_app_app counit_app_app]
protected def whiskerRight (adj : F ⊣ G) :
    (whiskeringRight C D E).obj F ⊣ (whiskeringRight C E D).obj G :=
  mkOfUnitCounit
    { unit :=
        { app := fun X =>
            (Functor.rightUnitor _).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator _ _ _).inv
          naturality := by 

Proof state:
C : Type u_1
D : Type u_2
E : Type u_3
inst✝² : Category.{?u.63, u_1} C
inst✝¹ : Category.{?u.67, u_2} D
inst✝ : Category.{?u.71, u_3} E
F : D ⥤ E
G : E ⥤ D
adj : F ⊣ G
⊢ ∀ ⦃X Y : C ⥤ D⦄ (f : X ⟶ Y),
    (𝟭 (C ⥤ D)).map f ≫
        (fun X =>
            (Functor.rightUnitor ((𝟭 (C ⥤ D)).obj X)).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator X F G).inv)
          Y =
      (fun X => (Functor.rightUnitor ((𝟭 (C ⥤ D)).obj X)).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator X F G).inv)
          X ≫
        ((whiskeringRight C D E).obj F ⋙ (whiskeringRight C E D).obj G).map f

Next tactic:
intros
/-- Given an adjunction `F ⊣ G`, this provides the natural adjunction
  `(whiskeringRight C _ _).obj F ⊣ (whiskeringRight C _ _).obj G`. -/
@[simps! unit_app_app counit_app_app]
protected def whiskerRight (adj : F ⊣ G) :
    (whiskeringRight C D E).obj F ⊣ (whiskeringRight C E D).obj G :=
  mkOfUnitCounit
    { unit :=
        { app := fun X =>
            (Functor.rightUnitor _).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator _ _ _).inv
          naturality := by intros; 

Proof state:
C : Type u_1
D : Type u_2
E : Type u_3
inst✝² : Category.{?u.63, u_1} C
inst✝¹ : Category.{?u.67, u_2} D
inst✝ : Category.{?u.71, u_3} E
F : D ⥤ E
G : E ⥤ D
adj : F ⊣ G
X✝ Y✝ : C ⥤ D
f✝ : X✝ ⟶ Y✝
⊢ (𝟭 (C ⥤ D)).map f✝ ≫
      (fun X => (Functor.rightUnitor ((𝟭 (C ⥤ D)).obj X)).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator X F G).inv)
        Y✝ =
    (fun X => (Functor.rightUnitor ((𝟭 (C ⥤ D)).obj X)).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator X F G).inv)
        X✝ ≫
      ((whiskeringRight C D E).obj F ⋙ (whiskeringRight C E D).obj G).map f✝

Next tactic:
ext
/-- Given an adjunction `F ⊣ G`, this provides the natural adjunction
  `(whiskeringRight C _ _).obj F ⊣ (whiskeringRight C _ _).obj G`. -/
@[simps! unit_app_app counit_app_app]
protected def whiskerRight (adj : F ⊣ G) :
    (whiskeringRight C D E).obj F ⊣ (whiskeringRight C E D).obj G :=
  mkOfUnitCounit
    { unit :=
        { app := fun X =>
            (Functor.rightUnitor _).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator _ _ _).inv
          naturality := by intros; ext; 

Proof state:
case w.h
C : Type u_1
D : Type u_2
E : Type u_3
inst✝² : Category.{?u.63, u_1} C
inst✝¹ : Category.{?u.67, u_2} D
inst✝ : Category.{?u.71, u_3} E
F : D ⥤ E
G : E ⥤ D
adj : F ⊣ G
X✝ Y✝ : C ⥤ D
f✝ : X✝ ⟶ Y✝
x✝ : C
⊢ ((𝟭 (C ⥤ D)).map f✝ ≫
          (fun X =>
              (Functor.rightUnitor ((𝟭 (C ⥤ D)).obj X)).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator X F G).inv)
            Y✝).app
      x✝ =
    ((fun X => (Functor.rightUnitor ((𝟭 (C ⥤ D)).obj X)).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator X F G).inv)
            X✝ ≫
          ((whiskeringRight C D E).obj F ⋙ (whiskeringRight C E D).obj G).map f✝).app
      x✝

Next tactic:
dsimp
/-- Given an adjunction `F ⊣ G`, this provides the natural adjunction
  `(whiskeringRight C _ _).obj F ⊣ (whiskeringRight C _ _).obj G`. -/
@[simps! unit_app_app counit_app_app]
protected def whiskerRight (adj : F ⊣ G) :
    (whiskeringRight C D E).obj F ⊣ (whiskeringRight C E D).obj G :=
  mkOfUnitCounit
    { unit :=
        { app := fun X =>
            (Functor.rightUnitor _).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator _ _ _).inv
          naturality := by intros; ext; dsimp; 

Proof state:
case w.h
C : Type u_1
D : Type u_2
E : Type u_3
inst✝² : Category.{?u.63, u_1} C
inst✝¹ : Category.{?u.67, u_2} D
inst✝ : Category.{?u.71, u_3} E
F : D ⥤ E
G : E ⥤ D
adj : F ⊣ G
X✝ Y✝ : C ⥤ D
f✝ : X✝ ⟶ Y✝
x✝ : C
⊢ f✝.app x✝ ≫ 𝟙 (Y✝.obj x✝) ≫ adj.unit.app (Y✝.obj x✝) ≫ 𝟙 (G.obj (F.obj (Y✝.obj x✝))) =
    (𝟙 (X✝.obj x✝) ≫ adj.unit.app (X✝.obj x✝) ≫ 𝟙 (G.obj (F.obj (X✝.obj x✝)))) ≫ G.map (F.map (f✝.app x✝))

Next tactic:
simp
/-- Given an adjunction `F ⊣ G`, this provides the natural adjunction
  `(whiskeringRight C _ _).obj F ⊣ (whiskeringRight C _ _).obj G`. -/
@[simps! unit_app_app counit_app_app]
protected def whiskerRight (adj : F ⊣ G) :
    (whiskeringRight C D E).obj F ⊣ (whiskeringRight C E D).obj G :=
  mkOfUnitCounit
    { unit :=
        { app := fun X =>
            (Functor.rightUnitor _).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator _ _ _).inv
          naturality := by intros; ext; dsimp; simp }
      counit :=
        { app := fun X =>
            (Functor.associator _ _ _).hom ≫ whiskerLeft X adj.counit ≫ (Functor.rightUnitor _).hom
          naturality := by 

Proof state:
C : Type u_1
D : Type u_2
E : Type u_3
inst✝² : Category.{?u.63, u_1} C
inst✝¹ : Category.{?u.67, u_2} D
inst✝ : Category.{?u.71, u_3} E
F : D ⥤ E
G : E ⥤ D
adj : F ⊣ G
⊢ ∀ ⦃X Y : C ⥤ E⦄ (f : X ⟶ Y),
    ((whiskeringRight C E D).obj G ⋙ (whiskeringRight C D E).obj F).map f ≫
        (fun X => (Functor.associator X G F).hom ≫ whiskerLeft X adj.counit ≫ (Functor.rightUnitor X).hom) Y =
      (fun X => (Functor.associator X G F).hom ≫ whiskerLeft X adj.counit ≫ (Functor.rightUnitor X).hom) X ≫
        (𝟭 (C ⥤ E)).map f

Next tactic:
intros
/-- Given an adjunction `F ⊣ G`, this provides the natural adjunction
  `(whiskeringRight C _ _).obj F ⊣ (whiskeringRight C _ _).obj G`. -/
@[simps! unit_app_app counit_app_app]
protected def whiskerRight (adj : F ⊣ G) :
    (whiskeringRight C D E).obj F ⊣ (whiskeringRight C E D).obj G :=
  mkOfUnitCounit
    { unit :=
        { app := fun X =>
            (Functor.rightUnitor _).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator _ _ _).inv
          naturality := by intros; ext; dsimp; simp }
      counit :=
        { app := fun X =>
            (Functor.associator _ _ _).hom ≫ whiskerLeft X adj.counit ≫ (Functor.rightUnitor _).hom
          naturality := by intros; 

Proof state:
C : Type u_1
D : Type u_2
E : Type u_3
inst✝² : Category.{?u.63, u_1} C
inst✝¹ : Category.{?u.67, u_2} D
inst✝ : Category.{?u.71, u_3} E
F : D ⥤ E
G : E ⥤ D
adj : F ⊣ G
X✝ Y✝ : C ⥤ E
f✝ : X✝ ⟶ Y✝
⊢ ((whiskeringRight C E D).obj G ⋙ (whiskeringRight C D E).obj F).map f✝ ≫
      (fun X => (Functor.associator X G F).hom ≫ whiskerLeft X adj.counit ≫ (Functor.rightUnitor X).hom) Y✝ =
    (fun X => (Functor.associator X G F).hom ≫ whiskerLeft X adj.counit ≫ (Functor.rightUnitor X).hom) X✝ ≫
      (𝟭 (C ⥤ E)).map f✝

Next tactic:
ext
/-- Given an adjunction `F ⊣ G`, this provides the natural adjunction
  `(whiskeringRight C _ _).obj F ⊣ (whiskeringRight C _ _).obj G`. -/
@[simps! unit_app_app counit_app_app]
protected def whiskerRight (adj : F ⊣ G) :
    (whiskeringRight C D E).obj F ⊣ (whiskeringRight C E D).obj G :=
  mkOfUnitCounit
    { unit :=
        { app := fun X =>
            (Functor.rightUnitor _).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator _ _ _).inv
          naturality := by intros; ext; dsimp; simp }
      counit :=
        { app := fun X =>
            (Functor.associator _ _ _).hom ≫ whiskerLeft X adj.counit ≫ (Functor.rightUnitor _).hom
          naturality := by intros; ext; 

Proof state:
case w.h
C : Type u_1
D : Type u_2
E : Type u_3
inst✝² : Category.{?u.63, u_1} C
inst✝¹ : Category.{?u.67, u_2} D
inst✝ : Category.{?u.71, u_3} E
F : D ⥤ E
G : E ⥤ D
adj : F ⊣ G
X✝ Y✝ : C ⥤ E
f✝ : X✝ ⟶ Y✝
x✝ : C
⊢ (((whiskeringRight C E D).obj G ⋙ (whiskeringRight C D E).obj F).map f✝ ≫
          (fun X => (Functor.associator X G F).hom ≫ whiskerLeft X adj.counit ≫ (Functor.rightUnitor X).hom) Y✝).app
      x✝ =
    ((fun X => (Functor.associator X G F).hom ≫ whiskerLeft X adj.counit ≫ (Functor.rightUnitor X).hom) X✝ ≫
          (𝟭 (C ⥤ E)).map f✝).app
      x✝

Next tactic:
dsimp
/-- Given an adjunction `F ⊣ G`, this provides the natural adjunction
  `(whiskeringRight C _ _).obj F ⊣ (whiskeringRight C _ _).obj G`. -/
@[simps! unit_app_app counit_app_app]
protected def whiskerRight (adj : F ⊣ G) :
    (whiskeringRight C D E).obj F ⊣ (whiskeringRight C E D).obj G :=
  mkOfUnitCounit
    { unit :=
        { app := fun X =>
            (Functor.rightUnitor _).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator _ _ _).inv
          naturality := by intros; ext; dsimp; simp }
      counit :=
        { app := fun X =>
            (Functor.associator _ _ _).hom ≫ whiskerLeft X adj.counit ≫ (Functor.rightUnitor _).hom
          naturality := by intros; ext; dsimp; 

Proof state:
case w.h
C : Type u_1
D : Type u_2
E : Type u_3
inst✝² : Category.{?u.63, u_1} C
inst✝¹ : Category.{?u.67, u_2} D
inst✝ : Category.{?u.71, u_3} E
F : D ⥤ E
G : E ⥤ D
adj : F ⊣ G
X✝ Y✝ : C ⥤ E
f✝ : X✝ ⟶ Y✝
x✝ : C
⊢ F.map (G.map (f✝.app x✝)) ≫ 𝟙 (F.obj (G.obj (Y✝.obj x✝))) ≫ adj.counit.app (Y✝.obj x✝) ≫ 𝟙 (Y✝.obj x✝) =
    (𝟙 (F.obj (G.obj (X✝.obj x✝))) ≫ adj.counit.app (X✝.obj x✝) ≫ 𝟙 (X✝.obj x✝)) ≫ f✝.app x✝

Next tactic:
simp
/-- Given an adjunction `F ⊣ G`, this provides the natural adjunction
  `(whiskeringRight C _ _).obj F ⊣ (whiskeringRight C _ _).obj G`. -/
@[simps! unit_app_app counit_app_app]
protected def whiskerRight (adj : F ⊣ G) :
    (whiskeringRight C D E).obj F ⊣ (whiskeringRight C E D).obj G :=
  mkOfUnitCounit
    { unit :=
        { app := fun X =>
            (Functor.rightUnitor _).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator _ _ _).inv
          naturality := by intros; ext; dsimp; simp }
      counit :=
        { app := fun X =>
            (Functor.associator _ _ _).hom ≫ whiskerLeft X adj.counit ≫ (Functor.rightUnitor _).hom
          naturality := by intros; ext; dsimp; simp }
      left_triangle  := by 

Proof state:
C : Type u_1
D : Type u_2
E : Type u_3
inst✝² : Category.{?u.63, u_1} C
inst✝¹ : Category.{?u.67, u_2} D
inst✝ : Category.{?u.71, u_3} E
F : D ⥤ E
G : E ⥤ D
adj : F ⊣ G
⊢ whiskerRight
        (NatTrans.mk fun X =>
          (Functor.rightUnitor ((𝟭 (C ⥤ D)).obj X)).inv ≫ whiskerLeft X adj.unit ≫ (Functor.associator X F G).inv)
        ((whiskeringRight C D E).obj F) ≫
      (Functor.associator ((whiskeringRight C D E).obj F) ((whiskeringRight C E D).obj G)
            ((whiskeringRight C D E).obj F)).hom ≫
        whiskerLeft ((whiskeringRight C D E).obj F)
          (NatTrans.mk fun X =>
            (Functor.associator X G F).hom ≫ whiskerLeft X adj.counit ≫ (Functor.rightUnitor X).hom) =
    NatTrans.id (𝟭 (C ⥤ D) ⋙ (whiskeringRight C D E).obj F)

Next tactic:
ext