core/vnl/algo/vnl_svd_economy.txx
Go to the documentation of this file.
00001 // This is core/vnl/algo/vnl_svd_economy.txx
00002 #ifndef vnl_svd_economy_txx_
00003 #define vnl_svd_economy_txx_
00004 
00005 #include "vnl_svd_economy.h"
00006 
00007 #include <vcl_iostream.h>
00008 #include <vcl_algorithm.h>
00009 #include <vcl_cmath.h> // for std::abs(double)
00010 
00011 #include <vnl/vnl_fortran_copy.h>
00012 #include <vnl/algo/vnl_netlib.h> // dsvdc_()
00013 #include <vnl/vnl_matlab_print.h>
00014 
00015 #define macro(p, T) \
00016 inline void vnl_linpack_svdc_economy(vnl_netlib_svd_proto(T)) \
00017 { v3p_netlib_##p##svdc_(vnl_netlib_svd_params); }
00018 macro(s, float);
00019 macro(d, double);
00020 macro(c, vcl_complex<float>);
00021 macro(z, vcl_complex<double>);
00022 #undef macro
00023 
00024 template <class real_t>
00025 vnl_svd_economy<real_t>::vnl_svd_economy( vnl_matrix<real_t> const& M ) :
00026   m_(M.rows()), n_(M.columns()),
00027   V_(n_,n_),
00028   sv_(n_)
00029 {
00030   vnl_fortran_copy<real_t> X(M);
00031 
00032   int mm = vcl_min(m_+1L,n_);
00033 
00034   // Make workspace vectors.
00035   vnl_vector<real_t> work(m_, real_t(0));
00036   vnl_vector<real_t> vspace(n_*n_, real_t(0));
00037   vnl_vector<real_t> wspace(mm, real_t(0)); // complex fortran routine actually _wants_ complex W!
00038   vnl_vector<real_t> espace(n_, real_t(0));
00039 
00040   // Call Linpack SVD
00041   long ldu = 0;
00042   long info = 0;
00043   const long job = 01; // no U, n svs in V (i.e. super-economy size)
00044   vnl_linpack_svdc_economy((real_t*)X, &m_, &m_, &n_,
00045                            wspace.data_block(),
00046                            espace.data_block(),
00047                            0, &ldu,
00048                            vspace.data_block(), &n_,
00049                            work.data_block(),
00050                            &job, &info);
00051 
00052   // Error return?
00053   if (info != 0)
00054   {
00055     // If info is non-zero, it contains the number of singular values
00056     // for this the SVD algorithm failed to converge. The condition is
00057     // not bogus. Even if the returned singular values are sensible,
00058     // the singular vectors can be utterly wrong.
00059 
00060     // It is possible the failure was due to NaNs or infinities in the
00061     // matrix. Check for that now.
00062     M.assert_finite();
00063 
00064     // If we get here it might be because
00065     // 1. The scalar type has such
00066     // extreme precision that too few iterations were performed to
00067     // converge to within machine precision (that is the svdc criterion).
00068     // One solution to that is to increase the maximum number of
00069     // iterations in the netlib code.
00070     //
00071     // 2. The LINPACK dsvdc_ code expects correct IEEE rounding behaviour,
00072     // which some platforms (notably x86 processors)
00073     // have trouble doing. For example, gcc can output
00074     // code in -O2 and static-linked code that causes this problem.
00075     // One solution to this is to persuade gcc to output slightly different code
00076     // by adding and -fPIC option to the command line for v3p\netlib\dsvdc.c. If
00077     // that doesn't work try adding -ffloat-store, which should fix the problem
00078     // at the expense of being significantly slower for big problems. Note that
00079     // if this is the cause, core/vnl/tests/test_svd should have failed.
00080     //
00081     // You may be able to diagnose the problem here by printing a warning message.
00082     vcl_cerr << __FILE__ ": suspicious return value (" << info << ") from SVDC\n"
00083              << __FILE__ ": M is " << M.rows() << 'x' << M.cols() << vcl_endl;
00084 
00085     vnl_matlab_print(vcl_cerr, M, "M", vnl_matlab_print_format_long);
00086     //    valid_ = false;
00087   }
00088 #if 0
00089   else
00090     valid_ = true;
00091 #endif
00092 
00093   for (int j = 0; j < mm; ++j)
00094     sv_[j] = vcl_abs(wspace(j)); // we get rid of complexness here.
00095 
00096   for (int j = mm; j < n_; ++j)
00097     sv_[j] = 0;
00098 
00099   {
00100     const real_t *d = vspace.data_block();
00101     for (int j = 0; j < n_; ++j)
00102       for (int i = 0; i < n_; ++i)
00103         V_[i][j] = *(d++);
00104   }
00105 }
00106 
00107 template <class real_t>
00108 vnl_vector<real_t>
00109 vnl_svd_economy<real_t>::nullvector()
00110 {
00111   return V_.get_column( n_ - 1 );
00112 }
00113 
00114 #undef VNL_SVD_ECONOMY_INSTANTIATE
00115 #define VNL_SVD_ECONOMY_INSTANTIATE(T) template class vnl_svd_economy<T >
00116 
00117 #endif // vnl_svd_economy_txx_