File : scalvectors-ops.adb



package body ScalVectors.Ops is

  procedure Dgefa(A: in out Matrix; Pvt: out Pivot) is
--- adapted from linpack routine dgefa, http://www.netlib.org/linpack/
--- factors a matrix by Gaussian elimination, see Linear.Ops.dgefa for details
    N: constant Integer := Pvt'Last;
    L: Integer;
    X,Y: Radius;
    O,T: Scalar;
  begin
    SetZero(O);
    for K in 1 .. N-1 loop
      Y := Inf(abs(A(N,K)));
      L := N;
      for M in reverse K .. N-1 loop
        X := Inf(abs(A(M,K)));
        if X >= Y then Y := X; L := M; end if;
      end loop;
      Pvt(K) := L;
      if A(L,K) /= O then
        if L /= K then
          T := A(L,K);
          A(L,K) := A(K,K);
          A(K,K) := T;
        end if;
        T := -Inv(A(K,K));
        for M in K+1 .. N loop
          A(M,K) := T*A(M,K);
        end loop;
        for J in K+1 .. N loop
          T := A(L,J);
          if L /= K then
            A(L,J) := A(K,J);
            A(K,J) := T;
          end if;
          for M in K+1 .. N loop
            A(M,J) := A(M,J)+T*A(M,K);
          end loop;
        end loop;
      end if;
    end loop;
    Pvt(N) := N;
  end Dgefa;

  procedure Dgesl(Pvt: in Pivot; A: in Matrix; B: in out Vector) is
--- adapted from linpack routine dgesl, http://www.netlib.org/linpack/
--- solves the system AX=B, see Linear.Ops.dgesl for details
    N: constant Integer := Pvt'Last;
    L: Integer;
    T: Scalar;
  begin
    for K in 1 .. N-1 loop
      L := Pvt(K);
      T := B(L);
      if L /= K then
        B(L) := B(K);
        B(K) := T;
      end if;
      for M in K+1 .. N loop
        B(M) := B(M)+T*A(M,K);
      end loop;
    end loop;
    for K in reverse 1 .. N loop
      B(K) := B(K)/A(K,K);
      T := -B(K);
      for M in 1 .. K-1 loop
        B(M) := B(M)+T*A(M,K);
      end loop;
    end loop;
  end Dgesl;

  procedure Dgedi(Pvt: in Pivot; A: in out Matrix; B: in out Vector) is
--- adapted from linpack routine dgedi, http://www.netlib.org/linpack/
--- computes the inverse of a matrix, see Linear.Ops.dgedi for details
    N: constant Integer := Pvt'Last;
    L: integer;
    O,T: Scalar;
  begin
    SetZero(O);
    for K in 1 .. N loop
      A(K,K) := Inv(A(K,K));
      T := -A(K,K);
      for M in 1 .. K-1 loop
        A(M,K) := T*A(M,K);
      end loop;
      for J in K+1 .. N loop
        T := A(K,J);
        A(K,J) := O;
        for M in 1 .. K loop
          A(M,J) := A(M,J)+T*A(M,K);
        end loop;
      end loop;
    end loop;
    for K in reverse 1 .. N-1 loop
      for I in K+1 .. N loop
        B(I) := A(I,K);
        A(I,K) := O;
      end loop;
      for J in K+1 .. N loop
        T := B(J);
        for M in 1 .. N loop
          A(M,K) := A(M,K)+T*A(M,J);
        end loop;
      end loop;
      L := Pvt(K);
      if L /= K  then
        for M in 1 .. N loop
          T := A(M,K);
          A(M,K) := A(M,L);
          A(M,L) := T;
        end loop;
      end if;
    end loop;
  end Dgedi;

  procedure Solve(A: in Matrix; B: in Vector; X: out Vector) is
    Pvt: Pivot(A'Range(1));
    Ar: Matrix(A'Range(1),A'Range(2));
  begin
    Ar := A;
    X := B;
    Dgefa(Ar,Pvt);
    Dgesl(Pvt,Ar,X);
  end Solve;

  procedure Invert(A: in out Matrix) is
    Pvt: Pivot(A'Range(2));
    B: Vector(A'Range(2));
  begin
    Dgefa(A,Pvt);
    Dgedi(Pvt,A,B);
  end Invert;

end ScalVectors.Ops;