use super::lanes::Simd;
use super::profile::{ElemFromI32, ElemToI32};
use crate::align::sisd::{ScalarInit, NEG_INF};
use crate::align::{AlignmentType, Scoring};
use crate::graph::{EdgeId, Graph};
#[inline]
fn value_at<S>(v: S::Vec, lane: usize) -> i32
where
S: Simd,
S::Elem: ElemFromI32 + ElemToI32,
{
let mut buf = vec![S::Elem::from_i32(0); S::LANES];
S::storeu(v, &mut buf);
buf[lane].to_i32()
}
#[inline]
fn row_max<S>(v: S::Vec) -> i32
where
S: Simd,
S::Elem: ElemFromI32 + ElemToI32,
{
let mut buf = vec![S::Elem::from_i32(0); S::LANES];
S::storeu(v, &mut buf);
buf.iter()
.map(|elem| elem.to_i32())
.max()
.expect("LANES >= 1")
}
#[inline]
fn index_of<S>(row: &[S::Vec], row_width: usize, value: i32) -> i32
where
S: Simd,
S::Elem: ElemFromI32 + ElemToI32,
{
let mut buf = vec![S::Elem::from_i32(0); S::LANES];
for (segment, &vec) in row.iter().take(row_width).enumerate() {
S::storeu(vec, &mut buf);
for (lane, &elem) in buf.iter().enumerate() {
if elem.to_i32() == value {
return (segment * S::LANES + lane) as i32;
}
}
}
-1
}
#[inline]
fn seed_striped_row0<S>(
striped: &mut [S::Vec],
row_major: &[i32],
matrix_width_vecs: usize,
seq_len: usize,
) where
S: Simd,
S::Elem: ElemFromI32,
{
let lanes = S::LANES;
let mut lane_buf = vec![S::Elem::from_i32(0); lanes];
for (segment, slot) in striped.iter_mut().take(matrix_width_vecs).enumerate() {
for (k, lane) in lane_buf.iter_mut().enumerate() {
let pos = segment * lanes + k;
*lane = if pos >= seq_len || row_major[pos + 1] <= NEG_INF {
S::NEG_INF
} else {
S::Elem::from_i32(row_major[pos + 1])
};
}
*slot = S::loadu(&lane_buf);
}
}
#[allow(clippy::too_many_arguments)]
#[inline(always)]
pub(crate) fn fill_linear<S>(
graph: &Graph,
seq_len: usize,
scoring: Scoring,
alignment_type: AlignmentType,
seeded: &ScalarInit,
profile: &[S::Vec],
masks: &[S::Vec],
penalties: &[S::Vec],
striped_h: &mut Vec<S::Vec>,
) -> (usize, usize, i32)
where
S: Simd,
S::Elem: ElemFromI32 + ElemToI32,
{
let lanes = S::LANES;
let matrix_width_vecs = seq_len.div_ceil(lanes);
let matrix_width = seeded.matrix_width; let matrix_height = graph.nodes.len() + 1;
let node_id_to_rank = &seeded.node_id_to_rank;
let g_vec = S::splat(S::Elem::from_i32(i32::from(scoring.g)));
let zeroes = S::splat(S::Elem::from_i32(0));
let carry_mask = masks[S::LOG_LANES as usize];
let first_column = |r: usize| -> i32 { seeded.h[r * matrix_width] };
let pred_row = |edge_id: EdgeId| -> usize {
let tail = graph.edges[edge_id.0 as usize].tail;
node_id_to_rank[tail.0 as usize] as usize + 1
};
let cells = matrix_height * matrix_width_vecs;
striped_h.clear();
striped_h.resize(cells, S::splat(S::NEG_INF));
{
let mut lane_buf = vec![S::Elem::from_i32(0); lanes];
for (segment, slot) in striped_h.iter_mut().take(matrix_width_vecs).enumerate() {
for (k, lane) in lane_buf.iter_mut().enumerate() {
let pos = segment * lanes + k;
*lane = if pos < seq_len {
S::Elem::from_i32(seeded.h[pos + 1]) } else {
S::NEG_INF
};
}
*slot = S::loadu(&lane_buf);
}
}
let mut max_score: i32 = match alignment_type {
AlignmentType::Local => 0,
AlignmentType::Global | AlignmentType::Overlap => NEG_INF,
};
let mut max_i: usize = 0; let last_column_id = (seq_len - 1) % lanes;
for &node_id in &graph.rank_to_node {
let node = &graph.nodes[node_id.0 as usize];
let i = node_id_to_rank[node_id.0 as usize] as usize + 1;
let profile_base = node.code as usize * matrix_width_vecs;
let row_base = i * matrix_width_vecs;
let mut pred_i = if node.inedges.is_empty() {
0
} else {
pred_row(node.inedges[0])
};
let pred_base = pred_i * matrix_width_vecs;
let mut x = S::srli_top_lane(S::splat(S::Elem::from_i32(first_column(pred_i))));
for j in 0..matrix_width_vecs {
let h_pred = striped_h[pred_base + j];
let t1 = S::srli_top_lane(h_pred);
let diag = S::or(S::slli_one_lane(h_pred), x);
x = t1;
let value = S::max(
S::add(diag, profile[profile_base + j]),
S::add(h_pred, g_vec),
);
striped_h[row_base + j] = value;
}
for p in 1..node.inedges.len() {
pred_i = pred_row(node.inedges[p]);
let pred_base = pred_i * matrix_width_vecs;
let mut x = S::srli_top_lane(S::splat(S::Elem::from_i32(first_column(pred_i))));
for j in 0..matrix_width_vecs {
let h_pred = striped_h[pred_base + j];
let t1 = S::srli_top_lane(h_pred);
let m = S::or(S::slli_one_lane(h_pred), x);
x = t1;
let cur = striped_h[row_base + j];
let candidate = S::max(S::add(m, profile[profile_base + j]), S::add(h_pred, g_vec));
striped_h[row_base + j] = S::max(cur, candidate);
}
}
let mut score = S::splat(S::NEG_INF);
let mut x = S::srli_top_lane(S::add(S::splat(S::Elem::from_i32(first_column(i))), g_vec));
for j in 0..matrix_width_vecs {
let mut hv = striped_h[row_base + j];
hv = S::max(hv, S::or(x, carry_mask));
hv = S::prefix_max(hv, penalties, masks);
x = S::srli_top_lane(S::add(hv, g_vec));
if alignment_type == AlignmentType::Local {
hv = S::max(hv, zeroes);
}
striped_h[row_base + j] = hv;
score = S::max(score, hv);
}
match alignment_type {
AlignmentType::Local => {
let row_score = S::horizontal_max(score).to_i32();
if max_score < row_score {
max_score = row_score;
max_i = i;
}
}
AlignmentType::Overlap => {
if node.outedges.is_empty() {
let row_score = row_max::<S>(score);
if max_score < row_score {
max_score = row_score;
max_i = i;
}
}
}
AlignmentType::Global => {
if node.outedges.is_empty() {
let last = striped_h[row_base + (matrix_width_vecs - 1)];
let row_score = value_at::<S>(last, last_column_id);
if max_score < row_score {
max_score = row_score;
max_i = i;
}
}
}
}
}
if max_i == 0 {
return (0, 0, max_score);
}
let max_j = match alignment_type {
AlignmentType::Global => seq_len,
AlignmentType::Local | AlignmentType::Overlap => {
let row = &striped_h[max_i * matrix_width_vecs..(max_i + 1) * matrix_width_vecs];
let idx = index_of::<S>(row, matrix_width_vecs, max_score);
if idx < 0 {
return (0, 0, max_score);
}
idx as usize + 1
}
};
(max_i, max_j, max_score)
}
#[allow(clippy::too_many_arguments)]
#[inline(always)]
pub(crate) fn fill_affine<S>(
graph: &Graph,
seq_len: usize,
scoring: Scoring,
alignment_type: AlignmentType,
seeded: &ScalarInit,
profile: &[S::Vec],
masks: &[S::Vec],
penalties: &[S::Vec],
striped_h: &mut Vec<S::Vec>,
striped_e: &mut Vec<S::Vec>,
striped_f: &mut Vec<S::Vec>,
) -> (usize, usize, i32)
where
S: Simd,
S::Elem: ElemFromI32 + ElemToI32,
{
let lanes = S::LANES;
let matrix_width_vecs = seq_len.div_ceil(lanes);
let matrix_width = seeded.matrix_width; let matrix_height = graph.nodes.len() + 1;
let node_id_to_rank = &seeded.node_id_to_rank;
let g_minus_e = S::splat(S::Elem::from_i32(
i32::from(scoring.g) - i32::from(scoring.e),
));
let e_vec = S::splat(S::Elem::from_i32(i32::from(scoring.e)));
let zeroes = S::splat(S::Elem::from_i32(0));
let first_column = |r: usize| -> i32 { seeded.h[r * matrix_width] };
let pred_row = |edge_id: EdgeId| -> usize {
let tail = graph.edges[edge_id.0 as usize].tail;
node_id_to_rank[tail.0 as usize] as usize + 1
};
let cells = matrix_height * matrix_width_vecs;
for buf in [&mut *striped_h, &mut *striped_e, &mut *striped_f] {
buf.clear();
buf.resize(cells, S::splat(S::NEG_INF));
}
seed_striped_row0::<S>(striped_h, &seeded.h, matrix_width_vecs, seq_len);
seed_striped_row0::<S>(striped_f, &seeded.f, matrix_width_vecs, seq_len);
let mut max_score: i32 = match alignment_type {
AlignmentType::Local => 0,
AlignmentType::Global | AlignmentType::Overlap => NEG_INF,
};
let mut max_i: usize = 0; let last_column_id = (seq_len - 1) % lanes;
for &node_id in &graph.rank_to_node {
let node = &graph.nodes[node_id.0 as usize];
let i = node_id_to_rank[node_id.0 as usize] as usize + 1;
let profile_base = node.code as usize * matrix_width_vecs;
let row_base = i * matrix_width_vecs;
let mut pred_i = if node.inedges.is_empty() {
0
} else {
pred_row(node.inedges[0])
};
let mut pred_base = pred_i * matrix_width_vecs;
let mut x = S::srli_top_lane(S::splat(S::Elem::from_i32(first_column(pred_i))));
for j in 0..matrix_width_vecs {
let h_pred = striped_h[pred_base + j];
let f_pred = striped_f[pred_base + j];
striped_f[row_base + j] = S::add(S::max(S::add(h_pred, g_minus_e), f_pred), e_vec);
let diag = S::or(S::slli_one_lane(h_pred), x);
x = S::srli_top_lane(h_pred);
striped_h[row_base + j] = S::add(diag, profile[profile_base + j]);
}
for p in 1..node.inedges.len() {
pred_i = pred_row(node.inedges[p]);
pred_base = pred_i * matrix_width_vecs;
let mut x = S::srli_top_lane(S::splat(S::Elem::from_i32(first_column(pred_i))));
for j in 0..matrix_width_vecs {
let h_pred = striped_h[pred_base + j];
let f_pred = striped_f[pred_base + j];
let cur_f = striped_f[row_base + j];
let cand_f = S::add(S::max(S::add(h_pred, g_minus_e), f_pred), e_vec);
striped_f[row_base + j] = S::max(cur_f, cand_f);
let diag = S::or(S::slli_one_lane(h_pred), x);
x = S::srli_top_lane(h_pred);
let cur_h = striped_h[row_base + j];
let cand_h = S::add(diag, profile[profile_base + j]);
striped_h[row_base + j] = S::max(cur_h, cand_h);
}
}
let mut score = S::splat(S::NEG_INF);
let mut x = S::splat(S::Elem::from_i32(first_column(i)));
for j in 0..matrix_width_vecs {
let hf = S::max(striped_h[row_base + j], striped_f[row_base + j]);
let e_open = S::add(
S::add(S::or(S::slli_one_lane(hf), S::srli_top_lane(x)), g_minus_e),
e_vec,
);
let e_row = S::prefix_max(e_open, penalties, masks);
striped_e[row_base + j] = e_row;
let mut hv = S::max(hf, e_row);
x = S::max(hv, S::sub(e_row, g_minus_e));
if alignment_type == AlignmentType::Local {
hv = S::max(hv, zeroes);
}
striped_h[row_base + j] = hv;
score = S::max(score, hv);
}
match alignment_type {
AlignmentType::Local => {
let row_score = S::horizontal_max(score).to_i32();
if max_score < row_score {
max_score = row_score;
max_i = i;
}
}
AlignmentType::Overlap => {
if node.outedges.is_empty() {
let row_score = row_max::<S>(score);
if max_score < row_score {
max_score = row_score;
max_i = i;
}
}
}
AlignmentType::Global => {
if node.outedges.is_empty() {
let last = striped_h[row_base + (matrix_width_vecs - 1)];
let row_score = value_at::<S>(last, last_column_id);
if max_score < row_score {
max_score = row_score;
max_i = i;
}
}
}
}
}
if max_i == 0 {
return (0, 0, max_score);
}
let max_j = match alignment_type {
AlignmentType::Global => seq_len,
AlignmentType::Local | AlignmentType::Overlap => {
let row = &striped_h[max_i * matrix_width_vecs..(max_i + 1) * matrix_width_vecs];
let idx = index_of::<S>(row, matrix_width_vecs, max_score);
if idx < 0 {
return (0, 0, max_score);
}
idx as usize + 1
}
};
(max_i, max_j, max_score)
}
#[allow(clippy::too_many_arguments)]
#[inline(always)]
pub(crate) fn fill_convex<S>(
graph: &Graph,
seq_len: usize,
scoring: Scoring,
alignment_type: AlignmentType,
seeded: &ScalarInit,
profile: &[S::Vec],
masks: &[S::Vec],
penalties_e: &[S::Vec],
penalties_c: &[S::Vec],
striped_h: &mut Vec<S::Vec>,
striped_e: &mut Vec<S::Vec>,
striped_f: &mut Vec<S::Vec>,
striped_o: &mut Vec<S::Vec>,
striped_q: &mut Vec<S::Vec>,
) -> (usize, usize, i32)
where
S: Simd,
S::Elem: ElemFromI32 + ElemToI32,
{
let lanes = S::LANES;
let matrix_width_vecs = seq_len.div_ceil(lanes);
let matrix_width = seeded.matrix_width; let matrix_height = graph.nodes.len() + 1;
let node_id_to_rank = &seeded.node_id_to_rank;
let g_minus_e = S::splat(S::Elem::from_i32(
i32::from(scoring.g) - i32::from(scoring.e),
));
let e_vec = S::splat(S::Elem::from_i32(i32::from(scoring.e)));
let q_minus_c = S::splat(S::Elem::from_i32(
i32::from(scoring.q) - i32::from(scoring.c),
));
let c_vec = S::splat(S::Elem::from_i32(i32::from(scoring.c)));
let zeroes = S::splat(S::Elem::from_i32(0));
let first_column = |r: usize| -> i32 { seeded.h[r * matrix_width] };
let pred_row = |edge_id: EdgeId| -> usize {
let tail = graph.edges[edge_id.0 as usize].tail;
node_id_to_rank[tail.0 as usize] as usize + 1
};
let cells = matrix_height * matrix_width_vecs;
for buf in [
&mut *striped_h,
&mut *striped_e,
&mut *striped_f,
&mut *striped_o,
&mut *striped_q,
] {
buf.clear();
buf.resize(cells, S::splat(S::NEG_INF));
}
seed_striped_row0::<S>(striped_h, &seeded.h, matrix_width_vecs, seq_len);
seed_striped_row0::<S>(striped_f, &seeded.f, matrix_width_vecs, seq_len);
seed_striped_row0::<S>(striped_o, &seeded.o, matrix_width_vecs, seq_len);
let mut max_score: i32 = match alignment_type {
AlignmentType::Local => 0,
AlignmentType::Global | AlignmentType::Overlap => NEG_INF,
};
let mut max_i: usize = 0; let last_column_id = (seq_len - 1) % lanes;
for &node_id in &graph.rank_to_node {
let node = &graph.nodes[node_id.0 as usize];
let i = node_id_to_rank[node_id.0 as usize] as usize + 1;
let profile_base = node.code as usize * matrix_width_vecs;
let row_base = i * matrix_width_vecs;
let mut pred_i = if node.inedges.is_empty() {
0
} else {
pred_row(node.inedges[0])
};
let mut pred_base = pred_i * matrix_width_vecs;
let mut x = S::srli_top_lane(S::splat(S::Elem::from_i32(first_column(pred_i))));
for j in 0..matrix_width_vecs {
let h_pred = striped_h[pred_base + j];
let f_pred = striped_f[pred_base + j];
let o_pred = striped_o[pred_base + j];
striped_f[row_base + j] = S::add(S::max(S::add(h_pred, g_minus_e), f_pred), e_vec);
striped_o[row_base + j] = S::add(S::max(S::add(h_pred, q_minus_c), o_pred), c_vec);
let diag = S::or(S::slli_one_lane(h_pred), x);
x = S::srli_top_lane(h_pred);
striped_h[row_base + j] = S::add(diag, profile[profile_base + j]);
}
for p in 1..node.inedges.len() {
pred_i = pred_row(node.inedges[p]);
pred_base = pred_i * matrix_width_vecs;
let mut x = S::srli_top_lane(S::splat(S::Elem::from_i32(first_column(pred_i))));
for j in 0..matrix_width_vecs {
let h_pred = striped_h[pred_base + j];
let f_pred = striped_f[pred_base + j];
let o_pred = striped_o[pred_base + j];
let cur_f = striped_f[row_base + j];
let cand_f = S::add(S::max(S::add(h_pred, g_minus_e), f_pred), e_vec);
striped_f[row_base + j] = S::max(cur_f, cand_f);
let cur_o = striped_o[row_base + j];
let cand_o = S::add(S::max(S::add(h_pred, q_minus_c), o_pred), c_vec);
striped_o[row_base + j] = S::max(cur_o, cand_o);
let diag = S::or(S::slli_one_lane(h_pred), x);
x = S::srli_top_lane(h_pred);
let cur_h = striped_h[row_base + j];
let cand_h = S::add(diag, profile[profile_base + j]);
striped_h[row_base + j] = S::max(cur_h, cand_h);
}
}
let mut score = S::splat(S::NEG_INF);
let mut x = S::splat(S::Elem::from_i32(first_column(i)));
let mut y = S::splat(S::Elem::from_i32(first_column(i)));
for j in 0..matrix_width_vecs {
let hfo = S::max(
striped_h[row_base + j],
S::max(striped_f[row_base + j], striped_o[row_base + j]),
);
let e_open = S::add(
S::add(S::or(S::slli_one_lane(hfo), S::srli_top_lane(x)), g_minus_e),
e_vec,
);
let e_row = S::prefix_max(e_open, penalties_e, masks);
let q_open = S::add(
S::add(S::or(S::slli_one_lane(hfo), S::srli_top_lane(y)), q_minus_c),
c_vec,
);
let q_row = S::prefix_max(q_open, penalties_c, masks);
striped_e[row_base + j] = e_row;
striped_q[row_base + j] = q_row;
let mut hv = S::max(hfo, S::max(e_row, q_row));
x = S::max(hv, S::sub(e_row, g_minus_e));
y = S::max(hv, S::sub(q_row, q_minus_c));
if alignment_type == AlignmentType::Local {
hv = S::max(hv, zeroes);
}
striped_h[row_base + j] = hv;
score = S::max(score, hv);
}
match alignment_type {
AlignmentType::Local => {
let row_score = S::horizontal_max(score).to_i32();
if max_score < row_score {
max_score = row_score;
max_i = i;
}
}
AlignmentType::Overlap => {
if node.outedges.is_empty() {
let row_score = row_max::<S>(score);
if max_score < row_score {
max_score = row_score;
max_i = i;
}
}
}
AlignmentType::Global => {
if node.outedges.is_empty() {
let last = striped_h[row_base + (matrix_width_vecs - 1)];
let row_score = value_at::<S>(last, last_column_id);
if max_score < row_score {
max_score = row_score;
max_i = i;
}
}
}
}
}
if max_i == 0 {
return (0, 0, max_score);
}
let max_j = match alignment_type {
AlignmentType::Global => seq_len,
AlignmentType::Local | AlignmentType::Overlap => {
let row = &striped_h[max_i * matrix_width_vecs..(max_i + 1) * matrix_width_vecs];
let idx = index_of::<S>(row, matrix_width_vecs, max_score);
if idx < 0 {
return (0, 0, max_score);
}
idx as usize + 1
}
};
(max_i, max_j, max_score)
}