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.
Files changed (75) hide show
  1. package/README.md +4 -0
  2. package/bin/eyelang.js +1 -1
  3. package/conformance-report.md +3 -3
  4. package/docs/guide.md +12 -11
  5. package/docs/language-reference.md +22 -16
  6. package/examples/abstract-interpretation.pl +0 -1
  7. package/examples/bayes-therapy.pl +1 -4
  8. package/examples/binomial-vandermonde.pl +1 -2
  9. package/examples/catalan-convolution.pl +1 -2
  10. package/examples/chart-parser.pl +1 -2
  11. package/examples/collatz-1000.pl +1 -2
  12. package/examples/continued-fraction-sqrt2.pl +1 -2
  13. package/examples/critical-path-schedule.pl +0 -2
  14. package/examples/dijkstra-risk-path.pl +0 -1
  15. package/examples/drone-corridor-planner.pl +0 -1
  16. package/examples/equality-saturation.pl +0 -2
  17. package/examples/family-cousins.pl +0 -3
  18. package/examples/fibonacci.pl +0 -1
  19. package/examples/gd-step-certified.pl +0 -7
  20. package/examples/gps.pl +0 -2
  21. package/examples/hamiltonian-path.pl +0 -1
  22. package/examples/hanoi.pl +0 -1
  23. package/examples/integer-partitions.pl +0 -1
  24. package/examples/intuitionistic-logic-kripke.pl +0 -2
  25. package/examples/knuth-bendix-completion.pl +0 -1
  26. package/examples/language.pl +1 -2
  27. package/examples/matrix-chain-order.pl +1 -2
  28. package/examples/modular-exponentiation.pl +0 -1
  29. package/examples/monkey-bananas.pl +0 -1
  30. package/examples/n-queens-8.pl +0 -1
  31. package/examples/output/chart-parser.pl +1 -1
  32. package/examples/partial-evaluator.pl +0 -1
  33. package/examples/peano-calculus.pl +0 -3
  34. package/examples/pell-equation.pl +1 -2
  35. package/examples/pointer-analysis.pl +0 -2
  36. package/examples/prime-range.pl +0 -1
  37. package/examples/proof/chart-parser.pl +91 -77
  38. package/examples/proof/hanoi.pl +16 -16
  39. package/examples/proof/intuitionistic-logic-kripke.pl +16 -16
  40. package/examples/route-planning.pl +0 -1
  41. package/examples/stirling-bell-numbers.pl +0 -4
  42. package/examples/totient-summatory.pl +1 -3
  43. package/examples/truth-maintenance-system.pl +0 -1
  44. package/examples/type-inference.pl +0 -1
  45. package/examples/web-names.pl +0 -1
  46. package/examples/weighted-interval-scheduling.pl +2 -3
  47. package/examples/wolf-goat-cabbage.pl +0 -1
  48. package/index.d.ts +1 -0
  49. package/package.json +1 -1
  50. package/src/explain.js +3 -1
  51. package/src/program.js +88 -9
  52. package/src/solver.js +95 -46
  53. package/test/conformance/cases/{table/038_table_declaration.pl → automatic-tabling/038_automatic_tabling.pl} +1 -2
  54. package/test/conformance/cases/{table/102_table_declaration.pl → automatic-tabling/102_recursive_inference.pl} +1 -2
  55. package/test/conformance/cases/{table/tabled_left_recursion_path.pl → automatic-tabling/automatic_left_recursion_path.pl} +0 -1
  56. package/test/conformance/cases/{table/table_does_not_change_answers.pl → automatic-tabling/automatic_tabling_preserves_answers.pl} +1 -2
  57. package/test/conformance/cases/{table/extra_table_bound_cycle.pl → automatic-tabling/extra_automatic_bound_cycle.pl} +0 -1
  58. package/test/conformance/cases/{table/extra_table_open_call_fallback.pl → automatic-tabling/extra_automatic_open_call_fallback.pl} +0 -1
  59. package/test/conformance/cases/rules/transitive_rule_three_edges.pl +0 -1
  60. package/test/conformance/expected/{table/tabled_left_recursion_path.pl → automatic-tabling/automatic_left_recursion_path.pl} +1 -0
  61. package/test/conformance/expected-proofs/proofs/{table_recursive.pl → automatic_recursive.pl} +8 -8
  62. package/test/conformance/expected-proofs/proofs/{extra_table_path_bound.pl → extra_automatic_path_bound.pl} +8 -8
  63. package/test/conformance/proofs/proofs/{table_recursive.pl → automatic_recursive.pl} +1 -2
  64. package/test/conformance/proofs/proofs/{extra_table_path_bound.pl → extra_automatic_path_bound.pl} +0 -1
  65. package/test/conformance/warnings/negation/{extra_stratified_negation_with_table_quiet.pl → extra_stratified_negation_with_recursion_quiet.pl} +0 -1
  66. package/test/run-regression.mjs +52 -11
  67. package/test/conformance/cases/declarations/table_is_also_fact.pl +0 -4
  68. package/test/conformance/expected/declarations/table_is_also_fact.pl +0 -1
  69. /package/test/conformance/expected/{table/038_table_declaration.pl → automatic-tabling/038_automatic_tabling.pl} +0 -0
  70. /package/test/conformance/expected/{table/102_table_declaration.pl → automatic-tabling/102_recursive_inference.pl} +0 -0
  71. /package/test/conformance/expected/{table/table_does_not_change_answers.pl → automatic-tabling/automatic_tabling_preserves_answers.pl} +0 -0
  72. /package/test/conformance/expected/{table/extra_table_bound_cycle.pl → automatic-tabling/extra_automatic_bound_cycle.pl} +0 -0
  73. /package/test/conformance/expected/{table/extra_table_open_call_fallback.pl → automatic-tabling/extra_automatic_open_call_fallback.pl} +0 -0
  74. /package/test/conformance/expected-warnings/negation/{extra_stratified_negation_with_table_quiet.pl → extra_stratified_negation_with_recursion_quiet.pl} +0 -0
  75. /package/test/conformance/expected-warnings/negation/{extra_stratified_negation_with_table_quiet.txt → extra_stratified_negation_with_recursion_quiet.txt} +0 -0
@@ -3,12 +3,12 @@ why(
3
3
  path(a, b),
4
4
  proof(
5
5
  goal(path(a, b)),
6
- by(rule("<stdin>", clause(5))),
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(3)))
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(5))),
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(4)))
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(6))),
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(3)))
43
+ by(fact("<stdin>", clause(2)))
44
44
  ),
45
45
  proof(
46
46
  goal(path(b, c)),
47
- by(rule("<stdin>", clause(5))),
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(4)))
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(7))),
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(5))),
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(3)))
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(7))),
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(6))),
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(3)))
39
+ by(fact("<stdin>", clause(2)))
40
40
  ),
41
41
  proof(
42
42
  goal(path(b, c)),
43
- by(rule("<stdin>", clause(5))),
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(4)))
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).
@@ -1,5 +1,4 @@
1
1
  materialize(answer, 2).
2
- table(path, 2).
3
2
  edge(a, b).
4
3
  edge(b, c).
5
4
  path(X, Y) :- edge(X, Y).
@@ -1,5 +1,4 @@
1
1
  materialize(open, 1).
2
- table(path, 2).
3
2
  edge(a, b).
4
3
  path(X, Y) :- edge(X, Y).
5
4
  closed(c).
@@ -749,21 +749,59 @@ function whiteBoxCases() {
749
749
  },
750
750
  },
751
751
  {
752
- name: 'table declaration marks predicate group tabled',
752
+ name: 'recursive predicate groups are tabled automatically',
753
753
  run: () => {
754
- const program = Program.parse('table(path, 2).\nedge(a, b).\npath(X, Y) :- edge(X, Y).\n');
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 through table/2');
757
+ assertEqual(group.tabled, true, 'path/2 tabled automatically');
758
758
  },
759
759
  },
760
760
  {
761
- name: 'memoize fact does not table predicates',
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 is not a table declaration');
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 keep dynamic-programming predicates tabled',
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, false],
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, false],
797
- ['critical-path-schedule.pl', 'finish_time', 2, false],
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, false],
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, true, `${filename} ${name}/${arity} 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,4 +0,0 @@
1
- % Declarations remain ordinary facts unless materialized output excludes them.
2
- materialize(answer, 2).
3
- table(path, 2).
4
- answer(Name, Arity) :- table(Name, Arity).
@@ -1 +0,0 @@
1
- answer(path, 2).