eyeling 1.11.20 → 1.11.21

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 CHANGED
@@ -182,7 +182,7 @@ Eyeling interns IRIs and Literals by string value. Interning is a quiet performa
182
182
 
183
183
  In addition, interned **Iri**/**Literal** terms (and generated **Blank** terms) get a small, non-enumerable integer id `.__tid` that is stable for the lifetime of the process. This `__tid` is used as the engine’s “fast key”:
184
184
 
185
- - fact indexes (`__byPred` / `__byPS` / `__byPO`) key by `__tid` values (predicate buckets are keyed by `predicate.__tid`, and PS/PO buckets are keyed by the subject/object `.__tid`)
185
+ - fact indexes (`__byPred` / `__byPS` / `__byPO`) key by `__tid` values **and store fact *indices*** (predicate buckets are keyed by `predicate.__tid`, and PS/PO buckets are keyed by the subject/object `.__tid`; buckets contain integer indices into the `facts` array)
186
186
  - duplicate detection uses `"sid pid oid"` where each component is a `__tid`
187
187
  - unification/equality has an early-out when two terms share the same `__tid`
188
188
 
@@ -441,9 +441,9 @@ Facts live in an array `facts: Triple[]`.
441
441
 
442
442
  Eyeling attaches hidden (non-enumerable) index fields:
443
443
 
444
- * `facts.__byPred: Map<predicateId, Triple[]>` where `predicateId` is `predicate.__tid`
445
- * `facts.__byPS: Map<predicateId, Map<termId, Triple[]>>` where `termId` is `term.__tid`
446
- * `facts.__byPO: Map<predicateId, Map<termId, Triple[]>>` where `termId` is `term.__tid`
444
+ * `facts.__byPred: Map<predicateId, number[]>` where each entry is an index into `facts` (and `predicateId` is `predicate.__tid`)
445
+ * `facts.__byPS: Map<predicateId, Map<termId, number[]>>` where each entry is an index into `facts` (and `termId` is `term.__tid`)
446
+ * `facts.__byPO: Map<predicateId, Map<termId, number[]>>` where each entry is an index into `facts` (and `termId` is `term.__tid`)
447
447
  * `facts.__keySet: Set<string>` for a fast-path `"sid pid oid"` key (all three are `__tid` values)
448
448
 
449
449
  `termFastKey(term)` returns a `termId` (`term.__tid`) for **Iri**, **Literal**, and **Blank** terms, and `null` for structured terms (lists, quoted graphs) and variables.
package/eyeling.js CHANGED
@@ -1027,14 +1027,15 @@ function __rdfListObjectsForSP(facts, predIri, subj) {
1027
1027
  const ps = facts.__byPS.get(pk);
1028
1028
  if (ps) {
1029
1029
  const bucket = ps.get(sk);
1030
- if (bucket && bucket.length) return bucket.map((tr) => tr.o);
1030
+ if (bucket && bucket.length) return bucket.map((i) => facts[i].o);
1031
1031
  }
1032
1032
  }
1033
1033
 
1034
1034
  // Fallback scan (covers non-indexable terms)
1035
1035
  const pb = facts.__byPred.get(pk) || [];
1036
1036
  const out = [];
1037
- for (const tr of pb) {
1037
+ for (const i of pb) {
1038
+ const tr = facts[i];
1038
1039
  if (termsEqual(tr.s, subj)) out.push(tr.o);
1039
1040
  }
1040
1041
  return out;
@@ -4955,9 +4956,9 @@ function alphaEqGraphTriples(xs, ys) {
4955
4956
  // ===========================================================================
4956
4957
  //
4957
4958
  // Facts:
4958
- // - __byPred: Map<predicateId, Triple[]>
4959
- // - __byPS: Map<predicateId, Map<subjectId, Triple[]>>
4960
- // - __byPO: Map<predicateId, Map<objectId, Triple[]>>
4959
+ // - __byPred: Map<predicateId, number[]> (indices into facts array)
4960
+ // - __byPS: Map<predicateId, Map<subjectId, number[]>>
4961
+ // - __byPO: Map<predicateId, Map<objectId, number[]>>
4961
4962
  // - __keySet: Set<"S\tP\tO"> for Iri/Literal/Blank-only triples (fast dup check)
4962
4963
  //
4963
4964
  // Backward rules:
@@ -5001,10 +5002,10 @@ function ensureFactIndexes(facts) {
5001
5002
  writable: true,
5002
5003
  });
5003
5004
 
5004
- for (const f of facts) indexFact(facts, f);
5005
+ for (let i = 0; i < facts.length; i++) indexFact(facts, facts[i], i);
5005
5006
  }
5006
5007
 
5007
- function indexFact(facts, tr) {
5008
+ function indexFact(facts, tr, idx) {
5008
5009
  if (tr.p instanceof Iri) {
5009
5010
  // Use predicate term id as the primary key to avoid hashing long IRI strings.
5010
5011
  const pk = tr.p.__tid;
@@ -5014,7 +5015,7 @@ function indexFact(facts, tr) {
5014
5015
  pb = [];
5015
5016
  facts.__byPred.set(pk, pb);
5016
5017
  }
5017
- pb.push(tr);
5018
+ pb.push(idx);
5018
5019
 
5019
5020
  const sk = termFastKey(tr.s);
5020
5021
  if (sk !== null) {
@@ -5028,7 +5029,7 @@ function indexFact(facts, tr) {
5028
5029
  psb = [];
5029
5030
  ps.set(sk, psb);
5030
5031
  }
5031
- psb.push(tr);
5032
+ psb.push(idx);
5032
5033
  }
5033
5034
 
5034
5035
  const ok = termFastKey(tr.o);
@@ -5043,7 +5044,7 @@ function indexFact(facts, tr) {
5043
5044
  pob = [];
5044
5045
  po.set(ok, pob);
5045
5046
  }
5046
- pob.push(tr);
5047
+ pob.push(idx);
5047
5048
  }
5048
5049
  }
5049
5050
 
@@ -5060,14 +5061,14 @@ function candidateFacts(facts, goal) {
5060
5061
  const sk = termFastKey(goal.s);
5061
5062
  const ok = termFastKey(goal.o);
5062
5063
 
5063
- /** @type {Triple[] | null} */
5064
+ /** @type {number[] | null} */
5064
5065
  let byPS = null;
5065
5066
  if (sk !== null) {
5066
5067
  const ps = facts.__byPS.get(pk);
5067
5068
  if (ps) byPS = ps.get(sk) || null;
5068
5069
  }
5069
5070
 
5070
- /** @type {Triple[] | null} */
5071
+ /** @type {number[] | null} */
5071
5072
  let byPO = null;
5072
5073
  if (ok !== null) {
5073
5074
  const po = facts.__byPO.get(pk);
@@ -5081,7 +5082,7 @@ function candidateFacts(facts, goal) {
5081
5082
  return facts.__byPred.get(pk) || [];
5082
5083
  }
5083
5084
 
5084
- return facts;
5085
+ return null;
5085
5086
  }
5086
5087
 
5087
5088
  function hasFactIndexed(facts, tr) {
@@ -5102,12 +5103,12 @@ function hasFactIndexed(facts, tr) {
5102
5103
  // different existentials unless explicitly connected. Do NOT treat
5103
5104
  // triples as duplicates modulo blank renaming, or you'll incorrectly
5104
5105
  // drop facts like: _:sk_0 :x 8.0 (because _:b8 :x 8.0 exists).
5105
- return pob.some((t) => triplesEqual(t, tr));
5106
+ return pob.some((i) => triplesEqual(facts[i], tr));
5106
5107
  }
5107
5108
  }
5108
5109
 
5109
5110
  const pb = facts.__byPred.get(pk) || [];
5110
- return pb.some((t) => triplesEqual(t, tr));
5111
+ return pb.some((i) => triplesEqual(facts[i], tr));
5111
5112
  }
5112
5113
 
5113
5114
  // Non-IRI predicate: fall back to strict triple equality.
@@ -5116,8 +5117,9 @@ function hasFactIndexed(facts, tr) {
5116
5117
 
5117
5118
  function pushFactIndexed(facts, tr) {
5118
5119
  ensureFactIndexes(facts);
5120
+ const idx = facts.length;
5119
5121
  facts.push(tr);
5120
- indexFact(facts, tr);
5122
+ indexFact(facts, tr, idx);
5121
5123
  }
5122
5124
 
5123
5125
  function ensureBackRuleIndexes(backRules) {
@@ -5934,7 +5936,8 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxR
5934
5936
  // 4) Try to satisfy the goal from known facts
5935
5937
  if (goal0.p instanceof Iri) {
5936
5938
  const candidates = candidateFacts(facts, goal0);
5937
- for (const f of candidates) {
5939
+ for (const idx of candidates) {
5940
+ const f = facts[idx];
5938
5941
  const mark = trail.length;
5939
5942
  if (!unifyTripleTrail(goal0, f)) {
5940
5943
  undoTo(mark);
package/lib/builtins.js CHANGED
@@ -1015,14 +1015,15 @@ function __rdfListObjectsForSP(facts, predIri, subj) {
1015
1015
  const ps = facts.__byPS.get(pk);
1016
1016
  if (ps) {
1017
1017
  const bucket = ps.get(sk);
1018
- if (bucket && bucket.length) return bucket.map((tr) => tr.o);
1018
+ if (bucket && bucket.length) return bucket.map((i) => facts[i].o);
1019
1019
  }
1020
1020
  }
1021
1021
 
1022
1022
  // Fallback scan (covers non-indexable terms)
1023
1023
  const pb = facts.__byPred.get(pk) || [];
1024
1024
  const out = [];
1025
- for (const tr of pb) {
1025
+ for (const i of pb) {
1026
+ const tr = facts[i];
1026
1027
  if (termsEqual(tr.s, subj)) out.push(tr.o);
1027
1028
  }
1028
1029
  return out;
package/lib/engine.js CHANGED
@@ -579,9 +579,9 @@ function alphaEqGraphTriples(xs, ys) {
579
579
  // ===========================================================================
580
580
  //
581
581
  // Facts:
582
- // - __byPred: Map<predicateId, Triple[]>
583
- // - __byPS: Map<predicateId, Map<subjectId, Triple[]>>
584
- // - __byPO: Map<predicateId, Map<objectId, Triple[]>>
582
+ // - __byPred: Map<predicateId, number[]> (indices into facts array)
583
+ // - __byPS: Map<predicateId, Map<subjectId, number[]>>
584
+ // - __byPO: Map<predicateId, Map<objectId, number[]>>
585
585
  // - __keySet: Set<"S\tP\tO"> for Iri/Literal/Blank-only triples (fast dup check)
586
586
  //
587
587
  // Backward rules:
@@ -625,10 +625,10 @@ function ensureFactIndexes(facts) {
625
625
  writable: true,
626
626
  });
627
627
 
628
- for (const f of facts) indexFact(facts, f);
628
+ for (let i = 0; i < facts.length; i++) indexFact(facts, facts[i], i);
629
629
  }
630
630
 
631
- function indexFact(facts, tr) {
631
+ function indexFact(facts, tr, idx) {
632
632
  if (tr.p instanceof Iri) {
633
633
  // Use predicate term id as the primary key to avoid hashing long IRI strings.
634
634
  const pk = tr.p.__tid;
@@ -638,7 +638,7 @@ function indexFact(facts, tr) {
638
638
  pb = [];
639
639
  facts.__byPred.set(pk, pb);
640
640
  }
641
- pb.push(tr);
641
+ pb.push(idx);
642
642
 
643
643
  const sk = termFastKey(tr.s);
644
644
  if (sk !== null) {
@@ -652,7 +652,7 @@ function indexFact(facts, tr) {
652
652
  psb = [];
653
653
  ps.set(sk, psb);
654
654
  }
655
- psb.push(tr);
655
+ psb.push(idx);
656
656
  }
657
657
 
658
658
  const ok = termFastKey(tr.o);
@@ -667,7 +667,7 @@ function indexFact(facts, tr) {
667
667
  pob = [];
668
668
  po.set(ok, pob);
669
669
  }
670
- pob.push(tr);
670
+ pob.push(idx);
671
671
  }
672
672
  }
673
673
 
@@ -684,14 +684,14 @@ function candidateFacts(facts, goal) {
684
684
  const sk = termFastKey(goal.s);
685
685
  const ok = termFastKey(goal.o);
686
686
 
687
- /** @type {Triple[] | null} */
687
+ /** @type {number[] | null} */
688
688
  let byPS = null;
689
689
  if (sk !== null) {
690
690
  const ps = facts.__byPS.get(pk);
691
691
  if (ps) byPS = ps.get(sk) || null;
692
692
  }
693
693
 
694
- /** @type {Triple[] | null} */
694
+ /** @type {number[] | null} */
695
695
  let byPO = null;
696
696
  if (ok !== null) {
697
697
  const po = facts.__byPO.get(pk);
@@ -705,7 +705,7 @@ function candidateFacts(facts, goal) {
705
705
  return facts.__byPred.get(pk) || [];
706
706
  }
707
707
 
708
- return facts;
708
+ return null;
709
709
  }
710
710
 
711
711
  function hasFactIndexed(facts, tr) {
@@ -726,12 +726,12 @@ function hasFactIndexed(facts, tr) {
726
726
  // different existentials unless explicitly connected. Do NOT treat
727
727
  // triples as duplicates modulo blank renaming, or you'll incorrectly
728
728
  // drop facts like: _:sk_0 :x 8.0 (because _:b8 :x 8.0 exists).
729
- return pob.some((t) => triplesEqual(t, tr));
729
+ return pob.some((i) => triplesEqual(facts[i], tr));
730
730
  }
731
731
  }
732
732
 
733
733
  const pb = facts.__byPred.get(pk) || [];
734
- return pb.some((t) => triplesEqual(t, tr));
734
+ return pb.some((i) => triplesEqual(facts[i], tr));
735
735
  }
736
736
 
737
737
  // Non-IRI predicate: fall back to strict triple equality.
@@ -740,8 +740,9 @@ function hasFactIndexed(facts, tr) {
740
740
 
741
741
  function pushFactIndexed(facts, tr) {
742
742
  ensureFactIndexes(facts);
743
+ const idx = facts.length;
743
744
  facts.push(tr);
744
- indexFact(facts, tr);
745
+ indexFact(facts, tr, idx);
745
746
  }
746
747
 
747
748
  function ensureBackRuleIndexes(backRules) {
@@ -1558,7 +1559,8 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxR
1558
1559
  // 4) Try to satisfy the goal from known facts
1559
1560
  if (goal0.p instanceof Iri) {
1560
1561
  const candidates = candidateFacts(facts, goal0);
1561
- for (const f of candidates) {
1562
+ for (const idx of candidates) {
1563
+ const f = facts[idx];
1562
1564
  const mark = trail.length;
1563
1565
  if (!unifyTripleTrail(goal0, f)) {
1564
1566
  undoTo(mark);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.11.20",
3
+ "version": "1.11.21",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [