support comparison and unification of cyclic partial strings

This commit is contained in:
Mark Thom
2021-11-17 23:29:23 -07:00
parent ffd1b7069f
commit b24e7cce38
3 changed files with 134 additions and 113 deletions

View File

@@ -343,6 +343,13 @@ impl MachineState {
(HeapCellValueTag::CStr, cstr_atom) => { (HeapCellValueTag::CStr, cstr_atom) => {
self.fail = atom != cstr_atom; self.fail = atom != cstr_atom;
} }
(HeapCellValueTag::Str | HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
self.unify_partial_string(atom_as_cstr_cell!(atom), value);
if !self.pdl.is_empty() {
self.unify();
}
}
_ => { _ => {
self.fail = true; self.fail = true;
} }
@@ -367,12 +374,20 @@ impl MachineState {
match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) { match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) {
PStrCmpResult::Ordered(Ordering::Equal) => {} PStrCmpResult::Ordered(Ordering::Equal) => {}
PStrCmpResult::Ordered(Ordering::Less) => { PStrCmpResult::Ordered(Ordering::Less) => {
self.pdl.push(empty_list_as_cell!()); if pstr_iter2.focus.as_var().is_none() {
self.pdl.push(pstr_iter2.focus); self.fail = true;
} else {
self.pdl.push(empty_list_as_cell!());
self.pdl.push(pstr_iter2.focus);
}
} }
PStrCmpResult::Ordered(Ordering::Greater) => { PStrCmpResult::Ordered(Ordering::Greater) => {
self.pdl.push(empty_list_as_cell!()); if pstr_iter1.focus.as_var().is_none() {
self.pdl.push(pstr_iter1.focus); self.fail = true;
} else {
self.pdl.push(empty_list_as_cell!());
self.pdl.push(pstr_iter1.focus);
}
} }
continuable @ PStrCmpResult::FirstIterContinuable(iteratee) | continuable @ PStrCmpResult::FirstIterContinuable(iteratee) |
continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => { continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => {
@@ -1014,12 +1029,20 @@ impl MachineState {
match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) { match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) {
PStrCmpResult::Ordered(Ordering::Equal) => {} PStrCmpResult::Ordered(Ordering::Equal) => {}
PStrCmpResult::Ordered(Ordering::Less) => { PStrCmpResult::Ordered(Ordering::Less) => {
self.pdl.push(empty_list_as_cell!()); if pstr_iter2.focus.as_var().is_none() {
self.pdl.push(pstr_iter2.focus); self.fail = true;
} else {
self.pdl.push(empty_list_as_cell!());
self.pdl.push(pstr_iter2.focus);
}
} }
PStrCmpResult::Ordered(Ordering::Greater) => { PStrCmpResult::Ordered(Ordering::Greater) => {
self.pdl.push(empty_list_as_cell!()); if pstr_iter1.focus.as_var().is_none() {
self.pdl.push(pstr_iter1.focus); self.fail = true;
} else {
self.pdl.push(empty_list_as_cell!());
self.pdl.push(pstr_iter1.focus);
}
} }
continuable @ PStrCmpResult::FirstIterContinuable(iteratee) | continuable @ PStrCmpResult::FirstIterContinuable(iteratee) |
continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => { continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => {

View File

@@ -539,18 +539,33 @@ pub fn compare_pstr_prefixes<'a>(
i2: &mut HeapPStrIter<'a>, i2: &mut HeapPStrIter<'a>,
) -> PStrCmpResult { ) -> PStrCmpResult {
#[inline(always)] #[inline(always)]
fn consolidate_step(iter: &mut HeapPStrIter, step: &PStrIterStep) -> bool { fn step(iter: &mut HeapPStrIter, hare: usize) -> Option<PStrIterStep> {
iter.focus = iter.heap[step.next_hare]; let result = iter.step(hare);
iter.focus = iter.heap[hare];
if iter.focus.is_string_terminator(iter.heap) { if iter.focus.is_string_terminator(iter.heap) {
iter.focus = empty_list_as_cell!(); iter.focus = empty_list_as_cell!();
} }
!iter.brent_st.step(step.next_hare).is_some() result
} }
let mut r1 = i1.step(i1.brent_st.hare); #[inline(always)]
let mut r2 = i2.step(i2.brent_st.hare); fn cycle_detection_step(i1: &mut HeapPStrIter, i2: &HeapPStrIter, step: &PStrIterStep) -> bool {
if i1.cycle_detected() {
i1.brent_st.hare = step.next_hare;
i2.cycle_detected()
} else if i1.brent_st.step(step.next_hare).is_some() {
i1.stepper = HeapPStrIter::post_cycle_discovery_stepper;
i2.cycle_detected()
} else {
false
}
}
let mut r1 = step(i1, i1.brent_st.hare);
let mut r2 = step(i2, i2.brent_st.hare);
loop { loop {
if let Some(step_1) = r1.as_mut() { if let Some(step_1) = r1.as_mut() {
@@ -561,21 +576,14 @@ pub fn compare_pstr_prefixes<'a>(
return PStrCmpResult::Ordered(c1.cmp(&c2)); return PStrCmpResult::Ordered(c1.cmp(&c2));
} }
let c1_result = consolidate_step(i1, &step_1); cycle_detection_step(i1, i2, &step_1);
let c2_result = consolidate_step(i2, &step_2); let both_cyclic = cycle_detection_step(i2, i1, &step_2);
if c1_result { r1 = step(i1, i1.brent_st.hare);
r1 = i1.step(i1.brent_st.hare); r2 = step(i2, i2.brent_st.hare);
}
if c2_result { if !both_cyclic {
r2 = i2.step(i2.brent_st.hare);
}
if c1_result && c2_result {
continue; continue;
} else {
break;
} }
} }
(PStrIteratee::Char(_, c1), PStrIteratee::PStrSegment(f2, pstr_atom, n)) => { (PStrIteratee::Char(_, c1), PStrIteratee::PStrSegment(f2, pstr_atom, n)) => {
@@ -591,36 +599,29 @@ pub fn compare_pstr_prefixes<'a>(
if n1 < pstr_atom.len() { if n1 < pstr_atom.len() {
step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr_atom, n1); step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr_atom, n1);
if consolidate_step(i1, &step_1) { let c1_result = cycle_detection_step(i1, i2, &step_1);
r1 = i1.step(step_1.next_hare); r1 = step(i1, i1.brent_st.hare);
if !c1_result {
continue; continue;
} else {
break;
} }
} else { } else {
let c1_result = consolidate_step(i1, &step_1); cycle_detection_step(i1, i2, &step_1);
let c2_result = consolidate_step(i2, &step_2); let both_cyclic = cycle_detection_step(i2, i1, &step_2);
if c1_result { r1 = step(i1, i1.brent_st.hare);
r1 = i1.step(i1.brent_st.hare); r2 = step(i2, i2.brent_st.hare);
}
if c2_result { if !both_cyclic {
r2 = i2.step(i2.brent_st.hare);
}
if c1_result && c2_result {
continue; continue;
} else {
break;
} }
} }
} else { } else {
if consolidate_step(i2, &step_2) { let c2_result = cycle_detection_step(i2, i1, &step_2);
r2 = i2.step(step_2.next_hare); r2 = step(i2, i2.brent_st.hare);
if !c2_result {
continue; continue;
} else {
break;
} }
} }
} }
@@ -637,54 +638,42 @@ pub fn compare_pstr_prefixes<'a>(
if n1 < pstr_atom.len() { if n1 < pstr_atom.len() {
step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr_atom, n1); step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr_atom, n1);
if consolidate_step(i2, &step_2) { let c2_result = cycle_detection_step(i2, i1, &step_2);
r2 = i2.step(step_2.next_hare); r2 = step(i2, step_2.next_hare);
if !c2_result {
continue; continue;
} else {
break;
} }
} else { } else {
let c1_result = consolidate_step(i1, &step_1); cycle_detection_step(i1, i2, &step_1);
let c2_result = consolidate_step(i2, &step_2); let both_cyclic = cycle_detection_step(i2, i1, &step_2);
if c1_result { r1 = step(i1, i1.brent_st.hare);
r1 = i1.step(i1.brent_st.hare); r2 = step(i2, i2.brent_st.hare);
}
if c2_result { if !both_cyclic {
r2 = i2.step(i2.brent_st.hare);
}
if c1_result && c2_result {
continue; continue;
} else {
break;
} }
} }
} else { } else {
if consolidate_step(i1, &step_1) { let c1_result = cycle_detection_step(i1, i2, &step_1);
r1 = i1.step(step_1.next_hare); r1 = step(i1, i1.brent_st.hare);
if !c1_result {
continue; continue;
} else {
break;
} }
} }
} }
(PStrIteratee::PStrSegment(f1, pstr1_atom, n1), (PStrIteratee::PStrSegment(f1, pstr1_atom, n1),
PStrIteratee::PStrSegment(f2, pstr2_atom, n2)) => { PStrIteratee::PStrSegment(f2, pstr2_atom, n2)) => {
if pstr1_atom == pstr2_atom && n1 == n2 { if pstr1_atom == pstr2_atom && n1 == n2 {
let c_result1 = consolidate_step(i1, &step_1); cycle_detection_step(i1, i2, &step_1);
let c_result2 = consolidate_step(i2, &step_2); let both_cyclic = cycle_detection_step(i2, i1, &step_2);
if c_result1 { r1 = step(i1, i1.brent_st.hare);
r1 = i1.step(step_1.next_hare); r2 = step(i2, i2.brent_st.hare);
}
if c_result2 { if !both_cyclic {
r2 = i2.step(step_2.next_hare);
}
if c_result1 && c_result2 {
continue; continue;
} }
@@ -699,41 +688,32 @@ pub fn compare_pstr_prefixes<'a>(
match str1.len().cmp(&str2.len()) { match str1.len().cmp(&str2.len()) {
Ordering::Equal if str1 == str2 => { Ordering::Equal if str1 == str2 => {
let c_result1 = consolidate_step(i1, &step_1); cycle_detection_step(i1, i2, &step_1);
let c_result2 = consolidate_step(i2, &step_2); let both_cyclic = cycle_detection_step(i2, i1, &step_2);
if c_result1 { r1 = step(i1, i1.brent_st.hare);
r1 = i1.step(step_1.next_hare); r2 = step(i2, i2.brent_st.hare);
}
if c_result2 { if !both_cyclic {
r2 = i2.step(step_2.next_hare);
}
if c_result1 && c_result2 {
continue; continue;
} }
break;
} }
Ordering::Less if str2.starts_with(str1) => { Ordering::Less if str2.starts_with(str1) => {
step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr2_atom, n2 + str1.len()); step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr2_atom, n2 + str1.len());
let c1_result = cycle_detection_step(i1, i2, &step_1);
r1 = step(i1, i1.brent_st.hare);
if consolidate_step(i1, &step_1) { if !c1_result {
r1 = i1.step(step_1.next_hare);
continue; continue;
} else {
break;
} }
} }
Ordering::Greater if str1.starts_with(str2) => { Ordering::Greater if str1.starts_with(str2) => {
step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr1_atom, n1 + str2.len()); step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr1_atom, n1 + str2.len());
let c2_result = cycle_detection_step(i2, i1, &step_2);
r2 = step(i2, i2.brent_st.hare);
if consolidate_step(i2, &step_2) { if !c2_result {
r2 = i2.step(step_2.next_hare);
continue; continue;
} else {
break;
} }
} }
_ => { _ => {
@@ -757,22 +737,33 @@ pub fn compare_pstr_prefixes<'a>(
// and thus matched by the compare_pstr_prefixes loop previously, // and thus matched by the compare_pstr_prefixes loop previously,
// so here it suffices to check if they are both continuable. // so here it suffices to check if they are both continuable.
if i1.focus == i2.focus { let r1_at_end = r1.is_none();
PStrCmpResult::Ordered(Ordering::Equal) let r2_at_end = r2.is_none();
} else if i1.focus == empty_list_as_cell!() {
PStrCmpResult::Ordered(Ordering::Less)
} else if i2.focus == empty_list_as_cell!() {
PStrCmpResult::Ordered(Ordering::Greater)
} else if i1.is_continuable() {
if i2.is_continuable() {
return PStrCmpResult::Ordered(Ordering::Equal);
}
PStrCmpResult::FirstIterContinuable(r1.unwrap().iteratee) if r1_at_end && r2_at_end {
} else if i2.is_continuable() { if i1.focus == i2.focus {
PStrCmpResult::SecondIterContinuable(r2.unwrap().iteratee) PStrCmpResult::Ordered(Ordering::Equal)
} else {
PStrCmpResult::Unordered
}
} else if r1_at_end {
if i1.focus == empty_list_as_cell!() {
PStrCmpResult::Ordered(Ordering::Less)
} else {
PStrCmpResult::SecondIterContinuable(r2.unwrap().iteratee)
}
} else if r2_at_end {
if i2.focus == empty_list_as_cell!() {
PStrCmpResult::Ordered(Ordering::Greater)
} else {
PStrCmpResult::FirstIterContinuable(r1.unwrap().iteratee)
}
} else { } else {
PStrCmpResult::Unordered if i1.is_continuable() && i2.is_continuable() {
PStrCmpResult::Ordered(Ordering::Equal)
} else {
PStrCmpResult::Unordered
}
} }
} }

View File

@@ -113,6 +113,15 @@ impl BrentAlgState {
} }
} }
#[inline(always)]
pub fn teleport_tortoise(&mut self) {
if self.lam == self.power {
self.tortoise = self.hare;
self.power <<= 1;
self.lam = 0;
}
}
#[inline(always)] #[inline(always)]
pub fn step(&mut self, hare: usize) -> Option<CycleSearchResult> { pub fn step(&mut self, hare: usize) -> Option<CycleSearchResult> {
self.hare = hare; self.hare = hare;
@@ -120,10 +129,8 @@ impl BrentAlgState {
if self.tortoise == self.hare { if self.tortoise == self.hare {
return Some(CycleSearchResult::NotList); return Some(CycleSearchResult::NotList);
} else if self.lam == self.power { } else {
self.tortoise = self.hare; self.teleport_tortoise();
self.power <<= 1;
self.lam = 0;
} }
None None