Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - feat: left and right homology data are dual notions #5674

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
174 changes: 171 additions & 3 deletions Mathlib/Algebra/Homology/ShortComplex/RightHomology.lean
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Authors: Joël Riou
-/

import Mathlib.Algebra.Homology.ShortComplex.LeftHomology
import Mathlib.CategoryTheory.Limits.Opposites

/-! RightHomology of short complexes

Expand Down Expand Up @@ -32,7 +33,7 @@ open Category Limits
namespace ShortComplex

variable {C : Type _} [Category C] [HasZeroMorphisms C]
(S : ShortComplex C)
(S : ShortComplex C) {S₁ S₂ S₃ : ShortComplex C}

/-- A right homology data for a short complex `S` consists of morphisms `p : S.X₂ ⟶ Q` and
`ι : H ⟶ Q` such that `p` identifies `Q` to the kernel of `f : S.X₁ ⟶ S.X₂`,
Expand Down Expand Up @@ -209,8 +210,8 @@ lemma ofZeros_g' (hf : S.f = 0) (hg : S.g = 0) :
end RightHomologyData

/-- A short complex `S` has right homology when there exists a `S.RightHomologyData` -/
class HasRightHomology : Prop :=
(condition : Nonempty S.RightHomologyData)
class HasRightHomology : Prop where
condition : Nonempty S.RightHomologyData

/-- A chosen `S.RightHomologyData` for a short complex `S` that has right homology -/
noncomputable def rightHomologyData [HasRightHomology S] :
Expand Down Expand Up @@ -240,6 +241,173 @@ instance of_zeros (X Y Z : C) :

end HasRightHomology

namespace RightHomologyData

/-- A right homology data for a short complex `S` induces a left homology data for `S.op`. -/
@[simps]
def op (h : S.RightHomologyData) : S.op.LeftHomologyData where
K := Opposite.op h.Q
H := Opposite.op h.H
i := h.p.op
π := h.ι.op
wi := Quiver.Hom.unop_inj h.wp
hi := CokernelCofork.IsColimit.ofπOp _ _ h.hp
wπ := Quiver.Hom.unop_inj h.wι
hπ := KernelFork.IsLimit.ofιOp _ _ h.hι

@[simp] lemma op_f' (h : S.RightHomologyData) :
h.op.f' = h.g'.op := rfl

/-- A right homology data for a short complex `S` in the opposite category
induces a left homology data for `S.unop`. -/
@[simps]
def unop {S : ShortComplex Cᵒᵖ} (h : S.RightHomologyData) : S.unop.LeftHomologyData where
K := Opposite.unop h.Q
H := Opposite.unop h.H
i := h.p.unop
π := h.ι.unop
wi := Quiver.Hom.op_inj h.wp
hi := CokernelCofork.IsColimit.ofπUnop _ _ h.hp
wπ := Quiver.Hom.op_inj h.wι
hπ := KernelFork.IsLimit.ofιUnop _ _ h.hι

@[simp] lemma unop_f' {S : ShortComplex Cᵒᵖ} (h : S.RightHomologyData) :
h.unop.f' = h.g'.unop := rfl

end RightHomologyData

namespace LeftHomologyData

/-- A left homology data for a short complex `S` induces a right homology data for `S.op`. -/
@[simps]
def op (h : S.LeftHomologyData) : S.op.RightHomologyData where
Q := Opposite.op h.K
H := Opposite.op h.H
p := h.i.op
ι := h.π.op
wp := Quiver.Hom.unop_inj h.wi
hp := KernelFork.IsLimit.ofιOp _ _ h.hi
wι := Quiver.Hom.unop_inj h.wπ
hι := CokernelCofork.IsColimit.ofπOp _ _ h.hπ

@[simp] lemma op_g' (h : S.LeftHomologyData) :
h.op.g' = h.f'.op := rfl

/-- A left homology data for a short complex `S` in the opposite category
induces a right homology data for `S.unop`. -/
@[simps]
def unop {S : ShortComplex Cᵒᵖ} (h : S.LeftHomologyData) : S.unop.RightHomologyData where
Q := Opposite.unop h.K
H := Opposite.unop h.H
p := h.i.unop
ι := h.π.unop
wp := Quiver.Hom.op_inj h.wi
hp := KernelFork.IsLimit.ofιUnop _ _ h.hi
wι := Quiver.Hom.op_inj h.wπ
hι := CokernelCofork.IsColimit.ofπUnop _ _ h.hπ

@[simp] lemma unop_g' {S : ShortComplex Cᵒᵖ} (h : S.LeftHomologyData) :
h.unop.g' = h.f'.unop := rfl

end LeftHomologyData

instance [S.HasLeftHomology] : HasRightHomology S.op :=
HasRightHomology.mk' S.leftHomologyData.op

instance [S.HasRightHomology] : HasLeftHomology S.op :=
HasLeftHomology.mk' S.rightHomologyData.op

lemma hasLeftHomology_iff_op (S : ShortComplex C) :
S.HasLeftHomology ↔ S.op.HasRightHomology :=
⟨fun _ => inferInstance, fun _ => HasLeftHomology.mk' S.op.rightHomologyData.unop⟩

lemma hasRightHomology_iff_op (S : ShortComplex C) :
S.HasRightHomology ↔ S.op.HasLeftHomology :=
⟨fun _ => inferInstance, fun _ => HasRightHomology.mk' S.op.leftHomologyData.unop⟩

lemma hasLeftHomology_iff_unop (S : ShortComplex Cᵒᵖ) :
S.HasLeftHomology ↔ S.unop.HasRightHomology :=
S.unop.hasRightHomology_iff_op.symm

lemma hasRightHomology_iff_unop (S : ShortComplex Cᵒᵖ) :
S.HasRightHomology ↔ S.unop.HasLeftHomology :=
S.unop.hasLeftHomology_iff_op.symm

section

variable (φ : S₁ ⟶ S₂) (h₁ : S₁.RightHomologyData) (h₂ : S₂.RightHomologyData)

/-- Given right homology data `h₁` and `h₂` for two short complexes `S₁` and `S₂`,
a `RightHomologyMapData` for a morphism `φ : S₁ ⟶ S₂`
consists of a description of the induced morphisms on the `Q` (opcycles)
and `H` (right homology) fields of `h₁` and `h₂`. -/
structure RightHomologyMapData where
/-- the induced map on opcycles -/
φQ : h₁.Q ⟶ h₂.Q
/-- the induced map on right homology -/
φH : h₁.H ⟶ h₂.H
/-- commutation with `p` -/
commp : h₁.p ≫ φQ = φ.τ₂ ≫ h₂.p := by aesop_cat
/-- commutation with `g'` -/
commg' : φQ ≫ h₂.g' = h₁.g' ≫ φ.τ₃ := by aesop_cat
/-- commutation with `ι` -/
commι : φH ≫ h₂.ι = h₁.ι ≫ φQ := by aesop_cat

namespace RightHomologyMapData

attribute [reassoc (attr := simp)] commp commg' commι
attribute [nolint simpNF] mk.injEq

/-- The right homology map data associated to the zero morphism between two short complexes. -/
@[simps]
def zero (h₁ : S₁.RightHomologyData) (h₂ : S₂.RightHomologyData) :
RightHomologyMapData 0 h₁ h₂ where
φQ := 0
φH := 0

/-- The right homology map data associated to the identity morphism of a short complex. -/
@[simps]
def id (h : S.RightHomologyData) : RightHomologyMapData (𝟙 S) h h where
φQ := 𝟙 _
φH := 𝟙 _

/-- The composition of right homology map data. -/
@[simps]
def comp {φ : S₁ ⟶ S₂} {φ' : S₂ ⟶ S₃} {h₁ : S₁.RightHomologyData}
{h₂ : S₂.RightHomologyData} {h₃ : S₃.RightHomologyData}
(ψ : RightHomologyMapData φ h₁ h₂) (ψ' : RightHomologyMapData φ' h₂ h₃) :
RightHomologyMapData (φ ≫ φ') h₁ h₃ where
φQ := ψ.φQ ≫ ψ'.φQ
φH := ψ.φH ≫ ψ'.φH

instance : Subsingleton (RightHomologyMapData φ h₁ h₂) :=
⟨fun ψ₁ ψ₂ => by
have hQ : ψ₁.φQ = ψ₂.φQ := by rw [← cancel_epi h₁.p, commp, commp]
have hH : ψ₁.φH = ψ₂.φH := by rw [← cancel_mono h₂.ι, commι, commι, hQ]
cases ψ₁
cases ψ₂
congr⟩

instance : Inhabited (RightHomologyMapData φ h₁ h₂) := ⟨by
let φQ : h₁.Q ⟶ h₂.Q := h₁.descQ (φ.τ₂ ≫ h₂.p) (by rw [← φ.comm₁₂_assoc, h₂.wp, comp_zero])
have commg' : φQ ≫ h₂.g' = h₁.g' ≫ φ.τ₃ :=
by rw [← cancel_epi h₁.p, RightHomologyData.p_descQ_assoc, assoc,
RightHomologyData.p_g', φ.comm₂₃, RightHomologyData.p_g'_assoc]
let φH : h₁.H ⟶ h₂.H := h₂.liftH (h₁.ι ≫ φQ)
(by rw [assoc, commg', RightHomologyData.ι_g'_assoc, zero_comp])
exact ⟨φQ, φH, by simp, commg', by simp⟩⟩

instance : Unique (RightHomologyMapData φ h₁ h₂) := Unique.mk' _

variable {φ h₁ h₂}

lemma congr_φH {γ₁ γ₂ : RightHomologyMapData φ h₁ h₂} (eq : γ₁ = γ₂) : γ₁.φH = γ₂.φH := by rw [eq]
lemma congr_φQ {γ₁ γ₂ : RightHomologyMapData φ h₁ h₂} (eq : γ₁ = γ₂) : γ₁.φQ = γ₂.φQ := by rw [eq]

end RightHomologyMapData

end

end ShortComplex

end CategoryTheory
51 changes: 51 additions & 0 deletions Mathlib/CategoryTheory/Limits/Opposites.lean
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Authors: Scott Morrison, Floris van Doorn
-/
import Mathlib.CategoryTheory.Limits.Filtered
import Mathlib.CategoryTheory.Limits.Shapes.FiniteProducts
import Mathlib.CategoryTheory.Limits.Shapes.Kernels
import Mathlib.CategoryTheory.DiscreteCategory

#align_import category_theory.limits.opposites from "leanprover-community/mathlib"@"ac3ae212f394f508df43e37aa093722fa9b65d31"
Expand Down Expand Up @@ -707,4 +708,54 @@ theorem pushoutIsoUnopPullback_inv_snd {X Y Z : C} (f : X ⟶ Z) (g : X ⟶ Y) [

end Pushout

section HasZeroMorphisms

variable [HasZeroMorphisms C]

/-- A colimit cokernel cofork gives a limit kernel fork in the opposite category -/
def CokernelCofork.IsColimit.ofπOp {X Y Q : C} (p : Y ⟶ Q) {f : X ⟶ Y}
(w : f ≫ p = 0) (h : IsColimit (CokernelCofork.ofπ p w)) :
IsLimit (KernelFork.ofι p.op (show p.op ≫ f.op = 0 by rw [← op_comp, w, op_zero])) :=
KernelFork.IsLimit.ofι _ _
(fun x hx => (h.desc (CokernelCofork.ofπ x.unop (Quiver.Hom.op_inj hx))).op)
(fun x hx => Quiver.Hom.unop_inj (Cofork.IsColimit.π_desc h))
(fun x hx b hb => Quiver.Hom.unop_inj (Cofork.IsColimit.hom_ext h
(by simpa only [Quiver.Hom.unop_op, Cofork.IsColimit.π_desc] using Quiver.Hom.op_inj hb)))

/-- A colimit cokernel cofork in the opposite category gives a limit kernel fork
in the original category -/
def CokernelCofork.IsColimit.ofπUnop {X Y Q : Cᵒᵖ} (p : Y ⟶ Q) {f : X ⟶ Y}
(w : f ≫ p = 0) (h : IsColimit (CokernelCofork.ofπ p w)) :
IsLimit (KernelFork.ofι p.unop (show p.unop ≫ f.unop = 0 by rw [← unop_comp, w, unop_zero])) :=
KernelFork.IsLimit.ofι _ _
(fun x hx => (h.desc (CokernelCofork.ofπ x.op (Quiver.Hom.unop_inj hx))).unop)
(fun x hx => Quiver.Hom.op_inj (Cofork.IsColimit.π_desc h))
(fun x hx b hb => Quiver.Hom.op_inj (Cofork.IsColimit.hom_ext h
(by simpa only [Quiver.Hom.op_unop, Cofork.IsColimit.π_desc] using Quiver.Hom.unop_inj hb)))

/-- A limit kernel fork gives a colimit cokernel cofork in the opposite category -/
def KernelFork.IsLimit.ofιOp {K X Y : C} (i : K ⟶ X) {f : X ⟶ Y}
(w : i ≫ f = 0) (h : IsLimit (KernelFork.ofι i w)) :
IsColimit (CokernelCofork.ofπ i.op
(show f.op ≫ i.op = 0 by rw [← op_comp, w, op_zero])) :=
CokernelCofork.IsColimit.ofπ _ _
(fun x hx => (h.lift (KernelFork.ofι x.unop (Quiver.Hom.op_inj hx))).op)
(fun x hx => Quiver.Hom.unop_inj (Fork.IsLimit.lift_ι h))
(fun x hx b hb => Quiver.Hom.unop_inj (Fork.IsLimit.hom_ext h (by
simpa only [Quiver.Hom.unop_op, Fork.IsLimit.lift_ι] using Quiver.Hom.op_inj hb)))

/-- A limit kernel fork in the opposite category gives a colimit cokernel cofork
in the original category -/
def KernelFork.IsLimit.ofιUnop {K X Y : Cᵒᵖ} (i : K ⟶ X) {f : X ⟶ Y}
(w : i ≫ f = 0) (h : IsLimit (KernelFork.ofι i w)) :
IsColimit (CokernelCofork.ofπ i.unop
(show f.unop ≫ i.unop = 0 by rw [← unop_comp, w, unop_zero])) :=
CokernelCofork.IsColimit.ofπ _ _
(fun x hx => (h.lift (KernelFork.ofι x.op (Quiver.Hom.unop_inj hx))).unop)
(fun x hx => Quiver.Hom.op_inj (Fork.IsLimit.lift_ι h))
(fun x hx b hb => Quiver.Hom.op_inj (Fork.IsLimit.hom_ext h (by
simpa only [Quiver.Hom.op_unop, Fork.IsLimit.lift_ι] using Quiver.Hom.unop_inj hb)))

end HasZeroMorphisms

end CategoryTheory.Limits
6 changes: 6 additions & 0 deletions Mathlib/CategoryTheory/Limits/Shapes/ZeroMorphisms.lean
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ section

variable [HasZeroMorphisms C]

@[simp] lemma op_zero (X Y : C) : (0 : X ⟶ Y).op = 0 := rfl
#align category_theory.op_zero CategoryTheory.Limits.op_zero

@[simp] lemma unop_zero (X Y : Cᵒᵖ) : (0 : X ⟶ Y).unop = 0 := rfl
#align category_theory.unop_zero CategoryTheory.Limits.unop_zero

theorem zero_of_comp_mono {X Y Z : C} {f : X ⟶ Y} (g : Y ⟶ Z) [Mono g] (h : f ≫ g = 0) : f = 0 := by
rw [← zero_comp, cancel_mono] at h
exact h
Expand Down
10 changes: 0 additions & 10 deletions Mathlib/CategoryTheory/Preadditive/Opposite.lean
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@ instance moduleEndLeft {X : Cᵒᵖ} {Y : C} : Module (End X) (unop X ⟶ Y) whe
zero_smul _ := Limits.zero_comp
#align category_theory.module_End_left CategoryTheory.moduleEndLeft

@[simp]
theorem unop_zero (X Y : Cᵒᵖ) : (0 : X ⟶ Y).unop = 0 :=
rfl
#align category_theory.unop_zero CategoryTheory.unop_zero

@[simp]
theorem unop_add {X Y : Cᵒᵖ} (f g : X ⟶ Y) : (f + g).unop = f.unop + g.unop :=
rfl
Expand All @@ -52,11 +47,6 @@ theorem unop_neg {X Y : Cᵒᵖ} (f : X ⟶ Y) : (-f).unop = -f.unop :=
rfl
#align category_theory.unop_neg CategoryTheory.unop_neg

@[simp]
theorem op_zero (X Y : C) : (0 : X ⟶ Y).op = 0 :=
rfl
#align category_theory.op_zero CategoryTheory.op_zero

@[simp]
theorem op_add {X Y : C} (f g : X ⟶ Y) : (f + g).op = f.op + g.op :=
rfl
Expand Down