eyeling 1.24.1 → 1.24.3

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 (77) hide show
  1. package/HANDBOOK.md +134 -0
  2. package/dist/browser/eyeling.browser.js +454 -22
  3. package/eyeling.js +454 -22
  4. package/index.js +2 -0
  5. package/lib/cli.js +27 -10
  6. package/lib/engine.js +17 -7
  7. package/lib/lexer.js +295 -2
  8. package/lib/multisource.js +9 -2
  9. package/lib/printing.js +106 -1
  10. package/package.json +1 -1
  11. package/see/README.md +4 -0
  12. package/see/examples/_see.js +33 -2
  13. package/see/examples/age.js +27 -1
  14. package/see/examples/annotation.js +27 -1
  15. package/see/examples/backward.js +27 -1
  16. package/see/examples/backward_recursion.js +27 -1
  17. package/see/examples/bayes_diagnosis.js +27 -1
  18. package/see/examples/bayes_therapy.js +27 -1
  19. package/see/examples/bmi.js +27 -1
  20. package/see/examples/builtin_coverage.js +27 -1
  21. package/see/examples/collection.js +27 -1
  22. package/see/examples/complex.js +27 -1
  23. package/see/examples/complex_matrix_stability.js +27 -1
  24. package/see/examples/composition_of_injective_functions_is_injective.js +27 -1
  25. package/see/examples/control_system.js +27 -1
  26. package/see/examples/crypto_builtins_tests.js +27 -1
  27. package/see/examples/delfour.js +27 -1
  28. package/see/examples/digital_product_passport.js +27 -1
  29. package/see/examples/dijkstra.js +27 -1
  30. package/see/examples/dijkstra_risk_path.js +27 -1
  31. package/see/examples/doc/rdf_dataset.md +26 -0
  32. package/see/examples/doc/triple_terms.md +26 -0
  33. package/see/examples/dog.js +27 -1
  34. package/see/examples/eco_route_insight.js +27 -1
  35. package/see/examples/equals.js +27 -1
  36. package/see/examples/equivalence_classes_overlap_implies_same_class.js +27 -1
  37. package/see/examples/euler_identity.js +27 -1
  38. package/see/examples/ev_roundtrip_planner.js +27 -1
  39. package/see/examples/existential_rule.js +27 -1
  40. package/see/examples/expression_eval.js +27 -1
  41. package/see/examples/family_cousins.js +27 -1
  42. package/see/examples/fastpow.js +27 -1
  43. package/see/examples/fibonacci.js +27 -1
  44. package/see/examples/french_cities.js +27 -1
  45. package/see/examples/fundamental_theorem_arithmetic.js +27 -1
  46. package/see/examples/genetic_knapsack_selection.js +27 -1
  47. package/see/examples/goldbach_1000.js +27 -1
  48. package/see/examples/good_cobbler.js +27 -1
  49. package/see/examples/gps.js +27 -1
  50. package/see/examples/gray_code_counter.js +27 -1
  51. package/see/examples/greatest_lower_bound_uniqueness.js +27 -1
  52. package/see/examples/group_inverse_uniqueness.js +27 -1
  53. package/see/examples/hadamard_approx.js +27 -1
  54. package/see/examples/hanoi.js +27 -1
  55. package/see/examples/input/rdf_dataset.trig +34 -0
  56. package/see/examples/input/triple_terms.trig +28 -0
  57. package/see/examples/n3/rdf_dataset.n3 +34 -0
  58. package/see/examples/n3/triple_terms.n3 +23 -0
  59. package/see/examples/odrl_dpv_risk_ranked.js +27 -1
  60. package/see/examples/output/rdf_dataset.md +54 -0
  61. package/see/examples/output/triple_terms.md +53 -0
  62. package/see/examples/path_discovery.js +27 -1
  63. package/see/examples/rc_discharge_envelope.js +27 -1
  64. package/see/examples/rdf_dataset.js +1512 -0
  65. package/see/examples/rdf_message_flow.js +27 -1
  66. package/see/examples/rdf_messages.js +27 -1
  67. package/see/examples/school_placement_audit.js +27 -1
  68. package/see/examples/smoke_arithmetic.js +27 -1
  69. package/see/examples/socrates.js +27 -1
  70. package/see/examples/triple_terms.js +1442 -0
  71. package/see/examples/wind_turbine.js +27 -1
  72. package/see/examples/witch.js +27 -1
  73. package/see/see.js +101 -4
  74. package/test/api.test.js +86 -0
  75. package/test/see.test.js +0 -0
  76. package/tools/bundle.js +0 -0
  77. package/tools/n3gen.js +0 -0
@@ -0,0 +1,53 @@
1
+ # Triple terms
2
+
3
+ ## Entailment
4
+ The compiled query selected 1 fact(s) after the rule closure was computed.
5
+ Main entailment: **:observation :entails <<( :sensor :needs :inspection )>>.**
6
+
7
+ Selected entailments:
8
+ - :observation :entails <<( :sensor :needs :inspection )>> .
9
+
10
+ ## Explanation
11
+ Starts with 2 source fact(s), applies 1 rule(s), and reaches a fixpoint.
12
+ The log:query projection then keeps only the matching fact(s) shown above.
13
+
14
+ Derivation steps:
15
+ - Rule 1: ?observation rdf:reifies <<( ?device :reports ?condition )>>; ?condition :requires ?action => ?observation :entails <<( ?device :needs ?action )>> derives :observation :entails <<( :sensor :needs :inspection )>> .
16
+ - Uses: :observation rdf:reifies <<( :sensor :reports :overheating )>> . _(source)_; :overheating :requires :inspection . _(source)_
17
+
18
+ Selected explanation support:
19
+ - :observation :entails <<( :sensor :needs :inspection )>> . _(derived by Rule 1)_
20
+ - :observation rdf:reifies <<( :sensor :reports :overheating )>> . _(source)_
21
+ - :overheating :requires :inspection . _(source)_
22
+
23
+ The query-selected facts are serialized in the Formal TriG Output section.
24
+
25
+ ## Formal TriG Output
26
+
27
+ ```trig
28
+ VERSION "1.2"
29
+
30
+ @prefix : <https://eyereasoner.github.io/eyeling/see/examples/triple_terms#> .
31
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
32
+ @prefix log: <http://www.w3.org/2000/10/swap/log#> .
33
+ @prefix see: <https://example.org/see#> .
34
+ @prefix in: <https://example.org/see/input#> .
35
+
36
+ :observation :entails <<( :sensor :needs :inspection )>> .
37
+
38
+ in:metadata {
39
+ in:run a see:InputDataset .
40
+ in:run see:name "triple_terms" .
41
+ in:run see:title "Triple terms" .
42
+ in:run see:sourceFile "examples/n3/triple_terms.n3" .
43
+ in:run see:sourceSHA256 "f94fae1b4087f790c085c4dd1570875694238a882213951b457480ee26c06944" .
44
+ in:run see:description "Demonstrates RDF 1.2 TriG triple terms as input evidence and as a derived entailment." .
45
+ in:run see:compiler "see.js N3-to-JS compiler" .
46
+ in:run see:inputFacts 2 .
47
+ in:run see:compiledRules 1 .
48
+ in:run see:compiledBackwardRules 0 .
49
+ in:run see:compiledFuses 0 .
50
+ in:run see:compiledQueries 1 .
51
+ }
52
+ ```
53
+
@@ -8,6 +8,7 @@ const crypto = require('crypto');
8
8
 
9
9
  function canonical(term) {
10
10
  if (term.kind === 'list') return ['list', term.items.map(canonical)];
11
+ if (term.kind === 'triple') return ['triple', canonical(term.s), canonical(term.p), canonical(term.o)];
11
12
  if (term.kind === 'formula') return ['formula', term.atoms.map((a) => [canonical(a.s), canonical(a.p), canonical(a.o)])];
12
13
  return [term.kind, term.value];
13
14
  }
@@ -17,6 +18,7 @@ function compoundIndexKey() { return Array.from(arguments).map(termIndexKey).joi
17
18
  function termIsConcrete(t) {
18
19
  if (!t || t.kind === 'var') return false;
19
20
  if (t.kind === 'list') return t.items.every(termIsConcrete);
21
+ if (t.kind === 'triple') return termIsConcrete(t.s) && termIsConcrete(t.p) && termIsConcrete(t.o);
20
22
  if (t.kind === 'formula') return t.atoms.every((a) => termIsConcrete(a.s) && termIsConcrete(a.p) && termIsConcrete(a.o));
21
23
  return true;
22
24
  }
@@ -32,6 +34,7 @@ function primitive(t) {
32
34
  if (t.kind === 'iri') return t.value.replace(/^:/, '');
33
35
  if (t.kind === 'blank') return t.value;
34
36
  if (t.kind === 'list') return t.items.map(primitive);
37
+ if (t.kind === 'triple') return termToN3(t);
35
38
  if (t.kind === 'formula') return termToN3(t);
36
39
  return undefined;
37
40
  }
@@ -52,6 +55,7 @@ function termToN3(t) {
52
55
  if (t.kind === 'var') return '?' + t.value;
53
56
  if (t.kind === 'blank') return t.value.startsWith('_:') ? t.value : '_:' + t.value.replace(/^_+/, '');
54
57
  if (t.kind === 'list') return '(' + t.items.map(termToN3).join(' ') + ')';
58
+ if (t.kind === 'triple') return '<<( ' + termToN3(t.s) + ' ' + termToN3(t.p) + ' ' + termToN3(t.o) + ' )>>';
55
59
  if (t.kind === 'formula') return '{ ' + t.atoms.map(atomToN3).join(' . ') + ' }';
56
60
  return String(t.value ?? t);
57
61
  }
@@ -74,6 +78,7 @@ function resolve(term, env, seen = new Set()) {
74
78
  return resolve(env[term.value], env, seen);
75
79
  }
76
80
  if (term.kind === 'list') return list(term.items.map((item) => resolve(item, env, seen)));
81
+ if (term.kind === 'triple') return { kind: 'triple', s: resolve(term.s, env), p: resolve(term.p, env), o: resolve(term.o, env) };
77
82
  if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: resolve(a.s, env), p: resolve(a.p, env), o: resolve(a.o, env) })) };
78
83
  return term;
79
84
  }
@@ -91,6 +96,14 @@ function unify(a, b, env) {
91
96
  }
92
97
  return out;
93
98
  }
99
+ if (a.kind === 'triple' || b.kind === 'triple') {
100
+ if (a.kind !== 'triple' || b.kind !== 'triple') return null;
101
+ let out = unify(a.s, b.s, env);
102
+ if (!out) return null;
103
+ out = unify(a.p, b.p, out);
104
+ if (!out) return null;
105
+ return unify(a.o, b.o, out);
106
+ }
94
107
  return deepEqual(a, b) ? env : null;
95
108
  }
96
109
  function bind(pattern, value, env) { return unify(pattern, value, env); }
@@ -106,6 +119,7 @@ function termIsGround(t, env) {
106
119
  const r = resolve(t, env);
107
120
  if (r.kind === 'var') return false;
108
121
  if (r.kind === 'list') return r.items.every((item) => termIsGround(item, env));
122
+ if (r.kind === 'triple') return termIsGround(r.s, env) && termIsGround(r.p, env) && termIsGround(r.o, env);
109
123
  if (r.kind === 'formula') return r.atoms.every((atom) => atomIsGround(atom, env));
110
124
  return true;
111
125
  }
@@ -665,6 +679,7 @@ function instantiate(term, env, ruleId) {
665
679
  }
666
680
  if (term.kind === 'blank') return blank('_:r' + ruleId + '_' + envSignature(env) + '_' + term.value.replace(/^_/, ''));
667
681
  if (term.kind === 'list') return list(term.items.map((item) => instantiate(item, env, ruleId)));
682
+ if (term.kind === 'triple') return { kind: 'triple', s: instantiate(term.s, env, ruleId), p: instantiate(term.p, env, ruleId), o: instantiate(term.o, env, ruleId) };
668
683
  if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: instantiate(a.s, env, ruleId), p: instantiate(a.p, env, ruleId), o: instantiate(a.o, env, ruleId) })) };
669
684
  return cloneTerm(term);
670
685
  }
@@ -1683,6 +1698,16 @@ function formalOutputFacts(graph, queries, rules, initialFacts) {
1683
1698
  }
1684
1699
  return out;
1685
1700
  }
1701
+ function termHasTripleTerm(term) {
1702
+ if (!term) return false;
1703
+ if (term.kind === 'triple') return true;
1704
+ if (term.kind === 'list') return term.items.some(termHasTripleTerm);
1705
+ if (term.kind === 'formula') return term.atoms.some(atomHasTripleTerm);
1706
+ return false;
1707
+ }
1708
+ function atomHasTripleTerm(atom) { return termHasTripleTerm(atom.s) || termHasTripleTerm(atom.p) || termHasTripleTerm(atom.o); }
1709
+ function factsHaveTripleTerms(facts) { return (facts || []).some(atomHasTripleTerm); }
1710
+ function trigHasVersion12(trig) { return /^s*(?:@version|VERSION)s+["']1.2["']/mi.test(String(trig || '')); }
1686
1711
  function trigGraphBlock(label, atoms) {
1687
1712
  const lines = [label + ' {'];
1688
1713
  for (const atom of atoms || []) lines.push(' ' + atomToN3(atom) + ' .');
@@ -1730,7 +1755,8 @@ function formalOutputToTrig(facts, trig) {
1730
1755
  const prefixes = prefixLinesFromTrig(trig);
1731
1756
  if (state.needOutPrefix && !prefixes.some((line) => line.toLowerCase().startsWith('@prefix out:'))) prefixes.push('@prefix out: <https://example.org/see/output#> .');
1732
1757
  const nl = String.fromCharCode(10);
1733
- return prefixes.join(nl) + nl + nl + body.join(nl);
1758
+ const version = factsHaveTripleTerms(facts) ? 'VERSION "1.2"' + nl + nl : '';
1759
+ return version + prefixes.join(nl) + nl + nl + body.join(nl);
1734
1760
  }
1735
1761
  function appendFormalTrigOutput(markdown, graph, queries, rules, initialFacts, data) {
1736
1762
  const trig = formalOutputToTrig(formalOutputFacts(graph, queries, rules, initialFacts), data && data.trig);
@@ -8,6 +8,7 @@ const crypto = require('crypto');
8
8
 
9
9
  function canonical(term) {
10
10
  if (term.kind === 'list') return ['list', term.items.map(canonical)];
11
+ if (term.kind === 'triple') return ['triple', canonical(term.s), canonical(term.p), canonical(term.o)];
11
12
  if (term.kind === 'formula') return ['formula', term.atoms.map((a) => [canonical(a.s), canonical(a.p), canonical(a.o)])];
12
13
  return [term.kind, term.value];
13
14
  }
@@ -17,6 +18,7 @@ function compoundIndexKey() { return Array.from(arguments).map(termIndexKey).joi
17
18
  function termIsConcrete(t) {
18
19
  if (!t || t.kind === 'var') return false;
19
20
  if (t.kind === 'list') return t.items.every(termIsConcrete);
21
+ if (t.kind === 'triple') return termIsConcrete(t.s) && termIsConcrete(t.p) && termIsConcrete(t.o);
20
22
  if (t.kind === 'formula') return t.atoms.every((a) => termIsConcrete(a.s) && termIsConcrete(a.p) && termIsConcrete(a.o));
21
23
  return true;
22
24
  }
@@ -32,6 +34,7 @@ function primitive(t) {
32
34
  if (t.kind === 'iri') return t.value.replace(/^:/, '');
33
35
  if (t.kind === 'blank') return t.value;
34
36
  if (t.kind === 'list') return t.items.map(primitive);
37
+ if (t.kind === 'triple') return termToN3(t);
35
38
  if (t.kind === 'formula') return termToN3(t);
36
39
  return undefined;
37
40
  }
@@ -52,6 +55,7 @@ function termToN3(t) {
52
55
  if (t.kind === 'var') return '?' + t.value;
53
56
  if (t.kind === 'blank') return t.value.startsWith('_:') ? t.value : '_:' + t.value.replace(/^_+/, '');
54
57
  if (t.kind === 'list') return '(' + t.items.map(termToN3).join(' ') + ')';
58
+ if (t.kind === 'triple') return '<<( ' + termToN3(t.s) + ' ' + termToN3(t.p) + ' ' + termToN3(t.o) + ' )>>';
55
59
  if (t.kind === 'formula') return '{ ' + t.atoms.map(atomToN3).join(' . ') + ' }';
56
60
  return String(t.value ?? t);
57
61
  }
@@ -74,6 +78,7 @@ function resolve(term, env, seen = new Set()) {
74
78
  return resolve(env[term.value], env, seen);
75
79
  }
76
80
  if (term.kind === 'list') return list(term.items.map((item) => resolve(item, env, seen)));
81
+ if (term.kind === 'triple') return { kind: 'triple', s: resolve(term.s, env), p: resolve(term.p, env), o: resolve(term.o, env) };
77
82
  if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: resolve(a.s, env), p: resolve(a.p, env), o: resolve(a.o, env) })) };
78
83
  return term;
79
84
  }
@@ -91,6 +96,14 @@ function unify(a, b, env) {
91
96
  }
92
97
  return out;
93
98
  }
99
+ if (a.kind === 'triple' || b.kind === 'triple') {
100
+ if (a.kind !== 'triple' || b.kind !== 'triple') return null;
101
+ let out = unify(a.s, b.s, env);
102
+ if (!out) return null;
103
+ out = unify(a.p, b.p, out);
104
+ if (!out) return null;
105
+ return unify(a.o, b.o, out);
106
+ }
94
107
  return deepEqual(a, b) ? env : null;
95
108
  }
96
109
  function bind(pattern, value, env) { return unify(pattern, value, env); }
@@ -106,6 +119,7 @@ function termIsGround(t, env) {
106
119
  const r = resolve(t, env);
107
120
  if (r.kind === 'var') return false;
108
121
  if (r.kind === 'list') return r.items.every((item) => termIsGround(item, env));
122
+ if (r.kind === 'triple') return termIsGround(r.s, env) && termIsGround(r.p, env) && termIsGround(r.o, env);
109
123
  if (r.kind === 'formula') return r.atoms.every((atom) => atomIsGround(atom, env));
110
124
  return true;
111
125
  }
@@ -665,6 +679,7 @@ function instantiate(term, env, ruleId) {
665
679
  }
666
680
  if (term.kind === 'blank') return blank('_:r' + ruleId + '_' + envSignature(env) + '_' + term.value.replace(/^_/, ''));
667
681
  if (term.kind === 'list') return list(term.items.map((item) => instantiate(item, env, ruleId)));
682
+ if (term.kind === 'triple') return { kind: 'triple', s: instantiate(term.s, env, ruleId), p: instantiate(term.p, env, ruleId), o: instantiate(term.o, env, ruleId) };
668
683
  if (term.kind === 'formula') return { kind: 'formula', atoms: term.atoms.map((a) => ({ s: instantiate(a.s, env, ruleId), p: instantiate(a.p, env, ruleId), o: instantiate(a.o, env, ruleId) })) };
669
684
  return cloneTerm(term);
670
685
  }
@@ -1902,6 +1917,16 @@ function formalOutputFacts(graph, queries, rules, initialFacts) {
1902
1917
  }
1903
1918
  return out;
1904
1919
  }
1920
+ function termHasTripleTerm(term) {
1921
+ if (!term) return false;
1922
+ if (term.kind === 'triple') return true;
1923
+ if (term.kind === 'list') return term.items.some(termHasTripleTerm);
1924
+ if (term.kind === 'formula') return term.atoms.some(atomHasTripleTerm);
1925
+ return false;
1926
+ }
1927
+ function atomHasTripleTerm(atom) { return termHasTripleTerm(atom.s) || termHasTripleTerm(atom.p) || termHasTripleTerm(atom.o); }
1928
+ function factsHaveTripleTerms(facts) { return (facts || []).some(atomHasTripleTerm); }
1929
+ function trigHasVersion12(trig) { return /^s*(?:@version|VERSION)s+["']1.2["']/mi.test(String(trig || '')); }
1905
1930
  function trigGraphBlock(label, atoms) {
1906
1931
  const lines = [label + ' {'];
1907
1932
  for (const atom of atoms || []) lines.push(' ' + atomToN3(atom) + ' .');
@@ -1949,7 +1974,8 @@ function formalOutputToTrig(facts, trig) {
1949
1974
  const prefixes = prefixLinesFromTrig(trig);
1950
1975
  if (state.needOutPrefix && !prefixes.some((line) => line.toLowerCase().startsWith('@prefix out:'))) prefixes.push('@prefix out: <https://example.org/see/output#> .');
1951
1976
  const nl = String.fromCharCode(10);
1952
- return prefixes.join(nl) + nl + nl + body.join(nl);
1977
+ const version = factsHaveTripleTerms(facts) ? 'VERSION "1.2"' + nl + nl : '';
1978
+ return version + prefixes.join(nl) + nl + nl + body.join(nl);
1953
1979
  }
1954
1980
  function appendFormalTrigOutput(markdown, graph, queries, rules, initialFacts, data) {
1955
1981
  const trig = formalOutputToTrig(formalOutputFacts(graph, queries, rules, initialFacts), data && data.trig);