00001
00002 #ifndef vnl_symmetric_eigensystem_txx_
00003 #define vnl_symmetric_eigensystem_txx_
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "vnl_symmetric_eigensystem.h"
00016 #include <vcl_cassert.h>
00017 #include <vcl_algorithm.h>
00018 #include <vcl_cmath.h>
00019 #include <vcl_iostream.h>
00020 #include <vnl/vnl_copy.h>
00021 #include <vnl/vnl_math.h>
00022 #include <vnl/algo/vnl_netlib.h>
00023
00024
00025
00026
00027
00028
00029
00030 template <class T>
00031 void vnl_symmetric_eigensystem_compute_eigenvals(
00032 T M11, T M12, T M13,
00033 T M22, T M23,
00034 T M33,
00035 T &l1, T &l2, T &l3)
00036 {
00037
00038
00039 const T b = -M11-M22-M33;
00040 const T c = M11*M22 +M11*M33 +M22*M33 -M12*M12 -M13*M13 -M23*M23;
00041 const T d = M11*M23*M23 +M12*M12*M33 +M13*M13*M22 -2*M12*M13*M23 -M11*M22*M33;
00042
00043
00044 const T b_3 = b/3;
00045 const T f = b_3*b_3 - c/3 ;
00046 const T g = b*c/6 - b_3*b_3*b_3 - d/2;
00047
00048 if (f == 0 && g == 0)
00049 {
00050 l1 = l2 = l3 = - b_3 ;
00051 return;
00052 }
00053
00054 const T f3 = f*f*f;
00055 const T g2 = g*g;
00056 const T sqrt_f = -vcl_sqrt(f);
00057
00058
00059
00060
00061
00062 assert((g2 - f3) / vnl_math_sqr(vnl_math_cube(b)) < 1e-8);
00063
00064 if (g2 >= f3)
00065 {
00066 if (g < 0)
00067 {
00068 l1 = 2 * sqrt_f - b_3;
00069 l2 = l3 = - sqrt_f - b_3;
00070 }
00071 else
00072 {
00073 l1 = l2 = sqrt_f - b_3;
00074 l3 = -2 * sqrt_f - b_3;
00075 }
00076 return;
00077 }
00078
00079
00080 const T sqrt_f3 = sqrt_f * sqrt_f * sqrt_f;
00081 const T k = vcl_acos(g / sqrt_f3) / 3;
00082 const T j = 2 * sqrt_f;
00083 l1 = j * vcl_cos(k) - b_3;
00084 l2 = j * vcl_cos(k + T(vnl_math::pi * 2.0 / 3.0)) - b_3;
00085 l3 = j * vcl_cos(k - T(vnl_math::pi * 2.0 / 3.0)) - b_3;
00086
00087 if (l2 < l1) vcl_swap(l2, l1);
00088 if (l3 < l2)
00089 {
00090 vcl_swap(l2, l3);
00091 if (l2 < l1) vcl_swap(l2, l1);
00092 }
00093 }
00094
00095 template <class T>
00096 bool vnl_symmetric_eigensystem_compute(vnl_matrix<T> const & A,
00097 vnl_matrix<T> & V,
00098 vnl_vector<T> & D)
00099 {
00100 A.assert_finite();
00101 const long n = A.rows();
00102
00103
00104 if (D.size() != A.rows())
00105 D.set_size(n);
00106
00107
00108 vnl_matrix<double> Ad(A.rows(), A.cols()); vnl_copy(A, Ad);
00109 vnl_vector<double> Dd(D.size());
00110 vnl_vector<double> work1(n);
00111 vnl_vector<double> work2(n);
00112 vnl_vector<double> Vvec(n*n);
00113
00114 long want_eigenvectors = 1;
00115 long ierr = 0;
00116
00117
00118 v3p_netlib_rs_(&n, &n, Ad.data_block(), &Dd[0], &want_eigenvectors, &Vvec[0], &work1[0], &work2[0], &ierr);
00119 vnl_copy(Dd, D);
00120
00121 if (ierr) {
00122 vcl_cerr << "vnl_symmetric_eigensystem: ierr = " << ierr << vcl_endl;
00123 return false;
00124 }
00125
00126
00127 if (V.rows() != A.rows() || V.cols() != A.rows())
00128 V.set_size(n,n);
00129 double *vptr = &Vvec[0];
00130 for (int c = 0; c < n; ++c)
00131 for (int r = 0; r < n; ++r)
00132 V(r,c) = T(*vptr++);
00133
00134 return true;
00135 }
00136
00137
00138
00139
00140 template <class T>
00141 vnl_symmetric_eigensystem<T>::vnl_symmetric_eigensystem(vnl_matrix<T> const& A)
00142 : n_(A.rows()), V(n_, n_), D(n_)
00143 {
00144 vnl_vector<T> Dvec(n_);
00145
00146 vnl_symmetric_eigensystem_compute(A, V, Dvec);
00147
00148
00149 for (int i = 0; i < n_; ++i)
00150 D(i,i) = Dvec[i];
00151 }
00152
00153 template <class T>
00154 vnl_vector<T> vnl_symmetric_eigensystem<T>::get_eigenvector(int i) const
00155 {
00156 return vnl_vector<T>(V.extract(n_,1,0,i).data_block(), n_);
00157 }
00158
00159 template <class T>
00160 T vnl_symmetric_eigensystem<T>::get_eigenvalue(int i) const
00161 {
00162 return D(i, i);
00163 }
00164
00165 template <class T>
00166 vnl_vector<T> vnl_symmetric_eigensystem<T>::solve(vnl_vector<T> const& b)
00167 {
00168
00169
00170 vnl_vector<T> ret(b*V);
00171
00172 vnl_vector<T> tmp(b.size());
00173 D.solve(ret, &tmp);
00174
00175 return V * tmp;
00176 }
00177
00178 template <class T>
00179 T vnl_symmetric_eigensystem<T>::determinant() const
00180 {
00181 int const n = D.size();
00182 T det(1);
00183 for (int i=0; i<n; ++i)
00184 det *= D[i];
00185 return det;
00186 }
00187
00188 template <class T>
00189 vnl_matrix<T> vnl_symmetric_eigensystem<T>::pinverse() const
00190 {
00191 unsigned n = D.rows();
00192 vnl_diag_matrix<T> invD(n);
00193 for (unsigned i=0; i<n; ++i)
00194 if (D(i, i) == 0) {
00195 vcl_cerr << __FILE__ ": pinverse(): eigenvalue " << i << " is zero.\n";
00196 invD(i, i) = 0;
00197 }
00198 else
00199 invD(i, i) = 1 / D(i, i);
00200 return V * invD * V.transpose();
00201 }
00202
00203 template <class T>
00204 vnl_matrix<T> vnl_symmetric_eigensystem<T>::square_root() const
00205 {
00206 unsigned n = D.rows();
00207 vnl_diag_matrix<T> sqrtD(n);
00208 for (unsigned i=0; i<n; ++i)
00209 if (D(i, i) < 0) {
00210 vcl_cerr << __FILE__ ": square_root(): eigenvalue " << i << " is negative (" << D(i, i) << ").\n";
00211 sqrtD(i, i) = (T)vcl_sqrt((typename vnl_numeric_traits<T>::real_t)(-D(i, i)));
00212
00213 }
00214 else
00215 sqrtD(i, i) = (T)vcl_sqrt((typename vnl_numeric_traits<T>::real_t)(D(i, i)));
00216 return V * sqrtD * V.transpose();
00217 }
00218
00219 template <class T>
00220 vnl_matrix<T> vnl_symmetric_eigensystem<T>::inverse_square_root() const
00221 {
00222 unsigned n = D.rows();
00223 vnl_diag_matrix<T> inv_sqrtD(n);
00224 for (unsigned i=0; i<n; ++i)
00225 if (D(i, i) <= 0) {
00226 vcl_cerr << __FILE__ ": square_root(): eigenvalue " << i << " is non-positive (" << D(i, i) << ").\n";
00227 inv_sqrtD(i, i) = (T)vcl_sqrt(-1.0/(typename vnl_numeric_traits<T>::real_t)(D(i, i)));
00228 }
00229 else
00230 inv_sqrtD(i, i) = (T)vcl_sqrt(1.0/(typename vnl_numeric_traits<T>::real_t)(D(i, i)));
00231 return V * inv_sqrtD * V.transpose();
00232 }
00233
00234
00235
00236 #undef VNL_SYMMETRIC_EIGENSYSTEM_INSTANTIATE
00237 #define VNL_SYMMETRIC_EIGENSYSTEM_INSTANTIATE(T) \
00238 template class vnl_symmetric_eigensystem<T >; \
00239 template void vnl_symmetric_eigensystem_compute_eigenvals(T,T,T,T,T,T,T&,T&,T&); \
00240 template bool vnl_symmetric_eigensystem_compute(vnl_matrix<T > const&, vnl_matrix<T > &, vnl_vector<T >&)
00241
00242 #endif // vnl_symmetric_eigensystem_txx_