Study performance of Arnoldi approximation of eigenvalues on matrices from the Harwell-Boeing collection. Demonstrate use of mixed Fortran-Python coding.
Define Python environment
import numpy as np
import pylab as plt
import scipy as sci
import scipy.io as sio
import scipy.sparse as sp
import os
os.getcwd()
Load a matrix
Asp=sio.mmread("./examples/Arnoldi/tols4000.mtx");
plt.spy(Asp)
sp.issparse(Asp)
A = np.array(Asp.todense('F'))
A.dtype
[m,mcol]=np.shape(A)
[m,mcol]
Find eigenvalues through np.eigvals for comparison with Arnoldi-Ritz estimates
Lambda=np.linalg.eigvals(A)
Lambda[0:10]
Lambda[3990:4000]
If the instruction below leads to errors, the fortran_magic module is probably not yet install. Do so in a terminal by:
sudo pip install -U fortran-magic
%load_ext fortranmagic
In the background, FortranMagic invokes the f2py utility to compile Fortran code and transparently provide an interface for calls from Python
%%fortran -v
subroutine arnoldi(A,b,H,Q,v,nK,m,n)
integer, intent(in) :: m,n
integer, intent(out) :: nK
real*8, intent(in) :: A(m,m), b(m)
real*8, intent(out) :: H(n+1,n), Q(m,n+1), v(m)
H = 0.d0
Q(:,1) = b/NORM2(b)
do k=1,n
v = MATMUL(A,Q(:,k)); nK=k
do j=1,k
H(j,k) = DOT_PRODUCT(Q(:,j),v)
v = v - H(j,k)*Q(:,j)
end do
H(k+1,k) = NORM2(v)
if (H(k+1,k)<1.0d-14) exit
Q(:,k+1) = v/H(k+1,k)
end do
end subroutine arnoldi
arnoldi
routine¶Invoke the Arnoldi algorithm to return
n=10
b=np.array(np.ones(m) , dtype='float64', order='F')
H=np.array(np.zeros([n+1,n]), dtype='float64', order='F')
Q=np.array(np.zeros([m,n+1]), dtype='float64', order='F')
v=np.array(np.zeros([m,1]) , dtype='float64', order='F')
[H,Q,v,nK]=arnoldi(A,b,n)
nK
Ritz = np.linalg.eigvals(H[0:nK,0:nK])
plt.plot(Lambda.real,Lambda.imag,'.',Ritz.real,Ritz.imag,'or')
Invoke the Arnoldi algorithm to return
n=20
b=np.array(np.random.randn(m) , dtype='float64', order='F')
H=np.array(np.zeros([n+1,n]), dtype='float64', order='F')
Q=np.array(np.zeros([m,n+1]), dtype='float64', order='F')
v=np.array(np.zeros([m,1]) , dtype='float64', order='F')
[H,Q,v,nK]=arnoldi(A,b,n)
nK
Ritz = np.linalg.eigvals(H[0:nK,0:nK])
plt.plot(Lambda.real,Lambda.imag,'.',Ritz.real,Ritz.imag,'or')
Invoke the Arnoldi algorithm to return
n=200
b=np.array(np.ones(m) , dtype='float64', order='F')
H=np.array(np.zeros([n+1,n]), dtype='float64', order='F')
Q=np.array(np.zeros([m,n+1]), dtype='float64', order='F')
v=np.array(np.zeros([m,1]) , dtype='float64', order='F')
[H,Q,v,nK]=arnoldi(A,b,n)
nK
Ritz = np.linalg.eigvals(H[0:nK,0:nK])
plt.plot(Lambda.real,Lambda.imag,'.',Ritz.real,Ritz.imag,'or')
Invoke the Arnoldi algorithm to return
n=400
b=np.array(np.ones(m) , dtype='float64', order='F')
H=np.array(np.zeros([n+1,n]), dtype='float64', order='F')
Q=np.array(np.zeros([m,n+1]), dtype='float64', order='F')
v=np.array(np.zeros([m,1]) , dtype='float64', order='F')
[H,Q,v,nK]=arnoldi(A,b,n)
nK
Ritz = np.linalg.eigvals(H[0:nK,0:nK])
plt.plot(Lambda.real,Lambda.imag,'.',Ritz.real,Ritz.imag,'or')