在之前的文章中,我对SVD进行了大致的了解,它在互联网高端领域中有广泛的应用,至于它的一些详细应
用以后再进一步学习。现在主要的问题是如何有效地实现SVD分解,接下来我会先用两种方法来实现SVD分
解,即基于双边Jacobi旋转的SVD和基于单边Jacobi旋转的SVD。
这两种方法重点参考中国知网上的一篇论文:《并行JACOBI方法求解矩阵奇异值的研究》
代码:
#include <string.h> #include <stdio.h> #include <math.h> #include <map> #include "matrix.h" using namespace std; const double EPS = 1e-8; const int ITER_NUM = 30; int sign(double x) { if(x < 0) return -1; return 1; } void rotate(Matrix<double> &matrix, int i, int j, bool &pass, Matrix<double> &J) { double ele = matrix.get(i, j); if(fabs(ele) < EPS) return; pass = false; double ele1 = matrix.get(i, i); double ele2 = matrix.get(j, j); double tao = (ele1 - ele2) / (2 * ele); double tan = sign(tao) / (fabs(tao) + sqrt(1 + pow(tao, 2))); double cos = 1 / sqrt(1 + pow(tan, 2)); double sin = cos * tan; int size = matrix.getRows(); Matrix<double>G(IdentityMatrix<double>(size, size)); G.put(i, i, cos); G.put(i, j, -1 * sin); G.put(j, i, sin); G.put(j, j, cos); matrix = G.getTranspose() * matrix * G; J *= G; } void jacobi(Matrix<double> &matrix, int size, vector<double> &E, Matrix<double> &J) { int iter_num = ITER_NUM; while(iter_num-- > 0) { bool pass = true; for(int i = 0; i < size; i++) { for(int j = i + 1; j < size; j++) rotate(matrix, i, j, pass, J); } if(pass) break; } cout << "迭代次数:" << ITER_NUM - iter_num << endl; for(int i = 0; i < size; i++) { E[i] = matrix.get(i, i); if(E[i] < EPS) E[i] = 0.0; } } void svd(Matrix<double> &A, Matrix<double> &U, Matrix<double> &V, vector<double> &E) { int rows = A.getRows(); int columns = A.getColumns(); assert(rows <= columns); assert(U.getRows() == rows); assert(U.getColumns() == rows); assert(V.getRows() == columns); assert(V.getColumns() == columns); assert(E.size() == columns); Matrix<double> B = A.getTranspose() * A; Matrix<double> J(IdentityMatrix<double>(columns, columns)); vector<double> S(columns); jacobi(B, columns, S, J); for(int i = 0; i < S.size(); i++) S[i] = sqrt(S[i]); multimap<double, int> eigen; for(int i = 0; i < S.size(); i++) eigen.insert(make_pair(S[i], i)); multimap<double, int>::const_iterator iter = --eigen.end(); int num_eig = 0; for(int i = 0; i < columns; i++, iter--) { int index = iter->second; E[i] = S[index]; if(E[i] > EPS) num_eig++; for(int row = 0; row < columns; row++) V.put(row, i, J.get(row, index)); } assert(num_eig <= rows); for(int i = 0; i < num_eig; i++) { Matrix<double> vi = V.getColumn(i); double sigma = E[i]; Matrix<double> ui(rows, 1); ui = A * vi; for(int j = 0; j < rows; j++) U.put(j, i, ui.get(j, 0) / sigma); } } int main() { const int ROW = 4; const int COL = 5; assert(ROW <= COL); double arr[ROW * COL] = {1, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0 }; Matrix<double> A(ROW, COL); A = arr; Matrix<double> U(ROW, ROW); Matrix<double> V(COL, COL); vector<double> E(COL); svd(A, U, V, E); Matrix<double> Sigma(ROW, COL); for(int i = 0; i < ROW; i++) Sigma.put(i, i, E[i]); cout << "U = " << endl << U; cout << "Sigma = " << endl << Sigma; cout << "V^T = " << endl << V.getTranspose(); Matrix<double> AA = U * Sigma * V.getTranspose(); cout << "Result AA = " << endl << AA; return 0; }
供参考文章:http://www.cnblogs.com/zhangchaoyang/articles/2575948.html