home *** CD-ROM | disk | FTP | other *** search
- unit MATRIXU;
-
- {by Josh Mitteldorf
- 6800 Scotforth Rd
- Philadelphia, PA 19119
- 70441,1305 }
-
- INTERFACE
- uses CRT;
-
- type float = double;
- floatarray = array[0..99] of float;
- vector = ^floatarray;
- matrix = ^floatarray;
-
- {You can change the definition of float above, to real or single or extended,
- and all computations will be to the specified precision. You must change to
- float = real in order to run this unit without a coprocessor.
-
- In all these procedures and functions, the last argument d is the dimension.
- All matrices are square, of dimension d x d. Everything is accessed as a
- pointer in order to facilitate the flexibility of being able to specify d when
- the procedure is called. Thus matrix and vector are just two different names
- for the same thing, namely a pointer to array of type float.
-
- The calling unit may be structured as follows:
-
- const n=4;
-
- type float=real;
- vector=array[1..n] of float;
- matrix=array[1..n] of vector;
-
- var x,y :vector;
- z :matrix;
-
- ...
-
- Prod(addr(z),addr(x),addr(y));
- ...
-
- Then the element z[i,j] in the calling unit becomes a^[i*(d-1)+j] in the
- present unit.
-
- CAUTION: You can't declare the size of a matrix larger than what you
- actually use as dimension in calling matrix procedures from this
- unit. In other words, the constant n in the above example
- MUST be used as d in all calls to matrix functions in this unit.
- (This is so that the elements of the matrix are all contiguous
- in memory.) For calls to functions that involve vectors only,
- you may specify any d you want.
-
- }
-
- procedure ScalarMult(a :matrix; s :float; b: matrix; d:integer);
- {Multiplies matrix a by scalar s to give matrix b}
- procedure ScalarMultV( a :vector; s :float; b :vector; d:integer);
- {Multiplies vector a by scalar s to give vector b}
- procedure VecSum( a,b,c :vector; d:integer);
- {Adds vector a to vector b to give vector c}
- procedure VecDif( a,b,c :vector; d:integer);
- {Subtracts vector b from vector a to give vector c}
- procedure Diadic( a,b :vector; c:matrix; d:integer);
- {Multiplies every element of vector a by every element of b
- to give the symmetric matrix c.}
- procedure VecPrint ( v:vector; d: integer);
- {Prints a vector to the screen in one.}
- procedure MatPrint ( m: matrix; d:integer);
- {Prints a matrix to the screen in one.}
- procedure Transpose( a :matrix; b :matrix; d:integer);
- {Transposes b[i,j]:=a[j,i].}
- procedure MatSum( a,b :matrix; c :matrix; d:integer);
- {Adds matrix a to matrix b to give matrix c.}
- procedure MatDif( a,b :matrix; c :matrix; d:integer);
- {Subtracts matrix b from matrix a to give matrix c.}
- procedure Cross( a,b,c :vector);
- {Vector c is the cross product a x c. (Only makes sense for d=3.) }
- procedure Prod( a:matrix; b,c :vector; d :integer);
- {Matrix a is multiplied by vector b to give vector c.}
- procedure MatProd( a,b,c :matrix; d:integer);
- {Matrix a is multiplied by matrix b to give matrix c.}
- procedure Inverse( a,b :matrix; d :integer);
- {Matrix b is the inverse of matrix a.}
- procedure Solve( a :matrix; b,c :vector; d :integer);
- {solves a.c=b for c, where a is a matrix and b and c are vectors.}
- procedure MatQuot( a,b,c :matrix; d:integer);
- {Divides matrix a by matrix b to give matrix c.}
- function Dot( a,b :vector; d:integer):float;
- {Returns the scalar product of vectors a and b.}
- function Mag( a: vector; d:integer):float;
- {Returns the sqrt of the sum of the squares of elements of a.
- To obtain the magnitude of a square matrix, call Mag with last
- argument = d².}
- function Det(aa:matrix; d :integer):float;
- {Returns the determinant of matrix aa.}
-
- IMPLEMENTATION
-
- procedure ScalarMult;
- var i,j :integer;
- begin
- for i:=0 to pred(d) do
- for j:=0 to pred(d) do
- b^[d*i+j]:=a^[d*i+j]*s;
- end;
-
- procedure ScalarMultV;
- var i :integer;
- begin
- for i:=0 to pred(d) do b^[i]:=a^[i]*s;
- end;
-
- procedure VecSum;
- var i :integer;
- begin
- for i:=0 to pred(d) do c^[i]:=a^[i]+b^[i];
- end;
-
- procedure VecDif;
- var i :integer;
- begin
- for i:=0 to pred(d) do c^[i]:=a^[i]-b^[i];
- end;
-
- procedure Diadic;
- var i,j :integer;
- begin
- for i:=0 to pred(d) do
- for j:=0 to pred(d) do
- c^[d*i+j]:=a^[i]*b^[j];
- end;
-
- procedure VecPrint;
- var i: integer;
- begin
- for i:=0 to pred(d) do write(v^[i]:7:4,' ');
- writeln;
- end;
-
- procedure MatPrint;
- var i,j: integer;
- begin
- for i:=0 to pred(d) do begin
- for j:=0 to pred(d) do write(m^[d*i+j]:7:4,' ');
- writeln;
- end;
- end;
-
- procedure Transpose;
- var i,j: integer;
- begin
- for i:=0 to pred(d) do
- for j:=0 to pred(d) do b^[d*i+j]:=a^[j*d+i];
- end;
-
- function Dot;
- var i :integer; partial :float;
- begin
- partial:=0;
- for i:=0 to pred(d) do partial:=partial+a^[i]*b^[i];
- dot:= partial;
- end;
-
- function Mag;
- begin
- Mag:=sqrt(Dot(a,a,d));
- end;
-
- procedure MatSum;
- var i,j :integer;
- begin
- for i:=1 to d do
- for j:=1 to d do
- c^[d*i+j]:=a^[d*i+j]+b^[d*i+j];
- end;
-
- procedure MatDif;
- var i,j :integer;
- begin
- for i:=0 to pred(d) do
- for j:=0 to pred(d) do
- c^[d*i+j]:=a^[d*i+j]-b^[d*i+j];
- end;
-
- procedure Cross;
- begin
- c^[1]:=a^[2]*b^[3] - a^[3]*b^[2];
- c^[2]:=a^[3]*b^[1] - a^[1]*b^[3];
- c^[3]:=a^[1]*b^[2] - a^[2]*b^[1];
- end;
-
- procedure Prod;
- var i,j,d1 :integer; { Multiplies square matrix a by vector b }
- sum :float; { to give vector c }
- size :word;
-
- begin
- d1:=pred(d);
- size:=d*sizeof(float);
- for i:=0 to d1 do begin
- sum:=0;
- for j:=0 to d1 do sum:=sum+b^[j]*a^[d*i+j];
- c^[i]:=sum;
- end;
- end;
-
- function Det;
- var i,j,k :integer;
- wr :float;
- a :matrix;
- size :word;
- begin
- if (d>3) then begin
- size:=sqr(d)*sizeof(float);
- GetMem(a,size);
- move(aa^,a^,size);
- for i:=0 to d-2 do begin
- for j:= succ(i) to pred(d) do begin
- wr:=a^[i*d+i];
- if (wr=0) then begin det:=0; exit end;
- wr:=a^[j*d+i]/wr;
- for k:= succ(i) to pred(d) do a^[j*d+k]:= a^[j*d+k] - a^[i*d+k]*wr;
- end;
- end;
- wr:=a^[0];
- for i:=1 to pred(d) do wr:=wr*a^[i*d+i];
- Det:=wr;
- FreeMem(a,size);
- end
- else if (d=3) then Det:= aa^[0]*aa^[4]*aa^[8] +aa^[1]*aa^[5]*aa^[6] +aa^[2]*aa^[3]*aa^[7]
- -aa^[0]*aa^[7]*aa^[5] -aa^[1]*aa^[3]*aa^[8] -aa^[2]*aa^[4]*aa^[6]
- else if (d=2) then Det:=aa^[0]*aa^[3] - aa^[1]*aa^[2]
- else if (d=1) then Det:=aa^[0]
- else writeln('ERROR: DETERMINANT OF MATRIX OF ORDER ',d);
- end;
-
- {
- THIS FUNCTION works fine but takes time proportional to factorial d,
- so it's a useless mathematical curiosity.
- The function above that replaces it takes time proportional to d^3.
- function Det;
- var minor :matrix;
- partial :float;
- i,j,dmin,plusminus :integer;
- size :word;
-
- begin
- size:=sqr(pred(d))*sizeof(float));
- GetMem(minor,size);
- dmin:=pred(d);
- if (d>3) then begin
- partial:=0;
- plusminus:=1;
- minor:=a^;
- for i:=d downto 1 do begin
- partial:=partial+plusminus*a^[i*d+d]*det(minor,dmin);
- plusminus:=-plusminus;
- if i>1 then minor[pred(i)]:=a^[i];
- end;
- Det:=partial;
- end
- else if (d=3) then
- Det:= a^[1*d+1]*a^[2*d+2]*a^[3*d+3] +a^[1*d+2]*a^[2*d+3]*a^[3*d+1] +a^[1*d+3]*a^[2*d+1]*a^[3*d+2]
- -a^[1*d+1]*a^[2*d+3]*a^[3*d+2] -a^[1*d+2]*a^[2*d+1]*a^[3*d+3] -a^[1*d+3]*a^[2*d+2]*a^[3*d+1]
- else if (d=2) then Det:=a^[1*d+1]*a^[2*d+2] - a^[1*d+2]*a^[2*d+1]
- else if (d=1) then Det:=a^[1*d+1]
- else writeln('ERROR: DETERMINANT OF MATRIX OF ORDER ',d);
- FreeMem(minor,size);
- end;
- }
- procedure MatProd;
- var i,j,k,pd :integer;
- sum :float;
- begin
- pd:=pred(d);
- for i:=0 to pd do
- for j:=0 to pd do begin
- sum:=0;
- for k:=0 to pd do sum:=sum + a^[i*d+k]*b^[k*d+j];
- c^[i*d+j]:=sum;
- end;
- end;
-
- procedure Inverse;
- var determinant :float;
- minor :matrix;
- ai :matrix;
- plusminus,i,j,ii,jj,d1,d2 :integer;
- flsize,sqsize,dsize,d1size,element :word;
- ki :char;
-
- begin
- determinant:= det(a,d);
- if (determinant=0) then writeln('Error: inverse of singular matrix.')
- else begin
- flsize:=sizeof(float);
- dsize:=d*flsize; {1 row of matrix}
- d1size:=dsize - flsize; {1 row of submatrix}
- sqsize:=d1*d1size; {Entire submatrix}
- GetMem(minor,sqsize);
- d1:=pred(d);
- d2:=pred(d1);
- for i:=0 to d1 do
- for j:=0 to d1 do begin
- {First load minor^ with the minor of [i,j]}
- for ii:=0 to d2 do
- for jj:=0 to d2 do begin
- element:=ii*d+jj;
- if (ii>=i) then element:=element+d;
- if (jj>=j) then inc(element);
- minor^[ii*d1+jj]:=a^[element];
- end;
- {writeln('Minor of ',i,',',j,':'); MatPrint(minor,d1); writeln; ki:=readkey;}
- {Then take the determinant of minor^. Note that b^[i,j] is transpose
- of position [j,i] of which determinant is taken.}
- if ((i xor j) and 1 =0) then plusminus:=1 else plusminus:=-1;
- b^[j*d+i]:=plusminus*Det(minor,d1) / determinant;
- end;
- FreeMem(minor,sqsize);
- end;
- end;
-
- procedure Solve;
- var aa :matrix;
- i,j :integer;
- det0 :float;
- size,d1 :word;
- begin
- det0:=Det(a,d);
- if (det0=0) then writeln('ERROR: Singular argument in SOLVE.') else begin
- size:=sqr(d)*sizeof(float);
- GetMem(aa,size);
- d1:=pred(d);
- for i:=0 to d1 do begin
- move(a^,aa^,size);
- for j:=0 to d1 do aa^[j*d+i]:=b^[j];
- c^[i]:=Det(aa,d)/det0;
- end;
- FreeMem(aa,size);
- end;
- end;
-
- procedure MatQuot;
- var bi :matrix;
- i,j :integer;
- size :word;
- begin
- size:=sqr(d)*sizeof(float);
- GetMem(bi,size);
- Inverse(b,bi,d);
- MatProd(bi,a,c,d);
- FreeMem(bi,size);
- end;
-
- end. {of MATRIX unit}