Skip to content
The Lumenary

Formal mathematics laboratory

Lumenary.LimitsColimits

Limits and colimits

Formal library

  • equalizer_universaltheoremProved here from basic factsQuot.sound
    equalizer_universalLean 4Proved here from basic factsFormally verified
    /-- **The equaliser in the category of types** of `f g : X → Y` is the subtype
    `{x // f x = g x}` with its inclusion. Universal property: every `h : W → X` with
    `f ∘ h = g ∘ h` factors through the inclusion by exactly one map `u`, namely
    `u w = ⟨h w, _⟩`; uniqueness holds because an element of a subtype is determined by its value. -/
    theorem equalizer_universal (f g : X → Y) (h : W → X) (hh : f ∘ h = g ∘ h) :
        ∃! u : W → {x : X // f x = g x}, Subtype.val ∘ u = h := by
      refine ⟨fun w => ⟨h w, congr_fun hh w⟩, rfl, ?_⟩
      intro u hu
      funext w
      exact Subtype.ext (congr_fun hu w)
    Axioms used: Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor
  • homEqualizerEquivdefDefinitionQuot.sound
    homEqualizerEquivLean 4Formally verified
    /-- **Maps into an equaliser are maps that equalise.** For every type `W`, maps
    `W → {x // f x = g x}` correspond bijectively to maps `h : W → X` with `f ∘ h = g ∘ h`. In other
    words the hom functor `Hom(W, −)` sends the equaliser of `f, g` to the equaliser of
    `f ∘ −, g ∘ −` — the simplest case of "hom functors preserve limits". -/
    def homEqualizerEquiv (f g : X → Y) (W : Type u) :
        (W → {x : X // f x = g x}) ≃ {h : W → X // f ∘ h = g ∘ h} where
      toFun u := ⟨Subtype.val ∘ u, funext fun w => (u w).2⟩
      invFun h := fun w => ⟨h.1 w, congr_fun h.2 w⟩
      left_inv _ := rfl
      right_inv _ := rfl
    Axioms used: Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor
  • pullback_universaltheoremProved here from basic factsQuot.sound
    pullback_universalLean 4Proved here from basic factsFormally verified
    /-- **The pullback in the category of types** of `f : A → C` and `g : B → C` is the subtype
    `{(a, b) // f a = g b}` of `A × B` — the equaliser of `f ∘ fst` and `g ∘ snd`, exactly the
    construction "limits from products and equalisers". Universal property: maps `a : W → A`,
    `b : W → B` with `f ∘ a = g ∘ b` factor through it by exactly one map, `w ↦ (a w, b w)`. -/
    theorem pullback_universal (f : A → C) (g : B → C) (a : W → A) (b : W → B)
        (hab : f ∘ a = g ∘ b) :
        ∃! u : W → {p : A × B // f p.1 = g p.2},
          (fun w => (u w).1.1) = a ∧ (fun w => (u w).1.2) = b := by
      refine ⟨fun w => ⟨(a w, b w), congr_fun hab w⟩, ⟨rfl, rfl⟩, ?_⟩
      rintro u ⟨h₁, h₂⟩
      funext w
      exact Subtype.ext (Prod.ext (congr_fun h₁ w) (congr_fun h₂ w))
    Axioms used: Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor
  • CoeqReldefDefinitionNo axioms
    CoeqRelLean 4Formally verified
    /-- The relation generating the **coequaliser** of `f g : X → Y`: `f x` is related to `g x`. -/
    def CoeqRel (f g : X → Y) : Y → Y → Prop :=
      fun y y' => ∃ x, f x = y ∧ g x = y'
    Axioms used: No axiomsformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor
  • coequalizer_universaltheoremProved here from basic factsQuot.sound
    coequalizer_universalLean 4Proved here from basic factsFormally verified
    /-- **The coequaliser in the category of types** is the quotient `Quot (CoeqRel f g)` of `Y` by
    the equivalence relation generated by `f x ~ g x`, with the quotient map. Universal property:
    every `h : Y → Z` with `h ∘ f = h ∘ g` factors through the quotient by exactly one map
    (`Quot.lift`); uniqueness holds because every element of the quotient is a class `[y]`. Colimits
    of types glue, limits of types carve out. -/
    theorem coequalizer_universal (f g : X → Y) (h : Y → Z) (hh : h ∘ f = h ∘ g) :
        ∃! u : Quot (CoeqRel f g) → Z, u ∘ Quot.mk _ = h := by
      refine ⟨Quot.lift h ?_, rfl, ?_⟩
      · rintro _ _ ⟨x, rfl, rfl⟩
        exact congr_fun hh x
      · intro u hu
        funext q
        induction q using Quot.ind with
        | mk y => exact congr_fun hu y
    Axioms used: Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor
  • cone_naturalitytheoremApplies a library theorempropext, Classical.choice, Quot.sound
    cone_naturalityLean 4Applies a library theoremFormally verified
    /-- **A cone is a natural transformation from a constant functor.** A cone over `F : J ⥤ C` has
    an apex and legs `c.π.app j : apex ⟶ F j`; naturality of `c.π : const apex ⟶ F` at
    `f : j ⟶ j'` says exactly that the legs are compatible: `F f ∘ π_j = π_j'`. This is Mathlib's
    `Cone.w`. -/
    theorem cone_naturality {J : Type*} [Category J] {C : Type*} [Category C] {F : J ⥤ C}
        (c : Cone F) {j j' : J} (f : j ⟶ j') : c.π.app j ≫ F.map f = c.π.app j' :=
      c.w f
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor
  • limits_of_products_equalizerstheoremApplies a library theorempropext, Classical.choice, Quot.sound
    limits_of_products_equalizersLean 4Applies a library theoremFormally verified
    /-- **Products and equalisers give all limits.** A category with all small products and all
    equalisers has all small limits: the limit of `F` is the equaliser of two maps
    `∏ⱼ F j ⇉ ∏_{u : i ⟶ j} F j`. This applies Mathlib's `has_limits_of_hasEqualizers_and_products`;
    the lesson proves it. -/
    theorem limits_of_products_equalizers {C : Type u} [Category.{v} C] [HasProducts.{v} C]
        [HasEqualizers C] : HasLimits C :=
      has_limits_of_hasEqualizers_and_products
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor
  • pullbacks_of_products_equalizerstheoremApplies a library theorempropext, Classical.choice, Quot.sound
    pullbacks_of_products_equalizersLean 4Applies a library theoremFormally verified
    /-- **Binary products and equalisers give pullbacks**: the pullback of `f : A ⟶ C` and
    `g : B ⟶ C` is the equaliser of `f ∘ π₁` and `g ∘ π₂` on `A × B`. This applies Mathlib's
    `hasPullbacks_of_hasBinaryProducts_of_hasEqualizers`. -/
    theorem pullbacks_of_products_equalizers (C : Type u) [Category.{v} C] [HasBinaryProducts C]
        [HasEqualizers C] : HasPullbacks C :=
      hasPullbacks_of_hasBinaryProducts_of_hasEqualizers C
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor
  • complete_cocompletetheoremApplies a library theorempropext, Classical.choice, Quot.sound
    complete_cocompleteLean 4Applies a library theoremFormally verified
    /-- **Completeness and cocompleteness.** Types and topological spaces have all small limits and
    colimits; groups have all small limits and abelian groups all small colimits. These are Mathlib
    instances (limits of types are compatible families, colimits are quotients of disjoint unions). -/
    theorem complete_cocomplete :
        HasLimits (Type u) ∧ HasColimits (Type u) ∧ HasLimits TopCat.{u} ∧ HasColimits TopCat.{u} ∧
          HasLimits GrpCat.{u} ∧ HasColimits AddCommGrpCat.{u} :=
      ⟨inferInstance, inferInstance, inferInstance, inferInstance, inferInstance, inferInstance⟩
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor
  • hom_preserves_limitstheoremApplies a library theorempropext, Classical.choice, Quot.sound
    hom_preserves_limitsLean 4Applies a library theoremFormally verified
    /-- **Hom functors preserve limits.** For every object `A`, the functor
    `Hom(A, −) = coyoneda.obj (op A) : C ⥤ Type v` sends limit cones to limit cones:
    `Hom(A, lim F) ≅ lim Hom(A, F −)`. This is Mathlib's instance `coyoneda_preservesLimits`. -/
    theorem hom_preserves_limits {C : Type u} [Category.{v} C] (A : C) :
        PreservesLimits (coyoneda.obj (op A)) :=
      inferInstance
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor
  • forget_preserves_limitstheoremApplies a library theorempropext, Classical.choice, Quot.sound
    forget_preserves_limitsLean 4Applies a library theoremFormally verified
    /-- **The forgetful functor `Grp → Set` preserves limits**: the underlying set of a limit of
    groups is the limit of the underlying sets (Mathlib's `GrpCat.forget_preservesLimits`). -/
    theorem forget_preserves_limits : PreservesLimits (forget GrpCat.{u}) :=
      inferInstance
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor
  • forget_not_preserves_coproducttheoremProved here from basic factspropext, Classical.choice, Quot.sound
    forget_not_preserves_coproductLean 4Proved here from basic factsFormally verified
    /-- **…but not coproducts.** If the forgetful functor preserved the coproduct `ℤ ∗ ℤ`, the
    canonical map from the disjoint union `ℤ ⊔ ℤ` of underlying sets to the underlying set of `ℤ ∗ ℤ`
    (sending the summands by `inl`, `inr`) would be a bijection. It is not even surjective: `x y`
    (with `x = inl 1`, `y = inr 1`) is not in its image. Proof: map `ℤ ∗ ℤ → S₃` by `x ↦ (0 1)`,
    `y ↦ (1 2)` (universal property). Every `inl n` goes to a power of `(0 1)`, which fixes `2`;
    every `inr n` to a power of `(1 2)`, which fixes `0`; but `x y` goes to `(0 1)(1 2)`, which moves
    both `0` and `2`. -/
    theorem forget_not_preserves_coproduct :
        ¬ Function.Surjective (Sum.elim (inl : Multiplicative ℤ →* _) (inr : Multiplicative ℤ →* _) :
          Multiplicative ℤ ⊕ Multiplicative ℤ → Multiplicative ℤ ∗ Multiplicative ℤ) := by
      intro hsurj
      let σ : Equiv.Perm (Fin 3) := Equiv.swap 0 1
      let τ : Equiv.Perm (Fin 3) := Equiv.swap 1 2
      let φ := lift (zpowersHom (Equiv.Perm (Fin 3)) σ) (zpowersHom (Equiv.Perm (Fin 3)) τ)
      obtain ⟨z, hz⟩ := hsurj (inl (Multiplicative.ofAdd 1) * inr (Multiplicative.ofAdd 1))
      have key : φ (inl (Multiplicative.ofAdd 1) * inr (Multiplicative.ofAdd 1)) = σ * τ := by
        simp [φ]
      rcases z with n | n
      · -- `φ (inl n) = σ ^ n` fixes `2`, but `σ * τ` does not.
        have h₁ : φ (inl n) 2 = 2 := by
          simp only [φ, lift_apply_inl, zpowersHom_apply]
          exact Equiv.Perm.zpow_apply_eq_self_of_apply_eq_self (by decide) _
        have h₂ : (σ * τ) 2 ≠ 2 := by decide
        simp only [Sum.elim_inl] at hz
        rw [hz, key] at h₁
        exact h₂ h₁
      · -- `φ (inr n) = τ ^ n` fixes `0`, but `σ * τ` does not.
        have h₁ : φ (inr n) 0 = 0 := by
          simp only [φ, lift_apply_inr, zpowersHom_apply]
          exact Equiv.Perm.zpow_apply_eq_self_of_apply_eq_self (by decide) _
        have h₂ : (σ * τ) 0 ≠ 0 := by decide
        simp only [Sum.elim_inr] at hz
        rw [hz, key] at h₁
        exact h₂ h₁
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor
  • padic_inverse_limittheoremApplies a library theorempropext, Classical.choice, Quot.sound
    padic_inverse_limitLean 4Applies a library theoremFormally verified
    /-- **`ℤ_p` is the inverse limit of the rings `ℤ/pⁿ`.** The reduction maps
    `toZModPow n : ℤ_[p] → ℤ/pⁿ` form a cone (they are compatible with the reductions
    `ℤ/pⁿ → ℤ/pᵐ`, `m ≤ n`), and it is a limit cone in rings: every compatible family of ring maps
    `f n : R → ℤ/pⁿ` comes from exactly one ring map `R → ℤ_[p]`. This applies Mathlib's
    `PadicInt.zmod_cast_comp_toZModPow`, `PadicInt.lift_spec` and `PadicInt.lift_unique`. -/
    theorem padic_inverse_limit (p : ℕ) [Fact p.Prime] {R : Type*} [NonAssocSemiring R]
        (f : ∀ k : ℕ, R →+* ZMod (p ^ k))
        (f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂),
          (ZMod.castHom (pow_dvd_pow p hk) _).comp (f k₂) = f k₁) :
        (∀ (m n : ℕ) (h : m ≤ n),
          (ZMod.castHom (pow_dvd_pow p h) (ZMod (p ^ m))).comp (PadicInt.toZModPow n) =
            PadicInt.toZModPow m) ∧
        ∃! g : R →+* ℤ_[p], ∀ n, (PadicInt.toZModPow n).comp g = f n :=
      ⟨PadicInt.zmod_cast_comp_toZModPow, PadicInt.lift f_compat, PadicInt.lift_spec f_compat,
        fun g hg => (PadicInt.lift_unique f_compat g hg).symm⟩
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor
  • increasing_limit_is_colimittheoremApplies a library theorempropext, Classical.choice, Quot.sound
    increasing_limit_is_colimitLean 4Applies a library theoremFormally verified
    /-- **When the two meanings of "limit" meet.** In the poset `(ℝ, ≤)` regarded as a category, an
    increasing sequence `u 0 ≤ u 1 ≤ ⋯` is a diagram of shape `ℕ`, and its colimit is its least upper
    bound. For such a sequence, converging to `L` (analysis) is the same as `L` being the least upper
    bound of its values (category theory). This applies Mathlib's `isLUB_of_tendsto_atTop` and
    `tendsto_atTop_isLUB`. -/
    theorem increasing_limit_is_colimit {u : ℕ → ℝ} (hu : Monotone u) (L : ℝ) :
        Tendsto u atTop (𝓝 L) ↔ IsLUB (Set.range u) L :=
      ⟨isLUB_of_tendsto_atTop hu, tendsto_atTop_isLUB hu⟩
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor

Formal exercises

Each exercise contains a sorry for you to replace. Open it in the Lean web editor, or clone the repository and run lake build.

equalizer_universalsorry × 1Try it in the Lean web editor
/-- The universal property of the equaliser of types.
Hint: the map is `fun w => ⟨h w, congr_fun hh w⟩`. For uniqueness, take another `u` with
`Subtype.val ∘ u = h`, use `funext w`, and compare values with `Subtype.ext`. -/
theorem equalizer_universal (f g : X → Y) (h : W → X) (hh : f ∘ h = g ∘ h) :
    ∃! u : W → {x : X // f x = g x}, Subtype.val ∘ u = h := by
  sorry
Show the compiled solution
equalizer_universalLean 4Proved here from basic factsFormally verified
/-- **The equaliser in the category of types** of `f g : X → Y` is the subtype
`{x // f x = g x}` with its inclusion. Universal property: every `h : W → X` with
`f ∘ h = g ∘ h` factors through the inclusion by exactly one map `u`, namely
`u w = ⟨h w, _⟩`; uniqueness holds because an element of a subtype is determined by its value. -/
theorem equalizer_universal (f g : X → Y) (h : W → X) (hh : f ∘ h = g ∘ h) :
    ∃! u : W → {x : X // f x = g x}, Subtype.val ∘ u = h := by
  refine ⟨fun w => ⟨h w, congr_fun hh w⟩, rfl, ?_⟩
  intro u hu
  funext w
  exact Subtype.ext (congr_fun hu w)
Axioms used: Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor
coequalizer_universalsorry × 1Try it in the Lean web editor
/-- The universal property of the coequaliser of types.
Hint: existence is `Quot.lift h _`, where the missing proof says that related elements have the
same image (`rintro _ _ ⟨x, rfl, rfl⟩`). For uniqueness, use `funext q` and `Quot.ind`. -/
theorem coequalizer_universal (f g : X → Y) (h : Y → Z) (hh : h ∘ f = h ∘ g) :
    ∃! u : Quot (CoeqRel f g) → Z, u ∘ Quot.mk _ = h := by
  sorry
Show the compiled solution
coequalizer_universalLean 4Proved here from basic factsFormally verified
/-- **The coequaliser in the category of types** is the quotient `Quot (CoeqRel f g)` of `Y` by
the equivalence relation generated by `f x ~ g x`, with the quotient map. Universal property:
every `h : Y → Z` with `h ∘ f = h ∘ g` factors through the quotient by exactly one map
(`Quot.lift`); uniqueness holds because every element of the quotient is a class `[y]`. Colimits
of types glue, limits of types carve out. -/
theorem coequalizer_universal (f g : X → Y) (h : Y → Z) (hh : h ∘ f = h ∘ g) :
    ∃! u : Quot (CoeqRel f g) → Z, u ∘ Quot.mk _ = h := by
  refine ⟨Quot.lift h ?_, rfl, ?_⟩
  · rintro _ _ ⟨x, rfl, rfl⟩
    exact congr_fun hh x
  · intro u hu
    funext q
    induction q using Quot.ind with
    | mk y => exact congr_fun hu y
Axioms used: Quot.soundformal/Lumenary/LimitsColimits.leanTry it in the Lean web editor