Contributor: VITUS WAGNER

{
From: "Victor B. Wagner" 
************************************************************
*                   ALGEBRA.PAS                            *
*           a simple matrix algebra unit                   *
*           Turbo Pascal 4.0 or higher                     *
*           Copyright (c) by Vitus Wagner,1990             *
************************************************************
}
unit algebra;
interface
   const MaxN=30;{You can increase it up to 100,not greater
                 but each matrix variable would have size of
                 sqr(MaxN)*sizeof(Real). It is possible to write
                 unit for work with dinamically sized matrices,
                 but i have no needs to do this.
                 You can work with matrices with size less that MaxN,
                 but while you work with this unit you must allocate
                 memory for matrix MaxN x MaxN and leave rest of space
                 unised}
   type vector=array[1..MaxN]of real;
        matrix=array[1..MaxN,1..MaxN]of real;
        sett=set of 1..MaxN;
 var algebrerr:boolean;
 function scalar(a,b:vector;n:integer):real;
 {Scalar multiplication of vectors a and b of n components}
 procedure systeq(a:matrix;b:vector;var x:vector;n:integer);
 { solving n line equation system A*X=B by Gauss method}
 { sets algebrerr to True if system cannot be solved}
 procedure matmult(a,b:matrix;var c:matrix;n:integer);
 { multiplication of two NxN matrixs A and B.Result - matrix C AxB=C}
 procedure matadd(a,b:matrix;var c :matrix;n:integer);
 { addition of two NxN matrixs A+B=C }
 procedure matconst(c:real;a:matrix;var b:matrix;n:integer);
 { multiplication matrix A on constant c  cxA=B }
 procedure matcadd(c1:real;a1:matrix;c2:real;a2:matrix;var b:matrix;n:integer);
 { addition of two NxN matrixs with multiplication each of them on constant
   c1xA1+c2xA2=B }
 procedure matinv(a:matrix;var ainv:matrix;n:integer);
 { inversion of NxN matrix A}
 { sets algebrerr to True if matrix cannot be inverted}
 procedure matvec(a:matrix;b:vector;var c:vector;n:integer);
 { multiplication NxN matrix A to N-component vector B AxB=C}
 function det(a:matrix;n:integer):real;
 { determinant of NxN matrix }
 procedure compress(a:matrix;var b:matrix;n:integer;s:sett);
 { converse triangle matrix to simmetric,exclude rows and columns that is not
   in set s (type sett=set of 0..maxN)}
 function distance(a,b:vector;n:integer):real;
 { Calculate Euclide distantion in N-dimensioned space between A & B }
 Procedure Transpose(var A:Matrix;M,N:Integer);
 { Transpose MxN Matrix. Put result in the same place}
 Procedure EMatrix(var A:Matrix;N:Integer);
 {Fills matrix by 0 and main diagonal by 1}
implementation
 function scalar(a,b:vector;n:integer):real;
  var i:integer;
      r:real;
  begin
   r:=0.0;
   for i:=1 to n do
    r:=r+a[i]*b[i];
   scalar:=r;
  end;
 procedure systeq(a:matrix;b:vector;var x:vector;n:integer);
  var i,j,k:integer;
      max:real;
  begin
  algebrerr:=false;
   { Conversion matrix to triangle }
   for i:=1 to n do
    begin
     max:=abs(a[i,i]);k:=i;
     for j:=succ(i) to n do
      if abs(a[j,i])>max then
       begin
        max:=abs(a[j,i]);k:=j
       end;
      if max<1E-10 then begin algebrerr:=true;exit end;
      if k<>i then
       begin
        for  j:=i to n do
         begin
          max:=a[k,j];
          a[k,j]:=a[i,j];
          a[i,j]:=max;
         end;
        max:=b[k];
        b[k]:=b[i];
        b[i]:=max;
       end;
      for j:=succ(i) to n do
       a[i,j]:=a[i,j]/a[i,i];
       b[i]:=b[i]/a[i,i];
      for j:=succ(i) to n do
       begin
        for k:=succ(i) to n do
         a[j,k]:=a[j,k]-a[i,k]*a[j,i];
        b[j]:=b[j]-b[i]*a[j,i];
       end;
    end;
     { X calculation}
     x[n]:=b[n];
     for i:=pred(n) downto 1 do
      begin
       max:=b[i];
       for j:=succ(i) to n do
        max:=max-a[i,j]*x[j];
       x[i]:=max;
      end;
  end;
 procedure matmult(a,b:matrix;var c:matrix;n:integer);
  var i,j,k:integer;r:real;
  begin
   for i:=1 to n do
    for j:=1 to n do
     begin
      r:=0.0;
      for k:=1 to n do
       r:=r+a[i,k]*b[k,j];
      c[i,j]:=r;
     end;
  end;
 procedure matadd(a,b:matrix;var c :matrix;n:integer);
  var i,j:integer;
  begin
   for i:=1 to n do
    for j:=1 to n do
     c[i,j]:=a[i,j]+b[i,j];
  end;
 procedure matinv(a:matrix;var ainv:matrix;n:integer);
  var i,j,k:integer;
      e:matrix;
      max:real;
  begin
   algebrerr:=false;
   { creating single matrix }
   for i:=1 to n do
    for j:=1 to n do
     e[i,j]:=0.0;
   for i:=1 to n do
    e[i,i]:=1.0;
   { Conversion matrix to triangle }
   for i:=1 to n do
{1} begin
     max:=abs(a[i,i]);k:=i;
     for j:=succ(i) to n do
      if abs(a[j,i])>max then
{2}    begin
        max:=abs(a[j,i]);k:=j
{2}    end;
      if max<1E-10 then begin algebrerr:=true;exit end;
      if k<>i then
{2}    begin
        for  j:=i to n do
{3}      begin
          max:=a[k,j];
          a[k,j]:=a[i,j];
          a[i,j]:=max;
{3}      end;
      for j:=1 to n do
{3}    begin
        max:=e[k,j];
        e[k,j]:=e[i,j];
        e[i,j]:=max;
{3}    end;
{2}   end;
      for j:=succ(i) to n do
       a[i,j]:=a[i,j]/a[i,i];
       for k:=1 to n do
       e[i,k]:=e[i,k]/a[i,i];
      for j:=succ(i) to n do
{2}    begin
        for k:=succ(i) to n do
         a[j,k]:=a[j,k]-a[i,k]*a[j,i];
        for k:=1 to n do
        e[j,k]:=e[j,k]-e[i,k]*a[j,i];
{2}    end;
{1} end;
     { ainv calculation}
    for k:=1 to n do
{1} begin
     ainv[n,k]:=e[n,k];
     for i:=pred(n) downto 1 do
{2}   begin
       max:=e[i,k];
       for j:=succ(i) to n do
        max:=max-a[i,j]*ainv[j,k];
       ainv[i,k]:=max;
{2}   end;
{1}  end;
  end;
 procedure matvec(a:matrix;b:vector;var c:vector;n:integer);
  var i,j:integer;r:real;
  begin
   for i:=1 to n do
    begin
     r:=0.0;
     for j:=1 to n do
      r:=r+a[i,j]*b[j];
     c[i]:=r;
    end;
  end;
 function det(a:matrix;n:integer):real;
  var i,j,k:integer;d:real;
  begin
   for i:=1 to pred(n) do
    begin
     if abs(a[i,i])<1E-10 then begin det:=0.0;exit end;
     for j:=succ(i) to n do
      begin
       d:=a[j,i]/a[i,i];
       for k:=i to n do
        a[j,k]:=a[j,k]-d*a[i,k];
      end;
    end;
   d:=1.0;
   for i:=1 to n do
    d:=d*a[i,i];
   det:=d;
  end;
 procedure matconst(c:real;a:matrix;var b:matrix;n:integer);
 var i,j:integer;
 begin
  for i:=1 to n do
   for j:=1 to n do
    b[i,j]:=c*a[i,j];
 end;
 procedure matcadd(c1:real;a1:matrix;c2:real;a2:matrix;var b:matrix;n:integer);
 var i,j:integer;
 begin
  for i:=1 to n do
   for j:=1 to n do
    b[i,j]:=c1*a1[i,j]+c2*a2[i,j];
 end;
 procedure compress(a:matrix;var b:matrix;n:integer;s:sett);
 var i,j,k,l:integer;
  begin
   k:=1;
   for i:=1 to pred(n) do
    if i in s then
     begin
      l:=1;
      b[k,k]:=a[i,i];
      for j:=succ(i) to n do
       if j in s then
        begin
         b[k,l]:=a[i,j];
         b[l,k]:=a[i,j];
         inc(l);
        end;
      inc(k);
     end;
  end;
 function distance(a,b:vector;n:integer):real;
 var i:integer;r:real;
 begin
  r:=0;
  for i:=1 to n do
   r:=r+sqr(a[i]-b[i]);
  distance:=sqrt(r);
 end;
Procedure Transpose(var A:Matrix;M,N:Integer);
var i,j:Integer;Tmp:Real;
begin
 For i:=1 to n do
  for j:=i+1 to m do
   begin
    Tmp:=A[i,j];
    A[i,j]:=A[j,i];
    A[J,i]:=Tmp;
   end;
end;
Procedure EMatrix(var A:Matrix;N:Integer);
var I:Integer;
begin
  FillChar(A,SizeOf(A),0);
  For i:=1 to n do
   A[i,i]:=1.0;
end;

end.