00001
00002 #ifndef vnl_svd_fixed_txx_
00003 #define vnl_svd_fixed_txx_
00004
00005
00006
00007 #include "vnl_svd_fixed.h"
00008
00009 #include <vcl_cassert.h>
00010 #include <vcl_cstdlib.h>
00011 #include <vcl_complex.h>
00012 #include <vcl_iostream.h>
00013 #include <vcl_algorithm.h>
00014
00015 #include <vnl/vnl_math.h>
00016 #include <vnl/vnl_fortran_copy_fixed.h>
00017 #include <vnl/algo/vnl_netlib.h>
00018
00019
00020 #define macro(p, T) \
00021 inline void vnl_linpack_svdc_fixed(vnl_netlib_svd_proto(T)) \
00022 { v3p_netlib_##p##svdc_(vnl_netlib_svd_params); }
00023 macro(s, float);
00024 macro(d, double);
00025 macro(c, vcl_complex<float>);
00026 macro(z, vcl_complex<double>);
00027 #undef macro
00028
00029
00030
00031 static bool vnl_svd_fixed_test_heavily = false;
00032 #include <vnl/vnl_matlab_print.h>
00033
00034 template <class T, unsigned int R, unsigned int C>
00035 vnl_svd_fixed<T,R,C>::vnl_svd_fixed(vnl_matrix_fixed<T,R,C> const& M, double zero_out_tol)
00036 {
00037 {
00038 const long n=R, p=C;
00039 const unsigned mm = vcl_min(R+1u,C);
00040
00041
00042
00043 vnl_fortran_copy_fixed<T,R,C> X(M);
00044
00045
00046 vnl_vector_fixed<T, C> work(T(0));
00047 vnl_vector_fixed<T, R*C> uspace(T(0));
00048 vnl_vector_fixed<T, C*C> vspace(T(0));
00049 vnl_vector_fixed<T, (R+1<C?R+1:C)> wspace(T(0));
00050 vnl_vector_fixed<T, C> espace(T(0));
00051
00052
00053 long info = 0;
00054 const long job = 21;
00055 vnl_linpack_svdc_fixed((T*)X, &n, &n, &p,
00056 wspace.data_block(),
00057 espace.data_block(),
00058 uspace.data_block(), &n,
00059 vspace.data_block(), &p,
00060 work.data_block(),
00061 &job, &info);
00062
00063
00064 if (info != 0)
00065 {
00066
00067
00068
00069
00070
00071
00072
00073 M.assert_finite();
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093 vcl_cerr << __FILE__ ": suspicious return value (" << info << ") from SVDC\n"
00094 << __FILE__ ": M is " << M.rows() << 'x' << M.cols() << vcl_endl;
00095
00096 vnl_matlab_print(vcl_cerr, M, "M", vnl_matlab_print_format_long);
00097 valid_ = false;
00098 }
00099 else
00100 valid_ = true;
00101
00102
00103 {
00104 const T *d = uspace.data_block();
00105 for (long j = 0; j < p; ++j)
00106 for (long i = 0; i < n; ++i)
00107 U_(i,j) = *d++;
00108 }
00109
00110 for (unsigned j = 0; j < mm; ++j)
00111 W_(j, j) = vcl_abs(wspace(j));
00112
00113 for (unsigned j = mm; j < C; ++j)
00114 W_(j, j) = 0;
00115
00116 {
00117 const T *d = vspace.data_block();
00118 for (unsigned j = 0; j < C; ++j)
00119 for (unsigned i = 0; i < C; ++i)
00120 V_(i,j) = *d++;
00121 }
00122 }
00123
00124 if (vnl_svd_fixed_test_heavily)
00125 {
00126
00127 typedef typename vnl_numeric_traits<T>::abs_t abs_t;
00128 abs_t recomposition_residual = vcl_abs((recompose() - M).fro_norm());
00129 abs_t n = vcl_abs(M.fro_norm());
00130 abs_t thresh = abs_t(R) * abs_t(vnl_math::eps) * n;
00131 if (recomposition_residual > thresh)
00132 {
00133 vcl_cerr << "vnl_svd_fixed<T>::vnl_svd_fixed<T>() -- Warning, recomposition_residual = "
00134 << recomposition_residual << vcl_endl
00135 << "fro_norm(M) = " << n << vcl_endl
00136 << "eps*fro_norm(M) = " << thresh << vcl_endl
00137 << "Press return to continue\n";
00138 char x;
00139 vcl_cin.get(&x, 1, '\n');
00140 }
00141 }
00142
00143 if (zero_out_tol >= 0)
00144
00145 zero_out_absolute(double(+zero_out_tol));
00146 else
00147
00148 zero_out_relative(double(-zero_out_tol));
00149 }
00150
00151 template <class T, unsigned int R, unsigned int C>
00152 vcl_ostream& operator<<(vcl_ostream& s, const vnl_svd_fixed<T,R,C>& svd)
00153 {
00154 s << "vnl_svd_fixed<T,R,C>:\n"
00155 #if 0
00156 << "M = [\n" << M << "]\n"
00157 #endif // 0
00158 << "U = [\n" << svd.U() << "]\n"
00159 << "W = " << svd.W() << '\n'
00160 << "V = [\n" << svd.V() << "]\n"
00161 << "rank = " << svd.rank() << vcl_endl;
00162 return s;
00163 }
00164
00165
00166
00167
00168
00169 template <class T, unsigned int R, unsigned int C>
00170 void vnl_svd_fixed<T,R,C>::zero_out_absolute(double tol)
00171 {
00172 last_tol_ = tol;
00173 rank_ = C;
00174 for (unsigned k = 0; k < C; k++)
00175 {
00176 singval_t& weight = W_(k, k);
00177 if (vcl_abs(weight) <= tol)
00178 {
00179 Winverse_(k,k) = 0;
00180 weight = 0;
00181 --rank_;
00182 }
00183 else
00184 {
00185 Winverse_(k,k) = singval_t(1.0)/weight;
00186 }
00187 }
00188 }
00189
00190
00191 template <class T, unsigned int R, unsigned int C>
00192 void vnl_svd_fixed<T,R,C>::zero_out_relative(double tol)
00193 {
00194 zero_out_absolute(tol * vcl_abs(sigma_max()));
00195 }
00196
00197 static bool wf=false;
00198 inline bool warned_f() { if (wf) return true; else { wf=true; return false; } }
00199
00200
00201 template <class T, unsigned int R, unsigned int C>
00202 typename vnl_svd_fixed<T,R,C>::singval_t vnl_svd_fixed<T,R,C>::determinant_magnitude() const
00203 {
00204 if (!warned_f() && R != C)
00205 vcl_cerr << __FILE__ ": called determinant_magnitude() on SVD of non-square matrix\n"
00206 << "(This warning is displayed only once)\n";
00207 singval_t product = W_(0, 0);
00208 for (unsigned long k = 1; k < C; k++)
00209 product *= W_(k, k);
00210
00211 return product;
00212 }
00213
00214 template <class T, unsigned int R, unsigned int C>
00215 typename vnl_svd_fixed<T,R,C>::singval_t vnl_svd_fixed<T,R,C>::norm() const
00216 {
00217 return vcl_abs(sigma_max());
00218 }
00219
00220
00221 template <class T, unsigned int R, unsigned int C>
00222 vnl_matrix_fixed<T,R,C> vnl_svd_fixed<T,R,C>::recompose(unsigned int rnk) const
00223 {
00224 if (rnk > rank_) rnk=rank_;
00225 vnl_diag_matrix_fixed<T,C> Wmatr(W_);
00226 for (unsigned int i=rnk;i<C;++i)
00227 Wmatr(i,i)=0;
00228
00229 return U_*Wmatr*V_.conjugate_transpose();
00230 }
00231
00232
00233
00234 template <class T, unsigned int R, unsigned int C>
00235 vnl_matrix_fixed<T,C,R> vnl_svd_fixed<T,R,C>::pinverse(unsigned int rnk) const
00236 {
00237 if (rnk > rank_) rnk=rank_;
00238 vnl_diag_matrix_fixed<T,C> W_inverse(Winverse_);
00239 for (unsigned int i=rnk;i<C;++i)
00240 W_inverse(i,i)=0;
00241
00242 return V_ * W_inverse * U_.conjugate_transpose();
00243 }
00244
00245
00246
00247 template <class T, unsigned int R, unsigned int C>
00248 vnl_matrix_fixed<T,R,C> vnl_svd_fixed<T,R,C>::tinverse(unsigned int rnk) const
00249 {
00250 if (rnk > rank_) rnk=rank_;
00251 vnl_diag_matrix_fixed<T,C> W_inverse(Winverse_);
00252 for (unsigned int i=rnk;i<C;++i)
00253 W_inverse(i,i)=0;
00254
00255 return U_ * W_inverse * V_.conjugate_transpose();
00256 }
00257
00258
00259
00260 template <class T, unsigned int R, unsigned int C>
00261 vnl_matrix<T> vnl_svd_fixed<T,R,C>::solve(vnl_matrix<T> const& B) const
00262 {
00263 vnl_matrix<T> x;
00264 if (U_.rows() < U_.columns()) {
00265 vnl_matrix<T> yy(U_.rows(), B.columns(), T(0));
00266 yy.update(B);
00267 x = U_.conjugate_transpose() * yy;
00268 }
00269 else
00270 x = U_.conjugate_transpose() * B;
00271 for (unsigned long i = 0; i < x.rows(); ++i) {
00272 T weight = W_(i, i);
00273 if (weight != T(0))
00274 weight = T(1) / weight;
00275 for (unsigned long j = 0; j < x.columns(); ++j)
00276 x(i, j) *= weight;
00277 }
00278 x = V_ * x;
00279 return x;
00280 }
00281
00282
00283 template <class T, unsigned int R, unsigned int C>
00284 vnl_vector_fixed<T, C> vnl_svd_fixed<T,R,C>::solve(vnl_vector_fixed<T, R> const& y) const
00285 {
00286 vnl_vector_fixed<T, C> x;
00287 x = U_.conjugate_transpose() * y;
00288
00289 for (unsigned i = 0; i < C; i++) {
00290 T weight = W_(i, i), zero_(0);
00291 if (weight != zero_)
00292 x[i] /= weight;
00293 else
00294 x[i] = zero_;
00295 }
00296 return V_ * x;
00297 }
00298
00299 template <class T, unsigned int R, unsigned int C>
00300 void vnl_svd_fixed<T,R,C>::solve(T const *y, T *x) const
00301 {
00302 solve(vnl_vector_fixed<T, R>(y)).copy_out(x);
00303 }
00304
00305
00306
00307 template <class T, unsigned int R, unsigned int C>
00308 void vnl_svd_fixed<T,R,C>::solve_preinverted(vnl_vector_fixed<T, R> const& y, vnl_vector_fixed<T, C>* x_out) const
00309 {
00310 vnl_vector_fixed<T, C> x;
00311 x = U_.conjugate_transpose() * y;
00312 for (unsigned i = 0; i < C; i++)
00313 x[i] *= W_(i, i);
00314
00315 *x_out = V_ * x;
00316 }
00317
00318
00319
00320 template <class T, unsigned int R, unsigned int C>
00321 vnl_matrix<T> vnl_svd_fixed<T,R,C>::nullspace() const
00322 {
00323 int k = rank();
00324 if (k == C)
00325 vcl_cerr << "vnl_svd_fixed<T>::nullspace() -- Matrix is full rank." << last_tol_ << vcl_endl;
00326 return nullspace(C-k);
00327 }
00328
00329
00330
00331 template <class T, unsigned int R, unsigned int C>
00332 vnl_matrix<T> vnl_svd_fixed<T,R,C>::nullspace(int required_nullspace_dimension) const
00333 {
00334 return V_.extract(V_.rows(), required_nullspace_dimension, 0, C - required_nullspace_dimension);
00335 }
00336
00337
00338
00339 template <class T, unsigned int R, unsigned int C>
00340 vnl_matrix<T> vnl_svd_fixed<T,R,C>::left_nullspace() const
00341 {
00342 int k = rank();
00343 if (k == C)
00344 vcl_cerr << "vnl_svd_fixed<T>::left_nullspace() -- Matrix is full rank." << last_tol_ << vcl_endl;
00345 return U_.extract(U_.rows(), C-k, 0, k);
00346 }
00347
00348
00349
00350 template <class T, unsigned int R, unsigned int C>
00351 vnl_matrix<T> vnl_svd_fixed<T,R,C>::left_nullspace(int ) const
00352 {
00353 return left_nullspace();
00354 }
00355
00356
00357
00358
00359
00360
00361 template <class T, unsigned int R, unsigned int C>
00362 vnl_vector_fixed <T,C> vnl_svd_fixed<T,R,C>::nullvector() const
00363 {
00364 vnl_vector_fixed<T, C> ret;
00365 for (unsigned i = 0; i < C; ++i)
00366 ret(i) = V_(i, C-1);
00367 return ret;
00368 }
00369
00370
00371
00372
00373 template <class T, unsigned int R, unsigned int C>
00374 vnl_vector_fixed <T,R> vnl_svd_fixed<T,R,C>::left_nullvector() const
00375 {
00376 vnl_vector_fixed<T,R> ret;
00377 const unsigned col = vcl_min(R, C) - 1;
00378 for (unsigned i = 0; i < R; ++i)
00379 ret(i) = U_(i, col);
00380 return ret;
00381 }
00382
00383
00384
00385 #undef VNL_SVD_FIXED_INSTANTIATE
00386 #define VNL_SVD_FIXED_INSTANTIATE(T , R , C ) \
00387 template class vnl_svd_fixed<T, R, C >; \
00388 template vcl_ostream& operator<<(vcl_ostream &, vnl_svd_fixed<T, R, C > const &)
00389
00390 #endif // vnl_svd_fixed_txx_