home *** CD-ROM | disk | FTP | other *** search
/ Programmer's ROM - The Computer Language Library / programmersrom.iso / ada / math / matrix.ada < prev    next >
Encoding:
Text File  |  1988-05-03  |  17.2 KB  |  532 lines

  1. ------------ SIMTEL20 Ada Software Repository Proloque --------------
  2. --                                   -*
  3. -- Unit name    : MATRIX_PACKAGE
  4. -- Version       : 1.0
  5. -- Author    : Dr. Roger Lee
  6. --        : Naval Air Developement Center
  7. --        : Advanced Software Technology Division
  8. --        : Warminster Pa. 18974
  9. -- DDN Address    : LEE at NADC        
  10. -- Copyright    : (c) 1984 Roger Lee
  11. -- Date created    : Feb 84 
  12. -- Release date    : 7 Jun 85
  13. -- Last update     : Feb 84
  14. -- Machine/System Compiled/Run on : VMS VAX11/780 Telesoft Ada compiler
  15. --                                     -*
  16. -----------------------------------------------------------------------
  17. --                                     -*
  18. -- Keywords    : 
  19. ----------------: MATRIX,VECTOR
  20. --
  21. -- ABSTRACT    :
  22. ----------------: MATRIX_PACKAGE is a general purpose matrix package.
  23. -- It defines data types VECTOR and MATRIX, and contains functions
  24. -- to perform general matrix algebra operations.  It provides for addition,
  25. -- subtraction, and multiplication of VECTORS, MATRICES and SCALARS.
  26. -- It also provides for matrix inversion and vector dot product.
  27. --
  28. --                                      -*
  29. ---------------- Revision history --------------------------------------
  30. --                                      -*
  31. -- DATE        VERSION AUTHOR            HISTORY
  32. -- 2/84          1.0    Roger Lee               Initial Release
  33. --                                      -*
  34. ---------------- Distribution and Copyright ----------------------------       
  35. --                                      -*
  36. -- This prologue must be included in all copies of this software.
  37. --
  38. -- This software is copyright by the author.
  39. --
  40. -- This software is released to the Ada community.
  41. -- This software is released to the Public Domain (note:
  42. --   software released to the Public Domain is not subject
  43. --   to copyright protection).
  44. -- Restrictions on use or distribution:  NONE
  45. --                                      -*
  46. --------------------- Disclaimer ---------------------------------------
  47. --                                      -*
  48. -- This software and its documentation are provided "AS IS" and
  49. -- without any expressed or implied warranties whatsoever.
  50. -- No warranties as to performance, merchantability, or fitness
  51. -- for a particular purpose exist.
  52. --
  53. -- Because of the diverity of conditions and hardware under  
  54. -- which this software may be used, no warranty of fitness for
  55. -- a particular purpose is offered.  The user is advised to
  56. -- test the software thoroughly before relying on it.  The user 
  57. -- must assume the entire risk and liability of using this 
  58. -- software.
  59. --
  60. -- In no event shall any person or organization of people  be
  61. -- held responsible for any direct, indirect, consequential
  62. -- or inconsequential damages or lost profits.
  63. --                                       -*
  64. -------------------- END-PROLOGUE ---------------------------------------
  65. --
  66. --
  67. --
  68. package MATRIX_PACKAGE is
  69. --> PROLOGUE
  70. -->
  71. -->**************************************************************************
  72. --> This package is a general purpose matrix package. It defines data types
  73. --> VECTOR and MATRIX, and contains functions to perform general matrix 
  74. --> algebra operations.
  75. -->**************************************************************************
  76. -->
  77.  
  78.     type VECTOR is array(INTEGER range<>) of FLOAT ;
  79.     type MATRIX is array(INTEGER range<>,INTEGER range <>) of FLOAT;
  80.     INCOMPARABLE_DIMENSION :exception; -- the dimension of matrices
  81.                                            -- or vectors to be operated are 
  82.                        -- incomparable
  83.     SINGULAR : exception;    -- matrix to be inverted is singular
  84.     function TRANSPOSE(A : MATRIX) return MATRIX ; -- transpose of matrix
  85.         function TRANSPOSE(A : VECTOR) return VECTOR ; -- transpose of vector
  86.     function "+" (A : VECTOR; B : VECTOR) return VECTOR ; -- sum of vector
  87.     function "+" (A : MATRIX; B : MATRIX) return MATRIX ; -- sum of matrix
  88.     function "-" (A : VECTOR; B : VECTOR) return VECTOR ; 
  89.                            -- difference of vector
  90.     function "-" (A : MATRIX; B : MATRIX) return MATRIX ; 
  91.                            -- difference of matrix
  92.     function "*" (A : FLOAT;  B : VECTOR) return VECTOR ; 
  93.                            -- scalar, vector multiplication
  94.     function "*" (A : VECTOR; B : FLOAT)  return VECTOR ; 
  95.                            -- vector, scalar multiplication
  96.     function "*" (A : VECTOR; B : VECTOR) return FLOAT ;  
  97.                            -- inner(dot) product of two vectors
  98.     function "*" (A : MATRIX; B : VECTOR) return VECTOR ; 
  99.                            -- matrix,column vector multiplication
  100.     function "*" (A : VECTOR; B : MATRIX) return VECTOR ; 
  101.                            -- row vector,matrix multiplication
  102.     function "*" (A : FLOAT;  B : MATRIX) return MATRIX ; 
  103.                            -- scalar, matrix multiplication
  104.     function "*" (A : MATRIX; B : FLOAT)  return MATRIX ; 
  105.                            -- matrix, scalar multiplication
  106.     function "*" (A : MATRIX; B : MATRIX) return MATRIX ; 
  107.                            -- matrix, matrix multiplication
  108.     function "**"(A : MATRIX; P : INTEGER) return MATRIX; 
  109.                            -- square matrix raised to integer 
  110.                            -- power
  111. --
  112. --> CALLS
  113. -->       NONE
  114. -->
  115. end MATRIX_PACKAGE;
  116.  
  117.  
  118. ---
  119. package body MATRIX_PACKAGE is
  120.  
  121. ---
  122.     function TRANSPOSE(A : MATRIX) return MATRIX is
  123.         B : MATRIX(A'FIRST(2)..A'LAST(2),A'FIRST(1)..A'LAST(1)) ;
  124. --        ******************************************************************
  125. --      This function performs the tranpose of input matrix A
  126. --    ******************************************************************
  127.     begin
  128.         for I in A'RANGE(2) loop
  129.             for J in A'RANGE(1) loop
  130.                 B(I,J) := A(J,I) ;
  131.             end loop ;
  132.         end loop ;
  133.         return B ;
  134.     end TRANSPOSE;
  135. ---
  136.     function TRANSPOSE(A : VECTOR) return VECTOR is
  137. --    *****************************************************************
  138. --      This function returns the transpose of a vector. In programming
  139. --      a vector is always stored as one-dimensional array. Therefore,
  140. --        there is no difference between row vector and column vector.
  141. --        Thus, this function just returns the input vector (do nothing).
  142. --    *****************************************************************
  143.         begin
  144.             return A;
  145.         end TRANSPOSE;
  146. ---
  147.     function "+" (A : VECTOR; B : VECTOR) return VECTOR is
  148.         C : VECTOR(A'FIRST..A'LAST) ;
  149. --    **************************************************************
  150. --      This function performs the addition of vector A and vector B
  151. --       resulting in a vector. Comparability of dimensions is checked.
  152. --    **************************************************************
  153.     begin
  154.         if A'FIRST /= B'FIRST or A'LAST /= B'LAST then
  155.             raise INCOMPARABLE_DIMENSION;
  156.         end if ;
  157.         for I in A'RANGE loop
  158.             C(I) := A(I)+B(I) ;
  159.         end loop ;
  160.         return C ;
  161.     end "+";
  162. ---
  163.     function "+" (A : MATRIX; B : MATRIX) return MATRIX is
  164.         C : MATRIX(A'FIRST(1)..A'LAST(1),A'FIRST(2)..A'LAST(2)) ;
  165. --    *******************************************************************
  166. --      This function performs the addition of matrix A and matrix B
  167. --      resulting in a matrix. Comparability of dimensions is checked.
  168. --    *******************************************************************
  169.     begin
  170.         if (A'FIRST(1) /= B'FIRST(1) or A'LAST(1) /= B'LAST(1)) 
  171.           or (A'FIRST(2) /= B'FIRST(2) or A'LAST(2) /= B'LAST(2)) then
  172.             raise INCOMPARABLE_DIMENSION;
  173.         end if ;
  174.         for I in A'RANGE(1) loop
  175.             for J in A'RANGE(2) loop
  176.                 C(I,J) := A(I,J)+B(I,J) ;
  177.             end loop ;
  178.         end loop ;
  179.         return C ;
  180.     end "+";
  181. ---
  182.     function "-" (A : VECTOR; B : VECTOR) return VECTOR is
  183.         C : VECTOR(A'FIRST..A'LAST) ;
  184. --    ******************************************************************
  185. --      This function performs the subtraction of vector B from vector A
  186. --      resulting in a vector. Comparability of dimensions is checked.
  187. --    ******************************************************************
  188.     begin
  189.         if A'FIRST /= B'FIRST or A'LAST /= B'LAST then
  190.             raise INCOMPARABLE_DIMENSION;
  191.         end if ;
  192.         for I in A'RANGE loop
  193.             C(I) := A(I)-B(I) ;
  194.         end loop ;
  195.         return C ;
  196.     end "-";
  197. ---
  198.     function "-" (A : MATRIX; B : MATRIX) return MATRIX is
  199.         C : MATRIX(A'FIRST(1)..A'LAST(1),A'FIRST(2)..A'LAST(2)) ;
  200. --    ******************************************************************
  201. --      This function performs the subtraction of matrix B from matrix A
  202. --      resulting in a matrix. Comparability of dimensions is checked.
  203. --    ******************************************************************
  204.     begin
  205.         if (A'FIRST(1) /= B'FIRST(1) or A'LAST(1) /= B'LAST(1)) 
  206.           or (A'FIRST(2) /= B'FIRST(2) or A'LAST(2) /= B'LAST(2)) then
  207.             raise INCOMPARABLE_DIMENSION;
  208.         end if ;
  209.         for I in A'RANGE(1) loop
  210.             for J in A'RANGE(2) loop
  211.                 C(I,J) := A(I,J)-B(I,J) ;
  212.             end loop ;
  213.         end loop ;
  214.         return C ;
  215.     end "-";
  216. ---
  217.     function "*" (A:FLOAT; B:VECTOR) return VECTOR is
  218.         C: VECTOR(B'FIRST..B'LAST);
  219. --    ******************************************************************
  220. --      This function performs the scalar multiplication of a floating
  221. --      number A and a vector B resulting in a vector.
  222. --    ******************************************************************
  223.     begin
  224.         for I in B'RANGE loop
  225.             C(I):=A*B(I);
  226.         end loop;
  227.         return C ;
  228.     end "*";
  229.                                     
  230. ---
  231.     function "*" (A:VECTOR; B:FLOAT) return VECTOR is
  232.     begin
  233. --    ********************************************************************
  234. --      This function performs the scalar multiplication of a vector A and
  235. --      a floating number B resulting in a vector.
  236. --    ********************************************************************
  237.         return B*A;
  238.     end "*";
  239.                                     
  240. ---
  241.     function "*" (A : VECTOR; B : VECTOR) return FLOAT is
  242.         S :FLOAT:=0.0;
  243. --    *******************************************************************
  244. --      This function performs the inner (dot) product of two vectors A
  245. --      and B resulting in a floating number.
  246. --      Comparability of dimensions is checked.
  247. --    *******************************************************************
  248.     begin
  249.         if A'FIRST /= B'FIRST or A'LAST /= B'LAST then
  250.             raise INCOMPARABLE_DIMENSION;
  251.         end if ;
  252.         for I in A'RANGE loop
  253.             S := S+A(I)*B(I) ;
  254.         end loop ;
  255.         return S ;
  256.     end "*";
  257. ---
  258.     function "*" (A:MATRIX; B:VECTOR) return VECTOR is
  259.         C:VECTOR(A'FIRST(1)..A'LAST(1));
  260.         SUM:FLOAT;
  261. --    **********************************************************************
  262. --      This function performs the multiplication of a matrix A and a column
  263. --      vector B resulting in a column vector.
  264. --      Comparability of dimensions is checked.
  265. --    **********************************************************************
  266.     begin
  267.         if A'FIRST(2)/=B'FIRST or A'LAST(2) /= B'LAST then
  268.             raise INCOMPARABLE_DIMENSION;
  269.         end if ;
  270.         for I in A'RANGE(1) loop
  271.             SUM := 0.0 ;
  272.             for K in A'RANGE(2) loop
  273.                 SUM := SUM+A(I,K)*B(K);
  274.             end loop;
  275.             C(I):=SUM;
  276.         end loop ;
  277.         return C ;
  278.     end "*";
  279. ---
  280.     function "*" (A:VECTOR; B:MATRIX) return VECTOR is
  281.         C:VECTOR(B'FIRST(2)..B'LAST(2));
  282.         SUM:FLOAT;
  283. --    ********************************************************************
  284. --      This function performs the multiplication of a row vector A and a
  285. --      matrix B resulting in a row vector.
  286. --      Comparability of dimensions is checked.
  287. --    ********************************************************************
  288.     begin
  289.         if A'FIRST/=B'FIRST(1) or A'LAST/=B'LAST(1) then
  290.             raise INCOMPARABLE_DIMENSION;
  291.         end if ;
  292.         for J in B'RANGE(2) loop
  293.             SUM := 0.0 ;
  294.             for K in A'RANGE loop
  295.                 SUM := SUM+A(K)*B(K,J);
  296.             end loop;
  297.             C(J):=SUM;
  298.         end loop ;
  299.         return C ;
  300.     end "*";
  301. ---
  302.     function "*" (A:FLOAT; B:MATRIX) return MATRIX is
  303.         C:MATRIX(B'FIRST(1)..B'LAST(1),B'FIRST(2)..B'LAST(2));
  304. --    ********************************************************************
  305. --      This function performs the scalar multipliction of a matrix B by
  306. --      a floating number A resulting in a matrix.
  307. --    ********************************************************************
  308.     begin
  309.         for I in B'RANGE(1) loop
  310.             for J in B'RANGE(2) loop
  311.                 C(I,J) := A*B(I,J);
  312.             end loop ;
  313.         end loop ;
  314.         return C ;
  315.     end "*";
  316. ---
  317.     function "*" (A:MATRIX; B:FLOAT) return MATRIX is
  318.         C:MATRIX(A'FIRST(1)..A'LAST(1),A'FIRST(2)..A'LAST(2));
  319. --    *****************************************************************
  320. --      This function performs the scalar multipliction of a matrix A 
  321. --      by a floating number B resulting in a matrix.
  322. --    *****************************************************************
  323.     begin
  324.         return B*A ;
  325.     end "*";
  326. ---
  327.     function "*" (A:MATRIX; B:MATRIX) return MATRIX is
  328.         C:MATRIX(A'FIRST(1)..A'LAST(1),B'FIRST(2)..B'LAST(2));
  329.         SUM: FLOAT;
  330. --    ********************************************************************
  331. --      This function performs the multiplication of matrix A and matrix B
  332. --      resulting in a matrix. Comparability of dimensions is checked.
  333. --    ********************************************************************
  334.     begin
  335.         if A'FIRST(2)/=B'FIRST(1) or A'LAST(2)/=B'LAST(1) then
  336.             raise INCOMPARABLE_DIMENSION;
  337.         end if ;
  338.         for I in A'RANGE(1) loop
  339.             for J in B'RANGE(2) loop
  340.                 SUM := 0.0 ;
  341.                 for K in A'RANGE(2) loop
  342.                     SUM := SUM+A(I,K)*B(K,J);
  343.                 end loop;
  344.                 C(I,J) := SUM;
  345.             end loop ;
  346.         end loop ;
  347.         return C ;
  348.     end "*";
  349. ---
  350.     function "**" (A : MATRIX; P : INTEGER)    return MATRIX is
  351.         B,C : MATRIX(A'FIRST(1)..A'LAST(1), A'FIRST(1)..A'LAST(1));
  352.         I_PIVOT,J_PIVOT : INTEGER range A'FIRST(1)..A'LAST(1);
  353.         BIG_ENTRY, TEMP, EPSILON : FLOAT ;
  354.         L, M : array(A'RANGE(1)) of INTEGER ;
  355. --    *******************************************************************
  356. --      This function performs the square matrix operation of " matrix A
  357. --      raise to integer power P ".  When  P is negative , say P = -N ,
  358. --      A**(-N) = (inverse(A))**N , that is, the inverse of A raise to
  359. --      power N .  In this case, matrix A must be non-singular.
  360. --      Exceptions will be raised if the matrix A is not a square matrix,
  361. --      or if matrix A is singular.
  362. --    *******************************************************************
  363.     begin 
  364.         if A'FIRST(1)/=A'FIRST(2) or A'LAST(1)/=A'LAST(2) then
  365.                     -- if not a square matrix
  366.             raise INCOMPARABLE_DIMENSION ;
  367.         end if;
  368.  
  369.         if P=0 then 
  370.             --& B = identity matrix
  371.  
  372.                   for I in A'RANGE(1) loop
  373.             for J in A'RANGE(1) loop
  374.                 if I /= J then
  375.                     B(I,J) := 0.0;
  376.                 else
  377.                 B(I,J) := 1.0;
  378.                 end if;
  379.             end loop;
  380.             end loop;
  381.             return B;
  382.         end if ;
  383.  
  384.         B := A ;
  385.  
  386.         if P>0 then
  387.                 --& B = A multiplied itself for P times
  388.  
  389.             for I in 1..P-1 loop
  390.                 B := B*A ;
  391.             end loop ;
  392.             return B ;
  393.         end if;
  394.  
  395.     -- P is negative, find inverse first
  396.  
  397.         -- initiate the row and column interchange information
  398.  
  399.         for K in B'RANGE(1) loop
  400.             L(K) := K ;    -- row interchage information
  401.             M(K) := K ;    -- column interchange information
  402.         end loop;
  403.  
  404.             -- major loop for inverse
  405.  
  406.         for K in B'RANGE(1) loop
  407.  
  408.             -- & search for row and column index I_PIVOT, J_PIVOT 
  409.             -- & both in (K .. B'LAST(1) ) for maximum B(I,J)
  410.             -- & in absolute value :BIG_ENTRY
  411.  
  412.             BIG_ENTRY := 0.0 ;
  413.                    --
  414.              -- check matrix singularity
  415.                  --
  416.             for I in K..B'LAST(1) loop
  417.                 for J in K..B'LAST(1) loop
  418.                     if abs(B(I,J)) > abs(BIG_ENTRY) then
  419.                         BIG_ENTRY := B(I,J) ;
  420.                         I_PIVOT := I ;
  421.                         J_PIVOT := J ;
  422.                     end if;
  423.                 end loop;
  424.             end loop;
  425.             if K = B'FIRST(1) then
  426.                 if BIG_ENTRY = 0.0 then
  427.                 raise SINGULAR;
  428.                 else
  429.                 EPSILON := FLOAT(A'LENGTH(1))*abs(BIG_ENTRY)
  430.                                  *0.000001;
  431.                 end if;
  432.             else
  433.                 if abs(BIG_ENTRY) < EPSILON then
  434.                 raise SINGULAR ;
  435.                 end if;
  436.             end if;
  437.  
  438.             -- interchange row and column
  439.  
  440.                 --& interchange K-th and I_PIVOT-th rows
  441.             if I_PIVOT/=K then
  442.                 for J in B'RANGE(1) loop
  443.                     TEMP := B(I_PIVOT,J);
  444.                     B(I_PIVOT,J) := B(K,J) ;
  445.                     B(K,J) := TEMP ;
  446.                 end loop;
  447.                 L(K) := I_PIVOT ;
  448.             end if;
  449.                 --& interchange K-th and J_PIVOT-th columns
  450.             if J_PIVOT/=K then
  451.                 for I in B'RANGE(1) loop
  452.                     TEMP := B(I,J_PIVOT) ;
  453.                     B(I,J_PIVOT) := B(I,K) ;
  454.                     B(I,K) := TEMP ;
  455.                 end loop ;
  456.                 M(K) := J_PIVOT ;
  457.             end if ;
  458.  
  459.             --& divide K-th column by minus pivot (-BIG_ENTRY)
  460.  
  461.             for I in B'RANGE(1) loop
  462.                 if I/=K then
  463.                     B(I,K) := B(I,K)/(-BIG_ENTRY) ;
  464.                 end if;
  465.             end loop ;
  466.  
  467.             -- reduce matrix row by row
  468.  
  469.             for I in B'RANGE(1) loop
  470.                 if I/=K then
  471.                     for J in B'RANGE(1) loop
  472.                          if J/=K then
  473.                           B(I,J):=B(I,J)+B(I,K)*B(K,J);
  474.                          end if ;
  475.                     end loop ;
  476.                 end if ;
  477.             end loop ;        
  478.  
  479.             --& divide K-th row by pivot
  480.  
  481.             for J in B'RANGE(1) loop
  482.                 if J/=K then
  483.                     B(K,J) := B(K,J)/BIG_ENTRY ;
  484.                 end if ;
  485.             end loop ;
  486.             B(K,K) := 1.0/BIG_ENTRY ;
  487.  
  488.         end loop ;    -- end of major inverse loop
  489.     
  490.         -- final column and row interchange to obtain 
  491.         -- inverse of A, i.e. A**(-1)
  492.  
  493.         for K in reverse B'RANGE(1) loop
  494.                 -- column interchage
  495.             J_PIVOT := L(K) ;
  496.             if J_PIVOT/=K then
  497.                     --& intechange B(I,J_PIVOT) and B(I,K) for each row I
  498.                 for I in B'RANGE(1) loop
  499.                     TEMP := B(I,J_PIVOT) ;
  500.                     B(I,J_PIVOT) := B(I,K) ;
  501.                     B(I,K) := TEMP ;
  502.                 end loop ;
  503.             end if ;
  504.                 -- row interchage
  505.             I_PIVOT := M(K) ;
  506.             if I_PIVOT/=K then
  507.                 --& INTECHANGE B(I_PIVOT,J) and B(K,J) for each column J
  508.                 for J in B'RANGE(1) loop
  509.                     TEMP := B(I_PIVOT,J) ;
  510.                     B(I_PIVOT,J) := B(K,J) ;
  511.                     B(K,J) := TEMP ;
  512.                 end loop ;
  513.             end if ;
  514.         end loop ;
  515.  
  516.         -- inverse of A is obtained and stored in B
  517.         -- now ready to handle the negative power
  518.  
  519.                 -- & C = B**(-P)        
  520.         if P=-1 then
  521.             return B ;
  522.         end if ;
  523.  
  524.         C := B ;
  525.         for I in P+1..-1 loop
  526.             C:= C*B ;
  527.         end loop ;
  528.         return C;
  529.     end "**" ;
  530. ---
  531. end MATRIX_PACKAGE;
  532.