eyeling 1.25.2 → 1.25.4

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
@@ -559,21 +559,25 @@ Facts live in an array `facts: Triple[]`.
559
559
  Eyeling attaches hidden (non-enumerable) index fields:
560
560
 
561
561
  - `facts.__byPred: Map<predicateId, number[]>` where each entry is an index into `facts` (and `predicateId` is `predicate.__tid`)
562
- - `facts.__byPS: Map<predicateId, Map<termId, number[]>>` where each entry is an index into `facts` (and `termId` is `term.__tid`)
563
- - `facts.__byPO: Map<predicateId, Map<termId, number[]>>` where each entry is an index into `facts` (and `termId` is `term.__tid`)
562
+ - `facts.__byPS: Map<predicateId, Map<lookupKey, number[]>>` where each entry is an index into `facts`
563
+ - `facts.__byPO: Map<predicateId, Map<lookupKey, number[]>>` where each entry is an index into `facts`
564
+ - `facts.__byPNonFastS` / `facts.__byPNonFastO` for the small fallback set of IRI-predicate facts whose subject/object cannot be fast-keyed (for example variables or quoted formulas)
565
+ - `facts.__varPred*` for top-level facts whose predicate is a variable; these are the only non-IRI-predicate facts that can match a ground IRI predicate goal
564
566
  - `facts.__keySet: Set<string>` for a fast-path `"sid pid oid"` key (all three are `__tid` values)
565
567
 
566
- `termFastKey(term)` returns a `termId` (`term.__tid`) for **Iri**, **Literal**, and **Blank** terms, and `null` for structured terms (lists, quoted graphs) and variables.
568
+ `termFastKey(term)` returns a `termId` (`term.__tid`) for **Iri**, **Literal**, **Blank**, and strict-ground list terms, and `null` for quoted graphs, open lists, and variables. Proving-time lookup uses `termLookupKey(term)`, which is aligned with `unifyTerm`: it keeps exact ids for IRIs/blanks/strings, but canonicalizes value-equivalent booleans and numerics such as `true` / `"1"^^xsd:boolean` and `1.0` / `1.00`.
567
569
 
568
- The “fast key” only exists when `termFastKey` succeeds for all three terms.
570
+ The duplicate-check “fast key” only exists when `termFastKey` succeeds for all three terms; the proof indexes use the broader `termLookupKey`.
569
571
 
570
572
  ### 7.2 Candidate selection: pick the smallest bucket
571
573
 
572
574
  When proving a goal with IRI predicate, Eyeling computes candidate facts by:
573
575
 
574
- 1. restricting to predicate bucket
575
- 2. optionally narrowing further by subject or object fast key
576
- 3. choosing the smaller of (p,s) vs (p,o) when both exist
576
+ 1. restricting to the IRI predicate bucket
577
+ 2. if subject or object has a lookup key, using the matching `(p,s)` or `(p,o)` bucket plus only the non-fast fallback facts for that same position
578
+ 3. choosing the smaller of the subject-constrained and object-constrained candidate sets when both exist
579
+
580
+ Variable-predicate facts are kept in a separate tiny fallback index. Blank/list/formula predicates are not scanned for an IRI predicate goal because they cannot unify with an IRI predicate.
577
581
 
578
582
  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.
579
583
 
@@ -583,7 +587,7 @@ The same selectivity idea is also reused by the single-premise forward-rule agen
583
587
 
584
588
  When adding derived facts, Eyeling uses a fast-path duplicate check when possible:
585
589
 
586
- - If all three terms have a fast key (Iri/Literal/Blank → `__tid`), it checks membership in `facts.__keySet` using the `"sid pid oid"` key.
590
+ - If all three terms have a duplicate-check fast key, it checks membership in `facts.__keySet` using the `"sid pid oid"` key.
587
591
  - Otherwise (lists, quoted graphs, variables), it falls back to structural triple equality.
588
592
 
589
593
  This still treats blanks correctly: blanks are _not_ interchangeable; the blank **label** (and thus its `__tid`) is part of the key.