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.
- package/HANDBOOK.md +134 -0
- package/dist/browser/eyeling.browser.js +454 -22
- package/eyeling.js +454 -22
- package/index.js +2 -0
- package/lib/cli.js +27 -10
- package/lib/engine.js +17 -7
- package/lib/lexer.js +295 -2
- package/lib/multisource.js +9 -2
- package/lib/printing.js +106 -1
- package/package.json +1 -1
- package/see/README.md +4 -0
- package/see/examples/_see.js +33 -2
- package/see/examples/age.js +27 -1
- package/see/examples/annotation.js +27 -1
- package/see/examples/backward.js +27 -1
- package/see/examples/backward_recursion.js +27 -1
- package/see/examples/bayes_diagnosis.js +27 -1
- package/see/examples/bayes_therapy.js +27 -1
- package/see/examples/bmi.js +27 -1
- package/see/examples/builtin_coverage.js +27 -1
- package/see/examples/collection.js +27 -1
- package/see/examples/complex.js +27 -1
- package/see/examples/complex_matrix_stability.js +27 -1
- package/see/examples/composition_of_injective_functions_is_injective.js +27 -1
- package/see/examples/control_system.js +27 -1
- package/see/examples/crypto_builtins_tests.js +27 -1
- package/see/examples/delfour.js +27 -1
- package/see/examples/digital_product_passport.js +27 -1
- package/see/examples/dijkstra.js +27 -1
- package/see/examples/dijkstra_risk_path.js +27 -1
- package/see/examples/doc/rdf_dataset.md +26 -0
- package/see/examples/doc/triple_terms.md +26 -0
- package/see/examples/dog.js +27 -1
- package/see/examples/eco_route_insight.js +27 -1
- package/see/examples/equals.js +27 -1
- package/see/examples/equivalence_classes_overlap_implies_same_class.js +27 -1
- package/see/examples/euler_identity.js +27 -1
- package/see/examples/ev_roundtrip_planner.js +27 -1
- package/see/examples/existential_rule.js +27 -1
- package/see/examples/expression_eval.js +27 -1
- package/see/examples/family_cousins.js +27 -1
- package/see/examples/fastpow.js +27 -1
- package/see/examples/fibonacci.js +27 -1
- package/see/examples/french_cities.js +27 -1
- package/see/examples/fundamental_theorem_arithmetic.js +27 -1
- package/see/examples/genetic_knapsack_selection.js +27 -1
- package/see/examples/goldbach_1000.js +27 -1
- package/see/examples/good_cobbler.js +27 -1
- package/see/examples/gps.js +27 -1
- package/see/examples/gray_code_counter.js +27 -1
- package/see/examples/greatest_lower_bound_uniqueness.js +27 -1
- package/see/examples/group_inverse_uniqueness.js +27 -1
- package/see/examples/hadamard_approx.js +27 -1
- package/see/examples/hanoi.js +27 -1
- package/see/examples/input/rdf_dataset.trig +34 -0
- package/see/examples/input/triple_terms.trig +28 -0
- package/see/examples/n3/rdf_dataset.n3 +34 -0
- package/see/examples/n3/triple_terms.n3 +23 -0
- package/see/examples/odrl_dpv_risk_ranked.js +27 -1
- package/see/examples/output/rdf_dataset.md +54 -0
- package/see/examples/output/triple_terms.md +53 -0
- package/see/examples/path_discovery.js +27 -1
- package/see/examples/rc_discharge_envelope.js +27 -1
- package/see/examples/rdf_dataset.js +1512 -0
- package/see/examples/rdf_message_flow.js +27 -1
- package/see/examples/rdf_messages.js +27 -1
- package/see/examples/school_placement_audit.js +27 -1
- package/see/examples/smoke_arithmetic.js +27 -1
- package/see/examples/socrates.js +27 -1
- package/see/examples/triple_terms.js +1442 -0
- package/see/examples/wind_turbine.js +27 -1
- package/see/examples/witch.js +27 -1
- package/see/see.js +101 -4
- package/test/api.test.js +86 -0
- package/test/see.test.js +0 -0
- package/tools/bundle.js +0 -0
- package/tools/n3gen.js +0 -0
|
@@ -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
|
}
|
|
@@ -1827,6 +1842,16 @@ function formalOutputFacts(graph, queries, rules, initialFacts) {
|
|
|
1827
1842
|
}
|
|
1828
1843
|
return out;
|
|
1829
1844
|
}
|
|
1845
|
+
function termHasTripleTerm(term) {
|
|
1846
|
+
if (!term) return false;
|
|
1847
|
+
if (term.kind === 'triple') return true;
|
|
1848
|
+
if (term.kind === 'list') return term.items.some(termHasTripleTerm);
|
|
1849
|
+
if (term.kind === 'formula') return term.atoms.some(atomHasTripleTerm);
|
|
1850
|
+
return false;
|
|
1851
|
+
}
|
|
1852
|
+
function atomHasTripleTerm(atom) { return termHasTripleTerm(atom.s) || termHasTripleTerm(atom.p) || termHasTripleTerm(atom.o); }
|
|
1853
|
+
function factsHaveTripleTerms(facts) { return (facts || []).some(atomHasTripleTerm); }
|
|
1854
|
+
function trigHasVersion12(trig) { return /^s*(?:@version|VERSION)s+["']1.2["']/mi.test(String(trig || '')); }
|
|
1830
1855
|
function trigGraphBlock(label, atoms) {
|
|
1831
1856
|
const lines = [label + ' {'];
|
|
1832
1857
|
for (const atom of atoms || []) lines.push(' ' + atomToN3(atom) + ' .');
|
|
@@ -1874,7 +1899,8 @@ function formalOutputToTrig(facts, trig) {
|
|
|
1874
1899
|
const prefixes = prefixLinesFromTrig(trig);
|
|
1875
1900
|
if (state.needOutPrefix && !prefixes.some((line) => line.toLowerCase().startsWith('@prefix out:'))) prefixes.push('@prefix out: <https://example.org/see/output#> .');
|
|
1876
1901
|
const nl = String.fromCharCode(10);
|
|
1877
|
-
|
|
1902
|
+
const version = factsHaveTripleTerms(facts) ? 'VERSION "1.2"' + nl + nl : '';
|
|
1903
|
+
return version + prefixes.join(nl) + nl + nl + body.join(nl);
|
|
1878
1904
|
}
|
|
1879
1905
|
function appendFormalTrigOutput(markdown, graph, queries, rules, initialFacts, data) {
|
|
1880
1906
|
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
|
}
|
|
@@ -1806,6 +1821,16 @@ function formalOutputFacts(graph, queries, rules, initialFacts) {
|
|
|
1806
1821
|
}
|
|
1807
1822
|
return out;
|
|
1808
1823
|
}
|
|
1824
|
+
function termHasTripleTerm(term) {
|
|
1825
|
+
if (!term) return false;
|
|
1826
|
+
if (term.kind === 'triple') return true;
|
|
1827
|
+
if (term.kind === 'list') return term.items.some(termHasTripleTerm);
|
|
1828
|
+
if (term.kind === 'formula') return term.atoms.some(atomHasTripleTerm);
|
|
1829
|
+
return false;
|
|
1830
|
+
}
|
|
1831
|
+
function atomHasTripleTerm(atom) { return termHasTripleTerm(atom.s) || termHasTripleTerm(atom.p) || termHasTripleTerm(atom.o); }
|
|
1832
|
+
function factsHaveTripleTerms(facts) { return (facts || []).some(atomHasTripleTerm); }
|
|
1833
|
+
function trigHasVersion12(trig) { return /^s*(?:@version|VERSION)s+["']1.2["']/mi.test(String(trig || '')); }
|
|
1809
1834
|
function trigGraphBlock(label, atoms) {
|
|
1810
1835
|
const lines = [label + ' {'];
|
|
1811
1836
|
for (const atom of atoms || []) lines.push(' ' + atomToN3(atom) + ' .');
|
|
@@ -1853,7 +1878,8 @@ function formalOutputToTrig(facts, trig) {
|
|
|
1853
1878
|
const prefixes = prefixLinesFromTrig(trig);
|
|
1854
1879
|
if (state.needOutPrefix && !prefixes.some((line) => line.toLowerCase().startsWith('@prefix out:'))) prefixes.push('@prefix out: <https://example.org/see/output#> .');
|
|
1855
1880
|
const nl = String.fromCharCode(10);
|
|
1856
|
-
|
|
1881
|
+
const version = factsHaveTripleTerms(facts) ? 'VERSION "1.2"' + nl + nl : '';
|
|
1882
|
+
return version + prefixes.join(nl) + nl + nl + body.join(nl);
|
|
1857
1883
|
}
|
|
1858
1884
|
function appendFormalTrigOutput(markdown, graph, queries, rules, initialFacts, data) {
|
|
1859
1885
|
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
|
}
|
|
@@ -4326,6 +4341,16 @@ function formalOutputFacts(graph, queries, rules, initialFacts) {
|
|
|
4326
4341
|
}
|
|
4327
4342
|
return out;
|
|
4328
4343
|
}
|
|
4344
|
+
function termHasTripleTerm(term) {
|
|
4345
|
+
if (!term) return false;
|
|
4346
|
+
if (term.kind === 'triple') return true;
|
|
4347
|
+
if (term.kind === 'list') return term.items.some(termHasTripleTerm);
|
|
4348
|
+
if (term.kind === 'formula') return term.atoms.some(atomHasTripleTerm);
|
|
4349
|
+
return false;
|
|
4350
|
+
}
|
|
4351
|
+
function atomHasTripleTerm(atom) { return termHasTripleTerm(atom.s) || termHasTripleTerm(atom.p) || termHasTripleTerm(atom.o); }
|
|
4352
|
+
function factsHaveTripleTerms(facts) { return (facts || []).some(atomHasTripleTerm); }
|
|
4353
|
+
function trigHasVersion12(trig) { return /^s*(?:@version|VERSION)s+["']1.2["']/mi.test(String(trig || '')); }
|
|
4329
4354
|
function trigGraphBlock(label, atoms) {
|
|
4330
4355
|
const lines = [label + ' {'];
|
|
4331
4356
|
for (const atom of atoms || []) lines.push(' ' + atomToN3(atom) + ' .');
|
|
@@ -4373,7 +4398,8 @@ function formalOutputToTrig(facts, trig) {
|
|
|
4373
4398
|
const prefixes = prefixLinesFromTrig(trig);
|
|
4374
4399
|
if (state.needOutPrefix && !prefixes.some((line) => line.toLowerCase().startsWith('@prefix out:'))) prefixes.push('@prefix out: <https://example.org/see/output#> .');
|
|
4375
4400
|
const nl = String.fromCharCode(10);
|
|
4376
|
-
|
|
4401
|
+
const version = factsHaveTripleTerms(facts) ? 'VERSION "1.2"' + nl + nl : '';
|
|
4402
|
+
return version + prefixes.join(nl) + nl + nl + body.join(nl);
|
|
4377
4403
|
}
|
|
4378
4404
|
function appendFormalTrigOutput(markdown, graph, queries, rules, initialFacts, data) {
|
|
4379
4405
|
const trig = formalOutputToTrig(formalOutputFacts(graph, queries, rules, initialFacts), data && data.trig);
|
package/see/examples/hanoi.js
CHANGED
|
@@ -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
|
}
|
|
@@ -1534,6 +1549,16 @@ function formalOutputFacts(graph, queries, rules, initialFacts) {
|
|
|
1534
1549
|
}
|
|
1535
1550
|
return out;
|
|
1536
1551
|
}
|
|
1552
|
+
function termHasTripleTerm(term) {
|
|
1553
|
+
if (!term) return false;
|
|
1554
|
+
if (term.kind === 'triple') return true;
|
|
1555
|
+
if (term.kind === 'list') return term.items.some(termHasTripleTerm);
|
|
1556
|
+
if (term.kind === 'formula') return term.atoms.some(atomHasTripleTerm);
|
|
1557
|
+
return false;
|
|
1558
|
+
}
|
|
1559
|
+
function atomHasTripleTerm(atom) { return termHasTripleTerm(atom.s) || termHasTripleTerm(atom.p) || termHasTripleTerm(atom.o); }
|
|
1560
|
+
function factsHaveTripleTerms(facts) { return (facts || []).some(atomHasTripleTerm); }
|
|
1561
|
+
function trigHasVersion12(trig) { return /^s*(?:@version|VERSION)s+["']1.2["']/mi.test(String(trig || '')); }
|
|
1537
1562
|
function trigGraphBlock(label, atoms) {
|
|
1538
1563
|
const lines = [label + ' {'];
|
|
1539
1564
|
for (const atom of atoms || []) lines.push(' ' + atomToN3(atom) + ' .');
|
|
@@ -1581,7 +1606,8 @@ function formalOutputToTrig(facts, trig) {
|
|
|
1581
1606
|
const prefixes = prefixLinesFromTrig(trig);
|
|
1582
1607
|
if (state.needOutPrefix && !prefixes.some((line) => line.toLowerCase().startsWith('@prefix out:'))) prefixes.push('@prefix out: <https://example.org/see/output#> .');
|
|
1583
1608
|
const nl = String.fromCharCode(10);
|
|
1584
|
-
|
|
1609
|
+
const version = factsHaveTripleTerms(facts) ? 'VERSION "1.2"' + nl + nl : '';
|
|
1610
|
+
return version + prefixes.join(nl) + nl + nl + body.join(nl);
|
|
1585
1611
|
}
|
|
1586
1612
|
function appendFormalTrigOutput(markdown, graph, queries, rules, initialFacts, data) {
|
|
1587
1613
|
const trig = formalOutputToTrig(formalOutputFacts(graph, queries, rules, initialFacts), data && data.trig);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
VERSION "1.2"
|
|
2
|
+
|
|
3
|
+
@prefix : <https://eyereasoner.github.io/see/examples/rdf-dataset#> .
|
|
4
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
5
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
6
|
+
@prefix see: <https://example.org/see#> .
|
|
7
|
+
@prefix in: <https://example.org/see/input#> .
|
|
8
|
+
|
|
9
|
+
# Formal SEE input evidence in RDF 1.2 TriG.
|
|
10
|
+
# The generated runner reads this TriG evidence directly.
|
|
11
|
+
|
|
12
|
+
:sensor :reports :overheating .
|
|
13
|
+
:overheating :requires :inspection .
|
|
14
|
+
:maintenanceSystem :trusted true .
|
|
15
|
+
|
|
16
|
+
:factoryDataset {
|
|
17
|
+
:observation rdf:reifies <<( :sensor :reports :overheating )>> .
|
|
18
|
+
:observation :recordedBy :maintenanceSystem .
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
in:metadata {
|
|
22
|
+
in:run a see:InputDataset .
|
|
23
|
+
in:run see:name "rdf_dataset" .
|
|
24
|
+
in:run see:title "RDF dataset compatibility" .
|
|
25
|
+
in:run see:sourceFile "examples/n3/rdf_dataset.n3" .
|
|
26
|
+
in:run see:sourceSHA256 "76035a24eb72fc1d28a5e1f3021baefee0dde667aa8fc9f2b0a111f9c773b744" .
|
|
27
|
+
in:run see:description "RDF 1.1 named graph data and RDF 1.2 triple terms are normalized to ordinary N3 graph terms before SEE compiles the derivation." .
|
|
28
|
+
in:run see:compiler "see.js N3-to-JS compiler" .
|
|
29
|
+
in:run see:inputFacts 4 .
|
|
30
|
+
in:run see:compiledRules 1 .
|
|
31
|
+
in:run see:compiledBackwardRules 0 .
|
|
32
|
+
in:run see:compiledFuses 0 .
|
|
33
|
+
in:run see:compiledQueries 1 .
|
|
34
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
VERSION "1.2"
|
|
2
|
+
|
|
3
|
+
@prefix : <https://eyereasoner.github.io/eyeling/see/examples/triple_terms#> .
|
|
4
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
5
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
6
|
+
@prefix see: <https://example.org/see#> .
|
|
7
|
+
@prefix in: <https://example.org/see/input#> .
|
|
8
|
+
|
|
9
|
+
# Formal SEE input evidence in RDF 1.2 TriG.
|
|
10
|
+
# The generated runner reads this TriG evidence directly.
|
|
11
|
+
|
|
12
|
+
:observation rdf:reifies <<( :sensor :reports :overheating )>> .
|
|
13
|
+
:overheating :requires :inspection .
|
|
14
|
+
|
|
15
|
+
in:metadata {
|
|
16
|
+
in:run a see:InputDataset .
|
|
17
|
+
in:run see:name "triple_terms" .
|
|
18
|
+
in:run see:title "Triple terms" .
|
|
19
|
+
in:run see:sourceFile "examples/n3/triple_terms.n3" .
|
|
20
|
+
in:run see:sourceSHA256 "f94fae1b4087f790c085c4dd1570875694238a882213951b457480ee26c06944" .
|
|
21
|
+
in:run see:description "Demonstrates RDF 1.2 TriG triple terms as input evidence and as a derived entailment." .
|
|
22
|
+
in:run see:compiler "see.js N3-to-JS compiler" .
|
|
23
|
+
in:run see:inputFacts 2 .
|
|
24
|
+
in:run see:compiledRules 1 .
|
|
25
|
+
in:run see:compiledBackwardRules 0 .
|
|
26
|
+
in:run see:compiledFuses 0 .
|
|
27
|
+
in:run see:compiledQueries 1 .
|
|
28
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# RDF dataset compatibility
|
|
2
|
+
# RDF 1.1 named graph data and RDF 1.2 triple terms are normalized to ordinary N3 graph terms before SEE compiles the derivation.
|
|
3
|
+
|
|
4
|
+
VERSION "1.2"
|
|
5
|
+
@prefix : <https://eyereasoner.github.io/see/examples/rdf-dataset#> .
|
|
6
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
7
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
8
|
+
|
|
9
|
+
:sensor :reports :overheating .
|
|
10
|
+
:overheating :requires :inspection .
|
|
11
|
+
:maintenanceSystem :trusted true .
|
|
12
|
+
|
|
13
|
+
:factoryDataset {
|
|
14
|
+
:observation rdf:reifies <<( :sensor :reports :overheating )>> .
|
|
15
|
+
:observation :recordedBy :maintenanceSystem .
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
{
|
|
19
|
+
:sensor :reports ?condition .
|
|
20
|
+
?condition :requires ?action .
|
|
21
|
+
:maintenanceSystem :trusted true .
|
|
22
|
+
} => {
|
|
23
|
+
:workOrder :entails <<( :sensor :needs ?action )>> .
|
|
24
|
+
:audit log:nameOf {
|
|
25
|
+
:workOrder :basedOn :factoryDataset .
|
|
26
|
+
:workOrder :checkedBy :maintenanceSystem .
|
|
27
|
+
} .
|
|
28
|
+
} .
|
|
29
|
+
|
|
30
|
+
{
|
|
31
|
+
:workOrder :entails <<( ?device :needs ?action )>> .
|
|
32
|
+
} log:query {
|
|
33
|
+
:workOrder :entails <<( ?device :needs ?action )>> .
|
|
34
|
+
} .
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Triple terms
|
|
2
|
+
#
|
|
3
|
+
# Demonstrates RDF 1.2 TriG triple terms as input evidence and as a derived entailment.
|
|
4
|
+
|
|
5
|
+
VERSION "1.2"
|
|
6
|
+
|
|
7
|
+
@prefix : <https://eyereasoner.github.io/eyeling/see/examples/triple_terms#> .
|
|
8
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
9
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
10
|
+
|
|
11
|
+
:observation rdf:reifies <<( :sensor :reports :overheating )>> .
|
|
12
|
+
:overheating :requires :inspection .
|
|
13
|
+
|
|
14
|
+
{
|
|
15
|
+
?observation rdf:reifies <<( ?device :reports ?condition )>> .
|
|
16
|
+
?condition :requires ?action .
|
|
17
|
+
} => {
|
|
18
|
+
?observation :entails <<( ?device :needs ?action )>> .
|
|
19
|
+
} .
|
|
20
|
+
|
|
21
|
+
{ ?observation :entails ?entailment }
|
|
22
|
+
log:query
|
|
23
|
+
{ ?observation :entails ?entailment } .
|
|
@@ -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
|
}
|
|
@@ -5037,6 +5052,16 @@ function formalOutputFacts(graph, queries, rules, initialFacts) {
|
|
|
5037
5052
|
}
|
|
5038
5053
|
return out;
|
|
5039
5054
|
}
|
|
5055
|
+
function termHasTripleTerm(term) {
|
|
5056
|
+
if (!term) return false;
|
|
5057
|
+
if (term.kind === 'triple') return true;
|
|
5058
|
+
if (term.kind === 'list') return term.items.some(termHasTripleTerm);
|
|
5059
|
+
if (term.kind === 'formula') return term.atoms.some(atomHasTripleTerm);
|
|
5060
|
+
return false;
|
|
5061
|
+
}
|
|
5062
|
+
function atomHasTripleTerm(atom) { return termHasTripleTerm(atom.s) || termHasTripleTerm(atom.p) || termHasTripleTerm(atom.o); }
|
|
5063
|
+
function factsHaveTripleTerms(facts) { return (facts || []).some(atomHasTripleTerm); }
|
|
5064
|
+
function trigHasVersion12(trig) { return /^s*(?:@version|VERSION)s+["']1.2["']/mi.test(String(trig || '')); }
|
|
5040
5065
|
function trigGraphBlock(label, atoms) {
|
|
5041
5066
|
const lines = [label + ' {'];
|
|
5042
5067
|
for (const atom of atoms || []) lines.push(' ' + atomToN3(atom) + ' .');
|
|
@@ -5084,7 +5109,8 @@ function formalOutputToTrig(facts, trig) {
|
|
|
5084
5109
|
const prefixes = prefixLinesFromTrig(trig);
|
|
5085
5110
|
if (state.needOutPrefix && !prefixes.some((line) => line.toLowerCase().startsWith('@prefix out:'))) prefixes.push('@prefix out: <https://example.org/see/output#> .');
|
|
5086
5111
|
const nl = String.fromCharCode(10);
|
|
5087
|
-
|
|
5112
|
+
const version = factsHaveTripleTerms(facts) ? 'VERSION "1.2"' + nl + nl : '';
|
|
5113
|
+
return version + prefixes.join(nl) + nl + nl + body.join(nl);
|
|
5088
5114
|
}
|
|
5089
5115
|
function appendFormalTrigOutput(markdown, graph, queries, rules, initialFacts, data) {
|
|
5090
5116
|
const trig = formalOutputToTrig(formalOutputFacts(graph, queries, rules, initialFacts), data && data.trig);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# RDF dataset compatibility
|
|
2
|
+
|
|
3
|
+
## Entailment
|
|
4
|
+
The compiled query selected 1 fact(s) after the rule closure was computed.
|
|
5
|
+
Main entailment: **:workOrder :entails <<( :sensor :needs :inspection )>>.**
|
|
6
|
+
|
|
7
|
+
Selected entailments:
|
|
8
|
+
- :workOrder :entails <<( :sensor :needs :inspection )>> .
|
|
9
|
+
|
|
10
|
+
## Explanation
|
|
11
|
+
Starts with 4 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 (3 premise pattern(s) => 2 conclusion pattern(s)) derives :workOrder :entails <<( :sensor :needs :inspection )>> ., :audit log:nameOf { :workOrder :basedOn :factoryDataset . :workOrder :checkedBy :maintenanceSystem } .
|
|
16
|
+
- Uses: :sensor :reports :overheating . _(source)_; :overheating :requires :inspection . _(source)_; :maintenanceSystem :trusted true . _(source)_
|
|
17
|
+
|
|
18
|
+
Selected explanation support:
|
|
19
|
+
- :workOrder :entails <<( :sensor :needs :inspection )>> . _(derived by Rule 1)_
|
|
20
|
+
- :sensor :reports :overheating . _(source)_
|
|
21
|
+
- :overheating :requires :inspection . _(source)_
|
|
22
|
+
- :maintenanceSystem :trusted true . _(source)_
|
|
23
|
+
|
|
24
|
+
The query-selected facts are serialized in the Formal TriG Output section.
|
|
25
|
+
|
|
26
|
+
## Formal TriG Output
|
|
27
|
+
|
|
28
|
+
```trig
|
|
29
|
+
VERSION "1.2"
|
|
30
|
+
|
|
31
|
+
@prefix : <https://eyereasoner.github.io/see/examples/rdf-dataset#> .
|
|
32
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
33
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
34
|
+
@prefix see: <https://example.org/see#> .
|
|
35
|
+
@prefix in: <https://example.org/see/input#> .
|
|
36
|
+
|
|
37
|
+
:workOrder :entails <<( :sensor :needs :inspection )>> .
|
|
38
|
+
|
|
39
|
+
in:metadata {
|
|
40
|
+
in:run a see:InputDataset .
|
|
41
|
+
in:run see:name "rdf_dataset" .
|
|
42
|
+
in:run see:title "RDF dataset compatibility" .
|
|
43
|
+
in:run see:sourceFile "examples/n3/rdf_dataset.n3" .
|
|
44
|
+
in:run see:sourceSHA256 "76035a24eb72fc1d28a5e1f3021baefee0dde667aa8fc9f2b0a111f9c773b744" .
|
|
45
|
+
in:run see:description "RDF 1.1 named graph data and RDF 1.2 triple terms are normalized to ordinary N3 graph terms before SEE compiles the derivation." .
|
|
46
|
+
in:run see:compiler "see.js N3-to-JS compiler" .
|
|
47
|
+
in:run see:inputFacts 4 .
|
|
48
|
+
in:run see:compiledRules 1 .
|
|
49
|
+
in:run see:compiledBackwardRules 0 .
|
|
50
|
+
in:run see:compiledFuses 0 .
|
|
51
|
+
in:run see:compiledQueries 1 .
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|