realSymetric.js (7832B)
1 import { clone } from '../../../utils/object.js'; 2 export function createRealSymmetric(_ref) { 3 var { 4 config, 5 addScalar, 6 subtract, 7 abs, 8 atan, 9 cos, 10 sin, 11 multiplyScalar, 12 inv, 13 bignumber, 14 multiply, 15 add 16 } = _ref; 17 18 /** 19 * @param {number[] | BigNumber[]} arr 20 * @param {number} N 21 * @param {number} prec 22 * @param {'number' | 'BigNumber'} type 23 */ 24 function main(arr, N) { 25 var prec = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : config.epsilon; 26 var type = arguments.length > 3 ? arguments[3] : undefined; 27 28 if (type === 'number') { 29 return diag(arr, prec); 30 } 31 32 if (type === 'BigNumber') { 33 return diagBig(arr, prec); 34 } 35 36 throw TypeError('Unsupported data type: ' + type); 37 } // diagonalization implementation for number (efficient) 38 39 40 function diag(x, precision) { 41 var N = x.length; 42 var e0 = Math.abs(precision / N); 43 var psi; 44 var Sij = new Array(N); // Sij is Identity Matrix 45 46 for (var i = 0; i < N; i++) { 47 Sij[i] = createArray(N, 0); 48 Sij[i][i] = 1.0; 49 } // initial error 50 51 52 var Vab = getAij(x); 53 54 while (Math.abs(Vab[1]) >= Math.abs(e0)) { 55 var _i = Vab[0][0]; 56 var j = Vab[0][1]; 57 psi = getTheta(x[_i][_i], x[j][j], x[_i][j]); 58 x = x1(x, psi, _i, j); 59 Sij = Sij1(Sij, psi, _i, j); 60 Vab = getAij(x); 61 } 62 63 var Ei = createArray(N, 0); // eigenvalues 64 65 for (var _i2 = 0; _i2 < N; _i2++) { 66 Ei[_i2] = x[_i2][_i2]; 67 } 68 69 return sorting(clone(Ei), clone(Sij)); 70 } // diagonalization implementation for bigNumber 71 72 73 function diagBig(x, precision) { 74 var N = x.length; 75 var e0 = abs(precision / N); 76 var psi; 77 var Sij = new Array(N); // Sij is Identity Matrix 78 79 for (var i = 0; i < N; i++) { 80 Sij[i] = createArray(N, 0); 81 Sij[i][i] = 1.0; 82 } // initial error 83 84 85 var Vab = getAijBig(x); 86 87 while (abs(Vab[1]) >= abs(e0)) { 88 var _i3 = Vab[0][0]; 89 var j = Vab[0][1]; 90 psi = getThetaBig(x[_i3][_i3], x[j][j], x[_i3][j]); 91 x = x1Big(x, psi, _i3, j); 92 Sij = Sij1Big(Sij, psi, _i3, j); 93 Vab = getAijBig(x); 94 } 95 96 var Ei = createArray(N, 0); // eigenvalues 97 98 for (var _i4 = 0; _i4 < N; _i4++) { 99 Ei[_i4] = x[_i4][_i4]; 100 } // return [clone(Ei), clone(Sij)] 101 102 103 return sorting(clone(Ei), clone(Sij)); 104 } // get angle 105 106 107 function getTheta(aii, ajj, aij) { 108 var denom = ajj - aii; 109 110 if (Math.abs(denom) <= config.epsilon) { 111 return Math.PI / 4.0; 112 } else { 113 return 0.5 * Math.atan(2.0 * aij / (ajj - aii)); 114 } 115 } // get angle 116 117 118 function getThetaBig(aii, ajj, aij) { 119 var denom = subtract(ajj, aii); 120 121 if (abs(denom) <= config.epsilon) { 122 return bignumber(-1).acos().div(4); 123 } else { 124 return multiplyScalar(0.5, atan(multiply(2.0, aij, inv(denom)))); 125 } 126 } // update eigvec 127 128 129 function Sij1(Sij, theta, i, j) { 130 var N = Sij.length; 131 var c = Math.cos(theta); 132 var s = Math.sin(theta); 133 var Ski = createArray(N, 0); 134 var Skj = createArray(N, 0); 135 136 for (var k = 0; k < N; k++) { 137 Ski[k] = c * Sij[k][i] - s * Sij[k][j]; 138 Skj[k] = s * Sij[k][i] + c * Sij[k][j]; 139 } 140 141 for (var _k = 0; _k < N; _k++) { 142 Sij[_k][i] = Ski[_k]; 143 Sij[_k][j] = Skj[_k]; 144 } 145 146 return Sij; 147 } // update eigvec for overlap 148 149 150 function Sij1Big(Sij, theta, i, j) { 151 var N = Sij.length; 152 var c = cos(theta); 153 var s = sin(theta); 154 var Ski = createArray(N, bignumber(0)); 155 var Skj = createArray(N, bignumber(0)); 156 157 for (var k = 0; k < N; k++) { 158 Ski[k] = subtract(multiplyScalar(c, Sij[k][i]), multiplyScalar(s, Sij[k][j])); 159 Skj[k] = addScalar(multiplyScalar(s, Sij[k][i]), multiplyScalar(c, Sij[k][j])); 160 } 161 162 for (var _k2 = 0; _k2 < N; _k2++) { 163 Sij[_k2][i] = Ski[_k2]; 164 Sij[_k2][j] = Skj[_k2]; 165 } 166 167 return Sij; 168 } // update matrix 169 170 171 function x1Big(Hij, theta, i, j) { 172 var N = Hij.length; 173 var c = bignumber(cos(theta)); 174 var s = bignumber(sin(theta)); 175 var c2 = multiplyScalar(c, c); 176 var s2 = multiplyScalar(s, s); 177 var Aki = createArray(N, bignumber(0)); 178 var Akj = createArray(N, bignumber(0)); // 2cs Hij 179 180 var csHij = multiply(bignumber(2), c, s, Hij[i][j]); // Aii 181 182 var Aii = addScalar(subtract(multiplyScalar(c2, Hij[i][i]), csHij), multiplyScalar(s2, Hij[j][j])); 183 var Ajj = add(multiplyScalar(s2, Hij[i][i]), csHij, multiplyScalar(c2, Hij[j][j])); // 0 to i 184 185 for (var k = 0; k < N; k++) { 186 Aki[k] = subtract(multiplyScalar(c, Hij[i][k]), multiplyScalar(s, Hij[j][k])); 187 Akj[k] = addScalar(multiplyScalar(s, Hij[i][k]), multiplyScalar(c, Hij[j][k])); 188 } // Modify Hij 189 190 191 Hij[i][i] = Aii; 192 Hij[j][j] = Ajj; 193 Hij[i][j] = bignumber(0); 194 Hij[j][i] = bignumber(0); // 0 to i 195 196 for (var _k3 = 0; _k3 < N; _k3++) { 197 if (_k3 !== i && _k3 !== j) { 198 Hij[i][_k3] = Aki[_k3]; 199 Hij[_k3][i] = Aki[_k3]; 200 Hij[j][_k3] = Akj[_k3]; 201 Hij[_k3][j] = Akj[_k3]; 202 } 203 } 204 205 return Hij; 206 } // update matrix 207 208 209 function x1(Hij, theta, i, j) { 210 var N = Hij.length; 211 var c = Math.cos(theta); 212 var s = Math.sin(theta); 213 var c2 = c * c; 214 var s2 = s * s; 215 var Aki = createArray(N, 0); 216 var Akj = createArray(N, 0); // Aii 217 218 var Aii = c2 * Hij[i][i] - 2 * c * s * Hij[i][j] + s2 * Hij[j][j]; 219 var Ajj = s2 * Hij[i][i] + 2 * c * s * Hij[i][j] + c2 * Hij[j][j]; // 0 to i 220 221 for (var k = 0; k < N; k++) { 222 Aki[k] = c * Hij[i][k] - s * Hij[j][k]; 223 Akj[k] = s * Hij[i][k] + c * Hij[j][k]; 224 } // Modify Hij 225 226 227 Hij[i][i] = Aii; 228 Hij[j][j] = Ajj; 229 Hij[i][j] = 0; 230 Hij[j][i] = 0; // 0 to i 231 232 for (var _k4 = 0; _k4 < N; _k4++) { 233 if (_k4 !== i && _k4 !== j) { 234 Hij[i][_k4] = Aki[_k4]; 235 Hij[_k4][i] = Aki[_k4]; 236 Hij[j][_k4] = Akj[_k4]; 237 Hij[_k4][j] = Akj[_k4]; 238 } 239 } 240 241 return Hij; 242 } // get max off-diagonal value from Upper Diagonal 243 244 245 function getAij(Mij) { 246 var N = Mij.length; 247 var maxMij = 0; 248 var maxIJ = [0, 1]; 249 250 for (var i = 0; i < N; i++) { 251 for (var j = i + 1; j < N; j++) { 252 if (Math.abs(maxMij) < Math.abs(Mij[i][j])) { 253 maxMij = Math.abs(Mij[i][j]); 254 maxIJ = [i, j]; 255 } 256 } 257 } 258 259 return [maxIJ, maxMij]; 260 } // get max off-diagonal value from Upper Diagonal 261 262 263 function getAijBig(Mij) { 264 var N = Mij.length; 265 var maxMij = 0; 266 var maxIJ = [0, 1]; 267 268 for (var i = 0; i < N; i++) { 269 for (var j = i + 1; j < N; j++) { 270 if (abs(maxMij) < abs(Mij[i][j])) { 271 maxMij = abs(Mij[i][j]); 272 maxIJ = [i, j]; 273 } 274 } 275 } 276 277 return [maxIJ, maxMij]; 278 } // sort results 279 280 281 function sorting(E, S) { 282 var N = E.length; 283 var values = Array(N); 284 var vectors = Array(N); 285 286 for (var k = 0; k < N; k++) { 287 vectors[k] = Array(N); 288 } 289 290 for (var i = 0; i < N; i++) { 291 var minID = 0; 292 var minE = E[0]; 293 294 for (var j = 0; j < E.length; j++) { 295 if (abs(E[j]) < abs(minE)) { 296 minID = j; 297 minE = E[minID]; 298 } 299 } 300 301 values[i] = E.splice(minID, 1)[0]; 302 303 for (var _k5 = 0; _k5 < N; _k5++) { 304 vectors[_k5][i] = S[_k5][minID]; 305 306 S[_k5].splice(minID, 1); 307 } 308 } 309 310 return { 311 values, 312 vectors 313 }; 314 } 315 /** 316 * Create an array of a certain size and fill all items with an initial value 317 * @param {number} size 318 * @param {number} value 319 * @return {number[]} 320 */ 321 322 323 function createArray(size, value) { 324 // TODO: as soon as all browsers support Array.fill, use that instead (IE doesn't support it) 325 var array = new Array(size); 326 327 for (var i = 0; i < size; i++) { 328 array[i] = value; 329 } 330 331 return array; 332 } 333 334 return main; 335 }