Compare commits

..
1 Commits
+35 -15
View File
@@ -1,6 +1,10 @@
//! # Levenshtein Distance
//! 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)]
pub enum EditOperation {
Insert { char: char }, // Insert a character from the target string
@@ -10,9 +14,9 @@ pub enum EditOperation {
}
pub struct EditCost {
pub insert: usize,
pub delete: usize,
pub substitute: usize,
pub insert: i32,
pub delete: i32,
pub substitute: i32,
}
impl Default for EditCost {
@@ -26,7 +30,7 @@ impl Default for EditCost {
}
impl EditCost {
pub fn new(insert: usize, delete: usize, substitute: usize) -> Self {
pub fn new(insert: i32, delete: i32, substitute: i32) -> Self {
EditCost {
insert,
delete,
@@ -34,13 +38,13 @@ impl EditCost {
}
}
}
/// custom cost for each [`EditOperation`]s operation
pub trait CustomCost {
fn cost(&self, operation: &EditOperation) -> usize;
fn cost(&self, operation: &EditOperation) -> i32;
}
impl CustomCost for EditCost {
fn cost(&self, operation: &EditOperation) -> usize {
fn cost(&self, operation: &EditOperation) -> i32 {
match operation {
EditOperation::Insert { .. } => self.insert,
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)]
pub struct CostOperation {
cost: usize,
operation: Option<EditOperation>,
pub cost: i32,
pub operation: Option<EditOperation>,
}
// absolutely phenomenal naming
use std::fmt::Display;
@@ -76,12 +82,14 @@ impl Display for CostOperation {
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(
str1: &str,
str2: &str,
cost_calc: &impl CustomCost,
) -> (usize, Vec<Vec<CostOperation>>) {
) -> (i32, Vec<Vec<CostOperation>>) {
let len1 = str1.len();
let len2 = str2.len();
let mut dp = vec![
@@ -100,7 +108,7 @@ pub fn levenshtein_with_operations(
// Fill the base cases
for i in 0..=len1 {
dp[i][0] = CostOperation {
cost: i,
cost: i as i32,
operation: if i > 0 {
Some(EditOperation::Delete {
char: chars1[i - 1],
@@ -112,7 +120,7 @@ pub fn levenshtein_with_operations(
}
for j in 0..=len2 {
dp[0][j] = CostOperation {
cost: j,
cost: j as i32,
operation: if j > 0 {
Some(EditOperation::Insert {
char: chars2[j - 1],
@@ -167,6 +175,9 @@ pub fn levenshtein_with_operations(
(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> {
let mut i = str1.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
}
/// alignment
/// is ass dont use
pub fn generate_alignment(
str1: &str,
str2: &str,
@@ -246,11 +260,16 @@ pub fn generate_alignment(
(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);
(c, edit_sequence(&d, str1, str2))
}
/// get source str from [`edit_sequence`]
pub fn reconstruct_from(vector: &Vec<EditOperation>) -> String {
let mut funny = String::new();
for operation in vector {
@@ -270,6 +289,7 @@ pub fn reconstruct_from(vector: &Vec<EditOperation>) -> String {
funny
}
/// get changed str from [`edit_sequence`]
pub fn reconstruct_to(vector: &Vec<EditOperation>) -> String {
let mut funny = String::new();
for operation in vector {