Repository navigation
Fetch walk rows a run at a time, not a segment at a time - #81
Merged
Merged
Conversation
Increment E, #75. `_write_walks_mc` called `fetch(".", id-1, id)` once per `S` line; it now reads the GFA through in one pass, remembers the segment ids, and fetches each run of consecutive ids in a second. Across the five committed fixtures that is 1,226 lookups down to 11. #74 measured what a lookup costs: 770 point fetches take 90.0 s where two range fetches take 0.31 s, and the parse inside them is 0.12 s of that. The parse body is unchanged, character for character, and so is the W-line emission phase. `contiguous_runs` is not new either — the v1 path thirty lines above has grouped ids into runs since before this was written, and the v2 path never picked it up. One deliberate departure from docs/increment-e-batched-walk-reads §3, which proposed grouping `sorted(segment_ids)` with an ascending-ids assertion and a per-segment fallback where that failed. Grouping in S-line order instead makes a run form only where the file already ascends by one, so rows always arrive in the order the per-segment loop saw them — unconditionally, with no second path to keep in agreement. That matters because `coord_table` is built by appending and the emission phase's sort is stable, so parse order breaks ties. On the five fixtures the two are identical; the difference is that this one cannot reorder a W line on a fixture nobody has seen yet. The acceptance oracle is the fixtures' own W lines, byte for byte. That is possible without the multi-gigabyte derivative because the output determines the input closely enough to invert: a W line gives an assembly, a contig and an ordered walk, the S lines give lengths, and the coordinates accumulate. Rebuild the derivative from a fixture, feed it back, and the same W lines must come out. All five do. Verified with mutation: an off-by-one on the run start fails 7 tests, and reverting to per-segment fetches fails 5. Grouping `sorted(...)` still passes, because all five fixtures ascend — which is exactly why `_contiguous_runs`'s ordering is pinned by its own unit test instead. test_an_interrupted_extraction_leaves_no_subgraph now uses ids 1,2,5. Its stand-in fails on the second fetch, and 1,2,3 is now a single fetch, so there was no longer a midway for it to fail at. Duplicate handling is preserved bug for bug, deliberately — it is #76's, and the byte-identical oracle depends on it staying wrong. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013Q66fG2JF4diSxfYMEsGCW
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Increment E. Closes #75. Unblocked by #74, whose write-up is #80.
_write_walks_mccalledfetch(".", id-1, id)once perSline. It now reads the GFA through in one pass, remembering the segment ids, and fetches each run of consecutive ids in a second pass. Across the five committed fixtures that is 1,226 lookups down to 11.#74 measured what a lookup costs on the 8.0 kb region: 770 point fetches take 90.0 s where two range fetches take 0.31 s, and the parse inside them is 0.12 s of that.
The parse body is unchanged character for character, and so is the
W-line emission phase.contiguous_runsis not new — the v1 path thirty lines above has grouped ids into runs since before this was written, and the v2 path never picked it up.One deliberate departure from the design doc
docs/increment-e-batched-walk-reads§3 proposed groupingsorted(segment_ids), and §4(b) noted the risk that comes with it — parse order changes fromS-line order to ascending id,coord_tableis built by appending, and the emission phase's sort is stable, so parse order breaks ties. Its mitigation was an ascending-ids assertion with a per-segment fallback.This groups in
S-line order instead. A run then forms only where the file already ascends by one, so rows always arrive in the order the per-segment loop saw them — unconditionally. Difference (b) stops existing rather than being guarded, and there is no second code path to keep in agreement. On the five fixtures the two produce identical runs; the difference is that this one cannot reorder aWline on a fixture nobody has captured yet.The oracle
Byte-identical
Wlines across all five committed fixtures, as #75 asked — and running in CI, which needed solving, because the realhprc-v2.0-mc-grch38-v2.2.walk.gzis team-generated, multi-gigabyte, and on no machine that runs these tests. That is the same reason #74 had to run on the server._write_walks_mc's output determines its input closely enough to invert: aWline names an assembly, a contig, a start and an ordered walk, theSlines give every segment's length, and a walk is contiguous by construction, so each segment's coordinate accumulates. Rebuild a derivative from a fixture's ownWlines, feed it back in, and the sameWlines must come out. All five do.Its one gap is stated in the test module: column 5 (repeat placements) is rebuilt as
., because aWline cannot say which coordinates arrived that way. Harmless for the round trip — a dup that survived into the real output was reinserted into the regular lists and comes back as a regular placement — but it means the dedupe atmain.py:373runs against an empty table there.test_the_duplicate_quirks_are_preservedcovers it head-on instead, and pins some genuinely strange behaviour: a surviving dup gets reinserted next to the identical regular placement, and the gap check then splits one unbroken path into twoWlines. That is #76's, not this ticket's, and the byte-identical oracle depends on it staying exactly that wrong.Verified by mutation
sorted(segment_ids)(the doc's version)The third passing is the honest limit and is stated as such: all five fixtures ascend, so sorting is a no-op on them.
test_runs_break_on_a_gap_and_follow_file_orderpins the ordering directly instead.Also
test_an_interrupted_extraction_leaves_no_subgraphnow uses ids1,2,5. Its stand-in fails on the second fetch, and1,2,3is now a single fetch, so there was no longer a midway for it to fail at. The gap restores the test's meaning, with a comment saying why.log.infoper request with the segment count and the run count, so the win is legible in production rather than only in a benchmark.vg, which isn't on this machine).Not in this PR
293.8xis a warm-cache ratio and is not published as a speedup.GenerateWalksMC's stage time on a cold ~10 kb region against the published 30.1 s of a 38.9 s request needs the server, like Split GenerateWalksMC's per-segment cost between the lookup and the parse #74 did.chr1:25,331,646is 280 segments across a span of 5,569 in 5 runs, where a range fetch decompresses far more rows than it uses. Correctness there is covered above; whether it is a speed win is the roadmap's open bullet, and it is the measurement that would set the gap-coalescing parameter §6 ships at zero. Best taken against this implementation.🤖 Generated with Claude Code
https://claude.ai/code/session_013Q66fG2JF4diSxfYMEsGCW