MODULE LR3 EXPORTS LR3, LR3Extras;
(* 
  Hand-optimized implementation of the interfaces "LR3" and "LR3Extras".

  Created by J. Stolfi, with contributions by
  M. C. Carrard and R. L. W. Liesenfeld. *)

IMPORT LR3Rep, LRN, Math, Wr, Thread, Random, GaussRandom;

PROCEDURE Zero(): T =
  BEGIN 
    RETURN T{0.0d0, 0.0d0, 0.0d0}
  END Zero;
    
PROCEDURE All(x: LONGREAL): T =
  BEGIN
    RETURN T{x, x, x}
  END All;

PROCEDURE Axis(i: [0..N-1]): T =
  VAR r: T := T{0.0d0, 0.0d0, 0.0d0};
  BEGIN
    r[i] := 1.0d0;
    RETURN r
  END Axis;

PROCEDURE Get(READONLY a: T; i: [0..N-1]): LONGREAL =
  BEGIN
    RETURN a[i]
  END Get;
    
PROCEDURE Set(VAR a: T; i: [0..N-1]; x: LONGREAL) =
  BEGIN
    a[i] := x
  END Set;

PROCEDURE Add(READONLY a, b: T): T =
  BEGIN
    RETURN T{a[0] + b[0], a[1] + b[1], a[2] + b[2]}
  END Add;

PROCEDURE Sub(READONLY a, b: T): T =
  BEGIN
    RETURN T{a[0] - b[0], a[1] - b[1], a[2] - b[2]}
  END Sub;

PROCEDURE Neg(READONLY a: T): T =
  BEGIN
    RETURN T{- a[0], - a[1], - a[2]}
  END Neg;

PROCEDURE Scale(s: LONGREAL; READONLY a: T): T = 
  BEGIN
    WITH
      a0 = s * a[0],
      a1 = s * a[1],
      a2 = s * a[2]
    DO
      RETURN T{a0, a1, a2}
    END
  END Scale;

PROCEDURE Weigh(READONLY w: LongRealT; READONLY a: T): T =
  BEGIN
    RETURN T{a[0] * w[0], a[1] * w[1], a[2] * w[2]}
  END Weigh;

PROCEDURE Mix(s: LONGREAL; READONLY a: T; t: LONGREAL; READONLY b: T): T = 
  BEGIN
    WITH
      c0 = s * a[0] + t * b[0],
      c1 = s * a[1] + t * b[1],
      c2 = s * a[2] + t * b[2]
    DO
      RETURN T{c0, c1, c2}
    END
  END Mix;

PROCEDURE Norm(READONLY a: T): LONGREAL =
  BEGIN
    WITH
      a0 = a[0],
      a1 = a[1],
      a2 = a[2],
      norm = Math.hypot(Math.hypot(a0, a1), a2)
    DO
      RETURN norm
    END
  END Norm;

PROCEDURE NormSqr(READONLY a: T): LONGREAL =
  BEGIN
    WITH
      a0 = a[0],
      a1 = a[1],
      a2 = a[2],
      normSqr = a0*a0 + a1*a1 + a2*a2
    DO
      RETURN normSqr
    END
  END NormSqr;

PROCEDURE Dist(READONLY a, b: T): LONGREAL =
  BEGIN
    WITH
      t0 = a[0] - b[0],
      t1 = a[1] - b[1],
      t2 = a[2] - b[2],
      dist = Math.hypot(Math.hypot(t0, t1), t2)
    DO
      RETURN dist
    END
  END Dist;
    
PROCEDURE DistSqr(READONLY a, b: T): LONGREAL =
  BEGIN
    WITH
      t0 = a[0] - b[0],
      t1 = a[1] - b[1],
      t2 = a[2] - b[2],
      distSqr = t0*t0 + t1*t1 + t2*t2
    DO
      RETURN distSqr
    END
  END DistSqr;

PROCEDURE LInfNorm(READONLY a: T): LONGREAL =
  BEGIN
    WITH 
      norm = MAX(MAX(ABS(a[0]), ABS(a[1])), ABS(a[2]))
    DO
      RETURN norm
    END
  END LInfNorm;  

PROCEDURE LInfDist(READONLY a, b: T): LONGREAL =
  BEGIN
    WITH 
      dist = MAX(ABS(a[0] - b[0]), MAX(ABS(a[1] - b[1]), ABS(a[2] - b[2])))
    DO
      RETURN dist
    END
  END LInfDist;  

PROCEDURE Dir(READONLY a: T): T =
  BEGIN
    WITH
      a0 = a[0],
      a1 = a[1],
      a2 = a[2],
      norm = Math.hypot(Math.hypot(a0, a1), a2)
    DO
      RETURN T{a0/norm, a1/norm, a2/norm}
    END
  END Dir; 

PROCEDURE LInfDir(READONLY a: T): T =
  BEGIN
    WITH 
      norm = MAX(MAX(ABS(a[0]), ABS(a[1])), ABS(a[2]))
    DO
      RETURN T{a[0]/norm, a[1]/norm, a[2]/norm}
    END
  END LInfDir;  

PROCEDURE Dot(READONLY a, b: T): LONGREAL =
  BEGIN
    WITH
      a0 = a[0],
      a1 = a[1],
      a2 = a[2],
               
      b0 = b[0],
      b1 = b[1],
      b2 = b[2],

      dot = a0*b0 + a1*b1 + a2*b2
    DO
      RETURN dot
    END
  END Dot;

PROCEDURE Cos(READONLY a, b: T): LONGREAL =
  BEGIN
    WITH
      a0 = a[0],
      a1 = a[1],
      a2 = a[2],
           
      b0 = b[0],
      b1 = b[1],
      b2 = b[2],

      aa = a0*a0 + a1*a1 + a2*a2,
      bb = b0*b0 + b1*b1 + b2*b2,
      ab = a0*b0 + a1*b1 + a2*b2,
      cos = ab/(Math.sqrt(aa)*Math.sqrt(bb))
    DO
      RETURN cos
    END
  END Cos;

PROCEDURE Sin(READONLY a, b: T): LONGREAL =
  BEGIN 
    WITH 
      a0 = a[0],
      a1 = a[1],
      a2 = a[2],
               
      b0 = b[0],
      b1 = b[1],
      b2 = b[2],
      
      c0 = a1*b2 - a2*b1,
      c1 = a2*b1 - a1*b2,
      c2 = a0*b1 - a1*b0,

      aa = a0*a0 + a1*a1 + a2*a2,
      bb = b0*b0 + b1*b1 + b2*b2,
      cc = c0*c0 + c1*c1 + c2*c2,
      sin = Math.sqrt(cc/aa/bb)
    DO
      RETURN sin
    END
  END Sin;

PROCEDURE Det(READONLY a, b, c: T): LONGREAL =
  BEGIN
    WITH
      a_0 = a[0],
      a_1 = a[1],
      a_2 = a[2],
                
      b_0 = b[0],
      b_1 = b[1],
      b_2 = b[2],
                
      c_0 = c[0],
      c_1 = c[1],
      c_2 = c[2],
      
      ab_01 = a_0 * b_1 - a_1 * b_0,
      ab_02 = a_0 * b_2 - a_2 * b_0,
      ab_12 = a_1 * b_2 - a_2 * b_1,

      t = + ab_01 * c_2 - ab_02 * c_1 + ab_12 * c_0
    DO
      RETURN t
    END
  END Det;  

PROCEDURE Cross(READONLY a, b: T): T =
  BEGIN
    WITH
      a0 = a[0],
      a1 = a[1],
      a2 = a[2],
               
      b0 = b[0],
      b1 = b[1],
      b2 = b[2],

      t01 = a0*b1 - a1*b0,
      t02 = a0*b2 - a2*b0,
      t12 = a1*b2 - a2*b1
    DO
      RETURN T{+ t12, - t02, + t01}
    END;
  END Cross;
  
PROCEDURE Project(READONLY a, u: T): T =
  BEGIN
    WITH
      a0 = a[0],
      a1 = a[1],
      a2 = a[2],
               
      u0 = u[0],
      u1 = u[1],
      u2 = u[2],

      sau = a0*u0 + a1*u1 + a2*u2
    DO
      IF sau = 0.0d0 THEN
        RETURN T{0.0d0, 0.0d0, 0.0d0}
      ELSE
        WITH
          suu = u0*u0 + u1*u1 + u2*u2,
          c = sau/suu
        DO
          RETURN T{c*u0, c*u1, c*u2}
        END
      END
    END;
  END Project;
  
PROCEDURE Orthize(READONLY a, u: T): T =
  BEGIN
    WITH
      u0 = u[0],
      u1 = u[1],
      u2 = u[2],

      suu = u0*u0 + u1*u1 + u2*u2
    DO
      IF suu = 0.0d0 THEN
        RETURN a
      ELSE
        WITH
          a0 = a[0],
          a1 = a[1],
          a2 = a[2],

          sau = a0*u0 + a1*u1 + a2*u2
        DO
          IF sau = 0.0d0 THEN
            RETURN a
          ELSE
            WITH
              c = sau/suu
            DO
              RETURN T{a0-c*u0, a1-c*u1, a2-c*u2}
            END
          END
        END
      END
    END;
  END Orthize;
  
PROCEDURE ToReal(READONLY a: T): RealT =
  BEGIN
    RETURN RealT{
      FLOAT(a[0], REAL),
      FLOAT(a[1], REAL),
      FLOAT(a[2], REAL)
    }
  END ToReal;
  
PROCEDURE FromReal(READONLY a: RealT): T =
  BEGIN
    RETURN T{
      FLOAT(a[0], LONGREAL),
      FLOAT(a[1], LONGREAL),
      FLOAT(a[2], LONGREAL)
    }
  END FromReal;

PROCEDURE ToLongReal(READONLY a: T): LongRealT =
  BEGIN RETURN a END ToLongReal;
  
PROCEDURE FromLongReal(READONLY a: LongRealT): T =
  BEGIN RETURN a END FromLongReal;

PROCEDURE URandom(rnd: Random.T; min, max: LONGREAL): T =
  VAR r: T;
  BEGIN
    FOR i := 0 TO N-1 DO
      r[i] := rnd.longreal(min, max)
    END;
    RETURN r
  END URandom;
    
PROCEDURE NRandom(rnd: Random.T; avg, dev: LONGREAL): T =
  VAR r: T;
  BEGIN
    FOR i := 0 TO N-1 DO
      r[i] := avg + dev * GaussRandom.LongReal(rnd)
    END;
    RETURN r
  END NRandom;

PROCEDURE Print(
    wr: Wr.T;
    READONLY a: T;
    lp := "("; sep := " "; rp := ")";
    fmt: PROCEDURE (x: ElemT): TEXT := LR3Rep.DefaultElemFmt;
  ) RAISES {Wr.Failure, Thread.Alerted} =
  BEGIN
    LRN.Print(wr, a, lp, sep, rp, fmt)
  END Print;

PROCEDURE ToText(READONLY a: T): TEXT =
  BEGIN
    RETURN LRN.ToText(a)
  END ToText;

BEGIN 
END LR3.