public SVD(Matrix M) { Matrix A; /* The implementation requires that rows > columns. * If this is not the case, we decompose M^T instead. * Swapping the resulting U and V gives the desired * result for M as * * M^T = U S V^T (decomposition of M^T) * * M = (U S V^T)^T (transpose) * * M = (V^T^T S^T U^T) ((AB)^T = B^T A^T) * * M = V S U^T (idempotence of transposition, * symmetry of diagonal matrix S) */ if (M.rows() >= M.columns()) { A = new Matrix(M); transpose_ = false; } else { A = Matrix.transpose(M); transpose_ = true; } m_ = A.rows(); n_ = A.columns(); // we're sure that m_ >= n_ s_ = new Vector(n_); U_ = new Matrix(m_, n_); V_ = new Matrix(n_, n_); Vector e = new Vector(n_); Vector work = new Vector(m_); int i, j, k; // Reduce A to bidiagonal form, storing the diagonal elements // in s and the super-diagonal elements in e. int nct = Math.Min(m_ - 1, n_); int nrt = Math.Max(0, n_ - 2); for (k = 0; k < Math.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. s_[k] = 0; for (i = k; i < m_; i++) { s_[k] = hypot(s_[k], A[i, k]); } if (s_[k] != 0.0) { if (A[k, k] < 0.0) { s_[k] = -s_[k]; } for (i = k; i < m_; i++) { A[i, k] /= s_[k]; } A[k, k] += 1.0; } s_[k] = -s_[k]; } for (j = k + 1; j < n_; j++) { if ((k < nct) && (s_[k] != 0.0)) { // Apply the transformation. double t = 0; for (i = k; i < m_; i++) { t += A[i, k] * A[i, j]; } t = -t / A[k, k]; for (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 (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 (i = k + 1; i < n_; i++) { e[k] = hypot(e[k], e[i]); } if (e[k] != 0.0) { if (e[k + 1] < 0.0) { e[k] = -e[k]; } for (i = k + 1; i < n_; i++) { e[i] /= e[k]; } e[k + 1] += 1.0; } e[k] = -e[k]; if ((k + 1 < m_) & (e[k] != 0.0)) { // Apply the transformation. for (i = k + 1; i < m_; i++) { work[i] = 0.0; } for (j = k + 1; j < n_; j++) { for (i = k + 1; i < m_; i++) { work[i] += e[j] * A[i, j]; } } for (j = k + 1; j < n_; j++) { double t = -e[j] / e[k + 1]; for (i = k + 1; i < m_; i++) { A[i, j] += t * work[i]; } } } // Place the transformation in V for subsequent back multiplication. for (i = k + 1; i < n_; i++) { V_[i, k] = e[i]; } } } // Set up the final bidiagonal matrix or order n. if (nct < n_) { s_[nct] = A[nct, nct]; } if (nrt + 1 < n_) { e[nrt] = A[nrt, n_ - 1]; } e[n_ - 1] = 0.0; // generate U for (j = nct; j < n_; j++) { for (i = 0; i < m_; i++) { U_[i, j] = 0.0; } U_[j, j] = 1.0; } for (k = nct - 1; k >= 0; --k) { if (s_[k] != 0.0) { for (j = k + 1; j < n_; ++j) { double t = 0; for (i = k; i < m_; i++) { t += U_[i, k] * U_[i, j]; } t = -t / U_[k, k]; for (i = k; i < m_; i++) { U_[i, j] += t * U_[i, k]; } } for (i = k; i < m_; i++) { U_[i, k] = -U_[i, k]; } U_[k, k] = 1.0 + U_[k, k]; for (i = 0; i < k - 1; i++) { U_[i, k] = 0.0; } } else { for (i = 0; i < m_; i++) { U_[i, k] = 0.0; } U_[k, k] = 1.0; } } // generate V for (k = n_ - 1; k >= 0; --k) { if ((k < nrt) & (e[k] != 0.0)) { for (j = k + 1; j < n_; ++j) { double t = 0; for (i = k + 1; i < n_; i++) { t += V_[i, k] * V_[i, j]; } t = -t / V_[k + 1, k]; for (i = k + 1; i < n_; i++) { V_[i, j] += t * V_[i, k]; } } } for (i = 0; i < n_; i++) { V_[i, k] = 0.0; } V_[k, k] = 1.0; } // Main iteration loop for the singular values. int p = n_, pp = p - 1; int iter = 0; double eps = Math.Pow(2.0, -52.0); while (p > 0) { 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 >= -1; --k) { if (k == -1) { break; } if (Math.Abs(e[k]) <= eps * (Math.Abs(s_[k]) + Math.Abs(s_[k + 1]))) { e[k] = 0.0; break; } } if (k == p - 2) { kase = 4; } else { int ks; for (ks = p - 1; ks >= k; --ks) { if (ks == k) { break; } double t = (ks != p ? Math.Abs(e[ks]) : 0) + (ks != k + 1 ? Math.Abs(e[ks - 1]) : 0); if (Math.Abs(s_[ks]) <= eps * t) { s_[ks] = 0.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. switch (kase) { // Deflate negligible s(p). case 1: { double f = e[p - 2]; e[p - 2] = 0.0; for (j = p - 2; j >= k; --j) { double t = hypot(s_[j], f); double cs = s_[j] / t; double sn = f / t; s_[j] = t; if (j != k) { f = -sn * e[j - 1]; e[j - 1] = cs * e[j - 1]; } for (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: { double f = e[k - 1]; e[k - 1] = 0.0; for (j = k; j < p; j++) { double t = hypot(s_[j], f); double cs = s_[j] / t; double sn = f / t; s_[j] = t; f = -sn * e[j]; e[j] = cs * e[j]; for (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. double scale = Math.Max( Math.Max( Math.Max( Math.Max(Math.Abs(s_[p - 1]), Math.Abs(s_[p - 2])), Math.Abs(e[p - 2])), Math.Abs(s_[k])), Math.Abs(e[k])); double sp = s_[p - 1] / scale; double spm1 = s_[p - 2] / scale; double epm1 = e[p - 2] / scale; double sk = s_[k] / scale; double ek = e[k] / scale; double b = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2.0; double c = (sp * epm1) * (sp * epm1); double shift = 0.0; if ((b != 0.0) | (c != 0.0)) { shift = Math.Sqrt(b * b + c); if (b < 0.0) { shift = -shift; } shift = c / (b + shift); } double f = (sk + sp) * (sk - sp) + shift; double g = sk * ek; // Chase zeros. for (j = k; j < p - 1; j++) { double t = hypot(f, g); double cs = f / t; double sn = g / t; if (j != k) { e[j - 1] = t; } f = cs * s_[j] + sn * e[j]; e[j] = cs * e[j] - sn * s_[j]; g = sn * s_[j + 1]; s_[j + 1] = cs * s_[j + 1]; for (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 = hypot(f, g); cs = f / t; sn = g / t; s_[j] = t; f = cs * e[j] + sn * s_[j + 1]; s_[j + 1] = -sn * e[j] + cs * s_[j + 1]; g = sn * e[j + 1]; e[j + 1] = cs * e[j + 1]; if (j < m_ - 1) { for (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; iter = iter + 1; } break; // Convergence. case 4: { // Make the singular values positive. if (s_[k] <= 0.0) { s_[k] = (s_[k] < 0.0 ? -s_[k] : 0.0); for (i = 0; i <= pp; i++) { V_[i, k] = -V_[i, k]; } } // Order the singular values. while (k < pp) { if (s_[k] >= s_[k + 1]) { break; } s_.swap(k, k + 1); if (k < n_ - 1) { for (i = 0; i < n_; i++) { V_.swap(i, k, i, k + 1); } } if (k < m_ - 1) { for (i = 0; i < m_; i++) { U_.swap(i, k, i, k + 1); } } k++; } iter = 0; --p; } break; } } }
public SVD(Matrix M) { Matrix A; /* The implementation requires that rows > columns. If this is not the case, we decompose M^T instead. Swapping the resulting U and V gives the desired result for M as M^T = U S V^T (decomposition of M^T) M = (U S V^T)^T (transpose) M = (V^T^T S^T U^T) ((AB)^T = B^T A^T) M = V S U^T (idempotence of transposition, symmetry of diagonal matrix S) */ if (M.rows() >= M.columns()) { A = new Matrix(M); transpose_ = false; } else { A = Matrix.transpose(M); transpose_ = true; } m_ = A.rows(); n_ = A.columns(); // we're sure that m_ >= n_ s_ = new Vector(n_); U_ = new Matrix(m_, n_); V_ = new Matrix(n_, n_); Vector e = new Vector(n_); Vector work = new Vector(m_); int i, j, k; // Reduce A to bidiagonal form, storing the diagonal elements // in s and the super-diagonal elements in e. int nct = Math.Min(m_ - 1, n_); int nrt = Math.Max(0, n_ - 2); for (k = 0; k < Math.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. s_[k] = 0; for (i = k; i < m_; i++) { s_[k] = hypot(s_[k], A[i, k]); } if (s_[k] != 0.0) { if (A[k, k] < 0.0) { s_[k] = -s_[k]; } for (i = k; i < m_; i++) { A[i, k] /= s_[k]; } A[k, k] += 1.0; } s_[k] = -s_[k]; } for (j = k + 1; j < n_; j++) { if ((k < nct) && (s_[k] != 0.0)) { // Apply the transformation. double t = 0; for (i = k; i < m_; i++) { t += A[i, k] * A[i, j]; } t = -t / A[k, k]; for (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 (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 (i = k + 1; i < n_; i++) { e[k] = hypot(e[k], e[i]); } if (e[k] != 0.0) { if (e[k + 1] < 0.0) { e[k] = -e[k]; } for (i = k + 1; i < n_; i++) { e[i] /= e[k]; } e[k + 1] += 1.0; } e[k] = -e[k]; if ((k + 1 < m_) & (e[k] != 0.0)) { // Apply the transformation. for (i = k + 1; i < m_; i++) { work[i] = 0.0; } for (j = k + 1; j < n_; j++) { for (i = k + 1; i < m_; i++) { work[i] += e[j] * A[i, j]; } } for (j = k + 1; j < n_; j++) { double t = -e[j] / e[k + 1]; for (i = k + 1; i < m_; i++) { A[i, j] += t * work[i]; } } } // Place the transformation in V for subsequent back multiplication. for (i = k + 1; i < n_; i++) { V_[i, k] = e[i]; } } } // Set up the final bidiagonal matrix or order n. if (nct < n_) { s_[nct] = A[nct, nct]; } if (nrt + 1 < n_) { e[nrt] = A[nrt, n_ - 1]; } e[n_ - 1] = 0.0; // generate U for (j = nct; j < n_; j++) { for (i = 0; i < m_; i++) { U_[i, j] = 0.0; } U_[j, j] = 1.0; } for (k = nct - 1; k >= 0; --k) { if (s_[k] != 0.0) { for (j = k + 1; j < n_; ++j) { double t = 0; for (i = k; i < m_; i++) { t += U_[i, k] * U_[i, j]; } t = -t / U_[k, k]; for (i = k; i < m_; i++) { U_[i, j] += t * U_[i, k]; } } for (i = k; i < m_; i++) { U_[i, k] = -U_[i, k]; } U_[k, k] = 1.0 + U_[k, k]; for (i = 0; i < k - 1; i++) { U_[i, k] = 0.0; } } else { for (i = 0; i < m_; i++) { U_[i, k] = 0.0; } U_[k, k] = 1.0; } } // generate V for (k = n_ - 1; k >= 0; --k) { if ((k < nrt) & (e[k] != 0.0)) { for (j = k + 1; j < n_; ++j) { double t = 0; for (i = k + 1; i < n_; i++) { t += V_[i, k] * V_[i, j]; } t = -t / V_[k + 1, k]; for (i = k + 1; i < n_; i++) { V_[i, j] += t * V_[i, k]; } } } for (i = 0; i < n_; i++) { V_[i, k] = 0.0; } V_[k, k] = 1.0; } // Main iteration loop for the singular values. int p = n_, pp = p - 1; int iter = 0; double eps = Math.Pow(2.0, -52.0); while (p > 0) { 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 >= -1; --k) { if (k == -1) { break; } if (Math.Abs(e[k]) <= eps * (Math.Abs(s_[k]) + Math.Abs(s_[k + 1]))) { e[k] = 0.0; break; } } if (k == p - 2) { kase = 4; } else { int ks; for (ks = p - 1; ks >= k; --ks) { if (ks == k) { break; } double t = (ks != p ? Math.Abs(e[ks]) : 0) + (ks != k + 1 ? Math.Abs(e[ks - 1]) : 0); if (Math.Abs(s_[ks]) <= eps * t) { s_[ks] = 0.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. switch (kase) { // Deflate negligible s(p). case 1: { double f = e[p - 2]; e[p - 2] = 0.0; for (j = p - 2; j >= k; --j) { double t = hypot(s_[j], f); double cs = s_[j] / t; double sn = f / t; s_[j] = t; if (j != k) { f = -sn * e[j - 1]; e[j - 1] = cs * e[j - 1]; } for (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: { double f = e[k - 1]; e[k - 1] = 0.0; for (j = k; j < p; j++) { double t = hypot(s_[j], f); double cs = s_[j] / t; double sn = f / t; s_[j] = t; f = -sn * e[j]; e[j] = cs * e[j]; for (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. double scale = Math.Max( Math.Max( Math.Max( Math.Max(Math.Abs(s_[p - 1]), Math.Abs(s_[p - 2])), Math.Abs(e[p - 2])), Math.Abs(s_[k])), Math.Abs(e[k])); double sp = s_[p - 1] / scale; double spm1 = s_[p - 2] / scale; double epm1 = e[p - 2] / scale; double sk = s_[k] / scale; double ek = e[k] / scale; double b = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2.0; double c = (sp * epm1) * (sp * epm1); double shift = 0.0; if ((b != 0.0) | (c != 0.0)) { shift = Math.Sqrt(b * b + c); if (b < 0.0) { shift = -shift; } shift = c / (b + shift); } double f = (sk + sp) * (sk - sp) + shift; double g = sk * ek; // Chase zeros. for (j = k; j < p - 1; j++) { double t = hypot(f, g); double cs = f / t; double sn = g / t; if (j != k) { e[j - 1] = t; } f = cs * s_[j] + sn * e[j]; e[j] = cs * e[j] - sn * s_[j]; g = sn * s_[j + 1]; s_[j + 1] = cs * s_[j + 1]; for (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 = hypot(f, g); cs = f / t; sn = g / t; s_[j] = t; f = cs * e[j] + sn * s_[j + 1]; s_[j + 1] = -sn * e[j] + cs * s_[j + 1]; g = sn * e[j + 1]; e[j + 1] = cs * e[j + 1]; if (j < m_ - 1) { for (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; iter = iter + 1; } break; // Convergence. case 4: { // Make the singular values positive. if (s_[k] <= 0.0) { s_[k] = (s_[k] < 0.0 ? -s_[k] : 0.0); for (i = 0; i <= pp; i++) { V_[i, k] = -V_[i, k]; } } // Order the singular values. while (k < pp) { if (s_[k] >= s_[k + 1]) { break; } s_.swap(k, k + 1); if (k < n_ - 1) { for (i = 0; i < n_; i++) { V_.swap(i, k, i, k + 1); } } if (k < m_ - 1) { for (i = 0; i < m_; i++) { U_.swap(i, k, i, k + 1); } } k++; } iter = 0; --p; } break; } } }