Skip to content

perf(spectrum): min_intv-truncated backward reseed span via RC-downward scan - #27

Merged
nh13 merged 1 commit into
mainfrom
feat/v0.3-trunc-iv
Jun 11, 2026
Merged

perf(spectrum): min_intv-truncated backward reseed span via RC-downward scan#27
nh13 merged 1 commit into
mainfrom
feat/v0.3-trunc-iv

Conversation

@nh13

@nh13 nh13 commented Jun 11, 2026

Copy link
Copy Markdown

v0.3 perf series (authored fresh on main; built on #26's forward_maximal_len → (match_len, ip)).

What

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, floored at anchor_len — the consumer's min_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 decreasing L by a linear outward scan capped at min_intv — no per-candidate model launch. This replaces the binary search that issued a full forward mem_search per 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's forward_maximal_len returns the insertion point, not the in-interval neighbor the scan needs as a seed — so the function derives the in-interval seed with one shares_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 the collect module + FFI will use). Sibling-consistent with mem_search_backward (checked pivot + anchor_len, occ_count==0 → 0, (b & 0x3) ^ 0x3 RC build).

Self-reviewed with /coderabbitai-review before opening (0 findings).

Summary by CodeRabbit

  • New Features

    • Added a backward search method with occurrence count filtering and span truncation for enhanced pattern matching capabilities.
  • Tests

    • Added property-based tests to validate the new search functionality across varying parameter configurations.

…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.
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f656171e-2e9b-4c44-b455-137a09b25ba5

📥 Commits

Reviewing files that changed from the base of the PR and between f41c224 and aa473b1.

📒 Files selected for processing (1)
  • prmi/src/index/spectrum.rs

📝 Walkthrough

Walkthrough

This 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.

Changes

RC-backward truncated span

Layer / File(s) Summary
Truncated span algorithm implementation
prmi/src/index/spectrum.rs
mem_search_backward_truncated_span_rc derives the RC pattern, seeds an SA interval via insertion-point neighbor selection, expands the interval outward to maximal depth, then iteratively reduces span and rescans until occurrence count threshold is met or anchor floor is reached.
Test oracle and property verification
prmi/src/index/spectrum.rs
truncated_span_oracle and mem_search_backward_truncated_span_rc_equals_oracle validate the new primitive against brute-force enumeration across multiple pivots and min_intv edge cases.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • fg-labs/prmi#26: Both PRs modify spectrum.rs around forward-maximal-len and interval seeding/recovery for spectrum-based searches; the truncated-span primitive depends on the same interval-expansion mechanics.
  • fg-labs/prmi#23: The new mem_search_backward_truncated_span_rc primitive builds directly on RC-based interval search machinery (e.g., forward_maximal_len and RC-based mem_search_backward logic) introduced in this PR, extending it with truncated-span outward scanning.

Poem

🐰 A span that bends and stretches right,
From anchor down with RC light,
The interval expands to reach its dreams,
Till min_intv fills the seams!
One primitive call, no loops to fret—
The truest backward search we've met! 🧬

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding a new performance-optimized RC-downward scan primitive for backward truncated span search with min_intv constraints.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nh13
nh13 merged commit c67b2e3 into main Jun 11, 2026
4 checks passed
@nh13
nh13 deleted the feat/v0.3-trunc-iv branch June 11, 2026 21:33
nh13 added a commit that referenced this pull request Jun 12, 2026
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).
nh13 added a commit that referenced this pull request Jun 12, 2026
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).
nh13 added a commit that referenced this pull request Jun 12, 2026
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).
nh13 added a commit that referenced this pull request Jun 13, 2026
`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.
nh13 added a commit that referenced this pull request Jun 13, 2026
`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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant