Skip to content

feat(ForMathlib): per-scale count↔volume bridge (1/2) - #17

Open
CBirkbeck wants to merge 14 commits into
masterfrom
lpc-1
Open

CBirkbeck wants to merge 14 commits into
masterfrom
lpc-1

Conversation

@CBirkbeck

@CBirkbeck CBirkbeck commented Jun 18, 2026 •

Copy link
Copy Markdown
Owner

Part 1 of 2 — the former whole-file PR #11, split into stacked slices. Stacked on the IndexImageCount stack (PR 4/4) — review that first; GitHub retargets this base to master as the parents merge.

Adds CebotarevDensity/ForMathlib/LatticePointCount.lean with the per-scale count↔volume bridge and the two private helpers it consumes (bundled because the bridge is the module's first public result — a pure-helper slice would be an all-private module):

  • index_mem_image_frontier_of_box_meet_not_subset — a box meeting but not contained in s has its index in the frontier image.
  • measureReal_biUnion_box — the real measure of a finite union of grid boxes is card · n⁻ᵈ.
  • abs_card_inter_sub_volume_mul_pow_le — #(s ∩ n⁻¹·ℤ^ι) differs from vol(s)·nᵈ by at most the number of n⁻¹ℤ^ι grid cells meeting ∂s.

The O(nᵈ⁻¹) boundary-cell bound it consumes (ncard_index_image_frontier_le) lives in IndexImageCount.lean (the parent stack). The terminal export follows in part 2. Wired into the umbrella CebotarevDensity import.

Builds green on the v4.31.0-rc1 / mathlib-master pin (identical to master's pin).

🤖 Generated with Claude Code


CBirkbeck and others added 5 commits June 18, 2026 17:12
First slice of the index-image counting bounds (formerly the whole-file PR #10,
split per review into ~50-LOC stacked PRs). Adds `IndexImageCount.lean` with the
finiteness foundation:

* `ceil_natCast_mul_le_ceil_natCast_mul_add` — ceiling subadditivity helper.
* `abs_sub_le_one_div_of_ceil_natCast_mul_eq` — same-cell points are `1/n`-close.
* `setFinite_index_image_of_isBounded` — the `index n`-image of a bounded set is finite.

The diameter bound and the `O(nᵈ⁻¹)` boundary-cell counts are the stacked follow-ups
(2/4–4/4). Wired into the umbrella `CebotarevDensity` import.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Second slice (stacked on 1/4). Adds:

* `ncard_index_image_le_of_diam_le` — a set of diameter `≤ r` meets at most
  `(2⌈n·r⌉₊ + 1)ᵈ` cells of the `n⁻¹ℤ^ι` grid.

Consumes the `1/n`-closeness helper from 1/4. The `O(nᵈ⁻¹)` chart/frontier counts
follow in 3/4–4/4.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Third slice (stacked on 2/4). Adds:

* `ncard_index_image_chart_le` — for one `M`-Lipschitz chart `φ` of `[0,1]ᵈ⁻¹`,
  the number of `n⁻¹ℤ^ι` grid cells meeting `φ '' [0,1]ᵈ⁻¹` is `O(nᵈ⁻¹)`.

Consumes the diameter bound from 2/4. The frontier-cover sum follows in 4/4.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Final slice (stacked on 3/4) — completes `IndexImageCount.lean`. Adds:

* `ncard_index_image_frontier_le` — if `∂s` is covered by `m` images
  `φⱼ '' [0,1]ᵈ⁻¹` of `M`-Lipschitz maps, the number of `n⁻¹ℤ^ι` grid cells
  meeting `∂s` is `O(nᵈ⁻¹)`, with explicit constant `m · (2⌈M⌉₊+1)ᵈ · 2ᵈ⁻¹`.

Sums the single-chart count from 3/4 over the cover. This is the boundary-cell
input the effective lattice-point count (next stack) consumes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First slice of the effective lattice-point count (formerly the whole-file PR #11,
split into ~50-LOC stacked PRs). Stacked on the IndexImageCount stack. Adds
`LatticePointCount.lean` with the count↔volume bridge and its two private helpers
(kept together since the bridge is the module's first public result):

* `index_mem_image_frontier_of_box_meet_not_subset` — a box meeting but not contained
  in `s` has its `index` in the frontier image.
* `measureReal_biUnion_box` — the real measure of a finite union of grid boxes.
* `abs_card_inter_sub_volume_mul_pow_le` — `#(s ∩ n⁻¹ℤ^ι)` differs from `vol(s)·nᵈ`
  by at most the number of grid cells meeting `∂s`.

The terminal export follows in 2/2. Wired into the umbrella `CebotarevDensity` import.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@xroblot

xroblot commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Merge and fix the conflicts

# Conflicts:
#	CebotarevDensity.lean
#	CebotarevDensity/ForMathlib/IndexImageCount.lean
@CBirkbeck

Copy link
Copy Markdown
Owner Author

Merged idx-4 and resolved the conflicts: kept the LatticePointCount import in the umbrella, and took idx-4's IndexImageCount.lean (this branch was carrying a stale pre-reorder copy). Full build is green. (Note: idx-4 itself is a bit behind idx-3 — it doesn't yet have the abs_sub 0 < n fix from PR #15 — so that'll flow down the stack separately as the lower PRs land.)

@xroblot

xroblot commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Merge with master

@CBirkbeck
CBirkbeck changed the base branch from idx-4 to master July 13, 2026 08:45
@CBirkbeck

Copy link
Copy Markdown
Owner Author

Done in 39c61fb — merged master into lpc-1 and retargeted this PR's base from idx-4 to master (idx-4 / #16 is now merged, so it's an ancestor of master).

The merge was clean (no conflicts); it bumps the toolchain v4.31.0-rc1 → v4.32.0-rc1 in line with master. Net diff vs master is the intended 2-file slice — the LatticePointCount import in CebotarevDensity.lean plus CebotarevDensity/ForMathlib/LatticePointCount.lean. lake build CebotarevDensity is green against v4.32 (LatticePointCount compiles clean; the only sorry warnings are the pre-existing headline-theorem placeholders inherited from master).

Comment thread CebotarevDensity/ForMathlib/LatticePointCount.lean Outdated
Comment thread CebotarevDensity/ForMathlib/LatticePointCount.lean Outdated
Comment thread CebotarevDensity/ForMathlib/LatticePointCount.lean Outdated
Comment thread CebotarevDensity/ForMathlib/LatticePointCount.lean Outdated
… code)

- trim module docstring to this slice: drop the exists_... terminal-export
  bullet (it lands in lpc-2 / #18) and reword the intro to the per-scale
  bridge; remaining refs (tendsto_card_div_pow_atTop_volume,
  abs_card_inter_sub_volume_mul_pow_le, ncard_index_image_frontier_le) all exist
- remove unneeded classical (by_cases is already classical in mathlib)
- remove unused hn0 positivity have
- drop unused set-equation names with hInside / hMeet / hBd; keep hTag, hV

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread CebotarevDensity/ForMathlib/LatticePointCount.lean
Addresses xroblot review on PR #17: the abs_card_inter_sub_volume_mul_pow_le
proof was too long. Extract three reusable public lemmas and compose them:
- natCard_inter_smul_span_eq_ncard_setOf_tag_mem: lattice-point count = tag count
- ncard_setOf_box_subset_le_measureReal_mul_pow: sandwich lower bound
- measureReal_mul_pow_le_ncard_setOf_box_meet: sandwich upper bound

The main theorem now assembles the count identity, the two volume bounds, and
the combinatorial Inside/Tag/Meet sandwich. The tag lemma needs only [Finite ι]
(basisFun is Finite; tag is Fintype-free) per the standard-set linter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread CebotarevDensity/ForMathlib/LatticePointCount.lean Outdated
Comment thread CebotarevDensity/ForMathlib/LatticePointCount.lean Outdated
… + hnsub)

Group the two lemmas that don't use `[Fintype ι]`
(`index_mem_image_frontier_of_box_meet_not_subset`,
`natCard_inter_smul_span_eq_ncard_setOf_tag_mem`) above a
`variable [Fintype ι]` line introduced right before the first result
that uses it (`measureReal_biUnion_box`), dropping both `omit [Fintype ι] in`.

Also simplify `index_mem_…`: after `rw [Set.not_subset] at hnsub`, `hnsub`
is already the witness, so obtain from it directly instead of re-deriving
the `∩ sᶜ` nonempty form.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CBirkbeck added a commit that referenced this pull request Jul 19, 2026
Addresses xroblot review on PR #17 (lpc-1):
- remove unneeded classical (by_cases is already classical in mathlib)
- remove unused hn0 positivity have (nothing references it)
- drop unused set-equation names with hInside / hMeet / hBd; keep hTag, hV
  which are used

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CBirkbeck added a commit that referenced this pull request Jul 19, 2026
Addresses xroblot review on PR #17: the abs_card_inter_sub_volume_mul_pow_le
proof was too long. Extract three reusable public lemmas and compose them:
- natCard_inter_smul_span_eq_ncard_setOf_tag_mem: lattice-point count = tag count
- ncard_setOf_box_subset_le_measureReal_mul_pow: sandwich lower bound
- measureReal_mul_pow_le_ncard_setOf_box_meet: sandwich upper bound

The main theorem now just assembles the count identity, the two volume bounds,
and the combinatorial Inside/Tag/Meet sandwich. The tag lemma needs only
[Finite ι] (basisFun is Finite; tag is Fintype-free) per the standard-set linter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread CebotarevDensity/ForMathlib/LatticePointCount.lean Outdated
Comment thread CebotarevDensity/ForMathlib/LatticePointCount.lean Outdated
…op have name)

Per xroblot's review on `abs_card_inter_sub_volume_mul_pow_le`:
- anonymise `have hne : NeZero n` → `have : NeZero n` (the name was only used
  as an instance, so naming it is unnecessary);
- `set` → `let` for `Inside`/`Meet`/`Bd`/`Tag` (set's rewriting / equation
  hypotheses aren't needed here; the final `linarith` still closes).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

variable [Fintype ι]

private lemma measureReal_biUnion_box (n : ℕ) [NeZero n] (t : Finset (ι → ℤ)) :

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That looks like a lemma that could be useful elsewhere. Can you make it non private and see if you can use it somewhere else

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 693cd09 — dropped private from index_mem_image_frontier_of_box_meet_not_subset and added a docstring. Searched the codebase for another box/frontier-membership argument it could replace (IndexImageCount.lean, Cyclotomic.lean's preconnectedness use); found no other current call site with this exact shape, so it's exposed for future reuse rather than swapped in anywhere. (Also on development in d190652.)

…ox_meet_not_subset

Address xroblot review: expose the box-meets-frontier lemma for reuse elsewhere.

Co-Authored-By: Claude <noreply@anthropic.com>
Comment on lines +128 to +132
≤ ({ν : ι → ℤ | ((box n ν : Set (ι → ℝ)) ∩ s).Nonempty}.ncard : ℝ) := by
have hnpow : (0 : ℝ) < (n : ℝ) ^ Fintype.card ι :=
pow_pos (by exact_mod_cast Nat.pos_of_ne_zero (NeZero.ne n)) _
have hMeetSub : {ν : ι → ℤ | ((box n ν : Set (ι → ℝ)) ∩ s).Nonempty} ⊆ index n '' s := by
rintro ν ⟨x, hxb, hxs⟩

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
≤ ({ν : ι → ℤ | ((box n ν : Set (ι → ℝ)) ∩ s).Nonempty}.ncard : ℝ) := by
have hnpow : (0 : ℝ) < (n : ℝ) ^ Fintype.card ι :=
pow_pos (by exact_mod_cast Nat.pos_of_ne_zero (NeZero.ne n)) _
have hMeetSub : {ν : ι → ℤ | ((box n ν : Set (ι → ℝ)) ∩ s).Nonempty} ⊆ index n '' s := by
rintro ν ⟨x, hxb, hxs⟩
have hMeetSub : {ν : ι → ℤ | ((box n ν : Set (ι → ℝ)) ∩ s).Nonempty} ⊆ index n '' s := by
rintro ν ⟨x, hxb, hxs⟩
exact ⟨x, hxs, mem_box_iff_index.mp hxb⟩
have hFin : {ν : ι → ℤ | ((box n ν : Set (ι → ℝ)) ∩ s).Nonempty}.Finite :=
(setFinite_index_image_of_isBounded n hbdd).subset hMeetSub

This code is also used in a similar way L170-173. It should probably be a lemma

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in dc87809 — extracted setFinite_setOf_box_meet_nonempty (only needs [Finite ι], so it lives above the variable [Fintype ι] line to avoid an unused-instance lint) and swapped it in at both call sites: hFin in measureReal_mul_pow_le_ncard_setOf_box_meet (dropping the now-redundant hMeetSub) and hMeetFin in abs_card_inter_sub_volume_mul_pow_le. (Also on development in a11de5b.)

Dedupe the "Meet-set injects into index n '' s, hence finite" argument
that was inlined both in measureReal_mul_pow_le_ncard_setOf_box_meet
and in abs_card_inter_sub_volume_mul_pow_le, per xroblot review.

Co-Authored-By: Claude <noreply@anthropic.com>
Comment on lines +42 to +44
/-- If a closed box meets `s` but is not contained in `s`, its tag lies in the image of the
frontier of `s` under `index n`: the box, being connected, cannot split between the interior
and the exterior of `s` without crossing the frontier. -/

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This docstring should say "index" instead of "tag"

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in dd3c659 — the lemma concludes ν ∈ index n '' frontier s, so the docstring now says "its index lies in the image" instead of "tag". (Also on development in 8575c9d.)

Comment on lines +54 to +57
have hcon' : (box n ν : Set (ι → ℝ)) ∩ frontier s = ∅ := by
rw [Set.eq_empty_iff_forall_notMem]
rintro x ⟨hxb, hxf⟩
exact hcon ⟨x, hxf, mem_box_iff_index.mp hxb⟩

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
have hcon' : (box n ν : Set (ι → ℝ)) ∩ frontier s = ∅ := by
rw [Set.eq_empty_iff_forall_notMem]
rintro x ⟨hxb, hxf⟩
exact hcon ⟨x, hxf, mem_box_iff_index.mp hxb⟩
have hcon' : (box n ν : Set (ι → ℝ)) ∩ frontier s = ∅ :=
Set.eq_empty_iff_forall_notMem.mpr fun x ⟨hxb, hxf⟩ ↦ hcon ⟨x, hxf, mem_box_iff_index.mp hxb⟩

You should be able to do the same kind of golf at many places in this PR and elsewhere

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in dd3c659 — hcon' is now the one-line Set.eq_empty_iff_forall_notMem.mpr fun x ⟨hxb, hxf⟩ ↦ hcon ⟨x, hxf, mem_box_iff_index.mp hxb⟩ as suggested. Will look for the same pattern elsewhere in a follow-up pass rather than bundling it into this reply. (Also on development in 8575c9d.)

…ine hcon')

Docstring said "tag" but the conclusion is about `index n`; corrected. Golfed
hcon' to a single-expression proof per suggestion.

Co-Authored-By: Claude <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

2 participants