Skip to content

Commit 89a6c39

Browse files
author
leanprover-community-mathlib4-bot
committed
Merge master into nightly-testing
2 parents 811b0aa + 1414404 commit 89a6c39

5 files changed

Lines changed: 170 additions & 7 deletions

File tree

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5611,6 +5611,7 @@ import Mathlib.Tactic.CategoryTheory.Coherence.Datatypes
56115611
import Mathlib.Tactic.CategoryTheory.Coherence.Normalize
56125612
import Mathlib.Tactic.CategoryTheory.Coherence.PureCoherence
56135613
import Mathlib.Tactic.CategoryTheory.Elementwise
5614+
import Mathlib.Tactic.CategoryTheory.IsoReassoc
56145615
import Mathlib.Tactic.CategoryTheory.Monoidal.Basic
56155616
import Mathlib.Tactic.CategoryTheory.Monoidal.Datatypes
56165617
import Mathlib.Tactic.CategoryTheory.Monoidal.Normalize

Mathlib/Tactic.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import Mathlib.Tactic.CategoryTheory.Coherence.Datatypes
3636
import Mathlib.Tactic.CategoryTheory.Coherence.Normalize
3737
import Mathlib.Tactic.CategoryTheory.Coherence.PureCoherence
3838
import Mathlib.Tactic.CategoryTheory.Elementwise
39+
import Mathlib.Tactic.CategoryTheory.IsoReassoc
3940
import Mathlib.Tactic.CategoryTheory.Monoidal.Basic
4041
import Mathlib.Tactic.CategoryTheory.Monoidal.Datatypes
4142
import Mathlib.Tactic.CategoryTheory.Monoidal.Normalize
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/-
2+
Copyright (c) 2025 Robin Carlier. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Robin Carlier
5+
-/
6+
import Mathlib.CategoryTheory.Iso
7+
8+
/-!
9+
# Extension of `reassoc` to isomorphisms.
10+
11+
We extend `reassoc` and `reassoc_of%` for equality of isomorphisms.
12+
Adding `@[reassoc]` to a lemma named `F` of shape `∀ .., f = g`,
13+
where `f g : X ≅ Y` in some category will create a new lemma named `F_assoc` of shape
14+
`∀ .. {Z : C} (h : Y ≅ Z), f ≪≫ h = g ≪≫ h`
15+
but with the conclusions simplified using basic propertions in isomorphisms in a category
16+
(`Iso.trans_refl`, `Iso.refl_trans`, `Iso.trans_assoc`, `Iso.trans_symm`,
17+
`Iso.symm_self_id` and `Iso.self_symm_id`).
18+
19+
This is useful for generating lemmas which the simplifier can use even on expressions
20+
that are already right associated.
21+
-/
22+
23+
open Lean Meta Elab Tactic
24+
open Mathlib.Tactic
25+
26+
namespace CategoryTheory
27+
28+
variable {C : Type*} [Category C]
29+
30+
theorem Iso.eq_whisker {X Y : C} {f g : X ≅ Y} (w : f = g) {Z : C} (h : Y ≅ Z) :
31+
f ≪≫ h = g ≪≫ h := by rw [w]
32+
33+
/-- Simplify an expression using only the axioms of a groupoid. -/
34+
def categoryIsoSimp (e : Expr) : MetaM Simp.Result :=
35+
simpOnlyNames [``Iso.trans_symm, ``Iso.trans_refl, ``Iso.refl_trans, ``Iso.trans_assoc,
36+
``Iso.symm_self_id, ``Iso.self_symm_id, ``Iso.symm_self_id_assoc, ``Iso.self_symm_id_assoc,
37+
``Functor.mapIso_trans, ``Functor.mapIso_symm, ``Functor.mapIso_refl, ``Functor.id_obj] e
38+
(config := { decide := false })
39+
40+
/--
41+
Given an equation `f = g` between isomorphisms `X ≅ Y` in a category,
42+
produce the equation `∀ {Z} (h : Y ≅ Z), f ≪≫ h = g ≪≫ h`,
43+
but with compositions fully right associated, identities removed, and functors applied.
44+
-/
45+
def reassocExprIso (e : Expr) : MetaM Expr := do
46+
simpType categoryIsoSimp (← mkAppM ``Iso.eq_whisker #[e])
47+
48+
initialize registerReassocExpr reassocExprIso
49+
50+
end CategoryTheory

Mathlib/Tactic/CategoryTheory/Reassoc.lean

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/-
22
Copyright (c) 2022 Kim Morrison. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
4-
Authors: Kim Morrison
4+
Authors: Kim Morrison, Robin Carlier
55
-/
66
import Mathlib.CategoryTheory.Functor.Basic
77
import Mathlib.Lean.Meta.Simp
@@ -22,6 +22,9 @@ This is useful for generating lemmas which the simplifier can use even on expres
2222
that are already right associated.
2323
2424
There is also a term elaborator `reassoc_of% t` for use within proofs.
25+
26+
The `Mathlib.Tactic.CategoryTheory.IsoReassoc` extends `@[reassoc]` and `reassoc_of%`
27+
to support creating isomorphism reassociation lemmas.
2528
-/
2629

2730
open Lean Meta Elab Tactic
@@ -42,12 +45,12 @@ def categorySimp (e : Expr) : MetaM Simp.Result :=
4245
(config := { decide := false })
4346

4447
/--
45-
Given an equation `f = g` between morphisms `X ⟶ Y` in a category (possibly after a `∀` binder),
48+
Given an equation `f = g` between morphisms `X ⟶ Y` in a category,
4649
produce the equation `∀ {Z} (h : Y ⟶ Z), f ≫ h = g ≫ h`,
4750
but with compositions fully right associated and identities removed.
4851
-/
49-
def reassocExpr (e : Expr) : MetaM Expr := do
50-
mapForallTelescope (fun e => do simpType categorySimp (← mkAppM ``eq_whisker' #[e])) e
52+
def reassocExprHom (e : Expr) : MetaM Expr := do
53+
simpType categorySimp (← mkAppM ``eq_whisker' #[e])
5154

5255
/--
5356
Adding `@[reassoc]` to a lemma named `F` of shape `∀ .., f = g`, where `f g : X ⟶ Y` are
@@ -66,9 +69,44 @@ Note that if you want both the lemma and the reassociated lemma to be
6669
`simp` lemmas, you should tag the lemma `@[reassoc (attr := simp)]`.
6770
The variant `@[simp, reassoc]` on a lemma `F` will tag `F` with `@[simp]`,
6871
but not `F_assoc` (this is sometimes useful).
72+
73+
This attribute also works for lemmas of shape `∀ .., f = g` where `f g : X ≅ Y` are
74+
isomorphisms, provided that `Tactic.CategoryTheory.IsoReassoc` has been imported.
6975
-/
7076
syntax (name := reassoc) "reassoc" (" (" &"attr" " := " Parser.Term.attrInstance,* ")")? : attr
7177

78+
/--
79+
IO ref for reassociation handlers `reassoc` attribute, so that it can be extended
80+
with additional handlers. Handlers take a proof of the equation.
81+
82+
The default handler is `reassocExprHom` for morphism reassociation.
83+
This will be extended in `Tactic.CategoryTheory.IsoReassoc` for isomorphism reassociation.
84+
-/
85+
private initialize reassocImplRef : IO.Ref (Array (Expr → MetaM Expr)) ← IO.mkRef #[]
86+
87+
/--
88+
Registers a handler for `reassocExpr`. The handler takes a proof of an equation
89+
and returns a proof of the reassociation lemma.
90+
Handlers are considered in order of registration.
91+
They are applied directly to the equation in the body of the forall.
92+
-/
93+
def registerReassocExpr (f : Expr → MetaM Expr) : IO Unit := do
94+
reassocImplRef.modify (·.push f)
95+
96+
initialize registerReassocExpr reassocExprHom
97+
98+
/--
99+
Reassociates the morphisms in `type?` using the registered handlers,
100+
using `reassocExprHom` as the default.
101+
If `type?` is not given, it is assumed to be the type of `pf`.
102+
-/
103+
def reassocExpr (pf : Expr) (type? : Option Expr) : MetaM Expr := do
104+
let pf ← if let some type := type? then mkExpectedTypeHint pf type else pure pf
105+
mapForallTelescope (forallTerm := pf) fun pf => do
106+
let handlers ← reassocImplRef.get
107+
handlers.firstM (fun h => h pf) <|> do
108+
throwError "`reassoc` can only be used on terms about equality of (iso)morphisms"
109+
72110
initialize registerBuiltinAttribute {
73111
name := `reassoc
74112
descr := ""
@@ -78,17 +116,19 @@ initialize registerBuiltinAttribute {
78116
if (kind != AttributeKind.global) then
79117
throwError "`reassoc` can only be used as a global attribute"
80118
addRelatedDecl src "_assoc" ref stx? fun type value levels => do
81-
pure (← reassocExpr (← mkExpectedTypeHint value type), levels)
119+
pure (← reassocExpr value type, levels)
82120
| _ => throwUnsupportedSyntax }
83121

84-
open Term in
85122
/--
86123
`reassoc_of% t`, where `t` is
87124
an equation `f = g` between morphisms `X ⟶ Y` in a category (possibly after a `∀` binder),
88125
produce the equation `∀ {Z} (h : Y ⟶ Z), f ≫ h = g ≫ h`,
89126
but with compositions fully right associated and identities removed.
127+
This also works for equations between isomorphisms, provided that
128+
`Tactic.CategoryTheory.IsoReassoc` has been imported.
90129
-/
91130
elab "reassoc_of% " t:term : term => do
92-
reassocExpr (← elabTerm t none)
131+
let e ← Term.elabTerm t none
132+
reassocExpr e none
93133

94134
end CategoryTheory
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import Mathlib.Tactic.CategoryTheory.IsoReassoc
2+
3+
open CategoryTheory
4+
namespace Tests.Reassoc
5+
6+
universe v₁ v₂ v₃ u₁ u₂ u₃
7+
8+
variable {C : Type u₁} {D : Type u₂} {E : Type u₃}
9+
[Category.{v₁} C] [Category.{v₂} D] [Category.{v₃} E]
10+
{F : C ⥤ D} {G : D ⥤ E}
11+
12+
@[reassoc]
13+
lemma foo {x y z : C} (f : x ⟶ y) (g : y ⟶ z) (h : x ⟶ z) (w : f ≫ g = h) :
14+
f ≫ g = h := w
15+
16+
@[reassoc]
17+
lemma foo_iso {x y z : C} (f : x ≅ y) (g : y ≅ z) (h : x ≅ z) (w : f ≪≫ g = h) :
18+
f ≪≫ g = h := w
19+
20+
/--
21+
info: Tests.Reassoc.foo_assoc.{v₁, u₁} {C : Type u₁} [Category.{v₁, u₁} C] {x y z : C} (f : x ⟶ y) (g : y ⟶ z) (h : x ⟶ z)
22+
(w : f ≫ g = h) {Z : C} (h✝ : z ⟶ Z) : f ≫ g ≫ h✝ = h ≫ h✝
23+
-/
24+
#guard_msgs in
25+
#check foo_assoc
26+
27+
/--
28+
info: Tests.Reassoc.foo_iso_assoc.{v₁, u₁} {C : Type u₁} [Category.{v₁, u₁} C] {x y z : C} (f : x ≅ y) (g : y ≅ z) (h : x ≅ z)
29+
(w : f ≪≫ g = h) {Z : C} (h✝ : z ≅ Z) : f ≪≫ g ≪≫ h✝ = h ≪≫ h✝
30+
-/
31+
#guard_msgs in
32+
#check foo_iso_assoc
33+
34+
/-- error: `reassoc` can only be used on terms about equality of (iso)morphisms -/
35+
#guard_msgs in
36+
@[reassoc]
37+
def one : Nat := 1
38+
39+
/-- error: `reassoc` can only be used on terms about equality of (iso)morphisms -/
40+
#guard_msgs in
41+
@[reassoc]
42+
def one_plus_one : 1 + 1 = 2 := rfl
43+
44+
@[reassoc]
45+
lemma foo_functor {x y z : C} (f : x ≅ y) (g : y ≅ z) (h : x ≅ z)
46+
(w : F.mapIso (f ≪≫ g) = F.mapIso h) :
47+
F.mapIso (f ≪≫ g) = F.mapIso h := w
48+
49+
/--
50+
info: Tests.Reassoc.foo_functor_assoc.{v₁, v₂, u₁, u₂} {C : Type u₁} {D : Type u₂} [Category.{v₁, u₁} C] [Category.{v₂, u₂} D]
51+
{F : C ⥤ D} {x y z : C} (f : x ≅ y) (g : y ≅ z) (h : x ≅ z) (w : F.mapIso (f ≪≫ g) = F.mapIso h) {Z : D}
52+
(h✝ : F.obj z ≅ Z) : F.mapIso f ≪≫ F.mapIso g ≪≫ h✝ = F.mapIso h ≪≫ h✝
53+
-/
54+
#guard_msgs in
55+
#check foo_functor_assoc
56+
57+
@[reassoc]
58+
lemma foo_functor' {x y z : C} (f : x ≅ y) (g : y ≅ z) (h : x ≅ z)
59+
(w : F.mapIso (f ≪≫ g) = F.mapIso h) {Z : D} (e : F.obj z ≅ Z) :
60+
F.mapIso f ≪≫ F.mapIso g ≪≫ e = F.mapIso h ≪≫ e := (reassoc_of% w) e
61+
62+
-- checking that _assoc expressions are indeed right_associated:
63+
/--
64+
info: Tests.Reassoc.foo_functor'_assoc.{v₁, v₂, u₁, u₂} {C : Type u₁} {D : Type u₂} [Category.{v₁, u₁} C]
65+
[Category.{v₂, u₂} D] {F : C ⥤ D} {x y z : C} (f : x ≅ y) (g : y ≅ z) (h : x ≅ z) (w : F.mapIso (f ≪≫ g) = F.mapIso h)
66+
{Z : D} (e : F.obj z ≅ Z) {Z✝ : D} (h✝ : Z ≅ Z✝) : F.mapIso f ≪≫ F.mapIso g ≪≫ e ≪≫ h✝ = F.mapIso h ≪≫ e ≪≫ h✝
67+
-/
68+
#guard_msgs in
69+
#check foo_functor'_assoc
70+
71+
end Tests.Reassoc

0 commit comments

Comments
 (0)