ml-matrix 6.12.2 → 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 CHANGED
@@ -616,6 +616,26 @@ export abstract class AbstractMatrix {
616
616
  */
617
617
  mmul(other: MaybeMatrix): Matrix;
618
618
 
619
+ /**
620
+ * Returns the Gram matrix `thisᵀ · this` (the `columns × columns` matrix of
621
+ * the dot products of every pair of columns). The result is symmetric, so only
622
+ * its upper triangle is computed and mirrored, and the transpose is never
623
+ * materialized, making it about twice as fast as `this.transpose().mmul(this)`
624
+ * on dense matrices and much faster on sparse ones (zero entries are skipped).
625
+ * For finite inputs the result is identical to `this.transpose().mmul(this)`.
626
+ */
627
+ gram(): Matrix;
628
+
629
+ /**
630
+ * Returns the matrix product between `this` and its transpose (`this · thisᵀ`),
631
+ * optionally weighting each column by `scale` (`this · diag(scale) · thisᵀ`).
632
+ * The result is symmetric, so only its upper triangle is computed and mirrored
633
+ * and the transpose is never materialized, making it about twice as fast as
634
+ * `this.mmul(this.transpose())`.
635
+ * @param scale - Optional per-column factors (length equal to the number of columns).
636
+ */
637
+ mmulByTranspose(scale?: ArrayLike<number>): Matrix;
638
+
619
639
  /**
620
640
  * Returns the square matrix raised to the given power
621
641
  * @param scalar - the non-negative integer power to raise this matrix to
@@ -860,7 +880,7 @@ export abstract class AbstractMatrix {
860
880
  [row: number, column: number, value: number],
861
881
  void,
862
882
  void
863
- >;
883
+ >;
864
884
 
865
885
  /**
866
886
  * iterator from left to right, from top to bottom
@@ -1489,7 +1509,7 @@ export { EigenvalueDecomposition as EVD };
1489
1509
  * The Cholesky decomposition of a matrix. Given a matrix A, the Cholesky Decomposition of A is L
1490
1510
  * such that A = (L)(L.transpose).
1491
1511
  * Only works for symmetric, positive definite matrix A.
1492
- *
1512
+ *
1493
1513
  * @link https://github.com/lutzroeder/Mapack/blob/master/Source/CholeskyDecomposition.cs
1494
1514
  */
1495
1515
  export class CholeskyDecomposition {
package/matrix.js CHANGED
@@ -2216,6 +2216,78 @@ class AbstractMatrix {
2216
2216
  return result;
2217
2217
  }
2218
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
+
2219
2291
  mpow(scalar) {
2220
2292
  if (!this.isSquare()) {
2221
2293
  throw new RangeError('Matrix must be square');
@@ -3851,6 +3923,27 @@ class LuDecomposition {
3851
3923
  }
3852
3924
  }
3853
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
+
3854
3947
  function hypotenuse(a, b) {
3855
3948
  let r = 0;
3856
3949
  if (Math.abs(a) > Math.abs(b)) {
@@ -4029,32 +4122,40 @@ class SingularValueDecomposition {
4029
4122
  let wantu = Boolean(computeLeftSingularVectors);
4030
4123
  let wantv = Boolean(computeRightSingularVectors);
4031
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.
4032
4129
  let swapped = false;
4033
- let a;
4130
+ let at;
4034
4131
  if (m < n) {
4035
4132
  if (!autoTranspose) {
4036
- a = value.clone();
4037
4133
  // eslint-disable-next-line no-console
4038
4134
  console.warn(
4039
4135
  'Computing SVD on a matrix with more columns than rows. Consider enabling autoTranspose',
4040
4136
  );
4137
+ at = value.transpose();
4041
4138
  } else {
4042
- a = value.transpose();
4043
- m = a.rows;
4044
- n = a.columns;
4139
+ at = value.clone();
4140
+ m = value.columns;
4141
+ n = value.rows;
4045
4142
  swapped = true;
4046
4143
  let aux = wantu;
4047
4144
  wantu = wantv;
4048
4145
  wantv = aux;
4049
4146
  }
4050
4147
  } else {
4051
- a = value.clone();
4148
+ at = value.transpose();
4052
4149
  }
4053
4150
 
4054
4151
  let nu = Math.min(m, n);
4055
4152
  let ni = Math.min(m + 1, n);
4056
4153
  let s = new Float64Array(ni);
4057
- let U = new Matrix(m, nu);
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);
4058
4159
  let V = new Matrix(n, n);
4059
4160
 
4060
4161
  let e = new Float64Array(n);
@@ -4071,16 +4172,16 @@ class SingularValueDecomposition {
4071
4172
  if (k < nct) {
4072
4173
  s[k] = 0;
4073
4174
  for (let i = k; i < m; i++) {
4074
- s[k] = hypotenuse(s[k], a.get(i, k));
4175
+ s[k] = hypotenuse(s[k], at.get(k, i));
4075
4176
  }
4076
4177
  if (s[k] !== 0) {
4077
- if (a.get(k, k) < 0) {
4178
+ if (at.get(k, k) < 0) {
4078
4179
  s[k] = -s[k];
4079
4180
  }
4080
4181
  for (let i = k; i < m; i++) {
4081
- a.set(i, k, a.get(i, k) / s[k]);
4182
+ at.set(k, i, at.get(k, i) / s[k]);
4082
4183
  }
4083
- a.set(k, k, a.get(k, k) + 1);
4184
+ at.set(k, k, at.get(k, k) + 1);
4084
4185
  }
4085
4186
  s[k] = -s[k];
4086
4187
  }
@@ -4089,19 +4190,19 @@ class SingularValueDecomposition {
4089
4190
  if (k < nct && s[k] !== 0) {
4090
4191
  let t = 0;
4091
4192
  for (let i = k; i < m; i++) {
4092
- t += a.get(i, k) * a.get(i, j);
4193
+ t += at.get(k, i) * at.get(j, i);
4093
4194
  }
4094
- t = -t / a.get(k, k);
4195
+ t = -t / at.get(k, k);
4095
4196
  for (let i = k; i < m; i++) {
4096
- a.set(i, j, a.get(i, j) + t * a.get(i, k));
4197
+ at.set(j, i, at.get(j, i) + t * at.get(k, i));
4097
4198
  }
4098
4199
  }
4099
- e[j] = a.get(k, j);
4200
+ e[j] = at.get(j, k);
4100
4201
  }
4101
4202
 
4102
4203
  if (wantu && k < nct) {
4103
4204
  for (let i = k; i < m; i++) {
4104
- U.set(i, k, a.get(i, k));
4205
+ U.set(k, i, at.get(k, i));
4105
4206
  }
4106
4207
  }
4107
4208
 
@@ -4126,19 +4227,19 @@ class SingularValueDecomposition {
4126
4227
  }
4127
4228
  for (let i = k + 1; i < m; i++) {
4128
4229
  for (let j = k + 1; j < n; j++) {
4129
- work[i] += e[j] * a.get(i, j);
4230
+ work[i] += e[j] * at.get(j, i);
4130
4231
  }
4131
4232
  }
4132
4233
  for (let j = k + 1; j < n; j++) {
4133
4234
  let t = -e[j] / e[k + 1];
4134
4235
  for (let i = k + 1; i < m; i++) {
4135
- a.set(i, j, a.get(i, j) + t * work[i]);
4236
+ at.set(j, i, at.get(j, i) + t * work[i]);
4136
4237
  }
4137
4238
  }
4138
4239
  }
4139
4240
  if (wantv) {
4140
4241
  for (let i = k + 1; i < n; i++) {
4141
- V.set(i, k, e[i]);
4242
+ V.set(k, i, e[i]);
4142
4243
  }
4143
4244
  }
4144
4245
  }
@@ -4146,20 +4247,20 @@ class SingularValueDecomposition {
4146
4247
 
4147
4248
  let p = Math.min(n, m + 1);
4148
4249
  if (nct < n) {
4149
- s[nct] = a.get(nct, nct);
4250
+ s[nct] = at.get(nct, nct);
4150
4251
  }
4151
4252
  if (m < p) {
4152
4253
  s[p - 1] = 0;
4153
4254
  }
4154
4255
  if (nrt + 1 < p) {
4155
- e[nrt] = a.get(nrt, p - 1);
4256
+ e[nrt] = at.get(p - 1, nrt);
4156
4257
  }
4157
4258
  e[p - 1] = 0;
4158
4259
 
4159
4260
  if (wantu) {
4160
4261
  for (let j = nct; j < nu; j++) {
4161
4262
  for (let i = 0; i < m; i++) {
4162
- U.set(i, j, 0);
4263
+ U.set(j, i, 0);
4163
4264
  }
4164
4265
  U.set(j, j, 1);
4165
4266
  }
@@ -4168,23 +4269,23 @@ class SingularValueDecomposition {
4168
4269
  for (let j = k + 1; j < nu; j++) {
4169
4270
  let t = 0;
4170
4271
  for (let i = k; i < m; i++) {
4171
- t += U.get(i, k) * U.get(i, j);
4272
+ t += U.get(k, i) * U.get(j, i);
4172
4273
  }
4173
4274
  t = -t / U.get(k, k);
4174
4275
  for (let i = k; i < m; i++) {
4175
- U.set(i, j, U.get(i, j) + t * U.get(i, k));
4276
+ U.set(j, i, U.get(j, i) + t * U.get(k, i));
4176
4277
  }
4177
4278
  }
4178
4279
  for (let i = k; i < m; i++) {
4179
- U.set(i, k, -U.get(i, k));
4280
+ U.set(k, i, -U.get(k, i));
4180
4281
  }
4181
4282
  U.set(k, k, 1 + U.get(k, k));
4182
4283
  for (let i = 0; i < k - 1; i++) {
4183
- U.set(i, k, 0);
4284
+ U.set(k, i, 0);
4184
4285
  }
4185
4286
  } else {
4186
4287
  for (let i = 0; i < m; i++) {
4187
- U.set(i, k, 0);
4288
+ U.set(k, i, 0);
4188
4289
  }
4189
4290
  U.set(k, k, 1);
4190
4291
  }
@@ -4197,16 +4298,16 @@ class SingularValueDecomposition {
4197
4298
  for (let j = k + 1; j < n; j++) {
4198
4299
  let t = 0;
4199
4300
  for (let i = k + 1; i < n; i++) {
4200
- t += V.get(i, k) * V.get(i, j);
4301
+ t += V.get(k, i) * V.get(j, i);
4201
4302
  }
4202
- t = -t / V.get(k + 1, k);
4303
+ t = -t / V.get(k, k + 1);
4203
4304
  for (let i = k + 1; i < n; i++) {
4204
- V.set(i, j, V.get(i, j) + t * V.get(i, k));
4305
+ V.set(j, i, V.get(j, i) + t * V.get(k, i));
4205
4306
  }
4206
4307
  }
4207
4308
  }
4208
4309
  for (let i = 0; i < n; i++) {
4209
- V.set(i, k, 0);
4310
+ V.set(k, i, 0);
4210
4311
  }
4211
4312
  V.set(k, k, 1);
4212
4313
  }
@@ -4270,9 +4371,9 @@ class SingularValueDecomposition {
4270
4371
  }
4271
4372
  if (wantv) {
4272
4373
  for (let i = 0; i < n; i++) {
4273
- t = cs * V.get(i, j) + sn * V.get(i, p - 1);
4274
- V.set(i, p - 1, -sn * V.get(i, j) + cs * V.get(i, p - 1));
4275
- V.set(i, j, t);
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);
4276
4377
  }
4277
4378
  }
4278
4379
  }
@@ -4290,9 +4391,9 @@ class SingularValueDecomposition {
4290
4391
  e[j] = cs * e[j];
4291
4392
  if (wantu) {
4292
4393
  for (let i = 0; i < m; i++) {
4293
- t = cs * U.get(i, j) + sn * U.get(i, k - 1);
4294
- U.set(i, k - 1, -sn * U.get(i, j) + cs * U.get(i, k - 1));
4295
- U.set(i, j, t);
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);
4296
4397
  }
4297
4398
  }
4298
4399
  }
@@ -4338,9 +4439,9 @@ class SingularValueDecomposition {
4338
4439
  s[j + 1] = cs * s[j + 1];
4339
4440
  if (wantv) {
4340
4441
  for (let i = 0; i < n; i++) {
4341
- t = cs * V.get(i, j) + sn * V.get(i, j + 1);
4342
- V.set(i, j + 1, -sn * V.get(i, j) + cs * V.get(i, j + 1));
4343
- V.set(i, j, t);
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);
4344
4445
  }
4345
4446
  }
4346
4447
  t = hypotenuse(f, g);
@@ -4354,9 +4455,9 @@ class SingularValueDecomposition {
4354
4455
  e[j + 1] = cs * e[j + 1];
4355
4456
  if (wantu && j < m - 1) {
4356
4457
  for (let i = 0; i < m; i++) {
4357
- t = cs * U.get(i, j) + sn * U.get(i, j + 1);
4358
- U.set(i, j + 1, -sn * U.get(i, j) + cs * U.get(i, j + 1));
4359
- U.set(i, j, t);
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);
4360
4461
  }
4361
4462
  }
4362
4463
  }
@@ -4368,7 +4469,7 @@ class SingularValueDecomposition {
4368
4469
  s[k] = s[k] < 0 ? -s[k] : 0;
4369
4470
  if (wantv) {
4370
4471
  for (let i = 0; i <= pp; i++) {
4371
- V.set(i, k, -V.get(i, k));
4472
+ V.set(k, i, -V.get(k, i));
4372
4473
  }
4373
4474
  }
4374
4475
  }
@@ -4381,16 +4482,16 @@ class SingularValueDecomposition {
4381
4482
  s[k + 1] = t;
4382
4483
  if (wantv && k < n - 1) {
4383
4484
  for (let i = 0; i < n; i++) {
4384
- t = V.get(i, k + 1);
4385
- V.set(i, k + 1, V.get(i, k));
4386
- V.set(i, k, t);
4485
+ t = V.get(k + 1, i);
4486
+ V.set(k + 1, i, V.get(k, i));
4487
+ V.set(k, i, t);
4387
4488
  }
4388
4489
  }
4389
4490
  if (wantu && k < m - 1) {
4390
4491
  for (let i = 0; i < m; i++) {
4391
- t = U.get(i, k + 1);
4392
- U.set(i, k + 1, U.get(i, k));
4393
- U.set(i, k, t);
4492
+ t = U.get(k + 1, i);
4493
+ U.set(k + 1, i, U.get(k, i));
4494
+ U.set(k, i, t);
4394
4495
  }
4395
4496
  }
4396
4497
  k++;
@@ -4402,6 +4503,13 @@ class SingularValueDecomposition {
4402
4503
  }
4403
4504
  }
4404
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
+
4405
4513
  if (swapped) {
4406
4514
  let tmp = V;
4407
4515
  V = U;
@@ -4777,14 +4885,25 @@ class EigenvalueDecomposition {
4777
4885
  }
4778
4886
 
4779
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).
4780
4893
  for (i = 0; i < n; i++) {
4781
4894
  for (j = 0; j < n; j++) {
4782
- V.set(i, j, value.get(i, j));
4895
+ V.set(j, i, value.get(i, j));
4783
4896
  }
4784
4897
  }
4785
4898
  tred2(n, e, d, V);
4786
4899
  tql2(n, e, d, V);
4900
+ // V is square; restore the logical layout in place (no allocation).
4901
+ transposeSquareInPlace(V);
4787
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.
4788
4907
  let H = new Matrix(n, n);
4789
4908
  let ort = new Float64Array(n);
4790
4909
  for (j = 0; j < n; j++) {
@@ -4839,7 +4958,7 @@ function tred2(n, e, d, V) {
4839
4958
  let f, g, h, i, j, k, hh, scale;
4840
4959
 
4841
4960
  for (j = 0; j < n; j++) {
4842
- d[j] = V.get(n - 1, j);
4961
+ d[j] = V.get(j, n - 1);
4843
4962
  }
4844
4963
 
4845
4964
  for (i = n - 1; i > 0; i--) {
@@ -4852,9 +4971,9 @@ function tred2(n, e, d, V) {
4852
4971
  if (scale === 0) {
4853
4972
  e[i] = d[i - 1];
4854
4973
  for (j = 0; j < i; j++) {
4855
- d[j] = V.get(i - 1, j);
4856
- V.set(i, j, 0);
4974
+ d[j] = V.get(j, i - 1);
4857
4975
  V.set(j, i, 0);
4976
+ V.set(i, j, 0);
4858
4977
  }
4859
4978
  } else {
4860
4979
  for (k = 0; k < i; k++) {
@@ -4877,11 +4996,11 @@ function tred2(n, e, d, V) {
4877
4996
 
4878
4997
  for (j = 0; j < i; j++) {
4879
4998
  f = d[j];
4880
- V.set(j, i, f);
4999
+ V.set(i, j, f);
4881
5000
  g = e[j] + V.get(j, j) * f;
4882
5001
  for (k = j + 1; k <= i - 1; k++) {
4883
- g += V.get(k, j) * d[k];
4884
- e[k] += V.get(k, j) * f;
5002
+ g += V.get(j, k) * d[k];
5003
+ e[k] += V.get(j, k) * f;
4885
5004
  }
4886
5005
  e[j] = g;
4887
5006
  }
@@ -4901,43 +5020,43 @@ function tred2(n, e, d, V) {
4901
5020
  f = d[j];
4902
5021
  g = e[j];
4903
5022
  for (k = j; k <= i - 1; k++) {
4904
- V.set(k, j, V.get(k, j) - (f * e[k] + g * d[k]));
5023
+ V.set(j, k, V.get(j, k) - (f * e[k] + g * d[k]));
4905
5024
  }
4906
- d[j] = V.get(i - 1, j);
4907
- V.set(i, j, 0);
5025
+ d[j] = V.get(j, i - 1);
5026
+ V.set(j, i, 0);
4908
5027
  }
4909
5028
  }
4910
5029
  d[i] = h;
4911
5030
  }
4912
5031
 
4913
5032
  for (i = 0; i < n - 1; i++) {
4914
- V.set(n - 1, i, V.get(i, i));
5033
+ V.set(i, n - 1, V.get(i, i));
4915
5034
  V.set(i, i, 1);
4916
5035
  h = d[i + 1];
4917
5036
  if (h !== 0) {
4918
5037
  for (k = 0; k <= i; k++) {
4919
- d[k] = V.get(k, i + 1) / h;
5038
+ d[k] = V.get(i + 1, k) / h;
4920
5039
  }
4921
5040
 
4922
5041
  for (j = 0; j <= i; j++) {
4923
5042
  g = 0;
4924
5043
  for (k = 0; k <= i; k++) {
4925
- g += V.get(k, i + 1) * V.get(k, j);
5044
+ g += V.get(i + 1, k) * V.get(j, k);
4926
5045
  }
4927
5046
  for (k = 0; k <= i; k++) {
4928
- V.set(k, j, V.get(k, j) - g * d[k]);
5047
+ V.set(j, k, V.get(j, k) - g * d[k]);
4929
5048
  }
4930
5049
  }
4931
5050
  }
4932
5051
 
4933
5052
  for (k = 0; k <= i; k++) {
4934
- V.set(k, i + 1, 0);
5053
+ V.set(i + 1, k, 0);
4935
5054
  }
4936
5055
  }
4937
5056
 
4938
5057
  for (j = 0; j < n; j++) {
4939
- d[j] = V.get(n - 1, j);
4940
- V.set(n - 1, j, 0);
5058
+ d[j] = V.get(j, n - 1);
5059
+ V.set(j, n - 1, 0);
4941
5060
  }
4942
5061
 
4943
5062
  V.set(n - 1, n - 1, 1);
@@ -5008,9 +5127,9 @@ function tql2(n, e, d, V) {
5008
5127
  d[i + 1] = h + s * (c * g + s * d[i]);
5009
5128
 
5010
5129
  for (k = 0; k < n; k++) {
5011
- h = V.get(k, i + 1);
5012
- V.set(k, i + 1, s * V.get(k, i) + c * h);
5013
- V.set(k, i, c * V.get(k, i) - s * h);
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);
5014
5133
  }
5015
5134
  }
5016
5135
 
@@ -5037,9 +5156,9 @@ function tql2(n, e, d, V) {
5037
5156
  d[k] = d[i];
5038
5157
  d[i] = p;
5039
5158
  for (j = 0; j < n; j++) {
5040
- p = V.get(j, i);
5041
- V.set(j, i, V.get(j, k));
5042
- V.set(j, k, p);
5159
+ p = V.get(i, j);
5160
+ V.set(i, j, V.get(k, j));
5161
+ V.set(k, j, p);
5043
5162
  }
5044
5163
  }
5045
5164
  }