seqtree 0.5.0__tar.gz → 0.6.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. {seqtree-0.5.0 → seqtree-0.6.1}/CHANGELOG.md +38 -0
  2. {seqtree-0.5.0 → seqtree-0.6.1}/PKG-INFO +5 -2
  3. {seqtree-0.5.0 → seqtree-0.6.1}/README.md +4 -1
  4. {seqtree-0.5.0 → seqtree-0.6.1}/SOURCES.md +7 -1
  5. {seqtree-0.5.0 → seqtree-0.6.1}/pyproject.toml +1 -1
  6. {seqtree-0.5.0 → seqtree-0.6.1}/skills/seqtree/SKILL.md +1 -1
  7. {seqtree-0.5.0 → seqtree-0.6.1}/src/gapblock.cpp +5 -5
  8. {seqtree-0.5.0 → seqtree-0.6.1}/src/structural.inc +4 -4
  9. {seqtree-0.5.0 → seqtree-0.6.1}/.gitattributes +0 -0
  10. {seqtree-0.5.0 → seqtree-0.6.1}/.gitignore +0 -0
  11. {seqtree-0.5.0 → seqtree-0.6.1}/CMakeLists.txt +0 -0
  12. {seqtree-0.5.0 → seqtree-0.6.1}/LICENSE +0 -0
  13. {seqtree-0.5.0 → seqtree-0.6.1}/ROADMAP.md +0 -0
  14. {seqtree-0.5.0 → seqtree-0.6.1}/appendix/.gitignore +0 -0
  15. {seqtree-0.5.0 → seqtree-0.6.1}/appendix/.latexmkrc +0 -0
  16. {seqtree-0.5.0 → seqtree-0.6.1}/appendix/Makefile +0 -0
  17. {seqtree-0.5.0 → seqtree-0.6.1}/appendix/epitope_detection.pdf +0 -0
  18. {seqtree-0.5.0 → seqtree-0.6.1}/appendix/evalue.pdf +0 -0
  19. {seqtree-0.5.0 → seqtree-0.6.1}/appendix/evalue.tex +0 -0
  20. {seqtree-0.5.0 → seqtree-0.6.1}/appendix/evalue_matrix.pdf +0 -0
  21. {seqtree-0.5.0 → seqtree-0.6.1}/appendix/mhc1_rocpr.pdf +0 -0
  22. {seqtree-0.5.0 → seqtree-0.6.1}/appendix/mhc2_rocpr.pdf +0 -0
  23. {seqtree-0.5.0 → seqtree-0.6.1}/appendix/refs.bib +0 -0
  24. {seqtree-0.5.0 → seqtree-0.6.1}/examples/01_gapped_search.py +0 -0
  25. {seqtree-0.5.0 → seqtree-0.6.1}/examples/02_sequence_dendrogram.py +0 -0
  26. {seqtree-0.5.0 → seqtree-0.6.1}/examples/03_indel_positions.py +0 -0
  27. {seqtree-0.5.0 → seqtree-0.6.1}/examples/04_island_profile.py +0 -0
  28. {seqtree-0.5.0 → seqtree-0.6.1}/include/seqtree/kmer_index.hpp +0 -0
  29. {seqtree-0.5.0 → seqtree-0.6.1}/include/seqtree/seqtree.hpp +0 -0
  30. {seqtree-0.5.0 → seqtree-0.6.1}/include/seqtree/types.hpp +0 -0
  31. {seqtree-0.5.0 → seqtree-0.6.1}/python/seqtree/__init__.py +0 -0
  32. {seqtree-0.5.0 → seqtree-0.6.1}/python/seqtree/control.py +0 -0
  33. {seqtree-0.5.0 → seqtree-0.6.1}/python/seqtree/data/control_human_trb_aa.txt.gz +0 -0
  34. {seqtree-0.5.0 → seqtree-0.6.1}/python/seqtree/distance.py +0 -0
  35. {seqtree-0.5.0 → seqtree-0.6.1}/python/seqtree/evalue.py +0 -0
  36. {seqtree-0.5.0 → seqtree-0.6.1}/python/seqtree/gapblock.py +0 -0
  37. {seqtree-0.5.0 → seqtree-0.6.1}/python/seqtree/layout.py +0 -0
  38. {seqtree-0.5.0 → seqtree-0.6.1}/python/seqtree/pairwise.py +0 -0
  39. {seqtree-0.5.0 → seqtree-0.6.1}/python/seqtree/pmhc.py +0 -0
  40. {seqtree-0.5.0 → seqtree-0.6.1}/python/seqtree/pmhc_evalue.py +0 -0
  41. {seqtree-0.5.0 → seqtree-0.6.1}/python/seqtree/py.typed +0 -0
  42. {seqtree-0.5.0 → seqtree-0.6.1}/python/seqtree/seeds.py +0 -0
  43. {seqtree-0.5.0 → seqtree-0.6.1}/src/_bindings.cpp +0 -0
  44. {seqtree-0.5.0 → seqtree-0.6.1}/src/atomic_write.hpp +0 -0
  45. {seqtree-0.5.0 → seqtree-0.6.1}/src/blosum45.inc +0 -0
  46. {seqtree-0.5.0 → seqtree-0.6.1}/src/blosum62.inc +0 -0
  47. {seqtree-0.5.0 → seqtree-0.6.1}/src/blosum80.inc +0 -0
  48. {seqtree-0.5.0 → seqtree-0.6.1}/src/codec.cpp +0 -0
  49. {seqtree-0.5.0 → seqtree-0.6.1}/src/distance.cpp +0 -0
  50. {seqtree-0.5.0 → seqtree-0.6.1}/src/engine_seqtm.cpp +0 -0
  51. {seqtree-0.5.0 → seqtree-0.6.1}/src/engine_seqtrie.cpp +0 -0
  52. {seqtree-0.5.0 → seqtree-0.6.1}/src/engines.hpp +0 -0
  53. {seqtree-0.5.0 → seqtree-0.6.1}/src/index.cpp +0 -0
  54. {seqtree-0.5.0 → seqtree-0.6.1}/src/kmer_index.cpp +0 -0
  55. {seqtree-0.5.0 → seqtree-0.6.1}/src/pairwise.cpp +0 -0
  56. {seqtree-0.5.0 → seqtree-0.6.1}/src/pam100.inc +0 -0
  57. {seqtree-0.5.0 → seqtree-0.6.1}/src/pam250.inc +0 -0
  58. {seqtree-0.5.0 → seqtree-0.6.1}/src/positional_matrix.cpp +0 -0
  59. {seqtree-0.5.0 → seqtree-0.6.1}/src/searcher.cpp +0 -0
  60. {seqtree-0.5.0 → seqtree-0.6.1}/src/substitution_matrix.cpp +0 -0
  61. {seqtree-0.5.0 → seqtree-0.6.1}/src/trie.cpp +0 -0
  62. {seqtree-0.5.0 → seqtree-0.6.1}/src/trie.hpp +0 -0
@@ -3,6 +3,44 @@
3
3
  All notable changes to `seqtree`. Dates are release dates; the project is pre-1.0, so a **minor**
4
4
  bump may carry breaking changes.
5
5
 
6
+ ## [0.6.1] — 2026-07-30
7
+
8
+ ### Fixed
9
+
10
+ - **`gapblock_matrix`'s out-of-alphabet error named only the bad symbol**, not which sequence it
11
+ came from (`"symbol '_' is not in the alphabet"`) — unhelpful when a single malformed row (e.g.
12
+ a `junction_aa` containing a legacy out-of-frame marker) is buried in a batch of hundreds of
13
+ thousands. The message now names the side, index, and offending string:
14
+ `"queries[42] ('CASSIRS_YEQYF'): symbol '_' is not in the alphabet"`. No change to which symbols
15
+ are accepted (still the standard 20 + B/Z/X/* for `alphabet="aa"`).
16
+
17
+ ## [0.6.0] — 2026-07-17
18
+
19
+ ### Fixed
20
+
21
+ - **`structural` scored A–N contacts as if they did not interact, because the source table is
22
+ corrupted there.** The Miyazawa–Jernigan A–N contact energy was transcribed as `0.00` — the
23
+ generator's comment excused it as a pair the source left unlisted. It is not unlisted. In
24
+ `MJ_Keskin_potentials.csv` the lower triangle runs `A-A`, `R-A`, `R-R`, `[N-A]`, `N-R`, …, and
25
+ the `N-A` slot reads `V,1` (mirrored `1,V`), where `1` is a mangled residue symbol. The true
26
+ value is **0.15**. It is not a stray duplicate of `V-N` either — the V row separately lists
27
+ `N = 0.12`.
28
+
29
+ Substituting `0.00` for `0.15` understated A's interaction strength and overstated N's
30
+ (`q(A)` −0.04100 → −0.03350, `q(N)` +0.04350 → +0.05100). Since `structural` is rank-1 by
31
+ construction — every cell is a function of the 20 per-residue strengths — this moved the
32
+ strong→weak ordering that the matrix exists to encode, swapping N and P:
33
+ `FWCLYMIVHGAT`**`NP`**`RSQDEK` → `FWCLYMIVHGAT`**`PN`**`RSQDEK`.
34
+
35
+ Four cells of the 24×24 grid change: `A-W`/`W-A` 6 → 5, and `B-C`/`C-B` 4 → 3 (`B` is
36
+ `mean(N, D)`, so N's shift carries into it). **Scores from `structural()` change for sequences
37
+ containing A, W, or B**; all other matrices are untouched. N and P were near-tied, which is why
38
+ a real correction to the ordering moves so few cells.
39
+
40
+ - **The same comment claimed the source is "near- but not perfectly symmetric".** It is perfectly
41
+ symmetric — 0 asymmetric directed pairs across all 400. The symmetrisation in
42
+ `structural_grid()` is a no-op guard, not a repair, and is now documented as such.
43
+
6
44
  ## [0.5.0] — 2026-07-16
7
45
 
8
46
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: seqtree
3
- Version: 0.5.0
3
+ Version: 0.6.1
4
4
  Summary: Fast fuzzy search over biological sequences (C++ core, Python bindings)
5
5
  Keywords: sequence-search,fuzzy-matching,CDR3,immunology,bioinformatics,trie
6
6
  Author-Email: ISALGO laboratory <mikhail.shugay@gmail.com>
@@ -114,8 +114,11 @@ needs a C++17 compiler and CMake (pulled in automatically by the build).
114
114
 
115
115
  ## Build from source
116
116
 
117
+ Needs [uv](https://docs.astral.sh/uv/) (`brew install uv`); `setup.sh` uses it for the venv and
118
+ the editable install.
119
+
117
120
  ```fish
118
- bash setup.sh # repo-local .venv + editable install
121
+ bash setup.sh # uv-managed .venv + editable install
119
122
  bash setup.sh --tests # + pytest
120
123
  bash setup.sh --bench # + benchmark deps (huggingface_hub, psutil)
121
124
  ```
@@ -80,8 +80,11 @@ needs a C++17 compiler and CMake (pulled in automatically by the build).
80
80
 
81
81
  ## Build from source
82
82
 
83
+ Needs [uv](https://docs.astral.sh/uv/) (`brew install uv`); `setup.sh` uses it for the venv and
84
+ the editable install.
85
+
83
86
  ```fish
84
- bash setup.sh # repo-local .venv + editable install
87
+ bash setup.sh # uv-managed .venv + editable install
85
88
  bash setup.sh --tests # + pytest
86
89
  bash setup.sh --bench # + benchmark deps (huggingface_hub, psutil)
87
90
  ```
@@ -32,12 +32,18 @@ possible; and out-of-frame junctions escape thymic selection, making them a samp
32
32
  | | |
33
33
  |---|---|
34
34
  | provenance | **derived** (published log-odds / interaction-strength matrices) |
35
- | origin | BLOSUM62 (NCBI); EMBOSS EPAM250, EPAM100; Miyazawa–Jernigan interaction strengths |
35
+ | origin | BLOSUM62 (NCBI); EMBOSS EPAM250, EPAM100; Miyazawa–Jernigan interaction strengths, transcribed into `MJ_CONTACT` in `bench/gen_matrices.py` from the `MJ` rows of `tcren-ms/src/tcren/data/MJ_Keskin_potentials.csv` (Miyazawa & Jernigan, J Mol Biol 1996, as tabulated by Keskin et al., Protein Sci 1998) |
36
36
  | regenerate | `python bench/gen_matrices.py` |
37
37
 
38
38
  Stored as non-negative penalties via the Gram transform `pen[a][b] = s[a][a] + s[b][b] − 2·s[a][b]`,
39
39
  clamped at zero, so `penalty(a, a) == 0` and the score defines a ball.
40
40
 
41
+ **Known corruption in the MJ source.** `MJ_Keskin_potentials.csv` has no `A,N` row: the lower-triangle
42
+ slot where `N-A` belongs is mangled to `V,1` (mirrored `1,V`) for *both* the `MJ` and `Keskin`
43
+ potentials. `MJ_CONTACT` carries the correct `A-N = 0.15` from that row, so the constant will not
44
+ diff cleanly against the CSV at that pair. The `Keskin` rows are unused here. Fix not yet upstreamed
45
+ to `tcren-ms`.
46
+
41
47
  ## Downloaded on demand
42
48
 
43
49
  ### `load_control(name)` → `~/.cache/seqtree/control_*.sqtree`
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "seqtree"
7
- version = "0.5.0"
7
+ version = "0.6.1"
8
8
  description = "Fast fuzzy search over biological sequences (C++ core, Python bindings)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -237,7 +237,7 @@ Count it in the control.
237
237
  4. OLGA generates from `P_gen`, which is **not** the post-selection background `P_0`. Do not use
238
238
  an OLGA sample as the null for an operational cutoff.
239
239
  5. Rebuild after pulling: a stale `_core.so` has silently shadowed new Python-visible C++ methods
240
- more than once (`pip install -e .`).
240
+ more than once (`bash setup.sh`, or `uv pip install -e .`).
241
241
 
242
242
  ## Layering
243
243
 
@@ -9,13 +9,13 @@
9
9
  namespace seqtree {
10
10
  namespace {
11
11
 
12
- std::vector<uint8_t> encode(const Codec& c, const std::string& s) {
12
+ std::vector<uint8_t> encode(const Codec& c, const std::string& s, const char* label, size_t idx) {
13
13
  std::vector<uint8_t> out(s.size());
14
14
  for (size_t i = 0; i < s.size(); ++i) {
15
15
  uint8_t v = c.encode(s[i]);
16
16
  if (v == Codec::kInvalid)
17
- throw std::invalid_argument(std::string("symbol '") + s[i] +
18
- "' is not in the alphabet");
17
+ throw std::invalid_argument(label + std::string("[") + std::to_string(idx) + "] ('" + s +
18
+ "'): symbol '" + s[i] + "' is not in the alphabet");
19
19
  out[i] = v;
20
20
  }
21
21
  return out;
@@ -85,11 +85,11 @@ std::vector<int32_t> gapblock_matrix(const std::vector<std::string>& queries,
85
85
  std::vector<std::vector<uint8_t>> qc(N), rc(K);
86
86
  uint32_t longest = 0;
87
87
  for (size_t i = 0; i < N; ++i) {
88
- qc[i] = encode(codec, queries[i]);
88
+ qc[i] = encode(codec, queries[i], "queries", i);
89
89
  longest = std::max<uint32_t>(longest, uint32_t(qc[i].size()));
90
90
  }
91
91
  for (size_t k = 0; k < K; ++k) {
92
- rc[k] = encode(codec, refs[k]);
92
+ rc[k] = encode(codec, refs[k], "refs", k);
93
93
  longest = std::max<uint32_t>(longest, uint32_t(rc[k].size()));
94
94
  }
95
95
 
@@ -4,11 +4,11 @@
4
4
  static const int32_t kStructuralSize = 24;
5
5
  static const int32_t kStructural[24 * 24] = {
6
6
  // A R N D C Q E G H I L K M F P S T W Y V B Z X *
7
- 10, 9, 9, 7, 6, 8, 7, 10, 9, 6, 6, 5, 6, 5, 9, 8, 9, 6, 6, 7, 8, 7, 7, 0,
7
+ 10, 9, 9, 7, 6, 8, 7, 10, 9, 6, 6, 5, 6, 5, 9, 8, 9, 5, 6, 7, 8, 7, 7, 0,
8
8
  9, 10, 10, 8, 4, 9, 8, 8, 8, 5, 4, 6, 5, 4, 10, 10, 9, 4, 5, 6, 9, 9, 7, 0,
9
9
  9, 10, 10, 8, 4, 9, 8, 8, 8, 5, 4, 6, 5, 4, 10, 10, 9, 4, 5, 6, 9, 9, 7, 0,
10
10
  7, 8, 8, 10, 3, 9, 10, 7, 6, 3, 3, 8, 3, 2, 8, 9, 8, 3, 3, 4, 9, 9, 6, 0,
11
- 6, 4, 4, 3, 10, 4, 2, 6, 7, 9, 10, 1, 9, 9, 4, 4, 5, 10, 10, 8, 4, 3, 6, 0,
11
+ 6, 4, 4, 3, 10, 4, 2, 6, 7, 9, 10, 1, 9, 9, 4, 4, 5, 10, 10, 8, 3, 3, 6, 0,
12
12
  8, 9, 9, 9, 4, 10, 9, 8, 7, 4, 4, 7, 4, 3, 9, 10, 9, 3, 4, 5, 9, 9, 7, 0,
13
13
  7, 8, 8, 10, 2, 9, 10, 6, 6, 3, 2, 8, 3, 2, 8, 8, 7, 2, 3, 4, 9, 9, 6, 0,
14
14
  10, 8, 8, 7, 6, 8, 6, 10, 9, 7, 6, 5, 6, 5, 8, 8, 9, 6, 6, 8, 8, 7, 7, 0,
@@ -21,10 +21,10 @@ static const int32_t kStructural[24 * 24] = {
21
21
  9, 10, 10, 8, 4, 9, 8, 8, 8, 5, 4, 6, 5, 4, 10, 10, 9, 4, 5, 6, 9, 9, 7, 0,
22
22
  8, 10, 10, 9, 4, 10, 8, 8, 7, 5, 4, 6, 5, 4, 10, 10, 9, 4, 4, 6, 9, 9, 7, 0,
23
23
  9, 9, 9, 8, 5, 9, 7, 9, 8, 6, 5, 6, 5, 4, 9, 9, 10, 5, 5, 7, 9, 8, 7, 0,
24
- 6, 4, 4, 3, 10, 3, 2, 6, 6, 9, 10, 0, 9, 10, 4, 4, 5, 10, 9, 8, 3, 3, 6, 0,
24
+ 5, 4, 4, 3, 10, 3, 2, 6, 6, 9, 10, 0, 9, 10, 4, 4, 5, 10, 9, 8, 3, 3, 6, 0,
25
25
  6, 5, 5, 3, 10, 4, 3, 6, 7, 10, 10, 1, 10, 9, 5, 4, 5, 9, 10, 9, 4, 3, 6, 0,
26
26
  7, 6, 6, 4, 8, 5, 4, 8, 8, 9, 8, 2, 9, 8, 6, 6, 7, 8, 9, 10, 5, 5, 7, 0,
27
- 8, 9, 9, 9, 4, 9, 9, 8, 7, 4, 4, 7, 4, 3, 9, 9, 9, 3, 4, 5, 9, 9, 7, 0,
27
+ 8, 9, 9, 9, 3, 9, 9, 8, 7, 4, 4, 7, 4, 3, 9, 9, 9, 3, 4, 5, 9, 9, 7, 0,
28
28
  7, 9, 9, 9, 3, 9, 9, 7, 6, 4, 3, 8, 4, 2, 9, 9, 8, 3, 3, 5, 9, 9, 6, 0,
29
29
  7, 7, 7, 6, 6, 7, 6, 7, 7, 7, 6, 4, 7, 6, 7, 7, 7, 6, 6, 7, 7, 6, 7, 0,
30
30
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes