seqpro 0.13.0__tar.gz → 0.15.0__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.
- {seqpro-0.13.0/.claude/skills/zensical-setup → seqpro-0.15.0/.claude/skills/zensical}/SKILL.md +1 -1
- {seqpro-0.13.0 → seqpro-0.15.0}/.github/workflows/release.yaml +2 -9
- {seqpro-0.13.0 → seqpro-0.15.0}/CHANGELOG.md +38 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/CLAUDE.md +2 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/PKG-INFO +1 -1
- seqpro-0.15.0/benchmarks/bench_to_packed.py +187 -0
- seqpro-0.15.0/docs/superpowers/plans/2026-05-31-rag-to-packed.md +815 -0
- seqpro-0.15.0/docs/superpowers/plans/2026-06-05-translate-unknown-codon-policy.md +1085 -0
- seqpro-0.15.0/docs/superpowers/specs/2026-05-31-rag-to-packed-design.md +134 -0
- seqpro-0.15.0/docs/superpowers/specs/2026-06-05-translate-unknown-codon-policy-design.md +213 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/pyproject.toml +1 -1
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/_encoders.py +4 -5
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/_numba.py +110 -12
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/alphabets/_alphabets.py +138 -21
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/rag/__init__.py +2 -1
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/rag/_array.py +22 -11
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/rag/_ops.py +148 -5
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/xr/__init__.py +2 -1
- {seqpro-0.13.0 → seqpro-0.15.0}/skills/seqpro/SKILL.md +4 -3
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/bench_translate_lut.py +4 -4
- seqpro-0.15.0/tests/test_rag_to_packed.py +130 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/test_translate.py +218 -12
- seqpro-0.13.0/.claude/skills/zensical-setup/.skillfish.json +0 -10
- {seqpro-0.13.0 → seqpro-0.15.0}/.gitattributes +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/.github/workflows/bump.yaml +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/.github/workflows/docs.yml +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/.github/workflows/lint.yaml +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/.github/workflows/merge.yaml +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/.github/workflows/publish.yaml +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/.github/workflows/release-pipeline.yaml +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/.github/workflows/test.yaml +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/.gitignore +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/.pre-commit-config.yaml +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/Cargo.lock +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/Cargo.toml +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/LICENSE +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/README.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/benches/kshuffle.rs +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/api/alphabets.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/api/bed.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/api/gtf.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/api/index.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/api/ragged.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/api/types.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/index.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/ragged.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/plans/2026-05-04-ragged-record-array.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/plans/2026-05-05-documentation-site.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/plans/2026-05-05-narwhals-coord-schema.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/plans/2026-05-05-ragged-zip-and-record-introspection.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/plans/2026-05-20-kshuffle-optimization.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/plans/2026-05-20-kshuffle-pooled-buffers-and-k2-fast-path.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/plans/2026-05-20-kshuffle-wilson-single-pass.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/plans/2026-05-20-release-pipeline.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/plans/2026-05-28-translate-lut-validation.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/plans/2026-05-31-flat-buffer-to-padded.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/specs/2026-05-04-ragged-record-array-design.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/specs/2026-05-05-documentation-site-design.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/specs/2026-05-05-narwhals-coord-schema-design.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/specs/2026-05-05-ragged-zip-and-record-introspection-design.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/specs/2026-05-20-kshuffle-optimization-design.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/specs/2026-05-20-kshuffle-pooled-buffers-and-k2-fast-path-design.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/specs/2026-05-20-kshuffle-wilson-single-pass-design.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/specs/2026-05-20-release-pipeline-design.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/specs/2026-05-28-translate-lut-and-validation-design.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/docs/superpowers/specs/2026-05-31-flat-buffer-to-padded-design.md +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/meta.yaml +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/pixi.lock +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/pixi.toml +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/__init__.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/_analyzers.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/_cleaners.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/_coords.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/_modifiers.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/_types.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/_utils.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/alphabets/__init__.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/bed.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/experimental/_experimental.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/experimental/_visualizers.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/gtf.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/py.typed +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/rag/_gufuncs.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/rag/_types.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/rag/_utils.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/transforms/__init__.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/transforms/augmentation.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/python/seqpro/transforms/tmm.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/scratch_bench_rc.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/scratch_bench_to_padded.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/src/kmer_encode.rs +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/src/kshuffle.rs +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/src/kshuffle_ref.rs +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/src/lib.rs +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/_shape_fixtures.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/bed/test_pyranges.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/bed/test_read.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/bed/test_sort.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/bed/test_with_length.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/conftest.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/test_analyzers.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/test_coords.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/test_encoders.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/test_modifiers.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/test_ohe.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/test_ragged.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/test_ragged_rc.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/test_ragged_to_padded.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/test_shape_matrix.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/test_tokenize.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/tests/test_transforms.py +0 -0
- {seqpro-0.13.0 → seqpro-0.15.0}/zensical.toml +0 -0
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
name: Create release
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- '[0-9]+.[0-9]+.[0-9]+'
|
|
7
4
|
workflow_dispatch:
|
|
8
5
|
inputs:
|
|
9
6
|
tag:
|
|
@@ -30,15 +27,11 @@ jobs:
|
|
|
30
27
|
- uses: actions/checkout@v4
|
|
31
28
|
with:
|
|
32
29
|
fetch-depth: 0
|
|
30
|
+
ref: ${{ inputs.tag }}
|
|
33
31
|
|
|
34
32
|
- name: Resolve tag
|
|
35
33
|
id: tag
|
|
36
|
-
run:
|
|
37
|
-
case "${{ github.event_name }}" in
|
|
38
|
-
push) echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT ;;
|
|
39
|
-
workflow_dispatch) echo "tag=${{ inputs.tag }}" >> $GITHUB_OUTPUT ;;
|
|
40
|
-
workflow_call) echo "tag=${{ inputs.tag }}" >> $GITHUB_OUTPUT ;;
|
|
41
|
-
esac
|
|
34
|
+
run: echo "tag=${{ inputs.tag }}" >> $GITHUB_OUTPUT
|
|
42
35
|
|
|
43
36
|
- name: Extract changelog section
|
|
44
37
|
run: |
|
|
@@ -1,3 +1,41 @@
|
|
|
1
|
+
## 0.15.0 (2026-06-07)
|
|
2
|
+
|
|
3
|
+
### Feat
|
|
4
|
+
|
|
5
|
+
- **translate**: Ragged pad + drop paths via unknown=
|
|
6
|
+
- **translate**: add unknown= param (pad path) and overloads
|
|
7
|
+
- **translate**: case-insensitive validate=True
|
|
8
|
+
- **translate**: add _nb_drop_unknown_codons compaction kernel
|
|
9
|
+
|
|
10
|
+
### Fix
|
|
11
|
+
|
|
12
|
+
- **translate**: update seqpro.xr translate call for marker_byte arg
|
|
13
|
+
- **translate**: restrict unknown marker to ASCII; document drop dense-table assumption
|
|
14
|
+
- **translate**: marker sentinel + case-folding in gufunc_translate_lut
|
|
15
|
+
- **translate**: marker sentinel + case-folding in gufunc_translate
|
|
16
|
+
|
|
17
|
+
## 0.14.0 (2026-06-01)
|
|
18
|
+
|
|
19
|
+
### Feat
|
|
20
|
+
|
|
21
|
+
- **rag**: add Ragged.to_packed method and export to_packed
|
|
22
|
+
- **rag**: add Numba-parallelized to_packed for flat layouts
|
|
23
|
+
|
|
24
|
+
### Fix
|
|
25
|
+
|
|
26
|
+
- **ci**: check out release tag and drop duplicate release trigger
|
|
27
|
+
- **rag**: produce canonical list-of-records layout in to_packed
|
|
28
|
+
|
|
29
|
+
### Refactor
|
|
30
|
+
|
|
31
|
+
- **rag**: make Ragged.to_packed copy keyword-only; add multibyte-trailing test
|
|
32
|
+
- **rag**: drop unused as_contiguous packing path in unbox
|
|
33
|
+
|
|
34
|
+
### Perf
|
|
35
|
+
|
|
36
|
+
- **rag**: microbenchmark to_packed throughput vs ak.to_packed
|
|
37
|
+
- **rag**: use to_packed at internal ak.to_packed call sites
|
|
38
|
+
|
|
1
39
|
## 0.13.0 (2026-06-01)
|
|
2
40
|
|
|
3
41
|
### Feat
|
|
@@ -72,6 +72,8 @@ Only `kshuffle.rs` is compiled. It's exposed as `seqpro._k_shuffle` (called by `
|
|
|
72
72
|
- Axis arguments (`length_axis`, `ohe_axis`) are always integers referring to the NumPy axis index; negative indexing is supported.
|
|
73
73
|
- The `transforms/` module wraps functional ops into callable objects with `__call__` for use in data pipelines.
|
|
74
74
|
- Conventional commits are enforced — use `feat:`, `fix:`, `ci:`, `bump:`, `refactor:`, `docs:`, etc. prefixes.
|
|
75
|
+
- **Validation is opt-in and front-loaded.** Add fast-fail/input validation via a `validate=` flag (or equivalent single opt-in), not per-feature `error` modes. There must be one obvious way to ask "is this input clean?" — don't duplicate the check across parameters.
|
|
76
|
+
- **No naive NumPy in hot paths.** Never use raw Python loops or naive NumPy (e.g. per-segment `np.concatenate`, Python `for` over sequences) where a Numba kernel is faster and leaner — unless the NumPy version is *verifiably* comparable in time and memory. When Numba is a poor fit (graph algorithms like k-shuffle), use the Rust/PyO3 extension (`src/`).
|
|
75
77
|
|
|
76
78
|
## Skills
|
|
77
79
|
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""Microbenchmark: seqpro.rag.to_packed vs ak.to_packed vs NumPy gather.
|
|
2
|
+
|
|
3
|
+
Run in the bench env:
|
|
4
|
+
pixi run -e bench python benchmarks/bench_to_packed.py --out bench_to_packed
|
|
5
|
+
|
|
6
|
+
Outputs <out>.csv and <out>_*.png. Sweeps n_rows, mean length, length
|
|
7
|
+
distribution, source (RAM vs memmap), dtype itemsize, and thread count, and
|
|
8
|
+
prints an effect-size ranking of which axes most affect the speedup ratio.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import os
|
|
15
|
+
import time
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def make_lengths(rng, n_rows, mean_len, distribution):
|
|
22
|
+
if distribution == "uniform":
|
|
23
|
+
lo, hi = max(1, mean_len // 2), mean_len * 2
|
|
24
|
+
return rng.integers(lo, hi + 1, size=n_rows)
|
|
25
|
+
# long-tailed: most rows short, a few very long (load imbalance)
|
|
26
|
+
lengths = rng.integers(1, max(2, mean_len // 4), size=n_rows)
|
|
27
|
+
n_big = max(1, n_rows // 100)
|
|
28
|
+
lengths[rng.choice(n_rows, n_big, replace=False)] = mean_len * 50
|
|
29
|
+
return lengths
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def build(rng, n_rows, mean_len, distribution, dtype, source, tmpdir):
|
|
33
|
+
import seqpro.rag as spr
|
|
34
|
+
|
|
35
|
+
lengths = make_lengths(rng, n_rows, mean_len, distribution).astype(np.int64)
|
|
36
|
+
total = int(lengths.sum())
|
|
37
|
+
if source == "memmap":
|
|
38
|
+
path = Path(tmpdir) / "data.dat"
|
|
39
|
+
data = np.memmap(path, dtype=dtype, mode="w+", shape=(total,))
|
|
40
|
+
data[:] = rng.integers(0, 255, size=total).astype(dtype)
|
|
41
|
+
else:
|
|
42
|
+
data = rng.integers(0, 255, size=total).astype(dtype)
|
|
43
|
+
rag = spr.Ragged.from_lengths(data, lengths)
|
|
44
|
+
# reorder so the layout is an (unpacked) ListArray, forcing a real gather
|
|
45
|
+
return rag[rng.permutation(n_rows)], total * np.dtype(dtype).itemsize
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def numpy_gather(rag):
|
|
49
|
+
import seqpro.rag as spr
|
|
50
|
+
|
|
51
|
+
parts = rag._parts
|
|
52
|
+
offs = parts.offsets
|
|
53
|
+
starts, stops = (offs[0], offs[1]) if offs.ndim == 2 else (offs[:-1], offs[1:])
|
|
54
|
+
lengths = stops - starts
|
|
55
|
+
out_off = np.empty(lengths.size + 1, dtype=np.int64)
|
|
56
|
+
out_off[0] = 0
|
|
57
|
+
np.cumsum(lengths, out=out_off[1:])
|
|
58
|
+
idx = np.repeat(starts - out_off[:-1], lengths) + np.arange(int(out_off[-1]))
|
|
59
|
+
return spr.Ragged.from_offsets(parts.data[idx], parts.shape, out_off)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def timeit(fn, arg, repeats):
|
|
63
|
+
fn(arg) # warm up (JIT, caches)
|
|
64
|
+
times = []
|
|
65
|
+
for _ in range(repeats):
|
|
66
|
+
t0 = time.perf_counter()
|
|
67
|
+
fn(arg)
|
|
68
|
+
times.append(time.perf_counter() - t0)
|
|
69
|
+
return float(np.median(times))
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def main():
|
|
73
|
+
p = argparse.ArgumentParser()
|
|
74
|
+
p.add_argument("--out", default="bench_to_packed")
|
|
75
|
+
p.add_argument("--repeats", type=int, default=5)
|
|
76
|
+
p.add_argument(
|
|
77
|
+
"--n-rows", type=int, nargs="+", default=[1000, 10000, 100000, 1000000]
|
|
78
|
+
)
|
|
79
|
+
p.add_argument("--mean-len", type=int, nargs="+", default=[16, 256, 4096])
|
|
80
|
+
p.add_argument("--distributions", nargs="+", default=["uniform", "longtail"])
|
|
81
|
+
p.add_argument("--sources", nargs="+", default=["ram", "memmap"])
|
|
82
|
+
p.add_argument("--dtypes", nargs="+", default=["uint8", "float64"])
|
|
83
|
+
p.add_argument("--threads", type=int, nargs="+", default=[int(os.cpu_count() or 1)])
|
|
84
|
+
args = p.parse_args()
|
|
85
|
+
|
|
86
|
+
import awkward as ak
|
|
87
|
+
import pandas as pd
|
|
88
|
+
import seqpro.rag as spr # noqa: F401 (ensures kernel import)
|
|
89
|
+
import tempfile
|
|
90
|
+
|
|
91
|
+
rng = np.random.default_rng(0)
|
|
92
|
+
rows = []
|
|
93
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
94
|
+
for nthreads in args.threads:
|
|
95
|
+
import numba
|
|
96
|
+
|
|
97
|
+
numba.set_num_threads(nthreads)
|
|
98
|
+
impls = {
|
|
99
|
+
"seqpro": lambda r: r.to_packed(),
|
|
100
|
+
"ak": lambda r: spr.Ragged(ak.to_packed(r)),
|
|
101
|
+
"numpy": numpy_gather,
|
|
102
|
+
}
|
|
103
|
+
for n_rows in args.n_rows:
|
|
104
|
+
for mean_len in args.mean_len:
|
|
105
|
+
for dist in args.distributions:
|
|
106
|
+
for src in args.sources:
|
|
107
|
+
for dt in args.dtypes:
|
|
108
|
+
rag, nbytes = build(
|
|
109
|
+
rng, n_rows, mean_len, dist, dt, src, tmp
|
|
110
|
+
)
|
|
111
|
+
for name, fn in impls.items():
|
|
112
|
+
t = timeit(fn, rag, args.repeats)
|
|
113
|
+
rows.append(
|
|
114
|
+
dict(
|
|
115
|
+
impl=name,
|
|
116
|
+
n_rows=n_rows,
|
|
117
|
+
mean_len=mean_len,
|
|
118
|
+
distribution=dist,
|
|
119
|
+
source=src,
|
|
120
|
+
dtype=dt,
|
|
121
|
+
threads=nthreads,
|
|
122
|
+
seconds=t,
|
|
123
|
+
gbps=nbytes / t / 1e9,
|
|
124
|
+
)
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
df = pd.DataFrame(rows)
|
|
128
|
+
df.to_csv(f"{args.out}.csv", index=False)
|
|
129
|
+
_plots_and_summary(df, args.out)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _plots_and_summary(df, out):
|
|
133
|
+
import matplotlib
|
|
134
|
+
|
|
135
|
+
matplotlib.use("Agg")
|
|
136
|
+
import matplotlib.pyplot as plt
|
|
137
|
+
import seaborn as sns
|
|
138
|
+
|
|
139
|
+
# throughput vs n_rows, faceted by mean_len x dtype, hue impl
|
|
140
|
+
g = sns.relplot(
|
|
141
|
+
data=df,
|
|
142
|
+
x="n_rows",
|
|
143
|
+
y="gbps",
|
|
144
|
+
hue="impl",
|
|
145
|
+
style="source",
|
|
146
|
+
col="mean_len",
|
|
147
|
+
row="dtype",
|
|
148
|
+
kind="line",
|
|
149
|
+
marker="o",
|
|
150
|
+
facet_kws=dict(sharey=False),
|
|
151
|
+
)
|
|
152
|
+
g.set(xscale="log")
|
|
153
|
+
g.savefig(f"{out}_throughput.png", dpi=120)
|
|
154
|
+
|
|
155
|
+
# thread scaling for seqpro
|
|
156
|
+
if df["threads"].nunique() > 1:
|
|
157
|
+
sub = df[df.impl == "seqpro"]
|
|
158
|
+
gt = sns.relplot(
|
|
159
|
+
data=sub, x="threads", y="gbps", hue="mean_len", kind="line", marker="o"
|
|
160
|
+
)
|
|
161
|
+
gt.savefig(f"{out}_threads.png", dpi=120)
|
|
162
|
+
plt.close("all")
|
|
163
|
+
|
|
164
|
+
# effect-size ranking on speedup (seqpro / ak) — goal 2
|
|
165
|
+
wide = df.pivot_table(
|
|
166
|
+
index=["n_rows", "mean_len", "distribution", "source", "dtype", "threads"],
|
|
167
|
+
columns="impl",
|
|
168
|
+
values="gbps",
|
|
169
|
+
).reset_index()
|
|
170
|
+
wide["speedup"] = wide["seqpro"] / wide["ak"]
|
|
171
|
+
print("\n=== Speedup (seqpro / ak) summary ===")
|
|
172
|
+
print(wide["speedup"].describe())
|
|
173
|
+
print("\n=== Mean speedup by axis (effect size) ===")
|
|
174
|
+
axes = ["n_rows", "mean_len", "distribution", "source", "dtype", "threads"]
|
|
175
|
+
spreads = {}
|
|
176
|
+
for ax in axes:
|
|
177
|
+
means = wide.groupby(ax)["speedup"].mean()
|
|
178
|
+
spreads[ax] = means.max() - means.min()
|
|
179
|
+
print(f"\n{ax}:")
|
|
180
|
+
print(means)
|
|
181
|
+
print("\n=== Axes ranked by speedup spread (most influential first) ===")
|
|
182
|
+
for ax, s in sorted(spreads.items(), key=lambda kv: -kv[1]):
|
|
183
|
+
print(f" {ax:14s} spread={s:.2f}")
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
if __name__ == "__main__":
|
|
187
|
+
main()
|