@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
@@ -0,0 +1,481 @@
1
+ import { ComplexNumber } from "./ComplexNumber.ts";
2
+ import { Decimal } from "./Decimal.ts";
3
+ import { DualNumber } from "./DualNumber.ts";
4
+ import { Quaternion } from "./Quaternion.ts";
5
+ import { Rational } from "./Rational.ts";
6
+ import { Vector } from "./Vector.ts";
7
+ import { type Matrix, VectorUtils } from "./VectorUtils.ts";
8
+
9
+ /**
10
+ * Structure — a generic algebraic structure (group, ring, field, …) defined by
11
+ * its membership criteria, operations, inverses and identities. Given those, it
12
+ * provides linear algebra (vectors and matrices) over the structure, mirroring
13
+ * {@link RealMath}/{@link ComplexMath} but parameterised by arbitrary operations.
14
+ *
15
+ * Ported from Mallory's ActionScript `Structure`. The AS3 matrix section was
16
+ * essentially non-functional — several methods were mistakenly declared `static`
17
+ * yet called instance operations, many referenced undefined capitalised names
18
+ * (`Scale`, `ScaleMatrix`, `Determinant`), `crossProduct` overwrote its first
19
+ * operand with the second and read index 3, `powerMatrix` invoked a method that
20
+ * does not exist, and `vectorSum`/`vectorProduct` never returned. All of this is
21
+ * reconstructed here as working instance methods. The `chriteria` spelling is
22
+ * corrected to `criteria`.
23
+ */
24
+
25
+ export interface StructureOptions<T> {
26
+ /** Membership predicates; an element is a member iff it satisfies them all. */
27
+ criteria?: Array<(element: unknown) => boolean>;
28
+ /** Binary operations; `operations[0]` is "add", `operations[1]` is "multiply". */
29
+ operations?: Array<(a: T, b: T) => T>;
30
+ /** Inverse maps; `inverses[0]` is "negative", `inverses[1]` is "reciprocal". */
31
+ inverses?: Array<(x: T) => T>;
32
+ /** Identity elements; `identities[0]` is "zero", `identities[1]` is "one". */
33
+ identities?: T[];
34
+ /** Optional coercion of an arbitrary value into the structure. */
35
+ wrap?: (x: unknown) => T;
36
+ /** Optional equality test (defaults to strict `===`). */
37
+ equality?: (a: T, b: T) => boolean;
38
+ }
39
+
40
+ type SVec<T> = Vector<T>;
41
+ type SMat<T> = Matrix<T>;
42
+
43
+ export class Structure<T = unknown> {
44
+ private readonly _criteria: Array<(element: unknown) => boolean>;
45
+ private readonly _operations: Array<(a: T, b: T) => T>;
46
+ private readonly _inverses: Array<(x: T) => T>;
47
+ private readonly _identities: T[];
48
+ private readonly _wrapMethod: (x: unknown) => T;
49
+ private readonly _equalityMethod: (a: T, b: T) => boolean;
50
+
51
+ constructor(options: StructureOptions<T> = {}) {
52
+ this._criteria = options.criteria ?? [];
53
+ this._operations = options.operations ?? [];
54
+ this._inverses = options.inverses ?? [];
55
+ this._identities = options.identities ?? [];
56
+ this._wrapMethod = options.wrap ?? ((x) => x as T);
57
+ this._equalityMethod = options.equality ?? ((a, b) => a === b);
58
+ }
59
+
60
+ // -- criteria ------------------------------------------------------------
61
+
62
+ criterion(index: number): (element: unknown) => boolean {
63
+ return this._criteria[index] as (element: unknown) => boolean;
64
+ }
65
+
66
+ isMember(element: unknown): boolean {
67
+ return this._criteria.every((c) => c(element) !== false);
68
+ }
69
+
70
+ // -- operations ----------------------------------------------------------
71
+
72
+ operation(index: number): (a: T, b: T) => T {
73
+ return this._operations[index] as (a: T, b: T) => T;
74
+ }
75
+
76
+ /** Repeatedly apply `operation(operationIndex)` `power` times (using the inverse for negative powers). */
77
+ integerPower(scalar: T, power: number, operationIndex = 0): T {
78
+ let result = this.identity(operationIndex);
79
+ const op = this.operation(operationIndex);
80
+ let s = scalar;
81
+ let p = power;
82
+ if (p < 0) {
83
+ p = -p;
84
+ s = this.inverse(operationIndex)(scalar);
85
+ }
86
+ for (let i = 0; i < p; i++) result = op(result, s);
87
+ return result;
88
+ }
89
+
90
+ get add(): (a: T, b: T) => T {
91
+ return this._operations[0] as (a: T, b: T) => T;
92
+ }
93
+ addPower(scalar: T, power: number): T {
94
+ return this.integerPower(scalar, power, 0);
95
+ }
96
+
97
+ get multiply(): (a: T, b: T) => T {
98
+ return this._operations[1] as (a: T, b: T) => T;
99
+ }
100
+ multiplyPower(scalar: T, power: number): T {
101
+ return this.integerPower(scalar, power, 1);
102
+ }
103
+
104
+ // -- inverses ------------------------------------------------------------
105
+
106
+ inverse(index = 0): (x: T) => T {
107
+ return this._inverses[index] as (x: T) => T;
108
+ }
109
+ get negative(): (x: T) => T {
110
+ return this.inverse(0);
111
+ }
112
+ get reciprocal(): (x: T) => T {
113
+ return this.inverse(1);
114
+ }
115
+
116
+ subtract(a: T, b: T): T {
117
+ return this.add(a, this.negative(b));
118
+ }
119
+ divide(a: T, b: T): T {
120
+ return this.multiply(a, this.reciprocal(b));
121
+ }
122
+
123
+ // -- identities ----------------------------------------------------------
124
+
125
+ identity(index = 0): T {
126
+ return this._identities[index] as T;
127
+ }
128
+ get zero(): T {
129
+ return this._identities[0] as T;
130
+ }
131
+ get one(): T {
132
+ return this._identities[1] as T;
133
+ }
134
+
135
+ get wrap(): (x: unknown) => T {
136
+ return this._wrapMethod;
137
+ }
138
+ get equality(): (a: T, b: T) => boolean {
139
+ return this._equalityMethod;
140
+ }
141
+
142
+ // -- vectors -------------------------------------------------------------
143
+
144
+ contains(alpha: SVec<T>, element: T): boolean {
145
+ return VectorUtils.contains(alpha, element, this.equality);
146
+ }
147
+
148
+ wrapVector(alpha: Vector<unknown>): SVec<T> {
149
+ return VectorUtils.transform(alpha, this.wrap);
150
+ }
151
+
152
+ addVector(alpha: SVec<T>, beta: SVec<T>): SVec<T> {
153
+ return VectorUtils.combine(alpha, beta, this.add, this.zero) as SVec<T>;
154
+ }
155
+
156
+ scaleVector(alpha: SVec<T>, scalar: T): SVec<T> {
157
+ return VectorUtils.transform(alpha, (x) => this.multiply(scalar, x));
158
+ }
159
+
160
+ negativeVector(alpha: SVec<T>): SVec<T> {
161
+ return VectorUtils.transform(alpha, this.negative);
162
+ }
163
+
164
+ reciprocalVector(alpha: SVec<T>): SVec<T> {
165
+ return VectorUtils.transform(alpha, this.reciprocal);
166
+ }
167
+
168
+ inverseVector(alpha: SVec<T>, index = 0): SVec<T> {
169
+ return VectorUtils.transform(alpha, this.inverse(index));
170
+ }
171
+
172
+ subtractVector(alpha: SVec<T>, beta: SVec<T>): SVec<T> {
173
+ return this.addVector(alpha, this.negativeVector(beta));
174
+ }
175
+
176
+ dotProduct(alpha: SVec<T>, beta: SVec<T>): T {
177
+ const collapsable = VectorUtils.combine(alpha, beta, this.multiply, this.zero) as SVec<T>;
178
+ return VectorUtils.collapse(collapsable, this.add) as T;
179
+ }
180
+
181
+ /** 3D cross product (bug fix: correct operands and index 2 for the z-component). */
182
+ crossProduct(alpha: SVec<T>, beta: SVec<T>): SVec<T> {
183
+ const a: T[] = [this.zero, this.zero, this.zero];
184
+ const b: T[] = [this.zero, this.zero, this.zero];
185
+ for (let idx = 0; idx < 3; idx++) {
186
+ if (idx < alpha.length && alpha[idx] != null) a[idx] = alpha[idx] as T;
187
+ if (idx < beta.length && beta[idx] != null) b[idx] = beta[idx] as T;
188
+ }
189
+ const i = this.subtract(this.multiply(a[1] as T, b[2] as T), this.multiply(a[2] as T, b[1] as T));
190
+ const j = this.subtract(this.multiply(a[2] as T, b[0] as T), this.multiply(a[0] as T, b[2] as T));
191
+ const k = this.subtract(this.multiply(a[0] as T, b[1] as T), this.multiply(a[1] as T, b[0] as T));
192
+ return Vector.fromArray([i, j, k]);
193
+ }
194
+
195
+ kroneckerProduct(A: SVec<T>, B: SVec<T>): SVec<T> {
196
+ let kronecker = VectorUtils.constantVector(A.length, null as unknown) as Vector<unknown>;
197
+ kronecker = VectorUtils.fillByIndex(kronecker, (i) => this.scaleVector(B, A[i] as T));
198
+ return VectorUtils.flattenSDLevels(kronecker, 2) as SVec<T>;
199
+ }
200
+
201
+ // -- matrices ------------------------------------------------------------
202
+
203
+ generateIdentity(height = 1, width = 1): SMat<T> {
204
+ return VectorUtils.generateIdentity(height, width, this.one, this.zero);
205
+ }
206
+
207
+ addMatrix(alpha: SMat<T>, beta: SMat<T>): SMat<T> {
208
+ return VectorUtils.combine(alpha, beta, (a, b) => this.addVector(a, b)) as SMat<T>;
209
+ }
210
+
211
+ scaleMatrix(alpha: SMat<T>, scalar: T): SMat<T> {
212
+ return VectorUtils.transformEndNodes(alpha, (x) => this.multiply(scalar, x as T)) as SMat<T>;
213
+ }
214
+
215
+ negativeMatrix(alpha: SMat<T>): SMat<T> {
216
+ return VectorUtils.transformEndNodes(alpha, (x) => this.negative(x as T)) as SMat<T>;
217
+ }
218
+
219
+ subtractMatrix(alpha: SMat<T>, beta: SMat<T>): SMat<T> {
220
+ return this.addMatrix(alpha, this.negativeMatrix(beta));
221
+ }
222
+
223
+ scaleRow(alpha: SMat<T>, index = 0, scalar: T): SMat<T> {
224
+ const newM = alpha.clone();
225
+ return VectorUtils.rowSet(newM, this.scaleVector(newM[index] as SVec<T>, scalar), index);
226
+ }
227
+
228
+ scaleColumn(alpha: SMat<T>, index = 0, scalar: T): SMat<T> {
229
+ return VectorUtils.transpose(this.scaleRow(alpha, index, scalar));
230
+ }
231
+
232
+ trace(alpha: SMat<T>): T {
233
+ return VectorUtils.collapse(VectorUtils.diagonal(alpha), this.add) as T;
234
+ }
235
+
236
+ kroneckerMatrixProduct(alpha: SMat<T>, beta: SMat<T>): SMat<T> {
237
+ let kronecker = VectorUtils.constantMatrix(
238
+ VectorUtils.height(alpha),
239
+ VectorUtils.width(alpha),
240
+ null as unknown,
241
+ ) as Matrix<unknown>;
242
+ kronecker = VectorUtils.fillMatrixByIndex(kronecker, (i, j) =>
243
+ this.scaleMatrix(beta, (alpha[i] as SVec<T>)[j] as T),
244
+ );
245
+ return VectorUtils.breakBlock(kronecker as Matrix<SMat<T>>);
246
+ }
247
+
248
+ multiplyMatrix(alpha: SMat<T>, beta: SMat<T>): SMat<T> {
249
+ const kroneckerList = new Vector<SMat<T>>();
250
+ for (let i = 0; i < VectorUtils.width(alpha); i++) {
251
+ kroneckerList.push(this.kroneckerMatrixProduct(VectorUtils.getColumn(alpha, i), VectorUtils.getRow(beta, i)));
252
+ }
253
+ return VectorUtils.collapse(kroneckerList, (a, b) => this.addMatrix(a, b)) as SMat<T>;
254
+ }
255
+
256
+ /** Integer matrix power (bug fix: actually accumulates the factors). */
257
+ powerMatrix(alpha: SMat<T>, power = 1): SMat<T> {
258
+ if (power === 0) return this.generateIdentity(VectorUtils.height(alpha), VectorUtils.width(alpha));
259
+ const base = power > 0 ? alpha.clone() : this.invertMatrix(alpha);
260
+ const powerList = new Vector<SMat<T>>();
261
+ for (let i = 0; i < Math.abs(power); i++) powerList.push(base.clone());
262
+ return VectorUtils.collapse(powerList, (a, b) => this.multiplyMatrix(a, b)) as SMat<T>;
263
+ }
264
+
265
+ /**
266
+ * Determinant via Gaussian elimination with row-swap pivoting, O(n^3)
267
+ * instead of the previous O(n!) cofactor (Laplace) expansion.
268
+ */
269
+ determinant(alpha: SMat<T>): T {
270
+ if (VectorUtils.width(alpha) !== VectorUtils.height(alpha)) return this.zero;
271
+ const n = VectorUtils.width(alpha);
272
+ if (n < 2) return (alpha[0] as SVec<T>)[0] as T;
273
+
274
+ const mat: T[][] = [...alpha].map((row) => [...(row as SVec<T>)]);
275
+ let det = this.one;
276
+ let sign = this.one;
277
+
278
+ for (let col = 0; col < n; col++) {
279
+ if (this.equality(mat[col][col] as T, this.zero)) {
280
+ let swap = -1;
281
+ for (let r = col + 1; r < n; r++) {
282
+ if (!this.equality(mat[r][col] as T, this.zero)) {
283
+ swap = r;
284
+ break;
285
+ }
286
+ }
287
+ if (swap === -1) return this.zero;
288
+ [mat[col], mat[swap]] = [mat[swap], mat[col]];
289
+ sign = this.negative(sign);
290
+ }
291
+ const pivot = mat[col][col] as T;
292
+ det = this.multiply(det, pivot);
293
+ const pivotInv = this.reciprocal(pivot);
294
+ for (let r = col + 1; r < n; r++) {
295
+ const factor = this.multiply(mat[r][col] as T, pivotInv);
296
+ if (this.equality(factor, this.zero)) continue;
297
+ for (let k = col; k < n; k++) {
298
+ mat[r][k] = this.subtract(mat[r][k] as T, this.multiply(factor, mat[col][k] as T));
299
+ }
300
+ }
301
+ }
302
+ return this.multiply(sign, det);
303
+ }
304
+
305
+ permanent(alpha: SMat<T>): T {
306
+ if (VectorUtils.width(alpha) < 2) return (alpha[0] as SVec<T>)[0] as T;
307
+ const detList = new Vector<T>();
308
+ for (let i = 0; i < VectorUtils.width(alpha); i++) {
309
+ const temp = VectorUtils.columnRemoved(VectorUtils.rowRemoved(alpha, 0), i);
310
+ detList.push(this.multiply((alpha[0] as SVec<T>)[i] as T, this.permanent(temp)));
311
+ }
312
+ return VectorUtils.collapse(detList, this.add) as T;
313
+ }
314
+
315
+ /**
316
+ * Matrix inverse by Gauss-Jordan elimination over the structure's field
317
+ * operations, with a zero-pivot row swap (bug fix — the AS3 version had no
318
+ * pivoting and divided by a zero pivot).
319
+ */
320
+ invertMatrix(alpha: SMat<T>, checkDeterminant = true): SMat<T> {
321
+ const n = VectorUtils.height(alpha);
322
+ const w = VectorUtils.width(alpha);
323
+ if (checkDeterminant && this.equality(this.determinant(alpha), this.zero)) {
324
+ return VectorUtils.constantMatrix(n, w, this.zero);
325
+ }
326
+
327
+ const mat: T[][] = [...alpha].map((row) => [...(row as SVec<T>)]);
328
+ const inv: T[][] = [...this.generateIdentity(n, n)].map((row) => [...(row as SVec<T>)]);
329
+
330
+ for (let col = 0; col < n; col++) {
331
+ if (this.equality(mat[col][col] as T, this.zero)) {
332
+ let swap = -1;
333
+ for (let r = col + 1; r < n; r++) {
334
+ if (!this.equality(mat[r][col] as T, this.zero)) {
335
+ swap = r;
336
+ break;
337
+ }
338
+ }
339
+ if (swap === -1) continue; // singular column
340
+ [mat[col], mat[swap]] = [mat[swap], mat[col]];
341
+ [inv[col], inv[swap]] = [inv[swap], inv[col]];
342
+ }
343
+ const pivotInv = this.reciprocal(mat[col][col] as T);
344
+ for (let k = 0; k < n; k++) {
345
+ mat[col][k] = this.multiply(mat[col][k] as T, pivotInv);
346
+ inv[col][k] = this.multiply(inv[col][k] as T, pivotInv);
347
+ }
348
+ for (let r = 0; r < n; r++) {
349
+ if (r === col) continue;
350
+ const f = mat[r][col] as T;
351
+ for (let k = 0; k < n; k++) {
352
+ mat[r][k] = this.subtract(mat[r][k] as T, this.multiply(f, mat[col][k] as T));
353
+ inv[r][k] = this.subtract(inv[r][k] as T, this.multiply(f, inv[col][k] as T));
354
+ }
355
+ }
356
+ }
357
+ return Vector.fromArray(inv.map((row) => Vector.fromArray(row)));
358
+ }
359
+
360
+ // -- vector statistics (bug fix: the AS3 versions never returned) --------
361
+
362
+ vectorSum(alpha: SVec<T>): T {
363
+ return VectorUtils.collapse(alpha, this.add) as T;
364
+ }
365
+
366
+ vectorProduct(alpha: SVec<T>): T {
367
+ return VectorUtils.collapse(alpha, this.multiply) as T;
368
+ }
369
+
370
+ vectorCollapseOperation(alpha: SVec<T>, index = 0): T {
371
+ return VectorUtils.collapse(alpha, this.operation(index)) as T;
372
+ }
373
+
374
+ // -- ready-made structures -----------------------------------------------
375
+
376
+ /** The field of real numbers (JS `number`). */
377
+ static realField(): Structure<number> {
378
+ return new Structure<number>({
379
+ criteria: [(x) => typeof x === "number"],
380
+ operations: [(a, b) => a + b, (a, b) => a * b],
381
+ inverses: [(x) => -x, (x) => 1 / x],
382
+ identities: [0, 1],
383
+ equality: (a, b) => a === b,
384
+ wrap: (x) => Number(x),
385
+ });
386
+ }
387
+
388
+ /** The field of complex numbers ({@link ComplexNumber}). */
389
+ static complexField(): Structure<ComplexNumber> {
390
+ return new Structure<ComplexNumber>({
391
+ criteria: [(x) => x instanceof ComplexNumber],
392
+ operations: [(a, b) => a.add(b), (a, b) => a.multiply(b)],
393
+ inverses: [(x) => x.neg(), (x) => x.reciprocal()],
394
+ identities: [ComplexNumber.Zero, ComplexNumber.One],
395
+ equality: (a, b) => a.equals(b),
396
+ wrap: (x) => (x instanceof ComplexNumber ? x : new ComplexNumber(x as number)),
397
+ });
398
+ }
399
+
400
+ /**
401
+ * The ring of integers modulo `n` (Z/nZ). It is a field when `n` is prime; for
402
+ * a composite `n`, {@link reciprocal} returns `NaN` for non-invertible elements.
403
+ */
404
+ static integersModulo(n: number): Structure<number> {
405
+ const mod = (x: number) => ((x % n) + n) % n;
406
+ const modInverse = (a: number): number => {
407
+ let [oldR, r] = [mod(a), n];
408
+ let [oldS, s] = [1, 0];
409
+ while (r !== 0) {
410
+ const q = Math.floor(oldR / r);
411
+ [oldR, r] = [r, oldR - q * r];
412
+ [oldS, s] = [s, oldS - q * s];
413
+ }
414
+ return oldR !== 1 ? NaN : mod(oldS);
415
+ };
416
+ return new Structure<number>({
417
+ criteria: [(x) => typeof x === "number"],
418
+ operations: [(a, b) => mod(a + b), (a, b) => mod(a * b)],
419
+ inverses: [(x) => mod(-x), modInverse],
420
+ identities: [0, 1],
421
+ equality: (a, b) => mod(a) === mod(b),
422
+ wrap: (x) => mod(Number(x)),
423
+ });
424
+ }
425
+
426
+ /** The Boolean ring GF(2): XOR is addition, AND is multiplication (elements 0/1). */
427
+ static booleanRing(): Structure<number> {
428
+ return Structure.integersModulo(2);
429
+ }
430
+
431
+ /** The field of exact rational numbers ({@link Rational}). */
432
+ static rationalField(): Structure<Rational> {
433
+ return new Structure<Rational>({
434
+ criteria: [(x) => x instanceof Rational],
435
+ operations: [(a, b) => a.add(b), (a, b) => a.multiply(b)],
436
+ inverses: [(x) => x.negate(), (x) => x.reciprocal()],
437
+ identities: [Rational.Zero, Rational.One],
438
+ equality: (a, b) => a.equals(b),
439
+ wrap: (x) => Rational.from(x as number),
440
+ });
441
+ }
442
+
443
+ /**
444
+ * The field of arbitrary-precision {@link Decimal}s. Division is approximate
445
+ * (rounded to `Decimal.DEFAULT_PRECISION` significant digits) — the one place
446
+ * this "field" isn't exact, matching `Decimal.divide` itself.
447
+ */
448
+ static decimalField(): Structure<Decimal> {
449
+ return new Structure<Decimal>({
450
+ criteria: [(x) => x instanceof Decimal],
451
+ operations: [(a, b) => a.add(b), (a, b) => a.multiply(b)],
452
+ inverses: [(x) => x.negate(), (x) => Decimal.One.divide(x)],
453
+ identities: [Decimal.Zero, Decimal.One],
454
+ equality: (a, b) => a.equals(b),
455
+ wrap: (x) => Decimal.from(x as number | string | bigint),
456
+ });
457
+ }
458
+
459
+ /** The (non-commutative) division ring of {@link Quaternion}s. */
460
+ static quaternionRing(): Structure<Quaternion> {
461
+ return new Structure<Quaternion>({
462
+ criteria: [(x) => x instanceof Quaternion],
463
+ operations: [(a, b) => a.add(b), (a, b) => a.multiply(b)],
464
+ inverses: [(x) => x.negate(), (x) => x.inverse()],
465
+ identities: [Quaternion.Zero, Quaternion.Identity],
466
+ equality: (a, b) => a.equals(b),
467
+ });
468
+ }
469
+
470
+ /** The commutative ring of {@link DualNumber}s (autodiff carrier). */
471
+ static dualNumbers(): Structure<DualNumber> {
472
+ return new Structure<DualNumber>({
473
+ criteria: [(x) => x instanceof DualNumber],
474
+ operations: [(a, b) => a.add(b), (a, b) => a.multiply(b)],
475
+ inverses: [(x) => x.negate(), (x) => new DualNumber(1, 0).divide(x)],
476
+ identities: [new DualNumber(0, 0), new DualNumber(1, 0)],
477
+ equality: (a, b) => a.value === b.value && a.deriv === b.deriv,
478
+ wrap: (x) => (x instanceof DualNumber ? x : DualNumber.constant(x as number)),
479
+ });
480
+ }
481
+ }