Mathlib Phrasebook

3.2. Associativity of the composition🔗

The composition of morphisms in a category is associative. When a term is a composition of more than two morphisms, the syntax is set up so that f ≫ g ≫ h means f ≫ (g ≫ h), and this is also the simp normal form (i.e. (f ≫ g) ≫ h simplifies to f ≫ g ≫ h):

variable {X Y Z T : C} (f : X ⟶ Y) (g : Y ⟶ Z) (h : Z ⟶ T) example : f ≫ g ≫ h = f ≫ (g ≫ h) := rfl example : (f ≫ g) ≫ h = f ≫ g ≫ h := Category.assoc f g h

In non-formalized mathematics, the associativity of the composition is often used implicitly. In formalized mathematics, we need to take care about this associativity in one way or another when proving equalities of morphisms:

variable {X₀ X₁ X₂ X₃ X₄ : C} (f₀ : X₀ ⟶ X₁) (f₁ : X₁ ⟶ X₂) (f₂ : X₂ ⟶ X₃) (f₃ : X₃ ⟶ X₄) (φ : X₁ ⟶ X₃) (h : f₁ ≫ f₂ = φ) example : f₀ ≫ f₁ ≫ f₂ ≫ f₃ = f₀ ≫ φ ≫ f₃ := C:Type u_1inst✝:Category.{v_1, u_1} CX:CY:CZ:CT:Cf:X ⟶ Yg:Y ⟶ Zh✝:Z ⟶ TX₀:CX₁:CX₂:CX₃:CX₄:Cf₀:X₀ ⟶ X₁f₁:X₁ ⟶ X₂f₂:X₂ ⟶ X₃f₃:X₃ ⟶ X₄φ:X₁ ⟶ X₃h:f₁ ≫ f₂ = φ⊢ f₀ ≫ f₁ ≫ f₂ ≫ f₃ = f₀ ≫ φ ≫ f₃ All goals completed! 🐙

This proof uses the associativity in order to make the term f₀ ≫ (f₁ ≫ f₂) ≫ f₃ appear, which allows to rewrite h. Proceeding like this would be very unpractical in more intricate cases, and it is also inconvenient because this would often require using Category.assoc explicitly in both forward and backwards directions. As it is a simp lemma, it is recommended to use it explicitly only in the forward direction.

An alternative proof can be obtained using specialized tactics:

example : f₀ ≫ f₁ ≫ f₂ ≫ f₃ = f₀ ≫ φ ≫ f₃ := C:Type u_1inst✝:Category.{v_1, u_1} CX:CY:CZ:CT:Cf:X ⟶ Yg:Y ⟶ Zh✝:Z ⟶ TX₀:CX₁:CX₂:CX₃:CX₄:Cf₀:X₀ ⟶ X₁f₁:X₁ ⟶ X₂f₂:X₂ ⟶ X₃f₃:X₃ ⟶ X₄φ:X₁ ⟶ X₃h:f₁ ≫ f₂ = φ⊢ f₀ ≫ f₁ ≫ f₂ ≫ f₃ = f₀ ≫ φ ≫ f₃ slice_lhs 2 3 => C:Type u_1inst✝:Category.{v_1, u_1} CX:CY:CZ:CT:Cf:X ⟶ Yg:Y ⟶ Zh✝:Z ⟶ TX₀:CX₁:CX₂:CX₃:CX₄:Cf₀:X₀ ⟶ X₁f₁:X₁ ⟶ X₂f₂:X₂ ⟶ X₃f₃:X₃ ⟶ X₄φ:X₁ ⟶ X₃h:f₁ ≫ f₂ = φ| φC:Type u_1inst✝:Category.{v_1, u_1} CX:CY:CZ:CT:Cf:X ⟶ Yg:Y ⟶ Zh✝:Z ⟶ TX₀:CX₁:CX₂:CX₃:CX₄:Cf₀:X₀ ⟶ X₁f₁:X₁ ⟶ X₂f₂:X₂ ⟶ X₃f₃:X₃ ⟶ X₄φ:X₁ ⟶ X₃h:f₁ ≫ f₂ = φ| f₃C:Type u_1inst✝:Category.{v_1, u_1} CX:CY:CZ:CT:Cf:X ⟶ Yg:Y ⟶ Zh✝:Z ⟶ TX₀:CX₁:CX₂:CX₃:CX₄:Cf₀:X₀ ⟶ X₁f₁:X₁ ⟶ X₂f₂:X₂ ⟶ X₃f₃:X₃ ⟶ X₄φ:X₁ ⟶ X₃h:f₁ ≫ f₂ = φ| f₀

slice_lhs (and slice_rhs) are specialized conv-like tactics which allow to zoom on certain chunks in the middle of compositions of multiple morphisms. When there is no better way, this method can be used when dealing with very long compositions.

In this case, the preferred proof would be:

example : f₀ ≫ f₁ ≫ f₂ ≫ f₃ = f₀ ≫ φ ≫ f₃ := C:Type u_1inst✝:Category.{v_1, u_1} CX:CY:CZ:CT:Cf:X ⟶ Yg:Y ⟶ Zh✝:Z ⟶ TX₀:CX₁:CX₂:CX₃:CX₄:Cf₀:X₀ ⟶ X₁f₁:X₁ ⟶ X₂f₂:X₂ ⟶ X₃f₃:X₃ ⟶ X₄φ:X₁ ⟶ X₃h:f₁ ≫ f₂ = φ⊢ f₀ ≫ f₁ ≫ f₂ ≫ f₃ = f₀ ≫ φ ≫ f₃ All goals completed! 🐙

This proof uses the term elaborator reassoc_of%: from an an equality like h : f₁ ≫ f₂ = φ, it produces a term f₁ ≫ f₂ ≫ α = f₂ ≫ α for a generic morphism α, and it can be used in rewrites. Note that we do not need the "dual" construction of a term β ≫ f₁ ≫ f₂ = β ≫ f₂ because h can be directly rewritten in it. Indeed, this reassoc_of% h term could be rewritten in an arbitrary composition like β₀ ≫ ... ≫ βₙ ≫ f₁ ≫ f₂ ≫ γ₀ ≫ ... ≫ γₘ as soon as the list [γ₀, ..., γₘ] is nonempty.

Similarly, we have a @[reassoc] attribute (often used in combination with simp as @[reassoc (attr := simp)]); when it is applied to a lemma foo, it generates another lemma foo_assoc similarly as reassoc_of% h is generated from h above.