eyeling 1.7.4 → 1.7.6

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.
@@ -0,0 +1,17 @@
1
+ # ========================================================
2
+ # List map
3
+ # behaves like the functional programming operator flatMap
4
+ # Examples from Giacomo Citi
5
+ # ========================================================
6
+
7
+ @prefix list: <http://www.w3.org/2000/10/swap/list#> .
8
+ @prefix : <http://example.org/#>.
9
+
10
+ :s1 :p1 :o1 .
11
+ :s2 :p1 :o2 .
12
+ :s3 :p1 :o3, :o4 .
13
+
14
+ { ((:s1 :s2) :p1) list:map (:o1 :o2) } => { :test1 :is true } .
15
+ { ((:s1 :s2 :s3) :p1) list:map (:o1 :o2 :o3 :o4) } => { :test2 :is true } .
16
+ { ((:s4) :p1) list:map () } => { :test3 :is true } .
17
+ { ((:s1) :p2) list:map () } => { :test4 :is true } .
@@ -0,0 +1,20 @@
1
+ # ======================
2
+ # log:conclusion example
3
+ # ======================
4
+
5
+ @prefix : <http://example.org/>.
6
+ @prefix log: <http://www.w3.org/2000/10/swap/log#> .
7
+
8
+ :let :param {
9
+ :Felix a :Cat .
10
+ { ?X a :Cat . } => { ?X :says "Meow" . } .
11
+ } .
12
+
13
+ {
14
+ :let :param ?param .
15
+ ?param log:conclusion ?conclusion .
16
+ }
17
+ =>
18
+ {
19
+ :result :is ?conclusion .
20
+ } .
@@ -0,0 +1,6 @@
1
+ @prefix : <http://example.org/#> .
2
+
3
+ :test1 :is true .
4
+ :test2 :is true .
5
+ :test3 :is true .
6
+ :test4 :is true .
@@ -0,0 +1,13 @@
1
+ @prefix : <http://example.org/> .
2
+ @prefix log: <http://www.w3.org/2000/10/swap/log#> .
3
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
4
+
5
+ :result :is {
6
+ :Felix a :Cat .
7
+ {
8
+ ?X a :Cat .
9
+ } => {
10
+ ?X :says "Meow" .
11
+ } .
12
+ :Felix :says "Meow" .
13
+ } .
package/eyeling.js CHANGED
@@ -89,6 +89,7 @@ const jsonPointerCache = new Map();
89
89
  // Key is the dereferenced document IRI *without* fragment.
90
90
  const __logContentCache = new Map(); // iri -> string | null (null means fetch/read failed)
91
91
  const __logSemanticsCache = new Map(); // iri -> GraphTerm | null (null means parse failed)
92
+ const __logConclusionCache = new WeakMap(); // GraphTerm -> GraphTerm (deductive closure)
92
93
 
93
94
  function __stripFragment(iri) {
94
95
  const i = iri.indexOf('#');
@@ -233,6 +234,87 @@ function __derefSemanticsSync(iriNoFrag) {
233
234
  return null;
234
235
  }
235
236
  }
237
+ function __makeRuleFromTerms(left, right, isForward) {
238
+ // Mirror Parser.makeRule, but usable at runtime (e.g., log:conclusion).
239
+ let premiseTerm, conclTerm;
240
+
241
+ if (isForward) {
242
+ premiseTerm = left;
243
+ conclTerm = right;
244
+ } else {
245
+ premiseTerm = right;
246
+ conclTerm = left;
247
+ }
248
+
249
+ let isFuse = false;
250
+ if (isForward) {
251
+ if (conclTerm instanceof Literal && conclTerm.value === 'false') {
252
+ isFuse = true;
253
+ }
254
+ }
255
+
256
+ let rawPremise;
257
+ if (premiseTerm instanceof GraphTerm) {
258
+ rawPremise = premiseTerm.triples;
259
+ } else if (premiseTerm instanceof Literal && premiseTerm.value === 'true') {
260
+ rawPremise = [];
261
+ } else {
262
+ rawPremise = [];
263
+ }
264
+
265
+ let rawConclusion;
266
+ if (conclTerm instanceof GraphTerm) {
267
+ rawConclusion = conclTerm.triples;
268
+ } else if (conclTerm instanceof Literal && conclTerm.value === 'false') {
269
+ rawConclusion = [];
270
+ } else {
271
+ rawConclusion = [];
272
+ }
273
+
274
+ const headBlankLabels = collectBlankLabelsInTriples(rawConclusion);
275
+ const [premise0, conclusion] = liftBlankRuleVars(rawPremise, rawConclusion);
276
+ const premise = isForward ? reorderPremiseForConstraints(premise0) : premise0;
277
+ return new Rule(premise, conclusion, isForward, isFuse, headBlankLabels);
278
+ }
279
+
280
+ function __computeConclusionFromFormula(formula) {
281
+ if (!(formula instanceof GraphTerm)) return null;
282
+
283
+ const cached = __logConclusionCache.get(formula);
284
+ if (cached) return cached;
285
+
286
+ // Facts start as *all* triples in the formula, including rule triples.
287
+ const facts2 = formula.triples.slice();
288
+
289
+ // Extract rules from rule-triples present inside the formula.
290
+ const fw = [];
291
+ const bw = [];
292
+
293
+ for (const tr of formula.triples) {
294
+ // Treat {A} => {B} as a forward rule.
295
+ if (isLogImplies(tr.p)) {
296
+ fw.push(__makeRuleFromTerms(tr.s, tr.o, true));
297
+ continue;
298
+ }
299
+
300
+ // Treat {A} <= {B} as the same rule in the other direction, i.e., {B} => {A},
301
+ // so it participates in deductive closure even if only <= is used.
302
+ if (isLogImpliedBy(tr.p)) {
303
+ fw.push(__makeRuleFromTerms(tr.o, tr.s, true));
304
+ // Also index it as a backward rule for completeness (helps proveGoals in some cases).
305
+ bw.push(__makeRuleFromTerms(tr.s, tr.o, false));
306
+ continue;
307
+ }
308
+ }
309
+
310
+ // Saturate within this local formula only.
311
+ forwardChain(facts2, fw, bw);
312
+
313
+ const out = new GraphTerm(facts2.slice());
314
+ __logConclusionCache.set(formula, out);
315
+ return out;
316
+ }
317
+
236
318
 
237
319
 
238
320
  // Controls whether human-readable proof comments are printed.
@@ -4722,19 +4804,26 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4722
4804
  const inputList = inputTerm.elems;
4723
4805
  if (!(predTerm instanceof Iri)) return [];
4724
4806
  const pred = internIri(predTerm.value);
4725
- if (!isBuiltinPred(pred)) return [];
4807
+
4808
+ // Allow mapping *any* predicate (not just builtins).
4809
+ // Semantics: for each input element `el`, collect *all* solutions of `el pred ?y`
4810
+ // (facts, rules, and builtins), in order, and concatenate them into the output list.
4811
+ // If an element has no solutions, it contributes nothing.
4726
4812
  if (!inputList.every((e) => isGroundTerm(e))) return [];
4727
4813
 
4728
4814
  const results = [];
4729
4815
  for (const el of inputList) {
4730
4816
  const yvar = new Var('_mapY');
4731
4817
  const goal2 = new Triple(el, pred, yvar);
4732
- const sols = evalBuiltin(goal2, subst, facts, backRules, depth + 1, varGen);
4733
- if (!sols.length) return [];
4734
- const yval = applySubstTerm(yvar, sols[0]);
4735
- if (yval instanceof Var) return [];
4736
- results.push(yval);
4818
+ const sols = proveGoals([goal2], subst, facts, backRules, depth + 1, [], varGen);
4819
+
4820
+ for (const sol of sols) {
4821
+ const yval = applySubstTerm(yvar, sol);
4822
+ if (yval instanceof Var) continue;
4823
+ results.push(yval);
4824
+ }
4737
4825
  }
4826
+
4738
4827
  const outList = new ListTerm(results);
4739
4828
  const s2 = unifyTerm(g.o, outList, subst);
4740
4829
  return s2 !== null ? [s2] : [];
@@ -4843,6 +4932,31 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
4843
4932
  return s2 !== null ? [s2] : [];
4844
4933
  }
4845
4934
 
4935
+
4936
+ // log:conclusion
4937
+ // Schema: $s+ log:conclusion $o?
4938
+ // $o is the deductive closure of the subject formula $s (including rule inferences).
4939
+ if (pv === LOG_NS + 'conclusion') {
4940
+ // Accept 'true' as the empty formula.
4941
+ let inFormula = null;
4942
+ if (g.s instanceof GraphTerm) inFormula = g.s;
4943
+ else if (g.s instanceof Literal && g.s.value === 'true') inFormula = new GraphTerm([]);
4944
+ else return [];
4945
+
4946
+ const conclusion = __computeConclusionFromFormula(inFormula);
4947
+ if (!(conclusion instanceof GraphTerm)) return [];
4948
+
4949
+ if (g.o instanceof Var) {
4950
+ const s2 = { ...subst };
4951
+ s2[g.o.name] = conclusion;
4952
+ return [s2];
4953
+ }
4954
+ if (g.o instanceof Blank) return [{ ...subst }];
4955
+
4956
+ const s2 = unifyTerm(g.o, conclusion, subst);
4957
+ return s2 !== null ? [s2] : [];
4958
+ }
4959
+
4846
4960
  // log:content
4847
4961
  // Schema: $s+ log:content $o?
4848
4962
  // Dereferences $s and returns the online resource as an xsd:string.
@@ -5991,10 +6105,17 @@ function termToN3(t, pref) {
5991
6105
  return '(' + inside.join(' ') + ')';
5992
6106
  }
5993
6107
  if (t instanceof GraphTerm) {
6108
+ const indent = ' ';
6109
+ const indentBlock = (str) =>
6110
+ str
6111
+ .split(/\r?\n/)
6112
+ .map((ln) => (ln.length ? indent + ln : ln))
6113
+ .join('\n');
6114
+
5994
6115
  let s = '{\n';
5995
6116
  for (const tr of t.triples) {
5996
- let line = tripleToN3(tr, pref).trimEnd();
5997
- if (line) s += ' ' + line + '\n';
6117
+ const block = tripleToN3(tr, pref).trimEnd();
6118
+ if (block) s += indentBlock(block) + '\n';
5998
6119
  }
5999
6120
  s += '}';
6000
6121
  return s;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.7.4",
3
+ "version": "1.7.6",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [