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

  1. {----------------------------------------------------------------------------}
  2. {-                                                                          -}
  3. {-     Turbo Pascal Numerical Methods Toolbox                               -}
  4. {-     Copyright (c) 1986, 87 by Borland International, Inc.                -}
  5. {-                                                                          -}
  6. {----------------------------------------------------------------------------}
  7.  
  8. procedure Determinant{(Dimen : integer;
  9.                       Data   : TNmatrix;
  10.                   var Det    : Float;
  11.                   var Error  : byte)};
  12.  
  13. procedure Initial(Dimen : integer;
  14.               var Data  : TNmatrix;
  15.               var Det   : Float;
  16.               var Error : byte);
  17.  
  18. {---------------------------------------------------------}
  19. {- This procedure tests for errors in the value of Dimen -}
  20. {---------------------------------------------------------}
  21.  
  22. begin
  23.   Error := 0;
  24.   if Dimen < 1 then
  25.     Error := 1
  26.   else
  27.     if Dimen = 1 then
  28.       Det := Data[1, 1];
  29. end; { procedure Initial }
  30.  
  31. procedure EROswitch(var Row1 : TNvector;
  32.                     var Row2 : TNvector);
  33.  
  34. {-------------------------------------------------}
  35. {- Elementary row operation - switching two rows -}
  36. {-------------------------------------------------}
  37.  
  38. var
  39.   DummyRow : TNvector;
  40.  
  41. begin
  42.   DummyRow := Row1;
  43.   Row1 := Row2;
  44.   Row2 := DummyRow;
  45. end; { procedure EROswitch }
  46.  
  47. procedure EROmultAdd(Multiplier   : Float;
  48.                      Dimen        : integer;
  49.                  var ReferenceRow : TNvector;
  50.                  var ChangingRow  : TNvector);
  51.  
  52. {-----------------------------------------------------------}
  53. {- Row operation - adding a multiple of one row to another -}
  54. {-----------------------------------------------------------}
  55.  
  56. var
  57.   Term : integer;
  58.  
  59. begin
  60.   for Term := 1 to Dimen do
  61.     ChangingRow[Term] := ChangingRow[Term] + Multiplier * ReferenceRow[Term];
  62. end; { procedure EROmultAdd }
  63.  
  64. function Deter(Dimen : integer;
  65.            var Data  : TNmatrix) : Float;
  66.  
  67. {-------------------------------------------------------}
  68. {- Input: Dimen, Data                                  -}
  69. {- Output: Deter                                       -}
  70. {-                                                     -}
  71. {- Function returns the determinant of the Data matrix -}
  72. {-------------------------------------------------------}
  73.  
  74. var
  75.   PartialDeter, Multiplier : Float;
  76.   Row, ReferenceRow : integer;
  77.   DetEqualsZero : boolean;
  78.  
  79. procedure Pivot(Dimen         : integer;
  80.                 ReferenceRow  : integer;
  81.             var Data          : TNmatrix;
  82.             var PartialDeter  : Float;
  83.             var DetEqualsZero : boolean);
  84.  
  85. {------------------------------------------------------------}
  86. {- Input: Dimen, ReferenceRow, Data, PartialDeter           -}
  87. {- Output: Data, PartialDeter, DetEqualsZero                -}
  88. {-                                                          -}
  89. {- This procedure searches the ReferenceRow column of the   -}
  90. {- matrix Data for the first non-zero element below the     -}
  91. {- diagonal. If it finds one, then the procedure switches   -}
  92. {- rows so that the non-zero element is on the diagonal.    -}
  93. {- Switching rows changes the determinant by a factor of    -}
  94. {- -1; this change is returned in PartialDeter.             -}
  95. {- If it doesn't find one, the matrix is singular and the   -}
  96. {- Determinant is zero (DetEqualsZero = true is returned).  -}
  97. {------------------------------------------------------------}
  98.  
  99. var
  100.   NewRow : integer;
  101.  
  102. begin
  103.   DetEqualsZero := true;
  104.   NewRow := ReferenceRow;
  105.   while DetEqualsZero and (NewRow < Dimen) do  { Try to find a row  }
  106.                                                { with a non-zero    }
  107.                                                { element in this    }
  108.                                                { column             }
  109.   begin
  110.     NewRow := Succ(NewRow);
  111.     if ABS(Data[NewRow, ReferenceRow]) > TNNearlyZero then
  112.     begin
  113.       EROswitch(Data[NewRow], Data[ReferenceRow]);
  114.       { Switch these two rows }
  115.       DetEqualsZero := false;
  116.       PartialDeter := -PartialDeter;  { Switching rows changes }
  117.                                       { the determinant by a   }
  118.                                       { factor of -1           }
  119.     end;
  120.   end;
  121. end; { procedure Pivot }
  122.  
  123. begin  { function Deter }
  124.   DetEqualsZero := false;
  125.   PartialDeter := 1;
  126.   ReferenceRow := 0;
  127.   { Make the matrix upper triangular }
  128.   while not(DetEqualsZero) and (ReferenceRow < Dimen - 1) do
  129.   begin
  130.     ReferenceRow := Succ(ReferenceRow);
  131.     { If diagonal element is zero then switch rows }
  132.     if ABS(Data[ReferenceRow, ReferenceRow]) < TNNearlyZero then
  133.       Pivot(Dimen, ReferenceRow, Data, PartialDeter, DetEqualsZero);
  134.     if not(DetEqualsZero) then
  135.       for Row := ReferenceRow + 1 to Dimen do
  136.         { Make the ReferenceRow element of this row zero }
  137.         if ABS(Data[Row, ReferenceRow]) > TNNearlyZero then
  138.         begin
  139.           Multiplier := -Data[Row, ReferenceRow] /
  140.                         Data[ReferenceRow, ReferenceRow];
  141.           EROmultAdd(Multiplier, Dimen, Data[ReferenceRow], Data[Row]);
  142.         end;
  143.     { Multiply the diagonal Term into PartialDeter }
  144.     PartialDeter := PartialDeter * Data[ReferenceRow, ReferenceRow];
  145.   end;
  146.   if DetEqualsZero then
  147.     Deter := 0
  148.   else
  149.     Deter := PartialDeter * Data[Dimen, Dimen];
  150. end; { function Deter }
  151.  
  152. begin { procedure Determinant }
  153.   Initial(Dimen, Data, Det, Error);
  154.   if Dimen > 1 then
  155.     Det := Deter(Dimen, Data);
  156. end; { procedure Determinant }
  157.  
  158. procedure Inverse{(Dimen : integer;
  159.                   Data   : TNmatrix;
  160.               var Inv    : TNmatrix;
  161.               var Error  : byte)};
  162.  
  163.  
  164. procedure Initial(Dimen : integer;
  165.               var Data  : TNmatrix;
  166.               var Inv   : TNmatrix;
  167.               var Error : byte);
  168.  
  169. {--------------------------------------------------------}
  170. {- Input: Dimen, Data                                   -}
  171. {- Output: Inv, Error                                   -}
  172. {-                                                      -}
  173. {- This procedure test for errors in the value of Dimen -}
  174. {--------------------------------------------------------}
  175.  
  176. var
  177.   Row : integer;
  178.  
  179. begin
  180.   Error := 0;
  181.   if Dimen < 1 then
  182.     Error := 1
  183.   else
  184.     begin
  185.       { First make the inverse-to-be the identity matrix }
  186.       FillChar(Inv, SizeOf(Inv), 0);
  187.       for Row := 1 to Dimen do
  188.         Inv[Row, Row] := 1;
  189.       if Dimen = 1 then
  190.         if ABS(Data[1, 1]) < TNNearlyZero then
  191.           Error := 2   { Singular matrix }
  192.         else
  193.           Inv[1, 1] := 1 / Data[1, 1];
  194.     end;
  195. end; { procedure Initial }
  196.  
  197. procedure EROdiv(Divisor : Float;
  198.                  Dimen   : integer;
  199.              var Row     : TNvector);
  200.  
  201. {-----------------------------------------------------}
  202. {- Input: Divisor, Dimen, Row                        -}
  203. {-                                                   -}
  204. {- elementary row operation - dividing by a constant -}
  205. {-----------------------------------------------------}
  206.  
  207. var
  208.   Term : integer;
  209.  
  210. begin
  211.   for Term := 1 to Dimen do
  212.     Row[Term] := Row[Term] / Divisor;
  213. end; { procedure EROdiv }
  214.  
  215. procedure EROswitch(var Row1 : TNvector;
  216.                     var Row2 : TNvector);
  217.  
  218. {-------------------------------------------------}
  219. {- Input: Row1, Row2                             -}
  220. {- Output: Row1, Row2                            -}
  221. {-                                               -}
  222. {- Elementary row operation - switching two rows -}
  223. {-------------------------------------------------}
  224.  
  225. var
  226.   DummyRow : TNvector;
  227.  
  228. begin
  229.   DummyRow := Row1;
  230.   Row1 := Row2;
  231.   Row2 := DummyRow;
  232. end; { procedure EROswitch }
  233.  
  234. procedure EROmultAdd(Multiplier   : Float;
  235.                      Dimen        : integer;
  236.                  var ReferenceRow : TNvector;
  237.                  var ChangingRow  : TNvector);
  238.  
  239. {-----------------------------------------------------------}
  240. {- Input: Multiplier, Dimen, ReferenceRow, ChangingRow     -}
  241. {- Output: ChangingRow                                     -}
  242. {-                                                         -}
  243. {- Row operation - adding a multiple of one row to another -}
  244. {-----------------------------------------------------------}
  245.  
  246. var
  247.   Term : integer;
  248.  
  249. begin
  250.   for Term := 1 to Dimen do
  251.     ChangingRow[Term] := ChangingRow[Term] + Multiplier*ReferenceRow[Term];
  252. end; { procedure EROmultAdd }
  253.  
  254.  
  255. procedure Inver(Dimen : integer;
  256.             var Data  : TNmatrix;
  257.             var Inv   : TNmatrix;
  258.             var Error : byte);
  259.  
  260. {----------------------------------------------------------}
  261. {- Input: Dimen, Data                                     -}
  262. {- Output: Inv, Error                                     -}
  263. {-                                                        -}
  264. {- This procedure computes the inverse of the matrix Data -}
  265. {- and stores it in the matrix Inv.  If the matrix Data   -}
  266. {- is singular, then Error = 2 is returned.               -}
  267. {----------------------------------------------------------}
  268.  
  269. var
  270.   Divisor, Multiplier : Float;
  271.   Row, ReferenceRow : integer;
  272.  
  273. procedure Pivot(Dimen        : integer;
  274.                 ReferenceRow : integer;
  275.             var Data         : TNmatrix;
  276.             var Inv          : TNmatrix;
  277.             var Error        : byte);
  278.  
  279. {-------------------------------------------------------------}
  280. {- Input: Dimen, ReferenceRow, Data, Inv                     -}
  281. {- Output: Data, Inv, Error                                  -}
  282. {-                                                           -}
  283. {- This procedure searches the ReferenceRow column of        -}
  284. {- the Data matrix for the first non-zero element below      -}
  285. {- the diagonal. If it finds one, then the procedure         -}
  286. {- switches rows so that the non-zero element is on the      -}
  287. {- diagonal. This same operation is applied to the Inv       -}
  288. {- matrix. If no non-zero element exists in a column, the    -}
  289. {- matrix is singular and no inverse exists.                 -}
  290. {-------------------------------------------------------------}
  291.  
  292. var
  293.   NewRow : integer;
  294.  
  295. begin
  296.   Error := 2;  { No inverse exists }
  297.   NewRow := ReferenceRow;
  298.   while (Error > 0) and (NewRow < Dimen) do
  299.   { Try to find a       }
  300.   { row with a non-zero }
  301.   { diagonal element    }
  302.   begin
  303.     NewRow := Succ(NewRow);
  304.     if ABS(Data[NewRow, ReferenceRow]) > TNNearlyZero then
  305.     begin
  306.       EROswitch(Data[NewRow], Data[ReferenceRow]);
  307.       { Switch these two rows }
  308.       EROswitch(Inv[NewRow], Inv[ReferenceRow]);
  309.       Error := 0;
  310.     end;
  311.   end; { while }
  312. end; { procedure Pivot }
  313.  
  314. begin { procedure Inver }
  315.   { Make Data matrix upper triangular }
  316.   ReferenceRow := 0;
  317.   while (Error = 0) and (ReferenceRow < Dimen) do
  318.   begin
  319.     ReferenceRow := Succ(ReferenceRow);
  320.     { Check to see if the diagonal element is zero }
  321.     if ABS(Data[ReferenceRow, ReferenceRow]) < TNNearlyZero then
  322.       Pivot(Dimen, ReferenceRow, Data, Inv, Error);
  323.     if Error = 0 then
  324.     begin
  325.       Divisor := Data[ReferenceRow, ReferenceRow];
  326.       EROdiv(Divisor, Dimen, Data[ReferenceRow]);
  327.       EROdiv(Divisor, Dimen, Inv[ReferenceRow]);
  328.       for Row := 1 to Dimen do
  329.         { Make the ReferenceRow element of this row zero }
  330.         if (Row <> ReferenceRow) and
  331.            (ABS(Data[Row, ReferenceRow]) > TNNearlyZero) then
  332.         begin
  333.           Multiplier := -Data[Row, ReferenceRow] /
  334.                          Data[ReferenceRow, ReferenceRow];
  335.           EROmultAdd(Multiplier, Dimen, Data[ReferenceRow], Data[Row]);
  336.           EROmultAdd(Multiplier, Dimen, Inv[ReferenceRow], Inv[Row]);
  337.         end;
  338.     end;
  339.   end;
  340. end; { procedure Inver }
  341.  
  342. begin { procedure Inverse }
  343.   Initial(Dimen, Data, Inv, Error);
  344.   if Dimen > 1 then
  345.     Inver(Dimen, Data, Inv, Error);
  346. end; { procedure Inverse }
  347.  
  348. procedure Gaussian_Elimination{(Dimen       : integer;
  349.                                Coefficients : TNmatrix;
  350.                                Constants    : TNvector;
  351.                            var Solution     : TNvector;
  352.                            var Error        : byte)};
  353.  
  354. procedure Initial(Dimen        : integer;
  355.               var Coefficients : TNmatrix;
  356.               var Constants    : TNvector;
  357.               var Solution     : TNvector;
  358.               var Error        : byte);
  359.  
  360. {----------------------------------------------------------}
  361. {- Input: Dimen, Coefficients, Constants                  -}
  362. {- Output: Solution, Error                                -}
  363. {-                                                        -}
  364. {- This procedure test for errors in the value of Dimen.  -}
  365. {- This procedure also finds the solution for the         -}
  366. {- trivial case Dimen = 1.                                -}
  367. {----------------------------------------------------------}
  368.  
  369. begin
  370.   Error := 0;
  371.   if Dimen < 1 then
  372.     Error := 1
  373.   else
  374.     if Dimen = 1 then
  375.       if ABS(Coefficients[1, 1]) < TNNearlyZero then
  376.         Error := 2
  377.       else
  378.         Solution[1] := Constants[1] / Coefficients[1, 1];
  379. end; { procedure Initial }
  380.  
  381. procedure EROswitch(var Row1 : TNvector;
  382.                     var Row2 : TNvector);
  383.  
  384. {-------------------------------------------------}
  385. {- Input: Row1, Row2                             -}
  386. {- Output: Row1, Row2                            -}
  387. {-                                               -}
  388. {- elementary row operation - switching two rows -}
  389. {-------------------------------------------------}
  390.  
  391. var
  392.   DummyRow : TNvector;
  393.  
  394. begin
  395.   DummyRow := Row1;
  396.   Row1 := Row2;
  397.   Row2 := DummyRow;
  398. end; { procedure EROswitch }
  399.  
  400. procedure EROmultAdd(Multiplier   : Float;
  401.                      Dimen        : integer;
  402.                  var ReferenceRow : TNvector;
  403.                  var ChangingRow  : TNvector);
  404.  
  405. {-----------------------------------------------------------}
  406. {- Input: Multiplier, Dimen, ReferenceRow, ChangingRow     -}
  407. {- Output: ChangingRow                                     -}
  408. {-                                                         -}
  409. {- row operation - adding a multiple of one row to another -}
  410. {-----------------------------------------------------------}
  411.  
  412. var
  413.   Term : integer;
  414.  
  415. begin
  416.   for Term := 1 to Dimen do
  417.     ChangingRow[Term] := ChangingRow[Term] + Multiplier*ReferenceRow[Term];
  418. end; { procedure EROmultAdd }
  419.  
  420. procedure UpperTriangular(Dimen        : integer;
  421.                       var Coefficients : TNmatrix;
  422.                       var Constants    : TNvector;
  423.                       var Error        : byte);
  424.  
  425. {-----------------------------------------------------------------}
  426. {- Input: Dimen, Coefficients, Constants                         -}
  427. {- Output: Coefficients, Constants, Error                        -}
  428. {-                                                               -}
  429. {- This procedure makes the coefficient matrix upper triangular. -}
  430. {- The operations which perform this are also performed on the   -}
  431. {- Constants vector.                                             -}
  432. {- If one of the main diagonal elements of the upper triangular  -}
  433. {- matrix is zero, then the Coefficients matrix is singular and  -}
  434. {- no solution exists (Error = 2 is returned).                   -}
  435. {-----------------------------------------------------------------}
  436.  
  437. var
  438.   Multiplier        : Float;
  439.   Row, ReferenceRow : integer;
  440.  
  441. procedure Pivot(Dimen        : integer;
  442.                 ReferenceRow : integer;
  443.             var Coefficients : TNmatrix;
  444.             var Constants    : TNvector;
  445.             var Error        : byte);
  446.  
  447. {--------------------------------------------------------------}
  448. {- Input: Dimen, ReferenceRow, Coefficients                   -}
  449. {- Output: Coefficients, Constants, Error                     -}
  450. {-                                                            -}
  451. {- This procedure searches the ReferenceRow column of the     -}
  452. {- Coefficients matrix for the first non-zero element below   -}
  453. {- the diagonal. If it finds one, then the procedure switches -}
  454. {- rows so that the non-zero element is on the diagonal.      -}
  455. {- It also switches the corresponding elements in the         -}
  456. {- Constants vector. If it doesn't find one, the matrix is    -}
  457. {- singular and no solution exists (Error = 2 is returned).   -}
  458. {--------------------------------------------------------------}
  459.  
  460. var
  461.   NewRow : integer;
  462.   Dummy : Float;
  463.  
  464. begin
  465.   Error := 2;          { No solution exists }
  466.   NewRow := ReferenceRow;
  467.   while (Error > 0) and (NewRow < Dimen) do    { Try to find a       }
  468.                                                { row with a non-zero }
  469.                                                { diagonal element    }
  470.   begin
  471.     NewRow := Succ(NewRow);
  472.     if ABS(Coefficients[NewRow, ReferenceRow]) > TNNearlyZero then
  473.     begin
  474.       EROswitch(Coefficients[NewRow], Coefficients[ReferenceRow]);
  475.       { Switch these two rows }
  476.       Dummy := Constants[NewRow];
  477.       Constants[NewRow] := Constants[ReferenceRow];
  478.       Constants[ReferenceRow] := Dummy;
  479.       Error := 0;    { Solution may exist }
  480.     end;
  481.   end;
  482. end; { procedure Pivot }
  483.  
  484. begin { procedure UpperTriangular }
  485.   ReferenceRow := 0;
  486.   while (Error = 0) and (ReferenceRow < Dimen - 1) do
  487.   begin
  488.     ReferenceRow := Succ(ReferenceRow);
  489.     { Check to see if the main diagonal element is zero }
  490.     if ABS(Coefficients[ReferenceRow, ReferenceRow]) < TNNearlyZero then
  491.       Pivot(Dimen, ReferenceRow, Coefficients, Constants, Error);
  492.     if Error = 0 then
  493.       for Row := ReferenceRow + 1 to Dimen do
  494.         { Make the ReferenceRow element of this row zero }
  495.         if ABS(Coefficients[Row, ReferenceRow]) > TNNearlyZero then
  496.         begin
  497.           Multiplier := -Coefficients[Row, ReferenceRow] /
  498.                          Coefficients[ReferenceRow,ReferenceRow];
  499.           EROmultAdd(Multiplier, Dimen,
  500.                      Coefficients[ReferenceRow], Coefficients[Row]);
  501.           Constants[Row] := Constants[Row] +
  502.                             Multiplier * Constants[ReferenceRow];
  503.         end;
  504.   end; { while }
  505.   if ABS(Coefficients[Dimen, Dimen]) < TNNearlyZero then
  506.     Error := 2;    { No solution }
  507. end; { procedure UpperTriangular }
  508.  
  509. procedure BackwardsSub(Dimen        : integer;
  510.                    var Coefficients : TNmatrix;
  511.                    var Constants    : TNvector;
  512.                    var Solution     : TNvector);
  513.  
  514. {----------------------------------------------------------------}
  515. {- Input: Dimen, Coefficients, Constants                        -}
  516. {- Output: Solution                                             -}
  517. {-                                                              -}
  518. {- This procedure applies backwards substitution to the upper   -}
  519. {- triangular Coefficients matrix and Constants vector. The     -}
  520. {- resulting vector is the solution to the set of equations and -}
  521. {- is returned in the vector Solution.                          -}
  522. {----------------------------------------------------------------}
  523.  
  524. var
  525.   Term, Row : integer;
  526.   Sum : Float;
  527.  
  528. begin
  529.   Term := Dimen;
  530.   while Term >= 1 do
  531.   begin
  532.     Sum := 0;
  533.     for Row := Term + 1 to Dimen do
  534.       Sum := Sum + Coefficients[Term, Row] * Solution[Row];
  535.     Solution[Term] := (Constants[Term] - Sum) / Coefficients[Term, Term];
  536.     Term := Pred(Term);
  537.   end;
  538. end; { procedure BackwardsSub }
  539.  
  540. begin { procedure Gaussian_Elimination }
  541.   Initial(Dimen, Coefficients, Constants, Solution, Error);
  542.   if Dimen > 1 then
  543.   begin
  544.     UpperTriangular(Dimen, Coefficients, Constants, Error);
  545.     if Error = 0 then
  546.       BackwardsSub(Dimen, Coefficients, Constants, Solution);
  547.   end;
  548. end; { procedure Gaussian_Elimination }
  549.  
  550. procedure Partial_Pivoting{(Dimen       : integer;
  551.                            Coefficients : TNmatrix;
  552.                            Constants    : TNvector;
  553.                        var Solution     : TNvector;
  554.                        var Error        : byte)};
  555.  
  556.  
  557. procedure Initial(Dimen        : integer;
  558.               var Coefficients : TNmatrix;
  559.               var Constants    : TNvector;
  560.               var Solution     : TNvector;
  561.               var Error        : byte);
  562.  
  563. {----------------------------------------------------------}
  564. {- Input: Dimen, Coefficients, Constants                  -}
  565. {- Output: Solution, Error                                -}
  566. {-                                                        -}
  567. {- This procedure test for errors in the value of Dimen.  -}
  568. {- This procedure also finds the solution for the         -}
  569. {- trivial case Dimen = 1.                                -}
  570. {----------------------------------------------------------}
  571.  
  572. begin
  573.   Error := 0;
  574.   if Dimen < 1 then
  575.     Error := 1
  576.   else
  577.     if Dimen = 1 then
  578.       if ABS(Coefficients[1, 1]) < TNNearlyZero then
  579.         Error := 2
  580.       else
  581.         Solution[1] := Constants[1] / Coefficients[1, 1];
  582. end; { procedure Initial }
  583.  
  584. procedure EROswitch(var Row1 : TNvector;
  585.                     var Row2 : TNvector);
  586.  
  587. {-------------------------------------------------}
  588. {- Input: Row1, Row2                             -}
  589. {- Output: Row1, Row2                            -}
  590. {-                                               -}
  591. {- elementary row operation - switching two rows -}
  592. {-------------------------------------------------}
  593.  
  594. var
  595.   DummyRow : TNvector;
  596.  
  597. begin
  598.   DummyRow := Row1;
  599.   Row1 := Row2;
  600.   Row2 := DummyRow;
  601. end; { procedure EROswitch }
  602.  
  603. procedure EROmultAdd(Multiplier   : Float;
  604.                      Dimen        : integer;
  605.                  var ReferenceRow : TNvector;
  606.                  var ChangingRow  : TNvector);
  607.  
  608. {-----------------------------------------------------------}
  609. {- Input: Multiplier, Dimen, ReferenceRow, ChangingRow     -}
  610. {- Output: ChangingRow                                     -}
  611. {-                                                         -}
  612. {- Row operation - adding a multiple of one row to another -}
  613. {-----------------------------------------------------------}
  614.  
  615. var
  616.   Term : integer;
  617.  
  618. begin
  619.   for Term := 1 to Dimen do
  620.     ChangingRow[Term] := ChangingRow[Term] + Multiplier*ReferenceRow[Term];
  621. end; { procedure EROmultAdd }
  622.  
  623. procedure UpperTriangular(Dimen        : integer;
  624.                       var Coefficients : TNmatrix;
  625.                       var Constants    : TNvector;
  626.                       var Error        : byte);
  627.  
  628. {-----------------------------------------------------------------}
  629. {- Input: Dimen, Coefficients, Constants                         -}
  630. {- Output: Coefficients, Constants, Error                        -}
  631. {-                                                               -}
  632. {- This procedure makes the coefficient matrix upper triangular. -}
  633. {- The operations which perform this are also performed on the   -}
  634. {- Constants vector.                                             -}
  635. {- If one of the main diagonal elements of the upper triangular  -}
  636. {- matrix is zero, then the Coefficients matrix is singular and  -}
  637. {- no solution exists (Error = 2 is returned).                   -}
  638. {-----------------------------------------------------------------}
  639.  
  640. var
  641.   Multiplier : Float;
  642.   Row, ReferenceRow : integer;
  643.  
  644. procedure Pivot(Dimen        : integer;
  645.                 ReferenceRow : integer;
  646.             var Coefficients : TNmatrix;
  647.             var Constants    : TNvector;
  648.             var Error        : byte);
  649.  
  650. {----------------------------------------------------------------}
  651. {- Input: Dimen, ReferenceRow, Coefficients                     -}
  652. {- Output: Coefficients, Constants, Error                       -}
  653. {-                                                              -}
  654. {- This procedure searches the ReferenceRow column of the       -}
  655. {- Coefficients matrix for the largest non-zero element below   -}
  656. {- the diagonal. If it finds one, then the procedure switches   -}
  657. {- rows so that the largest non-zero element is on the          -}
  658. {- diagonal. It also switches the corresponding elements in     -}
  659. {- the Constants vector. If it doesn't find a non-zero element, -}
  660. {- the matrix is singular and no solution exists                -}
  661. {- (Error = 2 is returned).                                     -}
  662. {----------------------------------------------------------------}
  663.  
  664. var
  665.   PivotRow, Row : integer;
  666.   Dummy : Float;
  667.  
  668. begin
  669.   { First, find the row with the largest element }
  670.   PivotRow := ReferenceRow;
  671.   for Row := ReferenceRow + 1 to Dimen do
  672.     if ABS(Coefficients[Row, ReferenceRow]) >
  673.        ABS(Coefficients[PivotRow, ReferenceRow]) then
  674.       PivotRow := Row;
  675.   if PivotRow <> ReferenceRow then
  676.     { Second, switch these two rows }
  677.     begin
  678.       EROswitch(Coefficients[PivotRow], Coefficients[ReferenceRow]);
  679.       Dummy := Constants[PivotRow];
  680.       Constants[PivotRow] := Constants[ReferenceRow];
  681.       Constants[ReferenceRow] := Dummy;
  682.     end
  683.   else { If the diagonal element is zero, no solution exists }
  684.     if ABS(Coefficients[ReferenceRow, ReferenceRow]) < TNNearlyZero then
  685.       Error := 2;     { No solution }
  686. end; { procedure Pivot }
  687.  
  688. begin { procedure UpperTriangular }
  689.   { Make Coefficients matrix upper triangular }
  690.   ReferenceRow := 0;
  691.   while (Error = 0) and (ReferenceRow < Dimen - 1) do
  692.   begin
  693.     ReferenceRow := Succ(ReferenceRow);
  694.     { Find row with largest element in this column }
  695.     { and switch this row with the ReferenceRow    }
  696.     Pivot(Dimen, ReferenceRow, Coefficients, Constants, Error);
  697.     if Error = 0 then
  698.       for Row := ReferenceRow + 1 to Dimen do
  699.         { Make the ReferenceRow element of these rows zero }
  700.         if ABS(Coefficients[Row, ReferenceRow]) > TNNearlyZero then
  701.         begin
  702.           Multiplier := -Coefficients[Row, ReferenceRow] /
  703.                          Coefficients[ReferenceRow,ReferenceRow];
  704.           EROmultAdd(Multiplier, Dimen,
  705.                      Coefficients[ReferenceRow], Coefficients[Row]);
  706.           Constants[Row] := Constants[Row] +
  707.                             Multiplier * Constants[ReferenceRow];
  708.         end;
  709.   end;
  710.   if ABS(Coefficients[Dimen, Dimen]) < TNNearlyZero then
  711.     Error := 2;    { No solution }
  712. end; { procedure UpperTriangular }
  713.  
  714. procedure BackwardsSub(Dimen        : integer;
  715.                    var Coefficients : TNmatrix;
  716.                    var Constants    : TNvector;
  717.                    var Solution     : TNvector);
  718.  
  719. {----------------------------------------------------------------}
  720. {- Input: Dimen, Coefficients, Constants                        -}
  721. {- Output: Solution                                             -}
  722. {-                                                              -}
  723. {- This procedure applies backwards substitution to the upper   -}
  724. {- triangular Coefficients matrix and Constants vector. The     -}
  725. {- resulting vector is the solution to the set of equations and -}
  726. {- is stored in the vector Solution.                            -}
  727. {----------------------------------------------------------------}
  728.  
  729. var
  730.   Term, Row : integer;
  731.   Sum : Float;
  732.  
  733. begin
  734.   Term := Dimen;
  735.   while Term >= 1 do
  736.   begin
  737.     Sum := 0;
  738.     for Row := Term + 1 to Dimen do
  739.       Sum := Sum + Coefficients[Term, Row] * Solution[Row];
  740.     Solution[Term] := (Constants[Term] - Sum) / Coefficients[Term, Term];
  741.     Term := Pred(Term);
  742.   end;
  743. end; { procedure BackwardsSub }
  744.  
  745. begin  { procedure Partial_Pivoting }
  746.   Initial(Dimen, Coefficients, Constants, Solution, Error);
  747.   if Dimen > 1 then
  748.   begin
  749.     UpperTriangular(Dimen, Coefficients, Constants, Error);
  750.     if Error = 0 then
  751.       BackwardsSub(Dimen, Coefficients, Constants, Solution);
  752.   end;
  753. end; { procedure Partial_Pivoting }
  754.  
  755. procedure LU_Decompose{(Dimen       : integer;
  756.                        Coefficients : TNmatrix;
  757.                    var Decomp       : TNmatrix;
  758.                    var Permute      : TNmatrix;
  759.                    var Error        : byte)};
  760.  
  761.  
  762. procedure TestInput(Dimen : integer;
  763.                 var Error : byte);
  764.  
  765. {---------------------------------------}
  766. {- Input: Dimen                        -}
  767. {- Output: Error                       -}
  768. {-                                     -}
  769. {- This procedure checks to see if the -}
  770. {- value of Dimen is greater than 1.   -}
  771. {---------------------------------------}
  772.  
  773. begin
  774.   Error := 0;
  775.   if Dimen < 1 then
  776.     Error := 1;
  777. end; { procedure TestInput }
  778.  
  779. function RowColumnMult(Row    : integer;
  780.                    var Lower  : TNmatrix;
  781.                        Column : integer;
  782.                    var Upper  : TNmatrix) : Float;
  783.  
  784. {----------------------------------------------------}
  785. {- Input: Row, Lower, Column, Upper                 -}
  786. {- Function return: dot product of row Row of Lower -}
  787. {-                  and column Column of Upper      -}
  788. {----------------------------------------------------}
  789.  
  790. var
  791.   Term : integer;
  792.   Sum : Float;
  793.  
  794. begin
  795.   Sum := 0;
  796.   for Term := 1 to Row - 1 do
  797.     Sum := Sum + Lower[Row, Term] * Upper[Term, Column];
  798.   RowColumnMult := Sum;
  799. end; { function RowColumnMult }
  800.  
  801.  
  802. procedure Pivot(Dimen        : integer;
  803.                 ReferenceRow : integer;
  804.             var Coefficients : TNmatrix;
  805.             var Lower        : TNmatrix;
  806.             var Upper        : TNmatrix;
  807.             var Permute      : TNmatrix;
  808.             var Error        : byte);
  809.  
  810. {----------------------------------------------------------------}
  811. {- Input: Dimen, ReferenceRow, Coefficients,                    -}
  812. {-        Lower, Upper, Permute                                 -}
  813. {- Output: Coefficients, Lower, Permute, Error                  -}
  814. {-                                                              -}
  815. {- This procedure searches the ReferenceRow column of the       -}
  816. {- Coefficients matrix for the element in the Row below the     -}
  817. {- main diagonal which produces the largest value of            -}
  818. {-                                                              -}
  819. {-         Coefficients[Row, ReferenceRow] -                    -}
  820. {-                                                              -}
  821. {-          Sum K=1 to ReferenceRow - 1 of                      -}
  822. {-                  Upper[Row, k] - Lower[k, ReferenceRow]      -}
  823. {-                                                              -}
  824. {- If it finds one, then the procedure switches                 -}
  825. {- rows so that this element is on the main diagonal. The       -}
  826. {- procedure also switches the corresponding elements in the    -}
  827. {- Permute matrix and the Lower matrix. If the largest value of -}
  828. {- the above expression is zero, then the matrix is singular    -}
  829. {- and no solution exists (Error = 2 is returned).              -}
  830. {----------------------------------------------------------------}
  831.  
  832. var
  833.   PivotRow, Row : integer;
  834.   ColumnMax, TestMax : Float;
  835.  
  836. procedure EROswitch(var Row1 : TNvector;
  837.                     var Row2 : TNvector);
  838.  
  839. {-------------------------------------------------}
  840. {- Input: Row1, Row2                             -}
  841. {- Output: Row1, Row2                            -}
  842. {-                                               -}
  843. {- elementary row operation - switching two rows -}
  844. {-------------------------------------------------}
  845.  
  846. var
  847.   DummyRow : TNvector;
  848.  
  849. begin
  850.   DummyRow := Row1;
  851.   Row1 := Row2;
  852.   Row2 := DummyRow;
  853. end; { procedure EROswitch }
  854.  
  855. begin { procedure Pivot }
  856.   { First, find the row with the largest TestMax }
  857.   PivotRow := ReferenceRow;
  858.   ColumnMax := ABS(Coefficients[ReferenceRow, ReferenceRow] -
  859.                RowColumnMult(ReferenceRow, Lower, ReferenceRow, Upper));
  860.   for Row := ReferenceRow + 1 to Dimen do
  861.   begin
  862.     TestMax := ABS(Coefficients[Row, ReferenceRow] -
  863.                RowColumnMult(Row, Lower, ReferenceRow, Upper));
  864.  
  865.     if TestMax > ColumnMax then
  866.     begin
  867.       PivotRow := Row;
  868.       ColumnMax := TestMax;
  869.     end;
  870.   end;
  871.  
  872.   if PivotRow <> ReferenceRow then
  873.     { Second, switch these two rows }
  874.     begin
  875.       EROswitch(Coefficients[PivotRow], Coefficients[ReferenceRow]);
  876.       EROswitch(Lower[PivotRow], Lower[ReferenceRow]);
  877.       EROswitch(Permute[PivotRow], Permute[ReferenceRow]);
  878.     end
  879.   else
  880.     { If ColumnMax is zero, no solution exists }
  881.     if ColumnMax < TNNearlyZero then
  882.       Error := 2;     { No solution exists }
  883. end; { procedure Pivot }
  884.  
  885. procedure Decompose(Dimen        : integer;
  886.                 var Coefficients : TNmatrix;
  887.                 var Decomp       : TNmatrix;
  888.                 var Permute      : TNmatrix;
  889.                 var Error        : byte);
  890.  
  891. {---------------------------------------------------------}
  892. {- Input: Dimen, Coefficients                            -}
  893. {- Output: Decomp, Permute, Error                        -}
  894. {-                                                       -}
  895. {- This procedure decomposes the Coefficients matrix     -}
  896. {- into two triangular matrices, a lower and an upper    -}
  897. {- one.  The lower and upper matrices are combined       -}
  898. {- into one matrix, Decomp.  The permutation matrix,     -}
  899. {- Permute, records the effects of partial pivoting.     -}
  900. {---------------------------------------------------------}
  901.  
  902. var
  903.   Upper, Lower : TNmatrix;
  904.   Term, Index : integer;
  905.  
  906. procedure Initialize(Dimen   : integer;
  907.                  var Lower   : TNmatrix;
  908.                  var Upper   : TNmatrix;
  909.                  var Permute : TNmatrix);
  910.  
  911. {---------------------------------------------------}
  912. {- Output: Dimen, Lower, Upper, Permute            -}
  913. {-                                                 -}
  914. {- This procedure initializes the above variables. -}
  915. {- Lower and Upper are initialized to the zero     -}
  916. {- matrix and Diag is initialized to the identity  -}
  917. {- matrix.                                         -}
  918. {---------------------------------------------------}
  919.  
  920. var
  921.   Diag : integer;
  922.  
  923. begin
  924.   FillChar(Upper, SizeOf(Upper), 0);
  925.   FillChar(Lower, SizeOf(Lower), 0);
  926.   FillChar(Permute, SizeOf(Permute), 0);
  927.   for Diag := 1 to Dimen do
  928.     Permute[Diag, Diag] := 1;
  929. end; { procedure Initialize }
  930.  
  931. begin { procedure Decompose }
  932.   Initialize(Dimen, Lower, Upper, Permute);
  933.  
  934.   {  partial pivoting on row 1 }
  935.   Pivot(Dimen, 1, Coefficients, Lower, Upper, Permute, Error);
  936.   if Error = 0 then
  937.   begin
  938.     Lower[1, 1] := 1;
  939.     Upper[1, 1] := Coefficients[1, 1];
  940.  
  941.     for Term := 1 to Dimen do
  942.     begin
  943.       Lower[Term, 1] := Coefficients[Term, 1] / Upper[1, 1];
  944.       Upper[1, Term] := Coefficients[1, Term] / Lower[1, 1];
  945.     end;
  946.   end;
  947.  
  948.   Term := 1;
  949.   while (Error = 0) and (Term < Dimen - 1) do
  950.   begin
  951.     Term := Succ(Term);
  952.  
  953.     { perform partial pivoting on row Term }
  954.     Pivot(Dimen, Term, Coefficients, Lower, Upper, Permute, Error);
  955.  
  956.     Lower[Term, Term] := 1;
  957.     Upper[Term, Term] := Coefficients[Term, Term] -
  958.                          RowColumnMult(Term, Lower, Term, Upper);
  959.  
  960.     if ABS(Upper[Term, Term]) < TNNearlyZero then
  961.       Error := 2   { no solutions }
  962.     else
  963.       for Index := Term + 1 to Dimen do
  964.       begin
  965.         Upper[Term, Index] := Coefficients[Term, Index] -
  966.                               RowColumnMult(Term, Lower, Index, Upper);
  967.         Lower[Index, Term] := (Coefficients[Index, Term] -
  968.                               RowColumnMult(Index, Lower, Term, Upper)) /
  969.                               Upper[Term, Term];
  970.       end;
  971.   end;
  972.  
  973.   Lower[Dimen, Dimen] := 1;
  974.   Upper[Dimen, Dimen] := Coefficients[Dimen, Dimen] -
  975.                          RowColumnMult(Dimen, Lower, Dimen, Upper);
  976.   if ABS(Upper[Dimen, Dimen]) < TNNearlyZero then
  977.     Error := 2;
  978.   { Combine the upper and lower triangular matrices into one }
  979.   Decomp := Upper;
  980.  
  981.   for Term := 2 to Dimen do
  982.     for Index := 1 to Term - 1 do
  983.       Decomp[Term, Index] := Lower[Term, Index];
  984. end; { procedure Decompose }
  985.  
  986. begin { procedure LU_Decompose }
  987.   TestInput(Dimen, Error);
  988.   if Error = 0 then
  989.     if Dimen = 1 then
  990.       begin
  991.         Decomp := Coefficients;
  992.         Permute[1, 1] := 1;
  993.       end
  994.     else
  995.       Decompose(Dimen, Coefficients, Decomp, Permute, Error);
  996. end; { procedure LU_Decompose }
  997.  
  998. procedure LU_Solve{(Dimen     : integer;
  999.                var Decomp    : TNmatrix;
  1000.                    Constants : TNvector;
  1001.                var Permute   : TNmatrix;
  1002.                var Solution  : TNvector;
  1003.                var Error     : byte)};
  1004.  
  1005. procedure Initial(Dimen    : integer;
  1006.               var Solution : TNvector;
  1007.               var Error    : byte);
  1008.  
  1009. {----------------------------------------------------}
  1010. {- Input: Dimen                                     -}
  1011. {- Output: Solution, Error                          -}
  1012. {-                                                  -}
  1013. {- This procedure initializes the Solution vector.  -}
  1014. {- It also checks to see if the value of Dimen is   -}
  1015. {- greater than 1.                                  -}
  1016. {----------------------------------------------------}
  1017.  
  1018. begin
  1019.   Error := 0;
  1020.   FillChar(Solution, SizeOf(Solution), 0);
  1021.   if Dimen < 1 then
  1022.     Error := 1;
  1023. end; { procedure Initial }
  1024.  
  1025. procedure FindSolution(Dimen     : integer;
  1026.                    var Decomp    : TNmatrix;
  1027.                    var Constants : TNvector;
  1028.                    var Solution  : TNvector);
  1029.  
  1030. {---------------------------------------------------------------}
  1031. {- Input: Dimen, Decomp, Constants                             -}
  1032. {- Output: Solution                                            -}
  1033. {-                                                             -}
  1034. {- The Decom matrix contains a lower and upper triangular      -}
  1035. {- matrix.                                                     -}
  1036. {- This procedure performs a two step backwards substitution   -}
  1037. {- to compute the solution to the system of equations.  First, -}
  1038. {- forward substitution is applied to the lower triangular     -}
  1039. {- matrix and Constants vector yielding PartialSolution.  Then -}
  1040. {- backwards substitution is applied to the Upper matrix and   -}
  1041. {- the PartialSolution vector yielding Solution.               -}
  1042. {---------------------------------------------------------------}
  1043.  
  1044. var
  1045.   PartialSolution : TNvector;
  1046.   Term, Index : integer;
  1047.   Sum : Float;
  1048.  
  1049. begin { procedure FindSolution }
  1050.   { First solve the lower triangular matrix }
  1051.   PartialSolution[1] := Constants[1];
  1052.   for Term := 2 to Dimen do
  1053.   begin
  1054.     Sum := 0;
  1055.     for Index := 1 to Term - 1 do
  1056.       if Term = Index then
  1057.         Sum := Sum + PartialSolution[Index]
  1058.       else
  1059.         Sum := Sum + Decomp[Term, Index] * PartialSolution[Index];
  1060.     PartialSolution[Term] := Constants[Term] - Sum;
  1061.   end;
  1062.   { Then solve the upper triangular matrix }
  1063.   Solution[Dimen] := PartialSolution[Dimen] / Decomp[Dimen, Dimen];
  1064.   for Term := Dimen - 1 downto 1 do
  1065.   begin
  1066.     Sum := 0;
  1067.     for Index := Term + 1 to Dimen do
  1068.       Sum := Sum + Decomp[Term, Index] * Solution[Index];
  1069.     Solution[Term] := (PartialSolution[Term] - Sum)/Decomp[Term, Term];
  1070.   end;
  1071. end; { procedure FindSolution }
  1072.  
  1073. procedure PermuteConstants(Dimen     : integer;
  1074.                        var Permute   : TNmatrix;
  1075.                        var Constants : TNvector);
  1076.  
  1077. var
  1078.   Row, Column : integer;
  1079.   Entry : Float;
  1080.   TempConstants : TNvector;
  1081.  
  1082. begin
  1083.   for Row := 1 to Dimen do
  1084.   begin
  1085.     Entry := 0;
  1086.     for Column := 1 to Dimen do
  1087.       Entry := Entry + Permute[Row, Column] * Constants[Column];
  1088.     TempConstants[Row] := Entry;
  1089.   end;
  1090.   Constants := TempConstants;
  1091. end; { procedure PermuteConstants }
  1092.  
  1093. begin { procedure Solve_LU_Decompostion }
  1094.   Initial(Dimen, Solution, Error);
  1095.   if Error = 0 then
  1096.     PermuteConstants(Dimen, Permute, Constants);
  1097.   FindSolution(Dimen, Decomp, Constants, Solution);
  1098. end; { procedure LU_Solve }
  1099.  
  1100. procedure Gauss_Seidel{(Dimen      : integer;
  1101.                       Coefficients : TNmatrix;
  1102.                       Constants    : TNvector;
  1103.                       Tol          : Float;
  1104.                       MaxIter      : integer;
  1105.                   var Solution     : TNvector;
  1106.                   var Iter         : integer;
  1107.                   var Error        : byte)};
  1108.  
  1109.  
  1110. var
  1111.   Guess : TNvector;
  1112.  
  1113. procedure TestInput(Dimen        : integer;
  1114.                     Tol          : Float;
  1115.                     MaxIter      : integer;
  1116.                 var Coefficients : TNmatrix;
  1117.                 var Constants    : TNvector;
  1118.                 var Solution     : TNvector;
  1119.                 var Error        : byte);
  1120.  
  1121. {----------------------------------}
  1122. {- Input: Dimen, Tol, MaxIter     -}
  1123. {-        Coefficients,           -}
  1124. {-        Constants               -}
  1125. {- Output: Solution, Error        -}
  1126. {-                                -}
  1127. {- test the input data for errors -}
  1128. {- The procedure also finds the   -}
  1129. {- solution for the trivial case  -}
  1130. {- Dimen = 0.                     -}
  1131. {----------------------------------}
  1132.  
  1133. begin
  1134.   Error := 0;
  1135.   if Dimen < 1 then
  1136.     Error := 3
  1137.   else
  1138.     if Tol <= 0 then
  1139.       Error := 4
  1140.      else
  1141.        if MaxIter < 0 then
  1142.          Error := 5;
  1143.   if (Error = 0) and (Dimen = 1) then
  1144.   begin
  1145.     if ABS(Coefficients[1, 1]) < TNNearlyZero then
  1146.       Error := 6
  1147.     else
  1148.       Solution[1] := Constants[1] / Coefficients[1, 1];
  1149.   end;
  1150. end; { procedure TestInput }
  1151.  
  1152. procedure TestForDiagDominance(Dimen        : integer;
  1153.                            var Coefficients : TNmatrix;
  1154.                            var Error        : byte);
  1155.  
  1156. {-------------------------------------------------------------------}
  1157. {- Input: Dimen, Coefficients                                      -}
  1158. {- Output: Error                                                   -}
  1159. {-                                                                 -}
  1160. {- This procedure examines the Coefficients matrix to see if it is -}
  1161. {- diagonally dominant. If it is, then the Gauss-Seidel iterative  -}
  1162. {- method will converge to a solution of this system of equations; -}
  1163. {- if not, then convergence may not be possible with this method   -}
  1164. {- and Error = 1 (which is a warning) is returned. If one of the   -}
  1165. {- elements on the main diagonal of the Coefficients matrix is     -}
  1166. {- zero, then the matrix is singular and cannot be solved and      -}
  1167. {- Error = 6 is returned. In such a case, one of the direct        -}
  1168. {- methods for solving systems of equations (e.g. Gaussian         -}
  1169. {- elimination) should be used.                                    -}
  1170. {-------------------------------------------------------------------}
  1171.  
  1172. var
  1173.   Row, Column : integer;
  1174.   Sum : Float;
  1175.  
  1176. begin
  1177.   Row := 0;
  1178.   while (Row < Dimen) and (Error < 2) do
  1179.   begin
  1180.     Row := Succ(Row);
  1181.     Sum := 0;
  1182.     for Column := 1 to Dimen do
  1183.       if Column <> Row then
  1184.         Sum := Sum + ABS(Coefficients[Row, Column]);
  1185.     if Sum > ABS(Coefficients[Row, Row]) then
  1186.       Error := 1;  { WARNING! convergence may not be }
  1187.                    { possible because matrix isn't   }
  1188.                    { diagonally dominant             }
  1189.     if ABS(Coefficients[Row, Row]) < TNNearlyZero then
  1190.       Error := 6;  { Singular matrix - can't be solved  }
  1191.                    { by the Gauss-Seidel method.        }
  1192.   end; { while }
  1193. end; { procedure TestForDiagDominance }
  1194.  
  1195. procedure MakeInitialGuess(Dimen        : integer;
  1196.                        var Coefficients : TNmatrix;
  1197.                        var Constants    : TNvector;
  1198.                        var Guess        : TNvector);
  1199.  
  1200. {-------------------------------------------------------------------}
  1201. {- Input: Dimen, Coefficients, Constants                           -}
  1202. {- Output: Guess                                                   -}
  1203. {-                                                                 -}
  1204. {- This procedure creates an initial approximation to the solution -}
  1205. {- by dividing the Constants terms by the corresponding terms      -}
  1206. {- on the main diagonal of the Coefficients matrix.                -}
  1207. {-------------------------------------------------------------------}
  1208.  
  1209. var
  1210.   Term : integer;
  1211.  
  1212. begin
  1213.   FillChar(Guess, SizeOf(Guess), 0);
  1214.   for Term := 1 to Dimen do
  1215.     if ABS(Coefficients[Term, Term]) > TNNearlyZero then
  1216.       Guess[Term] := Constants[Term] / Coefficients[Term, Term];
  1217. end; { procedure MakeInitialGuess }
  1218.  
  1219. procedure TestForConvergence(Dimen     : integer;
  1220.                          var OldApprox : TNvector;
  1221.                          var NewApprox : TNvector;
  1222.                              Tol       : Float;
  1223.                          var Done      : boolean;
  1224.                          var Product   : Float;
  1225.                          var Error     : byte);
  1226.  
  1227. {----------------------------------------------------------------------}
  1228. {- Input: Dimen, OldApprox, NewApprox, Tol, Product                   -}
  1229. {- Output: Done, Product, Error                                       -}
  1230. {-                                                                    -}
  1231. {- This procedure determines if the sequence of approximations        -}
  1232. {- has converged. For convergence to occur, the relative difference   -}
  1233. {- between each Term of OldApprox and NewApprox must be less than     -}
  1234. {- the tolerance, Tol. If so, Done = TRUE is returned.                -}
  1235. {-                                                                    -}
  1236. {- This procedure also determines if the sequence of approximations   -}
  1237. {- is diverging. Product records the total fractional change from     -}
  1238. {- the initial guess to the current iteration.  If Product is greater -}
  1239. {- than 1E20, then the sequence is assumed to have diverged. If so,   -}
  1240. {- Error = 7 is returned.                                             -}
  1241. {----------------------------------------------------------------------}
  1242.  
  1243. var
  1244.   Term : integer;
  1245.   PartProd : Float;
  1246.  
  1247. begin
  1248.   Done := true;
  1249.   PartProd := 0;
  1250.   for Term := 1 to Dimen do
  1251.   begin
  1252.     if ABS(OldApprox[Term] - NewApprox[Term]) > ABS(NewApprox[Term] * Tol) then
  1253.       Done := false;
  1254.     if (ABS(OldApprox[Term]) > TNNearlyZero) and (Error = 1) then
  1255.       { This is part of the divergence test }
  1256.       PartProd := PartProd + ABS(NewApprox[Term] / OldApprox[Term]);
  1257.   end;
  1258.   Product := Product * PartProd / Dimen;
  1259.   if Product > 1E20 then
  1260.     Error := 7   { Sequence is diverging }
  1261. end; { procedure TestForConvergence }
  1262.  
  1263. procedure Iterate(Dimen        : integer;
  1264.               var Coefficients : TNmatrix;
  1265.               var Constants    : TNvector;
  1266.               var Guess        : TNvector;
  1267.                   Tol          : Float;
  1268.                   MaxIter      : integer;
  1269.               var Solution     : TNvector;
  1270.               var Iter         : integer;
  1271.               var Error        : byte);
  1272.  
  1273. {--------------------------------------------------------------}
  1274. {- Input: Dimen, Coefficients, Constants, Guess, Tol, MaxIter -}
  1275. {- Output: Solution, Iter, Error                              -}
  1276. {-                                                            -}
  1277. {- This procedure performs the Gauss-Seidel iteration and     -}
  1278. {- returns either an error or the approximated solution and   -}
  1279. {- the number of iterations.                                  -}
  1280. {--------------------------------------------------------------}
  1281.  
  1282. var
  1283.   Done : boolean;
  1284.   OldApprox, NewApprox : TNvector;
  1285.   Term, Loop : integer;
  1286.   FirstSum, SecondSum, Product : Float;
  1287.  
  1288. begin { procedure Iterate }
  1289.   Product := 1;
  1290.   Done := false;
  1291.   Iter := 0;
  1292.   NewApprox := Guess;
  1293.   OldApprox := Guess;
  1294.   while (Iter < MaxIter) and not(Done) and (Error <= 1) do
  1295.   begin
  1296.     Iter := Succ(Iter);
  1297.     for Term := 1 to Dimen do
  1298.     begin
  1299.       FirstSum := 0;
  1300.       SecondSum := 0;
  1301.       for Loop := 1 to Term - 1 do
  1302.         FirstSum := FirstSum + Coefficients[Term, Loop] * NewApprox[Loop];
  1303.         for Loop := Term + 1 to Dimen do
  1304.           SecondSum := SecondSum + Coefficients[Term, Loop] * OldApprox[Loop];
  1305.       NewApprox[Term] := (Constants[Term] - FirstSum - SecondSum) /
  1306.                           Coefficients[Term, Term];
  1307.     end;
  1308.     TestForConvergence(Dimen, OldApprox, NewApprox, Tol, Done, Product, Error);
  1309.     OldApprox := NewApprox;
  1310.   end; { while }
  1311.   if (Iter < MaxIter) and (Error = 1) then
  1312.     Error := 0;  { The sequence converged, }
  1313.                  {  disregard the warning  }
  1314.   if (Iter >= MaxIter) and (Error = 1) then
  1315.     Error := 1;  { Matrix is not diagonally dominant; }
  1316.                  { convergence is probably impossible }
  1317.   if (Iter >= MaxIter) and (Error = 0) then
  1318.      Error := 2; { Convergence IS possible;   }
  1319.                  { more iterations are needed }
  1320.   Solution := NewApprox;
  1321. end; { procedure Iterate }
  1322.  
  1323. begin  { procedure Gauss_Seidel }
  1324.   TestInput(Dimen, Tol, MaxIter, Coefficients, Constants, Solution, Error);
  1325.   if Dimen > 1 then
  1326.   begin
  1327.     TestForDiagDominance(Dimen, Coefficients, Error);
  1328.     if Error < 2 then
  1329.     begin
  1330.       MakeInitialGuess(Dimen, Coefficients, Constants, Guess);
  1331.       Iterate(Dimen, Coefficients, Constants, Guess, Tol,
  1332.               MaxIter, Solution, Iter, Error);
  1333.     end;
  1334.   end;
  1335. end; { procedure Gauss_Seidel }
  1336.