Imports
/- Copyright (c) 2026 Terence Rokop. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Terence Rokop -/ module public import Geb.Mathlib.CategoryTheory.FinCat.Hom public import Mathlib.CategoryTheory.NatTrans

2-cell specifications

A natural transformation between two functor specifications with the same source and target is specified by a component at each object index and a Bool equation asserting naturality. The component ranges over the target's full hom type from the outset, so the identity 2-cell has every component an identity.

The 2-cells between a fixed pair of functor specifications form a category under componentwise composition, and each of them generates a mathlib natural transformation between the generated functors.

Main definitions

    CategoryTheory.FinCat.Hom₂.natCheckOf, CategoryTheory.FinCat.Hom₂.natCheck — the decidable naturality check on client morphisms.

    CategoryTheory.FinCat.Hom₂ — the 2-cell specification type.

    CategoryTheory.FinCat.Hom.instCategory — the hom-category: vertical composition and the identity 2-cell.

    CategoryTheory.FinCat.Hom₂.toNatTrans — the mathlib natural transformation a 2-cell specification generates.

Main statements

    FinCat.Hom₂.natCheck_eq_true_iff — the check reflects naturality on client morphisms.

    FinCat.Hom₂.eq_of_app_eq, FinCat.Hom₂.ext — extensionality, at FinCat.Hom₂ F G and at F ⟶ G respectively.

    FinCat.Hom₂.app_id, FinCat.Hom₂.app_comp — the components of the identity 2-cell and of a vertical composite.

    FinCat.Hom₂.natCheck_total — naturality, on all morphisms.

Implementation notes

natCheckOf precedes the structure because the natValid field's type mentions it. The enclosing namespace FinCat stays open throughout; the inner namespace Hom₂ blocks close around structure Hom₂, which cannot be declared inside a namespace of its own name, and around instance Hom.instCategory, whose full name is a FinCat.Hom name and so cannot be written inside a namespace Hom₂ either.

eq_of_app_eq precedes the category instance because the instance's three law fields need it and the hom notation does not exist until the instance does. CategoryTheory.Cat.Hom.instCategory discharges its counterparts by congrArg, which is available there because CategoryTheory.Cat.Hom₂ is a one-field wrapper; FinCat.Hom is not such a bundling, so that route is unavailable here.

natCheck_total extends the check off the client range, as FinCat.Hom.mapTotal_compTotal does for the composition check. The extension, rather than the check itself, is what toNatTrans needs: a morphism of the generated category is an arbitrary element of the full hom type, not an embedded client morphism.

toNatTrans states its result type as CategoryTheory.NatTrans rather than through . The two are the same type, but the notation names it via CategoryTheory.Functor.category, whose category laws are discharged by aesop_cat and so depend on Classical.choice; the notation therefore carries that dependence into the type of any declaration written with it.

The check is stated over the total composition and the total morphism maps, for the reason FinCat.Hom.compCheckOf is: a client composite may land on the reserved identity index, on which the client's morphism map is undefined.

FinCat.Hom₂ is not marked @[ext]. A structure-derived extensionality lemma does not fire on goals stated through the hom notation F ⟶ G, so it would be unusable at the only place it is needed; the name FinCat.Hom₂.ext is left free for a hand-written lemma phrased at F ⟶ G, matching what mathlib does for CategoryTheory.Cat.Hom₂.

References

    [JohnsonYau2021] § 1.1 — the notion of natural transformation, of which this module's specification type is a presentation.

Tags

category, functor, natural transformation, finite category, decidable, constructive, choice-free

@[expose] public sectionnamespace CategoryTheorynamespace FinCatnamespace Hom₂

Naturality, as a Bool, on client morphisms. Stated over the total composition and the total morphism maps, for the reason FinCat.Hom.compCheckOf is.

def natCheckOf (S T : FinCat) (F G : Hom S T) (app : (i : Fin S.objCount) T.Mor (F.objMap i) (G.objMap i)) : Bool := decide <| (i j : Fin S.objCount) (f : Fin (S.nonIdCount i j)), T.compTotal (F.mapTotal (S.emb f)) (app j) = T.compTotal (app i) (G.mapTotal (S.emb f))
end Hom₂

A 2-cell specification: a natural transformation between two functor specifications.

The component at each object. It ranges over the full hom type from the outset, the identity 2-cell having every component an identity.

Naturality.

structure Hom₂ {S T : FinCat} (F G : Hom S T) where app : (i : Fin S.objCount) T.Mor (F.objMap i) (G.objMap i) natValid : Hom₂.natCheckOf S T F G app = true
namespace Hom₂

The naturality check reflects naturality on client morphisms.

theorem natCheck_eq_true_iff (S T : FinCat) (F G : Hom S T) (app : (i : Fin S.objCount) T.Mor (F.objMap i) (G.objMap i)) : natCheckOf S T F G app = true (i j : Fin S.objCount) (f : Fin (S.nonIdCount i j)), T.compTotal (F.mapTotal (S.emb f)) (app j) = T.compTotal (app i) (G.mapTotal (S.emb f)) := decide_eq_true_iff

α's naturality check.

def natCheck {S T : FinCat} {F G : Hom S T} (α : Hom₂ F G) : Bool := natCheckOf S T F G α.app

Two 2-cells with equal components are equal. Stated at FinCat.Hom₂ F G rather than at F ⟶ G, so that it is available before the hom-category instance exists.

theorem eq_of_app_eq {S T : FinCat} {F G : Hom S T} {α β : Hom₂ F G} (h : i, α.app i = β.app i) : α = β := S:FinCatT:FinCatF:S.Hom TG:S.Hom Tα:Hom₂ F Gβ:Hom₂ F Gh: (i : Fin S.objCount), α.app i = β.app iα = β S:FinCatT:FinCatF:S.Hom TG:S.Hom Tβ:Hom₂ F Ga:(i : Fin S.objCount) T.Mor (F.objMap i) (G.objMap i)natValid✝:natCheckOf S T F G a = trueh: (i : Fin S.objCount), { app := a, natValid := natValid✝ }.app i = β.app i{ app := a, natValid := natValid✝ } = β S:FinCatT:FinCatF:S.Hom TG:S.Hom Ta:(i : Fin S.objCount) T.Mor (F.objMap i) (G.objMap i)natValid✝¹:natCheckOf S T F G a = trueb:(i : Fin S.objCount) T.Mor (F.objMap i) (G.objMap i)natValid✝:natCheckOf S T F G b = trueh: (i : Fin S.objCount), { app := a, natValid := natValid✝¹ }.app i = { app := b, natValid := natValid✝ }.app i{ app := a, natValid := natValid✝¹ } = { app := b, natValid := natValid✝ } S:FinCatT:FinCatF:S.Hom TG:S.Hom Ta:(i : Fin S.objCount) T.Mor (F.objMap i) (G.objMap i)natValid✝¹:natCheckOf S T F G a = trueb:(i : Fin S.objCount) T.Mor (F.objMap i) (G.objMap i)natValid✝:natCheckOf S T F G b = trueh: (i : Fin S.objCount), { app := a, natValid := natValid✝¹ }.app i = { app := b, natValid := natValid✝ }.app ihab:a = b{ app := a, natValid := natValid✝¹ } = { app := b, natValid := natValid✝ } S:FinCatT:FinCatF:S.Hom TG:S.Hom Ta:(i : Fin S.objCount) T.Mor (F.objMap i) (G.objMap i)natValid✝¹:natCheckOf S T F G a = truenatValid✝:natCheckOf S T F G a = trueh: (i : Fin S.objCount), { app := a, natValid := natValid✝¹ }.app i = { app := a, natValid := natValid✝ }.app i{ app := a, natValid := natValid✝¹ } = { app := a, natValid := natValid✝ } All goals completed! 🐙
end Hom₂

The category of 2-cells between two functor specifications: vertical composition and the identity 2-cell.

instance Hom.instCategory {S T : FinCat} : Category (Hom S T) where Hom F G := Hom₂ F G id F := { app := fun i T.id (F.objMap i) natValid := S:FinCatT:FinCatF:S.Hom T(Hom₂.natCheckOf S T F F fun i T.id (F.objMap i)) = true S:FinCatT:FinCatF:S.Hom T (i j : Fin S.objCount) (f : Fin (S.nonIdCount i j)), T.compTotal (F.mapTotal (emb f)) (T.id (F.objMap j)) = T.compTotal (T.id (F.objMap i)) (F.mapTotal (emb f)) S:FinCatT:FinCatF:S.Hom Ti:Fin S.objCountj:Fin S.objCountf:Fin (S.nonIdCount i j)T.compTotal (F.mapTotal (emb f)) (T.id (F.objMap j)) = T.compTotal (T.id (F.objMap i)) (F.mapTotal (emb f)) All goals completed! 🐙 } comp α β := { app := fun i T.compTotal (α.app i) (β.app i) natValid := S:FinCatT:FinCatX✝:S.Hom TY✝:S.Hom TZ✝:S.Hom Tα:Hom₂ X✝ Y✝β:Hom₂ Y✝ Z✝(Hom₂.natCheckOf S T X✝ Z✝ fun i T.compTotal (α.app i) (β.app i)) = true S:FinCatT:FinCatX✝:S.Hom TY✝:S.Hom TZ✝:S.Hom Tα:Hom₂ X✝ Y✝β:Hom₂ Y✝ Z✝ (i j : Fin S.objCount) (f : Fin (S.nonIdCount i j)), T.compTotal (X✝.mapTotal (emb f)) (T.compTotal (α.app j) (β.app j)) = T.compTotal (T.compTotal (α.app i) (β.app i)) (Z✝.mapTotal (emb f)) S:FinCatT:FinCatX✝:S.Hom TY✝:S.Hom TZ✝:S.Hom Tα:Hom₂ X✝ Y✝β:Hom₂ Y✝ Z✝i:Fin S.objCountj:Fin S.objCountf:Fin (S.nonIdCount i j)T.compTotal (X✝.mapTotal (emb f)) (T.compTotal (α.app j) (β.app j)) = T.compTotal (T.compTotal (α.app i) (β.app i)) (Z✝.mapTotal (emb f)) All goals completed! 🐙 } id_comp α := Hom₂.eq_of_app_eq fun i T.id_comp (α.app i) comp_id α := Hom₂.eq_of_app_eq fun i T.comp_id (α.app i) assoc α β γ := Hom₂.eq_of_app_eq fun i T.compTotal_assoc (α.app i) (β.app i) (γ.app i)
namespace Hom₂variable {S T : FinCat}

The identity 2-cell's components are the reserved identities.

@[simp] theorem app_id {F : Hom S T} (i : Fin S.objCount) : (𝟙 F : F F).app i = T.id (F.objMap i) := rfl

A vertical composite's components are the composites.

@[simp] theorem app_comp {F G H : Hom S T} (α : F G) (β : G H) (i : Fin S.objCount) : (α β).app i = T.compTotal (α.app i) (β.app i) := rfl

Two 2-cells with equal components are equal, phrased at F ⟶ G so that the ext tactic fires on goals stated through the hom notation.

@[ext] theorem ext {F G : Hom S T} {α β : F G} (h : i, α.app i = β.app i) : α = β := eq_of_app_eq h

Naturality at total morphisms, extending natCheck off the client range.

theorem natCheck_total {F G : Hom S T} (α : Hom₂ F G) {i j : Fin S.objCount} (x : S.Mor i j) : T.compTotal (F.mapTotal x) (α.app j) = T.compTotal (α.app i) (G.mapTotal x) := S:FinCatT:FinCatF:S.Hom TG:S.Hom Tα:Hom₂ F Gi:Fin S.objCountj:Fin S.objCountx:S.Mor i jT.compTotal (F.mapTotal x) (α.app j) = T.compTotal (α.app i) (G.mapTotal x) S:FinCatT:FinCatF:S.Hom TG:S.Hom Tα:Hom₂ F Gi:Fin S.objCountj:Fin S.objCountx:S.Mor i jhx:x < S.nonIdCount i jT.compTotal (F.mapTotal x) (α.app j) = T.compTotal (α.app i) (G.mapTotal x)S:FinCatT:FinCatF:S.Hom TG:S.Hom Tα:Hom₂ F Gi:Fin S.objCountj:Fin S.objCountx:S.Mor i jhx:¬x < S.nonIdCount i jT.compTotal (F.mapTotal x) (α.app j) = T.compTotal (α.app i) (G.mapTotal x) S:FinCatT:FinCatF:S.Hom TG:S.Hom Tα:Hom₂ F Gi:Fin S.objCountj:Fin S.objCountx:S.Mor i jhx:x < S.nonIdCount i jT.compTotal (F.mapTotal x) (α.app j) = T.compTotal (α.app i) (G.mapTotal x) S:FinCatT:FinCatF:S.Hom TG:S.Hom Tα:Hom₂ F Gi:Fin S.objCountj:Fin S.objCountx:S.Mor i jhx:x < S.nonIdCount i jh:T.compTotal (F.mapTotal (emb x, hx)) (α.app j) = T.compTotal (α.app i) (G.mapTotal (emb x, hx))T.compTotal (F.mapTotal x) (α.app j) = T.compTotal (α.app i) (G.mapTotal x) rwa [S:FinCatT:FinCatF:S.Hom TG:S.Hom Tα:Hom₂ F Gi:Fin S.objCountj:Fin S.objCountx:S.Mor i jhx:x < S.nonIdCount i jh:T.compTotal (F.mapTotal x) (α.app j) = T.compTotal (α.app i) (G.mapTotal x)T.compTotal (F.mapTotal x) (α.app j) = T.compTotal (α.app i) (G.mapTotal x)S:FinCatT:FinCatF:S.Hom TG:S.Hom Tα:Hom₂ F Gi:Fin S.objCountj:Fin S.objCountx:S.Mor i jhx:x < S.nonIdCount i jh:T.compTotal (F.mapTotal x) (α.app j) = T.compTotal (α.app i) (G.mapTotal x)T.compTotal (F.mapTotal x) (α.app j) = T.compTotal (α.app i) (G.mapTotal x) at h S:FinCatT:FinCatF:S.Hom TG:S.Hom Tα:Hom₂ F Gi:Fin S.objCountj:Fin S.objCountx:S.Mor i jhx:¬x < S.nonIdCount i jT.compTotal (F.mapTotal x) (α.app j) = T.compTotal (α.app i) (G.mapTotal x) S:FinCatT:FinCatF:S.Hom TG:S.Hom Tα:Hom₂ F Gi:Fin S.objCountj:Fin S.objCountx:S.Mor i jhx:¬x < S.nonIdCount i jhij:i = jT.compTotal (F.mapTotal x) (α.app j) = T.compTotal (α.app i) (G.mapTotal x) S:FinCatT:FinCatF:S.Hom TG:S.Hom Tα:Hom₂ F Gi:Fin S.objCountx:S.Mor i ihx:¬x < S.nonIdCount i iT.compTotal (F.mapTotal x) (α.app i) = T.compTotal (α.app i) (G.mapTotal x) All goals completed! 🐙

The mathlib natural transformation a 2-cell specification generates.

def toNatTrans.{v, u} {F G : Hom S T} (α : Hom₂ F G) : NatTrans F.toFunctor.{v, u} G.toFunctor.{v, u} where app X := ULift.up (α.app X.idx.down) naturality _ _ f := congrArg ULift.up (α.natCheck_total f.down)
end Hom₂end FinCatend CategoryTheory