@@ -7074,6 +7074,136 @@ def test_failure_with_migrations(self):
70747074 ts .trim ()
70757075
70767076
7077+ class TestShift :
7078+ """
7079+ Test the shift functionality
7080+ """
7081+
7082+ @pytest .mark .parametrize ("shift" , [- 0.5 , 0 , 0.5 ])
7083+ def test_shift (self , shift ):
7084+ ts = tskit .Tree .generate_comb (2 , span = 2 ).tree_sequence
7085+ tables = ts .dump_tables ()
7086+ tables .delete_intervals ([[0 , 1 ]], simplify = False )
7087+ tables .sites .add_row (1.5 , "A" )
7088+ ts = tables .tree_sequence ()
7089+ ts = ts .shift (shift )
7090+ assert ts .sequence_length == 2 + shift
7091+ assert np .min (ts .tables .edges .left ) == 1 + shift
7092+ assert np .max (ts .tables .edges .right ) == 2 + shift
7093+ assert np .all (ts .tables .sites .position == 1.5 + shift )
7094+
7095+ def test_sequence_length (self ):
7096+ ts = tskit .Tree .generate_comb (2 ).tree_sequence
7097+ ts = ts .shift (1 , sequence_length = 3 )
7098+ assert ts .sequence_length == 3
7099+ ts = ts .shift (- 1 , sequence_length = 1 )
7100+ assert ts .sequence_length == 1
7101+
7102+ def test_empty (self ):
7103+ empty_ts = tskit .TableCollection (1.0 ).tree_sequence ()
7104+ empty_ts = empty_ts .shift (1 )
7105+ assert empty_ts .sequence_length == 2
7106+ empty_ts = empty_ts .shift (- 1.5 )
7107+ assert empty_ts .sequence_length == 0.5
7108+ assert empty_ts .num_nodes == 0
7109+
7110+ def test_provenance (self ):
7111+ ts = tskit .Tree .generate_comb (2 ).tree_sequence
7112+ ts = ts .shift (1 , record_provenance = False )
7113+ params = json .loads (ts .provenance (- 1 ).record )["parameters" ]
7114+ assert params ["command" ] != "shift"
7115+ ts = ts .shift (1 , sequence_length = 9 )
7116+ params = json .loads (ts .provenance (- 1 ).record )["parameters" ]
7117+ assert params ["command" ] == "shift"
7118+ assert params ["value" ] == 1
7119+ assert params ["sequence_length" ] == 9
7120+
7121+ def test_too_negative (self ):
7122+ ts = tskit .Tree .generate_comb (2 ).tree_sequence
7123+ with pytest .raises (tskit .LibraryError , match = "TSK_ERR_BAD_SEQUENCE_LENGTH" ):
7124+ ts .shift (- 1 )
7125+
7126+ def test_bad_seq_len (self ):
7127+ ts = tskit .Tree .generate_comb (2 ).tree_sequence
7128+ with pytest .raises (
7129+ tskit .LibraryError , match = "TSK_ERR_RIGHT_GREATER_SEQ_LENGTH"
7130+ ):
7131+ ts .shift (1 , sequence_length = 1 )
7132+
7133+
7134+ class TestConcatenate :
7135+ def test_simple (self ):
7136+ ts1 = tskit .Tree .generate_comb (5 , span = 2 ).tree_sequence
7137+ ts2 = tskit .Tree .generate_balanced (5 , arity = 3 , span = 3 ).tree_sequence
7138+ assert ts1 .num_samples == ts2 .num_samples
7139+ assert ts1 .num_nodes != ts2 .num_nodes
7140+ joint_ts = ts1 .concatenate (ts2 )
7141+ assert joint_ts .num_nodes == ts1 .num_nodes + ts2 .num_nodes - 5
7142+ assert joint_ts .sequence_length == ts1 .sequence_length + ts2 .sequence_length
7143+ assert joint_ts .num_samples == ts1 .num_samples
7144+ ts3 = joint_ts .delete_intervals ([[2 , 5 ]]).rtrim ()
7145+ # Have to simplify here, to remove the redundant nodes
7146+ assert ts3 .equals (ts1 .simplify (), ignore_provenance = True )
7147+ ts4 = joint_ts .delete_intervals ([[0 , 2 ]]).ltrim ()
7148+ assert ts4 .equals (ts2 .simplify (), ignore_provenance = True )
7149+
7150+ def test_empty (self ):
7151+ empty_ts = tskit .TableCollection (10 ).tree_sequence ()
7152+ ts = empty_ts .concatenate (empty_ts )
7153+ assert ts .num_nodes == 0
7154+ assert ts .sequence_length == 20
7155+
7156+ def test_samples_at_end (self ):
7157+ ts1 = tskit .Tree .generate_comb (5 , span = 2 ).tree_sequence
7158+ ts2 = tskit .Tree .generate_balanced (5 , arity = 3 , span = 3 ).tree_sequence
7159+ # reverse the node order
7160+ ts1 = ts1 .subset (np .arange (ts1 .num_nodes )[::- 1 ])
7161+ assert ts1 .num_samples == ts2 .num_samples
7162+ assert np .all (ts1 .samples () != ts2 .samples ())
7163+ joint_ts = ts1 .concatenate (ts2 )
7164+ assert joint_ts .num_samples == ts1 .num_samples
7165+ assert np .all (joint_ts .samples () == ts1 .samples ())
7166+
7167+ def test_internal_samples (self ):
7168+ tables = tskit .Tree .generate_comb (4 , span = 2 ).tree_sequence .dump_tables ()
7169+ nodes_flags = tables .nodes .flags
7170+ nodes_flags [:] = tskit .NODE_IS_SAMPLE
7171+ nodes_flags [- 1 ] = 0 # Only root is not a sample
7172+ tables .nodes .flags = nodes_flags
7173+ ts = tables .tree_sequence ()
7174+ joint_ts = ts .concatenate (ts )
7175+ assert joint_ts .num_samples == ts .num_samples
7176+ assert joint_ts .num_nodes == ts .num_nodes + 1
7177+ assert joint_ts .sequence_length == ts .sequence_length * 2
7178+
7179+ def test_some_shared_samples (self ):
7180+ ts1 = tskit .Tree .generate_comb (4 , span = 2 ).tree_sequence
7181+ ts2 = tskit .Tree .generate_balanced (8 , arity = 3 , span = 3 ).tree_sequence
7182+ shared = np .full (ts2 .num_nodes , tskit .NULL )
7183+ shared [0 ] = 1
7184+ shared [1 ] = 0
7185+ joint_ts = ts1 .concatenate (ts2 , node_mapping = shared )
7186+ assert joint_ts .sequence_length == ts1 .sequence_length + ts2 .sequence_length
7187+ assert joint_ts .num_samples == ts1 .num_samples + ts2 .num_samples - 2
7188+ assert joint_ts .num_nodes == ts1 .num_nodes + ts2 .num_nodes - 2
7189+
7190+ def test_provenance (self ):
7191+ ts = tskit .Tree .generate_comb (2 ).tree_sequence
7192+ ts = ts .concatenate (ts , record_provenance = False )
7193+ params = json .loads (ts .provenance (- 1 ).record )["parameters" ]
7194+ assert params ["command" ] != "concatenate"
7195+
7196+ ts = ts .concatenate (ts )
7197+ params = json .loads (ts .provenance (- 1 ).record )["parameters" ]
7198+ assert params ["command" ] == "concatenate"
7199+
7200+ def test_unequal_samples (self ):
7201+ ts1 = tskit .Tree .generate_comb (5 , span = 2 ).tree_sequence
7202+ ts2 = tskit .Tree .generate_balanced (4 , arity = 3 , span = 3 ).tree_sequence
7203+ with pytest .raises (ValueError , match = "must have the same number of samples" ):
7204+ ts1 .concatenate (ts2 )
7205+
7206+
70777207class TestMissingData :
70787208 """
70797209 Test various aspects of missing data functionality
0 commit comments