@johnhenry/math 0.0.0

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.
Files changed (242) hide show
  1. package/README.md +165 -0
  2. package/dist/Bivector4.d.ts +52 -0
  3. package/dist/Bivector4.d.ts.map +1 -0
  4. package/dist/Bivector4.js +105 -0
  5. package/dist/Bivector4.js.map +1 -0
  6. package/dist/CellGraph.d.ts +259 -0
  7. package/dist/CellGraph.d.ts.map +1 -0
  8. package/dist/CellGraph.js +637 -0
  9. package/dist/CellGraph.js.map +1 -0
  10. package/dist/Clifford4Internal.d.ts +35 -0
  11. package/dist/Clifford4Internal.d.ts.map +1 -0
  12. package/dist/Clifford4Internal.js +86 -0
  13. package/dist/Clifford4Internal.js.map +1 -0
  14. package/dist/Combinatorics.d.ts +61 -0
  15. package/dist/Combinatorics.d.ts.map +1 -0
  16. package/dist/Combinatorics.js +186 -0
  17. package/dist/Combinatorics.js.map +1 -0
  18. package/dist/CombinatoricsGenerators.d.ts +44 -0
  19. package/dist/CombinatoricsGenerators.d.ts.map +1 -0
  20. package/dist/CombinatoricsGenerators.js +148 -0
  21. package/dist/CombinatoricsGenerators.js.map +1 -0
  22. package/dist/ComplexMath.d.ts +46 -0
  23. package/dist/ComplexMath.d.ts.map +1 -0
  24. package/dist/ComplexMath.js +98 -0
  25. package/dist/ComplexMath.js.map +1 -0
  26. package/dist/ComplexNumber.d.ts +174 -0
  27. package/dist/ComplexNumber.d.ts.map +1 -0
  28. package/dist/ComplexNumber.js +443 -0
  29. package/dist/ComplexNumber.js.map +1 -0
  30. package/dist/Cycle.d.ts +42 -0
  31. package/dist/Cycle.d.ts.map +1 -0
  32. package/dist/Cycle.js +120 -0
  33. package/dist/Cycle.js.map +1 -0
  34. package/dist/Decimal.d.ts +45 -0
  35. package/dist/Decimal.d.ts.map +1 -0
  36. package/dist/Decimal.js +135 -0
  37. package/dist/Decimal.js.map +1 -0
  38. package/dist/Distributions.d.ts +55 -0
  39. package/dist/Distributions.d.ts.map +1 -0
  40. package/dist/Distributions.js +222 -0
  41. package/dist/Distributions.js.map +1 -0
  42. package/dist/DualNumber.d.ts +42 -0
  43. package/dist/DualNumber.d.ts.map +1 -0
  44. package/dist/DualNumber.js +91 -0
  45. package/dist/DualNumber.js.map +1 -0
  46. package/dist/Environment.d.ts +44 -0
  47. package/dist/Environment.d.ts.map +1 -0
  48. package/dist/Environment.js +129 -0
  49. package/dist/Environment.js.map +1 -0
  50. package/dist/Expression.d.ts +19 -0
  51. package/dist/Expression.d.ts.map +1 -0
  52. package/dist/Expression.js +43 -0
  53. package/dist/Expression.js.map +1 -0
  54. package/dist/FFT.d.ts +21 -0
  55. package/dist/FFT.d.ts.map +1 -0
  56. package/dist/FFT.js +136 -0
  57. package/dist/FFT.js.map +1 -0
  58. package/dist/GeometricAlgebra4.d.ts +73 -0
  59. package/dist/GeometricAlgebra4.d.ts.map +1 -0
  60. package/dist/GeometricAlgebra4.js +115 -0
  61. package/dist/GeometricAlgebra4.js.map +1 -0
  62. package/dist/Geometry.d.ts +41 -0
  63. package/dist/Geometry.d.ts.map +1 -0
  64. package/dist/Geometry.js +167 -0
  65. package/dist/Geometry.js.map +1 -0
  66. package/dist/Graph.d.ts +72 -0
  67. package/dist/Graph.d.ts.map +1 -0
  68. package/dist/Graph.js +337 -0
  69. package/dist/Graph.js.map +1 -0
  70. package/dist/Graph3DUtils.d.ts +80 -0
  71. package/dist/Graph3DUtils.d.ts.map +1 -0
  72. package/dist/Graph3DUtils.js +156 -0
  73. package/dist/Graph3DUtils.js.map +1 -0
  74. package/dist/GraphUtils.d.ts +67 -0
  75. package/dist/GraphUtils.d.ts.map +1 -0
  76. package/dist/GraphUtils.js +72 -0
  77. package/dist/GraphUtils.js.map +1 -0
  78. package/dist/GroupTheory.d.ts +73 -0
  79. package/dist/GroupTheory.d.ts.map +1 -0
  80. package/dist/GroupTheory.js +194 -0
  81. package/dist/GroupTheory.js.map +1 -0
  82. package/dist/IntUtils.d.ts +33 -0
  83. package/dist/IntUtils.d.ts.map +1 -0
  84. package/dist/IntUtils.js +185 -0
  85. package/dist/IntUtils.js.map +1 -0
  86. package/dist/Interval.d.ts +44 -0
  87. package/dist/Interval.d.ts.map +1 -0
  88. package/dist/Interval.js +165 -0
  89. package/dist/Interval.js.map +1 -0
  90. package/dist/Lattice.d.ts +48 -0
  91. package/dist/Lattice.d.ts.map +1 -0
  92. package/dist/Lattice.js +65 -0
  93. package/dist/Lattice.js.map +1 -0
  94. package/dist/Logic.d.ts +22 -0
  95. package/dist/Logic.d.ts.map +1 -0
  96. package/dist/Logic.js +34 -0
  97. package/dist/Logic.js.map +1 -0
  98. package/dist/MatrixMath.d.ts +71 -0
  99. package/dist/MatrixMath.d.ts.map +1 -0
  100. package/dist/MatrixMath.js +302 -0
  101. package/dist/MatrixMath.js.map +1 -0
  102. package/dist/NumberTheory.d.ts +49 -0
  103. package/dist/NumberTheory.d.ts.map +1 -0
  104. package/dist/NumberTheory.js +230 -0
  105. package/dist/NumberTheory.js.map +1 -0
  106. package/dist/Numerical.d.ts +85 -0
  107. package/dist/Numerical.d.ts.map +1 -0
  108. package/dist/Numerical.js +343 -0
  109. package/dist/Numerical.js.map +1 -0
  110. package/dist/Permutation.d.ts +43 -0
  111. package/dist/Permutation.d.ts.map +1 -0
  112. package/dist/Permutation.js +142 -0
  113. package/dist/Permutation.js.map +1 -0
  114. package/dist/Polygon.d.ts +64 -0
  115. package/dist/Polygon.d.ts.map +1 -0
  116. package/dist/Polygon.js +221 -0
  117. package/dist/Polygon.js.map +1 -0
  118. package/dist/PolynomialRing.d.ts +74 -0
  119. package/dist/PolynomialRing.d.ts.map +1 -0
  120. package/dist/PolynomialRing.js +231 -0
  121. package/dist/PolynomialRing.js.map +1 -0
  122. package/dist/Quaternion.d.ts +37 -0
  123. package/dist/Quaternion.d.ts.map +1 -0
  124. package/dist/Quaternion.js +106 -0
  125. package/dist/Quaternion.js.map +1 -0
  126. package/dist/Rational.d.ts +34 -0
  127. package/dist/Rational.d.ts.map +1 -0
  128. package/dist/Rational.js +136 -0
  129. package/dist/Rational.js.map +1 -0
  130. package/dist/RealMath.d.ts +112 -0
  131. package/dist/RealMath.d.ts.map +1 -0
  132. package/dist/RealMath.js +262 -0
  133. package/dist/RealMath.js.map +1 -0
  134. package/dist/Rotor4.d.ts +180 -0
  135. package/dist/Rotor4.d.ts.map +1 -0
  136. package/dist/Rotor4.js +388 -0
  137. package/dist/Rotor4.js.map +1 -0
  138. package/dist/SpecialFunctions.d.ts +32 -0
  139. package/dist/SpecialFunctions.d.ts.map +1 -0
  140. package/dist/SpecialFunctions.js +161 -0
  141. package/dist/SpecialFunctions.js.map +1 -0
  142. package/dist/SpecialOperator.d.ts +21 -0
  143. package/dist/SpecialOperator.d.ts.map +1 -0
  144. package/dist/SpecialOperator.js +26 -0
  145. package/dist/SpecialOperator.js.map +1 -0
  146. package/dist/Statistics.d.ts +50 -0
  147. package/dist/Statistics.d.ts.map +1 -0
  148. package/dist/Statistics.js +131 -0
  149. package/dist/Statistics.js.map +1 -0
  150. package/dist/StringEvaluator.d.ts +48 -0
  151. package/dist/StringEvaluator.d.ts.map +1 -0
  152. package/dist/StringEvaluator.js +190 -0
  153. package/dist/StringEvaluator.js.map +1 -0
  154. package/dist/Structure.d.ts +130 -0
  155. package/dist/Structure.d.ts.map +1 -0
  156. package/dist/Structure.js +394 -0
  157. package/dist/Structure.js.map +1 -0
  158. package/dist/Symbolic.d.ts +501 -0
  159. package/dist/Symbolic.d.ts.map +1 -0
  160. package/dist/Symbolic.js +4077 -0
  161. package/dist/Symbolic.js.map +1 -0
  162. package/dist/Type.d.ts +31 -0
  163. package/dist/Type.d.ts.map +1 -0
  164. package/dist/Type.js +47 -0
  165. package/dist/Type.js.map +1 -0
  166. package/dist/Utilities.d.ts +27 -0
  167. package/dist/Utilities.d.ts.map +1 -0
  168. package/dist/Utilities.js +47 -0
  169. package/dist/Utilities.js.map +1 -0
  170. package/dist/Vec4.d.ts +39 -0
  171. package/dist/Vec4.d.ts.map +1 -0
  172. package/dist/Vec4.js +82 -0
  173. package/dist/Vec4.js.map +1 -0
  174. package/dist/Vector.d.ts +83 -0
  175. package/dist/Vector.d.ts.map +1 -0
  176. package/dist/Vector.js +173 -0
  177. package/dist/Vector.js.map +1 -0
  178. package/dist/VectorCalculus.d.ts +42 -0
  179. package/dist/VectorCalculus.d.ts.map +1 -0
  180. package/dist/VectorCalculus.js +82 -0
  181. package/dist/VectorCalculus.js.map +1 -0
  182. package/dist/VectorUtils.d.ts +172 -0
  183. package/dist/VectorUtils.d.ts.map +1 -0
  184. package/dist/VectorUtils.js +706 -0
  185. package/dist/VectorUtils.js.map +1 -0
  186. package/dist/differentiation-rules.d.ts +21 -0
  187. package/dist/differentiation-rules.d.ts.map +1 -0
  188. package/dist/differentiation-rules.js +52 -0
  189. package/dist/differentiation-rules.js.map +1 -0
  190. package/dist/index.d.ts +52 -0
  191. package/dist/index.d.ts.map +1 -0
  192. package/dist/index.js +66 -0
  193. package/dist/index.js.map +1 -0
  194. package/package.json +68 -0
  195. package/src/Bivector4.ts +136 -0
  196. package/src/CellGraph.ts +669 -0
  197. package/src/Clifford4Internal.ts +90 -0
  198. package/src/Combinatorics.ts +183 -0
  199. package/src/CombinatoricsGenerators.ts +144 -0
  200. package/src/ComplexMath.ts +162 -0
  201. package/src/ComplexNumber.ts +491 -0
  202. package/src/Cycle.ts +126 -0
  203. package/src/Decimal.ts +145 -0
  204. package/src/Distributions.ts +269 -0
  205. package/src/DualNumber.ts +105 -0
  206. package/src/Environment.ts +127 -0
  207. package/src/Expression.ts +48 -0
  208. package/src/FFT.ts +146 -0
  209. package/src/GeometricAlgebra4.ts +157 -0
  210. package/src/Geometry.ts +173 -0
  211. package/src/Graph.ts +337 -0
  212. package/src/Graph3DUtils.ts +269 -0
  213. package/src/GraphUtils.ts +159 -0
  214. package/src/GroupTheory.ts +214 -0
  215. package/src/IntUtils.ts +200 -0
  216. package/src/Interval.ts +171 -0
  217. package/src/Lattice.ts +87 -0
  218. package/src/Logic.ts +38 -0
  219. package/src/MatrixMath.ts +326 -0
  220. package/src/NumberTheory.ts +228 -0
  221. package/src/Numerical.ts +390 -0
  222. package/src/Permutation.ts +148 -0
  223. package/src/Polygon.ts +229 -0
  224. package/src/PolynomialRing.ts +242 -0
  225. package/src/Quaternion.ts +125 -0
  226. package/src/Rational.ts +148 -0
  227. package/src/RealMath.ts +346 -0
  228. package/src/Rotor4.ts +440 -0
  229. package/src/SpecialFunctions.ts +152 -0
  230. package/src/SpecialOperator.ts +28 -0
  231. package/src/Statistics.ts +170 -0
  232. package/src/StringEvaluator.ts +208 -0
  233. package/src/Structure.ts +481 -0
  234. package/src/Symbolic.ts +4313 -0
  235. package/src/Type.ts +48 -0
  236. package/src/Utilities.ts +49 -0
  237. package/src/Vec4.ts +98 -0
  238. package/src/Vector.ts +189 -0
  239. package/src/VectorCalculus.ts +87 -0
  240. package/src/VectorUtils.ts +797 -0
  241. package/src/differentiation-rules.ts +73 -0
  242. package/src/index.ts +140 -0
package/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # @johnhenry/math
2
+
3
+ **Advanced college-level mathematics for TypeScript** — a modern, fully-typed,
4
+ test-covered port of the Mallory ActionScript 3 library (a project worked on,
5
+ on and off, since 2004), published to npm as `@johnhenry/math`.
6
+
7
+ Complex numbers, linear algebra over arbitrary algebraic structures,
8
+ combinatorics and number theory, an expression evaluator, and renderer-agnostic
9
+ graphing geometry — all rewritten in modern TypeScript with `node:test`
10
+ (example-based and, for algebraic laws, property-based via `fast-check`).
11
+
12
+ ```ts
13
+ import { ComplexNumber, Structure, Vector, StringEvaluator } from "@johnhenry/math";
14
+
15
+ ComplexNumber.E.power(new ComplexNumber(0, Math.PI)); // ≈ -1 (Euler)
16
+ Structure.realField().determinant(/* 3×3 matrix, as Vector<Vector<number>> */);
17
+ StringEvaluator.evaluate("sin(pi/2) + 2^3", StringEvaluator.mathEnvironment()); // 9
18
+ ```
19
+
20
+ ## Install & use
21
+
22
+ Requires Node.js ≥ 22.6 (the test suite runs `.ts` directly via Node's built-in
23
+ type stripping).
24
+
25
+ ```bash
26
+ npm install @johnhenry/math
27
+ ```
28
+
29
+ To work on the library itself from within this monorepo:
30
+
31
+ ```bash
32
+ npm install
33
+ npm test # run the node:test suite (against src/)
34
+ npm run typecheck # tsc --noEmit
35
+ npm run check # Biome lint + format check
36
+ npm run check:fix # apply Biome fixes
37
+ npm run build # emit ./dist (ESM + .d.ts)
38
+ npm run test:build # build, then smoke-test the emitted package
39
+ npm run docs # generate the API reference into docs/api (TypeDoc)
40
+ ```
41
+
42
+ Continuous integration (`.github/workflows/ci.yml`) runs typecheck → lint →
43
+ tests → build → dist smoke test → docs build on Node 22 and 24.
44
+
45
+ **Documentation:**
46
+
47
+ - **[Cookbook](docs/COOKBOOK.md)** — task-oriented recipes across every
48
+ domain (linear algebra, symbolic calculus, number theory, group theory,
49
+ FFT, geometry, graphs, and more), each one verified against the test suite.
50
+ - **API reference** — generated with [TypeDoc](https://typedoc.org) from
51
+ the source JSDoc; run `npm run docs` and open `docs/api/index.html`.
52
+
53
+ ## Modules
54
+
55
+ | Area | Modules |
56
+ |------|---------|
57
+ | Foundations | `Vector`, `ComplexNumber` (arithmetic, trig, logs as fluent instance methods), `Type` |
58
+ | Real & complex analysis | `RealMath` (plain scalar functions, not a class), `ComplexMath` (complex vectors + probability helpers), `Statistics` (descriptive stats on `number[]`) |
59
+ | Linear algebra | `VectorUtils`, generic linear algebra in `Structure`, numerical decompositions in `MatrixMath` |
60
+ | Algebraic structures | `Structure` — groups/rings/fields; do linear algebra over e.g. GF(7) |
61
+ | Number theory & combinatorics | `Permutation`, `Cycle` |
62
+ | Geometry | `Polygon`, `GraphUtils`, `Graph3DUtils` (emit paths/meshes as plain data) |
63
+ | Expressions | `Environment`, `Expression`, `StringEvaluator` |
64
+ | Misc | `Utilities`, `Logic`, `IntUtils`, `SpecialOperator` |
65
+
66
+ ## About the port
67
+
68
+ This is a faithful port that **fixes bugs rather than carrying them over**, and
69
+ takes advantage of modern JavaScript/TypeScript: ES classes, generics, iterators,
70
+ `Array` subclassing, tagged unions, and `.ts`-native execution. Every module was
71
+ translated **test-first**.
72
+
73
+ A sampling of the ~40 bugs found and fixed while translating:
74
+
75
+ - **`RealMath.subtract` returned `a * b`.** (Yes, really.)
76
+ - **Order statistics were broken:** `sort` used the default *lexicographic* sort,
77
+ so `minimum`/`maximum`/`median` were wrong for numbers.
78
+ - **`ComplexMath.divide`** compared `alpha.ivalue` (lowercase `v`, always
79
+ `undefined`), so all eight directed-infinity results were dead code.
80
+ - **`ComplexMath.normalDistribution`** reciprocated the whole expression, putting
81
+ the exponential in the denominator (wrong sign) — the normal PDF was inverted.
82
+ - **`solveN`** wasn't Newton's method — it assumed a derivative of 1 and diverged;
83
+ now a real numeric Newton–Raphson.
84
+ - **`integrateN`** sampled at `2·x + interval`; **`differentiateN`** was a forward
85
+ difference despite claiming to be symmetric.
86
+ - **`invertMatrix`** had no pivoting (divide-by-zero on a zero pivot); now uses
87
+ partial pivoting (and a zero-pivot row swap in `Structure`, for finite fields).
88
+ - **`crossProduct`** read index 3 for the z-component and used truthiness tests
89
+ that dropped zero components; **`powerMatrix`** never actually multiplied.
90
+ - **`Vector.setElement`** infinitely recursed on a falsy slot.
91
+ - **`ComplexNumber` string parsing** crashed on non-matches and couldn't
92
+ round-trip negative imaginary parts; it also swallowed every `*`, so `"4*2"`
93
+ parsed as `42`.
94
+ - **`StringEvaluator`** was uniformly right-associative (`10-2-3 → 11`); now
95
+ left-associative for `+ - * / %` and right-associative for `^`.
96
+ - **`Polynomial.multiply`** referenced a non-existent `dimension.value`;
97
+ **`Polynomial.antiderivative`** dropped its highest-degree term.
98
+ - **`IntegerMath.modulus`** recursed one step at a time (stack overflow);
99
+ `primeFactors` infinite-looped on `0` and negatives.
100
+ - **`Structure`**'s matrix section was non-functional (static/instance confusion,
101
+ undefined references) and is reconstructed as working generic linear algebra.
102
+ - `IntUtils` spelled "forty" and "ninety" as "fourty" and "ninty".
103
+
104
+ Where the original genuinely had *no* verifiable intended behavior — the Flash
105
+ 3D ribbon geometry in `Graph3DUtils` — the math is ported verbatim with an
106
+ explicit note rather than "fixed" by guesswork. The Flash rendering utilities
107
+ (`GraphUtils`/`Graph3DUtils`) now return renderer-agnostic geometry (2D paths,
108
+ 3D meshes) instead of Flash display objects.
109
+
110
+ ## Beyond the original
111
+
112
+ A completeness pass added the missing counterparts and a few natural supplements
113
+ the AS3 library never had:
114
+
115
+ - **`ComplexNumber`**: `fromPolar`, `fromVector`, `fromXML` (inverses of
116
+ `magnitude`/`angle`, `toVector`, `toXML`).
117
+ - **`Vector`**: `fromXML`, `fromString` (best-effort inverses of `toXML`/`toString`).
118
+ - **`PolynomialRing`**: `evaluate` (Horner), `add`/`subtract`, `divide`/`mod`/`divmod`
119
+ (long division), `derivative`/`antiderivative` (generalized to any `Structure`,
120
+ not just reals), and the real-number-only `parsePolynomial`/`polynomialToString`
121
+ helpers (inverses of each other).
122
+ - **`Polygon`**: `centroid`, `contains` (point-in-polygon), `isConvex`, `isSimple`.
123
+ - **`Statistics`**: `populationVariance` / `populationStandardDeviation`
124
+ alongside the sample versions.
125
+ - **`Structure` presets**: `Structure.realField()`, `complexField()`,
126
+ `integersModulo(n)` (a field when `n` is prime), and `booleanRing()` — so you
127
+ can do linear algebra over these without wiring up operations by hand:
128
+
129
+ ```ts
130
+ const gf7 = Structure.integersModulo(7);
131
+ gf7.invertMatrix(/* a matrix over GF(7) */); // Gauss-Jordan over the finite field
132
+ ```
133
+
134
+ ## Expanded mathematics
135
+
136
+ Well beyond the original ActionScript scope, the library now spans:
137
+
138
+ | Area | Module(s) | Highlights |
139
+ |------|-----------|------------|
140
+ | Numerical linear algebra | `MatrixMath` | LU, QR, Cholesky, symmetric eigen (Jacobi), SVD; `solve`, RREF, rank, null space, least squares, pseudo-inverse, norms, condition number |
141
+ | Symbolic calculus | `Symbolic` | expression parser (41 unary elementary functions incl. inverse-trig, reciprocal-trig, hyperbolic/inverse-hyperbolic, `abs`/`log10`/`log2`/`cbrt`/`floor`/`ceil`/`round`/`sign`/`trunc`, and `expm1`/`log1p`/`sigmoid`/`erf`/`relu`, with `arcsin`/`logistic`-style aliases and `\|x\|` bar syntax, plus N-ary `atan2`/`hypot`/`min`/`max`/`gcd`/`lcm`, `log(base, x)`/`clamp(x, lo, hi)`, and `piecewise(cond, expr, ..., otherwise)` with `<`/`<=`/`>`/`>=`/`==`/`!=` comparisons), symbolic differentiation (incl. the multivariate chain rule for the N-ary functions and branch-wise piecewise differentiation) with a u-substitution fallback for `integrate`, algebraic simplification with like-term collection and constant-folding, elementary integration (incl. by-parts, arctan/arcsin forms, and u-substitution), `integrateDefinite` (closed-form first, adaptive-quadrature fallback), `sumSeries` (finite/infinite, closed-form geometric recognition + numeric fallback), Taylor series, `expand`/`substitute`, polynomial `solve`/`factor`, linear `solveSystem`, L'Hopital `limit` (incl. limits at infinity), LaTeX round-trip (`toLatex`/`fromLatex`, incl. `\operatorname{...}`, bracket notation for `abs`/`floor`/`ceil`/`cbrt`, and `\begin{cases}` for piecewise), `evaluateExact` (exact `Rational` evaluation), `evaluateOverStructure` (folds an `Expr` through an arbitrary `Structure`'s own algebra, e.g. for plotting over Z/7Z), and `freeVariables`/`assertVariables` (auto-detect an expression's variables, or opt into strict mode and throw `UndeclaredVariableError` instead of silently resolving an undeclared one to `NaN`) |
142
+ | Number types | `Rational`, `Quaternion`, `DualNumber`, `Interval` | exact bigint rationals, 3D-rotation quaternions, forward-mode autodiff, rigorous interval arithmetic — each also a `Structure` preset |
143
+ | 4D geometric algebra | `Vec4`, `Bivector4`, `Rotor4`, `GeometricAlgebra4` | a genuine fourth *spatial* dimension (not time): 4D vectors, 6-component bivectors (the 2-planes of 4D), and rotors that generalize `Quaternion` to 4D — including 4D-only **double rotations** (simultaneous, independent rotation in two orthogonal planes at once); built on an internal Cl(4,0) blade engine for correctness (verified against `Quaternion` on their shared 3D subspace). `GeometricAlgebra4` also has the `commutatorProduct` and `leftContraction` operations n-dimensional rigid-body dynamics needs (generalized Euler's equation, point velocity). `Rotor4.factor()`/`renormalize()` implement Perwass-style rotor factorization — the proper fix for numerical drift on a double rotation, where naive magnitude normalization silently produces an invalid rotor (verified against 200+ random plane orientations/angles, including the isoclinic and right-isoclinic degenerate cases) |
144
+ | Number theory | `NumberTheory` | `bigint` modPow, extended GCD, CRT, Miller–Rabin, Pollard-rho factorization, Legendre/Jacobi |
145
+ | Group theory | `GroupTheory` | Cayley tables, axiom checks, element order, generated subgroups, cosets, Lagrange, orbits, Sₙ/Zₙ |
146
+ | Numerical methods | `Numerical` | bisection/secant/Newton/Brent; Simpson, adaptive Simpson, Gauss–Legendre; Euler & RK4 ODE solvers |
147
+ | Probability & special functions | `SpecialFunctions`, `Distributions` | gamma/beta/erf, incomplete gamma/beta; normal/exponential/uniform/gamma/χ²/t/binomial/Poisson; t-tests, χ² GoF, CIs |
148
+ | Signal processing | `FFT` | radix-2 FFT/IFFT, DFT, FFT convolution |
149
+ | Computational geometry | `Geometry`, `Transform2D` | convex hull, predicates, point-in-polygon, 2D affine transforms |
150
+ | Graph theory | `Graph` | BFS/DFS, Dijkstra, Kruskal MST, topological sort, components, Floyd–Warshall |
151
+ | Counting mathematics | `Combinatorics` | `bigint` factorials, nCk/nPk, multinomial coefficients, Catalan/Stirling/Bell numbers, integer partitions, derangements |
152
+ | Arbitrary precision | `Decimal` | `bigint`-backed decimal arithmetic — exact add/subtract/multiply, configurable-precision division; also a `Structure` preset |
153
+ | Abstract algebra | `PolynomialRing` | polynomials over any `Structure` (finite fields, rationals, ...) — long division, monic GCD, Horner evaluation, derivative/antiderivative |
154
+ | Multivariable calculus | `VectorCalculus` | gradient, directional derivative, Jacobian, divergence, curl, Hessian (via `DualNumber` autodiff), plus an exact symbolic gradient |
155
+
156
+ Many of these interlock: `GroupTheory` runs over any `Structure` (including
157
+ `integersModulo`); `Graph.floydWarshall` emits matrices for `MatrixMath`;
158
+ `DualNumber` gives exact derivatives, which both `Structure.dualNumbers()` and
159
+ `VectorCalculus` build on; `PolynomialRing` composes with any `Structure`
160
+ preset (including the new `Decimal`-backed `decimalField()`); and
161
+ `SpecialFunctions` gives the `Distributions` CDFs exact closed forms.
162
+
163
+ ## License
164
+
165
+ MIT
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Bivector4 — an oriented 2-plane in 4D space, i.e. an element of grade 2 in
3
+ * Cl(4,0). Basis: `e12, e13, e14, e23, e24, e34` (6 components — in general nD
4
+ * there are `n(n-1)/2` independent 2-planes: 1 in 2D, 3 in 3D, 6 in 4D).
5
+ *
6
+ * In 3D, angular velocity/momentum/torque are conventionally written as
7
+ * *vectors* via the cross product, but that only works because 3D vectors
8
+ * happen to have the same dimension (3) as 3D bivectors — a coincidence
9
+ * unique to 3D. In 4D (and in general) these quantities are properly
10
+ * bivectors, not vectors: see {@link Rotor4} for how a bivector generates a
11
+ * rotation, and the physics package for angular velocity/momentum as
12
+ * Bivector4.
13
+ */
14
+ export declare class Bivector4 {
15
+ /** e12 component — the xy rotation plane. */
16
+ readonly xy: number;
17
+ /** e13 component — the xz rotation plane. */
18
+ readonly xz: number;
19
+ /** e14 component — the xw rotation plane. */
20
+ readonly xw: number;
21
+ /** e23 component — the yz rotation plane. */
22
+ readonly yz: number;
23
+ /** e24 component — the yw rotation plane. */
24
+ readonly yw: number;
25
+ /** e34 component — the zw rotation plane. */
26
+ readonly zw: number;
27
+ static readonly Zero: Bivector4;
28
+ constructor(xy?: number, xz?: number, xw?: number, yz?: number, yw?: number, zw?: number);
29
+ add(b: Bivector4): Bivector4;
30
+ subtract(b: Bivector4): Bivector4;
31
+ scale(s: number): Bivector4;
32
+ negate(): Bivector4;
33
+ /** Component-wise inner product (the basis bivectors e12..e34 are mutually orthonormal, so this is just the Euclidean dot product of components). */
34
+ dot(b: Bivector4): number;
35
+ get magnitude(): number;
36
+ get magnitudeSquared(): number;
37
+ normalize(): Bivector4;
38
+ /**
39
+ * True when this bivector is *simple* (a.k.a. a blade): it represents
40
+ * rotation in a single 2-plane, like every 3D bivector always does. A 4D
41
+ * bivector is simple iff its self-wedge `B ∧ B` vanishes (equivalently,
42
+ * `B * B` — the geometric product with itself — has no pseudoscalar part).
43
+ * Non-simple ("compound") bivectors are the ones responsible for 4D's
44
+ * double rotations — see {@link Rotor4}.
45
+ */
46
+ isSimple(epsilon?: number): boolean;
47
+ equals(b: Bivector4, epsilon?: number): boolean;
48
+ toArray(): [number, number, number, number, number, number];
49
+ static fromArray(a: readonly [number, number, number, number, number, number]): Bivector4;
50
+ toString(): string;
51
+ }
52
+ //# sourceMappingURL=Bivector4.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Bivector4.d.ts","sourceRoot":"","sources":["../src/Bivector4.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,qBAAa,SAAS;IACpB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,MAAM,CAAC,QAAQ,CAAC,IAAI,YAAmC;gBAE3C,EAAE,SAAI,EAAE,EAAE,SAAI,EAAE,EAAE,SAAI,EAAE,EAAE,SAAI,EAAE,EAAE,SAAI,EAAE,EAAE,SAAI;IAS1D,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,SAAS;IAW5B,QAAQ,CAAC,CAAC,EAAE,SAAS,GAAG,SAAS;IAWjC,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS;IAI3B,MAAM,IAAI,SAAS;IAInB,qJAAqJ;IACrJ,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM;IAIzB,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAED,SAAS,IAAI,SAAS;IAMtB;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,SAAO,GAAG,OAAO;IAQjC,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,SAAI,GAAG,OAAO;IAqB1C,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAI3D,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS;IAIzF,QAAQ,IAAI,MAAM;CAGnB"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Bivector4 — an oriented 2-plane in 4D space, i.e. an element of grade 2 in
3
+ * Cl(4,0). Basis: `e12, e13, e14, e23, e24, e34` (6 components — in general nD
4
+ * there are `n(n-1)/2` independent 2-planes: 1 in 2D, 3 in 3D, 6 in 4D).
5
+ *
6
+ * In 3D, angular velocity/momentum/torque are conventionally written as
7
+ * *vectors* via the cross product, but that only works because 3D vectors
8
+ * happen to have the same dimension (3) as 3D bivectors — a coincidence
9
+ * unique to 3D. In 4D (and in general) these quantities are properly
10
+ * bivectors, not vectors: see {@link Rotor4} for how a bivector generates a
11
+ * rotation, and the physics package for angular velocity/momentum as
12
+ * Bivector4.
13
+ */
14
+ export class Bivector4 {
15
+ /** e12 component — the xy rotation plane. */
16
+ xy;
17
+ /** e13 component — the xz rotation plane. */
18
+ xz;
19
+ /** e14 component — the xw rotation plane. */
20
+ xw;
21
+ /** e23 component — the yz rotation plane. */
22
+ yz;
23
+ /** e24 component — the yw rotation plane. */
24
+ yw;
25
+ /** e34 component — the zw rotation plane. */
26
+ zw;
27
+ static Zero = new Bivector4(0, 0, 0, 0, 0, 0);
28
+ constructor(xy = 0, xz = 0, xw = 0, yz = 0, yw = 0, zw = 0) {
29
+ this.xy = xy;
30
+ this.xz = xz;
31
+ this.xw = xw;
32
+ this.yz = yz;
33
+ this.yw = yw;
34
+ this.zw = zw;
35
+ }
36
+ add(b) {
37
+ return new Bivector4(this.xy + b.xy, this.xz + b.xz, this.xw + b.xw, this.yz + b.yz, this.yw + b.yw, this.zw + b.zw);
38
+ }
39
+ subtract(b) {
40
+ return new Bivector4(this.xy - b.xy, this.xz - b.xz, this.xw - b.xw, this.yz - b.yz, this.yw - b.yw, this.zw - b.zw);
41
+ }
42
+ scale(s) {
43
+ return new Bivector4(this.xy * s, this.xz * s, this.xw * s, this.yz * s, this.yw * s, this.zw * s);
44
+ }
45
+ negate() {
46
+ return this.scale(-1);
47
+ }
48
+ /** Component-wise inner product (the basis bivectors e12..e34 are mutually orthonormal, so this is just the Euclidean dot product of components). */
49
+ dot(b) {
50
+ return this.xy * b.xy + this.xz * b.xz + this.xw * b.xw + this.yz * b.yz + this.yw * b.yw + this.zw * b.zw;
51
+ }
52
+ get magnitude() {
53
+ return Math.sqrt(this.dot(this));
54
+ }
55
+ get magnitudeSquared() {
56
+ return this.dot(this);
57
+ }
58
+ normalize() {
59
+ const m = this.magnitude;
60
+ if (m === 0)
61
+ throw new Error("Cannot normalize the zero bivector.");
62
+ return this.scale(1 / m);
63
+ }
64
+ /**
65
+ * True when this bivector is *simple* (a.k.a. a blade): it represents
66
+ * rotation in a single 2-plane, like every 3D bivector always does. A 4D
67
+ * bivector is simple iff its self-wedge `B ∧ B` vanishes (equivalently,
68
+ * `B * B` — the geometric product with itself — has no pseudoscalar part).
69
+ * Non-simple ("compound") bivectors are the ones responsible for 4D's
70
+ * double rotations — see {@link Rotor4}.
71
+ */
72
+ isSimple(epsilon = 1e-9) {
73
+ // B ∧ B for a bivector reduces to twice the Pfaffian-like pairing of
74
+ // opposite basis planes: (xy*zw - xz*yw + xw*yz), matching the
75
+ // pseudoscalar component produced by the geometric product B*B.
76
+ const pfaffian = this.xy * this.zw - this.xz * this.yw + this.xw * this.yz;
77
+ return Math.abs(pfaffian) <= epsilon;
78
+ }
79
+ equals(b, epsilon = 0) {
80
+ if (epsilon === 0) {
81
+ return (this.xy === b.xy &&
82
+ this.xz === b.xz &&
83
+ this.xw === b.xw &&
84
+ this.yz === b.yz &&
85
+ this.yw === b.yw &&
86
+ this.zw === b.zw);
87
+ }
88
+ return (Math.abs(this.xy - b.xy) <= epsilon &&
89
+ Math.abs(this.xz - b.xz) <= epsilon &&
90
+ Math.abs(this.xw - b.xw) <= epsilon &&
91
+ Math.abs(this.yz - b.yz) <= epsilon &&
92
+ Math.abs(this.yw - b.yw) <= epsilon &&
93
+ Math.abs(this.zw - b.zw) <= epsilon);
94
+ }
95
+ toArray() {
96
+ return [this.xy, this.xz, this.xw, this.yz, this.yw, this.zw];
97
+ }
98
+ static fromArray(a) {
99
+ return new Bivector4(a[0], a[1], a[2], a[3], a[4], a[5]);
100
+ }
101
+ toString() {
102
+ return `${this.xy}e12 + ${this.xz}e13 + ${this.xw}e14 + ${this.yz}e23 + ${this.yw}e24 + ${this.zw}e34`;
103
+ }
104
+ }
105
+ //# sourceMappingURL=Bivector4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Bivector4.js","sourceRoot":"","sources":["../src/Bivector4.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,259 @@
1
+ /**
2
+ * CellGraph — a reactive, pull-based dependency graph. Cells hold typed
3
+ * values (numbers, points, curves, whatever) rather than flattened
4
+ * primitives; a derived cell's `compute` reads other cells via `graph.get`,
5
+ * and the graph records the resulting edges automatically (no manual tag
6
+ * declarations, unlike mcp-query's cache).
7
+ *
8
+ * Writes (`set`) mark transitive dependents dirty and bump their version
9
+ * counters immediately — cheap, no recompute. Recomputation happens lazily,
10
+ * the next time a dirty cell is `get`, and a structural-equality check skips
11
+ * the version bump (and further propagation) when a recompute produces a
12
+ * value that's deep-equal to what was already cached, so unaffected
13
+ * downstream consumers don't re-render.
14
+ *
15
+ * Promoted here from johnhenry/mallory (originally `src/lib/cell-
16
+ * graph.ts`, powering every panel there via `useCell`/`useSyncExternalStore`)
17
+ * once johnhenry/math-grapher became a second consumer of a frozen
18
+ * vendored copy — two consumers is this monorepo's own extract-to-a-package
19
+ * trigger. See johnhenry/math#56. UI-framework-agnostic and dependency-
20
+ * free by design: nothing here references React or any host application.
21
+ */
22
+ type Listener = () => void;
23
+ type ComputeFn<T> = () => T;
24
+ export type CellRole = "free" | "dependent" | "unknown";
25
+ export declare class CircularDependencyError extends Error {
26
+ constructor(path: string[]);
27
+ }
28
+ export declare class CellGraph {
29
+ private cells;
30
+ private listeners;
31
+ private globalListeners;
32
+ private writeListeners;
33
+ private stack;
34
+ private emitting;
35
+ /**
36
+ * Nesting depth of the current "logical write" -- incremented around the
37
+ * body of every top-level mutating entry point ({@link set}, {@link
38
+ * define}, {@link delete}) and decremented in a `finally` when it returns.
39
+ * A single `set()` on a root of a diamond-shaped dependency graph cascades
40
+ * through `propagateDirty` and calls `emit()` once per cell it reaches
41
+ * (root, then each newly-dirtied dependent) -- all of those belong to the
42
+ * SAME logical write and must produce exactly one `subscribeAll`
43
+ * notification, not one per cell. While this is above zero, a request to
44
+ * notify global listeners (see {@link scheduleGlobalNotify}) is deferred
45
+ * instead of firing immediately; it only actually fires once depth
46
+ * unwinds back to zero, i.e. once the outermost `set`/`define`/`delete`
47
+ * call (including any cells it transitively dirtied) has fully finished.
48
+ */
49
+ private globalNotifyDepth;
50
+ /** Set by {@link scheduleGlobalNotify} while `globalNotifyDepth > 0`, so the deferred notification isn't lost once depth returns to zero. */
51
+ private globalNotifyPending;
52
+ /**
53
+ * Guards the global-listener-invocation loop itself against being
54
+ * re-entered while it's already running -- e.g. a global listener that
55
+ * synchronously calls `set()` on a DIFFERENT cell from inside its own
56
+ * callback. Unlike the shared boolean this replaces, a reentrant request
57
+ * that arrives while this is `true` is NOT dropped: it re-arms {@link
58
+ * globalNotifyPending}, which is drained (fired again) right after the
59
+ * in-progress loop finishes -- see {@link flushGlobalNotify}. This is what
60
+ * keeps a reentrant write to a different cell from being silently
61
+ * swallowed (issue #234), while still bounding recursion depth to one
62
+ * extra level per reentrant write, the same way `emitting` bounds it for
63
+ * same-id reentrancy on local listeners.
64
+ */
65
+ private notifyingGlobalListeners;
66
+ /**
67
+ * Write a raw source-of-truth value (e.g. a slider drag or text input).
68
+ * Structurally, a cell written via `set` (no `compute` fn) is what makes
69
+ * it "free" -- see {@link role}.
70
+ *
71
+ * @param options.auxiliary Marks this cell hidden-by-default in an
72
+ * Algebra-view-style listing (see {@link list}) -- e.g. an internal
73
+ * sampling parameter that isn't itself meaningful to show the user,
74
+ * distinct from a top-level named object. Only applied when the cell
75
+ * doesn't already exist, or is transitioning from a compute-backed
76
+ * (dependent) cell to a free one; an existing free cell's auxiliary flag
77
+ * is left as originally set.
78
+ */
79
+ set<T>(id: string, value: T, options?: {
80
+ auxiliary?: boolean;
81
+ }): void;
82
+ /**
83
+ * Subscribe to raw `set()` writes -- id plus the new value -- across
84
+ * every cell in the graph (issue #47's live-collaboration groundwork).
85
+ * Deliberately narrower than `subscribeAll`: it fires ONLY for an actual
86
+ * `set()` call with a real (structurally-different) value, never for a
87
+ * `define()`-driven recompute cascade. That's the exact shape a
88
+ * broadcast-to-other-peers use case needs -- each peer re-derives its
89
+ * own dependent cells locally once a base write arrives over the wire
90
+ * and gets applied via `set()` there too, so only the raw user-initiated
91
+ * writes need to cross the network, not every recomputed cell downstream
92
+ * of them.
93
+ */
94
+ subscribeWrites(fn: (id: string, value: unknown) => void): () => void;
95
+ private emitWrite;
96
+ /**
97
+ * Define (or redefine) a derived cell computed from other cells.
98
+ * Structurally, a cell written via `define` (has a `compute` fn) is what
99
+ * makes it "dependent" -- see {@link role}.
100
+ *
101
+ * @param options.auxiliary See {@link set}'s equivalent option; applied
102
+ * the same way (only on first definition, or a transition from free to
103
+ * dependent).
104
+ */
105
+ define<T>(id: string, compute: ComputeFn<T>, options?: {
106
+ auxiliary?: boolean;
107
+ }): void;
108
+ private defineImpl;
109
+ /**
110
+ * Whether `id` is "free" (writable directly via `set`, no `compute` fn --
111
+ * e.g. a slider or text input), "dependent" (computed via `define` from
112
+ * other cells), or "unknown" (`id` has never been `set`/`define`d, only
113
+ * read, or doesn't exist at all).
114
+ */
115
+ role(id: string): CellRole;
116
+ /** Whether `id` was marked `auxiliary` (hidden-by-default in an Algebra-view-style listing) -- see {@link set}/{@link define}. */
117
+ isAuxiliary(id: string): boolean;
118
+ /**
119
+ * Every cell currently in the graph, with its role and auxiliary flag --
120
+ * the basis for an Algebra-view-style listing (GeoGebra's free/dependent/
121
+ * auxiliary object model). Includes cells with no value yet (role
122
+ * "unknown") since a caller may still want to know such an id exists
123
+ * (e.g. was read but never written).
124
+ */
125
+ list(): Array<{
126
+ id: string;
127
+ role: CellRole;
128
+ auxiliary: boolean;
129
+ hasValue: boolean;
130
+ }>;
131
+ /** Read a cell's current value, recomputing if stale. Auto-tracks dependency edges. */
132
+ get<T>(id: string): T;
133
+ private recomputeAndEmit;
134
+ /** The value useSyncExternalStore observes for this cell. */
135
+ getVersion(id: string): number;
136
+ /** Subscribe to changes on one cell. Returns an unsubscribe function. */
137
+ subscribe(id: string, fn: Listener): () => void;
138
+ /** Subscribe to changes on any cell (e.g. to drive a canvas render loop). */
139
+ subscribeAll(fn: Listener): () => void;
140
+ /**
141
+ * Subscribe to changes on a fixed, known set of specific cells -- e.g.
142
+ * every cell a serialized URL fragment reads. Narrower than
143
+ * `subscribeAll`: `fn` fires only for a write on one of `ids`, not for
144
+ * literally any cell in the graph (issue #235 -- several panels' URL-sync
145
+ * effects used `subscribeAll` for exactly this "a handful of specific
146
+ * cells" shape, so they also fired on unrelated high-frequency writes
147
+ * elsewhere in the same graph -- an RAF-driven playback clock, a live
148
+ * drag preview, a per-epoch training metric -- that the listener's own
149
+ * output never actually depended on). Just sugar over one `subscribe`
150
+ * call per id; not appropriate when the relevant id set is itself dynamic
151
+ * (e.g. "every currently-visible row's cells", where the row list can
152
+ * grow/shrink) -- that shape still needs `subscribeAll` (ideally
153
+ * debounced) or per-id `subscribe` calls re-issued as the id set changes.
154
+ */
155
+ subscribeMany(ids: string[], fn: Listener): () => void;
156
+ has(id: string): boolean;
157
+ /**
158
+ * Whether `id` has a real value yet, as opposed to merely existing as an
159
+ * empty record (`has()` returns true for a cell the instant anything reads
160
+ * it via `get`, even before it's ever been `set` or `define`d -- not a
161
+ * reliable "should I seed this?" check from a post-render effect that runs
162
+ * after a sibling compute has already read-and-thus-created it).
163
+ */
164
+ hasValue(id: string): boolean;
165
+ /**
166
+ * Remove a cell entirely. Former *dependents* are marked dirty and
167
+ * notified (same as a `set()` would), so a compute that read the deleted
168
+ * cell re-runs and can fall back to whatever "this cell doesn't exist"
169
+ * means for it -- without this, a dependent kept its stale cached value
170
+ * forever, AND (because its dependency edges only rebuild during a
171
+ * recompute that never came) writes to its other dependencies stopped
172
+ * reaching it too. The notification happens *after* the cell is gone, so
173
+ * the reentrant recompute a listener may trigger sees the post-delete
174
+ * world: a `get()` on the deleted id re-creates an empty record
175
+ * (`hasValue: false`), exactly the "never existed" semantics callers
176
+ * like ExpressionRow's params compute already handle.
177
+ */
178
+ delete(id: string): void;
179
+ private ensure;
180
+ private propagateDirty;
181
+ /**
182
+ * Notify `id`'s listeners that it may have changed. Guarded against
183
+ * reentrancy per-id: a `useSyncExternalStore` listener synchronously
184
+ * calls `getSnapshot` (React's own tearing check) as soon as it's
185
+ * notified, which re-enters `get()` and, on a real recompute, calls back
186
+ * into `emit(id)` for the very same id before this call has returned.
187
+ * Without the guard that nested call re-invokes every listener again
188
+ * (including the one currently on the stack), which re-triggers the same
189
+ * reentrant read, forever -- an unbounded synchronous storm that pins the
190
+ * CPU and eventually OOMs the JS heap. It's always safe to drop the
191
+ * nested notification: any consumer notified mid-flight still reads the
192
+ * freshest value the next time it calls `get()`, so no update is lost by
193
+ * collapsing repeat notifications for the same id into one.
194
+ *
195
+ * The global (`subscribeAll`) notification is requested here but not
196
+ * fired directly -- see {@link scheduleGlobalNotify}: a single logical
197
+ * write (e.g. one `set()` on the root of a diamond-shaped dependency
198
+ * graph) calls `emit()` once per cell it transitively dirties, but must
199
+ * still only produce ONE `subscribeAll` notification (issue #234).
200
+ */
201
+ private emit;
202
+ /**
203
+ * Run `fn` as one "logical write" for the purposes of global-listener
204
+ * batching -- see {@link globalNotifyDepth}. Reentrant calls (e.g. a
205
+ * `subscribe()` listener triggered mid-cascade that synchronously calls
206
+ * `get()`, which recomputes and dirties further cells) nest transparently:
207
+ * only the outermost call's `finally` can bring the depth back to zero and
208
+ * trigger the deferred flush.
209
+ */
210
+ private runBatched;
211
+ /**
212
+ * Run `fn`, a sequence of otherwise-independent `set`/`define`/`delete`
213
+ * calls, as a SINGLE logical write for `subscribeAll` purposes (see
214
+ * {@link runBatched}/{@link scheduleGlobalNotify}). Without this, a
215
+ * multi-step mutation like a clear-then-replay (#374/#375) fires a
216
+ * `subscribeAll` notification after each individual call, so a listener
217
+ * that reads back across multiple cells (e.g. a canvas redraw walking an
218
+ * object-list cell and dereferencing each entry's point cells) can
219
+ * observe a transient state mid-sequence -- e.g. an id still listed in
220
+ * one cell whose corresponding point cell has already been deleted by an
221
+ * earlier call in the same `fn`. Wrapping the whole sequence here defers
222
+ * every `subscribeAll` notification until `fn` fully returns, so
223
+ * listeners only ever see the state before or after, never in between.
224
+ */
225
+ transaction<T>(fn: () => T): T;
226
+ /**
227
+ * Request a `subscribeAll` notification. While a logical write is still
228
+ * in progress ({@link globalNotifyDepth} > 0), the request is only
229
+ * recorded ({@link globalNotifyPending}) -- {@link runBatched} flushes it
230
+ * once that write (including everything it cascaded into) fully unwinds.
231
+ * Outside of any write (e.g. a standalone `get()` that lazily recomputes a
232
+ * dirty cell with no `set`/`define`/`delete` on the stack), there's no
233
+ * outer call to flush later, so it fires immediately.
234
+ */
235
+ private scheduleGlobalNotify;
236
+ /**
237
+ * Actually invoke every `subscribeAll` listener, once, for the batch of
238
+ * cell changes accumulated since the last flush.
239
+ *
240
+ * Guarded against reentering the listener-invocation loop itself --
241
+ * `notifyingGlobalListeners`, scoped to "is a global-listener loop
242
+ * currently on the stack" rather than per-cell-id, because by this point
243
+ * the notification is no longer about any single cell; it's "this batch
244
+ * of writes changed something." A listener that synchronously starts a
245
+ * NEW logical write (e.g. `set()` on a different cell) re-arms {@link
246
+ * globalNotifyPending} instead of recursing into a second, nested
247
+ * invocation of every listener -- that pending flag is drained in the
248
+ * `while` loop below once the in-progress loop returns, so that second
249
+ * write's notification still fires (once), it's just deferred to right
250
+ * after the first finishes rather than dropped. This is what fixes issue
251
+ * #234's bug 2: the previous shared `notifyingGlobal` boolean guard
252
+ * skipped (silently discarded) exactly this case instead of deferring it.
253
+ */
254
+ private flushGlobalNotify;
255
+ }
256
+ /** Deep structural equality, used to skip redraws when a recompute is a no-op. */
257
+ export declare function structuralEqual(a: unknown, b: unknown): boolean;
258
+ export {};
259
+ //# sourceMappingURL=CellGraph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CellGraph.d.ts","sourceRoot":"","sources":["../src/CellGraph.ts"],"names":[],"mappings":"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"}