Skip to content

Commit 9edd90d

Browse files
authored
Merge pull request #194 from algbio/193-failing-debug-assertion-in-compute_ts_equal_cost_ranges
193 failing debug assertion in compute ts equal cost ranges
2 parents 838529c + 0e64da0 commit 9edd90d

6 files changed

Lines changed: 96 additions & 88 deletions

File tree

lib_tsalign/src/a_star_aligner/alignment_result/alignment/template_switch_specifics.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -759,12 +759,11 @@ impl Alignment<AlignmentType> {
759759
descendant = ts_descendant;
760760
ancestor = ts_ancestor;
761761
direction = ts_direction;
762-
let cost_increment = config.base_cost.get(descendant, ancestor, direction);
763-
let Some(cost_increment) = cost_increment.checked_add(
764-
&config
765-
.offset_costs(descendant, ancestor)
766-
.evaluate(&first_offset),
767-
) else {
762+
let base_cost = config.base_cost.get(descendant, ancestor, direction);
763+
let offset_cost = config
764+
.offset_costs(descendant, ancestor)
765+
.evaluate(&first_offset);
766+
let Some(cost_increment) = base_cost.checked_add(&offset_cost) else {
768767
return Cost::max_value();
769768
};
770769
descendant_index = match descendant {
@@ -1298,7 +1297,6 @@ mod tests {
12981297
for (expected_alignment, expected_cost) in
12991298
START_ALIGNMENTS[1..].iter().zip(&START_COSTS[1..])
13001299
{
1301-
println!("{}", alignment.cigar());
13021300
assert!(alignment.move_template_switch_start_backwards(
13031301
reference.as_genome_subsequence(),
13041302
query.as_genome_subsequence(),

lib_tsalign/src/a_star_aligner/configurable_a_star_align.rs

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ use super::{
6262
pub use compact_genome::implementation::alphabets;
6363
pub use compact_genome::interface::alphabet::Alphabet;
6464

65+
#[cfg(test)]
66+
mod tests;
67+
6568
#[derive(Debug, Default)]
6669
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
6770
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
@@ -434,34 +437,3 @@ impl<AlphabetType: Alphabet> Aligner<AlphabetType> {
434437
)
435438
}
436439
}
437-
438-
#[cfg(test)]
439-
mod tests {
440-
use num_traits::real::Real;
441-
442-
use crate::a_star_aligner::alignment_geometry::AlignmentCoordinates;
443-
444-
use super::*;
445-
446-
/// This test case uses real data and used to panic.
447-
#[test]
448-
fn test_panic() {
449-
let mut aligner = Aligner::new();
450-
aligner.set_min_length_strategy(MinLengthStrategySelector::PreprocessFilter);
451-
let res = aligner.align(
452-
"reference",
453-
b"TACCGAGACTGCAGAAAGTGAAAGCTATACTAA",
454-
"query",
455-
b"TAACTTTTAATGCCAAATATTTTATCCAAATAGGAAATTGTTTTCCGGTAAAATTTAACAAAAGAACCAGTTTACCCCCTTCAATGATTTATTTTTCTTCTTAGATTGAACTCTCGGGTTAGATCTCATTTTAACTGAAATTTGGTAAAAAATCCATATTACGGTTCAAGCCTAACCGAGACTGCAGAAAGTGAAAGCTAAAAGCTAATTTTTTTTTTTTTTTTGTATTTCACACCTATCGCAATACATCCTGGACAACACTGTATATTGAAACATTTTTTGCCTACAGCAATGGGCCTATAATTTTTTCTCGGCATTAGCTCTACAATCCAATTCTATCCTGCTTCTTCTTGTAAACAGGGATAACTTTAACTAACATTCAGTTTGCTTGGGAAAGAACCGATTGATAATGTA",
456-
AlignmentRange::new_offset_limit(
457-
AlignmentCoordinates::new(27, 200),
458-
AlignmentCoordinates::new(33, 214)
459-
).into(),
460-
&[],
461-
None,
462-
None,
463-
true);
464-
println!("{res:#?}");
465-
assert!(res.statistics().cost.is_sign_positive());
466-
}
467-
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use num_traits::real::Real;
2+
3+
use crate::a_star_aligner::alignment_geometry::AlignmentCoordinates;
4+
5+
use super::*;
6+
7+
/// This test case uses real data and used to panic.
8+
#[test]
9+
fn test_panic() {
10+
let mut aligner = Aligner::new();
11+
aligner.set_min_length_strategy(MinLengthStrategySelector::PreprocessFilter);
12+
let res = aligner.align(
13+
"reference",
14+
b"TACCGAGACTGCAGAAAGTGAAAGCTATACTAA",
15+
"query",
16+
b"TAACTTTTAATGCCAAATATTTTATCCAAATAGGAAATTGTTTTCCGGTAAAATTTAACAAAAGAACCAGTTTACCCCCTTCAATGATTTATTTTTCTTCTTAGATTGAACTCTCGGGTTAGATCTCATTTTAACTGAAATTTGGTAAAAAATCCATATTACGGTTCAAGCCTAACCGAGACTGCAGAAAGTGAAAGCTAAAAGCTAATTTTTTTTTTTTTTTTGTATTTCACACCTATCGCAATACATCCTGGACAACACTGTATATTGAAACATTTTTTGCCTACAGCAATGGGCCTATAATTTTTTCTCGGCATTAGCTCTACAATCCAATTCTATCCTGCTTCTTCTTGTAAACAGGGATAACTTTAACTAACATTCAGTTTGCTTGGGAAAGAACCGATTGATAATGTA",
17+
AlignmentRange::new_offset_limit(
18+
AlignmentCoordinates::new(27, 200),
19+
AlignmentCoordinates::new(33, 214)
20+
).into(),
21+
&[],
22+
None,
23+
None,
24+
true);
25+
println!("{res:#?}");
26+
assert!(res.statistics().cost.is_sign_positive());
27+
}
28+
29+
#[test]
30+
fn test_193() {
31+
// [-- 10 --][-- 11 ---]1
32+
let r = b"AAAAAAAAAACCCCCCCCCCCC";
33+
let q = b"AAAAAAAAAATTTTTTTTTTTC";
34+
35+
let mut tsa = Aligner::<DnaAlphabetOrN>::default();
36+
37+
let mut costs = TemplateSwitchConfig::default();
38+
costs.base_cost.qrr = 4u64.into();
39+
tsa.set_costs(costs.clone());
40+
let _tsa_res = tsa.align("ref", r, "qry", q, None, &[], None, None, false);
41+
}

lib_tsalign/src/a_star_aligner/template_switch_distance.rs

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::fmt::Display;
22

33
use compact_genome::interface::sequence::GenomeSequence;
44
use generic_a_star::{AStarNode, cost::AStarCost};
5-
use num_traits::{Bounded, Zero};
5+
use num_traits::{Bounded, CheckedAdd, Zero};
66
use strategies::{
77
AlignmentStrategiesNodeMemory, AlignmentStrategySelector, node_ord::NodeOrdStrategy,
88
primary_match::PrimaryMatchStrategy,
@@ -25,7 +25,7 @@ pub use identifier::{
2525

2626
use crate::{
2727
a_star_aligner::template_switch_distance::strategies::descendant::TemplateSwitchDescendantStrategy,
28-
config::BaseCost,
28+
config::BaseCost, costs::cost_function::CostFunction,
2929
};
3030

3131
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -223,8 +223,8 @@ impl<Strategies: AlignmentStrategySelector> Node<Strategies> {
223223
SubsequenceType: GenomeSequence<Strategies::Alphabet, SubsequenceType> + ?Sized,
224224
>(
225225
&'result self,
226-
rq_qr_cost_increment: Strategies::Cost,
227-
rr_qq_cost_increment: Strategies::Cost,
226+
rq_qr_offset_costs: &'result CostFunction<isize, Strategies::Cost>,
227+
rr_qq_offset_costs: &'result CostFunction<isize, Strategies::Cost>,
228228
base_cost: &'result BaseCost<Strategies::Cost>,
229229
context: &'result Context<SubsequenceType, Strategies>,
230230
) -> impl 'result + Iterator<Item = Self> {
@@ -234,10 +234,6 @@ impl<Strategies: AlignmentStrategySelector> Node<Strategies> {
234234
) {
235235
unreachable!("This method is only called on primary nodes.")
236236
}
237-
debug_assert!(
238-
rq_qr_cost_increment < Strategies::Cost::max_value()
239-
|| rr_qq_cost_increment < Strategies::Cost::max_value(),
240-
);
241237

242238
self.node_data
243239
.identifier
@@ -268,34 +264,42 @@ impl<Strategies: AlignmentStrategySelector> Node<Strategies> {
268264
*template_switch_ancestor,
269265
*template_switch_direction,
270266
);
271-
let cost_increment = match (*template_switch_descendant, *template_switch_ancestor)
272-
{
267+
let cost_function = match (*template_switch_descendant, *template_switch_ancestor) {
273268
(TemplateSwitchDescendant::Reference, TemplateSwitchAncestor::Query)
274269
| (TemplateSwitchDescendant::Query, TemplateSwitchAncestor::Reference) => {
275-
rq_qr_cost_increment
270+
rq_qr_offset_costs
276271
}
277272
(TemplateSwitchDescendant::Reference, TemplateSwitchAncestor::Reference)
278273
| (TemplateSwitchDescendant::Query, TemplateSwitchAncestor::Query) => {
279-
rr_qq_cost_increment
274+
rr_qq_offset_costs
280275
}
281276
};
277+
let cost_increment = cost_function.evaluate(template_switch_first_offset);
282278

283-
(base_cost != Strategies::Cost::max_value()
284-
&& cost_increment != Strategies::Cost::max_value())
285-
.then(|| {
286-
self.generate_successor(
287-
identifier,
288-
base_cost + cost_increment,
289-
AlignmentType::TemplateSwitchEntrance {
290-
descendant: *template_switch_descendant,
291-
ancestor: *template_switch_ancestor,
292-
direction: *template_switch_direction,
293-
equal_cost_range: EqualCostRange::new_invalid(),
294-
first_offset: *template_switch_first_offset,
295-
},
296-
context,
297-
)
298-
})
279+
if base_cost != Strategies::Cost::max_value()
280+
&& cost_increment != Strategies::Cost::max_value()
281+
{
282+
if let Some(cost_increment) = base_cost.checked_add(&cost_increment)
283+
&& cost_increment != Strategies::Cost::max_value()
284+
{
285+
Some(self.generate_successor(
286+
identifier,
287+
cost_increment,
288+
AlignmentType::TemplateSwitchEntrance {
289+
descendant: *template_switch_descendant,
290+
ancestor: *template_switch_ancestor,
291+
direction: *template_switch_direction,
292+
equal_cost_range: EqualCostRange::new_invalid(),
293+
first_offset: *template_switch_first_offset,
294+
},
295+
context,
296+
))
297+
} else {
298+
None
299+
}
300+
} else {
301+
None
302+
}
299303
})
300304
}
301305

lib_tsalign/src/a_star_aligner/template_switch_distance/context.rs

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,8 @@ impl<
208208
opened_nodes_output.extend(
209209
primary_node
210210
.generate_initial_template_switch_entrance_successors(
211-
config.rq_qr_offset_costs.evaluate(&0),
212-
config.rr_qq_offset_costs.evaluate(&0),
211+
&config.rq_qr_offset_costs,
212+
&config.rr_qq_offset_costs,
213213
&config.base_cost,
214214
self,
215215
)
@@ -444,22 +444,15 @@ impl<
444444

445445
// Template switches are always allowed, as long as we have a left flank.
446446
if flank_index == config.left_flank_length && can_start_another_template_switch {
447-
let rq_qr_offset_costs = config.rq_qr_offset_costs.evaluate(&0);
448-
let rr_qq_offset_costs = config.rr_qq_offset_costs.evaluate(&0);
449-
450-
if rq_qr_offset_costs != Strategies::Cost::max_value()
451-
|| rr_qq_offset_costs != Strategies::Cost::max_value()
452-
{
453-
opened_nodes_output.extend(
454-
node.generate_initial_template_switch_entrance_successors(
455-
rq_qr_offset_costs,
456-
rr_qq_offset_costs,
457-
&config.base_cost,
458-
self,
459-
)
460-
.map(Into::into),
461-
);
462-
}
447+
opened_nodes_output.extend(
448+
node.generate_initial_template_switch_entrance_successors(
449+
&config.rq_qr_offset_costs,
450+
&config.rr_qq_offset_costs,
451+
&config.base_cost,
452+
self,
453+
)
454+
.map(Into::into),
455+
);
463456
}
464457
}
465458

lib_tsalign/src/config.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,10 @@ impl<AlphabetType: Alphabet, Cost: AStarCost> Default for TemplateSwitchConfig<A
223223
right_flank_length: 0,
224224
template_switch_min_length: 5,
225225
base_cost: BaseCost {
226-
rrf: 4.into(),
227-
rqf: 4.into(),
228-
qrf: 4.into(),
229-
qqf: 4.into(),
226+
rrf: 40.into(),
227+
rqf: 40.into(),
228+
qrf: 40.into(),
229+
qqf: 40.into(),
230230
rrr: 3.into(),
231231
rqr: 2.into(),
232232
qrr: 2.into(),

0 commit comments

Comments
 (0)