Skip to content

perf(reseed): neighbour-LCP scan for SMEM truncation (byte-identical, +13.5%) - #48

Merged
nh13 merged 2 commits into
mainfrom
perf/reseed-neighbor-scan
Jun 20, 2026
Merged

perf(reseed): neighbour-LCP scan for SMEM truncation (byte-identical, +13.5%)#48
nh13 merged 2 commits into
mainfrom
perf/reseed-neighbor-scan

Conversation

@nh13

@nh13 nh13 commented Jun 17, 2026

Copy link
Copy Markdown

Summary

Replace the per-length linear length-walk in the reseed truncation primitives — forward_truncate_below_maximal and mem_search_backward_truncated_span_rc (src/index/spectrum.rs) — with an O(min_intv) neighbour-LCP scan. Signatures are unchanged, so the production fused seeding path (collect_smems → these primitives) benefits directly.

Correctness is defined as byte-identity to the existing walk (not a re-derivation of the result): the converged L*/interval and emitted SMEMs are unchanged.

What changed

  • forward_truncate_below_maximal: the O(lmax−L*) per-length walk becomes an O(min_intv) scan over neighbouring SA entries' LCPs.
  • mem_search_backward_truncated_span_rc: the same neighbour-axis scan applied to the reverse-complement span.

Validation (all green)

  • Unit byte-identity: existing oracle proptests (forward_truncate_below_maximal_equals_oracle, mem_search_backward_truncated_span_rc_equals_oracle, span_rc_zero_occ_floors_to_anchor_len) plus a new repeats/ties corpus (24,130 cases incl. shared-L* ties and occ(maximal) ∈ [2, min_intv)).
  • Probe budget (the perf change): forward 264 → 18 probes/call on long-unique reads; RC 242 → 15 — new guard tests fail on the old walk, pass on the scan.
  • End-to-end SMEM (rid,m,n,occ) parity: 0 differences vs current on E. coli K12 and phiX (fwd+revcomp) across the seeding param grid (msl 17/19/31, max_mem_intv 0, split_width 5 — counts genuinely vary).
  • hg38, 200k WGS reads: byte-identical SMEM count vs current.

Performance

Warm hg38, 200k WGS reads, single-thread, load-excluded (the fused collect_smems path): 76,459 → 66,119 ns/read (−13.5%), tight variance, identical SMEM count.

Test plan

  • cargo test (oracle + proptests, feature on/off)
  • cargo clippy --all-features --all-targets -- -D warnings, cargo fmt --check
  • dump 0/0 on ecoli + phiX across the grid
  • wall non-regression

Summary by CodeRabbit

  • Refactor

    • Optimized internal truncation algorithms for improved performance in candidate discovery.
  • Tests

    • Extended test coverage with new correctness and performance regression tests, including edge cases and stress scenarios.

nh13 added 2 commits June 16, 2026 14:29
…ts corpus

Replace the O(lmax-L*) per-length walk in forward_truncate_below_maximal with
an O(min_intv) neighbor-LCP scan: read the LCP of the query with the SA suffixes
just outside the interval and extend the larger-LCP side until occ>=min_intv,
then recover the exact interval via find_boundary (span-only for want_interval=false).

Byte-identical to the old walk / naive oracle, proven by the existing
forward_truncate_below_maximal_equals_oracle proptest plus a new repeats/ties
corpus test exercising shared-L* ties and occ(maximal) in [2,min_intv), both
want_interval modes. Probe budget on long-unique reads: 264 -> 18.
@nh13

nh13 commented Jun 20, 2026

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4668e4c9-1b30-434e-9146-6ff8097386ce

📥 Commits

Reviewing files that changed from the base of the PR and between 01a2627 and 350b68d.

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

Walkthrough

Replaces per-base downward walks in span_rc_walk and forward_truncate_below_maximal with neighbor-LCP-driven scans to locate truncation length L*. Adds a structured repeat_corpus() generator and oracle-comparison plus probe-count regression tests for both rewritten paths.

Changes

Neighbor-LCP truncation algorithm and tests

Layer / File(s) Summary
span_rc_walk and forward_truncate_below_maximal rewrites
prmi/src/index/spectrum.rs
span_rc_walk drops the per-base expand(l,…) loop; now caps neighbor-LCPs and extends toward the higher-LCP side until occ >= min_intv. forward_truncate_below_maximal hoists the full-32 q_key, caps neighbor-LCPs at lmax-1, tracks best_len, and terminates on occ >= min_intv or exhausted expansion—replacing the l-decrement/shares_prefix loop.
Repeat corpus and oracle regression tests
prmi/src/index/spectrum.rs
repeat_corpus() generates an LCG backbone with embedded motifs, tandem repeats, and homopolymer runs. forward_truncate_equals_oracle_on_repeats_both_modes and span_rc_equals_oracle_on_repeats compare both rewritten paths against brute-force oracles for multiple min_intv values and both want_interval modes; under spectrum-probe-count, probe counts are asserted bounded to guard the new asymptotic.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • fg-labs/prmi#27: Introduces the backward-truncated-span RC primitive using a downward/outward walk—the same span_rc_walk logic this PR replaces with neighbor-LCP scans.
  • fg-labs/prmi#31: Adds forward_truncate_below_maximal as a new primitive with the stepwise length-decrement loop that this PR rewrites.
  • fg-labs/prmi#45: Modifies the same two functions (span_rc_walk, forward_truncate_below_maximal) to hoist/reuse the full-32 q_key, a precursor change this PR builds on.
🚥 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 describes the core optimization: replacing per-length walks with neighbour-LCP scans for SMEM truncation, with the quantified performance improvement (+13.5%). It directly reflects the main change.
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
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/reseed-neighbor-scan

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 commented Jun 20, 2026

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nh13
nh13 merged commit 44b8b19 into main Jun 20, 2026
4 checks passed
@nh13
nh13 deleted the perf/reseed-neighbor-scan branch June 20, 2026 17:49
nh13 added a commit that referenced this pull request Jun 21, 2026
Times the full per-read SMEM driver (ns/read) over a FASTQ; built at two commits
(pre/post #48) it measures the reseed-neighbor-scan wall win on a large ref.
nh13 added a commit that referenced this pull request Jun 22, 2026
Times the full per-read SMEM driver (ns/read) over a FASTQ; built at two commits
(pre/post #48) it measures the reseed-neighbor-scan wall win on a large ref.
nh13 added a commit that referenced this pull request Jun 22, 2026
…t_wall bench (#49)

* perf(spectrum): forward reseed truncate via neighbor-LCP scan + repeats corpus

Replace the O(lmax-L*) per-length walk in forward_truncate_below_maximal with
an O(min_intv) neighbor-LCP scan: read the LCP of the query with the SA suffixes
just outside the interval and extend the larger-LCP side until occ>=min_intv,
then recover the exact interval via find_boundary (span-only for want_interval=false).

Byte-identical to the old walk / naive oracle, proven by the existing
forward_truncate_below_maximal_equals_oracle proptest plus a new repeats/ties
corpus test exercising shared-L* ties and occ(maximal) in [2,min_intv), both
want_interval modes. Probe budget on long-unique reads: 264 -> 18.

* perf(spectrum): RC reseed span via neighbor-LCP scan (byte-identical, O(min_intv))

* test(spectrum): deterministic neighbor-scan boundary cases

Adversarial review of the reseed-neighbor-scan flagged three reasoned-correct but
unexecuted branches. Add forward_truncate_boundary_cases covering: (a) lmax==1
(lcap=0 -> zero), and (b) SA-end exhaustion where min_intv exceeds any achievable
occ, so the scan walks both neighbours off the SA ends and breaks on
llo==0 && lhi==0 -> zero (not via the lmax cap). Both modes (want_interval
true/false) and an oracle cross-check. No production-code change.

* test(bench): collect_wall — per-read collect_smems wall harness

Times the full per-read SMEM driver (ns/read) over a FASTQ; built at two commits
(pre/post #48) it measures the reseed-neighbor-scan wall win on a large ref.
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