Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 10 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ Fast fuzzy search over biological sequences (amino-acid or nucleotide), as a C++
core with a minimal Python binding. Build an immutable index once, then search
single queries or massive batches in parallel.

<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/antigenomics/seqtree/master/assets/workflow-dark.svg">
<source srcset="https://raw.githubusercontent.com/antigenomics/seqtree/master/assets/workflow-light.svg">
<img alt="seqtree workflow: inputs, batched processing and outputs. Schematic illustrations." src="https://raw.githubusercontent.com/antigenomics/seqtree/master/assets/workflow.png" width="100%">
</picture>

## Install

```fish
Expand All @@ -31,29 +37,12 @@ p = seqtree.SearchParams(max_subs=2, engine="seqtm")
for hit in idx.search("CASSLAPGATNEKLFF", p):
print(hit.ref_id, hit.score, hit.n_subs)

# parallel batch (releases the GIL)
results = idx.search_batch(queries, p, threads=0) # 0 = automatic, up to 16 allocated CPUs

# matrix-weighted budget. Name seqtrie -- engine="auto" always means seqtm.
# gap_open must follow the matrix: 2 * blosum62.scale() == 28, not the default 1.
pm = seqtree.SearchParams(matrix="blosum62", max_penalty=12, engine="seqtrie", gap_open=28)
top = idx.search_top("CASSLAPGATNEKLFF", pm, k=5)

# alignment on demand
aln = idx.align(0, "CASSLELGATNEKLFF", p)
print(aln.aligned_query, aln.aligned_ref, aln.ops)

# batch-vs-batch (auto-indexes the larger set)
pairs = seqtree.pairwise_batch(query_set, db_set, p, alphabet="aa")

# a short query against a long TEXT (a proteome), one index for every query length
tix = seqtree.TextIndex.build(proteome_records, alphabet="aa", k=4)
res = tix.search_batch(peptides, max_subs=2, threads=0)
for hit in res[0]:
print(hit.ref_id, hit.offset, hit.n_subs, hit.mismatches)
# Batch search uses the automatic budget (up to 16 allocated CPUs).
queries = ["CASSLAPGATNEKLFF", "CASSLELGATNEKLFF"]
results = idx.search_batch(queries, p)
```

That is the whole core loop. Significance, gap blocks, alignment and distances are in
Significance, gap blocks, alignment and distances are in
[More examples](#more-examples) below, and the
[docs](https://antigenomics.github.io/seqtree/) explain the why.

Expand Down
70 changes: 70 additions & 0 deletions assets/workflow-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
70 changes: 70 additions & 0 deletions assets/workflow-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/workflow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions docs/gapblock.rst
Original file line number Diff line number Diff line change
Expand Up @@ -341,9 +341,9 @@ rows identical in both views. No cross-row combinations are created.
from seqtree.gapblock import topk_batch, count_batch

queries, refs = ["ACDE", "ACD"], ["ACDE", "ACD", "ACDF"]
hits = topk_batch(queries, refs, k=2, threads=1)
hits = topk_batch(queries, refs, k=2, threads=0)
thresholds = [[h.score for h in row] for row in hits]
counts = count_batch(queries, refs, thresholds, threads=1)
counts = count_batch(queries, refs, thresholds, threads=0)

Each operation runs as one native batch with the GIL released. Top-k results use
O(Q*k) storage and each worker uses O(k + maximum sequence length) scratch.
Expand Down
10 changes: 10 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
seqtree
=======

.. image:: ../assets/workflow-light.svg
:alt: seqtree workflow overview: inputs, processing and outputs.
:width: 100%
:class: only-light

.. image:: ../assets/workflow-dark.svg
:alt: seqtree workflow overview: inputs, processing and outputs.
:width: 100%
:class: only-dark

.. raw:: html

<div class="proj-intro">
Expand Down
8 changes: 4 additions & 4 deletions skills/seqtree/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ operations, not domain datasets, clustering policy, or biological interpretation

Read the installed signatures or the public headers for the version being used.
Python-only convenience layers do not imply matching C++ classes.
In a source checkout, consult [API contracts](../../docs/api.rst),
[gap-block operations](../../docs/gapblock.rst), and
[E-value methodology](../../docs/evalue.rst) for advanced reductions and layouts.
In a source checkout, consult [API contracts](https://antigenomics.github.io/seqtree/api.html),
[gap-block operations](https://antigenomics.github.io/seqtree/gapblock.html), and
[E-value methodology](https://antigenomics.github.io/seqtree/evalue.html) for advanced reductions and layouts.

## C++ integration

Expand Down Expand Up @@ -73,7 +73,7 @@ from seqtree.pairwise import score, align

index = seqtree.Index.build(["CAT", "CAR", "WST"], alphabet="aa")
params = seqtree.SearchParams(max_subs=1, engine="seqtm")
rows = index.search_batch(["CAT", "CAR"], params, threads=1)
rows = index.search_batch(["CAT", "CAR"], params, threads=0)
assert {hit.ref_id for hit in rows[0]} == {0, 1}

matrix = seqtree.SubstitutionMatrix.blosum62()
Expand Down
Loading