leven_distance/
structures.rs

1/// A struct to hold the results of a Levenshtein distance calculation.
2///
3/// This struct contains the Levenshtein distance between two sequences and the sequence of
4/// operations (represented as a matrix of integers) that describe how to transform the first sequence into the second.
5pub struct Results {
6    /// The Levenshtein distance between two sequences.
7    distance: i32,
8    /// The sequence of operations required to transform one sequence into another.
9    /// This is represented as a matrix where each cell contains an operation code.
10    sequence: Vec<Vec<i32>>,
11}
12
13impl Results {
14    pub fn new(distance: i32, sequence: Vec<Vec<i32>>) -> Self {
15        Self { distance, sequence }
16    }
17
18    /// Returns the Levenshtein distance.
19    ///
20    /// This is the minimum number of single-character edits (insertions, deletions, or substitutions)
21    /// required to change one sequence into the other.
22    ///
23    /// # Returns
24    ///
25    /// Returns an `i32` representing the Levenshtein distance.
26    ///
27    /// # Examples
28    ///
29    /// ```
30    /// let results = Results::new(3, vec![vec![0, 1, 2], vec![1, 2, 3]]);
31    /// assert_eq!(results.distance(), 3);
32    /// ```
33    pub fn distance(&self) -> i32 {
34        self.distance
35    }
36
37    /// Returns a reference to the sequence of operations matrix.
38    ///
39    /// Each element in the matrix represents an operation code corresponding to an edit operation.
40    ///
41    /// # Returns
42    ///
43    /// Returns a reference to a `Vec<Vec<i32>>` representing the sequence of operations.
44    ///
45    /// # Examples
46    ///
47    /// ```
48    /// let results = Results::new(3, vec![vec![0, 1, 2], vec![1, 2, 3]]);
49    /// assert_eq!(results.sequence(), &vec![vec![0, 1, 2], vec![1, 2, 3]]);
50    /// ```
51    pub fn sequence(&self) -> &Vec<Vec<i32>> {
52        &self.sequence
53    }
54}
55
56pub struct Position {
57    pub x: i32,
58    pub y: i32,
59}
60
61impl Position {
62    pub fn new(x: i32, y: i32) -> Self {
63        Self { x, y }
64    }
65}
66
67pub struct Costs {
68    pub on_set: i32,
69    pub on_match: i32,
70    pub on_insert: i32,
71    pub on_replace: i32,
72    pub on_delete: i32,
73}
74
75impl Costs {
76    pub fn new() -> Self {
77        Self {
78            on_set: 0,
79            on_match: 0,
80            on_insert: 1,
81            on_replace: 1,
82            on_delete: 1,
83        }
84    }
85
86    pub fn as_slice(&self) -> [i32; 5] {
87        let slice: [i32; 5] = [
88            self.on_set,
89            self.on_match,
90            self.on_insert,
91            self.on_replace,
92            self.on_delete,
93        ];
94        slice
95    }
96}
97
98pub struct Mapping {
99    pub length: (usize, usize),
100    pub sequence: Vec<Vec<i32>>,
101    pub lookup: Vec<Vec<(usize, char)>>,
102}
103
104impl Mapping {
105    fn proc_sequence(seq: &str) -> Vec<char> {
106        std::iter::once('\0').chain(seq.chars()).collect()
107    }
108
109    fn proc_lookup(lookup: &mut Vec<Vec<(usize, char)>>, seq: &Vec<char>) {
110        let mut char_lookup: Vec<(usize, char)> = Vec::with_capacity(seq.len());
111        for (l_index, &letter) in seq.iter().enumerate() {
112            char_lookup.push((l_index, letter));
113        }
114        lookup.push(char_lookup);
115    }
116}
117
118impl Mapping {
119    pub fn new(seq1: &str, seq2: &str) -> Self {
120        let seq1: Vec<char> = Self::proc_sequence(seq1);
121        let seq2: Vec<char> = Self::proc_sequence(seq2);
122        let length: (usize, usize) = (seq1.len(), seq2.len());
123
124        let sequence: Vec<Vec<i32>> = vec![vec![0; length.0]; length.1];
125        let mut lookup: Vec<Vec<(usize, char)>> = Vec::with_capacity(2);
126
127        Self::proc_lookup(&mut lookup, &seq1);
128        Self::proc_lookup(&mut lookup, &seq2);
129
130        Self {
131            length,
132            sequence,
133            lookup,
134        }
135    }
136
137    pub fn distance(&self) -> i32 {
138        let (l1, l2): (usize, usize) = self.length;
139        self.sequence[l2 - 1][l1 - 1]
140    }
141
142    pub fn value(&self, position: &Position) -> i32 {
143        let (x, y) = (position.x, position.y);
144        if x >= 0 && y >= 0 {
145            return self.sequence[y as usize][x as usize];
146        }
147        0
148    }
149
150    pub fn insert_position(&self, x: i32, y: i32) -> Position {
151        if self.length.0 < self.length.1 {
152            return Position::new(x, y - 1);
153        }
154        Position::new(x - 1, y)
155    }
156
157    pub fn replace_position(&self, x: i32, y: i32) -> Position {
158        Position::new(x - 1, y - 1)
159    }
160
161    pub fn delete_position(&self, x: i32, y: i32) -> Position {
162        if self.length.0 < self.length.1 {
163            return Position::new(x - 1, y);
164        }
165        Position::new(x, y - 1)
166    }
167
168    pub fn onset_array(&self) -> [i32; 4] {
169        [0, 0, 0, 0]
170    }
171
172    pub fn match_array(&self, replace: &Position) -> [i32; 4] {
173        let value: i32 = self.value(replace);
174        [replace.x, replace.y, value, 1]
175    }
176
177    pub fn insert_array(&self, insert: &Position) -> [i32; 4] {
178        let value: i32 = self.value(insert);
179        [insert.x, insert.y, value, 2]
180    }
181
182    pub fn replace_array(&self, replace: &Position) -> [i32; 4] {
183        let value: i32 = self.value(replace);
184        [replace.x, replace.y, value, 3]
185    }
186
187    pub fn delete_array(&self, delete: &Position) -> [i32; 4] {
188        let value: i32 = self.value(delete);
189        [delete.x, delete.y, value, 4]
190    }
191}