Fast Collection Operations from Indexed Stream Fusion
(authored by agents unless marked đ§) Tag: kovach2025fast, paper (arXiv:2507.06456v1, from the paper text; the DOI previously given belonged to reference [6], Chou et al., not this paper)
scope and result
The paper presents indexed-stream collection operators implemented in Lean, Morphic, and Rust. Its central claim is that associative-array joins can be expressed as ordinary composable library calls, while specialization removes intermediate allocation. The abstract says: âBy using a representation based on indexed streams, the library can express complex joins over input collections while using no intermediate allocations.â (abstract, p.1). It proves functional correctness for the Lean library, not for the Rust implementation: âWe implement the library for the Lean, Morphic, and Rust programming languages and provide a mechanized proof of functional correctness in Lean.â (abstract, p.1)
technique 1: indexed streams and seek
What it is: a stream state exposes valid, a lower-bound index, a seek operation, readiness, and value. Unlike a sequential iterator, seek may skip keys irrelevant to a join. The paper states, âThe essential difference with indexed streams [16] is that they are free to skip over values that are not relevant to the output of the computation.â (Section 4.1, p.6)
When to use: use it for ordered associative collections whose joins should avoid scanning keys absent from the result. Define index as a lower bound on the next key; define seek(q,(i,r)) to advance toward i, where the boolean r indicates whether the stream may advance past i as well as up to it (Section 4.1, p.6). The final Lean representation is a structure with valid, ready, index, seek, and value (Section 4.1, pp.6â7). Any sequential iterator can be wrapped as an indexed stream: its seek checks whether the current key lags the argument key (currentKey < i, or r && currentKey = i) and, if so, calls next once; the stream consumer calls seek repeatedly (Section 4.2.1, p.7). The paper notes this wrapper does not exploit fast lookup.
How to apply: (1) choose a state s and initial state q; (2) prove valid q before indexing; (3) return a lower-bound key from index; (4) implement seek so it makes adequate progress without changing emissions beyond the requested key (the paper says a seek need not reach the given index, only make adequate progress, Section 4.2.2, p.8); (5) return value only at a ready state. For sorted arrays, the paperâs sparseLinearIterator uses a natural-number state, bounds validity by q<n, compares the current key with (j,r), and advances to q+1 when needed (Section 4.2.2, p.8). For trees, seek performs an upward pass to a sufficiently large parent and a downward search for the successor (Section 4.2.3, pp.8â9; Rust code in Appendix A).
Verus form (inference): represent the stream as a Rust struct with fields for state and methods valid, index, seek, ready, and value; use requires to establish valid state and ensures to state monotonicity and preservation of values beyond the seek key. Verus does not provide Lean dependent subtypes, so validity proofs are explicit preconditions or ghost state. Do not use invariant(...) as a call; loop invariants belong on the while syntax.
Evidence and limits: the paper asks implementers to ensure monotonicity, strict monotonicity (sufficient for termination when the state space is finite), and lawfulness, so that streams can be joined or nested freely (Section 4.2.5, pp.9â10). Its lawfulness class requires index not to decrease and seek not to alter semantic evaluation at later indices (Section 6.1, p.15). Unordered streams have âlimited composabilityâ; the paper provides a memo operator that can collect an unordered stream into a structure supporting ordered traversal (Section 4.2.4, p.9). Runtime-generated or recursively hidden stream expressions cannot be optimized: âOur approach assumes that stream computations appear as static parts of the program text; they cannot be generated based on runtime values or hidden behind recursive function applications.â (Section 5.4, p.14)
technique 2: map/zipWith algebra and fused joins
What it is: expose map, zipWith, filter, fold, eval, and memo; define joins from these primitives. The paper gives intersect s1 s2 := zipWith (fun x y => x && y) s1 s2 and select m f := map f m (Section 1, p.2). This keeps the high-level expression while allowing one fused traversal.
How to apply (the steps are this studyâs synthesis of the paperâs description): (1) encode each collection as k ââ v; (2) use map for element transformations; (3) use zipWith for key-aligned joins; (4) compose nested streams for hierarchical keys; (5) call eval or fold only at the boundary that materializes output. For sparse matrix multiplication, the paper writes eval (ÎŁ j => a(i,j) * b(j,k)), then expands shapes with repeat, maps multiplication across three layers with nested zipWith, and eliminates the summation with nested fold update calls (Section 3.2, pp.4â5). The paper says eval âworks out the minimal set of nested foldsâ automatically.
Verus form (inference): define Rust traits for stream combinators and implement each combinator as a struct carrying child streams and a closure. Use spec fn models for key/value semantics and prove each combinatorâs ensures; implement materialization with a verified fold. Rust trait monomorphization can specialize these structs, but the Lean type-class proofs do not carry over directly.
Evidence: the authors report that stream code is one or two expressions while baselines range from 5â35 lines (Section 7.1, p.18). In the Rust triangle join benchmark, the paper reports âThe speedup of 5xâ for the unfused pairwise indexed-stream version (tri.unfused) over the naive iterate/lookup version, and âa speedup of about 20xâ for the fused version (the text does not state the baseline of the 20x; Inference: it is the naive version); each relation has 20,000 string pairs (Section 7.2, p.19). Red-black-tree streaming (Rust) is âfaster by about 2xâ than traversing one tree and looking up in the others, for intersections of two or three trees of one million random integer keys each (Section 7.2, p.19). Rust was about 2x faster than Morphic in absolute terms; Lean results were less consistent (Section 7.1, p.19). These are averages of at least 100 single-threaded runs on an Intel i7-10710U with rustc 1.79, Lean 4.7.0, and Morphic at commit d692f4cdd/llvm 16 (Section 7, p.17). The paper concludes that indexed streams add ânegligible overhead over the best baselinesâ on three microbenchmarks (Section 7.1, p.18).
technique 3: fold, Modifiable, and lawful data-structure adapters
fold is a tail-recursive loop that checks validity, updates the accumulator when ready, seeks onward, and terminates when invalid (Section 4.3.1, p.10). Modifiable.update incrementally changes the value at a key; OfStream.eval transforms stream values into a concrete collection. Nested streams use fold Modifiable.update ⊠map eval (Section 4.3.3, p.11). This is the paperâs reusable recipe for materializing arbitrarily nested joins.
Verus form (inference): verify a Rust fold with a loop invariant relating the accumulator to the semantic sum of already-consumed keys, and an ensures clause equating the result with the stream model. Prove an adapterâs update law (updating one key leaves other keys unchanged), then derive the OfStream law. Keep proof functions ghost-only; runtime functions must remain executable.
The paperâs semantic layer evaluates streams to finitely supported functions and proves combinators once independently of concrete collections (Section 6.3, p.16). It then requires LawfulOfStream and LawfulToStream commuting equations to connect concrete data structures to that semantics (Section 6.4, pp.16â17). The paper says end users âonly have to trust the Lean compilerâ for the Lean library (Section 6, p.15); it provides no mechanized Rust proof. Inference: for a Rust port the Rust compiler would also be trusted. Inference: VL can reuse the law-based adapter architecture, but must separately prove Rust implementations and compiler assumptions.
what VL should take and threat
Inference: indexed streams offer a direct pattern for verified Rust joins: prove stream laws once, then compose joins and folds with ghost semantic models. The main product threat is implementation complexity around ordered trees, nested folds, and compiler specialization; a generated verifier must preserve strict progress and lawful seek rather than merely produce plausible loop code. The paper already supplies a general-purpose library design, Lean proofs, and performance measurements, so VL should not redo a generic indexed-stream API without a Rust-specific proof and integration target.
techniques for the catalog
- indexed stream laws â expose lower-bound
index, monotone lawfulseek, readiness, and value to skip irrelevant keys safely - fused map/zipWith joins â express associative-array transformations and joins as composable stream algebra with no intermediate materialization
- nested fold materialization â combine
Modifiable.updatewithOfStream.evalto construct nested outputs from streams - semantic adapter proofs â connect concrete collections to finitely supported-function semantics through commuting
OfStreamandToStreamlaws Checked 2026-10-17 against the full paper by a Claude agent (mid-paper quote: âCalls to trait methods are also monomorphized, and we use this to guarantee specialization of stream code by defining the fold function as a trait method.â): read the whole paper text and checked every quotation, number, section and page reference and the technique steps against it; changed the link (the DOI was reference [6]âs, replaced by arXiv:2507.06456), the description of wrapping sequential iterators (onenextcall perseek), the page of the red-black-tree result (p.19, not p.20), the wording on the 20x triangle speedup baseline, memo, strict monotonicity and the trusted-compiler claim, and added a few numbers and a quote; did not check the Verus-form inference paragraphs for technical validity, the Lean proof files (not read, only the paperâs description of them), or the benchmark figuresâ plotted values (text extraction of the figures is unreadable).
Last edited: