eyeling 1.11.27 → 1.11.28

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 (3) hide show
  1. package/eyeling.js +199 -186
  2. package/lib/engine.js +199 -186
  3. package/package.json +1 -1
package/eyeling.js CHANGED
@@ -4437,6 +4437,8 @@ const { deterministicSkolemIdFromKey } = require('./skolem');
4437
4437
 
4438
4438
  const deref = require('./deref');
4439
4439
 
4440
+ const hasOwn = Object.prototype.hasOwnProperty;
4441
+
4440
4442
  let version = 'dev';
4441
4443
  try {
4442
4444
  // Node: keep package.json version if available
@@ -4556,6 +4558,191 @@ function __isStrictGroundTriple(tr) {
4556
4558
  return __isStrictGroundTerm(tr.s) && __isStrictGroundTerm(tr.p) && __isStrictGroundTerm(tr.o);
4557
4559
  }
4558
4560
 
4561
+ // -----------------------------------------------------------------------------
4562
+ // Rule identity / firing keys
4563
+ // -----------------------------------------------------------------------------
4564
+ // Used to maintain O(1) membership sets for dynamically promoted rules, and to
4565
+ // memoize per-firing head-blank skolemization.
4566
+ function __ruleKey(isForward, isFuse, premise, conclusion) {
4567
+ let out = (isForward ? 'F' : 'B') + (isFuse ? '!' : '') + '|P|';
4568
+ for (let i = 0; i < premise.length; i++) {
4569
+ const tr = premise[i];
4570
+ if (i) out += '\n';
4571
+ out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
4572
+ }
4573
+ out += '|C|';
4574
+ for (let i = 0; i < conclusion.length; i++) {
4575
+ const tr = conclusion[i];
4576
+ if (i) out += '\n';
4577
+ out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
4578
+ }
4579
+ return out;
4580
+ }
4581
+
4582
+ function __firingKey(ruleIndex, instantiatedPremises) {
4583
+ // Deterministic key derived from the instantiated body (ground per substitution).
4584
+ let out = `R${ruleIndex}|`;
4585
+ for (let i = 0; i < instantiatedPremises.length; i++) {
4586
+ const tr = instantiatedPremises[i];
4587
+ if (i) out += '\n';
4588
+ out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
4589
+ }
4590
+ return out;
4591
+ }
4592
+
4593
+ // -----------------------------------------------------------------------------
4594
+ // Scoped-closure helpers (log:* builtins)
4595
+ // -----------------------------------------------------------------------------
4596
+ // Parse a 'naturalPriority' used by log:* scoped-closure builtins (e.g., log:collectAllIn).
4597
+ // Accept non-negative integral numeric literals; return null if not parseable.
4598
+ function __logNaturalPriorityFromTerm(t) {
4599
+ if (!(t instanceof Literal)) return null;
4600
+ const info = parseNumericLiteralInfo(t);
4601
+ if (!info) return null;
4602
+
4603
+ if (info.kind === 'integer') {
4604
+ const bi = info.value; // BigInt
4605
+ if (bi < 0n) return null;
4606
+ // clamp to MAX_SAFE_INTEGER (priorities are expected to be small)
4607
+ const max = BigInt(Number.MAX_SAFE_INTEGER);
4608
+ return Number(bi > max ? max : bi);
4609
+ }
4610
+
4611
+ if (info.kind === 'decimal') {
4612
+ const n = info.value; // number
4613
+ if (!Number.isFinite(n)) return null;
4614
+ if (Math.floor(n) !== n) return null;
4615
+ if (n < 0) return null;
4616
+ return n;
4617
+ }
4618
+
4619
+ return null;
4620
+ }
4621
+
4622
+ function __computeMaxScopedClosurePriorityNeeded(forwardRules, backRules) {
4623
+ let maxP = 0;
4624
+
4625
+ function scanTriple(tr) {
4626
+ if (!(tr && tr.p instanceof Iri)) return;
4627
+ const pv = tr.p.value;
4628
+
4629
+ // log:collectAllIn / log:forAllIn use the object position for the priority.
4630
+ if (pv === LOG_NS + 'collectAllIn' || pv === LOG_NS + 'forAllIn') {
4631
+ // Explicit scope graphs are immediate and do not require a closure.
4632
+ if (tr.o instanceof GraphTerm) return;
4633
+ // Variable or non-numeric object => default priority 1 (if used).
4634
+ if (tr.o instanceof Var) {
4635
+ if (maxP < 1) maxP = 1;
4636
+ return;
4637
+ }
4638
+ const p0 = __logNaturalPriorityFromTerm(tr.o);
4639
+ if (p0 !== null) {
4640
+ if (p0 > maxP) maxP = p0;
4641
+ } else {
4642
+ if (maxP < 1) maxP = 1;
4643
+ }
4644
+ return;
4645
+ }
4646
+
4647
+ // log:includes / log:notIncludes use the subject position for the priority.
4648
+ if (pv === LOG_NS + 'includes' || pv === LOG_NS + 'notIncludes') {
4649
+ // Explicit scope graphs are immediate and do not require a closure.
4650
+ if (tr.s instanceof GraphTerm) return;
4651
+ // Variable or non-numeric subject => default priority 1 (if used).
4652
+ if (tr.s instanceof Var) {
4653
+ if (maxP < 1) maxP = 1;
4654
+ return;
4655
+ }
4656
+ const p0 = __logNaturalPriorityFromTerm(tr.s);
4657
+ if (p0 !== null) {
4658
+ if (p0 > maxP) maxP = p0;
4659
+ } else {
4660
+ if (maxP < 1) maxP = 1;
4661
+ }
4662
+ }
4663
+ }
4664
+
4665
+ for (const r of forwardRules) {
4666
+ for (const tr of r.premise) scanTriple(tr);
4667
+ }
4668
+ for (const r of backRules) {
4669
+ for (const tr of r.premise) scanTriple(tr);
4670
+ }
4671
+ return maxP;
4672
+ }
4673
+
4674
+ function __termContainsVarName(t, name) {
4675
+ if (t instanceof Var) return t.name === name;
4676
+ if (t instanceof ListTerm) return t.elems.some((e) => __termContainsVarName(e, name));
4677
+ if (t instanceof OpenListTerm) return t.tailVar === name || t.prefix.some((e) => __termContainsVarName(e, name));
4678
+ if (t instanceof GraphTerm)
4679
+ return t.triples.some(
4680
+ (tr) =>
4681
+ __termContainsVarName(tr.s, name) || __termContainsVarName(tr.p, name) || __termContainsVarName(tr.o, name),
4682
+ );
4683
+ return false;
4684
+ }
4685
+
4686
+ function __varOccursElsewhereInPremise(premise, name, idx, field) {
4687
+ for (let i = 0; i < premise.length; i++) {
4688
+ const tr = premise[i];
4689
+ if (!(tr && tr.s && tr.p && tr.o)) continue;
4690
+
4691
+ // Skip the specific scope/priority occurrence we are analyzing.
4692
+ if (!(i === idx && field === 's') && __termContainsVarName(tr.s, name)) return true;
4693
+ if (!(i === idx && field === 'p') && __termContainsVarName(tr.p, name)) return true;
4694
+ if (!(i === idx && field === 'o') && __termContainsVarName(tr.o, name)) return true;
4695
+ }
4696
+ return false;
4697
+ }
4698
+
4699
+ function __computeForwardRuleScopedSkipInfo(rule) {
4700
+ let needsSnap = false;
4701
+ let requiredLevel = 0;
4702
+
4703
+ for (let i = 0; i < rule.premise.length; i++) {
4704
+ const tr = rule.premise[i];
4705
+ if (!(tr && tr.p instanceof Iri)) continue;
4706
+ const pv = tr.p.value;
4707
+
4708
+ if (pv === LOG_NS + 'collectAllIn' || pv === LOG_NS + 'forAllIn') {
4709
+ if (tr.o instanceof GraphTerm) continue; // explicit scope
4710
+ // If scope term is a Var that appears elsewhere, it might be bound to a GraphTerm.
4711
+ // Be conservative and do not skip in that case.
4712
+ if (tr.o instanceof Var) {
4713
+ if (__varOccursElsewhereInPremise(rule.premise, tr.o.name, i, 'o')) return null;
4714
+ needsSnap = true;
4715
+ requiredLevel = Math.max(requiredLevel, 1);
4716
+ } else {
4717
+ needsSnap = true;
4718
+ let prio = 1;
4719
+ const p0 = __logNaturalPriorityFromTerm(tr.o);
4720
+ if (p0 !== null) prio = p0;
4721
+ requiredLevel = Math.max(requiredLevel, prio);
4722
+ }
4723
+ continue;
4724
+ }
4725
+
4726
+ if (pv === LOG_NS + 'includes' || pv === LOG_NS + 'notIncludes') {
4727
+ if (tr.s instanceof GraphTerm) continue; // explicit scope
4728
+ if (tr.s instanceof Var) {
4729
+ if (__varOccursElsewhereInPremise(rule.premise, tr.s.name, i, 's')) return null;
4730
+ needsSnap = true;
4731
+ requiredLevel = Math.max(requiredLevel, 1);
4732
+ } else {
4733
+ needsSnap = true;
4734
+ let prio = 1;
4735
+ const p0 = __logNaturalPriorityFromTerm(tr.s);
4736
+ if (p0 !== null) prio = p0;
4737
+ requiredLevel = Math.max(requiredLevel, prio);
4738
+ }
4739
+ }
4740
+ }
4741
+
4742
+ if (!needsSnap) return { needsSnap: false, requiredLevel: 0 };
4743
+ return { needsSnap: true, requiredLevel };
4744
+ }
4745
+
4559
4746
  // -----------------------------------------------------------------------------
4560
4747
  // log:conclusion cache
4561
4748
  // -----------------------------------------------------------------------------
@@ -6008,23 +6195,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
6008
6195
 
6009
6196
  // Speed up dynamic rule promotion by maintaining O(1) membership sets.
6010
6197
  // (Some workloads derive many rule-producing triples.)
6011
- function __ruleKey(isForward, isFuse, premise, conclusion) {
6012
- let out = (isForward ? 'F' : 'B') + (isFuse ? '!' : '') + '|P|';
6013
- for (let i = 0; i < premise.length; i++) {
6014
- const tr = premise[i];
6015
- if (i) out += '\n';
6016
- out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
6017
- }
6018
- out += '|C|';
6019
- for (let i = 0; i < conclusion.length; i++) {
6020
- const tr = conclusion[i];
6021
- if (i) out += '\n';
6022
- out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
6023
- }
6024
- return out;
6025
- }
6026
6198
 
6027
- if (!Object.prototype.hasOwnProperty.call(forwardRules, '__ruleKeySet')) {
6199
+ if (!hasOwn.call(forwardRules, '__ruleKeySet')) {
6028
6200
  Object.defineProperty(forwardRules, '__ruleKeySet', {
6029
6201
  value: new Set(forwardRules.map((r) => __ruleKey(r.isForward, r.isFuse, r.premise, r.conclusion))),
6030
6202
  enumerable: false,
@@ -6032,7 +6204,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
6032
6204
  configurable: true,
6033
6205
  });
6034
6206
  }
6035
- if (!Object.prototype.hasOwnProperty.call(backRules, '__ruleKeySet')) {
6207
+ if (!hasOwn.call(backRules, '__ruleKeySet')) {
6036
6208
  Object.defineProperty(backRules, '__ruleKeySet', {
6037
6209
  value: new Set(backRules.map((r) => __ruleKey(r.isForward, r.isFuse, r.premise, r.conclusion))),
6038
6210
  enumerable: false,
@@ -6046,18 +6218,6 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
6046
6218
  // rule+substitution instance across outer fixpoint iterations.
6047
6219
  const headSkolemCache = new Map();
6048
6220
 
6049
- function firingKey(ruleIndex, instantiatedPremises) {
6050
- // Deterministic key derived from the instantiated body (ground per substitution).
6051
- // Avoid repeated JSON.stringify of arrays-of-strings (hot path).
6052
- let out = `R${ruleIndex}|`;
6053
- for (let i = 0; i < instantiatedPremises.length; i++) {
6054
- const tr = instantiatedPremises[i];
6055
- if (i) out += '\n';
6056
- out += skolemKeyFromTerm(tr.s) + ' ' + skolemKeyFromTerm(tr.p) + ' ' + skolemKeyFromTerm(tr.o);
6057
- }
6058
- return out;
6059
- }
6060
-
6061
6221
  // Make rules visible to introspection builtins
6062
6222
  backRules.__allForwardRules = forwardRules;
6063
6223
  backRules.__allBackwardRules = backRules;
@@ -6066,161 +6226,14 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
6066
6226
  // Level 0 means "no frozen snapshot" (during Phase A of each outer iteration).
6067
6227
  let scopedClosureLevel = 0;
6068
6228
 
6069
- // Scan known rules for the maximum requested closure priority in
6070
- // log:collectAllIn / log:forAllIn goals.
6071
- function __logNaturalPriorityFromTerm(t) {
6072
- // Parse a 'naturalPriority' used by log:* scoped-closure builtins (e.g., log:collectAllIn).
6073
- // Accept non-negative integral numeric literals; return null if not parseable.
6074
- if (!(t instanceof Literal)) return null;
6075
- const info = parseNumericLiteralInfo(t);
6076
- if (!info) return null;
6077
- if (info.kind === 'integer') {
6078
- const bi = info.value; // BigInt
6079
- if (bi < 0n) return null;
6080
- // clamp to MAX_SAFE_INTEGER (priorities are expected to be small)
6081
- const max = BigInt(Number.MAX_SAFE_INTEGER);
6082
- return Number(bi > max ? max : bi);
6083
- }
6084
- if (info.kind === 'decimal') {
6085
- const n = info.value; // number
6086
- if (!Number.isFinite(n)) return null;
6087
- if (Math.floor(n) !== n) return null;
6088
- if (n < 0) return null;
6089
- return n;
6090
- }
6091
- return null;
6092
- }
6093
-
6094
- function computeMaxScopedClosurePriorityNeeded() {
6095
- let maxP = 0;
6096
- function scanTriple(tr) {
6097
- if (!(tr && tr.p instanceof Iri)) return;
6098
- const pv = tr.p.value;
6099
-
6100
- // log:collectAllIn / log:forAllIn use the object position for the priority.
6101
- if (pv === LOG_NS + 'collectAllIn' || pv === LOG_NS + 'forAllIn') {
6102
- // Explicit scope graphs are immediate and do not require a closure.
6103
- if (tr.o instanceof GraphTerm) return;
6104
- // Variable or non-numeric object => default priority 1 (if used).
6105
- if (tr.o instanceof Var) {
6106
- if (maxP < 1) maxP = 1;
6107
- return;
6108
- }
6109
- const p0 = __logNaturalPriorityFromTerm(tr.o);
6110
- if (p0 !== null) {
6111
- if (p0 > maxP) maxP = p0;
6112
- } else {
6113
- if (maxP < 1) maxP = 1;
6114
- }
6115
- return;
6116
- }
6117
-
6118
- // log:includes / log:notIncludes use the subject position for the priority.
6119
- if (pv === LOG_NS + 'includes' || pv === LOG_NS + 'notIncludes') {
6120
- // Explicit scope graphs are immediate and do not require a closure.
6121
- if (tr.s instanceof GraphTerm) return;
6122
- // Variable or non-numeric subject => default priority 1 (if used).
6123
- if (tr.s instanceof Var) {
6124
- if (maxP < 1) maxP = 1;
6125
- return;
6126
- }
6127
- const p0 = __logNaturalPriorityFromTerm(tr.s);
6128
- if (p0 !== null) {
6129
- if (p0 > maxP) maxP = p0;
6130
- } else {
6131
- if (maxP < 1) maxP = 1;
6132
- }
6133
- }
6134
- }
6135
-
6136
- for (const r of forwardRules) {
6137
- for (const tr of r.premise) scanTriple(tr);
6138
- }
6139
- for (const r of backRules) {
6140
- for (const tr of r.premise) scanTriple(tr);
6141
- }
6142
- return maxP;
6143
- }
6144
-
6145
- let maxScopedClosurePriorityNeeded = computeMaxScopedClosurePriorityNeeded();
6229
+ // Scan known rules for the maximum requested closure priority in scoped log:* goals.
6230
+ let maxScopedClosurePriorityNeeded = __computeMaxScopedClosurePriorityNeeded(forwardRules, backRules);
6146
6231
 
6147
6232
  // Conservative fast-skip for forward rules that cannot possibly succeed
6148
6233
  // until a scoped snapshot exists (or a given closure level is reached).
6149
- // This avoids expensive work (e.g. deep backward chaining) in Phase A.
6150
- function __termContainsVarName(t, name) {
6151
- if (t instanceof Var) return t.name === name;
6152
- if (t instanceof ListTerm) return t.elems.some((e) => __termContainsVarName(e, name));
6153
- if (t instanceof OpenListTerm) return t.tailVar === name || t.prefix.some((e) => __termContainsVarName(e, name));
6154
- if (t instanceof GraphTerm)
6155
- return t.triples.some(
6156
- (tr) =>
6157
- __termContainsVarName(tr.s, name) || __termContainsVarName(tr.p, name) || __termContainsVarName(tr.o, name),
6158
- );
6159
- return false;
6160
- }
6161
-
6162
- function __varOccursElsewhereInPremise(premise, name, idx, field) {
6163
- for (let i = 0; i < premise.length; i++) {
6164
- const tr = premise[i];
6165
- if (!(tr && tr.s && tr.p && tr.o)) continue;
6166
-
6167
- // Skip the specific scope/priority occurrence we are analyzing.
6168
- if (!(i === idx && field === 's') && __termContainsVarName(tr.s, name)) return true;
6169
- if (!(i === idx && field === 'p') && __termContainsVarName(tr.p, name)) return true;
6170
- if (!(i === idx && field === 'o') && __termContainsVarName(tr.o, name)) return true;
6171
- }
6172
- return false;
6173
- }
6174
-
6175
- function __computeForwardRuleScopedSkipInfo(rule) {
6176
- let needsSnap = false;
6177
- let requiredLevel = 0;
6178
-
6179
- for (let i = 0; i < rule.premise.length; i++) {
6180
- const tr = rule.premise[i];
6181
- if (!(tr && tr.p instanceof Iri)) continue;
6182
- const pv = tr.p.value;
6183
-
6184
- if (pv === LOG_NS + 'collectAllIn' || pv === LOG_NS + 'forAllIn') {
6185
- if (tr.o instanceof GraphTerm) continue; // explicit scope
6186
- // If scope term is a Var that appears elsewhere, it might be bound to a GraphTerm.
6187
- // Be conservative and do not skip in that case.
6188
- if (tr.o instanceof Var) {
6189
- if (__varOccursElsewhereInPremise(rule.premise, tr.o.name, i, 'o')) return null;
6190
- needsSnap = true;
6191
- requiredLevel = Math.max(requiredLevel, 1);
6192
- } else {
6193
- needsSnap = true;
6194
- let prio = 1;
6195
- const p0 = __logNaturalPriorityFromTerm(tr.o);
6196
- if (p0 !== null) prio = p0;
6197
- requiredLevel = Math.max(requiredLevel, prio);
6198
- }
6199
- continue;
6200
- }
6201
-
6202
- if (pv === LOG_NS + 'includes' || pv === LOG_NS + 'notIncludes') {
6203
- if (tr.s instanceof GraphTerm) continue; // explicit scope
6204
- if (tr.s instanceof Var) {
6205
- if (__varOccursElsewhereInPremise(rule.premise, tr.s.name, i, 's')) return null;
6206
- needsSnap = true;
6207
- requiredLevel = Math.max(requiredLevel, 1);
6208
- } else {
6209
- needsSnap = true;
6210
- let prio = 1;
6211
- const p0 = __logNaturalPriorityFromTerm(tr.s);
6212
- if (p0 !== null) prio = p0;
6213
- requiredLevel = Math.max(requiredLevel, prio);
6214
- }
6215
- }
6216
- }
6217
-
6218
- if (!needsSnap) return { needsSnap: false, requiredLevel: 0 };
6219
- return { needsSnap: true, requiredLevel };
6220
- }
6221
-
6234
+ // Helper functions are module-scoped: __computeForwardRuleScopedSkipInfo, etc.
6222
6235
  function setScopedSnapshot(snap, level) {
6223
- if (!Object.prototype.hasOwnProperty.call(facts, '__scopedSnapshot')) {
6236
+ if (!hasOwn.call(facts, '__scopedSnapshot')) {
6224
6237
  Object.defineProperty(facts, '__scopedSnapshot', {
6225
6238
  value: snap,
6226
6239
  enumerable: false,
@@ -6231,7 +6244,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
6231
6244
  facts.__scopedSnapshot = snap;
6232
6245
  }
6233
6246
 
6234
- if (!Object.prototype.hasOwnProperty.call(facts, '__scopedClosureLevel')) {
6247
+ if (!hasOwn.call(facts, '__scopedClosureLevel')) {
6235
6248
  Object.defineProperty(facts, '__scopedClosureLevel', {
6236
6249
  value: level,
6237
6250
  enumerable: false,
@@ -6276,7 +6289,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
6276
6289
  // until a snapshot exists (and a certain closure level is reached).
6277
6290
  // This prevents expensive proofs that will definitely fail in Phase A
6278
6291
  // and in early closure levels.
6279
- if (!Object.prototype.hasOwnProperty.call(r, '__scopedSkipInfo')) {
6292
+ if (!hasOwn.call(r, '__scopedSkipInfo')) {
6280
6293
  const info = __computeForwardRuleScopedSkipInfo(r);
6281
6294
  Object.defineProperty(r, '__scopedSkipInfo', {
6282
6295
  value: info,
@@ -6300,7 +6313,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
6300
6313
  // quoted formulas) and has no head blanks, then the head does not depend on which body
6301
6314
  // solution we pick. In that case, we only need *one* proof of the body, and once all head
6302
6315
  // triples are already known we can skip proving the body entirely.
6303
- if (!Object.prototype.hasOwnProperty.call(r, '__headIsStrictGround')) {
6316
+ if (!hasOwn.call(r, '__headIsStrictGround')) {
6304
6317
  let strict = true;
6305
6318
  if (r.isFuse) strict = false;
6306
6319
  else if (r.headBlankLabels && r.headBlankLabels.size) strict = false;
@@ -6353,7 +6366,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
6353
6366
  // IMPORTANT: one skolem map per *rule firing*
6354
6367
  const skMap = {};
6355
6368
  const instantiatedPremises = r.premise.map((b) => applySubstTriple(b, s));
6356
- const fireKey = firingKey(i, instantiatedPremises);
6369
+ const fireKey = __firingKey(i, instantiatedPremises);
6357
6370
 
6358
6371
  for (const cpat of r.conclusion) {
6359
6372
  const instantiated = applySubstTriple(cpat, s);
@@ -6474,7 +6487,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
6474
6487
  // introducing scoped builtins and/or higher closure priorities.
6475
6488
  maxScopedClosurePriorityNeeded = Math.max(
6476
6489
  maxScopedClosurePriorityNeeded,
6477
- computeMaxScopedClosurePriorityNeeded(),
6490
+ __computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
6478
6491
  );
6479
6492
 
6480
6493
  // If there are no scoped builtins in the entire program, Phase B is pure
@@ -6493,7 +6506,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
6493
6506
  // Phase B can also derive rule-producing triples.
6494
6507
  maxScopedClosurePriorityNeeded = Math.max(
6495
6508
  maxScopedClosurePriorityNeeded,
6496
- computeMaxScopedClosurePriorityNeeded(),
6509
+ __computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
6497
6510
  );
6498
6511
 
6499
6512
  if (!changedA && !changedB && scopedClosureLevel >= maxScopedClosurePriorityNeeded) break;
package/lib/engine.js CHANGED
@@ -60,6 +60,8 @@ const { deterministicSkolemIdFromKey } = require('./skolem');
60
60
 
61
61
  const deref = require('./deref');
62
62
 
63
+ const hasOwn = Object.prototype.hasOwnProperty;
64
+
63
65
  let version = 'dev';
64
66
  try {
65
67
  // Node: keep package.json version if available
@@ -179,6 +181,191 @@ function __isStrictGroundTriple(tr) {
179
181
  return __isStrictGroundTerm(tr.s) && __isStrictGroundTerm(tr.p) && __isStrictGroundTerm(tr.o);
180
182
  }
181
183
 
184
+ // -----------------------------------------------------------------------------
185
+ // Rule identity / firing keys
186
+ // -----------------------------------------------------------------------------
187
+ // Used to maintain O(1) membership sets for dynamically promoted rules, and to
188
+ // memoize per-firing head-blank skolemization.
189
+ function __ruleKey(isForward, isFuse, premise, conclusion) {
190
+ let out = (isForward ? 'F' : 'B') + (isFuse ? '!' : '') + '|P|';
191
+ for (let i = 0; i < premise.length; i++) {
192
+ const tr = premise[i];
193
+ if (i) out += '\n';
194
+ out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
195
+ }
196
+ out += '|C|';
197
+ for (let i = 0; i < conclusion.length; i++) {
198
+ const tr = conclusion[i];
199
+ if (i) out += '\n';
200
+ out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
201
+ }
202
+ return out;
203
+ }
204
+
205
+ function __firingKey(ruleIndex, instantiatedPremises) {
206
+ // Deterministic key derived from the instantiated body (ground per substitution).
207
+ let out = `R${ruleIndex}|`;
208
+ for (let i = 0; i < instantiatedPremises.length; i++) {
209
+ const tr = instantiatedPremises[i];
210
+ if (i) out += '\n';
211
+ out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
212
+ }
213
+ return out;
214
+ }
215
+
216
+ // -----------------------------------------------------------------------------
217
+ // Scoped-closure helpers (log:* builtins)
218
+ // -----------------------------------------------------------------------------
219
+ // Parse a 'naturalPriority' used by log:* scoped-closure builtins (e.g., log:collectAllIn).
220
+ // Accept non-negative integral numeric literals; return null if not parseable.
221
+ function __logNaturalPriorityFromTerm(t) {
222
+ if (!(t instanceof Literal)) return null;
223
+ const info = parseNumericLiteralInfo(t);
224
+ if (!info) return null;
225
+
226
+ if (info.kind === 'integer') {
227
+ const bi = info.value; // BigInt
228
+ if (bi < 0n) return null;
229
+ // clamp to MAX_SAFE_INTEGER (priorities are expected to be small)
230
+ const max = BigInt(Number.MAX_SAFE_INTEGER);
231
+ return Number(bi > max ? max : bi);
232
+ }
233
+
234
+ if (info.kind === 'decimal') {
235
+ const n = info.value; // number
236
+ if (!Number.isFinite(n)) return null;
237
+ if (Math.floor(n) !== n) return null;
238
+ if (n < 0) return null;
239
+ return n;
240
+ }
241
+
242
+ return null;
243
+ }
244
+
245
+ function __computeMaxScopedClosurePriorityNeeded(forwardRules, backRules) {
246
+ let maxP = 0;
247
+
248
+ function scanTriple(tr) {
249
+ if (!(tr && tr.p instanceof Iri)) return;
250
+ const pv = tr.p.value;
251
+
252
+ // log:collectAllIn / log:forAllIn use the object position for the priority.
253
+ if (pv === LOG_NS + 'collectAllIn' || pv === LOG_NS + 'forAllIn') {
254
+ // Explicit scope graphs are immediate and do not require a closure.
255
+ if (tr.o instanceof GraphTerm) return;
256
+ // Variable or non-numeric object => default priority 1 (if used).
257
+ if (tr.o instanceof Var) {
258
+ if (maxP < 1) maxP = 1;
259
+ return;
260
+ }
261
+ const p0 = __logNaturalPriorityFromTerm(tr.o);
262
+ if (p0 !== null) {
263
+ if (p0 > maxP) maxP = p0;
264
+ } else {
265
+ if (maxP < 1) maxP = 1;
266
+ }
267
+ return;
268
+ }
269
+
270
+ // log:includes / log:notIncludes use the subject position for the priority.
271
+ if (pv === LOG_NS + 'includes' || pv === LOG_NS + 'notIncludes') {
272
+ // Explicit scope graphs are immediate and do not require a closure.
273
+ if (tr.s instanceof GraphTerm) return;
274
+ // Variable or non-numeric subject => default priority 1 (if used).
275
+ if (tr.s instanceof Var) {
276
+ if (maxP < 1) maxP = 1;
277
+ return;
278
+ }
279
+ const p0 = __logNaturalPriorityFromTerm(tr.s);
280
+ if (p0 !== null) {
281
+ if (p0 > maxP) maxP = p0;
282
+ } else {
283
+ if (maxP < 1) maxP = 1;
284
+ }
285
+ }
286
+ }
287
+
288
+ for (const r of forwardRules) {
289
+ for (const tr of r.premise) scanTriple(tr);
290
+ }
291
+ for (const r of backRules) {
292
+ for (const tr of r.premise) scanTriple(tr);
293
+ }
294
+ return maxP;
295
+ }
296
+
297
+ function __termContainsVarName(t, name) {
298
+ if (t instanceof Var) return t.name === name;
299
+ if (t instanceof ListTerm) return t.elems.some((e) => __termContainsVarName(e, name));
300
+ if (t instanceof OpenListTerm) return t.tailVar === name || t.prefix.some((e) => __termContainsVarName(e, name));
301
+ if (t instanceof GraphTerm)
302
+ return t.triples.some(
303
+ (tr) =>
304
+ __termContainsVarName(tr.s, name) || __termContainsVarName(tr.p, name) || __termContainsVarName(tr.o, name),
305
+ );
306
+ return false;
307
+ }
308
+
309
+ function __varOccursElsewhereInPremise(premise, name, idx, field) {
310
+ for (let i = 0; i < premise.length; i++) {
311
+ const tr = premise[i];
312
+ if (!(tr && tr.s && tr.p && tr.o)) continue;
313
+
314
+ // Skip the specific scope/priority occurrence we are analyzing.
315
+ if (!(i === idx && field === 's') && __termContainsVarName(tr.s, name)) return true;
316
+ if (!(i === idx && field === 'p') && __termContainsVarName(tr.p, name)) return true;
317
+ if (!(i === idx && field === 'o') && __termContainsVarName(tr.o, name)) return true;
318
+ }
319
+ return false;
320
+ }
321
+
322
+ function __computeForwardRuleScopedSkipInfo(rule) {
323
+ let needsSnap = false;
324
+ let requiredLevel = 0;
325
+
326
+ for (let i = 0; i < rule.premise.length; i++) {
327
+ const tr = rule.premise[i];
328
+ if (!(tr && tr.p instanceof Iri)) continue;
329
+ const pv = tr.p.value;
330
+
331
+ if (pv === LOG_NS + 'collectAllIn' || pv === LOG_NS + 'forAllIn') {
332
+ if (tr.o instanceof GraphTerm) continue; // explicit scope
333
+ // If scope term is a Var that appears elsewhere, it might be bound to a GraphTerm.
334
+ // Be conservative and do not skip in that case.
335
+ if (tr.o instanceof Var) {
336
+ if (__varOccursElsewhereInPremise(rule.premise, tr.o.name, i, 'o')) return null;
337
+ needsSnap = true;
338
+ requiredLevel = Math.max(requiredLevel, 1);
339
+ } else {
340
+ needsSnap = true;
341
+ let prio = 1;
342
+ const p0 = __logNaturalPriorityFromTerm(tr.o);
343
+ if (p0 !== null) prio = p0;
344
+ requiredLevel = Math.max(requiredLevel, prio);
345
+ }
346
+ continue;
347
+ }
348
+
349
+ if (pv === LOG_NS + 'includes' || pv === LOG_NS + 'notIncludes') {
350
+ if (tr.s instanceof GraphTerm) continue; // explicit scope
351
+ if (tr.s instanceof Var) {
352
+ if (__varOccursElsewhereInPremise(rule.premise, tr.s.name, i, 's')) return null;
353
+ needsSnap = true;
354
+ requiredLevel = Math.max(requiredLevel, 1);
355
+ } else {
356
+ needsSnap = true;
357
+ let prio = 1;
358
+ const p0 = __logNaturalPriorityFromTerm(tr.s);
359
+ if (p0 !== null) prio = p0;
360
+ requiredLevel = Math.max(requiredLevel, prio);
361
+ }
362
+ }
363
+ }
364
+
365
+ if (!needsSnap) return { needsSnap: false, requiredLevel: 0 };
366
+ return { needsSnap: true, requiredLevel };
367
+ }
368
+
182
369
  // -----------------------------------------------------------------------------
183
370
  // log:conclusion cache
184
371
  // -----------------------------------------------------------------------------
@@ -1631,23 +1818,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
1631
1818
 
1632
1819
  // Speed up dynamic rule promotion by maintaining O(1) membership sets.
1633
1820
  // (Some workloads derive many rule-producing triples.)
1634
- function __ruleKey(isForward, isFuse, premise, conclusion) {
1635
- let out = (isForward ? 'F' : 'B') + (isFuse ? '!' : '') + '|P|';
1636
- for (let i = 0; i < premise.length; i++) {
1637
- const tr = premise[i];
1638
- if (i) out += '\n';
1639
- out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
1640
- }
1641
- out += '|C|';
1642
- for (let i = 0; i < conclusion.length; i++) {
1643
- const tr = conclusion[i];
1644
- if (i) out += '\n';
1645
- out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
1646
- }
1647
- return out;
1648
- }
1649
1821
 
1650
- if (!Object.prototype.hasOwnProperty.call(forwardRules, '__ruleKeySet')) {
1822
+ if (!hasOwn.call(forwardRules, '__ruleKeySet')) {
1651
1823
  Object.defineProperty(forwardRules, '__ruleKeySet', {
1652
1824
  value: new Set(forwardRules.map((r) => __ruleKey(r.isForward, r.isFuse, r.premise, r.conclusion))),
1653
1825
  enumerable: false,
@@ -1655,7 +1827,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
1655
1827
  configurable: true,
1656
1828
  });
1657
1829
  }
1658
- if (!Object.prototype.hasOwnProperty.call(backRules, '__ruleKeySet')) {
1830
+ if (!hasOwn.call(backRules, '__ruleKeySet')) {
1659
1831
  Object.defineProperty(backRules, '__ruleKeySet', {
1660
1832
  value: new Set(backRules.map((r) => __ruleKey(r.isForward, r.isFuse, r.premise, r.conclusion))),
1661
1833
  enumerable: false,
@@ -1669,18 +1841,6 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
1669
1841
  // rule+substitution instance across outer fixpoint iterations.
1670
1842
  const headSkolemCache = new Map();
1671
1843
 
1672
- function firingKey(ruleIndex, instantiatedPremises) {
1673
- // Deterministic key derived from the instantiated body (ground per substitution).
1674
- // Avoid repeated JSON.stringify of arrays-of-strings (hot path).
1675
- let out = `R${ruleIndex}|`;
1676
- for (let i = 0; i < instantiatedPremises.length; i++) {
1677
- const tr = instantiatedPremises[i];
1678
- if (i) out += '\n';
1679
- out += skolemKeyFromTerm(tr.s) + ' ' + skolemKeyFromTerm(tr.p) + ' ' + skolemKeyFromTerm(tr.o);
1680
- }
1681
- return out;
1682
- }
1683
-
1684
1844
  // Make rules visible to introspection builtins
1685
1845
  backRules.__allForwardRules = forwardRules;
1686
1846
  backRules.__allBackwardRules = backRules;
@@ -1689,161 +1849,14 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
1689
1849
  // Level 0 means "no frozen snapshot" (during Phase A of each outer iteration).
1690
1850
  let scopedClosureLevel = 0;
1691
1851
 
1692
- // Scan known rules for the maximum requested closure priority in
1693
- // log:collectAllIn / log:forAllIn goals.
1694
- function __logNaturalPriorityFromTerm(t) {
1695
- // Parse a 'naturalPriority' used by log:* scoped-closure builtins (e.g., log:collectAllIn).
1696
- // Accept non-negative integral numeric literals; return null if not parseable.
1697
- if (!(t instanceof Literal)) return null;
1698
- const info = parseNumericLiteralInfo(t);
1699
- if (!info) return null;
1700
- if (info.kind === 'integer') {
1701
- const bi = info.value; // BigInt
1702
- if (bi < 0n) return null;
1703
- // clamp to MAX_SAFE_INTEGER (priorities are expected to be small)
1704
- const max = BigInt(Number.MAX_SAFE_INTEGER);
1705
- return Number(bi > max ? max : bi);
1706
- }
1707
- if (info.kind === 'decimal') {
1708
- const n = info.value; // number
1709
- if (!Number.isFinite(n)) return null;
1710
- if (Math.floor(n) !== n) return null;
1711
- if (n < 0) return null;
1712
- return n;
1713
- }
1714
- return null;
1715
- }
1716
-
1717
- function computeMaxScopedClosurePriorityNeeded() {
1718
- let maxP = 0;
1719
- function scanTriple(tr) {
1720
- if (!(tr && tr.p instanceof Iri)) return;
1721
- const pv = tr.p.value;
1722
-
1723
- // log:collectAllIn / log:forAllIn use the object position for the priority.
1724
- if (pv === LOG_NS + 'collectAllIn' || pv === LOG_NS + 'forAllIn') {
1725
- // Explicit scope graphs are immediate and do not require a closure.
1726
- if (tr.o instanceof GraphTerm) return;
1727
- // Variable or non-numeric object => default priority 1 (if used).
1728
- if (tr.o instanceof Var) {
1729
- if (maxP < 1) maxP = 1;
1730
- return;
1731
- }
1732
- const p0 = __logNaturalPriorityFromTerm(tr.o);
1733
- if (p0 !== null) {
1734
- if (p0 > maxP) maxP = p0;
1735
- } else {
1736
- if (maxP < 1) maxP = 1;
1737
- }
1738
- return;
1739
- }
1740
-
1741
- // log:includes / log:notIncludes use the subject position for the priority.
1742
- if (pv === LOG_NS + 'includes' || pv === LOG_NS + 'notIncludes') {
1743
- // Explicit scope graphs are immediate and do not require a closure.
1744
- if (tr.s instanceof GraphTerm) return;
1745
- // Variable or non-numeric subject => default priority 1 (if used).
1746
- if (tr.s instanceof Var) {
1747
- if (maxP < 1) maxP = 1;
1748
- return;
1749
- }
1750
- const p0 = __logNaturalPriorityFromTerm(tr.s);
1751
- if (p0 !== null) {
1752
- if (p0 > maxP) maxP = p0;
1753
- } else {
1754
- if (maxP < 1) maxP = 1;
1755
- }
1756
- }
1757
- }
1758
-
1759
- for (const r of forwardRules) {
1760
- for (const tr of r.premise) scanTriple(tr);
1761
- }
1762
- for (const r of backRules) {
1763
- for (const tr of r.premise) scanTriple(tr);
1764
- }
1765
- return maxP;
1766
- }
1767
-
1768
- let maxScopedClosurePriorityNeeded = computeMaxScopedClosurePriorityNeeded();
1852
+ // Scan known rules for the maximum requested closure priority in scoped log:* goals.
1853
+ let maxScopedClosurePriorityNeeded = __computeMaxScopedClosurePriorityNeeded(forwardRules, backRules);
1769
1854
 
1770
1855
  // Conservative fast-skip for forward rules that cannot possibly succeed
1771
1856
  // until a scoped snapshot exists (or a given closure level is reached).
1772
- // This avoids expensive work (e.g. deep backward chaining) in Phase A.
1773
- function __termContainsVarName(t, name) {
1774
- if (t instanceof Var) return t.name === name;
1775
- if (t instanceof ListTerm) return t.elems.some((e) => __termContainsVarName(e, name));
1776
- if (t instanceof OpenListTerm) return t.tailVar === name || t.prefix.some((e) => __termContainsVarName(e, name));
1777
- if (t instanceof GraphTerm)
1778
- return t.triples.some(
1779
- (tr) =>
1780
- __termContainsVarName(tr.s, name) || __termContainsVarName(tr.p, name) || __termContainsVarName(tr.o, name),
1781
- );
1782
- return false;
1783
- }
1784
-
1785
- function __varOccursElsewhereInPremise(premise, name, idx, field) {
1786
- for (let i = 0; i < premise.length; i++) {
1787
- const tr = premise[i];
1788
- if (!(tr && tr.s && tr.p && tr.o)) continue;
1789
-
1790
- // Skip the specific scope/priority occurrence we are analyzing.
1791
- if (!(i === idx && field === 's') && __termContainsVarName(tr.s, name)) return true;
1792
- if (!(i === idx && field === 'p') && __termContainsVarName(tr.p, name)) return true;
1793
- if (!(i === idx && field === 'o') && __termContainsVarName(tr.o, name)) return true;
1794
- }
1795
- return false;
1796
- }
1797
-
1798
- function __computeForwardRuleScopedSkipInfo(rule) {
1799
- let needsSnap = false;
1800
- let requiredLevel = 0;
1801
-
1802
- for (let i = 0; i < rule.premise.length; i++) {
1803
- const tr = rule.premise[i];
1804
- if (!(tr && tr.p instanceof Iri)) continue;
1805
- const pv = tr.p.value;
1806
-
1807
- if (pv === LOG_NS + 'collectAllIn' || pv === LOG_NS + 'forAllIn') {
1808
- if (tr.o instanceof GraphTerm) continue; // explicit scope
1809
- // If scope term is a Var that appears elsewhere, it might be bound to a GraphTerm.
1810
- // Be conservative and do not skip in that case.
1811
- if (tr.o instanceof Var) {
1812
- if (__varOccursElsewhereInPremise(rule.premise, tr.o.name, i, 'o')) return null;
1813
- needsSnap = true;
1814
- requiredLevel = Math.max(requiredLevel, 1);
1815
- } else {
1816
- needsSnap = true;
1817
- let prio = 1;
1818
- const p0 = __logNaturalPriorityFromTerm(tr.o);
1819
- if (p0 !== null) prio = p0;
1820
- requiredLevel = Math.max(requiredLevel, prio);
1821
- }
1822
- continue;
1823
- }
1824
-
1825
- if (pv === LOG_NS + 'includes' || pv === LOG_NS + 'notIncludes') {
1826
- if (tr.s instanceof GraphTerm) continue; // explicit scope
1827
- if (tr.s instanceof Var) {
1828
- if (__varOccursElsewhereInPremise(rule.premise, tr.s.name, i, 's')) return null;
1829
- needsSnap = true;
1830
- requiredLevel = Math.max(requiredLevel, 1);
1831
- } else {
1832
- needsSnap = true;
1833
- let prio = 1;
1834
- const p0 = __logNaturalPriorityFromTerm(tr.s);
1835
- if (p0 !== null) prio = p0;
1836
- requiredLevel = Math.max(requiredLevel, prio);
1837
- }
1838
- }
1839
- }
1840
-
1841
- if (!needsSnap) return { needsSnap: false, requiredLevel: 0 };
1842
- return { needsSnap: true, requiredLevel };
1843
- }
1844
-
1857
+ // Helper functions are module-scoped: __computeForwardRuleScopedSkipInfo, etc.
1845
1858
  function setScopedSnapshot(snap, level) {
1846
- if (!Object.prototype.hasOwnProperty.call(facts, '__scopedSnapshot')) {
1859
+ if (!hasOwn.call(facts, '__scopedSnapshot')) {
1847
1860
  Object.defineProperty(facts, '__scopedSnapshot', {
1848
1861
  value: snap,
1849
1862
  enumerable: false,
@@ -1854,7 +1867,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
1854
1867
  facts.__scopedSnapshot = snap;
1855
1868
  }
1856
1869
 
1857
- if (!Object.prototype.hasOwnProperty.call(facts, '__scopedClosureLevel')) {
1870
+ if (!hasOwn.call(facts, '__scopedClosureLevel')) {
1858
1871
  Object.defineProperty(facts, '__scopedClosureLevel', {
1859
1872
  value: level,
1860
1873
  enumerable: false,
@@ -1899,7 +1912,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
1899
1912
  // until a snapshot exists (and a certain closure level is reached).
1900
1913
  // This prevents expensive proofs that will definitely fail in Phase A
1901
1914
  // and in early closure levels.
1902
- if (!Object.prototype.hasOwnProperty.call(r, '__scopedSkipInfo')) {
1915
+ if (!hasOwn.call(r, '__scopedSkipInfo')) {
1903
1916
  const info = __computeForwardRuleScopedSkipInfo(r);
1904
1917
  Object.defineProperty(r, '__scopedSkipInfo', {
1905
1918
  value: info,
@@ -1923,7 +1936,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
1923
1936
  // quoted formulas) and has no head blanks, then the head does not depend on which body
1924
1937
  // solution we pick. In that case, we only need *one* proof of the body, and once all head
1925
1938
  // triples are already known we can skip proving the body entirely.
1926
- if (!Object.prototype.hasOwnProperty.call(r, '__headIsStrictGround')) {
1939
+ if (!hasOwn.call(r, '__headIsStrictGround')) {
1927
1940
  let strict = true;
1928
1941
  if (r.isFuse) strict = false;
1929
1942
  else if (r.headBlankLabels && r.headBlankLabels.size) strict = false;
@@ -1976,7 +1989,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
1976
1989
  // IMPORTANT: one skolem map per *rule firing*
1977
1990
  const skMap = {};
1978
1991
  const instantiatedPremises = r.premise.map((b) => applySubstTriple(b, s));
1979
- const fireKey = firingKey(i, instantiatedPremises);
1992
+ const fireKey = __firingKey(i, instantiatedPremises);
1980
1993
 
1981
1994
  for (const cpat of r.conclusion) {
1982
1995
  const instantiated = applySubstTriple(cpat, s);
@@ -2097,7 +2110,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
2097
2110
  // introducing scoped builtins and/or higher closure priorities.
2098
2111
  maxScopedClosurePriorityNeeded = Math.max(
2099
2112
  maxScopedClosurePriorityNeeded,
2100
- computeMaxScopedClosurePriorityNeeded(),
2113
+ __computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
2101
2114
  );
2102
2115
 
2103
2116
  // If there are no scoped builtins in the entire program, Phase B is pure
@@ -2116,7 +2129,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */)
2116
2129
  // Phase B can also derive rule-producing triples.
2117
2130
  maxScopedClosurePriorityNeeded = Math.max(
2118
2131
  maxScopedClosurePriorityNeeded,
2119
- computeMaxScopedClosurePriorityNeeded(),
2132
+ __computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
2120
2133
  );
2121
2134
 
2122
2135
  if (!changedA && !changedB && scopedClosureLevel >= maxScopedClosurePriorityNeeded) break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.11.27",
3
+ "version": "1.11.28",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [