Skip to content

indel search: label each group's hits from its own index - #37

Merged
dmx2 merged 2 commits into
IEDB:masterfrom
Roman-Young:fix/indel-labels-per-index
Oct 16, 2026
Merged

dmx2 merged 2 commits into
IEDB:masterfrom
Roman-Young:fix/indel-labels-per-index

Conversation

@Roman-Young

Copy link
Copy Markdown
Contributor

Indel search splits a batch by query length: short queries go on a 2-mer table and the rest use their own k. Every group's hits were labeled from the last group's index, so if the per-k .pepidx files came from different versions of the FASTA, a short query's hit could be named after the wrong protein. Each group now uses its own index.

Also:

  • An indel search with no hits returned null-typed Matched Sequence and Indel Positions columns. They're strings now, so the schema is always the same.
  • One-indel annotations read the valid positions straight off the common prefix and suffix. Same placements in the same order (checked exhaustively against the old code on small alphabets, plus 1M random pairs). Output building for 50k one-indel queries goes from 0.91 s to 0.65 s.

Recall is unchanged: 100% on all 11 indel benchmark sets with output identical to master (every column, row order and type), and 9,000 random mixed batches match the brute-force oracle. Full test suite passes on top of #35 and #36.

indel_search splits a batch by query length (short queries on a 2-mer table, the
rest on their own k) but joined every group's hits to the last group's index for
metadata. Protein numbers are each index's own FASTA ordinals, so when the per-k
.pepidx files come from different versions of the FASTA (they're reused by name,
eg. after the FASTA is edited in place) a short query's hit got named after
whichever protein holds that number in the other file. Each group's frame is now
built from its own index and the frames are stacked with vertical_relaxed. With
consistent index files nothing changes.

An all-miss indel search also returned Matched Sequence and Indel Positions as
null-typed columns; they're cast to String so every search has the same schema.

Recall is unchanged: 100% on all 11 local indel benchmark sets with outputs
identical to master, and 9,000 random mixed batches (a third with stale tables)
match the brute-force oracle. New tests cover per-index labeling with stale
tables, a batch equal to its short and long queries searched separately, and the
all-miss types. test_metadata_rows' stale-index test now checks the error hint
directly, since indel search no longer reads another group's index.
With one edit, a placement is valid exactly where the two strings agree before it
and after it, so the valid positions are one run between the common prefix and
the common suffix. _indel_placements now reads that run off the two lengths
instead of building agreement runs for every shift and walking them. Two-edit
pairs keep the general path.

Placements are identical and in the same order: test_indel_positions_equivalence
checks them against the original brute-force implementation exhaustively over
small alphabets, and 1,000,000 random pairs agree as well. Annotation time
halves, and output building for 50k 1-indel queries drops from 0.91 s to 0.65 s.
@dmx2
dmx2 merged commit 0437b85 into IEDB:master Oct 16, 2026
12 checks passed
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.

2 participants