Skip to content

refactor: route Core.approxPerm through Equiv.Perm.exists_extending_pair (−31 lines)#20

Merged
cameronfreer merged 1 commit into
mainfrom
refactor-approxPerm
May 18, 2026
Merged

refactor: route Core.approxPerm through Equiv.Perm.exists_extending_pair (−31 lines)#20
cameronfreer merged 1 commit into
mainfrom
refactor-approxPerm

Conversation

@cameronfreer

Copy link
Copy Markdown
Owner

Summary

Second in the post-bump series of targeted mathlib-refactor PRs (after #18). Routes Core.approxPerm through the same Equiv.Perm.exists_extending_pair API (mathlib #34599) that PR #18 used for exists_perm_extending_strictMono.

Net diff: 1 file, +14 / −45 (−31 lines) in Exchangeability/Core.lean.

Why this PR is focused on Core.approxPerm only

Core.approxPerm (line 547) and its supporting approxEquiv (line 511) used the exact same pattern that PR #18 already removed from Contractability.lean: hand-built subtype equivalence + Equiv.extendSubtype + extendSubtype_apply_of_mem. The Equiv.Perm.exists_extending_pair mathlib API collapses this directly.

Per agreed scope, the Fin.castLE consistency cleanup is deferred to a tiny separate PR; this one is just the approxPerm rewrite.

What changed

  • Added private theorem exists_approxPerm packaging the existence witness via Equiv.Perm.exists_extending_pair with:
    • f := Fin.castLE (le_permBound (π:=π) (n:=n)) (initial-segment inclusion)
    • g := fun i => ⟨π i, lt_permBound_fin (π:=π) (n:=n) (i:=i)⟩ (π-image inclusion)
    • hf := Fin.castLE_injective _
    • hg := fun _ _ hij => Fin.ext (π.injective (Fin.mk.inj hij)) (lifts ℕ-injectivity of π to Fin n-injectivity of g via Fin.ext)
  • approxPerm body becomes Classical.choose (exists_approxPerm (π:=π) (n:=n)).
  • approxPerm_apply_cast body becomes Classical.choose_spec (exists_approxPerm (π:=π) (n:=n)) i.
  • Removed unused local helper approxEquiv (the only caller was approxPerm itself, now gone).
  • approxPerm_apply_cast_coe unchanged (it's a coercion wrapper around approxPerm_apply_cast).

approxPerm, approxPerm_apply_cast, and approxPerm_apply_cast_coe keep their signatures, so the downstream caller marginals_perm_eq (line 593+) is unaffected. The noncomputable section opened at line 52 already covers the new Classical.choose usage, so no explicit noncomputable keyword is needed.

approxEquiv was a public def with no in-repo callers; removing it is a public-API deletion in the narrow sense. Calling it out explicitly: removes unused local helper approxEquiv; keeps approxPerm and apply lemmas unchanged.

Axiom footprint

Identical. Equiv.extendSubtype already pulled in Classical.choice; switching to Classical.choose of an exists_extending_pair-based proof uses the same axiom.

Verification

Check Baseline (main = bd32ed2) This branch
lake build clean (3531 jobs) clean (3531 jobs)
Axioms (11 theorem decls) standard only standard only
Sorries (Exchangeability + ForMathlib) 0 0
Proof-file churn 1 file, +14 / −45

Out of scope (planned next tiny PR)

Fin.castLE consistency cleanup at two sites that don't touch lemma statements:

  • Exchangeability/Contractability.lean:470 (call site of exists_perm_extending_strictMono)
  • Exchangeability/Util/FinsetHelpers.lean:32

(Contractability.lean:408 is inside a lemma statement via a let, so a Fin.castLE substitution there would be statement-level cleanup, not proof-body-only. Deferred unless statement-level cleanup is explicitly in scope.)

The previous implementation built `approxPerm : Perm (Fin (permBound π n))`
by first constructing a 32-line subtype equivalence `approxEquiv` (between
`{x // x < n}` and `{x // ∃ j : Fin n, x = π j}`) and then calling
`.extendSubtype`. This is exactly the pattern mathlib's
`Equiv.Perm.exists_extending_pair` (landed via mathlib #34599) abstracts.

Refactor:
- Add `private theorem exists_approxPerm` packaging the existence witness
  via `Equiv.Perm.exists_extending_pair` with
  `f = Fin.castLE (le_permBound π n)` and
  `g i = ⟨π i, lt_permBound_fin (π:=π) (n:=n) (i:=i)⟩`.
- `approxPerm` becomes `Classical.choose exists_approxPerm`.
- `approxPerm_apply_cast` becomes `Classical.choose_spec exists_approxPerm i`.
- `approxPerm_apply_cast_coe` (coercion wrapper) is unchanged.

The unused local helper `approxEquiv` is removed. `approxPerm`,
`approxPerm_apply_cast`, and `approxPerm_apply_cast_coe` keep their
signatures and behavior, so downstream callers (`marginals_perm_eq`) are
unaffected. The enclosing `noncomputable section` covers the new
`Classical.choose` usage; no new `noncomputable` keyword is needed.

Axiom footprint is identical: `Equiv.extendSubtype` already pulled in
`Classical.choice`.

- Exchangeability/Core.lean: -31 net lines.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant