@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/src/Type.ts ADDED
@@ -0,0 +1,48 @@
1
+ import { ComplexNumber } from "./ComplexNumber.ts";
2
+ import { Vector } from "./Vector.ts";
3
+ import { VectorUtils } from "./VectorUtils.ts";
4
+
5
+ /**
6
+ * Type — runtime classification used for the polymorphic `*Generic` dispatchers
7
+ * in {@link RealMath}/{@link ComplexMath}. Ported from Mallory's ActionScript
8
+ * `Type`. The string tags are preserved.
9
+ *
10
+ * Note: the AS3 version had an explicit `obj is Expression -> FUNCTION` branch,
11
+ * but its fall-through default was already `FUNCTION`, so the check is redundant
12
+ * and omitted here (an Expression still classifies as `FUNCTION`).
13
+ */
14
+ export const TypeTag = {
15
+ NUMBER: "number",
16
+ VECTOR: "vector",
17
+ MATRIX: "matrix",
18
+ FUNCTION: "function",
19
+ ERROR: "error",
20
+ BOOLEAN: "boolean",
21
+ PERMUTATION: "permutation",
22
+ } as const;
23
+
24
+ export type TypeTag = (typeof TypeTag)[keyof typeof TypeTag];
25
+
26
+ export class Type {
27
+ static readonly NUMBER = TypeTag.NUMBER;
28
+ static readonly VECTOR = TypeTag.VECTOR;
29
+ static readonly MATRIX = TypeTag.MATRIX;
30
+ static readonly FUNCTION = TypeTag.FUNCTION;
31
+ static readonly ERROR = TypeTag.ERROR;
32
+ static readonly BOOLEAN = TypeTag.BOOLEAN;
33
+ static readonly PERMUTATION = TypeTag.PERMUTATION;
34
+
35
+ /** Classify a runtime value into one of the {@link TypeTag} strings. */
36
+ static getType(obj: unknown): TypeTag {
37
+ if (typeof obj === "number" || obj instanceof ComplexNumber || ComplexNumber.isComplex(obj)) {
38
+ return TypeTag.NUMBER;
39
+ }
40
+ if (obj instanceof Vector) {
41
+ return VectorUtils.isMatrix(obj) ? TypeTag.MATRIX : TypeTag.VECTOR;
42
+ }
43
+ if (obj instanceof Error) return TypeTag.ERROR;
44
+ if (typeof obj === "boolean") return TypeTag.BOOLEAN;
45
+ if (typeof obj === "string") return TypeTag.ERROR;
46
+ return TypeTag.FUNCTION;
47
+ }
48
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Utilities — small general-purpose helpers.
3
+ *
4
+ * In the ActionScript original the entire body of this class was commented out.
5
+ * The helpers were clearly intended to ship (they are referenced conceptually
6
+ * throughout the library and `RoundTo` is re-implemented ad hoc elsewhere), so
7
+ * they are revived here as ordinary functions. Array helpers that merely duplicate
8
+ * built-ins (`CloneArray`, `MapArray`, `isMember`) are kept for API parity.
9
+ */
10
+ export class Utilities {
11
+ static readonly DefaultPrecision = 8;
12
+
13
+ /**
14
+ * Round a real number to `precision` decimal places. Extremely large
15
+ * magnitudes collapse to ±Infinity and denormally-small ones to 0, matching
16
+ * the AS3 `RoundTo` behaviour.
17
+ */
18
+ static roundTo(value: number, precision: number = Utilities.DefaultPrecision): number {
19
+ if (value >= Number.MAX_VALUE) return Number.POSITIVE_INFINITY;
20
+ if (value <= -Number.MAX_VALUE) return Number.NEGATIVE_INFINITY;
21
+ if (Math.abs(value) <= Number.MIN_VALUE) return 0;
22
+ const factor = 10 ** precision;
23
+ return Math.round(value * factor) / factor;
24
+ }
25
+
26
+ static radiansToDegrees(r: number): number {
27
+ return (180 / Math.PI) * r;
28
+ }
29
+
30
+ static degreesToRadians(d: number): number {
31
+ return (Math.PI / 180) * d;
32
+ }
33
+
34
+ /** Shallow copy of an array. */
35
+ static cloneArray<T>(array: readonly T[]): T[] {
36
+ return [...array];
37
+ }
38
+
39
+ /** Map `mapper` over an array (kept for parity with the AS3 API). */
40
+ static mapArray<T, U>(elements: readonly T[], mapper: (value: T) => U): U[] {
41
+ return elements.map(mapper);
42
+ }
43
+
44
+ /** True when `value` is (loosely) equal to a member of `group`. */
45
+ static isMember(value: unknown, group: readonly unknown[]): boolean {
46
+ // biome-ignore lint/suspicious/noDoubleEquals: faithful to AS3 loose `==` coercion semantics
47
+ return group.some((i) => value == i);
48
+ }
49
+ }
package/src/Vec4.ts ADDED
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Vec4 — a Euclidean 4D vector `(x, y, z, w)`.
3
+ *
4
+ * This is a genuine fourth *spatial* dimension (not time): all four
5
+ * components are treated symmetrically, exactly like {@link Quaternion}'s
6
+ * imaginary triple but one dimension further. Built to support 4D geometric
7
+ * algebra ({@link Bivector4}, {@link Rotor4}) for applications like simulating
8
+ * or rendering four-dimensional space.
9
+ */
10
+ export class Vec4 {
11
+ readonly x: number;
12
+ readonly y: number;
13
+ readonly z: number;
14
+ readonly w: number;
15
+
16
+ static readonly Zero = new Vec4(0, 0, 0, 0);
17
+ static readonly Ex = new Vec4(1, 0, 0, 0);
18
+ static readonly Ey = new Vec4(0, 1, 0, 0);
19
+ static readonly Ez = new Vec4(0, 0, 1, 0);
20
+ static readonly Ew = new Vec4(0, 0, 0, 1);
21
+
22
+ constructor(x = 0, y = 0, z = 0, w = 0) {
23
+ this.x = x;
24
+ this.y = y;
25
+ this.z = z;
26
+ this.w = w;
27
+ }
28
+
29
+ static of(x: number, y: number, z: number, w: number): Vec4 {
30
+ return new Vec4(x, y, z, w);
31
+ }
32
+
33
+ add(v: Vec4): Vec4 {
34
+ return new Vec4(this.x + v.x, this.y + v.y, this.z + v.z, this.w + v.w);
35
+ }
36
+
37
+ subtract(v: Vec4): Vec4 {
38
+ return new Vec4(this.x - v.x, this.y - v.y, this.z - v.z, this.w - v.w);
39
+ }
40
+
41
+ scale(s: number): Vec4 {
42
+ return new Vec4(this.x * s, this.y * s, this.z * s, this.w * s);
43
+ }
44
+
45
+ negate(): Vec4 {
46
+ return this.scale(-1);
47
+ }
48
+
49
+ /** Euclidean inner product. */
50
+ dot(v: Vec4): number {
51
+ return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
52
+ }
53
+
54
+ get magnitude(): number {
55
+ return Math.hypot(this.x, this.y, this.z, this.w);
56
+ }
57
+
58
+ get magnitudeSquared(): number {
59
+ return this.dot(this);
60
+ }
61
+
62
+ normalize(): Vec4 {
63
+ const m = this.magnitude;
64
+ if (m === 0) throw new Error("Cannot normalize the zero vector.");
65
+ return this.scale(1 / m);
66
+ }
67
+
68
+ lerp(v: Vec4, t: number): Vec4 {
69
+ return this.add(v.subtract(this).scale(t));
70
+ }
71
+
72
+ equals(v: Vec4, epsilon = 0): boolean {
73
+ if (epsilon === 0) return this.x === v.x && this.y === v.y && this.z === v.z && this.w === v.w;
74
+ return (
75
+ Math.abs(this.x - v.x) <= epsilon &&
76
+ Math.abs(this.y - v.y) <= epsilon &&
77
+ Math.abs(this.z - v.z) <= epsilon &&
78
+ Math.abs(this.w - v.w) <= epsilon
79
+ );
80
+ }
81
+
82
+ /** The 3D subvector `(x, y, z)` obtained by dropping the w-axis — useful when reading out the current 3D "slice" of a 4D scene. */
83
+ dropW(): [number, number, number] {
84
+ return [this.x, this.y, this.z];
85
+ }
86
+
87
+ toArray(): [number, number, number, number] {
88
+ return [this.x, this.y, this.z, this.w];
89
+ }
90
+
91
+ static fromArray(a: readonly [number, number, number, number]): Vec4 {
92
+ return new Vec4(a[0], a[1], a[2], a[3]);
93
+ }
94
+
95
+ toString(): string {
96
+ return `(${this.x}, ${this.y}, ${this.z}, ${this.w})`;
97
+ }
98
+ }
package/src/Vector.ts ADDED
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Vector — an `Array` subclass that doubles as a mathematical vector / matrix row.
3
+ *
4
+ * Ported from Mallory's ActionScript `Vector` (`dynamic class Vector extends Array`).
5
+ * In the original the class was used both as a plain sequence container and, when
6
+ * nested (a Vector of Vectors), as a matrix. That dual role is preserved here.
7
+ *
8
+ * Modernisations & bug fixes relative to the AS3 original:
9
+ * - `setElement` no longer infinitely recurses when the target slot holds a
10
+ * falsy value (the AS3 version looped forever whenever `this[index]` was
11
+ * `0`/`null`/`undefined`). It now pads with the placeholder and assigns.
12
+ * - The `x`/`y`/`z`/`t` accessors return a genuinely stored `0` instead of
13
+ * silently coercing every falsy slot to `0`.
14
+ * - `toXML` returns a `string` (AS3 `XML` no longer exists in JS land).
15
+ * - The class is generic and iterable (inherited from `Array`).
16
+ */
17
+ export class Vector<T = unknown> extends Array<T> {
18
+ /** A shared, empty vector — mirrors AS3 `Vector.Empty`. */
19
+ static readonly Empty: Vector<never> = new Vector<never>();
20
+
21
+ /**
22
+ * Build a Vector from the given elements.
23
+ *
24
+ * NOTE on the single-number case: because `Array` (and therefore this
25
+ * subclass) treats `new Vector(n)` as "create a sparse vector of length n",
26
+ * that behaviour is retained — it is also what `Array.prototype` methods rely
27
+ * on via `Symbol.species` when they allocate result vectors. Use
28
+ * {@link Vector.of} or {@link Vector.from} to wrap a literal single number.
29
+ */
30
+ constructor(length: number);
31
+ constructor(...rest: T[]);
32
+ constructor(...rest: T[]) {
33
+ // Reproduce Array's constructor contract: a lone number means "length".
34
+ if (rest.length === 1 && typeof rest[0] === "number") {
35
+ super(rest[0] as number);
36
+ } else {
37
+ super(...rest);
38
+ }
39
+ }
40
+
41
+ /** Ensure `map`/`filter`/`slice`/etc. produce plain `Vector`s, not typed views. */
42
+ static override get [Symbol.species](): ArrayConstructor {
43
+ return Array as unknown as ArrayConstructor;
44
+ }
45
+
46
+ /** Convert any array-like into a Vector (shallow). Mirrors AS3 `ArrayToVector`. */
47
+ static fromArray<U>(array: Iterable<U>): Vector<U> {
48
+ const v = new Vector<U>();
49
+ for (const e of array) v.push(e);
50
+ return v;
51
+ }
52
+
53
+ /**
54
+ * Parse the `<vector>` form produced by {@link toXML} (best-effort inverse:
55
+ * numeric coordinates become numbers, everything else stays a string).
56
+ */
57
+ static fromXML(xml: string): Vector<number | string> {
58
+ const out = new Vector<number | string>();
59
+ for (const match of xml.matchAll(/<coordinate>(.*?)<\/coordinate>/g)) {
60
+ const raw = match[1] as string;
61
+ const n = Number(raw);
62
+ out.push(raw !== "" && !Number.isNaN(n) ? n : raw);
63
+ }
64
+ return out;
65
+ }
66
+
67
+ /**
68
+ * Parse the bracketed form produced by {@link toString} (best-effort inverse:
69
+ * numeric elements become numbers, everything else stays a trimmed string).
70
+ */
71
+ static fromString(str: string, seperator = ",", leftBracket = "[", rightBracket = "]"): Vector<number | string> {
72
+ let s = str.trim();
73
+ if (s.startsWith(leftBracket)) s = s.slice(leftBracket.length);
74
+ if (s.endsWith(rightBracket)) s = s.slice(0, s.length - rightBracket.length);
75
+ const out = new Vector<number | string>();
76
+ if (s === "") return out;
77
+ for (const part of s.split(seperator)) {
78
+ const t = part.trim();
79
+ const n = Number(t);
80
+ out.push(t !== "" && !Number.isNaN(n) ? n : t);
81
+ }
82
+ return out;
83
+ }
84
+
85
+ /** String representation, e.g. `[1,2,3]`. */
86
+ override toString(seperator = ",", leftBracket = "[", rightBracket = "]"): string {
87
+ let out = leftBracket;
88
+ for (let i = 0; i < this.length; i++) {
89
+ out += this[i] != null ? String(this[i]) : String(null);
90
+ if (i !== this.length - 1) out += seperator;
91
+ }
92
+ return out + rightBracket;
93
+ }
94
+
95
+ /** XML-ish serialisation, kept for compatibility with the AS3 API. */
96
+ toXML(): string {
97
+ const parts: string[] = [];
98
+ for (let i = 0; i < this.length; i++) {
99
+ parts.push(`<coordinate>${this[i]}</coordinate>`);
100
+ }
101
+ return `<vector>${parts.join("")}</vector>`;
102
+ }
103
+
104
+ /** Return the element at `index` (defaults to the first). */
105
+ getElement(index = 0): T | undefined {
106
+ return this[index];
107
+ }
108
+
109
+ /** Remove and return the element at `index`. */
110
+ removeElement(index = 0): T | undefined {
111
+ return this.splice(index, 1)[0];
112
+ }
113
+
114
+ /**
115
+ * Set the element at `index`, padding with `placeHolder` if the vector is too
116
+ * short. Returns the previously stored value (or `undefined`).
117
+ *
118
+ * Bug fix: the AS3 version recursed infinitely whenever the slot was falsy.
119
+ */
120
+ setElement(newElement: T, index = 0, placeHolder: T | null = null): T | undefined {
121
+ while (this.length < index) this.push(placeHolder as T);
122
+ const previous = this[index];
123
+ this[index] = newElement;
124
+ return previous;
125
+ }
126
+
127
+ /**
128
+ * Insert `newElement` at `index`. With no index (or a negative one) it is
129
+ * appended. If `index` is beyond the current end, the gap is filled with
130
+ * `placeHolder`. Returns the resulting length.
131
+ */
132
+ addElement(newElement: T | null = null, index = -1, placeHolder: T | null = null): number {
133
+ if (index < 0) return this.push(newElement as T);
134
+ while (index > this.length) this.push(placeHolder as T);
135
+ this.splice(index, 0, newElement as T);
136
+ return this.length;
137
+ }
138
+
139
+ // The x/y/z/t accessors let a Vector act as a 1-to-4 dimensional point.
140
+ private coord(i: number): T | 0 {
141
+ return i < this.length && this[i] != null ? (this[i] as T) : 0;
142
+ }
143
+
144
+ get x(): T | 0 {
145
+ return this.coord(0);
146
+ }
147
+ get y(): T | 0 {
148
+ return this.coord(1);
149
+ }
150
+ get z(): T | 0 {
151
+ return this.coord(2);
152
+ }
153
+ get t(): T | 0 {
154
+ return this.coord(3);
155
+ }
156
+
157
+ set x(value: T) {
158
+ this.setElement(value, 0);
159
+ }
160
+ set y(value: T) {
161
+ this.setElement(value, 1);
162
+ }
163
+ set z(value: T) {
164
+ this.setElement(value, 2);
165
+ }
166
+ set t(value: T) {
167
+ this.setElement(value, 3);
168
+ }
169
+
170
+ /**
171
+ * Clone the vector. When `deep` is true (default) nested Vectors are cloned
172
+ * recursively, so a matrix is duplicated rather than sharing its rows.
173
+ */
174
+ clone(deep = true): Vector<T> {
175
+ const out = new Vector<T>();
176
+ for (let i = 0; i < this.length; i++) {
177
+ const el = this[i];
178
+ out[i] = deep && el instanceof Vector ? (el.clone() as unknown as T) : (el as T);
179
+ }
180
+ return out;
181
+ }
182
+
183
+ /** Return a new vector with the elements in reverse order. */
184
+ reversed(): Vector<T> {
185
+ const out = new Vector<T>();
186
+ for (let i = 0; i < this.length; i++) out[i] = this[this.length - 1 - i] as T;
187
+ return out;
188
+ }
189
+ }
@@ -0,0 +1,87 @@
1
+ import { DualNumber } from "./DualNumber.ts";
2
+ import { Symbolic } from "./Symbolic.ts";
3
+
4
+ /**
5
+ * VectorCalculus — multivariable differential calculus: gradients, Jacobians,
6
+ * divergence, curl, and Hessians. Built entirely on existing exact-derivative
7
+ * machinery rather than a new autodiff engine: {@link gradient}/{@link jacobian}
8
+ * reuse {@link DualNumber} forward-mode autodiff (exact, first-order);
9
+ * {@link symbolicGradient} reuses {@link Symbolic} differentiation/evaluation
10
+ * for string-expression functions.
11
+ *
12
+ * {@link hessian} is the one approximate method — it takes central differences
13
+ * of the *exact* gradient (not of `f` itself), which is more accurate than a
14
+ * naive finite-difference Hessian without the scope of implementing
15
+ * second-order (hyperdual) numbers.
16
+ */
17
+ export class VectorCalculus {
18
+ /** The gradient of a scalar field `f` at `point` (exact, via {@link DualNumber}). */
19
+ static gradient(f: (xs: DualNumber[]) => DualNumber, point: number[]): number[] {
20
+ return DualNumber.gradient(f, point);
21
+ }
22
+
23
+ /** The rate of change of `f` at `point` along `direction` (need not be a unit vector). */
24
+ static directionalDerivative(f: (xs: DualNumber[]) => DualNumber, point: number[], direction: number[]): number {
25
+ const norm = Math.sqrt(direction.reduce((s, d) => s + d * d, 0));
26
+ if (norm === 0) throw new Error("VectorCalculus.directionalDerivative: direction must be non-zero");
27
+ const grad = VectorCalculus.gradient(f, point);
28
+ return grad.reduce((s, g, i) => s + (g * (direction[i] as number)) / norm, 0);
29
+ }
30
+
31
+ /**
32
+ * The Jacobian of a vector field `f: R^n -> R^m` at `point`, as an `m × n`
33
+ * matrix (`J[i][j] = ∂f_i/∂x_j`). Computed via `n` forward autodiff passes,
34
+ * one dual-seeded input dimension at a time.
35
+ */
36
+ static jacobian(f: (xs: DualNumber[]) => DualNumber[], point: number[]): number[][] {
37
+ const n = point.length;
38
+ const columns: number[][] = [];
39
+ for (let i = 0; i < n; i++) {
40
+ const seeded = point.map((x, j) => new DualNumber(x, i === j ? 1 : 0));
41
+ columns.push(f(seeded).map((o) => o.deriv));
42
+ }
43
+ const m = columns[0]?.length ?? 0;
44
+ return Array.from({ length: m }, (_, row) => columns.map((column) => column[row] as number));
45
+ }
46
+
47
+ /** The divergence of a vector field `f: R^n -> R^n` at `point` (the trace of its Jacobian). */
48
+ static divergence(f: (xs: DualNumber[]) => DualNumber[], point: number[]): number {
49
+ const J = VectorCalculus.jacobian(f, point);
50
+ return point.reduce((sum, _, i) => sum + (J[i]?.[i] as number), 0);
51
+ }
52
+
53
+ /** The curl of a 3D vector field `f: R^3 -> R^3` at `point`. */
54
+ static curl3D(f: (xs: DualNumber[]) => DualNumber[], point: [number, number, number]): [number, number, number] {
55
+ const J = VectorCalculus.jacobian(f, point);
56
+ return [
57
+ (J[2]?.[1] as number) - (J[1]?.[2] as number),
58
+ (J[0]?.[2] as number) - (J[2]?.[0] as number),
59
+ (J[1]?.[0] as number) - (J[0]?.[1] as number),
60
+ ];
61
+ }
62
+
63
+ /**
64
+ * The Hessian of a scalar field `f` at `point`: central differences (step
65
+ * `h`) of the exact gradient, i.e. `H[i][j] ≈ ∂(∂f/∂x_j)/∂x_i`.
66
+ */
67
+ static hessian(f: (xs: DualNumber[]) => DualNumber, point: number[], h = 1e-4): number[][] {
68
+ return point.map((_, i) => {
69
+ const plus = point.slice();
70
+ const minus = point.slice();
71
+ plus[i] = (plus[i] as number) + h;
72
+ minus[i] = (minus[i] as number) - h;
73
+ const gradPlus = VectorCalculus.gradient(f, plus);
74
+ const gradMinus = VectorCalculus.gradient(f, minus);
75
+ return gradPlus.map((g, j) => (g - (gradMinus[j] as number)) / (2 * h));
76
+ });
77
+ }
78
+
79
+ /**
80
+ * The exact gradient of a string expression at `point`, via
81
+ * {@link Symbolic.differentiate}/{@link Symbolic.evaluate} (one partial
82
+ * derivative per named variable — every other variable is held constant).
83
+ */
84
+ static symbolicGradient(expr: string, variables: string[], point: Record<string, number>): number[] {
85
+ return variables.map((variable) => Symbolic.evaluate(Symbolic.differentiate(expr, variable), point));
86
+ }
87
+ }