/-
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura

notation, basic datatypes and type classes
-/
prelude
import Init.Core
set_option linter.missingDocs true -- keep it documented

theorem of_eq_true (h : p = True) : p := h ▸ trivial

theorem eq_true (h : p) : p = True :=
  propext ⟨fun _ => trivial, fun _ => h⟩

theorem eq_false (h : ¬ p) : p = False :=
  propext ⟨fun h' => absurd h' h, fun h' => False.elim h'⟩

theorem eq_false' (h : p → False) : p = False := eq_false h

theorem eq_true_of_decide {p : Prop} {_ : Decidable p} (h : decide p = true) : p = True :=
  eq_true (of_decide_eq_true h)

theorem eq_false_of_decide {p : Prop} {_ : Decidable p} (h : decide p = false) : p = False :=
  eq_false (of_decide_eq_false h)

@[simp] theorem eq_self (a : α) : (a = a) = True := eq_true rfl

theorem implies_congr {p₁ p₂ : Sort u} {q₁ q₂ : Sort v} (h₁ : p₁ = p₂) (h₂ : q₁ = q₂) : (p₁ → q₁) = (p₂ → q₂) :=
  h₁ ▸ h₂ ▸ rfl

theorem implies_dep_congr_ctx {p₁ p₂ q₁ : Prop} (h₁ : p₁ = p₂) {q₂ : p₂ → Prop} (h₂ : (h : p₂) → q₁ = q₂ h) : (p₁ → q₁) = ((h : p₂) → q₂ h) :=
  propext ⟨
    fun hl hp₂ => (h₂ hp₂).mp (hl (h₁.mpr hp₂)),
    fun hr hp₁ => (h₂ (h₁.mp hp₁)).mpr (hr (h₁.mp hp₁))⟩

theorem implies_congr_ctx {p₁ p₂ q₁ q₂ : Prop} (h₁ : p₁ = p₂) (h₂ : p₂ → q₁ = q₂) : (p₁ → q₁) = (p₂ → q₂) :=
  implies_dep_congr_ctx h₁ h₂

theorem forall_congr {α : Sort u} {p q : α → Prop} (h : ∀ a, p a = q a) : (∀ a, p a) = (∀ a, q a) :=
  (funext h : p = q) ▸ rfl

theorem let_congr {α : Sort u} {β : Sort v} {a a' : α} {b b' : α → β}
    (h₁ : a = a') (h₂ : ∀ x, b x = b' x) : (let x := a; b x) = (let x := a'; b' x) :=
  h₁ ▸ (funext h₂ : b = b') ▸ rfl

theorem let_val_congr {α : Sort u} {β : Sort v} {a a' : α}
    (b : α → β) (h : a = a') : (let x := a; b x) = (let x := a'; b x) := h ▸ rfl

theorem let_body_congr {α : Sort u} {β : α → Sort v} {b b' : (a : α) → β a}
    (a : α) (h : ∀ x, b x = b' x) : (let x := a; b x) = (let x := a; b' x) :=
  (funext h : b = b') ▸ rfl

@[congr]
theorem ite_congr {x y u v : α} {s : Decidable b} [Decidable c]
    (h₁ : b = c) (h₂ : c → x = u) (h₃ : ¬ c → y = v) : ite b x y = ite c u v := by
  cases Decidable.em c with
  | inl h => rw [if_pos h]; subst b; rw [if_pos h]; exact h₂ h
  | inr h => rw [if_neg h]; subst b; rw [if_neg h]; exact h₃ h

theorem Eq.mpr_prop {p q : Prop} (h₁ : p = q) (h₂ : q)  : p  := h₁ ▸ h₂
theorem Eq.mpr_not  {p q : Prop} (h₁ : p = q) (h₂ : ¬q) : ¬p := h₁ ▸ h₂

@[congr]
theorem dite_congr {_ : Decidable b} [Decidable c]
    {x : b → α} {u : c → α} {y : ¬b → α} {v : ¬c → α}
    (h₁ : b = c)
    (h₂ : (h : c)  → x (h₁.mpr_prop h) = u h)
    (h₃ : (h : ¬c) → y (h₁.mpr_not h)  = v h) :
    dite b x y = dite c u v := by
  cases Decidable.em c with
  | inl h => rw [dif_pos h]; subst b; rw [dif_pos h]; exact h₂ h
  | inr h => rw [dif_neg h]; subst b; rw [dif_neg h]; exact h₃ h

@[simp] theorem ne_eq (a b : α) : (a ≠ b) = ¬(a = b) := rfl
@[simp] theorem ite_true (a b : α) : (if True then a else b) = a := rfl
@[simp] theorem ite_false (a b : α) : (if False then a else b) = b := rfl
@[simp] theorem dite_true {α : Sort u} {t : True → α} {e : ¬ True → α} : (dite True t e) = t True.intro := rfl
@[simp] theorem dite_false {α : Sort u} {t : False → α} {e : ¬ False → α} : (dite False t e) = e not_false := rfl
@[simp] theorem ite_self {α : Sort u} {c : Prop} {d : Decidable c} (a : α) : ite c a a = a := by cases d <;> rfl
@[simp] theorem and_self (p : Prop) : (p ∧ p) = p := propext ⟨(·.1), fun h => ⟨h, h⟩⟩
@[simp] theorem and_true (p : Prop) : (p ∧ True) = p := propext ⟨(·.1), (⟨·, trivial⟩)⟩
@[simp] theorem true_and (p : Prop) : (True ∧ p) = p := propext ⟨(·.2), (⟨trivial, ·⟩)⟩
@[simp] theorem and_false (p : Prop) : (p ∧ False) = False := eq_false (·.2)
@[simp] theorem false_and (p : Prop) : (False ∧ p) = False := eq_false (·.1)
@[simp] theorem or_self (p : Prop) : (p ∨ p) = p := propext ⟨fun | .inl h | .inr h => h, .inl⟩
@[simp] theorem or_true (p : Prop) : (p ∨ True) = True := eq_true (.inr trivial)
@[simp] theorem true_or (p : Prop) : (True ∨ p) = True := eq_true (.inl trivial)
@[simp] theorem or_false (p : Prop) : (p ∨ False) = p := propext ⟨fun (.inl h) => h, .inl⟩
@[simp] theorem false_or (p : Prop) : (False ∨ p) = p := propext ⟨fun (.inr h) => h, .inr⟩
@[simp] theorem iff_self (p : Prop) : (p ↔ p) = True := eq_true .rfl
@[simp] theorem iff_true (p : Prop) : (p ↔ True) = p := propext ⟨(·.2 trivial), fun h => ⟨fun _ => trivial, fun _ => h⟩⟩
@[simp] theorem true_iff (p : Prop) : (True ↔ p) = p := propext ⟨(·.1 trivial), fun h => ⟨fun _ => h, fun _ => trivial⟩⟩
@[simp] theorem iff_false (p : Prop) : (p ↔ False) = ¬p := propext ⟨(·.1), (⟨·, False.elim⟩)⟩
@[simp] theorem false_iff (p : Prop) : (False ↔ p) = ¬p := propext ⟨(·.2), (⟨False.elim, ·⟩)⟩
@[simp] theorem false_implies (p : Prop) : (False → p) = True := eq_true False.elim
@[simp] theorem implies_true (α : Sort u) : (α → True) = True := eq_true fun _ => trivial
@[simp] theorem true_implies (p : Prop) : (True → p) = p := propext ⟨(· trivial), (fun _ => ·)⟩

@[simp] theorem Bool.or_false (b : Bool) : (b || false) = b  := by cases b <;> rfl
@[simp] theorem Bool.or_true (b : Bool) : (b || true) = true := by cases b <;> rfl
@[simp] theorem Bool.false_or (b : Bool) : (false || b) = b  := by cases b <;> rfl
@[simp] theorem Bool.true_or (b : Bool) : (true || b) = true := by cases b <;> rfl
@[simp] theorem Bool.or_self (b : Bool) : (b || b) = b       := by cases b <;> rfl
@[simp] theorem Bool.or_eq_true (a b : Bool) : ((a || b) = true) = (a = true ∨ b = true) := by
  cases a <;> cases b <;> decide

@[simp] theorem Bool.and_false (b : Bool) : (b && false) = false := by cases b <;> rfl
@[simp] theorem Bool.and_true (b : Bool) : (b && true) = b       := by cases b <;> rfl
@[simp] theorem Bool.false_and (b : Bool) : (false && b) = false := by cases b <;> rfl
@[simp] theorem Bool.true_and (b : Bool) : (true && b) = b       := by cases b <;> rfl
@[simp] theorem Bool.and_self (b : Bool) : (b && b) = b          := by cases b <;> rfl
@[simp] theorem Bool.and_eq_true (a b : Bool) : ((a && b) = true) = (a = true ∧ b = true) := by
  cases a <;> cases b <;> decide

theorem Bool.and_assoc (a b c : Bool) : (a && b && c) = (a && (b && c)) := by
  cases a <;> cases b <;> cases c <;> decide
theorem Bool.or_assoc (a b c : Bool) : (a || b || c) = (a || (b || c)) := by
  cases a <;> cases b <;> cases c <;> decide

@[simp] theorem Bool.not_not (b : Bool) : (!!b) = b := by cases b <;> rfl
@[simp] theorem Bool.not_true  : (!true) = false := by decide
@[simp] theorem Bool.not_false : (!false) = true := by decide
@[simp] theorem Bool.not_beq_true (b : Bool) : (!(b == true)) = (b == false) := by cases b <;> rfl
@[simp] theorem Bool.not_beq_false (b : Bool) : (!(b == false)) = (b == true) := by cases b <;> rfl
@[simp] theorem Bool.not_eq_true' (b : Bool) : ((!b) = true) = (b = false) := by cases b <;> simp
@[simp] theorem Bool.not_eq_false' (b : Bool) : ((!b) = false) = (b = true) := by cases b <;> simp

@[simp] theorem Bool.beq_to_eq (a b : Bool) :
  (a == b) = (a = b) := by cases a <;> cases b <;> decide
@[simp] theorem Bool.not_beq_to_not_eq (a b : Bool) :
  (!(a == b)) = ¬(a = b) := by cases a <;> cases b <;> decide

@[simp] theorem Bool.not_eq_true (b : Bool) : (¬(b = true)) = (b = false) := by cases b <;> decide
@[simp] theorem Bool.not_eq_false (b : Bool) : (¬(b = false)) = (b = true) := by cases b <;> decide

@[simp] theorem decide_eq_true_eq [Decidable p] : (decide p = true) = p := propext <| Iff.intro of_decide_eq_true decide_eq_true
@[simp] theorem decide_not [h : Decidable p] : decide (¬ p) = !decide p := by cases h <;> rfl
@[simp] theorem not_decide_eq_true [h : Decidable p] : ((!decide p) = true) = ¬ p := by cases h <;> simp [decide, *]

@[simp] theorem heq_eq_eq {α : Sort u} (a b : α) : HEq a b = (a = b) := propext <| Iff.intro eq_of_heq heq_of_eq

@[simp] theorem cond_true (a b : α) : cond true a b = a := rfl
@[simp] theorem cond_false (a b : α) : cond false a b = b := rfl

@[simp] theorem beq_self_eq_true [BEq α] [LawfulBEq α] (a : α) : (a == a) = true := LawfulBEq.rfl
@[simp] theorem beq_self_eq_true' [DecidableEq α] (a : α) : (a == a) = true := by simp [BEq.beq]

@[simp] theorem bne_self_eq_false [BEq α] [LawfulBEq α] (a : α) : (a != a) = false := by simp [bne]
@[simp] theorem bne_self_eq_false' [DecidableEq α] (a : α) : (a != a) = false := by simp [bne]

@[simp] theorem Nat.le_zero_eq (a : Nat) : (a ≤ 0) = (a = 0) :=
  propext ⟨fun h => Nat.le_antisymm h (Nat.zero_le ..), fun h => by simp [h]⟩

@[simp] theorem decide_False : decide False = false := rfl
@[simp] theorem decide_True : decide True = true := rfl


import data.set
import .basis
import .basic

/-!
# What is going on here?

Here we define the notion of spanning, independence, and basis for a family of terms in a pregeometry.
By a family, we just mean a function `ι : S → T` from some other type `S`.

The following lemmas help in going back and forth between the definitions here and those in `src/pregeom/basis.lean`:
1. `spanning_iff_range_spanning` says that `ι` spans if and only if its image does.
2. `indep_iff_injective_range_indep` says that `ι` is independent if and only if `ι` is injective and its image is independent.
3. `basis_iff_injective_range_basis` says that `ι` is a basis if and only if `ι` is injective and its image is a basis.

-/

open_locale classical

variables {T : Type*}
variables {S : Type*} (ι : S → T)

namespace pregeom
namespace basis_family

open set
open function

/-- The restriction of ι to the complemenet of {x}. -/
def res (x : S) : {y : S // y ≠ x} → T := λ ⟨y,_⟩, ι y

/-- Independence for a family. -/
def is_indep [has_cl T] : Prop := ∀ x : S, ι x ∉ cl (range $ res ι x)

/-- Spanning condition for a family. -/
def is_spanning [has_cl T] : Prop := ∀ t : T, t ∈ cl (range ι)

/-- Definition of a basis for a family. -/
def is_basis [has_cl T] : Prop := is_indep ι ∧ is_spanning ι

variable {ι}

/-- If ι is injective, then the image of the restriction of ι to the complement of s is
the complement of ι s in the image of ι. -/
lemma range_res_eq_sub_range_of_injective {s : S} : injective ι → range (res ι s) = range ι \ {ι s} :=
begin
  intro h,
  ext, refine ⟨by tidy, _⟩,
  rintro ⟨⟨y,rfl⟩,h2⟩,
  use y,
  repeat {finish},
end

variable [pregeom T]

/-- If ι is independence, then ι is injective. -/
theorem injective_of_indep : is_indep ι → injective ι :=
begin
  intro indep,
  intros y x h,
  by_contradiction contra,
  replace indep := indep x,
  have : ι y ∈ range (res ι x), by exact ⟨⟨y,contra⟩, by finish⟩,
  rw h at this,
  replace this := inclusive this,
  contradiction,
end

/-- ι spans if and only if its image spans. -/
theorem spanning_iff_range_spanning : is_spanning ι ↔ basis.is_spanning (range ι) := by tauto

/-- ι is independent if and only if ι is injective and its image is independent. -/
theorem indep_iff_injective_range_indep : is_indep ι ↔ injective ι ∧ basis.is_indep (range ι) :=
begin
  split,
  { intro h,
    have c1 := injective_of_indep h,
    refine ⟨c1,_⟩,
    rintros _ ⟨y,rfl⟩,
    replace h := h y,
    change _ ∉ cl (range ι \ _),
    rwa ←range_res_eq_sub_range_of_injective c1, },
  { rintros ⟨h1,h2⟩,
    intro s,
    rw range_res_eq_sub_range_of_injective h1,
    apply h2,
    use s, }
end

/-- ι is a basis if and only if ι is injective and its image is a basis.
This can be used to go back and forth between the definition of bases for sets and for families.
 -/
theorem basis_iff_injective_range_basis : is_basis ι ↔ injective ι ∧ basis.is_basis (range ι) :=
begin
  split,
  { rintro ⟨h1,h2⟩,
    rw indep_iff_injective_range_indep at h1,
    exact ⟨h1.1,⟨h1.2,h2⟩⟩, },
  { rintro ⟨h1,h2,h3⟩,
    refine ⟨_,h3⟩,
    rw indep_iff_injective_range_indep,
    finish, }
end

end basis_family
end pregeom


/-
Copyright (c) 2022 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Scott Morrison

! This file was ported from Lean 3 source module category_theory.linear.functor_category
! leanprover-community/mathlib commit 69c6a5a12d8a2b159f20933e60115a4f2de62b58
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.CategoryTheory.Preadditive.FunctorCategory
import Mathbin.CategoryTheory.Linear.Basic

/-!
# Linear structure on functor categories

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.

If `C` and `D` are categories and `D` is `R`-linear,
then `C ⥤ D` is also `R`-linear.

-/

open BigOperators

namespace CategoryTheory

open CategoryTheory.Limits Linear

variable {R : Type _} [Semiring R]

variable {C D : Type _} [Category C] [Category D] [Preadditive D] [Linear R D]

#print CategoryTheory.functorCategoryLinear /-
instance functorCategoryLinear : Linear R (C ⥤ D)
    where
  homModule F G :=
    { smul := fun r α =>
        { app := fun X => r • α.app X
          naturality' := by
            intros
            rw [comp_smul, smul_comp, α.naturality] }
      one_smul := by
        intros
        ext
        apply one_smul
      zero_smul := by
        intros
        ext
        apply zero_smul
      smul_zero := by
        intros
        ext
        apply smul_zero
      add_smul := by
        intros
        ext
        apply add_smul
      smul_add := by
        intros
        ext
        apply smul_add
      mul_smul := by
        intros
        ext
        apply mul_smul }
  smul_comp' := by
    intros
    ext
    apply smul_comp
  comp_smul' := by
    intros
    ext
    apply comp_smul
#align category_theory.functor_category_linear CategoryTheory.functorCategoryLinear
-/

namespace NatTrans

variable {F G : C ⥤ D}

/- warning: category_theory.nat_trans.app_linear_map -> CategoryTheory.NatTrans.appLinearMap is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Semiring.{u1} R] {C : Type.{u2}} {D : Type.{u3}} [_inst_2 : CategoryTheory.Category.{u4, u2} C] [_inst_3 : CategoryTheory.Category.{u5, u3} D] [_inst_4 : CategoryTheory.Preadditive.{u5, u3} D _inst_3] [_inst_5 : CategoryTheory.Linear.{u1, u5, u3} R _inst_1 D _inst_3 _inst_4] {F : CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3} {G : CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3} (X : C), LinearMap.{u1, u1, max u2 u5, u5} R R _inst_1 _inst_1 (RingHom.id.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1)) (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (AddCommGroup.toAddCommMonoid.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (CategoryTheory.Preadditive.homGroup.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.functorCategoryPreadditive.{u2, u3, u4, u5} C D _inst_2 _inst_3 _inst_4) F G)) (AddCommGroup.toAddCommMonoid.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (CategoryTheory.Preadditive.homGroup.{u5, u3} D _inst_3 _inst_4 (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X))) (CategoryTheory.Linear.homModule.{u1, max u2 u5, max u4 u5 u2 u3} R _inst_1 (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.functorCategoryPreadditive.{u2, u3, u4, u5} C D _inst_2 _inst_3 _inst_4) (CategoryTheory.functorCategoryLinear.{u1, u2, u3, u4, u5} R _inst_1 C D _inst_2 _inst_3 _inst_4 _inst_5) F G) (CategoryTheory.Linear.homModule.{u1, u5, u3} R _inst_1 D _inst_3 _inst_4 _inst_5 (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : Semiring.{u1} R] {C : Type.{u2}} {D : Type.{u3}} [_inst_2 : CategoryTheory.Category.{u4, u2} C] [_inst_3 : CategoryTheory.Category.{u5, u3} D] [_inst_4 : CategoryTheory.Preadditive.{u5, u3} D _inst_3] [_inst_5 : CategoryTheory.Linear.{u1, u5, u3} R _inst_1 D _inst_3 _inst_4] {F : CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3} {G : CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3} (X : C), LinearMap.{u1, u1, max u2 u5, u5} R R _inst_1 _inst_1 (RingHom.id.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1)) (Quiver.Hom.{succ (max u2 u5), max (max (max u2 u3) u4) u5} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max (max (max u2 u3) u4) u5} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max (max (max u2 u3) u4) u5} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (Prefunctor.obj.{succ u4, succ u5, u2, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u4, u2} C (CategoryTheory.Category.toCategoryStruct.{u4, u2} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u4, u5, u2, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u4, succ u5, u2, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u4, u2} C (CategoryTheory.Category.toCategoryStruct.{u4, u2} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u4, u5, u2, u3} C _inst_2 D _inst_3 G) X)) (AddCommGroup.toAddCommMonoid.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max (max (max u2 u3) u4) u5} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max (max (max u2 u3) u4) u5} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max (max (max u2 u3) u4) u5} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (CategoryTheory.Preadditive.homGroup.{max u2 u5, max (max (max u2 u3) u4) u5} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.functorCategoryPreadditive.{u2, u3, u4, u5} C D _inst_2 _inst_3 _inst_4) F G)) (AddCommGroup.toAddCommMonoid.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (Prefunctor.obj.{succ u4, succ u5, u2, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u4, u2} C (CategoryTheory.Category.toCategoryStruct.{u4, u2} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u4, u5, u2, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u4, succ u5, u2, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u4, u2} C (CategoryTheory.Category.toCategoryStruct.{u4, u2} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u4, u5, u2, u3} C _inst_2 D _inst_3 G) X)) (CategoryTheory.Preadditive.homGroup.{u5, u3} D _inst_3 _inst_4 (Prefunctor.obj.{succ u4, succ u5, u2, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u4, u2} C (CategoryTheory.Category.toCategoryStruct.{u4, u2} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u4, u5, u2, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u4, succ u5, u2, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u4, u2} C (CategoryTheory.Category.toCategoryStruct.{u4, u2} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u4, u5, u2, u3} C _inst_2 D _inst_3 G) X))) (CategoryTheory.Linear.homModule.{u1, max u2 u5, max (max (max u2 u3) u4) u5} R _inst_1 (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.functorCategoryPreadditive.{u2, u3, u4, u5} C D _inst_2 _inst_3 _inst_4) (CategoryTheory.functorCategoryLinear.{u1, u2, u3, u4, u5} R _inst_1 C D _inst_2 _inst_3 _inst_4 _inst_5) F G) (CategoryTheory.Linear.homModule.{u1, u5, u3} R _inst_1 D _inst_3 _inst_4 _inst_5 (Prefunctor.obj.{succ u4, succ u5, u2, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u4, u2} C (CategoryTheory.Category.toCategoryStruct.{u4, u2} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u4, u5, u2, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u4, succ u5, u2, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u4, u2} C (CategoryTheory.Category.toCategoryStruct.{u4, u2} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u4, u5, u2, u3} C _inst_2 D _inst_3 G) X))
Case conversion may be inaccurate. Consider using '#align category_theory.nat_trans.app_linear_map CategoryTheory.NatTrans.appLinearMapₓ'. -/
/-- Application of a natural transformation at a fixed object,
as group homomorphism -/
@[simps]
def appLinearMap (X : C) : (F ⟶ G) →ₗ[R] F.obj X ⟶ G.obj X
    where
  toFun α := α.app X
  map_add' _ _ := rfl
  map_smul' _ _ := rfl
#align category_theory.nat_trans.app_linear_map CategoryTheory.NatTrans.appLinearMap

/- warning: category_theory.nat_trans.app_smul -> CategoryTheory.NatTrans.app_smul is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Semiring.{u1} R] {C : Type.{u2}} {D : Type.{u3}} [_inst_2 : CategoryTheory.Category.{u4, u2} C] [_inst_3 : CategoryTheory.Category.{u5, u3} D] [_inst_4 : CategoryTheory.Preadditive.{u5, u3} D _inst_3] [_inst_5 : CategoryTheory.Linear.{u1, u5, u3} R _inst_1 D _inst_3 _inst_4] {F : CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3} {G : CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3} (X : C) (r : R) (α : Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G), Eq.{succ u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (CategoryTheory.NatTrans.app.{u4, u5, u2, u3} C _inst_2 D _inst_3 F G (SMul.smul.{u1, max u2 u5} R (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (SMulZeroClass.toHasSmul.{u1, max u2 u5} R (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (AddZeroClass.toHasZero.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (AddMonoid.toAddZeroClass.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (AddCommMonoid.toAddMonoid.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (AddCommGroup.toAddCommMonoid.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (CategoryTheory.Preadditive.homGroup.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.functorCategoryPreadditive.{u2, u3, u4, u5} C D _inst_2 _inst_3 _inst_4) F G))))) (SMulWithZero.toSmulZeroClass.{u1, max u2 u5} R (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (MulZeroClass.toHasZero.{u1} R (MulZeroOneClass.toMulZeroClass.{u1} R (MonoidWithZero.toMulZeroOneClass.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1)))) (AddZeroClass.toHasZero.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (AddMonoid.toAddZeroClass.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (AddCommMonoid.toAddMonoid.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (AddCommGroup.toAddCommMonoid.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (CategoryTheory.Preadditive.homGroup.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.functorCategoryPreadditive.{u2, u3, u4, u5} C D _inst_2 _inst_3 _inst_4) F G))))) (MulActionWithZero.toSMulWithZero.{u1, max u2 u5} R (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (Semiring.toMonoidWithZero.{u1} R _inst_1) (AddZeroClass.toHasZero.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (AddMonoid.toAddZeroClass.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (AddCommMonoid.toAddMonoid.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (AddCommGroup.toAddCommMonoid.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (CategoryTheory.Preadditive.homGroup.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.functorCategoryPreadditive.{u2, u3, u4, u5} C D _inst_2 _inst_3 _inst_4) F G))))) (Module.toMulActionWithZero.{u1, max u2 u5} R (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) _inst_1 (AddCommGroup.toAddCommMonoid.{max u2 u5} (Quiver.Hom.{succ (max u2 u5), max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3))) F G) (CategoryTheory.Preadditive.homGroup.{max u2 u5, max u4 u5 u2 u3} (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.functorCategoryPreadditive.{u2, u3, u4, u5} C D _inst_2 _inst_3 _inst_4) F G)) (CategoryTheory.Linear.homModule.{u1, max u2 u5, max u4 u5 u2 u3} R _inst_1 (CategoryTheory.Functor.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u4, u5, u2, u3} C _inst_2 D _inst_3) (CategoryTheory.functorCategoryPreadditive.{u2, u3, u4, u5} C D _inst_2 _inst_3 _inst_4) (CategoryTheory.functorCategoryLinear.{u1, u2, u3, u4, u5} R _inst_1 C D _inst_2 _inst_3 _inst_4 _inst_5) F G))))) r α) X) (SMul.smul.{u1, u5} R (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (SMulZeroClass.toHasSmul.{u1, u5} R (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (AddZeroClass.toHasZero.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (AddMonoid.toAddZeroClass.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (AddCommMonoid.toAddMonoid.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (AddCommGroup.toAddCommMonoid.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (CategoryTheory.Preadditive.homGroup.{u5, u3} D _inst_3 _inst_4 (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)))))) (SMulWithZero.toSmulZeroClass.{u1, u5} R (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (MulZeroClass.toHasZero.{u1} R (MulZeroOneClass.toMulZeroClass.{u1} R (MonoidWithZero.toMulZeroOneClass.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1)))) (AddZeroClass.toHasZero.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (AddMonoid.toAddZeroClass.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (AddCommMonoid.toAddMonoid.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (AddCommGroup.toAddCommMonoid.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (CategoryTheory.Preadditive.homGroup.{u5, u3} D _inst_3 _inst_4 (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)))))) (MulActionWithZero.toSMulWithZero.{u1, u5} R (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (Semiring.toMonoidWithZero.{u1} R _inst_1) (AddZeroClass.toHasZero.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (AddMonoid.toAddZeroClass.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (AddCommMonoid.toAddMonoid.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (AddCommGroup.toAddCommMonoid.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (CategoryTheory.Preadditive.homGroup.{u5, u3} D _inst_3 _inst_4 (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)))))) (Module.toMulActionWithZero.{u1, u5} R (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) _inst_1 (AddCommGroup.toAddCommMonoid.{u5} (Quiver.Hom.{succ u5, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u5, u3} D (CategoryTheory.Category.toCategoryStruct.{u5, u3} D _inst_3)) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)) (CategoryTheory.Preadditive.homGroup.{u5, u3} D _inst_3 _inst_4 (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X))) (CategoryTheory.Linear.homModule.{u1, u5, u3} R _inst_1 D _inst_3 _inst_4 _inst_5 (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 F X) (CategoryTheory.Functor.obj.{u4, u5, u2, u3} C _inst_2 D _inst_3 G X)))))) r (CategoryTheory.NatTrans.app.{u4, u5, u2, u3} C _inst_2 D _inst_3 F G α X))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : Semiring.{u1} R] {C : Type.{u5}} {D : Type.{u3}} [_inst_2 : CategoryTheory.Category.{u2, u5} C] [_inst_3 : CategoryTheory.Category.{u4, u3} D] [_inst_4 : CategoryTheory.Preadditive.{u4, u3} D _inst_3] [_inst_5 : CategoryTheory.Linear.{u1, u4, u3} R _inst_1 D _inst_3 _inst_4] {F : CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3} {G : CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3} (X : C) (r : R) (α : Quiver.Hom.{max (succ u5) (succ u4), max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u2, u4, u5, u3} C _inst_2 D _inst_3))) F G), Eq.{succ u4} (Quiver.Hom.{succ u4, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 G) X)) (CategoryTheory.NatTrans.app.{u2, u4, u5, u3} C _inst_2 D _inst_3 F G (HSMul.hSMul.{u1, max u5 u4, max u5 u4} R (Quiver.Hom.{max (succ u5) (succ u4), max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u2, u4, u5, u3} C _inst_2 D _inst_3))) F G) (Quiver.Hom.{max (succ u5) (succ u4), max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u2, u4, u5, u3} C _inst_2 D _inst_3))) F G) (instHSMul.{u1, max u5 u4} R (Quiver.Hom.{max (succ u5) (succ u4), max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u2, u4, u5, u3} C _inst_2 D _inst_3))) F G) (SMulZeroClass.toSMul.{u1, max u5 u4} R (Quiver.Hom.{max (succ u5) (succ u4), max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u2, u4, u5, u3} C _inst_2 D _inst_3))) F G) (CategoryTheory.Limits.HasZeroMorphisms.Zero.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Limits.instHasZeroMorphismsFunctorCategory.{u2, u5, u4, u3} C _inst_2 D _inst_3 (CategoryTheory.Preadditive.preadditiveHasZeroMorphisms.{u4, u3} D _inst_3 _inst_4)) F G) (SMulWithZero.toSMulZeroClass.{u1, max u5 u4} R (Quiver.Hom.{max (succ u5) (succ u4), max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u2, u4, u5, u3} C _inst_2 D _inst_3))) F G) (MonoidWithZero.toZero.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1)) (CategoryTheory.Limits.HasZeroMorphisms.Zero.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Limits.instHasZeroMorphismsFunctorCategory.{u2, u5, u4, u3} C _inst_2 D _inst_3 (CategoryTheory.Preadditive.preadditiveHasZeroMorphisms.{u4, u3} D _inst_3 _inst_4)) F G) (MulActionWithZero.toSMulWithZero.{u1, max u5 u4} R (Quiver.Hom.{max (succ u5) (succ u4), max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u2, u4, u5, u3} C _inst_2 D _inst_3))) F G) (Semiring.toMonoidWithZero.{u1} R _inst_1) (CategoryTheory.Limits.HasZeroMorphisms.Zero.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Limits.instHasZeroMorphismsFunctorCategory.{u2, u5, u4, u3} C _inst_2 D _inst_3 (CategoryTheory.Preadditive.preadditiveHasZeroMorphisms.{u4, u3} D _inst_3 _inst_4)) F G) (Module.toMulActionWithZero.{u1, max u5 u4} R (Quiver.Hom.{max (succ u5) (succ u4), max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u2, u4, u5, u3} C _inst_2 D _inst_3))) F G) _inst_1 (AddCommGroup.toAddCommMonoid.{max u5 u4} (Quiver.Hom.{max (succ u5) (succ u4), max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.CategoryStruct.toQuiver.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Category.toCategoryStruct.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u2, u4, u5, u3} C _inst_2 D _inst_3))) F G) (CategoryTheory.Preadditive.homGroup.{max u5 u4, max (max (max u5 u3) u2) u4} (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.functorCategoryPreadditive.{u5, u3, u2, u4} C D _inst_2 _inst_3 _inst_4) F G)) (CategoryTheory.Linear.homModule.{u1, max u5 u4, max (max (max u5 u3) u2) u4} R _inst_1 (CategoryTheory.Functor.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.Functor.category.{u2, u4, u5, u3} C _inst_2 D _inst_3) (CategoryTheory.functorCategoryPreadditive.{u5, u3, u2, u4} C D _inst_2 _inst_3 _inst_4) (CategoryTheory.functorCategoryLinear.{u1, u5, u3, u2, u4} R _inst_1 C D _inst_2 _inst_3 _inst_4 _inst_5) F G)))))) r α) X) (HSMul.hSMul.{u1, u4, u4} R (Quiver.Hom.{succ u4, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 G) X)) (Quiver.Hom.{succ u4, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 G) X)) (instHSMul.{u1, u4} R (Quiver.Hom.{succ u4, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 G) X)) (SMulZeroClass.toSMul.{u1, u4} R (Quiver.Hom.{succ u4, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 G) X)) (CategoryTheory.Limits.HasZeroMorphisms.Zero.{u4, u3} D _inst_3 (CategoryTheory.Preadditive.preadditiveHasZeroMorphisms.{u4, u3} D _inst_3 _inst_4) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 G) X)) (SMulWithZero.toSMulZeroClass.{u1, u4} R (Quiver.Hom.{succ u4, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 G) X)) (MonoidWithZero.toZero.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1)) (CategoryTheory.Limits.HasZeroMorphisms.Zero.{u4, u3} D _inst_3 (CategoryTheory.Preadditive.preadditiveHasZeroMorphisms.{u4, u3} D _inst_3 _inst_4) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 G) X)) (MulActionWithZero.toSMulWithZero.{u1, u4} R (Quiver.Hom.{succ u4, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 G) X)) (Semiring.toMonoidWithZero.{u1} R _inst_1) (CategoryTheory.Limits.HasZeroMorphisms.Zero.{u4, u3} D _inst_3 (CategoryTheory.Preadditive.preadditiveHasZeroMorphisms.{u4, u3} D _inst_3 _inst_4) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 G) X)) (Module.toMulActionWithZero.{u1, u4} R (Quiver.Hom.{succ u4, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 G) X)) _inst_1 (AddCommGroup.toAddCommMonoid.{u4} (Quiver.Hom.{succ u4, u3} D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 G) X)) (CategoryTheory.Preadditive.homGroup.{u4, u3} D _inst_3 _inst_4 (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 G) X))) (CategoryTheory.Linear.homModule.{u1, u4, u3} R _inst_1 D _inst_3 _inst_4 _inst_5 (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 F) X) (Prefunctor.obj.{succ u2, succ u4, u5, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u2, u5} C (CategoryTheory.Category.toCategoryStruct.{u2, u5} C _inst_2)) D (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} D (CategoryTheory.Category.toCategoryStruct.{u4, u3} D _inst_3)) (CategoryTheory.Functor.toPrefunctor.{u2, u4, u5, u3} C _inst_2 D _inst_3 G) X))))))) r (CategoryTheory.NatTrans.app.{u2, u4, u5, u3} C _inst_2 D _inst_3 F G α X))
Case conversion may be inaccurate. Consider using '#align category_theory.nat_trans.app_smul CategoryTheory.NatTrans.app_smulₓ'. -/
@[simp]
theorem app_smul (X : C) (r : R) (α : F ⟶ G) : (r • α).app X = r • α.app X :=
  rfl
#align category_theory.nat_trans.app_smul CategoryTheory.NatTrans.app_smul

end NatTrans

end CategoryTheory


import .love07_metaprogramming_demo

/-! # LoVe Exercise 7: Metaprogramming -/

set_option pp.beta true
set_option pp.generalized_field_notation false

namespace LoVe

/-! ## Question 1: A Term Exploder

In this question, we develop a string format for the `expr` metatype. By
default, there is no `has_repr` instance to print a nice string. For example: -/

#eval (expr.app (expr.var 0) (expr.var 1) : expr)   -- result: `[external]`
#eval (`(λx : ℕ, x + x) : expr)                     -- result: `[external]`

/-! 1.1. Define a metafunction `expr.repr` that converts an `expr` into a
`string`. It is acceptable to leave out some fields from the `expr`
constructors, such as the level `l` of a sort, the binder information `bi` of
a `λ` or `∀` binder, and the arguments of the `macro` constructor.

Hint: Use `name.to_string` to convert a name to a string, and `repr` for other
types that belong to the `has_repr` type class. -/

meta def expr.repr : expr → string
| (expr.var n)                := "(var " ++ repr n ++ ")"
-- enter the missing cases here

/-! We register `expr.repr` in the `has_repr` type class, so that we can use
`repr` without qualification in the future, and so that it is available to
`#eval`. We need the `meta` keyword in front of the command we enter. -/

meta instance expr.has_repr : has_repr expr :=
{ repr := expr.repr }

/-! 1.2. Test your setup. -/

#eval (expr.app (expr.var 0) (expr.var 1) : expr)
#eval (`(λx : ℕ, x + x) : expr)

/-! ## Question 2: `destruct_and` on Steroids

Recall from the lecture that `destruct_and` fails on easy goals such as -/

lemma abc_ac₂ (a b c : Prop) (h : a ∧ b ∧ c) :
  a ∧ c :=
sorry

/-! We will now address this by developing a new tactic called `destro_and`,
which applies both **des**truction and in**tro**duction rules for conjunction.
It will also go automatically through the hypotheses instead of taking an
argument. We will develop it in three steps.

2.1. Develop a tactic `intro_ands` that replaces all goals of the form
`a ∧ b` with two new goals `a` and `b` systematically, until all top-level
conjunctions are gone.

For this, we can use tactics such as `tactic.repeat` (which repeatedly applies a
tactic on all goals and subgoals until the tactic fails on each of the goal) and
`tactic.applyc` (which can be used to apply a rule, in connection with backtick
quoting). -/

#check tactic.repeat
#check tactic.applyc

meta def intro_ands : tactic unit :=
sorry

lemma abcd_bd (a b c d : Prop) (h : a ∧ (b ∧ c) ∧ d) :
  b ∧ d :=
begin
  intro_ands,
  /- The proof state should be as follows:

  2 goals
  a b c d : Prop,
  h : a ∧ (b ∧ c) ∧ d
  ⊢ b

  a b c d : Prop,
  h : a ∧ (b ∧ c) ∧ d
  ⊢ d -/
  repeat { sorry }
end

lemma abcd_bacb (a b c d : Prop) (h : a ∧ (b ∧ c) ∧ d) :
  b ∧ (a ∧ (c ∧ b)) :=
begin
  intro_ands,
  /- The proof state should be as follows:

  4 goals
  a b c d : Prop,
  h : a ∧ (b ∧ c) ∧ d
  ⊢ b

  a b c d : Prop,
  h : a ∧ (b ∧ c) ∧ d
  ⊢ a

  a b c d : Prop,
  h : a ∧ (b ∧ c) ∧ d
  ⊢ c

  a b c d : Prop,
  h : a ∧ (b ∧ c) ∧ d
  ⊢ b -/
  repeat { sorry }
end

/-! 2.2. Develop a tactic `destruct_ands` that replaces hypotheses of the form
`h : a ∧ b` by two new hypotheses `h_left : a` and `h_right : b` systematically,
until all top-level conjunctions are gone.

Here is some pseudocode that you can follow:

1. Retrieve the list of hypotheses from the context. This is provided by the
   metaconstant `tactic.local_context`.

2. Find the first hypothesis (= term) with a type (= proposition) of the form
   `_ ∧ _`. Here, you can use the `list.mfirst` function, in conjunction with
   pattern matching. You can use `tactic.infer_type` to query the type of a
   term.

3. Perform a case split on the first found hypothesis. This can be achieved
   using `tactic.cases`, a metaprogram that corresponds roughly to `cases'`.

4. Repeat.

The above procedure might fail if there exists no hypotheses of the required
form. Make sure to handle this failure gracefully, for example using
`tactic.try` or `<|> pure ()`. -/

meta def destruct_ands : tactic unit :=
sorry

lemma abcd_bd₂ (a b c d : Prop) (h : a ∧ (b ∧ c) ∧ d) :
  b ∧ d :=
begin
  destruct_ands,
  /- The proof state should be as follows:

  a b c d : Prop,
  h_left : a,
  h_right_right : d,
  h_right_left_left : b,
  h_right_left_right : c
  ⊢ b ∧ d -/
  sorry
end

/-! 2.3. Combine the two tactics developed above and `tactic.assumption` to
implement the desired `destro_and` tactic. -/

meta def destro_and : tactic unit :=
sorry

lemma abcd_bd₃ (a b c d : Prop) (h : a ∧ (b ∧ c) ∧ d) :
  b ∧ d :=
by destro_and

lemma abcd_bacb₂ (a b c d : Prop) (h : a ∧ (b ∧ c) ∧ d) :
  b ∧ (a ∧ (c ∧ b)) :=
by destro_and

lemma abd_bacb (a b c d : Prop) (h : a ∧ b ∧ d) :
  b ∧ (a ∧ (c ∧ b)) :=
begin
  destro_and,
  /- The proof state should be roughly as follows:

  a b c d : Prop,
  h_left : a,
  h_right_left : b,
  h_right_right : d
  ⊢ c -/
  sorry   -- unprovable
end

/-! 2.4. Provide some more examples for `destro_and` to convince yourself that
it works as expected also on more complicated examples. -/

-- enter your examples here

/-! ## Question 3 (**optional**): A Theorem Finder

We will implement a function that allows us to find theorems by constants
appearing in their statements. So given a list of constant names, the function
will list all theorems in which all these constants appear.

You can use the following metaconstants:

* `declaration` contains all data (name, type, value) associated with a
  declaration understood broadly (e.g., axiom, lemma, constant, etc.).

* `tactic.get_env` gives us access to the `environment`, a metatype that lists
  all `declaration`s (including all theorems).

* `environment.fold` allows us to walk through the environment and collect data.

* `expr.fold` allows us to walk through an expression and collect data.

3.1 (**optional**). Write a metafunction that checks whether an expression
contains a specific constant.

You can use `expr.fold` to walk through the expression, `||` and `ff` for
Booleans, and `expr.is_constant_of` to check whether an expression is a
constant. -/

meta def term_contains (e : expr) (nam : name) : bool :=
sorry

/-! 3.2 (**optional**). Write a metafunction that checks whether an expression
contains **all** constants in a list.

You can use `list.band` (Boolean and). -/

meta def term_contains_all (nams : list name) (e : expr) : bool :=
sorry

/-! 3.3 (**optional**). Produce the list of all theorems that contain all
constants `nams` in their statement.

`environment.fold` allows you to walk over the list of declarations. With
`declaration.type`, you get the type of a theorem, and with
`declaration.to_name` you get the name. -/

meta def list_constants (nams : list name) (e : environment) : list name :=
sorry

/-! Finally, we develop a tactic that uses the above metafunctions to log all
found theorems: -/

meta def find_constants (nams : list name) : tactic unit :=
do
  env ← tactic.get_env,
  list.mmap' tactic.trace (list_constants nams env)

/-! We test the solution. -/

run_cmd find_constants []   -- lists all theorems
run_cmd find_constants [`list.map, `function.comp]

end LoVe


/-
Copyright (c) 2021 Markus Himmel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Markus Himmel
-/
import category_theory.monoidal.functor

/-!
# The free monoidal category over a type

Given a type `C`, the free monoidal category over `C` has as objects formal expressions built from
(formal) tensor products of terms of `C` and a formal unit. Its morphisms are compositions and
tensor products of identities, unitors and associators.

In this file, we construct the free monoidal category and prove that it is a monoidal category. If
`D` is a monoidal category, we construct the functor `free_monoidal_category C ⥤ D` associated to
a function `C → D`.

The free monoidal category has two important properties: it is a groupoid and it is thin. The former
is obvious from the construction, and the latter is what is commonly known as the monoidal coherence
theorem. Both of these properties are proved in the file `coherence.lean`.

-/

universes v' u u'

namespace category_theory
open monoidal_category

variables {C : Type u}

section
variables (C)

/--
Given a type `C`, the free monoidal category over `C` has as objects formal expressions built from
(formal) tensor products of terms of `C` and a formal unit. Its morphisms are compositions and
tensor products of identities, unitors and associators.
-/
@[derive inhabited]
inductive free_monoidal_category : Type u
| of : C → free_monoidal_category
| unit : free_monoidal_category
| tensor : free_monoidal_category → free_monoidal_category → free_monoidal_category

end

local notation `F` := free_monoidal_category

namespace free_monoidal_category

/-- Formal compositions and tensor products of identities, unitors and associators. The morphisms
    of the free monoidal category are obtained as a quotient of these formal morphisms by the
    relations defining a monoidal category. -/
@[nolint has_nonempty_instance]
inductive hom : F C → F C → Type u
| id (X) : hom X X
| α_hom (X Y Z : F C) : hom ((X.tensor Y).tensor Z) (X.tensor (Y.tensor Z))
| α_inv (X Y Z : F C) : hom (X.tensor (Y.tensor Z)) ((X.tensor Y).tensor Z)
| l_hom (X) : hom (unit.tensor X) X
| l_inv (X) : hom X (unit.tensor X)
| ρ_hom (X : F C) : hom (X.tensor unit) X
| ρ_inv (X : F C) : hom X (X.tensor unit)
| comp {X Y Z} (f : hom X Y) (g : hom Y Z) : hom X Z
| tensor {W X Y Z} (f : hom W Y) (g : hom X Z) : hom (W.tensor X) (Y.tensor Z)

local infixr ` ⟶ᵐ `:10 := hom

/-- The morphisms of the free monoidal category satisfy 21 relations ensuring that the resulting
    category is in fact a category and that it is monoidal. -/
inductive hom_equiv : Π {X Y : F C}, (X ⟶ᵐ Y) → (X ⟶ᵐ Y) → Prop
| refl {X Y} (f : X ⟶ᵐ Y) : hom_equiv f f
| symm {X Y} (f g : X ⟶ᵐ Y) : hom_equiv f g → hom_equiv g f
| trans {X Y} {f g h : X ⟶ᵐ Y} : hom_equiv f g → hom_equiv g h → hom_equiv f h
| comp {X Y Z} {f f' : X ⟶ᵐ Y} {g g' : Y ⟶ᵐ Z} :
    hom_equiv f f' → hom_equiv g g' → hom_equiv (f.comp g) (f'.comp g')
| tensor {W X Y Z} {f f' : W ⟶ᵐ X} {g g' : Y ⟶ᵐ Z} :
    hom_equiv f f' → hom_equiv g g' → hom_equiv (f.tensor g) (f'.tensor g')
| comp_id {X Y} (f : X ⟶ᵐ Y) : hom_equiv (f.comp (hom.id _)) f
| id_comp {X Y} (f : X ⟶ᵐ Y) : hom_equiv ((hom.id _).comp f) f
| assoc {X Y U V : F C} (f : X ⟶ᵐ U) (g : U ⟶ᵐ V) (h : V ⟶ᵐ Y) :
    hom_equiv ((f.comp g).comp h) (f.comp (g.comp h))
| tensor_id {X Y} : hom_equiv ((hom.id X).tensor (hom.id Y)) (hom.id _)
| tensor_comp {X₁ Y₁ Z₁ X₂ Y₂ Z₂ : F C}
    (f₁ : X₁ ⟶ᵐ Y₁) (f₂ : X₂ ⟶ᵐ Y₂) (g₁ : Y₁ ⟶ᵐ Z₁) (g₂ : Y₂ ⟶ᵐ Z₂) :
    hom_equiv ((f₁.comp g₁).tensor (f₂.comp g₂)) ((f₁.tensor f₂).comp (g₁.tensor g₂))
| α_hom_inv {X Y Z} : hom_equiv ((hom.α_hom X Y Z).comp (hom.α_inv X Y Z)) (hom.id _)
| α_inv_hom {X Y Z} : hom_equiv ((hom.α_inv X Y Z).comp (hom.α_hom X Y Z)) (hom.id _)
| associator_naturality {X₁ X₂ X₃ Y₁ Y₂ Y₃} (f₁ : X₁ ⟶ᵐ Y₁) (f₂ : X₂ ⟶ᵐ Y₂) (f₃ : X₃ ⟶ᵐ Y₃) :
    hom_equiv (((f₁.tensor f₂).tensor f₃).comp (hom.α_hom Y₁ Y₂ Y₃))
      ((hom.α_hom X₁ X₂ X₃).comp (f₁.tensor (f₂.tensor f₃)))
| ρ_hom_inv {X} : hom_equiv ((hom.ρ_hom X).comp (hom.ρ_inv X)) (hom.id _)
| ρ_inv_hom {X} : hom_equiv ((hom.ρ_inv X).comp (hom.ρ_hom X)) (hom.id _)
| ρ_naturality {X Y} (f : X ⟶ᵐ Y) : hom_equiv
    ((f.tensor (hom.id unit)).comp (hom.ρ_hom Y)) ((hom.ρ_hom X).comp f)
| l_hom_inv {X} : hom_equiv ((hom.l_hom X).comp (hom.l_inv X)) (hom.id _)
| l_inv_hom {X} : hom_equiv ((hom.l_inv X).comp (hom.l_hom X)) (hom.id _)
| l_naturality {X Y} (f : X ⟶ᵐ Y) : hom_equiv
    (((hom.id unit).tensor f).comp (hom.l_hom Y)) ((hom.l_hom X).comp f)
| pentagon {W X Y Z} : hom_equiv
  (((hom.α_hom W X Y).tensor (hom.id Z)).comp
    ((hom.α_hom W (X.tensor Y) Z).comp ((hom.id W).tensor (hom.α_hom X Y Z))))
  ((hom.α_hom (W.tensor X) Y Z).comp (hom.α_hom W X (Y.tensor Z)))
| triangle {X Y} : hom_equiv ((hom.α_hom X unit Y).comp ((hom.id X).tensor (hom.l_hom Y)))
  ((hom.ρ_hom X).tensor (hom.id Y))

/-- We say that two formal morphisms in the free monoidal category are equivalent if they become
    equal if we apply the relations that are true in a monoidal category. Note that we will prove
    that there is only one equivalence class -- this is the monoidal coherence theorem. -/
def setoid_hom (X Y : F C) : setoid (X ⟶ᵐ Y) :=
⟨hom_equiv,
  ⟨λ f, hom_equiv.refl f, λ f g, hom_equiv.symm f g, λ f g h hfg hgh, hom_equiv.trans hfg hgh⟩⟩

attribute [instance] setoid_hom

section
open free_monoidal_category.hom_equiv

instance category_free_monoidal_category : category.{u} (F C) :=
{ hom := λ X Y, quotient (free_monoidal_category.setoid_hom X Y),
  id := λ X, ⟦free_monoidal_category.hom.id _⟧,
  comp := λ X Y Z f g, quotient.map₂ hom.comp (by { intros f f' hf g g' hg, exact comp hf hg }) f g,
  id_comp' := by { rintro X Y ⟨f⟩, exact quotient.sound (id_comp f) },
  comp_id' := by { rintro X Y ⟨f⟩, exact quotient.sound (comp_id f) },
  assoc' := by { rintro W X Y Z ⟨f⟩ ⟨g⟩ ⟨h⟩, exact quotient.sound (assoc f g h) } }

instance : monoidal_category (F C) :=
{ tensor_obj := λ X Y, free_monoidal_category.tensor X Y,
  tensor_hom := λ X₁ Y₁ X₂ Y₂, quotient.map₂ hom.tensor $
    by { intros _ _ h _ _ h', exact hom_equiv.tensor h h'},
  tensor_id' := λ X Y, quotient.sound tensor_id,
  tensor_comp' := λ X₁ Y₁ Z₁ X₂ Y₂ Z₂,
    by { rintros ⟨f₁⟩ ⟨f₂⟩ ⟨g₁⟩ ⟨g₂⟩, exact quotient.sound (tensor_comp _ _ _ _) },
  tensor_unit := free_monoidal_category.unit,
  associator := λ X Y Z,
    ⟨⟦hom.α_hom X Y Z⟧, ⟦hom.α_inv X Y Z⟧, quotient.sound α_hom_inv, quotient.sound α_inv_hom⟩,
  associator_naturality' := λ X₁ X₂ X₃ Y₁ Y₂ Y₃,
    by { rintros ⟨f₁⟩ ⟨f₂⟩ ⟨f₃⟩, exact quotient.sound (associator_naturality _ _ _) },
  left_unitor := λ X,
   ⟨⟦hom.l_hom X⟧, ⟦hom.l_inv X⟧, quotient.sound l_hom_inv, quotient.sound l_inv_hom⟩,
  left_unitor_naturality' := λ X Y, by { rintro ⟨f⟩, exact quotient.sound (l_naturality _) },
  right_unitor := λ X,
   ⟨⟦hom.ρ_hom X⟧, ⟦hom.ρ_inv X⟧, quotient.sound ρ_hom_inv, quotient.sound ρ_inv_hom⟩,
  right_unitor_naturality' := λ X Y, by { rintro ⟨f⟩, exact quotient.sound (ρ_naturality _) },
  pentagon' := λ W X Y Z, quotient.sound pentagon,
  triangle' := λ X Y, quotient.sound triangle }

@[simp] lemma mk_comp {X Y Z : F C} (f : X ⟶ᵐ Y) (g : Y ⟶ᵐ Z) :
  ⟦f.comp g⟧ = @category_struct.comp (F C) _ _ _ _ ⟦f⟧ ⟦g⟧ :=
rfl

@[simp] lemma mk_tensor {X₁ Y₁ X₂ Y₂ : F C} (f : X₁ ⟶ᵐ Y₁) (g : X₂ ⟶ᵐ Y₂) :
  ⟦f.tensor g⟧ = @monoidal_category.tensor_hom (F C) _ _ _ _ _ _ ⟦f⟧ ⟦g⟧ :=
rfl

@[simp] lemma mk_id {X : F C} : ⟦hom.id X⟧ = 𝟙 X := rfl
@[simp] lemma mk_α_hom {X Y Z : F C} : ⟦hom.α_hom X Y Z⟧ = (α_ X Y Z).hom := rfl
@[simp] lemma mk_α_inv {X Y Z : F C} : ⟦hom.α_inv X Y Z⟧ = (α_ X Y Z).inv := rfl
@[simp] lemma mk_ρ_hom {X : F C} : ⟦hom.ρ_hom X⟧ = (ρ_ X).hom := rfl
@[simp] lemma mk_ρ_inv {X : F C} : ⟦hom.ρ_inv X⟧ = (ρ_ X).inv := rfl
@[simp] lemma mk_l_hom {X : F C} : ⟦hom.l_hom X⟧ = (λ_ X).hom := rfl
@[simp] lemma mk_l_inv {X : F C} : ⟦hom.l_inv X⟧ = (λ_ X).inv := rfl
@[simp] lemma tensor_eq_tensor {X Y : F C} : X.tensor Y = X ⊗ Y := rfl
@[simp] lemma unit_eq_unit : free_monoidal_category.unit = 𝟙_ (F C) := rfl

section functor
variables {D : Type u'} [category.{v'} D] [monoidal_category D] (f : C → D)

/-- Auxiliary definition for `free_monoidal_category.project`. -/
def project_obj : F C → D
| (free_monoidal_category.of X) := f X
| free_monoidal_category.unit := 𝟙_ D
| (free_monoidal_category.tensor X Y) := project_obj X ⊗ project_obj Y

section
open hom

/-- Auxiliary definition for `free_monoidal_category.project`. -/
@[simp] def project_map_aux : Π {X Y : F C}, (X ⟶ᵐ Y) → (project_obj f X ⟶ project_obj f Y)
| _ _ (id _) := 𝟙 _
| _ _ (α_hom _ _ _) := (α_ _ _ _).hom
| _ _ (α_inv _ _ _) := (α_ _ _ _).inv
| _ _ (l_hom _) := (λ_ _).hom
| _ _ (l_inv _) := (λ_ _).inv
| _ _ (ρ_hom _) := (ρ_ _).hom
| _ _ (ρ_inv _) := (ρ_ _).inv
| _ _ (comp f g) := project_map_aux f ≫ project_map_aux g
| _ _ (hom.tensor f g) := project_map_aux f ⊗ project_map_aux g

/-- Auxiliary definition for `free_monoidal_category.project`. -/
def project_map (X Y : F C) : (X ⟶ Y) → (project_obj f X ⟶ project_obj f Y) :=
quotient.lift (project_map_aux f)
begin
  intros f g h,
  induction h with X Y f X Y f g hfg hfg' X Y f g h _ _ hfg hgh X Y Z f f' g g' _ _ hf hg
    W X Y Z f g f' g' _ _ hfg hfg',
  { refl },
  { exact hfg'.symm },
  { exact hfg.trans hgh },
  { simp only [project_map_aux, hf, hg] },
  { simp only [project_map_aux, hfg, hfg'] },
  { simp only [project_map_aux, category.comp_id] },
  { simp only [project_map_aux, category.id_comp] },
  { simp only [project_map_aux, category.assoc ] },
  { simp only [project_map_aux, monoidal_category.tensor_id], refl },
  { simp only [project_map_aux, monoidal_category.tensor_comp] },
  { simp only [project_map_aux, iso.hom_inv_id] },
  { simp only [project_map_aux, iso.inv_hom_id] },
  { simp only [project_map_aux, monoidal_category.associator_naturality] },
  { simp only [project_map_aux, iso.hom_inv_id] },
  { simp only [project_map_aux, iso.inv_hom_id] },
  { simp only [project_map_aux], dsimp [project_obj],
    exact monoidal_category.right_unitor_naturality _ },
  { simp only [project_map_aux, iso.hom_inv_id] },
  { simp only [project_map_aux, iso.inv_hom_id] },
  { simp only [project_map_aux], dsimp [project_obj],
    exact monoidal_category.left_unitor_naturality _ },
  { simp only [project_map_aux], exact monoidal_category.pentagon _ _ _ _ },
  { simp only [project_map_aux], exact monoidal_category.triangle _ _ }
end

end

/-- If `D` is a monoidal category and we have a function `C → D`, then we have a functor from the
    free monoidal category over `C` to the category `D`. -/
def project : monoidal_functor (F C) D :=
{ obj := project_obj f,
  map := project_map f,
  ε := 𝟙 _,
  μ := λ X Y, 𝟙 _ }

end functor

end

end free_monoidal_category

end category_theory


/-
Copyright (c) 2018 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Chris Hughes
-/
import data.polynomial.field_division
import linear_algebra.finite_dimensional
import ring_theory.adjoin.basic
import ring_theory.power_basis
import ring_theory.principal_ideal_domain

/-!
# Adjoining roots of polynomials

This file defines the commutative ring `adjoin_root f`, the ring R[X]/(f) obtained from a
commutative ring `R` and a polynomial `f : R[X]`. If furthermore `R` is a field and `f` is
irreducible, the field structure on `adjoin_root f` is constructed.

## Main definitions and results

The main definitions are in the `adjoin_root` namespace.

*  `mk f : polynomial R →+* adjoin_root f`, the natural ring homomorphism.

*  `of f : R →+* adjoin_root f`, the natural ring homomorphism.

* `root f : adjoin_root f`, the image of X in R[X]/(f).

* `lift (i : R →+* S) (x : S) (h : f.eval₂ i x = 0) : (adjoin_root f) →+* S`, the ring
  homomorphism from R[X]/(f) to S extending `i : R →+* S` and sending `X` to `x`.

* `lift_hom (x : S) (hfx : aeval x f = 0) : adjoin_root f →ₐ[R] S`, the algebra
  homomorphism from R[X]/(f) to S extending `algebra_map R S` and sending `X` to `x`

* `equiv : (adjoin_root f →ₐ[F] E) ≃ {x // x ∈ (f.map (algebra_map F E)).roots}` a
  bijection between algebra homomorphisms from `adjoin_root` and roots of `f` in `S`

-/
noncomputable theory
open_locale classical
open_locale big_operators

universes u v w

variables {R : Type u} {S : Type v} {K : Type w}

open polynomial ideal

/-- Adjoin a root of a polynomial `f` to a commutative ring `R`. We define the new ring
as the quotient of `polynomial R` by the principal ideal generated by `f`. -/
def adjoin_root [comm_ring R] (f : polynomial R) : Type u :=
polynomial R ⧸ (span {f} : ideal (polynomial R))

namespace adjoin_root

section comm_ring
variables [comm_ring R] (f : polynomial R)

instance : comm_ring (adjoin_root f) := ideal.quotient.comm_ring _

instance : inhabited (adjoin_root f) := ⟨0⟩

instance : decidable_eq (adjoin_root f) := classical.dec_eq _

/-- Ring homomorphism from `R[x]` to `adjoin_root f` sending `X` to the `root`. -/
def mk : polynomial R →+* adjoin_root f := ideal.quotient.mk _

@[elab_as_eliminator]
theorem induction_on {C : adjoin_root f → Prop} (x : adjoin_root f)
  (ih : ∀ p : polynomial R, C (mk f p)) : C x :=
quotient.induction_on' x ih

/-- Embedding of the original ring `R` into `adjoin_root f`. -/
def of : R →+* adjoin_root f := (mk f).comp C

instance [comm_semiring S] [algebra S R] : algebra S (adjoin_root f) :=
ideal.quotient.algebra S

instance [comm_semiring S] [comm_semiring K] [has_scalar S K] [algebra S R] [algebra K R]
  [is_scalar_tower S K R] :
  is_scalar_tower S K (adjoin_root f) :=
submodule.quotient.has_quotient.quotient.is_scalar_tower _ _

instance [comm_semiring S] [comm_semiring K] [algebra S R] [algebra K R] [smul_comm_class S K R] :
  smul_comm_class S K (adjoin_root f) :=
submodule.quotient.has_quotient.quotient.smul_comm_class _ _

@[simp]

variables (S)

lemma algebra_map_eq' [comm_semiring S] [algebra S R] :
  algebra_map S (adjoin_root f) = (of f).comp (algebra_map S R) := rfl

variables {S}

/-- The adjoined root. -/
def root : adjoin_root f := mk f X

variables {f}

instance adjoin_root.has_coe_t : has_coe_t R (adjoin_root f) := ⟨of f⟩

@[simp] lemma mk_eq_mk {g h : polynomial R} : mk f g = mk f h ↔ f ∣ g - h :=
ideal.quotient.eq.trans ideal.mem_span_singleton

@[simp] lemma mk_self : mk f f = 0 :=
quotient.sound' (mem_span_singleton.2 $ by simp)

@[simp] lemma mk_C (x : R) : mk f (C x) = x := rfl

@[simp] lemma mk_X : mk f X = root f := rfl

@[simp] lemma aeval_eq (p : polynomial R) : aeval (root f) p = mk f p :=
polynomial.induction_on p (λ x, by { rw aeval_C, refl })
  (λ p q ihp ihq, by rw [alg_hom.map_add, ring_hom.map_add, ihp, ihq])
  (λ n x ih, by { rw [alg_hom.map_mul, aeval_C, alg_hom.map_pow, aeval_X,
    ring_hom.map_mul, mk_C, ring_hom.map_pow, mk_X], refl })

theorem adjoin_root_eq_top : algebra.adjoin R ({root f} : set (adjoin_root f)) = ⊤ :=
algebra.eq_top_iff.2 $ λ x, induction_on f x $ λ p,
(algebra.adjoin_singleton_eq_range_aeval R (root f)).symm ▸ ⟨p, aeval_eq p⟩

@[simp] lemma eval₂_root (f : polynomial R) : f.eval₂ (of f) (root f) = 0 :=
by rw [← algebra_map_eq, ← aeval_def, aeval_eq, mk_self]

lemma is_root_root (f : polynomial R) : is_root (f.map (of f)) (root f) :=
by rw [is_root, eval_map, eval₂_root]

lemma is_algebraic_root (hf : f ≠ 0) : is_algebraic R (root f) :=
⟨f, hf, eval₂_root f⟩

variables [comm_ring S]

/-- Lift a ring homomorphism `i : R →+* S` to `adjoin_root f →+* S`. -/
def lift (i : R →+* S) (x : S) (h : f.eval₂ i x = 0) : (adjoin_root f) →+* S :=
begin
  apply ideal.quotient.lift _ (eval₂_ring_hom i x),
  intros g H,
  rcases mem_span_singleton.1 H with ⟨y, hy⟩,
  rw [hy, ring_hom.map_mul, coe_eval₂_ring_hom, h, zero_mul]
end

variables {i : R →+* S} {a : S} (h : f.eval₂ i a = 0)

@[simp] lemma lift_mk (g : polynomial R) : lift i a h (mk f g) = g.eval₂ i a :=
ideal.quotient.lift_mk _ _ _

@[simp] lemma lift_root : lift i a h (root f) = a := by rw [root, lift_mk, eval₂_X]

@[simp] lemma lift_of {x : R} : lift i a h x = i x :=
by rw [← mk_C x, lift_mk, eval₂_C]

@[simp] lemma lift_comp_of : (lift i a h).comp (of f) = i :=
ring_hom.ext $ λ _, @lift_of _ _ _ _ _ _ _ h _

variables (f) [algebra R S]

/-- Produce an algebra homomorphism `adjoin_root f →ₐ[R] S` sending `root f` to
a root of `f` in `S`. -/
def lift_hom (x : S) (hfx : aeval x f = 0) : adjoin_root f →ₐ[R] S :=
{ commutes' := λ r, show lift _ _ hfx r = _, from lift_of hfx,
  .. lift (algebra_map R S) x hfx }

@[simp] lemma coe_lift_hom (x : S) (hfx : aeval x f = 0) :
  (lift_hom f x hfx : adjoin_root f →+* S) = lift (algebra_map R S) x hfx := rfl

@[simp] lemma aeval_alg_hom_eq_zero (ϕ : adjoin_root f →ₐ[R] S) : aeval (ϕ (root f)) f = 0 :=
begin
  have h : ϕ.to_ring_hom.comp (of f) = algebra_map R S := ring_hom.ext_iff.mpr (ϕ.commutes),
  rw [aeval_def, ←h, ←ring_hom.map_zero ϕ.to_ring_hom, ←eval₂_root f, hom_eval₂],
  refl,
end

@[simp] lemma lift_hom_eq_alg_hom (f : polynomial R) (ϕ : adjoin_root f →ₐ[R] S) :
  lift_hom f (ϕ (root f)) (aeval_alg_hom_eq_zero f ϕ) = ϕ :=
begin
  suffices : ϕ.equalizer (lift_hom f (ϕ (root f)) (aeval_alg_hom_eq_zero f ϕ)) = ⊤,
  { exact (alg_hom.ext (λ x, (set_like.ext_iff.mp (this) x).mpr algebra.mem_top)).symm },
  rw [eq_top_iff, ←adjoin_root_eq_top, algebra.adjoin_le_iff, set.singleton_subset_iff],
  exact (@lift_root _ _ _ _ _ _ _ (aeval_alg_hom_eq_zero f ϕ)).symm,
end

variables (hfx : aeval a f = 0)

@[simp] lemma lift_hom_mk {g : polynomial R} : lift_hom f a hfx (mk f g) = aeval a g :=
lift_mk hfx g

@[simp] lemma lift_hom_root : lift_hom f a hfx (root f) = a :=
lift_root hfx

@[simp] lemma lift_hom_of {x : R} : lift_hom f a hfx (of f x) = algebra_map _ _ x :=
lift_of hfx

end comm_ring

section irreducible

variables [field K] {f : polynomial K} [irreducible f]

instance is_maximal_span : is_maximal (span {f} : ideal (polynomial K)) :=
principal_ideal_ring.is_maximal_of_irreducible ‹irreducible f›

noncomputable instance field : field (adjoin_root f) :=
{ ..adjoin_root.comm_ring f,
  ..ideal.quotient.field (span {f} : ideal (polynomial K)) }

lemma coe_injective : function.injective (coe : K → adjoin_root f) :=
(of f).injective

variable (f)

lemma mul_div_root_cancel :
  ((X - C (root f)) * (f.map (of f) / (X - C (root f))) : polynomial (adjoin_root f)) =
    f.map (of f) :=
mul_div_eq_iff_is_root.2 $ is_root_root _

end irreducible

section power_basis

variables [comm_ring R] {g : polynomial R}

lemma is_integral_root' (hg : g.monic) : is_integral R (root g) :=
⟨g, hg, eval₂_root g⟩

/-- `adjoin_root.mod_by_monic_hom` sends the equivalence class of `f` mod `g` to `f %ₘ g`.

This is a well-defined right inverse to `adjoin_root.mk`, see `adjoin_root.mk_left_inverse`. -/
def mod_by_monic_hom [nontrivial R] (hg : g.monic) :
  adjoin_root g →ₗ[R] polynomial R :=
(submodule.liftq _ (polynomial.mod_by_monic_hom hg)
  (λ f (hf : f ∈ (ideal.span {g}).restrict_scalars R),
    (mem_ker_mod_by_monic hg).mpr (ideal.mem_span_singleton.mp hf))).comp $
(submodule.quotient.restrict_scalars_equiv R (ideal.span {g} : ideal (polynomial R)))
  .symm.to_linear_map

@[simp] lemma mod_by_monic_hom_mk [nontrivial R] (hg : g.monic) (f : polynomial R) :
  mod_by_monic_hom hg (mk g f) = f %ₘ g := rfl

lemma mk_left_inverse [nontrivial R] (hg : g.monic) :
  function.left_inverse (mk g) (mod_by_monic_hom hg) :=
λ f, induction_on g f $ λ f, begin
  rw [mod_by_monic_hom_mk hg, mk_eq_mk, mod_by_monic_eq_sub_mul_div _ hg,
      sub_sub_cancel_left, dvd_neg],
  apply dvd_mul_right
end

lemma mk_surjective [nontrivial R] (hg : g.monic) : function.surjective (mk g) :=
(mk_left_inverse hg).surjective

/-- The elements `1, root g, ..., root g ^ (d - 1)` form a basis for `adjoin_root g`,
where `g` is a monic polynomial of degree `d`. -/
@[simps] def power_basis_aux' [nontrivial R] (hg : g.monic) :
  basis (fin g.nat_degree) R (adjoin_root g) :=
basis.of_equiv_fun
{ to_fun := λ f i, (mod_by_monic_hom hg f).coeff i,
  inv_fun := λ c, mk g $ ∑ (i : fin g.nat_degree), monomial i (c i),
  map_add' := λ f₁ f₂, funext $ λ i,
    by simp only [(mod_by_monic_hom hg).map_add, coeff_add, pi.add_apply],
  map_smul' := λ f₁ f₂, funext $ λ i,
    by simp only [(mod_by_monic_hom hg).map_smul, coeff_smul, pi.smul_apply, ring_hom.id_apply],
  left_inv := λ f, induction_on g f (λ f, eq.symm $ mk_eq_mk.mpr $
    by { simp only [mod_by_monic_hom_mk, sum_mod_by_monic_coeff hg degree_le_nat_degree],
         rw [mod_by_monic_eq_sub_mul_div _ hg, sub_sub_cancel],
         exact dvd_mul_right _ _ }),
  right_inv := λ x, funext $ λ i, begin
    simp only [mod_by_monic_hom_mk],
    rw [(mod_by_monic_eq_self_iff hg).mpr, finset_sum_coeff, finset.sum_eq_single i];
      try { simp only [coeff_monomial, eq_self_iff_true, if_true] },
    { intros j _ hj, exact if_neg (fin.coe_injective.ne hj) },
    { intros, have := finset.mem_univ i, contradiction },
    { refine (degree_sum_le _ _).trans_lt ((finset.sup_lt_iff _).mpr (λ j _, _)),
      { exact bot_lt_iff_ne_bot.mpr (mt degree_eq_bot.mp hg.ne_zero) },
      { refine (degree_monomial_le _ _).trans_lt _,
        rw [degree_eq_nat_degree hg.ne_zero, with_bot.coe_lt_coe],
        exact j.2 } },
  end}

/-- The power basis `1, root g, ..., root g ^ (d - 1)` for `adjoin_root g`,
where `g` is a monic polynomial of degree `d`. -/
@[simps] def power_basis' [nontrivial R] (hg : g.monic) :
  power_basis R (adjoin_root g) :=
{ gen := root g,
  dim := g.nat_degree,
  basis := power_basis_aux' hg,
  basis_eq_pow := λ i, begin
    simp only [power_basis_aux', basis.coe_of_equiv_fun, linear_equiv.coe_symm_mk],
    rw finset.sum_eq_single i,
    { rw [function.update_same, monomial_one_right_eq_X_pow, (mk g).map_pow, mk_X] },
    { intros j _ hj,
      rw ← monomial_zero_right _,
      convert congr_arg _ (function.update_noteq hj _ _) }, -- Fix `decidable_eq` mismatch
    { intros, have := finset.mem_univ i, contradiction },
  end}

variables [field K] {f : polynomial K}

lemma is_integral_root (hf : f ≠ 0) : is_integral K (root f) :=
(is_algebraic_iff_is_integral _).mp (is_algebraic_root hf)

lemma minpoly_root (hf : f ≠ 0) : minpoly K (root f) = f * C (f.leading_coeff⁻¹) :=
begin
  have f'_monic : monic _ := monic_mul_leading_coeff_inv hf,
  refine (minpoly.unique K _ f'_monic _ _).symm,
  { rw [alg_hom.map_mul, aeval_eq, mk_self, zero_mul] },
  intros q q_monic q_aeval,
  have commutes : (lift (algebra_map K (adjoin_root f)) (root f) q_aeval).comp (mk q) = mk f,
  { ext,
    { simp only [ring_hom.comp_apply, mk_C, lift_of], refl },
    { simp only [ring_hom.comp_apply, mk_X, lift_root] } },
  rw [degree_eq_nat_degree f'_monic.ne_zero, degree_eq_nat_degree q_monic.ne_zero,
      with_bot.coe_le_coe, nat_degree_mul hf, nat_degree_C, add_zero],
  apply nat_degree_le_of_dvd,
  { have : mk f q = 0, by rw [←commutes, ring_hom.comp_apply, mk_self, ring_hom.map_zero],
    rwa [←ideal.mem_span_singleton, ←ideal.quotient.eq_zero_iff_mem] },
  { exact q_monic.ne_zero },
  { rwa [ne.def, C_eq_zero, inv_eq_zero, leading_coeff_eq_zero] },
end

/-- The elements `1, root f, ..., root f ^ (d - 1)` form a basis for `adjoin_root f`,
where `f` is an irreducible polynomial over a field of degree `d`. -/
def power_basis_aux (hf : f ≠ 0) : basis (fin f.nat_degree) K (adjoin_root f) :=
begin
  set f' := f * C (f.leading_coeff⁻¹) with f'_def,
  have deg_f' : f'.nat_degree = f.nat_degree,
  { rw [nat_degree_mul hf, nat_degree_C, add_zero],
    { rwa [ne.def, C_eq_zero, inv_eq_zero, leading_coeff_eq_zero] } },
  have minpoly_eq : minpoly K (root f) = f' := minpoly_root hf,
  apply @basis.mk _ _ _ (λ (i : fin f.nat_degree), (root f ^ i.val)),
  { rw [← deg_f', ← minpoly_eq],
    exact (is_integral_root hf).linear_independent_pow },
  { rw _root_.eq_top_iff,
    rintros y -,
    rw [← deg_f', ← minpoly_eq],
    apply (is_integral_root hf).mem_span_pow,
    obtain ⟨g⟩ := y,
    use g,
    rw aeval_eq,
    refl }
end

/-- The power basis `1, root f, ..., root f ^ (d - 1)` for `adjoin_root f`,
where `f` is an irreducible polynomial over a field of degree `d`. -/
@[simps] def power_basis (hf : f ≠ 0) :
  power_basis K (adjoin_root f) :=
{ gen := root f,
  dim := f.nat_degree,
  basis := power_basis_aux hf,
  basis_eq_pow := basis.mk_apply _ _ }

lemma minpoly_power_basis_gen (hf : f ≠ 0) :
  minpoly K (power_basis hf).gen = f * C (f.leading_coeff⁻¹) :=
by rw [power_basis_gen, minpoly_root hf]

lemma minpoly_power_basis_gen_of_monic (hf : f.monic) (hf' : f ≠ 0 := hf.ne_zero) :
  minpoly K (power_basis hf').gen = f :=
by rw [minpoly_power_basis_gen hf', hf.leading_coeff, inv_one, C.map_one, mul_one]

end power_basis

section equiv

section is_domain

variables [comm_ring R] [is_domain R] [comm_ring S] [is_domain S] [algebra R S]
variables (g : polynomial R) (pb : _root_.power_basis R S)

/-- If `S` is an extension of `R` with power basis `pb` and `g` is a monic polynomial over `R`
such that `pb.gen` has a minimal polynomial `g`, then `S` is isomorphic to `adjoin_root g`.

Compare `power_basis.equiv_of_root`, which would require
`h₂ : aeval pb.gen (minpoly R (root g)) = 0`; that minimal polynomial is not
guaranteed to be identical to `g`. -/
@[simps {fully_applied := ff}]
def equiv' (h₁ : aeval (root g) (minpoly R pb.gen) = 0) (h₂ : aeval pb.gen g = 0) :
  adjoin_root g ≃ₐ[R] S :=
{ to_fun := adjoin_root.lift_hom g pb.gen h₂,
  inv_fun := pb.lift (root g) h₁,
  left_inv := λ x, induction_on g x $ λ f, by rw [lift_hom_mk, pb.lift_aeval, aeval_eq],
  right_inv := λ x, begin
    obtain ⟨f, hf, rfl⟩ := pb.exists_eq_aeval x,
    rw [pb.lift_aeval, aeval_eq, lift_hom_mk]
  end,
  .. adjoin_root.lift_hom g pb.gen h₂ }

@[simp] lemma equiv'_to_alg_hom
  (h₁ : aeval (root g) (minpoly R pb.gen) = 0) (h₂ : aeval pb.gen g = 0) :
  (equiv' g pb h₁ h₂).to_alg_hom = adjoin_root.lift_hom g pb.gen h₂ :=
rfl

@[simp] lemma equiv'_symm_to_alg_hom
  (h₁ : aeval (root g) (minpoly R pb.gen) = 0) (h₂ : aeval pb.gen g = 0) :
  (equiv' g pb h₁ h₂).symm.to_alg_hom = pb.lift (root g) h₁ :=
rfl

end is_domain

section field

variables (K) (L F : Type*) [field F] [field K] [field L] [algebra F K] [algebra F L]
variables (pb : _root_.power_basis F K)

/-- If `L` is a field extension of `F` and `f` is a polynomial over `F` then the set
of maps from `F[x]/(f)` into `L` is in bijection with the set of roots of `f` in `L`. -/
def equiv (f : polynomial F) (hf : f ≠ 0) :
  (adjoin_root f →ₐ[F] L) ≃ {x // x ∈ (f.map (algebra_map F L)).roots} :=
(power_basis hf).lift_equiv'.trans ((equiv.refl _).subtype_equiv (λ x,
  begin
    rw [power_basis_gen, minpoly_root hf, polynomial.map_mul, roots_mul,
        polynomial.map_C, roots_C, add_zero, equiv.refl_apply],
    { rw ← polynomial.map_mul, exact map_monic_ne_zero (monic_mul_leading_coeff_inv hf) }
  end))

end field

end equiv

end adjoin_root


import Mathlib.Data.Rat.Basic
import Mathlib.CategoryTheory.Bicategory.Basic

/-
We have see how structures as a way to carry around addition data.
But there can be _a lot_ of additional in general.
-/

#print Rat

/- For the rational numbers `ℚ` or `Rat` are lots of natural
things to do, add, multiply, divide (if nonzero), take floors,...
Building a single structure with all of these as fields is
not a good idea.

(Type)Classes provide an answer to this. The syntax looks very
similar to a structure.
-/

example (q r : ℚ) : ℚ := q+r

example : Add ℚ := inferInstance

example : ℚ := default

class LawlessGroup (α : Type) where
  unit : α
  mul : α → α → α
  inv : α → α

#print LawlessGroup

/- While can declare instances of a class like with structure
using `def` or `example`, we can also declare instances
using the `instance` keyword -/

instance : LawlessGroup ℕ where
  unit := 0
  mul n m := n + m
  inv _ := 0

/- The advantage of classes is that Lean keeps track of
typeclass instancs and will try to provide one in the
correct context -/

-- `inferInstance` is basically telling Lean to find one
example : LawlessGroup ℕ := inferInstance

-- Now Lean can find `mul` from the instance of `LawlessGroup` on `ℕ`
example : ℕ → ℕ → ℕ := LawlessGroup.mul

-- Even better, we can open the `LawlessGroup` namespace

open LawlessGroup

example : ℕ → ℕ := inv

#print Inhabited
#print Nonempty

instance myInstance { α β : Type } [ Inhabited α ] (f : α → β) : Inhabited β :=
  { default := f default }
#check myInstance
example (β : Type) (f : ℕ → β) : Inhabited β := myInstance f

instance {α β : Type} [Add β] : Add (α → β) where
  add := fun f g a => f a + g a

#check Add

def myAdd {α : Type} [Add α] (l l' : List α) : (List α) :=
  match l, l' with
  | [],_ => []
  | _,[] => []
  | a::as, a'::as' => (Add.add a a') :: myAdd as as'

#eval myAdd [1,2] [3]

instance [Add α] : Add (List α) where
  add := myAdd

def myHead { α : Type} [Inhabited α] (l : List α) : α :=
  match l with
  | [] => default
  | a::_ => a


example (p q : ℕ → Prop) :
  (∃ x, p x ∧ q x) → ∃ x, q x ∧ p x :=
begin
  intro h,
  cases h with x hpqx,
  cases hpqx with hpx hqx,
  existsi x, split; assumption
end