home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / ECO30603.ZIP / ECO30603.LZH / ECOLIBII / ECO_MTRX.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-08-28  |  10.4 KB  |  375 lines

  1. (*
  2.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  3.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  4.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  5.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  6.     ▓▓▓▓▓▓▓▓·──                                              ──·▓▓▓▓▓▓▓▓▓▓▓
  7.     ▓▓▓▓▓▓▓▓│                                                  │░░▓▓▓▓▓▓▓▓▓
  8.     ▓▓▓▓▓▓▓▓   ECO_MTRX was NOT Conceived, Designed and         ░░▓▓▓▓▓▓▓▓▓
  9.     ▓▓▓▓▓▓▓▓   Written by Floor A.C. Naaijkens for              ░░▓▓▓▓▓▓▓▓▓
  10.     ▓▓▓▓▓▓▓▓   UltiHouse Software / The ECO Group.              ░░▓▓▓▓▓▓▓▓▓
  11.     ▓▓▓▓▓▓▓▓                                                    ░░▓▓▓▓▓▓▓▓▓
  12.     ▓▓▓▓▓▓▓▓   (C) MCMXCII by EUROCON PANATIONAL CORPORATION.   ░░▓▓▓▓▓▓▓▓▓
  13.     ▓▓▓▓▓▓▓▓   All Rights Reserved for The ECO Group.           ░░▓▓▓▓▓▓▓▓▓
  14.     ▓▓▓▓▓▓▓▓                                                    ░░▓▓▓▓▓▓▓▓▓
  15.     ▓▓▓▓▓▓▓▓   Credit where credit is due.                      ░░▓▓▓▓▓▓▓▓▓
  16.     ▓▓▓▓▓▓▓▓│                                                  │░░▓▓▓▓▓▓▓▓▓
  17.     ▓▓▓▓▓▓▓▓·──                                              ──·░░▓▓▓▓▓▓▓▓▓
  18.     ▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓▓▓▓▓
  19.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  20.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  21.     ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  22. *)
  23. {
  24.  
  25. Msg # 639   
  26. Date: 19 Aug 92 15:41:00
  27. From: Greg Smith
  28.   To: Kevin Lamonte
  29. Subj: [1/3] Matrix Problem
  30. ____________________________________________________________________________
  31.  
  32. AREA:PASCAL
  33. EID:ac30 19137d20
  34. In a message to All <18 Aug 92  14:07> Kevin Lamonte wrote:
  35.  
  36.  KL> Help!  I'm trying to write a general matrices-math unit.  One of
  37. the
  38.  KL> functions is to calculate a determinant on an NxN matrice (limit is
  39. set
  40.  
  41. Here's a copy of a Matrix unit that I wrote earlier this year.
  42. Unfortunately, as you'll find out, it'd dead SLOW!  (Part due to the OOP
  43. design, and part due to me not wanting to get into piles of math to
  44. figure out the best algorithms to use).  It should work for matrices up
  45. to 80x80, however I've never tested it on anything greater than 9x9 due
  46. to speed problems.
  47. }
  48.  
  49.  
  50.  
  51. (*----------------------------------------------------------*)
  52. (* unit for doing everything you'll ever want to do with    *)
  53. (* matrices... and more.                                    *)
  54. (* requirements: turbo pascal 5.5 or better                 *)
  55. (* no rights reserved, no copyright, released into the pd   *)
  56. (* by the author: gregory p. smith of boulder, co. usa      *)
  57. (* credit not required, but is greatly appreciated          *)
  58. (*----------------------------------------------------------*)
  59. (* last update: april  4th, 1992   -- gregory p. smith      *)
  60. (*----------------------------------------------------------*)
  61. unit eco_mtrx;
  62. {$N+,E+,G+  -- support high precision numbers }
  63.  
  64.  
  65. interface
  66.  
  67.  
  68. type
  69. {$IFDEF HIPREC}  Real = Extended; {$ENDIF}
  70.   MXArray = Array[0..6399] of Real;              { allows 80x80 matrix }
  71.   mxarrptr = ^mxarray;
  72.   mxptr = ^matrix;
  73.   matrix = object
  74.     {------------------- variables -----------------------}
  75.     m     : mxarrptr;                       { matrix data }
  76.     cols,                             { columns in matrix }
  77.     rows  : byte;                        { rows in matrix }
  78.     {------------------- procedures ----------------------}
  79.     constructor init(c, r: byte);     { create the matrix }
  80.     procedure  setelement(c, r: byte; e: real);
  81.     function   getelement(c, r: byte): real;
  82.     procedure  multbyconst(con: real); { mult. by a const. }
  83.     function   determinant: real;
  84.     function   minor(c, r: byte): real;     { matrix minor }
  85.     function   cofactor(c, r: byte): real;  { signed minor }
  86.     function   adjoint: mxptr; { returns ptr to adj matrix }
  87.     function   inverse: mxptr; { returns ptr to inv matrix }
  88.     destructor done;                     { free up memory }
  89.   end; { matrix }
  90.  
  91.  
  92. const
  93.   needmemory = -1; { need memory for temporary matrix. }
  94.   notsquare  = -2; { square matrix required for this operation. }
  95.   noinverse  = -3; { no inverse could be computed. }
  96.   badsizes   = -4; { matrices were not comptiable for multiplication. }
  97.   matherror  : shortint = 0; { holds one of the above error codes. }
  98.  
  99.  
  100.  
  101.   procedure writemx(var out: text; mx: mxptr);
  102.   procedure showmatherror(err: integer);
  103.   function  multmx(a, b: mxptr): mxptr;
  104.  
  105.  
  106.  
  107.  
  108.  
  109. implementation
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116. (*----------------- matrix implementation --------------------------*)
  117.  
  118.   constructor matrix.init(c, r: byte);
  119.   begin
  120.     if c*r*sizeof(real) > sizeof(mxarray) then fail;
  121.     getmem(m, c*r*sizeof(real));
  122.   {$IFDEF HEAPMGR}
  123.     if m = nil then fail;
  124.   {$ENDIF}
  125.     cols := c;
  126.     rows := r;
  127.   end;
  128.  
  129.  
  130.  
  131.   procedure matrix.setelement(c, r: byte; e: real);
  132.   begin  { warning: no bounds checking to see if you're sane... }
  133.     m^[(pred(r)*cols)+pred(c)] := e;
  134.   end;
  135.  
  136.  
  137.  
  138.   function matrix.getelement(c, r: byte): real;
  139.   begin  { warning: no bounds checking to see if you're sane... }
  140.     getelement := m^[(pred(r)*cols)+pred(c)];
  141.   end;
  142.  
  143.  
  144.  
  145.   procedure matrix.multbyconst(con: real);
  146.   var
  147.     t : byte;
  148.   begin
  149.     t := pred(rows * cols);
  150.     for t := pred(rows * cols) downto 0 do
  151.      m^[t] := m^[t] * con;
  152.   end;
  153.   
  154.  
  155.   
  156.   function matrix.determinant: real;
  157.   var
  158.     s   : byte;
  159.     tmp : real;
  160.  
  161.   begin
  162.     if rows <> cols then begin
  163.       matherror := notsquare;
  164.       determinant := 0;
  165.       exit;
  166.     end;
  167.     case rows of
  168.       3..255 : begin { 3x3 and up }
  169.         tmp := 0;
  170.         for s := 1 to cols do tmp := tmp + (m^[pred(s)] * cofactor(s, 1));
  171.         determinant := tmp;
  172.       end; { 3x3 and up }
  173.       2 : begin { 2x2 }  { ((1,1) * (2,2)) - ((1,2) * (2,1)) }
  174.         determinant := (m^[0] * m^[3]) - (m^[2] * m^[1]);
  175.       end; { 2x2 }
  176.       1 : begin
  177.         determinant := m^[0]; { (1,1) }
  178.       end;
  179.     end; { case rows ... }
  180.     matherror := 0;
  181.   end;
  182.   
  183.  
  184.   
  185.   
  186.   
  187.   function matrix.minor(c, r: byte): real;
  188.   var
  189.     tm : matrix;
  190.     x, y,               { indexes to this matrix }
  191.     tx, ty : byte;      { indexes to temp matrix }
  192.   begin
  193.     if (cols <> rows) or (cols < 2) { or (rows < 2) } then begin
  194.       matherror := notsquare;
  195.       minor := 0;
  196.       exit;
  197.     end;
  198.     tm.init(pred(cols), pred(rows));
  199.     { the minor is the determinant of the lower order matrix formed by }
  200.     { excluding the row and column of the element we're computing for. }
  201.     ty := 1;
  202.     for y := 1 to rows do begin        { create lower order matrix }
  203.       tx := 1;
  204.       if y <> r then begin
  205.         for x := 1 to cols do if x <> c then begin        { getelement(x, y) }
  206.           tm.m^[(pred(ty)*tm.cols)+pred(tx)] := m^[(pred(y)*cols)+pred(x)];
  207.           (* tm.setelement(tx, ty, m^[(pred(y)*cols)+pred(x)]); *)
  208.           inc(tx);
  209.         end;
  210.         inc(ty);
  211.       end;
  212.     end;
  213.     minor := tm.determinant;
  214.     tm.done;
  215.     matherror := 0;
  216.   end;
  217.  
  218.  
  219.  
  220.  
  221.   function matrix.cofactor(c, r: byte): real;
  222.   begin
  223.     { cofactor is the signed minor, depending upon whether the sum of }
  224.     { the row and column is even or odd. }
  225.     if odd(c+r) then cofactor := minor(c, r) * -1
  226.      else cofactor := minor(c, r);
  227.   end;
  228.  
  229.  
  230.  
  231.   function matrix.adjoint: mxptr;
  232.   var
  233.     tm   : mxptr;
  234.     x, y : byte;    { index into both matrices }
  235.  
  236.   begin
  237.     if (cols < 2) or (rows < 2) then begin
  238.       matherror := notsquare;
  239.       adjoint := nil;
  240.       exit;
  241.     end;
  242.     new(tm, init(rows, cols));
  243.     {$IFDEF HEAPMGR}
  244.     if tm = nil then begin
  245.       matherror := needmemory;
  246.       adjoint := nil;
  247.       exit;
  248.     end;
  249.     {$ENDIF}
  250.  
  251.     { adjoint matrix'es row elements correspond to the cofactors of the }
  252.     { original matrices column elements.  not fun by hand... ;-}
  253.     for y := 1 to rows do for x := 1 to cols do
  254.       tm^.setelement(x, y, cofactor(y, x));
  255.     adjoint := tm;
  256.     matherror := 0;
  257.   end;
  258.  
  259.  
  260.  
  261.  
  262.   function matrix.inverse: mxptr;
  263.   var    { warning: returns nil for undefined inverses }
  264.     tm  : mxptr;
  265.     det :  real;
  266.  
  267.   begin
  268.     det := determinant;
  269.     if det = 0 then begin
  270.       inverse := nil;
  271.       matherror := noinverse;
  272.       exit;
  273.     end;
  274.     { inverse a is 1/deta * adja }
  275.     tm := adjoint;
  276.     if tm = nil then begin
  277.       inverse := nil;
  278.       exit;
  279.     end;
  280.     tm^.multbyconst(1 / det);
  281.     inverse := tm;
  282.   end;
  283.  
  284.  
  285.  
  286.   destructor matrix.done;
  287.   begin
  288.     freemem(m, cols*rows*sizeof(real));
  289.   end;
  290.  
  291.  
  292.  
  293.  
  294. (*------------- end matrix implementation --------------------------*)
  295.  
  296.  
  297.  
  298.  
  299.   procedure showmatherror(err: integer);
  300.   begin
  301.     write('ERROR: ');
  302.     case err of
  303.     {$IFDEF HEAPMGR}
  304.       needmemory : writeln('Out of memory for temporary matrix!');
  305.     {$ENDIF}
  306.       notsquare  : writeln(
  307.         'Attempted to perform square operation on a rectangular matrix!'
  308.       );
  309.       noinverse  : writeln('Inverse undefined.');
  310.       badsizes   : writeln(
  311.         'Matrices not of compatible sizes to be multiplied!'
  312.       );
  313.     end;
  314.     halt(abs(err));
  315.   end;
  316.  
  317.  
  318.  
  319.  
  320.   procedure writemx(var out: text; mx: mxptr);
  321.   var x, y : byte;
  322.   begin
  323.     with mx^ do for x := 1 to rows do begin
  324.       for y := 1 to cols do write(out,getelement(y, x):10:3);
  325.       writeln(out);
  326.     end;
  327.   end;
  328.  
  329.  
  330.  
  331.  
  332.  
  333.   function multmx(a, b: mxptr): mxptr;
  334.   var
  335.     tm       : mxptr;
  336.     x, y, tx :  byte;
  337.     tmp      :  real;
  338.  
  339.   begin
  340.     if (a^.cols <> b^.rows) then begin
  341.       matherror := badsizes;
  342.       multmx := nil;
  343.       exit;
  344.     end;
  345.     new(tm, init(a^.rows, b^.cols));
  346.     if tm = nil then begin
  347.       matherror := needmemory;
  348.       multmx := nil;
  349.       exit;
  350.     end;
  351.     for x := 1 to b^.cols do for y := 1 to a^.rows do begin
  352.       tmp := 0;
  353.       for tx := 1 to a^.cols { b^.rows } do
  354.       tmp := tmp + a^.getelement(y, tx) * b^.getelement(tx, x);
  355.       tm^.setelement(y, x, tmp);
  356.     end;
  357.     multmx := tm;
  358.   end;
  359.  
  360.  
  361.  
  362. end. { unit }
  363.  
  364.  
  365. ===  hope that works for you.
  366.    << greg smith >>
  367.  
  368.  
  369. ---
  370.  * origin: interconnect - littleton, co. (303)797-0296 (1:104/60.0)
  371. seen-by: 2/777 13/13 28/777 29/777 105/27 42 138/112 234/50 270/18
  372. seen-by: 280/0 283/1 500/0 1 2 3 4 5 7 8 9 13 222 512/0 1 4 8 23 32
  373. seen-by: 512/37 44 45 47 112 133 146 148 149 167 168 172 1007
  374. path: 518 512 1 13/13 138/112 105/27 42 500/1 9 512/0 167 172 172.1
  375.