mathjs 11.12.0 → 12.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. package/HISTORY.md +39 -2
  2. package/README.md +1 -1
  3. package/lib/browser/math.js +1 -1
  4. package/lib/browser/math.js.LICENSE.txt +1 -1
  5. package/lib/browser/math.js.map +1 -1
  6. package/lib/cjs/entry/dependenciesAny/dependenciesEigs.generated.js +4 -0
  7. package/lib/cjs/entry/pureFunctionsAny.generated.js +2 -0
  8. package/lib/cjs/expression/embeddedDocs/function/matrix/eigs.js +2 -2
  9. package/lib/cjs/expression/node/AssignmentNode.js +1 -1
  10. package/lib/cjs/expression/node/FunctionAssignmentNode.js +1 -1
  11. package/lib/cjs/function/matrix/eigs/complexEigs.js +73 -68
  12. package/lib/cjs/function/matrix/eigs/{realSymetric.js → realSymmetric.js} +57 -51
  13. package/lib/cjs/function/matrix/eigs.js +118 -45
  14. package/lib/cjs/header.js +1 -1
  15. package/lib/cjs/utils/number.js +1 -1
  16. package/lib/cjs/version.js +1 -1
  17. package/lib/esm/entry/dependenciesAny/dependenciesEigs.generated.js +4 -0
  18. package/lib/esm/entry/pureFunctionsAny.generated.js +2 -0
  19. package/lib/esm/expression/embeddedDocs/function/matrix/eigs.js +2 -2
  20. package/lib/esm/expression/node/AssignmentNode.js +1 -1
  21. package/lib/esm/expression/node/FunctionAssignmentNode.js +1 -1
  22. package/lib/esm/function/matrix/eigs/complexEigs.js +73 -68
  23. package/lib/esm/function/matrix/eigs/{realSymetric.js → realSymmetric.js} +55 -51
  24. package/lib/esm/function/matrix/eigs.js +119 -47
  25. package/lib/esm/utils/number.js +1 -1
  26. package/lib/esm/version.js +1 -1
  27. package/package.json +2 -2
  28. package/types/EXPLANATION.md +54 -0
  29. package/types/index.d.ts +6797 -6477
@@ -1,18 +1,20 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
7
  exports.createEigs = void 0;
8
+ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
7
9
  var _factory = require("../../utils/factory.js");
8
10
  var _string = require("../../utils/string.js");
9
11
  var _complexEigs = require("./eigs/complexEigs.js");
10
- var _realSymetric = require("./eigs/realSymetric.js");
12
+ var _realSymmetric = require("./eigs/realSymmetric.js");
11
13
  var _is = require("../../utils/is.js");
12
14
  var name = 'eigs';
13
15
 
14
16
  // The absolute state of math.js's dependency system:
15
- var dependencies = ['config', 'typed', 'matrix', 'addScalar', 'equal', 'subtract', 'abs', 'atan', 'cos', 'sin', 'multiplyScalar', 'divideScalar', 'inv', 'bignumber', 'multiply', 'add', 'larger', 'column', 'flatten', 'number', 'complex', 'sqrt', 'diag', 'qr', 'usolve', 'usolveAll', 'im', 're', 'smaller', 'matrixFromColumns', 'dot'];
17
+ var dependencies = ['config', 'typed', 'matrix', 'addScalar', 'equal', 'subtract', 'abs', 'atan', 'cos', 'sin', 'multiplyScalar', 'divideScalar', 'inv', 'bignumber', 'multiply', 'add', 'larger', 'column', 'flatten', 'number', 'complex', 'sqrt', 'diag', 'size', 'reshape', 'qr', 'usolve', 'usolveAll', 'im', 're', 'smaller', 'matrixFromColumns', 'dot'];
16
18
  var createEigs = exports.createEigs = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
17
19
  var config = _ref.config,
18
20
  typed = _ref.typed,
@@ -37,6 +39,8 @@ var createEigs = exports.createEigs = /* #__PURE__ */(0, _factory.factory)(name,
37
39
  complex = _ref.complex,
38
40
  sqrt = _ref.sqrt,
39
41
  diag = _ref.diag,
42
+ size = _ref.size,
43
+ reshape = _ref.reshape,
40
44
  qr = _ref.qr,
41
45
  usolve = _ref.usolve,
42
46
  usolveAll = _ref.usolveAll,
@@ -45,7 +49,7 @@ var createEigs = exports.createEigs = /* #__PURE__ */(0, _factory.factory)(name,
45
49
  smaller = _ref.smaller,
46
50
  matrixFromColumns = _ref.matrixFromColumns,
47
51
  dot = _ref.dot;
48
- var doRealSymetric = (0, _realSymetric.createRealSymmetric)({
52
+ var doRealSymmetric = (0, _realSymmetric.createRealSymmetric)({
49
53
  config: config,
50
54
  addScalar: addScalar,
51
55
  subtract: subtract,
@@ -75,6 +79,8 @@ var createEigs = exports.createEigs = /* #__PURE__ */(0, _factory.factory)(name,
75
79
  abs: abs,
76
80
  bignumber: bignumber,
77
81
  diag: diag,
82
+ size: size,
83
+ reshape: reshape,
78
84
  qr: qr,
79
85
  inv: inv,
80
86
  usolve: usolve,
@@ -88,26 +94,54 @@ var createEigs = exports.createEigs = /* #__PURE__ */(0, _factory.factory)(name,
88
94
  });
89
95
 
90
96
  /**
91
- * Compute eigenvalues and eigenvectors of a matrix. The eigenvalues are sorted by their absolute value, ascending.
92
- * An eigenvalue with multiplicity k will be listed k times. The eigenvectors are returned as columns of a matrix
93
- * the eigenvector that belongs to the j-th eigenvalue in the list (eg. `values[j]`) is the j-th column (eg. `column(vectors, j)`).
94
- * If the algorithm fails to converge, it will throw an error – in that case, however, you may still find useful information
97
+ * Compute eigenvalues and optionally eigenvectors of a square matrix.
98
+ * The eigenvalues are sorted by their absolute value, ascending, and
99
+ * returned as a vector in the `values` property of the returned project.
100
+ * An eigenvalue with algebraic multiplicity k will be listed k times, so
101
+ * that the returned `values` vector always has length equal to the size
102
+ * of the input matrix.
103
+ *
104
+ * The `eigenvectors` property of the return value provides the eigenvectors.
105
+ * It is an array of plain objects: the `value` property of each gives the
106
+ * associated eigenvalue, and the `vector` property gives the eigenvector
107
+ * itself. Note that the same `value` property will occur as many times in
108
+ * the list provided by `eigenvectors` as the geometric multiplicity of
109
+ * that value.
110
+ *
111
+ * If the algorithm fails to converge, it will throw an error –
112
+ * in that case, however, you may still find useful information
95
113
  * in `err.values` and `err.vectors`.
96
114
  *
115
+ * Note that the 'precision' option does not directly specify the _accuracy_
116
+ * of the returned eigenvalues. Rather, it determines how small an entry
117
+ * of the iterative approximations to an upper triangular matrix must be
118
+ * in order to be considered zero. The actual accuracy of the returned
119
+ * eigenvalues may be greater or less than the precision, depending on the
120
+ * conditioning of the matrix and how far apart or close the actual
121
+ * eigenvalues are. Note that currently, relatively simple, "traditional"
122
+ * methods of eigenvalue computation are being used; this is not a modern,
123
+ * high-precision eigenvalue computation. That said, it should typically
124
+ * produce fairly reasonable results.
125
+ *
97
126
  * Syntax:
98
127
  *
99
128
  * math.eigs(x, [prec])
129
+ * math.eigs(x, {options})
100
130
  *
101
131
  * Examples:
102
132
  *
103
- * const { eigs, multiply, column, transpose } = math
133
+ * const { eigs, multiply, column, transpose, matrixFromColumns } = math
104
134
  * const H = [[5, 2.3], [2.3, 1]]
105
- * const ans = eigs(H) // returns {values: [E1,E2...sorted], vectors: [v1,v2.... corresponding vectors as columns]}
135
+ * const ans = eigs(H) // returns {values: [E1,E2...sorted], eigenvectors: [{value: E1, vector: v2}, {value: e, vector: v2}, ...]
106
136
  * const E = ans.values
107
- * const U = ans.vectors
108
- * multiply(H, column(U, 0)) // returns multiply(E[0], column(U, 0))
109
- * const UTxHxU = multiply(transpose(U), H, U) // diagonalizes H
110
- * E[0] == UTxHxU[0][0] // returns true
137
+ * const V = ans.eigenvectors
138
+ * multiply(H, V[0].vector)) // returns multiply(E[0], V[0].vector))
139
+ * const U = matrixFromColumns(...V.map(obj => obj.vector))
140
+ * const UTxHxU = multiply(transpose(U), H, U) // diagonalizes H if possible
141
+ * E[0] == UTxHxU[0][0] // returns true always
142
+ *
143
+ * // Compute only approximate eigenvalues:
144
+ * const {values} = eigs(H, {eigenvectors: false, precision: 1e-6})
111
145
  *
112
146
  * See also:
113
147
  *
@@ -115,57 +149,96 @@ var createEigs = exports.createEigs = /* #__PURE__ */(0, _factory.factory)(name,
115
149
  *
116
150
  * @param {Array | Matrix} x Matrix to be diagonalized
117
151
  *
118
- * @param {number | BigNumber} [prec] Precision, default value: 1e-15
119
- * @return {{values: Array|Matrix, vectors: Array|Matrix}} Object containing an array of eigenvalues and a matrix with eigenvectors as columns.
152
+ * @param {number | BigNumber | OptsObject} [opts] Object with keys `precision`, defaulting to config.epsilon, and `eigenvectors`, defaulting to true and specifying whether to compute eigenvectors. If just a number, specifies precision.
153
+ * @return {{values: Array|Matrix, eigenvectors?: Array<EVobj>}} Object containing an array of eigenvalues and an array of {value: number|BigNumber, vector: Array|Matrix} objects. The eigenvectors property is undefined if eigenvectors were not requested.
120
154
  *
121
155
  */
122
156
  return typed('eigs', {
157
+ // The conversion to matrix in the first two implementations,
158
+ // just to convert back to an array right away in
159
+ // computeValuesAndVectors, is unfortunate, and should perhaps be
160
+ // streamlined. It is done because the Matrix object carries some
161
+ // type information about its entries, and so constructing the matrix
162
+ // is a roundabout way of doing type detection.
123
163
  Array: function Array(x) {
124
- var mat = matrix(x);
125
- return computeValuesAndVectors(mat);
164
+ return doEigs(matrix(x));
126
165
  },
127
166
  'Array, number|BigNumber': function ArrayNumberBigNumber(x, prec) {
128
- var mat = matrix(x);
129
- return computeValuesAndVectors(mat, prec);
167
+ return doEigs(matrix(x), {
168
+ precision: prec
169
+ });
170
+ },
171
+ 'Array, Object': function ArrayObject(x, opts) {
172
+ return doEigs(matrix(x), opts);
130
173
  },
131
174
  Matrix: function Matrix(mat) {
132
- var _computeValuesAndVect = computeValuesAndVectors(mat),
133
- values = _computeValuesAndVect.values,
134
- vectors = _computeValuesAndVect.vectors;
135
- return {
136
- values: matrix(values),
137
- vectors: matrix(vectors)
138
- };
175
+ return doEigs(mat, {
176
+ matricize: true
177
+ });
139
178
  },
140
179
  'Matrix, number|BigNumber': function MatrixNumberBigNumber(mat, prec) {
141
- var _computeValuesAndVect2 = computeValuesAndVectors(mat, prec),
142
- values = _computeValuesAndVect2.values,
143
- vectors = _computeValuesAndVect2.vectors;
144
- return {
145
- values: matrix(values),
146
- vectors: matrix(vectors)
180
+ return doEigs(mat, {
181
+ precision: prec,
182
+ matricize: true
183
+ });
184
+ },
185
+ 'Matrix, Object': function MatrixObject(mat, opts) {
186
+ var useOpts = {
187
+ matricize: true
147
188
  };
189
+ (0, _extends2["default"])(useOpts, opts);
190
+ return doEigs(mat, useOpts);
148
191
  }
149
192
  });
150
- function computeValuesAndVectors(mat, prec) {
151
- if (prec === undefined) {
152
- prec = config.epsilon;
193
+ function doEigs(mat) {
194
+ var _opts$precision;
195
+ var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
196
+ var computeVectors = 'eigenvectors' in opts ? opts.eigenvectors : true;
197
+ var prec = (_opts$precision = opts.precision) !== null && _opts$precision !== void 0 ? _opts$precision : config.epsilon;
198
+ var result = computeValuesAndVectors(mat, prec, computeVectors);
199
+ if (opts.matricize) {
200
+ result.values = matrix(result.values);
201
+ if (computeVectors) {
202
+ result.eigenvectors = result.eigenvectors.map(function (_ref2) {
203
+ var value = _ref2.value,
204
+ vector = _ref2.vector;
205
+ return {
206
+ value: value,
207
+ vector: matrix(vector)
208
+ };
209
+ });
210
+ }
211
+ }
212
+ if (computeVectors) {
213
+ Object.defineProperty(result, 'vectors', {
214
+ enumerable: false,
215
+ // to make sure that the eigenvectors can still be
216
+ // converted to string.
217
+ get: function get() {
218
+ throw new Error('eigs(M).vectors replaced with eigs(M).eigenvectors');
219
+ }
220
+ });
153
221
  }
154
- var size = mat.size();
155
- if (size.length !== 2 || size[0] !== size[1]) {
156
- throw new RangeError('Matrix must be square (size: ' + (0, _string.format)(size) + ')');
222
+ return result;
223
+ }
224
+ function computeValuesAndVectors(mat, prec, computeVectors) {
225
+ var arr = mat.toArray(); // NOTE: arr is guaranteed to be unaliased
226
+ // and so safe to modify in place
227
+ var asize = mat.size();
228
+ if (asize.length !== 2 || asize[0] !== asize[1]) {
229
+ throw new RangeError("Matrix must be square (size: ".concat((0, _string.format)(asize), ")"));
157
230
  }
158
- var arr = mat.toArray();
159
- var N = size[0];
231
+ var N = asize[0];
160
232
  if (isReal(arr, N, prec)) {
161
- coerceReal(arr, N);
233
+ coerceReal(arr, N); // modifies arr by side effect
234
+
162
235
  if (isSymmetric(arr, N, prec)) {
163
- var _type = coerceTypes(mat, arr, N);
164
- return doRealSymetric(arr, N, prec, _type);
236
+ var _type = coerceTypes(mat, arr, N); // modifies arr by side effect
237
+ return doRealSymmetric(arr, N, prec, _type, computeVectors);
165
238
  }
166
239
  }
167
- var type = coerceTypes(mat, arr, N);
168
- return doComplexEigs(arr, N, prec, type);
240
+ var type = coerceTypes(mat, arr, N); // modifies arr by side effect
241
+ return doComplexEigs(arr, N, prec, type, computeVectors);
169
242
  }
170
243
 
171
244
  /** @return {boolean} */
package/lib/cjs/header.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * It features real and complex numbers, units, matrices, a large set of
7
7
  * mathematical functions, and a flexible expression parser.
8
8
  *
9
- * @version 11.12.0
9
+ * @version 12.0.0
10
10
  * @date 2023-10-26
11
11
  *
12
12
  * @license
@@ -604,7 +604,7 @@ function nearlyEqual(x, y, epsilon) {
604
604
  if (isFinite(x) && isFinite(y)) {
605
605
  // check numbers are very close, needed when comparing numbers near zero
606
606
  var diff = Math.abs(x - y);
607
- if (diff < DBL_EPSILON) {
607
+ if (diff <= DBL_EPSILON) {
608
608
  return true;
609
609
  } else {
610
610
  // use relative error
@@ -4,6 +4,6 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.version = void 0;
7
- var version = exports.version = '11.12.0';
7
+ var version = exports.version = '12.0.0';
8
8
  // Note: This file is automatically generated when building math.js.
9
9
  // Changes made in this file will be overwritten.
@@ -25,7 +25,9 @@ import { multiplyScalarDependencies } from './dependenciesMultiplyScalar.generat
25
25
  import { numberDependencies } from './dependenciesNumber.generated.js';
26
26
  import { qrDependencies } from './dependenciesQr.generated.js';
27
27
  import { reDependencies } from './dependenciesRe.generated.js';
28
+ import { reshapeDependencies } from './dependenciesReshape.generated.js';
28
29
  import { sinDependencies } from './dependenciesSin.generated.js';
30
+ import { sizeDependencies } from './dependenciesSize.generated.js';
29
31
  import { smallerDependencies } from './dependenciesSmaller.generated.js';
30
32
  import { sqrtDependencies } from './dependenciesSqrt.generated.js';
31
33
  import { subtractDependencies } from './dependenciesSubtract.generated.js';
@@ -57,7 +59,9 @@ export var eigsDependencies = {
57
59
  numberDependencies,
58
60
  qrDependencies,
59
61
  reDependencies,
62
+ reshapeDependencies,
60
63
  sinDependencies,
64
+ sizeDependencies,
61
65
  smallerDependencies,
62
66
  sqrtDependencies,
63
67
  subtractDependencies,
@@ -1582,7 +1582,9 @@ export var eigs = /* #__PURE__ */createEigs({
1582
1582
  number,
1583
1583
  qr,
1584
1584
  re,
1585
+ reshape,
1585
1586
  sin,
1587
+ size,
1586
1588
  smaller,
1587
1589
  sqrt,
1588
1590
  subtract,
@@ -2,7 +2,7 @@ export var eigsDocs = {
2
2
  name: 'eigs',
3
3
  category: 'Matrix',
4
4
  syntax: ['eigs(x)'],
5
- description: 'Calculate the eigenvalues and eigenvectors of a real symmetric matrix',
6
- examples: ['eigs([[5, 2.3], [2.3, 1]])'],
5
+ description: 'Calculate the eigenvalues and optionally eigenvectors of a square matrix',
6
+ examples: ['eigs([[5, 2.3], [2.3, 1]])', 'eigs([[1, 2, 3], [4, 5, 6], [7, 8, 9]], { precision: 1e-6, eigenvectors: false }'],
7
7
  seealso: ['inv']
8
8
  };
@@ -295,7 +295,7 @@ export var createAssignmentNode = /* #__PURE__ */factory(name, dependencies, _re
295
295
  if (needParenthesis(this, options && options.parenthesis, options && options.implicit)) {
296
296
  value = "\\left(".concat(value, "\\right)");
297
297
  }
298
- return object + index + ':=' + value;
298
+ return object + index + '=' + value;
299
299
  }
300
300
  }
301
301
  _defineProperty(AssignmentNode, "name", name);
@@ -224,7 +224,7 @@ export var createFunctionAssignmentNode = /* #__PURE__ */factory(name, dependenc
224
224
  if (needParenthesis(this, parenthesis, options && options.implicit)) {
225
225
  expr = "\\left(".concat(expr, "\\right)");
226
226
  }
227
- return '\\mathrm{' + this.name + '}\\left(' + this.params.map(toSymbol).join(',') + '\\right):=' + expr;
227
+ return '\\mathrm{' + this.name + '}\\left(' + this.params.map(toSymbol).join(',') + '\\right)=' + expr;
228
228
  }
229
229
  }
230
230
  _defineProperty(FunctionAssignmentNode, "name", name);
@@ -11,6 +11,8 @@ export function createComplexEigs(_ref) {
11
11
  abs,
12
12
  bignumber,
13
13
  diag,
14
+ size,
15
+ reshape,
14
16
  inv,
15
17
  qr,
16
18
  usolve,
@@ -31,11 +33,8 @@ export function createComplexEigs(_ref) {
31
33
  *
32
34
  * @returns {{ values: number[], vectors: number[][] }}
33
35
  */
34
- function complexEigs(arr, N, prec, type, findVectors) {
35
- if (findVectors === undefined) {
36
- findVectors = true;
37
- }
38
-
36
+ function complexEigs(arr, N, prec, type) {
37
+ var findVectors = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
39
38
  // TODO check if any row/col are zero except the diagonal
40
39
 
41
40
  // make sure corresponding rows and columns have similar magnitude
@@ -44,9 +43,9 @@ export function createComplexEigs(_ref) {
44
43
  var R = balance(arr, N, prec, type, findVectors);
45
44
 
46
45
  // R is the row transformation matrix
47
- // arr = A' = R A R⁻¹, A is the original matrix
46
+ // arr = A' = R A R^-1, A is the original matrix
48
47
  // (if findVectors is false, R is undefined)
49
- // (And so to return to original matrix: A = R⁻¹ arr R)
48
+ // (And so to return to original matrix: A = R^-1 arr R)
50
49
 
51
50
  // TODO if magnitudes of elements vary over many orders,
52
51
  // move greatest elements to the top left corner
@@ -56,7 +55,7 @@ export function createComplexEigs(_ref) {
56
55
  // updates the transformation matrix R with new row operationsq
57
56
  // MODIFIES arr by side effect!
58
57
  reduceToHessenberg(arr, N, prec, type, findVectors, R);
59
- // still true that original A = R⁻¹ arr R)
58
+ // still true that original A = R^-1 arr R)
60
59
 
61
60
  // find eigenvalues
62
61
  var {
@@ -67,17 +66,18 @@ export function createComplexEigs(_ref) {
67
66
  // values is the list of eigenvalues, C is the column
68
67
  // transformation matrix that transforms arr, the hessenberg
69
68
  // matrix, to upper triangular
70
- // (So U = C⁻¹ arr C and the relationship between current arr
69
+ // (So U = C^-1 arr C and the relationship between current arr
71
70
  // and original A is unchanged.)
72
71
 
73
- var vectors;
74
72
  if (findVectors) {
75
- vectors = findEigenvectors(arr, N, C, R, values, prec, type);
76
- vectors = matrixFromColumns(...vectors);
73
+ var eigenvectors = findEigenvectors(arr, N, C, R, values, prec, type);
74
+ return {
75
+ values,
76
+ eigenvectors
77
+ };
77
78
  }
78
79
  return {
79
- values,
80
- vectors
80
+ values
81
81
  };
82
82
  }
83
83
 
@@ -117,9 +117,8 @@ export function createComplexEigs(_ref) {
117
117
  var rowNorm = realzero;
118
118
  for (var j = 0; j < N; j++) {
119
119
  if (i === j) continue;
120
- var c = abs(arr[i][j]); // should be real
121
- colNorm = addScalar(colNorm, c);
122
- rowNorm = addScalar(rowNorm, c);
120
+ colNorm = addScalar(colNorm, abs(arr[j][i]));
121
+ rowNorm = addScalar(rowNorm, abs(arr[i][j]));
123
122
  }
124
123
  if (!equal(colNorm, 0) && !equal(rowNorm, 0)) {
125
124
  // find integer power closest to balancing the matrix
@@ -127,21 +126,21 @@ export function createComplexEigs(_ref) {
127
126
  // so that we don't lose any precision due to round-off)
128
127
 
129
128
  var f = realone;
130
- var _c = colNorm;
129
+ var c = colNorm;
131
130
  var rowDivRadix = divideScalar(rowNorm, radix);
132
131
  var rowMulRadix = multiplyScalar(rowNorm, radix);
133
- while (smaller(_c, rowDivRadix)) {
134
- _c = multiplyScalar(_c, radixSq);
132
+ while (smaller(c, rowDivRadix)) {
133
+ c = multiplyScalar(c, radixSq);
135
134
  f = multiplyScalar(f, radix);
136
135
  }
137
- while (larger(_c, rowMulRadix)) {
138
- _c = divideScalar(_c, radixSq);
136
+ while (larger(c, rowMulRadix)) {
137
+ c = divideScalar(c, radixSq);
139
138
  f = divideScalar(f, radix);
140
139
  }
141
140
 
142
141
  // check whether balancing is needed
143
142
  // condition = (c + rowNorm) / f < 0.95 * (colNorm + rowNorm)
144
- var condition = smaller(divideScalar(addScalar(_c, rowNorm), f), multiplyScalar(addScalar(colNorm, rowNorm), 0.95));
143
+ var condition = smaller(divideScalar(addScalar(c, rowNorm), f), multiplyScalar(addScalar(colNorm, rowNorm), 0.95));
145
144
 
146
145
  // apply balancing similarity transformation
147
146
  if (condition) {
@@ -153,13 +152,13 @@ export function createComplexEigs(_ref) {
153
152
  if (i === _j) {
154
153
  continue;
155
154
  }
156
- arr[i][_j] = multiplyScalar(arr[i][_j], f);
157
- arr[_j][i] = multiplyScalar(arr[_j][i], g);
155
+ arr[i][_j] = multiplyScalar(arr[i][_j], g);
156
+ arr[_j][i] = multiplyScalar(arr[_j][i], f);
158
157
  }
159
158
 
160
159
  // keep track of transformations
161
160
  if (findVectors) {
162
- Rdiag[i] = multiplyScalar(Rdiag[i], f);
161
+ Rdiag[i] = multiplyScalar(Rdiag[i], g);
163
162
  }
164
163
  }
165
164
  }
@@ -167,7 +166,7 @@ export function createComplexEigs(_ref) {
167
166
  }
168
167
 
169
168
  // return the diagonal row transformation matrix
170
- return diag(Rdiag);
169
+ return findVectors ? diag(Rdiag) : null;
171
170
  }
172
171
 
173
172
  /**
@@ -266,7 +265,7 @@ export function createComplexEigs(_ref) {
266
265
 
267
266
  // The Francis Algorithm
268
267
  // The core idea of this algorithm is that doing successive
269
- // A' = Q⁺AQ transformations will eventually converge to block-
268
+ // A' = QtAQ transformations will eventually converge to block-
270
269
  // upper-triangular with diagonal blocks either 1x1 or 2x2.
271
270
  // The Q here is the one from the QR decomposition, A = QR.
272
271
  // Since the eigenvalues of a block-upper-triangular matrix are
@@ -288,7 +287,7 @@ export function createComplexEigs(_ref) {
288
287
  // N×N matrix describing the overall transformation done during the QR algorithm
289
288
  var Qtotal = findVectors ? diag(Array(N).fill(one)) : undefined;
290
289
 
291
- // n×n matrix describing the QR transformations done since last convergence
290
+ // nxn matrix describing the QR transformations done since last convergence
292
291
  var Qpartial = findVectors ? diag(Array(n).fill(one)) : undefined;
293
292
 
294
293
  // last eigenvalue converged before this many steps
@@ -300,7 +299,12 @@ export function createComplexEigs(_ref) {
300
299
 
301
300
  // Perform the factorization
302
301
 
303
- var k = 0; // TODO set close to an eigenvalue
302
+ var k = arr[n - 1][n - 1]; // TODO this is apparently a somewhat
303
+ // old-fashioned choice; ideally set close to an eigenvalue, or
304
+ // perhaps better yet switch to the implicit QR version that is sometimes
305
+ // specifically called the "Francis algorithm" that is alluded to
306
+ // in the following TODO. (Or perhaps we switch to an independently
307
+ // optimized third-party package for the linear algebra operations...)
304
308
 
305
309
  for (var i = 0; i < n; i++) {
306
310
  arr[i][i] = subtract(arr[i][i], k);
@@ -414,17 +418,17 @@ export function createComplexEigs(_ref) {
414
418
  // this way it is easier to find eigenvectors
415
419
  var uniqueValues = [];
416
420
  var multiplicities = [];
417
- for (var λ of values) {
418
- var i = indexOf(uniqueValues, λ, equal);
421
+ for (var lambda of values) {
422
+ var i = indexOf(uniqueValues, lambda, equal);
419
423
  if (i === -1) {
420
- uniqueValues.push(λ);
424
+ uniqueValues.push(lambda);
421
425
  multiplicities.push(1);
422
426
  } else {
423
427
  multiplicities[i] += 1;
424
428
  }
425
429
  }
426
430
 
427
- // find eigenvectors by solving U − λE = 0
431
+ // find eigenvectors by solving U − lambdaE = 0
428
432
  // TODO replace with an iterative eigenvector algorithm
429
433
  // (this one might fail for imprecise eigenvalues)
430
434
 
@@ -432,41 +436,35 @@ export function createComplexEigs(_ref) {
432
436
  var len = uniqueValues.length;
433
437
  var b = Array(N).fill(zero);
434
438
  var E = diag(Array(N).fill(one));
435
-
436
- // eigenvalues for which usolve failed (due to numerical error)
437
- var failedLambdas = [];
438
439
  var _loop = function _loop() {
439
- var λ = uniqueValues[_i4];
440
- var S = subtract(U, multiply(λ, E)); // the characteristic matrix
440
+ var lambda = uniqueValues[_i4];
441
+ var S = subtract(U, multiply(lambda, E)); // the characteristic matrix
441
442
 
442
443
  var solutions = usolveAll(S, b);
443
444
  solutions.shift(); // ignore the null vector
444
445
 
445
446
  // looks like we missed something, try inverse iteration
447
+ // But if that fails, just presume that the original matrix truly
448
+ // was defective.
446
449
  while (solutions.length < multiplicities[_i4]) {
447
450
  var approxVec = inverseIterate(S, N, solutions, prec, type);
448
- if (approxVec == null) {
449
- // no more vectors were found
450
- failedLambdas.push(λ);
451
+ if (approxVec === null) {
451
452
  break;
452
- }
453
+ } // no more vectors were found
453
454
  solutions.push(approxVec);
454
455
  }
455
456
 
456
457
  // Transform back into original array coordinates
457
458
  var correction = multiply(inv(R), C);
458
459
  solutions = solutions.map(v => multiply(correction, v));
459
- vectors.push(...solutions.map(v => flatten(v)));
460
+ vectors.push(...solutions.map(v => ({
461
+ value: lambda,
462
+ vector: flatten(v)
463
+ })));
460
464
  };
461
465
  for (var _i4 = 0; _i4 < len; _i4++) {
462
466
  _loop();
463
467
  }
464
- if (failedLambdas.length !== 0) {
465
- var err = new Error('Failed to find eigenvectors for the following eigenvalues: ' + failedLambdas.join(', '));
466
- err.values = values;
467
- err.vectors = vectors;
468
- throw err;
469
- }
470
468
  return vectors;
471
469
  }
472
470
 
@@ -475,7 +473,7 @@ export function createComplexEigs(_ref) {
475
473
  * @return {[number,number]}
476
474
  */
477
475
  function eigenvalues2x2(a, b, c, d) {
478
- // λ± = ½ trA ± ½ ( tr²A - 4 detA )
476
+ // lambda_+- = 1/2 trA +- 1/2 sqrt( tr^2 A - 4 detA )
479
477
  var trA = addScalar(a, d);
480
478
  var detA = subtract(multiplyScalar(a, d), multiplyScalar(b, c));
481
479
  var x = multiplyScalar(trA, 0.5);
@@ -485,7 +483,7 @@ export function createComplexEigs(_ref) {
485
483
 
486
484
  /**
487
485
  * For an 2x2 matrix compute the transformation matrix S,
488
- * so that SAS⁻¹ is an upper triangular matrix
486
+ * so that SAS^-1 is an upper triangular matrix
489
487
  * @return {[[number,number],[number,number]]}
490
488
  * @see https://math.berkeley.edu/~ogus/old/Math_54-05/webfoils/jordan.pdf
491
489
  * @see http://people.math.harvard.edu/~knill/teaching/math21b2004/exhibits/2dmatrices/index.html
@@ -509,23 +507,22 @@ export function createComplexEigs(_ref) {
509
507
  }
510
508
 
511
509
  // matrix is not diagonalizable
512
- // compute off-diagonal elements of N = A - λI
513
- // N₁₂ = 0 ⇒ S = ( N⃗₁, I⃗₁ )
514
- // N₁₂ ≠ 0 ⇒ S = ( N⃗₂, I⃗₂ )
515
-
510
+ // compute diagonal elements of N = A - lambdaI
516
511
  var na = subtract(a, l1);
517
- var nb = subtract(b, l1);
518
- var nc = subtract(c, l1);
519
512
  var nd = subtract(d, l1);
520
- if (smaller(abs(nb), prec)) {
521
- return [[na, one], [nc, zero]];
513
+
514
+ // col(N,2) = 0 implies S = ( col(N,1), e_1 )
515
+ // col(N,2) != 0 implies S = ( col(N,2), e_2 )
516
+
517
+ if (smaller(abs(b), prec) && smaller(abs(nd), prec)) {
518
+ return [[na, one], [c, zero]];
522
519
  } else {
523
- return [[nb, zero], [nd, one]];
520
+ return [[b, zero], [nd, one]];
524
521
  }
525
522
  }
526
523
 
527
524
  /**
528
- * Enlarge the matrix from n×n to N×N, setting the new
525
+ * Enlarge the matrix from nxn to NxN, setting the new
529
526
  * elements to 1 on diagonal and 0 elsewhere
530
527
  */
531
528
  function inflateMatrix(arr, N) {
@@ -602,15 +599,21 @@ export function createComplexEigs(_ref) {
602
599
 
603
600
  // you better choose a random vector before I count to five
604
601
  var i = 0;
605
- while (true) {
602
+ for (; i < 5; ++i) {
606
603
  b = randomOrthogonalVector(N, orthog, type);
607
- b = usolve(A, b);
604
+ try {
605
+ b = usolve(A, b);
606
+ } catch (_unused) {
607
+ // That direction didn't work, likely because the original matrix
608
+ // was defective. But still make the full number of tries...
609
+ continue;
610
+ }
608
611
  if (larger(norm(b), largeNum)) {
609
612
  break;
610
613
  }
611
- if (++i >= 5) {
612
- return null;
613
- }
614
+ }
615
+ if (i >= 5) {
616
+ return null; // couldn't find any orthogonal vector in the image
614
617
  }
615
618
 
616
619
  // you better converge before I count to ten
@@ -660,8 +663,10 @@ export function createComplexEigs(_ref) {
660
663
  * Project vector v to the orthogonal complement of an array of vectors
661
664
  */
662
665
  function orthogonalComplement(v, orthog) {
666
+ var vectorShape = size(v);
663
667
  for (var w of orthog) {
664
- // v := v − (w, v)/∥w∥² w
668
+ w = reshape(w, vectorShape); // make sure this is just a vector computation
669
+ // v := v − (w, v)/|w|^2 w
665
670
  v = subtract(v, multiply(divideScalar(dot(w, v), dot(w, w)), w));
666
671
  }
667
672
  return v;