@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.
- package/README.md +165 -0
- package/dist/Bivector4.d.ts +52 -0
- package/dist/Bivector4.d.ts.map +1 -0
- package/dist/Bivector4.js +105 -0
- package/dist/Bivector4.js.map +1 -0
- package/dist/CellGraph.d.ts +259 -0
- package/dist/CellGraph.d.ts.map +1 -0
- package/dist/CellGraph.js +637 -0
- package/dist/CellGraph.js.map +1 -0
- package/dist/Clifford4Internal.d.ts +35 -0
- package/dist/Clifford4Internal.d.ts.map +1 -0
- package/dist/Clifford4Internal.js +86 -0
- package/dist/Clifford4Internal.js.map +1 -0
- package/dist/Combinatorics.d.ts +61 -0
- package/dist/Combinatorics.d.ts.map +1 -0
- package/dist/Combinatorics.js +186 -0
- package/dist/Combinatorics.js.map +1 -0
- package/dist/CombinatoricsGenerators.d.ts +44 -0
- package/dist/CombinatoricsGenerators.d.ts.map +1 -0
- package/dist/CombinatoricsGenerators.js +148 -0
- package/dist/CombinatoricsGenerators.js.map +1 -0
- package/dist/ComplexMath.d.ts +46 -0
- package/dist/ComplexMath.d.ts.map +1 -0
- package/dist/ComplexMath.js +98 -0
- package/dist/ComplexMath.js.map +1 -0
- package/dist/ComplexNumber.d.ts +174 -0
- package/dist/ComplexNumber.d.ts.map +1 -0
- package/dist/ComplexNumber.js +443 -0
- package/dist/ComplexNumber.js.map +1 -0
- package/dist/Cycle.d.ts +42 -0
- package/dist/Cycle.d.ts.map +1 -0
- package/dist/Cycle.js +120 -0
- package/dist/Cycle.js.map +1 -0
- package/dist/Decimal.d.ts +45 -0
- package/dist/Decimal.d.ts.map +1 -0
- package/dist/Decimal.js +135 -0
- package/dist/Decimal.js.map +1 -0
- package/dist/Distributions.d.ts +55 -0
- package/dist/Distributions.d.ts.map +1 -0
- package/dist/Distributions.js +222 -0
- package/dist/Distributions.js.map +1 -0
- package/dist/DualNumber.d.ts +42 -0
- package/dist/DualNumber.d.ts.map +1 -0
- package/dist/DualNumber.js +91 -0
- package/dist/DualNumber.js.map +1 -0
- package/dist/Environment.d.ts +44 -0
- package/dist/Environment.d.ts.map +1 -0
- package/dist/Environment.js +129 -0
- package/dist/Environment.js.map +1 -0
- package/dist/Expression.d.ts +19 -0
- package/dist/Expression.d.ts.map +1 -0
- package/dist/Expression.js +43 -0
- package/dist/Expression.js.map +1 -0
- package/dist/FFT.d.ts +21 -0
- package/dist/FFT.d.ts.map +1 -0
- package/dist/FFT.js +136 -0
- package/dist/FFT.js.map +1 -0
- package/dist/GeometricAlgebra4.d.ts +73 -0
- package/dist/GeometricAlgebra4.d.ts.map +1 -0
- package/dist/GeometricAlgebra4.js +115 -0
- package/dist/GeometricAlgebra4.js.map +1 -0
- package/dist/Geometry.d.ts +41 -0
- package/dist/Geometry.d.ts.map +1 -0
- package/dist/Geometry.js +167 -0
- package/dist/Geometry.js.map +1 -0
- package/dist/Graph.d.ts +72 -0
- package/dist/Graph.d.ts.map +1 -0
- package/dist/Graph.js +337 -0
- package/dist/Graph.js.map +1 -0
- package/dist/Graph3DUtils.d.ts +80 -0
- package/dist/Graph3DUtils.d.ts.map +1 -0
- package/dist/Graph3DUtils.js +156 -0
- package/dist/Graph3DUtils.js.map +1 -0
- package/dist/GraphUtils.d.ts +67 -0
- package/dist/GraphUtils.d.ts.map +1 -0
- package/dist/GraphUtils.js +72 -0
- package/dist/GraphUtils.js.map +1 -0
- package/dist/GroupTheory.d.ts +73 -0
- package/dist/GroupTheory.d.ts.map +1 -0
- package/dist/GroupTheory.js +194 -0
- package/dist/GroupTheory.js.map +1 -0
- package/dist/IntUtils.d.ts +33 -0
- package/dist/IntUtils.d.ts.map +1 -0
- package/dist/IntUtils.js +185 -0
- package/dist/IntUtils.js.map +1 -0
- package/dist/Interval.d.ts +44 -0
- package/dist/Interval.d.ts.map +1 -0
- package/dist/Interval.js +165 -0
- package/dist/Interval.js.map +1 -0
- package/dist/Lattice.d.ts +48 -0
- package/dist/Lattice.d.ts.map +1 -0
- package/dist/Lattice.js +65 -0
- package/dist/Lattice.js.map +1 -0
- package/dist/Logic.d.ts +22 -0
- package/dist/Logic.d.ts.map +1 -0
- package/dist/Logic.js +34 -0
- package/dist/Logic.js.map +1 -0
- package/dist/MatrixMath.d.ts +71 -0
- package/dist/MatrixMath.d.ts.map +1 -0
- package/dist/MatrixMath.js +302 -0
- package/dist/MatrixMath.js.map +1 -0
- package/dist/NumberTheory.d.ts +49 -0
- package/dist/NumberTheory.d.ts.map +1 -0
- package/dist/NumberTheory.js +230 -0
- package/dist/NumberTheory.js.map +1 -0
- package/dist/Numerical.d.ts +85 -0
- package/dist/Numerical.d.ts.map +1 -0
- package/dist/Numerical.js +343 -0
- package/dist/Numerical.js.map +1 -0
- package/dist/Permutation.d.ts +43 -0
- package/dist/Permutation.d.ts.map +1 -0
- package/dist/Permutation.js +142 -0
- package/dist/Permutation.js.map +1 -0
- package/dist/Polygon.d.ts +64 -0
- package/dist/Polygon.d.ts.map +1 -0
- package/dist/Polygon.js +221 -0
- package/dist/Polygon.js.map +1 -0
- package/dist/PolynomialRing.d.ts +74 -0
- package/dist/PolynomialRing.d.ts.map +1 -0
- package/dist/PolynomialRing.js +231 -0
- package/dist/PolynomialRing.js.map +1 -0
- package/dist/Quaternion.d.ts +37 -0
- package/dist/Quaternion.d.ts.map +1 -0
- package/dist/Quaternion.js +106 -0
- package/dist/Quaternion.js.map +1 -0
- package/dist/Rational.d.ts +34 -0
- package/dist/Rational.d.ts.map +1 -0
- package/dist/Rational.js +136 -0
- package/dist/Rational.js.map +1 -0
- package/dist/RealMath.d.ts +112 -0
- package/dist/RealMath.d.ts.map +1 -0
- package/dist/RealMath.js +262 -0
- package/dist/RealMath.js.map +1 -0
- package/dist/Rotor4.d.ts +180 -0
- package/dist/Rotor4.d.ts.map +1 -0
- package/dist/Rotor4.js +388 -0
- package/dist/Rotor4.js.map +1 -0
- package/dist/SpecialFunctions.d.ts +32 -0
- package/dist/SpecialFunctions.d.ts.map +1 -0
- package/dist/SpecialFunctions.js +161 -0
- package/dist/SpecialFunctions.js.map +1 -0
- package/dist/SpecialOperator.d.ts +21 -0
- package/dist/SpecialOperator.d.ts.map +1 -0
- package/dist/SpecialOperator.js +26 -0
- package/dist/SpecialOperator.js.map +1 -0
- package/dist/Statistics.d.ts +50 -0
- package/dist/Statistics.d.ts.map +1 -0
- package/dist/Statistics.js +131 -0
- package/dist/Statistics.js.map +1 -0
- package/dist/StringEvaluator.d.ts +48 -0
- package/dist/StringEvaluator.d.ts.map +1 -0
- package/dist/StringEvaluator.js +190 -0
- package/dist/StringEvaluator.js.map +1 -0
- package/dist/Structure.d.ts +130 -0
- package/dist/Structure.d.ts.map +1 -0
- package/dist/Structure.js +394 -0
- package/dist/Structure.js.map +1 -0
- package/dist/Symbolic.d.ts +501 -0
- package/dist/Symbolic.d.ts.map +1 -0
- package/dist/Symbolic.js +4077 -0
- package/dist/Symbolic.js.map +1 -0
- package/dist/Type.d.ts +31 -0
- package/dist/Type.d.ts.map +1 -0
- package/dist/Type.js +47 -0
- package/dist/Type.js.map +1 -0
- package/dist/Utilities.d.ts +27 -0
- package/dist/Utilities.d.ts.map +1 -0
- package/dist/Utilities.js +47 -0
- package/dist/Utilities.js.map +1 -0
- package/dist/Vec4.d.ts +39 -0
- package/dist/Vec4.d.ts.map +1 -0
- package/dist/Vec4.js +82 -0
- package/dist/Vec4.js.map +1 -0
- package/dist/Vector.d.ts +83 -0
- package/dist/Vector.d.ts.map +1 -0
- package/dist/Vector.js +173 -0
- package/dist/Vector.js.map +1 -0
- package/dist/VectorCalculus.d.ts +42 -0
- package/dist/VectorCalculus.d.ts.map +1 -0
- package/dist/VectorCalculus.js +82 -0
- package/dist/VectorCalculus.js.map +1 -0
- package/dist/VectorUtils.d.ts +172 -0
- package/dist/VectorUtils.d.ts.map +1 -0
- package/dist/VectorUtils.js +706 -0
- package/dist/VectorUtils.js.map +1 -0
- package/dist/differentiation-rules.d.ts +21 -0
- package/dist/differentiation-rules.d.ts.map +1 -0
- package/dist/differentiation-rules.js +52 -0
- package/dist/differentiation-rules.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -0
- package/src/Bivector4.ts +136 -0
- package/src/CellGraph.ts +669 -0
- package/src/Clifford4Internal.ts +90 -0
- package/src/Combinatorics.ts +183 -0
- package/src/CombinatoricsGenerators.ts +144 -0
- package/src/ComplexMath.ts +162 -0
- package/src/ComplexNumber.ts +491 -0
- package/src/Cycle.ts +126 -0
- package/src/Decimal.ts +145 -0
- package/src/Distributions.ts +269 -0
- package/src/DualNumber.ts +105 -0
- package/src/Environment.ts +127 -0
- package/src/Expression.ts +48 -0
- package/src/FFT.ts +146 -0
- package/src/GeometricAlgebra4.ts +157 -0
- package/src/Geometry.ts +173 -0
- package/src/Graph.ts +337 -0
- package/src/Graph3DUtils.ts +269 -0
- package/src/GraphUtils.ts +159 -0
- package/src/GroupTheory.ts +214 -0
- package/src/IntUtils.ts +200 -0
- package/src/Interval.ts +171 -0
- package/src/Lattice.ts +87 -0
- package/src/Logic.ts +38 -0
- package/src/MatrixMath.ts +326 -0
- package/src/NumberTheory.ts +228 -0
- package/src/Numerical.ts +390 -0
- package/src/Permutation.ts +148 -0
- package/src/Polygon.ts +229 -0
- package/src/PolynomialRing.ts +242 -0
- package/src/Quaternion.ts +125 -0
- package/src/Rational.ts +148 -0
- package/src/RealMath.ts +346 -0
- package/src/Rotor4.ts +440 -0
- package/src/SpecialFunctions.ts +152 -0
- package/src/SpecialOperator.ts +28 -0
- package/src/Statistics.ts +170 -0
- package/src/StringEvaluator.ts +208 -0
- package/src/Structure.ts +481 -0
- package/src/Symbolic.ts +4313 -0
- package/src/Type.ts +48 -0
- package/src/Utilities.ts +49 -0
- package/src/Vec4.ts +98 -0
- package/src/Vector.ts +189 -0
- package/src/VectorCalculus.ts +87 -0
- package/src/VectorUtils.ts +797 -0
- package/src/differentiation-rules.ts +73 -0
- package/src/index.ts +140 -0
package/src/Structure.ts
ADDED
|
@@ -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
|
+
}
|