in commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/linear/SingularValueDecomposition.java [87:480]
public SingularValueDecomposition(final RealMatrix matrix) {
final double[][] A;
// "m" is always the largest dimension.
if (matrix.getRowDimension() < matrix.getColumnDimension()) {
transposed = true;
A = matrix.transpose().getData();
m = matrix.getColumnDimension();
n = matrix.getRowDimension();
} else {
transposed = false;
A = matrix.getData();
m = matrix.getRowDimension();
n = matrix.getColumnDimension();
}
singularValues = new double[n];
final double[][] U = new double[m][n];
final double[][] V = new double[n][n];
final double[] e = new double[n];
final double[] work = new double[m];
// Reduce A to bidiagonal form, storing the diagonal elements
// in s and the super-diagonal elements in e.
final int nct = JdkMath.min(m - 1, n);
final int nrt = JdkMath.max(0, n - 2);
for (int k = 0; k < JdkMath.max(nct, nrt); k++) {
if (k < nct) {
// Compute the transformation for the k-th column and
// place the k-th diagonal in s[k].
// Compute 2-norm of k-th column without under/overflow.
singularValues[k] = 0;
for (int i = k; i < m; i++) {
singularValues[k] = JdkMath.hypot(singularValues[k], A[i][k]);
}
if (singularValues[k] != 0) {
if (A[k][k] < 0) {
singularValues[k] = -singularValues[k];
}
for (int i = k; i < m; i++) {
A[i][k] /= singularValues[k];
}
A[k][k] += 1;
}
singularValues[k] = -singularValues[k];
}
for (int j = k + 1; j < n; j++) {
if (k < nct &&
singularValues[k] != 0) {
// Apply the transformation.
double t = 0;
for (int i = k; i < m; i++) {
t += A[i][k] * A[i][j];
}
t = -t / A[k][k];
for (int i = k; i < m; i++) {
A[i][j] += t * A[i][k];
}
}
// Place the k-th row of A into e for the
// subsequent calculation of the row transformation.
e[j] = A[k][j];
}
if (k < nct) {
// Place the transformation in U for subsequent back
// multiplication.
for (int i = k; i < m; i++) {
U[i][k] = A[i][k];
}
}
if (k < nrt) {
// Compute the k-th row transformation and place the
// k-th super-diagonal in e[k].
// Compute 2-norm without under/overflow.
e[k] = 0;
for (int i = k + 1; i < n; i++) {
e[k] = JdkMath.hypot(e[k], e[i]);
}
if (e[k] != 0) {
if (e[k + 1] < 0) {
e[k] = -e[k];
}
for (int i = k + 1; i < n; i++) {
e[i] /= e[k];
}
e[k + 1] += 1;
}
e[k] = -e[k];
if (k + 1 < m &&
e[k] != 0) {
// Apply the transformation.
for (int i = k + 1; i < m; i++) {
work[i] = 0;
}
for (int j = k + 1; j < n; j++) {
for (int i = k + 1; i < m; i++) {
work[i] += e[j] * A[i][j];
}
}
for (int j = k + 1; j < n; j++) {
final double t = -e[j] / e[k + 1];
for (int i = k + 1; i < m; i++) {
A[i][j] += t * work[i];
}
}
}
// Place the transformation in V for subsequent
// back multiplication.
for (int i = k + 1; i < n; i++) {
V[i][k] = e[i];
}
}
}
// Set up the final bidiagonal matrix or order p.
int p = n;
if (nct < n) {
singularValues[nct] = A[nct][nct];
}
if (m < p) {
singularValues[p - 1] = 0;
}
if (nrt + 1 < p) {
e[nrt] = A[nrt][p - 1];
}
e[p - 1] = 0;
// Generate U.
for (int j = nct; j < n; j++) {
for (int i = 0; i < m; i++) {
U[i][j] = 0;
}
U[j][j] = 1;
}
for (int k = nct - 1; k >= 0; k--) {
if (singularValues[k] != 0) {
for (int j = k + 1; j < n; j++) {
double t = 0;
for (int i = k; i < m; i++) {
t += U[i][k] * U[i][j];
}
t = -t / U[k][k];
for (int i = k; i < m; i++) {
U[i][j] += t * U[i][k];
}
}
for (int i = k; i < m; i++) {
U[i][k] = -U[i][k];
}
U[k][k] = 1 + U[k][k];
for (int i = 0; i < k - 1; i++) {
U[i][k] = 0;
}
} else {
for (int i = 0; i < m; i++) {
U[i][k] = 0;
}
U[k][k] = 1;
}
}
// Generate V.
for (int k = n - 1; k >= 0; k--) {
if (k < nrt &&
e[k] != 0) {
for (int j = k + 1; j < n; j++) {
double t = 0;
for (int i = k + 1; i < n; i++) {
t += V[i][k] * V[i][j];
}
t = -t / V[k + 1][k];
for (int i = k + 1; i < n; i++) {
V[i][j] += t * V[i][k];
}
}
}
for (int i = 0; i < n; i++) {
V[i][k] = 0;
}
V[k][k] = 1;
}
// Main iteration loop for the singular values.
final int pp = p - 1;
while (p > 0) {
int k;
int kase;
// Here is where a test for too many iterations would go.
// This section of the program inspects for
// negligible elements in the s and e arrays. On
// completion the variables kase and k are set as follows.
// kase = 1 if s(p) and e[k-1] are negligible and k<p
// kase = 2 if s(k) is negligible and k<p
// kase = 3 if e[k-1] is negligible, k<p, and
// s(k), ..., s(p) are not negligible (qr step).
// kase = 4 if e(p-1) is negligible (convergence).
for (k = p - 2; k >= 0; k--) {
final double threshold
= TINY + EPS * (JdkMath.abs(singularValues[k]) +
JdkMath.abs(singularValues[k + 1]));
// the following condition is written this way in order
// to break out of the loop when NaN occurs, writing it
// as "if (JdkMath.abs(e[k]) <= threshold)" would loop
// indefinitely in case of NaNs because comparison on NaNs
// always return false, regardless of what is checked
// see issue MATH-947
if (!(JdkMath.abs(e[k]) > threshold)) {
e[k] = 0;
break;
}
}
if (k == p - 2) {
kase = 4;
} else {
int ks;
for (ks = p - 1; ks >= k; ks--) {
if (ks == k) {
break;
}
final double t = (ks != p ? JdkMath.abs(e[ks]) : 0) +
(ks != k + 1 ? JdkMath.abs(e[ks - 1]) : 0);
if (JdkMath.abs(singularValues[ks]) <= TINY + EPS * t) {
singularValues[ks] = 0;
break;
}
}
if (ks == k) {
kase = 3;
} else if (ks == p - 1) {
kase = 1;
} else {
kase = 2;
k = ks;
}
}
k++;
// Perform the task indicated by kase.
double f;
switch (kase) {
// Deflate negligible s(p).
case 1:
f = e[p - 2];
e[p - 2] = 0;
for (int j = p - 2; j >= k; j--) {
double t = JdkMath.hypot(singularValues[j], f);
final double cs = singularValues[j] / t;
final double sn = f / t;
singularValues[j] = t;
if (j != k) {
f = -sn * e[j - 1];
e[j - 1] = cs * e[j - 1];
}
for (int i = 0; i < n; i++) {
t = cs * V[i][j] + sn * V[i][p - 1];
V[i][p - 1] = -sn * V[i][j] + cs * V[i][p - 1];
V[i][j] = t;
}
}
break;
// Split at negligible s(k).
case 2:
f = e[k - 1];
e[k - 1] = 0;
for (int j = k; j < p; j++) {
double t = JdkMath.hypot(singularValues[j], f);
final double cs = singularValues[j] / t;
final double sn = f / t;
singularValues[j] = t;
f = -sn * e[j];
e[j] = cs * e[j];
for (int i = 0; i < m; i++) {
t = cs * U[i][j] + sn * U[i][k - 1];
U[i][k - 1] = -sn * U[i][j] + cs * U[i][k - 1];
U[i][j] = t;
}
}
break;
// Perform one qr step.
case 3:
// Calculate the shift.
final double maxPm1Pm2 = JdkMath.max(JdkMath.abs(singularValues[p - 1]),
JdkMath.abs(singularValues[p - 2]));
final double scale = JdkMath.max(JdkMath.max(JdkMath.max(maxPm1Pm2,
JdkMath.abs(e[p - 2])),
JdkMath.abs(singularValues[k])),
JdkMath.abs(e[k]));
final double sp = singularValues[p - 1] / scale;
final double spm1 = singularValues[p - 2] / scale;
final double epm1 = e[p - 2] / scale;
final double sk = singularValues[k] / scale;
final double ek = e[k] / scale;
final double b = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2.0;
final double c = (sp * epm1) * (sp * epm1);
double shift = 0;
if (b != 0 ||
c != 0) {
shift = JdkMath.sqrt(b * b + c);
if (b < 0) {
shift = -shift;
}
shift = c / (b + shift);
}
f = (sk + sp) * (sk - sp) + shift;
double g = sk * ek;
// Chase zeros.
for (int j = k; j < p - 1; j++) {
double t = JdkMath.hypot(f, g);
double cs = f / t;
double sn = g / t;
if (j != k) {
e[j - 1] = t;
}
f = cs * singularValues[j] + sn * e[j];
e[j] = cs * e[j] - sn * singularValues[j];
g = sn * singularValues[j + 1];
singularValues[j + 1] = cs * singularValues[j + 1];
for (int i = 0; i < n; i++) {
t = cs * V[i][j] + sn * V[i][j + 1];
V[i][j + 1] = -sn * V[i][j] + cs * V[i][j + 1];
V[i][j] = t;
}
t = JdkMath.hypot(f, g);
cs = f / t;
sn = g / t;
singularValues[j] = t;
f = cs * e[j] + sn * singularValues[j + 1];
singularValues[j + 1] = -sn * e[j] + cs * singularValues[j + 1];
g = sn * e[j + 1];
e[j + 1] = cs * e[j + 1];
if (j < m - 1) {
for (int i = 0; i < m; i++) {
t = cs * U[i][j] + sn * U[i][j + 1];
U[i][j + 1] = -sn * U[i][j] + cs * U[i][j + 1];
U[i][j] = t;
}
}
}
e[p - 2] = f;
break;
// Convergence.
default:
// Make the singular values positive.
if (singularValues[k] <= 0) {
singularValues[k] = singularValues[k] < 0 ? -singularValues[k] : 0;
for (int i = 0; i <= pp; i++) {
V[i][k] = -V[i][k];
}
}
// Order the singular values.
while (k < pp) {
if (singularValues[k] >= singularValues[k + 1]) {
break;
}
double t = singularValues[k];
singularValues[k] = singularValues[k + 1];
singularValues[k + 1] = t;
if (k < n - 1) {
for (int i = 0; i < n; i++) {
t = V[i][k + 1];
V[i][k + 1] = V[i][k];
V[i][k] = t;
}
}
if (k < m - 1) {
for (int i = 0; i < m; i++) {
t = U[i][k + 1];
U[i][k + 1] = U[i][k];
U[i][k] = t;
}
}
k++;
}
p--;
break;
}
}
// Set the small value tolerance used to calculate rank and pseudo-inverse
tol = JdkMath.max(m * singularValues[0] * EPS,
JdkMath.sqrt(Precision.SAFE_MIN));
if (!transposed) {
cachedU = MatrixUtils.createRealMatrix(U);
cachedV = MatrixUtils.createRealMatrix(V);
} else {
cachedU = MatrixUtils.createRealMatrix(V);
cachedV = MatrixUtils.createRealMatrix(U);
}
}