eyeling 1.15.3 → 1.15.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 +45 -2
- package/examples/floating-point-first-ema-tracker.n3 +193 -0
- package/examples/floating-point-first-rc-discharge.n3 +190 -0
- package/examples/floating-point-first-servo-envelope.n3 +195 -0
- package/examples/floating-point-first-thermal-cooling.n3 +190 -0
- package/examples/output/floating-point-first-ema-tracker.n3 +53 -0
- package/examples/output/floating-point-first-rc-discharge.n3 +41 -0
- package/examples/output/floating-point-first-servo-envelope.n3 +29 -0
- package/examples/output/floating-point-first-thermal-cooling.n3 +41 -0
- package/examples/output/tabling-query-cache-stress.n3 +26 -0
- package/examples/tabling-query-cache-stress.n3 +175 -0
- package/eyeling.js +109 -0
- package/lib/engine.js +109 -0
- package/package.json +1 -1
package/HANDBOOK.md
CHANGED
|
@@ -561,6 +561,47 @@ Implementation notes:
|
|
|
561
561
|
- Keys are _structural_. Atoms use stable IDs; lists use element keys; variables use their identity (so two different variables are **not** conflated). This keeps the cycle check conservative and avoids accidental pruning.
|
|
562
562
|
- This is not full tabling: it does not memoize answers, it only guards against immediate cycles (the common “A depends on A” loops).
|
|
563
563
|
|
|
564
|
+
### 8.4.1 Minimal completed-goal tabling
|
|
565
|
+
|
|
566
|
+
Eyeling has a **very small, deliberately conservative answer table** for backward goals.
|
|
567
|
+
|
|
568
|
+
What is cached:
|
|
569
|
+
|
|
570
|
+
- only **completed** answer sets
|
|
571
|
+
- keyed by the **fully substituted goal list**
|
|
572
|
+
- only when the proof is entered from a “top-level” call shape (no active per-branch `visited` context)
|
|
573
|
+
- only when the engine is not in a result-limiting mode such as `maxResults`
|
|
574
|
+
|
|
575
|
+
What is **not** cached:
|
|
576
|
+
|
|
577
|
+
- pending / in-progress goals
|
|
578
|
+
- recursive dependency states
|
|
579
|
+
- partial answer streams
|
|
580
|
+
- branch-local states inside an active recursive proof
|
|
581
|
+
|
|
582
|
+
This matters because exposing **pending** answers without dependency propagation would change the meaning of recursive programs. Eyeling therefore caches only results that are already complete and replays them only when the surrounding proof context is equivalent.
|
|
583
|
+
|
|
584
|
+
The cache is invalidated whenever any of the following changes:
|
|
585
|
+
|
|
586
|
+
- the number of known facts
|
|
587
|
+
- the number of backward rules
|
|
588
|
+
- the scoped-closure level
|
|
589
|
+
- whether a frozen scoped snapshot is active
|
|
590
|
+
|
|
591
|
+
So this is **not SLG tabling** and not a general recursion engine. It is best understood as a reuse optimization for repeated backward proofs in a stable proof environment.
|
|
592
|
+
|
|
593
|
+
Typical win cases:
|
|
594
|
+
|
|
595
|
+
- many repeated `log:query` directives with the **same premise**
|
|
596
|
+
- repeated forward-rule body proofs that ask the same completed backward question
|
|
597
|
+
- “query-like” workloads where the expensive part is a repeated backward proof and the fact store does not change between calls
|
|
598
|
+
|
|
599
|
+
Typical non-win cases:
|
|
600
|
+
|
|
601
|
+
- first-time proofs
|
|
602
|
+
- recursive subgoals whose value depends on future answers
|
|
603
|
+
- workloads where the fact set changes between almost every call
|
|
604
|
+
|
|
564
605
|
### 8.5 Backward rules: indexed by head predicate
|
|
565
606
|
|
|
566
607
|
Backward rules are indexed in `backRules.__byHeadPred`. When proving a goal with IRI predicate `p`, Eyeling retrieves:
|
|
@@ -706,7 +747,7 @@ Forward chaining runs inside an _outer loop_ that alternates:
|
|
|
706
747
|
|
|
707
748
|
This produces deterministic behavior for scoped operations: they observe a stable snapshot, not a moving target.
|
|
708
749
|
|
|
709
|
-
**Implementation note (performance):** the two-phase scheme is only needed when the program actually uses scoped built-ins. If no rule contains `log:collectAllIn`, `log:forAllIn`, `log:includes`, or `log:notIncludes`, Eyeling
|
|
750
|
+
**Implementation note (performance):** the two-phase scheme is only needed when the program actually uses scoped built-ins. If no rule contains `log:collectAllIn`, `log:forAllIn`, `log:includes`, or `log:notIncludes`, Eyeling **skips Phase B entirely** and runs only a single saturation. This avoids re-running the forward fixpoint and can prevent a “query-like” forward rule (one whose body contains an expensive backward proof search) from being executed twice.
|
|
710
751
|
|
|
711
752
|
**Implementation note (performance):** in Phase A there is no snapshot, so scoped built-ins (and priority-gated scoped queries) are guaranteed to “delay” by failing.
|
|
712
753
|
Instead of proving the entire forward-rule body only to fail at the end, Eyeling precomputes whether a forward rule depends on scoped built-ins and skips it until a snapshot exists and the requested closure level is reached. This can avoid very expensive proof searches in programs that combine recursion with `log:*In` built-ins.
|
|
@@ -1379,6 +1420,8 @@ Each enumerated rule is standardized apart (fresh variable names) before unifica
|
|
|
1379
1420
|
|
|
1380
1421
|
This is “forward-rule-like” in spirit (premise ⇒ conclusion), but the instantiated conclusion triples are **not added back into the fact store**; they are just what Eyeling prints.
|
|
1381
1422
|
|
|
1423
|
+
**Implementation note (performance):** repeated top-level `log:query` directives with the **same premise formula** are a good fit for Eyeling’s minimal completed-goal tabling (§8.4.1). The first query still performs the full backward proof; later identical premises can reuse the completed answer set as long as the saturated closure and scoped-query context are unchanged.
|
|
1424
|
+
|
|
1382
1425
|
**Important details:**
|
|
1383
1426
|
|
|
1384
1427
|
- Only **top-level** `{...} log:query {...}.` directives are recognized. Inside quoted formulas (or inside rule bodies/heads) it is just an ordinary triple.
|
|
@@ -2448,7 +2491,7 @@ It runs against the external suite.
|
|
|
2448
2491
|
|
|
2449
2492
|
That means:
|
|
2450
2493
|
|
|
2451
|
-
- the
|
|
2494
|
+
- the compliance test suite is shared
|
|
2452
2495
|
- the contract is public
|
|
2453
2496
|
- the result is independently meaningful
|
|
2454
2497
|
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# ====================================================================================
|
|
2
|
+
# Floating-point-first EMA tracking envelope
|
|
3
|
+
#
|
|
4
|
+
# Why this example exists:
|
|
5
|
+
# It is another floating-point-first certificate in the same family as the servo,
|
|
6
|
+
# RC-discharge, and thermal-cooling examples, but now phrased as an exponential
|
|
7
|
+
# moving average (EMA) tracker.
|
|
8
|
+
#
|
|
9
|
+
# Physical story:
|
|
10
|
+
# Let e(k) be the absolute tracking error of an EMA estimator relative to a constant
|
|
11
|
+
# target. Then
|
|
12
|
+
#
|
|
13
|
+
# e(k+1) = a * e(k)
|
|
14
|
+
#
|
|
15
|
+
# where a is the complement of the EMA gain. In this example we choose
|
|
16
|
+
#
|
|
17
|
+
# a = exp(-Ts/tau) = exp(-1/6)
|
|
18
|
+
#
|
|
19
|
+
# with Ts = 0.5 s and tau = 3 s.
|
|
20
|
+
#
|
|
21
|
+
# Since exp(-1/6) is transcendental, we certify it by a double interval:
|
|
22
|
+
#
|
|
23
|
+
# 8.464817248e-1 <= exp(-1/6) <= 8.464817249e-1
|
|
24
|
+
#
|
|
25
|
+
# and propagate a floating-point envelope for the tracking error.
|
|
26
|
+
#
|
|
27
|
+
# What is certified:
|
|
28
|
+
# * the double interval is nonempty and strictly below 1
|
|
29
|
+
# * the tracking-error envelope shrinks at every sample
|
|
30
|
+
# * from an initial error of 8.0e0, the estimator is guaranteed within 2.5e-1
|
|
31
|
+
# by sample 21
|
|
32
|
+
# * with Ts = 5.0e-1 s, that means guaranteed settling by 1.05e1 s
|
|
33
|
+
# ====================================================================================
|
|
34
|
+
|
|
35
|
+
@prefix : <http://example.org/floating-ema#>.
|
|
36
|
+
@prefix math: <http://www.w3.org/2000/10/swap/math#>.
|
|
37
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#>.
|
|
38
|
+
|
|
39
|
+
# ----------
|
|
40
|
+
# Parameters
|
|
41
|
+
# ----------
|
|
42
|
+
|
|
43
|
+
:ema a :SampledEMAEnvelope;
|
|
44
|
+
:samplePeriod 5.0e-1;
|
|
45
|
+
:timeConstant 3.0e0;
|
|
46
|
+
:exactDecaySymbol "exp(-1/6)";
|
|
47
|
+
:decayLower 8.464817248e-1;
|
|
48
|
+
:decayUpper 8.464817249e-1;
|
|
49
|
+
:initialAbsTrackingError 8.0e0;
|
|
50
|
+
:tolerance 2.5e-1;
|
|
51
|
+
:maxStep 24.
|
|
52
|
+
|
|
53
|
+
# ----------------------------------------------------------------
|
|
54
|
+
# The double interval is a finite certificate for a transcendental
|
|
55
|
+
# ----------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
{
|
|
58
|
+
:ema :decayLower ?lo.
|
|
59
|
+
:ema :decayUpper ?hi.
|
|
60
|
+
?lo math:lessThan ?hi.
|
|
61
|
+
?hi math:lessThan 1.0e0.
|
|
62
|
+
?lo math:greaterThan 0.0e0.
|
|
63
|
+
}
|
|
64
|
+
=>
|
|
65
|
+
{
|
|
66
|
+
:ema :decayCertificate :CertifiedDoubleInterval.
|
|
67
|
+
:ema :contractiveDecay true.
|
|
68
|
+
}.
|
|
69
|
+
|
|
70
|
+
# ----------------
|
|
71
|
+
# Initial envelope
|
|
72
|
+
# ----------------
|
|
73
|
+
|
|
74
|
+
{
|
|
75
|
+
:ema :initialAbsTrackingError ?e0.
|
|
76
|
+
}
|
|
77
|
+
=>
|
|
78
|
+
{
|
|
79
|
+
:ema :trackingErrorEnvelopeAt (0 ?e0 ?e0).
|
|
80
|
+
}.
|
|
81
|
+
|
|
82
|
+
# -------------------------------------
|
|
83
|
+
# Envelope propagation
|
|
84
|
+
# lower(k+1) = decayLower * lower(k)
|
|
85
|
+
# upper(k+1) = decayUpper * upper(k)
|
|
86
|
+
# -------------------------------------
|
|
87
|
+
|
|
88
|
+
{
|
|
89
|
+
:ema :maxStep ?max;
|
|
90
|
+
:decayLower ?aLo;
|
|
91
|
+
:decayUpper ?aHi.
|
|
92
|
+
:ema :trackingErrorEnvelopeAt (?k ?lo ?hi).
|
|
93
|
+
?k math:lessThan ?max.
|
|
94
|
+
( ?k 1 ) math:sum ?k1.
|
|
95
|
+
( ?aLo ?lo ) math:product ?lo1.
|
|
96
|
+
( ?aHi ?hi ) math:product ?hi1.
|
|
97
|
+
}
|
|
98
|
+
=>
|
|
99
|
+
{
|
|
100
|
+
:ema :trackingErrorEnvelopeAt (?k1 ?lo1 ?hi1).
|
|
101
|
+
}.
|
|
102
|
+
|
|
103
|
+
# -----------------------------
|
|
104
|
+
# The envelope shrinks strictly
|
|
105
|
+
# -----------------------------
|
|
106
|
+
|
|
107
|
+
{
|
|
108
|
+
:ema :trackingErrorEnvelopeAt (?k ?lo ?hi).
|
|
109
|
+
( ?k 1 ) math:sum ?k1.
|
|
110
|
+
:ema :trackingErrorEnvelopeAt (?k1 ?lo1 ?hi1).
|
|
111
|
+
?hi1 math:lessThan ?hi.
|
|
112
|
+
}
|
|
113
|
+
=>
|
|
114
|
+
{
|
|
115
|
+
:ema :strictContractionAt ?k.
|
|
116
|
+
}.
|
|
117
|
+
|
|
118
|
+
# --------------------------------
|
|
119
|
+
# Settlement in the tolerance band
|
|
120
|
+
# --------------------------------
|
|
121
|
+
|
|
122
|
+
{
|
|
123
|
+
:ema :trackingErrorEnvelopeAt (?k ?lo ?hi).
|
|
124
|
+
:ema :tolerance ?tol.
|
|
125
|
+
?hi math:lessThan ?tol.
|
|
126
|
+
}
|
|
127
|
+
=>
|
|
128
|
+
{
|
|
129
|
+
:ema :settledCandidate ?k.
|
|
130
|
+
}.
|
|
131
|
+
|
|
132
|
+
{
|
|
133
|
+
:ema :settledCandidate ?k.
|
|
134
|
+
?k math:greaterThan 0.
|
|
135
|
+
( ?k 1 ) math:difference ?km1.
|
|
136
|
+
:ema :trackingErrorEnvelopeAt (?km1 ?prevLo ?prevHi).
|
|
137
|
+
:ema :tolerance ?tol.
|
|
138
|
+
?prevHi math:notLessThan ?tol.
|
|
139
|
+
}
|
|
140
|
+
=>
|
|
141
|
+
{
|
|
142
|
+
:ema :firstSettledStep ?k.
|
|
143
|
+
}.
|
|
144
|
+
|
|
145
|
+
{
|
|
146
|
+
:ema :firstSettledStep ?k.
|
|
147
|
+
:ema :samplePeriod ?ts.
|
|
148
|
+
( ?k ?ts ) math:product ?t.
|
|
149
|
+
}
|
|
150
|
+
=>
|
|
151
|
+
{
|
|
152
|
+
:ema :firstSettledTime ?t.
|
|
153
|
+
}.
|
|
154
|
+
|
|
155
|
+
# -----------------------------------------------------------
|
|
156
|
+
# Readable engineering summary for the floating-point witness
|
|
157
|
+
# -----------------------------------------------------------
|
|
158
|
+
|
|
159
|
+
{
|
|
160
|
+
:ema :firstSettledStep ?k;
|
|
161
|
+
:firstSettledTime ?t;
|
|
162
|
+
:tolerance ?tol;
|
|
163
|
+
:exactDecaySymbol ?sym;
|
|
164
|
+
:decayLower ?aLo;
|
|
165
|
+
:decayUpper ?aHi.
|
|
166
|
+
}
|
|
167
|
+
log:query
|
|
168
|
+
{
|
|
169
|
+
:result :summary (
|
|
170
|
+
"exact-decay" ?sym
|
|
171
|
+
"double-lower" ?aLo
|
|
172
|
+
"double-upper" ?aHi
|
|
173
|
+
"tolerance" ?tol
|
|
174
|
+
"first-settled-step" ?k
|
|
175
|
+
"first-settled-time-s" ?t
|
|
176
|
+
).
|
|
177
|
+
}.
|
|
178
|
+
|
|
179
|
+
{
|
|
180
|
+
:ema :trackingErrorEnvelopeAt (?k ?lo ?hi).
|
|
181
|
+
}
|
|
182
|
+
log:query
|
|
183
|
+
{
|
|
184
|
+
:result :envelope (?k ?lo ?hi).
|
|
185
|
+
}.
|
|
186
|
+
|
|
187
|
+
{
|
|
188
|
+
:ema :strictContractionAt ?k.
|
|
189
|
+
}
|
|
190
|
+
log:query
|
|
191
|
+
{
|
|
192
|
+
:result :contractionAt ?k.
|
|
193
|
+
}.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# =======================================================================================
|
|
2
|
+
# Floating-point-first RC discharge envelope
|
|
3
|
+
#
|
|
4
|
+
# Why this example exists:
|
|
5
|
+
# It is another floating-point-first certificate, parallel to the servo-envelope style,
|
|
6
|
+
# but framed as a passive RC discharge.
|
|
7
|
+
#
|
|
8
|
+
# Physical story:
|
|
9
|
+
# A sampled RC voltage obeys
|
|
10
|
+
#
|
|
11
|
+
# v(k+1) = a * v(k)
|
|
12
|
+
#
|
|
13
|
+
# with exact discrete decay factor
|
|
14
|
+
#
|
|
15
|
+
# a = exp(-Ts/tau) = exp(-1/4)
|
|
16
|
+
#
|
|
17
|
+
# for Ts = 25 ms and tau = 100 ms.
|
|
18
|
+
#
|
|
19
|
+
# Because exp(-1/4) is transcendental, we certify it by a double interval:
|
|
20
|
+
#
|
|
21
|
+
# 7.788007830e-1 <= exp(-1/4) <= 7.788007831e-1
|
|
22
|
+
#
|
|
23
|
+
# and propagate a floating-point envelope on the capacitor voltage.
|
|
24
|
+
#
|
|
25
|
+
# What is certified:
|
|
26
|
+
# * the double interval is nonempty and strictly below 1
|
|
27
|
+
# * the voltage envelope shrinks sample by sample
|
|
28
|
+
# * from an initial voltage of 2.40e1 V, the capacitor is guaranteed below 1.0e0 V
|
|
29
|
+
# by sample 15
|
|
30
|
+
# * with Ts = 2.5e-2 s, that means guaranteed settling by 3.75e-1 s
|
|
31
|
+
# =======================================================================================
|
|
32
|
+
|
|
33
|
+
@prefix : <http://example.org/floating-rc#>.
|
|
34
|
+
@prefix math: <http://www.w3.org/2000/10/swap/math#>.
|
|
35
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#>.
|
|
36
|
+
|
|
37
|
+
# ----------
|
|
38
|
+
# Parameters
|
|
39
|
+
# ----------
|
|
40
|
+
|
|
41
|
+
:rc a :SampledRCEnvelope;
|
|
42
|
+
:samplePeriod 2.5e-2;
|
|
43
|
+
:timeConstant 1.0e-1;
|
|
44
|
+
:exactDecaySymbol "exp(-1/4)";
|
|
45
|
+
:decayLower 7.788007830e-1;
|
|
46
|
+
:decayUpper 7.788007831e-1;
|
|
47
|
+
:initialVoltage 2.40e1;
|
|
48
|
+
:tolerance 1.0e0;
|
|
49
|
+
:maxStep 18.
|
|
50
|
+
|
|
51
|
+
# ----------------------------------------------------------------
|
|
52
|
+
# The double interval is a finite certificate for a transcendental
|
|
53
|
+
# ----------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
{
|
|
56
|
+
:rc :decayLower ?lo; :decayUpper ?hi.
|
|
57
|
+
?lo math:lessThan ?hi.
|
|
58
|
+
?hi math:lessThan 1.0e0.
|
|
59
|
+
?lo math:greaterThan 0.0e0.
|
|
60
|
+
}
|
|
61
|
+
=>
|
|
62
|
+
{
|
|
63
|
+
:rc :decayCertificate :CertifiedDoubleInterval.
|
|
64
|
+
:rc :contractiveDecay true.
|
|
65
|
+
}.
|
|
66
|
+
|
|
67
|
+
# ----------------
|
|
68
|
+
# Initial envelope
|
|
69
|
+
# ----------------
|
|
70
|
+
|
|
71
|
+
{
|
|
72
|
+
:rc :initialVoltage ?v0.
|
|
73
|
+
}
|
|
74
|
+
=>
|
|
75
|
+
{
|
|
76
|
+
:rc :voltageEnvelopeAt (0 ?v0 ?v0).
|
|
77
|
+
}.
|
|
78
|
+
|
|
79
|
+
# -------------------------------------
|
|
80
|
+
# Envelope propagation
|
|
81
|
+
# lower(k+1) = decayLower * lower(k)
|
|
82
|
+
# upper(k+1) = decayUpper * upper(k)
|
|
83
|
+
# -------------------------------------
|
|
84
|
+
|
|
85
|
+
{
|
|
86
|
+
:rc :maxStep ?max;
|
|
87
|
+
:decayLower ?aLo;
|
|
88
|
+
:decayUpper ?aHi.
|
|
89
|
+
:rc :voltageEnvelopeAt (?k ?lo ?hi).
|
|
90
|
+
?k math:lessThan ?max.
|
|
91
|
+
( ?k 1 ) math:sum ?k1.
|
|
92
|
+
( ?aLo ?lo ) math:product ?lo1.
|
|
93
|
+
( ?aHi ?hi ) math:product ?hi1.
|
|
94
|
+
}
|
|
95
|
+
=>
|
|
96
|
+
{
|
|
97
|
+
:rc :voltageEnvelopeAt (?k1 ?lo1 ?hi1).
|
|
98
|
+
}.
|
|
99
|
+
|
|
100
|
+
# -----------------------------
|
|
101
|
+
# The envelope shrinks strictly
|
|
102
|
+
# -----------------------------
|
|
103
|
+
|
|
104
|
+
{
|
|
105
|
+
:rc :voltageEnvelopeAt (?k ?lo ?hi).
|
|
106
|
+
( ?k 1 ) math:sum ?k1.
|
|
107
|
+
:rc :voltageEnvelopeAt (?k1 ?lo1 ?hi1).
|
|
108
|
+
?hi1 math:lessThan ?hi.
|
|
109
|
+
}
|
|
110
|
+
=>
|
|
111
|
+
{
|
|
112
|
+
:rc :strictContractionAt ?k.
|
|
113
|
+
}.
|
|
114
|
+
|
|
115
|
+
# --------------------------------
|
|
116
|
+
# Settlement in the tolerance band
|
|
117
|
+
# --------------------------------
|
|
118
|
+
|
|
119
|
+
{
|
|
120
|
+
:rc :voltageEnvelopeAt (?k ?lo ?hi).
|
|
121
|
+
:rc :tolerance ?tol.
|
|
122
|
+
?hi math:lessThan ?tol.
|
|
123
|
+
}
|
|
124
|
+
=>
|
|
125
|
+
{
|
|
126
|
+
:rc :settledCandidate ?k.
|
|
127
|
+
}.
|
|
128
|
+
|
|
129
|
+
{
|
|
130
|
+
:rc :settledCandidate ?k.
|
|
131
|
+
?k math:greaterThan 0.
|
|
132
|
+
( ?k 1 ) math:difference ?km1.
|
|
133
|
+
:rc :voltageEnvelopeAt (?km1 ?prevLo ?prevHi).
|
|
134
|
+
:rc :tolerance ?tol.
|
|
135
|
+
?prevHi math:notLessThan ?tol.
|
|
136
|
+
}
|
|
137
|
+
=>
|
|
138
|
+
{
|
|
139
|
+
:rc :firstSettledStep ?k.
|
|
140
|
+
}.
|
|
141
|
+
|
|
142
|
+
{
|
|
143
|
+
:rc :firstSettledStep ?k.
|
|
144
|
+
:rc :samplePeriod ?ts.
|
|
145
|
+
( ?k ?ts ) math:product ?t.
|
|
146
|
+
}
|
|
147
|
+
=>
|
|
148
|
+
{
|
|
149
|
+
:rc :firstSettledTime ?t.
|
|
150
|
+
}.
|
|
151
|
+
|
|
152
|
+
# -----------------------------------------------------------
|
|
153
|
+
# Readable engineering summary for the floating-point witness
|
|
154
|
+
# -----------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
{
|
|
157
|
+
:rc :firstSettledStep ?k;
|
|
158
|
+
:firstSettledTime ?t;
|
|
159
|
+
:tolerance ?tol;
|
|
160
|
+
:exactDecaySymbol ?sym;
|
|
161
|
+
:decayLower ?aLo;
|
|
162
|
+
:decayUpper ?aHi.
|
|
163
|
+
}
|
|
164
|
+
log:query
|
|
165
|
+
{
|
|
166
|
+
:result :summary (
|
|
167
|
+
"exact-decay" ?sym
|
|
168
|
+
"double-lower" ?aLo
|
|
169
|
+
"double-upper" ?aHi
|
|
170
|
+
"tolerance" ?tol
|
|
171
|
+
"first-settled-step" ?k
|
|
172
|
+
"first-settled-time-s" ?t
|
|
173
|
+
).
|
|
174
|
+
}.
|
|
175
|
+
|
|
176
|
+
{
|
|
177
|
+
:rc :voltageEnvelopeAt (?k ?lo ?hi).
|
|
178
|
+
}
|
|
179
|
+
log:query
|
|
180
|
+
{
|
|
181
|
+
:result :envelope (?k ?lo ?hi).
|
|
182
|
+
}.
|
|
183
|
+
|
|
184
|
+
{
|
|
185
|
+
:rc :strictContractionAt ?k.
|
|
186
|
+
}
|
|
187
|
+
log:query
|
|
188
|
+
{
|
|
189
|
+
:result :contractionAt ?k.
|
|
190
|
+
}.
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# =======================================================================================
|
|
2
|
+
# Floating-point-first transcendental servo envelope
|
|
3
|
+
#
|
|
4
|
+
# Why this example exists:
|
|
5
|
+
# It complements the integer-first and decimal-first examples with a version whose
|
|
6
|
+
# certifying arithmetic starts from floating-point literals.
|
|
7
|
+
#
|
|
8
|
+
# Physical story:
|
|
9
|
+
# A sampled first-order servo has error dynamics
|
|
10
|
+
#
|
|
11
|
+
# e(k+1) = a * e(k)
|
|
12
|
+
#
|
|
13
|
+
# with exact discrete pole
|
|
14
|
+
#
|
|
15
|
+
# a = exp(-Ts/tau) = exp(-1/3)
|
|
16
|
+
#
|
|
17
|
+
# for Ts = 20 ms and tau = 60 ms.
|
|
18
|
+
#
|
|
19
|
+
# The number exp(-1/3) is transcendental, so it is not available as a finite exact
|
|
20
|
+
# decimal or rational. In this example we work floating-point-first: the certificate is
|
|
21
|
+
# carried by N3 double literals, written in exponent form.
|
|
22
|
+
#
|
|
23
|
+
# Floating-point-first move:
|
|
24
|
+
# We store a certified double interval
|
|
25
|
+
#
|
|
26
|
+
# 7.165313105e-1 <= exp(-1/3) <= 7.165313106e-1
|
|
27
|
+
#
|
|
28
|
+
# and propagate a double error envelope. The resulting derivations stay explicit and
|
|
29
|
+
# machine-checkable, but now the numeric layer is “floating-point first”.
|
|
30
|
+
#
|
|
31
|
+
# What is certified:
|
|
32
|
+
# * the double interval is nonempty and contractive
|
|
33
|
+
# * the error envelope shrinks at every sample
|
|
34
|
+
# * from an initial error of 1.25e1, the loop is guaranteed inside 5.0e-1 by sample 10
|
|
35
|
+
# * with Ts = 2.0e-2 s, that means guaranteed settling by 2.0e-1 s
|
|
36
|
+
# =======================================================================================
|
|
37
|
+
|
|
38
|
+
@prefix : <http://example.org/floating-servo#>.
|
|
39
|
+
@prefix math: <http://www.w3.org/2000/10/swap/math#>.
|
|
40
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#>.
|
|
41
|
+
|
|
42
|
+
# ----------
|
|
43
|
+
# Parameters
|
|
44
|
+
# ----------
|
|
45
|
+
|
|
46
|
+
:servo a :SampledServoEnvelope;
|
|
47
|
+
:samplePeriod 2.0e-2;
|
|
48
|
+
:timeConstant 6.0e-2;
|
|
49
|
+
:exactPoleSymbol "exp(-1/3)";
|
|
50
|
+
:poleLower 7.165313105e-1;
|
|
51
|
+
:poleUpper 7.165313106e-1;
|
|
52
|
+
:initialAbsError 1.25e1;
|
|
53
|
+
:tolerance 5.0e-1;
|
|
54
|
+
:maxStep 12.
|
|
55
|
+
|
|
56
|
+
# ----------------------------------------------------------------
|
|
57
|
+
# The double interval is a finite certificate for a transcendental
|
|
58
|
+
# ----------------------------------------------------------------
|
|
59
|
+
|
|
60
|
+
{
|
|
61
|
+
:servo :poleLower ?lo; :poleUpper ?hi.
|
|
62
|
+
?lo math:lessThan ?hi.
|
|
63
|
+
?hi math:lessThan 1.0e0.
|
|
64
|
+
?lo math:greaterThan 0.0e0.
|
|
65
|
+
}
|
|
66
|
+
=>
|
|
67
|
+
{
|
|
68
|
+
:servo :poleCertificate :CertifiedDoubleInterval.
|
|
69
|
+
:servo :contractivePole true.
|
|
70
|
+
}.
|
|
71
|
+
|
|
72
|
+
# ----------------
|
|
73
|
+
# Initial envelope
|
|
74
|
+
# ----------------
|
|
75
|
+
|
|
76
|
+
{
|
|
77
|
+
:servo :initialAbsError ?e0.
|
|
78
|
+
}
|
|
79
|
+
=>
|
|
80
|
+
{
|
|
81
|
+
:servo :errorEnvelopeAt (0 ?e0 ?e0).
|
|
82
|
+
}.
|
|
83
|
+
|
|
84
|
+
# -----------------------------------
|
|
85
|
+
# Envelope propagation
|
|
86
|
+
# lower(k+1) = poleLower * lower(k)
|
|
87
|
+
# upper(k+1) = poleUpper * upper(k)
|
|
88
|
+
# -----------------------------------
|
|
89
|
+
|
|
90
|
+
{
|
|
91
|
+
:servo :maxStep ?max;
|
|
92
|
+
:poleLower ?aLo;
|
|
93
|
+
:poleUpper ?aHi.
|
|
94
|
+
:servo :errorEnvelopeAt (?k ?lo ?hi).
|
|
95
|
+
?k math:lessThan ?max.
|
|
96
|
+
( ?k 1 ) math:sum ?k1.
|
|
97
|
+
( ?aLo ?lo ) math:product ?lo1.
|
|
98
|
+
( ?aHi ?hi ) math:product ?hi1.
|
|
99
|
+
}
|
|
100
|
+
=>
|
|
101
|
+
{
|
|
102
|
+
:servo :errorEnvelopeAt (?k1 ?lo1 ?hi1).
|
|
103
|
+
}.
|
|
104
|
+
|
|
105
|
+
# -----------------------------
|
|
106
|
+
# The envelope shrinks strictly
|
|
107
|
+
# -----------------------------
|
|
108
|
+
|
|
109
|
+
{
|
|
110
|
+
:servo :errorEnvelopeAt (?k ?lo ?hi).
|
|
111
|
+
( ?k 1 ) math:sum ?k1.
|
|
112
|
+
:servo :errorEnvelopeAt (?k1 ?lo1 ?hi1).
|
|
113
|
+
?hi1 math:lessThan ?hi.
|
|
114
|
+
}
|
|
115
|
+
=>
|
|
116
|
+
{
|
|
117
|
+
:servo :strictContractionAt ?k.
|
|
118
|
+
}.
|
|
119
|
+
|
|
120
|
+
# --------------------------------
|
|
121
|
+
# Settlement in the tolerance band
|
|
122
|
+
# --------------------------------
|
|
123
|
+
|
|
124
|
+
{
|
|
125
|
+
:servo :errorEnvelopeAt (?k ?lo ?hi).
|
|
126
|
+
:servo :tolerance ?tol.
|
|
127
|
+
?hi math:lessThan ?tol.
|
|
128
|
+
}
|
|
129
|
+
=>
|
|
130
|
+
{
|
|
131
|
+
:servo :settledCandidate ?k.
|
|
132
|
+
}.
|
|
133
|
+
|
|
134
|
+
{
|
|
135
|
+
:servo :settledCandidate ?k.
|
|
136
|
+
?k math:greaterThan 0.
|
|
137
|
+
( ?k 1 ) math:difference ?km1.
|
|
138
|
+
:servo :errorEnvelopeAt (?km1 ?prevLo ?prevHi).
|
|
139
|
+
:servo :tolerance ?tol.
|
|
140
|
+
?prevHi math:notLessThan ?tol.
|
|
141
|
+
}
|
|
142
|
+
=>
|
|
143
|
+
{
|
|
144
|
+
:servo :firstSettledStep ?k.
|
|
145
|
+
}.
|
|
146
|
+
|
|
147
|
+
{
|
|
148
|
+
:servo :firstSettledStep ?k.
|
|
149
|
+
:servo :samplePeriod ?ts.
|
|
150
|
+
( ?k ?ts ) math:product ?t.
|
|
151
|
+
}
|
|
152
|
+
=>
|
|
153
|
+
{
|
|
154
|
+
:servo :firstSettledTime ?t.
|
|
155
|
+
}.
|
|
156
|
+
|
|
157
|
+
# ---------------------------------------------------------------
|
|
158
|
+
# Readable engineering summary for the floating-point certificate
|
|
159
|
+
# ---------------------------------------------------------------
|
|
160
|
+
|
|
161
|
+
{
|
|
162
|
+
:servo :firstSettledStep ?k;
|
|
163
|
+
:firstSettledTime ?t;
|
|
164
|
+
:tolerance ?tol;
|
|
165
|
+
:exactPoleSymbol ?sym;
|
|
166
|
+
:poleLower ?aLo;
|
|
167
|
+
:poleUpper ?aHi.
|
|
168
|
+
}
|
|
169
|
+
log:query
|
|
170
|
+
{
|
|
171
|
+
:result :summary (
|
|
172
|
+
"exact-pole" ?sym
|
|
173
|
+
"double-lower" ?aLo
|
|
174
|
+
"double-upper" ?aHi
|
|
175
|
+
"tolerance" ?tol
|
|
176
|
+
"first-settled-step" ?k
|
|
177
|
+
"first-settled-time-s" ?t
|
|
178
|
+
).
|
|
179
|
+
}.
|
|
180
|
+
|
|
181
|
+
{
|
|
182
|
+
:servo :errorEnvelopeAt (?k ?lo ?hi).
|
|
183
|
+
}
|
|
184
|
+
log:query
|
|
185
|
+
{
|
|
186
|
+
:result :envelope (?k ?lo ?hi).
|
|
187
|
+
}.
|
|
188
|
+
|
|
189
|
+
{
|
|
190
|
+
:servo :strictContractionAt ?k.
|
|
191
|
+
}
|
|
192
|
+
log:query
|
|
193
|
+
{
|
|
194
|
+
:result :contractionAt ?k.
|
|
195
|
+
}.
|