Repository navigation
perf(CounterProgram): write programs once, as List.flatten of their blocks - #2208
Conversation
STCON.Reduction: instructions of the configuration-graph writer were read with `rfl`, which reduces the left-nested appends defining `writer` in exponentially many steps (~0.4 s per lookup). Read them from a flattened copy of its blocks (`writerBlocks`, checked equal by `code_writer`) via `instr_writer`, and rewrite the instance's arcs with a lemma instead of `change`. CondEPPRG: give the `wordStepPredictor` certificate explicitly instead of a 6-9 s `fun_prop` search, avoid slow defeq checks in `ofFn_packSeedEmb`, a `Subsingleton` instance and three `congr 1` steps, and replace all fourteen `nlinarith` calls, which were on goals that are linear given a product fact, with `omega`, `linarith` or a direct lemma. Statements are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG
…locks Counter programs assembled from blocks wrote their code as left-nested `b₀ ++ b₁ ++ ⋯`, and reading a label by `rfl` through those appends was slow (0.67 s per lookup in the STCON writer). #2192 worked around it with a second copy of the writer's code as a list of blocks. Writing each program's code as `List.flatten [b₀, b₁, …]` makes the lookup fast directly (8 ms for the same label), so the copy and its bridging lemmas go. `codeAt_of_prefix` places a block when the code from its label on starts with it; with flattened code, `codeAt_of_prefix ⟨_, rfl⟩` replaces the per-label `interval_cases i <;> rfl`, `codeAt_cons` and `codeAt_of_code_eq` proofs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG
…flatten-622 # Conflicts: # Complexity/Computability/Complexity/Problems/STCON/Reduction.lean
…y claim Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG
edemaine
left a comment
There was a problem hiding this comment.
APPROVE — reviewer-codex-edemaine, independent non-author review of 7e3e0474ed65a0e060b681e293bcdeb966628d85.
Read the complete seven-file diff, actual CounterProgram/instr/CodeAt definitions and representative placement/clocked-table clients. A static comparison confirms that all eight rewritten programs keep exactly the same ordered blocks and instruction operands; register counts are unchanged. All 292 retained explicit declaration signatures match. The prefix lemma derives the needed index bound from IsPrefix.length_le and length_drop before reading the underlying code, including the expected vacuous empty-block case. Its concrete clients replace repeated placement proofs without changing labels, semantics, encodings or resource bounds. Removed private helpers have migrated clients; the existing whole-code placement API remains useful. No abstract-meaning change.
Hygiene/simp, whitespace and canonical-aggregate checks pass. The author reports strict affected-client/full library-test-abstract builds, including the existing rfl comparison with the old coin-table code. I did not repeat Lean elaboration or timing measurements. At one inspection, title passed and library CI and Guide were running. Agent review, not human approval; required final validation remains before integration.
|
Please review at |
Change
Counter programs built from blocks wrote their code as
b₀ ++ b₁ ++ ⋯, which associates to the left. Reading a label withrflthrough those nested appends is slow: 0.67 s per lookup inSTCON.writerand about 40 ms inTwoSAT.decider. #2192 sped upSTCON.Reductionby adding a private second copy of the writer's code as a list of blocks (writerBlocks, withcode_writerandinstr_writerto bridge the two). See #622 comment 6563434936.This PR writes each such program once, as
List.flatten [b₀, b₁, …]. Lean reduces that list one label at a time, soshow P.instr N = _ from rflis fast as written: 8 ms for the sameSTCON.writerlabel, and 2.5–13 ms instead of 7–46 ms forTwoSAT.decider.writerBlocks,code_writerandinstr_writerare deleted. The STCON lookup sites are back to the form they had before #2192, and the 100+ lookup sites in the other files are unchanged.API (
LogSpace/CounterProgram.lean):codeAt_of_prefix (h : l <+: P.code.drop b) : P.CodeAt b l. A block sits at labelbwhen the code frombon starts with it. With flattened code,codeAt_of_prefix ⟨_, rfl⟩places a block in one line. It replaces 38 block-placement proofs, which usedinterval_cases i <;> rfl,codeAt_consfollowed by⟨rfl, rfl, rfl⟩, orcodeAt_of_code_eqwith explicitpre/postand asimpa. It also replaces the private helperscodeAt_forCode(STCON),codeAt_literal(TwoSAT) andcodeAt_header(Words).CounterProgramdocstring records the convention.codeAt_of_code_eqstays (the first-order model checkers use it for their whole code); it needs the code before and after the block spelled out, whichcodeAt_of_prefixavoids. The hypothesis uses core'sList.IsPrefixandList.drop; no new definition.Programs moved to
List.flatten:STCON.writer,TwoSAT.decider,TwoSAT.writer,Words.shiftProgram,Words.rangeProgram,Words.lookupProgram,Unary.unaryProgramandinputCountTableProgram. Each list keeps the old blocks and line breaks, with,in place of++.binaryProgramandltProgramkeep their singleheaderCode ++ […], since one append does not nest.Only definition bodies and proofs change; every theorem statement is unchanged. The new bodies are definitionally equal to the old ones. The existing
rfltest inComplexityTests/ClockedCoinTable.lean, which comparescoinTableProgramwith the old nested-append code, still passes.TwoSAT.MembershipandTwoSAT.Reductionno longer needMathlib.Tactic.IntervalCases.Why
List.flattenand not a simproc. A simproc that evaluatesP.code.getD Non nested appends would leave the programs as they are, but it adds custom meta code, and every lookup site would have to call it instead ofrfl. Writing the program as a flattened list of blocks makes Lean's own reduction fast and needs no new tactic. The lookup is still plainrfl, so noinstrlemma is needed.Timings
time lake env lean <file>: median of 5 runs, alternating before and after on the same machine, with prebuilt imports andLEAN_NUM_THREADS=4. "Before" ismainwith #2192. The machine is shared with other builds, so differences of a few hundredths of a second are noise.Problems.TwoSAT.MembershipProblems.TwoSAT.ReductionConfigurationGraph.InputTableCounterProgram.UnaryCounterProgram.WordsProblems.STCON.ReductionLogSpace.CounterProgramAbout 2 s of each figure is loading imports.
STCON.Reductionkeeps #2192's speed without the second copy.WordsandUnaryhad only shallow programs, so they are unchanged within noise.Per lookup (profiler, single declarations):
++List.flattenSTCON.writer, one labelTwoSAT.decider, labels 5–103decider.CodeAtof one blockinterval_cases i <;> rfl, 34–61 ms kernelcodeAt_of_prefix ⟨_, rfl⟩, 5–24 ms elaboration, 1.5–7.5 ms kernelValidation
scripts/check.sh --quickpassed on the 7 changed modules and their 61 affected targets, including the Immerman–Szelepcsényi abstract and bridge andComplexityTests.ClockedCoinTable. A locallake build --wfail --iofail Complexity ComplexityTests ComplexityAbstracts,lake exe lint-style,mk_all --check,check_hygiene.py --check-simp,check_tidy_surface.pyandcheck_changed_files.py --base origin/mainalso pass. There is no abstract impact: no statement changes, and the only new declaration iscodeAt_of_prefix.Overlap: #2179 also edits
LogSpace/CounterProgram.lean, adding one import line. This PR's hunks there (the docstring paragraph and the new lemma) are elsewhere in the file, so the two do not conflict.Contributes to #622; the issue stays open. Follows #2192.
AI assistance
Profiled and written by
worker-claude-015dlg8k-counterprog(Claude Code, Opus) forcoordinator-claude-015dlg8k. Needs independent review.🤖 Generated with Claude Code
https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG