File : vectors.adb


with Ints, Ints.IO;
use Ints;

pragma Elaborate (Ints);

package body Vectors is

  use Ints.IO;

  function IsZero(V: Vector) return Boolean is
  begin
    for N in V'Range loop
      if not IsZero(V(N)) then return False; end if;
    end loop;
    return True;
  end IsZero;

  procedure SetZero(V: out Vector) is
  begin
    for N in V'Range loop
      SetZero(V(N));
    end loop;
  end SetZero;

  function EffLast(V: Vector) return Integer is
  begin
    for N in reverse V'First+1 .. V'Last loop
      if not IsZero(V(N)) then return N; end if;
    end loop;
    return V'First;
  end EffLast;

  procedure Neg(V: in out Vector) is
  begin
    for N in V'First .. EffLast(V) loop
      Neg(V(N));
    end loop;
  end Neg;

  procedure Neg(V1: in Vector; V2: out Vector) is
    NFirst: constant Integer := IMin(V1'First,V2'First);
    NLast:  constant Integer := IMax(V1'Last,V2'Last);
  begin
    for N in NFirst .. NLast loop
      Neg(V1(N),V2(N));
    end loop;
  end Neg;

  function "-"(V: Vector) return Vector is
    W: Vector(V'Range);
  begin
    for N in V'First .. EffLast(V) loop
      Neg(V(N),W(N));
    end loop;
    return W;
  end "-";

  procedure Add(V1: in Vector; V2: in out Vector) is
  begin
    for N in V1'First .. EffLast(V1) loop
      Add(V1(N),V2(N));
    end loop;
  end Add;

  procedure Sum(V1,V2: in Vector; V3: out Vector) is
    NFirst: constant Integer := IMin(V1'First,V2'First,V3'First);
    NLast:  constant Integer := IMax(V1'Last,V2'Last,V3'Last);
  begin
    for N in NFirst .. NLast loop
      Sum(V1(N),V2(N),V3(N));
    end loop;
  end Sum;

  function "+"(V1,V2: Vector) return Vector is
    NFirst: constant Integer := IMin(V1'First,V2'First);
    NLast:  constant Integer := IMax(V1'Last,V2'Last);
    V3: Vector(V1'Range);
  begin
    for N in NFirst .. NLast loop
      Sum(V1(N),V2(N),V3(N));
    end loop;
    return V3;
  end "+";

  procedure Sub(V1: in Vector; V2: in out Vector) is
  begin
    for N in V1'First .. EffLast(V1) loop
      Sub(V1(N),V2(N));
    end loop;
  end Sub;

  procedure Diff(V1,V2: in Vector; V3: out Vector) is
    NFirst: constant Integer := IMin(V1'First,V2'First,V3'First);
    NLast:  constant Integer := IMax(V1'Last,V2'Last,V3'Last);
  begin
    for N in NFirst .. NLast loop
      Diff(V1(N),V2(N),V3(N));
    end loop;
  end Diff;

  function "-"(V1,V2: Vector) return Vector is
    NFirst: constant Integer := IMin(V1'First,V2'First);
    NLast:  constant Integer := IMax(V1'Last,V2'Last);
    V3: Vector(V1'Range);
  begin
    for N in NFirst .. NLast loop
      Diff(V1(N),V2(N),V3(N));
    end loop;
    return V3;
  end "-";

  procedure Mult(K: in Integer; V: in out Vector) is
  begin
    for N in V'First .. EffLast(V) loop
      Mult(K,V(N));
    end loop;
  end Mult;

  procedure Prod(K: in Integer; V1: in Vector; V2: out Vector) is
    NFirst: constant Integer := IMin(V1'First,V2'First);
    NLast:  constant Integer := IMax(V1'Last,V2'Last);
  begin
    for N in NFirst .. NLast loop
      Prod(K,V1(N),V2(N));
    end loop;
  end Prod;

  function "*"(K: Integer; V: Vector) return Vector is
    W: Vector(V'Range);
  begin
    for N in V'First .. EffLast(V) loop
      Prod(K,V(N),W(N));
    end loop;
    return W;
  end "*";

----------------

  procedure Mult(S: in Scalar; V: in out Vector) is
  begin
    for N in V'First .. EffLast(V) loop
      Mult(S,V(N));
    end loop;
  end Mult;

  procedure Prod(S: in Scalar; V1: in Vector; V2: out Vector) is
    NFirst: constant Integer := IMin(V1'First,V2'First);
    NLast:  constant Integer := IMax(V1'Last,V2'Last);
  begin
    for N in NFirst .. NLast loop
      Prod(S,V1(N),V2(N));
    end loop;
  end Prod;

  function "*"(S: Scalar; V: Vector) return Vector is
    W: Vector(V'Range);
  begin
    for N in V'First .. EffLast(V) loop
      Prod(S,V(N),W(N));
    end loop;
    return W;
  end "*";

  procedure MultAdd(S: Scalar; V1: in Vector; V2: in out Vector) is
  begin
    for N in V1'First .. EffLast(V1) loop
      MultAdd(S,V1(N),V2(N));
    end loop;
  end MultAdd;

  procedure Show1(N: in String; V: in Vector) is
    W: constant Positive := 5;
  begin
    for K in V'Range loop
      if not IsZero(V(K)) then
        Show1(N & Strng(K,W),V(K));
      end if;
    end loop;
    New_Line;
  end Show1;

  procedure Show2(N: in String; V1,V2: in Vector) is
    NFirst: constant Integer := IMin(V1'First,V2'First);
    NLast:  constant Integer := IMax(V1'Last,V2'Last);
    W: constant Positive := 5;
  begin
    for K in NFirst .. NLast loop
      if not (IsZero(V1(K)) and IsZero(V2(K))) then
        Show2(N & Strng(K,W),V1(K),V2(K));
      end if;
    end loop;
    New_Line;
  end Show2;

  procedure Get(F: in File_Type; V: out Vector; Decimal: in Boolean := False) is
    Trunc: Boolean := False;
    I,L: Integer;
    C: Component;
  begin
    SetZero(V);
    Get(F,L);
    I := V'First;
    for M in 1 .. L loop
      Get(F,C,Decimal);
      if I <= V'Last then V(I) := C; else Trunc := True; end if;
      I := I+1;
    end loop;
    if Trunc then
      Put_Line("Vectors.Get Warning: input vector truncated");
    end if;
  end Get;

  procedure Put(F: in File_Type; V: in Vector; Decimal: in Boolean := False) is
    VLast: constant Integer := EffLast(V);
    VLength: constant Integer := VLast-V'First+1;
  begin
    Put(F,VLength);
    for I in V'First .. VLast loop
      Put(F,V(I),Decimal);
    end loop;
  end Put;

  procedure Read(Name: in String; V: out Vector; Decimal: in Boolean := False) is
    F: File_Type;
  begin
    Put_Line("Reading " & Name);
    Open(F,In_File,Name);
    Get(F,V,Decimal);
    Close(F);
  end Read;

  procedure Write(Name: in String; V: in Vector; Decimal: in Boolean := False) is
    F: File_Type;
  begin
    Put_Line("Writing " & Name);
    Create(F,Out_File,Name);
    Put(F,V,Decimal);
    Close(F);
  end Write;

----------------------------------------------

  function IsZero(A: Matrix) return Boolean is
  begin
    for I in A'Range(1) loop
      for J in A'Range(2) loop
        if not IsZero(A(I,J)) then return False; end if;
      end loop;
    end loop;
    return True;
  end IsZero;

  procedure SetZero(A: out Matrix) is
  begin
    for I in A'Range(1) loop
      for J in A'Range(2) loop
        SetZero(A(I,J));
      end loop;
    end loop;
  end SetZero;

  procedure ZeroRow(I: in Integer; A: in out Matrix) is
  begin
    for J in A'Range(2) loop
      SetZero(A(I,J));
    end loop;
  end ZeroRow;

  procedure ZeroColumn(J: in Integer; A: in out Matrix) is
  begin
    for I in A'Range(1) loop
      SetZero(A(I,J));
    end loop;
  end ZeroColumn;

  procedure AddConst(R: Rep; A: in out Matrix) is
    AFirst: constant Integer := IMin(A'First(1),A'First(2));
    ALast: constant Integer := IMax(A'Last(1),A'Last(2));
  begin
    for K in AFirst .. ALast loop
      Add(Scal(R),A(K,K));
    end loop;
  end AddConst;

  function EffLast1(A: Matrix) return Integer is
  begin
    for I in reverse A'First(1)+1 .. A'Last(1) loop
      for J in A'Range(2) loop
        if not IsZero(A(I,J)) then return I; end if;
      end loop;
    end loop;
    return A'First(1);
  end EffLast1;

  function EffLast2(A: Matrix) return Integer is
  begin
    for J in reverse A'First(2)+1 .. A'Last(2) loop
      for I in A'Range(1) loop
        if not IsZero(A(I,J)) then return J; end if;
      end loop;
    end loop;
    return A'First(2);
  end EffLast2;

  procedure Transpose(A: in out Matrix) is
    AFirst: constant Integer := IMin(A'First(1),A'First(2));
    ALast: constant Integer := IMax(A'Last(1),A'Last(2));
    S: Scalar;
  begin
    for I in AFirst .. ALast loop
      for J in AFirst .. I-1 loop
        S := A(I,J);
        A(I,J) := A(J,I);
        A(J,I) := S;
      end loop;
    end loop;
  end Transpose;

  function Transpose(A: Matrix) return Matrix is
    B: Matrix(A'Range(2),A'Range(1));
  begin
    for I in A'Range(1) loop
      for J in A'Range(2) loop
        B(J,I) := A(I,J);
      end loop;
    end loop;
    return B;
  end Transpose;

  procedure Neg(A: in out Matrix) is
  begin
    for I in A'Range(1) loop
      for J in A'Range(2) loop
        Neg(A(I,J));
      end loop;
    end loop;
  end Neg;

  procedure Neg(A1: in Matrix; A2: out Matrix) is
    IFirst: constant Integer := Imin(A1'First(1),A2'First(1));
    ILast:  constant Integer := IMax(A1'Last(1),A2'Last(1));
    JFirst: constant Integer := Imin(A1'First(2),A2'First(2));
    JLast:  constant Integer := Imax(A1'Last(2),A2'Last(2));
  begin
    for I in IFirst .. ILast loop
      for J in JFirst .. JLast loop
        Neg(A1(I,J),A2(I,J));
      end loop;
    end loop;
  end Neg;

  function "-"(A: Matrix) return Matrix is
    B: Matrix(A'Range(1),A'Range(2));
  begin
    for I in A'Range(1) loop
      for J in A'Range(2) loop
        Neg(A(I,J),B(I,J));
      end loop;
    end loop;
    return B;
  end "-";

  procedure Add(A1: in Matrix; A2: in out Matrix) is
  begin
    for I in A1'Range(1) loop
      for J in A1'Range(2) loop
        Add(A1(I,J),A2(I,J));
      end loop;
    end loop;
  end Add;

  procedure Sum(A1,A2: in Matrix; A3: out Matrix) is
    IFirst: constant Integer := IMin(A1'First(1),A2'First(1),A3'First(1));
    ILast:  constant Integer := IMax(A1'Last(1),A2'Last(1),A3'Last(1));
    JFirst: constant Integer := IMin(A1'First(2),A2'First(2),A3'First(2));
    JLast:  constant Integer := IMax(A1'Last(2),A2'Last(2),A3'Last(2));
  begin
    for I in IFirst .. ILast loop
      for J in JFirst .. JLast loop
        Sum(A1(I,J),A2(I,J),A3(I,J));
      end loop;
    end loop;
  end Sum;

  function "+"(A1,A2: Matrix) return Matrix is
    IFirst: constant Integer := Imin(A1'First(1),A2'First(1));
    ILast:  constant Integer := IMax(A1'Last(1),A2'Last(1));
    JFirst: constant Integer := Imin(A1'First(2),A2'First(2));
    JLast:  constant Integer := Imax(A1'Last(2),A2'Last(2));
    A3: Matrix(A1'Range(1),A1'Range(2));
  begin
    for I in IFirst .. ILast loop
      for J in JFirst .. JLast loop
        Sum(A1(I,J),A2(I,J),A3(I,J));
      end loop;
    end loop;
    return A3;
  end "+";

  procedure Sub(A1: in Matrix; A2: in out Matrix) is
  begin
    for I in A1'Range(1) loop
      for J in A1'Range(2) loop
        Sub(A1(I,J),A2(I,J));
      end loop;
    end loop;
  end Sub;

  procedure Diff(A1,A2: in Matrix; A3: out Matrix) is
    IFirst: constant Integer := IMin(A1'First(1),A2'First(1),A3'First(1));
    ILast:  constant Integer := IMax(A1'Last(1),A2'Last(1),A3'Last(1));
    JFirst: constant Integer := IMin(A1'First(2),A2'First(2),A3'First(2));
    JLast:  constant Integer := IMax(A1'Last(2),A2'Last(2),A3'Last(2));
  begin
    for I in IFirst .. ILast loop
      for J in JFirst .. JLast loop
        Diff(A1(I,J),A2(I,J),A3(I,J));
      end loop;
    end loop;
  end Diff;

  function "-"(A1,A2: Matrix) return Matrix is
    IFirst: constant Integer := Imin(A1'First(1),A2'First(1));
    ILast:  constant Integer := IMax(A1'Last(1),A2'Last(1));
    JFirst: constant Integer := Imin(A1'First(2),A2'First(2));
    JLast:  constant Integer := Imax(A1'Last(2),A2'Last(2));
    A3: Matrix(A1'Range(1),A1'Range(2));
  begin
    for I in IFirst .. ILast loop
      for J in JFirst .. JLast loop
        Diff(A1(I,J),A2(I,J),A3(I,J));
      end loop;
    end loop;
    return A3;
  end "-";

  procedure Mult(K: in Integer; A: in out Matrix) is
  begin
    for I in A'Range(1) loop
      for J in A'Range(2) loop
        Mult(K,A(I,J));
      end loop;
    end loop;
  end Mult;

  procedure Prod(K: in Integer; A1: in Matrix; A2: out Matrix) is
    IFirst: constant Integer := Imin(A1'First(1),A2'First(1));
    ILast:  constant Integer := IMax(A1'Last(1),A2'Last(1));
    JFirst: constant Integer := Imin(A1'First(2),A2'First(2));
    JLast:  constant Integer := Imax(A1'Last(2),A2'Last(2));
  begin
    for I in IFirst .. ILast loop
      for J in JFirst .. JLast loop
        Prod(K,A1(I,J),A2(I,J));
      end loop;
    end loop;
  end Prod;

  function "*"(K: Integer; A: Matrix) return Matrix is
    B: Matrix(A'Range(1),A'Range(2));
  begin
    for I in A'Range(1) loop
      for J in A'Range(2) loop
        Prod(K,A(I,J),B(I,J));
      end loop;
    end loop;
    return B;
  end "*";

---------------

  procedure Mult(S: in Scalar; A: in out Matrix) is
  begin
    for I in A'Range(1) loop
      for J in A'Range(2) loop
        Mult(S,A(I,J));
      end loop;
    end loop;
  end Mult;

  procedure Prod(S: in Scalar; A1: in Matrix; A2: out Matrix) is
    IFirst: constant Integer := Imin(A1'First(1),A2'First(1));
    ILast:  constant Integer := IMax(A1'Last(1),A2'Last(1));
    JFirst: constant Integer := Imin(A1'First(2),A2'First(2));
    JLast:  constant Integer := Imax(A1'Last(2),A2'Last(2));
  begin
    for I in IFirst .. ILast loop
      for J in JFirst .. JLast loop
        Prod(S,A1(I,J),A2(I,J));
      end loop;
    end loop;
  end Prod;

  function "*"(S: Scalar; A: Matrix) return Matrix is
    B: Matrix(A'Range(1),A'Range(2));
  begin
    for I in A'Range(1) loop
      for J in A'Range(2) loop
        Prod(S,A(I,J),B(I,J));
      end loop;
    end loop;
    return B;
  end "*";

  procedure MultAdd(S: in Scalar; A1: in Matrix; A2: in out Matrix) is
  begin
    for I in A1'Range(1) loop
      for J in A1'Range(2) loop
        MultAdd(S,A1(I,J),A2(I,J));
      end loop;
    end loop;
  end MultAdd;

------------

  procedure Mult(A: in Matrix; V: in out Vector) is
    W: constant Vector := V;
  begin
    Prod(A,W,V);
  end Mult;

  procedure Prod(A: in Matrix; V1: in Vector; V2: out Vector) is
    IFirst: constant Integer := IMin(A'First(1),V2'First);
    ILast:  constant Integer := IMax(A'Last(1),V2'Last);
    JFirst: constant Integer := IMin(A'First(2),V1'First);
    JLast:  constant Integer := IMax(A'Last(2),V1'Last);
    S: Component;
  begin
    for I in IFirst .. ILast loop
      SetZero(S);
      for J in JFirst .. JLast loop
        MultAdd(A(I,J),V1(J),S);
      end loop;
      V2(I) := S;
    end loop;
  end Prod;

  function "*"(A: Matrix; V: Vector) return Vector is
    JFirst: constant Integer := IMin(A'First(2),V'First);
    JLast:  constant Integer := IMax(A'Last(2),V'Last);
    S: Component;
    W: Vector(A'Range(1));
  begin
    for I in A'Range(1) loop
      SetZero(S);
      for J in JFirst .. JLast loop
        MultAdd(A(I,J),V(J),S);
      end loop;
      W(I) := S;
    end loop;
    return W;
  end "*";

  procedure MultAdd(A: in Matrix; V1: in Vector; V2: in out Vector) is
    JFirst: constant Integer := IMin(A'First(2),V1'First);
    JLast:  constant Integer := IMax(A'Last(2),V1'Last);
    S: Component;
  begin
    for I in A'Range(1) loop
      S := V2(I);
      for J in JFirst .. JLast loop
        MultAdd(A(I,J),V1(J),S);
      end loop;
      V2(I) := S;
    end loop;
  end MultAdd;

  procedure Mult(A1: in Matrix; A2: in out Matrix) is
    B: constant Matrix := A2;
  begin
    Prod(A1,B,A2);
  end Mult;

  procedure Prod(A1,A2: in Matrix; A3: out Matrix) is
    IFirst: constant Integer := IMin(A1'First(1),A3'First(1));
    ILast:  constant Integer := IMax(A1'Last(1),A3'Last(1));
    JFirst: constant Integer := IMin(A2'First(2),A3'First(2));
    JLast:  constant Integer := IMax(A2'Last(2),A3'Last(2));
    KFirst: constant Integer := IMin(A1'First(2),A2'First(1));
    KLast:  constant Integer := IMax(A1'Last(2),A2'Last(1));
    S: Scalar;
  begin
    for I in IFirst .. ILast loop
      for J in JFirst .. JLast loop
        SetZero(S);
        for K in KFirst .. KLast loop
          MultAdd(A1(I,K),A2(K,J),S);
        end loop;
        A3(I,J) := S;
      end loop;
    end loop;
  end Prod;

  function "*"(A1,A2: Matrix) return Matrix is
    KFirst: constant Integer := IMin(A1'First(2),A2'First(1));
    KLast:  constant Integer := IMax(A1'Last(2),A2'Last(1));
    S: Scalar;
    A3: Matrix(A1'Range(1),A2'Range(2));
  begin
    for I in A1'Range(1) loop
      for J in A2'Range(2) loop
        SetZero(S);
        for K in KFirst .. KLast loop
          MultAdd(A1(I,K),A2(K,J),S);
        end loop;
        A3(I,J) := S;
      end loop;
    end loop;
    return A3;
  end "*";

  procedure MultAdd(A1,A2: in Matrix; A3: in out Matrix) is
    KFirst: constant Integer := IMin(A1'First(2),A2'First(1));
    KLast:  constant Integer := IMax(A1'Last(2),A2'Last(1));
    S: Scalar;
  begin
    for I in A1'Range(1) loop
      for J in A2'Range(2) loop
        S := A3(I,J);
        for K in KFirst .. KLast loop
          MultAdd(A1(I,K),A2(K,J),S);
        end loop;
        A3(I,J) := S;
      end loop;
    end loop;
  end MultAdd;

-------

  procedure Show1(N: in String; A: in Matrix) is
    W: constant Positive := 3;
    Z: Boolean;
  begin
    for I in A'Range(1) loop
      Z := True;
      for J in A'Range(2) loop
        if not IsZero(A(I,J)) then
          Z := False;
          Show1(N & Strng(I,W) & Strng(J,W),A(I,J));
        end if;
      end loop;
      if not Z then New_Line; end if;
    end loop;
  end Show1;

  procedure Show2(N: in String; A1,A2: in Matrix) is
    IFirst: constant Integer := Imin(A1'First(1),A2'First(1));
    ILast:  constant Integer := IMax(A1'Last(1),A2'Last(1));
    JFirst: constant Integer := Imin(A1'First(2),A2'First(2));
    JLast:  constant Integer := Imax(A1'Last(2),A2'Last(2));
    W: constant Positive := 5;
    Z: Boolean;
  begin
    for I in IFirst .. ILast loop
      Z := True;
      for J in JFirst .. JLast loop
        if not (IsZero(A1(I,J)) and IsZero(A2(I,J))) then
          Z := False;
          Show2(N & Strng(I,W) & Strng(J,W),A1(I,J),A2(I,J));
        end if;
      end loop;
      if not Z then New_Line; end if;
    end loop;
  end Show2;

  procedure Get(F: in File_Type; A: out Matrix; Decimal: in Boolean := True) is
    Trunc: Boolean := False;
    I,J,LM,LN: Integer;
    S: Scalar;
  begin
    SetZero(A);
    Get(F,LM);
    Get(F,LN);
    I := A'First(1);
    for M in 1 .. LM loop
      J := A'First(2);
      for N in 1 .. LN loop
        Get(F,S,Decimal);
        if I <= A'Last(1) and then J <= A'Last(2) then A(I,J) := S; else Trunc := True; end if;
        J := J+1;
      end loop;
      I := I+1;
    end loop;
    if Trunc then
      Put_Line("Vectors.Get Warning: input matrix truncated");
    end if;
  end Get;

  procedure Put(F: in File_Type; A: in Matrix; Decimal: in Boolean := True) is
    ALast1: constant Integer := EffLast1(A);
    ALast2: constant Integer := EffLast2(A);
    ALength1: constant Integer := ALast1-A'First(1)+1;
    ALength2: constant Integer := ALast2-A'First(2)+1;
  begin
    Put(F,ALength1);
    Put(F,ALength2);
    for I in A'First(1) .. ALast1 loop
      for J in A'First(2) .. ALast2 loop
        Put(F,A(I,J),Decimal);
      end loop;
    end loop;
  end Put;

  procedure Read(Name: in String; A: out Matrix; Decimal: in Boolean := False) is
    F: File_Type;
  begin
    Put_Line("Reading " & Name);
    Open(F,In_File,Name);
    Get(F,A,Decimal);
    Close(F);
  end Read;

   procedure Write(Name: in String; A: in Matrix; Decimal: in Boolean := False) is
    F: File_Type;
  begin
    Put_Line("Writing " & Name);
    Create(F,Out_File,Name);
    Put(F,A,Decimal);
    Close(F);
  end Write;

end Vectors;