perf(spectrum): min_intv-truncated backward reseed span via RC-downward scan - #27
Conversation
…rd scan Adds mem_search_backward_truncated_span_rc: the largest left-extension span L in [anchor_len, span_max] whose length-L window occurs >= min_intv times, in ONE call. Walks the reverse-complement strand DOWNWARD from the maximal extension — each left base prepended to the forward pattern is a base appended to its RC, so RC prefixes nest (forward intervals don't) and occ(RC(P)) == occ(P); the interval [lo, hi) is carried across decreasing L by a linear scan capped at min_intv, replacing the binary search that issued a full forward mem_search per step (the consumer's zz_left_span_reseed, ~2.9x fewer SA probes). Model-launched; the .isa-seeded path lands with the interval variant. Byte-identical to the brute-force truncated_span_oracle (new proptest mem_search_backward_truncated_span_rc_equals_oracle). Derives the in-interval seed from forward_maximal_len's insertion point with one shares_prefix probe (#26 returns the insertion point, not the in-interval neighbor). v0.3 perf series.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR adds a new RC-backward truncated-span search primitive that finds the largest left-extension span from an anchor position whose corresponding reverse-complement pattern interval contains at least a minimum number of occurrences. The method integrates pattern validation, SA interval seeding via prefix-sharing, iterative outward expansion, and downward span iteration, with comprehensive property-based test coverage against a brute-force oracle. ChangesRC-backward truncated span
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Add `forward_truncate_below_maximal`, the FORWARD analogue of the TRUNC_IV backward family (#27/#29/#30) for the reseed's right bound. Given a query and its already-found maximal match whose `occ < min_intv`, it finds the largest length L < match_len whose prefix occurs >= min_intv times and returns that interval (or the zero MemMatch when none qualifies). Forward PREFIX intervals nest directly (fixed start, shrinking end: query[..L] is a superset of query[..L+1]), unlike the LEFT reseed where prepending bases breaks forward nesting and forces the RC walk. So the walk carries [lo, hi) outward from the maximal interval as L shrinks — a short shares_prefix scan capped at min_intv per step, no model launch. `want_interval == false` returns only L* (the driver's next_pivot use); `true` recovers the exact interval by galloping find_boundary out from the capped walk's interior seed (seed-independent, so byte-identical to a cold mem_search). Adapted to main: 6-arg shares_prefix/ref_less (no keyed_compare_mask). Verified byte-identical against an independent per-length mem_search oracle across reference-lifted queries and a spread of min_intv. Pub primitive with no in-tree caller until the collect reseed module lands (the proptest is its only consumer).
Add `forward_truncate_below_maximal`, the FORWARD analogue of the TRUNC_IV backward family (#27/#29/#30) for the reseed's right bound. Given a query and its already-found maximal match whose `occ < min_intv`, it finds the largest length L < match_len whose prefix occurs >= min_intv times and returns that interval (or the zero MemMatch when none qualifies). Forward PREFIX intervals nest directly (fixed start, shrinking end: query[..L] is a superset of query[..L+1]), unlike the LEFT reseed where prepending bases breaks forward nesting and forces the RC walk. So the walk carries [lo, hi) outward from the maximal interval as L shrinks — a short shares_prefix scan capped at min_intv per step, no model launch. `want_interval == false` returns only L* (the driver's next_pivot use); `true` recovers the exact interval by galloping find_boundary out from the capped walk's interior seed (seed-independent, so byte-identical to a cold mem_search). Adapted to main: 6-arg shares_prefix/ref_less (no keyed_compare_mask). Verified byte-identical against an independent per-length mem_search oracle across reference-lifted queries and a spread of min_intv. Pub primitive with no in-tree caller until the collect reseed module lands (the proptest is its only consumer).
Add `forward_truncate_below_maximal`, the FORWARD analogue of the TRUNC_IV backward family (#27/#29/#30) for the reseed's right bound. Given a query and its already-found maximal match whose `occ < min_intv`, it finds the largest length L < match_len whose prefix occurs >= min_intv times and returns that interval (or the zero MemMatch when none qualifies). Forward PREFIX intervals nest directly (fixed start, shrinking end: query[..L] is a superset of query[..L+1]), unlike the LEFT reseed where prepending bases breaks forward nesting and forces the RC walk. So the walk carries [lo, hi) outward from the maximal interval as L shrinks — a short shares_prefix scan capped at min_intv per step, no model launch. `want_interval == false` returns only L* (the driver's next_pivot use); `true` recovers the exact interval by galloping find_boundary out from the capped walk's interior seed (seed-independent, so byte-identical to a cold mem_search). Adapted to main: 6-arg shares_prefix/ref_less (no keyed_compare_mask). Verified byte-identical against an independent per-length mem_search oracle across reference-lifted queries and a spread of min_intv. Pub primitive with no in-tree caller until the collect reseed module lands (the proptest is its only consumer).
`mem_search_backward` allocated a fresh `Vec` for the reverse-complement query on every call (the consumer fires ~50 backward calls/read). Build it into a 256-byte stack buffer for the common read length instead, falling back to the heap only for reads longer than the buffer (e.g. long-read tech). No probe/result change — byte-identical (the `mem_search_backward_equals_maximal_backward_step` oracle proptest passes unchanged) — just removes the per-call heap allocation from the hot backward path. This is the exact `rc_stack`/`rc_heap` pattern already merged in `mem_search_backward_truncated_span_rc`/`_interval_rc` (#27/#30), applied to `mem_search_backward`'s RC build.
`mem_search_backward` allocated a fresh `Vec` for the reverse-complement query on every call (the consumer fires ~50 backward calls/read). Build it into a 256-byte stack buffer for the common read length instead, falling back to the heap only for reads longer than the buffer (e.g. long-read tech). No probe/result change — byte-identical (the `mem_search_backward_equals_maximal_backward_step` oracle proptest passes unchanged) — just removes the per-call heap allocation from the hot backward path. This is the exact `rc_stack`/`rc_heap` pattern already merged in `mem_search_backward_truncated_span_rc`/`_interval_rc` (#27/#30), applied to `mem_search_backward`'s RC build.
v0.3 perf series (authored fresh on
main; built on #26'sforward_maximal_len → (match_len, ip)).What
Adds
mem_search_backward_truncated_span_rc: the largest left-extension spanLin[anchor_len, span_max]whose length-Lwindow occurs ≥min_intvtimes, floored atanchor_len— the consumer'smin_intv-truncated reseed span (zz_left_span_reseed), in one call.How
Walks the reverse-complement strand downward from the maximal extension: each left base prepended to the forward pattern is a base appended to its RC, so RC prefixes nest (forward intervals don't) and
occ(RC(P)) == occ(P). The interval[lo, hi)is carried across decreasingLby a linear outward scan capped atmin_intv— no per-candidate model launch. This replaces the binary search that issued a full forwardmem_searchper bisection step (~2.9× fewer SA probes on the consumer's reseed).Byte-identity
Verified by a new brute-force oracle proptest,
mem_search_backward_truncated_span_rc_equals_oracle(48 cases × pivots ×min_intv∈ {0, 1, 2, 5, 20, 1e6}). The oracle caught a real bug during development: #26'sforward_maximal_lenreturns the insertion point, not the in-interval neighbor the scan needs as a seed — so the function derives the in-interval seed with oneshares_prefix(ip-1)probe.Scope
Model-launched (the
.isa-seeded fast path and the interval-returning variant land in follow-up PRs, with their FFI; that's why this primitive has no in-tree caller yet — it's the verified building block thecollectmodule + FFI will use). Sibling-consistent withmem_search_backward(checkedpivot + anchor_len,occ_count==0 → 0,(b & 0x3) ^ 0x3RC build).Self-reviewed with
/coderabbitai-reviewbefore opening (0 findings).Summary by CodeRabbit
New Features
Tests