Skip to content

Commit 35dcda4

Browse files
committed
Restore seek_linear and add seek_skip as an option
1 parent 9af5784 commit 35dcda4

File tree

3 files changed

+74
-7
lines changed

3 files changed

+74
-7
lines changed

c/tskit/trees.c

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5878,7 +5878,47 @@ tsk_tree_seek_index(tsk_tree_t *self, tsk_id_t tree, tsk_flags_t options)
58785878
}
58795879

58805880
static int TSK_WARN_UNUSED
5881-
tsk_tree_seek_linear(tsk_tree_t *self, double x, tsk_flags_t TSK_UNUSED(options))
5881+
tsk_tree_seek_linear(tsk_tree_t *self, double x)
5882+
{
5883+
const double L = tsk_treeseq_get_sequence_length(self->tree_sequence);
5884+
const double t_l = self->interval.left;
5885+
const double t_r = self->interval.right;
5886+
int ret = 0;
5887+
double distance_left, distance_right;
5888+
5889+
if (x < t_l) {
5890+
/* |-----|-----|========|---------| */
5891+
/* 0 x t_l t_r L */
5892+
distance_left = t_l - x;
5893+
distance_right = L - t_r + x;
5894+
} else {
5895+
/* |------|========|------|-------| */
5896+
/* 0 t_l t_r x L */
5897+
distance_right = x - t_r;
5898+
distance_left = t_l + L - x;
5899+
}
5900+
if (distance_right <= distance_left) {
5901+
while (!tsk_tree_position_in_interval(self, x)) {
5902+
ret = tsk_tree_next(self);
5903+
if (ret < 0) {
5904+
goto out;
5905+
}
5906+
}
5907+
} else {
5908+
while (!tsk_tree_position_in_interval(self, x)) {
5909+
ret = tsk_tree_prev(self);
5910+
if (ret < 0) {
5911+
goto out;
5912+
}
5913+
}
5914+
}
5915+
ret = 0;
5916+
out:
5917+
return ret;
5918+
}
5919+
5920+
static int TSK_WARN_UNUSED
5921+
tsk_tree_seek_skip(tsk_tree_t *self, double x)
58825922
{
58835923
const double t_l = self->interval.left;
58845924
int ret = 0;
@@ -5914,7 +5954,11 @@ tsk_tree_seek(tsk_tree_t *self, double x, tsk_flags_t options)
59145954
if (self->index == -1) {
59155955
ret = tsk_tree_seek_from_null(self, x, options);
59165956
} else {
5917-
ret = tsk_tree_seek_linear(self, x, options);
5957+
if (options & TSK_TREE_SEEK_ENABLE_SKIPPING) {
5958+
ret = tsk_tree_seek_skip(self, x);
5959+
} else {
5960+
ret = tsk_tree_seek_linear(self, x);
5961+
}
59185962
}
59195963

59205964
out:

c/tskit/trees.h

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,13 @@ int tsk_tree_copy(const tsk_tree_t *self, tsk_tree_t *dest, tsk_flags_t options)
12071207
@{
12081208
*/
12091209

1210+
/** @brief Option to seek by skipping to the target tree, adding and removing as few
1211+
edges as possible. If not specified, a linear time algorithm is used instead.
1212+
1213+
@ingroup TREE_API_SEEKING_GROUP
1214+
*/
1215+
#define TSK_TREE_SEEK_ENABLE_SKIPPING (1 << 0)
1216+
12101217
/**
12111218
@brief Seek to the first tree in the sequence.
12121219
@@ -1216,7 +1223,7 @@ tree sequence.
12161223
@endrst
12171224
12181225
@param self A pointer to an initialised tsk_tree_t object.
1219-
@return Return TSK_TREE_OK on success; or a negative value if an error occurs.
1226+
@return Return on success; or a negative value if an error occurs.
12201227
*/
12211228
int tsk_tree_first(tsk_tree_t *self);
12221229

@@ -1312,12 +1319,22 @@ we will have ``position < tree.interval.right``.
13121319
13131320
Seeking to a position currently covered by the tree is
13141321
a constant time operation.
1322+
1323+
Seeking to a position from a non-null tree use a linear time
1324+
algorithm by default, unless the option :c:macro:`TSK_TREE_SEEK_ENABLE_SKIPPING`
1325+
is specified. In this case, a faster algorithm is employed which skips
1326+
to the target tree by removing and adding the minimal number of edges
1327+
possible. However, this approach does not guarantee that edges are
1328+
inserted and removed in time-sorted order.
1329+
1330+
.. warning:: Using the :c:macro:`TSK_TREE_SEEK_ENABLE_SKIPPING` option
1331+
may lead to edges not being inserted or removed in time-sorted order.
1332+
13151333
@endrst
13161334
13171335
@param self A pointer to an initialised tsk_tree_t object.
13181336
@param position The position in genome coordinates
1319-
@param options Seek options. Currently unused. Set to 0 for compatibility
1320-
with future versions of tskit.
1337+
@param options Seek options. See the notes above for details.
13211338
@return Return 0 on success or a negative value on failure.
13221339
*/
13231340
int tsk_tree_seek(tsk_tree_t *self, double position, tsk_flags_t options);

python/_tskitmodule.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* MIT License
33
*
4-
* Copyright (c) 2019-2023 Tskit Developers
4+
* Copyright (c) 2019-2024 Tskit Developers
55
* Copyright (c) 2015-2018 University of Oxford
66
*
77
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -11026,16 +11026,22 @@ static PyObject *
1102611026
Tree_seek(Tree *self, PyObject *args)
1102711027
{
1102811028
PyObject *ret = NULL;
11029+
tsk_flags_t options = 0;
11030+
int enable_skipping = true;
1102911031
double position;
1103011032
int err;
1103111033

11034+
if (enable_skipping) {
11035+
options |= TSK_TREE_SEEK_ENABLE_SKIPPING;
11036+
}
11037+
1103211038
if (Tree_check_state(self) != 0) {
1103311039
goto out;
1103411040
}
1103511041
if (!PyArg_ParseTuple(args, "d", &position)) {
1103611042
goto out;
1103711043
}
11038-
err = tsk_tree_seek(self->tree, position, 0);
11044+
err = tsk_tree_seek(self->tree, position, options);
1103911045
if (err != 0) {
1104011046
handle_library_error(err);
1104111047
goto out;

0 commit comments

Comments
 (0)