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

  1. {----------------------------------------------------------------------------}
  2. {-                                                                          -}
  3. {-     Turbo Pascal Numerical Methods Toolbox                               -}
  4. {-     Copyright (c) 1986, 87 by Borland International, Inc.                -}
  5. {-                                                                          -}
  6. {----------------------------------------------------------------------------}
  7.  
  8. procedure Power{(Dimen      : integer;
  9.             var Mat         : TNmatrix;
  10.             var GuessVector : TNvector;
  11.                 MaxIter     : integer;
  12.                 Tolerance   : Float;
  13.             var Eigenvalue  : Float;
  14.             var Eigenvector : TNvector;
  15.             var Iter        : integer;
  16.             var Error       : byte)};
  17.  
  18. type
  19.   TNThreeMatrix = array[0..2] of TNvector;
  20.  
  21. var
  22.   OldApprox, NewApprox : TNvector;     { Iteration variables }
  23.   ApproxEigenval : Float;               { Iteration variables }
  24.   AitkenVector : TNThreeMatrix;
  25.   Remainder : integer;
  26.   Found : boolean;
  27.   Index : integer;
  28.   Denom : Float;
  29.  
  30. procedure TestDataAndInitialize(Dimen          : integer;
  31.                             var Mat            : TNmatrix;
  32.                             var GuessVector    : TNvector;
  33.                                 Tolerance      : Float;
  34.                                 MaxIter        : integer;
  35.                             var Eigenvalue     : Float;
  36.                             var Eigenvector    : TNvector;
  37.                             var Found          : boolean;
  38.                             var Iter           : integer;
  39.                             var OldApprox      : TNvector;
  40.                             var AitkenVector   : TNThreeMatrix;
  41.                             var ApproxEigenval : Float;
  42.                             var Error          : byte);
  43.  
  44. {---------------------------------------------------------}
  45. {- Input: Dimen, Mat, GuessVector, Tolerance, MaxIter    -}
  46. {- Output: GuessVector, Eigenvalue, Eigenvector          -}
  47. {-         Found, Error                                  -}
  48. {-                                                       -}
  49. {- This procedure tests the input data for errors        -}
  50. {- If all the elements of the GuessVector are zero, then -}
  51. {- they are all replaced by ones.                        -}
  52. {- If the dimension of the matrix is one, then the       -}
  53. {- eigenvalue is equal to the matrix.                    -}
  54. {---------------------------------------------------------}
  55.  
  56. var
  57.   Term : integer;
  58.   Sum : Float;
  59.  
  60. begin
  61.   Error := 0;
  62.   Sum := 0;
  63.   for Term := 1 to Dimen do
  64.     Sum := Sum + Sqr(GuessVector[Term]);
  65.   if Sum < TNNearlyZero then { The GuessVector is the zero vector }
  66.     for Term := 1 to Dimen do
  67.       GuessVector[Term] := 1;
  68.   if Dimen < 1 then
  69.     Error := 1;
  70.   if Tolerance <= 0 then
  71.     Error := 2;
  72.   if MaxIter < 1 then
  73.     Error := 3;
  74.   if Error = 0 then
  75.   begin
  76.     Iter := 0;
  77.     OldApprox := GuessVector;
  78.     FillChar(AitkenVector, SizeOf(AitkenVector), 0);
  79.     ApproxEigenval := 0;
  80.     Found := false;
  81.   end;
  82.   if Dimen = 1 then
  83.   begin
  84.     Eigenvalue := Mat[1, 1];
  85.     Eigenvector[1] := 1;
  86.     Found := true;
  87.   end;
  88. end; { procedure TestDataAndInitialize }
  89.  
  90. procedure FindLargest(Dimen   : integer;
  91.                   var Vec     : TNvector;
  92.                   var Largest : Float);
  93.  
  94. {---------------------------------------}
  95. {- Input: Dimen, Vec                   -}
  96. {- Output: Largest                     -}
  97. {-                                     -}
  98. {- This procedure searches Vec for the -}
  99. {- element of largest absolute value.  -}
  100. {---------------------------------------}
  101.  
  102. var
  103.   Term : integer;
  104.  
  105. begin
  106.   Largest := Vec[Dimen];
  107.   for Term := Dimen - 1 downto 1 do
  108.     if ABS(Vec[Term]) > ABS(Largest) then
  109.       Largest := Vec[Term];
  110. end; { procedure FindLargest }
  111.  
  112. procedure Div_Vec_Const(Dimen   : integer;
  113.                     var Vec     : TNvector;
  114.                         Divisor : Float);
  115.  
  116. {----------------------------------------------}
  117. {- Input: Dimen, Vec, Divisor                 -}
  118. {- Output: Vec                                -}
  119. {-                                            -}
  120. {- This procedure divides each element        -}
  121. {- of the vector Vec by the constant Divisor. -}
  122. {----------------------------------------------}
  123.  
  124. var
  125.   Term : integer;
  126.  
  127. begin
  128.   for Term := 1 to Dimen do
  129.     Vec[Term] := Vec[Term] / Divisor;
  130. end; { procedure Div_Vec_Const }
  131.  
  132. procedure Mult_Mat_Vec(Dimen  : integer;
  133.                    var Mat    : TNmatrix;
  134.                    var Vec    : TNvector;
  135.                    var Result : TNvector);
  136.  
  137. {----------------------------------------}
  138. {- Input: Dimen, Mat, Vec               -}
  139. {- Output: Result                       -}
  140. {-                                      -}
  141. {- Multiply a vector by a square matrix -}
  142. {----------------------------------------}
  143.  
  144. var
  145.   Row, Column : integer;
  146.   Entry : Float;
  147.  
  148. begin
  149.   for Row := 1 to Dimen do
  150.   begin
  151.     Entry := 0;
  152.     for Column := 1 to Dimen do
  153.       Entry := Entry + Mat[Row, Column] * Vec[Column];
  154.     Result[Row] := Entry;
  155.   end;
  156. end; { procedure Mult_Mat_Vec }
  157.  
  158.  
  159. procedure TestForConvergence(Dimen     : integer;
  160.                          var OldApprox : TNvector;
  161.                          var NewApprox : TNvector;
  162.                              Tolerance : Float;
  163.                          var Found     : boolean);
  164.  
  165. {-----------------------------------------------------------------}
  166. {- Input: Dimen, OldApprox, NewApprox, Tolerance,                -}
  167. {- Output: Found                                                 -}
  168. {-                                                               -}
  169. {- This procedure determines if the iterations have converged.   -}
  170. {- on a solution.  If the absolute difference in EACH element of -}
  171. {- the eigenvector between the last two iterations (i.e. between -}
  172. {- OldApprox and NewApprox) is less than Tolerance, then         -}
  173. {- convergence has occurred and Found = true.  Otherwise,        -}
  174. {- Found = false.                                                -}
  175. {-----------------------------------------------------------------}
  176.  
  177. var
  178.   Index : integer;
  179.  
  180. begin
  181.   Index := 0;
  182.   Found := true;
  183.   while (Found = true) and (Index < Dimen) do
  184.   begin
  185.     Index := Succ(Index);
  186.     if ABS(OldApprox[Index] - NewApprox[Index]) > Tolerance then
  187.       Found := false;
  188.   end; { while }
  189. end; { procedure TestForConvergence }
  190.  
  191. begin { procedure Power }
  192.   TestDataAndInitialize(Dimen, Mat, GuessVector, Tolerance, MaxIter,
  193.                         Eigenvalue, Eigenvector, Found, Iter,
  194.                         OldApprox, AitkenVector, ApproxEigenval, Error);
  195.   if (Error = 0) and (Found = false) then
  196.   begin
  197.     FindLargest(Dimen, OldApprox, ApproxEigenval);
  198.     Div_Vec_Const(Dimen, OldApprox, ApproxEigenval);
  199.     while (Iter < MaxIter) and not Found do
  200.     begin
  201.       Iter := Succ(Iter);
  202.       Remainder := Iter MOD 3;
  203.       if Remainder = 0 then  { Use Aitken's acceleration algorithm to  }
  204.                              { generate the next iterate approximation }
  205.       begin
  206.         OldApprox := AitkenVector[0];
  207.         for Index := 1 to Dimen do
  208.         begin
  209.           Denom := AitkenVector[2, Index] -
  210.                    2 * AitkenVector[1, Index] + AitkenVector[0, Index];
  211.           if ABS(Denom) > TNNearlyZero then
  212.             OldApprox[Index] := AitkenVector[0, Index] -
  213.             Sqr(AitkenVector[1, Index] - AitkenVector[0, Index]) / Denom;
  214.         end;
  215.       end;
  216.       { Use the power method to generate }
  217.       { the next iterate approximation   }
  218.       Mult_Mat_Vec(Dimen, Mat, OldApprox, NewApprox);
  219.       FindLargest(Dimen, NewApprox, ApproxEigenval);
  220.       if ABS(ApproxEigenval) < TNNearlyZero then
  221.         begin
  222.           ApproxEigenval := 0;
  223.           Found := true;
  224.         end
  225.       else
  226.         begin
  227.           Div_Vec_Const(Dimen, NewApprox, ApproxEigenval);
  228.           TestForConvergence(Dimen, OldApprox, NewApprox, Tolerance, Found);
  229.           OldApprox := NewApprox;
  230.         end;
  231.       AitkenVector[Remainder] := NewApprox;
  232.     end; { while }
  233.     Eigenvector := OldApprox;
  234.     Eigenvalue := ApproxEigenval;
  235.     if Iter >= MaxIter then
  236.       Error := 4;
  237.   end;
  238. end; { procedure Power }
  239.  
  240. procedure InversePower{(Dimen      : integer;
  241.                        Mat         : TNmatrix;
  242.                    var GuessVector : TNvector;
  243.                        ClosestVal  : Float;
  244.                        MaxIter     : integer;
  245.                        Tolerance   : Float;
  246.                    var Eigenvalue  : Float;
  247.                    var Eigenvector : TNvector;
  248.                    var Iter        : integer;
  249.                    var Error       : byte)};
  250.  
  251. var
  252.   OldApprox, NewApprox : TNvector;     { Iteration variables }
  253.   ApproxEigenval : Float;               { Iteration variables }
  254.   Found : boolean;
  255.  
  256. procedure TestDataAndInitialize(Dimen          : integer;
  257.                             var Mat            : TNmatrix;
  258.                             var GuessVector    : TNvector;
  259.                                 Tolerance      : Float;
  260.                                 MaxIter        : integer;
  261.                             var Eigenvalue     : Float;
  262.                             var Eigenvector    : TNvector;
  263.                             var Found          : boolean;
  264.                             var Iter           : integer;
  265.                             var OldApprox      : TNvector;
  266.                             var ClosestVal     : Float;
  267.                             var ApproxEigenval : Float;
  268.                             var Error          : byte);
  269.  
  270. {--------------------------------------------------------}
  271. {- Input: Dimen, Mat, GuessVector, Tolerance, MaxIter   -}
  272. {- Output: Guess, Eigenvalue, Eigenvector, Found,       -}
  273. {-         Iter, OldApprox, ClosestVal, ApproxEigenval, -}
  274. {-         Error                                        -}
  275. {-                                                      -}
  276. {- This procedure tests the input data for errors       -}
  277. {- If all the elements of the GuessVector are           -}
  278. {- zero, then they are all replaced by ones.            -}
  279. {- If the dimension of the matrix is one, then the      -}
  280. {- eigenvalue equals the matrix.                        -}
  281. {--------------------------------------------------------}
  282.  
  283. var
  284.   Term : integer;
  285.   Sum : Float;
  286.  
  287. begin
  288.   Error := 0;
  289.   Sum := 0;
  290.   for Term := 1 to Dimen do
  291.     Sum := Sum + Sqr(GuessVector[Term]);
  292.   if Sum < TNNearlyZero then { The GuessVector is the zero vector }
  293.     for Term := 1 to Dimen do
  294.       GuessVector[Term] := 1;
  295.   if Dimen < 1 then
  296.     Error := 1;
  297.   if Tolerance <= 0 then
  298.     Error := 2;
  299.   if MaxIter < 1 then
  300.     Error := 3;
  301.   Found := false;
  302.   if Dimen = 1 then
  303.   begin
  304.     Eigenvalue := Mat[1, 1];
  305.     Eigenvector[1] := 1;
  306.     Found := true;
  307.   end;
  308.   if Error = 0 then
  309.   begin
  310.     Iter := 0;
  311.     OldApprox := GuessVector;
  312.     { Subtract ClosestVal from the main diagonal of Mat }
  313.     for Term := 1 to Dimen do
  314.       Mat[Term, Term] := Mat[Term, Term] - ClosestVal;
  315.     ApproxEigenval := 0;
  316.   end;
  317. end; { procedure TestDataAndInitialize }
  318.  
  319. procedure FindLargest(Dimen   : integer;
  320.                   var Vec     : TNvector;
  321.                   var Largest : Float);
  322.  
  323. {---------------------------------------}
  324. {- Input: Dimen, Vec                   -}
  325. {- Output: Largest                     -}
  326. {-                                     -}
  327. {- This procedure searches Vec for the -}
  328. {- element of largest absolute value.  -}
  329. {---------------------------------------}
  330.  
  331. var
  332.   Term : integer;
  333.  
  334. begin
  335.   Largest := Vec[Dimen];
  336.   for Term := Dimen - 1 downto 1 do
  337.     if ABS(Vec[Term]) > ABS(Largest) then
  338.       Largest := Vec[Term];
  339. end; { procedure FindLargest }
  340.  
  341. procedure Div_Vec_Const(Dimen   : integer;
  342.                     var Vec     : TNvector;
  343.                         Divisor : Float);
  344.  
  345. {----------------------------------------------}
  346. {- Input: Dimen, Vec, Divisor                 -}
  347. {- Output: Vec                                -}
  348. {-                                            -}
  349. {- This procedure divides each element        -}
  350. {- of the vector Vec by the constant Divisor. -}
  351. {----------------------------------------------}
  352.  
  353. var
  354.   Term : integer;
  355.  
  356. begin
  357.   for Term := 1 to Dimen do
  358.     Vec[Term] := Vec[Term] / Divisor;
  359. end; { procedure Div_Vec_Const }
  360.  
  361. procedure GetNewApprox(Dimen     : integer;
  362.                    var Mat       : TNmatrix;
  363.                    var OldApprox : TNvector;
  364.                    var NewApprox : TNvector;
  365.                        Iter      : integer;
  366.                    var Error     : byte);
  367.  
  368. {---------------------------------------------}
  369. {- Input: Dimen, Mat, OldApprox, Iter        -}
  370. {- Output: NewApprox, Error                  -}
  371. {-                                           -}
  372. {- This procedure uses Gaussian elimination  -}
  373. {- with partial pivoting to solve the linear -}
  374. {- system:                                   -}
  375. {-   Mat - NewApprox = OldApprox             -}
  376. {- If no unique solution exists, then        -}
  377. {- Error = 5 is returned.                    -}
  378. {---------------------------------------------}
  379.  
  380. var
  381.   Decomp: TNmatrix;
  382.   Permute : TNmatrix;
  383.  
  384. {----------------------------------------------------------------------------}
  385.  
  386. procedure Decompose(Dimen        : integer;
  387.                     Coefficients : TNmatrix;
  388.                 var Decomp       : TNmatrix;
  389.                 var Permute      : TNmatrix;
  390.                 var Error        : byte);
  391.  
  392. {----------------------------------------------------------------------------}
  393. {-                                                                          -}
  394. {-                Input: Dimen, Coefficients                                -}
  395. {-               Output: Decomp, Permute, Error                             -}
  396. {-                                                                          -}
  397. {-             Purpose : Decompose a square matrix into an upper            -}
  398. {-                       triangular and lower triangular matrix such that   -}
  399. {-                       the product of the two triangular matrices is      -}
  400. {-                       the original matrix. This procedure also returns   -}
  401. {-                       a permutation matrix which records the             -}
  402. {-                       permutations resulting from partial pivoting.      -}
  403. {-                                                                          -}
  404. {-  User-defined Types : TNvector = array[1..TNArraySize] of real           -}
  405. {-                       TNmatrix = array[1..TNArraySize] of TNvector       -}
  406. {-                                                                          -}
  407. {-    Global Variables : Dimen        : integer;  Dimen of the coefficients -}
  408. {-                                                matrix                    -}
  409. {-                       Coefficients : TNmatrix; Coefficients matrix       -}
  410. {-                       Decomp       : TNmatrix; Decomposition of          -}
  411. {-                                                coefficients matrix       -}
  412. {-                       Permute      : TNmatrix; Record of partial         -}
  413. {-                                                pivoting                  -}
  414. {-                       Error        : integer;  Flags if something goes   -}
  415. {-                                                wrong.                    -}
  416. {-                                                                          -}
  417. {-              Errors : 0: No errors;                                      -}
  418. {-                       1: Dimen < 1                                       -}
  419. {-                       2: No decomposition possible; singular matrix      -}
  420. {-                                                                          -}
  421. {----------------------------------------------------------------------------}
  422.  
  423. procedure TestInput(Dimen : integer;
  424.                 var Error : byte);
  425.  
  426. {---------------------------------------}
  427. {- Input: Dimen                        -}
  428. {- Output: Error                       -}
  429. {-                                     -}
  430. {- This procedure checks to see if the -}
  431. {- value of Dimen is greater than 1.   -}
  432. {---------------------------------------}
  433.  
  434. begin
  435.   Error := 0;
  436.   if Dimen < 1 then
  437.     Error := 1;
  438. end; { procedure TestInput }
  439.  
  440. function RowColumnMult(Row    : integer;
  441.                    var Lower  : TNmatrix;
  442.                        Column : integer;
  443.                    var Upper  : TNmatrix) : Float;
  444.  
  445. {----------------------------------------------------}
  446. {- Input: Row, Lower, Column, Upper                 -}
  447. {- Function return: dot product of row Row of Lower -}
  448. {-                  and column Column of Upper      -}
  449. {----------------------------------------------------}
  450.  
  451. var
  452.   Term : integer;
  453.   Sum : Float;
  454.  
  455. begin
  456.   Sum := 0;
  457.   for Term := 1 to Row - 1 do
  458.     Sum := Sum + Lower[Row, Term] * Upper[Term, Column];
  459.   RowColumnMult := Sum;
  460. end; { function RowColumnMult }
  461.  
  462.  
  463. procedure Pivot(Dimen        : integer;
  464.                 ReferenceRow : integer;
  465.             var Coefficients : TNmatrix;
  466.             var Lower        : TNmatrix;
  467.             var Upper        : TNmatrix;
  468.             var Permute      : TNmatrix;
  469.             var Error        : byte);
  470.  
  471. {----------------------------------------------------------------}
  472. {- Input: Dimen, ReferenceRow, Coefficients,                    -}
  473. {-        Lower, Upper, Permute                                 -}
  474. {- Output: Coefficients, Lower, Permute, Error                  -}
  475. {-                                                              -}
  476. {- This procedure searches the ReferenceRow column of the       -}
  477. {- Coefficients matrix for the element in the Row below the     -}
  478. {- main diagonal which produces the largest value of            -}
  479. {-                                                              -}
  480. {-         Coefficients[Row, ReferenceRow] -                    -}
  481. {-                                                              -}
  482. {-          SUM K=1 TO ReferenceRow - 1 of                      -}
  483. {-                  Upper[Row, k] - Lower[k, ReferenceRow]      -}
  484. {-                                                              -}
  485. {- If it finds one, then the procedure switches                 -}
  486. {- rows so that this element is on the main diagonal. The       -}
  487. {- procedure also switches the corresponding elements in the    -}
  488. {- Permute matrix and the Lower matrix. If the largest value of -}
  489. {- the above expression is zero, then the matrix is singular    -}
  490. {- and no solution exists (Error = 2 is returned).              -}
  491. {----------------------------------------------------------------}
  492.  
  493. var
  494.   PivotRow, Row : integer;
  495.   ColumnMax, TestMax : Float;
  496.  
  497. procedure EROswitch(var Row1 : TNvector;
  498.                     var Row2 : TNvector);
  499.  
  500. {-------------------------------------------------}
  501. {- Input: Row1, Row2                             -}
  502. {- Output: Row1, Row2                            -}
  503. {-                                               -}
  504. {- Elementary row operation - switching two rows -}
  505. {-------------------------------------------------}
  506.  
  507. var
  508.   DummyRow : TNvector;
  509.  
  510. begin
  511.   DummyRow := Row1;
  512.   Row1 := Row2;
  513.   Row2 := DummyRow;
  514. end; { procedure EROswitch }
  515.  
  516. begin { procedure Pivot }
  517.   { First, find the row with the largest TestMax }
  518.   PivotRow := ReferenceRow;
  519.   ColumnMax := ABS(Coefficients[ReferenceRow, ReferenceRow] -
  520.                RowColumnMult(ReferenceRow, Lower, ReferenceRow, Upper));
  521.   for Row := ReferenceRow + 1 to Dimen do
  522.   begin
  523.     TestMax := ABS(Coefficients[Row, ReferenceRow] -
  524.                RowColumnMult(Row, Lower, ReferenceRow, Upper));
  525.     if TestMax > ColumnMax then
  526.     begin
  527.       PivotRow := Row;
  528.       ColumnMax := TestMax;
  529.     end;
  530.   end;
  531.   if PivotRow <> ReferenceRow then
  532.     { Second, switch these two rows }
  533.     begin
  534.       EROswitch(Coefficients[PivotRow], Coefficients[ReferenceRow]);
  535.       EROswitch(Lower[PivotRow], Lower[ReferenceRow]);
  536.       EROswitch(Permute[PivotRow], Permute[ReferenceRow]);
  537.     end
  538.   else { If ColumnMax is zero, no solution exists }
  539.     if ColumnMax < TNNearlyZero then
  540.       Error := 2;     { No solution exists }
  541. end; { procedure Pivot }
  542.  
  543. procedure LU_Decompose(Dimen        : integer;
  544.                    var Coefficients : TNmatrix;
  545.                    var Decomp       : TNmatrix;
  546.                    var Permute      : TNmatrix;
  547.                    var Error        : byte);
  548.  
  549. {---------------------------------------------------------}
  550. {- Input: Dimen, Coefficients                            -}
  551. {- Output: Decomp, Permute, Error                        -}
  552. {-                                                       -}
  553. {- This procedure decomposes the Coefficients matrix     -}
  554. {- into two triangular matrices, a lower and an upper    -}
  555. {- one.  The lower and upper matrices are combined       -}
  556. {- into one matrix, Decomp.  The permutation matrix,     -}
  557. {- Permute, records the effects of partial pivoting.     -}
  558. {---------------------------------------------------------}
  559.  
  560. var
  561.   Upper, Lower : TNmatrix;
  562.   Term, Index : integer;
  563.  
  564. procedure Initialize(Dimen   : integer;
  565.                  var Lower   : TNmatrix;
  566.                  var Upper   : TNmatrix;
  567.                  var Permute : TNmatrix);
  568.  
  569. {---------------------------------------------------}
  570. {- Output: Dimen, Lower, Upper, Permute            -}
  571. {-                                                 -}
  572. {- This procedure initializes the above variables. -}
  573. {- Lower and Upper are initialized to the zero     -}
  574. {- matrix and Diag is initialized to the identity  -}
  575. {- matrix.                                         -}
  576. {---------------------------------------------------}
  577.  
  578. var
  579.   Diag : integer;
  580.  
  581. begin
  582.   FillChar(Upper, SizeOf(Upper), 0);
  583.   FillChar(Lower, SizeOf(Lower), 0);
  584.   FillChar(Permute, SizeOf(Permute), 0);
  585.   for Diag := 1 to Dimen do
  586.     Permute[Diag, Diag] := 1;
  587. end; { procedure Permute }
  588.  
  589. begin
  590.   Initialize(Dimen, Lower, Upper, Permute);
  591.   { Perform partial pivoting on row 1 }
  592.   Pivot(Dimen, 1, Coefficients, Lower, Upper, Permute, Error);
  593.   if Error = 0 then
  594.   begin
  595.     Lower[1, 1] := 1;
  596.     Upper[1, 1] := Coefficients[1, 1];
  597.     for Term := 1 to Dimen do
  598.     begin
  599.       Lower[Term, 1] := Coefficients[Term, 1] / Upper[1, 1];
  600.       Upper[1, Term] := Coefficients[1, Term] / Lower[1, 1];
  601.     end;
  602.   end;
  603.   Term := 1;
  604.   while (Error = 0) and (Term < Dimen - 1) do
  605.   begin
  606.     Term := Succ(Term);
  607.     { Perform partial pivoting on row Term }
  608.     Pivot(Dimen, Term, Coefficients, Lower, Upper, Permute, Error);
  609.     Lower[Term, Term] := 1;
  610.     Upper[Term, Term] := Coefficients[Term, Term] -
  611.                          RowColumnMult(Term, Lower, Term, Upper);
  612.     if ABS(Upper[Term, Term]) < TNNearlyZero then
  613.       Error := 2   { No solutions }
  614.     else
  615.       for Index := Term + 1 to Dimen do
  616.       begin
  617.         Upper[Term, Index] := Coefficients[Term, Index] -
  618.                               RowColumnMult(Term, Lower, Index, Upper);
  619.         Lower[Index, Term] := (Coefficients[Index, Term] -
  620.                               RowColumnMult(Index, Lower,Term, Upper)) /
  621.                               Upper[Term, Term];
  622.       end
  623.   end; { while }
  624.   Lower[Dimen, Dimen] := 1;
  625.   Upper[Dimen, Dimen] := Coefficients[Dimen, Dimen] -
  626.                          RowColumnMult(Dimen, Lower, Dimen, Upper);
  627.   if ABS(Upper[Dimen, Dimen]) < TNNearlyZero then
  628.     Error := 2;
  629.   { Combine the upper and lower triangular matrices into one }
  630.   Decomp := Upper;
  631.  
  632.   for Term := 2 to Dimen do
  633.     for Index := 1 to Term - 1 do
  634.       Decomp[Term, Index] := Lower[Term, Index];
  635. end; { procedure LU_Decompose }
  636.  
  637. begin  { procedure Decompose }
  638.   TestInput(Dimen, Error);
  639.   if Error = 0 then
  640.     if Dimen = 1 then
  641.       begin
  642.         Decomp := Coefficients;
  643.         Permute[1, 1] := 1;
  644.       end
  645.     else
  646.       LU_Decompose(Dimen, Coefficients, Decomp, Permute, Error);
  647. end; { procedure Decompose }
  648.  
  649. procedure Solve_LU_Decomposition(Dimen     : integer;
  650.                              var Decomp    : TNmatrix;
  651.                                  Constants : TNvector;
  652.                              var Permute   : TNmatrix;
  653.                              var Solution  : TNvector;
  654.                              var Error     : byte);
  655.  
  656. {----------------------------------------------------------------------------}
  657. {-                                                                          -}
  658. {-                Input: Dimen, Decomp, Constants, Permute                  -}
  659. {-               Output: Solution, Error                                    -}
  660. {-                                                                          -}
  661. {-             Purpose : Calculate the solution of a linear set of          -}
  662. {-                       equations using an LU decomposed matrix, a         -}
  663. {-                       permutation matrix and backwards substitution.     -}
  664. {-                                                                          -}
  665. {-  User_defined Types : TNvector = array[1..TNArraySize] of real           -}
  666. {-                       TNmatrix = array[1..TNArraySize] of TNvector       -}
  667. {-                                                                          -}
  668. {-    Global Variables : Dimen     : integer;   Dimen of the square         -}
  669. {-                                              matrix                      -}
  670. {-                       Decomp    : TNmatrix;  Decomposition of            -}
  671. {-                                              the matrix                  -}
  672. {-                       Constants : TNvector;  Constants of each equation  -}
  673. {-                       Permute   : TNmatrix;  Permutation matrix from     -}
  674. {-                                              partial pivoting            -}
  675. {-                       Solution  : TNvector;  Unique solution to the      -}
  676. {-                                              set of equations            -}
  677. {-                       Error     : integer;   Flags if something goes     -}
  678. {-                                              wrong.                      -}
  679. {-                                                                          -}
  680. {-              Errors : 0: No errors;                                      -}
  681. {-                       1: Dimen < 1                                       -}
  682. {-                                                                          -}
  683. {----------------------------------------------------------------------------}
  684.  
  685. procedure Initial(Dimen    : integer;
  686.               var Solution : TNvector;
  687.               var Error    : byte);
  688.  
  689. {----------------------------------------------------}
  690. {- Input: Dimen                                     -}
  691. {- Output: Solution, Error                          -}
  692. {-                                                  -}
  693. {- This procedure initializes the Solution vector.  -}
  694. {- It also checks to see if the value of Dimen is   -}
  695. {- greater than 1.                                  -}
  696. {----------------------------------------------------}
  697.  
  698. begin
  699.   Error := 0;
  700.   FillChar(Solution, SizeOf(Solution), 0);
  701.   if Dimen < 1 then
  702.     Error := 1;
  703. end; { procedure Initial }
  704.  
  705. procedure FindSolution(Dimen     : integer;
  706.                    var Decomp    : TNmatrix;
  707.                    var Constants : TNvector;
  708.                    var Solution  : TNvector);
  709.  
  710. {---------------------------------------------------------------}
  711. {- Input: Dimen, Decomp, Constants                             -}
  712. {- Output: Solution                                            -}
  713. {-                                                             -}
  714. {- The Decom matrix contains a lower and upper triangular      -}
  715. {- matrix.                                                     -}
  716. {- This procedure performs a two step backwards substitution   -}
  717. {- to compute the solution to the system of equations.  First, -}
  718. {- backwards substitution is applied to the lower triangular   -}
  719. {- matrix and Constants vector yielding PartialSolution.  Then -}
  720. {- backwards substitution is applied to the Upper matrix and   -}
  721. {- the PartialSolution vector yielding Solution.               -}
  722. {---------------------------------------------------------------}
  723.  
  724. var
  725.   PartialSolution : TNvector;
  726.   Term, Index : integer;
  727.   Sum : Float;
  728.  
  729. begin { procedure FindSolution }
  730.   { First solve the lower triangular matrix }
  731.   PartialSolution[1] := Constants[1];
  732.   for Term := 2 to Dimen do
  733.   begin
  734.     Sum := 0;
  735.     for Index := 1 to Term - 1 do
  736.       if Term = Index then
  737.         Sum := Sum + PartialSolution[Index]
  738.       else
  739.         Sum := Sum + Decomp[Term, Index] * PartialSolution[Index];
  740.     PartialSolution[Term] := Constants[Term] - Sum;
  741.   end;
  742.   { Then solve the upper triangular matrix }
  743.   Solution[Dimen] := PartialSolution[Dimen]/Decomp[Dimen, Dimen];
  744.   for Term := Dimen - 1 downto 1 do
  745.   begin
  746.     Sum := 0;
  747.     for Index := Term + 1 to Dimen do
  748.       Sum := Sum + Decomp[Term, Index] * Solution[Index];
  749.     Solution[Term] := (PartialSolution[Term] - Sum) / Decomp[Term, Term];
  750.   end;
  751. end; { procedure FindSolution }
  752.  
  753. procedure PermuteConstants(Dimen     : integer;
  754.                        var Permute   : TNmatrix;
  755.                        var Constants : TNvector);
  756.  
  757. var
  758.   Row, Column : integer;
  759.   Entry : Float;
  760.   TempConstants : TNvector;
  761.  
  762. begin
  763.   for Row := 1 to Dimen do
  764.   begin
  765.     Entry := 0;
  766.     for Column := 1 to Dimen do
  767.       Entry := Entry + Permute[Row, Column] * Constants[Column];
  768.     TempConstants[Row] := Entry;
  769.   end;  {FOR Row}
  770.   Constants := TempConstants;
  771. end; { procedure PermuteConstants }
  772.  
  773. begin { procedure Solve_LU_Decompostion }
  774.   Initial(Dimen, Solution, Error);
  775.   if Error = 0 then
  776.     PermuteConstants(Dimen, Permute, Constants);
  777.   FindSolution(Dimen, Decomp, Constants, Solution);
  778. end; { procedure Solve_LU_Decomposition }
  779.  
  780. {----------------------------------------------------------------------------}
  781.  
  782. begin { procedure GetNewApprox }
  783.   if Iter = 1 then
  784.   begin
  785.     Decompose(Dimen, Mat, Decomp, Permute, Error);
  786.     if Error = 2 then { Returned from Decompose - matrix is singular }
  787.       Error := 5;     { eigenvalue/eigenvector can't   }
  788.                       { be calculated with this method }
  789.   end;
  790.   if Error = 0 then
  791.     Solve_LU_Decomposition(Dimen, Decomp, OldApprox, Permute, NewApprox, Error);
  792. end; { procedure GetNewApprox }
  793.  
  794. procedure TestForConvergence(Dimen     : integer;
  795.                          var OldApprox : TNvector;
  796.                          var NewApprox : TNvector;
  797.                              Tolerance : Float;
  798.                          var Found     : boolean);
  799.  
  800. {-----------------------------------------------------------------}
  801. {- Input: Dimen, OldApprox, NewApprox, Tolerance,                -}
  802. {- Output: Found                                                 -}
  803. {-                                                               -}
  804. {- This procedure determines if the iterations have converged    -}
  805. {- on a solution.  If the absolute difference in each element of -}
  806. {- the eigenvector between the last two iterations (i.e. between -}
  807. {- OldApprox and NewApprox) is less than Tolerance, then         -}
  808. {- convergence has occurred and Found = true.  Otherwise,        -}
  809. {- Found = false.                                                -}
  810. {-----------------------------------------------------------------}
  811.  
  812. var
  813.   Index : integer;
  814.   Difference : Float;
  815.  
  816. begin
  817.   Index := 0;
  818.   Found := true;
  819.   while (Found = true) and (Index < Dimen) do
  820.   begin
  821.     Index := Succ(Index);
  822.     if (ABS(OldApprox[Index]) > TNNearlyZero) and
  823.        (ABS(NewApprox[Index]) > TNNearlyZero) then
  824.       begin
  825.         Difference := ABS(OldApprox[Index] - NewApprox[Index]);
  826.         if Difference > Tolerance then
  827.           Found := false;
  828.       end;
  829.   end; { while }
  830. end; { procedure TestForConvergence }
  831.  
  832. begin  { procedure InversePower }
  833.   TestDataAndInitialize(Dimen, Mat, GuessVector, Tolerance, MaxIter,
  834.                         Eigenvalue, Eigenvector, Found, Iter, OldApprox,
  835.                         ClosestVal, ApproxEigenval, Error);
  836.  
  837.   if (Error = 0) and (Found = false) then
  838.   begin
  839.     FindLargest(Dimen, OldApprox, ApproxEigenval);
  840.     Div_Vec_Const(Dimen, OldApprox, ApproxEigenval);
  841.     while (Iter < MaxIter) and not Found and (Error = 0) do
  842.     begin
  843.       Iter := Succ(Iter);
  844.       GetNewApprox(Dimen, Mat, OldApprox, NewApprox, Iter, Error);
  845.       if Error = 0 then
  846.       begin
  847.         FindLargest(Dimen, NewApprox, ApproxEigenval);
  848.         Div_Vec_Const(Dimen, NewApprox, ApproxEigenval);
  849.         TestForConvergence(Dimen, OldApprox, NewApprox, Tolerance, Found);
  850.         OldApprox := NewApprox;
  851.       end;
  852.     end; { while }
  853.     if Error = 5 then { Eigenvalue/vector not calculated }
  854.       Eigenvalue := ClosestVal
  855.     else
  856.       begin
  857.         Eigenvector := OldApprox;
  858.         Eigenvalue := 1 / ApproxEigenval + ClosestVal;
  859.       end;
  860.     if Iter >= MaxIter then
  861.       Error := 4;
  862.   end;
  863. end; { procedure InversePower }
  864.  
  865.