Repository navigation
Conversation
evalues() answers 'is this neighbourhood bigger than background?' for an Index. text_evalues() asks it of a TextIndex, where a short query matches inside long records. The arithmetic is evalue.evalue_result unchanged; what is specific to text search is two choices the derivation forces. Counts are per distinct record, not per offset. One query typically hits a record at several overlapping offsets -- a repeat, a low-complexity stretch, a tandem domain -- and those events are strongly dependent, so counting them separately gives the over-dispersed compound-Poisson count that appendix/evalue.tex collapses away by counting unique clonotypes rather than reads. N and M are num_refs. The ball is max_subs, never TextResult.score. That score is a similarity -- 0 at an exact match, more negative for a worse one -- the opposite sign to the non-negative penalty thetas_from_scores inverts. n_subs is non-negative, integer and monotone in the scope, so it nests the way the proof requires. The CSR arrays are read through memoryview rather than materialising TextHit objects, so a dense control ball costs a list of integers instead of one Python object per offset, and seqtree keeps its zero runtime dependencies. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nine tests on the calibration rather than the search, which the C++ suite already proves complete: a motif planted in 40 of 400 records is significant while a random octamer is not, a motif repeated three times inside one record counts once, E is monotone in the radius, exclude_exact drops only zero-mismatch records, an empty control and a negative radius are rejected, and the threshold round-trips to the E-value it was asked for and returns -1 when e_target is below the rule-of-three bound 3N/M. Also registers text_evalue in the doc-coverage submodule list, which fails on any new python/seqtree module that is not declared there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
api.rst gains the two functions under 'Significance -- is this hit real?'. text-index.rst no longer claims there is no E-value for TextIndex, which that line had asserted since the index was introduced. roadmap.rst item 3 records what still does not exist: there is no load_control analogue for texts, so the caller must supply a composition-matched decoy. SKILL.md gets a worked example plus the four things a caller gets wrong -- records not offsets, max_subs not score, a truncated search raising, and the background being the caller's own explicit choice. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Member
Author
|
Superseded by the consolidated seqtree 1.1.0 release PR #13; its implementation and validation are retained there. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
text_evaluesandtext_threshold_for_evalue: control-calibrated E-values forTextIndexsubstring hits, the wayevaluesalready does them for anIndex.docs/text-index.rsthad asserted "no E-value" since the index was introduced;that line is now wrong and is fixed here.
Why these choices
The arithmetic is
evalue.evalue_resultunchanged. Two things are specific totext search and both are forced by
appendix/evalue.texrather than chosen forconvenience.
Counts are per distinct record, not per offset. One query typically hits a
record at several overlapping offsets — a repeat, a low-complexity stretch, a
tandem domain — and those events are strongly dependent. Counting them
separately gives the over-dispersed compound-Poisson count that
prop:collapseremoves by counting unique clonotypes rather than reads, and
rem:seedfamilysays to count the union of a dependent family rather than correct for its size.
NandMare thereforenum_refs.The ball is
max_subs, neverTextResult.score. That score is asimilarity —
0at an exact match, more negative for a worse one — theopposite sign to the non-negative penalty
thetas_from_scoresinverts. Feedingit in would silently invert the cutoff.
n_subsis non-negative, integer andmonotone in the scope, so it nests the way
lem:monotonerequires andthetas_from_scoresis reused unchanged.Two limits, both refusals rather than partial answers
max_hitsraises. A truncated count isa floor, and an E-value computed from a floor is simply wrong.
load_controlfor texts. The background must be composition-and length-matched to the target; that assumption is what the whole
calibration rests on, nothing in the library can check it, so it stays the
caller's explicit choice.
docs/roadmap.rstitem 3 records the gap.Implementation notes
Pure Python — no C++ change, so no
editable.rebuildsurface and no Windows CIrisk. The CSR arrays are read through
memoryviewrather than materialisingTextHitobjects, so a dense control ball costs a list of integers instead ofone Python object per offset, and seqtree keeps its zero runtime dependencies.
Testing
Nine tests on the calibration rather than the search, which the C++ suite
already proves complete: a motif planted in 40 of 400 records is significant
while a random octamer is not; a motif repeated three times inside one record
produces three hits but counts once;
Eis monotone in the radius;exclude_exactdrops only zero-mismatch records; empty control and negativeradius are rejected; the threshold round-trips to the E-value it was asked for
and returns
-1below the rule-of-three bound3N/M.Gates:
pytest tests/python -q→ 429 passed, 49 skipped (includestest_doc_coverage.py, withtext_evalueregistered inSUBMODULES).sphinx-build -W --keep-going→ build succeeded.Validated in use
Driving an unrelated antibody mass-spec project: 3,784 LC-MS/MS peptides against
33,052 antibody records, with a control built by permuting each record's
hypervariable core in place so framework is preserved. Of 304 peptides with any
match, 10 are enriched at
p_enrichment < 0.01, and they are exactly the onesspanning the hypervariable junction. The control is told nothing about junctions
and recovers them anyway.
🤖 Generated with Claude Code