mathjs 11.12.0 → 12.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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;