use serde::{Deserialize, Serialize};
use crate::I;
pub type Cost = i32;
pub type Score = i32;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "clap", derive(clap::Args))]
pub struct CostModel {
#[cfg_attr(feature = "clap", clap(long, default_value_t = 1, value_name = "COST"))]
pub sub: Cost,
#[cfg_attr(feature = "clap", clap(long, default_value_t = 0, value_name = "COST"))]
pub open: Cost,
#[cfg_attr(feature = "clap", clap(long, default_value_t = 1, value_name = "COST"))]
pub extend: Cost,
}
impl CostModel {
pub fn unit() -> Self {
Self {
sub: 1,
open: 0,
extend: 1,
}
}
pub fn is_unit(&self) -> bool {
self == &Self::unit()
}
pub fn linear(sub: Cost, indel: Cost) -> Self {
Self {
sub,
open: 0,
extend: indel,
}
}
pub fn is_linear(&self) -> bool {
self.open == 0
}
pub fn affine(sub: Cost, open: Cost, extend: Cost) -> Self {
Self { sub, open, extend }
}
pub fn is_affine(&self) -> bool {
self.open > 0
}
pub fn sub(&self) -> Cost {
self.sub
}
pub fn maybe_sub(&self) -> Option<Cost> {
Some(self.sub)
}
pub fn ins(&self, len: I) -> Cost {
self.open + len * self.extend
}
pub fn del(&self, len: I) -> Cost {
self.open + len * self.extend
}
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub struct ScoreModel {
pub r#match: Score,
pub sub: Score,
pub open: Score,
pub extend: Score,
pub factor: i32,
}
impl ScoreModel {
const OFFSET: i32 = 1;
pub fn from_costs(cm: CostModel) -> Self {
let factor;
if cm.sub > 2 && cm.extend > 1 {
factor = 1;
} else if cm.sub == 1 {
factor = 3;
} else {
factor = 2;
}
Self {
r#match: Self::OFFSET * 2,
sub: -cm.sub * factor + Self::OFFSET * 2,
open: -cm.open * factor,
extend: -cm.extend * factor + Self::OFFSET,
factor,
}
}
pub fn global_cost(&self, score: Score, a_len: usize, b_len: usize) -> Cost {
let path_len = (a_len + b_len) as i32;
let s = -score + path_len * Self::OFFSET;
s / self.factor
}
}