am i happy
This commit is contained in:
1 parent
bfc7eab495
commit
39f466c59a
3 files changed
+612
-259
No files matched your search
+203
-258
@@ -2,9 +2,17 @@
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
/// a vec like struct, where everything is ever increasing and not by anything more than one.
|
||||
/// Represents a compressed sequence of monotonically increasing numbers where
|
||||
/// adjacent values can only differ by 0 or 1.
|
||||
///
|
||||
/// so you can have 1, 2, 3, 4, 5 but not 0, 1, 1, 1, 3
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # use lda_strdist::common_subsequence::db::DB;
|
||||
/// let mut db = DB::new();
|
||||
/// db.push(0); // [0]
|
||||
/// db.push(0); // [0, 0]
|
||||
/// db.push(1); // [0, 0, 1]
|
||||
/// ```
|
||||
#[derive(Debug, Default, PartialEq, Clone)]
|
||||
pub struct DB {
|
||||
/// inner starts from index 0 but inner\[0\] is the point where DB::vec is 1
|
||||
@@ -13,80 +21,78 @@ pub struct DB {
|
||||
}
|
||||
|
||||
impl DB {
|
||||
fn verify_increasing(&self) {
|
||||
assert!(
|
||||
matches!(
|
||||
self.inner.iter().try_fold(&u32::MIN, |lastele, current| {
|
||||
if current > lastele {
|
||||
Some(current)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
Some(_)
|
||||
), // what the fuck is this
|
||||
"the inner vec should be ever increasing, which it is not"
|
||||
);
|
||||
/// Validates the `DB` instance.
|
||||
pub fn validate(&self) -> Result<(), String> {
|
||||
if !self.inner.windows(2).all(|w| w[0] < w[1]) {
|
||||
return Err("Inner vector must be strictly increasing".to_string());
|
||||
}
|
||||
if self.inner.last().map_or(false, |&x| x >= self.len) {
|
||||
return Err("Inner values must be less than len".to_string());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn verify_len(&self) {
|
||||
let selflen = self.len();
|
||||
assert!(self.inner.last().unwrap_or(&0) < &selflen
|
||||
&& !self.inner.iter().any(|f| f >= &selflen),
|
||||
|
||||
"the inner vector elements denote at what indexes the DB::vec(&self) vec value jumps up by one, and so any inner elements should not exceed self.len(), which some of them do");
|
||||
}
|
||||
pub fn verify(&self) {
|
||||
self.verify_len();
|
||||
self.verify_increasing();
|
||||
}
|
||||
/// Creates a new `DB` instance.
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// Creates a new `DB` instance with a specified length.
|
||||
pub fn with_len(len: u32) -> Self {
|
||||
Self {
|
||||
len,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
pub fn push(&mut self, val: u32) {
|
||||
/// Adds a value to the sequence.
|
||||
pub fn push(&mut self, val: u32) -> Result<(), String> {
|
||||
let last = self.last().unwrap_or_default();
|
||||
if val == last + 1 {
|
||||
self.inner.push(self.len());
|
||||
self.len += 1;
|
||||
} else if val == last {
|
||||
self.len += 1;
|
||||
} else {
|
||||
panic!("trying value {val} is not equal or one bigger than current last {last}");
|
||||
match val {
|
||||
v if v == last + 1 => {
|
||||
self.inner.push(self.len());
|
||||
self.len += 1;
|
||||
Ok(())
|
||||
}
|
||||
v if v == last => {
|
||||
self.len += 1;
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(format!(
|
||||
"Value {val} is not equal or one bigger than current last {last}"
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the last value in the sequence.
|
||||
fn last(&self) -> Option<u32> {
|
||||
if self.len() > 0 {
|
||||
Some(self.inner.len() as _)
|
||||
if self.len > 0 {
|
||||
Some(self.inner.len() as u32)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn pop(&mut self) -> Option<u32> {
|
||||
let returnvalue = self.last();
|
||||
if let Some(_) = returnvalue {
|
||||
if let Some(bro) = self.inner.last() {
|
||||
if self.len() - bro == 1 {
|
||||
self.inner.pop();
|
||||
} else if self.len() < *bro {
|
||||
panic!("run DB::verify_len(&self) ")
|
||||
}
|
||||
// self.len -= 1;
|
||||
// }
|
||||
// else {
|
||||
}
|
||||
// self.len.checked_sub(1);
|
||||
self.len -= 1
|
||||
}
|
||||
return returnvalue;
|
||||
}
|
||||
|
||||
/// Returns the length of the sequence.
|
||||
fn len(&self) -> u32 {
|
||||
self.len
|
||||
}
|
||||
|
||||
/// Removes the last value from the sequence.
|
||||
pub fn pop(&mut self) -> Option<u32> {
|
||||
let return_value = self.last();
|
||||
if let Some(_) = return_value {
|
||||
if let Some(&last_inner) = self.inner.last() {
|
||||
if self.len - last_inner == 1 {
|
||||
self.inner.pop();
|
||||
} else if self.len < last_inner {
|
||||
panic!("run DB::validate(&self)");
|
||||
}
|
||||
}
|
||||
self.len -= 1;
|
||||
}
|
||||
return_value
|
||||
}
|
||||
/// Retrieves the value at a given index.
|
||||
/**
|
||||
get you know get it like its a traditional long ass vec
|
||||
|
||||
@@ -106,71 +112,58 @@ impl DB {
|
||||
```
|
||||
*/
|
||||
pub fn get(&self, ind: u32) -> Option<u32> {
|
||||
if self.len() <= ind {
|
||||
// panic!("index {ind} >= len {selflen} which is ugly")
|
||||
if self.len <= ind {
|
||||
return None;
|
||||
}
|
||||
(&self.inner)
|
||||
.iter()
|
||||
.rposition(|f| ind >= *f) // imagine got 7 > 4, and 4 is at index 2, so the value of 7 is 2
|
||||
.map(|c| c as u32 + 1) // hack
|
||||
.or(Some(0))
|
||||
Some(
|
||||
self.inner
|
||||
.iter()
|
||||
.rposition(|&f| ind >= f)
|
||||
.map_or(0, |c| c as u32 + 1),
|
||||
)
|
||||
}
|
||||
pub fn range_of(&self, ele: u32) -> Option<Range<u32>> {
|
||||
if ele == 0 {
|
||||
Some(0..*self.inner.get(0).unwrap_or(&self.len()))
|
||||
} else if ele > self.last().unwrap_or_default() {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
*self.inner.get(ele as usize - 1).unwrap_or(&self.len())
|
||||
..*self.inner.get(ele as usize).unwrap_or(&self.len()),
|
||||
)
|
||||
|
||||
/// Returns the range of indices where a value appears.
|
||||
pub fn range_of(&self, value: u32) -> Option<Range<u32>> {
|
||||
if value == 0 {
|
||||
return Some(0..self.inner.first().copied().unwrap_or(self.len));
|
||||
}
|
||||
let value = value as usize;
|
||||
if value > self.inner.len() {
|
||||
return None;
|
||||
}
|
||||
Some(
|
||||
self.inner.get(value - 1).copied().unwrap_or(self.len)
|
||||
..self.inner.get(value).copied().unwrap_or(self.len),
|
||||
)
|
||||
}
|
||||
|
||||
// the same with range of we have
|
||||
|
||||
/// Determines the available values for a given index.
|
||||
///index can be numbers in output.0, and output.1 tell you to select the bigger number at .0.1
|
||||
///
|
||||
/// output: (two numbers that can be, can be the same), (should be the other number; should be appending)
|
||||
/// output: (two numbers that can be, can be the same), (should be the other number; should be appending; is the current number)
|
||||
///
|
||||
/// must check for in len() range by yourself
|
||||
pub fn available_values(&self, ind: u32) -> (Option<[u32; 2]>, Option<bool>) {
|
||||
// let mut last_ind: u32 = 0;
|
||||
for (&cur_ind, cur_val) in // ([0].iter()).chain
|
||||
(self.inner.iter()).chain([self.len()].iter()).zip(1u32..)
|
||||
{
|
||||
// exactly at 3 == 3
|
||||
for (&cur_ind, cur_val) in self.inner.iter().chain([self.len].iter()).zip(1u32..) {
|
||||
if ind == cur_ind {
|
||||
// bug if vec[0] = 0 // no more
|
||||
// if cur_val == 0 {
|
||||
// // at 0 where there is nothing before it
|
||||
// return (Some([0, 0]), None);
|
||||
// } else {
|
||||
// at exactly eg 3, 8, 49, or the end where you can have another
|
||||
// end
|
||||
let choose = if cur_val >= self.inner.len() as _
|
||||
let choose = if cur_val >= self.inner.len() as u32
|
||||
|| cur_ind + 1 < self.inner[cur_val as usize]
|
||||
// not immediate
|
||||
{
|
||||
Some(true)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
return (Some([cur_val - 1, cur_val]), choose);
|
||||
// }
|
||||
} else if ind + 1 == cur_ind {
|
||||
// right before a number you can change the value and it is still ever increasing
|
||||
// not immediate (not sandwiched)
|
||||
// if cur_val - 2 passes then cur_val is not self.inner.len() (??)
|
||||
let choose = if (cur_val - 1)
|
||||
.checked_sub(1)
|
||||
.and_then(|c| self.inner.get(c as usize))
|
||||
.map(|c| *c < ind)
|
||||
.map(|&c| c < ind)
|
||||
.unwrap_or(0 < ind)
|
||||
|| cur_ind == self.len()
|
||||
// end
|
||||
|| cur_ind == self.len
|
||||
{
|
||||
Some(false)
|
||||
} else {
|
||||
@@ -178,30 +171,23 @@ impl DB {
|
||||
};
|
||||
return (Some([cur_val - 1, cur_val]), choose);
|
||||
} else if ind < cur_ind {
|
||||
// at the first instance where cur_ind > ind is where you know we have crossed it
|
||||
// also it passed the == and -1 check.
|
||||
// also it cant be bigger than cur_ind making it the last ind actually
|
||||
// so we use the last val that corresponds
|
||||
return (Some([cur_val - 1, cur_val - 1]), None);
|
||||
}
|
||||
// last_ind = cur_ind;
|
||||
}
|
||||
|
||||
(None, None)
|
||||
}
|
||||
|
||||
// result? change depend on up is not none
|
||||
/// Changes the value at a given index.
|
||||
pub fn change(&mut self, ind: u32, val: u32) {
|
||||
let (avail, up) = self.available_values(ind);
|
||||
if let (Some(avail), Some(up)) = (avail, up) {
|
||||
if val == avail[0] && up {
|
||||
if self.inner.len() == val as _ {
|
||||
if self.inner.len() == val as usize {
|
||||
self.inner.push(ind);
|
||||
} else {
|
||||
self.inner.get_mut(val as usize).map(|e| *e += 1);
|
||||
};
|
||||
// } else if val == avail[0] && !up {
|
||||
// self.inner.get_mut(val as usize).map(|e| *e -= 1);
|
||||
}
|
||||
} else if val == avail[1] && !up {
|
||||
self.inner
|
||||
.get_mut(avail[0] as usize)
|
||||
@@ -211,16 +197,15 @@ impl DB {
|
||||
}
|
||||
}
|
||||
|
||||
/// Propagates a value to the end of the sequence.
|
||||
/// override everything from ind on, that is if ind / val is good
|
||||
pub fn propagate_to_end(&mut self, ind: u32, val: u32) {
|
||||
// println!("idn = {ind}, vala{val}");
|
||||
if ind >= self.len() {
|
||||
panic!("uh oh out of bounds: {ind} >={}", self.len())
|
||||
if ind >= self.len {
|
||||
panic!("uh oh out of bounds: {ind} >= {}", self.len);
|
||||
}
|
||||
if self.len() > 0 {
|
||||
if matches!(self.last(), Some(x) if (x) > 0) {
|
||||
if self.len > 0 {
|
||||
if matches!(self.last(), Some(x) if x > 0) {
|
||||
match self.get(ind) {
|
||||
// what is this fucking logic idk man what the fuck is this code
|
||||
Some(vecv) if vecv == val => {
|
||||
self.inner.truncate(val as usize);
|
||||
}
|
||||
@@ -231,49 +216,48 @@ impl DB {
|
||||
Some(x) if val == x - 1 && self.inner[val as usize] == ind => {
|
||||
self.inner.truncate(val as usize);
|
||||
}
|
||||
None => {
|
||||
unreachable!("len is > 0")
|
||||
}
|
||||
None => unreachable!("len is > 0"),
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
if val == 1 {
|
||||
self.inner.push(ind);
|
||||
}
|
||||
} else if val == 1 {
|
||||
self.inner.push(ind);
|
||||
}
|
||||
// println!("{:?}", self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the compressed sequence back to a full vector.
|
||||
pub fn vec(&self) -> Vec<u32> {
|
||||
let mut count = (0..).into_iter();
|
||||
self.inner
|
||||
.iter()
|
||||
.chain([self.len()].iter())
|
||||
.scan(0u32, |c, f| {
|
||||
let r = Some(vec![count.next().unwrap(); (*f - *c) as usize]);
|
||||
*c = *f;
|
||||
return r;
|
||||
.chain([self.len].iter())
|
||||
.scan(0u32, |c, &f| {
|
||||
let r = Some(vec![count.next().unwrap(); (f - *c) as usize]);
|
||||
*c = f;
|
||||
r
|
||||
})
|
||||
.flatten()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Creates a `DB` instance from a full vector.
|
||||
pub fn try_from_vec(v: Vec<u32>) -> Option<Self> {
|
||||
// let mut count = (0..).into_iter();
|
||||
let len = v.len() as _;
|
||||
let mut inner: Vec<u32> = vec![];
|
||||
let len = v.len() as u32;
|
||||
let mut inner = Vec::new();
|
||||
let mut c = 0u32;
|
||||
for (i, f) in v.iter().enumerate() {
|
||||
if c + 1 == *f {
|
||||
inner.push(i as _);
|
||||
} else if c + 1 < *f || c > *f {
|
||||
for (i, &f) in v.iter().enumerate() {
|
||||
if c + 1 == f {
|
||||
inner.push(i as u32);
|
||||
} else if c + 1 < f || c > f {
|
||||
return None;
|
||||
};
|
||||
c = *f;
|
||||
}
|
||||
c = f;
|
||||
}
|
||||
Some(Self { inner, len })
|
||||
}
|
||||
}
|
||||
|
||||
/// working as intended: i am happy
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::DB;
|
||||
@@ -287,7 +271,7 @@ mod test {
|
||||
inner: ctodb,
|
||||
len: clen,
|
||||
};
|
||||
ctodb.verify();
|
||||
assert!(ctodb.validate().is_ok());
|
||||
assert_eq!(ctodb.vec(), c);
|
||||
}
|
||||
#[test]
|
||||
@@ -352,7 +336,7 @@ mod test {
|
||||
let mut db = DB::new();
|
||||
let mut c = vec![];
|
||||
let mut push = |i| {
|
||||
db.push(i);
|
||||
db.push(i).unwrap();
|
||||
c.push(i);
|
||||
};
|
||||
for _ in 0..6 {
|
||||
@@ -377,17 +361,17 @@ mod test {
|
||||
fn invalid_push() {
|
||||
let mut db = DB::new();
|
||||
// dbg!(&db.inner);
|
||||
db.push(1);
|
||||
db.push(1).unwrap();
|
||||
// dbg!(&db.inner);
|
||||
for _ in 3..=11 {
|
||||
db.push(1)
|
||||
db.push(1).unwrap();
|
||||
}
|
||||
|
||||
// dbg!(&db.inner);
|
||||
// dbg!(db.vec());
|
||||
db.push(2);
|
||||
db.push(2).unwrap();
|
||||
dbg!(db.len() != 0);
|
||||
db.push(4);
|
||||
db.push(4).expect("this is the one");
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
@@ -395,13 +379,13 @@ mod test {
|
||||
let mut db = DB::new();
|
||||
// dbg!(&db.inner);
|
||||
|
||||
db.push(0);
|
||||
db.push(1);
|
||||
db.push(0).unwrap();
|
||||
db.push(1).unwrap();
|
||||
// dbg!(&db.inner);
|
||||
// dbg!(db.vec());
|
||||
db.push(2);
|
||||
db.push(2).unwrap();
|
||||
dbg!(db.len() != 0);
|
||||
db.push(1);
|
||||
db.push(1).expect("this is the one yall");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -541,6 +525,84 @@ mod test {
|
||||
assert_eq!(db, db2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn change_harder() {
|
||||
let mut c = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13];
|
||||
let mut db = DB::try_from_vec(c.clone()).unwrap();
|
||||
let change = |d: &mut DB, c: &mut Vec<u32>, i, v| {
|
||||
d.change(i, v);
|
||||
c[i as usize] = v;
|
||||
};
|
||||
{
|
||||
println!("f: {c:?}");
|
||||
assert_eq!(db, DB::try_from_vec(c.clone()).unwrap());
|
||||
}
|
||||
|
||||
change(&mut db, &mut c, 12, 12);
|
||||
println!("m: {:?}", db);
|
||||
change(&mut db, &mut c, 16, 14);
|
||||
{
|
||||
println!("f: {c:?}");
|
||||
assert_eq!(db, DB::try_from_vec(c.clone()).unwrap());
|
||||
}
|
||||
|
||||
change(&mut db, &mut c, 13, 12);
|
||||
change(&mut db, &mut c, 14, 12);
|
||||
change(&mut db, &mut c, 11, 11);
|
||||
change(&mut db, &mut c, 12, 11);
|
||||
change(&mut db, &mut c, 13, 11);
|
||||
change(&mut db, &mut c, 10, 10);
|
||||
change(&mut db, &mut c, 11, 10);
|
||||
change(&mut db, &mut c, 12, 10);
|
||||
change(&mut db, &mut c, 9, 9);
|
||||
change(&mut db, &mut c, 10, 9);
|
||||
{
|
||||
println!("m: {:?}", db);
|
||||
print!("{c:?}");
|
||||
println!(", {:?}", DB::try_from_vec(c.clone()).unwrap().vec());
|
||||
}
|
||||
change(&mut db, &mut c, 11, 9);
|
||||
change(&mut db, &mut c, 8, 8);
|
||||
change(&mut db, &mut c, 9, 8);
|
||||
change(&mut db, &mut c, 10, 8);
|
||||
change(&mut db, &mut c, 7, 7);
|
||||
change(&mut db, &mut c, 8, 7);
|
||||
// change(&mut db, &mut c, 9, 7);
|
||||
{
|
||||
println!("m: {:?}", db);
|
||||
print!("{c:?}");
|
||||
println!(", {:?}", DB::try_from_vec(c.clone()).unwrap().vec());
|
||||
}
|
||||
change(&mut db, &mut c, 6, 6);
|
||||
change(&mut db, &mut c, 7, 6);
|
||||
// change(&mut db, &mut c, 8, 6);
|
||||
change(&mut db, &mut c, 5, 5);
|
||||
change(&mut db, &mut c, 6, 5);
|
||||
// change(&mut db, &mut c, 7, 5);
|
||||
change(&mut db, &mut c, 4, 4);
|
||||
change(&mut db, &mut c, 5, 4);
|
||||
// change(&mut db, &mut c, 6, 4);
|
||||
change(&mut db, &mut c, 3, 3);
|
||||
change(&mut db, &mut c, 4, 3);
|
||||
// change(&mut db, &mut c, 5, 3);
|
||||
change(&mut db, &mut c, 2, 2);
|
||||
change(&mut db, &mut c, 3, 2);
|
||||
// change(&mut db, &mut c, 4, 2);
|
||||
change(&mut db, &mut c, 1, 1);
|
||||
// change(&mut db, &mut c, 2, 1);
|
||||
// change(&mut db, &mut c, 3, 1);
|
||||
change(&mut db, &mut c, 0, 0);
|
||||
// change(&mut db, &mut c, 1, 0);
|
||||
// change(&mut db, &mut c, 2, 0);
|
||||
{
|
||||
let db2 = DB::try_from_vec(c.clone()).unwrap();
|
||||
println!("e: {c:?}, {:?}", db2.vec());
|
||||
println!("{:?}", db);
|
||||
assert_eq!(db, db2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prop_idk() {
|
||||
let c = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 13];
|
||||
@@ -606,120 +668,3 @@ mod test {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// // [0,0,0,1,1,1,2,2,3] 9
|
||||
// // 0,1,2,3,4,5,6,7,8
|
||||
// // [ 3, 6, 8]
|
||||
// fn change(&mut self, ind: u32, to: u32) {
|
||||
// // change means that the index is valid: 0..self.len(), if anything other than that crash
|
||||
// let Some(vec_ind_plus_one) = self.get(ind) else {
|
||||
// panic!("index not cool")
|
||||
// };
|
||||
// // vec_ind_plus_one is from 1 to self.inner.len(),
|
||||
// // // index is valid
|
||||
// let last_ = self.inner.len() as u32; // last element == last index + 1
|
||||
// assert!(if last_ == 0 {
|
||||
// vec_ind_plus_one == 0
|
||||
// } else {
|
||||
// vec_ind_plus_one <= last_
|
||||
// });
|
||||
// // // panic if to is too big
|
||||
// if to > last_ + 1 {
|
||||
// panic!("pushing something too big: {to} is way big compared to biggest number {last_}")
|
||||
// }
|
||||
// // // to is now ok
|
||||
// assert!(to <= last_ + 1);
|
||||
// // // if vec has 0 size, all cases
|
||||
// if last_ == 0 {
|
||||
// if to == 0 {
|
||||
// return;
|
||||
// } else if to != 1 {
|
||||
// panic!("{to} way bigger than {vec_ind_plus_one} which is not cool")
|
||||
// }
|
||||
|
||||
// // everything is 0, index is valid
|
||||
// self.inner.push(ind);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// assert_ne!(vec_ind_plus_one, 0);
|
||||
// assert_ne!(last_, 0);
|
||||
|
||||
// // vec[vec_ind] is going to be the first number that we care about
|
||||
// let vec_ind = vec_ind_plus_one - 1;
|
||||
// let ind_this = self.inner[vec_ind as usize];
|
||||
// assert!(ind_this <= ind);
|
||||
// let Some(&ind_next) = self.inner.get(vec_ind_plus_one as usize) else {
|
||||
// // ind is in range of ind_this..self.len()
|
||||
// assert_eq!(ind_this, last_);
|
||||
// // if to == vec_ind + 1 {
|
||||
// // // this is the case here
|
||||
// // }
|
||||
// if ind == self.len() - 1 && to == last_ + 1 {
|
||||
// self.inner.push(ind);
|
||||
// return;
|
||||
// }
|
||||
// // if to > last_ + 1 {
|
||||
// // panic!("uh we done this before")
|
||||
// // }
|
||||
// else if to == last_ - 1 && ind_this == ind {
|
||||
// // if let Some(c) = self.inner.last_mut() {
|
||||
// // *c += 1;
|
||||
// // }
|
||||
// // else {
|
||||
// // unreachable!()
|
||||
// // }
|
||||
// // or
|
||||
// self.inner[to as usize] += 1;
|
||||
// return;
|
||||
// } else if !(to == last_ && ind_this < ind) {
|
||||
// panic!("ever increasing vec")
|
||||
// }
|
||||
// return;
|
||||
// };
|
||||
|
||||
// assert!(ind < ind_next);
|
||||
// let ideal_to = vec_ind_plus_one;
|
||||
|
||||
// if to == ideal_to && (ind_this..ind_next).contains(&ind) {
|
||||
// return;
|
||||
// } else if to == ideal_to + 1 && ind == ind_next - 1 {
|
||||
// self.inner[to as usize] -= 1;
|
||||
// return;
|
||||
// } else if ind_this > 0 {
|
||||
// }
|
||||
|
||||
// // // vec is NOT 0 size now
|
||||
// // // let &last_changing_index = self
|
||||
// // // .inner
|
||||
// // // .last()
|
||||
// // // .expect("somehow this panics; self.inner.len() != 0");
|
||||
|
||||
// // // for the range of the last element (DB::vec from first element == last_ to end)
|
||||
|
||||
// // // if ind is strictly bigger than inner.last() and to is equal to last_
|
||||
// // // if ind > last_changing_index && to == last_ {
|
||||
// // // self.inner.push(ind);
|
||||
// // // return;
|
||||
// // // }
|
||||
|
||||
// // //literally the last element
|
||||
|
||||
// // // if to is 0
|
||||
// // // and vec is not 0, so vec[0] has to exist
|
||||
// // if to == 0 {
|
||||
// // // if nothing
|
||||
// // if ind < self.inner[0] {
|
||||
// // return;
|
||||
// // }
|
||||
// // if ind == self.inner[0] {
|
||||
// // self.inner[0] += 1;
|
||||
// // return;
|
||||
// // }
|
||||
// // }
|
||||
// // // if to is not 0,
|
||||
// // else if true {
|
||||
// // }
|
||||
|
||||
// // return;
|
||||
// }
|
||||
@@ -0,0 +1,348 @@
|
||||
use std::{
|
||||
error::Error,
|
||||
fmt::{Debug, Display},
|
||||
ops::Range,
|
||||
};
|
||||
|
||||
/// A compressed representation of a sequence where adjacent values can only be equal
|
||||
/// or increase by 1. For example: [0,0,0,1,1,2,3,3] is valid, but [0,2,1] is not.
|
||||
///
|
||||
/// This is particularly useful for storing dynamic programming rows in algorithms
|
||||
/// like Longest Common Subsequence (LCS) where values can only stay the same or
|
||||
/// increase by 1 between adjacent cells.
|
||||
///
|
||||
/// Internal representation:
|
||||
/// - Instead of storing all values, stores only the indices where values increase
|
||||
/// - For example, [0,0,0,1,1,2] is stored as inner=[3,5] with len=6
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use lda_strdist::common_subsequence::db2::DB; // adjust this
|
||||
///
|
||||
/// let mut db = DB::new();
|
||||
/// db.push(0)?; // [0]
|
||||
/// db.push(0)?; // [0,0]
|
||||
/// db.push(1)?; // [0,0,1]
|
||||
/// assert_eq!(db.get(2), Some(1));
|
||||
/// ```
|
||||
#[derive(Debug, Default, PartialEq, Clone)]
|
||||
pub struct DB {
|
||||
/// Indices where values increase by 1. Must be strictly increasing.
|
||||
inner: Vec<u32>,
|
||||
/// Total length of the sequence
|
||||
len: u32,
|
||||
}
|
||||
|
||||
/// Errors that can occur during DB operations
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum DBError {
|
||||
/// Value violates monotonic property (must be equal to or 1 more than previous)
|
||||
InvalidValue { value: u32, previous: u32 },
|
||||
/// Index out of bounds
|
||||
IndexOutOfBounds { index: u32, len: u32 },
|
||||
/// Invalid internal state (should never happen if invariants are maintained)
|
||||
InvalidState(String),
|
||||
}
|
||||
|
||||
impl Display for DBError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Debug::fmt(&self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for DBError {
|
||||
|
||||
}
|
||||
|
||||
impl DB {
|
||||
/// Creates a new empty DB
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Creates a new DB with specified length, all values 0
|
||||
pub fn with_len(len: u32) -> Self {
|
||||
Self {
|
||||
len,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the length of the sequence
|
||||
pub fn len(&self) -> u32 {
|
||||
self.len
|
||||
}
|
||||
|
||||
/// Returns true if the sequence is empty
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
|
||||
/// Returns the last value in the sequence
|
||||
pub fn last_value(&self) -> Option<u32> {
|
||||
if self.len() == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(self.inner.len() as u32)
|
||||
}
|
||||
}
|
||||
|
||||
/// Validates the internal state of the DB
|
||||
pub fn validate(&self) -> Result<(), DBError> {
|
||||
// Check that inner values are strictly increasing
|
||||
if !self.inner.windows(2).all(|w| w[0] < w[1]) {
|
||||
return Err(DBError::InvalidState(
|
||||
"Inner vector must be strictly increasing".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
// Check that all inner values are less than len
|
||||
if let Some(&max) = self.inner.last() {
|
||||
if max >= self.len {
|
||||
return Err(DBError::InvalidState(
|
||||
"Inner values must be less than len".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Appends a value to the end of the sequence.
|
||||
/// The value must be equal to or one more than the last value.
|
||||
pub fn push(&mut self, val: u32) -> Result<(), DBError> {
|
||||
let last = self.last_value().unwrap_or_default();
|
||||
match val {
|
||||
v if v == last + 1 => {
|
||||
self.inner.push(self.len);
|
||||
self.len += 1;
|
||||
Ok(())
|
||||
}
|
||||
v if v == last => {
|
||||
self.len += 1;
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(DBError::InvalidValue {
|
||||
value: val,
|
||||
previous: last,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes and returns the last value from the sequence
|
||||
pub fn pop(&mut self) -> Option<u32> {
|
||||
if self.len == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let value = self.last_value().unwrap();
|
||||
if let Some(&last_change) = self.inner.last() {
|
||||
if self.len - 1 == last_change {
|
||||
self.inner.pop();
|
||||
}
|
||||
}
|
||||
self.len -= 1;
|
||||
Some(value)
|
||||
}
|
||||
|
||||
/// Gets the value at the specified index
|
||||
pub fn get(&self, index: u32) -> Option<u32> {
|
||||
if index >= self.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(
|
||||
self.inner
|
||||
.iter()
|
||||
.rposition(|&change_idx| index >= change_idx)
|
||||
.map_or(0, |pos| pos as u32 + 1),
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the range of indices where a value appears
|
||||
pub fn range_of(&self, value: u32) -> Option<Range<u32>> {
|
||||
if value == 0 {
|
||||
return Some(0..self.inner.first().copied().unwrap_or(self.len));
|
||||
}
|
||||
|
||||
let value = value as usize;
|
||||
if value > self.inner.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(
|
||||
self.inner.get(value - 1).copied().unwrap_or(self.len)
|
||||
..self.inner.get(value).copied().unwrap_or(self.len),
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the available values that can be set at the given index,
|
||||
/// along with a hint about which value might be preferred
|
||||
pub fn available_values(&self, index: u32) -> Result<(Vec<u32>, Option<u32>), DBError> {
|
||||
if index >= self.len() {
|
||||
return Err(DBError::IndexOutOfBounds {
|
||||
index,
|
||||
len: self.len(),
|
||||
});
|
||||
}
|
||||
|
||||
let current = self.get(index).unwrap();
|
||||
let mut available = vec![current];
|
||||
let mut preferred = None;
|
||||
|
||||
// Can decrease by 1 if:
|
||||
// 1. Not at value 0
|
||||
// 2. Not at the start of a range
|
||||
if current > 0 && !self.inner.contains(&index) {
|
||||
available.push(current - 1);
|
||||
}
|
||||
|
||||
// Can increase by 1 if:
|
||||
// 1. At the end of a range
|
||||
// 2. Not at maximum value
|
||||
if let Some(range) = self.range_of(current) {
|
||||
if index == range.end - 1 && current < self.inner.len() as u32 {
|
||||
available.push(current + 1);
|
||||
preferred = Some(current + 1);
|
||||
}
|
||||
}
|
||||
|
||||
Ok((available, preferred))
|
||||
}
|
||||
|
||||
/// Changes the value at the given index, maintaining monotonicity
|
||||
pub fn change(&mut self, index: u32, value: u32) -> Result<(), DBError> {
|
||||
let (available, _) = self.available_values(index)?;
|
||||
if !available.contains(&value) {
|
||||
return Err(DBError::InvalidValue {
|
||||
value,
|
||||
previous: self.get(index).unwrap(),
|
||||
});
|
||||
}
|
||||
|
||||
// Handle value decrease
|
||||
if let Some(current_range) = self.range_of(self.get(index).unwrap()) {
|
||||
if current_range.start == index {
|
||||
// Remove this breakpoint
|
||||
if let Some(pos) = self.inner.iter().position(|&x| x == index) {
|
||||
self.inner.remove(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle value increase
|
||||
if let Some(new_range) = self.range_of(value) {
|
||||
if new_range.end == index {
|
||||
self.inner.push(index);
|
||||
self.inner.sort_unstable(); // Maintain sorted order
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Converts the compressed representation to a full vector
|
||||
pub fn to_vec(&self) -> Vec<u32> {
|
||||
let mut result = Vec::with_capacity(self.len() as usize);
|
||||
let mut current_value = 0;
|
||||
|
||||
for i in 0..self.len() {
|
||||
if self.inner.contains(&i) {
|
||||
current_value += 1;
|
||||
}
|
||||
result.push(current_value);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Creates a DB from a vector, validating monotonicity
|
||||
pub fn try_from_vec(vec: Vec<u32>) -> Result<Self, DBError> {
|
||||
let len = vec.len() as u32;
|
||||
let mut inner = Vec::new();
|
||||
let mut prev = None;
|
||||
|
||||
for (i, &value) in vec.iter().enumerate() {
|
||||
match prev {
|
||||
None => {
|
||||
if value > 0 {
|
||||
return Err(DBError::InvalidValue { value, previous: 0 });
|
||||
}
|
||||
}
|
||||
Some(prev_val) => match value.checked_sub(prev_val) {
|
||||
Some(0) => {}
|
||||
Some(1) => inner.push(i as u32),
|
||||
_ => {
|
||||
return Err(DBError::InvalidValue {
|
||||
value,
|
||||
previous: prev_val,
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
prev = Some(value);
|
||||
}
|
||||
|
||||
let db = Self { inner, len };
|
||||
db.validate()?;
|
||||
Ok(db)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_basic_operations() {
|
||||
let mut db = DB::new();
|
||||
assert!(db.is_empty());
|
||||
|
||||
// Test push
|
||||
db.push(0).unwrap();
|
||||
db.push(0).unwrap();
|
||||
db.push(1).unwrap();
|
||||
assert_eq!(db.to_vec(), vec![0, 0, 1]);
|
||||
|
||||
// Test get
|
||||
assert_eq!(db.get(0), Some(0));
|
||||
assert_eq!(db.get(2), Some(1));
|
||||
assert_eq!(db.get(3), None);
|
||||
|
||||
// Test pop
|
||||
assert_eq!(db.pop(), Some(1));
|
||||
assert_eq!(db.to_vec(), vec![0, 0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_operations() {
|
||||
let mut db = DB::new();
|
||||
|
||||
// Test invalid push
|
||||
db.push(0).unwrap();
|
||||
assert!(matches!(
|
||||
db.push(2),
|
||||
Err(DBError::InvalidValue {
|
||||
value: 2,
|
||||
previous: 0
|
||||
})
|
||||
));
|
||||
|
||||
// Test invalid change
|
||||
assert!(matches!(db.change(0, 2), Err(DBError::InvalidValue { .. })));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_of() {
|
||||
let mut db = DB::new();
|
||||
for _ in 0..3 {
|
||||
db.push(0).unwrap();
|
||||
}
|
||||
db.push(1).unwrap();
|
||||
db.push(1).unwrap();
|
||||
|
||||
assert_eq!(db.range_of(0), Some(0..3));
|
||||
assert_eq!(db.range_of(1), Some(3..5));
|
||||
assert_eq!(db.range_of(2), None);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
use db::DB;
|
||||
// use db2::{DBError, DB as DB2};
|
||||
|
||||
pub mod db;
|
||||
pub mod db2;
|
||||
|
||||
pub fn lcs_gen(str1: &str, str2: &str) -> Vec<Vec<u32>> {
|
||||
let c1: Vec<char> = str1.chars().collect();
|
||||
@@ -62,12 +64,50 @@ pub fn lcs_gen_db(str1: &str, str2: &str) -> Vec<DB> {
|
||||
db
|
||||
}
|
||||
|
||||
// #[allow(non_camel_case_types)]
|
||||
// #[derive(Debug)]
|
||||
// pub enum belper {
|
||||
// DBE(DBError),
|
||||
// None,
|
||||
// }
|
||||
|
||||
|
||||
// pub fn lcs_gen_dbai(str1: &str, str2: &str) -> Result<Vec<DB2>, belper> {
|
||||
// let c1: Vec<char> = str1.chars().collect();
|
||||
// let c1len = c1.len();
|
||||
// let c2: Vec<char> = str2.chars().collect();
|
||||
// let c2len = c2.len();
|
||||
// let mut db: Vec<DB2> = vec![DB2::with_len(c2len as u32 + 1); c1len + 1];
|
||||
// if c1len * c2len == 0 {
|
||||
// // for i in &db {
|
||||
// // println!("{i:?}")
|
||||
// // }
|
||||
// return Ok(db);
|
||||
// }
|
||||
// for i in 1..=c1len {
|
||||
// for j in 1..=c2len {
|
||||
// if c1[i - 1] == c2[j - 1] {
|
||||
// let val = db[i - 1].get(j as u32 - 1).ok_or(belper::None)? + 1;
|
||||
// db[i].push(val).map_err(|c| belper::DBE(c))?;
|
||||
// } else {
|
||||
// let val = db[i]
|
||||
// .get(j as u32 - 1)
|
||||
// .ok_or(belper::None)?
|
||||
// .max(db[i - 1].get(j as _).ok_or(belper::None)?);
|
||||
// db[i].push(val).map_err(|c| belper::DBE(c))?;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // for i in &db {
|
||||
// // println!("{i:?}")
|
||||
// // }
|
||||
// Ok(db)
|
||||
// }
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
// use crate::common_subsequence::{db2::DB as DB2, lcs_gen_dbai};
|
||||
|
||||
use super::{lcs_gen, lcs_gen_db, DB};
|
||||
#[test]
|
||||
fn test_normal_case() {
|
||||
@@ -142,6 +182,26 @@ mod test {
|
||||
.collect();
|
||||
assert_eq!(c, s)
|
||||
}
|
||||
// #[test]
|
||||
// fn test_dbai() {
|
||||
// // CURRENTLY BREAKING IDFK idk IDKF
|
||||
// let s: Vec<Vec<u32>> = vec![
|
||||
// vec![0, 0, 0, 0, 0, 0, 0, 0],
|
||||
// vec![0, 0, 0, 0, 0, 0, 1, 1],
|
||||
// vec![0, 1, 1, 1, 1, 1, 1, 1],
|
||||
// vec![0, 1, 1, 2, 2, 2, 2, 2],
|
||||
// vec![0, 1, 1, 2, 2, 2, 2, 2],
|
||||
// vec![0, 1, 1, 2, 3, 3, 3, 3],
|
||||
// vec![0, 1, 1, 2, 3, 3, 3, 4],
|
||||
// vec![0, 1, 2, 2, 3, 3, 3, 4],
|
||||
// ];
|
||||
// let c: Vec<Vec<u32>> = lcs_gen_dbai("XMJYAUZ", "MZJAWXU")
|
||||
// .expect("oops")
|
||||
// .iter()
|
||||
// .map(DB2::to_vec)
|
||||
// .collect();
|
||||
// assert_eq!(c, s)
|
||||
// }
|
||||
#[test]
|
||||
fn test_empty() {
|
||||
lcs_gen("", "");
|
||||
|
||||
Reference in new issue
Block a user