MODULE LR2 EXPORTS LR2, LR2Extras;
(* 
  Hand-optimized implementation of the interfaces "LR2" and "LR2Extras".
  
  Created by J. Stolfi, with contributions by
  M. C. Carrard and R. L. W. Liesenfeld. *)

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

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

PROCEDURE All(x: LONGREAL): T =
  BEGIN
    RETURN T{x, x}
  END All;
  
PROCEDURE Axis(i: [0..N-1]): T =
  VAR r: T := T{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]}
  END Add;

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

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

PROCEDURE Scale(s: LONGREAL; READONLY a: T): T = 
  BEGIN
    RETURN T{s*a[0], s*a[1]}
  END Scale;

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

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

PROCEDURE Norm(READONLY a: T): LONGREAL =
  BEGIN
    RETURN Math.hypot(a[0], a[1])
  END Norm;

PROCEDURE NormSqr(READONLY a: T): LONGREAL =
  BEGIN
    WITH 
      a0 = a[0],
      a1 = a[1],
      normSqr = a0*a0 + a1*a1 
    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],
      dist = Math.hypot(t0, t1)
    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],
      distSqr = t0*t0 + t1*t1
    DO
      RETURN distSqr
    END
  END DistSqr;
  
PROCEDURE Dir(READONLY a: T): T =
  BEGIN
    WITH
      a0 = a[0],
      a1 = a[1],
      norm = Math.hypot(a0, a1)
    DO
      RETURN T{a0/norm, a1/norm}
    END
  END Dir; 

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

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

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

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

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

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

      aa = a0*a0 + a1*a1,
      bb = b0*b0 + b1*b1,
      ab = a0*b0 + a1*b1,
      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],
               
      b0 = b[0],
      b1 = b[1],

      aa = a0*a0 + a1*a1,
      bb = b0*b0 + b1*b1,
      c = a0*b1 - a1*b0,
      sin = Math.sqrt((c/aa)*(c/bb))
    DO
      RETURN sin
    END
  END Sin;

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

      t = a0*b1 - a1*b0
    DO
      RETURN t
    END
  END Det;  
  
PROCEDURE Cross(READONLY a: T): T =
  BEGIN
    RETURN T{-a[1], +a[0]}
  END Cross;

PROCEDURE Project(READONLY a, u: T): T =
  BEGIN
    WITH
      a0 = a[0],
      a1 = a[1],
               
      u0 = u[0],
      u1 = u[1],

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

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

          sau = a0*u0 + a1*u1
        DO
          IF sau = 0.0d0 THEN
            RETURN a
          ELSE
            WITH
              c = sau/suu
            DO
              RETURN T{a0-c*u0, a1-c*u1}
            END
          END
        END
      END
    END;
  END Orthize;
  
PROCEDURE ToReal(READONLY a: T): RealT =
  BEGIN
    RETURN RealT{
      FLOAT(a[0], REAL),
      FLOAT(a[1], REAL)
    }
  END ToReal;
  
PROCEDURE FromReal(READONLY a: RealT): T =
  BEGIN
    RETURN T{
      FLOAT(a[0], LONGREAL),
      FLOAT(a[1], 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 := LR2Rep.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 LR2.