Skip to content

Print huge natVal literals in sub-quadratic time - #52

Open
lordwilsonDev wants to merge 1 commit into
leanprover:masterfrom
lordwilsonDev:fast-natval-decimal
Open

lordwilsonDev wants to merge 1 commit into
leanprover:masterfrom
lordwilsonDev:fast-natval-decimal

Conversation

@lordwilsonDev

@lordwilsonDev lordwilsonDev commented Sep 19, 2026

Copy link
Copy Markdown

Problem

natVal literals are printed with s!"{i}", i.e. Nat.repr, which converts one digit at a time with a division of the whole number: quadratic in the number of digits. A proof term that contains a literal with millions of digits makes the exporter sit at 100% CPU with no output (sample shows Nat.reprFasttoDigitsCore__gmpz_tdiv_q/_r__gmpn_divrem_1).

Real example: results_eliahou_theorem_1_1 in tangentstorm/eliahou-collatz-bounds @ db804ce6305ea99a817f067869607f8b677d895a (Lean v4.28.0, lake env lean4export Results -- results_eliahou_theorem_1_1). The closure contains literals of up to 25,628,966 digits (81 literals over 50 digits). Unpatched: the output stops at 71 MB and then makes no progress for 8+ minutes of CPU (I killed it; I have not shown it never finishes). It looks like a hang, and I first misdiagnosed it as a memoization problem until I sampled it.

Change

natToDecStr splits the number by 10^(18·2^k) recursively, so GMP's sub-quadratic division does the work, and pads the low parts to a fixed width. The output is identical to Nat.repr. Only the natVal case in dumpExprAux changes (+26/−1 lines, Export.lean only).

Evidence

  • With the patch the same export finishes in about 60–120 s: 187,326,147 bytes, complete.
  • The patched output is byte-identical to the unpatched output over the 71,147,000 bytes the unpatched exporter reached.
  • Equivalence test: natToDecStr n == toString n on ~3,000 pseudo-random numbers (up to 40th powers of 64-bit values) plus edge cases (0, 10^18−1, 10^18, 10^36±1, 2^200, 2^5000, 10^100−1): 0 mismatches.
  • The resulting export was type-checked by nanoda (17,464 declarations, no errors) using a companion patch for nanoda's own (also quadratic) decimal parser — see Parse huge decimal nat literals in sub-quadratic time ammkrn/nanoda_lib#36.

What I did not test

I built and tested this on Lean v4.28.0 and v4.34.0. master is on v4.35.0-rc2, which I could not install locally (disk); the patch applies cleanly to master and uses only Array, String.pushn, Nat division/modulo and Id.run, but CI is the first real build on that toolchain. If a newer Lean's Nat.repr is already sub-quadratic for big numbers, this may be unnecessary — I have not checked.

🤖 Generated with Claude Code

`Nat.repr` (used by s!"{i}") converts a Nat to decimal one digit at a time,
each step a division of the whole number: quadratic in the digit count. A proof
term containing a literal with millions of digits stalls the exporter at 100% CPU
inside Nat.reprFast/toDigitsCore/gmpn_divrem_1 with no output.

natToDecStr splits by 10^(18*2^k) so GMP's sub-quadratic division does the work.
Output is identical to Nat.repr.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
lordwilsonDev pushed a commit to lordwilsonDev/fcve that referenced this pull request Sep 19, 2026
…ependent checks

- skills/verifying-lean-proofs: snapshot of the upgraded skill (LESSONS.md, patches/, hardened scripts, BUG-002..005)
- independent-checks/skill-run2: 3 formerly BLOCKED theorems now PASS with the fast-literal tools
- HANDOFF: upstream PRs leanprover/lean4export#52 and ammkrn/nanoda_lib#36

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

nomeata commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Related issue: leanprover/lean4#5771

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.

3 participants