From f9c8ca81f3fe3fe42b734ddea12f0d595b491fe2 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Mon, 19 May 2025 14:27:35 +0300 Subject: [PATCH 1/3] Warn instead of crash with flanks. --- lib_tsalign/src/a_star_aligner/alignment_result.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib_tsalign/src/a_star_aligner/alignment_result.rs b/lib_tsalign/src/a_star_aligner/alignment_result.rs index d99344e9..b18c1ef8 100644 --- a/lib_tsalign/src/a_star_aligner/alignment_result.rs +++ b/lib_tsalign/src/a_star_aligner/alignment_result.rs @@ -4,7 +4,7 @@ use a_star_sequences::SequencePair; use alignment::{Alignment, stream::AlignmentStream}; use compact_genome::interface::{alphabet::Alphabet, sequence::GenomeSequence}; use generic_a_star::{AStarResult, cost::AStarCost}; -use log::trace; +use log::{trace, warn}; use noisy_float::types::{R64, r64}; use num_traits::{Float, Zero}; @@ -257,6 +257,10 @@ impl> else { return; }; + if config.left_flank_length > 0 || config.right_flank_length > 0 { + warn!("Alignment extension does not support flanks"); + return; + } // Compute cost before extending. let initial_cost = alignment.compute_cost( @@ -378,6 +382,7 @@ impl> return; }; if config.left_flank_length > 0 || config.right_flank_length > 0 { + warn!("TS extension does not support flanks"); return; } From 8b3510766ef1e19b22c46edf5f175ab22f0f538d Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Mon, 19 May 2025 14:31:13 +0300 Subject: [PATCH 2/3] Disable flanks in default config. --- sample_tsa_config/config.tsa | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sample_tsa_config/config.tsa b/sample_tsa_config/config.tsa index eba2d46b..96d8f074 100644 --- a/sample_tsa_config/config.tsa +++ b/sample_tsa_config/config.tsa @@ -1,7 +1,7 @@ # Limits -left_flank_length = 5 -right_flank_length = 5 +left_flank_length = 0 +right_flank_length = 0 # Base Cost From eccef51703405541fd779120809e1a810cec3523 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Mon, 19 May 2025 14:46:59 +0300 Subject: [PATCH 3/3] Fix TS extension does not update index. --- .../src/a_star_aligner/alignment_result.rs | 8 ++- .../alignment/template_switch_specifics.rs | 52 +++++++++---------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/lib_tsalign/src/a_star_aligner/alignment_result.rs b/lib_tsalign/src/a_star_aligner/alignment_result.rs index b18c1ef8..ca6454d3 100644 --- a/lib_tsalign/src/a_star_aligner/alignment_result.rs +++ b/lib_tsalign/src/a_star_aligner/alignment_result.rs @@ -421,12 +421,14 @@ impl> { let mut min_start_alignment = alignment.clone(); + let mut i = i; + while min_start_alignment.move_template_switch_start_backwards( reference, query, reference_offset, query_offset, - i, + &mut i, ) { let new_cost = min_start_alignment.compute_cost( reference, @@ -449,12 +451,14 @@ impl> { let mut max_start_alignment = alignment.clone(); + let mut i = i; + while max_start_alignment.move_template_switch_start_forwards( reference, query, reference_offset, query_offset, - i, + &mut i, ) { let new_cost = max_start_alignment.compute_cost( reference, diff --git a/lib_tsalign/src/a_star_aligner/alignment_result/alignment/template_switch_specifics.rs b/lib_tsalign/src/a_star_aligner/alignment_result/alignment/template_switch_specifics.rs index 53560817..fbc48f27 100644 --- a/lib_tsalign/src/a_star_aligner/alignment_result/alignment/template_switch_specifics.rs +++ b/lib_tsalign/src/a_star_aligner/alignment_result/alignment/template_switch_specifics.rs @@ -33,7 +33,7 @@ impl Alignment { query: &SubsequenceType, reference_offset: usize, query_offset: usize, - mut compact_index: usize, + compact_index: &mut usize, ) -> bool { let AlignmentType::TemplateSwitchEntrance { first_offset, @@ -41,7 +41,7 @@ impl Alignment { secondary, direction, .. - } = self.alignment[compact_index].1 + } = self.alignment[*compact_index].1 else { panic!() }; @@ -55,7 +55,7 @@ impl Alignment { ) { // Compute TS inner first indices. let mut stream = AlignmentStream::new(); - stream.push_all(self.iter_compact_cloned().take(compact_index)); + stream.push_all(self.iter_compact_cloned().take(*compact_index)); let ts_inner_primary_index = match primary { TemplateSwitchPrimary::Reference => { stream.head_coordinates().reference() + reference_offset @@ -92,14 +92,14 @@ impl Alignment { } // Remove one match or substitution from before the TS. - let multiplicity = &mut self.alignment[compact_index - 1].0; + let multiplicity = &mut self.alignment[*compact_index - 1].0; assert!(*multiplicity > 0); *multiplicity -= 1; // Remove the alignment entry if it has zero multiplicity. if *multiplicity == 0 { - compact_index -= 1; - self.alignment.remove(compact_index); + *compact_index -= 1; + self.alignment.remove(*compact_index); } // Check if the new inner pair is a match or a substitution. @@ -119,18 +119,18 @@ impl Alignment { }; // Insert new inner alignment. - if self.alignment[compact_index + 1].1 == inner_alignment_type { - self.alignment[compact_index + 1].0 += 1; + if self.alignment[*compact_index + 1].1 == inner_alignment_type { + self.alignment[*compact_index + 1].0 += 1; } else { self.alignment - .insert(compact_index + 1, (1, inner_alignment_type)); + .insert(*compact_index + 1, (1, inner_alignment_type)); } // If reverse TS, then fix first offset. // (If forward TS, the changes to points 1 and 2 cancel out.) if direction == TemplateSwitchDirection::Reverse { let AlignmentType::TemplateSwitchEntrance { first_offset, .. } = - &mut self.alignment[compact_index].1 + &mut self.alignment[*compact_index].1 else { unreachable!(); }; @@ -139,7 +139,7 @@ impl Alignment { // Fix anti-primary gap. let Some((_, AlignmentType::TemplateSwitchExit { anti_primary_gap })) = self.alignment - [compact_index..] + [*compact_index..] .iter_mut() .find(|(_, alignment_type)| alignment_type.is_template_switch_exit()) else { @@ -171,10 +171,10 @@ impl Alignment { query: &SubsequenceType, reference_offset: usize, query_offset: usize, - mut compact_index: usize, + compact_index: &mut usize, ) -> bool { let AlignmentType::TemplateSwitchEntrance { direction, .. } = - self.alignment[compact_index].1 + self.alignment[*compact_index].1 else { panic!() }; @@ -182,7 +182,7 @@ impl Alignment { // Assert that no flanks are involved. assert!( self.alignment - .get(compact_index - 1) + .get(*compact_index - 1) .map(|(_, alignment_type)| !matches!( alignment_type, AlignmentType::PrimaryFlankDeletion @@ -194,22 +194,22 @@ impl Alignment { ); if let Some((_, AlignmentType::SecondaryMatch | AlignmentType::SecondarySubstitution)) = - self.alignment.get(compact_index + 1) + self.alignment.get(*compact_index + 1) { // Compute TS outer first indices. let mut stream = AlignmentStream::new(); - stream.push_all(self.iter_compact_cloned().take(compact_index)); + stream.push_all(self.iter_compact_cloned().take(*compact_index)); let ts_outer_reference_index = stream.head_coordinates().reference() + reference_offset; let ts_outer_query_index = stream.head_coordinates().query() + query_offset; // Remove one match or substitution from inside the TS. - let multiplicity = &mut self.alignment[compact_index + 1].0; + let multiplicity = &mut self.alignment[*compact_index + 1].0; assert!(*multiplicity > 0); *multiplicity -= 1; // Remove the alignment entry if it has zero multiplicity. if *multiplicity == 0 { - self.alignment.remove(compact_index + 1); + self.alignment.remove(*compact_index + 1); } // Check if the new outer pair is a match or a substitution. @@ -222,19 +222,19 @@ impl Alignment { }; // Insert new outer alignment. - if self.alignment[compact_index - 1].1 == outer_alignment_type { - self.alignment[compact_index - 1].0 += 1; + if self.alignment[*compact_index - 1].1 == outer_alignment_type { + self.alignment[*compact_index - 1].0 += 1; } else { self.alignment - .insert(compact_index, (1, outer_alignment_type)); - compact_index += 1; + .insert(*compact_index, (1, outer_alignment_type)); + *compact_index += 1; } // If reverse TS, then fix first offset. // (If forward TS, the changes to points 1 and 2 cancel out.) if direction == TemplateSwitchDirection::Reverse { let AlignmentType::TemplateSwitchEntrance { first_offset, .. } = - &mut self.alignment[compact_index].1 + &mut self.alignment[*compact_index].1 else { unreachable!(); }; @@ -243,7 +243,7 @@ impl Alignment { // Fix anti-primary gap. let Some((_, AlignmentType::TemplateSwitchExit { anti_primary_gap })) = self.alignment - [compact_index..] + [*compact_index..] .iter_mut() .find(|(_, alignment_type)| alignment_type.is_template_switch_exit()) else { @@ -1197,7 +1197,7 @@ mod tests { query.as_genome_subsequence(), 2, 2, - 1 + &mut 1 )); assert_eq!(alignment, Alignment::from(expected_alignment.to_vec())); assert_eq!( @@ -1240,7 +1240,7 @@ mod tests { query.as_genome_subsequence(), 2, 2, - 1 + &mut 1 )); assert_eq!(alignment, Alignment::from(expected_alignment.to_vec())); assert_eq!(