function [ s, e, u, v, info ] = zsvdc ( x, ldx, n, p, ldu, ldv, job )

%*****************************************************************************80
%
%% ZSVDC applies the singular value decompostion to an N by P matrix.
%
%  Discussion:
%
%    The routine reduces a complex N by P matrix X, by unitary transformations
%    U and V, to diagonal form.
%
%    The diagonal elements, S(I), are the singular values of Z.  The
%    columns of U are the corresponding left singular vectors,
%    and the columns of V the right singular vectors.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    15 May 2007
%
%  Author:
%
%    MATLAB version by John Burkardt
%
%  Reference:
%
%    Jack Dongarra, Jim Bunch, Cleve Moler, Pete Stewart,
%    LINPACK User's Guide,
%    SIAM, 1979,
%    ISBN13: 978-0-898711-72-1,
%    LC: QA214.L56.
%
%  Parameters:
%
%    Input, complex X(LDX,P); the matrix whose singular value
%    decomposition is to be computed.
%
%    Input, integer LDX, the leading dimension of X.  N <= LDX.
%
%    Input, integer N, the number of rows of the matrix.
%
%    Input, integer P, the number of columns of the matrix X.
%
%    Input, integer LDU, the leading dimension of U.  N <= LDU.
%
%    Input, integer LDV, the leading dimension of V.  P <= LDV.
%
%    Input, integer JOB, controls the computation of the singular vectors.
%    It has the decimal expansion AB meaning:
%    A =  0, do not compute the left singular vectors.
%    A =  1, return the N left singular vectors in U.
%    A >= 2, returns the first min ( N, P ) left singular vectors in U.
%    B =  0, do not compute the right singular vectors.
%    B =  1, return the right singular vectors in V.
%
%    Output, complex S(MM), where MM = max ( N + 1, P ), the first min ( N, P )
%    entries of S contain the singular values of X arranged in descending
%    order of magnitude.
%
%    Output, complex E(MM), where MM = max ( N + 1, P ), ordinarily
%    contains zeros on output.  However, see the discussion of INFO
%    for exceptions.
%
%    Output, complex U(LDU,K).  If JOBA == 1 then K == n; if JOBA >= 2,
%    then K == min ( N, P ).  U contains the matrix of left singular vectors.
%    U is not referenced if JOBA == 0.
%
%    Output, complex V(LDV,P), if requested, the matrix of right singular
%    vectors.
%
%    Output, integer INFO.  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 == 0, all the singular values and
%    their vectors are correct.  In any event, the matrix
%      B = hermitian(U)*X*V
%    is the bidiagonal matrix with the elements of S on its diagonal
%    and the elements of E on its super-diagonal.  Hermitian(U)
%    is the conjugate-transpose of U.  Thus the singular values of X
%    and B are the same.
%
  maxit = 30;
  u = [];
  v = [];
%
%  Determine what is to be computed.
%
  wantu = 0;
  wantv = 0;
  jobu = floor ( mod ( job, 100 ) / 10 );

  if ( 1 < jobu )
    ncu = min ( n, p );
  else
    ncu = n;
  end

  if ( jobu ~= 0 )
    wantu = 1;
  end

  if ( mod ( job, 10 ) ~= 0 )
    wantv = 1;
  end
%
%  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 );
  nrt = max ( 0, min ( p - 2, n ) );
  lu = max ( nct, nrt );

  for l = 1 : lu
%
%  Compute the transformation for the L-th column and
%  place the L-th diagonal in S(L).
%
    if ( l <= nct )

      s(l) = dznrm2 ( n-l+1, x(l:n,l), 1 );

      if ( zabs1 ( s(l) ) ~= 0.0 )

        if ( zabs1 ( x(l,l) ) ~= 0.0 )
          s(l) = zsign2 ( s(l), x(l,l) );
        end

        x(l:n,l) = x(l:n,l) / s(l);
        x(l,l) = 1.0 + x(l,l);

      end

      s(l) = -s(l);

    end

    for j = l + 1 : p

      if ( l <= nct )
        if ( zabs1 ( s(l) ) ~= 0.0 )
          t = - ( conj ( transpose ( x(l:n,l) ) ) * x(l:n,j) ) / x(l,l);
          x(l:n,j) = x(l:n,j) + t * x(l:n,l);
        end
      end
%
%  Place the L-th row of X into E for the
%  subsequent calculation of the row transformation.
%
      e(j) = conj ( x(l,j) );

    end
%
%  Place the transformation in U for subsequent back multiplication.
%
    if ( wantu & l <= nct )
      u(l:n,l) = x(l:n,l);
    end

    if ( l <= nrt )
%
%  Compute the L-th row transformation and place the
%  L-th super-diagonal in E(L).
%
      e(l) = dznrm2 ( p-l, e(l+1:p), 1 );

      if ( zabs1 ( e(l) ) ~= 0.0 )

        if ( zabs1 ( e(l+1) ) ~= 0.0 )
          e(l) = zsign2 ( e(l), e(l+1) );
        end

        e(l+1:p) = e(l+1:p) / e(l);
        e(l+1) = 1.0 + e(l+1);

      end

      e(l) = -conj ( e(l) );
%
%  Apply the transformation.
%
      if ( l+1 <= n & zabs1 ( e(l) ) ~= 0.0 );

        work(l+1:n) = 0.0;

        for j = l+1 : p
          work(l+1:n) = work(l+1:n) + e(j) * transpose ( x(l+1:n,j) );
        end

        for j = l+1 : p
          x(l+1:n,j) = x(l+1:n,j) ...
            + conj ( -e(j) / e(l+1) ) * transpose ( work(l+1:n) );
        end

      end
%
%  Place the transformation in V for subsequent back multiplication.
%
      if ( wantv )
        v(l+1:p,l) = transpose ( e(l+1:p) );
      end

    end

  end
%
%  Set up the final bidiagonal matrix of order M.
%
  m = min ( p, n + 1 );
  nctp1 = nct + 1;
  nrtp1 = nrt + 1;

  if ( nct < p )
    s(nctp1) = x(nctp1,nctp1);
  end

  if ( n < m )
    s(m) = 0.0;
  end

  if ( nrtp1 < m )
    e(nrtp1) = x(nrtp1,m);
  end

  e(m) = 0.0;
%
%  If required, generate U.
%
  if ( wantu )

    for j = nctp1 : ncu
      u(1:n,j) = 0.0;
      u(j,j) = 1.0;
    end

    for ll = 1 : nct

      l = nct - ll + 1;

      if ( zabs1 ( s(l) ) ~= 0.0 )

        for j = l+1 : ncu
          t = - ( conj ( transpose ( 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

        u(l:n,l) = - u(l:n,l);
        u(l,l) = 1.0 + u(l,l);
        u(1:l-1,l) = 0.0;

      else

        u(1:n,l) = 0.0;
        u(l,l) = 1.0;

      end

    end

  end
%
%  If it is required, generate V.
%
  if ( wantv )

    for ll = 1 : p

      l = p - ll + 1;

      if ( l <= nrt )

        if ( zabs1 ( e(l) ) ~= 0.0 )
          for j = l+1 : p
            t = - ( conj ( transpose ( v(l+1:p,l) ) ) * v(l+1:p,j) ) / v(l+1,l);
            v(l+1:p,j) = v(l+1:p,j) + t * v(l+1:p,l);
          end
        end

      end

      v(1:p,l) = 0.0;
      v(l,l) = 1.0;

    end

  end
%
%  Transform S and E so that they are real.
%
  for i = 1 : m

    if ( zabs1 ( s(i) ) ~= 0.0 )

      t = abs ( s(i) );
      r = s(i) / t;
      s(i) = t;

      if ( i < m )
        e(i) = e(i) / r;
      end

      if ( wantu )
        u(1:n,i) = u(1:n,i) * r;
      end

    end

    if ( i == m )
      break
    end

    if ( zabs1 ( e(i) ) ~= 0.0 )

      t = abs ( e(i) );
      r = t / e(i);
      e(i) = t;
      s(i+1) = s(i+1) * r;

      if ( wantv )
        v(1:p,i+1) = v(1:p,i+1) * r;
      end

    end

  end
%
%  Main iteration loop for the singular values.
%
  mm = m;
  iter = 0;

  while ( 1 )
%
%  Quit if all the singular values have been found.
%
    if ( m == 0 )
      break
    end
%
%  If too many iterations have been performed, set flag and return.
%
    if ( maxit <= iter )
      info = m;
      break
    end
%
%  This section of the program inspects for negligible elements in S and E.
%
%  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).
%
    for ll = 1 : m

      l = m - ll;

      if ( l == 0 )
        break
      end

      test = abs ( s(l) ) + abs ( s(l+1) );
      ztest = test + abs ( e(l) );

      if ( ztest == test )
        e(l) = 0.0;
        break
      end

    end

    if ( l == m - 1 )

      kase = 4;

    else

      mp1 = m + 1;

      for lls = l+1 : mp1

        ls = m - lls + l + 1;

        if ( ls == l )
          break
        end

        test = 0.0;

        if ( ls ~= m )
          test = test + abs ( e(ls) );
        end

        if ( ls ~= l + 1 )
          test = test + abs ( e(ls-1) );
        end

        ztest = test + abs ( s(ls) );

        if ( ztest == test )
          s(ls) = 0.0;
          break
        end

      end

      if ( ls == l )
        kase = 3;
      elseif ( ls == m )
        kase = 1;
      else
        kase = 2;
        l = ls;
      end

    end

    l = l + 1;
%
%  Deflate negligible S(M).
%
    if ( kase == 1 )

      mm1 = m - 1;
      f = real ( e(m-1) );
      e(m-1) = 0.0;

      for kk = l : mm1

        k = mm1 - kk + l;
        t1 = real ( s(k) );
        [ cs, sn, t1, f ] = drotg ( t1, f );
        s(k) = t1;

        if ( k ~= l )
          f = -sn * real ( e(k-1) );
          e(k-1) = cs * e(k-1);
        end

        if ( wantv )
          [ v(1:p,k), v(1:p,m) ] = zdrot ( p, v(1:p,k), 1, v(1:p,m), 1, cs, sn );
        end

      end
%
%  Split at negligible S(L).
%
    elseif ( kase == 2 )

      f = real ( e(l-1) );
      e(l-1) = 0.0;

      for k = l : m

        t1 = real ( s(k) );
        [ cs, sn, t1, f ] = drotg ( t1, f );
        s(k) = t1;
        f = -sn * real ( e(k) );
        e(k) = cs * e(k);

        if ( wantu )
          [ u(1:n,k), u(1:n,l-1) ] = zdrot ( n, u(1:n,k), 1, u(1:n,l-1), 1, cs, sn );
        end

      end
%
%  Perform one QR step.
%
    elseif ( kase == 3 )
%
%  Calculate the shift.
%
      scale = max ( abs ( s(m) ), ...
              max ( abs ( s(m-1) ), ...
              max ( abs ( e(m-1) ), ...
              max ( abs ( s(l) ), abs ( e(l) ) ) ) ) );

      sm = real ( s(m) ) / scale;
      smm1 = real ( s(m-1) ) / scale;
      emm1 = real ( e(m-1) ) / scale;
      sl = real ( s(l) ) / scale;
      el = real ( e(l) ) / scale;
      b = ( ( smm1 + sm ) * ( smm1 - sm ) + emm1^2 ) / 2.0;
      c = ( sm * emm1 )^2;
      shift = 0.0;

      if ( b ~= 0.0 | c ~= 0.0 )
        shift = sqrt ( b^2 + c );
        if ( b < 0.0 )
          shift = -shift;
        end
        shift = c / ( b + shift );
      end

      f = ( sl + sm ) * ( sl - sm ) + shift;
      g = sl * el;
%
%  Chase zeros.
%
      mm1 = m - 1;

      for k = l : mm1

        [ cs, sn, f, g ] = drotg ( f, g );

        if ( k ~= l )
          e(k-1) = f;
        end

        f = cs * real ( s(k) ) + sn * real ( e(k) );
        e(k) = cs * e(k) - sn * s(k);
        g = sn * real ( s(k+1) );
        s(k+1) = cs * s(k+1);

        if ( wantv )
          [ v(1:p,k), v(1:p,k+1) ] = zdrot ( p, v(1:p,k), 1, v(1:p,k+1), 1, cs, sn );
        end

        [ cs, sn, f, g ] = drotg ( f, g );
        s(k) = f;
        f = cs * real ( e(k) ) + sn * real ( s(k+1) );
        s(k+1) = -sn * e(k) + cs * s(k+1);
        g = sn * real ( e(k+1) );
        e(k+1) = cs * e(k+1);

        if ( wantu & k < n )
          [ u(1:n,k), u(1:n,k+1) ] = zdrot ( n, u(1:n,k), 1, u(1:n,k+1), 1, cs, sn );
        end

      end

      e(m-1) = f;
      iter = iter + 1;
%
%  Convergence.
%
    elseif ( kase == 4 )
%
%  Make the singular value positive.
%
      if ( real ( s(l) ) < 0.0 )
        s(l) = -s(l);
        if ( wantv )
          v(1:p,l) = - v(1:p,l);
        end
      end
%
%  Order the singular values.
%
      while ( l ~= mm )

        if ( real ( s(l+1) ) <= real ( s(l) ) )
          break
        end

        t      = s(l);
        s(l)   = s(l+1);
        s(l+1) = t;

        if ( wantv & l < p )
          temp       = v(1:p,l);
          v(1:p,l)   = v(1:p,l+1);
          v(1:p,l+1) = temp;
        end

        if ( wantu & l < n )
          temp       = u(1:n,l);
          u(1:n,l)   = u(1:n,l+1);
          u(1:n,l+1) = temp;
        end

        l = l + 1;

      end

      iter = 0;
      m = m - 1;

    end

  end

  return
end
