use super::*;
use std::ops::Add;
#[must_use]
#[allow(clippy::cast_sign_loss)]
pub fn sw_scalar_score<const S: usize>(reference: &[u8], query: &ScalarProfile<S>) -> MaybeAligned<u32> {
let mut best_score = 0;
let mut h_row = vec![0; query.seq.len()];
let mut e_row = vec![query.gap_open; query.seq.len()];
for reference_base in reference.iter().copied() {
let mut f = query.gap_open;
let mut h = 0;
for c in 0..query.seq.len() {
let match_score = i32::from(query.matrix.get_weight(reference_base, query.seq[c]));
h += match_score;
let mut e = e_row[c];
h = h.max(e).max(f).max(0);
best_score = best_score.max(h);
e = e.add(query.gap_extend).max(h + query.gap_open);
f = f.add(query.gap_extend).max(h + query.gap_open);
(h, h_row[c]) = (h_row[c], h);
e_row[c] = e;
}
}
let best_score = best_score as u32;
if best_score > 0 {
MaybeAligned::Some(best_score)
} else {
MaybeAligned::Unmapped
}
}
#[must_use]
#[allow(clippy::cast_sign_loss)]
pub fn sw_scalar_align<const S: usize>(reference: &[u8], query: &ScalarProfile<S>) -> MaybeAligned<Alignment<u32>> {
if reference.is_empty() {
return MaybeAligned::Unmapped;
}
let mut best_score = 0;
let (mut r_end, mut c_end) = (0, 0);
let mut h_row = vec![0; query.seq.len()];
let mut e_row = vec![query.gap_open; query.seq.len()];
let mut backtrack = BacktrackMatrix::new(reference.len(), query.seq.len());
for (r, reference_base) in reference.iter().copied().enumerate() {
let mut f = query.gap_open;
let mut h = 0;
for c in 0..query.seq.len() {
backtrack.move_to(r, c);
let match_score = i32::from(query.matrix.get_weight(reference_base, query.seq[c]));
h += match_score;
let mut e = e_row[c];
h = h.max(e).max(f).max(0);
if h > best_score {
best_score = h;
r_end = r;
c_end = c;
}
if e == h {
backtrack.up();
}
if f == h {
backtrack.left();
}
if h == 0 {
backtrack.stop();
}
let next_diag = h_row[c];
h_row[c] = h;
h += query.gap_open;
e = e.add(query.gap_extend).max(h);
f = f.add(query.gap_extend).max(h);
if h != query.gap_open {
if e > h {
backtrack.up_extending();
}
if f > h {
backtrack.left_extending();
}
}
h = next_diag;
e_row[c] = e;
}
}
if best_score == 0 {
MaybeAligned::Unmapped
} else {
MaybeAligned::Some(backtrack.to_alignment(best_score as u32, r_end, c_end, reference.len(), query.seq.len()))
}
}
#[must_use]
#[allow(clippy::cast_sign_loss)]
#[cfg(feature = "alignment-diagnostics")]
pub fn sw_scalar_align_override<F, const S: usize>(
reference: &[u8], query: &ScalarProfile<S>, mut alter_score: F,
) -> MaybeAligned<Alignment<u32>>
where
F: FnMut(usize, usize, i32) -> i32, {
if reference.is_empty() {
return MaybeAligned::Unmapped;
}
let (mut best_score, mut r_end, mut c_end) = (0, 0, 0);
let mut h_row = vec![0; query.seq.len()];
let mut e_row = vec![query.gap_open; query.seq.len()];
let mut backtrack = BacktrackMatrix::new(reference.len(), query.seq.len());
for (r, reference_base) in reference.iter().copied().enumerate() {
let mut f = query.gap_open;
let mut h = 0;
for c in 0..query.seq.len() {
backtrack.move_to(r, c);
let match_score = i32::from(query.matrix.get_weight(reference_base, query.seq[c]));
h += match_score;
let mut e = e_row[c];
h = h.max(e).max(f).max(0);
h = alter_score(r, c, h);
if h > best_score {
best_score = h;
r_end = r;
c_end = c;
}
if e == h {
backtrack.up();
}
if f == h {
backtrack.left();
}
if h == 0 {
backtrack.stop();
}
let next_diag = h_row[c];
h_row[c] = h;
h += query.gap_open;
e = e.add(query.gap_extend).max(h);
f = f.add(query.gap_extend).max(h);
if h != query.gap_open {
if e > h {
backtrack.up_extending();
}
if f > h {
backtrack.left_extending();
}
}
h = next_diag;
e_row[c] = e;
}
}
if best_score == 0 {
MaybeAligned::Unmapped
} else {
MaybeAligned::Some(backtrack.to_alignment(best_score as u32, r_end, c_end, reference.len(), query.seq.len()))
}
}