home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / unity / d45 / ESBMATHS.ZIP / ESBMaths2.pas < prev    next >
Pascal/Delphi Source File  |  2001-06-19  |  17KB  |  566 lines

  1. unit ESBMaths2;
  2.  
  3. {:
  4.     ESBMaths 3.2.1 - contains useful Mathematical routines for Delphi 4, 5 & 6.
  5.  
  6.     Copyright ⌐1997-2001 ESB Consultancy<p>
  7.  
  8.     These routines are used by ESB Consultancy within the
  9.     development of their Customised Applications, and have been
  10.     under Development since the early Turbo Pascal days. Many of the
  11.     routines were developed for specific needs.<p>
  12.  
  13.     ESB Consultancy retains full copyright.<p>
  14.  
  15.     ESB Consultancy grants users of this code royalty free rights
  16.     to do with this code as they wish.<p>
  17.  
  18.     ESB Consultancy makes no guarantees nor excepts any liabilities
  19.     due to the use of these routines<p>
  20.  
  21.     We does ask that if this code helps you in you development
  22.     that you send as an email mailto:glenn@esbconsult.com.au or even
  23.     a local postcard. It would also be nice if you gave us a
  24.     mention in your About Box or Help File.<p>
  25.  
  26.     ESB Consultancy Home Page: http://www.esbconsult.com.au<p>
  27.  
  28.     Mail Address: PO Box 2259, Boulder, WA 6449 AUSTRALIA<p>
  29.  
  30.     Check out our new ESB Professional Computation Suite with
  31.     3000+ Routines and 80+ Components for Delphi 4, 5 & 6.<p>
  32.     http://www.esbconsult.com.au/esbpcs.html<p>
  33.  
  34.     Also check out Marcel Martin's HIT at:<p>
  35.     http://www.esbconsult.com.au/esbpcs-hit.html<p>
  36.     Marcel has been helping out to optimise and improve routines.<p>
  37.  
  38.     Rory Daulton has generously donated and helped with many optimised
  39.     routines. Our thanks to him as well.<p>
  40.  
  41.     Marcel van Brakel has also been very helpful has includes ESBMaths
  42.     into the Jedi Collection. http://www.delphi-jedi.org/
  43.  
  44.     Any mistakes made are mine rather than Rory's or the Marcels'.<p>
  45.  
  46.     History: See Whatsnew.txt
  47. }
  48.  
  49. interface
  50. {$IFDEF VER120}
  51. {$DEFINE D4andAbove}
  52. {$ENDIF}
  53.  
  54. {$IFDEF VER125}
  55. {$DEFINE D4andAbove}
  56. {$ENDIF}
  57.  
  58. {$IFDEF VER130}
  59. {$DEFINE D4andAbove}
  60. {$ENDIF}
  61.  
  62. {$IFDEF VER140}
  63. {$DEFINE D4andAbove}
  64. {$ENDIF}
  65.  
  66. {$J-} // Constants from here are not assignable
  67.  
  68. {$IFNDEF D4AndAbove}
  69. //Routines designed for Delphi 4 and Above only!
  70. {$ENDIF}
  71.  
  72. uses
  73.     ESBMaths;
  74.  
  75. type
  76.     TDynFloatArray = array of Extended;
  77.     TDynLWordArray = array of LongWord;
  78.     TDynLIntArray = array of LongInt;
  79.  
  80. type
  81.     TDynFloatMatrix = array of TDynFloatArray;
  82.     TDynLWordMatrix = array of TDynLWordArray;
  83.     TDynLIntMatrix = array of TDynLIntArray;
  84.  
  85. {--- Vector Operations ---}
  86.  
  87. {: Returns Vector X with all its elements squared }
  88. function SquareAll (const X: TDynFloatArray): TDynFloatArray;
  89.  
  90. {: Returns Vector X with all its elements inversed , i.e 1 / X [i].
  91. An exception is raised if any element is zero }
  92. function InverseAll (const X: TDynFloatArray): TDynFloatArray;
  93.  
  94. {: Returns Vector X with all the Natural Log of all its elements .
  95. An exception is raised if any element is not Positive }
  96. function LnAll (const X: TDynFloatArray): TDynFloatArray;
  97.  
  98. {: Returns Vector X with all the Log to Base 10 of all its elements .
  99. An exception is raised if any element is not Positive }
  100. function Log10All (const X: TDynFloatArray): TDynFloatArray;
  101.  
  102. {: Returns Vector X with all elements Linearly transformed.
  103.     NewX [i] = Offset + Scale * X [i] }
  104. function LinearTransform (const X: TDynFloatArray;
  105.     Offset, Scale: Extended): TDynFloatArray;
  106.  
  107. {: Returns a vector where each element is the corresponding elements
  108. of X and Y added together. The Length of the resultant vector is that
  109. of the smaller of X and Y. }
  110. function AddVectors (const X, Y: TDynFloatArray): TDynFloatArray;
  111.  
  112. {: Returns a vector where each element is the corresponding elements
  113. of Y subtracted from X added together. The Length of the resultant vector is
  114. that of the smaller of X and Y. }
  115. function SubVectors (const X, Y: TDynFloatArray): TDynFloatArray;
  116.  
  117. {: Returns a vector where each element is the corresponding elements
  118. of X and Y multiplied together. The Length of the resultant vector is that
  119. of the smaller of X and Y. }
  120. function MultVectors (const X, Y: TDynFloatArray): TDynFloatArray;
  121.  
  122. {: Returns the Dot Product of the two vectors, i.e. the sum of the pairwise
  123. products of the elements. If Vectors are not of equal length then only
  124. the shorter length is used.}
  125. function DotProduct (const X, Y: TDynFloatArray): Extended;
  126.  
  127. {: Returns the Norm of a vector, i.e. the square root of the sum of the
  128. squares of the elements. }
  129. function Norm (const X: TDynFloatArray): Extended;
  130.  
  131. {--- Matrix Operations ---}
  132.  
  133. {: Returns true if the Matrix is not nil and all the "columns" are
  134. the same length - Delphi allows a 2 Dimensional Dynamic Array with
  135. different length "columns" - this can cause problems in some operations }
  136. function MatrixIsRectangular (const X: TDynFloatMatrix): Boolean;
  137.  
  138. {: Returns Rectangular as true if the Matrix is not nil and all the "columns"
  139. are the same length - Delphi allows a 2 Dimensional Dynamic Array with
  140. different length "columns" - this can cause problems in some operations.
  141. Rows and Columns are the dimensions which really only make sense if the Matrix
  142. is Rectangular }
  143. procedure MatrixDimensions (const X: TDynFloatMatrix;
  144.     var Rows, Columns : LongWord; var Rectangular: Boolean);
  145.  
  146. {: For a Matrix to be Square it must be Rectangular and have the
  147. same number of "rows" and "columns" }
  148. function MatrixIsSquare (const X: TDynFloatMatrix): Boolean;
  149.  
  150. {: Matrices have the same dimensions if they are both Rectangular and
  151. they have the same number of "rows" and the same number of "columns"}
  152. function MatricesSameDimensions (const X, Y: TDynFloatMatrix): Boolean;
  153.  
  154. {: Returns a Dynamic Matrix that is the result of Adding the two supplied
  155. Matrices. Both X and Y must be truly Rectangular and must be of the same
  156. dimension otherwise an Exception is raised. }
  157. function AddMatrices (const X, Y: TDynFloatMatrix): TDynFloatMatrix;
  158.  
  159. {: In place Addition of Matrices. Add one Matrix to another, X := X + Y.
  160.     Both X and Y must be truly Rectangular and must be of the
  161.      same dimension otherwise an Exception is raised. }
  162. procedure AddToMatrix (var X: TDynFloatMatrix; const Y: TDynFloatMatrix);
  163.  
  164. {: Returns a Dynamic Matrix that is the result of Subtracting the two supplied
  165. Matrices. Both X and Y must be truly Rectangular and must be of the same
  166. dimension otherwise an Exception is raised. }
  167. function SubtractMatrices (const X, Y: TDynFloatMatrix): TDynFloatMatrix;
  168.  
  169. {: In place Subtraction of Matrices. Subtract one Matrix to another, X := X - Y.
  170.     Both X and Y must be truly Rectangular and must be of the
  171.      same dimension otherwise an Exception is raised. }
  172. procedure SubtractFromMatrix (var X: TDynFloatMatrix; const Y: TDynFloatMatrix);
  173.  
  174. {: Returns a Dynamic Matrix that is the result of multiplying each element
  175.     of X by the constant K. Will handle non-Rectangular Matrices }
  176. function MultiplyMatrixByConst (const X: TDynFloatMatrix; const K: Extended): TDynFloatMatrix;
  177.  
  178. {: Does an inplace multiplying each element of X by the constant K.
  179.     Will handle non-Rectangular Matrices }
  180. procedure MultiplyMatrixByConst2 (var X: TDynFloatMatrix; const K: Extended); overload;
  181.  
  182. {: Multiplies two Rectangular Matrices. The number of columns in X must
  183.     equal the number of rows in Y }
  184. function MultiplyMatrices (const X, Y: TDynFloatMatrix): TDynFloatMatrix; overload;
  185.  
  186. {: Transposes the Given Matrix. Only works with Rectangular Matrices. }
  187. function TransposeMatrix (const X: TDynFloatMatrix): TDynFloatMatrix; overload;
  188.  
  189. {: Calculates the Grand Mean of a Matrix: Sum of all the values
  190.     divided by no of values. Will handle non-Rectangular Matrices.
  191.     Also returns N the number of Values since the Matrix may not be Rectangular }
  192. function GrandMean (const X: TDynFloatMatrix; var N: LongWord): Extended;
  193.  
  194. implementation
  195.  
  196. uses
  197.     SysUtils;
  198.  
  199. function SquareAll (const X: TDynFloatArray): TDynFloatArray;
  200. var
  201.     I: LongWord;
  202. begin
  203.     SetLength (Result, High (X) + 1);
  204.     for I := 0 to High (X) do
  205.         Result [I] := Sqr (X [I]);
  206. end;
  207.  
  208. function InverseAll (const X: TDynFloatArray): TDynFloatArray;
  209. var
  210.     I: LongWord;
  211. begin
  212.     SetLength (Result, High (X) + 1);
  213.     for I := 0 to High (X) do
  214.     begin
  215.         if X [I] = 0 then
  216.             raise EMathError.Create ('Inverse of Zero');
  217.         Result [I] := 1 / (X [I]);
  218.     end;
  219. end;
  220.  
  221. function LnAll (const X: TDynFloatArray): TDynFloatArray;
  222. var
  223.     I: LongWord;
  224. begin
  225.     SetLength (Result, High (X) + 1);
  226.     for I := 0 to High (X) do
  227.     begin
  228.         if X [I] <= 0 then
  229.             raise EMathError.Create ('Logarithm on non-Positive');
  230.         Result [I] := Ln (X [I]);
  231.     end;
  232. end;
  233.  
  234. function Log10All (const X: TDynFloatArray): TDynFloatArray;
  235. var
  236.     I: LongWord;
  237. begin
  238.     SetLength (Result, High (X) + 1);
  239.     for I := 0 to High (X) do
  240.     begin
  241.         if X [I] <= 0 then
  242.             raise EMathError.Create ('Logarithm on non-Positive');
  243.         Result [I] := ESBLog10 (X [I]);
  244.     end;
  245. end;
  246.  
  247. function LinearTransform (const X: TDynFloatArray;
  248.     Offset, Scale: Extended): TDynFloatArray;
  249. var
  250.     I: LongWord;
  251. begin
  252.     SetLength (Result, High (X) + 1);
  253.     for I := 0 to High (X) do
  254.         Result [I] := OffSet + Scale * X [I];
  255. end;
  256.  
  257. function AddVectors (const X, Y: TDynFloatArray): TDynFloatArray;
  258. var
  259.     I: LongWord;
  260. begin
  261.     SetLength (Result, MinL (High (X), High (Y)) + 1);
  262.     for I := 0 to High (Result) do
  263.         Result [I] := X [I] + Y [I];
  264. end;
  265.  
  266. function SubVectors (const X, Y: TDynFloatArray): TDynFloatArray;
  267. var
  268.     I: LongWord;
  269. begin
  270.     SetLength (Result, MinL (High (X), High (Y)) + 1);
  271.     for I := 0 to High (Result) do
  272.         Result [I] := X [I] - Y [I];
  273. end;
  274.  
  275. function MultVectors (const X, Y: TDynFloatArray): TDynFloatArray;
  276. var
  277.     I: LongWord;
  278. begin
  279.     SetLength (Result, MinL (High (X), High (Y)) + 1);
  280.     for I := 0 to High (Result) do
  281.         Result [I] := X [I] * Y [I];
  282. end;
  283.  
  284. function DotProduct (const X, Y: TDynFloatArray): Extended;
  285. var
  286.     I, N: Longword;
  287. begin
  288.     Result := 0.0;
  289.     N := MinL (High (X), High (Y));
  290.     for I := 0 to N do
  291.         Result := Result + X [I] * Y [I];
  292. end;
  293.  
  294. function Norm (const X: TDynFloatArray): Extended;
  295. begin
  296.     Result := Sqrt (DotProduct (X, X));
  297. end;
  298.  
  299. function GrandMean (const X: TDynFloatMatrix; var N: LongWord): Extended;
  300. var
  301.     I, J: Integer;
  302. begin
  303.     Result := 0;
  304.     if (High (X) < 0) or (High (X [0]) < 0) then
  305.         raise EMathError.Create ('Matrix is Empty!');
  306.  
  307.     N := 0;
  308.     for I := 0 to High (X) do
  309.     begin
  310.         N := N + Longword (High (X [I])) + 1;
  311.         for J := 0 to High (X [I]) do
  312.             Result := Result + X [I, J];
  313.     end;
  314.     if N > 0 then
  315.         Result := Result / N
  316.     else
  317.         raise EMathError.Create ('Matrix is Empty!');
  318. end;
  319.  
  320. function AddMatrices (const X, Y: TDynFloatMatrix): TDynFloatMatrix;
  321. var
  322.     I, J, N: Integer;
  323. begin
  324.     Result := nil;
  325.     if (High (X) < 0) or (High (Y) < 0) then
  326.         raise EMathError.Create ('Matrix is Empty!');
  327.  
  328.     if (High (X) <> High (Y)) then
  329.         raise EMathError.Create ('Matrices must be the same Dimension to Add!');
  330.  
  331.     N := High (X [0]);
  332.     SetLength (Result, High (X) + 1, N + 1);
  333.     for I := 0 to High (X) do
  334.     begin
  335.         if (High (X [I]) <> N) then
  336.         begin
  337.             Result := nil;
  338.             raise EMathError.Create ('Matrices must be truly rectangular to Add!');
  339.         end;
  340.         if (High (Y [I]) <> N) then
  341.         begin
  342.             Result := nil;
  343.             raise EMathError.Create ('Matrices must be the same Dimension to Add!');
  344.         end;
  345.  
  346.         for J := 0 to N do
  347.             Result [I, J] := X [I, J] + Y [I, J];
  348.     end;
  349. end;
  350.  
  351. function SubtractMatrices (const X, Y: TDynFloatMatrix): TDynFloatMatrix;
  352. var
  353.     I, J, N: Integer;
  354. begin
  355.     Result := nil;
  356.     if (High (X) < 0) or (High (Y) < 0) then
  357.         raise EMathError.Create ('Matrix is Empty!');
  358.  
  359.     if (High (X) <> High (Y)) then
  360.         raise EMathError.Create ('Matrices must be the same Dimension to Subtract!');
  361.  
  362.     N := High (X [0]);
  363.     SetLength (Result, High (X) + 1, N + 1);
  364.     for I := 0 to High (X) do
  365.     begin
  366.         if (High (X [I]) <> N) then
  367.         begin
  368.             Result := nil;
  369.             raise EMathError.Create ('Matrices must be truly rectangular to Subtract!');
  370.         end;
  371.         if (High (Y [I]) <> N) then
  372.         begin
  373.             Result := nil;
  374.             raise EMathError.Create ('Matrices must be the same Dimension to Subtract!');
  375.         end;
  376.  
  377.         for J := 0 to N do
  378.             Result [I, J] := X [I, J] - Y [I, J];
  379.     end;
  380. end;
  381.  
  382. function MultiplyMatrixByConst (const X: TDynFloatMatrix; const K: Extended): TDynFloatMatrix;
  383. var
  384.     I, J: Integer;
  385. begin
  386.     Result := nil;
  387.     if (High (X) < 0) then
  388.         raise EMathError.Create ('Matrix is Empty!');
  389.  
  390.     SetLength (Result, High (X) + 1);
  391.     for I := 0 to High (X) do
  392.     begin
  393.         SetLength (Result [I], High (X [I]) + 1);
  394.         for J := 0 to High (X [I]) do
  395.             Result [I, J] := X [I, J] * K;
  396.     end;
  397. end;
  398.  
  399. function MatrixIsRectangular (const X: TDynFloatMatrix): Boolean;
  400. var
  401.     I, N: Integer;
  402. begin
  403.     Result := False;
  404.     if (High (X) < 0) then
  405.         Exit;
  406.  
  407.     N := High (X [0]);
  408.     for I := 0 to High (X) do
  409.         if (High (X [I]) <> N) then
  410.             Exit;
  411.  
  412.     Result := True;
  413. end;
  414.  
  415. procedure MatrixDimensions (const X: TDynFloatMatrix;
  416.     var Rows, Columns: LongWord; var Rectangular: Boolean);
  417. var
  418.     I: LongWord;
  419. begin
  420.     Rows := Length (X);
  421.      if Rows > 0 then
  422.         Columns := Length (X [0])
  423.      else
  424.          Columns := 0;
  425.  
  426.     Rectangular := False;
  427.     if (Rows = 0) or (Columns = 0) then
  428.         Exit;
  429.  
  430.     for I := 0 to Rows - 1 do
  431.         if (LongWord (Length (X [I])) <> Columns) then
  432.         begin
  433.             Columns := 0;
  434.             Exit;
  435.         end;
  436.  
  437.     Rectangular := True;
  438. end;
  439.  
  440. function MatrixIsSquare (const X: TDynFloatMatrix): Boolean;
  441. var
  442.     M, N: LongWord;
  443.     Rectangular: Boolean;
  444. begin
  445.     MatrixDimensions (X, M, N, Rectangular);
  446.     Result := Rectangular and (M = N);
  447. end;
  448.  
  449. function MatricesSameDimensions (const X, Y: TDynFloatMatrix): Boolean;
  450. var
  451.     M1, N1: LongWord;
  452.     Rectangular1: Boolean;
  453.     M2, N2: LongWord;
  454.     Rectangular2: Boolean;
  455. begin
  456.     MatrixDimensions (X, M1, N1, Rectangular1);
  457.     MatrixDimensions (Y, M2, N2, Rectangular2);
  458.     Result := Rectangular1 and Rectangular2 and (M1 = M2) and (N1 = N2);
  459. end;
  460.  
  461. procedure AddToMatrix (var X: TDynFloatMatrix; const Y: TDYnFloatMatrix);
  462. var
  463.     I, J: LongWord;
  464.      Rows, Columns: LongWord;
  465. begin
  466.     Rows := Length (X);
  467.     Columns := Length (X [0]);
  468.     if (Rows = 0) or (Columns = 0) then
  469.         raise EMathError.Create ('Matrix is Empty!');
  470.  
  471.     if not MatricesSameDimensions (X, Y) then
  472.         raise EMathError.Create ('Matrices must be the same Dimension to Add!');
  473.  
  474.     for I := 0 to Rows - 1 do
  475.         for J := 0 to Columns - 1 do
  476.             X [I, J] := X [I, J] + Y [I, J];
  477. end;
  478.  
  479. procedure SubtractFromMatrix (var X: TDynFloatMatrix; const Y: TDynFloatMatrix);
  480. var
  481.     I, J: LongWord;
  482.      Rows, Columns: LongWord;
  483. begin
  484.     Rows := Length (X);
  485.     Columns := Length (X [0]);
  486.     if (Rows = 0) or (Columns = 0) then
  487.         raise EMathError.Create ('Matrix is Empty!');
  488.  
  489.     if not MatricesSameDimensions (X, Y) then
  490.         raise EMathError.Create ('Matrices must be the same Dimension to Add!');
  491.  
  492.     for I := 0 to Rows - 1 do
  493.     begin
  494.         for J := 0 to Columns - 1 do
  495.             X [I, J] := X [I, J] - Y [I, J];
  496.     end;
  497. end;
  498.  
  499. procedure MultiplyMatrixByConst2 (var X: TDynFloatMatrix; const K: Extended); overload;
  500. var
  501.     I, J: LongWord;
  502.      Rows, Columns: LongWord;
  503. begin
  504.     Rows := Length (X);
  505.     if (Rows = 0) then
  506.         raise EMathError.Create ('Matrix is Empty!');
  507.  
  508.     for I := 0 to Rows - 1 do
  509.     begin
  510.         Columns := Length (X [0]);
  511.         for J := 0 to Columns - 1 do
  512.             X [I, J] := X [I, J] * K;
  513.     end;
  514. end;
  515.  
  516. function MultiplyMatrices (const X, Y: TDynFloatMatrix): TDynFloatMatrix;
  517. var
  518.     I, J, K: LongWord;
  519.      XRows, XColumns: LongWord;
  520.      YRows, YColumns: LongWord;
  521.      XRectangular, YRectangular: Boolean;
  522. begin
  523.     Result := nil;
  524.     MatrixDimensions (X, XRows, XColumns, XRectangular);
  525.     MatrixDimensions (Y, YRows, YColumns, YRectangular);
  526.  
  527.     if not XRectangular or not YRectangular then
  528.         raise EMathError.Create ('Matrices must both be Rectangular');
  529.     if (XRows = 0) or (YRows = 0) then
  530.         raise EMathError.Create ('Matrix is Empty!');
  531.      if XColumns <> YRows then
  532.         raise EMathError.Create ('Number of Columns in X does not equal'
  533.               + #13 + 'the Number of Rows in Y');
  534.  
  535.     SetLength (Result, XRows, YColumns);
  536.  
  537.     for I := 0 to XRows - 1 do
  538.         for J := 0 to YColumns - 1 do
  539.           begin
  540.               Result [I, J] := 0;
  541.                for K := 0 to XColumns - 1 do
  542.                 Result [I, J] := Result [I, J] + X [I, K] * Y [K, J];
  543.           end;
  544. end;
  545.  
  546. function TransposeMatrix (const X: TDynFloatMatrix): TDynFloatMatrix; overload;
  547. var
  548.     I, J: LongWord;
  549.      XRows, XColumns: LongWord;
  550.      XRectangular: Boolean;
  551. begin
  552.     Result := nil;
  553.     MatrixDimensions (X, XRows, XColumns, XRectangular);
  554.     if not XRectangular then
  555.         raise EMathError.Create ('Matrix must be Rectangular');
  556.     if (XRows = 0) or (XColumns = 0) then
  557.         Exit;
  558.  
  559.     SetLength (Result, XColumns, XRows);
  560.      for I := 0 to XRows - 1 do
  561.          for J := 0 to XColumns - 1 do
  562.             Result [J, I] := X [I, J];
  563. end;
  564.  
  565. end.
  566.