eyeling 1.11.13 → 1.11.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/HANDBOOK.md CHANGED
@@ -176,11 +176,19 @@ Two details matter later:
176
176
 
177
177
  Eyeling interns IRIs and Literals by string value. Interning is a quiet performance trick with big consequences:
178
178
 
179
- - repeated IRIs become pointer-equal
179
+ - repeated IRIs/Literals become pointer-equal
180
180
  - indexing is cheaper
181
181
  - comparisons are faster and allocations drop.
182
182
 
183
- Terms are treated as immutable: once interned, the code assumes you wont mutate `.value`.
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 engines “fast key”:
184
+
185
+ - fact indexes (`__byPS` / `__byPO`) key by `__tid` instead of building `"I:..."` / `"L:..."` strings
186
+ - duplicate detection uses `"sid pid oid"` where each component is a `__tid`
187
+ - unification/equality has an early-out when two terms share the same `__tid`
188
+
189
+ For blanks, the id is derived from the blank label (so different blank labels remain different existentials).
190
+
191
+ Terms are treated as immutable: once interned/created, the code assumes you won’t mutate `.value` (or `.label` for blanks).
184
192
 
185
193
  ### 3.4 Prefix environment
186
194
 
@@ -434,9 +442,11 @@ Facts live in an array `facts: Triple[]`.
434
442
  Eyeling attaches hidden (non-enumerable) index fields:
435
443
 
436
444
  * `facts.__byPred: Map<predicateIRI, Triple[]>`
437
- * `facts.__byPS: Map<predicateIRI, Map<subjectKey, Triple[]>>`
438
- * `facts.__byPO: Map<predicateIRI, Map<objectKey, Triple[]>>`
439
- * `facts.__keySet: Set<string>` for a fast-path “S\tP\tO” key when all terms are IRI/Literal-like
445
+ * `facts.__byPS: Map<predicateIRI, Map<termId, Triple[]>>` where `termId` is `term.__tid`
446
+ * `facts.__byPO: Map<predicateIRI, Map<termId, Triple[]>>` where `termId` is `term.__tid`
447
+ * `facts.__keySet: Set<string>` for a fast-path `"sid pid oid"` key (all three are `__tid` values)
448
+
449
+ `termFastKey(term)` returns a `termId` (`term.__tid`) for **Iri**, **Literal**, and **Blank** terms, and `null` for structured terms (lists, quoted graphs) and variables.
440
450
 
441
451
  The “fast key” only exists when `termFastKey` succeeds for all three terms.
442
452
 
@@ -450,14 +460,14 @@ When proving a goal with IRI predicate, Eyeling computes candidate facts by:
450
460
 
451
461
  This is a cheap selectivity heuristic. In type-heavy RDF, `(p,o)` is often extremely selective (e.g., `rdf:type` + a class IRI), so the PO index can be a major speed win.
452
462
 
453
- ### 7.3 Duplicate detection is careful about blanks
463
+ ### 7.3 Duplicate detection with fast keys
454
464
 
455
- A tempting optimization would be “treat two triples as duplicates modulo blank renaming.” Eyeling does **not** do this globally, because it would be unsound: different blank labels represent different existentials unless explicitly linked.
465
+ When adding derived facts, Eyeling uses a fast-path duplicate check when possible:
456
466
 
457
- So:
467
+ - If all three terms have a fast key (Iri/Literal/Blank → `__tid`), it checks membership in `facts.__keySet` using the `"sid pid oid"` key.
468
+ - Otherwise (lists, quoted graphs, variables), it falls back to structural triple equality.
458
469
 
459
- * fast-key dedup works for IRI/Literal-only triples
460
- * otherwise, it falls back to real triple equality on actual blank labels.
470
+ This still treats blanks correctly: blanks are *not* interchangeable; the blank **label** (and thus its `__tid`) is part of the key.
461
471
 
462
472
  ---
463
473
 
@@ -0,0 +1,5 @@
1
+ @prefix : <http://example.org/#> .
2
+
3
+ :discovered :airroute ("Ostend-Bruges International Airport" "Liège Airport" "Heraklion International Nikos Kazantzakis Airport" "Václav Havel Airport Prague") .
4
+ :discovered :airroute ("Ostend-Bruges International Airport" "Liège Airport" "Diagoras Airport" "Václav Havel Airport Prague") .
5
+ :discovered :airroute ("Ostend-Bruges International Airport" "Liège Airport" "Palma De Mallorca Airport" "Václav Havel Airport Prague") .