mathjs 11.12.0 → 12.0.0
Sign up to get free protection for your applications and to get access to all the features.
- package/HISTORY.md +39 -2
- package/README.md +1 -1
- package/lib/browser/math.js +1 -1
- package/lib/browser/math.js.LICENSE.txt +1 -1
- package/lib/browser/math.js.map +1 -1
- package/lib/cjs/entry/dependenciesAny/dependenciesEigs.generated.js +4 -0
- package/lib/cjs/entry/pureFunctionsAny.generated.js +2 -0
- package/lib/cjs/expression/embeddedDocs/function/matrix/eigs.js +2 -2
- package/lib/cjs/expression/node/AssignmentNode.js +1 -1
- package/lib/cjs/expression/node/FunctionAssignmentNode.js +1 -1
- package/lib/cjs/function/matrix/eigs/complexEigs.js +73 -68
- package/lib/cjs/function/matrix/eigs/{realSymetric.js → realSymmetric.js} +57 -51
- package/lib/cjs/function/matrix/eigs.js +118 -45
- package/lib/cjs/header.js +1 -1
- package/lib/cjs/utils/number.js +1 -1
- package/lib/cjs/version.js +1 -1
- package/lib/esm/entry/dependenciesAny/dependenciesEigs.generated.js +4 -0
- package/lib/esm/entry/pureFunctionsAny.generated.js +2 -0
- package/lib/esm/expression/embeddedDocs/function/matrix/eigs.js +2 -2
- package/lib/esm/expression/node/AssignmentNode.js +1 -1
- package/lib/esm/expression/node/FunctionAssignmentNode.js +1 -1
- package/lib/esm/function/matrix/eigs/complexEigs.js +73 -68
- package/lib/esm/function/matrix/eigs/{realSymetric.js → realSymmetric.js} +55 -51
- package/lib/esm/function/matrix/eigs.js +119 -47
- package/lib/esm/utils/number.js +1 -1
- package/lib/esm/version.js +1 -1
- package/package.json +2 -2
- package/types/EXPLANATION.md +54 -0
- 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
|
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
|
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.
|
92
|
-
*
|
93
|
-
*
|
94
|
-
*
|
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],
|
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
|
108
|
-
* multiply(H,
|
109
|
-
* const
|
110
|
-
*
|
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} [
|
119
|
-
* @return {{values: Array|Matrix,
|
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
|
-
|
125
|
-
return computeValuesAndVectors(mat);
|
164
|
+
return doEigs(matrix(x));
|
126
165
|
},
|
127
166
|
'Array, number|BigNumber': function ArrayNumberBigNumber(x, prec) {
|
128
|
-
|
129
|
-
|
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
|
-
|
133
|
-
|
134
|
-
|
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
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
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
|
151
|
-
|
152
|
-
|
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
|
-
|
155
|
-
|
156
|
-
|
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
|
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
|
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
package/lib/cjs/utils/number.js
CHANGED
@@ -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
|
607
|
+
if (diff <= DBL_EPSILON) {
|
608
608
|
return true;
|
609
609
|
} else {
|
610
610
|
// use relative error
|
package/lib/cjs/version.js
CHANGED
@@ -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 = '
|
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,
|
@@ -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
|
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 + '
|
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)
|
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
|
35
|
-
|
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
|
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
|
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
|
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
|
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
|
-
|
76
|
-
|
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
|
-
|
121
|
-
|
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
|
129
|
+
var c = colNorm;
|
131
130
|
var rowDivRadix = divideScalar(rowNorm, radix);
|
132
131
|
var rowMulRadix = multiplyScalar(rowNorm, radix);
|
133
|
-
while (smaller(
|
134
|
-
|
132
|
+
while (smaller(c, rowDivRadix)) {
|
133
|
+
c = multiplyScalar(c, radixSq);
|
135
134
|
f = multiplyScalar(f, radix);
|
136
135
|
}
|
137
|
-
while (larger(
|
138
|
-
|
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(
|
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],
|
157
|
-
arr[_j][i] = multiplyScalar(arr[_j][i],
|
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],
|
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' =
|
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
|
-
//
|
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 =
|
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
|
418
|
-
var i = indexOf(uniqueValues,
|
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 −
|
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
|
440
|
-
var S = subtract(U, multiply(
|
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
|
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 =>
|
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
|
-
//
|
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
|
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
|
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
|
-
|
521
|
-
|
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 [[
|
520
|
+
return [[b, zero], [nd, one]];
|
524
521
|
}
|
525
522
|
}
|
526
523
|
|
527
524
|
/**
|
528
|
-
* Enlarge the matrix from
|
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
|
-
|
602
|
+
for (; i < 5; ++i) {
|
606
603
|
b = randomOrthogonalVector(N, orthog, type);
|
607
|
-
|
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
|
-
|
612
|
-
|
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
|
-
|
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;
|