The SVD of a matrix provides with a powerful tool to reduce the dimensionality of a dataspace. It is used in the DMRG (density matrix renormalization group) to perform the decimation of the wavefunction basis to keep it from growing as nodes/spins are added to the system. It is used in image compression, and in PCA (principle component analysis) to reduce the dataspace to the most relevant dimensions.
SVD (singular value decomposition) is a decomposition of a matrix into , an , a “diagonal” , and , a matrix . Note that is a square . The columns of are the eigenvectors of . is a square and the columns of are it’s eigenvectors. Both and are positive semi-definite, their eigenvalues are non-negative. A matrix is positive semi-definite if for any real vector :
If is a square matrix then is its eigenvalue decomposition: is an orthogonal matrix made of the eigenvectors such that ie , where is a column vector (and is a row vector)
The SVD generalizes this no non-square arrays. Another useful decomposition:
(the eigendecomposition and decomposition of unity into projection operators)
Note that so is symmetric and real hence hermitian, so form a basis of orthogonal vectors, a property which we have used.
The Lanczos algorithm works very well to compute the largest singular value ,
consider that
an arbitrary vector has an expansion
where denotes the index of the maximal eigenvalue/vector of
as . Then since
Extract the most relevant (largest) singular value/generalized eigenvalue by the Lanczos algorithm , then subtract its contribution from to get
(since and ). Next apply the Lanczos algorithm to to get , the second most relevant singular value.
repeat times in total to get the most relevant singular values.
Let’s have it in julia
""" returns U,S,V for maximal singular value"""
maxsingularval=function(M,prec)
n,p=size(M)
v=ones(p)
v=v ./ sqrt(sum(v .* v))
w=M'*M*v
val=sqrt(sum(M*w .* M*w)/sum(w .* w))
iters=0
while true
w=M'*M*w
w=w ./ sqrt(sum(w .* w))
newval=sqrt(sum(M*w .* M*w)/sum(w .* w))
if(abs(newval-val) < prec)
break
end
val=newval
end
return val, M*w ./ sqrt(sum(M*w .* M*w)), w
end
""" svd decomposition, NN<= min(ncol(M),nrow(M))"""
mysvd=function(M,NN,prec)
n,p=size(M)
U=zeros(n,n)
S=zeros(n,p)
V=zeros(p,p)
S[1,1], U[:,1],V[:,1]=maxsingularval(M,prec)
Mp=M
for j in 2:NN
Mp=Mp - S[j-1,j-1]*U[:,j-1]*V[:,j-1]'
S[j,j], U[:,j],V[:,j]=maxsingularval(Mp,prec)
end
return S,U,V'
end
Let’s test it with a random array. We can use our decomposition to create a pseudoinverse of a nonsquare array and check its integrity.
psinv=function(M,prec)
n,p=size(M)
k=minimum([n,p])
ms,mu,mv=mysvd(M,k,prec)
for j in 1:k
if(ms[j,j]!=0.0)
ms[j,j]=1.0/ms[j,j]
end
end
mv'*ms'*mu'
end
m=random(7,9)
mS,mU,mV=mysvd(m,7,0.00001)
mU*mS*mV # should equal m, and it is VERY close
sum(abs.(m*psinv(m,0.0000001))) # should be a 7x9 with ones down the "diagonal" so sum
# of all entries should be 7, it returns 7.003860424
Next: applications.