Skip to content

Commit fc9e6c1

Browse files
committed
fix: IMPOSSIBLE_NB => Option(usize)
1 parent fa18a6b commit fc9e6c1

File tree

1 file changed

+47
-48
lines changed

1 file changed

+47
-48
lines changed

src/string/multiple_longest_common_subsequence.rs

Lines changed: 47 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ use std::cmp::max;
22
use std::cmp::Ordering;
33
use std::collections::HashMap;
44

5-
const IMPOSSIBLE_NB: usize = usize::MAX;
6-
75
// alphabet : the common alphabet
86
// chains : the strings among which the common subsequence is
97
// d : the number of strings
@@ -16,11 +14,11 @@ struct Context {
1614
alphabet: Vec<char>,
1715
chains: Vec<Vec<char>>,
1816
d: usize,
19-
f: HashMap<Vec<usize>, u64>,
20-
g: HashMap<Vec<usize>, u64>,
17+
f: HashMap<Vec<Option<usize>>, u64>,
18+
g: HashMap<Vec<Option<usize>>, u64>,
2119
ms: Vec<Vec<Vec<u64>>>,
22-
mt: Vec<Vec<Vec<usize>>>,
23-
parents: HashMap<Vec<usize>, Option<Vec<usize>>>,
20+
mt: Vec<Vec<Vec<Option<usize>>>>,
21+
parents: HashMap<Vec<Option<usize>>, Option<Vec<Option<usize>>>>,
2422
}
2523

2624
impl Context {
@@ -34,15 +32,15 @@ impl Context {
3432
let ms: Vec<Vec<Vec<u64>>> = matrices_score(&chains);
3533

3634
// an impossible to reach point, father of all points
37-
let p0 = vec![IMPOSSIBLE_NB; d];
35+
let p0 = vec![None; d];
3836

39-
let mut parents: HashMap<_, Option<Vec<usize>>> = HashMap::new();
37+
let mut parents: HashMap<_, Option<Vec<Option<usize>>>> = HashMap::new();
4038
parents.insert(p0.clone(), None);
4139

4240
let mut g = HashMap::new();
4341
g.insert(p0.clone(), 0);
4442

45-
let mut f: HashMap<Vec<usize>, u64> = HashMap::new();
43+
let mut f: HashMap<Vec<Option<usize>>, u64> = HashMap::new();
4644
f.insert(p0, 0);
4745

4846
let mt = mt_table(&chains, &mut alphabet);
@@ -61,7 +59,7 @@ impl Context {
6159

6260
// given a point p and his successor q, computes necessary informations
6361
// point p is marked PARENT of q
64-
pub fn update_suc(&mut self, p: Vec<usize>, q: Vec<usize>) {
62+
pub fn update_suc(&mut self, p: Vec<Option<usize>>, q: Vec<Option<usize>>) {
6563
// g(q) = g(p) + 1
6664
let nb = &self.g[&p] + 1;
6765
self.g.insert(q.clone(), nb);
@@ -82,17 +80,22 @@ impl Context {
8280
///
8381
/// # Returns
8482
/// An array of the successors
85-
pub fn get_successors(&self, p: &[usize]) -> Vec<Vec<usize>> {
86-
let mut successors: Vec<Vec<usize>> = vec![];
83+
pub fn get_successors(&self, p: &[Option<usize>]) -> Vec<Vec<Option<usize>>> {
84+
let mut successors: Vec<Vec<Option<usize>>> = vec![];
8785

8886
// for all alphabet letters
8987
for (ch_idx, _) in self.alphabet.iter().enumerate() {
9088
// for each string, finds the next position of that letter
91-
let mut succ: Vec<usize> = vec![];
89+
let mut succ: Vec<Option<usize>> = vec![];
9290
for (i, p_ith_elt) in p.iter().enumerate().take(self.chains.len()) {
93-
let next_ch_idx = self.mt[ch_idx][i][p_ith_elt + 1];
94-
// in case the letter is not rechable in the string
95-
if next_ch_idx == IMPOSSIBLE_NB {
91+
92+
let next_ch_idx = match p_ith_elt {
93+
Some(idx) => self.mt[ch_idx][i][idx + 1],
94+
None => continue, // Skip if current position is None
95+
};
96+
97+
// in case the letter is not reachable in the string
98+
if next_ch_idx.is_none() {
9699
break;
97100
}
98101

@@ -109,14 +112,17 @@ impl Context {
109112
}
110113

111114
// ascend back up the parent tree to form the common subsequence
112-
fn common_seq(&self, p: &Vec<usize>) -> String {
115+
fn common_seq(&self, p: &Vec<Option<usize>>) -> String {
113116
let ref_str: &Vec<char> = &self.chains[0];
114117
let mut common_subsequence: Vec<char> = vec![];
115118
// Gaining mutability
116119
let mut p = p;
117120

118121
while self.parents[p].is_some() {
119-
common_subsequence.push(ref_str[p[0]]);
122+
// Get the first element of p, which is the position in the first string
123+
if let Some(idx) = p[0] {
124+
common_subsequence.push(ref_str[idx]);
125+
}
120126

121127
// getting the parent of current point
122128
p = self.parents[p].as_ref().unwrap();
@@ -126,16 +132,16 @@ impl Context {
126132
}
127133

128134
/// CF Initqueue
129-
fn get_starting_p(&self) -> Vec<Vec<usize>> {
130-
let mut successors: Vec<Vec<usize>> = vec![];
135+
fn get_starting_p(&self) -> Vec<Vec<Option<usize>>> {
136+
let mut successors: Vec<Vec<Option<usize>>> = vec![];
131137

132138
// for each alphabet letter, finds the next match
133139
// meaning the a point where all strings share a character
134140
// example: In ["AB", "BC", "CB", "BF"],
135141
// A match for the letter B would be p = (1, 0, 1, 0)
136142
for (ch_idx, _) in self.alphabet.iter().enumerate() {
137143
// for each string, finds the next position of that letter
138-
let mut succ: Vec<usize> = vec![];
144+
let mut succ: Vec<Option<usize>> = vec![];
139145
for i in 0..(self.chains.len()) {
140146
// gets the next position of the current letter
141147
let next_ch_idx = self.mt[ch_idx][i][0];
@@ -152,17 +158,20 @@ impl Context {
152158
/// Computes the heuristic function given a point
153159
/// min ( { M_ij[ p[i] ][ p[j] ] | (i,j) in [0 ; d] } )
154160
/// [Documentation](https://github.com/epita-rs/MLCS/blob/main/doc/paper.pdf)
155-
fn heuristic(&self, p: &[usize]) -> u64 {
161+
fn heuristic(&self, p: &[Option<usize>]) -> u64 {
156162
let mut similarity: Vec<u64> = vec![];
157163
for i in 0..self.d {
158164
for j in 0..self.d {
159165
if i != j {
160-
similarity.push(self.ms[to_linear_index(i, j, self.d)][p[i]][p[j]]);
166+
// Skip if either point is None
167+
if let (Some(pi), Some(pj)) = (p[i], p[j]) {
168+
similarity.push(self.ms[to_linear_index(i, j, self.d)][pi][pj]);
169+
}
161170
}
162171
}
163172
}
164173

165-
*similarity.iter().min().unwrap()
174+
similarity.iter().min().copied().unwrap_or(0)
166175
}
167176

168177
/// Add the first matches to the queue
@@ -173,11 +182,11 @@ impl Context {
173182
///
174183
/// * `self' - A structure containing informations
175184
/// * 'queue' - The priority queue of points
176-
fn init_queue(&mut self) -> Vec<Vec<usize>> {
185+
fn init_queue(&mut self) -> Vec<Vec<Option<usize>>> {
177186
let mut queue = self.get_starting_p();
178187

179188
for q in queue.clone() {
180-
self.update_suc(vec![IMPOSSIBLE_NB; self.d], q.clone());
189+
self.update_suc(vec![None; self.d], q.clone());
181190
}
182191

183192
self.reorder_queue(&mut queue);
@@ -186,7 +195,7 @@ impl Context {
186195
}
187196

188197
// sorts the queue
189-
fn reorder_queue(&self, queue: &mut [Vec<usize>]) {
198+
fn reorder_queue(&self, queue: &mut [Vec<Option<usize>>]) {
190199
queue.sort_unstable_by(|p, q| {
191200
if (self.f.get(p) > self.f.get(q))
192201
|| (self.f.get(p) == self.f.get(q) && self.heuristic(p) > self.heuristic(q))
@@ -249,20 +258,20 @@ fn matrices_score(chains: &[Vec<char>]) -> Vec<Vec<Vec<u64>>> {
249258
/// An array of matrices.
250259
/// Each matrix is tied to a string and can indicate, given a letter,
251260
/// the next position of that letter in the string.
252-
fn mt_table(chains: &Vec<Vec<char>>, alphabet: &mut Vec<char>) -> Vec<Vec<Vec<usize>>> {
253-
let mut mt: Vec<Vec<Vec<usize>>> = vec![];
261+
fn mt_table(chains: &Vec<Vec<char>>, alphabet: &mut Vec<char>) -> Vec<Vec<Vec<Option<usize>>>> {
262+
let mut mt: Vec<Vec<Vec<Option<usize>>>> = vec![];
254263

255264
for ch in alphabet.clone() {
256-
let mut chain: Vec<Vec<usize>> = vec![];
265+
let mut chain: Vec<Vec<Option<usize>>> = vec![];
257266

258267
for s in chains {
259-
let mut v: Vec<usize> = vec![IMPOSSIBLE_NB; s.len()];
260-
let mut lpos = IMPOSSIBLE_NB;
268+
let mut v: Vec<Option<usize>> = vec![None; s.len()];
269+
let mut lpos = None;
261270

262271
// iterating backwards on the string
263272
for i in (0..(s.len())).rev() {
264273
if s[i] == ch {
265-
lpos = i;
274+
lpos = Some(i);
266275
}
267276
// pushing the index of the last encounter with the current letter
268277
v[i] = lpos;
@@ -272,7 +281,7 @@ fn mt_table(chains: &Vec<Vec<char>>, alphabet: &mut Vec<char>) -> Vec<Vec<Vec<us
272281

273282
// if the letter was never seen in the current string
274283
// then it can't part of the common alphabet
275-
if lpos == IMPOSSIBLE_NB {
284+
if lpos.is_none() {
276285
// removing that letter
277286
alphabet.retain(|&x| x != ch);
278287
chain = vec![];
@@ -282,16 +291,6 @@ fn mt_table(chains: &Vec<Vec<char>>, alphabet: &mut Vec<char>) -> Vec<Vec<Vec<us
282291

283292
// the letter was seen at leat once
284293
if !chain.is_empty() {
285-
// pushing an array or array
286-
// example on ["AB", "ABAA"]
287-
// string1 => {
288-
// 'A' => {0, IMPOSSIBLE_NB}
289-
// 'B' => {1, 1}
290-
// }
291-
// string2 => {
292-
// 'A' => {0, 2, 2, 3}
293-
// 'B' => {1, 1, IMPOSSIBLE_NB, IMPOSSIBLE_NB}
294-
// }
295294
mt.push(chain);
296295
}
297296
}
@@ -317,7 +316,7 @@ pub fn multiple_longest_common_subsequence(chains: &Vec<&str>) -> String {
317316
let mut ctx = Context::new(chains);
318317

319318
// queue
320-
let mut queue: Vec<Vec<usize>> = ctx.init_queue();
319+
let mut queue: Vec<Vec<Option<usize>>> = ctx.init_queue();
321320

322321
while !queue.is_empty() {
323322
// y = max( {f(p) | p in queue} )
@@ -333,7 +332,7 @@ pub fn multiple_longest_common_subsequence(chains: &Vec<&str>) -> String {
333332
.clone()
334333
.into_iter()
335334
.filter(|p| y <= ctx.f[p])
336-
.collect::<Vec<Vec<usize>>>();
335+
.collect::<Vec<Vec<Option<usize>>>>();
337336
queue.clear();
338337

339338
for p in second_queue {
@@ -432,7 +431,7 @@ mod tests {
432431
"=串-用2于测试2展67中中0xs中中中kkljhkkh示中测🚀测|测文|",
433432
"=串-|用2于ss串试056u展xx🚀示中lj测ggk测|ss文|",
434433
"=串-用2于-测22中中中uyty试串lj展gkks中示🚀测测s|测中文|b",
435-
"=串用2于测s-试2中中0中hgtihlkk展串🚀中示s中|文|",
434+
"=串-用2于测s-试2中中0中hgtihlkk展串🚀中示s中|文|",
436435
"=2串2中2中2中s用-于0t测🚀j试展示测s测hkkkg测中中串文|l",
437436
"=2串2中2中2中s用-于0测🚀试展示测s中k中l串文|",
438437
"=2串2中2中2中s用ur-于0测🚀试展示测jkjljkkllkskg中串文|;",
@@ -489,4 +488,4 @@ mod tests {
489488
),
490489

491490
}
492-
}
491+
}

0 commit comments

Comments
 (0)