SVD library update

Michael Riedl Michael Riedl 2018-08-26

added SVDLib1.def
added SVDLib1.mod.m2pp
changed Documentation.txt
changed F77func.def
changed F77func.mod
changed FMatEA.def
changed FMatEA.mod
changed LibDBlasF77.def.m2pp
changed LibDBlasLxF77.def.m2pp
changed LibDBlasM2.def
changed LibDBlasM2.mod
changed LinPack.mod.m2pp
changed Makefile
changed SMatEA.def
changed SMatEA.mod.m2pp
copied SVDLib2.mod -> SVDLib2.mod.m2pp
SVDLib1.def Diff Switch to side-by-side view
Loading...
SVDLib1.mod.m2pp Diff Switch to side-by-side view
Loading...
Documentation.txt Diff Switch to side-by-side view
Loading...
F77func.def Diff Switch to side-by-side view
Loading...
F77func.mod Diff Switch to side-by-side view
Loading...
FMatEA.def Diff Switch to side-by-side view
Loading...
FMatEA.mod Diff Switch to side-by-side view
Loading...
LibDBlasF77.def.m2pp Diff Switch to side-by-side view
Loading...
LibDBlasLxF77.def.m2pp Diff Switch to side-by-side view
Loading...
LibDBlasM2.def Diff Switch to side-by-side view
Loading...
LibDBlasM2.mod Diff Switch to side-by-side view
Loading...
LinPack.mod.m2pp Diff Switch to side-by-side view
Loading...
Makefile Diff Switch to side-by-side view
Loading...
SMatEA.def Diff Switch to side-by-side view
Loading...
SMatEA.mod.m2pp Diff Switch to side-by-side view
Loading...
SVDLib2.mod to SVDLib2.mod.m2pp
--- a/SVDLib2.mod
+++ b/SVDLib2.mod.m2pp
@@ -1,35 +1,86 @@
 IMPLEMENTATION MODULE SVDLib2;
 
+  (*========================================================================*)
+  (* WICHTIG: BITTE NUR DIE DATEI SVDLib2.mod.m2pp EDITIEREN !!!            *)
+  (*========================================================================*)
+  (* This file contains two versions - one calling Modula-2 LibDBlas        *)
+  (* the other the Fortran dblas level 1 routines (LibDBlasF77) in          *)
+  (* procedure PdSVDc                                                       *)
+  (*                                                                        *)
+  (*    m2pp    -D __{BLAS|BLASF77}__ < SVDLib2.mod.m2pp > SVDLib2.mod      *)
+  (*                                                                        *)
+  (*  or                                                                    *)
+  (*                                                                        *)
+  (*    m2pp -b -D __{BLAS|BLASF77}__ < SVDLib2.mod.m2pp > SVDLib2.mod      *)
+  (*                                                                        *)
+  (* to preserve line information from *.m2pp file                          *)
+  (*                                                                        *)
+  (* There is also a debug options included  which prints out some          *)
+  (* additonal but anoying info for the check of some procedures            *)
   (*------------------------------------------------------------------------*)
-  (* Modul zur Singul"arwertzerlegung.                                      *)
+  (* Modul zur Singul"arwertzerlegung von dynamisch erzeugten Matrizen      *)
+  (* Siehe hierzu auch die Module DynMat und PMatLib.                       *)
+  (*                                                                        *)
+  (* Modul providing routines to calculate the singual value decomposition  *)
+  (* of dynamically allocated Matrices (see modules DynMat and PMatLib)     *)
+  (* The SVD routines are based on the Eispack subroutine SVD and LinPack   *)
+  (* subroutine dsvdc with pointer MATRIX definitions.                      *)
   (*------------------------------------------------------------------------*)
   (* Letzte Bearbeitung:                                                    *)
   (*                                                                        *)
+  (*       95, MRi: Erstellen der ersten Version                            *)
   (* 10.01.97, MRi: Durchsicht                                              *)
-  (* 29.09.17, MRi: Herausloesen aus LinLib                                 *)
+  (* 29.09.17, MRi: Herausloesen aus LinLib (PSVD,PSVDSolv,POrderSVD)       *)
+  (* 07.12.17, MRi: Erstellen der ersten Verion von PdSVDc aus dSVDc        *)
+  (* 01.07.18, MRi: Zusammenfuehren aller Routinen mit dynamischer PMATRIX  *)
+  (*                in ein Modul, E und S in PdSVDc auf offene Felder       *)
+  (*                umgestellt.                                             *)
   (*------------------------------------------------------------------------*)
   (* Offene Punkte:                                                         *)
   (*                                                                        *)
-  (* - Prozedur OrderSVD auf schnelleren Sortieralgorithmus umstellen       *)
+  (* - Weiteres testen von PdSVDc                                           *)
+  (* - Parameter m,n und Form der Speicherung in A durchsehen, einheitlich  *)
+  (*   machen und dokumentieren !!!                                         *)
   (*------------------------------------------------------------------------*)
-  (* Licence : GNU Lesser General Public License (LGPL)                     *)
+  (* Tests for PdSVD & PdSVDc are given in TstSVD1u2a                       *)
   (*------------------------------------------------------------------------*)
-
-  (* $Id: SVDLib2.mod,v 1.1 2018/01/16 09:20:42 mriedl Exp mriedl $ *)
-
-FROM SYSTEM       IMPORT TSIZE,ADR;
-FROM Storage      IMPORT ALLOCATE,DEALLOCATE;
-FROM Deklera      IMPORT PMATRIX,PVEKTOR;
-FROM Errors       IMPORT Fehler,Fehlerflag,ErrOut,FatalError;
-FROM LongMath     IMPORT sqrt;
-FROM LMathLib     IMPORT MaxCard,Pythag;
-FROM MatLib       IMPORT AbsSumVek,SumVek;
-
-
-PROCEDURE SVD(VAR A   : PMATRIX; (* Dynamische Matrix A[1..n,1..m] *)
-                  m,n : INTEGER;
-              VAR W   : ARRAY OF LONGREAL;
-              VAR V   : PMATRIX);
+  (* Implementation : Michael Riedl                                         *)
+  (* Licence        : GNU Lesser General Public License (LGPL)              *)
+  (*------------------------------------------------------------------------*)
+
+  (* $Id: SVDLib2.mod.m2pp,v 1.3 2018/08/25 15:04:22 mriedl Exp mriedl $ *)
+
+
+FROM SYSTEM      IMPORT TSIZE;
+FROM Storage     IMPORT ALLOCATE,DEALLOCATE;
+FROM Deklera     IMPORT PMATRIX,PVEKTOR;
+FROM Errors      IMPORT Fehler,Fehlerflag,ErrOut,FatalError;
+                 IMPORT Errors;
+FROM LongMath    IMPORT sqrt;
+FROM LMathLib    IMPORT MaxCard,Pythag;
+FROM MatLib      IMPORT AbsSumVek,SumVek;
+<* IF (__debug__) THEN *>
+                 IMPORT TIO;
+                 IMPORT MatEA,FileSystem;
+<* END *> 
+<* IF (__BLAS__) THEN *>
+FROM LibDBlas    IMPORT daxpy,ddot,dnrm2,drot,drotg,dscal,dswap;
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+FROM LibDBlasF77 IMPORT daxpy,ddot,dnrm2,drot,drotg,dscal,dswap;
+<* END *> 
+
+<* IF (__BLAS__) THEN *>
+CONST tag = "SVDLib2 Modula-2 BLAS";
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+CONST tag = "SVDLib2 Fortran BLAS";
+<* END *> 
+
+PROCEDURE PdSVD(VAR A   : PMATRIX; (* Dynamische Matrix A[1..n,1..m] *)
+                    m,n : INTEGER;
+                VAR W   : ARRAY OF LONGREAL;
+                VAR V   : PMATRIX);
 
   PROCEDURE sign(x,y: LONGREAL): LONGREAL;
   
@@ -284,15 +335,15 @@
         END;
       END;
  *)
-END SVD;
-
-PROCEDURE SVDSolv(VAR U   : PMATRIX;           (* m,n *)
-                      Utr : CHAR;
-                  VAR W   : ARRAY OF LONGREAL; (* n   *)
-                  VAR V   : PMATRIX;           (* n,n *)
-                  VAR X   : ARRAY OF LONGREAL; (* n   *)
-                  VAR C   : ARRAY OF LONGREAL;
-                      m,n : CARDINAL);
+END PdSVD;
+
+PROCEDURE PSVDSolv(VAR U   : PMATRIX;           (* m,n *)
+                       Utr : CHAR;
+                   VAR W   : ARRAY OF LONGREAL; (* n   *)
+                   VAR V   : PMATRIX;           (* n,n *)
+                   VAR X   : ARRAY OF LONGREAL; (* n   *)
+                   VAR C   : ARRAY OF LONGREAL;
+                       m,n : CARDINAL);
 
           VAR  jj,j,i : CARDINAL;
                s      : LONGREAL;
@@ -302,7 +353,7 @@
       ALLOCATE(Zw,n*TSIZE(LONGREAL));
       ALLOCATE(Svek,MaxCard(n,m)*TSIZE(LONGREAL));
       IF (Zw = NIL) OR (Svek = NIL) THEN
-        FatalError("Kein Freispeicher vorhanden (SVDLib2.SVDSolv) !");
+        FatalError("Kein Freispeicher vorhanden (SVDLib1.SVDSolv) !");
       END;
       FOR j:=1 TO n DO
         s := 0.0;
@@ -324,12 +375,12 @@
       END;
       DEALLOCATE(Svek,MaxCard(n,m)*TSIZE(LONGREAL));
       DEALLOCATE(Zw,n*TSIZE(LONGREAL));
-END SVDSolv;
-
-PROCEDURE OrderSVD(VAR U    : PMATRIX;
-                   VAR W    : ARRAY OF LONGREAL;
-                   VAR V    : PMATRIX;
-                       m,n  : CARDINAL);
+END PSVDSolv;
+
+PROCEDURE POrderSVD(VAR U    : PMATRIX;
+                    VAR W    : ARRAY OF LONGREAL;
+                    VAR V    : PMATRIX;
+                        m,n  : CARDINAL);
 
           VAR i,j,MaxI : CARDINAL;
               zw,MaxW  : LONGREAL;
@@ -353,6 +404,585 @@
           END;
         END; (* IF *)
       END;
-END OrderSVD;
-
+END POrderSVD;
+
+PROCEDURE PdSVDc(VAR A    : PMATRIX;
+                     m    : INTEGER;
+                     n    : INTEGER;
+                 VAR S    : ARRAY OF LONGREAL;
+                 VAR E    : ARRAY OF LONGREAL;
+                 VAR U,V  : PMATRIX;
+                     job  : INTEGER;
+                 VAR info : INTEGER);
+
+          (*---------------------------------------------------------------*)
+          (* Modula-2 Version der LinPack SUBROUTINE DSVDC                 *)
+          (*                                                               *)
+          (* Anpassung an Modula-2 : Michael Riedl                         *)
+          (* Lizenz                : GNU public licence                    *)
+          (*                                                               *)
+<* IF (__BLAS__) THEN *>
+          (* Version basierend auf Modula-2 BLAS routinen                  *)
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+          (* Version basierend auf Fortran BLAS routinen                   *)
+<* END *> 
+          (*---------------------------------------------------------------*)
+
+          PROCEDURE dsign(a,b : LONGREAL) : LONGREAL;
+          BEGIN
+            IF (b >= 0.0) THEN RETURN ABS(a); ELSE RETURN -ABS(a); END;
+          END dsign;
+
+          PROCEDURE dmax(a,b : LONGREAL) : LONGREAL;
+          BEGIN
+            IF (a >= b) THEN RETURN a; ELSE RETURN b; END;
+          END dmax;
+
+          PROCEDURE imax(a,b : INTEGER) : INTEGER;
+          BEGIN
+            IF (a >= b) THEN RETURN a; ELSE RETURN b; END;
+          END imax;
+
+          PROCEDURE imin(a,b : INTEGER) : INTEGER;
+          BEGIN
+            IF (a <= b) THEN RETURN a; ELSE RETURN b; END;
+          END imin;
+
+          CONST maxit     = 30;
+
+          TYPE  WorkSpace =  POINTER TO ARRAY [1..MAX(INTEGER)-1]  OF LONGREAL;
+                PVEKTOR   =  WorkSpace;
+
+          VAR   b,c,cs,el,emm1,f,g                    : LONGREAL;
+                i,j,k,l,kk,ll,lls,ls,lu               : INTEGER;
+                lp1                                   : INTEGER;
+                iter,jobu,kase                        : INTEGER;
+                mm,mm1,mn,mp1,nct,nctp1,ncu,nrt,nrtp1 : INTEGER;
+                scale,shift,sl,sm,smm1,sn,t,t1,test   : LONGREAL;
+                wantu,wantv                           : BOOLEAN;
+                ztest                                 : LONGREAL;
+                work                                  : WorkSpace;
+<* IF (__BLASF77__) THEN *>
+                ione,num                              : INTEGER;
+                tmp                                   : LONGREAL;
+<* END *> 
+BEGIN
+      (* Determine what is to be computed.  *)
+
+      wantu := FALSE;
+      wantv := FALSE;
+      jobu := (job MOD 100) DIV 10;
+      IF (jobu > 1) THEN
+        ncu := imin(m,n);
+      ELSE
+        ncu := m;
+      END;
+      IF (jobu # 0) THEN
+        wantu := TRUE;
+      END;
+      IF ((job MOD 10) # 0) THEN
+        wantv := TRUE;
+      END;
+
+      (* Reduce A to bidiagonal form, storing the diagonal elements *)
+      (* in S and the super-diagonal elements in E.                 *)
+
+      info := 0;
+      nct  := imin(m-1,n);
+      nrt  := imax(0,imin(n-2,m));
+      lu   := imax(nct, nrt);
+
+      ALLOCATE(work,m*TSIZE(LONGREAL));
+
+      IF (work = NIL) THEN
+        Errors.Fehlerflag:="Kein Freispeicher vorhanden (SVDLib4.dSVDc)";
+        Errors.Fehler:=TRUE;
+        Errors.ErrOut(Errors.Fehlerflag);
+        info:=-1;
+        RETURN;
+      END;
+
+<* IF (__BLASF77__) THEN *>
+      ione:=1; (* Fuer F77 Blas routinen *)
+<* END *> 
+
+      FOR l:=1 TO lu DO
+        (* Compute the transformation for the L-th column and *)
+        (* place the L-th diagonal in S(L).                   *)
+        IF (l <= nct) THEN
+<* IF (__BLAS__) THEN *>
+          S[l-1] := dnrm2(m-l+1,A^[l]^[l],1);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+          num:=m-l+1;
+          S[l-1] := dnrm2(num,A^[l]^[l],ione);
+<* END *> 
+          IF (S[l-1] # 0.0) THEN
+            IF (A^[l]^[l] # 0.0) THEN
+              S[l-1] := dsign(S[l-1],A^[l]^[l]);
+            END;
+<* IF (__BLAS__) THEN *>
+            dscal(m-l+1,(1.0/S[l-1]),A^[l]^[l],1);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+            num:=m-l+1;
+            tmp:= 1.0 / S[l-1];
+            dscal(num,tmp,A^[l]^[l],ione);
+<* END *> 
+            A^[l]^[l]:=A^[l]^[l] + 1.0;
+          END;
+          S[l-1] := -S[l-1];
+        END;
+        FOR j:=l+1 TO n DO
+          (* Apply the transformation.  *)
+          IF (l <= nct) AND (S[l-1] # 0.0) THEN
+<* IF (__BLAS__) THEN *>
+            t := - ddot(m-l+1,A^[l]^[l],1,A^[j]^[l],1) / A^[l]^[l];
+            daxpy(m-l+1,t,A^[l]^[l],1,A^[j]^[l],1);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+            num:=m-l+1;
+(*          Korrektur (j-1 gegen j) MRi, 21.08.16
+            t := - ddot(num,A^[l]^[l],ione,A^[j-1]^[l],ione) / A^[l]^[l];
+            daxpy(num,t,A^[l]^[l],ione,A^[j-1]^[l],ione);
+ *)
+            t := - ddot(num,A^[l]^[l],ione,A^[j]^[l],ione) / A^[l]^[l];
+            daxpy(num,t,A^[l]^[l],ione,A^[j]^[l],ione);
+<* END *> 
+          END;
+          (* Palace the L-th row of A into E for the           *)
+          (* subsequent calculation of the row transformation. *)
+          E[j-1] := A^[j]^[l];
+        END; (* FOR j *)
+
+        (* Place the transformation in U for *)
+        (* subsequent back multiplication.   *)
+
+        IF (wantu) AND (l <= nct) THEN
+          FOR i:=l TO m DO
+            U^[l]^[i] := A^[l]^[i];
+          END;
+        END;
+        IF (l <= nrt) THEN
+          (* Compute the l-th row transformation and *)
+          (* place the l-th superdiagonal in E(l).   *)
+<* IF (__BLAS__) THEN *>
+          E[l-1] := dnrm2(n-l,E[l],1);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+          num:=n-l;
+          E[l-1] := dnrm2(num,E[l],ione);
+<* END *> 
+          IF (E[l-1] # 0.0) THEN
+            IF (E[l] # 0.0) THEN
+              E[l-1] := dsign(E[l-1],E[l]);
+            END;
+<* IF (__BLAS__) THEN *>
+            dscal(n-l,(1.0 / E[l-1]),E[l],1);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+            num:=n-l;
+            tmp:=1.0 / E[l-1];
+            dscal(num,tmp,E[l],ione);
+<* END *> 
+            E[l]:=E[l] + 1.0;
+          END;
+          E[l-1] := -E[l-1];
+
+          IF (l+1 <= m) AND (E[l-1] # 0.0) THEN
+            (* Apply the transformation *)
+            FOR i:=l+1 TO m DO
+              work^[i] := 0.0;
+            END;
+            FOR j:=l+1 TO n DO
+<* IF (__BLAS__) THEN *>
+              daxpy(m-l,E[j-1],A^[j]^[l+1],1,work^[l+1],1);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+              num:=m-l;
+              daxpy(num,E[j-1],A^[j]^[l+1],ione,work^[l+1],ione);
+<* END *> 
+            END;
+            FOR j:=l+1 TO n DO
+<* IF (__BLAS__) THEN *>
+              daxpy(m-l,-E[j-1]/E[l],work^[l+1],1,A^[j]^[l+1],1);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+              num:=m-l;
+              tmp:=-E[j-1]/E[l];
+              daxpy(num,tmp,work^[l+1],ione,A^[j]^[l+1],ione);
+<* END *> 
+            END;
+          END;
+          (* Place the transformation in V for *)
+          (* subsequent back multiplication.   *)
+          IF (wantv) THEN
+            FOR i:=l+1 TO n DO
+              V^[l]^[i] := E[i-1];
+            END;
+          END;
+        END; (* IF l *)
+      END; (* FOR l *)
+      DEALLOCATE(work,m*TSIZE(LONGREAL));
+  
+      (* Set up the final bidiagonal matrix of order MN.  *)
+
+      mn := imin(m+1,n);
+      nctp1 := nct + 1;
+      nrtp1 := nrt + 1;
+      IF (nct < n) THEN
+        S[nctp1-1] := A^[nctp1]^[nctp1];
+      END;
+      IF (m < mn) THEN
+        S[mn-1] := 0.0;
+      END;
+      IF (nrtp1 < mn) THEN
+        E[nrtp1-1] := A^[mn]^[nrtp1];
+      END;
+      E[mn-1] := 0.0;
+
+      IF (wantu) THEN (* If required, generate U. *)
+        FOR j:=nctp1 TO ncu DO
+          FOR i:=1 TO m DO
+            U^[j]^[i]:=0.0;
+          END;
+          U^[j]^[j]:=1.0;
+        END;
+(*
+        FOR l:=nct TO 1 BY -1 DO
+ *)
+        FOR ll:=1 TO nct DO
+          l := nct - ll + 1;
+          IF (S[l-1] # 0.0) THEN
+            FOR j:=l+1 TO ncu DO
+<* IF (__BLAS__) THEN *>
+              t := - ddot(m-l+1,U^[l]^[l],1,U^[j]^[l],1) / U^[l]^[l];
+              daxpy(m-l+1,t,U^[l]^[l],1,U^[j]^[l],1);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+              num:=m-l+1;
+              t := - ddot(num,U^[l]^[l],ione,U^[j]^[l],ione) / U^[l]^[l];
+              daxpy(num,t,U^[l]^[l],ione,U^[j]^[l],ione);
+<* END *> 
+            END;
+<* IF (__BLAS__) THEN *>
+            dscal(m-l+1,-1.0,U^[l]^[l],1);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+            num:=m-l+1;
+            tmp:=-1.0;
+            dscal(num,tmp,U^[l]^[l],ione);
+<* END *> 
+            U^[l]^[l]:=U^[l]^[l] + 1.0;
+            FOR i:=1 TO l-1 DO
+              U^[l]^[i]:=0.0;
+            END;
+          ELSE
+            FOR i:=1 TO m DO
+              U^[l]^[i]:=0.0;
+            END;
+            U^[l]^[l]:=1.0;
+          END;
+        END; (* FOR ll *)
+      END; (* IF wantu *)
+
+      IF (wantv) THEN (* If it is required, generate V.  *)
+(*
+        FOR l:=n TO 1 BY -1 DO
+ *)
+        FOR ll:=1 TO n DO
+          l   := n - ll + 1;
+          lp1 := l + 1;
+          IF (l <= nrt) AND (E[l-1] # 0.0) THEN
+            FOR j:=lp1 TO n DO
+<* IF (__BLAS__) THEN *>
+              t := - ddot(n-l,V^[l]^[lp1],1,V^[j]^[lp1],1) / V^[l]^[lp1];
+              daxpy(n-l,t,V^[l]^[lp1],1,V^[j]^[lp1],1);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+              num:=n-l;
+              t := - ddot(num,V^[l]^[lp1],ione,V^[j]^[lp1],ione) / V^[l]^[lp1];
+              daxpy(num,t,V^[l]^[lp1],ione,V^[j]^[lp1],ione);
+<* END *> 
+            END;
+          END;
+          FOR i:=1 TO n DO
+            V^[l]^[i] := 0.0;
+          END;
+          V^[l]^[l] := 1.0;
+        END;
+      END; (* IF wantu *)
+
+<* IF (__debug__  ) THEN *>
+  TIO.WrLn; TIO.WrStr("dSVDc mit MATRIX/VEKTOR"); TIO.WrLn; TIO.WrLn;
+
+  TIO.WrStr("A +"); MatEA.MATaus(FileSystem.Output,mn,mn,A,80,8,3);
+
+  TIO.WrLn; TIO.WrStr("E_i,S_i  i = 1,n");
+  TIO.WrLn; TIO.WrLn;
+  FOR l:=1 TO n DO
+    TIO.WrInt(l,3);
+    TIO.WrLngReal(E[l-1],12,4); TIO.WrLngReal(S[l-1],12,4); TIO.WrLn;
+  END;
+  TIO.WrLn;
+
+  mm:=imax(m,n)+1;
+  TIO.WrStr("U"); MatEA.MATaus(FileSystem.Output,mm,mm,U,80,8,3);
+  TIO.WrStr("V"); MatEA.MATaus(FileSystem.Output,mm,mm,V,80,8,3);
+<* END *> 
+
+      (* Main iteration loop for the singular values. *)
+
+      mm := mn;
+      iter := 0;
+      WHILE (mn # 0) AND (iter <= maxit) DO
+
+        (* This section of the program inspects for negligible elements  *)
+        (* in the S and E arrays. On completion the variables KASE and L *)
+        (* are set as follows:                                           *)
+        (*                                                               *)
+        (* KASE = 1     if S(MN) and E(L-1) are negligible and L < MN    *)
+        (* KASE = 2     if S(L) is negligible and L < MN                 *)
+        (* KASE = 3     if E(L-1) is negligible, L < MN, and             *)
+        (*              S(L), ..., S(MN) are not negligible (QR step).   *)
+        (* KASE = 4     if E(MN-1) is negligible (convergence).          *)
+
+        ll:=1;
+        LOOP
+          l := mn - ll;
+          IF (l = 0) THEN EXIT; END;
+          test := ABS(S[l-1]) + ABS(S[l]);
+          ztest := test + ABS(E[l-1]);
+          IF (ztest = test) THEN
+            E[l-1] := 0.0;
+            EXIT;
+          END;
+          INC(ll);
+        END;
+
+        IF (l = mn-1) THEN
+          kase := 4;
+        ELSE
+          lp1 := l  + 1;
+          mp1 := mn + 1;
+
+          ls := l; (* Wg. Compilerwarnung *)
+          lls:=lp1;
+          LOOP
+            IF (lls > mp1) THEN EXIT; END;
+            ls := mn - lls + lp1;
+            IF (ls = l) THEN
+              EXIT;
+            END;
+            test := 0.0;
+            IF (ls # mn) THEN
+              test:= ABS(E[ls-1]); (* + test *)
+            END;
+            IF (ls # l+1) THEN
+              test := test + ABS(E[ls-2]);
+            END;
+            ztest := test + ABS(S[ls-1]);
+            IF (ztest = test) THEN
+              S[ls-1] := 0.0;
+              EXIT;
+            END;
+            INC(lls);
+          END;
+          IF (ls = l) THEN
+            kase := 3;
+          ELSIF (ls = mn) THEN
+            kase := 1;
+          ELSE
+            kase := 2;
+            l := ls;
+          END;
+        END; (* IF l *)
+        l := l + 1;
+
+        IF (kase = 1) THEN
+          (* Deflate negligible S(MN). *) 
+          mm1     := mn - 1;
+          f       := E[mn-2];
+          E[mn-2] := 0.0;
+(*
+          FOR k:=mm1 TO l BY -1 DO
+ *)
+          FOR kk:=l TO mm1 DO
+            k  := mm1 - kk + l;
+            t1 := S[k-1];
+<* IF (__BLAS__) THEN *>
+            drotg(t1,f,cs,sn);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+            drotg(t1,f,cs,sn);
+<* END *> 
+            S[k-1] := t1;
+            IF (k # l) THEN
+              f      := -sn*E[k-2];
+              E[k-2] :=  cs*E[k-2];
+            END;
+            IF (wantv) THEN
+<* IF (__BLAS__) THEN *>
+              drot(n,V^[k]^[1],1,V^[mn]^[1],1,cs,sn);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+              drot(n,V^[k]^[1],ione,V^[mn]^[1],ione,cs,sn);
+<* END *> 
+            END;
+          END;
+        ELSIF (kase = 2) THEN
+          (* Split at negligible S(L).  *)
+          f      := E[l-2];
+          E[l-2] := 0.0;
+          FOR k:=l TO mn DO
+            t1   := S[k-1];
+<* IF (__BLAS__) THEN *>
+            drotg(t1,f,cs,sn);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+            drotg(t1,f,cs,sn);
+<* END *> 
+            S[k-1] := t1;
+            f      := - sn*E[k-1];
+            E[k-1] :=   cs*E[k-1];
+            IF (wantu) THEN
+<* IF (__BLAS__) THEN *>
+              drot(m,U^[k]^[1],1,U^[l-1]^[1],1,cs,sn);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+              drot(m,U^[k]^[1],ione,U^[l-1]^[1],ione,cs,sn);
+<* END *> 
+            END;
+          END;
+        ELSIF (kase = 3) THEN (* Perform one QR step.  *)
+
+          scale := dmax(ABS(S[mn-1]), (* Calculate the shift.  *)
+                     dmax (ABS(S[mn-2]),
+                       dmax (ABS(E[mn-2]),
+                         dmax(ABS(S[l-1]),ABS(E[l-1])
+                   ))));
+
+          sm   := S[mn-1]   / scale;
+          smm1 := S[mn-2] / scale;
+          emm1 := E[mn-2] / scale;
+          sl   := S[l-1]    / scale;
+          el   := E[l-1]    / scale;
+          b  := ((smm1 + sm)*(smm1 - sm) + emm1*emm1) / 2.0;
+          cs := (sm*emm1); c:=cs*cs;
+          shift := 0.0;
+          IF (b # 0.0) OR (c # 0.0) THEN
+(*          shift := sqrt(b*b + c); *)
+            shift := Pythag(b,cs);
+            IF (b < 0.0) THEN
+              shift := -shift;
+            END;
+            shift := c / (b + shift);
+          END;
+          f := (sl + sm)*(sl - sm) - shift;
+          g := sl*el;
+
+          (* Chase zeros *)
+
+          mm1 := mn - 1;
+          FOR k:=l TO mm1 DO
+<* IF (__BLAS__) THEN *>
+            drotg(f,g,cs,sn);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+            drotg(f,g,cs,sn);
+<* END *> 
+            IF (k # l) THEN
+              E[k-2] := f;
+            END;
+            f      := cs*S[k-1] + sn*E[k-1];
+            E[k-1] := cs*E[k-1] - sn*S[k-1];
+            g      := sn*S[k];
+            S[k]   := cs*S[k];
+            IF (wantv) THEN
+<* IF (__BLAS__) THEN *>
+              drot(n,V^[k]^[1],1,V^[k+1]^[1],1,cs,sn);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+              drot(n,V^[k]^[1],ione,V^[k+1]^[1],ione,cs,sn);
+<* END *> 
+            END;
+<* IF (__BLAS__) THEN *>
+            drotg(f,g,cs,sn);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+            drotg(f,g,cs,sn);
+<* END *> 
+            S[k-1] :=  f;
+            f      :=  cs*E[k-1] + sn*S[k];
+            S[k]   := -sn*E[k-1] + cs*S[k];
+            g      :=  sn*E[k];
+            E[k]   :=  cs*E[k];
+            IF (wantu) AND (k < m) THEN
+<* IF (__BLAS__) THEN *>
+              drot(m,U^[k]^[1],1,U^[k+1]^[1],1,cs,sn);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+              drot(m,U^[k]^[1],ione,U^[k+1]^[1],ione,cs,sn);
+<* END *> 
+            END;
+          END;
+          E[mn-2] := f;
+          INC(iter);
+        ELSIF (kase = 4) THEN
+          (* Convergence.  *)
+          IF (S[l-1] < 0.0) THEN
+            (* Make the singular value positive.  *)
+            S[l-1] := -S[l-1];
+            IF (wantv) THEN
+<* IF (__BLAS__) THEN *>
+              dscal(n,-1.0,V^[l]^[1],1);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+              tmp:=-1.0;
+              dscal(n,tmp,V^[l]^[1],ione);
+<* END *> 
+            END;
+          END;
+
+          (* Order the singular value.  *)
+
+          WHILE (l # mm) AND (S[l-1] < S[l]) DO
+            t      := S[l-1]; 
+            S[l-1] := S[l]; 
+            S[l]   := t;
+            IF (wantv) AND (l < n) THEN
+<* IF (__BLAS__) THEN *>
+              dswap(n,V^[l]^[1],1,V^[l+1]^[1],1);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+              dswap(n,V^[l]^[1],ione,V^[l+1]^[1],ione);
+<* END *> 
+            END;
+            IF (wantu) AND (l < m) THEN
+<* IF (__BLAS__) THEN *>
+              dswap(m,U^[l]^[1],1,U^[l+1]^[1],1);
+<* END *> 
+<* IF (__BLASF77__) THEN *>
+              dswap(m,U^[l]^[1],ione,U^[l+1]^[1],ione);
+<* END *> 
+            END;
+            INC(l);
+          END; (* WHILE*)
+          iter := 0;
+          DEC(mn);
+        END; (* IF kase = 4 *)
+      END; (* WHILE *)
+      IF (iter > maxit) THEN
+        (* If too many iterations have been performed set flag *) 
+        Errors.Fehlerflag:=
+        "Maximale Anzahl der Iterationen ueberschritten (LibSVD.dSVDc)";
+        Errors.Fehler:=TRUE;
+        info := mn;
+      END;
+END PdSVDc;
+
+BEGIN
+      Errors.WriteString(tag);
+      Errors.WriteLn;
 END SVDLib2.