use crate::{
alignment::phmm::{
CorePhmm, EmissionParams, PhmmNumber,
indexing::{PhmmIndex, PhmmIndexable, QueryIndex, QueryIndexable},
},
data::mappings::ByteIndexMap,
};
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct SemiLocalModule<T>(pub(crate) Vec<T>);
impl<T> SemiLocalModule<T> {
#[inline]
#[must_use]
#[cfg(feature = "alignment-diagnostics")]
pub fn as_slice(&self) -> &[T] {
&self.0
}
}
impl<T: PhmmNumber> SemiLocalModule<T> {
#[cfg(feature = "alignment-diagnostics")]
pub fn from_slice(params: &[T]) -> Self {
Self(params.to_vec())
}
#[inline]
#[must_use]
pub(crate) fn no_penalty<const S: usize>(core: &CorePhmm<T, S>) -> Self {
Self(vec![T::ZERO; core.num_pseudomatch()])
}
#[inline]
#[must_use]
pub(crate) fn get_score(&self, j: impl PhmmIndex) -> T {
self.0[self.get_dp_index(j)]
}
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct DomainModule<T, const S: usize> {
pub start_to_insert: T,
pub insert_to_insert: T,
pub insert_to_end: T,
pub start_to_end: T,
pub background_emission: EmissionParams<T, S>,
}
impl<T: PhmmNumber, const S: usize> DomainModule<T, S> {
pub(crate) fn precompute_begin_mod<Q: AsRef<[u8]>>(
&self, seq: Q, mapping: &ByteIndexMap<S>,
) -> PrecomputedDomainModule<T, S> {
let seq = seq.as_ref();
let mut domain_params = vec![self.start_to_insert + self.insert_to_end; seq.len() + 1];
domain_params[0] = self.start_to_end;
let mut emissions_sum = T::ZERO;
for (i, x_idx) in seq.iter().map(|x| mapping.to_index(*x)).enumerate() {
emissions_sum += self.background_emission[x_idx];
let insert_to_insert = if i > 0 {
T::cast_from(i) * self.insert_to_insert
} else {
T::ZERO
};
domain_params[i + 1] += emissions_sum + insert_to_insert;
}
PrecomputedDomainModule(domain_params)
}
pub(crate) fn precompute_end_mod<Q: AsRef<[u8]>>(
&self, seq: Q, mapping: &ByteIndexMap<S>,
) -> PrecomputedDomainModule<T, S> {
let seq = seq.as_ref();
let mut domain_params = vec![self.start_to_insert + self.insert_to_end; seq.len() + 1];
domain_params[seq.len()] = self.start_to_end;
let mut emissions_sum = T::ZERO;
for (i, x_idx) in seq.iter().rev().map(|x| mapping.to_index(*x)).enumerate() {
emissions_sum += self.background_emission[x_idx];
let insert_to_insert = if i > 0 {
T::cast_from(i) * self.insert_to_insert
} else {
T::ZERO
};
domain_params[seq.len() - i - 1] += emissions_sum + insert_to_insert;
}
PrecomputedDomainModule(domain_params)
}
}
pub(crate) struct PrecomputedDomainModule<T, const S: usize>(pub(crate) Vec<T>);
impl<T: Copy, const S: usize> PrecomputedDomainModule<T, S> {
pub(crate) fn get_score(&self, i: impl QueryIndex) -> T {
self.0[self.get_dp_index(i)]
}
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct LocalModule<T, const S: usize> {
pub semilocal_params: SemiLocalModule<T>,
pub domain_params: DomainModule<T, S>,
}
impl<T: PhmmNumber, const S: usize> LocalModule<T, S> {
#[inline]
#[must_use]
pub(crate) fn no_penalty(core: &CorePhmm<T, S>, background_emission: EmissionParams<T, S>) -> Self {
Self {
semilocal_params: SemiLocalModule::no_penalty(core),
domain_params: DomainModule::no_penalty(background_emission),
}
}
}
pub(crate) struct PrecomputedLocalModule<'a, T, const S: usize> {
pub(crate) semilocal_params: &'a SemiLocalModule<T>,
pub(crate) domain_params: PrecomputedDomainModule<T, S>,
}
impl<T: PhmmNumber, const S: usize> LocalModule<T, S> {
pub(crate) fn precompute_begin_mod<Q: AsRef<[u8]>>(
&self, seq: Q, mapping: &ByteIndexMap<S>,
) -> PrecomputedLocalModule<'_, T, S> {
PrecomputedLocalModule {
domain_params: self.domain_params.precompute_begin_mod(seq, mapping),
semilocal_params: &self.semilocal_params,
}
}
pub(crate) fn precompute_end_mod<Q: AsRef<[u8]>>(
&self, seq: Q, mapping: &ByteIndexMap<S>,
) -> PrecomputedLocalModule<'_, T, S> {
PrecomputedLocalModule {
domain_params: self.domain_params.precompute_end_mod(seq, mapping),
semilocal_params: &self.semilocal_params,
}
}
}
impl<T: PhmmNumber, const S: usize> PrecomputedLocalModule<'_, T, S> {
pub(crate) fn get_score(&self, i: impl QueryIndex, j: impl PhmmIndex) -> T {
self.domain_params.get_score(i) + self.semilocal_params.get_score(j)
}
}
impl<T: PhmmNumber, const S: usize> DomainModule<T, S> {
#[inline]
#[must_use]
pub fn no_penalty(background_emission: EmissionParams<T, S>) -> Self {
Self {
start_to_insert: T::ZERO,
insert_to_insert: T::ZERO,
insert_to_end: T::ZERO,
start_to_end: T::ZERO,
background_emission,
}
}
}
#[allow(dead_code)]
pub(crate) trait SemiLocalParams<T> {
#[must_use]
fn semilocal_params(&self) -> &SemiLocalModule<T>;
}
impl<T> SemiLocalParams<T> for SemiLocalModule<T> {
fn semilocal_params(&self) -> &SemiLocalModule<T> {
self
}
}
impl<T, const S: usize> SemiLocalParams<T> for LocalModule<T, S> {
fn semilocal_params(&self) -> &SemiLocalModule<T> {
&self.semilocal_params
}
}
#[allow(dead_code)]
pub(crate) trait DomainParams<T, const S: usize> {
#[must_use]
fn domain_params(&self) -> &DomainModule<T, S>;
}
impl<T, const S: usize> DomainParams<T, S> for DomainModule<T, S> {
fn domain_params(&self) -> &DomainModule<T, S> {
self
}
}
impl<T, const S: usize> DomainParams<T, S> for LocalModule<T, S> {
fn domain_params(&self) -> &DomainModule<T, S> {
&self.domain_params
}
}