eyeling 1.16.2 → 1.16.3
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 +4 -0
- package/examples/ershov-mixed-computation.n3 +106 -0
- package/examples/output/ershov-mixed-computation.n3 +15 -0
- package/eyeling.js +510 -263
- package/lib/cli.js +22 -12
- package/lib/engine.js +488 -251
- package/package.json +1 -1
package/HANDBOOK.md
CHANGED
|
@@ -484,6 +484,8 @@ When proving a goal with IRI predicate, Eyeling computes candidate facts by:
|
|
|
484
484
|
|
|
485
485
|
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.
|
|
486
486
|
|
|
487
|
+
The same selectivity idea is also reused by the single-premise forward-rule agenda in `forwardChain`: safe one-premise rules are pre-indexed by predicate / `(p,s)` / `(p,o)` patterns so a newly added fact only checks the small subset of rules that could match it.
|
|
488
|
+
|
|
487
489
|
### 7.3 Duplicate detection with fast keys
|
|
488
490
|
|
|
489
491
|
When adding derived facts, Eyeling uses a fast-path duplicate check when possible:
|
|
@@ -662,6 +664,8 @@ until not changed
|
|
|
662
664
|
|
|
663
665
|
Top-level input triples are kept as parsed (including non-ground triples such as ?X :p :o.). Groundness is enforced when adding derived facts during forward chaining, and when selecting printed/query output triples.
|
|
664
666
|
|
|
667
|
+
There is also a narrow fast path for some **single-premise** forward rules. When a rule has exactly one non-builtin premise and that premise cannot also be satisfied through backward rules, `forwardChain` can index the rule by that premise shape and fire it directly from newly added facts. This does **not** replace the general saturation loop; it is only an agenda-style shortcut for the safe one-premise case.
|
|
668
|
+
|
|
665
669
|
### 9.2 Strict-ground head optimization
|
|
666
670
|
|
|
667
671
|
There is a nice micro-compiler optimization in `runFixpoint()`:
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# =====================================================================
|
|
2
|
+
# Ershov mixed computation in Notation3
|
|
3
|
+
#
|
|
4
|
+
# This example illustrates the basic idea of Ershov mixed computation:
|
|
5
|
+
# a computation is split into two phases.
|
|
6
|
+
#
|
|
7
|
+
# Phase 1: specialization
|
|
8
|
+
# We take a generic pricing computation and the part of the input
|
|
9
|
+
# already known now (here: the customer is VIP), and we produce a
|
|
10
|
+
# residual program with those known values baked in.
|
|
11
|
+
#
|
|
12
|
+
# Phase 2: residual execution
|
|
13
|
+
# Later, when the remaining input becomes available
|
|
14
|
+
# (here: an order subtotal), we run the residual program and obtain
|
|
15
|
+
# the final result.
|
|
16
|
+
#
|
|
17
|
+
# In this example:
|
|
18
|
+
# generic formula: finalPrice = subtotal * discountRate + shippingFee
|
|
19
|
+
# known now: customerClass = VIP
|
|
20
|
+
# known later: subtotal = 100.00
|
|
21
|
+
#
|
|
22
|
+
# Specialization fixes:
|
|
23
|
+
# discountRate = 0.90
|
|
24
|
+
# shippingFee = 5.00
|
|
25
|
+
#
|
|
26
|
+
# So the residual program becomes:
|
|
27
|
+
# finalPrice = subtotal * 0.90 + 5.00
|
|
28
|
+
#
|
|
29
|
+
# With subtotal = 100.00, the expected result is:
|
|
30
|
+
# 100.00 * 0.90 + 5.00 = 95.00
|
|
31
|
+
#
|
|
32
|
+
# Typical eyeling output therefore includes:
|
|
33
|
+
# - the specialized residual rule
|
|
34
|
+
# - :futureOrder :computedByResidualProgram "95"^^xsd:decimal
|
|
35
|
+
#
|
|
36
|
+
# This is a tiny staging example, not a full partial evaluator.
|
|
37
|
+
# =====================================================================
|
|
38
|
+
|
|
39
|
+
@prefix : <http://example.org/mix#> .
|
|
40
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
41
|
+
@prefix math:<http://www.w3.org/2000/10/swap/math#> .
|
|
42
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
43
|
+
|
|
44
|
+
# ------------------------------------------------------------
|
|
45
|
+
# Generic computation, represented as static parameters
|
|
46
|
+
# ------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
:pricingProgram
|
|
49
|
+
:discountRate "0.90"^^xsd:decimal;
|
|
50
|
+
:shippingFee "5.00"^^xsd:decimal.
|
|
51
|
+
|
|
52
|
+
# Static input known at specialization time
|
|
53
|
+
:specialization :customerClass :VIP.
|
|
54
|
+
|
|
55
|
+
# ------------------------------------------------------------
|
|
56
|
+
# Phase 1: specialization
|
|
57
|
+
#
|
|
58
|
+
# Build a residual program for the VIP case by baking the static
|
|
59
|
+
# constants into a quoted rule.
|
|
60
|
+
# ------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
{
|
|
63
|
+
:pricingProgram :discountRate ?rate;
|
|
64
|
+
:shippingFee ?fee.
|
|
65
|
+
:specialization :customerClass :VIP.
|
|
66
|
+
}
|
|
67
|
+
=>
|
|
68
|
+
{
|
|
69
|
+
:specialization :residualProgram {
|
|
70
|
+
{
|
|
71
|
+
?order :subtotal ?subtotal.
|
|
72
|
+
(?subtotal ?rate) math:product ?discounted.
|
|
73
|
+
(?discounted ?fee) math:sum ?final.
|
|
74
|
+
}
|
|
75
|
+
=>
|
|
76
|
+
{
|
|
77
|
+
?order :finalPrice ?final.
|
|
78
|
+
} .
|
|
79
|
+
} .
|
|
80
|
+
} .
|
|
81
|
+
|
|
82
|
+
# ------------------------------------------------------------
|
|
83
|
+
# Phase 2: residual execution
|
|
84
|
+
#
|
|
85
|
+
# Later input arrives:
|
|
86
|
+
# :futureOrder :subtotal 100.00
|
|
87
|
+
#
|
|
88
|
+
# We combine that later input with the residual program, take the
|
|
89
|
+
# logical closure, and extract the inferred final price.
|
|
90
|
+
# ------------------------------------------------------------
|
|
91
|
+
|
|
92
|
+
{
|
|
93
|
+
:specialization :residualProgram ?rp.
|
|
94
|
+
|
|
95
|
+
( ?rp
|
|
96
|
+
{ :futureOrder :subtotal "100.00"^^xsd:decimal. }
|
|
97
|
+
) log:conjunction ?run .
|
|
98
|
+
|
|
99
|
+
?run log:conclusion ?closure .
|
|
100
|
+
|
|
101
|
+
?closure log:includes { :futureOrder :finalPrice ?price. } .
|
|
102
|
+
}
|
|
103
|
+
=>
|
|
104
|
+
{
|
|
105
|
+
:futureOrder :computedByResidualProgram ?price.
|
|
106
|
+
} .
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
@prefix : <http://example.org/mix#> .
|
|
2
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
3
|
+
@prefix math: <http://www.w3.org/2000/10/swap/math#> .
|
|
4
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
5
|
+
|
|
6
|
+
:specialization :residualProgram {
|
|
7
|
+
{
|
|
8
|
+
?order :subtotal ?subtotal .
|
|
9
|
+
(?subtotal "0.90"^^xsd:decimal) math:product ?discounted .
|
|
10
|
+
(?discounted "5.00"^^xsd:decimal) math:sum ?final .
|
|
11
|
+
} => {
|
|
12
|
+
?order :finalPrice ?final .
|
|
13
|
+
} .
|
|
14
|
+
} .
|
|
15
|
+
:futureOrder :computedByResidualProgram "95"^^xsd:decimal .
|