eyeprolog 1.3.73 → 1.3.75
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/iso.js +21 -8
- package/src/lib/clpz.pl +33 -10
- package/test/run-regression.mjs +10 -0
package/package.json
CHANGED
package/src/iso.js
CHANGED
|
@@ -2556,19 +2556,32 @@ function residueVariablesSince(snapshot, env) {
|
|
|
2556
2556
|
return names;
|
|
2557
2557
|
}
|
|
2558
2558
|
|
|
2559
|
-
function
|
|
2559
|
+
function callResidueVarsBuiltin({ solver, goal, env }) {
|
|
2560
2560
|
const invoked = callable(goal.args[0], env);
|
|
2561
2561
|
if (invoked.module == null) invoked.module = goal.module ?? 'user';
|
|
2562
2562
|
const snapshot = residueSnapshot(env);
|
|
2563
2563
|
const child = solver.cloneForInnerGoal();
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2564
|
+
let pending = true;
|
|
2565
|
+
// The wrapper iterator is resumable even for a deterministic Goal. Expose
|
|
2566
|
+
// the child's actual search state so the top level does not print a phantom
|
|
2567
|
+
// choicepoint after the final answer.
|
|
2568
|
+
const iterator = (function* residueSolutions() {
|
|
2569
|
+
try {
|
|
2570
|
+
for (const answerEnv of child.solve([invoked], env, 0)) {
|
|
2571
|
+
pending = child.hasPendingAlternatives();
|
|
2572
|
+
const next = answerEnv.clone();
|
|
2573
|
+
if (unify(goal.args[1], listFromItems(residueVariablesSince(snapshot, answerEnv)), next)) {
|
|
2574
|
+
yield next;
|
|
2575
|
+
if (!pending) return;
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
pending = false;
|
|
2579
|
+
} finally {
|
|
2580
|
+
solver.absorbStatsFrom(child);
|
|
2568
2581
|
}
|
|
2569
|
-
}
|
|
2570
|
-
|
|
2571
|
-
|
|
2582
|
+
})();
|
|
2583
|
+
iterator.hasPendingAlternatives = () => pending;
|
|
2584
|
+
return iterator;
|
|
2572
2585
|
}
|
|
2573
2586
|
|
|
2574
2587
|
function* freezeBuiltin({ solver, goal, env }) {
|
package/src/lib/clpz.pl
CHANGED
|
@@ -2248,10 +2248,15 @@ all_different([X|Right], Left, Orig) -->
|
|
|
2248
2248
|
all_distinct(Ls) :-
|
|
2249
2249
|
fd_must_be_list(Ls, all_distinct(Ls)-1),
|
|
2250
2250
|
maplist(fd_variable, Ls),
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2251
|
+
% A ground list needs validation, but no attributed propagator.
|
|
2252
|
+
( ground(Ls) ->
|
|
2253
|
+
sort(Ls, Distinct),
|
|
2254
|
+
same_length(Ls, Distinct)
|
|
2255
|
+
; make_propagator(pdistinct(Ls), Prop),
|
|
2256
|
+
new_queue(Q0),
|
|
2257
|
+
phrase((distinct_attach(Ls, Prop, []),trigger_prop(Prop),do_queue), [Q0], _),
|
|
2258
|
+
variables_same_queue(Ls)
|
|
2259
|
+
).
|
|
2255
2260
|
|
|
2256
2261
|
%% nvalue(?N, +Vars).
|
|
2257
2262
|
%
|
|
@@ -6707,10 +6712,21 @@ serialize_upper_bound(I, D_I, J, D_J, MState) -->
|
|
|
6707
6712
|
|
|
6708
6713
|
element(N, Is, V) :-
|
|
6709
6714
|
must_be(list, Is),
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6715
|
+
% A constant table is one extensional relation; expanding it into
|
|
6716
|
+
% reified implications and a second propagator is needlessly costly.
|
|
6717
|
+
( maplist(integer, Is) ->
|
|
6718
|
+
element_relation(Is, 1, Relation),
|
|
6719
|
+
tuples_in([[N,V]], Relation)
|
|
6720
|
+
; length(Is, L),
|
|
6721
|
+
N in 1..L,
|
|
6722
|
+
element_(Is, 1, N, V),
|
|
6723
|
+
propagator_init_trigger([N|Is], pelement(N,Is,V))
|
|
6724
|
+
).
|
|
6725
|
+
|
|
6726
|
+
element_relation([], _, []).
|
|
6727
|
+
element_relation([V|Vs], N, [[N,V]|Relation]) :-
|
|
6728
|
+
N1 is N + 1,
|
|
6729
|
+
element_relation(Vs, N1, Relation).
|
|
6714
6730
|
|
|
6715
6731
|
element_domain(V, VD) :-
|
|
6716
6732
|
( fd_get(V, VD, _) -> true
|
|
@@ -6799,8 +6815,15 @@ global_cardinality(Xs, Pairs, Options) :-
|
|
|
6799
6815
|
).
|
|
6800
6816
|
|
|
6801
6817
|
keys_costs(Keys, X, Row, C) :-
|
|
6802
|
-
|
|
6803
|
-
element
|
|
6818
|
+
% Keys and matrix rows are integers here. Zip them once instead of
|
|
6819
|
+
% connecting two element/3 constraints through an auxiliary index.
|
|
6820
|
+
keys_cost_relation(Keys, Row, Relation),
|
|
6821
|
+
tuples_in([[X,C]], Relation).
|
|
6822
|
+
|
|
6823
|
+
keys_cost_relation([Key|Keys], [Cost|Costs], [[Key,Cost]|Relation]) :-
|
|
6824
|
+
keys_cost_relation(Keys, Costs, Relation).
|
|
6825
|
+
keys_cost_relation([], _, []).
|
|
6826
|
+
keys_cost_relation([_|_], [], []).
|
|
6804
6827
|
|
|
6805
6828
|
gcc_pair(Pair) :-
|
|
6806
6829
|
( Pair = Key-Val ->
|
package/test/run-regression.mjs
CHANGED
|
@@ -178,6 +178,16 @@ check :- call_residue_vars(X in 1..3, Vs), Vs = [X].
|
|
|
178
178
|
`;
|
|
179
179
|
assertIncludes(run(clpzResidue, { goal: 'check' }).stdout, 'check.', 'call_residue_vars/2 includes CLP(Z) attributed variables');
|
|
180
180
|
|
|
181
|
+
const deterministicProgram = Program.parse(':- use_module(library(atts)).');
|
|
182
|
+
const deterministicSolver = new Solver(deterministicProgram);
|
|
183
|
+
const deterministicGoal = parseGoalText('call_residue_vars(true, Xs)');
|
|
184
|
+
const deterministicSolutions = deterministicSolver.solve([deterministicGoal], new Env(), 0);
|
|
185
|
+
const deterministicAnswer = deterministicSolutions.next();
|
|
186
|
+
assertEqual(deterministicAnswer.done, false, 'call_residue_vars/2 deterministic answer');
|
|
187
|
+
assertEqual(deterministicSolver.hasPendingAlternatives(), false,
|
|
188
|
+
'call_residue_vars/2 deterministic success has no leftover choicepoint');
|
|
189
|
+
deterministicSolutions.return();
|
|
190
|
+
|
|
181
191
|
const residualFile = path.join(tmp, `atts-residual-${++tmpCounter}.pl`);
|
|
182
192
|
fs.writeFileSync(residualFile, `:- use_module(library(atts)).
|
|
183
193
|
:- attribute required/1.
|