Skip to content

feat(collect): ISA forward-reseed warm-start (PRMI_ISA), byte-identical - #40

Merged
nh13 merged 1 commit into
mainfrom
feat/v0.3-isa-reseed-warmstart
Jun 13, 2026
Merged

feat(collect): ISA forward-reseed warm-start (PRMI_ISA), byte-identical#40
nh13 merged 1 commit into
mainfrom
feat/v0.3-isa-reseed-warmstart

Conversation

@nh13

@nh13 nh13 commented Jun 13, 2026

Copy link
Copy Markdown

What

Wires the inverse-suffix-array (ISA) hint into the fused collect_smems pass-2 forward reseed, behind the PRMI_ISA env gate. Each reseeded pass-1 SMEM carries a ReseedHint (refpos via sa_position_for(k), plus the read span [m, n]); the reseed's forward extension warm-starts mem_search from isa_at(refpos + offset) instead of a cold model launch + boundary gallop. When the hint is good the insertion-point search collapses to ~1–2 probes, skipping the model launch (the cost no model retrain could cut).

This is the first of the ISA-reseed re-derivations onto main. It is forward-only; the reseed-LEFT/RC warm-start (zz_left_span_reseed) stays cold here and lands in a follow-up.

Why it's byte-identical (the contract)

The hint only seeds the insertion-point search; find_boundary expands on a miss to the true boundary, so the result is identical to the cold mem_search for any hint — a non-maximal/stale projection just costs a few extra probes, never a wrong answer. That is precisely why every reseeded SMEM is hinted, including partial-match SMEMs whose cached occurrence diverges from the read past the span end (the common reseed case). With PRMI_ISA unset the reseed runs the existing cold path unchanged.

Changes

spectrum.rs

  • forward_maximal_len_seeded(seed_win) — splits forward_maximal_len into a delegating cold wrapper + a window-seeded variant. None is the cold path, verbatim.
  • mem_search_warmstart(query, hint)mem_search with the no-kmt launch seeded from hint; the kmt branch (tabled trace) ignores the hint and is byte-identical to mem_search's kmt branch.
  • mem_search_warmstart_equals_cold proptest — warm == cold for ANY hint (random-far, near-interval, in-interval): the seed-independence contract.

collect.rs

  • isa_reseed_enabled() (PRMI_ISA) + ReseedHint + reseed_isa_hint projection (valid inside the cached span).
  • Thread Option<ReseedHint> through zz_step1_reseedreseed_bounded_fwd / zz_right_emit_reseed; warm-start the forward search when the hint projects.
  • collect_smems_isa_equals_cold proptest + collect_smems_isa_warmstart_equals_cold_partial — ISA-on == ISA-off == cold reference across the full opts sweep, including partial-match reads. Test-only ISA_FORCE override + build_mode2_with_isa scaffolding.

Validation

  • cargo test --release -p prmi --lib — all pass except the pre-existing sa::doubled_text_tests::doubled_text_rejects_out_of_range_base (a #[should_panic] relying on a debug_assert! that release strips; in sa.rs, untouched here).
  • cargo clippy --release -p prmi --lib --all-features — clean.
  • New byte-id gates green: mem_search_warmstart_equals_cold, collect_smems_isa_equals_cold, collect_smems_isa_warmstart_equals_cold_partial.

Notes for the reviewer

Summary by CodeRabbit

Release Notes

  • New Features

    • Added warm-start search capability to optimize search performance using pre-computed hints.
  • Tests

    • Extended test coverage with new property tests verifying search result consistency.
    • Added per-thread test configuration options for enhanced testing flexibility.

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@nh13, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 28 minutes and 59 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1d6a3adb-a4a1-4d18-9baf-cc5bea89bd57

📥 Commits

Reviewing files that changed from the base of the PR and between ee2e936 and 3e7ab3e.

📒 Files selected for processing (2)
  • prmi/src/index/collect.rs
  • prmi/src/index/spectrum.rs
📝 Walkthrough

Walkthrough

Pass-2 SMEM reseeding now optionally uses ISA-based warm-start hints to seed suffix-array search. A new public mem_search_warmstart API accepts approximate SA-index hints and refactors maximal-prefix computation into seeded and cold variants. Reseed selection computes ReseedHint per pivot when enabled, and the reseed path chooses between warm-start and cold search. Tests verify byte-identity across ISA-enabled and cold collection, and warm-start equivalence.

Changes

ISA Warm-Start Hints for SMEM Collection

Layer / File(s) Summary
Warm-start search foundational API
prmi/src/index/spectrum.rs
New public mem_search_warmstart(query, hint) returns same MemMatch as mem_search but uses hint to seed insertion-point search when k-mer table is absent; ignores hint when present. Refactors forward_maximal_len into forward_maximal_len_seeded that optionally accepts caller-supplied seed window bounds. Property test verifies warm-start equals cold search across arbitrary hints.
ISA hint infrastructure and enablement
prmi/src/index/collect.rs
Adds ReseedHint structure and isa_reseed_enabled gate checking PRMI_ISA env at process lifetime. Implements reseed_isa_hint helper to project pivot positions into ISA launch indices via bounds-checked lookup. Test-only ISA_FORCE thread-local allows per-test ISA path enablement.
Hint-aware reseed pipeline and wiring
prmi/src/index/collect.rs
Pass-2 reseed selection builds ReseedHint per selected pass-1 SMEM. Updates reseed_bounded_fwd to accept optional hint and choose between mem_search_warmstart (hinted) or cold mem_search, preserving truncation/bounding behavior. Threads hint through zz_step1_reseed and zz_right_emit_reseed, updating all reseed zigzag driver call sites.
Test fixtures and equivalence validation
prmi/src/index/collect.rs
Adds build_mode2_with_isa fixture builder. Updates reseed driver and pipeline reference tests with hint=None. New property tests: collect_smems_isa_equals_cold byte-compares live-ISA and cold collection across full option sweeps; collect_smems_isa_warmstart_equals_cold_partial validates warm-start on partial-match reads.

Sequence Diagram

sequenceDiagram
  participant Collector as SMEM Collector
  participant ReseedSel as Reseed Selection
  participant HintCalc as ReseedHint Calculator
  participant ResBound as reseed_bounded_fwd
  participant WarmStart as mem_search_warmstart
  participant ColdSearch as mem_search
  
  Collector->>ReseedSel: Pass-1 SMEMs
  ReseedSel->>HintCalc: pivot position, ISA ref
  HintCalc->>ReseedSel: Option<ReseedHint>
  ReseedSel->>ResBound: (pivot, min_intv, hint)
  ResBound->>WarmStart: hint available?
  alt Hint Present
    WarmStart->>WarmStart: seed from hint, find_boundary
  else No Hint
    ResBound->>ColdSearch: cold search path
  end
  WarmStart->>ResBound: (match_len, interval)
  ColdSearch->>ResBound: (match_len, interval)
  ResBound->>Collector: truncated SMEM
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • fg-labs/prmi#26: Both PRs modify prmi/src/index/spectrum.rs's forward maximal-len computation/interval recovery to use the SA insertion point for find_boundary; main PR refactors into seeded vs cold variants for mem_search_warmstart.
  • fg-labs/prmi#32: Both PRs modify the SMEM fused collection implementation in prmi/src/index/collect.rs—main PR extends the pass-2 per-pivot reseeding path with ReseedHint and hint-aware forward reseed search, while retrieved PR introduces the per-read collect/zigzag pipeline.
  • fg-labs/prmi#23: Both PRs touch prmi/src/index/spectrum.rs's forward maximal-prefix/find_boundary logic; main PR extends that machinery into mem_search_warmstart and uses it for ISA warm-start reseed selection.

Poem

🐰 A hint from the ISA flies swift and true,
Warming the search for reseed paths anew.
Cold bounds now seeded, from pivot to start,
The suffix array finds its optimal part. ✨
One hint, two paths—yet bytes stay the same,
Equivalence proven, warm-start wins the game! 🎯

🚥 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 clearly and concisely summarizes the main change: adding ISA-based forward-reseed warm-start functionality with byte-identical behavior to cold search.
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.


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
prmi/src/index/spectrum.rs (1)

4887-4892: ⚡ Quick win

Exercise out-of-range hints in this proptest.

hint_raw % sa_num.max(1) keeps random hints in-range, so the documented clamp path (hint >= sa_num) is not directly tested. Add at least one raw out-of-range hint (for example u64::MAX) to pin that contract.

♻️ Suggested tweak
-                let mut hints = vec![hint_raw % sa_num.max(1)];
+                let mut hints = vec![hint_raw, u64::MAX];
+                if sa_num > 0 {
+                    hints.push(hint_raw % sa_num);
+                }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@prmi/src/index/spectrum.rs` around lines 4887 - 4892, The proptest currently
only pushes in-range hints via let mut hints = vec![hint_raw % sa_num.max(1)];
which never exercises the clamp branch for hint >= sa_num; modify the
construction of hints in the test (the code around hint_raw, sa_num and the
hints vec) to include at least one raw out-of-range hint (e.g. push u64::MAX or
another value >= sa_num) alongside the existing modulo-derived hint so the clamp
path is exercised; keep the existing logic that conditionally adds near-interval
hints when cold.occ > 0 unchanged.
prmi/src/index/collect.rs (1)

251-276: ⚡ Quick win

Skip ISA hint materialization when a k-mer table is loaded.

mem_search_warmstart ignores its hint on the kmt branch, so this code still pays sa_position_for() here and isa_at() later even though it can never skip the tabled launch. Gating use_isa on self.kmt.is_none() keeps kmt-backed indexes on the unchanged reseed path instead of adding dead per-reseed work.

♻️ Proposed fix
-        let use_isa = isa_reseed_enabled() && self.has_isa();
+        let use_isa = isa_reseed_enabled() && self.has_isa() && self.kmt.is_none();

Based on the mem_search_warmstart contract in prmi/src/index/spectrum.rs:1538-1626, hints are ignored when kmt is loaded.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@prmi/src/index/collect.rs` around lines 251 - 276, The code constructs ISA
reseed hints and calls self.sa_position_for() even when a k-mer table is loaded
and mem_search_warmstart will ignore hints; change the gating so hints are only
created when ISA reseeding is enabled, an ISA is present, AND there is no k-mer
table. Concretely, modify the use_isa boolean (currently set with
isa_reseed_enabled() && self.has_isa()) to also require self.kmt.is_none(), or
alternatively check self.kmt.is_none() before calling self.sa_position_for()
when building the ReseedHint so that sa_position_for() and isa_at() are not
invoked for kmt-backed indexes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@prmi/src/index/collect.rs`:
- Around line 251-276: The code constructs ISA reseed hints and calls
self.sa_position_for() even when a k-mer table is loaded and
mem_search_warmstart will ignore hints; change the gating so hints are only
created when ISA reseeding is enabled, an ISA is present, AND there is no k-mer
table. Concretely, modify the use_isa boolean (currently set with
isa_reseed_enabled() && self.has_isa()) to also require self.kmt.is_none(), or
alternatively check self.kmt.is_none() before calling self.sa_position_for()
when building the ReseedHint so that sa_position_for() and isa_at() are not
invoked for kmt-backed indexes.

In `@prmi/src/index/spectrum.rs`:
- Around line 4887-4892: The proptest currently only pushes in-range hints via
let mut hints = vec![hint_raw % sa_num.max(1)]; which never exercises the clamp
branch for hint >= sa_num; modify the construction of hints in the test (the
code around hint_raw, sa_num and the hints vec) to include at least one raw
out-of-range hint (e.g. push u64::MAX or another value >= sa_num) alongside the
existing modulo-derived hint so the clamp path is exercised; keep the existing
logic that conditionally adds near-interval hints when cold.occ > 0 unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f300c937-a315-4b9b-858c-173d9405610b

📥 Commits

Reviewing files that changed from the base of the PR and between 7da93a5 and ee2e936.

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

Wire the inverse-SA hint into the fused collect_smems pass-2 forward reseed,
behind the PRMI_ISA env gate. Each reseeded pass-1 SMEM carries a ReseedHint
(refpos via sa_position_for(k), plus the read span); the reseed's forward
extension warm-starts mem_search from isa_at(refpos + offset) instead of a cold
model launch + boundary gallop. When the hint is good the insertion search
collapses to ~1-2 probes.

Byte-identity is the contract, not an aspiration: the hint only seeds the
insertion-point search, and find_boundary expands on a miss to the true
boundary, so the result is identical to the cold mem_search for ANY hint —
a non-maximal/stale projection just costs a few extra probes. This is why every
reseeded SMEM is hinted, including partial-match SMEMs whose cached occurrence
diverges from the read past the span end.

spectrum.rs:
- forward_maximal_len_seeded(seed_win): split forward_maximal_len into a
  delegating cold wrapper + a window-seeded variant (None == cold, verbatim).
- mem_search_warmstart(query, hint): mem_search with the no-kmt launch seeded
  from hint; the kmt branch (tabled trace) ignores the hint, still byte-id.
- mem_search_warmstart_equals_cold proptest: warm == cold for ANY hint
  (far/near/in-interval), the seed-independence contract.

collect.rs:
- isa_reseed_enabled() (PRMI_ISA) + ReseedHint + reseed_isa_hint projection.
- Thread Option<ReseedHint> through zz_step1_reseed -> reseed_bounded_fwd /
  zz_right_emit_reseed; warm-start the forward search when the hint projects.
- collect_smems_isa_equals_cold proptest + collect_smems_isa_warmstart_equals_
  cold_partial: ISA-on == ISA-off == cold reference across the opts sweep,
  including partial-match reads. Test-only ISA_FORCE override + build_mode2_
  with_isa scaffolding.

The reseed-LEFT/RC warm-start (zz_left_span_reseed) stays cold here; it lands
in a follow-up so this PR is forward-only.
@nh13
nh13 force-pushed the feat/v0.3-isa-reseed-warmstart branch from ee2e936 to 3e7ab3e Compare June 13, 2026 22:11
@nh13
nh13 merged commit 102b01d into main Jun 13, 2026
4 checks passed
@nh13
nh13 deleted the feat/v0.3-isa-reseed-warmstart branch June 13, 2026 22:16
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