eyelang 4.0.6 → 4.0.8
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/README.md +4 -0
- package/bin/eyelang.js +1 -1
- package/conformance-report.md +3 -3
- package/docs/guide.md +12 -11
- package/docs/language-reference.md +22 -16
- package/examples/abstract-interpretation.pl +0 -1
- package/examples/bayes-therapy.pl +1 -4
- package/examples/binomial-vandermonde.pl +1 -2
- package/examples/catalan-convolution.pl +1 -2
- package/examples/chart-parser.pl +1 -2
- package/examples/collatz-1000.pl +1 -2
- package/examples/continued-fraction-sqrt2.pl +1 -2
- package/examples/critical-path-schedule.pl +0 -2
- package/examples/dijkstra-risk-path.pl +0 -1
- package/examples/drone-corridor-planner.pl +0 -1
- package/examples/equality-saturation.pl +0 -2
- package/examples/family-cousins.pl +0 -3
- package/examples/fibonacci.pl +0 -1
- package/examples/gd-step-certified.pl +0 -7
- package/examples/gps.pl +0 -2
- package/examples/hamiltonian-path.pl +0 -1
- package/examples/hanoi.pl +0 -1
- package/examples/integer-partitions.pl +0 -1
- package/examples/intuitionistic-logic-kripke.pl +0 -2
- package/examples/knuth-bendix-completion.pl +0 -1
- package/examples/language.pl +1 -2
- package/examples/matrix-chain-order.pl +1 -2
- package/examples/modular-exponentiation.pl +0 -1
- package/examples/monkey-bananas.pl +0 -1
- package/examples/n-queens-8.pl +0 -1
- package/examples/output/chart-parser.pl +1 -1
- package/examples/partial-evaluator.pl +0 -1
- package/examples/peano-calculus.pl +0 -3
- package/examples/pell-equation.pl +1 -2
- package/examples/pointer-analysis.pl +0 -2
- package/examples/prime-range.pl +0 -1
- package/examples/proof/chart-parser.pl +91 -77
- package/examples/proof/hanoi.pl +16 -16
- package/examples/proof/intuitionistic-logic-kripke.pl +16 -16
- package/examples/route-planning.pl +0 -1
- package/examples/stirling-bell-numbers.pl +0 -4
- package/examples/totient-summatory.pl +1 -3
- package/examples/truth-maintenance-system.pl +0 -1
- package/examples/type-inference.pl +0 -1
- package/examples/web-names.pl +0 -1
- package/examples/weighted-interval-scheduling.pl +2 -3
- package/examples/wolf-goat-cabbage.pl +0 -1
- package/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/explain.js +3 -1
- package/src/program.js +88 -9
- package/src/solver.js +95 -46
- package/test/conformance/cases/{table/038_table_declaration.pl → automatic-tabling/038_automatic_tabling.pl} +1 -2
- package/test/conformance/cases/{table/102_table_declaration.pl → automatic-tabling/102_recursive_inference.pl} +1 -2
- package/test/conformance/cases/{table/tabled_left_recursion_path.pl → automatic-tabling/automatic_left_recursion_path.pl} +0 -1
- package/test/conformance/cases/{table/table_does_not_change_answers.pl → automatic-tabling/automatic_tabling_preserves_answers.pl} +1 -2
- package/test/conformance/cases/{table/extra_table_bound_cycle.pl → automatic-tabling/extra_automatic_bound_cycle.pl} +0 -1
- package/test/conformance/cases/{table/extra_table_open_call_fallback.pl → automatic-tabling/extra_automatic_open_call_fallback.pl} +0 -1
- package/test/conformance/cases/rules/transitive_rule_three_edges.pl +0 -1
- package/test/conformance/expected/{table/tabled_left_recursion_path.pl → automatic-tabling/automatic_left_recursion_path.pl} +1 -0
- package/test/conformance/expected-proofs/proofs/{table_recursive.pl → automatic_recursive.pl} +8 -8
- package/test/conformance/expected-proofs/proofs/{extra_table_path_bound.pl → extra_automatic_path_bound.pl} +8 -8
- package/test/conformance/proofs/proofs/{table_recursive.pl → automatic_recursive.pl} +1 -2
- package/test/conformance/proofs/proofs/{extra_table_path_bound.pl → extra_automatic_path_bound.pl} +0 -1
- package/test/conformance/warnings/negation/{extra_stratified_negation_with_table_quiet.pl → extra_stratified_negation_with_recursion_quiet.pl} +0 -1
- package/test/run-regression.mjs +52 -11
- package/test/conformance/cases/declarations/table_is_also_fact.pl +0 -4
- package/test/conformance/expected/declarations/table_is_also_fact.pl +0 -1
- /package/test/conformance/expected/{table/038_table_declaration.pl → automatic-tabling/038_automatic_tabling.pl} +0 -0
- /package/test/conformance/expected/{table/102_table_declaration.pl → automatic-tabling/102_recursive_inference.pl} +0 -0
- /package/test/conformance/expected/{table/table_does_not_change_answers.pl → automatic-tabling/automatic_tabling_preserves_answers.pl} +0 -0
- /package/test/conformance/expected/{table/extra_table_bound_cycle.pl → automatic-tabling/extra_automatic_bound_cycle.pl} +0 -0
- /package/test/conformance/expected/{table/extra_table_open_call_fallback.pl → automatic-tabling/extra_automatic_open_call_fallback.pl} +0 -0
- /package/test/conformance/expected-warnings/negation/{extra_stratified_negation_with_table_quiet.pl → extra_stratified_negation_with_recursion_quiet.pl} +0 -0
- /package/test/conformance/expected-warnings/negation/{extra_stratified_negation_with_table_quiet.txt → extra_stratified_negation_with_recursion_quiet.txt} +0 -0
package/test/conformance/expected-proofs/proofs/{table_recursive.pl → automatic_recursive.pl}
RENAMED
|
@@ -3,12 +3,12 @@ why(
|
|
|
3
3
|
path(a, b),
|
|
4
4
|
proof(
|
|
5
5
|
goal(path(a, b)),
|
|
6
|
-
by(rule("<stdin>", clause(
|
|
6
|
+
by(rule("<stdin>", clause(4))),
|
|
7
7
|
bindings([binding("X", a), binding("Y", b)]),
|
|
8
8
|
uses([
|
|
9
9
|
proof(
|
|
10
10
|
goal(edge(a, b)),
|
|
11
|
-
by(fact("<stdin>", clause(
|
|
11
|
+
by(fact("<stdin>", clause(2)))
|
|
12
12
|
)
|
|
13
13
|
])
|
|
14
14
|
)
|
|
@@ -19,12 +19,12 @@ why(
|
|
|
19
19
|
path(b, c),
|
|
20
20
|
proof(
|
|
21
21
|
goal(path(b, c)),
|
|
22
|
-
by(rule("<stdin>", clause(
|
|
22
|
+
by(rule("<stdin>", clause(4))),
|
|
23
23
|
bindings([binding("X", b), binding("Y", c)]),
|
|
24
24
|
uses([
|
|
25
25
|
proof(
|
|
26
26
|
goal(edge(b, c)),
|
|
27
|
-
by(fact("<stdin>", clause(
|
|
27
|
+
by(fact("<stdin>", clause(3)))
|
|
28
28
|
)
|
|
29
29
|
])
|
|
30
30
|
)
|
|
@@ -35,21 +35,21 @@ why(
|
|
|
35
35
|
path(a, c),
|
|
36
36
|
proof(
|
|
37
37
|
goal(path(a, c)),
|
|
38
|
-
by(rule("<stdin>", clause(
|
|
38
|
+
by(rule("<stdin>", clause(5))),
|
|
39
39
|
bindings([binding("X", a), binding("Z", c), binding("Y", b)]),
|
|
40
40
|
uses([
|
|
41
41
|
proof(
|
|
42
42
|
goal(edge(a, b)),
|
|
43
|
-
by(fact("<stdin>", clause(
|
|
43
|
+
by(fact("<stdin>", clause(2)))
|
|
44
44
|
),
|
|
45
45
|
proof(
|
|
46
46
|
goal(path(b, c)),
|
|
47
|
-
by(rule("<stdin>", clause(
|
|
47
|
+
by(rule("<stdin>", clause(4))),
|
|
48
48
|
bindings([binding("X", b), binding("Y", c)]),
|
|
49
49
|
uses([
|
|
50
50
|
proof(
|
|
51
51
|
goal(edge(b, c)),
|
|
52
|
-
by(fact("<stdin>", clause(
|
|
52
|
+
by(fact("<stdin>", clause(3)))
|
|
53
53
|
)
|
|
54
54
|
])
|
|
55
55
|
)
|
|
@@ -3,17 +3,17 @@ why(
|
|
|
3
3
|
answer(table_path_bound, b),
|
|
4
4
|
proof(
|
|
5
5
|
goal(answer(table_path_bound, b)),
|
|
6
|
-
by(rule("<stdin>", clause(
|
|
6
|
+
by(rule("<stdin>", clause(6))),
|
|
7
7
|
bindings([binding("X", b)]),
|
|
8
8
|
uses([
|
|
9
9
|
proof(
|
|
10
10
|
goal(path(a, b)),
|
|
11
|
-
by(rule("<stdin>", clause(
|
|
11
|
+
by(rule("<stdin>", clause(4))),
|
|
12
12
|
bindings([binding("X", a), binding("Y", b)]),
|
|
13
13
|
uses([
|
|
14
14
|
proof(
|
|
15
15
|
goal(edge(a, b)),
|
|
16
|
-
by(fact("<stdin>", clause(
|
|
16
|
+
by(fact("<stdin>", clause(2)))
|
|
17
17
|
)
|
|
18
18
|
])
|
|
19
19
|
)
|
|
@@ -26,26 +26,26 @@ why(
|
|
|
26
26
|
answer(table_path_bound, c),
|
|
27
27
|
proof(
|
|
28
28
|
goal(answer(table_path_bound, c)),
|
|
29
|
-
by(rule("<stdin>", clause(
|
|
29
|
+
by(rule("<stdin>", clause(6))),
|
|
30
30
|
bindings([binding("X", c)]),
|
|
31
31
|
uses([
|
|
32
32
|
proof(
|
|
33
33
|
goal(path(a, c)),
|
|
34
|
-
by(rule("<stdin>", clause(
|
|
34
|
+
by(rule("<stdin>", clause(5))),
|
|
35
35
|
bindings([binding("X", a), binding("Z", c), binding("Y", b)]),
|
|
36
36
|
uses([
|
|
37
37
|
proof(
|
|
38
38
|
goal(edge(a, b)),
|
|
39
|
-
by(fact("<stdin>", clause(
|
|
39
|
+
by(fact("<stdin>", clause(2)))
|
|
40
40
|
),
|
|
41
41
|
proof(
|
|
42
42
|
goal(path(b, c)),
|
|
43
|
-
by(rule("<stdin>", clause(
|
|
43
|
+
by(rule("<stdin>", clause(4))),
|
|
44
44
|
bindings([binding("X", b), binding("Y", c)]),
|
|
45
45
|
uses([
|
|
46
46
|
proof(
|
|
47
47
|
goal(edge(b, c)),
|
|
48
|
-
by(fact("<stdin>", clause(
|
|
48
|
+
by(fact("<stdin>", clause(3)))
|
|
49
49
|
)
|
|
50
50
|
])
|
|
51
51
|
)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
% Reference 12: tabled recursive proofs still explain the successful derivation path.
|
|
1
|
+
% Reference 12: automatically tabled recursive proofs still explain the successful derivation path.
|
|
2
2
|
materialize(path, 2).
|
|
3
|
-
table(path, 2).
|
|
4
3
|
edge(a, b).
|
|
5
4
|
edge(b, c).
|
|
6
5
|
path(X, Y) :- edge(X, Y).
|
package/test/run-regression.mjs
CHANGED
|
@@ -749,21 +749,59 @@ function whiteBoxCases() {
|
|
|
749
749
|
},
|
|
750
750
|
},
|
|
751
751
|
{
|
|
752
|
-
name: '
|
|
752
|
+
name: 'recursive predicate groups are tabled automatically',
|
|
753
753
|
run: () => {
|
|
754
|
-
const program = Program.parse('
|
|
754
|
+
const program = Program.parse('edge(a, b).\npath(X, Y) :- edge(X, Y).\npath(X, Z) :- path(X, Y), edge(Y, Z).\n');
|
|
755
755
|
const group = program.findGroup('path', 2);
|
|
756
756
|
assertEqual(Boolean(group), true, 'path/2 group exists');
|
|
757
|
-
assertEqual(group.tabled, true, 'path/2 tabled
|
|
757
|
+
assertEqual(group.tabled, true, 'path/2 tabled automatically');
|
|
758
758
|
},
|
|
759
759
|
},
|
|
760
760
|
{
|
|
761
|
-
name: '
|
|
761
|
+
name: 'directly materialized recursive groups are tabled automatically',
|
|
762
|
+
run: () => {
|
|
763
|
+
const program = Program.parse('materialize(path, 2).\nedge(a, b).\npath(X, Y) :- edge(X, Y).\npath(X, Z) :- edge(X, Y), path(Y, Z).\n');
|
|
764
|
+
const group = program.findGroup('path', 2);
|
|
765
|
+
assertEqual(group.tabled, true, 'materialized path/2 tabled automatically');
|
|
766
|
+
},
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
name: 'cycles through negation retain guarded resolution',
|
|
770
|
+
run: () => {
|
|
771
|
+
const program = Program.parse('p(X) :- not(q(X)).\nq(X) :- p(X).\n');
|
|
772
|
+
assertEqual(program.findGroup('p', 1).recursive, true, 'p/1 recursive');
|
|
773
|
+
assertEqual(program.findGroup('q', 1).recursive, true, 'q/1 recursive');
|
|
774
|
+
assertEqual(program.findGroup('p', 1).tabled, false, 'p/1 not positively tabled');
|
|
775
|
+
assertEqual(program.findGroup('q', 1).tabled, false, 'q/1 not positively tabled');
|
|
776
|
+
},
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
name: 'cyclic tabling reaches a complete fixed point',
|
|
780
|
+
run: () => {
|
|
781
|
+
const result = run(Program.parse(`
|
|
782
|
+
materialize(path, 2).
|
|
783
|
+
edge(a, b).
|
|
784
|
+
edge(b, c).
|
|
785
|
+
edge(c, d).
|
|
786
|
+
edge(d, a).
|
|
787
|
+
path(X, Y) :- edge(X, Y).
|
|
788
|
+
path(X, Z) :- edge(X, Y), path(Y, Z).
|
|
789
|
+
`));
|
|
790
|
+
const answers = result.stdout.trim().split('\n');
|
|
791
|
+
assertEqual(answers.length, 16, 'four-node cycle transitive closure size');
|
|
792
|
+
for (const node of ['a', 'b', 'c', 'd']) {
|
|
793
|
+
assertIncludes(result.stdout, `path(${node}, ${node}).\n`, `${node} reaches itself`);
|
|
794
|
+
}
|
|
795
|
+
assertEqual(result.stats.table_fixpoint_rounds > 1, true, 'cyclic table required multiple rounds');
|
|
796
|
+
},
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
name: 'ordinary declaration-like facts do not table predicates',
|
|
762
800
|
run: () => {
|
|
763
801
|
const program = Program.parse('memoize(path, 2).\nedge(a, b).\npath(X, Y) :- edge(X, Y).\n');
|
|
764
802
|
const group = program.findGroup('path', 2);
|
|
765
803
|
assertEqual(Boolean(group), true, 'path/2 group exists');
|
|
766
|
-
assertEqual(group.tabled, false, 'memoize/2
|
|
804
|
+
assertEqual(group.tabled, false, 'memoize/2 has no search-control meaning');
|
|
767
805
|
},
|
|
768
806
|
},
|
|
769
807
|
{
|
|
@@ -786,17 +824,17 @@ function whiteBoxCases() {
|
|
|
786
824
|
},
|
|
787
825
|
},
|
|
788
826
|
{
|
|
789
|
-
name: 'challenging examples
|
|
827
|
+
name: 'challenging examples infer dynamic-programming predicates automatically',
|
|
790
828
|
run: () => {
|
|
791
829
|
const checks = [
|
|
792
830
|
['binomial-vandermonde.pl', 'choose_step', 5, true],
|
|
793
|
-
['catalan-convolution.pl', 'catalan', 2,
|
|
831
|
+
['catalan-convolution.pl', 'catalan', 2, true],
|
|
794
832
|
['chart-parser.pl', 'span', 4, true],
|
|
795
833
|
['continued-fraction-sqrt2.pl', 'conv', 3, true],
|
|
796
|
-
['critical-path-schedule.pl', 'earliest_start', 2,
|
|
797
|
-
['critical-path-schedule.pl', 'finish_time', 2,
|
|
834
|
+
['critical-path-schedule.pl', 'earliest_start', 2, true],
|
|
835
|
+
['critical-path-schedule.pl', 'finish_time', 2, true],
|
|
798
836
|
['integer-partitions.pl', 'partitions', 3, true],
|
|
799
|
-
['matrix-chain-order.pl', 'cost', 3,
|
|
837
|
+
['matrix-chain-order.pl', 'cost', 3, true],
|
|
800
838
|
['modular-exponentiation.pl', 'pow_mod', 4, true],
|
|
801
839
|
['pell-equation.pl', 'pell', 3, true],
|
|
802
840
|
['stirling-bell-numbers.pl', 'stirling2', 3, false],
|
|
@@ -809,7 +847,7 @@ function whiteBoxCases() {
|
|
|
809
847
|
const program = Program.parseSources([{ text, filename }]);
|
|
810
848
|
const group = program.findGroup(name, arity);
|
|
811
849
|
assertEqual(Boolean(group), true, `${filename} ${name}/${arity} group exists`);
|
|
812
|
-
assertEqual(group.tabled,
|
|
850
|
+
assertEqual(group.tabled, recursive, `${filename} ${name}/${arity} automatic table decision`);
|
|
813
851
|
assertEqual(group.recursive, recursive, `${filename} ${name}/${arity} recursive`);
|
|
814
852
|
}
|
|
815
853
|
},
|
|
@@ -823,6 +861,8 @@ function whiteBoxCases() {
|
|
|
823
861
|
assertEqual(Boolean(group), true, 'no_diagonal_attack/3 group exists');
|
|
824
862
|
assertEqual(group.tabled, true, 'no_diagonal_attack/3 tabled');
|
|
825
863
|
assertEqual(group.recursive, true, 'no_diagonal_attack/3 recursive');
|
|
864
|
+
assertEqual(group.tableInputPositions.join(','), '2', 'diagonal scan uses the remaining rows as input');
|
|
865
|
+
assertEqual(program.findGroup('perm', 2).tableInputPositions.join(','), '1', 'permutation output stays untabled while open');
|
|
826
866
|
},
|
|
827
867
|
},
|
|
828
868
|
{
|
|
@@ -834,6 +874,7 @@ function whiteBoxCases() {
|
|
|
834
874
|
assertEqual(Boolean(group), true, 'collatz/2 group exists');
|
|
835
875
|
assertEqual(group.tabled, true, 'collatz/2 tabled');
|
|
836
876
|
assertEqual(group.recursive, true, 'collatz/2 recursive');
|
|
877
|
+
assertEqual(group.tableInputPositions.join(','), '0', 'collatz uses its numeric seed as input');
|
|
837
878
|
},
|
|
838
879
|
},
|
|
839
880
|
{
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
answer(path, 2).
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|