l3lab/ntp-mathlib huggingface dataset:
theorem objSupIsoProdEqLocus_inv_eq_iff {X : TopCat.{u}} (F : X.Sheaf CommRingCat.{u})
    {U V W UW VW : Opens X} (e : W ≤ U ⊔ V) (x) (y : F.1.obj (op W))
    (h₁ : UW = U ⊓ W) (h₂ : VW = V ⊓ W) :
    F.1.map (homOfLE e).op ((F.objSupIsoProdEqLocus U V).inv x) = y ↔
    F.1.map (homOfLE (h₁ ▸ inf_le_left : UW ≤ U)).op x.1.1 =
      F.1.map (homOfLE <| h₁ ▸ inf_le_right).op y ∧
    F.1.map (homOfLE (h₂ ▸ inf_le_left : VW ≤ V)).op x.1.2 =
      F.1.map (homOfLE <| h₂ ▸ inf_le_right).op y := by
  subst h₁ h₂
  constructor
  · rintro rfl
    rw [← TopCat.Sheaf.objSupIsoProdEqLocus_inv_fst, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_snd]
    simp only [← comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp, and_self]
  · 

Proof state:
case mpr
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : ConcreteCategory C
X : TopCat
F : Sheaf CommRingCat X
U V W : Opens ↑X
e : W ≤ U ⊔ V
x :
  (CategoryTheory.forget CommRingCat).obj
    (CommRingCat.of
      ↥(RingHom.eqLocus
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ U)).op) (RingHom.fst ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ V)).op)
            (RingHom.snd ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))))
y : ↑(F.val.obj (op W))
⊢ (F.val.map (homOfLE (_ : U ⊓ W ≤ U)).op) (↑x).1 = (F.val.map (homOfLE (_ : U ⊓ W ≤ W)).op) y ∧
      (F.val.map (homOfLE (_ : V ⊓ W ≤ V)).op) (↑x).2 = (F.val.map (homOfLE (_ : V ⊓ W ≤ W)).op) y →
    (F.val.map (homOfLE e).op) ((objSupIsoProdEqLocus F U V).inv x) = y

Next tactic:
rintro ⟨e₁, e₂⟩
theorem objSupIsoProdEqLocus_inv_eq_iff {X : TopCat.{u}} (F : X.Sheaf CommRingCat.{u})
    {U V W UW VW : Opens X} (e : W ≤ U ⊔ V) (x) (y : F.1.obj (op W))
    (h₁ : UW = U ⊓ W) (h₂ : VW = V ⊓ W) :
    F.1.map (homOfLE e).op ((F.objSupIsoProdEqLocus U V).inv x) = y ↔
    F.1.map (homOfLE (h₁ ▸ inf_le_left : UW ≤ U)).op x.1.1 =
      F.1.map (homOfLE <| h₁ ▸ inf_le_right).op y ∧
    F.1.map (homOfLE (h₂ ▸ inf_le_left : VW ≤ V)).op x.1.2 =
      F.1.map (homOfLE <| h₂ ▸ inf_le_right).op y := by
  subst h₁ h₂
  constructor
  · rintro rfl
    rw [← TopCat.Sheaf.objSupIsoProdEqLocus_inv_fst, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_snd]
    simp only [← comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp, and_self]
  · rintro ⟨e₁, e₂⟩
    

Proof state:
case mpr.intro
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : ConcreteCategory C
X : TopCat
F : Sheaf CommRingCat X
U V W : Opens ↑X
e : W ≤ U ⊔ V
x :
  (CategoryTheory.forget CommRingCat).obj
    (CommRingCat.of
      ↥(RingHom.eqLocus
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ U)).op) (RingHom.fst ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ V)).op)
            (RingHom.snd ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))))
y : ↑(F.val.obj (op W))
e₁ : (F.val.map (homOfLE (_ : U ⊓ W ≤ U)).op) (↑x).1 = (F.val.map (homOfLE (_ : U ⊓ W ≤ W)).op) y
e₂ : (F.val.map (homOfLE (_ : V ⊓ W ≤ V)).op) (↑x).2 = (F.val.map (homOfLE (_ : V ⊓ W ≤ W)).op) y
⊢ (F.val.map (homOfLE e).op) ((objSupIsoProdEqLocus F U V).inv x) = y

Next tactic:
refine' F.eq_of_locally_eq₂
      (homOfLE (inf_le_right : U ⊓ W ≤ W)) (homOfLE (inf_le_right : V ⊓ W ≤ W)) _ _ _ _ _
theorem objSupIsoProdEqLocus_inv_eq_iff {X : TopCat.{u}} (F : X.Sheaf CommRingCat.{u})
    {U V W UW VW : Opens X} (e : W ≤ U ⊔ V) (x) (y : F.1.obj (op W))
    (h₁ : UW = U ⊓ W) (h₂ : VW = V ⊓ W) :
    F.1.map (homOfLE e).op ((F.objSupIsoProdEqLocus U V).inv x) = y ↔
    F.1.map (homOfLE (h₁ ▸ inf_le_left : UW ≤ U)).op x.1.1 =
      F.1.map (homOfLE <| h₁ ▸ inf_le_right).op y ∧
    F.1.map (homOfLE (h₂ ▸ inf_le_left : VW ≤ V)).op x.1.2 =
      F.1.map (homOfLE <| h₂ ▸ inf_le_right).op y := by
  subst h₁ h₂
  constructor
  · rintro rfl
    rw [← TopCat.Sheaf.objSupIsoProdEqLocus_inv_fst, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_snd]
    simp only [← comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp, and_self]
  · rintro ⟨e₁, e₂⟩
    refine' F.eq_of_locally_eq₂
      (homOfLE (inf_le_right : U ⊓ W ≤ W)) (homOfLE (inf_le_right : V ⊓ W ≤ W)) _ _ _ _ _
    · 

Proof state:
case mpr.intro.refine'_1
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : ConcreteCategory C
X : TopCat
F : Sheaf CommRingCat X
U V W : Opens ↑X
e : W ≤ U ⊔ V
x :
  (CategoryTheory.forget CommRingCat).obj
    (CommRingCat.of
      ↥(RingHom.eqLocus
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ U)).op) (RingHom.fst ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ V)).op)
            (RingHom.snd ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))))
y : ↑(F.val.obj (op W))
e₁ : (F.val.map (homOfLE (_ : U ⊓ W ≤ U)).op) (↑x).1 = (F.val.map (homOfLE (_ : U ⊓ W ≤ W)).op) y
e₂ : (F.val.map (homOfLE (_ : V ⊓ W ≤ V)).op) (↑x).2 = (F.val.map (homOfLE (_ : V ⊓ W ≤ W)).op) y
⊢ W ≤ U ⊓ W ⊔ V ⊓ W

Next tactic:
rw [← inf_sup_right]
theorem objSupIsoProdEqLocus_inv_eq_iff {X : TopCat.{u}} (F : X.Sheaf CommRingCat.{u})
    {U V W UW VW : Opens X} (e : W ≤ U ⊔ V) (x) (y : F.1.obj (op W))
    (h₁ : UW = U ⊓ W) (h₂ : VW = V ⊓ W) :
    F.1.map (homOfLE e).op ((F.objSupIsoProdEqLocus U V).inv x) = y ↔
    F.1.map (homOfLE (h₁ ▸ inf_le_left : UW ≤ U)).op x.1.1 =
      F.1.map (homOfLE <| h₁ ▸ inf_le_right).op y ∧
    F.1.map (homOfLE (h₂ ▸ inf_le_left : VW ≤ V)).op x.1.2 =
      F.1.map (homOfLE <| h₂ ▸ inf_le_right).op y := by
  subst h₁ h₂
  constructor
  · rintro rfl
    rw [← TopCat.Sheaf.objSupIsoProdEqLocus_inv_fst, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_snd]
    simp only [← comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp, and_self]
  · rintro ⟨e₁, e₂⟩
    refine' F.eq_of_locally_eq₂
      (homOfLE (inf_le_right : U ⊓ W ≤ W)) (homOfLE (inf_le_right : V ⊓ W ≤ W)) _ _ _ _ _
    · rw [← inf_sup_right]
      

Proof state:
case mpr.intro.refine'_1
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : ConcreteCategory C
X : TopCat
F : Sheaf CommRingCat X
U V W : Opens ↑X
e : W ≤ U ⊔ V
x :
  (CategoryTheory.forget CommRingCat).obj
    (CommRingCat.of
      ↥(RingHom.eqLocus
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ U)).op) (RingHom.fst ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ V)).op)
            (RingHom.snd ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))))
y : ↑(F.val.obj (op W))
e₁ : (F.val.map (homOfLE (_ : U ⊓ W ≤ U)).op) (↑x).1 = (F.val.map (homOfLE (_ : U ⊓ W ≤ W)).op) y
e₂ : (F.val.map (homOfLE (_ : V ⊓ W ≤ V)).op) (↑x).2 = (F.val.map (homOfLE (_ : V ⊓ W ≤ W)).op) y
⊢ W ≤ (U ⊔ V) ⊓ W

Next tactic:
exact le_inf e le_rfl
theorem objSupIsoProdEqLocus_inv_eq_iff {X : TopCat.{u}} (F : X.Sheaf CommRingCat.{u})
    {U V W UW VW : Opens X} (e : W ≤ U ⊔ V) (x) (y : F.1.obj (op W))
    (h₁ : UW = U ⊓ W) (h₂ : VW = V ⊓ W) :
    F.1.map (homOfLE e).op ((F.objSupIsoProdEqLocus U V).inv x) = y ↔
    F.1.map (homOfLE (h₁ ▸ inf_le_left : UW ≤ U)).op x.1.1 =
      F.1.map (homOfLE <| h₁ ▸ inf_le_right).op y ∧
    F.1.map (homOfLE (h₂ ▸ inf_le_left : VW ≤ V)).op x.1.2 =
      F.1.map (homOfLE <| h₂ ▸ inf_le_right).op y := by
  subst h₁ h₂
  constructor
  · rintro rfl
    rw [← TopCat.Sheaf.objSupIsoProdEqLocus_inv_fst, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_snd]
    simp only [← comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp, and_self]
  · rintro ⟨e₁, e₂⟩
    refine' F.eq_of_locally_eq₂
      (homOfLE (inf_le_right : U ⊓ W ≤ W)) (homOfLE (inf_le_right : V ⊓ W ≤ W)) _ _ _ _ _
    · rw [← inf_sup_right]
      exact le_inf e le_rfl
    · 

Proof state:
case mpr.intro.refine'_2
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : ConcreteCategory C
X : TopCat
F : Sheaf CommRingCat X
U V W : Opens ↑X
e : W ≤ U ⊔ V
x :
  (CategoryTheory.forget CommRingCat).obj
    (CommRingCat.of
      ↥(RingHom.eqLocus
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ U)).op) (RingHom.fst ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ V)).op)
            (RingHom.snd ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))))
y : ↑(F.val.obj (op W))
e₁ : (F.val.map (homOfLE (_ : U ⊓ W ≤ U)).op) (↑x).1 = (F.val.map (homOfLE (_ : U ⊓ W ≤ W)).op) y
e₂ : (F.val.map (homOfLE (_ : V ⊓ W ≤ V)).op) (↑x).2 = (F.val.map (homOfLE (_ : V ⊓ W ≤ W)).op) y
⊢ (F.val.map (homOfLE (_ : U ⊓ W ≤ W)).op) ((F.val.map (homOfLE e).op) ((objSupIsoProdEqLocus F U V).inv x)) =
    (F.val.map (homOfLE (_ : U ⊓ W ≤ W)).op) y

Next tactic:
rw [← e₁, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_fst]
theorem objSupIsoProdEqLocus_inv_eq_iff {X : TopCat.{u}} (F : X.Sheaf CommRingCat.{u})
    {U V W UW VW : Opens X} (e : W ≤ U ⊔ V) (x) (y : F.1.obj (op W))
    (h₁ : UW = U ⊓ W) (h₂ : VW = V ⊓ W) :
    F.1.map (homOfLE e).op ((F.objSupIsoProdEqLocus U V).inv x) = y ↔
    F.1.map (homOfLE (h₁ ▸ inf_le_left : UW ≤ U)).op x.1.1 =
      F.1.map (homOfLE <| h₁ ▸ inf_le_right).op y ∧
    F.1.map (homOfLE (h₂ ▸ inf_le_left : VW ≤ V)).op x.1.2 =
      F.1.map (homOfLE <| h₂ ▸ inf_le_right).op y := by
  subst h₁ h₂
  constructor
  · rintro rfl
    rw [← TopCat.Sheaf.objSupIsoProdEqLocus_inv_fst, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_snd]
    simp only [← comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp, and_self]
  · rintro ⟨e₁, e₂⟩
    refine' F.eq_of_locally_eq₂
      (homOfLE (inf_le_right : U ⊓ W ≤ W)) (homOfLE (inf_le_right : V ⊓ W ≤ W)) _ _ _ _ _
    · rw [← inf_sup_right]
      exact le_inf e le_rfl
    · rw [← e₁, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_fst]
      

Proof state:
case mpr.intro.refine'_2
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : ConcreteCategory C
X : TopCat
F : Sheaf CommRingCat X
U V W : Opens ↑X
e : W ≤ U ⊔ V
x :
  (CategoryTheory.forget CommRingCat).obj
    (CommRingCat.of
      ↥(RingHom.eqLocus
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ U)).op) (RingHom.fst ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ V)).op)
            (RingHom.snd ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))))
y : ↑(F.val.obj (op W))
e₁ : (F.val.map (homOfLE (_ : U ⊓ W ≤ U)).op) (↑x).1 = (F.val.map (homOfLE (_ : U ⊓ W ≤ W)).op) y
e₂ : (F.val.map (homOfLE (_ : V ⊓ W ≤ V)).op) (↑x).2 = (F.val.map (homOfLE (_ : V ⊓ W ≤ W)).op) y
⊢ (F.val.map (homOfLE (_ : U ⊓ W ≤ W)).op) ((F.val.map (homOfLE e).op) ((objSupIsoProdEqLocus F U V).inv x)) =
    (F.val.map (homOfLE (_ : U ⊓ W ≤ U)).op)
      ((F.val.map (homOfLE (_ : U ≤ U ⊔ V)).op) ((objSupIsoProdEqLocus F U V).inv x))

Next tactic:
simp only [← comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp]
theorem objSupIsoProdEqLocus_inv_eq_iff {X : TopCat.{u}} (F : X.Sheaf CommRingCat.{u})
    {U V W UW VW : Opens X} (e : W ≤ U ⊔ V) (x) (y : F.1.obj (op W))
    (h₁ : UW = U ⊓ W) (h₂ : VW = V ⊓ W) :
    F.1.map (homOfLE e).op ((F.objSupIsoProdEqLocus U V).inv x) = y ↔
    F.1.map (homOfLE (h₁ ▸ inf_le_left : UW ≤ U)).op x.1.1 =
      F.1.map (homOfLE <| h₁ ▸ inf_le_right).op y ∧
    F.1.map (homOfLE (h₂ ▸ inf_le_left : VW ≤ V)).op x.1.2 =
      F.1.map (homOfLE <| h₂ ▸ inf_le_right).op y := by
  subst h₁ h₂
  constructor
  · rintro rfl
    rw [← TopCat.Sheaf.objSupIsoProdEqLocus_inv_fst, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_snd]
    simp only [← comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp, and_self]
  · rintro ⟨e₁, e₂⟩
    refine' F.eq_of_locally_eq₂
      (homOfLE (inf_le_right : U ⊓ W ≤ W)) (homOfLE (inf_le_right : V ⊓ W ≤ W)) _ _ _ _ _
    · rw [← inf_sup_right]
      exact le_inf e le_rfl
    · rw [← e₁, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_fst]
      simp only [← comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp]
    · 

Proof state:
case mpr.intro.refine'_3
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : ConcreteCategory C
X : TopCat
F : Sheaf CommRingCat X
U V W : Opens ↑X
e : W ≤ U ⊔ V
x :
  (CategoryTheory.forget CommRingCat).obj
    (CommRingCat.of
      ↥(RingHom.eqLocus
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ U)).op) (RingHom.fst ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ V)).op)
            (RingHom.snd ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))))
y : ↑(F.val.obj (op W))
e₁ : (F.val.map (homOfLE (_ : U ⊓ W ≤ U)).op) (↑x).1 = (F.val.map (homOfLE (_ : U ⊓ W ≤ W)).op) y
e₂ : (F.val.map (homOfLE (_ : V ⊓ W ≤ V)).op) (↑x).2 = (F.val.map (homOfLE (_ : V ⊓ W ≤ W)).op) y
⊢ (F.val.map (homOfLE (_ : V ⊓ W ≤ W)).op) ((F.val.map (homOfLE e).op) ((objSupIsoProdEqLocus F U V).inv x)) =
    (F.val.map (homOfLE (_ : V ⊓ W ≤ W)).op) y

Next tactic:
rw [← e₂, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_snd]
theorem objSupIsoProdEqLocus_inv_eq_iff {X : TopCat.{u}} (F : X.Sheaf CommRingCat.{u})
    {U V W UW VW : Opens X} (e : W ≤ U ⊔ V) (x) (y : F.1.obj (op W))
    (h₁ : UW = U ⊓ W) (h₂ : VW = V ⊓ W) :
    F.1.map (homOfLE e).op ((F.objSupIsoProdEqLocus U V).inv x) = y ↔
    F.1.map (homOfLE (h₁ ▸ inf_le_left : UW ≤ U)).op x.1.1 =
      F.1.map (homOfLE <| h₁ ▸ inf_le_right).op y ∧
    F.1.map (homOfLE (h₂ ▸ inf_le_left : VW ≤ V)).op x.1.2 =
      F.1.map (homOfLE <| h₂ ▸ inf_le_right).op y := by
  subst h₁ h₂
  constructor
  · rintro rfl
    rw [← TopCat.Sheaf.objSupIsoProdEqLocus_inv_fst, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_snd]
    simp only [← comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp, and_self]
  · rintro ⟨e₁, e₂⟩
    refine' F.eq_of_locally_eq₂
      (homOfLE (inf_le_right : U ⊓ W ≤ W)) (homOfLE (inf_le_right : V ⊓ W ≤ W)) _ _ _ _ _
    · rw [← inf_sup_right]
      exact le_inf e le_rfl
    · rw [← e₁, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_fst]
      simp only [← comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp]
    · rw [← e₂, ← TopCat.Sheaf.objSupIsoProdEqLocus_inv_snd]
      

Proof state:
case mpr.intro.refine'_3
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : ConcreteCategory C
X : TopCat
F : Sheaf CommRingCat X
U V W : Opens ↑X
e : W ≤ U ⊔ V
x :
  (CategoryTheory.forget CommRingCat).obj
    (CommRingCat.of
      ↥(RingHom.eqLocus
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ U)).op) (RingHom.fst ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))
          (RingHom.comp (F.val.map (homOfLE (_ : U ⊓ V ≤ V)).op)
            (RingHom.snd ↑(F.val.obj (op U)) ↑(F.val.obj (op V))))))
y : ↑(F.val.obj (op W))
e₁ : (F.val.map (homOfLE (_ : U ⊓ W ≤ U)).op) (↑x).1 = (F.val.map (homOfLE (_ : U ⊓ W ≤ W)).op) y
e₂ : (F.val.map (homOfLE (_ : V ⊓ W ≤ V)).op) (↑x).2 = (F.val.map (homOfLE (_ : V ⊓ W ≤ W)).op) y
⊢ (F.val.map (homOfLE (_ : V ⊓ W ≤ W)).op) ((F.val.map (homOfLE e).op) ((objSupIsoProdEqLocus F U V).inv x)) =
    (F.val.map (homOfLE (_ : V ⊓ W ≤ V)).op)
      ((F.val.map (homOfLE (_ : V ≤ U ⊔ V)).op) ((objSupIsoProdEqLocus F U V).inv x))

Next tactic:
simp only [← comp_apply, ← Functor.map_comp, ← op_comp, Category.assoc, homOfLE_comp]
/-- Given candidate data for an exact pairing,
which is sent by a faithful monoidal functor to an exact pairing,
the equations holds automatically. -/
def exactPairingOfFaithful [Faithful F.toFunctor] {X Y : C} (eval : Y ⊗ X ⟶ 𝟙_ C)
    (coeval : 𝟙_ C ⟶ X ⊗ Y) [ExactPairing (F.obj X) (F.obj Y)]
    (map_eval : F.map eval = inv (F.μ _ _) ≫ ε_ _ _ ≫ F.ε)
    (map_coeval : F.map coeval = inv F.ε ≫ η_ _ _ ≫ F.μ _ _) : ExactPairing X Y where
  evaluation' := eval
  coevaluation' := coeval
  evaluation_coevaluation' :=
    F.toFunctor.map_injective (by simp [map_eval, map_coeval, MonoidalFunctor.map_tensor])
  coevaluation_evaluation' :=
    F.toFunctor.map_injective (by 

Proof state:
C : Type u_1
D : Type u_2
inst✝⁵ : Category.{?u.135, u_1} C
inst✝⁴ : Category.{?u.139, u_2} D
inst✝³ : MonoidalCategory C
inst✝² : MonoidalCategory D
F : MonoidalFunctor C D
inst✝¹ : Faithful F.toFunctor
X Y : C
eval : Y ⊗ X ⟶ 𝟙_ C
coeval : 𝟙_ C ⟶ X ⊗ Y
inst✝ : ExactPairing (F.obj X) (F.obj Y)
map_eval : F.map eval = inv (LaxMonoidalFunctor.μ F.toLaxMonoidalFunctor Y X) ≫ ε_ (F.obj X) (F.obj Y) ≫ F.ε
map_coeval : F.map coeval = inv F.ε ≫ η_ (F.obj X) (F.obj Y) ≫ LaxMonoidalFunctor.μ F.toLaxMonoidalFunctor X Y
⊢ F.map ((𝟙 Y ⊗ coeval) ≫ (α_ Y X Y).inv ≫ (eval ⊗ 𝟙 Y)) = F.map ((ρ_ Y).hom ≫ (λ_ Y).inv)

Next tactic:
simp [map_eval, map_coeval, MonoidalFunctor.map_tensor]
/-- Given candidate data for an exact pairing,
which is sent by a faithful monoidal functor to an exact pairing,
the equations holds automatically. -/
def exactPairingOfFaithful [Faithful F.toFunctor] {X Y : C} (eval : Y ⊗ X ⟶ 𝟙_ C)
    (coeval : 𝟙_ C ⟶ X ⊗ Y) [ExactPairing (F.obj X) (F.obj Y)]
    (map_eval : F.map eval = inv (F.μ _ _) ≫ ε_ _ _ ≫ F.ε)
    (map_coeval : F.map coeval = inv F.ε ≫ η_ _ _ ≫ F.μ _ _) : ExactPairing X Y where
  evaluation' := eval
  coevaluation' := coeval
  evaluation_coevaluation' :=
    F.toFunctor.map_injective (by 

Proof state:
C : Type u_1
D : Type u_2
inst✝⁵ : Category.{?u.135, u_1} C
inst✝⁴ : Category.{?u.139, u_2} D
inst✝³ : MonoidalCategory C
inst✝² : MonoidalCategory D
F : MonoidalFunctor C D
inst✝¹ : Faithful F.toFunctor
X Y : C
eval : Y ⊗ X ⟶ 𝟙_ C
coeval : 𝟙_ C ⟶ X ⊗ Y
inst✝ : ExactPairing (F.obj X) (F.obj Y)
map_eval : F.map eval = inv (LaxMonoidalFunctor.μ F.toLaxMonoidalFunctor Y X) ≫ ε_ (F.obj X) (F.obj Y) ≫ F.ε
map_coeval : F.map coeval = inv F.ε ≫ η_ (F.obj X) (F.obj Y) ≫ LaxMonoidalFunctor.μ F.toLaxMonoidalFunctor X Y
⊢ F.map ((coeval ⊗ 𝟙 X) ≫ (α_ X Y X).hom ≫ (𝟙 X ⊗ eval)) = F.map ((λ_ X).hom ≫ (ρ_ X).inv)

Next tactic:
simp [map_eval, map_coeval, MonoidalFunctor.map_tensor]
/-- Given a pair of objects which are sent by a fully faithful functor to a pair of objects
with an exact pairing, we get an exact pairing.
-/
def exactPairingOfFullyFaithful [Full F.toFunctor] [Faithful F.toFunctor] (X Y : C)
    [ExactPairing (F.obj X) (F.obj Y)] : ExactPairing X Y :=
  exactPairingOfFaithful F (F.toFunctor.preimage (inv (F.μ _ _) ≫ ε_ _ _ ≫ F.ε))
    (F.toFunctor.preimage (inv F.ε ≫ η_ _ _ ≫ F.μ _ _)) (by 

Proof state:
C : Type u_1
D : Type u_2
inst✝⁶ : Category.{?u.26286, u_1} C
inst✝⁵ : Category.{?u.26290, u_2} D
inst✝⁴ : MonoidalCategory C
inst✝³ : MonoidalCategory D
F : MonoidalFunctor C D
inst✝² : Full F.toFunctor
inst✝¹ : Faithful F.toFunctor
X Y : C
inst✝ : ExactPairing (F.obj X) (F.obj Y)
⊢ F.map (F.preimage (inv (LaxMonoidalFunctor.μ F.toLaxMonoidalFunctor Y X) ≫ ε_ (F.obj X) (F.obj Y) ≫ F.ε)) =
    inv (LaxMonoidalFunctor.μ F.toLaxMonoidalFunctor Y X) ≫ ε_ (F.obj X) (F.obj Y) ≫ F.ε

Next tactic:
simp
/-- Given a pair of objects which are sent by a fully faithful functor to a pair of objects
with an exact pairing, we get an exact pairing.
-/
def exactPairingOfFullyFaithful [Full F.toFunctor] [Faithful F.toFunctor] (X Y : C)
    [ExactPairing (F.obj X) (F.obj Y)] : ExactPairing X Y :=
  exactPairingOfFaithful F (F.toFunctor.preimage (inv (F.μ _ _) ≫ ε_ _ _ ≫ F.ε))
    (F.toFunctor.preimage (inv F.ε ≫ η_ _ _ ≫ F.μ _ _)) (by simp) (by 

Proof state:
C : Type u_1
D : Type u_2
inst✝⁶ : Category.{?u.26286, u_1} C
inst✝⁵ : Category.{?u.26290, u_2} D
inst✝⁴ : MonoidalCategory C
inst✝³ : MonoidalCategory D
F : MonoidalFunctor C D
inst✝² : Full F.toFunctor
inst✝¹ : Faithful F.toFunctor
X Y : C
inst✝ : ExactPairing (F.obj X) (F.obj Y)
⊢ F.map (F.preimage (inv F.ε ≫ η_ (F.obj X) (F.obj Y) ≫ LaxMonoidalFunctor.μ F.toLaxMonoidalFunctor X Y)) =
    inv F.ε ≫ η_ (F.obj X) (F.obj Y) ≫ LaxMonoidalFunctor.μ F.toLaxMonoidalFunctor X Y

Next tactic:
simp
/-- Pull back a left dual along an equivalence. -/
def hasLeftDualOfEquivalence [IsEquivalence F.toFunctor] (X : C) [HasLeftDual (F.obj X)] :
    HasLeftDual X where
  leftDual := F.toFunctor.inv.obj (ᘁ(F.obj X))
  exact := by
    -- porting note: in Lean3, `apply exactPairingOfFullyFaithful F _ _` automatically
    -- created the goals for `ExactPairing` type class
    

Proof state:
C : Type u_1
D : Type u_2
inst✝⁵ : Category.{?u.30945, u_1} C
inst✝⁴ : Category.{?u.30949, u_2} D
inst✝³ : MonoidalCategory C
inst✝² : MonoidalCategory D
F : MonoidalFunctor C D
inst✝¹ : IsEquivalence F.toFunctor
X : C
inst✝ : HasLeftDual (F.obj X)
⊢ ExactPairing ((Functor.inv F.toFunctor).obj ᘁ(F.obj X)) X

Next tactic:
refine @exactPairingOfFullyFaithful _ _ _ _ _ _ F _ _ _ _ ?_
/-- Pull back a left dual along an equivalence. -/
def hasLeftDualOfEquivalence [IsEquivalence F.toFunctor] (X : C) [HasLeftDual (F.obj X)] :
    HasLeftDual X where
  leftDual := F.toFunctor.inv.obj (ᘁ(F.obj X))
  exact := by
    -- porting note: in Lean3, `apply exactPairingOfFullyFaithful F _ _` automatically
    -- created the goals for `ExactPairing` type class
    refine @exactPairingOfFullyFaithful _ _ _ _ _ _ F _ _ _ _ ?_
    

Proof state:
C : Type u_1
D : Type u_2
inst✝⁵ : Category.{?u.30945, u_1} C
inst✝⁴ : Category.{?u.30949, u_2} D
inst✝³ : MonoidalCategory C
inst✝² : MonoidalCategory D
F : MonoidalFunctor C D
inst✝¹ : IsEquivalence F.toFunctor
X : C
inst✝ : HasLeftDual (F.obj X)
⊢ ExactPairing (F.obj ((Functor.inv F.toFunctor).obj ᘁ(F.obj X))) (F.obj X)

Next tactic:
refine @exactPairingCongrLeft _ _ _ _ _ _ ?_ (F.toFunctor.asEquivalence.counitIso.app _)
/-- Pull back a left dual along an equivalence. -/
def hasLeftDualOfEquivalence [IsEquivalence F.toFunctor] (X : C) [HasLeftDual (F.obj X)] :
    HasLeftDual X where
  leftDual := F.toFunctor.inv.obj (ᘁ(F.obj X))
  exact := by
    -- porting note: in Lean3, `apply exactPairingOfFullyFaithful F _ _` automatically
    -- created the goals for `ExactPairing` type class
    refine @exactPairingOfFullyFaithful _ _ _ _ _ _ F _ _ _ _ ?_
    refine @exactPairingCongrLeft _ _ _ _ _ _ ?_ (F.toFunctor.asEquivalence.counitIso.app _)
    

Proof state:
C : Type u_1
D : Type u_2
inst✝⁵ : Category.{?u.30945, u_1} C
inst✝⁴ : Category.{?u.30949, u_2} D
inst✝³ : MonoidalCategory C
inst✝² : MonoidalCategory D
F : MonoidalFunctor C D
inst✝¹ : IsEquivalence F.toFunctor
X : C
inst✝ : HasLeftDual (F.obj X)
⊢ ExactPairing ((𝟭 D).obj ᘁ(F.obj X)) (F.obj X)

Next tactic:
dsimp
/-- Pull back a left dual along an equivalence. -/
def hasLeftDualOfEquivalence [IsEquivalence F.toFunctor] (X : C) [HasLeftDual (F.obj X)] :
    HasLeftDual X where
  leftDual := F.toFunctor.inv.obj (ᘁ(F.obj X))
  exact := by
    -- porting note: in Lean3, `apply exactPairingOfFullyFaithful F _ _` automatically
    -- created the goals for `ExactPairing` type class
    refine @exactPairingOfFullyFaithful _ _ _ _ _ _ F _ _ _ _ ?_
    refine @exactPairingCongrLeft _ _ _ _ _ _ ?_ (F.toFunctor.asEquivalence.counitIso.app _)
    dsimp
    

Proof state:
C : Type u_1
D : Type u_2
inst✝⁵ : Category.{?u.30945, u_1} C
inst✝⁴ : Category.{?u.30949, u_2} D
inst✝³ : MonoidalCategory C
inst✝² : MonoidalCategory D
F : MonoidalFunctor C D
inst✝¹ : IsEquivalence F.toFunctor
X : C
inst✝ : HasLeftDual (F.obj X)
⊢ ExactPairing (ᘁ(F.obj X)) (F.obj X)

Next tactic:
infer_instance
/-- Pull back a right dual along an equivalence. -/
def hasRightDualOfEquivalence [IsEquivalence F.toFunctor] (X : C) [HasRightDual (F.obj X)] :
    HasRightDual X where
  rightDual := F.toFunctor.inv.obj ((F.obj X)ᘁ)
  exact := by
    

Proof state:
C : Type u_1
D : Type u_2
inst✝⁵ : Category.{?u.34458, u_1} C
inst✝⁴ : Category.{?u.34462, u_2} D
inst✝³ : MonoidalCategory C
inst✝² : MonoidalCategory D
F : MonoidalFunctor C D
inst✝¹ : IsEquivalence F.toFunctor
X : C
inst✝ : HasRightDual (F.obj X)
⊢ ExactPairing X ((Functor.inv F.toFunctor).obj (F.obj X)ᘁ)

Next tactic:
refine @exactPairingOfFullyFaithful _ _ _ _ _ _ F _ _ _ _ ?_
/-- Pull back a right dual along an equivalence. -/
def hasRightDualOfEquivalence [IsEquivalence F.toFunctor] (X : C) [HasRightDual (F.obj X)] :
    HasRightDual X where
  rightDual := F.toFunctor.inv.obj ((F.obj X)ᘁ)
  exact := by
    refine @exactPairingOfFullyFaithful _ _ _ _ _ _ F _ _ _ _ ?_
    

Proof state:
C : Type u_1
D : Type u_2
inst✝⁵ : Category.{?u.34458, u_1} C
inst✝⁴ : Category.{?u.34462, u_2} D
inst✝³ : MonoidalCategory C
inst✝² : MonoidalCategory D
F : MonoidalFunctor C D
inst✝¹ : IsEquivalence F.toFunctor
X : C
inst✝ : HasRightDual (F.obj X)
⊢ ExactPairing (F.obj X) (F.obj ((Functor.inv F.toFunctor).obj (F.obj X)ᘁ))

Next tactic:
refine @exactPairingCongrRight _ _ _ _ _ _ ?_ (F.toFunctor.asEquivalence.counitIso.app _)