eyeling 1.7.14 → 1.7.15
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 +1 -1
- package/eyeling.js +51 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -219,7 +219,7 @@ Commonly used N3/Turtle features:
|
|
|
219
219
|
- **log**: `log:collectAllIn` `log:content` `log:dtlit` `log:equalTo` `log:forAllIn` `log:impliedBy` `log:implies` `log:includes` `log:langlit` `log:notEqualTo` `log:notIncludes` `log:outputString` `log:parsedAsN3` `log:rawType` `log:semantics` `log:semanticsOrError` `log:skolem` `log:uri`
|
|
220
220
|
- **math**: `math:absoluteValue` `math:acos` `math:asin` `math:atan` `math:cos` `math:cosh` `math:degrees` `math:difference` `math:equalTo` `math:exponentiation` `math:greaterThan` `math:integerQuotient` `math:lessThan` `math:negation` `math:notEqualTo` `math:notGreaterThan` `math:notLessThan` `math:product` `math:quotient` `math:remainder` `math:rounded` `math:sin` `math:sinh` `math:sum` `math:tan` `math:tanh`
|
|
221
221
|
- **string**: `string:concatenation` `string:contains` `string:containsIgnoringCase` `string:endsWith` `string:equalIgnoringCase` `string:format` `string:greaterThan` `string:jsonPointer` `string:lessThan` `string:matches` `string:notEqualIgnoringCase` `string:notGreaterThan` `string:notLessThan` `string:notMatches` `string:replace` `string:scrape` `string:startsWith`
|
|
222
|
-
- **time**: `time:day` `time:localTime` `time:minute` `time:month` `time:second` `time:timeZone` `time:year`
|
|
222
|
+
- **time**: `time:day` `time:hour` `time:localTime` `time:minute` `time:month` `time:second` `time:timeZone` `time:year`
|
|
223
223
|
|
|
224
224
|
## License
|
|
225
225
|
|
package/eyeling.js
CHANGED
|
@@ -4131,7 +4131,7 @@ function evalCryptoHashBuiltin(g, subst, algo) {
|
|
|
4131
4131
|
// ===========================================================================
|
|
4132
4132
|
// Backward proof & builtins mutual recursion — declarations first
|
|
4133
4133
|
|
|
4134
|
-
function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
4134
|
+
function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
|
|
4135
4135
|
const g = applySubstTriple(goal, subst);
|
|
4136
4136
|
const pv = iriValue(g.p);
|
|
4137
4137
|
if (pv === null) return null;
|
|
@@ -5648,7 +5648,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
5648
5648
|
|
|
5649
5649
|
const visited2 = [];
|
|
5650
5650
|
// Start from the incoming substitution so bindings flow outward.
|
|
5651
|
-
return proveGoals(Array.from(g.o.triples), { ...subst }, scopeFacts, [], depth + 1, visited2, varGen);
|
|
5651
|
+
return proveGoals(Array.from(g.o.triples), { ...subst }, scopeFacts, [], depth + 1, visited2, varGen, maxResults);
|
|
5652
5652
|
}
|
|
5653
5653
|
|
|
5654
5654
|
// log:notIncludes
|
|
@@ -5669,7 +5669,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
5669
5669
|
});
|
|
5670
5670
|
|
|
5671
5671
|
const visited2 = [];
|
|
5672
|
-
const sols = proveGoals(Array.from(g.o.triples), { ...subst }, scopeFacts, [], depth + 1, visited2, varGen);
|
|
5672
|
+
const sols = proveGoals(Array.from(g.o.triples), { ...subst }, scopeFacts, [], depth + 1, visited2, varGen, 1);
|
|
5673
5673
|
return sols.length ? [] : [{ ...subst }];
|
|
5674
5674
|
}
|
|
5675
5675
|
|
|
@@ -6244,10 +6244,11 @@ function maybeCompactSubst(subst, goals, answerVars, depth) {
|
|
|
6244
6244
|
return gcCompactForGoals(subst, goals, answerVars);
|
|
6245
6245
|
}
|
|
6246
6246
|
|
|
6247
|
-
function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
|
|
6247
|
+
function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxResults) {
|
|
6248
6248
|
// Iterative DFS over proof states using an explicit stack.
|
|
6249
6249
|
// Each state carries its own substitution and remaining goals.
|
|
6250
6250
|
const results = [];
|
|
6251
|
+
const max = typeof maxResults === 'number' && maxResults > 0 ? maxResults : Infinity;
|
|
6251
6252
|
|
|
6252
6253
|
const initialGoals = Array.isArray(goals) ? goals.slice() : [];
|
|
6253
6254
|
const initialSubst = subst ? { ...subst } : {};
|
|
@@ -6258,6 +6259,8 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
|
|
|
6258
6259
|
gcCollectVarsInGoals(initialGoals, answerVars);
|
|
6259
6260
|
if (!initialGoals.length) {
|
|
6260
6261
|
results.push(gcCompactForGoals(initialSubst, [], answerVars));
|
|
6262
|
+
|
|
6263
|
+
if (results.length >= max) return results;
|
|
6261
6264
|
return results;
|
|
6262
6265
|
}
|
|
6263
6266
|
|
|
@@ -6275,6 +6278,8 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
|
|
|
6275
6278
|
|
|
6276
6279
|
if (!state.goals.length) {
|
|
6277
6280
|
results.push(gcCompactForGoals(state.subst, [], answerVars));
|
|
6281
|
+
|
|
6282
|
+
if (results.length >= max) return results;
|
|
6278
6283
|
continue;
|
|
6279
6284
|
}
|
|
6280
6285
|
|
|
@@ -6284,13 +6289,18 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
|
|
|
6284
6289
|
|
|
6285
6290
|
// 1) Builtins
|
|
6286
6291
|
if (isBuiltinPred(goal0.p)) {
|
|
6287
|
-
const
|
|
6292
|
+
const remaining = max - results.length;
|
|
6293
|
+
if (remaining <= 0) return results;
|
|
6294
|
+
const builtinMax = Number.isFinite(remaining) && !restGoals.length ? remaining : undefined;
|
|
6295
|
+
const deltas = evalBuiltin(goal0, {}, facts, backRules, state.depth, varGen, builtinMax);
|
|
6288
6296
|
const nextStates = [];
|
|
6289
6297
|
for (const delta of deltas) {
|
|
6290
6298
|
const composed = composeSubst(state.subst, delta);
|
|
6291
6299
|
if (composed === null) continue;
|
|
6292
6300
|
if (!restGoals.length) {
|
|
6293
6301
|
results.push(gcCompactForGoals(composed, [], answerVars));
|
|
6302
|
+
|
|
6303
|
+
if (results.length >= max) return results;
|
|
6294
6304
|
} else {
|
|
6295
6305
|
const nextSubst = maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
|
|
6296
6306
|
nextStates.push({
|
|
@@ -6321,6 +6331,8 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
|
|
|
6321
6331
|
if (composed === null) continue;
|
|
6322
6332
|
if (!restGoals.length) {
|
|
6323
6333
|
results.push(gcCompactForGoals(composed, [], answerVars));
|
|
6334
|
+
|
|
6335
|
+
if (results.length >= max) return results;
|
|
6324
6336
|
} else {
|
|
6325
6337
|
const nextSubst = maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
|
|
6326
6338
|
nextStates.push({
|
|
@@ -6342,6 +6354,8 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen) {
|
|
|
6342
6354
|
if (composed === null) continue;
|
|
6343
6355
|
if (!restGoals.length) {
|
|
6344
6356
|
results.push(gcCompactForGoals(composed, [], answerVars));
|
|
6357
|
+
|
|
6358
|
+
if (results.length >= max) return results;
|
|
6345
6359
|
} else {
|
|
6346
6360
|
const nextSubst = maybeCompactSubst(composed, restGoals, answerVars, state.depth + 1);
|
|
6347
6361
|
nextStates.push({
|
|
@@ -6454,7 +6468,38 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
|
|
|
6454
6468
|
const r = forwardRules[i];
|
|
6455
6469
|
const empty = {};
|
|
6456
6470
|
const visited = [];
|
|
6457
|
-
|
|
6471
|
+
// Optimization: if the rule head is **structurally ground** (no vars anywhere, even inside
|
|
6472
|
+
// quoted formulas) and has no head blanks, then the head does not depend on which body
|
|
6473
|
+
// solution we pick. In that case, we only need *one* proof of the body, and once all head
|
|
6474
|
+
// triples are already known we can skip proving the body entirely.
|
|
6475
|
+
function isStrictGroundTerm(t) {
|
|
6476
|
+
if (t instanceof Var) return false;
|
|
6477
|
+
if (t instanceof Blank) return false;
|
|
6478
|
+
if (t instanceof OpenListTerm) return false;
|
|
6479
|
+
if (t instanceof ListTerm) return t.elems.every(isStrictGroundTerm);
|
|
6480
|
+
if (t instanceof GraphTerm) return t.triples.every(isStrictGroundTriple);
|
|
6481
|
+
return true; // Iri/Literal and any other atomic terms
|
|
6482
|
+
}
|
|
6483
|
+
function isStrictGroundTriple(tr) {
|
|
6484
|
+
return isStrictGroundTerm(tr.s) && isStrictGroundTerm(tr.p) && isStrictGroundTerm(tr.o);
|
|
6485
|
+
}
|
|
6486
|
+
|
|
6487
|
+
const headIsStrictGround =
|
|
6488
|
+
!r.isFuse && (!r.headBlankLabels || r.headBlankLabels.size === 0) && r.conclusion.every(isStrictGroundTriple);
|
|
6489
|
+
|
|
6490
|
+
if (headIsStrictGround) {
|
|
6491
|
+
let allKnown = true;
|
|
6492
|
+
for (const tr of r.conclusion) {
|
|
6493
|
+
if (!hasFactIndexed(facts, tr)) {
|
|
6494
|
+
allKnown = false;
|
|
6495
|
+
break;
|
|
6496
|
+
}
|
|
6497
|
+
}
|
|
6498
|
+
if (allKnown) continue;
|
|
6499
|
+
}
|
|
6500
|
+
|
|
6501
|
+
const maxSols = (r.isFuse || headIsStrictGround) ? 1 : undefined;
|
|
6502
|
+
const sols = proveGoals(r.premise.slice(), empty, facts, backRules, 0, visited, varGen, maxSols);
|
|
6458
6503
|
|
|
6459
6504
|
// Inference fuse
|
|
6460
6505
|
if (r.isFuse && sols.length) {
|