lanczos算法及C++实现(〇)C++代码

目录###

代码包含4个文件,
main.cpp, 提供了一个调用svds的样例
fun.h, 提供了一些公共函数,比如排序等等
svds.cpp, 奇异值分解的实现
svds.h,奇异值分解的头文件

main.cpp###

#include "svds.h"
#include <iostream>
#include <cstdlib>
int main(){

	cout.precision(6);
	cout.setf(ios::fixed);
	srand(time(NULL));
	SparseMatrix A;
	A.rows=10;
	A.cols=8;
	int rank=4;
	for(int i=0;i<A.rows;i++){
		for(int j=0;j<A.cols;j++){
			A.cells.push_back(Cell(i,j,rand()*1.0/RAND_MAX-0.5));
		}
	}

	vector<vector<double> > U,V;
	vector<double> s;
	svds(A,rank,U,s,V);

	cout<<"[U,S,V]=svds(A,r)"<<endl;
	cout<<"r = "<<rank<<endl;
	cout<<"A = "<<endl;
	A.moveFirst();
	for(int i=0;i<A.rows;i++){
		for(int j=0;j<A.cols;j++)
			cout<<A.next().value<<' ';
		cout<<endl;
	}
	cout<<endl<<endl;
	

	cout<<endl<<endl;

	cout<<"U = "<<endl;
	print(U);

	cout<<"s = "<<endl;
	for(int i=0;i<s.size();i++){
		for(int j=0;j<s.size();j++){
			if(i==j)	
				cout<<s[i]<<' ';
			else
				cout<<0.0<<' ';
		}
		cout<<endl;
	}
	cout<<endl;
	cout<<endl;
	


	cout<<"V = "<<endl;
	print(V);

	return 0;
}

fun.h###

#ifndef FUN_H
#define FUN_H
#include <vector>
using namespace std;
template <class T>
void combine(vector<T> &v, int left, int m, int right, vector<int> &index)
{
	vector<T> tempv(v.begin()+left,v.begin()+right+1);
	vector<int> tempindex(index.begin()+left,index.begin()+right+1);

	int left_size=m-left+1;
	int size=right-left+1;
	int middle=m-left+1;
	int i=0;
	int j=middle;
	int k=left;
	while(i<left_size && j<size)
	{
		if(tempv[i]<=tempv[j])
		{
			v[k]=tempv[i];
			index[k]=tempindex[i];
			k++;
			i++;
		}else{
			v[k]=tempv[j];
			index[k]=tempindex[j];
			k++;
			j++;
		}
	}
	while(i<left_size)
	{
		v[k]=tempv[i];
		index[k]=tempindex[i];
		k++;
		i++;
	}
}


template <class T>
void merge_sort(vector<T> &v, int left, int right, vector<int> &index)
{
    if (left<right)
    {
        int m=(left+right)/2;
        merge_sort(v,left, m,index);
        merge_sort(v,m+1, right, index);
        combine(v,left, m, right,index);
    }
}


template <class T>
void merge_sort(vector<T> v, vector<int> &index)
//index[i] is the original index of i th best element
{
	index.clear();
	index.resize(v.size());
	for(int i=0;i<v.size();i++)
		index[i]=i;
	merge_sort(v,0,v.size()-1,index);
}
#endif

svds.h

#ifndef SVDS_H
#define SVDS_H
#include <vector>
#include <string>
using namespace std;
class Cell{
public:
	unsigned int row;
	unsigned int col;
	double value;
	Cell():row(0),col(0),value(0){};
	Cell(int r, int c, double v):row(r),col(c),value(v){};
};
class SparseMatrix{
public:
	unsigned int rows;
	unsigned int cols;
	vector<Cell> cells;

	int cellID;

	//read data sequentially, especially when loading large matrix from the disk.
	void moveFirst(){
		cellID=0;
	}
	bool hasNext(){
		return cellID<cells.size();
	}
	Cell next(){
		return cells[cellID++];
	}
};

void svds(SparseMatrix &A, int r, vector<vector<double> > &U, vector<double> &s, vector<vector<double> > &V, string algo="DC");
//decompose A = U * diag(s) *V'
//where A is a m*n matrix
//U is a m*r column orthogonal matrix
//s is a length r vector
//V is a n*r column orthogonal matrix

void print(vector<vector<double> > &X);
void hessenbergReduction(vector<vector<double> > &A, vector<vector<double> > &U);
void QRHessenbergBasic(vector<vector<double> > &A, vector<vector<double> > &Q);
void QRbasic(vector<vector<double> > &T, vector<vector<double> > &W);
void transpose(vector<vector<double> > &A, vector<vector<double> > &T);
void multiply(vector<vector<double> > &A, vector<vector<double> > &B, vector<vector<double> > &C);
void QRHessenberg(vector<vector<double> > &A, vector<vector<double> > &Q);
void QRTridiagonal(vector<vector<double> > &A, vector<vector<double> > &Q);
#endif

svds.cpp###

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cmath>
#include <climits>
#include <cstdlib>
#include <algorithm>
#include <iomanip>
#include "fun.h"
#include "svds.h"
using namespace std;
const double EPS=1e-15;
void print(vector<vector<double> > &X){
	cout.precision(6);
	cout.setf(ios::fixed);
	for(int i=0;i<X.size();i++){
		for(int j=0;j<X[i].size();j++)
			cout<<X[i][j]<<' ';
		cout<<endl;
	}
	cout<<endl;
}

void transpose(vector<vector<double> > &A, vector<vector<double> > &T){
	if(A.empty()||A[0].empty()) return;
	int m=A.size();
	int n=A[0].size();
	T.clear();
	T.resize(n,vector<double>(m,0));
	for(int i=0;i<m;i++)
		for(int j=0;j<n;j++)
			T[j][i]=A[i][j];
}
void transpose(vector<vector<double> > &A){
	int m=A.size();
	for(int i=0;i<m;i++)
		for(int j=i+1;j<m;j++)
			swap(A[i][j],A[j][i]);
}

void randUnitVector(int n, vector<double> &v){
	srand(time(NULL));
	v.clear();v.resize(n);
	while(true){
		double r=0;
		for(int i=0;i<n;i++){
			v[i]=rand()*1.0/RAND_MAX-0.5;
			r+=v[i]*v[i];
		}
		r=sqrt(r);
		if(r>EPS){
			for(int i=0;i<n;i++)
				v[i]/=r;
			break;
		}
	}
}
void multiply(vector<vector<double> > &A, vector<vector<double> > &B, vector<vector<double> > &C){
	//C=A*B
	C.clear();
	if(A.empty() || A[0].empty() || B.empty() || B[0].empty()) return ;
	C.resize(A.size(),vector<double>(B[0].size(),0));
	for(int i=0;i<A.size();i++){
		for(int j=0;j<B[0].size();j++){
			C[i][j]=0;
			for(int k=0;k<A[0].size();k++){
				C[i][j]+=A[i][k]*B[k][j];
			}
		}
	}
}

void multiply(const vector<vector<double> > &X, const vector<double> & v, vector<double> & res){
	res.clear();
	if(X.empty() || v.empty()) return;
	int m=X[0].size();
	res.resize(m,0);
	for(int i=0;i<m;i++){
		for(int j=0;X[i].size();j++){
			res[i]+=X[i][j]*v[j];
		}
	}
}
double dotProduct(const vector<double> & a, const vector<double> & b){
	double res=0;
	for(int i=0;i<a.size();i++)
		res+=a[i]*b[i];
	return res;
}


void rightMultiply(SparseMatrix &A, const vector<double> & v, vector<double> & res){
	//res= A*A'*v
	int m=A.rows;
	int n=A.cols;
	res.clear();
	res.resize(m,0);
	vector<double> w(n,0);
	A.moveFirst();
	while(A.hasNext()){
		Cell c=A.next();
		w[c.col]+=c.value*v[c.row];
	}
	A.moveFirst();
	while(A.hasNext()){
		Cell c=A.next();
		res[c.row]+=c.value*w[c.col];
	}
}
void leftMultiply(SparseMatrix &A, const vector<double> & v, vector<double> & res){
	//res= A'*A*v
	int m=A.rows;
	int n=A.cols;
	res.clear();
	res.resize(n,0);
	vector<double> w(m,0);
	A.moveFirst();
	while(A.hasNext()){
		Cell c=A.next();
		w[c.row]+=c.value*v[c.col];
	}
	A.moveFirst();
	while(A.hasNext()){
		Cell c=A.next();
		res[c.col]+=c.value*w[c.row];
	}
}

void rightMultiply(const vector<vector<double> > & B,SparseMatrix &A, vector<vector<double> > & C){
	//C= B'*A
	int m=B[0].size();
	int k=B.size();
	int n=A.cols;
	for(int i=0;i<C.size();i++) fill(C[i].begin(),C[i].end(),0);
	A.moveFirst();
	while(A.hasNext()){
		Cell c=A.next();
		for(int i=0;i<m;i++){
			C[c.col][i]+=c.value*B[c.row][i];
		}
	}
}
void leftMultiply(const vector<vector<double> > & B,SparseMatrix &A, vector<vector<double> > & C){
	//C <- A B
	int r=B[0].size();
	int n=B.size();
	int m=A.rows;
	C.clear();
	C.resize(m,vector<double>(r,0));
	A.moveFirst();
	while(A.hasNext()){
		Cell c=A.next();
		for(int i=0;i<r;i++){
			C[c.row][i]+=c.value*B[c.col][i];
		}
	}
}


double norm(const vector<double> &v){
	double r=0;
	for(int i=0;i<v.size();i++)
		r+=v[i]*v[i];
	return sqrt(r);
}

double normalize(vector<double> &v){
	double r=0;
	for(int i=0;i<v.size();i++)
		r+=v[i]*v[i];
	r=sqrt(r);
	if(r>EPS){
		for(int i=0;i<v.size();i++)
			v[i]/=r;
	}
	return r;
}

void multiply(vector<double> &v, double d){
	for(int i=0;i<v.size();i++)
		v[i]*=d;
}
void hessenbergReduction(vector<vector<double> > &A, vector<vector<double> > &U){
	//A: m*m matrix
	//Reduction A to Hessenberg form: H=U'AU (A=UHU'), H overwrite A to save memory
	int m=A.size();
	vector<double> v(m);
	U.clear();
	U.resize(m,vector<double>(m,0));
	for(int i=0;i<m;i++)
		U[i][i]=1;
	for(int i=1;i<m;i++){
		fill(v.begin(),v.end(),0);
		for(int j=i;j<m;j++)
			v[j]=A[j][i-1];
		v[i]-=norm(v);
		normalize(v);	//P=I-2*v*v'
		//A=PAP
		//1. PA
		for(int j=i-1;j<m;j++){
			double d=0;
			for(int k=i;k<m;k++)
				d+=A[k][j]*v[k];
			for(int k=i;k<m;k++)
				A[k][j]-=d*2*v[k];
		}
		//2. AP
		for(int j=0;j<m;j++){//row j
			double d=0;
			for(int k=i;k<m;k++)
				d+=A[j][k]*v[k];
			for(int k=i;k<m;k++)
				A[j][k]-=d*2*v[k];
		}

		//U=U*P
		for(int j=0;j<m;j++){
			double d=0;
			for(int k=i;k<m;k++)
				d+=U[j][k]*v[k];
			for(int k=i;k<m;k++)
				U[j][k]-=d*2*v[k];
		}
	}
}

void givensRotation(double a, double b, double &c, double &s){
	if(fabs(b)<EPS){
		c=1;s=0;
	}else{
		if(fabs(b)>fabs(a)){
			double r=a/b;
			s=1/sqrt(1+r*r);
			c=s*r;
		}else{
			double r=b/a;
			c=1/sqrt(1+r*r);
			s=c*r;
		}
	}
}

void QRTridiagonal(vector<vector<double> > &A, vector<vector<double> > &Q){
	//input: A m*m symmetry tridiagonal matrix
	//output: Upper triangular R, and orthogonal Q, such that A=QRQ'
	int n=A.size();
	Q.clear();
	Q.resize(n,vector<double>(n,0));
	vector<double> cs(n-1,0);
	vector<double> ss(n-1,0);
	for(int i=0;i<n;i++) Q[i][i]=1;
	for(int m=n;m>=2;m--){
		while(1){
			fill(cs.begin(),cs.end(),0);
			fill(ss.begin(),ss.end(),0);
			double delta=(A[m-2][m-2]-A[m-1][m-1])/2;
			double sign=1;
			if(delta<0) sign=-1;
			//Wilkinson shift
			double shift=A[m-1][m-1]-sign*A[m-1][m-2]*A[m-2][m-1]/(fabs(delta)+sqrt(delta*delta+A[m-1][m-2]*A[m-2][m-1]));
			for(int i=0;i<m;i++)
				A[i][i]-=shift;
			for(int i=0;i<m-1;i++){
				double a=A[i][i];
				double b=A[i+1][i];
				givensRotation(a,b,cs[i],ss[i]);
				for(int j=i;j<=i+2 && j<m;j++){
					a=A[i][j];
					b=A[i+1][j];
					A[i][j]=cs[i]*a+ss[i]*b;
					A[i+1][j]=-ss[i]*a+cs[i]*b;
				}
			}
			
			for(int j=1;j<m;j++){// cols	j-1, j						   c -s
				for(int i=max(0,j-2);i<=j;i++){// rows  0 ... j		[a ,b]	 s  c
					double a=A[i][j-1];
					double b=A[i][j];
					A[i][j-1]=cs[j-1]*a+ss[j-1]*b;
					A[i][j]=-ss[j-1]*a+cs[j-1]*b;
				}
			}
			for(int i=0;i<m;i++)
				A[i][i]+=shift;
			//Q=Q*G1...Gm
			for(int j=1;j<m;j++){
				for(int i=0;i<n;i++){
					double a=Q[i][j-1];
					double b=Q[i][j];
					Q[i][j-1]=cs[j-1]*a+ss[j-1]*b;
					Q[i][j]=-ss[j-1]*a+cs[j-1]*b;
				}
			}
			if(fabs(A[m-1][m-2])<1e-10)
				break;
		}
	}
}
vector<double> secularEquationSolver(vector<double> &z, vector<double> &D, double sigma){
	
	//solve equation
	// 1 + \sigma \sum_j \frac{b^2_j}{d_j-\lambda} =0
	int n=z.size();
	vector<double> res(n);

	//sort : d_0 < d_1 < ... < d_{n-1}
	vector<int> index;
	vector<double> d(n);
	merge_sort(D,index);
	if(sigma<0)
		reverse(index.begin(),index.end());
	vector<double> b(n);
	for(int i=0;i<n;i++){
		b[i]=z[index[i]];
		d[i]=D[index[i]];
	}

	vector<double> lambda(n);
	for(int i=0;i<n;i++){
		vector<double> delta(d.size());
		for(int j=0;j<delta.size();j++)
			delta[j]=(d[j]-d[i])/sigma;
		double gamma=0;
		if(i+1<n){
			//gamma>1/delta[i+1]
			double A=b[i]*b[i];
			double B=-A/delta[i+1]-1;
			for(int j=0;j<delta.size();j++)
				if(j!=i)
					B-=b[j]*b[j]/delta[j];
			double C=1;
			for(int j=0;j<delta.size();j++)
				if(j!=i)
					C+=b[j]*b[j]/delta[j];
			C/=delta[i+1];
			C-=b[i+1]*b[i+1]/delta[i+1];
			gamma=(-B+sqrt(B*B-4*A*C))/(2*A);
		}
		//start Newton
		double diff=1;
		while(diff*diff>EPS){
			double g=0;
			for(int j=0;j<n;j++){
				g-=b[j]*b[j]/((delta[j]*gamma-1)*(delta[j]*gamma-1));
			}
			double f=1;
			for(int j=0;j<n;j++){
				f+=b[j]*b[j]/(delta[j]-1/gamma);
			}
			//f+g(newGamma-gamma)=0
			double newGamma=-f/g+gamma;
			diff=fabs(newGamma-gamma);
			gamma=newGamma;
		}
		lambda[i]=1/gamma*sigma+d[i];
	}

	for(int i=0;i<n;i++)
		res[index[i]]=lambda[i];
	return res;
}

void DCSub(vector<double> &alpha, vector<double> &beta, vector<vector<double> > &Q, vector<double> &D, int start, int end){
	if(start==end){
		Q[start][start]=1;
		D[start]=alpha[start];
		return;
	}else{
		int mid=(start+end)/2;

		//		|	mid		mid+1
		//---------------------------------------------
		//	mid	|	a(mid)  	b(mid+1)
		//	mid+1	|	b(mid+1)	a(mid+1)

		alpha[mid]-=beta[mid+1];
		alpha[mid+1]-=beta[mid+1];
		DCSub(alpha,beta,Q,D,start,mid);
		DCSub(alpha,beta,Q,D,mid+1,end);
		//alpha[mid]+=beta[mid+1];
		//alpha[mid+1]+=beta[mid+1];


		int n=end-start+1;
		vector<double> z(n,0);
		for(int i=start;i<=mid;i++)
			z[i-start]=Q[mid][i];
		for(int i=mid+1;i<=end;i++)
			z[i-start]=Q[mid+1][i];

		//calculate eigen systems of matrix D+beta[mid+1]*z*z'

		vector<double> d(n,0);
		for(int i=0;i<n;i++)
			d[i]=D[i+start];

		//secular equation is:
		// 1 + \sum_j \frac{z^2_j}{d_j-\lambda} =0
		vector<double> lambda=secularEquationSolver(z, d, beta[mid+1]);

		
		//eigen vector: 
		//P = (D-\lambda I)^{-1} z
		vector<vector<double> > P(n,vector<double>(n));
		for(int i=0;i<n;i++){//for each eigen value
			vector<double> p(n);
			for(int j=0;j<n;j++)
				p[j]=1.0/(D[j+start]-lambda[i])*z[j];
			normalize(p);
			for(int j=0;j<n;j++)
				P[j][i]=p[j];
		}
		
		vector<vector<double> > oldQ(n,vector<double>(n));
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++){
				oldQ[i][j]=Q[i+start][j+start];
			}
		
		for(int i=0;i<n;i++){
			for(int j=0;j<n;j++){
				Q[i+start][j+start]=0;
				for(int k=0;k<n;k++){
					Q[i+start][j+start]+=oldQ[i][k]*P[k][j];
				}
			}
		}
		//eigen value
		for(int i=0;i<n;i++)
			D[i+start]=lambda[i];
	}
}
void DCTridiagonal(vector<double> alpha, vector<double> &beta, vector<vector<double> > &Q, vector<double> &D){
	//input: A m*m symmetry tridiagonal matrix
	//output: diagonal matrix D, and orthogonal D, such that A=QRQ'
	int m=alpha.size();
	Q.clear();
	Q.resize(m,vector<double>(m,0));
	D.clear();
	D.resize(m,0);
	DCSub(alpha, beta, Q, D, 0, m-1);
}

void QRHessenberg(vector<vector<double> > &A, vector<vector<double> > &Q){
	//input: A m*m square Hessenberg Matrix
	//output: Upper triangular R, and orthogonal Q, such that A=QRQ'
	int n=A.size();
	Q.clear();
	Q.resize(n,vector<double>(n,0));
	vector<double> cs(n-1,0);
	vector<double> ss(n-1,0);
	for(int i=0;i<n;i++) Q[i][i]=1;
	for(int m=n;m>=2;m--){
		while(1){
			fill(cs.begin(),cs.end(),0);
			fill(ss.begin(),ss.end(),0);
			double delta=(A[m-2][m-2]-A[m-1][m-1])/2;
			double sign=1;
			if(delta<0) sign=-1;
			//Wilkinson shift
			double shift=A[m-1][m-1]-sign*A[m-1][m-2]*A[m-2][m-1]/(fabs(delta)+sqrt(delta*delta+A[m-1][m-2]*A[m-2][m-1]));
			for(int i=0;i<m;i++)
				A[i][i]-=shift;
			for(int i=0;i<m-1;i++){
				double a=A[i][i];
				double b=A[i+1][i];
				givensRotation(a,b,cs[i],ss[i]);
				for(int j=i;j<m;j++){
					a=A[i][j];
					b=A[i+1][j];
					A[i][j]=cs[i]*a+ss[i]*b;
					A[i+1][j]=-ss[i]*a+cs[i]*b;
				}
			}
			
			for(int j=1;j<m;j++){// cols	j-1, j						   c -s
				for(int i=0;i<=j;i++){// rows  0 ... j		[a ,b]	 s  c
					double a=A[i][j-1];
					double b=A[i][j];
					A[i][j-1]=cs[j-1]*a+ss[j-1]*b;
					A[i][j]=-ss[j-1]*a+cs[j-1]*b;
				}
			}
			for(int i=0;i<m;i++)
				A[i][i]+=shift;
			//Q=Q*G1...Gm
			for(int j=1;j<m;j++){
				for(int i=0;i<n;i++){
					double a=Q[i][j-1];
					double b=Q[i][j];
					Q[i][j-1]=cs[j-1]*a+ss[j-1]*b;
					Q[i][j]=-ss[j-1]*a+cs[j-1]*b;
				}
			}
			if(fabs(A[m-1][m-2])<1e-10)
				break;
		}
	}
}
void QRHessenbergBasic(vector<vector<double> > &A, vector<vector<double> > &Q){
	//input: A m*m square Hessenberg Matrix
	//output: Upper triangular R such taht A=QRQ' for orthogonal matrix Q
	int m=A.size();
	vector<double> cs(m-1,0);
	vector<double> ss(m-1,0);
	double diff=1;
	Q.clear();
	Q.resize(m,vector<double>(m,0));
	for(int i=0;i<m;i++) Q[i][i]=1;
	while(1){
		for(int i=0;i<m-1;i++){
			double a=A[i][i];
			double b=A[i+1][i];
			givensRotation(a,b,cs[i],ss[i]);
			for(int j=i;j<m;j++){
				a=A[i][j];
				b=A[i+1][j];
				A[i][j]=cs[i]*a+ss[i]*b;
				A[i+1][j]=-ss[i]*a+cs[i]*b;
			}
		}
		
		for(int j=1;j<m;j++){// cols	j-1, j				c -s
			for(int i=0;i<=j;i++){// rows  0 ... j		[a ,b]	s  c
				double a=A[i][j-1];
				double b=A[i][j];
				A[i][j-1]=cs[j-1]*a+ss[j-1]*b;
				A[i][j]=-ss[j-1]*a+cs[j-1]*b;
			}
		}
		//Q=Q*G1...Gm
		for(int j=1;j<m;j++){
			for(int i=0;i<m;i++){
				double a=Q[i][j-1];
				double b=Q[i][j];
				Q[i][j-1]=cs[j-1]*a+ss[j-1]*b;
				Q[i][j]=-ss[j-1]*a+cs[j-1]*b;
			}
		}
		diff=0;
		for(int i=0;i+1<m;i++){
			diff+=A[i+1][i]*A[i+1][i];
		}
		diff=sqrt(diff);
		if(diff<1e-10)
			break;
	}
}


void QRFactorization(vector<vector<double> > &A, vector<vector<double> > &Q, vector<vector<double> > &R){
	//A=Q*R
	//A: m*n matrix
	//Q: m*m matrix
	//R: m*n matrix
	int m=A.size();
	int n=A[0].size();
	for(int i=0;i<Q.size();i++)
		fill(Q[i].begin(),Q[i].end(),0);
	for(int i=0;i<R.size();i++)
		fill(R[i].begin(),R[i].end(),0);

	vector<double> q(m);
	vector<double> r(n);
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++)
			q[j]=A[j][i];
		fill(r.begin(),r.end(),0);
		for(int j=0;j<i && j<m;j++){
			r[j]=0;
			for(int k=0;k<q.size();k++)
				r[j]+=Q[k][j]*q[k];
			for(int k=0;k<q.size();k++)
				q[k]-=Q[k][j]*r[j];
		}
		if(i<m){
			r[i]=normalize(q);
			for(int j=0;j<m;j++)
				Q[j][i]=q[j];
		}
		for(int j=0;j<m;j++){
			R[j][i]=r[j];
		}
	}
}


void lanczos(SparseMatrix &A, vector<vector<double> > &P, vector<double> &alpha, vector<double> &beta, unsigned int rank){
	//P'*A*A'*P = T = diag(alpha) + diag(beta,1) + diag(beta, -1)
	//P=[p1,p2, ... , pk]
	rank=min(A.cols,min(A.rows,rank));
	vector<double> p;
	unsigned int m=A.rows;
	unsigned int n=A.cols;
	vector<double> prevP(m,0);
	randUnitVector(m,p);
	P.clear();
	P.resize(m,vector<double>(rank,0));
	vector<double> v;
	alpha.clear();alpha.resize(rank);
	beta.clear();beta.resize(rank);
	beta[0]=0;
	for(int i=0;i<rank;i++){
		for(int j=0;j<p.size();j++){
			P[j][i]=p[j];
		}
		rightMultiply(A, p, v);
		alpha[i]=dotProduct(p,v);
		if(i+1<rank){
			for(int j=0;j<m;j++)
				v[j]=v[j]-beta[i]*prevP[j]-alpha[i]*p[j];
			beta[i+1]=norm(v);
			prevP=p;
			for(int j=0;j<m;j++)
				p[j]=v[j]/beta[i+1];
		}
	}
}

void lanczosT(SparseMatrix &A, vector<vector<double> > &P, vector<double> &alpha, vector<double> &beta, unsigned int rank){
	//P'*A'*A*P = T = diag(alpha) + diag(beta,1) + diag(beta, -1)
	//P=[p1,p2, ... , pk]
	rank=min(A.cols,min(A.rows,rank));
	vector<double> p;
	unsigned int m=A.rows;
	unsigned int n=A.cols;
	vector<double> prevP(n,0);
	randUnitVector(n,p);
	P.clear();
	P.resize(n,vector<double>(rank,0));
	vector<double> v;
	alpha.clear();alpha.resize(rank);
	beta.clear();beta.resize(rank);
	beta[0]=0;
	for(int i=0;i<rank;i++){
		for(int j=0;j<p.size();j++){
			P[j][i]=p[j];
		}
		leftMultiply(A, p, v);
		alpha[i]=dotProduct(p,v);
		if(i+1<rank){
			for(int j=0;j<n;j++)
				v[j]=v[j]-beta[i]*prevP[j]-alpha[i]*p[j];
			beta[i+1]=norm(v);
			prevP=p;
			for(int j=0;j<n;j++)
				p[j]=v[j]/beta[i+1];
		}
	}
}

void QRbasic(vector<vector<double> > &T, vector<vector<double> > &W){
	int l=T.size();
	W.clear();
	W.resize(l,vector<double>(l,0));
	vector<vector<double> > Q(l,vector<double>(l,0));
	vector<vector<double> > R(l,vector<double>(l,0));
	vector<vector<double> > nextW(l,vector<double>(l,0));
	for(int i=0;i<l;i++)
		W[i][i]=1;
	while(true){
		//T=Q*R
		QRFactorization(T,Q,R);
		//T=R*Q
		multiply(R,Q,T);
		//W=W*Q;
		multiply(W,Q,nextW);
		double diff=0;
		for(int i=0;i<l;i++)
			for(int j=0;j<l;j++)
				diff+=(W[i][j]-nextW[i][j]) * (W[i][j]-nextW[i][j]);
		W=nextW;
		if(diff<EPS*EPS)
			break;
	}
}
void svds(SparseMatrix &A, int r, vector<vector<double> > &U, vector<double> &s, vector<vector<double> > &V, string algo){
	//A=U*diag(s)*V'
	//A:m*n matrix sparse matrix
	//U:m*r matrix, U[i]=i th left singular vector
	//s:r vector
	//V:n*r matrix, V[i]=i th right singular vector
	int m=A.rows;
	int n=A.cols;
   
	//lanczos: A*A'=P*T*P'
	if(m<=n){
		int l=m;
		vector<vector<double> > P(m,vector<double>(l,0));
		vector<double> alpha(l,0);
		vector<double> beta(l,0);
		lanczos(A,P,alpha,beta,l);
		vector<vector<double> > W;
		if(algo=="QR"){
			vector<vector<double> > T(l,vector<double>(l,0));
			for(int i=0;i<l;i++){
				T[i][i]=alpha[i];
				if(i)
					T[i-1][i]=T[i][i-1]=beta[i];
			}
			QRTridiagonal(T,W);
		}else if(algo=="DC"){
			vector<double> D(l,0);
			vector<vector<double> > Q;
			DCTridiagonal(alpha,beta,Q,D);
			//need sort
			vector<int> index;
			merge_sort(D,index);
			reverse(index.begin(),index.end());
			W.resize(l,vector<double>(l));
			for(int i=0;i<l;i++)
				for(int j=0;j<l;j++)
					W[i][j]=Q[i][index[j]];
		}
		U.clear();U.resize(m,vector<double>(l));
		multiply(P,W,U);
		for(int i=0;i<U.size();i++)
			U[i].resize(r);
		V.clear();V.resize(n,vector<double>(r));
		rightMultiply(U,A,V);
		s.clear();s.resize(r,0);
		for(int i=0;i<r;i++){
			for(int j=0;j<n;j++)
				s[i]+=V[j][i]*V[j][i];
			s[i]=sqrt(s[i]);
			if(s[i]>EPS){
				for(int j=0;j<n;j++)
				V[j][i]/=s[i];
			}
		}
	}else{
		int l=n;
		vector<vector<double> > P(n,vector<double>(l,0));
		vector<double> alpha(l,0);
		vector<double> beta(l,0);
		lanczosT(A,P,alpha,beta,l);
		
		vector<vector<double> > W;
		if(algo=="QR"){
			vector<vector<double> > T(l,vector<double>(l,0));
			for(int i=0;i<l;i++){
				T[i][i]=alpha[i];
				if(i)
					T[i-1][i]=T[i][i-1]=beta[i];
			}
			QRTridiagonal(T,W);
		}else if(algo=="DC"){
			vector<double> D(l,0);
			vector<vector<double> > Q;
			DCTridiagonal(alpha,beta,Q,D);
			//need sort
			vector<int> index;
			merge_sort(D,index);
			reverse(index.begin(),index.end());
			W.resize(l,vector<double>(l));
			for(int i=0;i<l;i++)
				for(int j=0;j<l;j++)
					W[i][j]=Q[i][index[j]];

		}
		V.clear();V.resize(n,vector<double>(l,0));
		U.clear();U.resize(m,vector<double>(r,0));
		multiply(P,W,V);
		for(int i=0;i<V.size();i++)
			V[i].resize(r);
		leftMultiply(V,A,U);
		s.clear();s.resize(r,0);
		for(int i=0;i<r;i++){
			for(int j=0;j<m;j++)
				s[i]+=U[j][i]*U[j][i];
			s[i]=sqrt(s[i]);
			if(s[i]>EPS){
				for(int j=0;j<m;j++)
				U[j][i]/=s[i];
			}
		}
	}
}

 

本文属作者原创,转载请注明出处:

http://www.cnblogs.com/qxred/p/lanczoscpp.html

 

本系列目录:

lanczos算法及C++实现(〇)C++代码

lanczos算法及C++实现(一)框架及简单实现

lanczos算法及C++实现(二)实对称阵奇异值分解的QR算法

lanczos算法及C++实现(三)实对称三对角阵特征值分解的分治算法

posted @ 2016-09-21 02:51  qxred  阅读(5994)  评论(0编辑  收藏  举报