      MODULE SVD
      IMPLICIT NONE
      INTEGER, PARAMETER  :: dp = SELECTED_REAL_KIND(12, 60)

! Based upon routines from the NSWC (Naval Surface Warfare Center),
! which were based upon LAPACK routines.

! Code converted using TO_F90 by Alan Miller
! Date: 2003-11-11  Time: 17:50:44
! Revised pab 2007
! Converted to fixed form


      CONTAINS


      SUBROUTINE drotg(da, db, dc, ds)
 
!     DESIGNED BY C.L.LAWSON, JPL, 1977 SEPT 08
!
!     CONSTRUCT THE GIVENS TRANSFORMATION
!
!         ( DC  DS )
!     G = (        ) ,    DC**2 + DS**2 = 1 ,
!         (-DS  DC )
!
!     WHICH ZEROS THE SECOND ENTRY OF THE 2-VECTOR  (DA,DB)**T .
!
!     THE QUANTITY R = (+/-)SQRT(DA**2 + DB**2) OVERWRITES DA IN
!     STORAGE.  THE VALUE OF DB IS OVERWRITTEN BY A VALUE Z WHICH
!     ALLOWS DC AND DS TO BE RECOVERED BY THE FOLLOWING ALGORITHM:
!           IF Z=1  SET  DC=0.D0  AND  DS=1.D0
!           IF DABS(Z) < 1  SET  DC=SQRT(1-Z**2)  AND  DS=Z
!           IF DABS(Z) > 1  SET  DC=1/Z  AND  DS=SQRT(1-DC**2)
!
!     NORMALLY, THE SUBPROGRAM DROT(N,DX,INCX,DY,INCY,DC,DS) WILL
!     NEXT BE CALLED TO APPLY THE TRANSFORMATION TO A 2 BY N MATRIX.
!
! ------------------------------------------------------------------

      REAL (dp), INTENT(IN OUT)  :: da
      REAL (dp), INTENT(IN OUT)  :: db
      REAL (dp), INTENT(OUT)     :: dc
      REAL (dp), INTENT(OUT)     :: ds

      REAL (dp)  :: u, v, r
      IF (ABS(da) <= ABS(db)) GO TO 10

! *** HERE ABS(DA) > ABS(DB) ***

      u = da + da
      v = db / u

!     NOTE THAT U AND R HAVE THE SIGN OF DA

      r = SQRT(.25D0 + v**2) * u

!     NOTE THAT DC IS POSITIVE

      dc = da / r
      ds = v * (dc + dc)
      db = ds
      da = r
      RETURN

! *** HERE ABS(DA) <= ABS(DB) ***

   10 IF (db == 0.d0) GO TO 20
      u = db + db
      v = da / u

!     NOTE THAT U AND R HAVE THE SIGN OF DB
!     (R IS IMMEDIATELY STORED IN DA)

      da = SQRT(.25D0 + v**2) * u

!     NOTE THAT DS IS POSITIVE

      ds = db / da
      dc = v * (ds + ds)
      IF (dc == 0.d0) GO TO 15
      db = 1.d0 / dc
      RETURN
   15 db = 1.d0
      RETURN

! *** HERE DA = DB = 0.D0 ***

   20 dc = 1.d0
      ds = 0.d0
      RETURN

      END SUBROUTINE drotg


      SUBROUTINE dswap1 (n, dx, dy)
!     INTERCHANGES TWO VECTORS.
!     USES UNROLLED LOOPS FOR INCREMENTS EQUAL ONE.
!     JACK DONGARRA, LINPACK, 3/11/78.
!     This version is for increments = 1.

      INTEGER, INTENT(IN)        :: n
      REAL (dp), INTENT(IN OUT)  :: dx(*)
      REAL (dp), INTENT(IN OUT)  :: dy(*)

      REAL (dp)  :: dtemp
      INTEGER    :: i, m, mp1

      IF(n <= 0) RETURN

!       CODE FOR BOTH INCREMENTS EQUAL TO 1
!
!       CLEAN-UP LOOP

      m = MOD(n,3)
      IF( m == 0 ) GO TO 40
      DO  i = 1,m
       dtemp = dx(i)
       dx(i) = dy(i)
       dy(i) = dtemp
      END DO
      IF( n < 3 ) RETURN
  40  mp1 = m + 1
      DO  i = mp1,n,3
      dtemp = dx(i)
      dx(i) = dy(i)
      dy(i) = dtemp
      dtemp = dx(i + 1)
      dx(i + 1) = dy(i + 1)
      dy(i + 1) = dtemp
      dtemp = dx(i + 2)
      dx(i + 2) = dy(i + 2)
      dy(i + 2) = dtemp
      END DO
      RETURN
      END SUBROUTINE  dswap1


      SUBROUTINE  drot1 (n, dx, dy, c, s)
!     APPLIES A PLANE ROTATION.
!     JACK DONGARRA, LINPACK, 3/11/78.
!     This version is for increments = 1.

      INTEGER, INTENT(IN)        :: n
      REAL (dp), INTENT(IN OUT)  :: dx(*)
      REAL (dp), INTENT(IN OUT)  :: dy(*)
      REAL (dp), INTENT(IN)      :: c
      REAL (dp), INTENT(IN)      :: s

      REAL (dp)  :: dtemp
      INTEGER    :: i

      IF(n <= 0) RETURN
!       CODE FOR BOTH INCREMENTS EQUAL TO 1

      DO  i = 1,n
      dtemp = c*dx(i) + s*dy(i)
      dy(i) = c*dy(i) - s*dx(i)
      dx(i) = dtemp
      END DO
      RETURN
      END SUBROUTINE  drot1


      SUBROUTINE dsvdc(x, n, p, s, e, u, v, job, info)

      INTEGER, INTENT(IN)      :: n
      INTEGER, INTENT(IN)      :: p
      REAL (dp), INTENT(IN OUT)  :: x(:,:)
      REAL (dp), INTENT(OUT)   :: s(:)
      REAL (dp), INTENT(OUT)   :: e(:)
      REAL (dp), INTENT(OUT)   :: u(:,:)
      REAL (dp), INTENT(OUT)   :: v(:,:)
      INTEGER, INTENT(IN)      :: job
      INTEGER, INTENT(OUT)         :: info

!     DSVDC IS A SUBROUTINE TO REDUCE A DOUBLE PRECISION NXP MATRIX X
!     BY ORTHOGONAL TRANSFORMATIONS U AND V TO DIAGONAL FORM.  THE
!     DIAGONAL ELEMENTS S(I) ARE THE SINGULAR VALUES OF X.  THE
!     COLUMNS OF U ARE THE CORRESPONDING LEFT SINGULAR VECTORS,
!     AND THE COLUMNS OF V THE RIGHT SINGULAR VECTORS.
!
!     ON ENTRY
!
!         X         DOUBLE PRECISION(LDX,P), WHERE LDX.GE.N.
!                   X CONTAINS THE MATRIX WHOSE SINGULAR VALUE
!                   DECOMPOSITION IS TO BE COMPUTED.  X IS
!                   DESTROYED BY DSVDC.
!
!         LDX       INTEGER.
!                   LDX IS THE LEADING DIMENSION OF THE ARRAY X.
!
!         N         INTEGER.
!                   N IS THE NUMBER OF ROWS OF THE MATRIX X.
!
!         P         INTEGER.
!                   P IS THE NUMBER OF COLUMNS OF THE MATRIX X.
!
!         LDU       INTEGER.
!                   LDU IS THE LEADING DIMENSION OF THE ARRAY U.
!                   (SEE BELOW).
!
!         LDV       INTEGER.
!                   LDV IS THE LEADING DIMENSION OF THE ARRAY V.
!                   (SEE BELOW).
!
!         JOB       INTEGER.
!                   JOB CONTROLS THE COMPUTATION OF THE SINGULAR
!                   VECTORS.  IT HAS THE DECIMAL EXPANSION AB
!                   WITH THE FOLLOWING MEANING
!
!                        A.EQ.0    DO NOT COMPUTE THE LEFT SINGULAR VECTORS.
!                        A.EQ.1    RETURN THE N LEFT SINGULAR VECTORS IN U.
!                        A.GE.2    RETURN THE FIRST MIN(N,P) SINGULAR
!                                  VECTORS IN U.
!                        B.EQ.0    DO NOT COMPUTE THE RIGHT SINGULAR VECTORS.
!                        B.EQ.1    RETURN THE RIGHT SINGULAR VECTORS IN V.
!
!     ON RETURN
!
!         S         DOUBLE PRECISION(MM), WHERE MM=MIN(N+1,P).
!                   THE FIRST MIN(N,P) ENTRIES OF S CONTAIN THE SINGULAR
!                   VALUES OF X ARRANGED IN DESCENDING ORDER OF MAGNITUDE.
!
!         E         DOUBLE PRECISION(P).
!                   E ORDINARILY CONTAINS ZEROS.  HOWEVER SEE THE
!                   DISCUSSION OF INFO FOR EXCEPTIONS.
!
!         U         DOUBLE PRECISION(LDU,K), WHERE LDU.GE.N.  IF
!                                   JOBA.EQ.1 THEN K.EQ.N, IF JOBA.GE.2
!                                   THEN K.EQ.MIN(N,P).
!                   U CONTAINS THE MATRIX OF LEFT SINGULAR VECTORS.
!                   U IS NOT REFERENCED IF JOBA.EQ.0.  IF N.LE.P
!                   OR IF JOBA.EQ.2, THEN U MAY BE IDENTIFIED WITH X
!                   IN THE SUBROUTINE CALL.
!
!         V         DOUBLE PRECISION(LDV,P), WHERE LDV.GE.P.
!                   V CONTAINS THE MATRIX OF RIGHT SINGULAR VECTORS.
!                   V IS NOT REFERENCED IF JOB.EQ.0.  IF P.LE.N,
!                   THEN V MAY BE IDENTIFIED WITH X IN THE
!                   SUBROUTINE CALL.
!
!         INFO      INTEGER.
!                   THE SINGULAR VALUES (AND THEIR CORRESPONDING SINGULAR
!                   VECTORS) S(INFO+1),S(INFO+2),...,S(M) ARE CORRECT
!                   (HERE M=MIN(N,P)).  THUS IF INFO.EQ.0, ALL THE
!                   SINGULAR VALUES AND THEIR VECTORS ARE CORRECT.
!                   IN ANY EVENT, THE MATRIX B = TRANS(U)*X*V IS THE
!                   BIDIAGONAL MATRIX WITH THE ELEMENTS OF S ON ITS DIAGONAL
!                   AND THE ELEMENTS OF E ON ITS SUPER-DIAGONAL (TRANS(U)
!                   IS THE TRANSPOSE OF U).  THUS THE SINGULAR VALUES
!                   OF X AND B ARE THE SAME.
!
!     LINPACK. THIS VERSION DATED 03/19/79 .
!     G.W. STEWART, UNIVERSITY OF MARYLAND, ARGONNE NATIONAL LAB.
!
!     DSVDC USES THE FOLLOWING FUNCTIONS AND SUBPROGRAMS.
!
!     EXTERNAL DROT
!     BLAS DAXPY,DDOT,DSCAL,DSWAP,DNRM2,DROTG
!     FORTRAN DABS,DMAX1,MAX0,MIN0,MOD,DSQRT

!     INTERNAL VARIABLES

      INTEGER :: iter, j, jobu, k, kase, kk, l, ll, lls, lm1, lp1, ls, 
     & lu, m, maxit,mm, mm1, mp1, nct, nctp1, ncu, nrt, nrtp1
      REAL (dp) :: t, work(n)
      REAL (dp) :: b, c, cs, el, emm1, f, g, scale, shift, sl, sm, sn, 
     & smm1, t1, test, ztest
      LOGICAL :: wantu, wantv

!     SET THE MAXIMUM NUMBER OF ITERATIONS.

      maxit = 30

!     DETERMINE WHAT IS TO BE COMPUTED.

      wantu = .false.
      wantv = .false.
      jobu = MOD(job,100)/10
      ncu = n
      IF (jobu > 1) ncu = MIN(n,p)
      IF (jobu /= 0) wantu = .true.
      IF (MOD(job,10) /= 0) wantv = .true.

!     REDUCE X TO BIDIAGONAL FORM, STORING THE DIAGONAL ELEMENTS
!     IN S AND THE SUPER-DIAGONAL ELEMENTS IN E.

      info = 0
      nct = MIN(n-1, p)
      s(1:nct+1) = 0.0_dp
      nrt = MAX(0, MIN(p-2,n))
      lu = MAX(nct,nrt)
      IF (lu < 1) GO TO 170
      DO  l = 1, lu
        lp1 = l + 1
        IF (l > nct) GO TO 20
  
!           COMPUTE THE TRANSFORMATION FOR THE L-TH COLUMN AND
!           PLACE THE L-TH DIAGONAL IN S(L).
  
        s(l) = SQRT( SUM( x(l:n,l)**2 ) )
        IF (s(l) == 0.0D0) GO TO 10
        IF (x(l,l) /= 0.0D0) s(l) = SIGN(s(l), x(l,l))
        x(l:n,l) = x(l:n,l) / s(l)
        x(l,l) = 1.0D0 + x(l,l)

  10    s(l) = -s(l)

  20    IF (p < lp1) GO TO 50
        DO  j = lp1, p
          IF (l > nct) GO TO 30
          IF (s(l) == 0.0D0) GO TO 30
    
!              APPLY THE TRANSFORMATION.
    
          t = -DOT_PRODUCT(x(l:n,l), x(l:n,j)) / x(l,l)
          x(l:n,j) = x(l:n,j) + t * x(l:n,l)
    
!           PLACE THE L-TH ROW OF X INTO  E FOR THE
!           SUBSEQUENT CALCULATION OF THE ROW TRANSFORMATION.
    
   30     e(j) = x(l,j)
        END DO

   50   IF (.NOT.wantu .OR. l > nct) GO TO 70
  
! PLACE THE TRANSFORMATION IN U FOR SUBSEQUENT BACK MULTIPLICATION.
  
        u(l:n,l) = x(l:n,l)

   70   IF (l > nrt) CYCLE
  
!           COMPUTE THE L-TH ROW TRANSFORMATION AND PLACE THE
!           L-TH SUPER-DIAGONAL IN E(L).
  
        e(l) = SQRT( SUM( e(lp1:p)**2 ) )
        IF (e(l) == 0.0D0) GO TO 80
        IF (e(lp1) /= 0.0D0) e(l) = SIGN(e(l), e(lp1))
        e(lp1:lp1+p-l-1) = e(lp1:p) / e(l)
        e(lp1) = 1.0D0 + e(lp1)

   80   e(l) = -e(l)
        IF (lp1 > n .OR. e(l) == 0.0D0) GO TO 120
  
!              APPLY THE TRANSFORMATION.
  
        work(lp1:n) = 0.0D0
        DO  j = lp1, p
          work(lp1:lp1+n-l-1) = work(lp1:lp1+n-l-1) + e(j) * 
     &    x(lp1:lp1+n-l-1,j)
        END DO
        DO  j = lp1, p
          x(lp1:lp1+n-l-1,j) = x(lp1:lp1+n-l-1,j) - (e(j)/e(lp1)) *
     &     work(lp1:lp1+n-l-1)
        END DO

  120   IF (.NOT.wantv) CYCLE
  
!              PLACE THE TRANSFORMATION IN V FOR SUBSEQUENT
!              BACK MULTIPLICATION.
  
        v(lp1:p,l) = e(lp1:p)
      END DO

!     SET UP THE FINAL BIDIAGONAL MATRIX OF ORDER M.

  170 m = MIN(p,n+1)
      nctp1 = nct + 1
      nrtp1 = nrt + 1
      IF (nct < p) s(nctp1) = x(nctp1,nctp1)
      IF (n < m) s(m) = 0.0D0
      IF (nrtp1 < m) e(nrtp1) = x(nrtp1,m)
      e(m) = 0.0D0

!     IF REQUIRED, GENERATE U.

      IF (.NOT.wantu) GO TO 300
      IF (ncu < nctp1) GO TO 200
      DO  j = nctp1, ncu
        u(1:n,j) = 0.0_dp
        u(j,j) = 1.0_dp
      END DO

  200 DO  ll = 1, nct
        l = nct - ll + 1
        IF (s(l) == 0.0D0) GO TO 250
        lp1 = l + 1
        IF (ncu < lp1) GO TO 220
        DO  j = lp1, ncu
          t = -DOT_PRODUCT(u(l:n,l), u(l:n,j)) / u(l,l)
          u(l:n,j) = u(l:n,j) + t * u(l:n,l)
        END DO

  220   u(l:n,l) = -u(l:n,l)
        u(l,l) = 1.0D0 + u(l,l)
        lm1 = l - 1
        IF (lm1 < 1) CYCLE
        u(1:lm1,l) = 0.0_dp
        CYCLE

  250   u(1:n,l) = 0.0_dp
      u(l,l) = 1.0_dp
      END DO

!     IF IT IS REQUIRED, GENERATE V.

  300 IF (.NOT.wantv) GO TO 350
      DO  ll = 1, p
        l = p - ll + 1
        lp1 = l + 1
        IF (l > nrt) GO TO 320
        IF (e(l) == 0.0D0) GO TO 320
        DO  j = lp1, p
        t = -DOT_PRODUCT(v(lp1:lp1+p-l-1,l), 
     &                v(lp1:lp1+p-l-1,j)) / v(lp1,l)
        v(lp1:lp1+p-l-1,j) = v(lp1:lp1+p-l-1,j) + t * v(lp1:lp1+p-l-1,l)
        END DO

  320   v(1:p,l) = 0.0D0
        v(l,l) = 1.0D0
      END DO

!     MAIN ITERATION LOOP FOR THE SINGULAR VALUES.

  350 mm = m
      iter = 0

!        QUIT IF ALL THE SINGULAR VALUES HAVE BEEN FOUND.

!     ...EXIT
  360 IF (m == 0) GO TO 620

!        IF TOO MANY ITERATIONS HAVE BEEN PERFORMED, SET FLAG AND RETURN.

      IF (iter < maxit) GO TO 370
      info = m
!     ......EXIT
      GO TO 620

!        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(M) AND E(L-1) ARE NEGLIGIBLE AND L < M
!           KASE = 2     IF S(L) IS NEGLIGIBLE AND L < M
!           KASE = 3     IF E(L-1) IS NEGLIGIBLE, L < M, AND
!                        S(L), ..., S(M) ARE NOT NEGLIGIBLE (QR STEP).
!           KASE = 4     IF E(M-1) IS NEGLIGIBLE (CONVERGENCE).

  370 DO  ll = 1, m
          l = m - ll
!        ...EXIT
          IF (l == 0) EXIT
          test = ABS(s(l)) + ABS(s(l+1))
          ztest = test + ABS(e(l))
          IF (ztest /= test) CYCLE
          e(l) = 0.0D0
!        ......EXIT
          EXIT
      END DO

      IF (l /= m - 1) GO TO 410
      kase = 4
      GO TO 480

  410 lp1 = l + 1
      mp1 = m + 1
      DO  lls = lp1, mp1
      ls = m - lls + lp1
!           ...EXIT
      IF (ls == l) EXIT
      test = 0.0D0
      IF (ls /= m) test = test + ABS(e(ls))
      IF (ls /= l + 1) test = test + ABS(e(ls-1))
      ztest = test + ABS(s(ls))
      IF (ztest /= test) CYCLE
      s(ls) = 0.0D0
!           ......EXIT
      EXIT
      END DO

      IF (ls /= l) GO TO 450
      kase = 3
      GO TO 480

  450 IF (ls /= m) GO TO 460
      kase = 1
      GO TO 480

  460 kase = 2
      l = ls
  480 l = l + 1

!        PERFORM THE TASK INDICATED BY KASE.

      SELECT CASE ( kase )
      CASE (    1)
      GO TO 490
      CASE (    2)
      GO TO 520
      CASE (    3)
      GO TO 540
      CASE (    4)
      GO TO 570
      END SELECT

!        DEFLATE NEGLIGIBLE S(M).

  490 mm1 = m - 1
      f = e(m-1)
      e(m-1) = 0.0D0
      DO  kk = l, mm1
        k = mm1 - kk + l
        t1 = s(k)
        CALL drotg(t1, f, cs, sn)
        s(k) = t1
        IF (k == l) GO TO 500
        f = -sn*e(k-1)
        e(k-1) = cs*e(k-1)
      
  500   IF (wantv) CALL drot1(p, v(1:,k), v(1:,m), cs, sn)
      END DO
      GO TO 610

!        SPLIT AT NEGLIGIBLE S(L).

  520 f = e(l-1)
      e(l-1) = 0.0D0
      DO  k = l, m
      t1 = s(k)
      CALL drotg(t1, f, cs, sn)
      s(k) = t1
      f = -sn*e(k)
      e(k) = cs*e(k)
      IF (wantu) CALL drot1(n, u(1:,k), u(1:,l-1), cs, sn)
      END DO
      GO TO 610

!        PERFORM ONE QR STEP.
!
!           CALCULATE THE SHIFT.
 
  540 scale = MAX(ABS(s(m)),ABS(s(m-1)),ABS(e(m-1)),ABS(s(l)),ABS(e(l)))
      sm = s(m)/scale
      smm1 = s(m-1)/scale
      emm1 = e(m-1)/scale
      sl = s(l)/scale
      el = e(l)/scale
      b = ((smm1 + sm)*(smm1 - sm) + emm1**2)/2.0D0
      c = (sm*emm1)**2
      shift = 0.0D0
      IF (b == 0.0D0 .AND. c == 0.0D0) GO TO 550
      shift = SQRT(b**2+c)
      IF (b < 0.0D0) shift = -shift
      shift = c/(b + shift)

  550 f = (sl + sm)*(sl - sm) - shift
      g = sl*el

!           CHASE ZEROS.

      mm1 = m - 1
      DO  k = l, mm1
        CALL drotg(f, g, cs, sn)
        IF (k /= l) e(k-1) = f
        f = cs*s(k) + sn*e(k)
        e(k) = cs*e(k) - sn*s(k)
        g = sn*s(k+1)
        s(k+1) = cs*s(k+1)
        IF (wantv) CALL drot1(p, v(1:,k), v(1:,k+1), cs, sn)
        CALL drotg(f, g, cs, sn)
        s(k) = f
        f = cs*e(k) + sn*s(k+1)
        s(k+1) = -sn*e(k) + cs*s(k+1)
        g = sn*e(k+1)
        e(k+1) = cs*e(k+1)
        IF (wantu .AND. k < n) CALL drot1(n, u(1:,k), u(1:,k+1), cs, sn)
        END DO
        e(m-1) = f
        iter = iter + 1
       GO TO 610

!        CONVERGENCE.

!           MAKE THE SINGULAR VALUE  POSITIVE.

  570 IF (s(l) >= 0.0D0) GO TO 590
      s(l) = -s(l)
      IF (wantv) v(1:p,l) = -v(1:p,l)

!           ORDER THE SINGULAR VALUE.

  590 IF (l == mm) GO TO 600
!           ...EXIT
      IF (s(l) >= s(l+1)) GO TO 600
      t = s(l)
      s(l) = s(l+1)
      s(l+1) = t
      IF (wantv .AND. l < p) CALL dswap1(p, v(1:,l), v(1:,l+1))
      IF (wantu .AND. l < n) CALL dswap1(n, u(1:,l), u(1:,l+1))
      l = l + 1
      GO TO 590

  600 iter = 0
      m = m - 1

  610 GO TO 360

  620 RETURN
      END SUBROUTINE dsvdc

      END MODULE SVD
