this subroutine finds the eigenvalues of a complex upper hessenberg matrix by the qr method.
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
integer, | intent(in) | :: | nm |
row dimension of two-dimensional array parameters |
||
integer, | intent(in) | :: | n |
the order of the matrix |
||
integer, | intent(in) | :: | low |
integer determined by the balancing subroutine cbal. if cbal has not been used, set low=1 |
||
integer, | intent(in) | :: | igh |
integer determined by the balancing subroutine cbal. if cbal has not been used, igh=n. |
||
real(kind=wp), | intent(inout) | :: | hr(nm,n) |
On input: hr and hi contain the real and imaginary parts, respectively, of the complex upper hessenberg matrix. their lower triangles below the subdiagonal contain information about the unitary transformations used in the reduction by corth, if performed. On Output: the upper hessenberg portions of hr and hi have been destroyed. therefore, they must be saved before calling comqr if subsequent calculation of eigenvectors is to be performed. |
||
real(kind=wp), | intent(inout) | :: | hi(nm,n) |
See |
||
real(kind=wp), | intent(out) | :: | wr(n) |
the real parts of the eigenvalues. if an error
exit is made, the eigenvalues should be correct
for indices |
||
real(kind=wp), | intent(out) | :: | wi(n) |
the imaginary parts of the eigenvalues. if an error
exit is made, the eigenvalues should be correct
for indices |
||
integer, | intent(out) | :: | ierr |
is set to:
|
subroutine comqr(nm, n, low, igh, hr, hi, wr, wi, ierr) implicit none integer, intent(in) :: nm !! row dimension of two-dimensional array parameters integer, intent(in) :: n !! the order of the matrix integer, intent(in) :: low !! integer determined by the balancing !! subroutine cbal. if cbal has not been used, !! set low=1 integer, intent(in) :: igh !! integer determined by the balancing !! subroutine cbal. if cbal has not been used, !! igh=n. real(wp), intent(inout) :: hr(nm, n) !! On input: hr and hi contain the real and imaginary parts, !! respectively, of the complex upper hessenberg matrix. !! their lower triangles below the subdiagonal contain !! information about the unitary transformations used in !! the reduction by corth, if performed. !! !! On Output: the upper hessenberg portions of hr and hi have been !! destroyed. therefore, they must be saved before !! calling comqr if subsequent calculation of !! eigenvectors is to be performed. real(wp), intent(inout) :: hi(nm, n) !! See `hr` description real(wp), intent(out) :: wr(n) !! the real parts of the eigenvalues. if an error !! exit is made, the eigenvalues should be correct !! for indices `ierr+1,...,n`. real(wp), intent(out) :: wi(n) !! the imaginary parts of the eigenvalues. if an error !! exit is made, the eigenvalues should be correct !! for indices `ierr+1,...,n`. integer, intent(out) :: ierr !! is set to: !! !! * 0 -- for normal return !! * j -- if the limit of 30*n iterations is exhausted !! while the j-th eigenvalue is being sought. integer :: i, j, l, en, ll, itn, its, lp1, enm1 real(wp) :: si, sr, ti, tr, xi, xr, yi, yr, zzi, & zzr, norm, tst1, tst2, xr2, xi2 ierr = 0 if (low /= igh) then ! create real subdiagonal elements l = low + 1 do i = l, igh ll = min(i + 1, igh) if (hi(i, i - 1) /= 0.0_wp) then norm = pythag(hr(i, i - 1), hi(i, i - 1)) yr = hr(i, i - 1)/norm yi = hi(i, i - 1)/norm hr(i, i - 1) = norm hi(i, i - 1) = 0.0_wp do j = i, igh si = yr*hi(i, j) - yi*hr(i, j) hr(i, j) = yr*hr(i, j) + yi*hi(i, j) hi(i, j) = si end do do j = low, ll si = yr*hi(j, i) + yi*hr(j, i) hr(j, i) = yr*hr(j, i) - yi*hi(j, i) hi(j, i) = si end do end if end do end if ! store roots isolated by cbal do i = 1, n if (i < low .or. i > igh) then wr(i) = hr(i, i) wi(i) = hi(i, i) end if end do en = igh tr = 0.0_wp ti = 0.0_wp itn = 30*n main: do if (en < low) return ! search for next eigenvalue its = 0 enm1 = en - 1 do ! look for single small sub-diagonal element ! for l=en step -1 until low d0 -- do ll = low, en l = en + low - ll if (l == low) exit tst1 = abs(hr(l - 1, l - 1)) + abs(hi(l - 1, l - 1)) + abs(hr(l, l)) + abs(hi(l, l)) tst2 = tst1 + abs(hr(l, l - 1)) if (tst2 == tst1) exit end do ! form shift if (l == en) then ! a root found wr(en) = hr(en, en) + tr wi(en) = hi(en, en) + ti en = enm1 cycle main elseif (itn == 0) then ! set error -- all eigenvalues have not converged after 30*n iterations ierr = en return else if (its == 10 .or. its == 20) then ! form exceptional shift sr = abs(hr(en, enm1)) + abs(hr(enm1, en - 2)) si = 0.0_wp else sr = hr(en, en) si = hi(en, en) xr = hr(enm1, en)*hr(en, enm1) xi = hi(enm1, en)*hr(en, enm1) if (xr /= 0.0_wp .or. xi /= 0.0_wp) then yr = (hr(enm1, enm1) - sr)/2.0_wp yi = (hi(enm1, enm1) - si)/2.0_wp call csroot(yr**2 - yi**2 + xr, 2.0_wp*yr*yi + xi, zzr, zzi) if (yr*zzr + yi*zzi < 0.0_wp) then zzr = -zzr zzi = -zzi end if call cdiv(xr, xi, yr + zzr, yi + zzi, xr2, xi2) xr = xr2 xi = xi2 sr = sr - xr si = si - xi end if end if do i = low, en hr(i, i) = hr(i, i) - sr hi(i, i) = hi(i, i) - si end do tr = tr + sr ti = ti + si its = its + 1 itn = itn - 1 ! reduce to triangle (rows) lp1 = l + 1 do i = lp1, en sr = hr(i, i - 1) hr(i, i - 1) = 0.0_wp norm = pythag(pythag(hr(i - 1, i - 1), hi(i - 1, i - 1)), sr) xr = hr(i - 1, i - 1)/norm wr(i - 1) = xr xi = hi(i - 1, i - 1)/norm wi(i - 1) = xi hr(i - 1, i - 1) = norm hi(i - 1, i - 1) = 0.0_wp hi(i, i - 1) = sr/norm do j = i, en yr = hr(i - 1, j) yi = hi(i - 1, j) zzr = hr(i, j) zzi = hi(i, j) hr(i - 1, j) = xr*yr + xi*yi + hi(i, i - 1)*zzr hi(i - 1, j) = xr*yi - xi*yr + hi(i, i - 1)*zzi hr(i, j) = xr*zzr - xi*zzi - hi(i, i - 1)*yr hi(i, j) = xr*zzi + xi*zzr - hi(i, i - 1)*yi end do end do si = hi(en, en) if (si /= 0.0_wp) then norm = pythag(hr(en, en), si) sr = hr(en, en)/norm si = si/norm hr(en, en) = norm hi(en, en) = 0.0_wp end if ! inverse operation (columns) do j = lp1, en xr = wr(j - 1) xi = wi(j - 1) do i = l, j yr = hr(i, j - 1) yi = 0.0_wp zzr = hr(i, j) zzi = hi(i, j) if (i /= j) then yi = hi(i, j - 1) hi(i, j - 1) = xr*yi + xi*yr + hi(j, j - 1)*zzi end if hr(i, j - 1) = xr*yr - xi*yi + hi(j, j - 1)*zzr hr(i, j) = xr*zzr + xi*zzi - hi(j, j - 1)*yr hi(i, j) = xr*zzi - xi*zzr - hi(j, j - 1)*yi end do end do if (si /= 0.0_wp) then do i = l, en yr = hr(i, en) yi = hi(i, en) hr(i, en) = sr*yr - si*yi hi(i, en) = sr*yi + si*yr end do end if end if end do end do main end subroutine comqr