File: Mathlib/Tactic/CategoryTheory/Coherence.lean

full_name: Mathlib.Tactic.Coherence.LiftObj.lift
code: /-- A typeclass carrying a choice of lift of an object from `C` to `FreeMonoidalCategory C`.
It must be the case that `projectObj id (LiftObj.lift x) = x` by defeq. -/
class LiftObj (X : C) where
  protected lift : FreeMonoidalCategory C
goal: CategoryTheory.FreeMonoidalCategory C

full_name: Mathlib.Tactic.Coherence.LiftObj
code: /-- A typeclass carrying a choice of lift of an object from `C` to `FreeMonoidalCategory C`.
It must be the case that `projectObj id (LiftObj.lift x) = x` by defeq. -/
class LiftObj (X : C) where
  protected lift : FreeMonoidalCategory C
goal: Type u

full_name: Mathlib.Tactic.Coherence.LiftObj_unit
code: instance LiftObj_unit : LiftObj (𝟙_ C) 
goal: Mathlib.Tactic.Coherence.LiftObj (𝟙_ C)

full_name: Mathlib.Tactic.Coherence.LiftObj_tensor
code: instance LiftObj_tensor (X Y : C) [LiftObj X] [LiftObj Y] : LiftObj (X ⊗ Y) 
goal: Mathlib.Tactic.Coherence.LiftObj (CategoryTheory.MonoidalCategory.tensorObj X Y)

full_name: Mathlib.Tactic.Coherence.LiftObj_of
code: instance (priority := 100) LiftObj_of (X : C) : LiftObj X 
goal: Mathlib.Tactic.Coherence.LiftObj X

full_name: Mathlib.Tactic.Coherence.LiftHom.lift
code: /-- A typeclass carrying a choice of lift of a morphism from `C` to `FreeMonoidalCategory C`.
It must be the case that `projectMap id _ _ (LiftHom.lift f) = f` by defeq. -/
class LiftHom {X Y : C} [LiftObj X] [LiftObj Y] (f : X ⟶ Y) where
  protected lift : LiftObj.lift X ⟶ LiftObj.lift Y
goal: Mathlib.Tactic.Coherence.LiftObj.lift X ⟶ Mathlib.Tactic.Coherence.LiftObj.lift Y

full_name: Mathlib.Tactic.Coherence.LiftHom
code: /-- A typeclass carrying a choice of lift of a morphism from `C` to `FreeMonoidalCategory C`.
It must be the case that `projectMap id _ _ (LiftHom.lift f) = f` by defeq. -/
class LiftHom {X Y : C} [LiftObj X] [LiftObj Y] (f : X ⟶ Y) where
  protected lift : LiftObj.lift X ⟶ LiftObj.lift Y
goal: Type u

full_name: Mathlib.Tactic.Coherence.LiftHom_id
code: instance LiftHom_id (X : C) [LiftObj X] : LiftHom (𝟙 X) 
goal: Mathlib.Tactic.Coherence.LiftHom (𝟙 X)

full_name: Mathlib.Tactic.Coherence.LiftHom_left_unitor_hom
code: instance LiftHom_left_unitor_hom (X : C) [LiftObj X] : LiftHom (λ_ X).hom 
goal: Mathlib.Tactic.Coherence.LiftHom (CategoryTheory.MonoidalCategory.leftUnitor X).hom

full_name: Mathlib.Tactic.Coherence.LiftHom_left_unitor_inv
code: instance LiftHom_left_unitor_inv (X : C) [LiftObj X] : LiftHom (λ_ X).inv 
goal: Mathlib.Tactic.Coherence.LiftHom (CategoryTheory.MonoidalCategory.leftUnitor X).inv

full_name: Mathlib.Tactic.Coherence.LiftHom_right_unitor_hom
code: instance LiftHom_right_unitor_hom (X : C) [LiftObj X] : LiftHom (ρ_ X).hom 
goal: Mathlib.Tactic.Coherence.LiftHom (CategoryTheory.MonoidalCategory.rightUnitor X).hom

full_name: Mathlib.Tactic.Coherence.LiftHom_right_unitor_inv
code: instance LiftHom_right_unitor_inv (X : C) [LiftObj X] : LiftHom (ρ_ X).inv 
goal: Mathlib.Tactic.Coherence.LiftHom (CategoryTheory.MonoidalCategory.rightUnitor X).inv

full_name: Mathlib.Tactic.Coherence.LiftHom_associator_hom
code: instance LiftHom_associator_hom (X Y Z : C) [LiftObj X] [LiftObj Y] [LiftObj Z] :
    LiftHom (α_ X Y Z).hom 
goal: Mathlib.Tactic.Coherence.LiftHom (CategoryTheory.MonoidalCategory.associator X Y Z).hom

full_name: Mathlib.Tactic.Coherence.LiftHom_associator_inv
code: instance LiftHom_associator_inv (X Y Z : C) [LiftObj X] [LiftObj Y] [LiftObj Z] :
    LiftHom (α_ X Y Z).inv 
goal: Mathlib.Tactic.Coherence.LiftHom (CategoryTheory.MonoidalCategory.associator X Y Z).inv

full_name: Mathlib.Tactic.Coherence.LiftHom_comp
code: instance LiftHom_comp {X Y Z : C} [LiftObj X] [LiftObj Y] [LiftObj Z] (f : X ⟶ Y) (g : Y ⟶ Z)
    [LiftHom f] [LiftHom g] : LiftHom (f ≫ g) 
goal: Mathlib.Tactic.Coherence.LiftHom (f ≫ g)

full_name: Mathlib.Tactic.Coherence.liftHom_WhiskerLeft
code: instance liftHom_WhiskerLeft (X : C) [LiftObj X] {Y Z : C} [LiftObj Y] [LiftObj Z]
    (f : Y ⟶ Z) [LiftHom f] : LiftHom (X ◁ f) 
goal: Mathlib.Tactic.Coherence.LiftHom (CategoryTheory.MonoidalCategory.whiskerLeft X f)

full_name: Mathlib.Tactic.Coherence.liftHom_WhiskerRight
code: instance liftHom_WhiskerRight {X Y : C} (f : X ⟶ Y) [LiftObj X] [LiftObj Y] [LiftHom f]
    {Z : C} [LiftObj Z] : LiftHom (f ▷ Z) 
goal: Mathlib.Tactic.Coherence.LiftHom (CategoryTheory.MonoidalCategory.whiskerRight f Z)

full_name: Mathlib.Tactic.Coherence.LiftHom_tensor
code: instance LiftHom_tensor {W X Y Z : C} [LiftObj W] [LiftObj X] [LiftObj Y] [LiftObj Z]
    (f : W ⟶ X) (g : Y ⟶ Z) [LiftHom f] [LiftHom g] : LiftHom (f ⊗ g) 
goal: Mathlib.Tactic.Coherence.LiftHom (CategoryTheory.MonoidalCategory.tensorHom f g)

full_name: Mathlib.Tactic.Coherence.exception
code: /-- Helper function for throwing exceptions. -/
def exception {α : Type} (g : MVarId) (msg : MessageData) : MetaM α 
goal: Lean.MetaM α

full_name: Mathlib.Tactic.Coherence.exception'
code: /-- Helper function for throwing exceptions with respect to the main goal. -/
def exception' (msg : MessageData) : TacticM Unit 
goal: Lean.Elab.Tactic.TacticM Unit

full_name: Mathlib.Tactic.Coherence.mkProjectMapExpr
code: /-- Auxiliary definition for `monoidal_coherence`. -/
-- We could construct this expression directly without using `elabTerm`,
-- but it would require preparing many implicit arguments by hand.
def mkProjectMapExpr (e : Expr) : TermElabM Expr 
goal: Lean.Elab.TermElabM Lean.Expr

full_name: Mathlib.Tactic.Coherence.monoidal_coherence
code: /-- Coherence tactic for monoidal categories. -/
def monoidal_coherence (g : MVarId) : TermElabM Unit 
goal: Lean.Elab.TermElabM Unit

full_name: Mathlib.Tactic.Coherence.tacticMonoidal_coherence
code: /-- Coherence tactic for monoidal categories.
Use `pure_coherence` instead, which is a frontend to this one. -/
elab "monoidal_coherence" : tactic => do monoidal_coherence (← getMainGoal)
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.Coherence._aux_Mathlib_Tactic_CategoryTheory_Coherence___elabRules_Mathlib_Tactic_Coherence_tacticMonoidal_coherence_1
code: /-- Coherence tactic for monoidal categories.
Use `pure_coherence` instead, which is a frontend to this one. -/
elab "monoidal_coherence" : tactic => do monoidal_coherence (← getMainGoal)
goal: Lean.Elab.Tactic.Tactic

full_name: Mathlib.Tactic.Coherence._aux_Mathlib_Tactic_CategoryTheory_Coherence___elabRules_Mathlib_Tactic_Coherence_pure_coherence_1
code: /--
`pure_coherence` uses the coherence theorem for monoidal categories to prove the goal.
It can prove any equality made up only of associators, unitors, and identities.
```lean
example {C : Type} [Category C] [MonoidalCategory C] :
  (λ_ (𝟙_ C)).hom = (ρ_ (𝟙_ C)).hom := by
  pure_coherence
```

Users will typically just use the `coherence` tactic,
which can also cope with identities of the form
`a ≫ f ≫ b ≫ g ≫ c = a' ≫ f ≫ b' ≫ g ≫ c'`
where `a = a'`, `b = b'`, and `c = c'` can be proved using `pure_coherence`
-/
elab (name := pure_coherence) "pure_coherence" : tactic => do
  let g ← getMainGoal
  monoidal_coherence g <|> bicategory_coherence g
goal: Lean.Elab.Tactic.Tactic

full_name: Mathlib.Tactic.Coherence.pure_coherence
code: /--
`pure_coherence` uses the coherence theorem for monoidal categories to prove the goal.
It can prove any equality made up only of associators, unitors, and identities.
```lean
example {C : Type} [Category C] [MonoidalCategory C] :
  (λ_ (𝟙_ C)).hom = (ρ_ (𝟙_ C)).hom := by
  pure_coherence
```

Users will typically just use the `coherence` tactic,
which can also cope with identities of the form
`a ≫ f ≫ b ≫ g ≫ c = a' ≫ f ≫ b' ≫ g ≫ c'`
where `a = a'`, `b = b'`, and `c = c'` can be proved using `pure_coherence`
-/
elab (name := pure_coherence) "pure_coherence" : tactic => do
  let g ← getMainGoal
  monoidal_coherence g <|> bicategory_coherence g
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.Coherence.assoc_liftHom
code: /--
Auxiliary simp lemma for the `coherence` tactic:
this moves brackets to the left in order to expose a maximal prefix
built out of unitors and associators.
-/
-- We have unused typeclass arguments here.
-- They are intentional, to ensure that `simp only [assoc_LiftHom]` only left associates
-- monoidal structural morphisms.
@[nolint unusedArguments]
lemma assoc_liftHom {W X Y Z : C} [LiftObj W] [LiftObj X] [LiftObj Y]
    (f : W ⟶ X) (g : X ⟶ Y) (h : Y ⟶ Z) [LiftHom f] [LiftHom g] :
    f ≫ (g ≫ h) = (f ≫ g) ≫ h 
goal: f ≫ g ≫ h = (f ≫ g) ≫ h

full_name: Mathlib.Tactic.Coherence._aux_Mathlib_Tactic_CategoryTheory_Coherence___elabRules_Mathlib_Tactic_Coherence_liftable_prefixes_1
code: /--
Internal tactic used in `coherence`.

Rewrites an equation `f = g` as `f₀ ≫ f₁ = g₀ ≫ g₁`,
where `f₀` and `g₀` are maximal prefixes of `f` and `g` (possibly after reassociating)
which are "liftable" (i.e. expressible as compositions of unitors and associators).
-/
elab (name := liftable_prefixes) "liftable_prefixes" : tactic => do
  withOptions (fun opts => synthInstance.maxSize.set opts
    (max 256 (synthInstance.maxSize.get opts))) do
  evalTactic (← `(tactic|
    (simp (config := {failIfUnchanged := false}) only
      [monoidalComp, Category.assoc, MonoidalCoherence.hom]) <;>
    (apply (cancel_epi (𝟙 _)).1 <;> try infer_instance) <;>
    (simp (config := {failIfUnchanged := false}) only
      [assoc_liftHom, Mathlib.Tactic.BicategoryCoherence.assoc_liftHom₂])))
goal: Lean.Elab.Tactic.Tactic

full_name: Mathlib.Tactic.Coherence.liftable_prefixes
code: /--
Internal tactic used in `coherence`.

Rewrites an equation `f = g` as `f₀ ≫ f₁ = g₀ ≫ g₁`,
where `f₀` and `g₀` are maximal prefixes of `f` and `g` (possibly after reassociating)
which are "liftable" (i.e. expressible as compositions of unitors and associators).
-/
elab (name := liftable_prefixes) "liftable_prefixes" : tactic => do
  withOptions (fun opts => synthInstance.maxSize.set opts
    (max 256 (synthInstance.maxSize.get opts))) do
  evalTactic (← `(tactic|
    (simp (config := {failIfUnchanged := false}) only
      [monoidalComp, Category.assoc, MonoidalCoherence.hom]) <;>
    (apply (cancel_epi (𝟙 _)).1 <;> try infer_instance) <;>
    (simp (config := {failIfUnchanged := false}) only
      [assoc_liftHom, Mathlib.Tactic.BicategoryCoherence.assoc_liftHom₂])))
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.Coherence.insert_id_lhs
code: lemma insert_id_lhs {C : Type*} [Category C] {X Y : C} (f g : X ⟶ Y) (w : f ≫ 𝟙 _ = g) :
    f = g 
goal: f = g

full_name: Mathlib.Tactic.Coherence.insert_id_rhs
code: lemma insert_id_rhs {C : Type*} [Category C] {X Y : C} (f g : X ⟶ Y) (w : f = g ≫ 𝟙 _) :
    f = g 
goal: f = g

full_name: Mathlib.Tactic.Coherence.insertTrailingIds
code: /-- If either the lhs or rhs is not a composition, compose it on the right with an identity. -/
def insertTrailingIds (g : MVarId) : MetaM MVarId 
goal: Lean.MetaM Lean.MVarId

full_name: Mathlib.Tactic.Coherence.coherence_loop
code: /-- The main part of `coherence` tactic. -/
-- Porting note: this is an ugly port, using too many `evalTactic`s.
-- We can refactor later into either a `macro` (but the flow control is awkward)
-- or a `MetaM` tactic.
def coherence_loop (maxSteps := 37) : TacticM Unit 
goal: Lean.Elab.Tactic.TacticM Unit

full_name: Mathlib.Tactic.Coherence.monoidal_simps
code: /--
Simp lemmas for rewriting a hom in monoical categories into a normal form.
-/
syntax (name := monoidal_simps) "monoidal_simps" (config)? : tactic
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.Coherence._aux_Mathlib_Tactic_CategoryTheory_Coherence___elabRules_Mathlib_Tactic_Coherence_monoidal_simps_1
code: @[inherit_doc monoidal_simps]
elab_rules : tactic
| `(tactic| monoidal_simps $[$cfg]?) => do
  evalTactic (← `(tactic|
    simp $[$cfg]? only [
      Category.assoc, MonoidalCategory.tensor_whiskerLeft, MonoidalCategory.id_whiskerLeft,
      MonoidalCategory.whiskerRight_tensor, MonoidalCategory.whiskerRight_id,
      MonoidalCategory.whiskerLeft_comp, MonoidalCategory.whiskerLeft_id,
      MonoidalCategory.comp_whiskerRight, MonoidalCategory.id_whiskerRight,
      MonoidalCategory.whisker_assoc,
      MonoidalCategory.id_tensorHom, MonoidalCategory.tensorHom_id];
    -- I'm not sure if `tensorHom` should be expanded.
    try simp only [MonoidalCategory.tensorHom_def]
    ))
goal: Lean.Elab.Tactic.Tactic

full_name: Mathlib.Tactic.Coherence.coherence
code: /--
Use the coherence theorem for monoidal categories to solve equations in a monoidal equation,
where the two sides only differ by replacing strings of monoidal structural morphisms
(that is, associators, unitors, and identities)
with different strings of structural morphisms with the same source and target.

That is, `coherence` can handle goals of the form
`a ≫ f ≫ b ≫ g ≫ c = a' ≫ f ≫ b' ≫ g ≫ c'`
where `a = a'`, `b = b'`, and `c = c'` can be proved using `pure_coherence`.

(If you have very large equations on which `coherence` is unexpectedly failing,
you may need to increase the typeclass search depth,
using e.g. `set_option synthInstance.maxSize 500`.)
-/
syntax (name := coherence) "coherence" : tactic
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.Coherence._aux_Mathlib_Tactic_CategoryTheory_Coherence___elabRules_Mathlib_Tactic_Coherence_coherence_1
code: @[inherit_doc coherence]
elab_rules : tactic
| `(tactic| coherence) => do
  evalTactic (← `(tactic|
    (simp (config := {failIfUnchanged := false}) only [bicategoricalComp,
      BicategoricalCoherence.hom,
      monoidalComp]);
    whisker_simps (config := {failIfUnchanged := false});
    monoidal_simps (config := {failIfUnchanged := false})))
  coherence_loop
goal: Lean.Elab.Tactic.Tactic