Skip to content

Commit 2f1cca1

Browse files
duncanMRjeromekelleher
authored andcommitted
Restore seek_linear and add seek_skip as an option
1 parent fdd0561 commit 2f1cca1

File tree

3 files changed

+73
-6
lines changed

3 files changed

+73
-6
lines changed

c/tskit/trees.c

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

66356635
static int TSK_WARN_UNUSED
6636-
tsk_tree_seek_linear(tsk_tree_t *self, double x, tsk_flags_t TSK_UNUSED(options))
6636+
tsk_tree_seek_linear(tsk_tree_t *self, double x)
6637+
{
6638+
const double L = tsk_treeseq_get_sequence_length(self->tree_sequence);
6639+
const double t_l = self->interval.left;
6640+
const double t_r = self->interval.right;
6641+
int ret = 0;
6642+
double distance_left, distance_right;
6643+
6644+
if (x < t_l) {
6645+
/* |-----|-----|========|---------| */
6646+
/* 0 x t_l t_r L */
6647+
distance_left = t_l - x;
6648+
distance_right = L - t_r + x;
6649+
} else {
6650+
/* |------|========|------|-------| */
6651+
/* 0 t_l t_r x L */
6652+
distance_right = x - t_r;
6653+
distance_left = t_l + L - x;
6654+
}
6655+
if (distance_right <= distance_left) {
6656+
while (!tsk_tree_position_in_interval(self, x)) {
6657+
ret = tsk_tree_next(self);
6658+
if (ret < 0) {
6659+
goto out;
6660+
}
6661+
}
6662+
} else {
6663+
while (!tsk_tree_position_in_interval(self, x)) {
6664+
ret = tsk_tree_prev(self);
6665+
if (ret < 0) {
6666+
goto out;
6667+
}
6668+
}
6669+
}
6670+
ret = 0;
6671+
out:
6672+
return ret;
6673+
}
6674+
6675+
static int TSK_WARN_UNUSED
6676+
tsk_tree_seek_skip(tsk_tree_t *self, double x)
66376677
{
66386678
const double t_l = self->interval.left;
66396679
int ret = 0;
@@ -6669,7 +6709,11 @@ tsk_tree_seek(tsk_tree_t *self, double x, tsk_flags_t options)
66696709
if (self->index == -1) {
66706710
ret = tsk_tree_seek_from_null(self, x, options);
66716711
} else {
6672-
ret = tsk_tree_seek_linear(self, x, options);
6712+
if (options & TSK_TREE_SEEK_ENABLE_SKIPPING) {
6713+
ret = tsk_tree_seek_skip(self, x);
6714+
} else {
6715+
ret = tsk_tree_seek_linear(self, x);
6716+
}
66736717
}
66746718

66756719
out:

c/tskit/trees.h

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

1273+
/** @brief Option to seek by skipping to the target tree, adding and removing as few
1274+
edges as possible. If not specified, a linear time algorithm is used instead.
1275+
1276+
@ingroup TREE_API_SEEKING_GROUP
1277+
*/
1278+
#define TSK_TREE_SEEK_ENABLE_SKIPPING (1 << 0)
1279+
12731280
/**
12741281
@brief Seek to the first tree in the sequence.
12751282
@@ -1279,7 +1286,7 @@ tree sequence.
12791286
@endrst
12801287
12811288
@param self A pointer to an initialised tsk_tree_t object.
1282-
@return Return TSK_TREE_OK on success; or a negative value if an error occurs.
1289+
@return Return on success; or a negative value if an error occurs.
12831290
*/
12841291
int tsk_tree_first(tsk_tree_t *self);
12851292

@@ -1375,12 +1382,22 @@ we will have ``position < tree.interval.right``.
13751382
13761383
Seeking to a position currently covered by the tree is
13771384
a constant time operation.
1385+
1386+
Seeking to a position from a non-null tree use a linear time
1387+
algorithm by default, unless the option :c:macro:`TSK_TREE_SEEK_ENABLE_SKIPPING`
1388+
is specified. In this case, a faster algorithm is employed which skips
1389+
to the target tree by removing and adding the minimal number of edges
1390+
possible. However, this approach does not guarantee that edges are
1391+
inserted and removed in time-sorted order.
1392+
1393+
.. warning:: Using the :c:macro:`TSK_TREE_SEEK_ENABLE_SKIPPING` option
1394+
may lead to edges not being inserted or removed in time-sorted order.
1395+
13781396
@endrst
13791397
13801398
@param self A pointer to an initialised tsk_tree_t object.
13811399
@param position The position in genome coordinates
1382-
@param options Seek options. Currently unused. Set to 0 for compatibility
1383-
with future versions of tskit.
1400+
@param options Seek options. See the notes above for details.
13841401
@return Return 0 on success or a negative value on failure.
13851402
*/
13861403
int tsk_tree_seek(tsk_tree_t *self, double position, tsk_flags_t options);

python/_tskitmodule.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12103,16 +12103,22 @@ static PyObject *
1210312103
Tree_seek(Tree *self, PyObject *args)
1210412104
{
1210512105
PyObject *ret = NULL;
12106+
tsk_flags_t options = 0;
12107+
int enable_skipping = true;
1210612108
double position;
1210712109
int err;
1210812110

12111+
if (enable_skipping) {
12112+
options |= TSK_TREE_SEEK_ENABLE_SKIPPING;
12113+
}
12114+
1210912115
if (Tree_check_state(self) != 0) {
1211012116
goto out;
1211112117
}
1211212118
if (!PyArg_ParseTuple(args, "d", &position)) {
1211312119
goto out;
1211412120
}
12115-
err = tsk_tree_seek(self->tree, position, 0);
12121+
err = tsk_tree_seek(self->tree, position, options);
1211612122
if (err != 0) {
1211712123
handle_library_error(err);
1211812124
goto out;

0 commit comments

Comments
 (0)