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)]
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::machine::heap::*;
@@ -12,6 +13,145 @@ use modular_bitfield::prelude::*;
use std::ops::Deref;
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)]
#[bits = 2]
enum IterStackLocTag {
@@ -198,11 +338,6 @@ impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> {
None
}
#[inline]
pub fn stack_len(&self) -> usize {
self.stack.len()
}
fn push_if_unmarked(&mut self, loc: IterStackLoc) {
let cell = self.read_cell_mut(loc);
@@ -236,17 +371,17 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists>
let cell = self.read_cell(loc);
read_heap_cell!(cell,
(HeapCellValueTag::Lis |
HeapCellValueTag::Str |
HeapCellValueTag::PStrLoc, vh) => {
(HeapCellValueTag::Lis, vh) => {
let forward = if ElideLists::elide_lists() { true } else { cell.get_mark_bit() };
if forward && self.heap[vh].get_mark_bit() {
self.read_cell_mut(loc).set_forwarding_bit(true);
}
}
(HeapCellValueTag::AttrVar |
HeapCellValueTag::Var, vh) => {
(HeapCellValueTag::Str |
HeapCellValueTag::AttrVar |
HeapCellValueTag::Var |
HeapCellValueTag::PStrLoc, vh) => {
if self.heap[vh].get_mark_bit() {
self.read_cell_mut(loc).set_forwarding_bit(true);
}
@@ -374,11 +509,20 @@ impl<'a, ElideLists: ListElisionPolicy> Iterator for StackfulPreOrderHeapIter<'a
#[inline(always)]
pub(crate) fn stackless_preorder_iter(
heap: &mut Vec<HeapCellValue>,
cell: HeapCellValue,
start: usize,
) -> 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)]
pub(crate) fn stackful_preorder_iter<'a, ElideLists: ListElisionPolicy>(
heap: &'a mut Vec<HeapCellValue>,
@@ -529,9 +673,9 @@ pub(crate) type RightistPostOrderHeapIter<'a> =
#[inline]
pub(crate) fn stackless_post_order_iter<'a>(
heap: &'a mut Heap,
cell: HeapCellValue,
start: usize,
) -> RightistPostOrderHeapIter<'a> {
PostOrderIterator::new(stackless_preorder_iter(heap, cell))
PostOrderIterator::new(stackless_preorder_iter(heap, start))
}
#[cfg(test)]
@@ -551,8 +695,10 @@ mod tests {
.heap
.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!(
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 {
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!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -628,7 +776,7 @@ mod tests {
));
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!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -659,7 +807,7 @@ mod tests {
{
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!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -680,7 +828,7 @@ mod tests {
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!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -715,7 +863,7 @@ mod tests {
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!(
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);
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!(
@@ -764,8 +914,7 @@ mod tests {
assert_eq!(wam.machine_st.heap[0], pstr_cell);
assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1));
wam.machine_st.heap.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(2));
wam.machine_st.heap[1] = pstr_loc_as_cell!(3);
let pstr_second_var_cell =
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 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_second_cell);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
heap_loc_as_cell!(3),
heap_loc_as_cell!(4),
);
assert!(iter.next().is_none());
}
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[2], pstr_second_cell);
assert_eq!(wam.machine_st.heap[3], heap_loc_as_cell!(3));
assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(3));
assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(0));
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.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(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);
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_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[1]),
pstr_loc_as_cell!(2)
);
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)
pstr_loc_as_cell!(3)
);
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell);
assert_eq!(
unmark_cell_bits!(wam.machine_st.heap[4]),
pstr_offset_as_cell!(0)
pstr_loc_as_cell!(5)
);
assert_eq!(
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))
);
@@ -840,31 +993,31 @@ mod tests {
.heap
.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);
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()), fixnum_as_cell!(Fixnum::build_with(0)));
assert_eq!(iter.next(), None);
}
all_cells_unmarked(&wam.machine_st.heap);
wam.machine_st.heap.pop();
wam.machine_st
.heap
.push(fixnum_as_cell!(Fixnum::build_with(1i64)));
wam.machine_st.heap[5] = 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_second_cell);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_loc_as_cell!(4));
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -874,13 +1027,17 @@ mod tests {
unmark_cell_bits!(iter.next().unwrap()),
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.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);
wam.machine_st.heap.clear();
@@ -896,7 +1053,7 @@ mod tests {
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!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -933,26 +1090,13 @@ mod tests {
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);
}
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!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -999,7 +1143,7 @@ mod tests {
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!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -1031,7 +1175,7 @@ mod tests {
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!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -1069,19 +1213,6 @@ mod tests {
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);
}
@@ -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!(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(), None);
}
@@ -1129,7 +1260,7 @@ mod tests {
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!(
@@ -1137,10 +1268,6 @@ mod tests {
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);
}
@@ -1176,9 +1303,10 @@ mod tests {
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!(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));
@@ -1217,6 +1345,7 @@ mod tests {
let clpz_atom = atom!("clpz");
let p_atom = atom!("p");
wam.machine_st.heap.pop();
wam.machine_st.heap.pop();
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(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!(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));
@@ -1368,10 +1498,9 @@ mod tests {
wam.machine_st.heap.clear();
{
let mut iter = stackless_preorder_iter(
&mut wam.machine_st.heap,
fixnum_as_cell!(Fixnum::build_with(0)),
);
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0)));
let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -1383,8 +1512,6 @@ mod tests {
all_cells_unmarked(&wam.machine_st.heap);
assert_eq!(wam.machine_st.heap.len(), 0);
wam.machine_st.heap.clear();
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")));
{
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!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -1406,7 +1533,7 @@ mod tests {
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());
}
@@ -1418,9 +1545,10 @@ mod tests {
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(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!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -1453,7 +1581,7 @@ mod tests {
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!(
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(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!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -1540,38 +1669,68 @@ mod tests {
wam.machine_st.heap.clear();
// representation of one of the heap terms as in issue #1384.
/*
wam.machine_st.heap.push(list_loc_as_cell!(7));
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));
wam.machine_st.heap.push(list_loc_as_cell!(7)); // 0
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
{
let mut iter = stackless_preorder_iter(
&mut wam.machine_st.heap,
heap_loc_as_cell!(0),
);
wam.machine_st.heap.push(heap_loc_as_cell!(0));
while let Some(_) = iter.next() {
print_heap_terms(iter.heap.iter(), 0);
println!("");
}
{
let mut iter = stackless_preorder_iter(
&mut wam.machine_st.heap,
9,
);
/*
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(atom!("f"), 2)
);
/*
while let Some(_) = iter.next() {
print_heap_terms(iter.heap.iter(), 0);
println!("");
}
*/
assert!(iter.next().is_none());
*/
}
*/
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
list_loc_as_cell!(7)
);
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]
@@ -2663,8 +2822,10 @@ mod tests {
.heap
.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!(
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 {
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));
@@ -2726,7 +2889,7 @@ mod tests {
wam.machine_st.heap.push(heap_loc_as_cell!(0));
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!(
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!(0));
let mut iter =
stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -2769,7 +2931,7 @@ mod tests {
{
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!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -2802,7 +2964,7 @@ mod tests {
{
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.
assert_eq!(
@@ -2831,7 +2993,7 @@ mod tests {
{
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
// 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);
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_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!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -2879,6 +3043,7 @@ mod tests {
assert_eq!(iter.next(), None);
}
wam.machine_st.heap.pop();
wam.machine_st.heap.pop();
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];
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
{
let mut iter =
stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 4);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -2914,9 +3080,10 @@ mod tests {
.heap
.push(fixnum_as_cell!(Fixnum::build_with(0)));
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
{
let mut iter =
stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 7);
let mut pstr_loc_cell = pstr_loc_as_cell!(0);
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!(
unmark_cell_bits!(iter.next().unwrap()),
pstr_offset_as_cell!(0)
);
assert_eq!(
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_second_cell);
@@ -2939,28 +3102,27 @@ mod tests {
all_cells_unmarked(&wam.machine_st.heap);
wam.machine_st.heap.pop();
wam.machine_st.heap.pop();
wam.machine_st
.heap
.push(fixnum_as_cell!(Fixnum::build_with(1)));
wam.machine_st.heap.push(pstr_loc_as_cell!(0));
{
let mut iter =
stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0));
let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 7);
//assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1)));
assert_eq!(
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)
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!(iter.next(), None);
}
@@ -2976,9 +3138,10 @@ mod tests {
wam.machine_st.heap.extend(functor);
wam.machine_st.heap.push(heap_loc_as_cell!(0));
{
let mut iter =
stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 9);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -3008,18 +3171,6 @@ mod tests {
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!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(f_atom, 3)
@@ -3038,8 +3189,7 @@ mod tests {
wam.machine_st.heap[4] = list_loc_as_cell!(1);
{
let mut iter =
stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
@@ -3059,25 +3209,15 @@ mod tests {
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!(
unmark_cell_bits!(iter.next().unwrap()),
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!(
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
!.
:- non_counted_backtracking get_cp/1.
get_cp(B) :- '$get_cp'(B).
:- non_counted_backtracking set_cp/1.
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.
dispatch_prep(Gs, B, [Cont|Conts]) :-
dispatch_prep(Gs, B, Conts) :-
( callable(Gs) ->
strip_module(Gs, M, Gs0),
( nonvar(Gs0),
dispatch_prep_(Gs0, B, [Cont|Conts]) ->
dispatch_prep_(Gs0, B, Conts) ->
true
; Gs0 == ! ->
Cont = '$call'(builtins:set_cp(B)),
Conts = []
Conts = ['$call'(builtins:set_cp(B))]
; nonvar(Gs0),
\+ callable(Gs0) ->
throw(dispatch_prep_error)
; Cont = Gs,
Conts = []
; Conts = [Gs]
)
; var(Gs) ->
Cont = Gs,
Conts = []
Conts = [Gs]
; throw(dispatch_prep_error)
).
@@ -387,20 +387,32 @@ dispatch_prep_((G1, G2), B, [Cont|Conts]) :-
dispatch_prep(G1, B, IConts1),
cont_list_goal(IConts1, Cont),
dispatch_prep(G2, B, Conts).
dispatch_prep_((G1 ; G2), B, [Cont|Conts]) :-
dispatch_prep(G1, B, IConts0),
dispatch_prep_((G1 ; G2), B, Conts) :-
( 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),
cont_list_goal(IConts0, Cont0),
cont_list_goal(IConts1, Cont1),
Cont = '$call'(builtins:staggered_sc(Cont0, Cont1)),
Conts = [].
dispatch_prep_((G1 -> G2), B, [Cont|Conts]) :-
dispatch_prep(G1, B, IConts1),
Conts = ['$call'(builtins:staggered_sc(Cont0, Cont1))].
dispatch_prep_((G1 -> G2), B, Conts) :-
dispatch_prep(G1, B1, IConts1),
dispatch_prep(G2, B, IConts2),
cont_list_goal(IConts1, Cont1),
cont_list_goal(IConts2, Cont2),
Cont = '$call'(builtins:staggered_if_then(Cont1, Cont2)),
Conts = [].
Conts = ['$call'(builtins:get_cp(B1)),
'$call'(builtins:staggered_if_then(Cont1, Cont2))].
:- 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)).
duodcg_body([], (As0=As,Bs0=Bs), As0, As, Bs0, Bs).
duodcg_body(Xs+Ys, (phrase(list(Xs), As0, As),
phrase(list(Ys), Bs0, Bs)), As0, As, Bs0, Bs).
duodcg_body(Xs+Ys, (phrase(seq(Xs), As0, As),
phrase(seq(Ys), Bs0, Bs)), As0, As, Bs0, Bs).
duodcg_body({Goal}, call(Goal), As, As, Bs, Bs).
duodcg_body((A0,B0), (A,B), As0, As, Bs0, Bs) :-
duodcg_body(A0, A, As0, As1, Bs0, Bs1),
@@ -1957,7 +1957,6 @@ choice_order_variable(step, Order, Var, Vars, Vars0, Selection, Consistency) :-
( Var = Next,
label(Vars, Selection, Order, step, Consistency)
; neq_num(Var, Next),
do_queue,
label(Vars0, Selection, Order, step, 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))],
m(A*B) => [p(ptimes(A, B, R))],
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(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 rem B) => [g(B #\= 0), p(prem(A, B, 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 div B) => [g(#R #= (A - (A mod B)) // B)],
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_goal(g(Goal)) --> [Goal].
parse_goal(p(Prop)) -->
{ term_variables(Prop, Vs) },
parse_goal(p(Prop0)) -->
{ term_variables(Prop0, Vs),
morphing_propagator(Prop0, Prop, _) },
[make_propagator(Prop, P),
new_queue(Q0),
phrase(init_propagator_(Vs, P), [Q0], [Q]),
variables_same_queue(Vs),
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(format)),
@@ -2734,14 +2756,12 @@ geq(A, B) :-
)
; ( AI cis_geq n(B) -> true
; domain_remove_smaller_than(AD, B, AD1),
fd_put(A, AD1, APs),
do_queue
fd_put(A, AD1, APs)
)
)
; fd_get(B, BD, BPs) ->
domain_remove_greater_than(BD, A, BD1),
fd_put(B, BD1, BPs),
do_queue
fd_put(B, BD1, BPs)
; 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(X,Z,Y))],
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)) =>
[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))],
@@ -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(d(X,Y), _) --> [parse_clpz(X, Y)].
match_goal(g(Goal), _) --> [Goal].
match_goal(p(Prop), _) -->
{ term_variables(Prop, Vs) },
match_goal(p(Prop0), _) -->
{ term_variables(Prop0, Vs),
morphing_propagator(Prop0, Prop, _) },
[make_propagator(Prop, P),
new_queue(Q0),
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
% general relations.
X #\= Y :- clpz_neq(X, Y), do_queue.
X #\= Y :- clpz_neq(X, Y).
% X #\= Y + Z
@@ -3359,7 +3380,7 @@ X #< Y :- Y #> X.
% X in inf.. -4\/1..9\/81..sup.
% ```
#\ Q :- reify(Q, 0), do_queue.
#\ Q :- reify(Q, 0).
%% #<==>(?P, ?Q)
%
@@ -3397,7 +3418,7 @@ X #< Y :- Y #> X.
% Z = 2.
% ```
L #<==> R :- reify(L, B), reify(R, B), do_queue.
L #<==> R :- reify(L, B), reify(R, B).
%% #==>(?P, ?Q)
%
@@ -3432,7 +3453,7 @@ L #<== R :- R #==> L.
%
% 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(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)
means that V is an auxiliary variable that was introduced while
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
or Y. l(L) means the literal L occurs in the described list.
it is (==)/2 X, and a(X,Y,V) means V is auxiliary unless it is
(==)/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
undefined, created auxiliary constraints are killed, and the
"clpz" attribute is removed from auxiliary variables.
For mod/2, div/2, rem/2 etc. we create a skeleton propagator and
remember it as an auxiliary constraint. The pskeleton propagator
can use the skeleton when the constraint is defined.
For (//)/2, (mod)/2 and (rem)/2, we create a skeleton propagator
and remember it as an auxiliary constraint. The pskeleton
propagator can use the skeleton when the constraint is defined.
We cannot use a skeleton propagator for (/)/2, since (/)/2 can
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(ptimes(A,B,R)), 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(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(A/B) => [p(preified_slash(A,B,D,R)), a(A,B,R)],
m(abs(A)) => [d(D), g(#R#>=0), p(pabs(A, R)), a(A,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 div B) => [skeleton(A,B,D,R,pdiv)],
m(A mod B) => [skeleton(A,B,D,R,pmod)],
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
m(\A) => [function(D,\,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(popcount(A)) => [function(D,popcount,A,R)],
m(sign(A)) => [function(D,sign,A,R)],
m(popcount(A)) => [d(D), p(ppopcount(A, R)), a(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(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))]]
).
@@ -3621,10 +3648,13 @@ reified_goal(d(D), Ds) -->
; { domain_error(one_or_two_element_list, Ds) }
).
reified_goal(g(Goal), _) --> [{Goal}].
reified_goal(p(Vs, Prop), _) -->
reified_goal(p(Vs, Prop0), _) -->
{ morphing_propagator(Prop0, Prop, Target) },
[{make_propagator(Prop, P)}],
target_propagator(Target),
parse_init_dcg(Vs, P),
[{trigger_once(P)}],
[{variables_same_queue(Vs),
trigger_once(P)}],
[( { propagator_state(P, S), S == dead } -> [] ; [p(P)])].
reified_goal(p(Prop), Ds) -->
{ 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_goals([d(D),p(pfunction(Op,A,R)),a(A,R)], 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)),
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).
@@ -3642,12 +3674,20 @@ reified_goal(a(V), _) --> [a(V)].
reified_goal(a(X,V), _) --> [a(X,V)].
reified_goal(a(X,Y,V), _) --> [a(X,Y,V)].
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([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, _).
@@ -3692,7 +3732,7 @@ reify_(tuples_in(Tuples, Relation), B) -->
#B #<==> And },
propagator_init_trigger([B], tuples_not_in(Tuples, Relation, B)),
kill_reified_tuples(Bs, Ps, Bs),
list(Ps),
seq(Ps),
as([B|Bs]).
reify_(finite_domain(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),
parse_reified_clpz(R, RR, RD)), Ps),
Prop =.. [Functor,LD,LR,RD,RR,Ps,B] },
list(Ps),
seq(Ps),
propagator_init_trigger([LD,LR,RD,RR,B], Prop),
a(B).
boolean(L, R, B, Functor) -->
{ reify(L, LR, Ps1), reify(R, RR, Ps2),
Prop =.. [Functor,LR,Ps1,RR,Ps2,B] },
list(Ps1), list(Ps2),
seq(Ps1), seq(Ps2),
propagator_init_trigger([LR,RR,B], Prop),
a(LR, RR, B).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
a(X,Y,B) -->
( nonvar(X) -> a(Y, B)
; nonvar(Y) -> a(X, B)
@@ -3872,7 +3909,6 @@ domain(V, Dom) :-
domains_intersection(Dom, Dom0, Dom1),
%format("intersected\n: ~w\n ~w\n==> ~w\n\n", [Dom,Dom0,Dom1]),
fd_put(V, Dom1, VPs),
do_queue,
reinforce(V)
; domain_contains(Dom, V)
).
@@ -4187,7 +4223,6 @@ activate_propagator(propagator(P,State)) -->
enable_queue :- true. % NOP
disable_queue :- true. % NOP
do_queue. % NOP
%do_queue --> print_queue, { false }.
do_queue -->
@@ -4769,7 +4804,7 @@ run_propagator(scalar_product_eq(Cs0,Vs0,P0), MState) -->
) }.
% X + Y = Z
run_propagator(pplus(X,Y,Z), MState) -->
run_propagator(pplus(X,Y,Z,Morph), MState) -->
( nonvar(X) ->
( X =:= 0 -> kill(MState), Y = Z
; 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) ->
( X == Y -> kill(MState), { even(Z), X is Z // 2 }
; { 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
; Y == Z -> kill(MState), X = 0
; { 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(Y) -> kill(MState), Z is X * Y
; 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) ->
( X == Y ->
kill(MState),
@@ -4877,7 +4913,8 @@ run_propagator(ptimes(X,Y,Z), MState) -->
; 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(Y, _, YL, YU, _),
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)
run_propagator(ptzdiv(X,Y,Z), MState) -->
run_propagator(ptzdiv(X,Y,Z,Morph), MState) -->
( nonvar(X) ->
( nonvar(Y) -> kill(MState), Y =\= 0, Z is X // Y
; { fd_get(Y, YD, YL, YU, YPs) },
@@ -4962,7 +4990,8 @@ run_propagator(ptzdiv(X,Y,Z), MState) -->
; nonvar(Y) ->
Y =\= 0,
( 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) },
( nonvar(Z) ->
kill(MState),
@@ -5412,9 +5441,11 @@ run_propagator(pmin(X,Y,Z), MState) -->
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% % 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 == 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 == 1 -> kill(MState), Z = X
; nonvar(X) ->
@@ -5474,7 +5505,9 @@ run_propagator(pexp(X,Y,Z), MState) -->
)
; nonvar(Y), Y > 0 ->
( { even(Y) } ->
{ geq(Z, 0) }
{ fd_get(Z, ZD0, ZPs0),
domain_remove_smaller_than(ZD0, 0, ZDG0) },
fd_put(Z, ZDG0, ZPs0)
; true
),
( { 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(Left), domain_to_list(Right).
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([V|Vs], FL0) -->
@@ -6415,8 +6477,7 @@ num_infinite(Var, N0, N) :-
weak_arc_all_distinct(Ls) :-
must_be(list, Ls),
Orig = original_goal(_, weak_arc_all_distinct(Ls)),
all_distinct(Ls, [], Orig),
do_queue.
all_distinct(Ls, [], Orig).
all_distinct([], _, _).
all_distinct([X|Right], Left, Orig) :-
@@ -6729,8 +6790,10 @@ gcc_pairs([Key-Num0|KNs], Vs, [Key-Num|Rest]) :-
gcc_global(Vs, KNs) :-
gcc_check(KNs),
% reach fix-point: all elements of clpz_gcc_vs must be variables
do_queue,
% previously: call do_queue/0 (now a NOP) here to reach a
% 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,
(gcc_arcs(KNs, S, Vals),
variables_with_num_occurrences(Vs, VNs),
@@ -7753,7 +7816,7 @@ attributes_goals([propagator(P, State)|As]) -->
; maplist(unwrap_with(=), Gs, Gs1)
),
maplist(with_clpz, Gs1, Gs2) },
list(Gs2)
seq(Gs2)
; [P] % possibly user-defined constraint
),
attributes_goals(As).
@@ -7771,17 +7834,15 @@ bare_integer(V0, V) :- ( integer(V0) -> V = V0 ; V = #V0 ).
attribute_goal_(presidual(Goal)) --> [Goal].
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_(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_(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_leq_y_plus_c(X,Y,C)) --> [#X #=< #Y + C].
attribute_goal_(ptzdiv(X,Y,Z)) --> [#X // #Y #= #Z].
attribute_goal_(pdiv(X,Y,Z)) --> [#X div #Y #= #Z].
attribute_goal_(prdiv(X,Y,Z)) --> [#X / #Y #= #Z].
attribute_goal_(pexp(X,Y,Z)) --> [#X ^ #Y #= #Z].
attribute_goal_(ptzdiv(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_(pabs(X,Y)) --> [#Y #= abs(#X)].
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_not(X, Y)) --> [#\ #X #<==> #Y].
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_(pfunction(Op, A, B, R)) -->
{ Expr =.. [Op,#A,#B] },

View File

@@ -1,5 +1,6 @@
use dashu::base::Abs;
use dashu::base::Gcd;
use dashu::base::{Abs, Gcd, UnsignedAbs};
use dashu::integer::IBig;
use dashu::integer::fast_div::ConstDivisor;
use divrem::*;
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 {
((n1 + Integer::ONE) / n2) - Integer::ONE
} 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]
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;
}
let mut iter = stackful_preorder_iter::<NonListElider>
(&mut self.heap, &mut self.stack, value);
let h = self.heap.len();
self.heap.push(value);
while let Some(value) = iter.next() {
if value.get_forwarding_bit() {
let value = unmark_cell_bits!(heap_bound_store(
iter.heap,
heap_bound_deref(iter.heap, value),
));
let found_cycle = {
let mut iter = cycle_detecting_stackless_preorder_iter(&mut self.heap, h);
if value.is_compound(iter.heap) {
return true;
while let Some(_) = iter.next() {
if iter.found_cycle() {
break;
}
}
}
false
iter.found_cycle()
};
self.heap.pop();
found_cycle
}
// arg(+N, +Term, ?Arg)
@@ -1621,56 +1623,12 @@ impl MachineState {
// returns true on failure.
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() {
return false;
}
let value = self.store(self.deref(self.registers[1]));
if value.is_stack_var() {
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) {
for term in iter {
if term.is_var() {
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

View File

@@ -584,20 +584,11 @@ impl MachineState {
seen_set: &mut IndexSet<HeapCellValue, S>,
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() {
let value = unmark_cell_bits!(value);
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);
}
for term in iter {
if term.is_var() {
seen_set.insert(term);
}
}
}
@@ -6891,6 +6882,17 @@ impl Machine {
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());
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) => {
Self::unify_constant(self, ptr_1, d2);
}
(HeapCellValueTag::CutPoint, n1) => {
Self::unify_fixnum(self, n1, d2);
}
_ => {
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::F64
| HeapCellValueTag::Fixnum
| HeapCellValueTag::CutPoint
| HeapCellValueTag::Char
| HeapCellValueTag::CStr => true,
HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() == 0,

View File

@@ -84,3 +84,30 @@ fn dif_tests() {
"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",
);
}