add findall/4, bagof/3, setof/3

This commit is contained in:
Mark Thom
2019-02-22 23:22:25 -07:00
parent 0f01d37618
commit 1d331757e2
6 changed files with 216 additions and 24 deletions

View File

@@ -15,16 +15,24 @@ impl Heap {
h: 0 }
}
#[inline]
pub fn push(&mut self, val: HeapCellValue) {
self.heap.push(val);
self.h += 1;
}
#[inline]
pub fn truncate(&mut self, h: usize) {
self.h = h;
self.heap.truncate(h);
}
#[inline]
pub fn last(&self) -> Option<&HeapCellValue> {
self.heap.last()
}
#[inline]
pub fn len(&self) -> usize {
self.heap.len()
}

View File

@@ -246,12 +246,14 @@ pub enum SystemClauseType {
EnqueueAttributedVar,
ExpandGoal,
ExpandTerm,
TruncateIfNoLiftedHeapGrowthDiff,
TruncateIfNoLiftedHeapGrowth,
GetAttributedVariableList,
GetAttrVarQueueDelimiter,
GetAttrVarQueueBeyond,
GetBValue,
GetLiftedHeapFromOffset,
GetLiftedHeapFromOffsetDiff,
GetSCCCleaner,
InstallSCCCleaner,
InstallInferenceCounter,
@@ -298,10 +300,12 @@ impl SystemClauseType {
&SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
&SystemClauseType::ExpandGoal => clause_name!("$expand_goal"),
&SystemClauseType::TruncateIfNoLiftedHeapGrowth => clause_name!("$truncate_if_no_lh_growth"),
&SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => clause_name!("$truncate_if_no_lh_growth_diff"),
&SystemClauseType::GetAttributedVariableList => clause_name!("$get_attr_list"),
&SystemClauseType::GetAttrVarQueueDelimiter => clause_name!("$get_attr_var_queue_delim"),
&SystemClauseType::GetAttrVarQueueBeyond => clause_name!("$get_attr_var_queue_beyond"),
&SystemClauseType::GetLiftedHeapFromOffset => clause_name!("$get_lh_from_offset"),
&SystemClauseType::GetLiftedHeapFromOffsetDiff => clause_name!("$get_lh_from_offset_diff"),
&SystemClauseType::GetBValue => clause_name!("$get_b_value"),
&SystemClauseType::GetDoubleQuotes => clause_name!("$get_double_quotes"),
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
@@ -349,9 +353,11 @@ impl SystemClauseType {
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
("$truncate_if_no_lh_growth", 1) => Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth),
("$truncate_if_no_lh_growth_diff", 2) => Some(SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff),
("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList),
("$get_b_value", 1) => Some(SystemClauseType::GetBValue),
("$get_lh_from_offset", 2) => Some(SystemClauseType::GetLiftedHeapFromOffset),
("$get_lh_from_offset_diff", 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff),
("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes),
("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner),
("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner),

View File

@@ -5,9 +5,9 @@
(rdiv)/2, (<<)/2, (>>)/2, (mod)/2, (rem)/2, (>)/2, (<)/2,
(=\=)/2, (=:=)/2, (-)/1, (>=)/2, (=<)/2, (,)/2, (->)/2, (;)/2,
(=..)/2, (==)/2, (\==)/2, (@=<)/2, (@>=)/2, (@<)/2, (@>)/2,
(=@=)/2, (\=@=)/2, (:)/2, call_with_inference_limit/3,
(=@=)/2, (\=@=)/2, (:)/2, bagof/3, call_with_inference_limit/3,
catch/3, current_prolog_flag/2, expand_goal/2, expand_term/2,
findall/3, set_prolog_flag/2, setup_call_cleanup/3,
findall/3, findall/4, set_prolog_flag/2, setof/3, setup_call_cleanup/3,
term_variables/2, throw/1, true/0, false/0, write/1,
write_canonical/1, writeq/1, write_term/2]).
@@ -363,12 +363,84 @@ throw(Ball) :- '$set_ball'(Ball), '$unwind_stack'.
truncate_lh_to(LhLength) :- '$truncate_lh_to'(LhLength).
findall(Template, Goal, Solutions) :-
'$skip_max_list'(_, -1, Solutions, R),
( nonvar(R), R \== [], throw(error(type_error(list, Solutions), findall/3))
check_for_compat_list(L) :-
'$skip_max_list'(_, -1, L, R),
( nonvar(R), R \== [], throw(error(type_error(list, L), findall/3))
; true
),
).
findall(Template, Goal, Solutions) :-
check_for_compat_list(Solutions),
'$lh_length'(LhLength),
'$call_with_default_policy'(catch('$iterate_find_all'(Template, Goal, Solutions, LhLength),
Error,
( truncate_lh_to(LhLength), throw(Error) ))).
:- non_counted_backtracking '$iterate_find_all_diff'/4.
'$iterate_find_all_diff'(Template, Goal, _, _, LhOffset) :-
call(Goal),
'$copy_to_lh'(LhOffset, Template),
'$fail'.
'$iterate_find_all_diff'(_, _, Solutions0, Solutions1, LhOffset) :-
'$truncate_if_no_lh_growth_diff'(LhOffset, Solutions1),
'$get_lh_from_offset_diff'(LhOffset, Solutions0, Solutions1).
findall(Template, Goal, Solutions0, Solutions1) :-
check_for_compat_list(Solutions0),
check_for_compat_list(Solutions1),
'$lh_length'(LhLength),
'$call_with_default_policy'(catch('$iterate_find_all_diff'(Template, Goal, Solutions0,
Solutions1, LhLength),
Error,
( truncate_lh_to(LhLength), throw(Error) ))).
set_difference([X|Xs], [Y|Ys], Zs) :-
X == Y, !, set_difference(Xs, [Y|Ys], Zs).
set_difference([X|Xs], [Y|Ys], [X|Zs]) :-
X @< Y, !, set_difference(Xs, [Y|Ys], Zs).
set_difference([X|Xs], [Y|Ys], Zs) :-
X @> Y, !, set_difference([X|Xs], Ys, Zs).
set_difference([], _, []) :- !.
set_difference(Xs, [], Xs).
group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :-
V1 =@= V2, !, V1 = V2, group_by_variant(Pairs, V2-S2, Solutions, Pairs0).
group_by_variant(Pairs, _, [], Pairs).
group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :-
group_by_variant([V-S|Pairs], V-S, Solution, Pairs0),
group_by_variants(Pairs0, Solutions).
group_by_variants([], []).
iterate_variants([V-Solution|GroupSolutions], V, Solution).
iterate_variants([_|GroupSolutions], Ws, Solution) :-
iterate_variants(GroupSolutions, Ws, Solution).
bagof(Template, Goal, Solution) :-
check_for_compat_list(Solution),
term_variables(Template, TemplateVars0),
term_variables(Goal, GoalVars0),
sort(TemplateVars0, TemplateVars),
sort(GoalVars0, GoalVars),
set_difference(GoalVars, TemplateVars, Witnesses),
findall(Witnesses-Template, Goal, PairedSolutions0),
keysort(PairedSolutions0, PairedSolutions),
group_by_variants(PairedSolutions, GroupedSolutions),
iterate_variants(GroupedSolutions, Witnesses, Solution).
iterate_variants_and_sort([V-Solution0|GroupSolutions], V, Solution) :-
sort(Solution0, Solution).
iterate_variants_and_sort([_|GroupSolutions], Ws, Solution) :-
iterate_variants_and_sort(GroupSolutions, Ws, Solution).
setof(Template, Goal, Solution) :-
term_variables(Template, TemplateVars0),
term_variables(Goal, GoalVars0),
sort(TemplateVars0, TemplateVars),
sort(GoalVars0, GoalVars),
set_difference(GoalVars, TemplateVars, Witnesses),
findall(Witnesses-Template, Goal, PairedSolutions0),
keysort(PairedSolutions0, PairedSolutions),
group_by_variants(PairedSolutions, GroupedSolutions),
iterate_variants_and_sort(GroupedSolutions, Witnesses, Solution).

View File

@@ -205,6 +205,23 @@ impl MachineState {
threshold + lh_offset + 2
}
fn truncate_if_no_lifted_heap_diff<AddrConstr>(&mut self, addr_constr: AddrConstr)
where AddrConstr: Fn(usize) -> Addr
{
match self.store(self.deref(self[temp_v!(1)].clone())) {
Addr::Con(Constant::Usize(lh_offset)) => {
if lh_offset >= self.lifted_heap.len() {
self.lifted_heap.truncate(lh_offset);
} else {
let threshold = self.lifted_heap.len() - lh_offset;
self.lifted_heap.push(HeapCellValue::Addr(addr_constr(threshold)));
}
},
_ =>
self.fail = true
}
}
pub(super) fn system_call(&mut self,
ct: &SystemClauseType,
indices: &IndexStore,
@@ -325,18 +342,10 @@ impl MachineState {
self.p = CodePtr::Local(LocalCodePtr::UserTermExpansion(0));
return Ok(());
},
&SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff =>
self.truncate_if_no_lifted_heap_diff(|h| Addr::HeapCell(h)),
&SystemClauseType::TruncateIfNoLiftedHeapGrowth =>
match self.store(self.deref(self[temp_v!(1)].clone())) {
Addr::Con(Constant::Usize(lh_offset)) => {
if lh_offset >= self.lifted_heap.len() {
self.lifted_heap.truncate(lh_offset);
} else {
self.lifted_heap.push(HeapCellValue::Addr(Addr::Con(Constant::EmptyList)));
}
},
_ =>
self.fail = true
},
self.truncate_if_no_lifted_heap_diff(|_| Addr::Con(Constant::EmptyList)),
&SystemClauseType::GetAttributedVariableList => {
let attr_var = self.store(self.deref(self[temp_v!(1)].clone()));
let mut attr_var_list = match attr_var {
@@ -381,8 +390,44 @@ impl MachineState {
_ => self.fail = true
}
},
&SystemClauseType::GetLiftedHeapFromOffsetDiff => {
let lh_offset = self[temp_v!(1)].clone();
match self.store(self.deref(lh_offset)) {
Addr::Con(Constant::Usize(lh_offset)) =>
if lh_offset >= self.lifted_heap.len() {
let solutions = self[temp_v!(2)].clone();
let diff = self[temp_v!(3)].clone();
self.unify(solutions, Addr::Con(Constant::EmptyList));
self.unify(diff, Addr::Con(Constant::EmptyList));
} else {
let h = self.heap.h;
for index in lh_offset .. self.lifted_heap.len() {
match self.lifted_heap[index].clone() {
HeapCellValue::Addr(addr) =>
self.heap.push(HeapCellValue::Addr(addr + h)),
value =>
self.heap.push(value)
}
}
if let Some(HeapCellValue::Addr(addr)) = self.heap.last().cloned() {
let diff = self[temp_v!(3)].clone();
self.unify(diff, addr);
}
self.lifted_heap.truncate(lh_offset);
let solutions = self[temp_v!(2)].clone();
self.unify(Addr::HeapCell(h), solutions);
},
_ => self.fail = true
}
},
&SystemClauseType::GetLiftedHeapFromOffset => {
let lh_offset = self[temp_v!(1)].clone();
let lh_offset = self[temp_v!(1)].clone();
match self.store(self.deref(lh_offset)) {
Addr::Con(Constant::Usize(lh_offset)) =>
@@ -391,7 +436,7 @@ impl MachineState {
self.unify(solutions, Addr::Con(Constant::EmptyList));
} else {
let h = self.heap.h;
for index in lh_offset .. self.lifted_heap.len() {
match self.lifted_heap[index].clone() {
HeapCellValue::Addr(addr) =>
@@ -402,7 +447,7 @@ impl MachineState {
}
self.lifted_heap.truncate(lh_offset);
let solutions = self[temp_v!(2)].clone();
self.unify(Addr::HeapCell(h), solutions);
},