vnl_svd.h
Go to the documentation of this file.
1 // This is core/vnl/algo/vnl_svd.h
2 #ifndef vnl_svd_h_
3 #define vnl_svd_h_
4 //:
5 // \file
6 // \brief Holds the singular value decomposition of a vnl_matrix.
7 // \author Andrew W. Fitzgibbon, Oxford IERG
8 // \date 15 Jul 96
9 //
10 // \verbatim
11 // Modifications
12 // fsm, Oxford IESRG, 26 Mar 1999
13 // 1. The singular values are now stored as reals (not complexes) when T is complex.
14 // 2. Fixed bug : for complex T, matrices have to be conjugated as well as transposed.
15 // Feb.2002 - Peter Vanroose - brief doxygen comment placed on single line
16 // \endverbatim
17 
18 #include <iosfwd>
19 #include <vnl/vnl_numeric_traits.h>
20 #include <vnl/vnl_vector.h>
21 #include <vnl/vnl_matrix.h>
22 #include <vnl/vnl_diag_matrix.h>
23 #include <vnl/algo/vnl_algo_export.h>
24 #ifdef _MSC_VER
25 # include <vcl_msvc_warnings.h>
26 #endif
27 
28 //: Holds the singular value decomposition of a vnl_matrix.
29 //
30 // The class holds three matrices U, W, V such that the original matrix
31 // $M = U W V^\top$. The DiagMatrix W stores the singular values in decreasing
32 // order. The columns of U which correspond to the nonzero singular values
33 // form a basis for range of M, while the columns of V corresponding to the
34 // zero singular values are the nullspace.
35 //
36 // The SVD is computed at construction time, and inquiries may then be made
37 // of the SVD. In particular, this allows easy access to multiple
38 // right-hand-side solves without the bother of putting all the RHS's into a
39 // Matrix.
40 //
41 // This class is supplied even though there is an existing vnl_matrix method
42 // for several reasons:
43 //
44 // It is more convenient to use as it manages all the storage for
45 // the U,S,V matrices, allowing repeated queries of the same SVD
46 // results.
47 //
48 // It avoids namespace clutter in the Matrix class. While svd()
49 // is a perfectly reasonable method for a Matrix, there are many other
50 // decompositions that might be of interest, and adding them all would
51 // make for a very large Matrix class.
52 //
53 // It demonstrates the holder model of compute class, implementing an
54 // algorithm on an object without adding a member that may not be of
55 // general interest. A similar pattern can be used for other
56 // decompositions which are not defined as members of the library Matrix
57 // class.
58 //
59 // It extends readily to n-ary operations, such as generalized
60 // eigensystems, which cannot be members of just one matrix.
61 
62 template <class T>
63 class VNL_ALGO_EXPORT vnl_svd
64 {
65  public:
66  //: The singular values of a matrix of complex<T> are of type T, not complex<T>
68 
69  //:
70  // Construct a vnl_svd<T> object from $m \times n$ matrix $M$. The
71  // vnl_svd<T> object contains matrices $U$, $W$, $V$ such that
72  // $U W V^\top = M$.
73  //
74  // Uses linpack routine DSVDC to calculate an ``economy-size'' SVD
75  // where the returned $U$ is the same size as $M$, while $W$
76  // and $V$ are both $n \times n$. This is efficient for
77  // large rectangular solves where $m > n$, typical in least squares.
78  //
79  // The optional argument zero_out_tol is used to mark the zero singular
80  // values: If nonnegative, any s.v. smaller than zero_out_tol in
81  // absolute value is set to zero. If zero_out_tol is negative, the
82  // zeroing is relative to |zero_out_tol| * sigma_max();
83 
84  vnl_svd(vnl_matrix<T> const &M, double zero_out_tol = 0.0);
85  virtual ~vnl_svd() = default;
86 
87  // Data Access---------------------------------------------------------------
88 
89  //: find weights below threshold tol, zero them out, and update W_ and Winverse_
90  void zero_out_absolute(double tol = 1e-8); //sqrt(machine epsilon)
91 
92  //: find weights below tol*max(w) and zero them out
93  void zero_out_relative(double tol = 1e-8); //sqrt(machine epsilon)
94  int singularities () const { return W_.rows() - rank(); }
95  unsigned int rank () const { return rank_; }
96  singval_t well_condition () const { return sigma_min()/sigma_max(); }
97 
98  //: Calculate determinant as product of diagonals in W.
99  singval_t determinant_magnitude () const;
100  singval_t norm() const;
101 
102  //: Return the matrix U.
103  vnl_matrix<T> & U() { return U_; }
104 
105  //: Return the matrix U.
106  vnl_matrix<T> const& U() const { return U_; }
107 
108  //: Return the matrix U's (i,j)th entry (to avoid svd.U()(i,j); ).
109  T U(int i, int j) const { return U_(i,j); }
110 
111  //: Get at DiagMatrix (q.v.) of singular values, sorted from largest to smallest
112  vnl_diag_matrix<singval_t> & W() { return W_; }
113 
114  //: Get at DiagMatrix (q.v.) of singular values, sorted from largest to smallest
115  vnl_diag_matrix<singval_t> const & W() const { return W_; }
116  vnl_diag_matrix<singval_t> & Winverse() { return Winverse_; }
117  vnl_diag_matrix<singval_t> const & Winverse() const { return Winverse_; }
118  singval_t & W(int i, int j) { return W_(i,j); }
119  singval_t & W(int i) { return W_(i,i); }
120  singval_t sigma_max() const { return W_(0,0); } // largest
121  singval_t sigma_min() const { return W_(n_-1,n_-1); } // smallest
122 
123  //: Return the matrix V.
124  vnl_matrix<T> & V() { return V_; }
125 
126  //: Return the matrix V.
127  vnl_matrix<T> const& V() const { return V_; }
128 
129  //: Return the matrix V's (i,j)th entry (to avoid svd.V()(i,j); ).
130  T V(int i, int j) const { return V_(i,j); }
131 
132  //:
133  inline vnl_matrix<T> inverse () const { return pinverse(); }
134 
135  //: pseudo-inverse (for non-square matrix) of desired rank.
136  vnl_matrix<T> pinverse (unsigned int rank = ~0u) const; // ~0u == (unsigned int)-1
137 
138  //: Calculate inverse of transpose, using desired rank.
139  vnl_matrix<T> tinverse (unsigned int rank = ~0u) const; // ~0u == (unsigned int)-1
140 
141  //: Recompose SVD to U*W*V', using desired rank.
142  vnl_matrix<T> recompose (unsigned int rank = ~0u) const; // ~0u == (unsigned int)-1
143 
144  //: Solve the matrix equation M X = B, returning X
145  vnl_matrix<T> solve (vnl_matrix<T> const& B) const;
146 
147  //: Solve the matrix-vector system M x = y, returning x.
148  vnl_vector<T> solve (vnl_vector<T> const& y) const;
149  void solve (T const *rhs, T *lhs) const; // min ||A*lhs - rhs||
150 
151  //: Solve the matrix-vector system M x = y.
152  // Assuming that the singular values W have been preinverted by the caller.
153  void solve_preinverted(vnl_vector<T> const& rhs, vnl_vector<T>* out) const;
154 
155  //: Return N such that M * N = 0
156  vnl_matrix<T> nullspace() const;
157 
158  //: Return N such that M' * N = 0
159  vnl_matrix<T> left_nullspace() const;
160 
161  //: Return N such that M * N = 0
162  vnl_matrix<T> nullspace(int required_nullspace_dimension) const;
163 
164  //: Implementation to be done yet; currently returns left_nullspace(). - PVR.
165  vnl_matrix<T> left_nullspace(int required_nullspace_dimension) const;
166 
167  //: Return the rightmost column of V.
168  // Does not check to see whether or not the matrix actually was rank-deficient -
169  // the caller is assumed to have examined W and decided that to his or her satisfaction.
170  vnl_vector<T> nullvector() const;
171 
172  //: Return the rightmost column of U.
173  // Does not check to see whether or not the matrix actually was rank-deficient.
174  vnl_vector<T> left_nullvector() const;
175 
176  bool valid() const { return valid_; }
177 
178  private:
179 
180  int m_, n_; // Size of M, local cache.
181  vnl_matrix<T> U_; // Columns Ui are basis for range of M for Wi != 0
182  vnl_diag_matrix<singval_t> W_;// Singular values, sorted in decreasing order
184  vnl_matrix<T> V_; // Columns Vi are basis for nullspace of M for Wi = 0
185  unsigned rank_;
186  bool have_max_;
188  bool have_min_;
190  double last_tol_;
191  bool valid_; // false if the NETLIB call failed.
192 
193  // Disallow assignment.
194  vnl_svd(vnl_svd<T> const &) { }
195  vnl_svd<T>& operator=(vnl_svd<T> const &) { return *this; }
196 };
197 
198 template <class T>
199 inline
201 {
202  return vnl_svd<T>(m).inverse();
203 }
204 
205 template <class T>
206 std::ostream& operator<<(std::ostream&, vnl_svd<T> const& svd);
207 
208 #endif // vnl_svd_h_
unsigned int rank() const
Definition: vnl_svd.h:95
vnl_matrix< T > U_
Definition: vnl_svd.h:181
An ordinary mathematical matrix.
bool valid() const
Definition: vnl_svd.h:176
double last_tol_
Definition: vnl_svd.h:190
vnl_svd< T > & operator=(vnl_svd< T > const &)
Definition: vnl_svd.h:195
Templated zero/one/precision.
singval_t well_condition() const
Definition: vnl_svd.h:96
singval_t min_
Definition: vnl_svd.h:189
vnl_diag_matrix< singval_t > const & Winverse() const
Definition: vnl_svd.h:117
vnl_matrix< T > & U()
Return the matrix U.
Definition: vnl_svd.h:103
#define m
Definition: vnl_vector.h:43
vnl_diag_matrix< singval_t > Winverse_
Definition: vnl_svd.h:183
singval_t sigma_min() const
Definition: vnl_svd.h:121
vnl_matrix< T > inverse() const
Definition: vnl_svd.h:133
singval_t & W(int i)
Definition: vnl_svd.h:119
bool valid_
Definition: vnl_svd.h:191
vnl_matrix< T > V_
Definition: vnl_svd.h:184
singval_t max_
Definition: vnl_svd.h:187
std::ostream & operator<<(std::ostream &s, vnl_decnum const &r)
decimal output.
Definition: vnl_decnum.h:393
vnl_diag_matrix< singval_t > W_
Definition: vnl_svd.h:182
int n_
Definition: vnl_svd.h:180
singval_t & W(int i, int j)
Definition: vnl_svd.h:118
vnl_diag_matrix< singval_t > & Winverse()
Definition: vnl_svd.h:116
vnl_matrix< T > const & V() const
Return the matrix V.
Definition: vnl_svd.h:127
T V(int i, int j) const
Return the matrix V's (i,j)th entry (to avoid svd.V()(i,j); ).
Definition: vnl_svd.h:130
An ordinary mathematical matrix.
Definition: vnl_adjugate.h:22
bool have_max_
Definition: vnl_svd.h:186
Mathematical vector class, templated by type of element.
Definition: vnl_fwd.h:16
vnl_matrix< T > const & U() const
Return the matrix U.
Definition: vnl_svd.h:106
vnl_matrix< T > & V()
Return the matrix V.
Definition: vnl_svd.h:124
vnl_svd(vnl_svd< T > const &)
Definition: vnl_svd.h:194
Contains class for diagonal matrices.
singval_t sigma_max() const
Definition: vnl_svd.h:120
unsigned rank_
Definition: vnl_svd.h:185
Holds the singular value decomposition of a vnl_matrix.
Definition: vnl_algo_fwd.h:7
bool have_min_
Definition: vnl_svd.h:188
vnl_numeric_traits< T >::abs_t singval_t
The singular values of a matrix of complex<T> are of type T, not complex<T>.
Definition: vnl_svd.h:67
vnl_matrix< T > vnl_svd_inverse(vnl_matrix< T > const &m)
Definition: vnl_svd.h:200
vnl_diag_matrix< singval_t > & W()
Get at DiagMatrix (q.v.) of singular values, sorted from largest to smallest.
Definition: vnl_svd.h:112
vnl_diag_matrix< singval_t > const & W() const
Get at DiagMatrix (q.v.) of singular values, sorted from largest to smallest.
Definition: vnl_svd.h:115
T U(int i, int j) const
Return the matrix U's (i,j)th entry (to avoid svd.U()(i,j); ).
Definition: vnl_svd.h:109
int singularities() const
Definition: vnl_svd.h:94