Skip to content

Commit ccc7d08

Browse files
committed
Tolerate invalid parents when computing mutation parents
1 parent 1acc108 commit ccc7d08

File tree

3 files changed

+77
-2
lines changed

3 files changed

+77
-2
lines changed

c/tests/test_tables.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10775,6 +10775,41 @@ test_check_integrity_bad_mutation_parent_topology(void)
1077510775
tsk_table_collection_free(&tables);
1077610776
}
1077710777

10778+
static void
10779+
test_table_collection_compute_mutation_parents_tolerates_invalid_input(void)
10780+
{
10781+
int ret;
10782+
tsk_table_collection_t tables;
10783+
tsk_id_t site;
10784+
10785+
ret = tsk_table_collection_init(&tables, 0);
10786+
CU_ASSERT_EQUAL_FATAL(ret, 0);
10787+
tables.sequence_length = 1.0;
10788+
10789+
ret = tsk_node_table_add_row(&tables.nodes, 0, 1.0, TSK_NULL, TSK_NULL, NULL, 0);
10790+
CU_ASSERT_FATAL(ret >= 0);
10791+
ret = tsk_node_table_add_row(
10792+
&tables.nodes, TSK_NODE_IS_SAMPLE, 0.0, TSK_NULL, TSK_NULL, NULL, 0);
10793+
CU_ASSERT_FATAL(ret >= 0);
10794+
ret = tsk_edge_table_add_row(&tables.edges, 0.0, 1.0, 0, 1, NULL, 0);
10795+
CU_ASSERT_EQUAL_FATAL(ret, 0);
10796+
site = tsk_site_table_add_row(&tables.sites, 0.0, "A", 1, NULL, 0);
10797+
CU_ASSERT_FATAL(site >= 0);
10798+
ret = tsk_mutation_table_add_row(
10799+
&tables.mutations, site, 1, TSK_NULL, TSK_UNKNOWN_TIME, "C", 1, NULL, 0);
10800+
CU_ASSERT_EQUAL_FATAL(ret, 0);
10801+
10802+
ret = tsk_table_collection_build_index(&tables, 0);
10803+
CU_ASSERT_EQUAL_FATAL(ret, 0);
10804+
tables.mutations.parent[0] = 42;
10805+
10806+
ret = tsk_table_collection_compute_mutation_parents(&tables, 0);
10807+
CU_ASSERT_EQUAL_FATAL(ret, 0);
10808+
CU_ASSERT_FATAL(tables.mutations.parent[0] == TSK_NULL);
10809+
10810+
tsk_table_collection_free(&tables);
10811+
}
10812+
1077810813
static void
1077910814
test_table_collection_subset_with_options(tsk_flags_t options)
1078010815
{
@@ -11934,6 +11969,8 @@ main(int argc, char **argv)
1193411969
test_table_collection_check_integrity_bad_indexes },
1193511970
{ "test_check_integrity_bad_mutation_parent_topology",
1193611971
test_check_integrity_bad_mutation_parent_topology },
11972+
{ "test_table_collection_compute_mutation_parents_tolerates_invalid_input",
11973+
test_table_collection_compute_mutation_parents_tolerates_invalid_input },
1193711974
{ "test_table_collection_subset", test_table_collection_subset },
1193811975
{ "test_table_collection_subset_unsorted",
1193911976
test_table_collection_subset_unsorted },

c/tskit/tables.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12436,22 +12436,48 @@ tsk_table_collection_compute_mutation_parents(
1243612436
tsk_table_collection_t *self, tsk_flags_t options)
1243712437
{
1243812438
int ret = 0;
12439+
tsk_mutation_table_t *mutations = &self->mutations;
12440+
tsk_id_t *parent_backup = NULL;
12441+
bool restore_parents = false;
1243912442

1244012443
if (!(options & TSK_NO_CHECK_INTEGRITY)) {
12444+
if (mutations->num_rows > 0) {
12445+
/* We need to wipe the parent column before computing, as otherwise invalid
12446+
* parents can cause integrity checks to fail. We take a copy to restore on
12447+
* error */
12448+
parent_backup = tsk_malloc(mutations->num_rows * sizeof(*parent_backup));
12449+
if (parent_backup == NULL) {
12450+
ret = tsk_trace_error(TSK_ERR_NO_MEMORY);
12451+
goto out;
12452+
}
12453+
tsk_memcpy(parent_backup, mutations->parent,
12454+
mutations->num_rows * sizeof(*parent_backup));
12455+
/* Set the parent pointers to TSK_NULL */
12456+
tsk_memset(mutations->parent, 0xff,
12457+
mutations->num_rows * sizeof(*mutations->parent));
12458+
restore_parents = true;
12459+
}
1244112460
/* Safe to cast here as we're not counting trees */
1244212461
ret = (int) tsk_table_collection_check_integrity(self, TSK_CHECK_TREES);
1244312462
if (ret < 0) {
12444-
goto out;
12463+
goto restore;
1244512464
}
1244612465
}
1244712466

1244812467
ret = tsk_table_collection_compute_mutation_parents_to_array(
1244912468
self, self->mutations.parent);
1245012469
if (ret != 0) {
12451-
goto out;
12470+
goto restore;
12471+
}
12472+
12473+
restore:
12474+
if (ret != 0 && restore_parents) {
12475+
tsk_memcpy(mutations->parent, parent_backup,
12476+
mutations->num_rows * sizeof(*parent_backup));
1245212477
}
1245312478

1245412479
out:
12480+
tsk_safe_free(parent_backup);
1245512481
return ret;
1245612482
}
1245712483

python/tests/test_tables.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3540,6 +3540,18 @@ def test_table_references(self):
35403540
assert str(populations) == before_populations
35413541
assert str(provenances) == before_provenances
35423542

3543+
def test_compute_mutation_parents_ignores_existing_values(self):
3544+
tables = tskit.TableCollection(sequence_length=1.0)
3545+
parent = tables.nodes.add_row(time=1.0)
3546+
child = tables.nodes.add_row(time=0, flags=tskit.NODE_IS_SAMPLE)
3547+
tables.edges.add_row(left=0.0, right=1.0, parent=parent, child=child)
3548+
site = tables.sites.add_row(position=0.0, ancestral_state="A")
3549+
tables.mutations.add_row(site=site, node=child, derived_state="C")
3550+
tables.build_index()
3551+
tables.mutations.parent[:] = 42
3552+
tables.compute_mutation_parents()
3553+
assert tables.mutations.parent[0] == tskit.NULL
3554+
35433555
def test_str(self):
35443556
ts = msprime.simulate(10, random_seed=1)
35453557
tables = ts.tables

0 commit comments

Comments
 (0)