eigs.js (6984B)
1 import { factory } from '../../utils/factory.js'; 2 import { format } from '../../utils/string.js'; 3 import { createComplexEigs } from './eigs/complexEigs.js'; 4 import { createRealSymmetric } from './eigs/realSymetric.js'; 5 import { typeOf, isNumber, isBigNumber, isComplex, isFraction } from '../../utils/is.js'; 6 var name = 'eigs'; // The absolute state of math.js's dependency system: 7 8 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']; 9 export var createEigs = /* #__PURE__ */factory(name, dependencies, _ref => { 10 var { 11 config, 12 typed, 13 matrix, 14 addScalar, 15 subtract, 16 equal, 17 abs, 18 atan, 19 cos, 20 sin, 21 multiplyScalar, 22 divideScalar, 23 inv, 24 bignumber, 25 multiply, 26 add, 27 larger, 28 column, 29 flatten, 30 number, 31 complex, 32 sqrt, 33 diag, 34 qr, 35 usolve, 36 usolveAll, 37 im, 38 re, 39 smaller, 40 matrixFromColumns, 41 dot 42 } = _ref; 43 var doRealSymetric = createRealSymmetric({ 44 config, 45 addScalar, 46 subtract, 47 column, 48 flatten, 49 equal, 50 abs, 51 atan, 52 cos, 53 sin, 54 multiplyScalar, 55 inv, 56 bignumber, 57 complex, 58 multiply, 59 add 60 }); 61 var doComplexEigs = createComplexEigs({ 62 config, 63 addScalar, 64 subtract, 65 multiply, 66 multiplyScalar, 67 flatten, 68 divideScalar, 69 sqrt, 70 abs, 71 bignumber, 72 diag, 73 qr, 74 inv, 75 usolve, 76 usolveAll, 77 equal, 78 complex, 79 larger, 80 smaller, 81 matrixFromColumns, 82 dot 83 }); 84 /** 85 * Compute eigenvalues and eigenvectors of a matrix. The eigenvalues are sorted by their absolute value, ascending. 86 * An eigenvalue with multiplicity k will be listed k times. The eigenvectors are returned as columns of a matrix – 87 * the eigenvector that belongs to the j-th eigenvalue in the list (eg. `values[j]`) is the j-th column (eg. `column(vectors, j)`). 88 * If the algorithm fails to converge, it will throw an error – in that case, however, you may still find useful information 89 * in `err.values` and `err.vectors`. 90 * 91 * Syntax: 92 * 93 * math.eigs(x, [prec]) 94 * 95 * Examples: 96 * 97 * const { eigs, multiply, column, transpose } = math 98 * const H = [[5, 2.3], [2.3, 1]] 99 * const ans = eigs(H) // returns {values: [E1,E2...sorted], vectors: [v1,v2.... corresponding vectors as columns]} 100 * const E = ans.values 101 * const U = ans.vectors 102 * multiply(H, column(U, 0)) // returns multiply(E[0], column(U, 0)) 103 * const UTxHxU = multiply(transpose(U), H, U) // diagonalizes H 104 * E[0] == UTxHxU[0][0] // returns true 105 * 106 * See also: 107 * 108 * inv 109 * 110 * @param {Array | Matrix} x Matrix to be diagonalized 111 * 112 * @param {number | BigNumber} [prec] Precision, default value: 1e-15 113 * @return {{values: Array|Matrix, vectors: Array|Matrix}} Object containing an array of eigenvalues and a matrix with eigenvectors as columns. 114 * 115 */ 116 117 return typed('eigs', { 118 Array: function Array(x) { 119 var mat = matrix(x); 120 return computeValuesAndVectors(mat); 121 }, 122 'Array, number|BigNumber': function ArrayNumberBigNumber(x, prec) { 123 var mat = matrix(x); 124 return computeValuesAndVectors(mat, prec); 125 }, 126 Matrix: function Matrix(mat) { 127 var { 128 values, 129 vectors 130 } = computeValuesAndVectors(mat); 131 return { 132 values: matrix(values), 133 vectors: matrix(vectors) 134 }; 135 }, 136 'Matrix, number|BigNumber': function MatrixNumberBigNumber(mat, prec) { 137 var { 138 values, 139 vectors 140 } = computeValuesAndVectors(mat, prec); 141 return { 142 values: matrix(values), 143 vectors: matrix(vectors) 144 }; 145 } 146 }); 147 148 function computeValuesAndVectors(mat, prec) { 149 if (prec === undefined) { 150 prec = config.epsilon; 151 } 152 153 var size = mat.size(); 154 155 if (size.length !== 2 || size[0] !== size[1]) { 156 throw new RangeError('Matrix must be square (size: ' + format(size) + ')'); 157 } 158 159 var arr = mat.toArray(); 160 var N = size[0]; 161 162 if (isReal(arr, N, prec)) { 163 coerceReal(arr, N); 164 165 if (isSymmetric(arr, N, prec)) { 166 var _type = coerceTypes(mat, arr, N); 167 168 return doRealSymetric(arr, N, prec, _type); 169 } 170 } 171 172 var type = coerceTypes(mat, arr, N); 173 return doComplexEigs(arr, N, prec, type); 174 } 175 /** @return {boolean} */ 176 177 178 function isSymmetric(arr, N, prec) { 179 for (var i = 0; i < N; i++) { 180 for (var j = i; j < N; j++) { 181 // TODO proper comparison of bignum and frac 182 if (larger(bignumber(abs(subtract(arr[i][j], arr[j][i]))), prec)) { 183 return false; 184 } 185 } 186 } 187 188 return true; 189 } 190 /** @return {boolean} */ 191 192 193 function isReal(arr, N, prec) { 194 for (var i = 0; i < N; i++) { 195 for (var j = 0; j < N; j++) { 196 // TODO proper comparison of bignum and frac 197 if (larger(bignumber(abs(im(arr[i][j]))), prec)) { 198 return false; 199 } 200 } 201 } 202 203 return true; 204 } 205 206 function coerceReal(arr, N) { 207 for (var i = 0; i < N; i++) { 208 for (var j = 0; j < N; j++) { 209 arr[i][j] = re(arr[i][j]); 210 } 211 } 212 } 213 /** @return {'number' | 'BigNumber' | 'Complex'} */ 214 215 216 function coerceTypes(mat, arr, N) { 217 /** @type {string} */ 218 var type = mat.datatype(); 219 220 if (type === 'number' || type === 'BigNumber' || type === 'Complex') { 221 return type; 222 } 223 224 var hasNumber = false; 225 var hasBig = false; 226 var hasComplex = false; 227 228 for (var i = 0; i < N; i++) { 229 for (var j = 0; j < N; j++) { 230 var el = arr[i][j]; 231 232 if (isNumber(el) || isFraction(el)) { 233 hasNumber = true; 234 } else if (isBigNumber(el)) { 235 hasBig = true; 236 } else if (isComplex(el)) { 237 hasComplex = true; 238 } else { 239 throw TypeError('Unsupported type in Matrix: ' + typeOf(el)); 240 } 241 } 242 } 243 244 if (hasBig && hasComplex) { 245 console.warn('Complex BigNumbers not supported, this operation will lose precission.'); 246 } 247 248 if (hasComplex) { 249 for (var _i = 0; _i < N; _i++) { 250 for (var _j = 0; _j < N; _j++) { 251 arr[_i][_j] = complex(arr[_i][_j]); 252 } 253 } 254 255 return 'Complex'; 256 } 257 258 if (hasBig) { 259 for (var _i2 = 0; _i2 < N; _i2++) { 260 for (var _j2 = 0; _j2 < N; _j2++) { 261 arr[_i2][_j2] = bignumber(arr[_i2][_j2]); 262 } 263 } 264 265 return 'BigNumber'; 266 } 267 268 if (hasNumber) { 269 for (var _i3 = 0; _i3 < N; _i3++) { 270 for (var _j3 = 0; _j3 < N; _j3++) { 271 arr[_i3][_j3] = number(arr[_i3][_j3]); 272 } 273 } 274 275 return 'number'; 276 } else { 277 throw TypeError('Matrix contains unsupported types only.'); 278 } 279 } 280 });