(* Copyright (C) 1992, Digital Equipment Corporation                         *)
(* All rights reserved.                                                      *)
(* See the file COPYRIGHT for a full description.                            *)
(*                                                                           *)
(* Created on Sep 15 1988 by Jorge Stolfi                      *)
(* Last modified on Tue Jun 16 18:29:57 PDT 1992 by muller     *)
(*      modified on Fri Nov 22 20:20:23 PST 1991 by stolfi     *)
(*      modified on Wed Jan  3 21:52:03 1990 by harrison       *)

MODULE R4x4;

IMPORT R4;

(********************************************************************)
(*                                                                  *)
(* WARNING: DO NOT EDIT THIS FILE.  IT WAS GENERATED MECHANICALLY.  *)
(* See the  Makefile for more details.                              *)
(*                                                                  *)
(********************************************************************)

(* TO DO : Use double precision for all dot/wedge products. *)

(* TO DO : Write a better Inv, Det; write Adjoint, Cofactors *)

PROCEDURE FromRows(READONLY p0, p1, p2, p3: R4.T): Matrix =
  VAR A: Matrix;
  BEGIN
    FOR i := 0 TO 3 DO
      A[0,i] := p0[i];
      A[1,i] := p1[i];

      A[2,i] := p2[i];

      A[3,i] := p3[i];

    END;
    RETURN A
  END FromRows;

PROCEDURE Equal (READONLY A, B: Matrix): BOOLEAN =
  BEGIN
    FOR i := 0 TO 3 DO
      FOR j := 0 TO 3 DO
        IF A[i,j] # B[i,j] THEN RETURN FALSE END;
      END
    END;
    RETURN TRUE;
  END Equal;

PROCEDURE Zero (): Matrix =
  VAR A: Matrix;
  BEGIN
    FOR i := 0 TO 3 DO
      FOR j := 0 TO 3 DO
        A[i,j] := 0.0
      END
    END;
    RETURN A
  END Zero;

PROCEDURE Identity (): Matrix =
  VAR A: Matrix;
  BEGIN
    FOR i := 0 TO 3 DO
      FOR j := 0 TO 3 DO
        IF i = j THEN A[i,j] := 1.0 ELSE A[i,j] := 0.0 END
      END
    END;
    RETURN A
  END Identity;

PROCEDURE Scale (alpha: REAL; READONLY A: Matrix): Matrix =
  VAR B: Matrix;
  BEGIN
    FOR i := 0 TO 3 DO
      FOR j := 0 TO 3 DO
        B[i,j] := alpha * A[i,j]
      END
    END;
    RETURN B
  END Scale;

PROCEDURE Add (READONLY A, B: Matrix): Matrix =
  VAR C: Matrix;
  BEGIN
    FOR i := 0 TO 3 DO
      FOR j := 0 TO 3 DO
        C[i,j] := A[i,j] + B[i,j]
      END
    END;
    RETURN C
  END Add;

PROCEDURE Sub (READONLY A, B: Matrix): Matrix =
  VAR C: Matrix;
  BEGIN
    FOR i := 0 TO 3 DO
      FOR j := 0 TO 3 DO
        C[i,j] := A[i,j] - B[i,j]
      END
    END;
    RETURN C
  END Sub;

PROCEDURE Minus (READONLY A: Matrix): Matrix =
  VAR B: Matrix;
  BEGIN
    FOR i := 0 TO 3 DO
      FOR j := 0 TO 3 DO
        B[i,j] := - A[i,j]
      END
    END;
    RETURN B
  END Minus;

PROCEDURE Map (READONLY p: R4.T; READONLY A: Matrix): R4.T =
  VAR rr: R4.T;

  BEGIN

    rr[0] := FLOAT(
        FLOAT(p[0], LONGREAL)*FLOAT(A[0][0], LONGREAL)
      + FLOAT(p[1], LONGREAL)*FLOAT(A[1][0], LONGREAL)
      + FLOAT(p[2], LONGREAL)*FLOAT(A[2][0], LONGREAL)
      + FLOAT(p[3], LONGREAL)*FLOAT(A[3][0], LONGREAL)
    );
    rr[1] := FLOAT(
        FLOAT(p[0], LONGREAL)*FLOAT(A[0][1], LONGREAL)
      + FLOAT(p[1], LONGREAL)*FLOAT(A[1][1], LONGREAL)
      + FLOAT(p[2], LONGREAL)*FLOAT(A[2][1], LONGREAL)
      + FLOAT(p[3], LONGREAL)*FLOAT(A[3][1], LONGREAL)
    );
    rr[2] := FLOAT(
        FLOAT(p[0], LONGREAL)*FLOAT(A[0][2], LONGREAL)
      + FLOAT(p[1], LONGREAL)*FLOAT(A[1][2], LONGREAL)
      + FLOAT(p[2], LONGREAL)*FLOAT(A[2][2], LONGREAL)
      + FLOAT(p[3], LONGREAL)*FLOAT(A[3][2], LONGREAL)
    );
    rr[3] := FLOAT(
        FLOAT(p[0], LONGREAL)*FLOAT(A[0][3], LONGREAL)
      + FLOAT(p[1], LONGREAL)*FLOAT(A[1][3], LONGREAL)
      + FLOAT(p[2], LONGREAL)*FLOAT(A[2][3], LONGREAL)
      + FLOAT(p[3], LONGREAL)*FLOAT(A[3][3], LONGREAL)
    );

    RETURN rr
  END Map;

PROCEDURE Transpose (READONLY A: Matrix): Matrix =
  VAR B: Matrix;
  BEGIN
    FOR i := 0 TO 3 DO
      FOR j := 0 TO 3 DO
        B[i,j] := A[j,i]
      END
    END;
    RETURN B
  END Transpose;

PROCEDURE TrMap (READONLY A: Matrix; READONLY p: R4.T): R4.T =
  VAR rr: R4.T;

  BEGIN

    rr[0] := FLOAT(
        FLOAT(A[0][0], LONGREAL)*FLOAT(p[0], LONGREAL)
      + FLOAT(A[0][1], LONGREAL)*FLOAT(p[1], LONGREAL)
      + FLOAT(A[0][2], LONGREAL)*FLOAT(p[2], LONGREAL)
      + FLOAT(A[0][3], LONGREAL)*FLOAT(p[3], LONGREAL)
    );
    rr[1] := FLOAT(
        FLOAT(A[1][0], LONGREAL)*FLOAT(p[0], LONGREAL)
      + FLOAT(A[1][1], LONGREAL)*FLOAT(p[1], LONGREAL)
      + FLOAT(A[1][2], LONGREAL)*FLOAT(p[2], LONGREAL)
      + FLOAT(A[1][3], LONGREAL)*FLOAT(p[3], LONGREAL)
    );
    rr[2] := FLOAT(
        FLOAT(A[2][0], LONGREAL)*FLOAT(p[0], LONGREAL)
      + FLOAT(A[2][1], LONGREAL)*FLOAT(p[1], LONGREAL)
      + FLOAT(A[2][2], LONGREAL)*FLOAT(p[2], LONGREAL)
      + FLOAT(A[2][3], LONGREAL)*FLOAT(p[3], LONGREAL)
    );
    rr[3] := FLOAT(
        FLOAT(A[3][0], LONGREAL)*FLOAT(p[0], LONGREAL)
      + FLOAT(A[3][1], LONGREAL)*FLOAT(p[1], LONGREAL)
      + FLOAT(A[3][2], LONGREAL)*FLOAT(p[2], LONGREAL)
      + FLOAT(A[3][3], LONGREAL)*FLOAT(p[3], LONGREAL)
    );

    RETURN rr
  END TrMap;

PROCEDURE Row(READONLY A: Matrix; i: Axis): R4.T =
  VAR r: R4.T;
  BEGIN

    FOR j := 0 TO 3 DO r[j] := A[i,j] END;

    RETURN r
  END Row;

PROCEDURE Col(READONLY A: Matrix; j: Axis): R4.T =
  VAR r: R4.T;
  BEGIN

    FOR i := 0 TO 3 DO r[i] := A[i,j] END;

    RETURN r
  END Col;

PROCEDURE Diagonal(READONLY A: Matrix): R4.T =
  VAR r: R4.T;
  BEGIN

    FOR i := 0 TO 3 DO r[i] := A[i,i] END;

    RETURN r
  END Diagonal;

PROCEDURE Mul (READONLY A, B: Matrix): Matrix =
  VAR MN: Matrix;
      s: LONGREAL;
  BEGIN
    FOR i := 0 TO 3 DO
      FOR j := 0 TO 3 DO
        s := 0.0D0;
        FOR t := 0 TO 3 DO
          s := s + FLOAT(A[i,t], LONGREAL) * FLOAT(B[t,j], LONGREAL)
        END;
        MN [i,j] := FLOAT(s)
      END;
    END;
    RETURN MN
  END Mul;

PROCEDURE Triangularize(VAR A, B: Matrix; useB: BOOLEAN) =
  VAR ipiv: NAT;
      abspiv, piv, c, t: REAL;
  BEGIN
    FOR i := 0 TO 2 DO 
      (* Find pivot row *)
      abspiv := ABS(A[i,i]); ipiv := i;
      FOR k := i + 1 TO 3 DO
        c := ABS(A[k,i]);
        IF c > abspiv THEN abspiv := c; ipiv := k END
      END;
      (* Permute equations to bring pivot to A[i,i] *)
      IF ipiv # i THEN
        FOR j := i TO 3 DO
          t := A[i,j]; A[i,j] := A[ipiv,j]; A[ipiv,j] := - t
        END;
        IF useB THEN
          FOR j := 0 TO 3 DO
            t := B[i,j]; B[i,j] := B[ipiv,j]; B[ipiv,j] := - t
          END;
        END;
      END;
      (* Eliminate variable i from equations i + 1..3 *)
      IF abspiv > 0.0 THEN
        piv := A[i,i];
        FOR k := i + 1 TO 3 DO
          c := A[k,i]/piv;
          IF c # 0.0 THEN
            A[k,i] := 0.0;
            FOR j := i + 1 TO 3 DO
              A[k,j] := A[k,j] - c * A[i,j]
            END;
            IF useB THEN
              FOR j := 0 TO 3 DO
                B[k,j] := B[k,j] - c * B[i,j]
              END;
            END;
          END;
        END;
      END;
    END;
  END Triangularize;

PROCEDURE Inv(READONLY M: Matrix): Matrix =
  VAR A, B: Matrix;
      t, diag: REAL;
  BEGIN
    (* !!! Needs improvement !!! *)
    A := M;
    B := Identity();
    Triangularize(A,B, TRUE);
    (* Now A is upper triangular; compute B := Inverse(A)*B *)
    FOR i := 3 TO 0 BY -1 DO
      diag := A[i,i];
      FOR j := 0 TO 3 DO
        (* Back-substitute known variables: *)
        t := B[i,j];
        FOR k := i + 1 TO 3 DO
          t := t - A[i,k] * B[k,j]
        END;
        (* Divide by diagonal element, checking for overflow: *)
        B[i,j] := t/diag
      END;
    END;
    RETURN B
  END Inv;

PROCEDURE Det (READONLY A: Matrix): REAL =
  (* !!!!! Should use double precision !!!!! *)
  BEGIN

    RETURN
      + (A[0,0]*A[1,1] - A[0,1]*A[1,0]) * (A[2,2]*A[3,3] - A[2,3]*A[3,2])
      - (A[0,0]*A[1,2] - A[0,2]*A[1,0]) * (A[2,1]*A[3,3] - A[2,3]*A[3,1])
      + (A[0,0]*A[1,3] - A[0,3]*A[1,0]) * (A[2,1]*A[3,2] - A[2,2]*A[3,1])
      + (A[0,1]*A[1,2] - A[0,2]*A[1,1]) * (A[2,0]*A[3,3] - A[2,3]*A[3,0])
      - (A[0,1]*A[1,3] - A[0,3]*A[1,1]) * (A[2,0]*A[3,2] - A[2,2]*A[3,0])
      + (A[0,2]*A[1,3] - A[0,3]*A[1,2]) * (A[2,0]*A[3,1] - A[2,1]*A[3,0])

  END Det;

BEGIN
END R4x4.

