tskit 1.0.0b3__tar.gz → 1.0.2__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 (98) hide show
  1. tskit-1.0.2/PKG-INFO +45 -0
  2. {tskit-1.0.0b3 → tskit-1.0.2}/_tskitmodule.c +201 -41
  3. {tskit-1.0.0b3 → tskit-1.0.2}/lib/subprojects/kastore/kastore.h +1 -1
  4. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit/core.c +77 -54
  5. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit/core.h +55 -29
  6. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit/genotypes.c +231 -8
  7. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit/haplotype_matching.c +6 -6
  8. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit/tables.c +71 -28
  9. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit/tables.h +16 -2
  10. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit/trees.c +356 -269
  11. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit/trees.h +55 -6
  12. {tskit-1.0.0b3 → tskit-1.0.2}/lwt_interface/tskit_lwt_interface.h +2 -2
  13. tskit-1.0.2/pyproject.toml +183 -0
  14. {tskit-1.0.0b3 → tskit-1.0.2}/setup.py +1 -2
  15. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_avl_tree.py +2 -3
  16. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_balance_metrics.py +2 -1
  17. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_cli.py +4 -6
  18. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_coalrate.py +5 -12
  19. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_combinatorics.py +2 -2
  20. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_distance_metrics.py +1 -0
  21. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_divmat.py +83 -42
  22. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_drawing.py +66 -66
  23. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_file_format.py +4 -9
  24. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_fileobj.py +8 -9
  25. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_genotype_matching.py +2 -5
  26. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_genotypes.py +627 -99
  27. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_haplotype_matching.py +2 -3
  28. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_highlevel.py +88 -15
  29. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_ibd.py +5 -7
  30. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_immutable_table_collection.py +36 -19
  31. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_intervals.py +1 -0
  32. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_ld_matrix.py +31 -41
  33. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_metadata.py +30 -0
  34. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_ms.py +1 -0
  35. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_parsimony.py +2 -4
  36. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_phylo_formats.py +6 -10
  37. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_provenance.py +1 -0
  38. tskit-1.0.0b3/tests/test_lowlevel.py → tskit-1.0.2/tests/test_python_c.py +214 -44
  39. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_reference_sequence.py +2 -3
  40. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_relatedness_vector.py +100 -39
  41. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_stats.py +1 -0
  42. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_table_transforms.py +1 -0
  43. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_tables.py +264 -42
  44. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_text_formats.py +1 -0
  45. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_threads.py +3 -6
  46. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_topology.py +104 -62
  47. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_tree_positioning.py +1 -0
  48. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_tree_stats.py +23 -62
  49. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_util.py +1 -0
  50. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_utilities.py +3 -7
  51. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_vcf.py +8 -14
  52. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_version.py +1 -0
  53. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_wright_fisher.py +1 -0
  54. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/_version.py +1 -1
  55. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/cli.py +1 -0
  56. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/combinatorics.py +2 -2
  57. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/drawing.py +20 -39
  58. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/exceptions.py +8 -7
  59. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/genotypes.py +25 -24
  60. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/intervals.py +1 -0
  61. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/jit/numba.py +1 -3
  62. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/metadata.py +10 -11
  63. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/provenance.py +2 -0
  64. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/stats.py +1 -0
  65. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/tables.py +60 -43
  66. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/text_formats.py +12 -22
  67. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/trees.py +451 -307
  68. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/util.py +16 -16
  69. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/vcf.py +1 -0
  70. tskit-1.0.2/tskit.egg-info/PKG-INFO +45 -0
  71. {tskit-1.0.0b3 → tskit-1.0.2}/tskit.egg-info/SOURCES.txt +1 -1
  72. tskit-1.0.2/tskit.egg-info/requires.txt +2 -0
  73. tskit-1.0.0b3/PKG-INFO +0 -105
  74. tskit-1.0.0b3/pyproject.toml +0 -132
  75. tskit-1.0.0b3/tskit.egg-info/PKG-INFO +0 -105
  76. tskit-1.0.0b3/tskit.egg-info/requires.txt +0 -64
  77. {tskit-1.0.0b3 → tskit-1.0.2}/LICENSE +0 -0
  78. {tskit-1.0.0b3 → tskit-1.0.2}/MANIFEST.in +0 -0
  79. {tskit-1.0.0b3 → tskit-1.0.2}/README.rst +0 -0
  80. {tskit-1.0.0b3 → tskit-1.0.2}/lib/subprojects/kastore/kastore.c +0 -0
  81. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit/convert.c +0 -0
  82. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit/convert.h +0 -0
  83. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit/genotypes.h +0 -0
  84. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit/haplotype_matching.h +0 -0
  85. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit/stats.c +0 -0
  86. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit/stats.h +0 -0
  87. {tskit-1.0.0b3 → tskit-1.0.2}/lib/tskit.h +0 -0
  88. {tskit-1.0.0b3 → tskit-1.0.2}/setup.cfg +0 -0
  89. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_dict_encoding.py +1 -1
  90. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_extend_haplotypes.py +0 -0
  91. {tskit-1.0.0b3 → tskit-1.0.2}/tests/test_jit.py +0 -0
  92. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/__init__.py +0 -0
  93. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/__main__.py +0 -0
  94. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/jit/__init__.py +0 -0
  95. {tskit-1.0.0b3 → tskit-1.0.2}/tskit/provenance.schema.json +0 -0
  96. {tskit-1.0.0b3 → tskit-1.0.2}/tskit.egg-info/dependency_links.txt +0 -0
  97. {tskit-1.0.0b3 → tskit-1.0.2}/tskit.egg-info/entry_points.txt +0 -0
  98. {tskit-1.0.0b3 → tskit-1.0.2}/tskit.egg-info/top_level.txt +0 -0
tskit-1.0.2/PKG-INFO ADDED
@@ -0,0 +1,45 @@
1
+ Metadata-Version: 2.4
2
+ Name: tskit
3
+ Version: 1.0.2
4
+ Summary: The tree sequence toolkit.
5
+ Author-email: Tskit Developers <admin@tskit.dev>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://tskit.dev/tskit
8
+ Project-URL: Documentation, https://tskit.dev/tskit/docs/stable
9
+ Project-URL: Changelog, https://tskit.dev/tskit/docs/stable/changelogs.html
10
+ Project-URL: Bug Tracker, https://github.com/tskit-dev/tskit/issues
11
+ Project-URL: GitHub, https://github.com/tskit-dev/tskit/
12
+ Keywords: population genetics,tree sequence,ancestral recombination graph,evolutionary tree,statistical genetics,phylogenetics,tskit
13
+ Classifier: Programming Language :: C
14
+ Classifier: Programming Language :: Python
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Classifier: Development Status :: 5 - Production/Stable
22
+ Classifier: Environment :: Other Environment
23
+ Classifier: Intended Audience :: Science/Research
24
+ Classifier: Operating System :: POSIX
25
+ Classifier: Operating System :: MacOS :: MacOS X
26
+ Classifier: Operating System :: Microsoft :: Windows
27
+ Classifier: Topic :: Scientific/Engineering
28
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
29
+ Requires-Python: >=3.11
30
+ Description-Content-Type: text/x-rst
31
+ License-File: LICENSE
32
+ Requires-Dist: jsonschema>=3.0.0
33
+ Requires-Dist: numpy>=2
34
+ Dynamic: license-file
35
+
36
+
37
+ The tree sequence toolkit.
38
+
39
+ Tskit is a cross-platform library for the storage and analysis of large-scale
40
+ genetic genealogy and variation data.
41
+ Please see the `documentation <https://tskit.dev/tskit/docs/stable/>`_
42
+ for further details.
43
+
44
+ Tskit is highly portable, and provides a number of
45
+ `installation options <https://tskit.dev/tskit/docs/stable/installation.html>`_.
@@ -36,10 +36,10 @@
36
36
  #define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION
37
37
  #undef NPY_FEATURE_VERSION
38
38
  #define NPY_FEATURE_VERSION NPY_2_0_API_VERSION
39
- #define HAVE_NUMPY_2 1
39
+ #define HAVE_NUMPY_2 1
40
40
  #else
41
41
  #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
42
- #define HAVE_NUMPY_2 0
42
+ #define HAVE_NUMPY_2 0
43
43
  #endif
44
44
  #include <numpy/arrayobject.h>
45
45
 
@@ -49,7 +49,7 @@
49
49
  #include "kastore.h"
50
50
  #include "tskit.h"
51
51
 
52
- #define SET_COLS 0
52
+ #define SET_COLS 0
53
53
  #define APPEND_COLS 1
54
54
 
55
55
  /* TskitException is the superclass of all exceptions that can be thrown by
@@ -4347,15 +4347,18 @@ TableCollection_union(TableCollection *self, PyObject *args, PyObject *kwds)
4347
4347
  npy_intp *shape;
4348
4348
  tsk_flags_t options = 0;
4349
4349
  int check_shared = true;
4350
+ int all_edges = false;
4351
+ int all_mutations = false;
4350
4352
  int add_populations = true;
4351
4353
  static char *kwlist[] = { "other", "other_node_mapping", "check_shared_equality",
4352
- "add_populations", NULL };
4354
+ "add_populations", "all_edges", "all_mutations", NULL };
4353
4355
 
4354
4356
  if (TableCollection_check_state(self) != 0) {
4355
4357
  goto out;
4356
4358
  }
4357
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O|ii", kwlist, &TableCollectionType,
4358
- &other, &other_node_mapping, &check_shared, &add_populations)) {
4359
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O|iiii", kwlist,
4360
+ &TableCollectionType, &other, &other_node_mapping, &check_shared,
4361
+ &add_populations, &all_edges, &all_mutations)) {
4359
4362
  goto out;
4360
4363
  }
4361
4364
  nmap_array = (PyArrayObject *) PyArray_FROMANY(
@@ -4370,6 +4373,12 @@ TableCollection_union(TableCollection *self, PyObject *args, PyObject *kwds)
4370
4373
  " number of nodes in the other tree sequence.");
4371
4374
  goto out;
4372
4375
  }
4376
+ if (all_edges) {
4377
+ options |= TSK_UNION_ALL_EDGES;
4378
+ }
4379
+ if (all_mutations) {
4380
+ options |= TSK_UNION_ALL_MUTATIONS;
4381
+ }
4373
4382
  if (!check_shared) {
4374
4383
  options |= TSK_UNION_NO_CHECK_SHARED;
4375
4384
  }
@@ -5335,6 +5344,69 @@ out:
5335
5344
  return ret;
5336
5345
  }
5337
5346
 
5347
+ static PyObject *
5348
+ TreeSequence_link_ancestors(TreeSequence *self, PyObject *args, PyObject *kwds)
5349
+ {
5350
+ int err;
5351
+ PyObject *ret = NULL;
5352
+ PyObject *samples = NULL;
5353
+ PyObject *ancestors = NULL;
5354
+ PyArrayObject *samples_array = NULL;
5355
+ PyArrayObject *ancestors_array = NULL;
5356
+ npy_intp *shape;
5357
+ tsk_size_t num_samples, num_ancestors;
5358
+ EdgeTable *result = NULL;
5359
+ PyObject *result_args = NULL;
5360
+ static char *kwlist[] = { "samples", "ancestors", NULL };
5361
+
5362
+ if (TreeSequence_check_state(self) != 0) {
5363
+ goto out;
5364
+ }
5365
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &samples, &ancestors)) {
5366
+ goto out;
5367
+ }
5368
+
5369
+ samples_array = (PyArrayObject *) PyArray_FROMANY(
5370
+ samples, NPY_INT32, 1, 1, NPY_ARRAY_IN_ARRAY);
5371
+ if (samples_array == NULL) {
5372
+ goto out;
5373
+ }
5374
+ shape = PyArray_DIMS(samples_array);
5375
+ num_samples = (tsk_size_t) shape[0];
5376
+
5377
+ ancestors_array = (PyArrayObject *) PyArray_FROMANY(
5378
+ ancestors, NPY_INT32, 1, 1, NPY_ARRAY_IN_ARRAY);
5379
+ if (ancestors_array == NULL) {
5380
+ goto out;
5381
+ }
5382
+ shape = PyArray_DIMS(ancestors_array);
5383
+ num_ancestors = (tsk_size_t) shape[0];
5384
+
5385
+ result_args = PyTuple_New(0);
5386
+ if (result_args == NULL) {
5387
+ goto out;
5388
+ }
5389
+ result = (EdgeTable *) PyObject_CallObject((PyObject *) &EdgeTableType, result_args);
5390
+ if (result == NULL) {
5391
+ goto out;
5392
+ }
5393
+ err = tsk_table_collection_link_ancestors(self->tree_sequence->tables,
5394
+ PyArray_DATA(samples_array), num_samples, PyArray_DATA(ancestors_array),
5395
+ num_ancestors, 0, result->table);
5396
+ if (err != 0) {
5397
+ handle_library_error(err);
5398
+ goto out;
5399
+ }
5400
+ ret = (PyObject *) result;
5401
+ result = NULL;
5402
+ out:
5403
+ Py_XDECREF(samples_array);
5404
+ Py_XDECREF(ancestors_array);
5405
+ Py_XDECREF(result);
5406
+ Py_XDECREF(result_args);
5407
+ return ret;
5408
+ }
5409
+
5338
5410
  static PyObject *
5339
5411
  TreeSequence_load(TreeSequence *self, PyObject *args, PyObject *kwds)
5340
5412
  {
@@ -6070,6 +6142,98 @@ out:
6070
6142
  return ret;
6071
6143
  }
6072
6144
 
6145
+ static PyObject *
6146
+ TreeSequence_decode_alignments(TreeSequence *self, PyObject *args, PyObject *kwds)
6147
+ {
6148
+ int err;
6149
+ PyObject *ret = NULL;
6150
+ PyObject *py_ref, *py_nodes, *py_missing;
6151
+ PyArrayObject *nodes_array = NULL;
6152
+ const char *ref_seq;
6153
+ Py_ssize_t ref_len, missing_len;
6154
+ tsk_id_t *nodes;
6155
+ tsk_size_t num_nodes;
6156
+ double left, right;
6157
+ char missing_char;
6158
+ const char *missing_utf8;
6159
+ int isolated_as_missing = 1;
6160
+ tsk_flags_t options = 0;
6161
+ PyObject *buf_obj = NULL;
6162
+ char *buf = NULL;
6163
+
6164
+ static char *kwlist[] = { "reference_sequence", "nodes", "left", "right",
6165
+ "missing_data_character", "isolated_as_missing", NULL };
6166
+
6167
+ if (TreeSequence_check_state(self) != 0) {
6168
+ goto out;
6169
+ }
6170
+
6171
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOddOp", kwlist, &py_ref, &py_nodes,
6172
+ &left, &right, &py_missing, &isolated_as_missing)) {
6173
+ goto out;
6174
+ }
6175
+
6176
+ if (!PyBytes_Check(py_ref)) {
6177
+ PyErr_SetString(PyExc_TypeError, "reference_sequence must be bytes");
6178
+ goto out;
6179
+ }
6180
+ if (PyBytes_AsStringAndSize(py_ref, (char **) &ref_seq, &ref_len) < 0) {
6181
+ goto out;
6182
+ }
6183
+
6184
+ if (!PyUnicode_Check(py_missing)) {
6185
+ PyErr_SetString(
6186
+ PyExc_TypeError, "missing_data_character must be a (length 1) string");
6187
+ goto out;
6188
+ }
6189
+ missing_utf8 = PyUnicode_AsUTF8AndSize(py_missing, &missing_len);
6190
+ if (missing_utf8 == NULL) {
6191
+ goto out;
6192
+ }
6193
+ if (missing_len != 1) {
6194
+ PyErr_SetString(
6195
+ PyExc_TypeError, "missing_data_character must be a single character");
6196
+ goto out;
6197
+ }
6198
+ missing_char = missing_utf8[0];
6199
+
6200
+ if (!isolated_as_missing) {
6201
+ options |= TSK_ISOLATED_NOT_MISSING;
6202
+ }
6203
+
6204
+ nodes_array = (PyArrayObject *) PyArray_FROMANY(
6205
+ py_nodes, NPY_INT32, 1, 1, NPY_ARRAY_IN_ARRAY);
6206
+ if (nodes_array == NULL) {
6207
+ goto out;
6208
+ }
6209
+ num_nodes = (tsk_size_t) PyArray_DIM(nodes_array, 0);
6210
+ nodes = PyArray_DATA(nodes_array);
6211
+
6212
+ buf_obj = PyBytes_FromStringAndSize(
6213
+ NULL, (Py_ssize_t) (num_nodes * (tsk_size_t) (right - left)));
6214
+ if (buf_obj == NULL) {
6215
+ goto out;
6216
+ }
6217
+ buf = PyBytes_AS_STRING(buf_obj);
6218
+
6219
+ Py_BEGIN_ALLOW_THREADS
6220
+ err = tsk_treeseq_decode_alignments(self->tree_sequence, ref_seq,
6221
+ (tsk_size_t) ref_len, nodes, num_nodes, left, right, missing_char, buf, options);
6222
+ Py_END_ALLOW_THREADS
6223
+ if (err != 0) {
6224
+ handle_library_error(err);
6225
+ goto out;
6226
+ }
6227
+
6228
+ ret = buf_obj;
6229
+ buf_obj = NULL;
6230
+
6231
+ out:
6232
+ Py_XDECREF(nodes_array);
6233
+ Py_XDECREF(buf_obj);
6234
+ return ret;
6235
+ }
6236
+
6073
6237
  static PyObject *
6074
6238
  TreeSequence_get_mutations_edge(TreeSequence *self)
6075
6239
  {
@@ -6169,11 +6333,12 @@ TreeSequence_genealogical_nearest_neighbours(
6169
6333
  goto out;
6170
6334
  }
6171
6335
 
6172
- Py_BEGIN_ALLOW_THREADS err = tsk_treeseq_genealogical_nearest_neighbours(
6173
- self->tree_sequence, PyArray_DATA(focal_array), num_focal, reference_sets,
6174
- reference_set_size, num_reference_sets, 0, PyArray_DATA(ret_array));
6175
- Py_END_ALLOW_THREADS if (err != 0)
6176
- {
6336
+ Py_BEGIN_ALLOW_THREADS
6337
+ err = tsk_treeseq_genealogical_nearest_neighbours(self->tree_sequence,
6338
+ PyArray_DATA(focal_array), num_focal, reference_sets, reference_set_size,
6339
+ num_reference_sets, 0, PyArray_DATA(ret_array));
6340
+ Py_END_ALLOW_THREADS
6341
+ if (err != 0) {
6177
6342
  handle_library_error(err);
6178
6343
  goto out;
6179
6344
  }
@@ -6289,11 +6454,11 @@ TreeSequence_mean_descendants(TreeSequence *self, PyObject *args, PyObject *kwds
6289
6454
  goto out;
6290
6455
  }
6291
6456
 
6292
- Py_BEGIN_ALLOW_THREADS err
6293
- = tsk_treeseq_mean_descendants(self->tree_sequence, reference_sets,
6294
- reference_set_size, num_reference_sets, 0, PyArray_DATA(ret_array));
6295
- Py_END_ALLOW_THREADS if (err != 0)
6296
- {
6457
+ Py_BEGIN_ALLOW_THREADS
6458
+ err = tsk_treeseq_mean_descendants(self->tree_sequence, reference_sets,
6459
+ reference_set_size, num_reference_sets, 0, PyArray_DATA(ret_array));
6460
+ Py_END_ALLOW_THREADS
6461
+ if (err != 0) {
6297
6462
  handle_library_error(err);
6298
6463
  goto out;
6299
6464
  }
@@ -7097,12 +7262,12 @@ TreeSequence_weighted_stat_vector_method(
7097
7262
  if (result_array == NULL) {
7098
7263
  goto out;
7099
7264
  }
7100
- Py_BEGIN_ALLOW_THREADS err
7101
- = method(self->tree_sequence, w_shape[1], PyArray_DATA(weights_array),
7102
- num_windows, PyArray_DATA(windows_array), num_focal_nodes,
7103
- PyArray_DATA(focal_nodes_array), PyArray_DATA(result_array), options);
7104
- Py_END_ALLOW_THREADS if (err != 0)
7105
- {
7265
+ Py_BEGIN_ALLOW_THREADS
7266
+ err = method(self->tree_sequence, w_shape[1], PyArray_DATA(weights_array),
7267
+ num_windows, PyArray_DATA(windows_array), num_focal_nodes,
7268
+ PyArray_DATA(focal_nodes_array), PyArray_DATA(result_array), options);
7269
+ Py_END_ALLOW_THREADS
7270
+ if (err != 0) {
7106
7271
  handle_library_error(err);
7107
7272
  goto out;
7108
7273
  }
@@ -7324,18 +7489,12 @@ TreeSequence_divergence_matrix(TreeSequence *self, PyObject *args, PyObject *kwd
7324
7489
  options |= TSK_STAT_SPAN_NORMALISE;
7325
7490
  }
7326
7491
 
7327
- // clang-format off
7328
7492
  Py_BEGIN_ALLOW_THREADS
7329
- err = tsk_treeseq_divergence_matrix(
7330
- self->tree_sequence,
7331
- num_sample_sets, sample_set_sizes, sample_sets,
7332
- num_windows, PyArray_DATA(windows_array),
7333
- options, PyArray_DATA(result_array));
7493
+ err = tsk_treeseq_divergence_matrix(self->tree_sequence, num_sample_sets,
7494
+ sample_set_sizes, sample_sets, num_windows, PyArray_DATA(windows_array), options,
7495
+ PyArray_DATA(result_array));
7334
7496
  Py_END_ALLOW_THREADS
7335
- // clang-format on
7336
- /* Clang-format insists on doing this in spite of the "off" instruction above */
7337
- if (err != 0)
7338
- {
7497
+ if (err != 0) {
7339
7498
  handle_library_error(err);
7340
7499
  goto out;
7341
7500
  }
@@ -7867,17 +8026,13 @@ TreeSequence_ld_matrix(TreeSequence *self, PyObject *args, PyObject *kwds,
7867
8026
  goto out;
7868
8027
  }
7869
8028
 
7870
- // clang-format off
7871
8029
  Py_BEGIN_ALLOW_THREADS
7872
8030
  err = method(self->tree_sequence, num_sample_sets,
7873
8031
  PyArray_DATA(sample_set_sizes_array), PyArray_DATA(sample_sets_array),
7874
8032
  result_dim[0], row_sites_parsed, row_positions_parsed, result_dim[1],
7875
8033
  col_sites_parsed, col_positions_parsed, options, PyArray_DATA(result_matrix));
7876
8034
  Py_END_ALLOW_THREADS
7877
- // clang-format on
7878
-
7879
- if (err != 0)
7880
- {
8035
+ if (err != 0) {
7881
8036
  handle_library_error(err);
7882
8037
  goto out;
7883
8038
  }
@@ -8050,7 +8205,6 @@ TreeSequence_k_way_ld_matrix(TreeSequence *self, PyObject *args, PyObject *kwds,
8050
8205
  goto out;
8051
8206
  }
8052
8207
 
8053
- // clang-format off
8054
8208
  Py_BEGIN_ALLOW_THREADS
8055
8209
  err = method(self->tree_sequence, num_sample_sets,
8056
8210
  PyArray_DATA(sample_set_sizes_array), PyArray_DATA(sample_sets_array),
@@ -8058,9 +8212,7 @@ TreeSequence_k_way_ld_matrix(TreeSequence *self, PyObject *args, PyObject *kwds,
8058
8212
  row_sites_parsed, row_positions_parsed, result_dim[1], col_sites_parsed,
8059
8213
  col_positions_parsed, options, PyArray_DATA(result_matrix));
8060
8214
  Py_END_ALLOW_THREADS
8061
- // clang-format on
8062
- if (err != 0)
8063
- {
8215
+ if (err != 0) {
8064
8216
  handle_library_error(err);
8065
8217
  goto out;
8066
8218
  }
@@ -8519,6 +8671,10 @@ static PyMethodDef TreeSequence_methods[] = {
8519
8671
  .ml_meth = (PyCFunction) TreeSequence_dump_tables,
8520
8672
  .ml_flags = METH_VARARGS | METH_KEYWORDS,
8521
8673
  .ml_doc = "Dumps the tree sequence to the specified set of tables" },
8674
+ { .ml_name = "link_ancestors",
8675
+ .ml_meth = (PyCFunction) TreeSequence_link_ancestors,
8676
+ .ml_flags = METH_VARARGS | METH_KEYWORDS,
8677
+ .ml_doc = "Returns an EdgeTable linking the specified samples and ancestors." },
8522
8678
  { .ml_name = "get_node",
8523
8679
  .ml_meth = (PyCFunction) TreeSequence_get_node,
8524
8680
  .ml_flags = METH_VARARGS,
@@ -8651,6 +8807,10 @@ static PyMethodDef TreeSequence_methods[] = {
8651
8807
  .ml_meth = (PyCFunction) TreeSequence_get_individuals_nodes,
8652
8808
  .ml_flags = METH_NOARGS,
8653
8809
  .ml_doc = "Returns an array of the node ids for each individual" },
8810
+ { .ml_name = "decode_alignments",
8811
+ .ml_meth = (PyCFunction) TreeSequence_decode_alignments,
8812
+ .ml_flags = METH_VARARGS | METH_KEYWORDS,
8813
+ .ml_doc = "Decode full alignments for given nodes and interval." },
8654
8814
  { .ml_name = "get_mutations_edge",
8655
8815
  .ml_meth = (PyCFunction) TreeSequence_get_mutations_edge,
8656
8816
  .ml_flags = METH_NOARGS,
@@ -157,7 +157,7 @@ to the API or ABI are introduced, i.e., the addition of a new function.
157
157
  The library patch version. Incremented when any changes not relevant to the
158
158
  to the API or ABI are introduced, i.e., internal refactors of bugfixes.
159
159
  */
160
- #define KAS_VERSION_PATCH 1
160
+ #define KAS_VERSION_PATCH 2
161
161
  /** @} */
162
162
 
163
163
  #define KAS_HEADER_SIZE 64
@@ -584,6 +584,14 @@ tsk_strerror_internal(int err)
584
584
  ret = "Must have at least one allele when specifying an allele map. "
585
585
  "(TSK_ERR_ZERO_ALLELES)";
586
586
  break;
587
+ case TSK_ERR_BAD_ALLELE_LENGTH:
588
+ ret = "Alleles used when decoding alignments must have length one. "
589
+ "(TSK_ERR_BAD_ALLELE_LENGTH)";
590
+ break;
591
+ case TSK_ERR_MISSING_CHAR_COLLISION:
592
+ ret = "Alleles used when decoding alignments must not match the missing "
593
+ "data character. (TSK_ERR_MISSING_CHAR_COLLISION)";
594
+ break;
587
595
 
588
596
  /* Distance metric errors */
589
597
  case TSK_ERR_SAMPLE_SIZE_MISMATCH:
@@ -875,8 +883,8 @@ tsk_search_sorted(const double *restrict array, tsk_size_t size, double value)
875
883
  upper = mid;
876
884
  }
877
885
  }
878
- offset = (int64_t)(array[lower] < value);
879
- return (tsk_size_t)(lower + offset);
886
+ offset = (int64_t) (array[lower] < value);
887
+ return (tsk_size_t) (lower + offset);
880
888
  }
881
889
 
882
890
  /* Rounds the specified double to the closest multiple of 10**-num_digits. If
@@ -1033,7 +1041,7 @@ FILE *
1033
1041
  tsk_get_debug_stream(void)
1034
1042
  {
1035
1043
  if (_tsk_debug_stream == NULL) {
1036
- _tsk_debug_stream = stdout;
1044
+ _tsk_debug_stream = TSK_DEFAULT_DEBUG_STREAM;
1037
1045
  }
1038
1046
  return _tsk_debug_stream;
1039
1047
  }
@@ -1260,16 +1268,16 @@ tsk_avl_tree_int_ordered_nodes(const tsk_avl_tree_int_t *self, tsk_avl_node_int_
1260
1268
  }
1261
1269
 
1262
1270
  // Bit Array implementation. Allows us to store unsigned integers in a compact manner.
1263
- // Currently implemented as an array of 32-bit unsigned integers for ease of counting.
1271
+ // Currently implemented as an array of 32-bit unsigned integers.
1264
1272
 
1265
1273
  int
1266
- tsk_bit_array_init(tsk_bit_array_t *self, tsk_size_t num_bits, tsk_size_t length)
1274
+ tsk_bitset_init(tsk_bitset_t *self, tsk_size_t num_bits, tsk_size_t length)
1267
1275
  {
1268
1276
  int ret = 0;
1269
1277
 
1270
- self->size = (num_bits >> TSK_BIT_ARRAY_CHUNK)
1271
- + (num_bits % TSK_BIT_ARRAY_NUM_BITS ? 1 : 0);
1272
- self->data = tsk_calloc(self->size * length, sizeof(*self->data));
1278
+ self->row_len = (num_bits / TSK_BITSET_BITS) + (num_bits % TSK_BITSET_BITS ? 1 : 0);
1279
+ self->len = length;
1280
+ self->data = tsk_calloc(self->row_len * length, sizeof(*self->data));
1273
1281
  if (self->data == NULL) {
1274
1282
  ret = tsk_trace_error(TSK_ERR_NO_MEMORY);
1275
1283
  goto out;
@@ -1278,96 +1286,111 @@ out:
1278
1286
  return ret;
1279
1287
  }
1280
1288
 
1281
- void
1282
- tsk_bit_array_get_row(const tsk_bit_array_t *self, tsk_size_t row, tsk_bit_array_t *out)
1283
- {
1284
- out->size = self->size;
1285
- out->data = self->data + (row * self->size);
1286
- }
1289
+ #define BITSET_DATA_ROW(bs, row) ((bs)->data + (row) * (bs)->row_len)
1287
1290
 
1288
1291
  void
1289
- tsk_bit_array_intersect(
1290
- const tsk_bit_array_t *self, const tsk_bit_array_t *other, tsk_bit_array_t *out)
1292
+ tsk_bitset_intersect(const tsk_bitset_t *self, tsk_size_t self_row,
1293
+ const tsk_bitset_t *other, tsk_size_t other_row, tsk_bitset_t *out)
1291
1294
  {
1292
- for (tsk_size_t i = 0; i < self->size; i++) {
1293
- out->data[i] = self->data[i] & other->data[i];
1295
+ const tsk_bitset_val_t *restrict self_d = BITSET_DATA_ROW(self, self_row);
1296
+ const tsk_bitset_val_t *restrict other_d = BITSET_DATA_ROW(other, other_row);
1297
+ tsk_bitset_val_t *restrict out_d = out->data;
1298
+ for (tsk_size_t i = 0; i < self->row_len; i++) {
1299
+ out_d[i] = self_d[i] & other_d[i];
1294
1300
  }
1295
1301
  }
1296
1302
 
1297
1303
  void
1298
- tsk_bit_array_subtract(tsk_bit_array_t *self, const tsk_bit_array_t *other)
1304
+ tsk_bitset_subtract(tsk_bitset_t *self, tsk_size_t self_row, const tsk_bitset_t *other,
1305
+ tsk_size_t other_row)
1299
1306
  {
1300
- for (tsk_size_t i = 0; i < self->size; i++) {
1301
- self->data[i] &= ~(other->data[i]);
1307
+ tsk_bitset_val_t *restrict self_d = BITSET_DATA_ROW(self, self_row);
1308
+ const tsk_bitset_val_t *restrict other_d = BITSET_DATA_ROW(other, other_row);
1309
+ for (tsk_size_t i = 0; i < self->row_len; i++) {
1310
+ self_d[i] &= ~(other_d[i]);
1302
1311
  }
1303
1312
  }
1304
1313
 
1305
1314
  void
1306
- tsk_bit_array_add(tsk_bit_array_t *self, const tsk_bit_array_t *other)
1315
+ tsk_bitset_union(tsk_bitset_t *self, tsk_size_t self_row, const tsk_bitset_t *other,
1316
+ tsk_size_t other_row)
1307
1317
  {
1308
- for (tsk_size_t i = 0; i < self->size; i++) {
1309
- self->data[i] |= other->data[i];
1318
+ tsk_bitset_val_t *restrict self_d = BITSET_DATA_ROW(self, self_row);
1319
+ const tsk_bitset_val_t *restrict other_d = BITSET_DATA_ROW(other, other_row);
1320
+ for (tsk_size_t i = 0; i < self->row_len; i++) {
1321
+ self_d[i] |= other_d[i];
1310
1322
  }
1311
1323
  }
1312
1324
 
1313
1325
  void
1314
- tsk_bit_array_add_bit(tsk_bit_array_t *self, const tsk_bit_array_value_t bit)
1326
+ tsk_bitset_set_bit(tsk_bitset_t *self, tsk_size_t row, const tsk_bitset_val_t bit)
1315
1327
  {
1316
- tsk_bit_array_value_t i = bit >> TSK_BIT_ARRAY_CHUNK;
1317
- self->data[i] |= (tsk_bit_array_value_t) 1 << (bit - (TSK_BIT_ARRAY_NUM_BITS * i));
1328
+ tsk_bitset_val_t i = (bit / TSK_BITSET_BITS);
1329
+ *(BITSET_DATA_ROW(self, row) + i) |= (tsk_bitset_val_t) 1
1330
+ << (bit - (TSK_BITSET_BITS * i));
1318
1331
  }
1319
1332
 
1320
1333
  bool
1321
- tsk_bit_array_contains(const tsk_bit_array_t *self, const tsk_bit_array_value_t bit)
1334
+ tsk_bitset_contains(const tsk_bitset_t *self, tsk_size_t row, const tsk_bitset_val_t bit)
1322
1335
  {
1323
- tsk_bit_array_value_t i = bit >> TSK_BIT_ARRAY_CHUNK;
1324
- return self->data[i]
1325
- & ((tsk_bit_array_value_t) 1 << (bit - (TSK_BIT_ARRAY_NUM_BITS * i)));
1336
+ tsk_bitset_val_t i = (bit / TSK_BITSET_BITS);
1337
+ return *(BITSET_DATA_ROW(self, row) + i)
1338
+ & ((tsk_bitset_val_t) 1 << (bit - (TSK_BITSET_BITS * i)));
1326
1339
  }
1327
1340
 
1328
- tsk_size_t
1329
- tsk_bit_array_count(const tsk_bit_array_t *self)
1341
+ static inline uint32_t
1342
+ popcount(tsk_bitset_val_t v)
1330
1343
  {
1331
- // Utilizes 12 operations per bit array. NB this only works on 32 bit integers.
1344
+ // Utilizes 12 operations per chunk. NB this only works on 32 bit integers.
1332
1345
  // Taken from:
1333
1346
  // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
1334
1347
  // There's a nice breakdown of this algorithm here:
1335
1348
  // https://stackoverflow.com/a/109025
1336
- // Could probably do better with explicit SIMD (instead of SWAR), but not as
1337
- // portable: https://arxiv.org/pdf/1611.07612.pdf
1338
1349
  //
1339
- // There is one solution to explore further, which uses __builtin_popcountll.
1340
- // This option is relatively simple, but requires a 64 bit bit array and also
1341
- // involves some compiler flag plumbing (-mpopcnt)
1350
+ // The gcc/clang compiler flag will -mpopcnt will convert this code to a
1351
+ // popcnt instruction (most if not all modern CPUs will support this). The
1352
+ // popcnt instruction will yield some speed improvements, which depend on
1353
+ // the tree sequence.
1354
+ //
1355
+ // NB: 32bit counting is typically faster than 64bit counting for this task.
1356
+ // (at least on x86-64)
1357
+
1358
+ v = v - ((v >> 1) & 0x55555555);
1359
+ v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
1360
+ return (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
1361
+ }
1342
1362
 
1343
- tsk_bit_array_value_t tmp;
1344
- tsk_size_t i, count = 0;
1363
+ tsk_size_t
1364
+ tsk_bitset_count(const tsk_bitset_t *self, tsk_size_t row)
1365
+ {
1366
+ tsk_size_t i = 0;
1367
+ tsk_size_t count = 0;
1368
+ const tsk_bitset_val_t *restrict self_d = BITSET_DATA_ROW(self, row);
1345
1369
 
1346
- for (i = 0; i < self->size; i++) {
1347
- tmp = self->data[i] - ((self->data[i] >> 1) & 0x55555555);
1348
- tmp = (tmp & 0x33333333) + ((tmp >> 2) & 0x33333333);
1349
- count += (((tmp + (tmp >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
1370
+ for (i = 0; i < self->row_len; i++) {
1371
+ count += popcount(self_d[i]);
1350
1372
  }
1351
1373
  return count;
1352
1374
  }
1353
1375
 
1354
1376
  void
1355
- tsk_bit_array_get_items(
1356
- const tsk_bit_array_t *self, tsk_id_t *items, tsk_size_t *n_items)
1377
+ tsk_bitset_get_items(
1378
+ const tsk_bitset_t *self, tsk_size_t row, tsk_id_t *items, tsk_size_t *n_items)
1357
1379
  {
1358
1380
  // Get the items stored in the row of a bitset.
1359
- // Uses a de Bruijn sequence lookup table to determine the lowest bit set. See the
1360
- // wikipedia article for more info: https://w.wiki/BYiF
1381
+ // Uses a de Bruijn sequence lookup table to determine the lowest bit set.
1382
+ // See the wikipedia article for more info: https://w.wiki/BYiF
1361
1383
 
1362
1384
  tsk_size_t i, n, off;
1363
- tsk_bit_array_value_t v, lsb; // least significant bit
1385
+ tsk_bitset_val_t v, lsb; // least significant bit
1364
1386
  static const tsk_id_t lookup[32] = { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25,
1365
1387
  17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 };
1388
+ const tsk_bitset_val_t *restrict self_d = BITSET_DATA_ROW(self, row);
1366
1389
 
1367
1390
  n = 0;
1368
- for (i = 0; i < self->size; i++) {
1369
- v = self->data[i];
1370
- off = i * ((tsk_size_t) TSK_BIT_ARRAY_NUM_BITS);
1391
+ for (i = 0; i < self->row_len; i++) {
1392
+ v = self_d[i];
1393
+ off = i * TSK_BITSET_BITS;
1371
1394
  if (v == 0) {
1372
1395
  continue;
1373
1396
  }
@@ -1381,7 +1404,7 @@ tsk_bit_array_get_items(
1381
1404
  }
1382
1405
 
1383
1406
  void
1384
- tsk_bit_array_free(tsk_bit_array_t *self)
1407
+ tsk_bitset_free(tsk_bitset_t *self)
1385
1408
  {
1386
1409
  tsk_safe_free(self->data);
1387
1410
  }