This commit is contained in:
lda committed 2025-01-23 16:53:29 +07:00
1 parent 055d3331ce
commit 3cdaa58c4f
5 files changed
+425 -56

No files matched your search

+2
View File
@@ -4,3 +4,5 @@ version = "0.0.1"
edition = "2021"
[dependencies]
lda_ansi = { version = "0.0.1", path = "../lda_ansi" }
+1 -2
View File
@@ -92,6 +92,7 @@ impl DB {
Some(return_value)
}
/// Retrieves the value at a given index.
///
/**
get you know get it like its a traditional long ass vec
@@ -102,12 +103,10 @@ impl DB {
DB::vec(dp).get(ind as usize);
# }
# fn main() {
let c = [0, 1, 1, 2, 3, 3, 3, 4, 4].to_vec();
let dp = DB::try_from_vec(c.clone()).expect("source vector with wrong form");
let ind = 5;
assert_eq!(DB::vec(&dp).get(ind as usize).cloned(), dp.get(ind));
# }
```
*/
pub fn get(&self, ind: u32) -> Option<u32> {
+104 -3
View File
@@ -105,8 +105,77 @@ pub fn lcs_gen_ms(str1: &str, str2: &str) -> Result<Vec<MonotonicSequence>, belp
}
#[allow(unused)]
pub fn lcs_traceback_vec(str1: &str, str2: &str, dp: Vec<Vec<u32>>) {
todo!()
pub fn lcs_traceback_vec(str1: &str, str2: &str, dp: &Vec<Vec<u32>>) -> Vec<String> {
/* function backtrackAll(C[0..m,0..n], X[1..m], Y[1..n], i, j)
if i = 0 or j = 0
return {""}
if X[i] = Y[j]
return {Z + X[i] for all Z in backtrackAll(C, X, Y, i-1, j-1)}
R := {}
if C[i,j-1] ≥ C[i-1,j]
R := backtrackAll(C, X, Y, i, j-1)
if C[i-1,j] ≥ C[i,j-1]
R := R ∪ backtrackAll(C, X, Y, i-1, j)
return R
*/
let c1: Vec<char> = str1.chars().collect();
let c2: Vec<char> = str2.chars().collect();
use std::collections::HashSet;
fn backtrack_all(
dp: &Vec<Vec<u32>>,
c1: &Vec<char>,
c2: &Vec<char>,
i: usize,
j: usize,
) -> HashSet<String> {
if i == 0 || j == 0 {
return HashSet::from(["".into()]);
}
if c1[i - 1] == c2[j - 1] {
let mut s: Vec<String> = backtrack_all(dp, c1, c2, i - 1, j - 1)
.into_iter()
.collect();
s.iter_mut().for_each(|f| f.push(c1[i - 1]));
return (HashSet::from_iter(s));
};
let mut w = HashSet::new();
if dp[i][j - 1] >= dp[i - 1][j] {
w.extend(backtrack_all(dp, c1, c2, i, j - 1));
}
if dp[i][j - 1] < dp[i - 1][j] {
w.extend(backtrack_all(dp, c1, c2, i - 1, j));
}
(w)
}
backtrack_all(dp, &c1, &c2, dp.len() - 1, dp[0].len() - 1)
.into_iter()
.collect()
}
pub fn lcs_traceback_funny(str1: &str, str2: &str, dp: &[Vec<u32>]) -> String {
let c1: Vec<char> = str1.chars().collect();
let _c2: Vec<char> = str2.chars().collect();
let (mut i, mut j) = (dp.len() - 1, dp[0].len() - 1);
let mut indices = vec![];
while dp[i][j] > 0 {
// up
while dp[i][j] == dp[i - 1][j] {
i -= 1;
}
//over
while dp[i][j] == dp[i][j - 1] {
j -= 1;
}
// this
indices.push(i); // c1
// cross
i -= 1;
j -= 1;
// way easier when i understand it
}
indices.into_iter().rev().map(|c| c1[c]).collect()
}
#[cfg(test)]
@@ -114,17 +183,42 @@ mod test {
// use crate::common_subsequence::{db2::DB as DB2, lcs_gen_dbai};
use crate::common_subsequence::{lcs_traceback_funny, lcs_traceback_vec};
use super::{lcs_gen_ms, monotonic_sequence::MonotonicSequence};
use super::{lcs_gen, lcs_gen_db, DB};
#[test]
fn test_normal_case() {
lcs_gen("asjhdgasdhj", "gajhdgashjd");
// use crate::wrapper_::StrDisplay;
let str1 = "qesadfghsjwergwse";
let str2 = "kufygkjhsvgsbvjhsawsfwaf";
// let (str1, str2) = ("XMJYAUZ", "MZJAWXU");
let d = lcs_gen(str1, str2);
// println!(" {c}", c = StrDisplay(str2));
// (" ".chars().chain(str1.chars()))
// .zip(d.iter())
// .for_each(|(c, v)| println!("{v:?} {c}"));
let ww = lcs_traceback_vec(str1, str2, &d);
// _ww.iter().for_each(|c|println!("{c}"));
// lcs_gen("", "");
let one = lcs_traceback_funny(str1, str2, &d);
dbg!(dbg!(&ww).contains(dbg!(&one)));
use crate::wrapper_::{ColoredInsanelySpecific, InsanelySpecific};
println!(
"{}",
ColoredInsanelySpecific(InsanelySpecific {
c1: &str1.chars().collect(),
c2: &str2.chars().collect(),
dp: &d,
})
)
}
#[test]
fn time() {
println!("asdas");
use std::time::Instant;
{
let start = Instant::now();
@@ -157,6 +251,13 @@ mod test {
// success to me
// ABSOLUTE FAILURE
{
let start = Instant::now();
test_normal_case();
let duration = start.elapsed();
println!("for test_normal_case is: {:?}", duration);
}
}
#[test]
+232 -51
View File
@@ -1,7 +1,7 @@
//! claude cooked
//! most of code is me
use std::ops::Range;
use std::{collections::VecDeque, ops::Range};
#[derive(Default, Debug, Clone, PartialEq)]
pub struct MonotonicSequence {
@@ -60,12 +60,10 @@ impl MonotonicSequence {
# use lda_strdist::common_subsequence::monotonic_sequence::MonotonicSequence;
# let ms = MonotonicSequence::try_from_vec(&[0,0,0,1,1,1,2,2,3,3,4,4,4]).unwrap();
# let (pos, val) = ms.jumps()[3];
let at = ms.get_jump_index(pos);
debug_assert_eq!(ms.jumps()[at].0, pos);
let at = ms.find_jump_index(val).unwrap();
debug_assert_eq!(ms.jumps()[at].1, val);
``` */
// notice that this thing gives 0 shit about self.length
pub fn get_jump_index(&self, pos: usize) -> usize {
match self.jumps.binary_search_by(|(jump_point, _value)| {
// if *jump_point <= pos {
@@ -89,7 +87,6 @@ impl MonotonicSequence {
/// Get value at position
///
/// this would return none if pos >= self.len()
///
pub fn get(&self, pos: usize) -> Option<u32> {
// check for bounds
if pos >= self.length {
@@ -174,7 +171,7 @@ impl MonotonicSequence {
}
// if bigger to big if smaller too small
/// manual use only
pub fn can_set_mini(
fn can_set_mini(
pos: usize,
new_value: u32,
(current_min, current_max): (u32, u32),
@@ -196,6 +193,12 @@ impl MonotonicSequence {
};
Ok(())
}
pub fn can_set_3(&self, pos: usize, new_value: u32) -> Result<(), SequenceError> {
let minmax = self.can_set(pos, new_value)?;
Self::can_set_mini(pos, new_value, minmax)
}
/// Change value at position
pub fn set(&mut self, pos: usize, value: u32) -> Result<(), SequenceError> {
let (min, max) = /*dbg!*/self.can_set(pos, value)?; // already checked for bounds here
@@ -217,13 +220,13 @@ impl MonotonicSequence {
// THE jump index from get_jump_index
if value == min {
assert_eq!(current_value, max); // solid logic
let at = self.get_jump_index(pos);
debug_assert_eq!(self.jumps[at].0, pos);
let at = self.find_jump_index(current_value).unwrap(); // because current value is in it
#[cfg(debug_assertions)]
{
let at2 = self.find_jump_index(current_value).unwrap(); // because current value is in it
assert_eq!(at2, at);
debug_assert_eq!(self.jumps[at2].1, current_value);
let at1 = self.get_jump_index(pos);
assert_eq!(at1, at);
debug_assert_eq!(self.jumps[at1].0, pos);
debug_assert_eq!(self.jumps[at].1, current_value);
}
// TODO: pos misuse?
let (ind, _ /*val*/) = self.jumps.get_mut(at).unwrap(); // pos here is valid. already checked bounds
@@ -256,13 +259,13 @@ impl MonotonicSequence {
};
// TODO: pos misuse?
let at = self.get_jump_index(pos + 1); // should land at
debug_assert_eq!(self.jumps[at].0, pos + 1);
let at = self.find_jump_index(value).unwrap(); // because current value is in it
#[cfg(debug_assertions)]
{
let at2 = self.find_jump_index(value).unwrap(); // because current value is in it
assert_eq!(at2, at);
debug_assert_eq!(self.jumps[at2].1, value);
let at1 = self.get_jump_index(pos + 1); // should land at
assert_eq!(at1, at);
debug_assert_eq!(self.jumps[at1].0, pos + 1);
debug_assert_eq!(self.jumps[at].1, value);
}
let (index, _val) = /*dbg!*/self.jumps.get_mut(at).unwrap();
@@ -277,10 +280,14 @@ impl MonotonicSequence {
*index -= 1;
if *index == 0 {
let val = *_val; // wow rust is cool guys
let removed = self.jumps.remove(0);
debug_assert_eq!(val - 1, current_value);
assert_eq!(removed, (0, val - 1));
#[cfg(debug_assertions)]
let _val = *_val; // wow rust is cool guys
let _removed = self.jumps.remove(0);
#[cfg(debug_assertions)]
{
debug_assert_eq!(_val - 1, current_value);
assert_eq!(_removed, (0, _val - 1));
}
}
}
@@ -384,21 +391,8 @@ impl MonotonicSequence {
}; // always 1 behind => lagging
let mut jumps = vec![(0, lagging_value)];
vec.iter().enumerate().skip(1).try_for_each(|(ind, &val)| {
// if val > lagging_value + 1 {
// return Err(SequenceError::ValueTooHigh {
// pos: ind,
// attempted: val,
// max_allowed: lagging_value + 1,
// });
// } else if val < lagging_value {
// return Err(SequenceError::ValueTooLow {
// pos: ind,
// attempted: val,
// min_allowed: lagging_value,
// });
// } else
Self::can_set_mini(ind, val, (lagging_value, lagging_value + 1))?;
if val == lagging_value + 1 {
jumps.push((ind, val));
}
@@ -417,15 +411,19 @@ impl MonotonicSequence {
let len = self.get_jump_index(pos) + 1;
self.jumps.truncate(len);
}
pub fn flatten_before(&mut self, pos: usize) {
/// push something at 0 or self.validate() will fail
fn cut_b4(&mut self, pos: usize) {
let len = self.get_jump_index(pos);
// let r = self.jumps[len..].to_vec();
self.jumps.rotate_left(len); // damn they figured it
// self.jumps.copy_within(len.., 0);
self.jumps.rotate_left(/*dbg!*/ len); // damn they figured it
// self.jumps.copy_within(len.., 0);
self.jumps.truncate(self.jumps.len() - len);
// assert_eq!(r, self.jumps, "rotate tricks failed");
}
pub fn flatten_before(&mut self, pos: usize) {
self.cut_b4(pos);
if let Some((ind, _)) = self.jumps.first_mut() {
*ind = 0;
}
@@ -456,12 +454,44 @@ impl MonotonicSequence {
self.truncate(new_size);
}
}
/// get a copy
pub fn jumps(&self) -> Vec<(usize, u32)> {
self.jumps.to_vec()
}
pub fn destroy(self) -> (Vec<(usize, u32)>, usize) {
(self.jumps, self.length)
}
/// rebuild
pub fn revive(jumps: Vec<(usize, u32)>, length: usize) -> Option<Self> {
let r = Self { jumps, length };
if r.validate() {
Some(r)
} else {
None
}
}
// set after
/// if pos is too big do nothing
/// if pos == 0 you would rather self::with(val, self.len())
pub fn propagate_to_end(&mut self, pos: usize, val: u32) -> Result<(), SequenceError> {
let len = self.len();
if len == 0 {
return Err(SequenceError::OutOfBounds { pos, length: len });
}
if pos == 0 {
self.jumps.truncate(1);
if let Some((_0, c)) = self.jumps.first_mut() {
debug_assert_eq!(*_0, 0);
*c = val;
}
return Ok(());
}
let Some(cur) = self.get(pos - 1) else {
// pos - 1 is too big for bro
return Ok(());
};
Self::can_set_mini(pos, val, (cur, cur + 1))?;
@@ -469,29 +499,73 @@ impl MonotonicSequence {
if val == cur + 1 {
self.jumps.push((pos, val));
}
self.length = len;
// self.length = len;
Ok(())
}
/// DESTRUCTIVE: if pos too big basically wipe
/// pos is kept, anything before pos is val if suitable
pub fn set_before(&mut self, pos: usize, val: u32) -> Result<(), SequenceError> {
let len = self.len();
if len == 0 {
return Err(SequenceError::OutOfBounds { pos, length: len });
}
if pos == 0 {
return Ok(());
}
let Some(cur) = self.get(pos) else {
self.jumps.truncate(1);
if let Some((_0, c)) = self.jumps.first_mut() {
debug_assert_eq!(*_0, 0);
*c = val;
}
return Ok(());
};
Self::can_set_mini(pos, val, (cur - 1, cur))?;
self.cut_b4(pos);
if let Some((curind, _curval)) = self.jumps.first_mut() {
debug_assert_eq!(*_curval, cur);
*curind = if val == cur {
0
} else if val + 1 == cur {
pos
} else {
unreachable!()
};
}
if val + 1 == cur {
self.jumps.insert(0, (0, val));
}
Ok(())
}
pub fn first_occurence_of(&self, value: u32) -> Option<usize> {
Some(self.jumps.get(self.find_jump_index(value)?)?.0)
}
// inspired by range2
// find from value is inherently easier than find from pos
/// use this over [get_jump_index](MonotonicSequence::get_jump_index) if can
///if plug Some(at) in `self.jumps[at].1` you get value back,
/// else is because theres no such value
///
/** ```
# use lda_strdist::common_subsequence::monotonic_sequence::MonotonicSequence;
# let ms = MonotonicSequence::try_from_vec(&[0,0,0,1,1,1,2,2,3,3,4,4,4]).unwrap();
# let (pos, val) = ms.jumps()[3];
let at = ms.get_jump_index(pos);
debug_assert_eq!(ms.jumps()[at].0, pos);
let at = ms.find_jump_index(val).unwrap();
debug_assert_eq!(ms.jumps()[at].1, val);
``` */
/// use this over [`get_jump_index`](MonotonicSequence::get_jump_index) if can
///
/// ```
/// # use lda_strdist::common_subsequence::monotonic_sequence::MonotonicSequence;
/// # let ms = MonotonicSequence::try_from_vec(&[0,0,0,1,1,1,2,2,3,3,4,4,4]).unwrap();
/// # let (pos, val) = ms.jumps()[3];
/// let at = ms.find_jump_index(val).unwrap();
/// debug_assert_eq!(ms.jumps()[at].1, val);
/// ```
// where is the run doctest TF
pub fn find_jump_index(&self, value: u32) -> Option<usize> {
if self.is_empty() {
return None;
};
debug_assert!(self.validate());
assert!(self.validate());
let jump_index = (value - self.first().unwrap()) as usize;
// {
// let &(_p, _v) = self.jumps.get(jump_index)?;
@@ -545,6 +619,68 @@ impl MonotonicSequence {
// },
}
}
/// iter returns an iter idk
/// equal to self.[into_iter](#method.into_iter)
pub fn iter(&self) -> MonotonicIter {
self.into_iter()
}
}
#[derive(Debug)]
pub struct MonotonicIter {
/// hey dont be stupid
pub dis: VecDeque<(usize, u32)>,
}
impl DoubleEndedIterator for MonotonicIter {
fn next_back(&mut self) -> Option<Self::Item> {
let (f_, v) = self.dis.back_mut()?;
let v = *v;
*f_ -= 1;
if *f_ == 0 {
self.dis.pop_back();
// return Some(self.dis.back()?.1);
}
Some(v)
}
}
impl Iterator for MonotonicIter {
type Item = u32;
// hit it from the front
fn next(&mut self) -> Option<Self::Item> {
let (f_, v)= self.dis.front_mut()?;
let v = *v;
*f_ -= 1;
if *f_ == 0 {
self.dis.pop_front();
// return Some(self.dis.front()?.1);
}
Some(v)
}
}
impl IntoIterator for &MonotonicSequence {
type IntoIter = MonotonicIter;
type Item = u32;
// hehe
fn into_iter(self) -> Self::IntoIter {
let dis: Vec<(usize, u32)> = self
.jumps()
.into_iter()
.chain([(self.length, 42)])
.collect();
let dis = dis
.windows(2)
.map(|w| {
let &[(f, v), (s, _)] = w else { unreachable!() };
debug_assert!(s > f);
(s - f, v)
})
.collect();
Self::IntoIter { dis }
}
}
// ai gen testcases: not quite sure because short + not updated with new methods
@@ -571,6 +707,8 @@ mod tests {
assert_eq!(seq.get(6), None);
assert_eq!(seq.to_vec(), vec![0, 0, 1, 1, 2, 2]);
println!("{seq:?}");
assert!(seq.validate())
}
#[test]
@@ -591,6 +729,8 @@ mod tests {
// Can't create invalid sequence
assert!(seq.set(3, 0).is_err());
println!("{seq:?}");
assert!(seq.validate())
}
#[test]
@@ -607,6 +747,10 @@ mod tests {
seq.set(1, 1).unwrap();
assert_eq!(seq.to_vec(), vec![0, 1, 1, 1, 2, 2]);
println!("{sec:?}");
assert!(sec.validate());
println!("{seq:?}");
assert!(seq.validate())
}
#[test]
fn test_basic_sequence() {
@@ -622,6 +766,11 @@ mod tests {
seq.set(4, 2).unwrap();
seq.extend(6);
assert_eq!(seq.to_vec(), vec![0, 0, 1, 1, 2, 2]);
seq.extend(10);
seq.propagate_to_end(8, 3).unwrap();
println!("{seq:?}, {tovec:?}", tovec = seq.to_vec());
assert!(seq.validate())
}
#[test]
fn test_edge_cases() {
@@ -639,6 +788,8 @@ mod tests {
seq.set(1, 5),
Err(SequenceError::ValueTooHigh { .. })
));
println!("{seq:?}");
assert!(seq.validate())
}
#[test]
fn test_push_pop() {
@@ -650,6 +801,7 @@ mod tests {
assert_eq!(seq.pop(), Some(1));
assert_eq!(seq.pop(), Some(1));
assert_eq!(seq.to_vec(), vec![0]);
assert!(seq.validate())
}
#[test]
fn test_flatten_after() {
@@ -658,8 +810,10 @@ mod tests {
seq.propagate_to_end(4, 2).unwrap();
assert_eq!(seq.to_vec(), vec![0, 0, 1, 1, 2, 2]);
seq.flatten_after(3);
seq.flatten_after(2);
assert_eq!(seq.to_vec(), vec![0, 0, 1, 1, 1, 1]);
println!("{seq:?}");
assert!(seq.validate())
}
#[test]
fn test_flatten_before() {
@@ -670,6 +824,9 @@ mod tests {
seq.flatten_before(3);
assert_eq!(seq.to_vec(), vec![1, 1, 1, 1, 2, 2]);
println!("{seq:?}");
assert!(seq.validate())
}
#[test]
@@ -677,6 +834,7 @@ mod tests {
// Valid sequence
let v = vec![0, 0, 1, 1, 2, 2];
let seq = MonotonicSequence::try_from_vec(&v).unwrap();
println!("{seq:?}");
assert_eq!(seq.to_vec(), v);
// Invalid jumps
@@ -685,11 +843,34 @@ mod tests {
MonotonicSequence::try_from_vec(&v),
Err(SequenceError::ValueTooHigh { .. })
));
assert!(seq.validate())
}
#[test]
fn absolute_devastation() {
let c = [0, 0, 0, 1, 1, 1, 2, 2, 2, 3];
let mut db = MonotonicSequence::try_from_vec(&c).unwrap();
assert!(db.propagate_to_end(3, 2).is_err());
assert!(db.set_before(6, 2).is_ok());
println!("{db:?}");
assert!(db.validate())
}
#[test]
fn iter() {
let c = [
0, 0, 0, 0, 1, 1, 2, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 8, 9, 9, 10, 11, 12, 13,
14, 15, 16,
];
let m = MonotonicSequence::try_from_vec(&c).unwrap();
println!("{m:?}");
let mut c = c.into_iter();
let mut m = m.into_iter();
println!("{m:?}");
for f in 0..35 {
let a = c.next();
let b = m.next();
assert_eq!(a, b, "{f}: {a:?} != {b:?}");
}
}
}
+86
View File
@@ -1,3 +1,5 @@
use std::fmt::Display;
use crate::levenshtein::EditOperation;
pub struct EditOperationVec<'e>(pub &'e Vec<EditOperation>);
@@ -53,3 +55,87 @@ impl std::fmt::Display for CostOperationVec<'_> {
Ok(())
}
}
pub struct StrDisplay<'e>(pub &'e str);
impl Display for StrDisplay<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[")?;
for (c, i) in self.0.chars().enumerate() {
if c != 0 {
write!(f, ", ")?;
}
write!(f, "{i}")?;
}
write!(f, "]")
}
}
pub struct InsanelySpecific<'e> {
pub c1: &'e Vec<char>,
pub c2: &'e Vec<char>,
pub dp: &'e Vec<Vec<u32>>,
}
pub struct ColoredInsanelySpecific<'e>(pub InsanelySpecific<'e>);
impl Display for InsanelySpecific<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, " ")?;
self.c2.iter().try_for_each(|c| write!(f, " {c}"))?;
writeln!(f)?;
self.dp.iter().zip(self.c1.iter()).try_for_each(|(v, c)| {
v.iter().try_for_each(|g| write!(f, "{g} "))?;
writeln!(f, "{c}")
})
}
}
impl Display for ColoredInsanelySpecific<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = &self.0;
write!(f, "-")?;
for i in s.c2 {
write!(f, " {i}")?;
}
writeln!(f)?;
use lda_ansi::ansi_backbone::Style as StyleConstruct;
use lda_ansi::ansi_colors_2::ansi_color_interface::ColorContext;
use lda_ansi::ansi_colors_2::Color;
use lda_ansi::ansi_colors_2::CustomColor;
use lda_ansi::ansi_styles::Style;
// use lda_ansi::AnsiStyles;
let hl = StyleConstruct::new().color(Color::Green.fg()).to_owned();
// let hl = AnsiStyles::new().style(hl);
let dim = StyleConstruct::new()
.color(CustomColor::Color256(236).fg())
.to_owned();
let reset = StyleConstruct::new().style(Style::Reset).to_owned();
// let reset = AnsiStyles::new().style(reset);
let b = s.dp[0][0] as usize;
let mut idfk = vec![b];
for (v, c) in s.dp.iter().zip(['-'].iter().chain(s.c1)) {
write!(f, "{dim}")?;
for (ind, v) in v.iter().enumerate() {
if let Some(old) = idfk.get_mut(*v as usize - b) {
if *old > ind {
write!(f, "{hl}{v}{dim} ")?;
*old = ind;
// continue;
} else {
write!(f, "{v} ")?;
// continue;
}
} else {
write!(f, "{hl}{v}{dim} ")?;
idfk.push(ind);
// continue;
}
}
writeln!(f, "{reset}{c}")?;
}
Ok(())
}
}