Skip to content

Switch to mature tskit-dev layout - #15

Merged
jeromekelleher merged 18 commits into
tskit-dev:mainfrom
jeromekelleher:maturity
Oct 30, 2026
Merged

jeromekelleher merged 18 commits into
tskit-dev:mainfrom
jeromekelleher:maturity

Conversation

@jeromekelleher

Copy link
Copy Markdown
Member

No description provided.

Jerome Kelleher added 10 commits October 30, 2026 10:09
Before the tsinfer-hmm and tskit-hmm engines are removed, capture small
cases from the sc2ts ARG, two tsinfer chr20p ancestor groups and a
multiallelic msprime simulation. For each query we record the tsls
Viterbi path, its mismatches and log likelihood, and for some cases the
forward log likelihoods and posteriors. tsinfer-hmm finds paths with the
same likelihood for every query, and the same path for all but four.

tests/test_regression.py checks that tsls reproduces them.
From tskit's LsHmm tests, before it is removed from tskit:

- exact Viterbi paths on a balanced tree with a unique mutation on each
  sample, with missing flanks and a missing middle;
- reversibility: the mirrored tree sequence gives the same Viterbi
  optimum and posteriors, and the same likelihood apart from the initial
  probability, which depends on the nodes in the tree at the first site;
- a haplotype with every site missing;
- extreme recombination and mismatch probabilities;
- comb trees with many distinct values;
- small msprime simulations.

All are checked against the dense implementation.
tsls replaces the tsinfer-hmm and tskit-hmm engines, so remove them,
along with the benchmarks and experiments that compare against them. The
results that matter are recorded in docs/likelihood_model.md, and the
regression cases captured in the previous commit pin tsls's outputs on
the benchmark workloads. Everything removed is in the git history.

The relicensing record of the tsinfer code that tsls is derived from
moves to LICENSING.md.
Follow the standard layout of a tskit-dev package with a C extension:
the C library in lib/, the Python package in tsls/, the tests in tests/,
and the packaging at the root, with lwt_interface and lib/subprojects/tskit
linking into the tskit submodule.

- Take the version from git with setuptools_scm (tsls.__version__).
- Don't compile tskit's haplotype matching code, which tsls doesn't use
  and which is being removed from tskit.
- Run the tests in CI with the shared tskit-dev workflows.
- Rewrite the README for the merged engine.
Add the shared lint workflow, prek config (ruff, clang-format and
zizmor), tskit's clang-format style and the zizmor config, and apply
the formatting.
tsinfer has a fixed numbering of the alleles at each site (from its VCZ
data), which can include alleles that aren't yet in the tree sequence.
tsls.TreeSequence now takes a list of alleles for each site, as well as
one list for every site, so callers don't need to translate between
numberings:

- alleles can be a sequence of sequences, or a 2D array padded with
  empty strings, as tsinfer stores them;
- the number of alleles at a site is the length of its list, which sets
  the mismatch odds, and a haplotype can have any of them, whether or
  not it's in the tree sequence there;
- TreeSequence.num_alleles gives the number of alleles at each site.

Also:

- raise ValueError rather than LibraryError for bad inputs (unknown or
  duplicate alleles, bad haplotype alleles, site ranges, thresholds);
- set the matched haplotype to -1 outside [start, end), rather than
  leaving it uninitialised, and document the path coordinates and that
  ties are broken arbitrarily.
The inverse of mismatch_odds, to give the same emission model with a
different number of alleles. sc2ts needs this when it treats deletions
as missing data: it matches with 4 alleles, but the tree sequence still
has 5 (ACGT-).
tsinfer is tested on Windows, so tsls needs to build there too:

- use _BitScanForward64 and __forceinline with MSVC, rather than GCC's
  __builtin_ctzll and always_inline attribute;
- include the submodule's lwt_interface directly, rather than through a
  symlink, which isn't a link in a checkout on Windows.
The tests moved to the root of the repository.
@codecov-commenter

Copy link
Copy Markdown

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

Thanks for integrating Codecov - We've got you covered ☂️

Jerome Kelleher added 8 commits October 30, 2026 11:49
tsinfer and sc2ts used functions from tsls.model. Everything public is
now exported from tsls itself (tsls.Hmm, tsls.path_threshold,
tsls.recombination_probability etc.), and the modules it's defined in
are private (_matching, _model), with each object's __module__ set to
tsls. tests/test_api.py pins the namespace.
Restore benchmarking/ without the tsinfer and tskit engines:

- matcher.py (from engines.py) sets tsls up for a workload's model;
- bench.py (from paired.py) times tsls on the sc2ts and tsinfer
  workloads, with its memory, traceback size and, for the tsinfer
  workloads, how often it finds tsinfer's path, and adds the full sc2ts
  ARG;
- run.py, tsinfer_summary.py, the profiling scripts and callgrind.py
  run tsls only;
- the workload and query builders are unchanged.

The README records the final comparison of tsls with tsinfer-hmm in
time and memory on these workloads, run with paired.py from 1d70724
(the sc2ts sub-ARG and full ARG rows are still to come), and points to
the git history for the engines and the earlier results.
Exporting the API from __init__.py is enough, so the modules don't need
to be private, and objects keep their own __module__.
tsi_blkalloc.c and tsi_blkalloc_t were named after tsinfer, where the
allocator came from. The functions are renamed to match
(tsls_blockalloc_init etc.).
TSI_ATOMIC, TSI_NO_ATOMICS and tsi_safe_free become TSLS_ATOMIC,
TSLS_NO_ATOMICS and tsls_safe_free.
The exact runs on the 100k and 300k sub-ARGs, and the full sc2ts ARG
with the k = 1 threshold.
tsls_hmm_get_inherited_likelihood was no longer used, which clang
reports as an error with -Werror in the C tests.
lib/subprojects/tskit was a symlink into the tskit submodule. Symlinks
aren't links in a checkout on Windows, and setup-uv fails when it walks
the repository (EPERM on stat). The C tests now download the tskit C
1.3.1 release, as tsinfer's do; the submodule's C library is the same
release, and the Python module is still built from the submodule.
There are now no symlinks in the repository.
@jeromekelleher
jeromekelleher merged commit a32ce06 into tskit-dev:main Oct 30, 2026
9 checks passed
@jeromekelleher
jeromekelleher deleted the maturity branch October 30, 2026 13:00
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