vnl_svd_economy.hxx
Go to the documentation of this file.
1 // This is core/vnl/algo/vnl_svd_economy.hxx
2 #ifndef vnl_svd_economy_hxx_
3 #define vnl_svd_economy_hxx_
4 
5 #include <iostream>
6 #include <algorithm>
7 #include <cmath>
8 #include "vnl_svd_economy.h"
9 
10 #ifdef _MSC_VER
11 # include <vcl_msvc_warnings.h>
12 #endif
13 
14 #include <vnl/vnl_fortran_copy.h>
15 #include <vnl/algo/vnl_netlib.h> // dsvdc_()
16 #include <vnl/vnl_matlab_print.h>
17 
18 #define macro(p, T) \
19 inline void vnl_linpack_svdc_economy(vnl_netlib_svd_proto(T)) \
20 { v3p_netlib_##p##svdc_(vnl_netlib_svd_params); }
21 macro(s, float);
22 macro(d, double);
23 macro(c, std::complex<float>);
24 macro(z, std::complex<double>);
25 #undef macro
26 
27 template <class real_t>
29  m_(M.rows()), n_(M.columns()),
30  V_(n_,n_),
31  sv_(n_)
32 {
34 
35  int mm = std::min(m_+1L,n_);
36 
37  // Make workspace vectors.
38  vnl_vector<real_t> work(m_, real_t(0));
39  vnl_vector<real_t> vspace(n_*n_, real_t(0));
40  vnl_vector<real_t> wspace(mm, real_t(0)); // complex fortran routine actually _wants_ complex W!
41  vnl_vector<real_t> espace(n_, real_t(0));
42 
43  // Call Linpack SVD
44  long ldu = 0;
45  long info = 0;
46  constexpr long job = 01; // no U, n svs in V (i.e. super-economy size)
47  vnl_linpack_svdc_economy((real_t*)X, &m_, &m_, &n_,
48  wspace.data_block(),
49  espace.data_block(),
50  nullptr, &ldu,
51  vspace.data_block(), &n_,
52  work.data_block(),
53  &job, &info);
54 
55  // Error return?
56  if (info != 0)
57  {
58  // If info is non-zero, it contains the number of singular values
59  // for this the SVD algorithm failed to converge. The condition is
60  // not bogus. Even if the returned singular values are sensible,
61  // the singular vectors can be utterly wrong.
62 
63  // It is possible the failure was due to NaNs or infinities in the
64  // matrix. Check for that now.
65  M.assert_finite();
66 
67  // If we get here it might be because
68  // 1. The scalar type has such
69  // extreme precision that too few iterations were performed to
70  // converge to within machine precision (that is the svdc criterion).
71  // One solution to that is to increase the maximum number of
72  // iterations in the netlib code.
73  //
74  // 2. The LINPACK dsvdc_ code expects correct IEEE rounding behaviour,
75  // which some platforms (notably x86 processors)
76  // have trouble doing. For example, gcc can output
77  // code in -O2 and static-linked code that causes this problem.
78  // One solution to this is to persuade gcc to output slightly different code
79  // by adding and -fPIC option to the command line for v3p\netlib\dsvdc.c. If
80  // that doesn't work try adding -ffloat-store, which should fix the problem
81  // at the expense of being significantly slower for big problems. Note that
82  // if this is the cause, core/vnl/tests/test_svd should have failed.
83  //
84  // You may be able to diagnose the problem here by printing a warning message.
85  std::cerr << __FILE__ ": suspicious return value (" << info << ") from SVDC\n"
86  << __FILE__ ": M is " << M.rows() << 'x' << M.cols() << std::endl;
87 
89  // valid_ = false;
90  }
91 
92  for (int j = 0; j < mm; ++j)
93  sv_[j] = std::abs(wspace(j)); // we get rid of complexness here.
94 
95  for (int j = mm; j < n_; ++j)
96  sv_[j] = 0;
97 
98  {
99  const real_t *d = vspace.data_block();
100  for (int j = 0; j < n_; ++j)
101  for (int i = 0; i < n_; ++i)
102  V_[i][j] = *(d++);
103  }
104 }
105 
106 template <class real_t>
109 {
110  return V_.get_column( n_ - 1 );
111 }
112 
113 
114 #undef VNL_SVD_ECONOMY_INSTANTIATE
115 #define VNL_SVD_ECONOMY_INSTANTIATE(T) \
116 template class VNL_ALGO_EXPORT vnl_svd_economy<T >
117 
118 #endif // vnl_svd_economy_hxx_
unsigned int cols() const
Return the number of columns.
Definition: vnl_matrix.h:183
void assert_finite() const
abort if matrix contains any INFs or NANs.
Definition: vnl_matrix.h:582
Print matrices and vectors in nice MATLAB format.
vnl_vector< singval_t > sv_
#define macro(p, T)
vnl_svd_economy(vnl_matrix< real_t > const &M)
T const * data_block() const
Access the contiguous block storing the elements in the vector. O(1).
Definition: vnl_vector.h:230
vnl_vector< real_t > nullvector()
Return the rightmost column of V.
SVD wrapper that doesn't compute the left singular vectors, U.
Convert row-stored matrix to column-stored.
VNL_EXPORT std::ostream & vnl_matlab_print(std::ostream &, T const *array, unsigned length, vnl_matlab_print_format=vnl_matlab_print_format_default)
print a 1D array.
Declare in a central place the list of symbols from netlib.
Convert row-stored matrix to column-stored.
Mathematical vector class, templated by type of element.
Definition: vnl_fwd.h:16
vnl_matrix< real_t > V_
vnl_bignum abs(vnl_bignum const &x)
Definition: vnl_bignum.h:432
unsigned int rows() const
Return the number of rows.
Definition: vnl_matrix.h:179
vnl_decnum min(vnl_decnum const &x, vnl_decnum const &y)
Definition: vnl_decnum.h:413