Skip to content

feat(CategoryTheory): add a grind propagator that normalizes morphism composition#39622

Draft
kim-em wants to merge 5 commits into
leanprover-community:masterfrom
kim-em:grind_cat_assoc
Draft

feat(CategoryTheory): add a grind propagator that normalizes morphism composition#39622
kim-em wants to merge 5 commits into
leanprover-community:masterfrom
kim-em:grind_cat_assoc

Conversation

@kim-em

@kim-em kim-em commented May 20, 2026

Copy link
Copy Markdown
Contributor

This PR adds a grind upward propagator on CategoryTheory.CategoryStruct.comp that, every time grind internalizes a composition f ≫ g, pushes the equality f ≫ g = (right-associated form with syntactic identity factors removed) back into the e-graph.

The motivation is the Catalan blow-up of e-matching on Category.assoc: a chain of length n lets e-matching generate all Catalan(n − 1) parenthesizations as e-graph terms. Mathlib already has the runaway documented at Mathlib/CategoryTheory/Iso.lean:146. The propagator commits to a single canonical representative per fresh composition; the normalized form is a fixed point, so it never re-fires on the form it produces — the e-graph grows by O(1) terms per user-visible composition instead of Catalan-many.

Notes:

  • The @[grind =] / @[grind _=_] attributes are removed from Category.id_comp, Category.comp_id, Category.assoc because the propagator subsumes them and they would re-introduce the blow-up.
  • uliftCategory in Category/Basic.lean now provides its three category axioms explicitly, since the cat_disch autoparam used to rely on the e-matching tags above and Category/Basic.lean runs before the propagator file is loaded.
  • The propagator is registered via initialize calling registerBuiltinUpwardPropagator directly. The builtin_grind_propagator macro can't be used downstream in module-mode mathlib (see Implement grind_propagator for downstream / mathlib use leanprover/lean4#13805) and grind_propagator (the user-facing form) is not yet implemented in lean4.
  • The normalizer is hand-written rather than reusing Meta.Simp.main, which has no IR body and crashes the interpreter when invoked from a module-mode downstream file.

Tests in MathlibTest/CategoryTheory/GrindCatNorm.lean cover associativity, identity removal, mixed cases, hypotheses flowing through the normalizer, reducible-alias morphism types, and a long-chain heart-beat guard.

Filed upstream tracking issue: leanprover/lean4#13805

🤖 Prepared with Claude Code

@github-actions

github-actions Bot commented May 20, 2026

Copy link
Copy Markdown

PR summary 998032a1c1

Import changes for modified files

No significant changes to the import graph

Import changes for all files
Files Import difference
Mathlib.CategoryTheory.Tactic.GrindCatNorm (new file) 273

Declarations diff

+ MorAlias
+ catCompPropagatorImpl

You can run this locally as follows
## from your `mathlib4` directory:
git clone https://github.com/leanprover-community/mathlib-ci.git ../mathlib-ci

## summary with just the declaration names:
../mathlib-ci/scripts/pr_summary/declarations_diff.sh <optional_commit>

## more verbose report:
../mathlib-ci/scripts/pr_summary/declarations_diff.sh long <optional_commit>

The doc-module for scripts/pr_summary/declarations_diff.sh in the mathlib-ci repository contains some details about this script.


No changes to strong technical debt.
No changes to weak technical debt.

@github-actions github-actions Bot added the t-category-theory Category theory label May 20, 2026
… composition

This PR adds a `grind` upward propagator on `CategoryTheory.CategoryStruct.comp`
that, every time `grind` internalizes a composition `f ≫ g`, pushes the
equality `f ≫ g = (right-associated form with syntactic identity factors
removed)` back into the e-graph.

The motivation is the Catalan blow-up of e-matching on `Category.assoc`: a
chain of length `n` lets e-matching generate all Catalan(n − 1)
parenthesizations as e-graph terms. Mathlib already has the runaway
documented at `CategoryTheory/Iso.lean:146`. The propagator commits to a
single canonical representative per fresh composition; the normalized form
is a fixed point, so it never re-fires on the form it produces — the
e-graph grows by O(1) terms per user-visible composition instead.

Notes:
- The `@[grind =]` / `@[grind _=_]` attributes are removed from
  `Category.id_comp`, `Category.comp_id`, `Category.assoc` because the
  propagator subsumes them and they would re-introduce the blow-up.
- `uliftCategory` in `Category/Basic.lean` now provides its three category
  axioms explicitly, since the `cat_disch` autoparam used to rely on the
  e-matching tags above and `Category/Basic.lean` runs before the
  propagator file is loaded.
- The propagator is registered via `initialize` calling
  `registerBuiltinUpwardPropagator` directly. The `builtin_grind_propagator`
  macro can't be used downstream in `module`-mode mathlib (see
  leanprover/lean4#13805) and `grind_propagator`
  (the user-facing form) is not yet implemented in lean4 v4.30.0-rc2.
- The normalizer is hand-written rather than reusing `Meta.Simp.main`,
  which has no IR body and crashes the interpreter when invoked from a
  `module`-mode downstream file.

Tests in `MathlibTest/CategoryTheory/GrindCatNorm.lean` cover
associativity, identity removal, mixed cases, hypotheses flowing through
the normalizer, reducible-alias morphism types, and a long-chain heart-beat
guard.

🤖 Prepared with Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kim-em
kim-em force-pushed the grind_cat_assoc branch from acadc36 to 542fff5 Compare May 20, 2026 17:00
kim-em and others added 4 commits May 21, 2026 03:02
- Replace explicit `id_comp/comp_id/assoc` fields on `uliftCategory`
  with `attribute [local grind =] / [local grind _=_]` on the three
  lemmas. The `cat_disch` autoparam can use the e-matching tags
  locally without leaking them to downstream files.
- Drop the implementation note about `Simp.main` from the
  `GrindCatNorm.lean` module docstring.

🤖 Prepared with Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the hand-written `normalizeComp` recursion (and supporting
`mkCompFromShell` / `extractHomEndpoints` helpers) with a single call
to `simpOnlyNames` on `Category.id_comp`, `Category.comp_id`,
`Category.assoc`. Simp already handles congruence, transitivity, and
maximal sharing, so the file shrinks from ~190 to ~110 lines.

The propagator still keeps the cheap `isNormalizedComp` structural
guard so that already-normal compositions don't pay the cost of
invoking simp. When simp fails (e.g. composition under a bare
`CategoryStruct` instance with no synthesizable `Category`), the
propagator silently skips that term rather than aborting `grind`.

Suggested by a second-opinion code review.

🤖 Prepared with Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drop helper `mkCompFromShell`/`extractHomEndpoints`/`combineProofs`
  bookkeeping; everything is one `simpOnlyNames` call.
- Inline `isIdMorphism` into the single structural check.
- Trim the docstring and remove the now-stale caveats section.

No behavioural change. 112 → 81 lines.

🤖 Prepared with Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Second-opinion review nits:
- `isNormal` now uses `match_expr` rather than `isAppOfArity` + positional
  `appFn!.appArg!`/`appArg!` accesses.
- The `catch _` around the `simp` call now logs the exception under
  `trace.grind.catNorm` so future failures aren't silently swallowed.
- Stale comment on the reducible-alias test ("reduces the inferred type
  until it hits Quiver.Hom" — that path no longer exists) replaced with
  a concise one-liner.

🤖 Prepared with Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t-category-theory Category theory

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant