begin
library A0, A1, A4, A5, A15;
comment
eigenvalues of a real symmetric matrix by the QR method.
Algorithm 253, P.A. Businger, CACM 8 (1965) 217.
;
integer n;
open(20);
open(30);
n := read(20);
begin
integer i,j;
real array a[1:n,1:n], b[1:n,1:n];
procedure symmetric QR1(n,g);
value n; integer n;
array g;
begin
comment
uses Householders's method and the QR algorithm to
find all n eigenvalues of the real symmetric matrix whose lower
triangular part is given in the array g[1:n,1:n].
The computed eigenvalues are stored as the diagonal elements g[i,i].
The original contents of the lower triangular part of g are lost
during the computation whereas the strictly upper triagular part
of g is left untouched.
;
real procedure sum(i,m,n,a);
value m,n; integer i,m,n;
real a;
begin
real s;
s:= 0;
for i:= m step 1 until n do s:= s + a;
sum:= s
end sum;
real procedure max (a,b);
value a,b; real a,b;
max:= if a > b then a else b;
procedure Housholder tridiagonalization 1(n,g,a,bq,norm);
value n; integer n;
array g,a,bq;
real norm;
comment nonlocal real procedure sum, max;
comment
reduces the given real symmetric n by n matrix g to tridiagonal form using
n - 2 elementary orthogonal trans-formations (I-2ww') = (I-gamma uu').
Only the lower triangular part of g need be given.
The diagonal elements and the squares of the subdiagonal elements
of the reduced matrix are stored in a[1:n] and bq[1:n-1] respectively.
norm is set equal to the infinity norm of the reduced matrix.
The columns of the strictly lower triagular part of g are replaced
by the nonzero portions of the vectors u.
;
begin
integer i,j,k;
real t,absb,alpha,beta,gamma,sigma;
array p[2:n];
norm:= absb:= 0;
for k:= 1 step 1 until n - 2 do
begin
a[k]:= g[k,k];
sigma:= bq[k]:= sum(i,k+1,n,g[i,k]^2);
t:= absb + abs(a[k]); absb:= sqrt(sigma);
norm:= max(norm,t+absb);
if sigma ± 0 then
begin
alpha:= g[k+1,k];
beta:= if alpha < 0 then absb else - absb;
gamma:= 1 / (sigma-alpha×beta); g[k+1,k]:= alpha - beta;
for i:= k + 1 step 1 until n do
p[i]:= gamma × (sum(j,k+1,i,g[i,j]×g[j,k]) + sum(j,i+1,n,g[j,i]×g[j,k]));
t:= 0.5 × gamma × sum(i,k+1,n,g[i,k]×p[i]);
for i:= k + 1 step 1 until n do
p[i]:= p[i] - t×g[i,k];
for i:= k + 1 step 1 until n do
for j:= k + 1 step 1 until i do
g[i,j]:= g[i,j] - g[i,k]×p[j] - p[i]×g[j,k]
end
end k;
a[n-1]:= g[n-1,n-1]; bq[n-1]:= g[n,n-1]^2;
a[n]:= g[n,n]; t:= abs(g[n,n-1]);
norm:= max(norm,absb+abs(a[n-1])+t);
norm:= max(norm,t+abs(a[n]))
end Housholder tridiagonalization 1;
integer i,k,m,m1;
real norm,epsq,lambda,mu,sq1,sq2,u,pq,gamma,t;
array a[1:n],bq[0:n-1];
Housholder tridiagonalization 1(n,g,a,bq,norm);
epsq:= 3.25º-24×norm^2;
comment
The tolerance used in the QR iteration depends on the square of the
relative machine precision. Here 3.25º-24 is used, which is
appropriate for a machine with a 39-bit mantissa, like KDF9.
;
mu:= 0; m:= n;
inspect:
if m = 0 then
goto return
else
i:= k:= m1:= m - 1;
bq[0]:= 0;
if bq[k] <= epsq then
begin
g[m,m]:= a[m]; mu:= 0; m:= k;
goto inspect
end;
for i:= i - 1 while bq[i] > epsq do k:= i;
if k = m1 then
begin comment treat 2 × 2 block separately;
mu:= a[m1]×a[m] - bq[m1]; sq1:= a[m1] + a[m];
sq2:= sqrt((a[m1]-a[m])^2+4×bq[m1]);
lambda:= 0.5×(if sq1>=0 then sq1+sq2 else sq1-sq2);
g[m1,m1]:= lambda; g[m,m]:= mu / lambda;
mu:= 0; m:= m - 2;
goto inspect
end;
lambda:=
if abs(a[m]-mu) < 0.5×abs(a[m]) then a[m] + 0.5×sqrt(bq[m1]) else 0.0;
mu:= a[m]; sq1:= sq2:= u:= 0;
for i:= k step 1 until m1 do
begin comment shortcut single QR iteration;
gamma:= a[i] - lambda - u;
pq:= if sq1 ± 1 then gamma^2/(1-sq1) else (1-sq2)×bq[i-1];
t:= pq + bq[i]; bq[i-1]:= sq1 × t; sq2:= sq1;
sq1:= bq[i] / t; u:= sq1 × (gamma+a[i+1]-lambda);
a[i]:= gamma + u + lambda
end i;
gamma:= a[m] - lambda - u;
bq[m1]:= sq1 × (if sq1±1 then gamma^2/(1-sq1) else (1-sq2)×bq[m1]);
a[m]:= gamma + lambda;
goto inspect;
return:
end symmetric QR 1;
for i:= 1 step 1 until n do
for j:= 1 step 1 until i do
b[i,j] := read(20);
for i:= 1 step 1 until n do
for j:= 1 step 1 until i do
a[i,j] := b[i,j];
symmetric QR 1(n,a);
for i:= 1 step 1 until n do
begin
write(30, format({nds}), i); write(30, format({+d.dddddddddº+ddc}), a[i,i])
end;
write(30, format({+d.dddddddddº+dd}), a[1,1]+a[2,2]);
writetext(30, {$should$equal$});
write(30, format({+d.dddddddddº+dd}), b[1,1]+b[n,n]);
writetext(30, {$and$});
write(30, format({+d.dddddddddº+ddc}), a[n-1,n-1]+a[n,n]);
writetext(30, {$sum$of$});
write(30, format({+d.dddddddddº+dd}), a[n-1,n-1]);
writetext(30, {$and$});
write(30, format({+d.dddddddddº+ddc}), a[n,n]);
end;
close(20);
close(30);
end
|