Skip to content

Commit 7ddcc95

Browse files
jeromekellehermergify[bot]
authored andcommitted
Use C implementation for seek_index
Closes #2696
1 parent edb3df2 commit 7ddcc95

File tree

6 files changed

+51
-8
lines changed

6 files changed

+51
-8
lines changed

c/CHANGELOG.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
[1.1.2] - 2023-XX-XX
33
--------------------
44

5+
**Performance improvements**
6+
7+
- tsk_tree_seek is now much faster at seeking to arbitrary points along
8+
the sequence from the null tree (:user:`molpopgen`, :pr:`2661`).
9+
510
**Features**
611

712
- The struct ``tsk_treeseq_t`` now has the variables ``min_time`` and ``max_time``,
@@ -24,6 +29,8 @@
2429
- Add `x_table_keep_rows` methods to provide efficient in-place table subsetting
2530
(:user:`jeromekelleher`, :pr:`2700`).
2631

32+
- Add `tsk_tree_seek_index` function
33+
2734
--------------------
2835
[1.1.1] - 2022-07-29
2936
--------------------

c/tskit/trees.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4640,7 +4640,7 @@ tsk_tree_seek_from_null(tsk_tree_t *self, double x, tsk_flags_t TSK_UNUSED(optio
46404640
*/
46414641
tree_index = (tsk_id_t) tsk_search_sorted(breakpoints, num_trees + 1, x);
46424642
if (breakpoints[tree_index] > x) {
4643-
tree_index -= 1;
4643+
tree_index--;
46444644
}
46454645
self->index = tree_index;
46464646
self->interval.left = breakpoints[tree_index];

python/CHANGELOG.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
[0.5.5] - 2023-01-XX
33
--------------------
44

5+
**Performance improvements**
6+
7+
- Methods like ts.at() which seek to a specified position on the sequence from
8+
a new Tree instance are now much faster (:user:`molpopgen`, :pr:`2661`).
9+
510
**Features**
611

712
- Add ``__repr__`` for variants to return a string representation of the raw data

python/_tskitmodule.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10658,6 +10658,29 @@ Tree_seek(Tree *self, PyObject *args)
1065810658
return ret;
1065910659
}
1066010660

10661+
static PyObject *
10662+
Tree_seek_index(Tree *self, PyObject *args)
10663+
{
10664+
PyObject *ret = NULL;
10665+
tsk_id_t index = 0;
10666+
int err;
10667+
10668+
if (Tree_check_state(self) != 0) {
10669+
goto out;
10670+
}
10671+
if (!PyArg_ParseTuple(args, "O&", tsk_id_converter, &index)) {
10672+
goto out;
10673+
}
10674+
err = tsk_tree_seek_index(self->tree, index, 0);
10675+
if (err != 0) {
10676+
handle_library_error(err);
10677+
goto out;
10678+
}
10679+
ret = Py_BuildValue("");
10680+
out:
10681+
return ret;
10682+
}
10683+
1066110684
static PyObject *
1066210685
Tree_clear(Tree *self)
1066310686
{
@@ -11796,6 +11819,10 @@ static PyMethodDef Tree_methods[] = {
1179611819
.ml_meth = (PyCFunction) Tree_seek,
1179711820
.ml_flags = METH_VARARGS,
1179811821
.ml_doc = "Seeks to the tree at the specified position" },
11822+
{ .ml_name = "seek_index",
11823+
.ml_meth = (PyCFunction) Tree_seek_index,
11824+
.ml_flags = METH_VARARGS,
11825+
.ml_doc = "Seeks to the tree at the specified index" },
1179911826
{ .ml_name = "clear",
1180011827
.ml_meth = (PyCFunction) Tree_clear,
1180111828
.ml_flags = METH_NOARGS,

python/tests/test_lowlevel.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2968,6 +2968,16 @@ def test_seek_errors(self):
29682968
with pytest.raises(_tskit.LibraryError):
29692969
tree.seek(bad_pos)
29702970

2971+
def test_seek_index_errors(self):
2972+
ts = self.get_example_tree_sequence()
2973+
tree = _tskit.Tree(ts)
2974+
for bad_type in ["", "x", {}]:
2975+
with pytest.raises(TypeError):
2976+
tree.seek_index(bad_type)
2977+
for bad_index in [-1, 10**6]:
2978+
with pytest.raises(_tskit.LibraryError):
2979+
tree.seek_index(bad_index)
2980+
29712981
def test_root_threshold(self):
29722982
for ts in self.get_example_tree_sequences():
29732983
tree = _tskit.Tree(ts)

python/tskit/trees.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -820,7 +820,6 @@ def seek_index(self, index):
820820
821821
.. include:: substitutions/linear_traversal_warning.rst
822822
823-
824823
:param int index: The tree index to seek to.
825824
:raises IndexError: If an index outside the acceptable range is provided.
826825
"""
@@ -829,12 +828,7 @@ def seek_index(self, index):
829828
index += num_trees
830829
if index < 0 or index >= num_trees:
831830
raise IndexError("Index out of bounds")
832-
# This should be implemented in C efficiently using the indexes.
833-
# No point in complicating the current implementation by trying
834-
# to seek from the correct direction.
835-
self.first()
836-
while self.index != index:
837-
self.next()
831+
self._ll_tree.seek_index(index)
838832

839833
def seek(self, position):
840834
"""

0 commit comments

Comments
 (0)