Skip to content

Commit 99f03e2

Browse files
committed
Expose low-level individual and provenance arrays
1 parent 07fcad9 commit 99f03e2

File tree

2 files changed

+152
-0
lines changed

2 files changed

+152
-0
lines changed

python/_tskitmodule.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11074,6 +11074,104 @@ TreeSequence_get_individuals_metadata_offset(TreeSequence *self, void *closure)
1107411074
return ret;
1107511075
}
1107611076

11077+
static PyObject *
11078+
TreeSequence_get_individuals_location(TreeSequence *self, void *closure)
11079+
{
11080+
PyObject *ret = NULL;
11081+
tsk_individual_table_t individuals;
11082+
11083+
if (TreeSequence_check_state(self) != 0) {
11084+
goto out;
11085+
}
11086+
individuals = self->tree_sequence->tables->individuals;
11087+
ret = TreeSequence_make_array(
11088+
self, individuals.location_length, NPY_FLOAT64, individuals.location);
11089+
out:
11090+
return ret;
11091+
}
11092+
11093+
static PyObject *
11094+
TreeSequence_get_individuals_location_offset(TreeSequence *self, void *closure)
11095+
{
11096+
PyObject *ret = NULL;
11097+
tsk_individual_table_t individuals;
11098+
11099+
if (TreeSequence_check_state(self) != 0) {
11100+
goto out;
11101+
}
11102+
individuals = self->tree_sequence->tables->individuals;
11103+
ret = TreeSequence_make_array(
11104+
self, individuals.num_rows + 1, NPY_UINT64, individuals.location_offset);
11105+
out:
11106+
return ret;
11107+
}
11108+
11109+
static PyObject *
11110+
TreeSequence_get_individuals_parents(TreeSequence *self, void *closure)
11111+
{
11112+
PyObject *ret = NULL;
11113+
tsk_individual_table_t individuals;
11114+
11115+
if (TreeSequence_check_state(self) != 0) {
11116+
goto out;
11117+
}
11118+
individuals = self->tree_sequence->tables->individuals;
11119+
ret = TreeSequence_make_array(
11120+
self, individuals.parents_length, NPY_INT32, individuals.parents);
11121+
out:
11122+
return ret;
11123+
}
11124+
11125+
static PyObject *
11126+
TreeSequence_get_individuals_parents_offset(TreeSequence *self, void *closure)
11127+
{
11128+
PyObject *ret = NULL;
11129+
tsk_individual_table_t individuals;
11130+
11131+
if (TreeSequence_check_state(self) != 0) {
11132+
goto out;
11133+
}
11134+
individuals = self->tree_sequence->tables->individuals;
11135+
ret = TreeSequence_make_array(
11136+
self, individuals.num_rows + 1, NPY_UINT64, individuals.parents_offset);
11137+
out:
11138+
return ret;
11139+
}
11140+
11141+
#if HAVE_NUMPY_2
11142+
static PyObject *
11143+
TreeSequence_get_provenances_timestamp(TreeSequence *self, void *closure)
11144+
{
11145+
PyObject *ret = NULL;
11146+
tsk_provenance_table_t provenances;
11147+
11148+
if (TreeSequence_check_state(self) != 0) {
11149+
goto out;
11150+
}
11151+
provenances = self->tree_sequence->tables->provenances;
11152+
ret = TreeSequence_decode_ragged_string_column(
11153+
self, provenances.num_rows, provenances.timestamp, provenances.timestamp_offset);
11154+
out:
11155+
return ret;
11156+
}
11157+
11158+
static PyObject *
11159+
TreeSequence_get_provenances_record(TreeSequence *self, void *closure)
11160+
{
11161+
PyObject *ret = NULL;
11162+
tsk_provenance_table_t provenances;
11163+
11164+
if (TreeSequence_check_state(self) != 0) {
11165+
goto out;
11166+
}
11167+
provenances = self->tree_sequence->tables->provenances;
11168+
ret = TreeSequence_decode_ragged_string_column(
11169+
self, provenances.num_rows, provenances.record, provenances.record_offset);
11170+
out:
11171+
return ret;
11172+
}
11173+
#endif
11174+
1107711175
static PyObject *
1107811176
TreeSequence_get_nodes_time(TreeSequence *self, void *closure)
1107911177
{
@@ -12005,6 +12103,18 @@ static PyGetSetDef TreeSequence_getsetters[] = {
1200512103
{ .name = "individuals_metadata_offset",
1200612104
.get = (getter) TreeSequence_get_individuals_metadata_offset,
1200712105
.doc = "The individual metadata offset array" },
12106+
{ .name = "individuals_location",
12107+
.get = (getter) TreeSequence_get_individuals_location,
12108+
.doc = "The individual location array" },
12109+
{ .name = "individuals_location_offset",
12110+
.get = (getter) TreeSequence_get_individuals_location_offset,
12111+
.doc = "The individual location offset array" },
12112+
{ .name = "individuals_parents",
12113+
.get = (getter) TreeSequence_get_individuals_parents,
12114+
.doc = "The individual parents array" },
12115+
{ .name = "individuals_parents_offset",
12116+
.get = (getter) TreeSequence_get_individuals_parents_offset,
12117+
.doc = "The individual parents offset array" },
1200812118
{ .name = "nodes_time",
1200912119
.get = (getter) TreeSequence_get_nodes_time,
1201012120
.doc = "The node time array" },
@@ -12117,6 +12227,14 @@ static PyGetSetDef TreeSequence_getsetters[] = {
1211712227
{ .name = "indexes_edge_removal_order",
1211812228
.get = (getter) TreeSequence_get_indexes_edge_removal_order,
1211912229
.doc = "The edge removal order array" },
12230+
#if HAVE_NUMPY_2
12231+
{ .name = "provenances_timestamp",
12232+
.get = (getter) TreeSequence_get_provenances_timestamp,
12233+
.doc = "The provenance timestamp array" },
12234+
{ .name = "provenances_record",
12235+
.get = (getter) TreeSequence_get_provenances_record,
12236+
.doc = "The provenance record array" },
12237+
#endif
1212012238
{ NULL } /* Sentinel */
1212112239
};
1212212240

python/tests/test_lowlevel.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,6 +1178,10 @@ class TestTreeSequence(LowLevelTestCase, MetadataTestMixin):
11781178

11791179
ARRAY_NAMES = [
11801180
"individuals_flags",
1181+
"individuals_location",
1182+
"individuals_location_offset",
1183+
"individuals_parents",
1184+
"individuals_parents_offset",
11811185
"individuals_metadata",
11821186
"individuals_metadata_offset",
11831187
"nodes_time",
@@ -2197,6 +2201,8 @@ def test_generated_columns(self, ts_fixture, name):
21972201
"sites_ancestral_state",
21982202
"mutations_derived_state",
21992203
"mutations_inherited_state",
2204+
"provenances_timestamp",
2205+
"provenances_record",
22002206
],
22012207
)
22022208
@pytest.mark.parametrize(
@@ -2218,6 +2224,12 @@ def test_string_arrays(self, ts_fixture, str_lengths, string_array):
22182224
elif string_array == "mutations_inherited_state":
22192225
assert ts.num_mutations > 0
22202226
assert {len(mut.inherited_state) for mut in ts.mutations()} == {1}
2227+
elif string_array == "provenances_timestamp":
2228+
assert ts.num_provenances > 0
2229+
assert len(ts.provenance(3).timestamp) == 1
2230+
elif string_array == "provenances_record":
2231+
assert ts.num_provenances > 0
2232+
assert len(ts.provenance(3).record) == 1
22212233
else:
22222234
tables = ts_fixture.dump_tables()
22232235

@@ -2266,6 +2278,22 @@ def test_string_arrays(self, ts_fixture, str_lengths, string_array):
22662278
derived_state=get_derived_state(i, mutation)
22672279
)
22682280
)
2281+
elif string_array == "provenances_timestamp":
2282+
provenances = tables.provenances.copy()
2283+
tables.provenances.clear()
2284+
get_timestamp = str_map[str_lengths]
2285+
for i, provenance in enumerate(provenances):
2286+
tables.provenances.append(
2287+
provenance.replace(timestamp=get_timestamp(i, provenance))
2288+
)
2289+
elif string_array == "provenances_record":
2290+
provenances = tables.provenances.copy()
2291+
tables.provenances.clear()
2292+
get_record = str_map[str_lengths]
2293+
for i, provenance in enumerate(provenances):
2294+
tables.provenances.append(
2295+
provenance.replace(record=get_record(i, provenance))
2296+
)
22692297

22702298
ts = tables.tree_sequence()
22712299
ll_ts = ts.ll_tree_sequence
@@ -2285,6 +2313,12 @@ def test_string_arrays(self, ts_fixture, str_lengths, string_array):
22852313
elif string_array == "mutations_inherited_state":
22862314
for mutation in ts.mutations():
22872315
assert a[mutation.id] == mutation.inherited_state
2316+
elif string_array == "provenances_timestamp":
2317+
for provenance in ts.provenances():
2318+
assert a[provenance.id] == provenance.timestamp
2319+
elif string_array == "provenances_record":
2320+
for provenance in ts.provenances():
2321+
assert a[provenance.id] == provenance.record
22882322

22892323
# Read only
22902324
with pytest.raises(AttributeError, match="not writable"):

0 commit comments

Comments
 (0)