UnattributedVar,
#[strum_discriminants(strum(props(Arity = "4", Name = "$get_db_refs")))]
GetDBRefs,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$keysort_with_constant_var_ordering")))]
+ KeySortWithConstantVarOrdering,
REPL(REPLCodePtr),
}
&Instruction::CallDeleteAllAttributesFromVar |
&Instruction::CallUnattributedVar |
&Instruction::CallGetDBRefs |
+ &Instruction::CallKeySortWithConstantVarOrdering |
&Instruction::CallFetchGlobalVar |
&Instruction::CallFirstStream |
&Instruction::CallFlushOutput |
&Instruction::ExecuteDeleteAllAttributesFromVar |
&Instruction::ExecuteUnattributedVar |
&Instruction::ExecuteGetDBRefs |
+ &Instruction::ExecuteKeySortWithConstantVarOrdering |
&Instruction::ExecuteFetchGlobalVar |
&Instruction::ExecuteFirstStream |
&Instruction::ExecuteFlushOutput |
}
}
+#[derive(Debug)]
+pub enum VarComparison {
+ Indistinct,
+ Distinct
+}
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Level {
Deep,
set_difference([], _, []) :- !.
set_difference(Xs, [], Xs).
+
+% variant/2 checks whether X is a variant of Y per the definition in
+% 7.1.6.1 of the ISO standard.
+
+:- non_counted_backtracking variant/4.
+
+variant(X,Y,VPs,VPs0) :-
+ ( var(X) ->
+ var(Y),
+ VPs = [X-Y|VPs0]
+ ; var(Y) ->
+ false
+ ; X =.. [FX | XArgs],
+ Y =.. [FX | YArgs],
+ lists:foldl('$call'(builtins:variant), XArgs, YArgs, VPs, VPs0)
+ ).
+
+:- non_counted_backtracking variant/2.
+
+singleton([_]).
+
+variant(X, Y) :-
+ variant(X,Y, VPs, []),
+ keysort(VPs, SVPs),
+ pairs:group_pairs_by_key(SVPs, SVPKs),
+ pairs:pairs_values(SVPKs, Vals),
+ lists:maplist('$call'(builtins:term_variables), Vals, Vs),
+ lists:maplist('$call'(builtins:singleton), Vs),
+ term_variables(Vs, YVars),
+ lists:length(SVPKs, N),
+ lists:length(YVars, N).
+
+
:- non_counted_backtracking group_by_variant/4.
group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :-
- V1 = V2, % \+ \+ (V1 = V2), % (2) % iso_ext:variant(V1, V2), % (1)
+ variant(V1, V2),
!,
- % V1 = V2, % (3)
+ V1 = V2,
group_by_variant(Pairs, V2-S2, Solutions, Pairs0).
group_by_variant(Pairs, _, [], Pairs).
term_variables(TemplateVars+GoalVars, TGVs),
lists:append(TemplateVars, Witnesses0, TGVs),
findall_with_existential(Template, Goal, PairedSolutions0, Witnesses0, Witnesses),
- keysort(PairedSolutions0, PairedSolutions),
+ '$keysort_with_constant_var_ordering'(PairedSolutions0, PairedSolutions), % see 7.2.1
group_by_variants(PairedSolutions, GroupedSolutions),
iterate_variants_and_sort(GroupedSolutions, Witnesses, Solution).
Ok(())
}
- fn keysort(&mut self) -> CallResult {
+ fn keysort(&mut self, var_comparison: VarComparison) -> CallResult {
self.check_keysort_errors()?;
let stub_gen = || functor_stub(atom!("keysort"), 2);
}
key_pairs.sort_by(|a1, a2| {
- compare_term_test!(self, a1.0, a2.0).unwrap_or(Ordering::Less)
+ compare_term_test!(self, a1.0, a2.0, var_comparison).unwrap_or(Ordering::Less)
});
let key_pairs = key_pairs.into_iter().map(|kp| kp.1);
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::DefaultCallKeySort => {
- try_or_throw!(self.machine_st, self.machine_st.keysort());
+ try_or_throw!(self.machine_st, self.machine_st.keysort(VarComparison::Distinct));
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::DefaultExecuteKeySort => {
- try_or_throw!(self.machine_st, self.machine_st.keysort());
+ try_or_throw!(self.machine_st, self.machine_st.keysort(VarComparison::Distinct));
if self.machine_st.fail {
self.machine_st.backtrack();
}
}
&Instruction::CallKeySort => {
- try_or_throw!(self.machine_st, self.machine_st.keysort());
+ try_or_throw!(self.machine_st, self.machine_st.keysort(VarComparison::Distinct));
if self.machine_st.fail {
self.machine_st.backtrack();
}
}
&Instruction::ExecuteKeySort => {
- try_or_throw!(self.machine_st, self.machine_st.keysort());
+ try_or_throw!(self.machine_st, self.machine_st.keysort(VarComparison::Distinct));
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p = self.machine_st.cp;
+ }
+ }
+ &Instruction::CallKeySortWithConstantVarOrdering => {
+ try_or_throw!(self.machine_st, self.machine_st.keysort(VarComparison::Indistinct));
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ } else {
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+
+ self.machine_st.p += 1;
+ }
+ }
+ &Instruction::ExecuteKeySortWithConstantVarOrdering => {
+ try_or_throw!(self.machine_st, self.machine_st.keysort(VarComparison::Indistinct));
if self.machine_st.fail {
self.machine_st.backtrack();
}
}
- pub fn compare_term_test(&mut self) -> Option<Ordering> {
+ pub fn compare_term_test(&mut self, var_comparison: VarComparison) -> Option<Ordering> {
let mut tabu_list = IndexSet::new();
while !self.pdl.is_empty() {
match order_cat_v1 {
Some(TermOrderCategory::Variable) => {
- let v1 = v1.as_var().unwrap();
- let v2 = v2.as_var().unwrap();
+ if let VarComparison::Distinct = var_comparison {
+ let v1 = v1.as_var().unwrap();
+ let v2 = v2.as_var().unwrap();
- if v1 != v2 {
- self.pdl.clear();
- return Some(v1.cmp(&v2));
+ if v1 != v2 {
+ self.pdl.clear();
+ return Some(v1.cmp(&v2));
+ }
}
}
Some(TermOrderCategory::FloatingPoint) => {
$machine_st.pdl.push($e2);
$machine_st.pdl.push($e1);
- $machine_st.compare_term_test()
+ $machine_st.compare_term_test(VarComparison::Distinct)
+ }};
+ ($machine_st:expr, $e1:expr, $e2:expr, $var_comparison:expr) => {{
+ $machine_st.pdl.push($e2);
+ $machine_st.pdl.push($e1);
+
+ $machine_st.compare_term_test($var_comparison)
}};
}