UNPKG

molstar

Version:

A comprehensive macromolecular library.

281 lines 8.55 kB
"use strict"; /** * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ Object.defineProperty(exports, "__esModule", { value: true }); exports.svd = exports.JacobiSVDImpl = exports.hypot = exports.swap = void 0; var matrix_1 = require("./matrix"); // svd method adapted from http://inspirit.github.io/jsfeat/ MIT Eugene Zatepyakin function swap(A, i0, i1, t) { t = A[i0]; A[i0] = A[i1]; A[i1] = t; } exports.swap = swap; function hypot(a, b) { a = Math.abs(a); b = Math.abs(b); if (a > b) { b /= a; return a * Math.sqrt(1.0 + b * b); } if (b > 0) { a /= b; return b * Math.sqrt(1.0 + a * a); } return 0.0; } exports.hypot = hypot; var EPSILON = 0.0000001192092896; var FLT_MIN = 1E-37; function JacobiSVDImpl(At, astep, _W, Vt, vstep, m, n, n1) { var eps = EPSILON * 2.0; var minval = FLT_MIN; var i = 0; var j = 0; var k = 0; var iter = 0; var maxIter = Math.max(m, 30); var Ai = 0; var Aj = 0; var Vi = 0; var Vj = 0; var changed = 0; var c = 0.0; var s = 0.0; var t = 0.0; var t0 = 0.0; var t1 = 0.0; var sd = 0.0; var beta = 0.0; var gamma = 0.0; var delta = 0.0; var a = 0.0; var p = 0.0; var b = 0.0; var seed = 0x1234; var val = 0.0; var val0 = 0.0; var asum = 0.0; var W = new Float64Array(n << 3); for (; i < n; i++) { for (k = 0, sd = 0; k < m; k++) { t = At[i * astep + k]; sd += t * t; } W[i] = sd; if (Vt) { for (k = 0; k < n; k++) { Vt[i * vstep + k] = 0; } Vt[i * vstep + i] = 1; } } for (; iter < maxIter; iter++) { changed = 0; for (i = 0; i < n - 1; i++) { for (j = i + 1; j < n; j++) { Ai = (i * astep) | 0; Aj = (j * astep) | 0; a = W[i]; p = 0; b = W[j]; k = 2; p += At[Ai] * At[Aj]; p += At[Ai + 1] * At[Aj + 1]; for (; k < m; k++) { p += At[Ai + k] * At[Aj + k]; } if (Math.abs(p) <= eps * Math.sqrt(a * b)) continue; p *= 2.0; beta = a - b; gamma = hypot(p, beta); if (beta < 0) { delta = (gamma - beta) * 0.5; s = Math.sqrt(delta / gamma); c = (p / (gamma * s * 2.0)); } else { c = Math.sqrt((gamma + beta) / (gamma * 2.0)); s = (p / (gamma * c * 2.0)); } a = 0.0; b = 0.0; k = 2; // unroll t0 = c * At[Ai] + s * At[Aj]; t1 = -s * At[Ai] + c * At[Aj]; At[Ai] = t0; At[Aj] = t1; a += t0 * t0; b += t1 * t1; t0 = c * At[Ai + 1] + s * At[Aj + 1]; t1 = -s * At[Ai + 1] + c * At[Aj + 1]; At[Ai + 1] = t0; At[Aj + 1] = t1; a += t0 * t0; b += t1 * t1; for (; k < m; k++) { t0 = c * At[Ai + k] + s * At[Aj + k]; t1 = -s * At[Ai + k] + c * At[Aj + k]; At[Ai + k] = t0; At[Aj + k] = t1; a += t0 * t0; b += t1 * t1; } W[i] = a; W[j] = b; changed = 1; if (Vt) { Vi = (i * vstep) | 0; Vj = (j * vstep) | 0; k = 2; t0 = c * Vt[Vi] + s * Vt[Vj]; t1 = -s * Vt[Vi] + c * Vt[Vj]; Vt[Vi] = t0; Vt[Vj] = t1; t0 = c * Vt[Vi + 1] + s * Vt[Vj + 1]; t1 = -s * Vt[Vi + 1] + c * Vt[Vj + 1]; Vt[Vi + 1] = t0; Vt[Vj + 1] = t1; for (; k < n; k++) { t0 = c * Vt[Vi + k] + s * Vt[Vj + k]; t1 = -s * Vt[Vi + k] + c * Vt[Vj + k]; Vt[Vi + k] = t0; Vt[Vj + k] = t1; } } } } if (changed === 0) break; } for (i = 0; i < n; i++) { for (k = 0, sd = 0; k < m; k++) { t = At[i * astep + k]; sd += t * t; } W[i] = Math.sqrt(sd); } for (i = 0; i < n - 1; i++) { j = i; for (k = i + 1; k < n; k++) { if (W[j] < W[k]) { j = k; } } if (i !== j) { swap(W, i, j, sd); if (Vt) { for (k = 0; k < m; k++) { swap(At, i * astep + k, j * astep + k, t); } for (k = 0; k < n; k++) { swap(Vt, i * vstep + k, j * vstep + k, t); } } } } for (i = 0; i < n; i++) { _W[i] = W[i]; } if (!Vt) { return; } for (i = 0; i < n1; i++) { sd = i < n ? W[i] : 0; while (sd <= minval) { // if we got a zero singular value, then in order to get the corresponding left singular vector // we generate a random vector, project it to the previously computed left singular vectors, // subtract the projection and normalize the difference. val0 = (1.0 / m); for (k = 0; k < m; k++) { seed = (seed * 214013 + 2531011); val = (((seed >> 16) & 0x7fff) & 256) !== 0 ? val0 : -val0; At[i * astep + k] = val; } for (iter = 0; iter < 2; iter++) { for (j = 0; j < i; j++) { sd = 0; for (k = 0; k < m; k++) { sd += At[i * astep + k] * At[j * astep + k]; } asum = 0.0; for (k = 0; k < m; k++) { t = (At[i * astep + k] - sd * At[j * astep + k]); At[i * astep + k] = t; asum += Math.abs(t); } asum = asum ? 1.0 / asum : 0; for (k = 0; k < m; k++) { At[i * astep + k] *= asum; } } } sd = 0; for (k = 0; k < m; k++) { t = At[i * astep + k]; sd += t * t; } sd = Math.sqrt(sd); } s = (1.0 / sd); for (k = 0; k < m; k++) { At[i * astep + k] *= s; } } } exports.JacobiSVDImpl = JacobiSVDImpl; function svd(A, W, U, V) { var at = 0; var i = 0; var _m = A.rows; var _n = A.cols; var m = _m; var n = _n; if (m < n) { at = 1; i = m; m = n; n = i; } var amt = matrix_1.Matrix.create(m, m); var wmt = matrix_1.Matrix.create(1, n); var vmt = matrix_1.Matrix.create(n, n); if (at === 0) { matrix_1.Matrix.transpose(amt, A); } else { for (i = 0; i < _n * _m; i++) { amt.data[i] = A.data[i]; } for (; i < n * m; i++) { amt.data[i] = 0; } } JacobiSVDImpl(amt.data, m, wmt.data, vmt.data, n, m, n, m); if (W) { for (i = 0; i < n; i++) { W.data[i] = wmt.data[i]; } for (; i < _n; i++) { W.data[i] = 0; } } if (at === 0) { if (U) matrix_1.Matrix.transpose(U, amt); if (V) matrix_1.Matrix.transpose(V, vmt); } else { if (U) matrix_1.Matrix.transpose(U, vmt); if (V) matrix_1.Matrix.transpose(V, amt); } } exports.svd = svd; //# sourceMappingURL=svd.js.map