Merge branch 'master' into library-use-case

This commit is contained in:
Nicolas Luck
2023-10-16 13:43:26 +02:00
13 changed files with 1403 additions and 570 deletions

View File

@@ -1,5 +1,6 @@
#[cfg(test)] #[cfg(test)]
pub(crate) use crate::machine::gc::{IteratorUMP, StacklessPreOrderHeapIter}; pub(crate) use crate::machine::gc::{IteratorUMP};
pub(crate) use crate::machine::gc::{CycleDetectorUMP, StacklessPreOrderHeapIter};
use crate::atom_table::*; use crate::atom_table::*;
use crate::machine::heap::*; use crate::machine::heap::*;
@@ -12,6 +13,145 @@ use modular_bitfield::prelude::*;
use std::ops::Deref; use std::ops::Deref;
use std::vec::Vec; use std::vec::Vec;
#[inline(always)]
pub fn eager_stackful_preorder_iter(
heap: &mut Heap,
value: HeapCellValue,
) -> EagerStackfulPreOrderHeapIter {
EagerStackfulPreOrderHeapIter::new(heap, value)
}
/*
* Unlike StackfulPreOrderHeapIter, this iterator not only marks
* cyclic terms for the sake of skipping them at the second visit but
* leaves them marked until it is dropped. This makes for, e.g., more
* efficient ground/1 and term_variables/2 definitions.
*/
pub struct EagerStackfulPreOrderHeapIter<'a> {
start_value: HeapCellValue,
iter_stack: Vec<HeapCellValue>,
mark_phase: bool,
heap: &'a mut Heap,
}
impl<'a> Drop for EagerStackfulPreOrderHeapIter<'a> {
fn drop(&mut self) {
self.mark_phase = false;
self.iter_stack.clear();
self.start_value.set_mark_bit(true);
self.iter_stack.push(self.start_value);
while let Some(_) = self.follow() {}
}
}
impl<'a> EagerStackfulPreOrderHeapIter<'a> {
pub fn new(heap: &'a mut Heap, value: HeapCellValue) -> Self {
Self {
start_value: value,
iter_stack: vec![value],
mark_phase: true,
heap,
}
}
#[inline]
fn is_self_ref_var(&self, value: HeapCellValue) -> bool {
if value.is_var() {
let h = value.get_value() as usize;
if self.heap[h].is_var() && self.heap[h].get_value() as usize == h {
return true;
}
}
false
}
fn follow(&mut self) -> Option<HeapCellValue> {
while let Some(value) = self.iter_stack.pop() {
if value.get_mark_bit() == self.mark_phase {
// follow marked variables to their end. only marked
// non-variables are ignored.
if self.is_self_ref_var(value) {
return Some(unmark_cell_bits!(value));
} else if !value.is_var() {
continue;
}
}
read_heap_cell!(value,
(HeapCellValueTag::Str, s) => {
let arity = cell_as_atom_cell!(self.heap[s]).get_arity();
for idx in (s + 1 .. s + arity + 1).rev() {
if self.heap[idx].get_mark_bit() != self.mark_phase {
self.iter_stack.push(self.heap[idx]);
self.heap[idx].set_mark_bit(self.mark_phase);
}
}
}
(HeapCellValueTag::Lis, l) => {
if self.heap[l+1].get_mark_bit() != self.mark_phase {
self.iter_stack.push(self.heap[l+1]);
self.heap[l+1].set_mark_bit(self.mark_phase);
}
if self.heap[l].get_mark_bit() != self.mark_phase {
self.iter_stack.push(self.heap[l]);
self.heap[l].set_mark_bit(self.mark_phase);
}
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
let var_value = self.heap[h];
self.heap[h].set_mark_bit(self.mark_phase);
if !(self.heap[h].is_var() && self.heap[h].get_value() as usize == h) {
self.iter_stack.push(var_value);
continue;
}
}
(HeapCellValueTag::PStrLoc, h) => {
let h = if self.heap[h].get_tag() == HeapCellValueTag::PStr {
h
} else {
debug_assert_eq!(self.heap[h].get_tag(), HeapCellValueTag::PStrOffset);
self.heap[h].get_value() as usize
};
if self.heap[h].get_mark_bit() == self.mark_phase {
continue;
}
let value = self.heap[h+1];
self.heap[h].set_mark_bit(self.mark_phase);
self.heap[h+1].set_mark_bit(self.mark_phase);
self.iter_stack.push(value);
}
_ => {
}
);
return Some(value);
}
None
}
}
impl<'a> Iterator for EagerStackfulPreOrderHeapIter<'a> {
type Item = HeapCellValue;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.follow()
}
}
#[derive(BitfieldSpecifier, Clone, Copy, Debug, PartialEq, Eq)] #[derive(BitfieldSpecifier, Clone, Copy, Debug, PartialEq, Eq)]
#[bits = 2] #[bits = 2]
enum IterStackLocTag { enum IterStackLocTag {
@@ -198,11 +338,6 @@ impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> {
None None
} }
#[inline]
pub fn stack_len(&self) -> usize {
self.stack.len()
}
fn push_if_unmarked(&mut self, loc: IterStackLoc) { fn push_if_unmarked(&mut self, loc: IterStackLoc) {
let cell = self.read_cell_mut(loc); let cell = self.read_cell_mut(loc);
@@ -236,17 +371,17 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists>
let cell = self.read_cell(loc); let cell = self.read_cell(loc);
read_heap_cell!(cell, read_heap_cell!(cell,
(HeapCellValueTag::Lis | (HeapCellValueTag::Lis, vh) => {
HeapCellValueTag::Str |
HeapCellValueTag::PStrLoc, vh) => {
let forward = if ElideLists::elide_lists() { true } else { cell.get_mark_bit() }; let forward = if ElideLists::elide_lists() { true } else { cell.get_mark_bit() };
if forward && self.heap[vh].get_mark_bit() { if forward && self.heap[vh].get_mark_bit() {
self.read_cell_mut(loc).set_forwarding_bit(true); self.read_cell_mut(loc).set_forwarding_bit(true);
} }
} }
(HeapCellValueTag::AttrVar | (HeapCellValueTag::Str |
HeapCellValueTag::Var, vh) => { HeapCellValueTag::AttrVar |
HeapCellValueTag::Var |
HeapCellValueTag::PStrLoc, vh) => {
if self.heap[vh].get_mark_bit() { if self.heap[vh].get_mark_bit() {
self.read_cell_mut(loc).set_forwarding_bit(true); self.read_cell_mut(loc).set_forwarding_bit(true);
} }
@@ -374,11 +509,20 @@ impl<'a, ElideLists: ListElisionPolicy> Iterator for StackfulPreOrderHeapIter<'a
#[inline(always)] #[inline(always)]
pub(crate) fn stackless_preorder_iter( pub(crate) fn stackless_preorder_iter(
heap: &mut Vec<HeapCellValue>, heap: &mut Vec<HeapCellValue>,
cell: HeapCellValue, start: usize,
) -> StacklessPreOrderHeapIter<IteratorUMP> { ) -> StacklessPreOrderHeapIter<IteratorUMP> {
StacklessPreOrderHeapIter::<IteratorUMP>::new(heap, cell) StacklessPreOrderHeapIter::<IteratorUMP>::new(heap, start)
} }
pub(crate) fn cycle_detecting_stackless_preorder_iter(
heap: &mut Heap,
start: usize,
) -> StacklessPreOrderHeapIter<CycleDetectorUMP> {
StacklessPreOrderHeapIter::<CycleDetectorUMP>::new(heap, start)
}
#[inline(always)] #[inline(always)]
pub(crate) fn stackful_preorder_iter<'a, ElideLists: ListElisionPolicy>( pub(crate) fn stackful_preorder_iter<'a, ElideLists: ListElisionPolicy>(
heap: &'a mut Vec<HeapCellValue>, heap: &'a mut Vec<HeapCellValue>,
@@ -529,9 +673,9 @@ pub(crate) type RightistPostOrderHeapIter<'a> =
#[inline] #[inline]
pub(crate) fn stackless_post_order_iter<'a>( pub(crate) fn stackless_post_order_iter<'a>(
heap: &'a mut Heap, heap: &'a mut Heap,
cell: HeapCellValue, start: usize,
) -> RightistPostOrderHeapIter<'a> { ) -> RightistPostOrderHeapIter<'a> {
PostOrderIterator::new(stackless_preorder_iter(heap, cell)) PostOrderIterator::new(stackless_preorder_iter(heap, start))
} }
#[cfg(test)] #[cfg(test)]
@@ -551,8 +695,10 @@ mod tests {
.heap .heap
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
wam.machine_st.heap.push(str_loc_as_cell!(0));
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 3);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -584,8 +730,10 @@ mod tests {
] ]
)); ));
wam.machine_st.heap.push(str_loc_as_cell!(0));
for _ in 0..20 { for _ in 0..20 {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 5);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -628,7 +776,7 @@ mod tests {
)); ));
for _ in 0..200000 { for _ in 0..200000 {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -659,7 +807,7 @@ mod tests {
{ {
wam.machine_st.heap.push(heap_loc_as_cell!(0)); wam.machine_st.heap.push(heap_loc_as_cell!(0));
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -680,7 +828,7 @@ mod tests {
wam.machine_st.heap.push(empty_list_as_cell!()); wam.machine_st.heap.push(empty_list_as_cell!());
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -715,7 +863,7 @@ mod tests {
wam.machine_st.heap.push(heap_loc_as_cell!(0)); wam.machine_st.heap.push(heap_loc_as_cell!(0));
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -749,8 +897,10 @@ mod tests {
put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl); put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl);
let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 2);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
assert_eq!( assert_eq!(
@@ -764,8 +914,7 @@ mod tests {
assert_eq!(wam.machine_st.heap[0], pstr_cell); assert_eq!(wam.machine_st.heap[0], pstr_cell);
assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1));
wam.machine_st.heap.pop(); wam.machine_st.heap[1] = pstr_loc_as_cell!(3);
wam.machine_st.heap.push(pstr_loc_as_cell!(2));
let pstr_second_var_cell = let pstr_second_var_cell =
put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl); put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl);
@@ -773,36 +922,40 @@ mod tests {
let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 2);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
heap_loc_as_cell!(3), heap_loc_as_cell!(4),
); );
assert!(iter.next().is_none()); assert!(iter.next().is_none());
} }
assert_eq!(wam.machine_st.heap[0], pstr_cell); assert_eq!(wam.machine_st.heap[0], pstr_cell);
assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(2)); assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(3));
assert_eq!(wam.machine_st.heap[2], pstr_second_cell); assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(0));
assert_eq!(wam.machine_st.heap[3], heap_loc_as_cell!(3)); assert_eq!(wam.machine_st.heap[3], pstr_second_cell);
assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(4));
wam.machine_st.heap.pop(); wam.machine_st.heap.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(4)); wam.machine_st.heap.push(pstr_loc_as_cell!(5));
wam.machine_st.heap.push(pstr_offset_as_cell!(0)); wam.machine_st.heap.push(pstr_offset_as_cell!(0));
wam.machine_st wam.machine_st
.heap .heap
.push(fixnum_as_cell!(Fixnum::build_with(2))); .push(fixnum_as_cell!(Fixnum::build_with(2)));
wam.machine_st.heap[2] = heap_loc_as_cell!(4);
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(4)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 2);
let pstr_offset_cell = pstr_offset_as_cell!(0); let pstr_offset_cell = pstr_offset_as_cell!(0);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), fixnum_as_cell!(Fixnum::build_with(2)));
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
@@ -812,19 +965,19 @@ mod tests {
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
assert_eq!( assert_eq!(
unmark_cell_bits!(wam.machine_st.heap[1]), unmark_cell_bits!(wam.machine_st.heap[1]),
pstr_loc_as_cell!(2) pstr_loc_as_cell!(3)
);
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell);
assert_eq!(
unmark_cell_bits!(wam.machine_st.heap[3]),
pstr_loc_as_cell!(4)
); );
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell);
assert_eq!( assert_eq!(
unmark_cell_bits!(wam.machine_st.heap[4]), unmark_cell_bits!(wam.machine_st.heap[4]),
pstr_offset_as_cell!(0) pstr_loc_as_cell!(5)
); );
assert_eq!( assert_eq!(
unmark_cell_bits!(wam.machine_st.heap[5]), unmark_cell_bits!(wam.machine_st.heap[5]),
pstr_offset_as_cell!(0)
);
assert_eq!(
unmark_cell_bits!(wam.machine_st.heap[6]),
fixnum_as_cell!(Fixnum::build_with(2)) fixnum_as_cell!(Fixnum::build_with(2))
); );
@@ -840,31 +993,31 @@ mod tests {
.heap .heap
.push(fixnum_as_cell!(Fixnum::build_with(0i64))); .push(fixnum_as_cell!(Fixnum::build_with(0i64)));
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 6);
let pstr_offset_cell = pstr_offset_as_cell!(0); let pstr_offset_cell = pstr_offset_as_cell!(0);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_loc_as_cell!(4));
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), fixnum_as_cell!(Fixnum::build_with(0)));
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
} }
all_cells_unmarked(&wam.machine_st.heap); all_cells_unmarked(&wam.machine_st.heap);
wam.machine_st.heap.pop(); wam.machine_st.heap[5] = fixnum_as_cell!(Fixnum::build_with(1i64));
wam.machine_st
.heap
.push(fixnum_as_cell!(Fixnum::build_with(1i64)));
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 6);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_loc_as_cell!(4));
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -874,13 +1027,17 @@ mod tests {
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
pstr_offset_as_cell!(0) pstr_offset_as_cell!(0)
); );
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
fixnum_as_cell!(Fixnum::build_with(1))
);
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
assert_eq!(iter.heap[4], pstr_offset_as_cell!(0));
assert_eq!(iter.heap[5], fixnum_as_cell!(Fixnum::build_with(1i64)));
} }
assert_eq!(wam.machine_st.heap[4], pstr_offset_as_cell!(0));
assert_eq!(wam.machine_st.heap[5], fixnum_as_cell!(Fixnum::build_with(1i64)));
all_cells_unmarked(&wam.machine_st.heap); all_cells_unmarked(&wam.machine_st.heap);
wam.machine_st.heap.clear(); wam.machine_st.heap.clear();
@@ -896,7 +1053,7 @@ mod tests {
wam.machine_st.heap.extend(functor); wam.machine_st.heap.extend(functor);
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -933,26 +1090,13 @@ mod tests {
atom_as_cell!(f_atom, 3) atom_as_cell!(f_atom, 3)
); );
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(b_atom)
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(b_atom)
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(a_atom)
);
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
} }
all_cells_unmarked(&wam.machine_st.heap); all_cells_unmarked(&wam.machine_st.heap);
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -999,7 +1143,7 @@ mod tests {
assert_eq!(wam.machine_st.heap[4], empty_list_as_cell!()); assert_eq!(wam.machine_st.heap[4], empty_list_as_cell!());
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -1031,7 +1175,7 @@ mod tests {
wam.machine_st.heap[4] = list_loc_as_cell!(1); wam.machine_st.heap[4] = list_loc_as_cell!(1);
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -1069,19 +1213,6 @@ mod tests {
atom_as_cell!(f_atom, 3) atom_as_cell!(f_atom, 3)
); );
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(b_atom)
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(b_atom)
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(a_atom)
);
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
} }
@@ -1093,12 +1224,12 @@ mod tests {
wam.machine_st.heap.push(heap_loc_as_cell!(2)); wam.machine_st.heap.push(heap_loc_as_cell!(2));
wam.machine_st.heap.push(heap_loc_as_cell!(3)); wam.machine_st.heap.push(heap_loc_as_cell!(3));
wam.machine_st.heap.push(heap_loc_as_cell!(3)); wam.machine_st.heap.push(heap_loc_as_cell!(3));
wam.machine_st.heap.push(heap_loc_as_cell!(0));
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 4);
assert_eq!(iter.next().unwrap(), heap_loc_as_cell!(3)); assert_eq!(iter.next().unwrap(), heap_loc_as_cell!(3));
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
} }
@@ -1129,7 +1260,7 @@ mod tests {
wam.machine_st.heap.push(list_loc_as_cell!(1)); wam.machine_st.heap.push(list_loc_as_cell!(1));
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1));
assert_eq!( assert_eq!(
@@ -1137,10 +1268,6 @@ mod tests {
list_loc_as_cell!(1) list_loc_as_cell!(1)
); );
assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1));
// this is what happens! this next line! We would like it not to happen though.
assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1));
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
} }
@@ -1176,9 +1303,10 @@ mod tests {
wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7. wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7.
wam.machine_st.heap.push(heap_loc_as_cell!(12)); wam.machine_st.heap.push(heap_loc_as_cell!(12));
wam.machine_st.heap.push(heap_loc_as_cell!(0));
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 13);
assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1));
@@ -1217,6 +1345,7 @@ mod tests {
let clpz_atom = atom!("clpz"); let clpz_atom = atom!("clpz");
let p_atom = atom!("p"); let p_atom = atom!("p");
wam.machine_st.heap.pop();
wam.machine_st.heap.pop(); wam.machine_st.heap.pop();
wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12 wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12
@@ -1231,9 +1360,10 @@ mod tests {
wam.machine_st.heap.push(empty_list_as_cell!()); // 21 wam.machine_st.heap.push(empty_list_as_cell!()); // 21
wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22 wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22
wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23 wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23
wam.machine_st.heap.push(heap_loc_as_cell!(0));
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 24);
assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1));
@@ -1368,10 +1498,9 @@ mod tests {
wam.machine_st.heap.clear(); wam.machine_st.heap.clear();
{ {
let mut iter = stackless_preorder_iter( wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0)));
&mut wam.machine_st.heap,
fixnum_as_cell!(Fixnum::build_with(0)), let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -1383,8 +1512,6 @@ mod tests {
all_cells_unmarked(&wam.machine_st.heap); all_cells_unmarked(&wam.machine_st.heap);
assert_eq!(wam.machine_st.heap.len(), 0);
wam.machine_st.heap.clear(); wam.machine_st.heap.clear();
wam.machine_st.heap.push(str_loc_as_cell!(1)); wam.machine_st.heap.push(str_loc_as_cell!(1));
@@ -1394,7 +1521,7 @@ mod tests {
wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); wam.machine_st.heap.push(atom_as_cell!(atom!("y")));
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, str_loc_as_cell!(1)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -1406,7 +1533,7 @@ mod tests {
atom_as_cell!(atom!("y")) atom_as_cell!(atom!("y"))
); );
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(0));
assert!(iter.next().is_none()); assert!(iter.next().is_none());
} }
@@ -1418,9 +1545,10 @@ mod tests {
wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2));
wam.machine_st.heap.push(str_loc_as_cell!(0)); wam.machine_st.heap.push(str_loc_as_cell!(0));
wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); wam.machine_st.heap.push(atom_as_cell!(atom!("y")));
wam.machine_st.heap.push(str_loc_as_cell!(0));
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 3);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -1453,7 +1581,7 @@ mod tests {
wam.machine_st.heap.push(empty_list_as_cell!()); wam.machine_st.heap.push(empty_list_as_cell!());
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(7)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 7);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -1511,9 +1639,10 @@ mod tests {
wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2)); wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2));
wam.machine_st.heap.push(heap_loc_as_cell!(1)); wam.machine_st.heap.push(heap_loc_as_cell!(1));
wam.machine_st.heap.push(heap_loc_as_cell!(1)); wam.machine_st.heap.push(heap_loc_as_cell!(1));
wam.machine_st.heap.push(str_loc_as_cell!(0));
{ {
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 3);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -1540,38 +1669,68 @@ mod tests {
wam.machine_st.heap.clear(); wam.machine_st.heap.clear();
// representation of one of the heap terms as in issue #1384. // representation of one of the heap terms as in issue #1384.
/* wam.machine_st.heap.push(list_loc_as_cell!(7)); // 0
wam.machine_st.heap.push(list_loc_as_cell!(7)); wam.machine_st.heap.push(heap_loc_as_cell!(0)); // 1
wam.machine_st.heap.push(list_loc_as_cell!(3)); // 2
wam.machine_st.heap.push(list_loc_as_cell!(5)); // 3
wam.machine_st.heap.push(empty_list_as_cell!()); // 4
wam.machine_st.heap.push(heap_loc_as_cell!(2)); // 5
wam.machine_st.heap.push(heap_loc_as_cell!(2)); // 6
wam.machine_st.heap.push(empty_list_as_cell!()); // 7
wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 8
wam.machine_st.heap.push(heap_loc_as_cell!(0)); wam.machine_st.heap.push(heap_loc_as_cell!(0));
wam.machine_st.heap.push(list_loc_as_cell!(3));
wam.machine_st.heap.push(list_loc_as_cell!(5));
wam.machine_st.heap.push(empty_list_as_cell!());
wam.machine_st.heap.push(heap_loc_as_cell!(2));
wam.machine_st.heap.push(heap_loc_as_cell!(2));
wam.machine_st.heap.push(empty_list_as_cell!());
wam.machine_st.heap.push(heap_loc_as_cell!(3));
{ {
let mut iter = stackless_preorder_iter( let mut iter = stackless_preorder_iter(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
heap_loc_as_cell!(0), 9,
); );
/*
while let Some(_) = iter.next() { while let Some(_) = iter.next() {
print_heap_terms(iter.heap.iter(), 0); print_heap_terms(iter.heap.iter(), 0);
println!(""); println!("");
} }
*/
/*
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(atom!("f"), 2) list_loc_as_cell!(7)
); );
assert!(iter.next().is_none()); assert_eq!(
*/ unmark_cell_bits!(iter.next().unwrap()),
list_loc_as_cell!(5)
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
heap_loc_as_cell!(2)
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
list_loc_as_cell!(3)
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
empty_list_as_cell!()
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
heap_loc_as_cell!(2)
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
empty_list_as_cell!()
);
assert_eq!(iter.next(), None);
} }
*/
} }
#[test] #[test]
@@ -2663,8 +2822,10 @@ mod tests {
.heap .heap
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
wam.machine_st.heap.push(str_loc_as_cell!(0));
{ {
let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 3);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -2694,8 +2855,10 @@ mod tests {
] ]
)); ));
wam.machine_st.heap.push(str_loc_as_cell!(0));
for _ in 0..20 { for _ in 0..20 {
let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 5);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0));
@@ -2726,7 +2889,7 @@ mod tests {
wam.machine_st.heap.push(heap_loc_as_cell!(0)); wam.machine_st.heap.push(heap_loc_as_cell!(0));
let mut iter = let mut iter =
stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); stackless_post_order_iter(&mut wam.machine_st.heap, 0);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -2742,8 +2905,7 @@ mod tests {
wam.machine_st.heap.push(heap_loc_as_cell!(1)); wam.machine_st.heap.push(heap_loc_as_cell!(1));
wam.machine_st.heap.push(heap_loc_as_cell!(0)); wam.machine_st.heap.push(heap_loc_as_cell!(0));
let mut iter = let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0);
stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -2769,7 +2931,7 @@ mod tests {
{ {
let mut iter = let mut iter =
stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); stackless_post_order_iter(&mut wam.machine_st.heap, 0);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -2802,7 +2964,7 @@ mod tests {
{ {
let mut iter = let mut iter =
stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); stackless_post_order_iter(&mut wam.machine_st.heap, 0);
// the cycle will be iterated twice before being detected. // the cycle will be iterated twice before being detected.
assert_eq!( assert_eq!(
@@ -2831,7 +2993,7 @@ mod tests {
{ {
let mut iter = let mut iter =
stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); stackless_post_order_iter(&mut wam.machine_st.heap, 0);
// cut the iteration short to check that all cells are // cut the iteration short to check that all cells are
// unmarked and unforwarded by the Drop instance of // unmarked and unforwarded by the Drop instance of
@@ -2865,9 +3027,11 @@ mod tests {
put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl); put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl);
let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
{ {
let mut iter = let mut iter =
stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); stackless_post_order_iter(&mut wam.machine_st.heap, 2);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -2879,6 +3043,7 @@ mod tests {
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
} }
wam.machine_st.heap.pop();
wam.machine_st.heap.pop(); wam.machine_st.heap.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(2)); wam.machine_st.heap.push(pstr_loc_as_cell!(2));
@@ -2887,9 +3052,10 @@ mod tests {
let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
{ {
let mut iter = let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 4);
stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -2914,9 +3080,10 @@ mod tests {
.heap .heap
.push(fixnum_as_cell!(Fixnum::build_with(0))); .push(fixnum_as_cell!(Fixnum::build_with(0)));
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
{ {
let mut iter = let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 7);
stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
let mut pstr_loc_cell = pstr_loc_as_cell!(0); let mut pstr_loc_cell = pstr_loc_as_cell!(0);
pstr_loc_cell.set_forwarding_bit(true); pstr_loc_cell.set_forwarding_bit(true);
@@ -2924,11 +3091,7 @@ mod tests {
// assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64))); // assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64)));
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
pstr_offset_as_cell!(0) heap_loc_as_cell!(3)
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
pstr_offset_as_cell!(0)
); );
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
@@ -2939,28 +3102,27 @@ mod tests {
all_cells_unmarked(&wam.machine_st.heap); all_cells_unmarked(&wam.machine_st.heap);
wam.machine_st.heap.pop();
wam.machine_st.heap.pop(); wam.machine_st.heap.pop();
wam.machine_st wam.machine_st
.heap .heap
.push(fixnum_as_cell!(Fixnum::build_with(1))); .push(fixnum_as_cell!(Fixnum::build_with(1)));
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
{ {
let mut iter = let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 7);
stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
//assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1))); //assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1)));
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
pstr_offset_as_cell!(0) heap_loc_as_cell!(3)
); );
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
pstr_offset_as_cell!(0) pstr_second_cell
); );
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
} }
@@ -2976,9 +3138,10 @@ mod tests {
wam.machine_st.heap.extend(functor); wam.machine_st.heap.extend(functor);
wam.machine_st.heap.push(heap_loc_as_cell!(0));
{ {
let mut iter = let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 9);
stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -3008,18 +3171,6 @@ mod tests {
list_loc_as_cell!(3) list_loc_as_cell!(3)
); );
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(b_atom)
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(b_atom)
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(a_atom)
);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(f_atom, 3) atom_as_cell!(f_atom, 3)
@@ -3038,8 +3189,7 @@ mod tests {
wam.machine_st.heap[4] = list_loc_as_cell!(1); wam.machine_st.heap[4] = list_loc_as_cell!(1);
{ {
let mut iter = let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0);
stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -3059,25 +3209,15 @@ mod tests {
atom_as_cell!(f_atom, 3) atom_as_cell!(f_atom, 3)
); );
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(b_atom)
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(b_atom)
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(a_atom)
);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(f_atom, 3) atom_as_cell!(f_atom, 3)
); );
assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
list_loc_as_cell!(1)
);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),

View File

@@ -328,6 +328,9 @@ staggered_sc(_, G) :- call(G).
% to reason about the programs. Also restricts the ability to run the program with alternative execution strategies % to reason about the programs. Also restricts the ability to run the program with alternative execution strategies
!. !.
:- non_counted_backtracking get_cp/1.
get_cp(B) :- '$get_cp'(B).
:- non_counted_backtracking set_cp/1. :- non_counted_backtracking set_cp/1.
set_cp(B) :- '$set_cp'(B). set_cp(B) :- '$set_cp'(B).
@@ -359,24 +362,21 @@ cont_list_goal(Conts, '$call'(builtins:dispatch_call_list(Conts))).
:- non_counted_backtracking dispatch_prep/3. :- non_counted_backtracking dispatch_prep/3.
dispatch_prep(Gs, B, [Cont|Conts]) :- dispatch_prep(Gs, B, Conts) :-
( callable(Gs) -> ( callable(Gs) ->
strip_module(Gs, M, Gs0), strip_module(Gs, M, Gs0),
( nonvar(Gs0), ( nonvar(Gs0),
dispatch_prep_(Gs0, B, [Cont|Conts]) -> dispatch_prep_(Gs0, B, Conts) ->
true true
; Gs0 == ! -> ; Gs0 == ! ->
Cont = '$call'(builtins:set_cp(B)), Conts = ['$call'(builtins:set_cp(B))]
Conts = []
; nonvar(Gs0), ; nonvar(Gs0),
\+ callable(Gs0) -> \+ callable(Gs0) ->
throw(dispatch_prep_error) throw(dispatch_prep_error)
; Cont = Gs, ; Conts = [Gs]
Conts = []
) )
; var(Gs) -> ; var(Gs) ->
Cont = Gs, Conts = [Gs]
Conts = []
; throw(dispatch_prep_error) ; throw(dispatch_prep_error)
). ).
@@ -387,20 +387,32 @@ dispatch_prep_((G1, G2), B, [Cont|Conts]) :-
dispatch_prep(G1, B, IConts1), dispatch_prep(G1, B, IConts1),
cont_list_goal(IConts1, Cont), cont_list_goal(IConts1, Cont),
dispatch_prep(G2, B, Conts). dispatch_prep(G2, B, Conts).
dispatch_prep_((G1 ; G2), B, [Cont|Conts]) :- dispatch_prep_((G1 ; G2), B, Conts) :-
dispatch_prep(G1, B, IConts0), ( nonvar(G1) ->
( G1 = (G11 -> G12) ->
dispatch_prep(G11, B, IConts2),
dispatch_prep(G12, B, IConts3),
cont_list_goal(IConts2, Cont2),
cont_list_goal(IConts3, Cont3),
Cont0 = '$call'(builtins:staggered_if_then(Cont2, Cont3))
; dispatch_prep(G1, B, IConts0),
dispatch_prep(G2, B, IConts1),
cont_list_goal(IConts0, Cont0)
)
; dispatch_prep(G1, B1, IConts0),
cont_list_goal(IConts0, Cont0)
),
dispatch_prep(G2, B, IConts1), dispatch_prep(G2, B, IConts1),
cont_list_goal(IConts0, Cont0), cont_list_goal(IConts0, Cont0),
cont_list_goal(IConts1, Cont1), cont_list_goal(IConts1, Cont1),
Cont = '$call'(builtins:staggered_sc(Cont0, Cont1)), Conts = ['$call'(builtins:staggered_sc(Cont0, Cont1))].
Conts = []. dispatch_prep_((G1 -> G2), B, Conts) :-
dispatch_prep_((G1 -> G2), B, [Cont|Conts]) :- dispatch_prep(G1, B1, IConts1),
dispatch_prep(G1, B, IConts1),
dispatch_prep(G2, B, IConts2), dispatch_prep(G2, B, IConts2),
cont_list_goal(IConts1, Cont1), cont_list_goal(IConts1, Cont1),
cont_list_goal(IConts2, Cont2), cont_list_goal(IConts2, Cont2),
Cont = '$call'(builtins:staggered_if_then(Cont1, Cont2)), Conts = ['$call'(builtins:get_cp(B1)),
Conts = []. '$call'(builtins:staggered_if_then(Cont1, Cont2))].
:- non_counted_backtracking dispatch_call_list/1. :- non_counted_backtracking dispatch_call_list/1.

View File

@@ -1030,8 +1030,8 @@ term_expansion(Term0, Term) :-
once(duodcg_body(Body0, Body, As0, As, Bs0, Bs)). once(duodcg_body(Body0, Body, As0, As, Bs0, Bs)).
duodcg_body([], (As0=As,Bs0=Bs), As0, As, Bs0, Bs). duodcg_body([], (As0=As,Bs0=Bs), As0, As, Bs0, Bs).
duodcg_body(Xs+Ys, (phrase(list(Xs), As0, As), duodcg_body(Xs+Ys, (phrase(seq(Xs), As0, As),
phrase(list(Ys), Bs0, Bs)), As0, As, Bs0, Bs). phrase(seq(Ys), Bs0, Bs)), As0, As, Bs0, Bs).
duodcg_body({Goal}, call(Goal), As, As, Bs, Bs). duodcg_body({Goal}, call(Goal), As, As, Bs, Bs).
duodcg_body((A0,B0), (A,B), As0, As, Bs0, Bs) :- duodcg_body((A0,B0), (A,B), As0, As, Bs0, Bs) :-
duodcg_body(A0, A, As0, As1, Bs0, Bs1), duodcg_body(A0, A, As0, As1, Bs0, Bs1),
@@ -1957,7 +1957,6 @@ choice_order_variable(step, Order, Var, Vars, Vars0, Selection, Consistency) :-
( Var = Next, ( Var = Next,
label(Vars, Selection, Order, step, Consistency) label(Vars, Selection, Order, step, Consistency)
; neq_num(Var, Next), ; neq_num(Var, Next),
do_queue,
label(Vars0, Selection, Order, step, Consistency) label(Vars0, Selection, Order, step, Consistency)
). ).
choice_order_variable(enum, Order, Var, Vars, _, Selection, Consistency) :- choice_order_variable(enum, Order, Var, Vars, _, Selection, Consistency) :-
@@ -2566,13 +2565,13 @@ parse_clpz(E, R,
g(power_var_num(E, V, N)) => [p(pexp(V, N, R))], g(power_var_num(E, V, N)) => [p(pexp(V, N, R))],
m(A*B) => [p(ptimes(A, B, R))], m(A*B) => [p(ptimes(A, B, R))],
m(A-B) => [p(pplus(R,B,A))], m(A-B) => [p(pplus(R,B,A))],
m(-A) => [p(ptimes(-1,A,R))], m(-A) => [p(pplus(A,R,0))],
m(max(A,B)) => [g(A #=< #R), g(B #=< R), p(pmax(A, B, R))], m(max(A,B)) => [g(A #=< #R), g(B #=< R), p(pmax(A, B, R))],
m(min(A,B)) => [g(A #>= #R), g(B #>= R), p(pmin(A, B, R))], m(min(A,B)) => [g(A #>= #R), g(B #>= R), p(pmin(A, B, R))],
m(A mod B) => [g(B #\= 0), p(pmod(A, B, R))], m(A mod B) => [g(B #\= 0), p(pmod(A, B, R))],
m(A rem B) => [g(B #\= 0), p(prem(A, B, R))], m(A rem B) => [g(B #\= 0), p(prem(A, B, R))],
m(abs(A)) => [g(#R #>= 0), p(pabs(A, R))], m(abs(A)) => [g(#R #>= 0), p(pabs(A, R))],
m(A/B) => [g(B #\= 0), p(prdiv(A, B, R))], m(A/B) => [g(B #\= 0), p(ptimes(R, B, A))],
m(A//B) => [g(B #\= 0), p(ptzdiv(A, B, R))], m(A//B) => [g(B #\= 0), p(ptzdiv(A, B, R))],
m(A div B) => [g(#R #= (A - (A mod B)) // B)], m(A div B) => [g(#R #= (A - (A mod B)) // B)],
m(A^B) => [p(pexp(A, B, R))], m(A^B) => [p(pexp(A, B, R))],
@@ -2636,14 +2635,37 @@ parse_goals([]) --> [].
parse_goals([G|Gs]) --> parse_goal(G), parse_goals(Gs). parse_goals([G|Gs]) --> parse_goal(G), parse_goals(Gs).
parse_goal(g(Goal)) --> [Goal]. parse_goal(g(Goal)) --> [Goal].
parse_goal(p(Prop)) --> parse_goal(p(Prop0)) -->
{ term_variables(Prop, Vs) }, { term_variables(Prop0, Vs),
morphing_propagator(Prop0, Prop, _) },
[make_propagator(Prop, P), [make_propagator(Prop, P),
new_queue(Q0), new_queue(Q0),
phrase(init_propagator_(Vs, P), [Q0], [Q]), phrase(init_propagator_(Vs, P), [Q0], [Q]),
variables_same_queue(Vs), variables_same_queue(Vs),
trigger_once_(P, Q)]. trigger_once_(P, Q)].
morphing(pplus).
morphing(ptimes).
morphing(pexp).
morphing(ptzdiv).
morphing_propagator(P0, P, Target) :-
P0 =.. [F|Args0],
( morphing(F) ->
append(Args0, [Last], Args),
Target = p(Last)
; Args = Args0,
Target = none
),
P =.. [F|Args].
morph_into_propagator(MState, Vs, P0, Morph) -->
kill(MState),
{ morphing_propagator(P0, P, _),
make_propagator(P, Morph) },
init_propagator_(Vs, Morph),
trigger_prop(Morph).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
?- use_module(library(lists)), ?- use_module(library(lists)),
use_module(library(format)), use_module(library(format)),
@@ -2734,14 +2756,12 @@ geq(A, B) :-
) )
; ( AI cis_geq n(B) -> true ; ( AI cis_geq n(B) -> true
; domain_remove_smaller_than(AD, B, AD1), ; domain_remove_smaller_than(AD, B, AD1),
fd_put(A, AD1, APs), fd_put(A, AD1, APs)
do_queue
) )
) )
; fd_get(B, BD, BPs) -> ; fd_get(B, BD, BPs) ->
domain_remove_greater_than(BD, A, BD1), domain_remove_greater_than(BD, A, BD1),
fd_put(B, BD1, BPs), fd_put(B, BD1, BPs)
do_queue
; A >= B ; A >= B
). ).
@@ -2811,7 +2831,7 @@ matches([
m(var(X) #= var(Y)+var(Z)) => [p(pplus(Y,Z,X))], m(var(X) #= var(Y)+var(Z)) => [p(pplus(Y,Z,X))],
m(var(X) #= var(Y)-var(Z)) => [p(pplus(X,Z,Y))], m(var(X) #= var(Y)-var(Z)) => [p(pplus(X,Z,Y))],
m(var(X) #= var(Y)*var(Z)) => [p(ptimes(Y,Z,X))], m(var(X) #= var(Y)*var(Z)) => [p(ptimes(Y,Z,X))],
m(var(X) #= -var(Z)) => [p(ptimes(-1, Z, X))], m(var(X) #= -var(Y)) => [p(pplus(X,Y,0))],
m_c(any(X) #= any(Y), left_right_linsum_const(X, Y, Cs, Vs, S)) => m_c(any(X) #= any(Y), left_right_linsum_const(X, Y, Cs, Vs, S)) =>
[g(scalar_product_(#=, Cs, Vs, S))], [g(scalar_product_(#=, Cs, Vs, S))],
m_c(var(X) #= abs(var(Y)) + any(V0), X == Y) => [d(V0,V),p(x_eq_abs_plus_v(X,V))], m_c(var(X) #= abs(var(Y)) + any(V0), X == Y) => [d(V0,V),p(x_eq_abs_plus_v(X,V))],
@@ -2907,8 +2927,9 @@ match_goals([G|Gs], F) --> match_goal(G, F), match_goals(Gs, F).
match_goal(r(X,Y), F) --> { G =.. [F,X,Y] }, [G]. match_goal(r(X,Y), F) --> { G =.. [F,X,Y] }, [G].
match_goal(d(X,Y), _) --> [parse_clpz(X, Y)]. match_goal(d(X,Y), _) --> [parse_clpz(X, Y)].
match_goal(g(Goal), _) --> [Goal]. match_goal(g(Goal), _) --> [Goal].
match_goal(p(Prop), _) --> match_goal(p(Prop0), _) -->
{ term_variables(Prop, Vs) }, { term_variables(Prop0, Vs),
morphing_propagator(Prop0, Prop, _) },
[make_propagator(Prop, P), [make_propagator(Prop, P),
new_queue(Q0), new_queue(Q0),
phrase(init_propagator_(Vs, P), [Q0], [Q]), phrase(init_propagator_(Vs, P), [Q0], [Q]),
@@ -3296,7 +3317,7 @@ integer_kroot_leq(L, U, N, K, R) :-
% When reasoning over integers, replace (=\=)/2 by (#\=)/2 to obtain more % When reasoning over integers, replace (=\=)/2 by (#\=)/2 to obtain more
% general relations. % general relations.
X #\= Y :- clpz_neq(X, Y), do_queue. X #\= Y :- clpz_neq(X, Y).
% X #\= Y + Z % X #\= Y + Z
@@ -3359,7 +3380,7 @@ X #< Y :- Y #> X.
% X in inf.. -4\/1..9\/81..sup. % X in inf.. -4\/1..9\/81..sup.
% ``` % ```
#\ Q :- reify(Q, 0), do_queue. #\ Q :- reify(Q, 0).
%% #<==>(?P, ?Q) %% #<==>(?P, ?Q)
% %
@@ -3397,7 +3418,7 @@ X #< Y :- Y #> X.
% Z = 2. % Z = 2.
% ``` % ```
L #<==> R :- reify(L, B), reify(R, B), do_queue. L #<==> R :- reify(L, B), reify(R, B).
%% #==>(?P, ?Q) %% #==>(?P, ?Q)
% %
@@ -3432,7 +3453,7 @@ L #<== R :- R #==> L.
% %
% P and Q hold. % P and Q hold.
L #/\ R :- reify(L, 1), reify(R, 1), do_queue. L #/\ R :- reify(L, 1), reify(R, 1).
conjunctive_neqs_var_drep(Eqs, Var, Drep) :- conjunctive_neqs_var_drep(Eqs, Var, Drep) :-
conjunctive_neqs_var(Eqs, Var), conjunctive_neqs_var(Eqs, Var),
@@ -3520,16 +3541,17 @@ L #\ R :- (L #\/ R) #/\ #\ (L #/\ R).
d(D) that states D is 1 iff all subexpressions are defined. a(V) d(D) that states D is 1 iff all subexpressions are defined. a(V)
means that V is an auxiliary variable that was introduced while means that V is an auxiliary variable that was introduced while
parsing a compound expression. a(X,V) means V is auxiliary unless parsing a compound expression. a(X,V) means V is auxiliary unless
it is ==/2 X, and a(X,Y,V) means V is auxiliary unless it is ==/2 X it is (==)/2 X, and a(X,Y,V) means V is auxiliary unless it is
or Y. l(L) means the literal L occurs in the described list. (==)/2 X or Y. l(L) means the literal L occurs in the described
list, and ls(Ls) means the literals Ls occur in the described list.
When a constraint becomes entailed or subexpressions become When a constraint becomes entailed or subexpressions become
undefined, created auxiliary constraints are killed, and the undefined, created auxiliary constraints are killed, and the
"clpz" attribute is removed from auxiliary variables. "clpz" attribute is removed from auxiliary variables.
For mod/2, div/2, rem/2 etc. we create a skeleton propagator and For (//)/2, (mod)/2 and (rem)/2, we create a skeleton propagator
remember it as an auxiliary constraint. The pskeleton propagator and remember it as an auxiliary constraint. The pskeleton
can use the skeleton when the constraint is defined. propagator can use the skeleton when the constraint is defined.
We cannot use a skeleton propagator for (/)/2, since (/)/2 can We cannot use a skeleton propagator for (/)/2, since (/)/2 can
fail in cases such as 0 #==> X #= 1/2, where we expect success. fail in cases such as 0 #==> X #= 1/2, where we expect success.
@@ -3545,27 +3567,32 @@ parse_reified(E, R, D,
m(A+B) => [d(D), p(pplus(A,B,R)), a(A,B,R)], m(A+B) => [d(D), p(pplus(A,B,R)), a(A,B,R)],
m(A*B) => [d(D), p(ptimes(A,B,R)), a(A,B,R)], m(A*B) => [d(D), p(ptimes(A,B,R)), a(A,B,R)],
m(A-B) => [d(D), p(pplus(R,B,A)), a(A,B,R)], m(A-B) => [d(D), p(pplus(R,B,A)), a(A,B,R)],
m(-A) => [d(D), p(ptimes(-1,A,R)), a(R)], m(-A) => [d(D), p(pplus(A,R,0)), a(R)],
m(max(A,B)) => [d(D), p(pgeq(R, A)), p(pgeq(R, B)), p(pmax(A,B,R)), a(A,B,R)], m(max(A,B)) => [d(D), p(pgeq(R, A)), p(pgeq(R, B)), p(pmax(A,B,R)), a(A,B,R)],
m(min(A,B)) => [d(D), p(pgeq(A, R)), p(pgeq(B, R)), p(pmin(A,B,R)), a(A,B,R)], m(min(A,B)) => [d(D), p(pgeq(A, R)), p(pgeq(B, R)), p(pmin(A,B,R)), a(A,B,R)],
m(abs(A)) => [g(#R#>=0), d(D), p(pabs(A, R)), a(A,R)], m(abs(A)) => [d(D), g(#R#>=0), p(pabs(A, R)), a(A,R)],
m(A/B) => [p(preified_slash(A,B,D,R)), a(A,B,R)], m(A^B) => [d(D1), p(preified_exp(A,B,D2,R)),
p(reified_and(D1,[],D2,[],D)),a(D2),a(A,B,R)],
m(A/B) => [d(D1), p(preified_slash(A,B,D2,R)),
p(reified_and(D1,[],D2,[],D)),a(D2),a(A,B,R)],
m(A div B) => [d(D1),
g(phrase(parse_reified_clpz(((A-(A mod B)) // B), R, D2), Ps)),
ls(Ps),
p(reified_and(D1,[],D2,[],D)),a(D2),a(A,B,R)],
m(A//B) => [skeleton(A,B,D,R,ptzdiv)], m(A//B) => [skeleton(A,B,D,R,ptzdiv)],
m(A div B) => [skeleton(A,B,D,R,pdiv)],
m(A mod B) => [skeleton(A,B,D,R,pmod)], m(A mod B) => [skeleton(A,B,D,R,pmod)],
m(A rem B) => [skeleton(A,B,D,R,prem)], m(A rem B) => [skeleton(A,B,D,R,prem)],
m(A^B) => [d(D), p(pexp(A,B,R)), a(A,B,R)],
% bitwise operations % bitwise operations
m(\A) => [function(D,\,A,R)], m(\A) => [function(D,\,A,R)],
m(msb(A)) => [g(#A#>0) ,function(D,msb,A,R)], m(msb(A)) => [g(#A#>0) ,function(D,msb,A,R)],
m(lsb(A)) => [g(#A#>0), function(D,lsb,A,R)], m(lsb(A)) => [g(#A#>0), function(D,lsb,A,R)],
m(popcount(A)) => [function(D,popcount,A,R)], m(popcount(A)) => [d(D), p(ppopcount(A, R)), a(A,R)],
m(sign(A)) => [function(D,sign,A,R)], m(sign(A)) => [d(D), p(psign(A, R)), a(A,R)],
m(A<<B) => [function(D,<<,A,B,R)], m(A<<B) => [function(D,<<,A,B,R)],
m(A>>B) => [function(D,>>,A,B,R)], m(A>>B) => [function(D,>>,A,B,R)],
m(A/\B) => [function(D,/\,A,B,R)], m(A/\B) => [function(D,/\,A,B,R)],
m(A\/B) => [function(D,\/,A,B,R)], m(A\/B) => [function(D,\/,A,B,R)],
m(xor(A, B)) => [function(D,xor,A,B,R)], m(xor(A, B)) => [skeleton(A,B,D,R,pxor)],
g(true) => [g(domain_error(clpz_expression, E))]] g(true) => [g(domain_error(clpz_expression, E))]]
). ).
@@ -3621,10 +3648,13 @@ reified_goal(d(D), Ds) -->
; { domain_error(one_or_two_element_list, Ds) } ; { domain_error(one_or_two_element_list, Ds) }
). ).
reified_goal(g(Goal), _) --> [{Goal}]. reified_goal(g(Goal), _) --> [{Goal}].
reified_goal(p(Vs, Prop), _) --> reified_goal(p(Vs, Prop0), _) -->
{ morphing_propagator(Prop0, Prop, Target) },
[{make_propagator(Prop, P)}], [{make_propagator(Prop, P)}],
target_propagator(Target),
parse_init_dcg(Vs, P), parse_init_dcg(Vs, P),
[{trigger_once(P)}], [{variables_same_queue(Vs),
trigger_once(P)}],
[( { propagator_state(P, S), S == dead } -> [] ; [p(P)])]. [( { propagator_state(P, S), S == dead } -> [] ; [p(P)])].
reified_goal(p(Prop), Ds) --> reified_goal(p(Prop), Ds) -->
{ term_variables(Prop, Vs) }, { term_variables(Prop, Vs) },
@@ -3634,7 +3664,9 @@ reified_goal(function(D,Op,A,B,R), Ds) -->
reified_goal(function(D,Op,A,R), Ds) --> reified_goal(function(D,Op,A,R), Ds) -->
reified_goals([d(D),p(pfunction(Op,A,R)),a(A,R)], Ds). reified_goals([d(D),p(pfunction(Op,A,R)),a(A,R)], Ds).
reified_goal(skeleton(A,B,D,R,F), Ds) --> reified_goal(skeleton(A,B,D,R,F), Ds) -->
{ Prop =.. [F,X,Y,Z] }, { Prop0 =.. [F,X,Y,Z],
morphing_propagator(Prop0, Prop, Target) },
target_propagator(Target),
reified_goals([d(D1),l(p(P)),g(make_propagator(Prop, P)), reified_goals([d(D1),l(p(P)),g(make_propagator(Prop, P)),
p([A,B,D2,R], pskeleton(A,B,D2,[X,Y,Z]-P,R,F)), p([A,B,D2,R], pskeleton(A,B,D2,[X,Y,Z]-P,R,F)),
p(reified_and(D1,[],D2,[],D)),a(D2),a(A,B,R)], Ds). p(reified_and(D1,[],D2,[],D)),a(D2),a(A,B,R)], Ds).
@@ -3642,12 +3674,20 @@ reified_goal(a(V), _) --> [a(V)].
reified_goal(a(X,V), _) --> [a(X,V)]. reified_goal(a(X,V), _) --> [a(X,V)].
reified_goal(a(X,Y,V), _) --> [a(X,Y,V)]. reified_goal(a(X,Y,V), _) --> [a(X,Y,V)].
reified_goal(l(L), _) --> [[L]]. reified_goal(l(L), _) --> [[L]].
reified_goal(ls(Ls), _) --> [Ls].
target_propagator(p(Prop)) --> [[p(Prop)]].
target_propagator(none) --> [].
parse_init_dcg([], _) --> []. parse_init_dcg([], _) --> [].
parse_init_dcg([V|Vs], P) --> [{init_propagator(V, P)}], parse_init_dcg(Vs, P). parse_init_dcg([V|Vs], P) --> [{init_propagator(V, P)}], parse_init_dcg(Vs, P).
%?- set_prolog_flag(answer_write_options, [portray(true)]), /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
% clpz:parse_reified_clauses(Cs), maplist(portray_clause, Cs). ?- use_module(library(lists)),
use_module(library(format)),
clpz:parse_reified_clauses(Cs),
maplist(portray_clause, Cs).
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
reify(E, B) :- reify(E, B, _). reify(E, B) :- reify(E, B, _).
@@ -3692,7 +3732,7 @@ reify_(tuples_in(Tuples, Relation), B) -->
#B #<==> And }, #B #<==> And },
propagator_init_trigger([B], tuples_not_in(Tuples, Relation, B)), propagator_init_trigger([B], tuples_not_in(Tuples, Relation, B)),
kill_reified_tuples(Bs, Ps, Bs), kill_reified_tuples(Bs, Ps, Bs),
list(Ps), seq(Ps),
as([B|Bs]). as([B|Bs]).
reify_(finite_domain(V), B) --> reify_(finite_domain(V), B) -->
propagator_init_trigger(reified_fd(V,B)), propagator_init_trigger(reified_fd(V,B)),
@@ -3724,20 +3764,17 @@ arithmetic(L, R, B, Functor) -->
{ phrase((parse_reified_clpz(L, LR, LD), { phrase((parse_reified_clpz(L, LR, LD),
parse_reified_clpz(R, RR, RD)), Ps), parse_reified_clpz(R, RR, RD)), Ps),
Prop =.. [Functor,LD,LR,RD,RR,Ps,B] }, Prop =.. [Functor,LD,LR,RD,RR,Ps,B] },
list(Ps), seq(Ps),
propagator_init_trigger([LD,LR,RD,RR,B], Prop), propagator_init_trigger([LD,LR,RD,RR,B], Prop),
a(B). a(B).
boolean(L, R, B, Functor) --> boolean(L, R, B, Functor) -->
{ reify(L, LR, Ps1), reify(R, RR, Ps2), { reify(L, LR, Ps1), reify(R, RR, Ps2),
Prop =.. [Functor,LR,Ps1,RR,Ps2,B] }, Prop =.. [Functor,LR,Ps1,RR,Ps2,B] },
list(Ps1), list(Ps2), seq(Ps1), seq(Ps2),
propagator_init_trigger([LR,RR,B], Prop), propagator_init_trigger([LR,RR,B], Prop),
a(LR, RR, B). a(LR, RR, B).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
a(X,Y,B) --> a(X,Y,B) -->
( nonvar(X) -> a(Y, B) ( nonvar(X) -> a(Y, B)
; nonvar(Y) -> a(X, B) ; nonvar(Y) -> a(X, B)
@@ -3872,7 +3909,6 @@ domain(V, Dom) :-
domains_intersection(Dom, Dom0, Dom1), domains_intersection(Dom, Dom0, Dom1),
%format("intersected\n: ~w\n ~w\n==> ~w\n\n", [Dom,Dom0,Dom1]), %format("intersected\n: ~w\n ~w\n==> ~w\n\n", [Dom,Dom0,Dom1]),
fd_put(V, Dom1, VPs), fd_put(V, Dom1, VPs),
do_queue,
reinforce(V) reinforce(V)
; domain_contains(Dom, V) ; domain_contains(Dom, V)
). ).
@@ -4187,7 +4223,6 @@ activate_propagator(propagator(P,State)) -->
enable_queue :- true. % NOP enable_queue :- true. % NOP
disable_queue :- true. % NOP disable_queue :- true. % NOP
do_queue. % NOP
%do_queue --> print_queue, { false }. %do_queue --> print_queue, { false }.
do_queue --> do_queue -->
@@ -4769,7 +4804,7 @@ run_propagator(scalar_product_eq(Cs0,Vs0,P0), MState) -->
) }. ) }.
% X + Y = Z % X + Y = Z
run_propagator(pplus(X,Y,Z), MState) --> run_propagator(pplus(X,Y,Z,Morph), MState) -->
( nonvar(X) -> ( nonvar(X) ->
( X =:= 0 -> kill(MState), Y = Z ( X =:= 0 -> kill(MState), Y = Z
; Y == Z -> kill(MState), X =:= 0 ; Y == Z -> kill(MState), X =:= 0
@@ -4788,7 +4823,7 @@ run_propagator(pplus(X,Y,Z), MState) -->
; [] ; []
) )
) )
; nonvar(Y) -> run_propagator(pplus(Y,X,Z), MState) ; nonvar(Y) -> run_propagator(pplus(Y,X,Z,Morph), MState)
; nonvar(Z) -> ; nonvar(Z) ->
( X == Y -> kill(MState), { even(Z), X is Z // 2 } ( X == Y -> kill(MState), { even(Z), X is Z // 2 }
; { fd_get(X, XD, _), ; { fd_get(X, XD, _),
@@ -4805,7 +4840,8 @@ run_propagator(pplus(X,Y,Z), MState) -->
; [] ; []
) )
) )
; ( X == Y -> { kill(MState), 2*X #= Z } ; ( X == Y ->
morph_into_propagator(MState, [X,Z], ptimes(2,X,Z), Morph)
; X == Z -> kill(MState), Y = 0 ; X == Z -> kill(MState), Y = 0
; Y == Z -> kill(MState), X = 0 ; Y == Z -> kill(MState), X = 0
; { fd_get(X, XD, XL, XU, XPs), ; { fd_get(X, XD, XL, XU, XPs),
@@ -4831,7 +4867,7 @@ run_propagator(pplus(X,Y,Z), MState) -->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
run_propagator(ptimes(X,Y,Z), MState) --> run_propagator(ptimes(X,Y,Z,Morph), MState) -->
( nonvar(X) -> ( nonvar(X) ->
( nonvar(Y) -> kill(MState), Z is X * Y ( nonvar(Y) -> kill(MState), Z is X * Y
; X =:= 0 -> kill(MState), Z = 0 ; X =:= 0 -> kill(MState), Z = 0
@@ -4851,7 +4887,7 @@ run_propagator(ptimes(X,Y,Z), MState) -->
) )
) )
) )
; nonvar(Y) -> run_propagator(ptimes(Y,X,Z), MState) ; nonvar(Y) -> run_propagator(ptimes(Y,X,Z,Morph), MState)
; nonvar(Z) -> ; nonvar(Z) ->
( X == Y -> ( X == Y ->
kill(MState), kill(MState),
@@ -4877,7 +4913,8 @@ run_propagator(ptimes(X,Y,Z), MState) -->
; neq_num(X, 0), neq_num(Y, 0) ; neq_num(X, 0), neq_num(Y, 0)
) )
) )
; ( X == Y -> kill(MState), { X^2 #= Z } ; ( X == Y ->
morph_into_propagator(MState, [X,Z], pexp(X,2,Z), Morph)
; { fd_get(X, XD, XL, XU, XPs), ; { fd_get(X, XD, XL, XU, XPs),
fd_get(Y, _, YL, YU, _), fd_get(Y, _, YL, YU, _),
fd_get(Z, ZD, ZL, ZU, _) }, fd_get(Z, ZD, ZL, ZU, _) },
@@ -4908,17 +4945,8 @@ run_propagator(ptimes(X,Y,Z), MState) -->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% X div Y = Z
run_propagator(pdiv(X,Y,Z), MState) -->
{ kill(MState), Z #= (X-(X mod Y)) // Y }.
% X rdiv Y = Z
run_propagator(prdiv(X,Y,Z), MState) -->
{ kill(MState), Z*Y #= X }.
% X // Y = Z (round towards zero) % X // Y = Z (round towards zero)
run_propagator(ptzdiv(X,Y,Z), MState) --> run_propagator(ptzdiv(X,Y,Z,Morph), MState) -->
( nonvar(X) -> ( nonvar(X) ->
( nonvar(Y) -> kill(MState), Y =\= 0, Z is X // Y ( nonvar(Y) -> kill(MState), Y =\= 0, Z is X // Y
; { fd_get(Y, YD, YL, YU, YPs) }, ; { fd_get(Y, YD, YL, YU, YPs) },
@@ -4962,7 +4990,8 @@ run_propagator(ptzdiv(X,Y,Z), MState) -->
; nonvar(Y) -> ; nonvar(Y) ->
Y =\= 0, Y =\= 0,
( Y =:= 1 -> kill(MState), X = Z ( Y =:= 1 -> kill(MState), X = Z
; Y =:= -1 -> kill(MState), { Z #= -X } ; Y =:= -1 ->
morph_into_propagator(MState, [X,Z], pplus(X,Z,0), Morph)
; { fd_get(X, XD, XL, XU, XPs) }, ; { fd_get(X, XD, XL, XU, XPs) },
( nonvar(Z) -> ( nonvar(Z) ->
kill(MState), kill(MState),
@@ -5412,9 +5441,11 @@ run_propagator(pmin(X,Y,Z), MState) -->
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% % Z = X ^ Y %% % Z = X ^ Y
run_propagator(pexp(X,Y,Z), MState) --> run_propagator(pexp(X,Y,Z,Morph), MState) -->
( X == 1 -> kill(MState), Z = 1 ( X == 1 -> kill(MState), Z = 1
; X == 0 -> kill(MState), queue_goal((Z in 0..1, Y #>= 0, Z #<==> Y #= 0)) ; X == 0 ->
queue_goal((Z in 0..1, Y #>= 0)),
morph_into_propagator(MState, [Y,Z], reified_eq(1,Y,1,0,[],Z), Morph)
; Y == 0 -> kill(MState), Z = 1 ; Y == 0 -> kill(MState), Z = 1
; Y == 1 -> kill(MState), Z = X ; Y == 1 -> kill(MState), Z = X
; nonvar(X) -> ; nonvar(X) ->
@@ -5474,7 +5505,9 @@ run_propagator(pexp(X,Y,Z), MState) -->
) )
; nonvar(Y), Y > 0 -> ; nonvar(Y), Y > 0 ->
( { even(Y) } -> ( { even(Y) } ->
{ geq(Z, 0) } { fd_get(Z, ZD0, ZPs0),
domain_remove_smaller_than(ZD0, 0, ZDG0) },
fd_put(Z, ZDG0, ZPs0)
; true ; true
), ),
( { fd_get(X, XD, XL, XU, _), fd_get(Z, ZD, ZL, ZU, ZPs) } -> ( { fd_get(X, XD, XL, XU, _), fd_get(Z, ZD, ZL, ZU, ZPs) } ->
@@ -5907,6 +5940,35 @@ run_propagator(preified_slash(X, Y, D, R), MState) -->
; [] ; []
). ).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
run_propagator(preified_exp(X, Y, D, R), MState) -->
( X == 1 ->
kill(MState),
D = 1,
R = 1
; Y == 0 ->
kill(MState),
D = 1,
R = 1
; Y == 1 ->
kill(MState),
D = 1,
R = X
; nonvar(X),
nonvar(Y) ->
kill(MState),
( ( abs(X) =:= 1 ; Y >= 0 ) ->
D = 1,
R is X^Y
; D = 0
)
; D == 1 ->
kill(MState),
queue_goal(X^Y #= R)
; []
).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -6055,7 +6117,7 @@ domain_to_list(Domain, List) :- phrase(domain_to_list(Domain), List).
domain_to_list(split(_, Left, Right)) --> domain_to_list(split(_, Left, Right)) -->
domain_to_list(Left), domain_to_list(Right). domain_to_list(Left), domain_to_list(Right).
domain_to_list(empty) --> []. domain_to_list(empty) --> [].
domain_to_list(from_to(n(F),n(T))) --> { numlist(F, T, Ns) }, list(Ns). domain_to_list(from_to(n(F),n(T))) --> { numlist(F, T, Ns) }, seq(Ns).
difference_arcs([], []) --> []. difference_arcs([], []) --> [].
difference_arcs([V|Vs], FL0) --> difference_arcs([V|Vs], FL0) -->
@@ -6415,8 +6477,7 @@ num_infinite(Var, N0, N) :-
weak_arc_all_distinct(Ls) :- weak_arc_all_distinct(Ls) :-
must_be(list, Ls), must_be(list, Ls),
Orig = original_goal(_, weak_arc_all_distinct(Ls)), Orig = original_goal(_, weak_arc_all_distinct(Ls)),
all_distinct(Ls, [], Orig), all_distinct(Ls, [], Orig).
do_queue.
all_distinct([], _, _). all_distinct([], _, _).
all_distinct([X|Right], Left, Orig) :- all_distinct([X|Right], Left, Orig) :-
@@ -6729,8 +6790,10 @@ gcc_pairs([Key-Num0|KNs], Vs, [Key-Num|Rest]) :-
gcc_global(Vs, KNs) :- gcc_global(Vs, KNs) :-
gcc_check(KNs), gcc_check(KNs),
% reach fix-point: all elements of clpz_gcc_vs must be variables % previously: call do_queue/0 (now a NOP) here to reach a
do_queue, % fix-point: all elements of clpz_gcc_vs must be variables. We
% must ensure this holds if gcc_check/1 is later rewritten to
% actually disable the queue.
with_local_attributes(Vs, with_local_attributes(Vs,
(gcc_arcs(KNs, S, Vals), (gcc_arcs(KNs, S, Vals),
variables_with_num_occurrences(Vs, VNs), variables_with_num_occurrences(Vs, VNs),
@@ -7753,7 +7816,7 @@ attributes_goals([propagator(P, State)|As]) -->
; maplist(unwrap_with(=), Gs, Gs1) ; maplist(unwrap_with(=), Gs, Gs1)
), ),
maplist(with_clpz, Gs1, Gs2) }, maplist(with_clpz, Gs1, Gs2) },
list(Gs2) seq(Gs2)
; [P] % possibly user-defined constraint ; [P] % possibly user-defined constraint
), ),
attributes_goals(As). attributes_goals(As).
@@ -7771,17 +7834,15 @@ bare_integer(V0, V) :- ( integer(V0) -> V = V0 ; V = #V0 ).
attribute_goal_(presidual(Goal)) --> [Goal]. attribute_goal_(presidual(Goal)) --> [Goal].
attribute_goal_(pgeq(A,B)) --> [#A #>= #B]. attribute_goal_(pgeq(A,B)) --> [#A #>= #B].
attribute_goal_(pplus(X,Y,Z)) --> [#X + #Y #= #Z]. attribute_goal_(pplus(X,Y,Z,_)) --> [#X + #Y #= #Z].
attribute_goal_(pneq(A,B)) --> [#A #\= #B]. attribute_goal_(pneq(A,B)) --> [#A #\= #B].
attribute_goal_(ptimes(X,Y,Z)) --> [#X * #Y #= #Z]. attribute_goal_(ptimes(X,Y,Z,_)) --> [#X * #Y #= #Z].
attribute_goal_(absdiff_neq(X,Y,C)) --> [abs(#X - #Y) #\= C]. attribute_goal_(absdiff_neq(X,Y,C)) --> [abs(#X - #Y) #\= C].
attribute_goal_(x_eq_abs_plus_v(X,V)) --> [#X #= abs(#X) + #V]. attribute_goal_(x_eq_abs_plus_v(X,V)) --> [#X #= abs(#X) + #V].
attribute_goal_(x_neq_y_plus_z(X,Y,Z)) --> [#X #\= #Y + #Z]. attribute_goal_(x_neq_y_plus_z(X,Y,Z)) --> [#X #\= #Y + #Z].
attribute_goal_(x_leq_y_plus_c(X,Y,C)) --> [#X #=< #Y + C]. attribute_goal_(x_leq_y_plus_c(X,Y,C)) --> [#X #=< #Y + C].
attribute_goal_(ptzdiv(X,Y,Z)) --> [#X // #Y #= #Z]. attribute_goal_(ptzdiv(X,Y,Z,_)) --> [#X // #Y #= #Z].
attribute_goal_(pdiv(X,Y,Z)) --> [#X div #Y #= #Z]. attribute_goal_(pexp(X,Y,Z,_)) --> [#X ^ #Y #= #Z].
attribute_goal_(prdiv(X,Y,Z)) --> [#X / #Y #= #Z].
attribute_goal_(pexp(X,Y,Z)) --> [#X ^ #Y #= #Z].
attribute_goal_(psign(X,Y)) --> [#Y #= sign(#X)]. attribute_goal_(psign(X,Y)) --> [#Y #= sign(#X)].
attribute_goal_(pabs(X,Y)) --> [#Y #= abs(#X)]. attribute_goal_(pabs(X,Y)) --> [#Y #= abs(#X)].
attribute_goal_(pmod(X,M,K)) --> [#X mod #M #= #K]. attribute_goal_(pmod(X,M,K)) --> [#X mod #M #= #K].
@@ -7841,6 +7902,7 @@ attribute_goal_(reified_and(X,_,Y,_,B)) --> [#X #/\ #Y #<==> #B].
attribute_goal_(reified_or(X, _, Y, _, B)) --> [#X #\/ #Y #<==> #B]. attribute_goal_(reified_or(X, _, Y, _, B)) --> [#X #\/ #Y #<==> #B].
attribute_goal_(reified_not(X, Y)) --> [#\ #X #<==> #Y]. attribute_goal_(reified_not(X, Y)) --> [#\ #X #<==> #Y].
attribute_goal_(preified_slash(X, Y, _, R)) --> [#X/ #Y #= R]. attribute_goal_(preified_slash(X, Y, _, R)) --> [#X/ #Y #= R].
attribute_goal_(preified_exp(X, Y, _, R)) --> [#X^ #Y #= R].
attribute_goal_(pimpl(X, Y, _)) --> [#X #==> #Y]. attribute_goal_(pimpl(X, Y, _)) --> [#X #==> #Y].
attribute_goal_(pfunction(Op, A, B, R)) --> attribute_goal_(pfunction(Op, A, B, R)) -->
{ Expr =.. [Op,#A,#B] }, { Expr =.. [Op,#A,#B] },

View File

@@ -1,5 +1,6 @@
use dashu::base::Abs; use dashu::base::{Abs, Gcd, UnsignedAbs};
use dashu::base::Gcd; use dashu::integer::IBig;
use dashu::integer::fast_div::ConstDivisor;
use divrem::*; use divrem::*;
use num_order::NumOrd; use num_order::NumOrd;
@@ -854,7 +855,9 @@ pub(crate) fn modulus(x: Number, y: Number, arena: &mut Arena) -> Result<Number,
} else if n1 < &Integer::ZERO && n2 > &Integer::ZERO { } else if n1 < &Integer::ZERO && n2 > &Integer::ZERO {
((n1 + Integer::ONE) / n2) - Integer::ONE ((n1 + Integer::ONE) / n2) - Integer::ONE
} else { } else {
n1 / n2 let ring = ConstDivisor::new(n2.unsigned_abs());
let n1 = n1.clone();
IBig::from(ring.reduce(n1).residue())
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1131,27 +1131,29 @@ impl MachineState {
#[inline] #[inline]
pub fn is_cyclic_term(&mut self, value: HeapCellValue) -> bool { pub fn is_cyclic_term(&mut self, value: HeapCellValue) -> bool {
if value.is_constant() { let value = self.store(self.deref(value));
if value.is_constant() || value.is_stack_var() {
return false; return false;
} }
let mut iter = stackful_preorder_iter::<NonListElider> let h = self.heap.len();
(&mut self.heap, &mut self.stack, value); self.heap.push(value);
while let Some(value) = iter.next() { let found_cycle = {
if value.get_forwarding_bit() { let mut iter = cycle_detecting_stackless_preorder_iter(&mut self.heap, h);
let value = unmark_cell_bits!(heap_bound_store(
iter.heap,
heap_bound_deref(iter.heap, value),
));
if value.is_compound(iter.heap) { while let Some(_) = iter.next() {
return true; if iter.found_cycle() {
} break;
} }
} }
false iter.found_cycle()
};
self.heap.pop();
found_cycle
} }
// arg(+N, +Term, ?Arg) // arg(+N, +Term, ?Arg)
@@ -1621,56 +1623,12 @@ impl MachineState {
// returns true on failure. // returns true on failure.
pub fn ground_test(&mut self) -> bool { pub fn ground_test(&mut self) -> bool {
use fxhash::FxBuildHasher; let iter = eager_stackful_preorder_iter(&mut self.heap, self.registers[1]);
if self.registers[1].is_constant() { for term in iter {
return false; if term.is_var() {
}
let value = self.store(self.deref(self.registers[1]));
if value.is_stack_var() {
return true; return true;
} }
let mut visited = IndexSet::with_hasher(FxBuildHasher::default());
let mut iter = stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, value);
let mut stack_len = 0;
let is_var = |heap: &Heap, value: HeapCellValue| -> bool {
let value = unmark_cell_bits!(value);
if value.is_var() {
let value = heap_bound_store(heap, heap_bound_deref(heap, value));
if value.is_var() {
return true;
}
}
false
};
while let Some(value) = iter.next() {
if is_var(iter.heap, value) {
return true;
}
if value.is_ref() {
if visited.contains(&value) {
while iter.stack_len() > stack_len {
if let Some(value) = iter.pop_stack() {
if is_var(iter.heap, value) {
return true;
}
}
}
} else {
visited.insert(value);
}
}
stack_len = iter.stack_len();
} }
false false

View File

@@ -584,20 +584,11 @@ impl MachineState {
seen_set: &mut IndexSet<HeapCellValue, S>, seen_set: &mut IndexSet<HeapCellValue, S>,
value: HeapCellValue, value: HeapCellValue,
) { ) {
let mut iter = stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, value); let iter = eager_stackful_preorder_iter(&mut self.heap, value);
while let Some(value) = iter.next() { for term in iter {
let value = unmark_cell_bits!(value); if term.is_var() {
seen_set.insert(term);
if value.is_var() {
let value = unmark_cell_bits!(heap_bound_store(
iter.heap,
heap_bound_deref(iter.heap, value)
));
if value.is_var() {
seen_set.insert(value);
}
} }
} }
} }
@@ -6891,6 +6882,17 @@ impl Machine {
return; return;
} }
let stored_v = if stored_v.is_stack_var() {
let h = self.machine_st.heap.len();
self.machine_st.heap.push(heap_loc_as_cell!(h));
self.machine_st.bind(Ref::heap_cell(h), stored_v);
heap_loc_as_cell!(h)
} else {
stored_v
};
let mut seen_set = IndexSet::with_hasher(FxBuildHasher::default()); let mut seen_set = IndexSet::with_hasher(FxBuildHasher::default());
self.machine_st.variable_set(&mut seen_set, stored_v); self.machine_st.variable_set(&mut seen_set, stored_v);

View File

@@ -691,6 +691,9 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
(HeapCellValueTag::Cons, ptr_1) => { (HeapCellValueTag::Cons, ptr_1) => {
Self::unify_constant(self, ptr_1, d2); Self::unify_constant(self, ptr_1, d2);
} }
(HeapCellValueTag::CutPoint, n1) => {
Self::unify_fixnum(self, n1, d2);
}
_ => { _ => {
unreachable!(); unreachable!();
} }

233
src/tests/acyclic_term.pl Normal file
View File

@@ -0,0 +1,233 @@
:- use_module(library(format)).
term1(A) :-
B=[C|D],
A=[D|C],
B=[C|B].
term2(A) :-
A=[B|C],
D=[C|C],
D=[B|D].
term3(A) :-
A=[_B|C],
D=[C|_E],
A=[C|D].
term4(A) :-
A=[B|C],
C=[C|B].
term5(A) :-
A=[_B|C],
D=[_E|C],
A=[C|D].
term6(A) :-
A=[B|B],
B=[C|C].
test("acyclic_term_1", (
L = [_Y,[M,B],B|M], acyclic_term(L)
)).
test("acyclic_term_2", (
L = [_Y,[M,_B,L]|M], \+ acyclic_term(L)
)).
test("acyclic_term_3", (
L = [_Y,[M,B,L,B]|M], \+ acyclic_term(L)
)).
test("acyclic_term_4", (
L = [_Y,[L,_A,_B]|_M], \+ acyclic_term(L)
)).
test("acyclic_term_5", (
L = [_Y,[M,_A,_B]|M], acyclic_term(L)
)).
test("acyclic_term_6", (
L = [_Y,[L,_A,_B]|_M], \+ acyclic_term(L)
)).
test("acyclic_term_7", (
L = [A], A = [T], T = [_|X], X = Y, Y = L, \+ acyclic_term(T)
)).
test("acyclic_term_8", (
L = [A], A = [T], T = [_|X], X = Y, Y = L, \+ acyclic_term(L)
)).
test("acyclic_term_9", (
L = [A], A = [T], T = [_|X], X = Y, Y = L, \+ acyclic_term(A)
)).
test("acyclic_term_10", (
L = [A], A = [T], T = [_|X], X = Y, Y = L, \+ acyclic_term(Y)
)).
test("acyclic_term_11", (
L = [A], A = [T], T = [_|X], X = Y, Y = L, \+ acyclic_term(X)
)).
test("acyclic_term_12", (
A = [1|2], X = A, T=a(X, A), acyclic_term(T)
)).
test("acyclic_term_13", (
A = [A|2], X = A, T=a(X, A), \+ acyclic_term(T)
)).
test("acyclic_term_13", (
A = [T|2], X = A, T=a(X, A), \+ acyclic_term(T)
)).
test("acyclic_term_14", (
T = [_A|T], \+ acyclic_term(T)
)).
test("acyclic_term_15", (
T = [T|_L], \+ acyclic_term(T)
)).
test("acyclic_term_16", (
A = [1|A], X = A, T=a(X, A), \+ acyclic_term(T)
)).
test("acyclic_term_17", (
T = [_A| [[[[L|T]|[]]]]], acyclic_term(L)
)).
test("acyclic_term_18", (
T = [A| [[[[_L|T]|[]]]]], acyclic_term(A)
)).
test("acyclic_term_19", (
T = [_A| [[[[_L|T]|[]]]]], \+ acyclic_term(T)
)).
test("acyclic_term_20", (
A = [_C|_B], X = A, T=a(t(X,A), A), acyclic_term(T)
)).
test("acyclic_term_21", (
X = [a | Rest], Rest = [_Y | Rest], \+ acyclic_term(X)
)).
test("acyclic_term_22", (
_X = [a | Rest], Rest = [_Y | Rest], \+ acyclic_term(Rest)
)).
test("acyclic_term_23", (
T = [[_A, T]], G = [1|T], \+ acyclic_term(G)
)).
test("acyclic_term_24", (
T = [[_A, T]], \+ acyclic_term(T)
)).
test("acyclic_term_25", (
T = [[_, _], T], \+ acyclic_term(T)
)).
test("acyclic_term_26", (
T = [[T, _], 1], \+ acyclic_term(T)
)).
test("acyclic_term_27", (
T = str(A,A), acyclic_term(T)
)).
test("acyclic_term_28", (
T = str(A,A,A), acyclic_term(T)
)).
test("acyclic_term_29", (
A = s(B, d(Y)), Y = B, acyclic_term(A),
acyclic_term(B), acyclic_term(Y)
)).
test("acyclic_term_30", (
A=str(B,B,B), C=str(A,_D,B), acyclic_term(C),
acyclic_term(A), acyclic_term(B)
)).
test("acyclic_term#2111_1", (
term1(A), \+ acyclic_term(A)
)).
test("acyclic_term#2111_2", (
term2(A), \+ acyclic_term(A)
)).
test("acyclic_term#2111_3", (
term3(A), \+ acyclic_term(A)
)).
test("acyclic_term#2111_4", (
term4(A), \+ acyclic_term(A)
)).
test("acyclic_term#2111_5", (
term5(A), \+ acyclic_term(A)
)).
test("acyclic_term#2111_6", (
term6(A), acyclic_term(A)
)).
test("acyclic_term#2113", (
A=[]*B,B=[]*B, \+ acyclic_term(A)
)).
test("acyclic_term#2114", (
A=B*B, acyclic_term(A)
)).
test("acyclic_term#2116", (
A=B*B,B=[]*[], acyclic_term(A)
)).
test("acyclic_term#2117", (
A=[]*A,B=[]*A, \+ acyclic_term(B)
)).
test("acyclic_term#2121", (
A=B*B, C=A*B, acyclic_term(C),
acyclic_term(A), acyclic_term(B)
)).
main :-
findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests(Tests, Failed),
show_failed(Failed),
halt.
main_quiet :-
findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests_quiet(Tests, Failed),
( Failed = [] ->
format("All tests passed", [])
; format("Some tests failed", [])
),
halt.
run_tests([], []).
run_tests([test(Name, Goal)|Tests], Failed) :-
format("Running test \"~s\"~n", [Name]),
( call(Goal) ->
Failed = Failed1
; format("Failed test \"~s\"~n", [Name]),
Failed = [Name|Failed1]
),
run_tests(Tests, Failed1).
run_tests_quiet([], []).
run_tests_quiet([test(Name, Goal)|Tests], Failed) :-
( call(Goal) ->
Failed = Failed1
; Failed = [Name|Failed1]
),
run_tests_quiet(Tests, Failed1).

83
src/tests/ground.pl Normal file
View File

@@ -0,0 +1,83 @@
/**/
:- use_module(library(format)).
:- use_module(library(dcgs)).
:- use_module(library(lists)).
:- use_module(library(debug)).
:- use_module(library(atts)).
:- attribute a/1.
a(Var) :- put_atts(Var, +a(hello)).
test("ground#239", (
% double negate to avoid residual goal being printed
\+ \+ (a(X), var(X), \+ ground(X))
)).
test("ground#1411",(
G_0 = ( A=s(A) ), G_0,
ground(A), ground(G_0)
)).
test("ground#2065",(
A = [B|_C], B = [A], \+ ground(B), \+ground([B])
)).
test("ground#2073",(
\+ ground(_-1+_-1),
\+ ground(1-1-_)
)).
test("ground#2075",(
G_0 = (_,_,ground(_)),
G_0 = (D=[D|_],_=D*[],ground(D)),
\+ G_0,
_=_B*_,_D=_B*_A,_B=_B*_D,\+ ground(_B),
A=[A|B],B=A*B,ground(A)
)).
main :-
findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests(Tests, Failed),
show_failed(Failed),
halt.
main_quiet :-
findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests_quiet(Tests, Failed),
( Failed = [] ->
format("All tests passed", [])
; format("Some tests failed", [])
),
halt.
run_tests([], []).
run_tests([test(Name, Goal)|Tests], Failed) :-
format("Running test \"~s\"~n", [Name]),
( call(Goal) ->
Failed = Failed1
; format("Failed test \"~s\"~n", [Name]),
Failed = [Name|Failed1]
),
run_tests(Tests, Failed1).
run_tests_quiet([], []).
run_tests_quiet([test(Name, Goal)|Tests], Failed) :-
( call(Goal) ->
Failed = Failed1
; Failed = [Name|Failed1]
),
run_tests_quiet(Tests, Failed1).
portray_failed_([]) --> [].
portray_failed_([F|Fs]) -->
"\"", F, "\"", "\n", portray_failed_(Fs).
portray_failed([]) --> [].
portray_failed([F|Fs]) -->
"\n", "Failed tests:", "\n", portray_failed_([F|Fs]).
show_failed(Failed) :-
phrase(portray_failed(Failed), F),
format("~s", [F]).

117
src/tests/term_variables.pl Normal file
View File

@@ -0,0 +1,117 @@
/**/
:- use_module(library(format)).
:- use_module(library(dcgs)).
:- use_module(library(lists)).
:- use_module(library(debug)).
test("term_variables#1400", (
term_variables(A+B*C/B-D, Vars),
term_variables(t(A,B,C,D), Vars),
Vars = [A,B,C,D]
)).
test("term_variables#1405", (
\+ (B=[C|D],C=[_|D],C=[B|B], term_variables(B,_), false)
)).
test("term_variables#1409", (
G_0 = (A=[B|B],A=[C|C]), G_0, term_variables(G_0, Vars), Vars = [B]
)).
test("term_variables#1410", (
\+ \+ (G_0 = ( A=s(A) ), G_0, term_variables(G_0, Vars), Vars = []),
E_0 = (_=[B|B]), G_0 = (E_0,\_=B), G_0, term_variables(G_0, Vars)
)).
test("term_variables#1412", (
G_0 = =([A|B],[A|B]), G_0, term_variables(G_0, Vars),
Vars = [A,B]
)).
test("term_variables#1414", (
\+ (\B=A,C=[A|D],B=[a,b|E],C=[D|E], term_variables(\E,_), false)
)).
test("term_variables#2063", (
A=[B|C], B=[A], term_variables([B], Vars),
Vars = [C]
)).
test("term_variables#2097", (
termt(T), term_variables(T,Vs),
T = [[[A|B]|A]|A], Vs == [A,B]
)).
test("term_variables#2100", (
termt2(T), term_variables(T,Vs),
T = [[T|A]|B], Vs == [A,B]
)).
test("term_variables#2101", (
termt3(T), term_variables(T,Vs),
T = [[[[A|B]|A]|A]|A], Vs == [A, B]
)).
termt(T) :-
T = [T1|T2],
T1 = [T3|A],
T3 = [A|_],
T2 = A.
termt2(T) :-
T = [T1|_B],
T1 = [T|_A].
termt3(T) :-
T = [T1|T0],
T1 = [T2|T3],
T2 = [T4|A],
T4 = [A|_],
T3 = A,
T0 = A.
main :-
findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests(Tests, Failed),
show_failed(Failed),
halt.
main_quiet :-
findall(test(Name, Goal), test(Name, Goal), Tests),
run_tests_quiet(Tests, Failed),
( Failed = [] ->
format("All tests passed", [])
; format("Some tests failed", [])
),
halt.
run_tests([], []).
run_tests([test(Name, Goal)|Tests], Failed) :-
format("Running test \"~s\"~n", [Name]),
( call(Goal) ->
Failed = Failed1
; format("Failed test \"~s\"~n", [Name]),
Failed = [Name|Failed1]
),
run_tests(Tests, Failed1).
run_tests_quiet([], []).
run_tests_quiet([test(Name, Goal)|Tests], Failed) :-
( call(Goal) ->
Failed = Failed1
; Failed = [Name|Failed1]
),
run_tests_quiet(Tests, Failed1).
portray_failed_([]) --> [].
portray_failed_([F|Fs]) -->
"\"", F, "\"", "\n", portray_failed_(Fs).
portray_failed([]) --> [].
portray_failed([F|Fs]) -->
"\n", "Failed tests:", "\n", portray_failed_([F|Fs]).
show_failed(Failed) :-
phrase(portray_failed(Failed), F),
format("~s", [F]).

View File

@@ -430,6 +430,7 @@ impl HeapCellValue {
HeapCellValueTag::Cons HeapCellValueTag::Cons
| HeapCellValueTag::F64 | HeapCellValueTag::F64
| HeapCellValueTag::Fixnum | HeapCellValueTag::Fixnum
| HeapCellValueTag::CutPoint
| HeapCellValueTag::Char | HeapCellValueTag::Char
| HeapCellValueTag::CStr => true, | HeapCellValueTag::CStr => true,
HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() == 0, HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() == 0,

View File

@@ -84,3 +84,30 @@ fn dif_tests() {
"All tests passed", "All tests passed",
); );
} }
#[test]
fn ground_tests() {
run_top_level_test_with_args(
&["src/tests/ground.pl", "-f", "-g", "main_quiet"],
"",
"All tests passed",
);
}
#[test]
fn term_variables_tests() {
run_top_level_test_with_args(
&["src/tests/term_variables.pl", "-f", "-g", "main_quiet"],
"",
"All tests passed",
);
}
#[test]
fn acyclic_term_tests() {
run_top_level_test_with_args(
&["src/tests/acyclic_term.pl", "-f", "-g", "main_quiet"],
"",
"All tests passed",
);
}