11/*
22 * MIT License
33 *
4- * Copyright (c) 2019-2023 Tskit Developers
4+ * Copyright (c) 2019-2024 Tskit Developers
55 *
66 * Permission is hereby granted, free of charge, to any person obtaining a copy
77 * of this software and associated documentation files (the "Software"), to deal
@@ -182,6 +182,8 @@ verify_tree_pos(const tsk_treeseq_t *ts, tsk_size_t num_trees, tsk_id_t *tree_pa
182182 const tsk_size_t N = tsk_treeseq_get_num_nodes (ts );
183183 const tsk_id_t * edges_parent = ts -> tables -> edges .parent ;
184184 const tsk_id_t * edges_child = ts -> tables -> edges .child ;
185+ const double * restrict edges_left = ts -> tables -> edges .left ;
186+ const double * restrict edges_right = ts -> tables -> edges .right ;
185187 tsk_tree_position_t tree_pos ;
186188 tsk_id_t * known_parent ;
187189 tsk_id_t * parent = tsk_malloc (N * sizeof (* parent ));
@@ -262,7 +264,62 @@ verify_tree_pos(const tsk_treeseq_t *ts, tsk_size_t num_trees, tsk_id_t *tree_pa
262264 CU_ASSERT_EQUAL (parent [u ], TSK_NULL );
263265 }
264266
265- tsk_tree_position_free (& tree_pos );
267+ for (index = 0 ; index < (tsk_id_t ) num_trees ; index ++ ) {
268+ known_parent = tree_parents + N * (tsk_size_t ) index ;
269+ ret = tsk_tree_position_init (& tree_pos , ts , 0 );
270+ CU_ASSERT_EQUAL_FATAL (ret , 0 );
271+
272+ ret = tsk_tree_position_seek_forward (& tree_pos , index );
273+ CU_ASSERT_EQUAL_FATAL (ret , 0 );
274+ CU_ASSERT_EQUAL (index , tree_pos .index );
275+
276+ for (j = tree_pos .in .start ; j != tree_pos .in .stop ; j ++ ) {
277+ e = tree_pos .in .order [j ];
278+ if (edges_left [e ] <= tree_pos .interval .left
279+ && tree_pos .interval .left < edges_right [e ]) {
280+ parent [edges_child [e ]] = edges_parent [e ];
281+ }
282+ }
283+ for (u = 0 ; u < (tsk_id_t ) N ; u ++ ) {
284+ CU_ASSERT_EQUAL (parent [u ], known_parent [u ]);
285+ }
286+
287+ tsk_tree_position_free (& tree_pos );
288+ for (u = 0 ; u < (tsk_id_t ) N ; u ++ ) {
289+ parent [u ] = TSK_NULL ;
290+ }
291+ }
292+
293+ valid = tsk_tree_position_next (& tree_pos );
294+ CU_ASSERT_FALSE (valid );
295+
296+ for (index = (tsk_id_t ) num_trees - 1 ; index >= 0 ; index -- ) {
297+ known_parent = tree_parents + N * (tsk_size_t ) index ;
298+ ret = tsk_tree_position_init (& tree_pos , ts , 0 );
299+ CU_ASSERT_EQUAL_FATAL (ret , 0 );
300+
301+ ret = tsk_tree_position_seek_backward (& tree_pos , index );
302+ CU_ASSERT_EQUAL_FATAL (ret , 0 );
303+ CU_ASSERT_EQUAL (index , tree_pos .index );
304+
305+ for (j = tree_pos .in .start ; j != tree_pos .in .stop ; j -- ) {
306+ e = tree_pos .in .order [j ];
307+ if (edges_right [e ] >= tree_pos .interval .right
308+ && tree_pos .interval .right > edges_left [e ]) {
309+ parent [edges_child [e ]] = edges_parent [e ];
310+ }
311+ }
312+
313+ for (u = 0 ; u < (tsk_id_t ) N ; u ++ ) {
314+ CU_ASSERT_EQUAL (parent [u ], known_parent [u ]);
315+ }
316+
317+ for (u = 0 ; u < (tsk_id_t ) N ; u ++ ) {
318+ parent [u ] = TSK_NULL ;
319+ }
320+ tsk_tree_position_free (& tree_pos );
321+ }
322+
266323 tsk_safe_free (parent );
267324}
268325
@@ -5350,6 +5407,7 @@ test_single_tree_tree_pos(void)
53505407 CU_ASSERT_EQUAL_FATAL (tree_pos .out .start , 0 );
53515408 CU_ASSERT_EQUAL_FATAL (tree_pos .out .stop , 0 );
53525409 CU_ASSERT_EQUAL_FATAL (tree_pos .out .order , ts .tables -> indexes .edge_removal_order );
5410+ CU_ASSERT_EQUAL_FATAL (tree_pos .direction , TSK_DIR_FORWARD );
53535411
53545412 valid = tsk_tree_position_next (& tree_pos );
53555413 CU_ASSERT_FATAL (!valid );
@@ -5360,6 +5418,7 @@ test_single_tree_tree_pos(void)
53605418 CU_ASSERT_EQUAL_FATAL (tree_pos .out .start , 0 );
53615419 CU_ASSERT_EQUAL_FATAL (tree_pos .out .stop , 6 );
53625420 CU_ASSERT_EQUAL_FATAL (tree_pos .out .order , ts .tables -> indexes .edge_removal_order );
5421+ CU_ASSERT_EQUAL_FATAL (tree_pos .direction , TSK_DIR_FORWARD );
53635422
53645423 valid = tsk_tree_position_prev (& tree_pos );
53655424 CU_ASSERT_FATAL (valid );
@@ -5372,6 +5431,7 @@ test_single_tree_tree_pos(void)
53725431 CU_ASSERT_EQUAL_FATAL (tree_pos .out .start , 5 );
53735432 CU_ASSERT_EQUAL_FATAL (tree_pos .out .stop , 5 );
53745433 CU_ASSERT_EQUAL_FATAL (tree_pos .out .order , ts .tables -> indexes .edge_insertion_order );
5434+ CU_ASSERT_EQUAL_FATAL (tree_pos .direction , TSK_DIR_REVERSE );
53755435
53765436 valid = tsk_tree_position_prev (& tree_pos );
53775437 CU_ASSERT_FATAL (!valid );
@@ -5380,6 +5440,42 @@ test_single_tree_tree_pos(void)
53805440 CU_ASSERT_EQUAL_FATAL (tree_pos .out .start , 5 );
53815441 CU_ASSERT_EQUAL_FATAL (tree_pos .out .stop , -1 );
53825442 CU_ASSERT_EQUAL_FATAL (tree_pos .out .order , ts .tables -> indexes .edge_insertion_order );
5443+ CU_ASSERT_EQUAL_FATAL (tree_pos .direction , TSK_DIR_REVERSE );
5444+
5445+ ret = tsk_tree_position_seek_forward (& tree_pos , 0 );
5446+ CU_ASSERT_EQUAL_FATAL (ret , 0 );
5447+
5448+ CU_ASSERT_EQUAL_FATAL (tree_pos .interval .left , 0 );
5449+ CU_ASSERT_EQUAL_FATAL (tree_pos .interval .right , 1 );
5450+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .start , 0 );
5451+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .stop , 6 );
5452+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .order , ts .tables -> indexes .edge_insertion_order );
5453+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .start , 0 );
5454+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .stop , 0 );
5455+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .order , ts .tables -> indexes .edge_removal_order )
5456+ CU_ASSERT_EQUAL_FATAL (tree_pos .direction , TSK_DIR_FORWARD );
5457+
5458+ valid = tsk_tree_position_next (& tree_pos );
5459+ CU_ASSERT_FATAL (!valid );
5460+
5461+ CU_ASSERT_EQUAL_FATAL (tree_pos .index , -1 );
5462+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .start , 0 );
5463+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .stop , 6 );
5464+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .order , ts .tables -> indexes .edge_removal_order );
5465+ CU_ASSERT_EQUAL_FATAL (tree_pos .direction , TSK_DIR_FORWARD );
5466+
5467+ ret = tsk_tree_position_seek_backward (& tree_pos , 0 );
5468+ CU_ASSERT_EQUAL_FATAL (ret , 0 );
5469+
5470+ CU_ASSERT_EQUAL_FATAL (tree_pos .interval .left , 0 );
5471+ CU_ASSERT_EQUAL_FATAL (tree_pos .interval .right , 1 );
5472+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .start , 5 );
5473+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .stop , -1 );
5474+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .order , ts .tables -> indexes .edge_removal_order );
5475+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .start , 5 );
5476+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .stop , 5 );
5477+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .order , ts .tables -> indexes .edge_insertion_order );
5478+ CU_ASSERT_EQUAL_FATAL (tree_pos .direction , TSK_DIR_REVERSE );
53835479
53845480 tsk_tree_position_free (& tree_pos );
53855481 tsk_treeseq_free (& ts );
@@ -5409,6 +5505,110 @@ test_simple_multi_tree(void)
54095505 tsk_treeseq_free (& ts );
54105506}
54115507
5508+ static void
5509+ test_multi_tree_direction_switching_tree_pos (void )
5510+ {
5511+ tsk_treeseq_t ts ;
5512+ tsk_tree_position_t tree_pos ;
5513+ bool valid ;
5514+ int ret = 0 ;
5515+
5516+ tsk_treeseq_from_text (& ts , 10 , paper_ex_nodes , paper_ex_edges , NULL , paper_ex_sites ,
5517+ paper_ex_mutations , paper_ex_individuals , NULL , 0 );
5518+
5519+ ret = tsk_tree_position_init (& tree_pos , & ts , 0 );
5520+ CU_ASSERT_EQUAL_FATAL (ret , 0 );
5521+ valid = tsk_tree_position_next (& tree_pos );
5522+ CU_ASSERT_FATAL (valid );
5523+
5524+ CU_ASSERT_EQUAL_FATAL (tree_pos .index , 0 );
5525+ CU_ASSERT_EQUAL_FATAL (tree_pos .interval .left , 0 );
5526+ CU_ASSERT_EQUAL_FATAL (tree_pos .interval .right , 2 );
5527+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .start , 0 );
5528+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .stop , 6 );
5529+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .order , ts .tables -> indexes .edge_insertion_order );
5530+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .start , 0 );
5531+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .stop , 0 );
5532+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .order , ts .tables -> indexes .edge_removal_order );
5533+ CU_ASSERT_EQUAL_FATAL (tree_pos .direction , TSK_DIR_FORWARD );
5534+
5535+ valid = tsk_tree_position_prev (& tree_pos );
5536+ CU_ASSERT_FATAL (!valid );
5537+
5538+ CU_ASSERT_EQUAL_FATAL (tree_pos .index , -1 );
5539+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .start , 5 );
5540+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .stop , -1 );
5541+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .order , ts .tables -> indexes .edge_insertion_order );
5542+ CU_ASSERT_EQUAL_FATAL (tree_pos .direction , TSK_DIR_REVERSE );
5543+
5544+ valid = tsk_tree_position_prev (& tree_pos );
5545+ CU_ASSERT_FATAL (valid );
5546+
5547+ CU_ASSERT_EQUAL_FATAL (tree_pos .index , 2 );
5548+ CU_ASSERT_EQUAL_FATAL (tree_pos .interval .left , 7 );
5549+ CU_ASSERT_EQUAL_FATAL (tree_pos .interval .right , 10 );
5550+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .start , 10 );
5551+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .stop , 4 );
5552+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .order , ts .tables -> indexes .edge_removal_order );
5553+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .start , 10 );
5554+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .stop , 10 );
5555+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .order , ts .tables -> indexes .edge_insertion_order );
5556+ CU_ASSERT_EQUAL_FATAL (tree_pos .direction , TSK_DIR_REVERSE );
5557+
5558+ valid = tsk_tree_position_next (& tree_pos );
5559+ CU_ASSERT_FATAL (!valid );
5560+
5561+ CU_ASSERT_EQUAL_FATAL (tree_pos .index , -1 );
5562+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .start , 5 );
5563+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .stop , 11 );
5564+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .order , ts .tables -> indexes .edge_removal_order );
5565+ CU_ASSERT_EQUAL_FATAL (tree_pos .direction , TSK_DIR_FORWARD );
5566+
5567+ ret = tsk_tree_position_seek_forward (& tree_pos , 2 );
5568+ CU_ASSERT_EQUAL_FATAL (ret , 0 );
5569+
5570+ CU_ASSERT_EQUAL_FATAL (tree_pos .interval .left , 7 );
5571+ CU_ASSERT_EQUAL_FATAL (tree_pos .interval .right , 10 );
5572+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .start , 0 );
5573+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .stop , 11 );
5574+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .order , ts .tables -> indexes .edge_insertion_order );
5575+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .start , 5 );
5576+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .stop , 5 );
5577+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .order , ts .tables -> indexes .edge_removal_order );
5578+ CU_ASSERT_EQUAL_FATAL (tree_pos .direction , TSK_DIR_FORWARD );
5579+
5580+ ret = tsk_tree_position_seek_backward (& tree_pos , 0 );
5581+ CU_ASSERT_EQUAL_FATAL (ret , 0 );
5582+
5583+ CU_ASSERT_EQUAL_FATAL (tree_pos .index , 0 );
5584+ CU_ASSERT_EQUAL_FATAL (tree_pos .interval .left , 0 );
5585+ CU_ASSERT_EQUAL_FATAL (tree_pos .interval .right , 2 );
5586+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .start , 4 );
5587+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .stop , -1 );
5588+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .order , ts .tables -> indexes .edge_removal_order );
5589+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .start , 10 );
5590+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .stop , 5 );
5591+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .order , ts .tables -> indexes .edge_insertion_order );
5592+ CU_ASSERT_EQUAL_FATAL (tree_pos .direction , TSK_DIR_REVERSE );
5593+
5594+ ret = tsk_tree_position_seek_forward (& tree_pos , 2 );
5595+ CU_ASSERT_EQUAL_FATAL (ret , 0 );
5596+
5597+ CU_ASSERT_EQUAL_FATAL (tree_pos .index , 2 );
5598+ CU_ASSERT_EQUAL_FATAL (tree_pos .interval .left , 7 );
5599+ CU_ASSERT_EQUAL_FATAL (tree_pos .interval .right , 10 );
5600+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .start , 6 );
5601+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .stop , 11 );
5602+ CU_ASSERT_EQUAL_FATAL (tree_pos .in .order , ts .tables -> indexes .edge_insertion_order );
5603+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .start , 0 );
5604+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .stop , 5 );
5605+ CU_ASSERT_EQUAL_FATAL (tree_pos .out .order , ts .tables -> indexes .edge_removal_order );
5606+ CU_ASSERT_EQUAL_FATAL (tree_pos .direction , TSK_DIR_FORWARD );
5607+
5608+ tsk_tree_position_free (& tree_pos );
5609+ tsk_treeseq_free (& ts );
5610+ }
5611+
54125612static void
54135613test_unary_multi_tree (void )
54145614{
@@ -8501,6 +8701,8 @@ main(int argc, char **argv)
85018701
85028702 /* Multi tree tests */
85038703 { "test_simple_multi_tree" , test_simple_multi_tree },
8704+ { "test_multi_tree_direction_switching_tree_pos" ,
8705+ test_multi_tree_direction_switching_tree_pos },
85048706 { "test_nonbinary_multi_tree" , test_nonbinary_multi_tree },
85058707 { "test_unary_multi_tree" , test_unary_multi_tree },
85068708 { "test_internal_sample_multi_tree" , test_internal_sample_multi_tree },
0 commit comments