Math-Polynomial-Solve
view release on metacpan or search on metacpan
reference/qralg/qralg.f view on Meta::CPAN
************************************************************************
*
* Solve the real coefficient monic algebraic equation by the QR-method.
*
************************************************************************
subroutine qr_algeq_solver(n,c,macheps,
& zr,zi,detil,
& a,cnt,rtn_code)
implicit none
integer n
double precision c(0:n-1)
double precision macheps
*
double precision zr(n),zi(n)
double precision detil
double precision a(n,n)
integer cnt(n)
integer rtn_code
Comments:
* n : degree of the monic polynomial.
* c : non-principal coefficients of the polynomial.
* i-th degree coefficients is stored in c(i).
* macheps : double precision machine epsilon.
* zr,zi : Re and Im part of output roots.
* detil : The accuracy hint.
* a : work matrix.
* cnt : work area for counting the qr-iterations.
* rtn_code: return code from hqr_eigen_hessenberg.
*end comments;
*================
integer i
integer iter
double precision afnorm
*
if(n.le.0)then
print *, 'qr_alg_solver: wrong arguments. (n<=0)'
rtn_code=3
return
endif
*
* Build the companion matrix A.
call build_companion(n,a,c)
*
* Balancing the A itself.
call balance_companion(n,a)
*
* Compute the Frobenius norm of the balanced companion matrix A.
call frobenius_norm_companion(n,a,afnorm)
*
* QR iterations from A.
call hqr_eigen_hessenberg(n,a,macheps, zr,zi,cnt,rtn_code)
if(rtn_code.ne.0)then
print*, 'in calling hqr_eigen_hessenberg abnormal condition'
print*, 'rtn_code=',rtn_code
if(rtn_code.eq.1) print *, 'matrix is completely zero.'
if(rtn_code.eq.2) print *, 'QR iteration does not converged.'
if(rtn_code.gt.3) print *, 'arguments violate the condition.'
return
endif
*
* Count the total QR iteration.
iter=0
do i=1,n
if(cnt(i).gt.0)iter=iter+cnt(i)
enddo
print *, 'iteration ',iter,' times.'
*
* Calculate the accuracy hint.
detil=macheps*n*iter*afnorm
print 600, 'O(del-e-tilda)=',detil
600 format(1x,a,1pe8.2)
*
end
************************************************************************
*
* build the Companion Matrix of the polynomial.
*
************************************************************************
subroutine build_companion(n,a,c)
implicit none
integer n
double precision a(n,n)
double precision c(0:n-1)
*
integer i,j
*
do j=1,n
do i=1,n
a(i,j)=0.d0
enddo
enddo
*
do i=2,n
a(i,i-1)=1.d0
enddo
*
do i=1,n
a(i,n)=-c(i-1)
enddo
*
end
************************************************************************
*
* Blancing the unsymmetric matrix A.
*
* This fortran code is based on the Algol code "balance" from paper:
* "Balancing a Matrixfor Calculation of Eigenvalues and Eigenvectors"
* by B.N.Parlett and C.Reinsch, Numer. Math. 13, 293-304(1969).
*
* Note: The only non-zero elements of the companion matrix are touched.
reference/qralg/qralg.f view on Meta::CPAN
a(j,i)=a(j,i)*f
enddo
endif
C end specific code.
endif
* Comment:
* the j joops may be done by exponent modification
* in machine Language;
100 enddo
if(noconv) goto 1
end
************************************************************************
*
* Calculate the Frobenius norm of the companion-like matrix.
* Note: The only non-zero elements of the companion matrix are touched.
*
************************************************************************
subroutine frobenius_norm_companion(n,a,afnorm)
implicit none
integer n
double precision a(n,n)
double precision afnorm
*
integer i,j
double precision sum
*
C sum=0.d0
C do j=1,n
C do i=1,n
C sum=sum+a(i,j)**2
C enddo
C enddo
*
sum=0.d0
do j=1,n-1
sum=sum+a(j+1,j)**2
enddo
do i=1,n
sum=sum+a(i,n)**2
enddo
*
afnorm=sqrt(sum)
end
************************************************************************
*
* Eigenvalue Computation by the Householder QR method
* for the Real Hessenberg matrix.
* This fortran code is based on the Algol code "hqr" from the paper:
* "The QR Algorithm for Real Hessenberg Matrices"
* by R.S.Martin, G.Peters and J.H.Wilkinson,
* Numer. Math. 14, 219-231(1970).
*
************************************************************************
subroutine hqr_eigen_hessenberg(n0,h,macheps, wr,wi,cnt,rtn_code)
implicit none
*Comment: Finds the eigenvalues of a real upper Hessenberg matrix,
* H, stored in the array h(1:n0,1:n0), and stores the real
* parts in the array wr(1:n0) and the imaginary parts in the
* array wi(1:n0). macheps is the relative machine precision.
* The procedure fails if any eigenvalue takes more than
* 30 iterations.
*
integer n0
double precision h(n0,n0)
double precision macheps
*
double precision wr(n0),wi(n0)
integer cnt(n0)
integer rtn_code
*===
integer i,j,k,l,m,na,its
double precision p,q,r,s,t,w,x,y,z
logical notlast
integer n
*===
* Note: n is changing in this subroutine.
n=n0
*
rtn_code=0
t=0.d0
*label nextw:
1 continue
if(n.eq.0)goto 9
its=0
na=n-1
*Comment: look for single small sub-diagonal element;
*label nextit:
2 continue
do l=n,2,-1
if(abs(h(l,l-1)).le.macheps*(abs(h(l-1,l-1))+abs(h(l,l))))then
go to 3
endif
enddo
l=1
*label cont1:
3 continue
x=h(n,n)
if(l.eq.n)goto 6
y=h(na,na)
w=h(n,na)*h(na,n)
if(l.eq.na)goto 7
if(its.eq.30)then
rtn_code=1
return
endif
if(its.eq.10.or.its.eq.20)then
* Comment: form exceptional shift;
t=t+x
do i=1,n
h(i,i)=h(i,i)-x
enddo
s=abs(h(n,na))+abs(h(na,n-2))
y=0.75*s
x=y
w=-0.4375*s**2
endif
its=its+1
* Comment: look for two consecutive small sub-diagonal
* elements;
do m=n-2,l,-1
z=h(m,m)
( run in 0.676 second using v1.01-cache-2.11-cpan-71847e10f99 )