program ALG092;
{ SYMMETRIC POWER METHOD

   To approximate the dominant eigenvalue and an associated
   eigenvector of the n by n symmetric matrix A given a nonzero vector x:

   INPUT:   Dimension n; matrix A; vector x; tolerance TOL;
            maximum number of iterations N.

   OUTPUT:  Approximate eigenvalue MU; approximate eigenvector x or
            a message that the maximum number of iterations was
            exceeded.
}
const
   ZERO = 1.0E-20;
var
   A : array [ 1..10, 1..10 ] of real;
   X,Y : array [ 1..10 ] of real;
   YMU,ERR,TOL : real;
   FLAG,N,I,J,NN,K : integer;
   OK : boolean;
   AA : char;
   NAME : string [ 14 ];
   INP,OUP : text;
procedure INPUT;
begin
   writeln('This is the Symmetric Power Method.');
   OK := false;
   writeln ('The array will be input from a text file in the order: ');
   writeln('A(1,1), A(1,2), ..., A(1,n), A(2,1), A(2,2), ..., A(2,n),');
   write ('..., A(n,1), ');
   writeln ('A(n,2), ..., A(n,n) '); writeln;
   write ('Place as many entries as desired on each line, but separate ');
   writeln ('entries with ');
   writeln ('at least one blank. ');
   writeln ('The initial approximation should follow in same format. ');
   writeln; writeln;
   writeln ('Has the input file been created? - enter Y or N. ');
   readln ( AA );
   if ( AA = 'Y' ) or ( AA = 'y' ) then
      begin
         writeln ('Input the file name in the form - drive:name.ext, ');
         writeln ('for example: A:DATA.DTA ');
         readln ( NAME );
         assign ( INP, NAME );
         reset ( INP );
         OK := false;
         while ( not OK ) do
            begin
               writeln ('Input the dimension n. ');
               readln ( N );
               if ( N > 0 ) then
                  begin
                     for I := 1 to N do
                        for J := 1 to N do read ( INP, A[I,J] );
{                    Because of the way in which the subroutine
                     norm computes the l2 norm of a vector,
                     the initial input of X is into Y and X
                     is initialized at the zero vector.             }
                     for I := 1 to N do read ( INP, Y[I] );
                     for I := 1 to N do X[I] := 0.0;
{                    Use X1 for XO                                  }
                     close ( INP );
                     while ( not OK ) do
                        begin
                           writeln ('Input the tolerance. ');
                           readln ( TOL );
                           if ( TOL > 0.0 ) then OK := true
                           else
                              writeln ('Tolerance must be positive number. ')
                        end;
                     OK := false;
                     while ( not OK ) do
                        begin
                           write ('Input maximum number of iterations ');
                           writeln ('- integer. ');
                           readln ( NN );
{                          Use NN for capital N for the maximum number of
                           iterations                                     }
                           if ( NN > 0 ) then OK := true
                           else
                              writeln ('Number must be positive integer. ')
                        end
                  end
               else writeln ('The dimension must be a positive integer. ')
            end
      end
   else writeln ('The program will end so the input file can be created. ')
end;
procedure OUTPUT;
   begin
      writeln ('Choice of output method: ');
      writeln ('1. Output to screen ');
      writeln ('2. Output to text file ');
      writeln ('Please enter 1 or 2. ');
      readln ( FLAG );
      if ( FLAG = 2 ) then
         begin
            writeln ('Input the file name in the form - drive:name.ext, ');
            writeln('for example:   A:OUTPUT.DTA');
            readln ( NAME );
            assign ( OUP, NAME )
         end
      else  assign ( OUP, 'CON' );
      rewrite ( OUP );
      writeln(OUP,'SYMMETRIC POWER METHOD');
      writeln(OUP);
      writeln(OUP,'iter   approx        approx eigenvector');
      writeln(OUP,'       eigenvalue');
   end;
procedure NORM;
   var
      XL,T : real;
      I : integer;
   begin
      XL := 0.0;
      for I := 1 to N do XL := XL + sqr( Y[I] );
      XL := sqrt( XL );
      ERR := 0.0;
      if ( XL > ZERO ) then
         begin
            for I := 1 to N do
               begin
                  T := Y[I] / XL;
                  ERR := ERR + sqr(X[I]-T);
                  X[I] := T
               end;
            ERR := sqrt(ERR)
         end
      else
         begin
            write ('A has a zero eigenvalue - select new vector and begin ');
            writeln ('again ');
            OK := false
         end
   end;
   begin
      INPUT;
      if ( OK ) then
         begin
            OUTPUT;
{           STEP 1                                                     }
            K := 1;
{           Norm computes the norm of the vector X and
            returns X divided by its norm in the variable Y            }
            NORM;
            if ( OK ) then
               begin
{                 STEP 2                                               }
                  while ( ( K <= NN ) and OK ) do
                     begin
{                       STEPS 3 AND 4                                  }
                        YMU := 0.0;
                        for I := 1 to N do
                           begin
                              Y[I] := 0.0;
                              for J := 1 to N do
                                 Y[I] := Y[I] + A[I,J] * X[J];
                              YMU := YMU + X[I] * Y[I]
                           end;
{                       STEP 5 (This step is accomplished in
                                subroutine norm.)                      }
{                       STEP 6                                         }
                        NORM;
           write ( OUP,K,' ', YMU:12:8,'   ');
           for I := 1 to N do write ( OUP, X[I]:12:8 );
           writeln(OUP);
                        if ( OK ) then
                           begin
{                             STEP 7                                   }
                              if ( ERR < TOL ) then
                                 begin
{                                   procedure completed successfully   }
                      writeln ( OUP ); writeln ( OUP );
                      write ( OUP, 'The eigenvalue = ', YMU:12:8 );
           writeln ( OUP, ' to tolerance = ', TOL );
           writeln ( OUP, 'obtained on iteration number = ', K );
           writeln ( OUP );
          writeln ( OUP, 'Unit eigenvector is: '); writeln ( OUP ) ;
          for I := 1 to N do write ( OUP, X[I]:12:8 );
                                    OK := false
                                 end
                              else
{                                STEP 8                                }
                                 K := K + 1
                           end
                     end;
{                 STEP 9                                               }
                  if ( K > NN ) then
                     writeln ('No convergence within ', NN, ' iterations ')
               end
         end;
         close(OUP);
   end.

