home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l042 / 1.ddi / CHAP7.ARC / EIGEN2.INC < prev    next >
Encoding:
Text File  |  1987-12-30  |  44.3 KB  |  1,196 lines

  1. {----------------------------------------------------------------------------}
  2. {-                                                                          -}
  3. {-     Turbo Pascal Numerical Methods Toolbox                               -}
  4. {-     Copyright (c) 1986, 87 by Borland International, Inc.                -}
  5. {-                                                                          -}
  6. {----------------------------------------------------------------------------}
  7.  
  8. procedure Wielandt{(Dimen       : integer;
  9.                    Mat          : TNmatrix;
  10.                var GuessVector  : TNvector;
  11.                    MaxEigens    : integer;
  12.                    MaxIter      : integer;
  13.                    Tolerance    : Float;
  14.                var NumEigens    : integer;
  15.                var Eigenvalues  : TNvector;
  16.                var Eigenvectors : TNmatrix;
  17.                var Iter         : TNIntVector;
  18.                var Error        : byte)};
  19.  
  20. type
  21.   LevelData = record
  22.                 Size : integer;
  23.                 ZeroPlace : integer;
  24.                 X : TNvector;
  25.                 QuasiEVecs : TNmatrix;
  26.               end;
  27.  
  28.   Ptr = ^ QueueItem;
  29.  
  30.   QueueItem = record
  31.                 Info : LevelData;
  32.                 Next : Ptr;
  33.               end;
  34.  
  35.   Queue = record
  36.             Front : Ptr;
  37.             Back : Ptr;
  38.           end;
  39.  
  40. var
  41.   TransformInfo : Queue;
  42.   Data : LevelData;
  43.  
  44. procedure InitializeQueue(var TransformInfo : Queue);
  45. begin
  46.   TransformInfo.Front := nil;
  47.   TransformInfo.Back := nil;
  48. end; { procedure InitializeQueue }
  49.  
  50. procedure InsertQueue(var Data          : LevelData;
  51.                       var TransformInfo : Queue);
  52.  
  53. {----------------------------------}
  54. {- Input: Data, TransformInfo     -}
  55. {- Output: TransformInfo          -}
  56. {-                                -}
  57. {- Insert Data onto back of Queue -}
  58. {----------------------------------}
  59.  
  60. var
  61.   NewNode : Ptr;
  62.  
  63. begin
  64.   New(NewNode);
  65.   NewNode^.Info := Data;
  66.   NewNode^.Next := nil;
  67.   if TransformInfo.Back = nil then
  68.     TransformInfo.Front := NewNode
  69.   else
  70.     TransformInfo.Back^.Next := NewNode;
  71.   TransformInfo.Back := NewNode;
  72. end; { procedure InsertQueue }
  73.  
  74. procedure RemoveQueue(var Data          : LevelData;
  75.                       var TransformInfo : Queue);
  76.  
  77. {---------------------------------}
  78. {- Input: TransformInfo          -}
  79. {- Output: Data, TransformInfo   -}
  80. {-                               -}
  81. {- Remove Data from the front    -}
  82. {- of the queue.                 -}
  83. {---------------------------------}
  84.  
  85. var
  86.   OldNode : Ptr;
  87.  
  88. begin
  89.   OldNode := TransformInfo.Front;
  90.   TransformInfo.Front := OldNode^.Next;
  91.   Data := OldNode^.Info;
  92.   if TransformInfo.Front = nil then
  93.     TransformInfo.Back := nil;
  94.   Dispose(OldNode);
  95. end; { procedure RemoveQueue }
  96.  
  97. procedure FindLargest(Dimen : integer;
  98.                   var Vec   : TNvector;
  99.                   var Posit : integer);
  100.  
  101. {---------------------------------------}
  102. {- Input: Dimen, Vec                   -}
  103. {- Output: Posit                       -}
  104. {-                                     -}
  105. {- This procedure searches Vec for the -}
  106. {- element of largest absolute value.  -}
  107. {- The position of the largest element -}
  108. {- is returned.                        -}
  109. {---------------------------------------}
  110.  
  111. var
  112.   Term : integer;
  113.   Largest : Float;
  114.  
  115. begin
  116.   Largest := Vec[1];
  117.   Posit := 1;
  118.   for Term := 2 to Dimen do
  119.     if ABS(Vec[Term]) > ABS(Largest) then
  120.     begin
  121.       Largest := Vec[Term];
  122.       Posit := Term;
  123.     end;
  124. end; { procedure FindLargest }
  125.  
  126. procedure DivVecConst(Dimen   : integer;
  127.                       Divisor : Float;
  128.                   var Vec     : TNvector;
  129.                   var Result  : TNvector);
  130.  
  131. {-----------------------------------}
  132. {- Input: Dimen, Divisor, Vec      -}
  133. {- Output: Result                  -}
  134. {-                                 -}
  135. {- Divide a vector by a constant   -}
  136. {-----------------------------------}
  137.  
  138. var
  139.   Term : integer;
  140.  
  141. begin
  142.   for Term := 1 to Dimen do
  143.     Result[Term] := Vec[Term] / Divisor;
  144. end; { procedure DivVecConst }
  145.  
  146. procedure CrossProduct(Dimen  : integer;
  147.                    var Vec1   : TNvector;
  148.                    var Vec2   : TNvector;
  149.                    var Result : TNmatrix);
  150.  
  151. {------------------------------------------}
  152. {- Input: Dimen, Vec1, Vec2               -}
  153. {- Output: Result                         -}
  154. {-                                        -}
  155. {- Multiply two vectors to yield a matrix -}
  156. {------------------------------------------}
  157.  
  158. var
  159.   Row, Column : integer;
  160.  
  161. begin
  162.   for Row := 1 to Dimen do
  163.     for Column := 1 to Dimen do
  164.       Result[Row, Column] := Vec1[Row] * Vec2[Column];
  165. end; { procedure  CrossProduct }
  166.  
  167. function DotProduct(Dimen : integer;
  168.                 var Vec1  : TNvector;
  169.                 var Vec2  : TNvector) : Float;
  170.  
  171. {--------------------------------------------}
  172. {- Input: Dimen, Vec1, Vec2                 -}
  173. {- Output: DotProduct                       -}
  174. {-                                          -}
  175. {- Calculate the dot product of two vectors -}
  176. {--------------------------------------------}
  177.  
  178. var
  179.   Row : integer;
  180.   Result : Float;
  181.  
  182. begin
  183.   Result := 0;
  184.   for Row := 1 to Dimen do
  185.     Result := Result + Vec1[Row] * Vec2[Row];
  186.   DotProduct := Result;
  187. end; { procedure DotProduct }
  188.  
  189. {-----------------------------------------------------------------------}
  190.  
  191. procedure Power(Dimen       : integer;
  192.             var Mat         : TNmatrix;
  193.             var GuessVector : TNvector;
  194.                 MaxIter     : integer;
  195.                 Tolerance   : Float;
  196.             var Eigenvalue  : Float;
  197.             var Eigenvector : TNvector;
  198.             var Iter        : integer;
  199.             var Error       : byte);
  200.  
  201. {----------------------------------------------------------------------------}
  202. {-                                                                          -}
  203. {-              Input:  Dimen, Mat, GuessVector, MaxIter, Tolerance         -}
  204. {-             Output:  Eigenvalue, Eigenvector, Iter, Error                -}
  205. {-                                                                          -}
  206. {-            Purpose:  The power method approximates the dominant          -}
  207. {-                      eigenvalue of a matrix.  The dominant               -}
  208. {-                      eigenvalue is the eigenvalue of largest             -}
  209. {-                      absolute magnitude. Given a square matrix Mat       -}
  210. {-                      and an arbitrary vector OldApprox, the vector       -}
  211. {-                      NewApprox is constructed by the matrix              -}
  212. {-                      operation NewApprox = Mat - OldApprox .             -}
  213. {-                      NewApprox is divided by its largest element         -}
  214. {-                      ApproxEigenval, thereby normalizing                 -}
  215. {-                      NewApprox. If NewApprox is the same as              -}
  216. {-                      OldApprox then ApproxEigenval is the dominant       -}
  217. {-                      eigenvalue and NewApprox is the associated          -}
  218. {-                      eigenvector of the matrix Mat. If NewApprox         -}
  219. {-                      is not the same as OldApprox then OldApprox         -}
  220. {-                      is set equal to NewApprox and the operation         -}
  221. {-                      repeats until a solution is reached. Aitken's       -}
  222. {-                      delta-squared acceleration is used to speed         -}
  223. {-                      the convergence from linear to quadratic.           -}
  224. {-                                                                          -}
  225. {- User-defined Types:  TNvector = array[1..TNArraySize] of real;           -}
  226. {-                      TNmatrix = array[1..TNArraySize] of TNvector;       -}
  227. {-                                                                          -}
  228. {-   Global Variables:  Dimen       : integer;  Dimension of the matrix     -}
  229. {-                      Mat         : TNmatrix; The matrix                  -}
  230. {-                      GuessVector : TNvector; An initial guess of an      -}
  231. {-                                              eigenvector                 -}
  232. {-                      MaxIter     : integer;  Max. number of iterations   -}
  233. {-                      Tolerance   : real;     Tolerance in answer         -}
  234. {-                      Eigenvalue  : real;     Eigenvalue of the matrix    -}
  235. {-                      Eigenvector : TNvector; Eigenvector of the matrix   -}
  236. {-                      Iter        : integer;  Number of iterations        -}
  237. {-                      Error       : byte;     Flags if something goes     -}
  238. {-                                              wrong                       -}
  239. {-             Errors:  0: No Errors                                        -}
  240. {-                      1: Dimen < 2                                        -}
  241. {-                      2: Tolerance <= 0                                   -}
  242. {-                      3: MaxIter < 1                                      -}
  243. {-                      4: Iter >= MaxIter                                  -}
  244. {-                                                                          -}
  245. {----------------------------------------------------------------------------}
  246.  
  247. type
  248.   TNThreeMatrix = array[0..2] of TNvector;
  249.  
  250. var
  251.   OldApprox, NewApprox : TNvector;     { Iteration variables }
  252.   ApproxEigenval : Float;               { Iteration variables }
  253.   AitkenVector : TNThreeMatrix;
  254.   Remainder : integer;
  255.   Found : boolean;
  256.   Index : integer;
  257.   Denom : Float;
  258.  
  259. procedure Initialize(var GuessVector    : TNvector;
  260.                      var Iter           : integer;
  261.                      var OldApprox      : TNvector;
  262.                      var AitkenVector   : TNThreeMatrix;
  263.                      var ApproxEigenval : Float;
  264.                      var Found          : boolean);
  265.  
  266. {----------------------------------------------------------}
  267. {- Input: GuessVector                                     -}
  268. {- Output: Iter, OldApprox, AitkenVector, ApproxEigenval  -}
  269. {-         Found                                          -}
  270. {-                                                        -}
  271. {- This procedure initializes the variables.  OldApprox   -}
  272. {- is initialized to be the user's input GuessVector.     -}
  273. {----------------------------------------------------------}
  274.  
  275. begin
  276.   Iter := 0;
  277.   OldApprox := GuessVector;
  278.   FillChar(AitkenVector, SizeOf(AitkenVector), 0);
  279.   ApproxEigenval := 0;
  280.   Found := false;
  281. end; { procedure Initialize }
  282.  
  283. procedure TestData(Dimen       : integer;
  284.                var Mat         : TNmatrix;
  285.                var GuessVector : TNvector;
  286.                    Tolerance   : Float;
  287.                    MaxIter     : integer;
  288.                var Eigenvalue  : Float;
  289.                var Eigenvector : TNvector;
  290.                var Found       : boolean;
  291.                var Error       : byte);
  292.  
  293. {---------------------------------------------------------}
  294. {- Input: Dimen, Mat, GuessVector, Tolerance, MaxIter    -}
  295. {- Output: GuessVector, Eigenvalue, Eigenvector          -}
  296. {-         Found, Error                                  -}
  297. {-                                                       -}
  298. {- This procedure tests the input data for errors        -}
  299. {- If all the elements of the GuessVector are zero, then -}
  300. {- they are all replaced by ones.                        -}
  301. {- If the dimension of the matrix is one, then the       -}
  302. {- eigenvalue is equal to the matrix.                    -}
  303. {---------------------------------------------------------}
  304.  
  305. var
  306.   Term : integer;
  307.   Sum : Float;
  308.  
  309. begin
  310.   Error := 0;
  311.   Sum := 0;
  312.   for Term := 1 to Dimen do
  313.     Sum := Sum + Sqr(GuessVector[Term]);
  314.   if Sum < TNNearlyZero then { the GuessVector is the zero vector }
  315.     for Term := 1 to Dimen do
  316.       GuessVector[Term] := 1;
  317.   if Dimen < 1 then
  318.     Error := 1;
  319.   if Tolerance <= 0 then
  320.     Error := 2;
  321.   if MaxIter < 1 then
  322.     Error := 3;
  323.   if Dimen = 1 then
  324.   begin
  325.     Eigenvalue := Mat[1, 1];
  326.     Eigenvector := GuessVector;
  327.     Found := true;
  328.   end;
  329. end; { procedure TestData }
  330.  
  331. procedure FindLargest(Dimen   : integer;
  332.                   var Vec     : TNvector;
  333.                   var Largest : Float);
  334.  
  335. {---------------------------------------}
  336. {- Input: Dimen, Vec                   -}
  337. {- Output: Largest                     -}
  338. {-                                     -}
  339. {- This procedure searches Vec for the -}
  340. {- element of largest absolute value.  -}
  341. {---------------------------------------}
  342.  
  343. var
  344.   Term : integer;
  345.  
  346. begin
  347.   Largest := Vec[Dimen];
  348.   for Term := Dimen - 1 downto 1 do
  349.     if ABS(Vec[Term]) > ABS(Largest) then
  350.       Largest := Vec[Term];
  351. end; { procedure FindLargest }
  352.  
  353. procedure Div_Vec_Const(Dimen   : integer;
  354.                     var Vec     : TNvector;
  355.                         Divisor : Float);
  356.  
  357. {----------------------------------------------}
  358. {- Input: Dimen, Vec, Divisor                 -}
  359. {- Output: Vec                                -}
  360. {-                                            -}
  361. {- This procedure divides each element        -}
  362. {- of the vector Vec by the constant Divisor. -}
  363. {----------------------------------------------}
  364.  
  365. var
  366.   Term : integer;
  367.  
  368. begin
  369.   for Term := 1 to Dimen do
  370.     Vec[Term] := Vec[Term] / Divisor;
  371. end; { procedure Div_Vec_Const }
  372.  
  373. procedure Mult_Mat_Vec(Dimen  : integer;
  374.                    var Mat    : TNmatrix;
  375.                    var Vec    : TNvector;
  376.                    var Result : TNvector);
  377.  
  378. {----------------------------------------}
  379. {- Input: Dimen, Mat, Vec               -}
  380. {- Output: Result                       -}
  381. {-                                      -}
  382. {- Multiply a vector by a square matrix -}
  383. {----------------------------------------}
  384.  
  385. var
  386.   Row, Column : integer;
  387.   Entry : Float;
  388.  
  389. begin
  390.   for Row := 1 to Dimen do
  391.   begin
  392.     Entry := 0;
  393.     for Column := 1 to Dimen do
  394.       Entry := Entry + Mat[Row, Column] * Vec[Column];
  395.     Result[Row] := Entry;
  396.   end;
  397. end; { procedure Mult_Mat_Vec }
  398.  
  399.  
  400. procedure TestForConvergence(Dimen     : integer;
  401.                          var OldApprox : TNvector;
  402.                          var NewApprox : TNvector;
  403.                              Tolerance : Float;
  404.                          var Found     : boolean);
  405.  
  406. {-----------------------------------------------------------------}
  407. {- Input: Dimen, OldApprox, NewApprox, Tolerance,                -}
  408. {- Output: Found                                                 -}
  409. {-                                                               -}
  410. {- This procedure determines if the iterations have converged.   -}
  411. {- on a solution.  If the absolute difference in EACH element of -}
  412. {- the eigenvector between the last two iterations (i.e. between -}
  413. {- OldApprox and NewApprox) is less than Tolerance, then         -}
  414. {- convergence has occurred and Found = true.  Otherwise,        -}
  415. {- Found = false.                                                -}
  416. {-----------------------------------------------------------------}
  417.  
  418. var
  419.   Index : integer;
  420.  
  421. begin
  422.   Index := 0;
  423.   Found := true;
  424.   while (Found = true) and (Index < Dimen) do
  425.   begin
  426.     Index := Succ(Index);
  427.     if ABS(OldApprox[Index] - NewApprox[Index]) > Tolerance then
  428.       Found := false;
  429.   end;
  430. end; { procedure TestForConvergence }
  431.  
  432. begin  { procedure Power }
  433.   Initialize(GuessVector, Iter, OldApprox, AitkenVector,
  434.              ApproxEigenval, Found);
  435.   TestData(Dimen, Mat, GuessVector, Tolerance, MaxIter,
  436.            Eigenvalue, Eigenvector, Found, Error);
  437.   if (Error = 0) and (Found = false) then
  438.   begin
  439.     FindLargest(Dimen, OldApprox, ApproxEigenval);
  440.     Div_Vec_Const(Dimen, OldApprox, ApproxEigenval);
  441.     while (Iter < MaxIter) and not Found do
  442.     begin
  443.       Iter := Succ(Iter);
  444.       Remainder := Iter MOD 3;
  445.       if Remainder = 0 then { Use Aitken's acceleration algorithm to  }
  446.                             { generate the next iterate approximation }
  447.       begin
  448.         OldApprox := AitkenVector[0];
  449.         for Index := 1 to Dimen do
  450.         begin
  451.           Denom := AitkenVector[2, Index] - 2 * AitkenVector[1, Index] +
  452.                    AitkenVector[0, Index];
  453.           if ABS(Denom) > TNNearlyZero then
  454.             OldApprox[Index] := AitkenVector[0, Index] -
  455.                                 Sqr(AitkenVector[1, Index] -
  456.                                 AitkenVector[0, Index]) / Denom;
  457.         end;
  458.       end;
  459.       { Use the power method to generate }
  460.       { the next iterate approximation   }
  461.       Mult_Mat_Vec(Dimen, Mat, OldApprox, NewApprox);
  462.       FindLargest(Dimen, NewApprox, ApproxEigenval);
  463.       if ABS(ApproxEigenval) < TNNearlyZero then
  464.         begin
  465.           ApproxEigenval := 0;
  466.           Found := true;
  467.         end
  468.       else
  469.         begin
  470.           Div_Vec_Const(Dimen, NewApprox, ApproxEigenval);
  471.           TestForConvergence(Dimen, OldApprox, NewApprox, Tolerance, Found);
  472.           OldApprox := NewApprox;
  473.         end;
  474.       AitkenVector[Remainder] := NewApprox;
  475.     end; { while }
  476.     Eigenvector := OldApprox;
  477.     Eigenvalue := ApproxEigenval;
  478.     if Iter >= MaxIter then
  479.       Error := 4;
  480.   end;
  481. end; { procedure Power }
  482. {-----------------------------------------------------------------------}
  483.  
  484. procedure TestDataAndInitialize(Dimen         : integer;
  485.                             var Mat           : TNmatrix;
  486.                             var GuessVector   : TNvector;
  487.                                 Tolerance     : Float;
  488.                                 MaxEigens     : integer;
  489.                                 MaxIter       : integer;
  490.                             var NumEigens     : integer;
  491.                             var Eigenvalue    : TNvector;
  492.                             var Eigenvector   : TNmatrix;
  493.                             var TransformInfo : Queue;
  494.                             var Iter          : TNIntVector;
  495.                             var Data          : LevelData;
  496.                             var Error         : byte);
  497.  
  498. {--------------------------------------------------}
  499. {- Input: Dimen, GuessVector, Tolerance,          -}
  500. {-        MaxEigens, MaxIter                      -}
  501. {- Output: GuessVector, NumEigens, Eigenvalue,    -}
  502. {-         Eigenvector, TransformInfo, Iter,      -}
  503. {-         Data, Error                            -}
  504. {-                                                -}
  505. {- This procedure initializes variable and tests  -}
  506. {- the input data for errors.                     -}
  507. {- If all the elements of the GuessVector are     -}
  508. {- zero, then they are all replaced by ones.      -}
  509. {- If the dimension of the matrix is one, then    -}
  510. {- the eigenvalue is equal to the matrix.         -}
  511. {--------------------------------------------------}
  512.  
  513. var
  514.   Term : integer;
  515.   Sum : Float;
  516.  
  517. begin
  518.   Error := 0;
  519.   Sum := 0;
  520.   for Term := 1 to Dimen do
  521.     Sum := Sum + Sqr(GuessVector[Term]);
  522.   if Sum < TNNearlyZero then  { The GuessVector is the zero vector  }
  523.                               { change all the elements to one.     }
  524.     for Term := 1 to Dimen do
  525.       GuessVector[Term] := 1;
  526.   if Tolerance <= 0 then
  527.     Error := 2;
  528.   if MaxIter < 1 then
  529.     Error := 3;
  530.   if (MaxEigens < 1) or (MaxEigens > Dimen) then
  531.     Error := 4;
  532.   if Dimen < 1 then
  533.     Error := 1;
  534.   if Error = 0 then
  535.   begin
  536.     InitializeQueue(TransformInfo);
  537.     FillChar(Iter, SizeOf(Iter), 0);
  538.     FillChar(Data, SizeOf(Data), 0);
  539.     NumEigens := 0;
  540.   end;
  541.   if Dimen = 1 then
  542.   begin
  543.     Eigenvalue[1] := Mat[1, 1];
  544.     Eigenvector[1, 1] := 1;
  545.     NumEigens := 1;
  546.   end;
  547. end; { procedure TestDataAndInitialize }
  548.  
  549. procedure ConstructX(Size        : integer;
  550.                  var Mat         : TNmatrix;
  551.                  var Eigenvector : TNvector;
  552.                  var ZeroPlace   : integer;
  553.                  var X           : TNvector);
  554.  
  555. {---------------------------------------------------------}
  556. {- Input: Size, Mat, Eigenvector                         -}
  557. {- Output: ZeroPlace, X                                  -}
  558. {-                                                       -}
  559. {- This procedure creates the vector X.  The formula is: -}
  560. {-   X := Mat[ZeroPlace]/Eigenvector[ZeroPlace]          -}
  561. {- where ZeroPlace is the Index of the largest element   -}
  562. {- in Eigenvector.                                       -}
  563. {---------------------------------------------------------}
  564.  
  565. begin
  566.   { ZeroPlace is the position of the largest element. }
  567.   FindLargest(Size, Eigenvector, ZeroPlace);
  568.   DivVecConst(Size, Eigenvector[ZeroPlace], Mat[ZeroPlace], X);
  569. end; { procedure ConstructX }
  570.  
  571. procedure MakeMatrix(Size        : integer;
  572.                  var Mat         : TNmatrix;
  573.                  var Eigenvector : TNvector;
  574.                      ZeroPlace   : integer;
  575.                  var X           : TNvector);
  576.  
  577. {-----------------------------------------------------------}
  578. {- Input: Size, Mat, Eigenvector, ZeroPlace, X             -}
  579. {- Output: Mat                                             -}
  580. {-                                                         -}
  581. {- This procedure changes the matrix Mat.  The formula is  -}
  582. {-    Mat := Mat - (Eigenvector # X)                       -}
  583. {- where the # represents a cross product.                 -}
  584. {- Then the ZeroPlace row and column are deleted from the  -}
  585. {- matrix.                                                 -}
  586. {-----------------------------------------------------------}
  587.  
  588. var
  589.   Row, Column : integer;
  590.   TempMatrix : TNmatrix;
  591.  
  592. begin
  593.   CrossProduct(Size, Eigenvector, X, TempMatrix);
  594.   for Row := 1 to ZeroPlace - 1 do
  595.     for Column := 1 to ZeroPlace - 1 do
  596.       Mat[Row, Column] := Mat[Row, Column] - TempMatrix[Row, Column];
  597.   for Row := 1 to ZeroPlace - 1 do
  598.     for Column := ZeroPlace to Size - 1 do
  599.       Mat[Row, Column] := Mat[Row, Column + 1] - TempMatrix[Row, Column + 1];
  600.   for Row := ZeroPlace to Size - 1 do
  601.     for Column := 1 to ZeroPlace - 1 do
  602.       Mat[Row, Column] := Mat[Row + 1, Column] - TempMatrix[Row + 1, Column];
  603.   for Row := ZeroPlace to Size - 1 do
  604.     for Column := ZeroPlace to Size - 1 do
  605.       Mat[Row, Column] := Mat[Row + 1, Column + 1]
  606.                           - TempMatrix[Row + 1, Column + 1];
  607. end; { procedure MakeMatrix }
  608.  
  609. procedure InsertZero(Size        : integer;
  610.                  var Eigenvector : TNvector;
  611.                      ZeroPlace   : integer;
  612.                  var TempVector  : TNvector);
  613.  
  614. {----------------------------------------------------}
  615. {- Input: Size, Eigenvector, ZeroPlace              -}
  616. {- Output: TempVector                               -}
  617. {-                                                  -}
  618. {- This procedure inserts a zero into the ZeroPlace -}
  619. {- element of Eigenvector.  The resulting vector is -}
  620. {- returned in TempVector.                          -}
  621. {----------------------------------------------------}
  622.  
  623. var
  624.   Index : integer;
  625.  
  626. begin
  627.   TempVector := Eigenvector;
  628.   for Index := Size - 1 downto ZeroPlace do
  629.     TempVector[Index + 1] := Eigenvector[Index];
  630.   TempVector[ZeroPlace] := 0;
  631. end; { procedure InsertZero }
  632.  
  633. procedure MakeNewVec(Size         : integer;
  634.                      Eigenval1    : Float;
  635.                      Eigenval2    : Float;
  636.                  var TempVec      : TNvector;
  637.                  var X            : TNvector;
  638.                  var OldQuasiEVec : TNvector;
  639.                  var NewQuasiEVec : TNvector);
  640.  
  641. {---------------------------------------------------------------}
  642. {- Input: Size, Eigenval1, Eigenval2, TempVec, X, OldQuasiEVec -}
  643. {- Output: NewQuasiEVec                                        -}
  644. {-                                                             -}
  645. {- This procedure transforms the TempVec into NewQuasiEVec.    -}
  646. {- The formula is:                                             -}
  647. {-   NewQuasiEVec = (Eigenval1 - Eigenval2) - TempVec          -}
  648. {-                  + X,TempVec - OldQuasiEVec                 -}
  649. {- where X,TempVec is the dot product of X and TempVec.        -}
  650. {---------------------------------------------------------------}
  651.  
  652. var
  653.   Difference, Multiplier : Float;
  654.   Index : integer;
  655.  
  656. begin
  657.   Difference := Eigenval1 - Eigenval2;
  658.   Multiplier := DotProduct(Size, X, TempVec);
  659.   for Index := 1 to Size do
  660.     NewQuasiEVec[Index] := Difference * TempVec[Index]
  661.                            + Multiplier * OldQuasiEVec[Index];
  662. end; { procedure MakeNewVec }
  663.  
  664. procedure TransformThroughLevels(NumEigens     : integer;
  665.                              var Data          : LevelData;
  666.                              var TransformInfo : Queue;
  667.                              var Eigenvalues   : TNvector);
  668. var
  669.   Index : integer;             { A counter }
  670.   Data1, Data2 : LevelData;    { Data1 is data from a level one }
  671.                                { higher than Data2.  Information }
  672.                                { from Data2 is transformed for Data1 }
  673.   TempVec : TNvector;          { A temporary vector used in calculations }
  674.  
  675. begin
  676.   Data2 := Data;
  677.   for Index := NumEigens - 1 downto 1 do
  678.   begin
  679.     RemoveQueue(Data1, TransformInfo);
  680.     InsertZero(Data1.Size, Data2.QuasiEVecs[NumEigens],
  681.                Data1.ZeroPlace, TempVec);
  682.     MakeNewVec(Data1.Size, Eigenvalues[NumEigens], Eigenvalues[Index],
  683.                TempVec, Data1.X, Data1.QuasiEVecs[Index],
  684.                Data1.QuasiEVecs[NumEigens]);
  685.     InsertQueue(Data2, TransformInfo);
  686.     Data2 := Data1;
  687.   end;
  688.   InsertQueue(Data2, TransformInfo);
  689. end; { procedure TransformThroughLevels }
  690.  
  691. procedure FindLastTwoEigens(Dimen         : integer;
  692.                         var NumEigens     : integer;
  693.                         var Mat           : TNmatrix;
  694.                         var Eigenvalues   : TNvector;
  695.                         var Data          : LevelData;
  696.                         var TransformInfo : Queue;
  697.                         var Error         : byte);
  698.  
  699. {--------------------------------------------------------------------}
  700. {- Input: Dimen, NumEigens, Mat, Eigenvalues                        -}
  701. {- Output: NumEigens, Data, TransformInfo                           -}
  702. {-                                                                  -}
  703. {- This procedure approximates the last eigenvalue/vector.  The     -}
  704. {- matrix Mat will be a two by two.  The last eigenvalue will       -}
  705. {- be the trace of the matrix Mat minus the second to last          -}
  706. {- eigenvalue (since the sum of the eigenvalues of a matrix is      -}
  707. {- the trace). The first element of the eigenvector is arbitrarily  -}
  708. {- made 1 (eigenvectors are only defined to a multiplicative        -}
  709. {- constant) and the second element is simply computed.  This       -}
  710. {- eigenvector of Mat is then transformed to an eigenvector of the  -}
  711. {- original matrix through the procedure TransformThroughLevels.    -}
  712. {--------------------------------------------------------------------}
  713.  
  714. var
  715.   A, B, C : Float;
  716.   Root1, Root2 : Float;
  717.  
  718. procedure QuadraticFormula(A     : Float;
  719.                            B     : Float;
  720.                            C     : Float;
  721.                        var Root1 : Float;
  722.                        var Root2 : Float;
  723.                        var Error : byte);
  724.  
  725. var
  726.   Discrim : Float;
  727.  
  728. begin
  729.   Discrim := Sqr(B) - 4*A*C;
  730.   if Discrim < -TNNearlyZero then
  731.     Error := 6       { No real roots }
  732.   else
  733.     if ABS(Discrim) < TNNearlyZero then  { Identical roots }
  734.       begin
  735.         Root1 := -B / (2 * A);
  736.         Root2 := Root1;
  737.       end
  738.     else
  739.       begin
  740.         Root1 := (-B - Sqrt(Discrim)) / (2 * A);
  741.         Root2 := -B / A - Root1;
  742.       end;
  743. end; { procedure QuadraticFactor }
  744.  
  745. begin  { procedure FindLastTwoEigens }
  746.   if (ABS(Mat[1, 2]) < TNNearlyZero) or (ABS(Mat[2, 1]) < TNNearlyZero) then
  747.     { zero on the off diagonal }
  748.     with Data do
  749.     begin
  750.       NumEigens := Dimen - 1;
  751.       Size := 2;
  752.       if (ABS(Mat[1, 2]) < TNNearlyZero) and
  753.          (ABS(Mat[2, 1]) < TNNearlyZero) then
  754.         { Zero's on both off diagonals; distinct }
  755.         { eigenvectors; possibly distinct eigenvalues }
  756.         begin
  757.           Eigenvalues[NumEigens] := Mat[2, 2];
  758.           QuasiEVecs[NumEigens, 1] := 0;
  759.           QuasiEVecs[NumEigens, 2] := 1;
  760.           Eigenvalues[NumEigens + 1] := Mat[1, 1];
  761.           QuasiEVecs[NumEigens + 1, 1] := 1;
  762.           QuasiEVecs[NumEigens + 1, 2] := 0;
  763.         end
  764.       else
  765.         { Only one zero on off diagonal }
  766.         if ABS(Mat[1, 2]) < TNNearlyZero then
  767.           begin
  768.             Eigenvalues[NumEigens] := Mat[2, 2];
  769.             QuasiEVecs[NumEigens, 1] := 0;
  770.             QuasiEVecs[NumEigens, 2] := 1;
  771.             Eigenvalues[NumEigens + 1] := Mat[1, 1];
  772.             if ABS(Mat[1, 1] - Mat[2, 2]) < TNNearlyZero then
  773.               { Degenerate eigenvalues/vectors }
  774.               QuasiEVecs[NumEigens + 1] := QuasiEVecs[NumEigens]
  775.             else
  776.               { Distinct eigenvalues/vectors }
  777.               begin
  778.                 QuasiEVecs[NumEigens + 1, 1] := 1;
  779.                 QuasiEVecs[NumEigens + 1, 2] := Mat[2, 1] /
  780.                                                 (Mat[1, 1] - Mat[2, 2]);
  781.               end;
  782.           end
  783.         else
  784.           { ABS(Mat[2, 1]) < TNNearlyZero }
  785.           begin
  786.             Eigenvalues[NumEigens] := Mat[1, 1];
  787.             QuasiEVecs[NumEigens, 1] := 1;
  788.             QuasiEVecs[NumEigens, 2] := 0;
  789.             Eigenvalues[NumEigens + 1] := Mat[2, 2];
  790.             if ABS(Mat[1, 1] - Mat[2, 2]) < TNNearlyZero then
  791.               { Degenerate eigenvalues/vectors }
  792.               QuasiEVecs[NumEigens + 1] := QuasiEVecs[NumEigens]
  793.             else
  794.               { Distinct eigenvalues/vectors }
  795.               begin
  796.                 QuasiEVecs[NumEigens + 1, 2] := 1;
  797.                 QuasiEVecs[NumEigens + 1, 1] := Mat[1, 2] / (Mat[2, 2] - Mat[1, 1]);
  798.               end;
  799.           end;
  800.       ConstructX(Size, Mat, QuasiEVecs[NumEigens], ZeroPlace, X);
  801.       TransformThroughLevels(NumEigens, Data, TransformInfo, Eigenvalues);
  802.       NumEigens := Dimen;
  803.       TransformThroughLevels(NumEigens, Data, TransformInfo, Eigenvalues);
  804.     end
  805.   else   { no zero's on the off diagonal }
  806.     begin
  807.       A := 1;
  808.       B := -(Mat[1, 1] + Mat[2, 2]);
  809.       C := Mat[1, 1] * Mat[2, 2] - Mat[1, 2] * Mat[2, 1];
  810.       QuadraticFormula(A, B, C, Root1, Root2, Error);
  811.       if Error = 0 then
  812.       with Data do
  813.       begin
  814.         NumEigens := Dimen - 1;
  815.         Size := 2;
  816.         Eigenvalues[NumEigens] := Root1;
  817.         QuasiEVecs[NumEigens, 1] := 1;
  818.         QuasiEVecs[NumEigens, 2] := (Eigenvalues[NumEigens]
  819.                                     - Mat[1, 1]) / Mat[1, 2];
  820.         Eigenvalues[NumEigens + 1] := Root2;
  821.         QuasiEVecs[NumEigens + 1, 1] := 1;
  822.         QuasiEVecs[NumEigens + 1, 2] := (Eigenvalues[NumEigens + 1]
  823.                                         - Mat[1, 1]) / Mat[1, 2];
  824.         ConstructX(Size, Mat, QuasiEVecs[NumEigens], ZeroPlace, X);
  825.         TransformThroughLevels(NumEigens, Data, TransformInfo, Eigenvalues);
  826.         NumEigens := Dimen;
  827.         TransformThroughLevels(NumEigens, Data, TransformInfo, Eigenvalues);
  828.       end; { with }
  829.     end;
  830. end; { procedure FindLastTwoEigens }
  831.  
  832. procedure NormalizeEigenvectors(Dimen         : integer;
  833.                                 NumEigens     : integer;
  834.                             var TransformInfo : Queue;
  835.                             var Eigenvectors  : TNmatrix);
  836.  
  837. {--------------------------------------------------------}
  838. {- Input: Dimen, NumEigens, TransformInfo, Eigenvectors -}
  839. {- Output: Eigenvectors                                 -}
  840. {-                                                      -}
  841. {- This procedure normalizes the eigenvectors so that   -}
  842. {- the element of largest absolute value equals 1.      -}
  843. {--------------------------------------------------------}
  844.  
  845. var
  846.   Index : integer;
  847.   Data : LevelData;
  848.   Posit : integer;
  849.  
  850. begin
  851.   { The eigenvectors are the }
  852.   { QuasiEVecs of the last Data }
  853.   { removed from the queue. }
  854.   for Index := 1 to NumEigens do
  855.     RemoveQueue(Data, TransformInfo);
  856.   Eigenvectors := Data.QuasiEVecs;
  857.   for Index := 1 to NumEigens do
  858.   begin
  859.     FindLargest(Dimen, Eigenvectors[Index], Posit);
  860.     if ABS(Eigenvectors[Index, Posit]) > TNNearlyZero then
  861.       DivVecConst(Dimen, Eigenvectors[Index, Posit],
  862.                   Eigenvectors[Index], Eigenvectors[Index]);
  863.   end;
  864. end; { procedure NormalizeEigenvectors }
  865.  
  866. begin { procedure Wielandt }
  867.   TestDataAndInitialize(Dimen, Mat, GuessVector, Tolerance,
  868.                         MaxEigens, MaxIter, NumEigens, Eigenvalues,
  869.                         Eigenvectors, TransformInfo, Iter, Data, Error);
  870.   if (Error = 0) and (Dimen > 1) then
  871.   begin
  872.     with Data do
  873.     while (NumEigens < Dimen - 2) and (NumEigens < MaxEigens) and (Error = 0) do
  874.     begin
  875.       NumEigens := Succ(NumEigens);
  876.       Size := Dimen - (NumEigens - 1);
  877.       Power(Size, Mat, GuessVector, MaxIter,Tolerance, Eigenvalues[NumEigens],
  878.             QuasiEVecs[NumEigens], Iter[NumEigens], Error);
  879.       ConstructX(Size, Mat, QuasiEVecs[NumEigens], ZeroPlace, X);
  880.       if Size > 2 then
  881.         MakeMatrix(Size, Mat, QuasiEVecs[NumEigens], ZeroPlace, X);
  882.       TransformThroughLevels(NumEigens, Data, TransformInfo, Eigenvalues);
  883.     end; { while }
  884.     if Error > 0 then
  885.       Error := 5     { The Error returned from Power means an }
  886.                      { eigen wasn't calculated, but the Error }
  887.                      { code may not be 5.                     }
  888.     else
  889.       if (NumEigens = Dimen - 2) and (NumEigens < MaxEigens) then
  890.         { Then NumEigens = Dimen - 2 and the      }
  891.         { last two eigenvectors can be calculated }
  892.         FindLastTwoEigens(Dimen, NumEigens, Mat, Eigenvalues,
  893.                           Data, TransformInfo, Error);
  894.     NormalizeEigenvectors(Dimen, NumEigens, TransformInfo, Eigenvectors);
  895.   end
  896. end; { procedure Wielandt }
  897.  
  898. procedure Jacobi{(Dimen       : integer;
  899.                  Mat          : TNmatrix;
  900.                  MaxIter      : integer;
  901.                  Tolerance    : Float;
  902.              var Eigenvalues  : TNvector;
  903.              var Eigenvectors : TNmatrix;
  904.              var Iter         : integer;
  905.              var Error        : byte)};
  906.  
  907. var
  908.   Row, Column, Diag : integer;
  909.   SinTheta, CosTheta : Float;
  910.   SumSquareDiag : Float;
  911.   Done : boolean;
  912.  
  913. procedure TestData(Dimen     : integer;
  914.                var Mat       : TNmatrix;
  915.                    MaxIter   : integer;
  916.                    Tolerance : Float;
  917.                var Error     : byte);
  918.  
  919. {---------------------------------------------------}
  920. {- Input: Dimen, Mat, MaxIter, Tolerance           -}
  921. {- Output: Error                                   -}
  922. {-                                                 -}
  923. {- This procedure tests the input data for errors. -}
  924. {---------------------------------------------------}
  925.  
  926. var
  927.   Row, Column : integer;
  928.  
  929. begin
  930.   Error := 0;
  931.   if Dimen < 1 then
  932.     Error := 1;
  933.   if Tolerance <= TNNearlyZero then
  934.     Error := 2;
  935.   if MaxIter < 1 then
  936.     Error := 3;
  937.   if Error = 0 then
  938.     for Row := 1 to Dimen - 1 do
  939.       for Column := Row + 1 to Dimen do
  940.         if ABS(Mat[Row, Column] - Mat[Column, Row]) > TNNearlyZero then
  941.           Error := 4;  { Matrix not symmetric }
  942. end; { procedure TestData }
  943.  
  944. procedure Initialize(Dimen        : integer;
  945.                  var Iter         : integer;
  946.                  var Eigenvectors : TNmatrix);
  947.  
  948. {--------------------------------------------}
  949. {- Input: Dimen                             -}
  950. {- Output: Iter, Eigenvectors               -}
  951. {-                                          -}
  952. {- This procedure initializes Iter to zero  -}
  953. {- and Eigenvectors to the identity matrix. -}
  954. {--------------------------------------------}
  955.  
  956. var
  957.   Diag : integer;
  958.  
  959. begin
  960.   Iter := 0;
  961.   FillChar(Eigenvectors, SizeOf(Eigenvectors), 0);
  962.   for Diag := 1 to Dimen do
  963.     Eigenvectors[Diag, Diag] := 1;
  964. end; { procedure Initialize }
  965.  
  966. procedure CalculateRotation(RowRow   : Float;
  967.                             RowCol   : Float;
  968.                             ColCol   : Float;
  969.                         var SinTheta : Float;
  970.                         var CosTheta : Float);
  971.  
  972.  
  973. {-----------------------------------------------------------}
  974. {- Input: RowRow, RowCol, ColCol                           -}
  975. {- Output: SinTheta, CosTheta                              -}
  976. {-                                                         -}
  977. {- This procedure calculates the sine and cosine of the    -}
  978. {- angle Theta through which to rotate the matrix Mat.     -}
  979. {- Given the tangent of 2-Theta, the tangent of Theta can  -}
  980. {- be calculated with the quadratic formula.  The cosine   -}
  981. {- and sine are easily calculable from the tangent. The    -}
  982. {- rotation must be such that the Row, Column element is   -}
  983. {- zero. RowRow is the Row,Row element; RowCol is the      -}
  984. {- Row,Column element; ColCol is the Column,Column element -}
  985. {- of Mat.                                                 -}
  986. {-----------------------------------------------------------}
  987.  
  988. var
  989.   TangentTwoTheta, TangentTheta, Dummy : Float;
  990.  
  991. begin
  992.   if ABS(RowRow - ColCol) > TNNearlyZero then
  993.     begin
  994.       TangentTwoTheta := (RowRow - ColCol) / (2 * RowCol);
  995.       Dummy := Sqrt(Sqr(TangentTwoTheta) + 1);
  996.       if TangentTwoTheta < 0 then  { Choose the root nearer to zero }
  997.         TangentTheta := -TangentTwoTheta - Dummy
  998.       else
  999.         TangentTheta := -TangentTwoTheta + Dummy;
  1000.       CosTheta := 1 / Sqrt(1 + Sqr(TangentTheta));
  1001.       SinTheta := CosTheta * TangentTheta;
  1002.     end
  1003.   else
  1004.     begin
  1005.       CosTheta := Sqrt(1/2);
  1006.       if RowCol < 0 then
  1007.         SinTheta := -Sqrt(1/2)
  1008.       else
  1009.         SinTheta := Sqrt(1/2);
  1010.     end;
  1011. end; { procedure CalculateRotation }
  1012.  
  1013. procedure RotateMatrix(Dimen    : integer;
  1014.                        SinTheta : Float;
  1015.                        CosTheta : Float;
  1016.                        Row      : integer;
  1017.                        Col      : integer;
  1018.                    var Mat      : TNmatrix);
  1019.  
  1020. {--------------------------------------------------------------}
  1021. {- Input: Dimen, SinTheta, CosTheta, Row, Col                 -}
  1022. {- Output: Mat                                                -}
  1023. {-                                                            -}
  1024. {- This procedure rotates the matrix Mat through an angle     -}
  1025. {- Theta.  The rotation matrix is the identity matrix execept -}
  1026. {- for the Row,Row; Row,Col; Col,Col; and Col,Row elements.   -}
  1027. {- The rotation will make the Row,Col element of Mat          -}
  1028. {- to be zero.                                                -}
  1029. {--------------------------------------------------------------}
  1030.  
  1031. var
  1032.   CosSqr, SinSqr, SinCos : Float;
  1033.   MatRowRow, MatColCol, MatRowCol, MatRowIndex, MatColIndex : Float;
  1034.  
  1035.   Index : integer;
  1036.  
  1037. begin
  1038.   CosSqr := Sqr(CosTheta);
  1039.   SinSqr := Sqr(SinTheta);
  1040.   SinCos := SinTheta * CosTheta;
  1041.   MatRowRow := Mat[Row, Row] * CosSqr + 2 * Mat[Row, Col] * SinCos +
  1042.                Mat[Col, Col] * SinSqr;
  1043.   MatColCol := Mat[Row, Row] * SinSqr - 2 * Mat[Row, Col] * SinCos +
  1044.                Mat[Col, Col] * CosSqr;
  1045.   MatRowCol := (Mat[Col, Col] - Mat[Row, Row]) * SinCos +
  1046.                Mat[Row, Col] * (CosSqr - SinSqr);
  1047.  
  1048.   for Index := 1 to Dimen do
  1049.     if not(Index in [Row, Col]) then
  1050.     begin
  1051.       MatRowIndex := Mat[Row, Index] * CosTheta +
  1052.                      Mat[Col, Index] * SinTheta;
  1053.       MatColIndex := -Mat[Row, Index] * SinTheta +
  1054.                       Mat[Col, Index] * CosTheta;
  1055.       Mat[Row, Index] := MatRowIndex;
  1056.       Mat[Index, Row] := MatRowIndex;
  1057.       Mat[Col, Index] := MatColIndex;
  1058.       Mat[Index, Col] := MatColIndex;
  1059.     end;
  1060.   Mat[Row, Row] := MatRowRow;
  1061.   Mat[Col, Col] := MatColCol;
  1062.   Mat[Row, Col] := MatRowCol;
  1063.   Mat[Col, Row] := MatRowCol;
  1064. end; { procedure RotateMatrix }
  1065.  
  1066. procedure RotateEigenvectors(Dimen        : integer;
  1067.                              SinTheta     : Float;
  1068.                              CosTheta     : Float;
  1069.                              Row          : integer;
  1070.                              Col          : integer;
  1071.                          var Eigenvectors : TNmatrix);
  1072.  
  1073. {--------------------------------------------------------------}
  1074. {- Input: Dimen, SinTheta, CosTheta, Row, Col                 -}
  1075. {- Output: Eigenvectors                                       -}
  1076. {-                                                            -}
  1077. {- This procedure rotates the Eigenvectors matrix through an  -}
  1078. {- angle Theta.  The rotation matrix is the identity matrix   -}
  1079. {- except for the Row,Row; Row,Col; Col,Col; and Col,Row      -}
  1080. {- elements.  The Eigenvectors matrix will be the product of  -}
  1081. {- all the rotation matrices which operate on Mat.            -}
  1082. {--------------------------------------------------------------}
  1083.  
  1084. var
  1085.   EigenvectorsRowIndex, EigenvectorsColIndex : Float;
  1086.  
  1087.   Index : integer;
  1088.  
  1089. begin
  1090.   { Transform eigenvector matrix }
  1091.   for Index := 1 to  Dimen do
  1092.   begin
  1093.     EigenvectorsRowIndex := CosTheta * Eigenvectors[Row, Index] +
  1094.                             SinTheta * Eigenvectors[Col, Index];
  1095.     EigenvectorsColIndex := -SinTheta * Eigenvectors[Row, Index] +
  1096.                              CosTheta * Eigenvectors[Col, Index];
  1097.     Eigenvectors[Row, Index] := EigenvectorsRowIndex;
  1098.     Eigenvectors[Col, Index] := EigenvectorsColIndex;
  1099.   end;
  1100. end; { procedure RotateEigenvectors }
  1101.  
  1102. procedure NormalizeEigenvectors(Dimen        : integer;
  1103.                             var Eigenvectors : TNmatrix);
  1104.  
  1105. {---------------------------------------------------}
  1106. {- Input: Dimen, Eigenvectors                      -}
  1107. {- Output: Eigenvectors                            -}
  1108. {-                                                 -}
  1109. {- This procedure normalizes the eigenvectors so   -}
  1110. {- that the largest element in each vector is one. -}
  1111. {---------------------------------------------------}
  1112.  
  1113. var
  1114.   Row : integer;
  1115.   Largest : Float;
  1116.  
  1117. procedure FindLargest(Dimen       : integer;
  1118.                   var Eigenvector : TNvector;
  1119.                   var Largest     : Float);
  1120.  
  1121. {---------------------------------------}
  1122. {- Input: Dimen, Eigenvectors          -}
  1123. {- Output: Largest                     -}
  1124. {-                                     -}
  1125. {- This procedure returns the value of -}
  1126. {- the largest element of the vector.  -}
  1127. {---------------------------------------}
  1128.  
  1129. var
  1130.   Term : integer;
  1131.  
  1132. begin
  1133.   Largest := Eigenvector[1];
  1134.   for Term := 2 to Dimen do
  1135.     if ABS(Eigenvector[Term]) > ABS(Largest) then
  1136.       Largest := Eigenvector[Term];
  1137. end; { procedure FindLargest }
  1138.  
  1139. procedure DivVecConst(Dimen       : integer;
  1140.                   var ChangingRow : TNvector;
  1141.                       Divisor     : Float);
  1142.  
  1143. {--------------------------------------------------------}
  1144. {- Input: Dimen, ChangingRow                            -}
  1145. {- Output: Divisor                                      -}
  1146. {-                                                      -}
  1147. {- elementary row operation - dividing by a constant    -}
  1148. {--------------------------------------------------------}
  1149.  
  1150. var
  1151.   Term : integer;
  1152.  
  1153. begin
  1154.   for Term := 1 to Dimen do
  1155.     ChangingRow[Term] := ChangingRow[Term] / Divisor;
  1156. end; { procedure DivVecConst }
  1157.  
  1158. begin { procedure NormalizeEigenvectors }
  1159.   for Row := 1 to Dimen do
  1160.   begin
  1161.     FindLargest(Dimen, Eigenvectors[Row], Largest);
  1162.     DivVecConst(Dimen, Eigenvectors[Row], Largest);
  1163.   end;
  1164. end; { procedure NormalizeEigenvectors }
  1165.  
  1166. begin { procedure Jacobi }
  1167.   TestData(Dimen, Mat, MaxIter, Tolerance, Error);
  1168.   if Error = 0 then
  1169.   begin
  1170.     Initialize(Dimen, Iter, Eigenvectors);
  1171.     repeat
  1172.       Iter := Succ(Iter);
  1173.       SumSquareDiag := 0;
  1174.       for Diag := 1 to Dimen do
  1175.         SumSquareDiag := SumSquareDiag + Sqr(Mat[Diag, Diag]);
  1176.       Done := true;
  1177.       for Row := 1 to Dimen - 1  do
  1178.         for Column := Row + 1 to Dimen do
  1179.           if ABS(Mat[Row, Column]) > Tolerance * SumSquareDiag then
  1180.           begin
  1181.             Done := false;
  1182.             CalculateRotation(Mat[Row, Row], Mat[Row, Column],
  1183.                               Mat[Column, Column], SinTheta, CosTheta);
  1184.             RotateMatrix(Dimen, SinTheta, CosTheta, Row, Column, Mat);
  1185.             RotateEigenvectors(Dimen, SinTheta, CosTheta, Row, Column,
  1186.                                Eigenvectors);
  1187.           end;
  1188.     until Done or (Iter > MaxIter);
  1189.     for Diag := 1 to Dimen do
  1190.       Eigenvalues[Diag] := Mat[Diag, Diag];
  1191.     NormalizeEigenvectors(Dimen, Eigenvectors);
  1192.     if Iter > MaxIter then
  1193.       Error := 5
  1194.   end;
  1195. end; { procedure Jacobi }
  1196.