Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ package.repository = "https://github.com/sebschmi/template-switch-aligner"

[workspace.dependencies]
serde = "1.0.219"
compact-genome = "12.3.0"
compact-genome = "12.5.0"
traitsequence = "8.1.2"
log = "0.4.27"
num-traits = "0.2.19"
Expand Down
16 changes: 13 additions & 3 deletions lib_tsalign/src/a_star_aligner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ pub fn template_switch_distance_a_star_align<
query: &SubsequenceType,
reference_name: &str,
query_name: &str,
range: Option<AlignmentRange>,
range: AlignmentRange,
config: &config::TemplateSwitchConfig<
Strategies::Alphabet,
<Strategies as AlignmentStrategySelector>::Cost,
Expand All @@ -167,6 +167,9 @@ pub fn template_switch_distance_a_star_align<
where
Strategies::Cost: From<u64>,
{
debug!("Reference sequence: {}", reference.as_string());
debug!("Query sequence: {}", query.as_string());

let memory = Memory {
template_switch_min_length:
<Strategies::TemplateSwitchMinLength as TemplateSwitchMinLengthStrategy<
Expand All @@ -180,6 +183,7 @@ where
primary_match: (),
};

info!("Calling aligner...");
let mut result = a_star_align(template_switch_distance::Context::<
SubsequenceType,
Strategies,
Expand All @@ -195,12 +199,18 @@ where
memory_limit,
force_label_correcting,
));
debug!("CIGAR before extending: {}", result.cigar());
info!("Main alignment finished");

info!("Extending template switches");
debug!("CIGAR before extending: {}", result.cigar());
let mut range = range;
result.extend_beyond_range_with_equal_cost(reference, query, &mut range, config);
let extension_steps =
result.extend_beyond_range_without_increasing_cost(reference, query, &mut range, config);
let range = range;
info!(
"Extended alignment {extension_steps} steps beyond the alignment range without increasing alignment costs"
);
info!("Alignment ranges after extension {range}");

result.compute_ts_equal_cost_ranges(reference, query, &range, config);
result
Expand Down
41 changes: 22 additions & 19 deletions lib_tsalign/src/a_star_aligner/alignment_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,32 +237,31 @@ impl<AlignmentType: IAlignmentType, Cost: AStarCost> AlignmentResult<AlignmentTy
impl<Cost: AStarCost + From<u64>>
AlignmentResult<super::template_switch_distance::AlignmentType, Cost>
{
/// Heuristically extend the alignment beyond the alignment range as long as this does not increase the alignment cost.
///
/// Returns the amount of steps the alignment was extended.
#[allow(clippy::too_many_lines)]
pub fn extend_beyond_range_with_equal_cost<
pub fn extend_beyond_range_without_increasing_cost<
AlphabetType: Alphabet,
SubsequenceType: GenomeSequence<AlphabetType, SubsequenceType> + ?Sized,
>(
&mut self,
reference: &SubsequenceType,
query: &SubsequenceType,
range: &mut Option<AlignmentRange>,
range: &mut AlignmentRange,
config: &TemplateSwitchConfig<AlphabetType, Cost>,
) {
let Some(range) = range else {
trace!("No range given to extend beyond.");
return;
};
) -> usize {
let Self::WithTarget {
alignment,
statistics,
} = self
else {
trace!("There is no alignment, therefore we cannot postprocess it.");
return;
return 0;
};
if config.left_flank_length > 0 || config.right_flank_length > 0 {
warn!("Alignment extension does not support flanks");
return;
return 0;
}

// Compute cost before extending.
Expand All @@ -280,6 +279,7 @@ impl<Cost: AStarCost + From<u64>>
"computed cost {current_cost} != alignment cost {alignment_cost}; {}",
alignment.cigar()
);
let mut extension_steps = 0;

// Extend left with equal cost.
while let Some(new_range) = range.move_offsets_left() {
Expand Down Expand Up @@ -312,8 +312,10 @@ impl<Cost: AStarCost + From<u64>>
config,
);

trace!("Extending left to {new_range}. Cost {current_cost} -> {new_cost}");

if new_cost > current_cost {
// If cost is not equal, revert alignment and break.
// If cost is increasing, revert alignment and break.
alignment.inner_mut()[0].0 -= 1;
if alignment.inner_mut()[0].0 == 0 {
alignment.inner_mut().remove(0);
Expand All @@ -322,6 +324,7 @@ impl<Cost: AStarCost + From<u64>>
}
current_cost = new_cost;
*range = new_range;
extension_steps += 1;
}

// Extend right with equal cost.
Expand Down Expand Up @@ -364,23 +367,28 @@ impl<Cost: AStarCost + From<u64>>
config,
);

trace!("Extending right to {new_range}. Cost {current_cost} -> {new_cost}");

if new_cost > current_cost {
// If cost is not equal, revert alignment and break.
// If cost is increasing, revert alignment and break.
let Some((n, _)) = alignment.inner_mut().last_mut() else {
unreachable!("As we have just added at least one element")
};
*n -= 1;
if *n == 0 {
alignment.inner_mut().pop();
}
break;
}
current_cost = new_cost;
*range = new_range;
extension_steps += 1;
}

// Update statistics from updated range
statistics.reference_offset = range.reference_offset();
statistics.query_offset = range.query_offset();
extension_steps
}

#[allow(clippy::too_many_lines)]
Expand All @@ -391,7 +399,7 @@ impl<Cost: AStarCost + From<u64>>
&mut self,
reference: &SubsequenceType,
query: &SubsequenceType,
range: &Option<AlignmentRange>,
range: &AlignmentRange,
config: &TemplateSwitchConfig<AlphabetType, Cost>,
) {
let Self::WithTarget {
Expand All @@ -407,13 +415,8 @@ impl<Cost: AStarCost + From<u64>>
return;
}

let reference_offset = range.as_ref().map_or(
0,
super::alignment_geometry::AlignmentRange::reference_offset,
);
let query_offset = range
.as_ref()
.map_or(0, super::alignment_geometry::AlignmentRange::query_offset);
let reference_offset = range.reference_offset();
let query_offset = range.query_offset();

for i in 0..alignment.inner_mut().len() {
let alignment_type = alignment.inner_mut()[i].1;
Expand Down
4 changes: 3 additions & 1 deletion lib_tsalign/src/a_star_aligner/configurable_a_star_align.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use compact_genome::{
interface::sequence::{GenomeSequence, OwnedGenomeSequence},
};
use generic_a_star::cost::U64Cost;
use traitsequence::interface::Sequence;

use crate::{
a_star_aligner::{
Expand Down Expand Up @@ -281,7 +282,8 @@ impl<AlphabetType: Alphabet> Aligner<AlphabetType> {
query.as_genome_subsequence(),
data.reference_name,
data.query_name,
data.ranges,
data.ranges
.unwrap_or_else(|| AlignmentRange::new_complete(reference.len(), query.len())),
&self.costs,
cost_limit,
data.memory_limit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ impl<
query: &'query SubsequenceType,
reference_name: &str,
query_name: &str,
range: Option<AlignmentRange>,
range: AlignmentRange,
config: TemplateSwitchConfig<Strategies::Alphabet, Strategies::Cost>,
memory: Memory<Strategies>,
cost_limit: Option<Strategies::Cost>,
Expand All @@ -92,8 +92,7 @@ impl<
query,
reference_name: reference_name.to_owned(),
query_name: query_name.to_owned(),
range: range
.unwrap_or_else(|| AlignmentRange::new_complete(reference.len(), query.len())),
range,
config,
a_star_buffers: Default::default(),
memory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ use compact_genome::{
};
use generic_a_star::{AStar, AStarNode, AStarResult, cost::AStarCost};
use log::{debug, info, trace};
use traitsequence::interface::Sequence;

use crate::{
a_star_aligner::{
alignment_geometry::AlignmentRange,
alignment_result::IAlignmentType,
template_switch_distance::{
Context, Identifier, Node,
Expand Down Expand Up @@ -93,7 +95,7 @@ impl<Cost: AStarCost> TemplateSwitchLowerBoundMatrix<Cost> {
genome.as_genome_subsequence(),
"",
"",
None,
AlignmentRange::new_complete(genome.len(), genome.len()),
lower_bound_config.clone(),
Memory {
template_switch_min_length: (),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ use compact_genome::{
use generic_a_star::{AStar, AStarNode, AStarResult, cost::AStarCost};
use log::{debug, info, trace};
use ndarray::Array2;
use traitsequence::interface::Sequence;

use crate::{
a_star_aligner::{
alignment_geometry::AlignmentRange,
alignment_result::IAlignmentType,
template_switch_distance::{
Context, Identifier,
Expand Down Expand Up @@ -95,7 +97,7 @@ impl<Cost: AStarCost> TemplateSwitchAlignmentLowerBoundMatrix<Cost> {
genome.as_genome_subsequence(),
"",
"",
None,
AlignmentRange::new_complete(genome.len(), genome.len()),
lower_bound_config.clone(),
Memory {
template_switch_min_length: (),
Expand Down
4 changes: 4 additions & 0 deletions test_files/twin_embedded.fa
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
>REF
ACCA|GGAA|TTGG
>QRY
AGCA|GGAA|TAGG
5 changes: 5 additions & 0 deletions tsalign-tests/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ fn test_align_with_cost_limit() -> Result<()> {
fn test_align_with_memory_limit() -> Result<()> {
run_in_repo_root("align -p test_files/twin_100_0.01.fa --memory-limit 1000")
}

#[test]
fn test_align_with_embedded_rq_ranges() -> Result<()> {
run_in_repo_root("align -p test_files/twin_embedded.fa --use-embedded-rq-ranges")
}
1 change: 1 addition & 0 deletions tsalign/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ toml = "0.8.19"
log.workspace = true
simplelog = "0.12.2"
anyhow = "1.0.97"
utf8-chars = "3.0.5"
Loading
Loading