ml-matrix 6.12.1 → 6.13.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/matrix.d.ts +22 -2
- package/matrix.js +315 -89
- package/matrix.js.map +1 -0
- package/matrix.umd.js +2 -1
- package/matrix.umd.js.map +1 -0
- package/package.json +17 -14
- package/src/dc/evd.js +35 -24
- package/src/dc/svd.js +66 -51
- package/src/dc/util.js +21 -0
- package/src/matrix.js +72 -0
package/matrix.js
CHANGED
|
@@ -2,8 +2,114 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
6
|
+
const toString = Object.prototype.toString;
|
|
7
|
+
/**
|
|
8
|
+
* Checks if an object is an instance of an Array (array or typed array, except those that contain bigint values).
|
|
9
|
+
* @param value - Object to check.
|
|
10
|
+
* @returns True if the object is an array or a typed array.
|
|
11
|
+
*/
|
|
12
|
+
function isAnyArray(value) {
|
|
13
|
+
const tag = toString.call(value);
|
|
14
|
+
return tag.endsWith('Array]') && !tag.includes('Big');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Computes the maximum of the given values.
|
|
19
|
+
*
|
|
20
|
+
* @param input
|
|
21
|
+
* @param options
|
|
22
|
+
*/
|
|
23
|
+
function max(input, options = {}) {
|
|
24
|
+
if (!isAnyArray(input)) {
|
|
25
|
+
throw new TypeError('input must be an array');
|
|
26
|
+
}
|
|
27
|
+
if (input.length === 0) {
|
|
28
|
+
throw new TypeError('input must not be empty');
|
|
29
|
+
}
|
|
30
|
+
const { fromIndex = 0, toIndex = input.length } = options;
|
|
31
|
+
if (fromIndex < 0 ||
|
|
32
|
+
fromIndex >= input.length ||
|
|
33
|
+
!Number.isInteger(fromIndex)) {
|
|
34
|
+
throw new Error('fromIndex must be a positive integer smaller than length');
|
|
35
|
+
}
|
|
36
|
+
if (toIndex <= fromIndex ||
|
|
37
|
+
toIndex > input.length ||
|
|
38
|
+
!Number.isInteger(toIndex)) {
|
|
39
|
+
throw new Error('toIndex must be an integer greater than fromIndex and at most equal to length');
|
|
40
|
+
}
|
|
41
|
+
let maxValue = input[fromIndex];
|
|
42
|
+
for (let i = fromIndex + 1; i < toIndex; i++) {
|
|
43
|
+
if (input[i] > maxValue)
|
|
44
|
+
maxValue = input[i];
|
|
45
|
+
}
|
|
46
|
+
return maxValue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Computes the minimum of the given values.
|
|
51
|
+
*/
|
|
52
|
+
function min(input, options = {}) {
|
|
53
|
+
if (!isAnyArray(input)) {
|
|
54
|
+
throw new TypeError('input must be an array');
|
|
55
|
+
}
|
|
56
|
+
if (input.length === 0) {
|
|
57
|
+
throw new TypeError('input must not be empty');
|
|
58
|
+
}
|
|
59
|
+
const { fromIndex = 0, toIndex = input.length } = options;
|
|
60
|
+
if (fromIndex < 0 ||
|
|
61
|
+
fromIndex >= input.length ||
|
|
62
|
+
!Number.isInteger(fromIndex)) {
|
|
63
|
+
throw new Error('fromIndex must be a positive integer smaller than length');
|
|
64
|
+
}
|
|
65
|
+
if (toIndex <= fromIndex ||
|
|
66
|
+
toIndex > input.length ||
|
|
67
|
+
!Number.isInteger(toIndex)) {
|
|
68
|
+
throw new Error('toIndex must be an integer greater than fromIndex and at most equal to length');
|
|
69
|
+
}
|
|
70
|
+
let minValue = input[fromIndex];
|
|
71
|
+
for (let i = fromIndex + 1; i < toIndex; i++) {
|
|
72
|
+
if (input[i] < minValue)
|
|
73
|
+
minValue = input[i];
|
|
74
|
+
}
|
|
75
|
+
return minValue;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Rescale an array into a range.
|
|
80
|
+
*/
|
|
81
|
+
function rescale(input, options = {}) {
|
|
82
|
+
if (!isAnyArray(input)) {
|
|
83
|
+
throw new TypeError('input must be an array');
|
|
84
|
+
}
|
|
85
|
+
else if (input.length === 0) {
|
|
86
|
+
throw new TypeError('input must not be empty');
|
|
87
|
+
}
|
|
88
|
+
let output;
|
|
89
|
+
if (options.output !== undefined) {
|
|
90
|
+
if (!isAnyArray(options.output)) {
|
|
91
|
+
throw new TypeError('output option must be an array if specified');
|
|
92
|
+
}
|
|
93
|
+
output = options.output;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
output = new Array(input.length);
|
|
97
|
+
}
|
|
98
|
+
const currentMin = min(input);
|
|
99
|
+
const currentMax = max(input);
|
|
100
|
+
if (currentMin === currentMax) {
|
|
101
|
+
throw new RangeError('minimum and maximum input values are equal. Cannot rescale a constant array');
|
|
102
|
+
}
|
|
103
|
+
const { min: minValue = options.autoMinMax ? currentMin : 0, max: maxValue = options.autoMinMax ? currentMax : 1, } = options;
|
|
104
|
+
if (minValue >= maxValue) {
|
|
105
|
+
throw new RangeError('min option must be smaller than max option');
|
|
106
|
+
}
|
|
107
|
+
const factor = (maxValue - minValue) / (currentMax - currentMin);
|
|
108
|
+
for (let i = 0; i < input.length; i++) {
|
|
109
|
+
output[i] = (input[i] - currentMin) * factor + minValue;
|
|
110
|
+
}
|
|
111
|
+
return output;
|
|
112
|
+
}
|
|
7
113
|
|
|
8
114
|
const indent = ' '.repeat(2);
|
|
9
115
|
const indentData = ' '.repeat(4);
|
|
@@ -992,7 +1098,7 @@ function checkColumnVector(matrix, vector) {
|
|
|
992
1098
|
}
|
|
993
1099
|
|
|
994
1100
|
function checkRowIndices(matrix, rowIndices) {
|
|
995
|
-
if (!isAnyArray
|
|
1101
|
+
if (!isAnyArray(rowIndices)) {
|
|
996
1102
|
throw new TypeError('row indices must be an array');
|
|
997
1103
|
}
|
|
998
1104
|
|
|
@@ -1004,7 +1110,7 @@ function checkRowIndices(matrix, rowIndices) {
|
|
|
1004
1110
|
}
|
|
1005
1111
|
|
|
1006
1112
|
function checkColumnIndices(matrix, columnIndices) {
|
|
1007
|
-
if (!isAnyArray
|
|
1113
|
+
if (!isAnyArray(columnIndices)) {
|
|
1008
1114
|
throw new TypeError('column indices must be an array');
|
|
1009
1115
|
}
|
|
1010
1116
|
|
|
@@ -2110,6 +2216,78 @@ class AbstractMatrix {
|
|
|
2110
2216
|
return result;
|
|
2111
2217
|
}
|
|
2112
2218
|
|
|
2219
|
+
gram() {
|
|
2220
|
+
const rows = this.rows;
|
|
2221
|
+
const n = this.columns;
|
|
2222
|
+
|
|
2223
|
+
// The Gram matrix `thisᵀ · this` is symmetric, so only its upper triangle is
|
|
2224
|
+
// accumulated (then mirrored) and the transpose is never materialized.
|
|
2225
|
+
// Row-streaming rank-1 updates read each row of `this` contiguously and skip
|
|
2226
|
+
// zero entries, so the cost scales with the number of non-zeros: it is as
|
|
2227
|
+
// fast as the dense version on dense matrices (the skip never fires) and far
|
|
2228
|
+
// faster on sparse ones.
|
|
2229
|
+
const gramData = new Float64Array(n * n);
|
|
2230
|
+
for (let r = 0; r < rows; r++) {
|
|
2231
|
+
for (let i = 0; i < n; i++) {
|
|
2232
|
+
const value = this.get(r, i);
|
|
2233
|
+
if (value === 0) continue;
|
|
2234
|
+
const offset = i * n;
|
|
2235
|
+
for (let j = i; j < n; j++) {
|
|
2236
|
+
gramData[offset + j] += value * this.get(r, j);
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
const result = new Matrix(n, n);
|
|
2242
|
+
for (let i = 0; i < n; i++) {
|
|
2243
|
+
const offset = i * n;
|
|
2244
|
+
for (let j = i; j < n; j++) {
|
|
2245
|
+
const value = gramData[offset + j];
|
|
2246
|
+
result.set(i, j, value);
|
|
2247
|
+
result.set(j, i, value);
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
return result;
|
|
2251
|
+
}
|
|
2252
|
+
|
|
2253
|
+
mmulByTranspose(scale) {
|
|
2254
|
+
let m = this.rows;
|
|
2255
|
+
let n = this.columns;
|
|
2256
|
+
|
|
2257
|
+
if (scale !== undefined && scale.length !== n) {
|
|
2258
|
+
throw new RangeError('scale must have one value per column');
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
let result = new Matrix(m, m);
|
|
2262
|
+
|
|
2263
|
+
// result = this · diag(scale) · thisᵀ is symmetric, so only the upper
|
|
2264
|
+
// triangle is computed and mirrored, and the transpose is never
|
|
2265
|
+
// materialized. `scale` (one factor per column) is folded into one operand.
|
|
2266
|
+
let rowj = new Float64Array(n);
|
|
2267
|
+
for (let j = 0; j < m; j++) {
|
|
2268
|
+
if (scale === undefined) {
|
|
2269
|
+
for (let k = 0; k < n; k++) {
|
|
2270
|
+
rowj[k] = this.get(j, k);
|
|
2271
|
+
}
|
|
2272
|
+
} else {
|
|
2273
|
+
for (let k = 0; k < n; k++) {
|
|
2274
|
+
rowj[k] = scale[k] * this.get(j, k);
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2278
|
+
for (let i = j; i < m; i++) {
|
|
2279
|
+
let s = 0;
|
|
2280
|
+
for (let k = 0; k < n; k++) {
|
|
2281
|
+
s += this.get(i, k) * rowj[k];
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
result.set(i, j, s);
|
|
2285
|
+
result.set(j, i, s);
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
return result;
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2113
2291
|
mpow(scalar) {
|
|
2114
2292
|
if (!this.isSquare()) {
|
|
2115
2293
|
throw new RangeError('Matrix must be square');
|
|
@@ -2659,13 +2837,13 @@ class AbstractMatrix {
|
|
|
2659
2837
|
}
|
|
2660
2838
|
switch (by) {
|
|
2661
2839
|
case 'row': {
|
|
2662
|
-
if (!isAnyArray
|
|
2840
|
+
if (!isAnyArray(mean)) {
|
|
2663
2841
|
throw new TypeError('mean must be an array');
|
|
2664
2842
|
}
|
|
2665
2843
|
return varianceByRow(this, unbiased, mean);
|
|
2666
2844
|
}
|
|
2667
2845
|
case 'column': {
|
|
2668
|
-
if (!isAnyArray
|
|
2846
|
+
if (!isAnyArray(mean)) {
|
|
2669
2847
|
throw new TypeError('mean must be an array');
|
|
2670
2848
|
}
|
|
2671
2849
|
return varianceByColumn(this, unbiased, mean);
|
|
@@ -2708,14 +2886,14 @@ class AbstractMatrix {
|
|
|
2708
2886
|
const { center = this.mean(by) } = options;
|
|
2709
2887
|
switch (by) {
|
|
2710
2888
|
case 'row': {
|
|
2711
|
-
if (!isAnyArray
|
|
2889
|
+
if (!isAnyArray(center)) {
|
|
2712
2890
|
throw new TypeError('center must be an array');
|
|
2713
2891
|
}
|
|
2714
2892
|
centerByRow(this, center);
|
|
2715
2893
|
return this;
|
|
2716
2894
|
}
|
|
2717
2895
|
case 'column': {
|
|
2718
|
-
if (!isAnyArray
|
|
2896
|
+
if (!isAnyArray(center)) {
|
|
2719
2897
|
throw new TypeError('center must be an array');
|
|
2720
2898
|
}
|
|
2721
2899
|
centerByColumn(this, center);
|
|
@@ -2746,7 +2924,7 @@ class AbstractMatrix {
|
|
|
2746
2924
|
case 'row': {
|
|
2747
2925
|
if (scale === undefined) {
|
|
2748
2926
|
scale = getScaleByRow(this);
|
|
2749
|
-
} else if (!isAnyArray
|
|
2927
|
+
} else if (!isAnyArray(scale)) {
|
|
2750
2928
|
throw new TypeError('scale must be an array');
|
|
2751
2929
|
}
|
|
2752
2930
|
scaleByRow(this, scale);
|
|
@@ -2755,7 +2933,7 @@ class AbstractMatrix {
|
|
|
2755
2933
|
case 'column': {
|
|
2756
2934
|
if (scale === undefined) {
|
|
2757
2935
|
scale = getScaleByColumn(this);
|
|
2758
|
-
} else if (!isAnyArray
|
|
2936
|
+
} else if (!isAnyArray(scale)) {
|
|
2759
2937
|
throw new TypeError('scale must be an array');
|
|
2760
2938
|
}
|
|
2761
2939
|
scaleByColumn(this, scale);
|
|
@@ -2869,7 +3047,7 @@ class Matrix extends AbstractMatrix {
|
|
|
2869
3047
|
Matrix.copy(nRows, this);
|
|
2870
3048
|
} else if (Number.isInteger(nRows) && nRows >= 0) {
|
|
2871
3049
|
this.#initData(nRows, nColumns);
|
|
2872
|
-
} else if (isAnyArray
|
|
3050
|
+
} else if (isAnyArray(nRows)) {
|
|
2873
3051
|
// Copy the values from the 2D array
|
|
2874
3052
|
const arrayData = nRows;
|
|
2875
3053
|
nRows = arrayData.length;
|
|
@@ -3565,8 +3743,8 @@ class WrapperMatrix2D extends AbstractMatrix {
|
|
|
3565
3743
|
}
|
|
3566
3744
|
|
|
3567
3745
|
function wrap(array, options) {
|
|
3568
|
-
if (isAnyArray
|
|
3569
|
-
if (array[0] && isAnyArray
|
|
3746
|
+
if (isAnyArray(array)) {
|
|
3747
|
+
if (array[0] && isAnyArray(array[0])) {
|
|
3570
3748
|
return new WrapperMatrix2D(array);
|
|
3571
3749
|
} else {
|
|
3572
3750
|
return new WrapperMatrix1D(array, options);
|
|
@@ -3745,6 +3923,27 @@ class LuDecomposition {
|
|
|
3745
3923
|
}
|
|
3746
3924
|
}
|
|
3747
3925
|
|
|
3926
|
+
/**
|
|
3927
|
+
* Transpose a square matrix in place, without allocating a copy.
|
|
3928
|
+
* Used to restore the logical layout of decomposition outputs that were
|
|
3929
|
+
* accumulated in transposed storage for cache-sequential inner loops.
|
|
3930
|
+
* @param {import('../matrix').default} matrix - square matrix, mutated in place
|
|
3931
|
+
* @returns {import('../matrix').default} the same matrix
|
|
3932
|
+
*/
|
|
3933
|
+
function transposeSquareInPlace(matrix) {
|
|
3934
|
+
const data = matrix.data;
|
|
3935
|
+
const n = matrix.rows;
|
|
3936
|
+
for (let i = 0; i < n; i++) {
|
|
3937
|
+
const rowI = data[i];
|
|
3938
|
+
for (let j = i + 1; j < n; j++) {
|
|
3939
|
+
const tmp = rowI[j];
|
|
3940
|
+
rowI[j] = data[j][i];
|
|
3941
|
+
data[j][i] = tmp;
|
|
3942
|
+
}
|
|
3943
|
+
}
|
|
3944
|
+
return matrix;
|
|
3945
|
+
}
|
|
3946
|
+
|
|
3748
3947
|
function hypotenuse(a, b) {
|
|
3749
3948
|
let r = 0;
|
|
3750
3949
|
if (Math.abs(a) > Math.abs(b)) {
|
|
@@ -3923,32 +4122,40 @@ class SingularValueDecomposition {
|
|
|
3923
4122
|
let wantu = Boolean(computeLeftSingularVectors);
|
|
3924
4123
|
let wantv = Boolean(computeRightSingularVectors);
|
|
3925
4124
|
|
|
4125
|
+
// Work on the transpose of the input so the hot inner loops (which iterate
|
|
4126
|
+
// over rows for a fixed column) scan memory sequentially in the row-major
|
|
4127
|
+
// backing store. `at` holds the transpose: at.get(j, i) === a.get(i, j)
|
|
4128
|
+
// where `a` is the logical m x n working matrix.
|
|
3926
4129
|
let swapped = false;
|
|
3927
|
-
let
|
|
4130
|
+
let at;
|
|
3928
4131
|
if (m < n) {
|
|
3929
4132
|
if (!autoTranspose) {
|
|
3930
|
-
a = value.clone();
|
|
3931
4133
|
// eslint-disable-next-line no-console
|
|
3932
4134
|
console.warn(
|
|
3933
4135
|
'Computing SVD on a matrix with more columns than rows. Consider enabling autoTranspose',
|
|
3934
4136
|
);
|
|
4137
|
+
at = value.transpose();
|
|
3935
4138
|
} else {
|
|
3936
|
-
|
|
3937
|
-
m =
|
|
3938
|
-
n =
|
|
4139
|
+
at = value.clone();
|
|
4140
|
+
m = value.columns;
|
|
4141
|
+
n = value.rows;
|
|
3939
4142
|
swapped = true;
|
|
3940
4143
|
let aux = wantu;
|
|
3941
4144
|
wantu = wantv;
|
|
3942
4145
|
wantv = aux;
|
|
3943
4146
|
}
|
|
3944
4147
|
} else {
|
|
3945
|
-
|
|
4148
|
+
at = value.transpose();
|
|
3946
4149
|
}
|
|
3947
4150
|
|
|
3948
4151
|
let nu = Math.min(m, n);
|
|
3949
4152
|
let ni = Math.min(m + 1, n);
|
|
3950
4153
|
let s = new Float64Array(ni);
|
|
3951
|
-
|
|
4154
|
+
// U and V are stored transposed during the computation so the inner loops
|
|
4155
|
+
// (which always vary the row index) scan memory sequentially. They are
|
|
4156
|
+
// transposed back to their logical layout before being returned.
|
|
4157
|
+
// Ut.get(j, i) === U.get(i, j) and Vt.get(j, i) === V.get(i, j).
|
|
4158
|
+
let U = new Matrix(nu, m);
|
|
3952
4159
|
let V = new Matrix(n, n);
|
|
3953
4160
|
|
|
3954
4161
|
let e = new Float64Array(n);
|
|
@@ -3965,16 +4172,16 @@ class SingularValueDecomposition {
|
|
|
3965
4172
|
if (k < nct) {
|
|
3966
4173
|
s[k] = 0;
|
|
3967
4174
|
for (let i = k; i < m; i++) {
|
|
3968
|
-
s[k] = hypotenuse(s[k],
|
|
4175
|
+
s[k] = hypotenuse(s[k], at.get(k, i));
|
|
3969
4176
|
}
|
|
3970
4177
|
if (s[k] !== 0) {
|
|
3971
|
-
if (
|
|
4178
|
+
if (at.get(k, k) < 0) {
|
|
3972
4179
|
s[k] = -s[k];
|
|
3973
4180
|
}
|
|
3974
4181
|
for (let i = k; i < m; i++) {
|
|
3975
|
-
|
|
4182
|
+
at.set(k, i, at.get(k, i) / s[k]);
|
|
3976
4183
|
}
|
|
3977
|
-
|
|
4184
|
+
at.set(k, k, at.get(k, k) + 1);
|
|
3978
4185
|
}
|
|
3979
4186
|
s[k] = -s[k];
|
|
3980
4187
|
}
|
|
@@ -3983,19 +4190,19 @@ class SingularValueDecomposition {
|
|
|
3983
4190
|
if (k < nct && s[k] !== 0) {
|
|
3984
4191
|
let t = 0;
|
|
3985
4192
|
for (let i = k; i < m; i++) {
|
|
3986
|
-
t +=
|
|
4193
|
+
t += at.get(k, i) * at.get(j, i);
|
|
3987
4194
|
}
|
|
3988
|
-
t = -t /
|
|
4195
|
+
t = -t / at.get(k, k);
|
|
3989
4196
|
for (let i = k; i < m; i++) {
|
|
3990
|
-
|
|
4197
|
+
at.set(j, i, at.get(j, i) + t * at.get(k, i));
|
|
3991
4198
|
}
|
|
3992
4199
|
}
|
|
3993
|
-
e[j] =
|
|
4200
|
+
e[j] = at.get(j, k);
|
|
3994
4201
|
}
|
|
3995
4202
|
|
|
3996
4203
|
if (wantu && k < nct) {
|
|
3997
4204
|
for (let i = k; i < m; i++) {
|
|
3998
|
-
U.set(
|
|
4205
|
+
U.set(k, i, at.get(k, i));
|
|
3999
4206
|
}
|
|
4000
4207
|
}
|
|
4001
4208
|
|
|
@@ -4020,19 +4227,19 @@ class SingularValueDecomposition {
|
|
|
4020
4227
|
}
|
|
4021
4228
|
for (let i = k + 1; i < m; i++) {
|
|
4022
4229
|
for (let j = k + 1; j < n; j++) {
|
|
4023
|
-
work[i] += e[j] *
|
|
4230
|
+
work[i] += e[j] * at.get(j, i);
|
|
4024
4231
|
}
|
|
4025
4232
|
}
|
|
4026
4233
|
for (let j = k + 1; j < n; j++) {
|
|
4027
4234
|
let t = -e[j] / e[k + 1];
|
|
4028
4235
|
for (let i = k + 1; i < m; i++) {
|
|
4029
|
-
|
|
4236
|
+
at.set(j, i, at.get(j, i) + t * work[i]);
|
|
4030
4237
|
}
|
|
4031
4238
|
}
|
|
4032
4239
|
}
|
|
4033
4240
|
if (wantv) {
|
|
4034
4241
|
for (let i = k + 1; i < n; i++) {
|
|
4035
|
-
V.set(
|
|
4242
|
+
V.set(k, i, e[i]);
|
|
4036
4243
|
}
|
|
4037
4244
|
}
|
|
4038
4245
|
}
|
|
@@ -4040,20 +4247,20 @@ class SingularValueDecomposition {
|
|
|
4040
4247
|
|
|
4041
4248
|
let p = Math.min(n, m + 1);
|
|
4042
4249
|
if (nct < n) {
|
|
4043
|
-
s[nct] =
|
|
4250
|
+
s[nct] = at.get(nct, nct);
|
|
4044
4251
|
}
|
|
4045
4252
|
if (m < p) {
|
|
4046
4253
|
s[p - 1] = 0;
|
|
4047
4254
|
}
|
|
4048
4255
|
if (nrt + 1 < p) {
|
|
4049
|
-
e[nrt] =
|
|
4256
|
+
e[nrt] = at.get(p - 1, nrt);
|
|
4050
4257
|
}
|
|
4051
4258
|
e[p - 1] = 0;
|
|
4052
4259
|
|
|
4053
4260
|
if (wantu) {
|
|
4054
4261
|
for (let j = nct; j < nu; j++) {
|
|
4055
4262
|
for (let i = 0; i < m; i++) {
|
|
4056
|
-
U.set(
|
|
4263
|
+
U.set(j, i, 0);
|
|
4057
4264
|
}
|
|
4058
4265
|
U.set(j, j, 1);
|
|
4059
4266
|
}
|
|
@@ -4062,23 +4269,23 @@ class SingularValueDecomposition {
|
|
|
4062
4269
|
for (let j = k + 1; j < nu; j++) {
|
|
4063
4270
|
let t = 0;
|
|
4064
4271
|
for (let i = k; i < m; i++) {
|
|
4065
|
-
t += U.get(
|
|
4272
|
+
t += U.get(k, i) * U.get(j, i);
|
|
4066
4273
|
}
|
|
4067
4274
|
t = -t / U.get(k, k);
|
|
4068
4275
|
for (let i = k; i < m; i++) {
|
|
4069
|
-
U.set(
|
|
4276
|
+
U.set(j, i, U.get(j, i) + t * U.get(k, i));
|
|
4070
4277
|
}
|
|
4071
4278
|
}
|
|
4072
4279
|
for (let i = k; i < m; i++) {
|
|
4073
|
-
U.set(
|
|
4280
|
+
U.set(k, i, -U.get(k, i));
|
|
4074
4281
|
}
|
|
4075
4282
|
U.set(k, k, 1 + U.get(k, k));
|
|
4076
4283
|
for (let i = 0; i < k - 1; i++) {
|
|
4077
|
-
U.set(
|
|
4284
|
+
U.set(k, i, 0);
|
|
4078
4285
|
}
|
|
4079
4286
|
} else {
|
|
4080
4287
|
for (let i = 0; i < m; i++) {
|
|
4081
|
-
U.set(
|
|
4288
|
+
U.set(k, i, 0);
|
|
4082
4289
|
}
|
|
4083
4290
|
U.set(k, k, 1);
|
|
4084
4291
|
}
|
|
@@ -4091,16 +4298,16 @@ class SingularValueDecomposition {
|
|
|
4091
4298
|
for (let j = k + 1; j < n; j++) {
|
|
4092
4299
|
let t = 0;
|
|
4093
4300
|
for (let i = k + 1; i < n; i++) {
|
|
4094
|
-
t += V.get(
|
|
4301
|
+
t += V.get(k, i) * V.get(j, i);
|
|
4095
4302
|
}
|
|
4096
|
-
t = -t / V.get(k + 1
|
|
4303
|
+
t = -t / V.get(k, k + 1);
|
|
4097
4304
|
for (let i = k + 1; i < n; i++) {
|
|
4098
|
-
V.set(
|
|
4305
|
+
V.set(j, i, V.get(j, i) + t * V.get(k, i));
|
|
4099
4306
|
}
|
|
4100
4307
|
}
|
|
4101
4308
|
}
|
|
4102
4309
|
for (let i = 0; i < n; i++) {
|
|
4103
|
-
V.set(
|
|
4310
|
+
V.set(k, i, 0);
|
|
4104
4311
|
}
|
|
4105
4312
|
V.set(k, k, 1);
|
|
4106
4313
|
}
|
|
@@ -4164,9 +4371,9 @@ class SingularValueDecomposition {
|
|
|
4164
4371
|
}
|
|
4165
4372
|
if (wantv) {
|
|
4166
4373
|
for (let i = 0; i < n; i++) {
|
|
4167
|
-
t = cs * V.get(
|
|
4168
|
-
V.set(
|
|
4169
|
-
V.set(
|
|
4374
|
+
t = cs * V.get(j, i) + sn * V.get(p - 1, i);
|
|
4375
|
+
V.set(p - 1, i, -sn * V.get(j, i) + cs * V.get(p - 1, i));
|
|
4376
|
+
V.set(j, i, t);
|
|
4170
4377
|
}
|
|
4171
4378
|
}
|
|
4172
4379
|
}
|
|
@@ -4184,9 +4391,9 @@ class SingularValueDecomposition {
|
|
|
4184
4391
|
e[j] = cs * e[j];
|
|
4185
4392
|
if (wantu) {
|
|
4186
4393
|
for (let i = 0; i < m; i++) {
|
|
4187
|
-
t = cs * U.get(
|
|
4188
|
-
U.set(
|
|
4189
|
-
U.set(
|
|
4394
|
+
t = cs * U.get(j, i) + sn * U.get(k - 1, i);
|
|
4395
|
+
U.set(k - 1, i, -sn * U.get(j, i) + cs * U.get(k - 1, i));
|
|
4396
|
+
U.set(j, i, t);
|
|
4190
4397
|
}
|
|
4191
4398
|
}
|
|
4192
4399
|
}
|
|
@@ -4232,9 +4439,9 @@ class SingularValueDecomposition {
|
|
|
4232
4439
|
s[j + 1] = cs * s[j + 1];
|
|
4233
4440
|
if (wantv) {
|
|
4234
4441
|
for (let i = 0; i < n; i++) {
|
|
4235
|
-
t = cs * V.get(
|
|
4236
|
-
V.set(
|
|
4237
|
-
V.set(
|
|
4442
|
+
t = cs * V.get(j, i) + sn * V.get(j + 1, i);
|
|
4443
|
+
V.set(j + 1, i, -sn * V.get(j, i) + cs * V.get(j + 1, i));
|
|
4444
|
+
V.set(j, i, t);
|
|
4238
4445
|
}
|
|
4239
4446
|
}
|
|
4240
4447
|
t = hypotenuse(f, g);
|
|
@@ -4248,9 +4455,9 @@ class SingularValueDecomposition {
|
|
|
4248
4455
|
e[j + 1] = cs * e[j + 1];
|
|
4249
4456
|
if (wantu && j < m - 1) {
|
|
4250
4457
|
for (let i = 0; i < m; i++) {
|
|
4251
|
-
t = cs * U.get(
|
|
4252
|
-
U.set(
|
|
4253
|
-
U.set(
|
|
4458
|
+
t = cs * U.get(j, i) + sn * U.get(j + 1, i);
|
|
4459
|
+
U.set(j + 1, i, -sn * U.get(j, i) + cs * U.get(j + 1, i));
|
|
4460
|
+
U.set(j, i, t);
|
|
4254
4461
|
}
|
|
4255
4462
|
}
|
|
4256
4463
|
}
|
|
@@ -4262,7 +4469,7 @@ class SingularValueDecomposition {
|
|
|
4262
4469
|
s[k] = s[k] < 0 ? -s[k] : 0;
|
|
4263
4470
|
if (wantv) {
|
|
4264
4471
|
for (let i = 0; i <= pp; i++) {
|
|
4265
|
-
V.set(
|
|
4472
|
+
V.set(k, i, -V.get(k, i));
|
|
4266
4473
|
}
|
|
4267
4474
|
}
|
|
4268
4475
|
}
|
|
@@ -4275,16 +4482,16 @@ class SingularValueDecomposition {
|
|
|
4275
4482
|
s[k + 1] = t;
|
|
4276
4483
|
if (wantv && k < n - 1) {
|
|
4277
4484
|
for (let i = 0; i < n; i++) {
|
|
4278
|
-
t = V.get(
|
|
4279
|
-
V.set(
|
|
4280
|
-
V.set(
|
|
4485
|
+
t = V.get(k + 1, i);
|
|
4486
|
+
V.set(k + 1, i, V.get(k, i));
|
|
4487
|
+
V.set(k, i, t);
|
|
4281
4488
|
}
|
|
4282
4489
|
}
|
|
4283
4490
|
if (wantu && k < m - 1) {
|
|
4284
4491
|
for (let i = 0; i < m; i++) {
|
|
4285
|
-
t = U.get(
|
|
4286
|
-
U.set(
|
|
4287
|
-
U.set(
|
|
4492
|
+
t = U.get(k + 1, i);
|
|
4493
|
+
U.set(k + 1, i, U.get(k, i));
|
|
4494
|
+
U.set(k, i, t);
|
|
4288
4495
|
}
|
|
4289
4496
|
}
|
|
4290
4497
|
k++;
|
|
@@ -4296,6 +4503,13 @@ class SingularValueDecomposition {
|
|
|
4296
4503
|
}
|
|
4297
4504
|
}
|
|
4298
4505
|
|
|
4506
|
+
// Restore the logical (row-major) layout of the singular vectors, which were
|
|
4507
|
+
// accumulated in transposed storage for cache-sequential inner loops. V is
|
|
4508
|
+
// always square and U is square whenever the input is, so this is done in
|
|
4509
|
+
// place (no allocation) in the common case.
|
|
4510
|
+
U = U.isSquare() ? transposeSquareInPlace(U) : U.transpose();
|
|
4511
|
+
V = transposeSquareInPlace(V);
|
|
4512
|
+
|
|
4299
4513
|
if (swapped) {
|
|
4300
4514
|
let tmp = V;
|
|
4301
4515
|
V = U;
|
|
@@ -4566,7 +4780,7 @@ function covariance(xMatrix, yMatrix = xMatrix, options = {}) {
|
|
|
4566
4780
|
if (
|
|
4567
4781
|
typeof yMatrix === 'object' &&
|
|
4568
4782
|
!Matrix.isMatrix(yMatrix) &&
|
|
4569
|
-
!isAnyArray
|
|
4783
|
+
!isAnyArray(yMatrix)
|
|
4570
4784
|
) {
|
|
4571
4785
|
options = yMatrix;
|
|
4572
4786
|
yMatrix = xMatrix;
|
|
@@ -4599,7 +4813,7 @@ function correlation(xMatrix, yMatrix = xMatrix, options = {}) {
|
|
|
4599
4813
|
if (
|
|
4600
4814
|
typeof yMatrix === 'object' &&
|
|
4601
4815
|
!Matrix.isMatrix(yMatrix) &&
|
|
4602
|
-
!isAnyArray
|
|
4816
|
+
!isAnyArray(yMatrix)
|
|
4603
4817
|
) {
|
|
4604
4818
|
options = yMatrix;
|
|
4605
4819
|
yMatrix = xMatrix;
|
|
@@ -4671,14 +4885,25 @@ class EigenvalueDecomposition {
|
|
|
4671
4885
|
}
|
|
4672
4886
|
|
|
4673
4887
|
if (isSymmetric) {
|
|
4888
|
+
// tred2/tql2 access V almost exclusively down columns (the row index
|
|
4889
|
+
// varies in the hot loops). Storing V transposed turns those into
|
|
4890
|
+
// sequential row scans of the row-major backing store; we transpose it
|
|
4891
|
+
// back to the logical layout before returning. V.get(j, i) holds the
|
|
4892
|
+
// logical V(i, j).
|
|
4674
4893
|
for (i = 0; i < n; i++) {
|
|
4675
4894
|
for (j = 0; j < n; j++) {
|
|
4676
|
-
V.set(
|
|
4895
|
+
V.set(j, i, value.get(i, j));
|
|
4677
4896
|
}
|
|
4678
4897
|
}
|
|
4679
4898
|
tred2(n, e, d, V);
|
|
4680
4899
|
tql2(n, e, d, V);
|
|
4900
|
+
// V is square; restore the logical layout in place (no allocation).
|
|
4901
|
+
transposeSquareInPlace(V);
|
|
4681
4902
|
} else {
|
|
4903
|
+
// The non-symmetric path (orthes/hqr2) has two O(n^3) phases with opposite
|
|
4904
|
+
// memory-layout preferences (the QR sweep favours column-major eigenvectors
|
|
4905
|
+
// while the back-transform favours row-major), so a single transposed
|
|
4906
|
+
// storage cannot help both. It is left in the original row-major layout.
|
|
4682
4907
|
let H = new Matrix(n, n);
|
|
4683
4908
|
let ort = new Float64Array(n);
|
|
4684
4909
|
for (j = 0; j < n; j++) {
|
|
@@ -4733,7 +4958,7 @@ function tred2(n, e, d, V) {
|
|
|
4733
4958
|
let f, g, h, i, j, k, hh, scale;
|
|
4734
4959
|
|
|
4735
4960
|
for (j = 0; j < n; j++) {
|
|
4736
|
-
d[j] = V.get(n - 1
|
|
4961
|
+
d[j] = V.get(j, n - 1);
|
|
4737
4962
|
}
|
|
4738
4963
|
|
|
4739
4964
|
for (i = n - 1; i > 0; i--) {
|
|
@@ -4746,9 +4971,9 @@ function tred2(n, e, d, V) {
|
|
|
4746
4971
|
if (scale === 0) {
|
|
4747
4972
|
e[i] = d[i - 1];
|
|
4748
4973
|
for (j = 0; j < i; j++) {
|
|
4749
|
-
d[j] = V.get(i - 1
|
|
4750
|
-
V.set(i, j, 0);
|
|
4974
|
+
d[j] = V.get(j, i - 1);
|
|
4751
4975
|
V.set(j, i, 0);
|
|
4976
|
+
V.set(i, j, 0);
|
|
4752
4977
|
}
|
|
4753
4978
|
} else {
|
|
4754
4979
|
for (k = 0; k < i; k++) {
|
|
@@ -4771,11 +4996,11 @@ function tred2(n, e, d, V) {
|
|
|
4771
4996
|
|
|
4772
4997
|
for (j = 0; j < i; j++) {
|
|
4773
4998
|
f = d[j];
|
|
4774
|
-
V.set(
|
|
4999
|
+
V.set(i, j, f);
|
|
4775
5000
|
g = e[j] + V.get(j, j) * f;
|
|
4776
5001
|
for (k = j + 1; k <= i - 1; k++) {
|
|
4777
|
-
g += V.get(
|
|
4778
|
-
e[k] += V.get(
|
|
5002
|
+
g += V.get(j, k) * d[k];
|
|
5003
|
+
e[k] += V.get(j, k) * f;
|
|
4779
5004
|
}
|
|
4780
5005
|
e[j] = g;
|
|
4781
5006
|
}
|
|
@@ -4795,43 +5020,43 @@ function tred2(n, e, d, V) {
|
|
|
4795
5020
|
f = d[j];
|
|
4796
5021
|
g = e[j];
|
|
4797
5022
|
for (k = j; k <= i - 1; k++) {
|
|
4798
|
-
V.set(
|
|
5023
|
+
V.set(j, k, V.get(j, k) - (f * e[k] + g * d[k]));
|
|
4799
5024
|
}
|
|
4800
|
-
d[j] = V.get(i - 1
|
|
4801
|
-
V.set(
|
|
5025
|
+
d[j] = V.get(j, i - 1);
|
|
5026
|
+
V.set(j, i, 0);
|
|
4802
5027
|
}
|
|
4803
5028
|
}
|
|
4804
5029
|
d[i] = h;
|
|
4805
5030
|
}
|
|
4806
5031
|
|
|
4807
5032
|
for (i = 0; i < n - 1; i++) {
|
|
4808
|
-
V.set(n - 1,
|
|
5033
|
+
V.set(i, n - 1, V.get(i, i));
|
|
4809
5034
|
V.set(i, i, 1);
|
|
4810
5035
|
h = d[i + 1];
|
|
4811
5036
|
if (h !== 0) {
|
|
4812
5037
|
for (k = 0; k <= i; k++) {
|
|
4813
|
-
d[k] = V.get(
|
|
5038
|
+
d[k] = V.get(i + 1, k) / h;
|
|
4814
5039
|
}
|
|
4815
5040
|
|
|
4816
5041
|
for (j = 0; j <= i; j++) {
|
|
4817
5042
|
g = 0;
|
|
4818
5043
|
for (k = 0; k <= i; k++) {
|
|
4819
|
-
g += V.get(
|
|
5044
|
+
g += V.get(i + 1, k) * V.get(j, k);
|
|
4820
5045
|
}
|
|
4821
5046
|
for (k = 0; k <= i; k++) {
|
|
4822
|
-
V.set(
|
|
5047
|
+
V.set(j, k, V.get(j, k) - g * d[k]);
|
|
4823
5048
|
}
|
|
4824
5049
|
}
|
|
4825
5050
|
}
|
|
4826
5051
|
|
|
4827
5052
|
for (k = 0; k <= i; k++) {
|
|
4828
|
-
V.set(
|
|
5053
|
+
V.set(i + 1, k, 0);
|
|
4829
5054
|
}
|
|
4830
5055
|
}
|
|
4831
5056
|
|
|
4832
5057
|
for (j = 0; j < n; j++) {
|
|
4833
|
-
d[j] = V.get(n - 1
|
|
4834
|
-
V.set(n - 1,
|
|
5058
|
+
d[j] = V.get(j, n - 1);
|
|
5059
|
+
V.set(j, n - 1, 0);
|
|
4835
5060
|
}
|
|
4836
5061
|
|
|
4837
5062
|
V.set(n - 1, n - 1, 1);
|
|
@@ -4902,9 +5127,9 @@ function tql2(n, e, d, V) {
|
|
|
4902
5127
|
d[i + 1] = h + s * (c * g + s * d[i]);
|
|
4903
5128
|
|
|
4904
5129
|
for (k = 0; k < n; k++) {
|
|
4905
|
-
h = V.get(
|
|
4906
|
-
V.set(
|
|
4907
|
-
V.set(
|
|
5130
|
+
h = V.get(i + 1, k);
|
|
5131
|
+
V.set(i + 1, k, s * V.get(i, k) + c * h);
|
|
5132
|
+
V.set(i, k, c * V.get(i, k) - s * h);
|
|
4908
5133
|
}
|
|
4909
5134
|
}
|
|
4910
5135
|
|
|
@@ -4931,9 +5156,9 @@ function tql2(n, e, d, V) {
|
|
|
4931
5156
|
d[k] = d[i];
|
|
4932
5157
|
d[i] = p;
|
|
4933
5158
|
for (j = 0; j < n; j++) {
|
|
4934
|
-
p = V.get(
|
|
4935
|
-
V.set(
|
|
4936
|
-
V.set(
|
|
5159
|
+
p = V.get(i, j);
|
|
5160
|
+
V.set(i, j, V.get(k, j));
|
|
5161
|
+
V.set(k, j, p);
|
|
4937
5162
|
}
|
|
4938
5163
|
}
|
|
4939
5164
|
}
|
|
@@ -5537,7 +5762,7 @@ class nipals {
|
|
|
5537
5762
|
|
|
5538
5763
|
let u;
|
|
5539
5764
|
if (Y) {
|
|
5540
|
-
if (isAnyArray
|
|
5765
|
+
if (isAnyArray(Y) && typeof Y[0] === 'number') {
|
|
5541
5766
|
Y = Matrix.columnVector(Y);
|
|
5542
5767
|
} else {
|
|
5543
5768
|
Y = WrapperMatrix2D.checkMatrix(Y);
|
|
@@ -5645,3 +5870,4 @@ exports.linearDependencies = linearDependencies;
|
|
|
5645
5870
|
exports.pseudoInverse = pseudoInverse;
|
|
5646
5871
|
exports.solve = solve;
|
|
5647
5872
|
exports.wrap = wrap;
|
|
5873
|
+
//# sourceMappingURL=matrix.js.map
|