add backward looking cyclicity check for variables in cycle detecting stackless iterator (#2111, #2117)

This commit is contained in:
Mark
2023-10-15 13:07:41 -06:00
parent 3a6aee72a3
commit e2000859b6
2 changed files with 33 additions and 8 deletions

View File

@@ -12,12 +12,15 @@ pub(crate) trait UnmarkPolicy {
fn invert_marker(iter: &mut StacklessPreOrderHeapIter<Self>) where Self: Sized; fn invert_marker(iter: &mut StacklessPreOrderHeapIter<Self>) where Self: Sized;
fn cycle_detected(&mut self) where Self: Sized; fn cycle_detected(&mut self) where Self: Sized;
fn mark_phase(&self) -> bool; fn mark_phase(&self) -> bool;
fn var_rooted_cycle(_iter: &mut StacklessPreOrderHeapIter<Self>, _var_loc: usize, _next: usize)
where
Self: Sized {}
fn detect_list_tail_cycle(_iter: &mut StacklessPreOrderHeapIter<Self>) where Self: Sized {}
fn list_head_cycle_detecting_backward( fn list_head_cycle_detecting_backward(
iter: &mut StacklessPreOrderHeapIter<Self>, iter: &mut StacklessPreOrderHeapIter<Self>,
) -> bool where Self: Sized { ) -> bool where Self: Sized {
iter.backward() iter.backward()
} }
fn detect_list_tail_cycle(_iter: &mut StacklessPreOrderHeapIter<Self>) where Self: Sized {}
} }
pub(crate) struct IteratorUMP { pub(crate) struct IteratorUMP {
@@ -89,7 +92,7 @@ impl UnmarkPolicy for CycleDetectorUMP {
iter: &mut StacklessPreOrderHeapIter<Self>, iter: &mut StacklessPreOrderHeapIter<Self>,
) -> bool { ) -> bool {
if !iter.iter_state.cycle_detected && iter.iter_state.mark_phase { if !iter.iter_state.cycle_detected && iter.iter_state.mark_phase {
iter.iter_state.cycle_detected = iter.detect_list_cycle(); iter.iter_state.cycle_detected = iter.detect_list_cycle(iter.current);
} }
iter.backward() iter.backward()
@@ -97,7 +100,13 @@ impl UnmarkPolicy for CycleDetectorUMP {
fn detect_list_tail_cycle(iter: &mut StacklessPreOrderHeapIter<Self>) { fn detect_list_tail_cycle(iter: &mut StacklessPreOrderHeapIter<Self>) {
if iter.iter_state.mark_phase && !iter.iter_state.cycle_detected { if iter.iter_state.mark_phase && !iter.iter_state.cycle_detected {
iter.iter_state.cycle_detected = iter.detect_list_cycle(); iter.iter_state.cycle_detected = iter.detect_list_cycle(iter.current);
}
}
fn var_rooted_cycle(iter: &mut StacklessPreOrderHeapIter<Self>, var_loc: usize, next: usize) {
if var_loc != next && iter.iter_state.mark_phase && !iter.iter_state.cycle_detected {
iter.iter_state.cycle_detected = iter.detect_list_cycle(next);
} }
} }
} }
@@ -200,7 +209,7 @@ impl<'a> StacklessPreOrderHeapIter<'a, CycleDetectorUMP> {
self.iter_state.cycle_detected self.iter_state.cycle_detected
} }
pub(crate) fn detect_list_cycle(&self) -> bool { pub(crate) fn detect_list_cycle(&self, next: usize) -> bool {
use crate::machine::system_calls::BrentAlgState; use crate::machine::system_calls::BrentAlgState;
let mut brent_alg_st = BrentAlgState::new(self.current); let mut brent_alg_st = BrentAlgState::new(self.current);
@@ -208,12 +217,12 @@ impl<'a> StacklessPreOrderHeapIter<'a, CycleDetectorUMP> {
while self.heap[brent_alg_st.hare].get_mark_bit() { while self.heap[brent_alg_st.hare].get_mark_bit() {
let temp = self.heap[brent_alg_st.hare].get_value() as usize; let temp = self.heap[brent_alg_st.hare].get_value() as usize;
if brent_alg_st.step(temp).is_some() || temp == self.current { if brent_alg_st.step(temp).is_some() || temp == next {
return true; return true;
} }
if temp == self.start { if temp == self.start {
return self.heap[temp].get_value() == self.current as u64; break;
} }
} }
@@ -272,7 +281,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
#[inline] #[inline]
fn is_cyclic(&self, var_current: usize, var_next: usize) -> bool { fn is_cyclic(&self, var_current: usize, var_next: usize) -> bool {
if self.heap[var_next].is_var() { if self.heap[var_next].is_var() {
!self.heap[var_next].get_forwarding_bit() && var_current != var_next self.heap[var_next].get_mark_bit() && var_current != var_next
} else if self.heap[var_next].is_ref() { } else if self.heap[var_next].is_ref() {
self.heap[var_next].get_mark_bit() self.heap[var_next].get_mark_bit()
} else { } else {
@@ -296,6 +305,8 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
} }
return Some(cell); return Some(cell);
} else if self.heap[next as usize].get_mark_bit() == self.iter_state.mark_phase() {
UMP::var_rooted_cycle(self, current, next as usize);
} }
if self.next < self.heap.len() as u64 { if self.next < self.heap.len() as u64 {
@@ -315,6 +326,8 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
} }
return Some(cell); return Some(cell);
} else if self.heap[next as usize].get_mark_bit() == self.iter_state.mark_phase() {
UMP::var_rooted_cycle(self, current, next as usize);
} }
if self.next < self.heap.len() as u64 { if self.next < self.heap.len() as u64 {

View File

@@ -24,6 +24,10 @@ term5(A) :-
D=[_E|C], D=[_E|C],
A=[C|D]. A=[C|D].
term6(A) :-
A=[B|B],
B=[C|C].
test("acyclic_term_1", ( test("acyclic_term_1", (
L = [_Y,[M,B],B|M], acyclic_term(L) L = [_Y,[M,B],B|M], acyclic_term(L)
)). )).
@@ -165,6 +169,10 @@ test("acyclic_term#2111_5", (
term5(A), \+ acyclic_term(A) term5(A), \+ acyclic_term(A)
)). )).
test("acyclic_term#2111_6", (
term6(A), acyclic_term(A)
)).
test("acyclic_term#2113", ( test("acyclic_term#2113", (
A=[]*B,B=[]*B, \+ acyclic_term(A) A=[]*B,B=[]*B, \+ acyclic_term(A)
)). )).
@@ -177,6 +185,10 @@ test("acyclic_term#2116", (
A=B*B,B=[]*[], acyclic_term(A) A=B*B,B=[]*[], acyclic_term(A)
)). )).
test("acyclic_term#2117", (
A=[]*A,B=[]*A, \+ acyclic_term(B)
)).
main :- main :-
findall(test(Name, Goal), test(Name, Goal), Tests), findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests(Tests, Failed), run_tests(Tests, Failed),
@@ -188,7 +200,7 @@ main_quiet :-
run_tests_quiet(Tests, Failed), run_tests_quiet(Tests, Failed),
( Failed = [] -> ( Failed = [] ->
format("All tests passed", []) format("All tests passed", [])
; format("Some tests failed", []) ; format("Some tests failed: ~w~n", [Failed])
), ),
halt. halt.