fmsl 0.7.0__tar.gz

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.
fmsl-0.7.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MJ Celedon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
fmsl-0.7.0/PKG-INFO ADDED
@@ -0,0 +1,553 @@
1
+ Metadata-Version: 2.4
2
+ Name: fmsl
3
+ Version: 0.7.0
4
+ Summary: Exact fluid states of 0/0 points: proven limits and the full set of limit values of rational functions in two and three variables, plus proven-safe code for formulas with 0/0 traps
5
+ Author: MJ Celedon
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/dazbuddies-sketch/fmsl
8
+ Project-URL: Issues, https://github.com/dazbuddies-sketch/fmsl/issues
9
+ Keywords: symbolic,limits,multivariate-limits,cluster-set,puiseux,newton-polygon,singularity,code-generation,numerical-stability,robotics,quantum,verified-computation
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
13
+ Classifier: Topic :: Scientific/Engineering :: Physics
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Provides-Extra: matrix
20
+ Requires-Dist: numpy>=1.20; extra == "matrix"
21
+ Dynamic: license-file
22
+
23
+ # FMSL — exact fluid states of 0/0 points
24
+
25
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23682015.svg)](https://doi.org/10.5281/zenodo.23682015)
26
+ [![tests](https://github.com/dazbuddies-sketch/fmsl/actions/workflows/tests.yml/badge.svg)](https://github.com/dazbuddies-sketch/fmsl/actions/workflows/tests.yml)
27
+
28
+ By **MJ Celedon**. FMSL computes exactly what a function does at a 0/0 point: the limit with a
29
+ proof when it exists, and otherwise the complete set of values it approaches (its *fluid
30
+ state*), for rational functions of two and three variables. It also generates proven-safe code
31
+ for one-variable formulas with 0/0 traps.
32
+
33
+ **Cite:** Celedon, MJ (2026). *FMSL: exact fluid states of 0/0 points.* Zenodo.
34
+ https://doi.org/10.5281/zenodo.23682015
35
+
36
+ ## Proven-safe code for formulas with 0/0 traps
37
+
38
+ Formulas like `sin(t)/t`, `(1 - cos t)/t²`, `(1 - e^(-10r))/r` and the quantum-mechanics
39
+ "φ functions" `(e^(iz) - 1 - iz)/(iz)²` are everywhere in robotics, graphics, finance and
40
+ physics simulation. At zero they divide by zero, and **near** zero, ordinary
41
+ floating-point code silently returns garbage:
42
+
43
+ ```python
44
+ >>> t = 1e-8
45
+ >>> (1 - math.cos(t)) / t**2 # true value: 0.5
46
+ 0.0
47
+ ```
48
+
49
+ FMSL is a small formula language and compiler that:
50
+
51
+ 1. **Proves** what a formula does at the trouble point: removable value, pole (with its exact direction to infinity), or essential singularity.
52
+ 2. **Proves** whether an expression is identically zero, or says honestly that it cannot.
53
+ 3. **Emits safe Python or C code** that uses an exact series near the trap and the original formula elsewhere.
54
+ 4. **Attaches a proof of the maximum error** in the danger zone near zero (a *Siletz bound*), then compiles the code and measures it as well.
55
+ 5. **Provides robust matrix functions for quantum dynamics** (propagators, φ functions and control gradients) that handle degenerate energy levels without thresholds.
56
+
57
+ Real and complex formulas are supported. The core has no dependencies (pure Python 3.9+);
58
+ the matrix module uses numpy.
59
+
60
+ ## Install
61
+
62
+ ```
63
+ pip install fmsl # core language and compiler
64
+ pip install fmsl[matrix] # plus matrix functions (numpy)
65
+ ```
66
+
67
+ or from source: `pip install .`
68
+
69
+ ## Example
70
+
71
+ ```
72
+ # robotics: SO(3) rotation coefficient
73
+ fluid B(t) = (1 - cos(t))/t^2
74
+
75
+ at t -> 0: B # removable: value 1/2 [proven]
76
+ check sin(t)^2 + cos(t)^2 - 1 # proven_zero
77
+ check exp(t^61) - 1 # proven_nonzero (order 61)
78
+ check exp(sin(t))*exp(-sin(t)) - 1 # unproven (zero through order 60; no certificate)
79
+ if B == 0.5 # TYPE ERROR: '==' on fluid values is not allowed
80
+ emit c B # safe C code + proven error bound, compiled and validated
81
+ ```
82
+
83
+ ```
84
+ # quantum: time-evolution phase integral as the frequency w -> 0
85
+ context T = 3
86
+ fluid prop(w) = (exp(-T*i*w) - 1)/(-i*w)
87
+ at w -> 0: prop # removable: value 3 [proven]
88
+ check exp(i*t) - cos(t) - i*sin(t) # proven_zero (Euler's formula)
89
+ ```
90
+
91
+ Run the examples:
92
+
93
+ ```
94
+ fmsl examples/realworld.fms
95
+ fmsl examples/quantum.fms
96
+ ```
97
+
98
+ ## Results
99
+
100
+ "Measured" is the worst relative error against exact values at about 190 points from
101
+ 10⁻¹² to 1 on both sides of zero. "Proven" is the Siletz bound: a mathematical guarantee
102
+ for **every** input in the series zone near zero. Proofs are worst-case, so they are looser
103
+ than measurements, but they hold for all inputs, not just tested ones. 1e-16 is full
104
+ double precision.
105
+
106
+ **Robotics, graphics, finance**
107
+
108
+ | Formula | Field | Proven value at 0 | Naive code | FMSL measured | FMSL proven (zone) |
109
+ |---|---|---|---|---|---|
110
+ | (1 − cos t)/t² | Robotics (SO(3)) | 1/2 | 1.0 (100% wrong) | 1.2e-16 | ≤ 4.7e-15 (\|t\| < 1) |
111
+ | (t − sin t)/t³ | Robotics (SO(3)) | 1/6 | 1.0 (100% wrong) | 1.7e-16 | ≤ 4.4e-15 (\|t\| < 1) |
112
+ | (1 − t·sin t / (2(1 − cos t)))/t² | Robotics (SO(3) log map) | 1/12 | inf / NaN | 4.9e-16 | ≤ 1.5e-14 (\|t\| < 1) |
113
+ | (1 − e^(−10r))/r | Finance (annuity, r → 0) | 10 | 1.1e-05 | 2.0e-16 | ≤ 1.8e-13 (\|r\| < 0.215) |
114
+ | sin(2t/3)/sin t | Graphics (slerp) | 2/3 | fails only at t = 0 | 1.7e-16 | ≤ 3.2e-15 (\|t\| < 1e-4) |
115
+
116
+ **Quantum mechanics** (ħ = 1, evolution time T = 3)
117
+
118
+ | Formula | Use | Proven value at 0 | Naive code | FMSL measured | FMSL proven (zone) |
119
+ |---|---|---|---|---|---|
120
+ | (e^(−iTw) − 1)/(−iw) | Time-evolution phase integral | 3 | 4.7e-09 | 9.1e-17 | ≤ 2.8e-14 (\|w\| < 0.5) |
121
+ | φ₁ = (e^(iz) − 1)/(iz) | Schrödinger / Lindblad solvers | 1 | 5.0e-09 | 5.8e-17 | ≤ 1.7e-14 (\|z\| < 1) |
122
+ | φ₂ = (e^(iz) − 1 − iz)/(iz)² | Schrödinger / Lindblad solvers | 1/2 | 1.0 (100% wrong) | 1.1e-16 | ≤ 1.2e-14 (\|z\| < 1) |
123
+ | φ₃ = (e^(iz) − 1 − iz + z²/2)/(iz)³ | Schrödinger / Lindblad solvers | 1/6 | **8.1e+12** | 3.0e-16 | ≤ 1.1e-14 (\|z\| < 1) |
124
+ | (e^(−iTd) − 1 + iTd)/d² | 2nd-order perturbation theory | −9/2 | 1.0 (100% wrong) | 5.1e-17 | ≤ 9.6e-14 (\|d\| < 1) |
125
+ | sin²(Td/2)/(d/2)² | Fermi's golden rule | 9 | fails only at d = 0 | 0 | ≤ 3.9e-14 (\|d\| < 1) |
126
+ | (e^(−Tg) − 1 + Tg)/g² | Open-system decay kernel | 9/2 | **1.3e+07** | 1.6e-16 | ≤ 1.8e-13 (\|g\| < 1) |
127
+
128
+ Soundness check: with the series deliberately truncated (2 to 16 terms) on six test
129
+ formulas, the proven bound stayed above the actual error in all 30 cases.
130
+
131
+ ## Matrix functions for quantum dynamics
132
+
133
+ `pip install fmsl[matrix]` (adds numpy). For a Hermitian Hamiltonian H:
134
+
135
+ ```python
136
+ from fmsl import matrix as fm
137
+ U = fm.propagator(H, t) # exp(-iHt)
138
+ P2 = fm.phi(2, H, t) # phi_2(-iHt), for exponential integrators
139
+ dU = fm.frechet(H, dH, t) # derivative of exp(-iHt) w.r.t. H in direction dH
140
+ grads = fm.frechet_many(H, [dH1, dH2, ...], t) # quantum-control gradients, one eigen-decomposition
141
+ ```
142
+
143
+ These use the eigen-decomposition (the fast method) with FMSL's safe kernels, so exact and
144
+ near-degenerate energy levels and zero energies need no thresholds. The divided difference
145
+ (e^a − e^b)/(a − b) is evaluated as e^b·φ₁(a − b), which never divides by a small gap.
146
+
147
+ The scalar kernel φ_k(z) works for all complex z: an exact-coefficient series with a
148
+ **proven** error bound on |z| ≤ 1 (≤ 1.3e-13 for k = 1 to 4), and elsewhere a per-element
149
+ choice between the series and the standard recurrence by running error analysis. Measured
150
+ against exact values on 2,300 points (oscillating, decaying and growing regimes): at most
151
+ 6.6e-16 relative error for φ₁ to φ₄. The naive formula is off by up to 3.4e+21 (φ₄).
152
+
153
+ **Accuracy** — relative error (Frobenius norm) against an independent 200-bit reference,
154
+ 8×8 Hamiltonians built exactly with prescribed eigenvalues, t = 1:
155
+
156
+ | Case | Quantity | FMSL | Textbook spectral formula | scipy (block-matrix) |
157
+ |---|---|---|---|---|
158
+ | Exact degeneracy + zero energy | gradient | 8.4e-16 | 6.0e-03 (with equality guard) | 3.0e-16 |
159
+ | | φ₂(−iHt) | 4.3e-16 | **5.4e-01** (with zero guard) | 2.6e-16 |
160
+ | Near-degenerate (gaps 1e-9, 1e-12) | gradient | 1.2e-15 | 1.7e-06 (equality guard) | 2.9e-16 |
161
+ | | φ₃(−iHt) | 6.6e-16 | **5.3e-01** | 2.7e-16 |
162
+ | Weak coupling (all \|E\| ≤ 1e-6) | gradient | 1.3e-15 | 5.6e-11 (even with tolerance 1e-8) | 2.2e-16 |
163
+ | | φ₂(−iHt) | 8.6e-16 | **3.5e-01** | 9.6e-17 |
164
+ | Generic spectrum | gradient | 1.2e-15 | 1.2e-15 | 2.6e-16 |
165
+
166
+ The textbook spectral formula fails because floating-point eigenvalues of a degenerate
167
+ Hamiltonian are never exactly equal, and a zero energy is never exactly zero, so the usual
168
+ guards do not fire. scipy's block-matrix routines (`expm_frechet`, augmented `expm`) avoid
169
+ eigenvalues entirely and are also accurate, slightly more so than FMSL.
170
+
171
+ **Speed** — what FMSL adds over scipy is that the *fast* spectral method becomes as robust
172
+ as the slow one. Quantum-control gradients for m = 10 control directions sharing one
173
+ Hamiltonian (random Hermitian H):
174
+
175
+ | n | FMSL `frechet_many` | scipy `expm_frechet` × 10 | Speedup | Agreement |
176
+ |---|---|---|---|---|
177
+ | 32 | 1.7 ms | 6.8 ms | 4.1× | 2.1e-15 |
178
+ | 64 | 4.3 ms | 28.8 ms | 6.7× | 2.9e-15 |
179
+ | 128 | 24.6 ms | 179.5 ms | 7.3× | 5.2e-15 |
180
+
181
+ Reproduce with `python benchmarks/matrix_bench.py`. Timings are from one machine and will vary.
182
+
183
+ ## Two variables: fluid states with direction
184
+
185
+ In two variables, a 0/0 point has no single state: the answer depends on the path of
186
+ approach. `fmsl.multivar` computes the full **state profile** of a rational function of x, y
187
+ at the origin, exactly:
188
+
189
+ ```python
190
+ from fmsl.multivar import describe
191
+ print(describe("x^2*y/(x^4+y^2)"))
192
+ # verdict: NO LIMIT (proven)
193
+ # because value depends on the path constant c along y = c*|x|^2: (c) / (1 + c^2)
194
+ # balance points (critical curvatures a): 2
195
+ ```
196
+
197
+ Every straight line into the origin gives 0 here, yet along the parabolas y = c·x² the value is
198
+ c/(1 + c²). The engine finds such hidden paths from the **Newton polygon**: the state can only
199
+ change at *balance curvatures*, where competing terms of the numerator and denominator tie.
200
+ Along each path y = c·|x|^a the problem reduces to one variable and is solved exactly; where a
201
+ leading form vanishes, the engine zooms in (Newton–Puiseux) to find paths hidden deeper, e.g.
202
+ y = x + c·x² for x⁴/((x − y)² + x⁴). Irrational balance constants such as c = √2 are handled
203
+ with exact real algebraic numbers (`fmsl.algebraic`: Sturm-sequence zero and sign tests, never
204
+ floating point).
205
+
206
+ **When to stop zooming (resolution rule).** Zooming is only needed at a *repeated* root of a
207
+ leading form, or a root shared by the numerator and denominator forms. A simple root is
208
+ already settled by a theorem:
209
+
210
+ - a simple root of the denominator form that the numerator form does not share means there is
211
+ a real curve where D = 0 and N ≠ 0 (implicit function theorem). So f is unbounded near it. If f
212
+ is near 0 on both sides of that curve, it also takes **every** real value nearby
213
+ (intermediate value theorem);
214
+ - a simple root of the numerator form, in a sector where f is unbounded, means f changes sign
215
+ through 0 there, so again it takes every real value.
216
+
217
+ This handles curves whose Puiseux series never ends, such as the pole curve x = −y³/(1 − y).
218
+ On 200 random functions it leaves **0 unproven** (21 before exact algebraic numbers and this
219
+ rule), and all 200 profiles take about 1 second.
220
+
221
+ **Why a LIMIT verdict is a proof.** The engine examines curved paths, not every possible approach.
222
+ That is enough by the **curve selection lemma** (Bruhat–Cartan–Wallace, Milnor): for a function
223
+ built from polynomials, if f does not tend to L, then f already fails to tend to L along a
224
+ single Puiseux arc x = ±tᵠ, y = c·tᵖ + … Every such arc falls into one of the profile's cases:
225
+ a sector between balance curvatures, a balance curvature with c not a root, or a zoom at a
226
+ root. So when every case gives L, the limit is L.
227
+
228
+ ### The fluid state is an exact arc
229
+
230
+ Cancel the common factors of N and D, and treat f as a map into the circle R ∪ {∞}. Near the
231
+ origin it is continuous, and a punctured disc is connected. So the set of all values f
232
+ approaches (its **cluster set**) is closed and **connected**. There are only three shapes:
233
+
234
+ | Shape | Meaning | Example |
235
+ |---|---|---|
236
+ | a single point | LIMIT = L, or DIVERGES (the point ∞) | x³/(x² + y²) → {0} |
237
+ | a closed arc | no limit; exactly these values are approached | x²y/(x⁴ + y²) → [−1/2, 1/2] |
238
+ | the whole circle | every value, including ∞, is approached | x³/(y − x²) |
239
+
240
+ The profile now outputs this set exactly (`profile(text)["cluster"]`, printed by `describe`).
241
+ Its endpoints can be irrational: for x²/(x² + 2y²) + y²/(3x² + y²) the set is [0.579796…, 1],
242
+ where the lower end is an exact algebraic number. An arc can also pass through ∞: for
243
+ xy/(x² − 3xy + y²) the values form the arc from −1/5 up through ∞ to −1. Equality of algebraic
244
+ numbers from different fields is decided exactly, using the characteristic polynomial of
245
+ multiplication by the number.
246
+
247
+ On the 200 random functions the shapes split 85 single points, 13 proper arcs and 102 whole
248
+ circles. So when a random rational function has no limit, it usually takes every value near
249
+ the origin.
250
+
251
+ **Two independent checks.**
252
+
253
+ 1. *The theorem itself.* A computed cluster set that is not connected would contradict the
254
+ theorem, so some family of paths would be missing. All 200 random cluster sets are connected
255
+ and exact. To measure how much this check can catch, I deleted parts of correct profiles on
256
+ purpose. It caught **72%** of deleted balance curvatures (29 of 40), but **0%** of deleted
257
+ pole and zero curves (0 of 36). Losing those leaves a smaller set that is still connected.
258
+ So it is a partial detector, not a completeness proof.
259
+ 2. *A different algorithm.* `benchmarks/loop_crosscheck.py` computes the image of f on small
260
+ squares |x|, |y| = r around the origin. On each side f is a one-variable ratio of
261
+ polynomials, monotone between exactly isolated breakpoints, and values at critical points are
262
+ evaluated as exact algebraic numbers. No Newton polygon is used. As r → 0 the image must
263
+ converge to the cluster set. On 13 classic and 100 random functions, the
264
+ loop image matches the engine's exact arc at every scale tested (r = 10⁻⁴, 10⁻⁸, 10⁻¹⁶, 10⁻³²):
265
+ **113 of 113, no difference on the circle.** This includes a curve hidden three zoom levels
266
+ deep, whose peak on the loop is narrower than r². When I injected errors on purpose, the loop
267
+ check caught **42 of 42**: all 19 deleted pole and zero curves, and all 23 deleted balance
268
+ curvatures. The connectedness test caught 14 of those 42.
269
+
270
+ **Validation of path values.** Every reported path value is re-checked by direct exact
271
+ evaluation of the original function along that path. The original validation (17 classic
272
+ cases, 200 random functions) found no disagreements across 20,360 path checks. The v0.4 engine
273
+ was re-validated on 200 new random functions, with 0 disagreements across 6,810 path checks; for
274
+ 18 functions, exact re-evaluation at algebraic points exceeded the checker's 4-minute limit.
275
+ Development uncovered and fixed three real errors (missed denominator roots, missed
276
+ numerator–denominator balance points, and a thin hidden curve that random sampling never
277
+ hits); all three are regression tests.
278
+
279
+ `python benchmarks/fluid_state_figures.py` draws the pictures from the engine's output.
280
+
281
+ ### Reproducing the published examples
282
+
283
+ `benchmarks/dgnp2022_examples.py` runs all 21 examples of Đinh, Guo, Nguyễn and Phạm (2022) through
284
+ FMSL. **All 21 agree** with the paper, including example 20, where the paper reports that
285
+ Maple 2021's `limit` returned a wrong range (Maple gave (3/4, 1); the true range is [3/4, +∞]).
286
+ The paper did not compute a range for example 5, because its denominator vanishes along curves
287
+ ("future work"). FMSL gives **[−∞, −3] ∪ [3, +∞]**, which is disconnected in the extended line
288
+ but connected on the circle. The independent loop computation confirms it.
289
+
290
+ The signed range (+∞ and −∞ kept apart, as in the paper) is `profile(...)["cluster"]["signed_text"]`.
291
+ Checked independently, the signed ranges agree with the loop computation on **53 of 53**
292
+ functions: 13 of the paper's examples and 40 random ones. The 8 very-high-degree product
293
+ examples (10–17) were left out of the loop check for time; FMSL's results on them still match
294
+ the paper.
295
+
296
+ ## Three variables
297
+
298
+ `fmsl.space` extends the fluid state to rational functions of x, y, z:
299
+
300
+ ```python
301
+ from fmsl.space import describe3
302
+ print(describe3("(x*y+y*z+z*x)/(x^2+y^2+z^2)"))
303
+ # verdict: NO LIMIT (proven)
304
+ # fluid state (signed): [-1/2, 1]
305
+ ```
306
+
307
+ An arc into the origin with x ≢ 0 has the form x = ±sᵠ, y = c·sᵖ + …, z = d·sʳ + …, so it
308
+ carries a weight (1, a, b). The (a, b) quarter-plane is cut by the lines where two terms tie
309
+ (the normal fan of the Newton polyhedra of N and D, plus N–D ties) into:
310
+
311
+ - **faces**, where the forms are monomials, so f → 0, ∞ (with signs) or a constant;
312
+ - **edges**, where the forms depend on one monomial u = cᵛ¹dᵛ², a one-variable problem solved
313
+ exactly;
314
+ - **vertices**, where the forms are genuine polynomials in (c, d). The exact range of fN/fD over
315
+ the whole plane is computed by `fmsl.plane`: critical values from resultants, values at
316
+ infinity from charts analysed by the two-variable engine, then one exact test value per gap,
317
+ decided by a cylindrical real-root test.
318
+
319
+ Simple roots are settled by the implicit function and intermediate value theorems. Repeated or
320
+ shared roots are zoomed: a change of variables, then the same analysis. Arcs inside the
321
+ coordinate planes go to the two-variable engine. The connectedness theorem holds in any number
322
+ of variables, because removing a curve of indeterminacy from a 3-ball leaves it connected. So
323
+ the result is again a point, an arc or the whole circle, and connectedness is checked.
324
+
325
+ Examples, each confirmed by hand or by a known closed form:
326
+
327
+ | f(x, y, z) | Fluid state | Why |
328
+ |---|---|---|
329
+ | xy/(x² + y² + z²) | [−1/2, 1/2] | 2xy ≤ x² + y² |
330
+ | x²y/(x⁴ + y² + z²) | [−1/2, 1/2] | the parabola trap, in 3-D |
331
+ | x⁴/((x − y)² + x⁴ + z²) | [0, 1] | curve hidden two levels deep |
332
+ | (xy + yz + zx)/(x² + y² + z²) | [−1/2, 1] | eigenvalues of the quadratic form |
333
+ | (xy − 2z² + xz)/(x² + 2y² + 3z²) | [−0.796873…, 0.394973…] | generalized eigenvalues |
334
+ | x²y²z²/(x⁶ + y⁶ + z⁶) | [0, 1/3] | decided at a vertex (c = d = 1) |
335
+ | xyz/(x⁴ + y⁴ + z²) | [−√2/4, √2/4] (to 40 digits) | max of cd/(1 + c⁴ + d²) |
336
+ | x²yz/((yz − x²)² + x⁶) | [−1/4, +∞] | zoom along the curve yz = x²: t/(t − 1)² ≥ −1/4 |
337
+ | 2x³y²z²/((y²z − x)² + x⁴) | {0} (limit 0) | a squared form touches 0 without crossing it |
338
+
339
+ On 200 random rational functions of three variables (`benchmarks/space_random.py`), the engine
340
+ decides **all 200** (24 limits, 162 no-limit, 14 divergent; median time 0.01 s). Every computed
341
+ fluid state is connected.
342
+
343
+ **Independent check.** `benchmarks/cube_crosscheck.py` computes the exact image of f on the
344
+ surface of small cubes |x|, |y|, |z| ≤ r. On each face f is a two-variable function over a
345
+ square, and its exact image comes from the box version of the range algorithm, plus the
346
+ two-variable fluid state at any point inside a face where the face function is 0/0. No Newton
347
+ polyhedra, weights or zooming are used. On 11 classic and 40 random functions, and on 54
348
+ functions built to vanish along curves (the curve zoom), the cube image matches the engine's
349
+ exact signed fluid state at r = 10⁻³ and 10⁻⁶ on **102 of 105**. The other 3 were too slow for
350
+ the cube (over 2 hours each); all three have the answer [−∞, +∞], confirmed independently: one
351
+ on the plane z = x, where the two-variable engine proves every real value is taken, and two by
352
+ explicit families of paths along which f tends to any chosen real number. The cube check found one real
353
+ engine error, fixed in 0.7.0: a squared denominator form had been treated as a pole surface.
354
+ When I deleted parts of correct answers on purpose (vertex ranges, pole and zero surfaces), the
355
+ cube check caught **11 of 11** changed answers. The connectedness test caught none of them. The low-level range algorithm itself was
356
+ tested against dense sampling: 60 of 60 random functions agree over a square, and 60 of 60 over
357
+ the whole plane.
358
+
359
+ **Version 1 limits.** The following are reported as UNPROVEN, never guessed: zooming along a
360
+ curve c^p d^q = u₀ with neither |p| nor |q| equal to 1; zooming at irrational points; depth > 4. A
361
+ critical value whose critical point is not cut out linearly is computed to 40 digits and
362
+ marked "approx.".
363
+
364
+ ## Iteration: bifurcations are balance points
365
+
366
+ Iterating a map x → f(x, r), new orbits are born at bifurcations. At a bifurcation point the
367
+ period polynomial Qₙ = (fⁿ(x) − x)/(f(x) − x) is a 0/0 point, and the new orbit grows along a
368
+ branch e = c·|u|^a (u = x − x₀, e = r − r₀) that `fmsl.bifurcation` finds exactly from the
369
+ Newton polygon. Verified against brute-force iteration (millions of steps):
370
+
371
+ | Bifurcation | Exact branch | Iteration ÷ prediction at e = 10⁻⁵ | Measured exponent |
372
+ |---|---|---|---|
373
+ | Transcritical (logistic, r = 1) | e = u | 0.99999 | 1.000 |
374
+ | Saddle-node (x + r − x²) | e = u² | 1.00000 | 0.500 |
375
+ | Pitchfork (x + rx − x³) | e = u² | 1.00000 | 0.500 |
376
+ | Period doubling (logistic, r = 3) | e = 9u² | 1.00000 | 0.500 |
377
+ | Second period doubling (logistic, r = 1 + √6) | e = c·u² | 0.99999 | 0.500 |
378
+
379
+ For the second period doubling the coefficient is exact:
380
+ **c = 20 + 10√2 + (35/3)√3 + (35/3)√6 ≈ 82.9268**, computed in Q(√2, √3) and confirmed by
381
+ iteration to five digits. These are leading-order laws: the agreement improves as e → 0.
382
+
383
+ **Stability, exactly.** Whether a new orbit attracts is decided by its multiplier
384
+ λ = (fⁿ)′(x) along the branch, which is a Puiseux series λ₀ + k·sᵐ + … with |λ₀| = 1 at the
385
+ bifurcation. `branch_stability` computes it exactly. Saddle-node: one branch stable, one unstable.
386
+ Pitchfork, transcritical and both period doublings: the new branch is stable. At r = 3 the
387
+ period-2 multiplier is exactly 1 − 36u² = 1 − 4e, which matches the known closed form
388
+ −r² + 2r + 4. At r = 1 + √6 the period-4 multiplier is exactly **1 − 8√6·e + …**, the value
389
+ flip-bifurcation theory predicts (4 × |d(multiplier of the 2-cycle)/dr| = 4 × 2√6). Iteration
390
+ at e = 10⁻⁴ measures 0.9980403, against the prediction 0.9980404.
391
+
392
+ `python benchmarks/bifurcation_demo.py` reproduces the table.
393
+
394
+ ## Repetition vs exact analysis
395
+
396
+ What do you learn by asking the same question many times along random approach paths
397
+ (Monte Carlo, 1,000 paths per function), compared with the exact profile? On 300 random rational
398
+ functions, sampling matched the exact verdict 228 times (76%):
399
+
400
+ | Exact verdict | Sampling agrees | Sampling says instead |
401
+ |---|---|---|
402
+ | LIMIT (79) | 71 | NO LIMIT: 8 |
403
+ | NO LIMIT (179) | 124 | LIMIT: 43, DIVERGES: 12 |
404
+ | DIVERGES (42) | 33 | NO LIMIT: 9 |
405
+
406
+ Each kind of disagreement teaches something:
407
+
408
+ - **Thin curves are invisible to sampling.** When exact says NO LIMIT and sampling says LIMIT,
409
+ the deciding behaviour sits on a curve that random paths almost never hit. Example:
410
+ 2x²y²/(3y² + x³) tends to 0 along every path sampling tries, but it blows up next to the
411
+ curve 3y² = −x³. On the built-in traps, more repetitions do not help: for x⁴/((x − y)² + x⁴)
412
+ and x(y − x³)²/((y − x³)² + x⁷), sampling finds nothing even with K = 10,000 paths.
413
+ - **Broad structure is found fast.** For the parabola trap x²y/(x⁴ + y²) and the √2 trap,
414
+ detection reaches 100% by K = 30. For the parabola trap, the histogram of sampled values
415
+ sketches the exact profile range [−1/2, 1/2].
416
+ - **Slow convergence looks like path dependence.** In all 8 cases where exact says LIMIT and
417
+ sampling says NO LIMIT, the exact verdict is right. Along shallow curves (a ≈ 1/4), the
418
+ deviation at sampling scale |x| ≈ 10⁻⁸ is still 8·10⁻², and it falls to 8·10⁻²⁵ only at
419
+ |x| ≈ 10⁻¹⁰⁰.
420
+
421
+ So repetition is a good way to find candidate structure, but it cannot prove a limit or rule
422
+ out a hidden curve. The exact profile does both, and it also explains what the samples showed.
423
+ `python benchmarks/ensemble_vs_exact.py` reproduces the study.
424
+
425
+ ## The language
426
+
427
+ | Statement | Meaning |
428
+ |---|---|
429
+ | `context NAME = EXPR` | Fixed exact parameter, e.g. `context T = 3` |
430
+ | `fluid NAME(VAR) = EXPR` | Define a value; the transition point is `VAR -> 0` |
431
+ | `at VAR -> 0: NAME` | Report the proven behavior at the point |
432
+ | `check EXPR` | Three-valued zero test: `proven_zero`, `proven_nonzero (order k)`, or `unproven` |
433
+ | `if NAME == ...` | Rejected by the type checker: equality on these values may be unprovable |
434
+ | `emit python NAME` / `emit c NAME` | Generate safe code with a proven error bound (C is compiled and validated if a C compiler is installed) |
435
+
436
+ Expressions: `+ - * /`, integer powers `^`, `sin cos exp`, exact decimal numbers, the
437
+ imaginary unit `i`, context parameters, and previously defined names, including
438
+ composition such as `B(t^2)`. Formulas containing `i` compile to complex code
439
+ (`cmath` in Python, C99 `double complex` in C).
440
+
441
+ Python API:
442
+
443
+ ```python
444
+ from fmsl import x, Sin, Cos, Exp, I
445
+ print(((1 - Cos(x)) / x**2).describe()) # removable, value 1/2
446
+ print((Exp(I*x) - Cos(x) - I*Sin(x)).describe()) # C_e (certified: identically zero)
447
+ print((I / x).describe()) # pole of order 1, heading 90 deg from the right ...
448
+ ```
449
+
450
+ ## How it works
451
+
452
+ Every value is an expression graph whose behavior at 0 is a **lazy Laurent series** with
453
+ exact coefficients in the Gaussian rationals Q(i), computed only as deep as a question needs.
454
+
455
+ **Zero certificate.** Certified values have the form E/Q, where Q is a polynomial and E is
456
+ built from `x^j · e^(q(x))` terms with polynomial exponents q (`sin` and `cos` use `±i·q`).
457
+ These building blocks are linearly independent, so a nonzero E must show a nonzero
458
+ coefficient within a computable window:
459
+
460
+ * **Linear exponents** (e^(λx), sin, cos, polynomials): E satisfies a constant-coefficient
461
+ linear ODE of order N, so the window is N terms.
462
+ * **Polynomial exponents** (e^(x²), sin(x³), …): the window is found exactly by Gaussian
463
+ elimination over Q(i).
464
+
465
+ If every coefficient in the window is zero, the value is **proven** identically zero.
466
+
467
+ **Siletz error bound.** For the emitted series branch, FMSL proves the maximum relative error:
468
+
469
+ 1. A rigorous upper bound on |h(z)| over a complex circle |z| = r is computed through the
470
+ expression graph (|a·b| ≤ |a|·|b|, |e^w| ≤ e^|w|, |sin w| ≤ sinh|w|, and dominant-term
471
+ lower bounds for divisors, which also prove the divisor has no zeros inside).
472
+ 2. Cauchy's estimate turns that into a bound on every series coefficient not yet computed,
473
+ which bounds the truncation error.
474
+ 3. A lower bound on |h| along the real interval is proven by subdivision, with exact
475
+ evaluation at midpoints.
476
+ 4. Floating-point rounding is bounded with Higham's Horner-scheme error analysis.
477
+
478
+ All bound arithmetic is exact rational arithmetic with outward rounding.
479
+
480
+ ## Limits (by design, stated honestly)
481
+
482
+ * **Compositions** like `exp(sin x)` and **division by** `sin`/`cos`: coefficients are
483
+ exact, but "is it identically zero?" is reported as `unproven`, never guessed. This
484
+ boundary is fundamental: zero-testing general expressions is undecidable
485
+ (Richardson's theorem).
486
+ * **Essential singularities** such as `exp(-1/t²)`, `sin(1/t)` and `exp(i/t)` are detected
487
+ and explained, but no series code is emitted, because none exists.
488
+ * **Constants** must be exact (rational or Gaussian rational): `exp(1 + t)` would need e
489
+ itself as a coefficient and is refused.
490
+ * **One variable**, transition point at 0; the variable is real (values may be complex).
491
+ * **Proof scope:** the Siletz bound covers the series zone near zero, where the danger is.
492
+ The direct formula used farther out calls the platform math library, which has no
493
+ formal accuracy guarantee, so that zone is measured, not proven.
494
+ * **Proven bounds are worst-case**, typically 10 to 1000× above the measured error.
495
+ The compiler may add extra series terms to tighten a proof (for example 53 terms
496
+ instead of 19 for the SO(3) log-map term).
497
+ * **Matrix module:** Hermitian Hamiltonians only (closed-system dynamics). The scalar φ
498
+ kernel has a proof on |z| ≤ 1; matrix-level accuracy is measured, not proven, since it
499
+ also depends on the eigen-decomposition. For non-Hermitian generators (e.g. Lindblad),
500
+ use scipy's block-matrix routines.
501
+
502
+ ## Prior work
503
+
504
+ The ingredients have a long history: lazy power series (McIlroy), zero-testing for
505
+ exponential polynomials via linear ODEs, limit computation for exp-log functions
506
+ (Gruntz's algorithm, used in SymPy and Maple), Cauchy estimates and rigorous ball/interval
507
+ arithmetic (e.g. the Arb library), and Higham's rounding-error analysis. The quantum φ
508
+ functions have their own numerical-analysis literature on stable evaluation; matrix
509
+ derivatives use the Daleckii–Krein formula, and scipy's `expm_frechet` implements the
510
+ Al-Mohy–Higham block method used as the baseline here. FMSL's
511
+ contribution is the combination: an always-defined treatment of 0/0 that never claims a
512
+ false zero, proven/unproven status enforced by the language, and automatic generation of
513
+ safe code that ships with a proof of its error.
514
+
515
+ For two-variable limits, the closest prior work is Đinh, Guo, Nguyễn and Phạm, *Limits of real
516
+ bivariate rational functions* (arXiv:2202.04889, 2022). It gives a Newton–Puiseux algorithm,
517
+ implemented in Maple, that computes the full range of limit values when the denominator has an
518
+ **isolated** zero; that range is a closed interval. For a denominator that vanishes along curves,
519
+ the authors note the range "may be not connected" in the extended line [−∞, +∞] and leave
520
+ computing it to future work. FMSL handles that case. Viewed on the circle R ∪ {∞}, where +∞ and −∞
521
+ are one point, the range is always connected. FMSL computes it exactly, as a point, an arc or the
522
+ whole circle, with algebraic endpoints, and checks it against an independent loop computation.
523
+ Related work computes limit existence for analytic quotients (arXiv:2102.01242) and Łojasiewicz
524
+ exponents (arXiv:2405.06302); the latter measure how fast a limit is approached. For three or more variables, the Extended Hensel Construction approach (core.ac.uk/works/9191392)
525
+ decides whether a limit exists, and computes it, when the denominator has an isolated zero. I did
526
+ not find a method that computes the full set of limit values in three variables, which
527
+ `fmsl.space` does (version 1, with the limits stated above). I have not done a full literature
528
+ search, so claims of novelty here are provisional.
529
+
530
+ ## Credit
531
+
532
+ FMSL is by **MJ Celedon**, creator of the *Fluid Mathematics System* (FMS). It is the rigorous
533
+ continuation of FMS: each FMS goal that could be made rigorous appears here in a testable form.
534
+
535
+ | FMS idea | FMSL counterpart |
536
+ |---|---|
537
+ | Zero Intermedium (𝓩): division by zero as a transition state | Exact 0/0 states: removable value, pole, or essential singularity |
538
+ | Celedon Point (Cₑ): x − x as balance | `C_e`, returned only when *proven* identically zero |
539
+ | Infinity Flow (𝓘): infinity as directed flow | Poles report the exact direction to infinity from each side |
540
+ | Siletz Precision System (𝓢): structured precision | Siletz bounds: proven error enclosures for emitted code |
541
+ | Meta-Value Processor (𝓜): context-dependent values | `context` parameters |
542
+ | Uniqueness (𝓤): values keep their identity | Values carry their full construction (provenance graph) |
543
+
544
+ The original FMS formulation did not survive rigorous testing as a whole; the mathematics here
545
+ is the part of its goals that could be made precise, proven and independently cross-checked.
546
+
547
+ Development was assisted by an AI system (Anthropic's Claude), which wrote much of the code and
548
+ tests under the author's direction. Every result reported here is verified by tests and
549
+ independent cross-checks in this repository.
550
+
551
+ ## License
552
+
553
+ MIT — free for any use. See [LICENSE](LICENSE).