Repository navigation
feat(Algorithms/WordRAM): Dijkstra's algorithm in O((m + 1) log n) time with a formal abstract - #1098
Conversation
…and ram_eval The statement forms of `wramStmt`, the `macro_rules` that expand `ram[`, `ram_block%` and `ram_stmt%`, and the tactic `ram_eval` with its `macro_rules` are now `scoped` to `Cslib.WordRAM`, like the entry points `ram[`, `ram_block%` and `ram_stmt%` already were. Only the category `wramStmt` and the syntax abbreviation `wramBlock` stay global, since Lean cannot scope them; without the open they parse nothing. Every current user is inside a `Cslib.WordRAM` namespace or opens it before use, so no other file changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…me with a formal abstract Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ent syntax `ExactNotation` writes its rules over the `wramStmt` statements, which are now scoped to `Cslib.WordRAM`, so it opens that scope, and its own `macro_rules` are scoped to `Cslib.Algorithms.WordRAM.Dijkstra`. The bridge's note on syntax in its imports now says that only the category `wramStmt` and the abbreviation `wramBlock` are global. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…global audit `ComplexityTests/Axioms.lean` audits every declaration of the `Complexity` modules against `propext`, `Classical.choice` and `Quot.sound`, and upstream (cslib-community#1004) removed the named guards whose expected list is exactly that set. The three guards here, on `logLinearStatement`, `logLinearSpec` and `heapDijkstra_spec`, were of that kind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… their module docs Add Main-list entries for the declarations that cslib-community#949 item 8 flags as having no outside reference, and a docstring for decodeDist_encodeDist. Doc comments only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rency option in Dijkstra `ListEncode` uses Mathlib's `Fin.sum_univ_def` instead of a private copy of it. `execWithin_append` is stated for any basis and register count, as `appendCode` is. `Invariant` no longer sets `backward.isDefEq.respectTransparency false`: its two path proofs apply `Quiver.Path.addWeight_cons` and `addWeight_nil` with `V := I.Vertex` given. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dRAMAbstract `Runs` is new in `DijkstraAbstract`; the other machine definitions are those of `WordRAMAbstract`. The paragraph is rewrapped; the theorem statement is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two vertices and no edge: the interpreter leaves `0` in the unreachable vertex's output cell within the bound of `heapDijkstra_spec`, where `m + 1 = 1`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Upstream's file template asks for `## References` in each module docstring. `BinaryHeap` and `HeapSift` cite `CLRS2009`; `ListEncode`, `HeapRelax` and `LogLinear` cite `Dijkstra1959` and `CLRS2009`; `ExactNotation`, which has no source of its own, points to the `ram[` notation and `Algolean2026`, as upstream's `WordRAM/Notation` does. Doc comments only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tatement, not Statement `Statement` uses no declaration of `Complexity.Computability.WordRAM.Time`. It needs only the `Fintype` instance on products for `maxWeight`, now imported from `Mathlib.Data.Fintype.Prod`, and `Cslib.Init`, now imported through `Complexity.Init` as upstream's file template asks. `HeapStatement`, whose `LogLinearSpec` is stated with the word-RAM machine, imports `Time`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ts two halves `siftDownBody` was written out in full in `HeapProgram` and again, for its proof, as the private `chooseCode` and `sinkCode` in `HeapSift`. Define the halves once, as the public `siftDownChoose` and `siftDownSink`, and `siftDownBody` as their sequence. `HeapSift` uses the new names, and `siftDownBody_spec` composes the two runs with `ExecWithin.seq`, so the split lemma `siftDownBody_eq` is no longer needed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # Complexity/Computability/WordRAM/Notation.lean
…oglinear-upstream
…Bounds Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
SamuelSchlesinger
left a comment
There was a problem hiding this comment.
reviewer-jetski-5208-1098 for coordinator-jetski-5208b1c7 (agent review, not human approval): APPROVED at 1c0567ee177866fafbbeec56da89d20e30e894e9
Thank you, Renfei, for a careful first contribution. The development is well structured and the PR description is unusually thorough.
What is proved. logLinearStatement and the abstract's dijkstra_logLinear give one word-RAM program over the exact basis (27 registers) and one constant K with the following property. For every directed graph on Fin n with natural-number weights (parallel edges and self-loops allowed), given as adjacency lists with n + 1 offsets, every source s, and every word size w with 8 (n + m + 2) (W + 2) < 2 ^ w, the program halts after at most K (m + 1) (⌊log₂ n⌋ + 1) instructions, halt included. Each output cell outAddr v then holds encodeDist (dist s v). Memory past the input starts at zero, and the input is placed in memory for free. That is why the bound has no separate n term. The PR states this convention honestly, and it is the standard RAM convention. The word-size condition makes w = O(log (n + m + W)), which is enough for the largest finite distance (n - 1) W.
Abstract against the sources. I checked the following, and found no mismatch:
DijkstraAbstract's machine (AluOp,AluOp.eval,Instr,State,Outcome,step,init) matchesWordRAMAbstracttext for text.IsWalk/dist(the infimum over walks inℕ∞,⊤when no walk exists) correspond to the library'sListInstance.dist(the lightest-edge weight matrix withQuiver.Path.addWeight) throughwalkDist_eq.numEdges,maxWeight,offset,encodeandoutAddrmatchListInstancedefinitionally.- The abstract's quantifiers (
∃ r p K, ∀ n G s w) matchLogLinearStatement. #check_abstractruns under#guard_msgswith no allowlist. CI builds and audits it throughComplexityTests/Abstracts/All.lean.
The bridge's port to Code.rand/programOf (isRandFree_of_step, then upstream's step_matches_at) looks right. No existing abstract or catalogue entry changes. The PR adds no catalogue entry, so CI does not render the abstract. In my view the result plausibly meets the headline bar (explicit model and encoding, satisfiable hypotheses, an honest bound), but promoting it is an editorial decision for the maintainers.
Checked instance. In the test graph (n = 3, m = 4, W = 5), encode has 14 = n + 2m + 3 words at addresses 1..14, so outAddr v = 15 + v is the first cell past the input. The word-size condition is 8·9·7 = 504 < 2^10. The interpreter finds [1, 4, 2], that is, distances 0, 3, 1. In the edgeless test, [1, 0] correctly encodes an unreachable vertex. Edge cases: for n = 0 the statement is vacuous, since Fin 0 has no source, and for n = 1 the bound is K (m + 1).
Other checks.
- Sources. I checked the Dijkstra (1959) quotations against the linked scan and the Erickson p. 288 quotation against the linked PDF; both match. I did not consult CLRS.
- Hygiene. No
sorry,axiom,native_decideor heartbeat overrides. The onlyset_optionis a linter switch inside theram_exact_evalmacro, and[simp]is used only on thedecodeDist/encodeDistround-trip lemmas. - Reuse. The new syntax is scoped, as described.
ExecWithin.loop_potentialis the deterministic counterpart of the existingExecRandWithin.loop_potential, not a duplicate. I found no parallel definitions.
Stacking. This branch contains #1091's head ae590c40 unchanged; Notation.lean is identical to that head. #1091 has its own agent approval at that SHA, so land #1091 first, or together with this PR. ci-checks is green at 1c0567ee177866fafbbeec56da89d20e30e894e9, and GitHub reports the branch mergeable.
Non-blocking requests.
- There is no linked issue. Please open a tracking issue, or ask a maintainer to, that records the follow-ups listed in the description: the quadratic version, moving
ExactNotation/appendCode/execWithin_appendintoComputability/WordRAM, narrowingLogLinear's@[expose]section, splittingHeapSift, and the ROADMAP note. A PR description alone is not a durable record for them. - Small nits are inline.
Limits of this review. I did not build locally; I relied on the green CI at this head. I read every public statement and definition, the abstract and the bridge in full, but only sampled the heap and relax proofs (HeapSift, HeapRelax, BinaryHeap), whose correctness Lean checks.
|
|
||
| * [E. W. Dijkstra, *A note on two problems in connexion with graphs*][Dijkstra1959] | ||
| * [T. H. Cormen, C. E. Leiserson, R. L. Rivest and C. Stein, *Introduction to | ||
| Algorithms*][CLRS2009], Section 24.3. |
There was a problem hiding this comment.
nit: The PR description quotes Erickson, Algorithms, §8.6, p. 288, for the O(E log V) binary-heap bound, but says CLRS could not be consulted, and the references here cite CLRS only. The CLRS locator is right: 3rd ed., §24.3 analyses the binary min-heap version as O((V + E) lg V). Still, you could add an Erickson2019 key to references.bib and cite it here and in HeapStatement/LogLinear, so that the reference you actually checked appears in the abstract.
| | c, d => .seq c d | ||
|
|
||
| /-- Running `c` and then `d`. -/ | ||
| theorem execWithin_append {B : Basis} {r w T₁ T₂ : ℕ} {c d : Code B r} {x y z : Data r} |
There was a problem hiding this comment.
nit, follow-up: appendCode and execWithin_append are basis-generic facts about structured Code, with nothing specific to Dijkstra. You already list moving them to Computability/WordRAM as a follow-up. Please record that in an issue, naming these two declarations and ExactNotation, so it doesn't get lost. It doesn't need to happen in this PR.
| (Instance.Inv.eq_dist G.toInstance hy.inv hd v).symm] | ||
| exact (encodeDist_decodeDist _).symm | ||
|
|
||
| /-- **Correctness and running time of the structured program.** -/ |
There was a problem hiding this comment.
nit: This docstring could state the result itself: from .init G.encode, the structured program reaches a state with the encoded distances in the output cells, within 200 (m + 1) (⌊log₂ n⌋ + 1) + 27 instructions, at every word size satisfying the condition. The module docstring already says this, but the declaration's hover text currently gives only the title.
Change
Depends on #1091 (
refactor(Computability/WordRAM): scope the word-RAM statement syntax and ram_eval, head ae590c4: the scoping commit 7c68492 and a merge of upstream/main). This branchcontains that head; until #1091 merges, the diff here includes it.
Upstream merge. This branch merges upstream/main f86ebad through #1091's refreshed head
ae590c4. Upstream's new
Code.randconstructor (#1141) gets one case inexecWithin_append(
HeapSift.lean). The bridge follows #1141's change ofinstrOfto take anoutOfBoundsargument: it translates the library program as
S.programOf q(upstream'sq.map (S.instrOf q.length)) and uses upstream'sstep_matches_atwith a proved lemmaisRandFree_of_step(a step that does not fault is not at arandinstruction, sincedeterministic
randfaults).dijkstra_logLinearandDijkstraAbstract.leanare unchanged.This PR adds Dijkstra's algorithm with a binary heap on the word RAM, and a formal abstract for it.
Upstream has no issue about Dijkstra's algorithm (
gh issue list --search Dijkstra --state allfinds none). This draft proposes the development.
Result.
Cslib.Algorithms.WordRAM.Dijkstra.logLinearStatement : LogLinearStatement(
Complexity/Algorithms/WordRAM/Dijkstra/LogLinear.lean): there are a word-RAM program over theexact basis, with a fixed number of registers, and a constant
Ksuch that the following holds.For every directed graph with
nvertices,medges and natural-number weights (parallel edgesand self-loops allowed), given by adjacency lists with offsets, and every word size
wwith8 (n + m + 2) (W + 2) < 2 ^ w(Wthe largest weight), the program halts after at mostK (m + 1) (⌊log₂ n⌋ + 1)instructions. It then holds the encoded distance from the source toeach vertex
vatoutAddr v(0for unreachable,d + 1for distanced). The proof givesK = 230with 27 registers. One program works for every word size.Source and mapping. Dijkstra (1959), Numerische Mathematik 1, p. 270, states the problem:
"Problem 2. Find the path of minimum total length between two given nodes P and Q." It also says:
"In the solution presented, the minimal paths from P to the other nodes are constructed in order of
increasing length until Q is reached." Remark 1 on the same page: "The above
process can also be applied in the case where the length of a branch depends on the direction in
which it is traversed." (Quoted from the scan at
https://courses.cs.cornell.edu/cs2110/2017sp/online/shortestPath/1959dijkstra.pdf.) The bound is
in Jeff Erickson, Algorithms, 1st ed. (June 2019), Chapter 8 "Shortest Paths", Section 8.6
"Best-First: Dijkstra's Algorithm", subsection "No Negative Edges", p. 288 (free from the author at
https://jeffe.cs.illinois.edu/teaching/algorithms/; quoted from
https://jeffe.cs.illinois.edu/teaching/algorithms/book/08-sssp.pdf): "Altogether Dijkstra
performs at most E DecreaseKey operations, and at most V Insert and ExtractMin operations. Thus,
if we implement the underlying priority queue using a standard binary heap, which supports each
operation in O(log V) time, Dijkstra runs in O(E log V) time." (The procedure names are set in
small capitals there.) There
G = (V, E, w)is "a weighted directed graph" (p. 273). The boundis also in Cormen, Leiserson, Rivest and Stein, Introduction to Algorithms, 3rd ed. (2009),
Section 24.3 (
CLRS2009), which we could not open.How the Lean statement maps the source:
Visn(the vertices areFin n).Eism, the total length of the adjacency lists, soparallel edges count separately.
log VbecomesNat.log 2 n + 1, that is⌊log₂ n⌋ + 1. The+ 1keeps the factor positivefor
n ≤ 1.("No Negative Edges"). Edges are directed, as in Erickson's
Gand Dijkstra's Remark 1.n, the source, then + 1offsets of the lists in an edge array, then each edge as target and weight (
encode).w-bit words. One instruction is one step,whatever its operands. The bound counts every instruction executed, the final
haltincluded.pwithrregisters and one constantK, then alln, graphs,sources and word sizes that satisfy the word-size condition.
input (
outAddr). An unreachable vertex (distance⊤) is encoded as0, and distancedasd + 1.The bound
(m + 1) (⌊log₂ n⌋ + 1)has nonterm and assumes no reachability. Erickson'sO(E log V)has noVterm either, but his initializationInitSSSP(Section 8.3, p. 276) setsdist(v) ← ∞"for all vertices v ≠ s". Here memory past the input starts at0, so theper-vertex arrays need no initialization, and the offsets give the adjacency list of any vertex
directly. So the program touches only the vertices it reaches
(
Dijkstra/HeapStatement.lean:19-21). Them + 1keeps the bound positive form = 0. Thisaccounting, with no initialization pass and an explicit constant, is ours, not the sources'.
Dijkstra (p. 269) restricts to graphs "where at least one path exists between any two nodes"; the
theorem does not.
Machine. The program is a
Program .exact r: every operation computes its exact value, and aninstruction faults on
x - ywithy > x, on/and%by zero, and on a value that is not aword. The algorithm is written as structured
Codeand compiled withCode.program. Theinstruction bound is proved for the structured code with
ExecWithin: rules for sequences,branches and loops (with
ExecWithin.loop_potentialfor the main loop), and symbolic interpretation(
ram_exact_eval, throughExecWithin.of_eval) for individual loop-free blocks.Exec.runsthentransfers the run and its step count to the compiled program. The only change to an existing
library implementation module is
ExecWithin.loop_potentialinComplexity/Computability/WordRAM/Structured.lean. It is a loop rule with a potential functionthat bounds the total cost of all iterations. The aggregators (
Complexity.lean,abstracts/ComplexityAbstracts.lean) andreferences.bibalso change.Files under
Complexity/Algorithms/WordRAM/Dijkstra/:Statement: the problem (Instance,dist,maxWeight,encodeDist).HeapStatement,ListEncode: the adjacency-list input layout,LogLinearSpecandLogLinearStatement.Invariant: Dijkstra's invariant on the abstract distances.ExactNotation,HeapProgram: scoped syntax for exact-basis structured code, and the program.BinaryHeap,HeapSift,HeapRelax: correctness and cost of the heap and the relax step.LogLinear: the main theorem.Abstract.
abstracts/ComplexityAbstracts/DijkstraAbstract.leanstatesdijkstra_logLinearwith its own graph, distance, input and output layout, word-size condition and machine. Apart from
Runs, its machine definitions are those ofWordRAMAbstract.#check_abstractpasses with noallowlist (218 root declarations, 229 dependencies).
DijkstraBridge.leanproves that theabstract's distance is the library's and that the abstract's machine runs as
Cslib.WordRAMoverthe exact basis. It then applies
logLinearStatement.Syntax in the bridge's imports. The bridge imports
LogLinear, whose imports includeExactNotationandComputability/WordRAM/Notation. These declare the syntax the programs arewritten in. With the scoping commit, all their syntax rules,
macro_rulesand tactics arescoped:Notation's toCslib.WordRAM, andExactNotation's (ram_exact[,ram_exact_block%,ram_exact_stmt%,ram_exact_eval) toCslib.Algorithms.WordRAM.Dijkstra.Only the syntax category
wramStmtand the syntax abbreviationwramBlockstay global, becauseLean has no
scopedform for them. Outside those namespaceswramStmthas no rules, so they parsenothing.
DijkstraAbstract.leanopens neither namespace. A scan of the bridge's import closurefinds no other global syntax,
macro_rules, elaborator or unification hint from these files.Tests.
ComplexityTests/WordRAMDijkstra.lean(in the test library's glob) checks:the word-size condition at
w = 10;logLinearSpecapplied to that graph: the run halts within230 · 5 · 2steps and the source'soutput cell holds
1;[1, 4, 2](distances0, 3, 1) within thecost bound of
heapDijkstra_spec(decide +kernel);[1, 0](vertex1unreachable) within the bound
200 · 1 · 2 + 27ofheapDijkstra_spec(decide +kernel).There are no named axiom guards: the global audit
ComplexityTests/Axioms.leancovers thesedeclarations, as for the guards removed in test: drop per-module named axiom guards that repeat the global audit #1004.
Not in this PR (follow-ups).
The quadratic version (adjacency-matrix input,
O(n²)time) and its files.Moving
ExactNotation,appendCodeandexecWithin_appendtoComputability/WordRAM.Narrowing the
@[expose] public sectioninLogLinear.Splitting
HeapSift(863 lines).A ROADMAP note.
Existing notions considered (upstream/main a512b10; CSLib 6ff325e and Mathlib 625d8914, as
pinned in
lake-manifest.json):Instance,Instance.Vertex,Instance.arrowWeight,Instance.dist,Instance.maxWeight,encodeDist): Mathlib'sSimpleGraph.dist(
Mathlib/Combinatorics/SimpleGraph/Metric.lean:206) is the length of a shortest walk in anundirected graph without weights, and
Quiver.shortestPath(
Mathlib/Combinatorics/Quiver/Arborescence.lean:105) minimizes the number of arrows.Upstream has no weighted graph or shortest-path distance:
Cslib.InductiveCounting.Graph(
Complexity/Algorithms/Reachability/InductiveCounting/Semantics.lean:48) is an unweightedBooledge relation, theGraphofComplexity/Computability/Complexity/Problems/Graph.lean:91is an unweighted edge list, and
Complexity/Foundations/Combinatorics/SimpleGraph/Metric.leanextends Mathlib's unweighted graph metric API. Mathlib's
Digraph(
Mathlib/Combinatorics/Digraph/Basic.lean:48) is an unweighted relation without paralleledges. CSLib has none either. So
distreuses Mathlib'sQuiver.PathandQuiver.Path.addWeight(Mathlib/Combinatorics/Quiver/Path/Weight.lean:48) on the quiverwhose arrows are the edges (
Dijkstra/Statement.lean:67-79), with no new path type.maxWeightandencodeDistare this problem's size parameter and output convention.ListInstancewithlightest,toInstance,dist,m,maxWeight,offset,encode,outAddr;ListInstance.dbase): the input is aList ℕplaced byupstream's
State.init, as for every upstream word-RAM program. Upstream has no adjacency-listencoding of a weighted graph; its graph encodings (the adjacency matrix of
USTCONBridge, theedge list above) carry no weights.
toInstancemaps the lists to the weight-matrixInstance, so the distance is defined once.decodeDist,Instance.relax,Instance.Inv,edgeWord,edgesWord,heapKey,HeapShape,Ordered,UpOrdered,DownOrdered,HeapInv, and inLogLineardistOf,visitedOf,remaining,potential,OuterInv): invariants of thisproof. The heap predicates describe three arrays in raw word-RAM memory (
ℕ → ℕ). Upstream hasno word-RAM binary heap:
Complexity/Computability/WordRAM/Heap.leanis a footprint and framecalculus for memory,
Complexity/Algorithms/WordRAM/VanEmdeBoas/is a van Emde Boas tree withits own layout, and
QueueandStackare FIFO and LIFO. Batteries'BinaryHeap(
Batteries/Data/BinaryHeap/Basic.lean:13) is a max-heap held in a LeanArray, not apredicate on machine memory. Its
decreaseKey(Basic.lean:185) takes a heap index, and itkeeps no position array from vertex to index, which Dijkstra's decrease-key needs.
swapCode,siftUpBody,siftUp,siftDownChoose,siftDownSink,siftDownBody,siftDown,extractMin,pushNew,edgeBody,relaxEdges,heapRound,heapSetup,heapDijkstra; the 27HeapRegabbrevs): the programs areCode .exact 27values written inram_exact[…]. The abbrevs name registers as elements ofFin 27, as upstream's word-RAM programs do (for exampleComplexity/Computability/WordRAM/PackedCount.lean:46-54andComplexity/Algorithms/WordRAM/VanEmdeBoas/Program.lean:65-69).appendCode: runs one structured program after another, nesting theCode.seqchain to theright as
ram[…]nests it. Upstream hasCode.seqand the notation, but no function thatappends two
Codevalues. Moving it toComputability/WordRAMis a listed follow-up.LogLinearSpec,LogLinearStatement: the nearest upstream notions areProgram.ComputesInTime(Complexity/Computability/WordRAM/Function.lean:61), whose programreturns one word
f awithhalt, andProgram.AnswersandProgram.DecidesInTime(
Complexity/Computability/WordRAM/Time.lean:70,:196), which return one bit. The outputhere is
nmemory cells, which neither can state without packing them into one word or runningonce per vertex. The spec is built from upstream's
Runs,step,FitsandState.init, andLogLinearStatementquantifies over programs asUniformComputableInTimedoes overProgram.ComputesInTime(Function.lean:81).Graph,IsWalk,dist,numEdges,maxWeight,offset,encode,outAddr,encodeDist,AluOp,Instr,Program,State,Outcome,step,init,Runs): restated because upstream's abstract rules ask for it. Every public referencein an abstract must resolve to the abstract itself, a background library or an allowlisted
module (
.agents/skills/lean-abstract/SKILL.md:34-39), and problem definitions stay in eachabstract, with only
ComplexityAbstracts.EncodingandComplexityAbstracts.Computationshared (
:50); neither has a word RAM. Apart fromRuns, the machine definitions are those ofWordRAMAbstract.DijkstraBridgeproves the correspondence with the library; its helpersWalkLaws,walkDist,haltsViaandstateOfserve only that proof.scripts/parallel_defs.py, run locally onthis branch built at 1c0567e, with
--base upstream/main(932e1bf), reports no candidateparallel definitions among the 102 examined declarations.
Validation and review
Tested revision: 1c0567e, which merges upstream/main f86ebad through #1091's head ae590c4.
git merge-tree --write-treeagainst upstream/main 932e1bf shows no conflict.CI: fork CI (Lean Action CI) on 1c0567e passed:
https://github.com/orbitingflea/complexitylib2/actions/runs/40449722655
Local checks (
LEAN_NUM_THREADS=2) at 1c0567e, all passed:scripts/check.sh(all six steps: build,mk_all --check, test, lint, lint-style,checkInitImports);python3 -B scripts/check_hygiene.py --check-simp,python3 -B scripts/check_tidy_surface.py,python3 -B scripts/check_changed_files.py --base upstream/main;lake build --wfail --iofail ComplexityAbstracts.DijkstraAbstract ComplexityAbstracts.DijkstraBridge;python3 -B scripts/build_abstracts.py --check(this PR adds no catalogue entry: 19 abstracts,29 headline theorems, as on upstream/main);
python3 -m unittest discover -s scripts -p 'test_*.py'(353 tests, 7 skipped) andpython3 -B -m unittest discover -s scripts -p 'test_*abstract*.py'(80 tests, 4 skipped);#print axiomsfordijkstra_logLinearandlogLinearStatement:[propext, Classical.choice, Quot.sound]. Nosorry, new axiom ornative_decide.Review (all by AI agents):
log-linear proof, a trimmed problem file, the tests, a complete syntax comment in the bridge and
fixes to the abstract's wording.
5.5) found no code or mathematical blocker. Both asked for this description to quote the source
and map it to the Lean statement, and Claude Opus 5.5 asked for an accurate AI disclosure.
Codex asked for an accurate account of the cost proof. Claude Opus 5.5 also listed small code
points. Revision b0e071e resolved them:
ListEncodeuses Mathlib'sFin.sum_univ_definstead of a private copy;
execWithin_appendis stated for any basis and register count;Invariantno longer setsbackward.isDefEq.respectTransparency; the abstract's sentence onWordRAMAbstractnow namesRunsas the one new definition; and the edgeless test above wasadded. The description gained the source paragraph, the cost account and the AI disclosure.
(gemini-4-argon-high), verdict ready. Its non-blocking points: six Dijkstra modules lacked the
## Referencessection of upstream's file template,StatementimportedComplexity.Computability.WordRAM.Timewithout using it, and the public helper surface islarge.
found the code clean. Their remaining points were all on this description: the existing notions
considered, a verbatim source quotation for the bound, and the upstream hash.
## References(citingDijkstra1959andCLRS2009;ExactNotationpoints to the
ram[notation andAlgolean2026);Complexity.Computability.WordRAM.Timemoved fromStatementtoHeapStatement, whoseLogLinearSpecuses it;Statementnow importsMathlib.Data.Fintype.ProdandComplexity.Initinstead;siftDownBodyis defined from the new publicsiftDownChooseandsiftDownSink, whichreplace the private copies
chooseCodeandsinkCodeinHeapSift;current upstream hash.
The public helper surface is listed above as a follow-up (moving
appendCodeandexecWithin_append, narrowing the public section ofLogLinear).gpt-6.1-sol (ready), Claude Opus 5.5 (ready after fixes to two line locators in this
description) and Gemini 4 Argon (gemini-4-argon-high; ready). Their points on this description
are applied here: one locator fixed (the other was already correct), and wording on the
graph-metric file,
Digraphand Batteries'decreaseKey.(d5cde69, eb3db42, af762a7): independent AI agent reviews by Codex gpt-6.1-sol, Claude Opus
5.5 and Gemini 4 Argon (gemini-4-argon-high), all ready. Their non-blocking points are applied in
1c0567e: the bridge's module doc now names
step_matches_atandprogramOf, therandcaseof
execWithin_appendnames its fieldsdst srcas upstream does, and this description givesHeapSift's new length. 1c0567e changes only that comment and those binder names.Headline abstracts
abstract or catalogue entry changes. This PR adds
DijkstraAbstractandDijkstraBridgetoComplexityAbstracts.lean. It adds nocatalogue.jsonentry and no README row. Whether theresult is a headline is left to the maintainers.
reviews only, as listed above (fork revisions aff3d3a and later; final round on 5768c1f;
Gemini 4 Argon and the confirmation round on b0e071e). The theorem statement
dijkstra_logLinearhas not changed since those reviews. Revision b0e071e changed one sentenceof the abstract's introduction (the
WordRAMAbstractcomparison above). After it, onlyeb3db42 and 1c0567e changed a file of this PR under
abstracts/:DijkstraBridge.lean, forthe upstream merge (see Change) and its module doc;
DijkstraAbstract.leanis unchanged. No human review yet.does not render the abstract because it is not in the catalogue. An AI agent rendered it
locally with
scripts/build_abstracts.py(render_entryon an in-memory entry) at 2419d5a(6 pages). That render was not rerun at 1edeec0, where one sentence of the introduction differs.
AI assistance
Written with Claude Code (Claude Opus 5.5), under Renfei Zhou's direction. Claude Code wrote the
Lean code, the proofs and this text. All reviews listed are AI agent reviews; no human has reviewed
this PR yet.
🤖 Generated with Claude Code