eyeprolog 1.5.66 → 1.5.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/lib/si.pl +30 -22
- package/test/regression/cases-regression.mjs +38 -0
package/package.json
CHANGED
package/src/lib/si.pl
CHANGED
|
@@ -70,12 +70,7 @@ si__condition((A;B)) :- si__condition(A), si__condition(B).
|
|
|
70
70
|
% f(a) vs f(Y) and X vs 1 are genuinely undecided.
|
|
71
71
|
compare_si(Order, A, B) :-
|
|
72
72
|
si__require_order(Order),
|
|
73
|
-
(
|
|
74
|
-
-> Order = (=)
|
|
75
|
-
; si__order_decided(A, B)
|
|
76
|
-
-> compare(Order, A, B)
|
|
77
|
-
; throw(error(instantiation_error, [predicate-compare_si/3]))
|
|
78
|
-
).
|
|
73
|
+
si__compare(Order, [A-B]).
|
|
79
74
|
|
|
80
75
|
si__require_order(Order) :- var(Order), !.
|
|
81
76
|
si__require_order(Order) :-
|
|
@@ -86,25 +81,38 @@ si__require_order(Order) :-
|
|
|
86
81
|
; throw(error(type_error(atom, Order), [predicate-compare_si/3]))
|
|
87
82
|
).
|
|
88
83
|
|
|
89
|
-
%
|
|
90
|
-
|
|
91
|
-
|
|
84
|
+
% Keep pending argument pairs in a work list. Recursing inside an if-then-else
|
|
85
|
+
% condition retains a child Solver per list cell; testing whole-tail identity
|
|
86
|
+
% at each step also repeatedly scans the same suffix (issue #105).
|
|
87
|
+
si__compare(=, []).
|
|
88
|
+
si__compare(Order, [A-B|Pairs]) :-
|
|
89
|
+
si__compare_pair(A, B, Comparison, Pairs, Next),
|
|
90
|
+
si__compare_next(Comparison, Order, Next).
|
|
91
|
+
|
|
92
|
+
si__compare_next(=, Order, Pairs) :- si__compare(Order, Pairs).
|
|
93
|
+
si__compare_next(<, <, _).
|
|
94
|
+
si__compare_next(>, >, _).
|
|
95
|
+
|
|
96
|
+
si__compare_pair(A, B, =, Pairs, Pairs) :-
|
|
97
|
+
( var(A) ; var(B) ), !,
|
|
98
|
+
( A == B -> true
|
|
99
|
+
; throw(error(instantiation_error, [predicate-compare_si/3])) ).
|
|
100
|
+
si__compare_pair([A|As], [B|Bs], =, Pairs, [A-B,As-Bs|Pairs]) :- !.
|
|
101
|
+
si__compare_pair(A, B, Comparison, Pairs, Next) :-
|
|
92
102
|
compound(A), compound(B), !,
|
|
93
103
|
functor(A, NameA, ArityA),
|
|
94
104
|
functor(B, NameB, ArityB),
|
|
95
|
-
( ArityA =\= ArityB ->
|
|
96
|
-
; NameA \== NameB ->
|
|
105
|
+
( ArityA =\= ArityB -> compare(Comparison, ArityA, ArityB), Next = Pairs
|
|
106
|
+
; NameA \== NameB -> compare(Comparison, NameA, NameB), Next = Pairs
|
|
97
107
|
; A =.. [_|ArgsA],
|
|
98
108
|
B =.. [_|ArgsB],
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
% Otherwise both are non-variables and at least one is atomic, so either the
|
|
102
|
-
% type order or the values themselves settle it and no instantiation can
|
|
103
|
-
% change the outcome.
|
|
104
|
-
si__order_decided(_, _).
|
|
105
|
-
|
|
106
|
-
si__args_decided([A|As], [B|Bs]) :-
|
|
107
|
-
( A == B
|
|
108
|
-
-> si__args_decided(As, Bs)
|
|
109
|
-
; si__order_decided(A, B)
|
|
109
|
+
Comparison = (=),
|
|
110
|
+
si__prepend_pairs(ArgsA, ArgsB, Next, Pairs)
|
|
110
111
|
).
|
|
112
|
+
si__compare_pair(A, _, >, Pairs, Pairs) :- compound(A), !.
|
|
113
|
+
si__compare_pair(_, B, <, Pairs, Pairs) :- compound(B), !.
|
|
114
|
+
si__compare_pair(A, B, Comparison, Pairs, Pairs) :- compare(Comparison, A, B).
|
|
115
|
+
|
|
116
|
+
si__prepend_pairs([], [], Pairs, Pairs).
|
|
117
|
+
si__prepend_pairs([A|As], [B|Bs], [A-B|Pairs], Tail) :-
|
|
118
|
+
si__prepend_pairs(As, Bs, Pairs, Tail).
|
|
@@ -28,6 +28,44 @@ import {
|
|
|
28
28
|
|
|
29
29
|
export function regressionCases() {
|
|
30
30
|
return [
|
|
31
|
+
{
|
|
32
|
+
name: 'timed compare_si/3 backtracks over growing prefixes without exhausting the host stack (issue #105)',
|
|
33
|
+
run: () => {
|
|
34
|
+
// Bound the reported generator so the regression exhausts every
|
|
35
|
+
// answer, including sizes beyond the original 256-cell failure.
|
|
36
|
+
const result = runCli(['-'], { input:
|
|
37
|
+
'%% goal: answer(I,R,S)\n' +
|
|
38
|
+
'answer(I,R,S) :- length(_,I), (I =< 9 -> true ; !, fail), ' +
|
|
39
|
+
'N is 2^I, length(P,N), append(P,[1],L1), append(P,[2],L2), ' +
|
|
40
|
+
'time(compare(R,L1,L2)), time(compare_si(S,L1,L2)).\n',
|
|
41
|
+
timeout: 20000,
|
|
42
|
+
});
|
|
43
|
+
assertEqual(result.status, 0, `exit status; error=${result.error}; stderr=${result.stderr}`);
|
|
44
|
+
for (let i = 0; i <= 9; i++) {
|
|
45
|
+
assertIncludes(result.stdout, `answer(${i}, <, <).`, 'comparison result');
|
|
46
|
+
}
|
|
47
|
+
assertNotIncludes(result.stderr + result.stdout, 'Maximum call stack', 'host stack');
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'compare_si/3 work list preserves argument priority and instantiation errors',
|
|
52
|
+
run: () => {
|
|
53
|
+
const goals = [
|
|
54
|
+
'compare_si(=,f(X,g(Y)),f(X,g(Y))),var(X),var(Y)',
|
|
55
|
+
'compare_si(<,f(g(X),a),f(g(X),b)),var(X)',
|
|
56
|
+
'compare_si(>,f(g(b),a),f(g(a),z))',
|
|
57
|
+
'compare_si(<,[a|X],[b|Y]),var(X),var(Y)',
|
|
58
|
+
'compare_si(>,f(X),a),var(X)',
|
|
59
|
+
'compare_si(<,a,f(X)),var(X)',
|
|
60
|
+
'\\+ compare_si(>,f(g(X),a),f(g(X),b))',
|
|
61
|
+
'catch((compare_si(_,f(g(X),a),f(g(Y),b)),fail),error(instantiation_error,[predicate-compare_si/3]),true),var(X),var(Y)',
|
|
62
|
+
];
|
|
63
|
+
for (const goal of goals) {
|
|
64
|
+
const result = runEyeProlog(`answer(ok) :- ${goal}.`, { goals: ['answer(X)'] });
|
|
65
|
+
assertIncludes(result.stdout, 'answer(ok)', goal);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
},
|
|
31
69
|
{
|
|
32
70
|
name: 'compare_si/3 validates Order before term instantiation (issue #100)',
|
|
33
71
|
run: () => {
|