minor update to types

This commit is contained in:
lda committed 2025-01-11 23:54:36 +07:00
1 parent 726104fd54
commit 6b24262927
1 file changed
+35 -15
+35 -15
View File
@@ -1,6 +1,10 @@
//! # Levenshtein Distance //! # Levenshtein Distance
//! This is a simple implementation of the Levenshtein distance algorithm with operations. //! This is a simple implementation of the Levenshtein distance algorithm with operations.
/// costs for different edit operations
///
/// each with the letters involved: so you can further tweak the cost in ur own [`CustomCost`]s impl
/// position? idk
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum EditOperation { pub enum EditOperation {
Insert { char: char }, // Insert a character from the target string Insert { char: char }, // Insert a character from the target string
@@ -10,9 +14,9 @@ pub enum EditOperation {
} }
pub struct EditCost { pub struct EditCost {
pub insert: usize, pub insert: i32,
pub delete: usize, pub delete: i32,
pub substitute: usize, pub substitute: i32,
} }
impl Default for EditCost { impl Default for EditCost {
@@ -26,7 +30,7 @@ impl Default for EditCost {
} }
impl EditCost { impl EditCost {
pub fn new(insert: usize, delete: usize, substitute: usize) -> Self { pub fn new(insert: i32, delete: i32, substitute: i32) -> Self {
EditCost { EditCost {
insert, insert,
delete, delete,
@@ -34,13 +38,13 @@ impl EditCost {
} }
} }
} }
/// custom cost for each [`EditOperation`]s operation
pub trait CustomCost { pub trait CustomCost {
fn cost(&self, operation: &EditOperation) -> usize; fn cost(&self, operation: &EditOperation) -> i32;
} }
impl CustomCost for EditCost { impl CustomCost for EditCost {
fn cost(&self, operation: &EditOperation) -> usize { fn cost(&self, operation: &EditOperation) -> i32 {
match operation { match operation {
EditOperation::Insert { .. } => self.insert, EditOperation::Insert { .. } => self.insert,
EditOperation::Delete { .. } => self.delete, EditOperation::Delete { .. } => self.delete,
@@ -49,11 +53,13 @@ impl CustomCost for EditCost {
} }
} }
} }
/// is this the main struct
///
/// cost of operation and the operation itself
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct CostOperation { pub struct CostOperation {
cost: usize, pub cost: i32,
operation: Option<EditOperation>, pub operation: Option<EditOperation>,
} }
// absolutely phenomenal naming // absolutely phenomenal naming
use std::fmt::Display; use std::fmt::Display;
@@ -76,12 +82,14 @@ impl Display for CostOperation {
write!(f, "Cost: {}, Operation: {:#?}", self.cost, self.operation) write!(f, "Cost: {}, Operation: {:#?}", self.cost, self.operation)
} }
} }
/// returns the distance + the dp table for who needs it
///
/// this the slow version yes
pub fn levenshtein_with_operations( pub fn levenshtein_with_operations(
str1: &str, str1: &str,
str2: &str, str2: &str,
cost_calc: &impl CustomCost, cost_calc: &impl CustomCost,
) -> (usize, Vec<Vec<CostOperation>>) { ) -> (i32, Vec<Vec<CostOperation>>) {
let len1 = str1.len(); let len1 = str1.len();
let len2 = str2.len(); let len2 = str2.len();
let mut dp = vec![ let mut dp = vec![
@@ -100,7 +108,7 @@ pub fn levenshtein_with_operations(
// Fill the base cases // Fill the base cases
for i in 0..=len1 { for i in 0..=len1 {
dp[i][0] = CostOperation { dp[i][0] = CostOperation {
cost: i, cost: i as i32,
operation: if i > 0 { operation: if i > 0 {
Some(EditOperation::Delete { Some(EditOperation::Delete {
char: chars1[i - 1], char: chars1[i - 1],
@@ -112,7 +120,7 @@ pub fn levenshtein_with_operations(
} }
for j in 0..=len2 { for j in 0..=len2 {
dp[0][j] = CostOperation { dp[0][j] = CostOperation {
cost: j, cost: j as i32,
operation: if j > 0 { operation: if j > 0 {
Some(EditOperation::Insert { Some(EditOperation::Insert {
char: chars2[j - 1], char: chars2[j - 1],
@@ -167,6 +175,9 @@ pub fn levenshtein_with_operations(
(dp[len1][len2].cost, dp) (dp[len1][len2].cost, dp)
} }
///extract the optimized edit sequence from the dp table
///
/// strs there just for the len() lmfao
pub fn edit_sequence(dp: &[Vec<CostOperation>], str1: &str, str2: &str) -> Vec<EditOperation> { pub fn edit_sequence(dp: &[Vec<CostOperation>], str1: &str, str2: &str) -> Vec<EditOperation> {
let mut i = str1.len(); let mut i = str1.len();
let mut j = str2.len(); let mut j = str2.len();
@@ -199,6 +210,9 @@ pub fn edit_sequence(dp: &[Vec<CostOperation>], str1: &str, str2: &str) -> Vec<E
funny.reverse(); funny.reverse();
funny funny
} }
/// alignment
/// is ass dont use
pub fn generate_alignment( pub fn generate_alignment(
str1: &str, str1: &str,
str2: &str, str2: &str,
@@ -246,11 +260,16 @@ pub fn generate_alignment(
(aligned_str1, aligned_str2) (aligned_str1, aligned_str2)
} }
pub fn levenstein_distance(str1: &str, str2: &str, cost: &EditCost) -> (usize, Vec<EditOperation>) { /// calculate distance, also get u the [`edit_sequence`]
/// use this one
///
/// what this does is call this ass [`levenshtein_with_operations`] and then the [`edit_sequence`] from the generated dp table
pub fn levenstein_distance(str1: &str, str2: &str, cost: &EditCost) -> (i32, Vec<EditOperation>) {
let (c, d) = levenshtein_with_operations(str1, str2, cost); let (c, d) = levenshtein_with_operations(str1, str2, cost);
(c, edit_sequence(&d, str1, str2)) (c, edit_sequence(&d, str1, str2))
} }
/// get source str from [`edit_sequence`]
pub fn reconstruct_from(vector: &Vec<EditOperation>) -> String { pub fn reconstruct_from(vector: &Vec<EditOperation>) -> String {
let mut funny = String::new(); let mut funny = String::new();
for operation in vector { for operation in vector {
@@ -270,6 +289,7 @@ pub fn reconstruct_from(vector: &Vec<EditOperation>) -> String {
funny funny
} }
/// get changed str from [`edit_sequence`]
pub fn reconstruct_to(vector: &Vec<EditOperation>) -> String { pub fn reconstruct_to(vector: &Vec<EditOperation>) -> String {
let mut funny = String::new(); let mut funny = String::new();
for operation in vector { for operation in vector {