Skip to content

Commit 1b3a295

Browse files
authored
Merge pull request #89 from Marwes/less_quadratic
perf: Trim identifical prefix and suffixes for LCS
2 parents 0c49186 + 9544ec9 commit 1b3a295

File tree

1 file changed

+41
-12
lines changed

1 file changed

+41
-12
lines changed

diffus/src/lcs.rs

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,30 @@ impl<T> Edit<T> {
1818
}
1919
}
2020

21-
fn c_matrix<T: Same, I: Iterator<Item = T>, J: Iterator<Item = T>>(
21+
fn c_matrix<T: Same, I, J>(
2222
x: impl Fn() -> I,
2323
y: impl Fn() -> J,
2424
x_len: usize,
2525
y_len: usize,
26-
) -> crate::twodvec::TwoDVec<usize> {
27-
let width = x_len + 1;
28-
let height = y_len + 1;
26+
) -> (usize, crate::twodvec::TwoDVec<usize>, usize)
27+
where
28+
I: DoubleEndedIterator<Item = T>,
29+
J: DoubleEndedIterator<Item = T>,
30+
{
31+
let prefix_eq = x().zip(y()).take_while(|(x, y)| x.same(y)).count();
32+
let suffix_eq = x()
33+
.rev()
34+
.zip(y().rev())
35+
.take_while(|(x, y)| x.same(y))
36+
.count();
37+
38+
let width = x_len.saturating_sub(prefix_eq + suffix_eq) + 1;
39+
let height = y_len.saturating_sub(prefix_eq + suffix_eq) + 1;
2940

3041
let mut c = crate::twodvec::TwoDVec::new(0, width, height);
3142

32-
for (i, x) in x().enumerate() {
33-
for (j, y) in y().enumerate() {
43+
for (i, x) in x().skip(prefix_eq).take(width - 1).enumerate() {
44+
for (j, y) in y().skip(prefix_eq).take(height - 1).enumerate() {
3445
c[j + 1][i + 1] = if x.same(&y) {
3546
c[j][i] + 1
3647
} else {
@@ -39,7 +50,7 @@ fn c_matrix<T: Same, I: Iterator<Item = T>, J: Iterator<Item = T>>(
3950
}
4051
}
4152

42-
c
53+
(prefix_eq, c, suffix_eq)
4354
}
4455

4556
fn lcs_base<T: Same>(
@@ -99,11 +110,29 @@ pub(crate) fn lcs<
99110
x_len: usize,
100111
y_len: usize,
101112
) -> impl Iterator<Item = Edit<T>> {
102-
lcs_base(
103-
c_matrix(|| x(), || y(), x_len, y_len),
104-
itertools::put_back(x().rev()),
105-
itertools::put_back(y().rev()),
106-
)
113+
let (prefix_eq, c, suffix_eq) = c_matrix(&x, &y, x_len, y_len);
114+
115+
x().zip(y())
116+
.take(prefix_eq)
117+
.map(|(x, y)| Edit::Same(x, y))
118+
.chain(lcs_base(
119+
c,
120+
itertools::put_back(
121+
x().rev()
122+
.skip(suffix_eq)
123+
.take(x_len.saturating_sub(prefix_eq + suffix_eq)),
124+
),
125+
itertools::put_back(
126+
y().rev()
127+
.skip(suffix_eq)
128+
.take(y_len.saturating_sub(prefix_eq + suffix_eq)),
129+
),
130+
))
131+
.chain(
132+
x().skip(x_len - suffix_eq)
133+
.zip(y().skip(y_len - suffix_eq))
134+
.map(|(x, y)| Edit::Same(x, y)),
135+
)
107136
}
108137

109138
// FIXME move out from lcs

0 commit comments

Comments
 (0)