/*! solve overdetermined or underdetermined A*x=y using dgels
  with the sum of residual squares output\n
  The residual is set as the sum of residual squares 
  for overdetermined problems
  while it is always zero for underdetermined problems.
*/
inline long dgematrix::dgels(dcovector& vec, double& residual)
{
#ifdef  CPPL_VERBOSE
  std::cerr << "# [MARK] dgematrix::dgels(dcovector&, double&)"
            << std::endl;
#endif//CPPL_VERBOSE
  
#ifdef  CPPL_DEBUG
  if(M!=vec.L){
    std::cerr << "[ERROR] dgematrix::dgels(dcovector&, double&) " << std::endl
              << "These matrix and vector cannot be solved." << std::endl
              << "Your input was (" << M << "x" << N << ") and ("
              << vec.L << ")." << std::endl;
    exit(1);
  }
#endif//CPPL_DEBUG    
  
  residual=0.0;
  
  if(M<N){ //underdetermined
    dcovector tmp(N);
    for(long i=0; i<vec.L; i++){ tmp(i)=vec(i); }
    vec.clear();
    swap(vec,tmp);
  }
  
  char TRANS('N');
  long NRHS(1), LDA(M), LDB(vec.L),
    LWORK(min(M,N)+max(min(M,N),NRHS)), INFO(1);
  double *WORK(new double[LWORK]);
  dgels_(TRANS, M, N, NRHS, Array, LDA, vec.Array, LDB, WORK, LWORK, INFO);
  delete [] WORK;
  
  if(M>N){ //overdetermined
    for(long i=0; i<M-N; i++){ residual+=std::pow(vec(N+i),2.0); }
    
    dcovector tmp(N);
    for(long i=0; i<tmp.L; i++){ tmp(i)=vec(i); }
    vec.clear();
    swap(vec,tmp);
  }
  
  if(INFO!=0){
    std::cerr << "[WARNING] dgematrix::dgels(dcovector&, double&) "
              << "Serious trouble happend. INFO = " << INFO << "."
              << std::endl;
  }
  return INFO;
}
/*! calculate the least-squares-least-norm solution for overdetermined or 
  underdetermined A*x=y using dgelss\n
*/
inline long dgematrix::dgelss(dcovector& B, dcovector& S, long& RANK,
                              const double RCOND =-1. )
{
#ifdef  CPPL_VERBOSE
  std::cerr << "# [MARK] dgematrix::dgelss(dcovector&, dcovector&, long&, const double)"
            << std::endl;
#endif//CPPL_VERBOSE
  
#ifdef  CPPL_DEBUG
  if(M!=B.L){
    std::cerr << "[ERROR] dgematrix::dgelss"
              << "(dcovector&, dcovector&, long, double) " << std::endl
              << "These matrix and vector cannot be solved." << std::endl
              << "Your input was (" << M << "x" << N << ") and ("
              << B.L << ")." << std::endl;
    exit(1);
  }
#endif//CPPL_DEBUG    
  
  if(M<N){ //underdetermined
    dcovector tmp(N);
    for(long i=0; i<B.L; i++){ tmp(i)=B(i); }
    B.clear();
    swap(B,tmp);
  }
  
  S.resize(min(M,N));
  
  long NRHS(1), LDA(M), LDB(B.L),
    LWORK(3*min(M,N)+max(max(2*min(M,N),max(M,N)), NRHS)), INFO(1);
  double *WORK(new double[LWORK]);
  dgelss_(M, N, NRHS, Array, LDA, B.Array, LDB, S.Array,
          RCOND, RANK, WORK, LWORK, INFO);
  delete [] WORK;

  if(INFO!=0){
    std::cerr << "[WARNING] dgematrix::dgelss"
              << "(dcovector&, docvector&, long, const double) "
              << "Serious trouble happend. INFO = " << INFO << "."
              << std::endl;
  }
  return INFO;
}