/*---------------------------------------------------------------------------*
 *                                   IT++			                         *
 *---------------------------------------------------------------------------*
 * Copyright (c) 1995-2004 by Tony Ottosson, Thomas Eriksson, Pål Frenger,   *
 * Tobias Ringström, and Jonas Samuelsson.                                   *
 *                                                                           *
 * Permission to use, copy, modify, and distribute this software and its     *
 * documentation under the terms of the GNU General Public License is hereby *
 * granted. No representations are made about the suitability of this        *
 * software for any purpose. It is provided "as is" without expressed or     *
 * implied warranty. See the GNU General Public License for more details.    *
 *---------------------------------------------------------------------------*/

/*!
  \file
  \brief Implementation of Singular Value Decompositions
  \author Tony Ottosson

  1.17

  2004/06/16 16:03:20
*/

#include "base/svd.h"
#include "base/matfunc.h"
#include "base/elmatfunc.h"
#include "../src/base/lapack.h"

namespace itpp { 

#ifndef NO_LAPACK

  bool svd(const mat &A, vec &S)
  {
    char jobu='N', jobvt='N';
    int m, n, lda, ldu, ldvt, lwork, info;
    m = lda = ldu = A.rows();
    n = ldvt = A.cols();
    lwork = std::max(3*std::min(m,n)+std::max(m,n), 5*std::min(m,n));

    mat U, V;
    S.set_size(std::min(m,n), false);
    vec work(lwork);

    mat B(A);

    dgesvd_(&jobu, &jobvt, &m, &n, B._data(), &lda, S._data(), U._data(), &ldu, V._data(), &ldvt, work._data(), &lwork, &info);

    return (info==0);
  }

  bool svd(const cmat &A, vec &S)
  {
    char jobu='N', jobvt='N';
    int m, n, lda, ldu, ldvt, lwork, info;
    m = lda = ldu = A.rows();
    n = ldvt = A.cols();
    lwork = 2*std::min(m,n)+std::max(m,n);

    cvec U, V;
    //U.set_size(m,m, false);
    //V.set_size(n,n, false);
    S.set_size(std::min(m,n), false);
    cvec work(lwork);
    vec rwork(std::max(1, 5*std::min(m, n)));

    cmat B(A);

    zgesvd_(&jobu, &jobvt, &m, &n, B._data(), &lda, S._data(), U._data(), &ldu, V._data(), &ldvt, work._data(), &lwork, rwork._data(), &info);

    return (info==0);
  }

  bool svd(const mat &A, mat &U, vec &S, mat &V)
  {
    char jobu='A', jobvt='A';
    int m, n, lda, ldu, ldvt, lwork, info;
    m = lda = ldu = A.rows();
    n = ldvt = A.cols();
    lwork = std::max(3*std::min(m,n)+std::max(m,n), 5*std::min(m,n));

    U.set_size(m,m, false);
    V.set_size(n,n, false);
    S.set_size(std::min(m,n), false);
    vec work(lwork);

    mat B(A);

    dgesvd_(&jobu, &jobvt, &m, &n, B._data(), &lda, S._data(), U._data(), &ldu, V._data(), &ldvt, work._data(), &lwork, &info);

    V = V.T(); // This is probably slow!!!

    return (info==0);
  }

  bool svd(const cmat &A, cmat &U, vec &S, cmat &V)
  {
    char jobu='A', jobvt='A';
    int m, n, lda, ldu, ldvt, lwork, info;
    m = lda = ldu = A.rows();
    n = ldvt = A.cols();
    lwork = 2*std::min(m,n)+std::max(m,n);

    U.set_size(m,m, false);
    V.set_size(n,n, false);
    S.set_size(std::min(m,n), false);
    cvec work(lwork);
    vec rwork(std::max(1, 5*std::min(m, n)));

    cmat B(A);

    zgesvd_(&jobu, &jobvt, &m, &n, B._data(), &lda, S._data(), U._data(), &ldu, V._data(), &ldvt, work._data(), &lwork, rwork._data(), &info);

    V = V.H(); // This is slow!!!

    return (info==0);
  }

  vec svd(const mat &A)
  {
    vec S;
    svd(A, S);
    return S;
  }

  vec svd(const cmat &A)
  {
    vec S;
    svd(A, S);
    return S;
  }


#endif // NO_LAPACK

} //namespace itpp


syntax highlighted by Code2HTML, v. 0.9.1