annotate armadillo-3.900.4/include/armadillo_bits/fn_eig.hpp @ 84:55a047986812 tip

Update library URI so as not to be document-local
author Chris Cannam
date Wed, 22 Apr 2020 14:21:57 +0100
parents 1ec0e2823891
children
rev   line source
Chris@49 1 // Copyright (C) 2008-2012 NICTA (www.nicta.com.au)
Chris@49 2 // Copyright (C) 2008-2012 Conrad Sanderson
Chris@49 3 // Copyright (C) 2009 Edmund Highcock
Chris@49 4 // Copyright (C) 2011 Stanislav Funiak
Chris@49 5 //
Chris@49 6 // This Source Code Form is subject to the terms of the Mozilla Public
Chris@49 7 // License, v. 2.0. If a copy of the MPL was not distributed with this
Chris@49 8 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
Chris@49 9
Chris@49 10
Chris@49 11 //! \addtogroup fn_eig
Chris@49 12 //! @{
Chris@49 13
Chris@49 14
Chris@49 15 //
Chris@49 16 // symmetric/hermitian matrices
Chris@49 17 //
Chris@49 18
Chris@49 19
Chris@49 20 //! Eigenvalues of real/complex symmetric/hermitian matrix X
Chris@49 21 template<typename T1>
Chris@49 22 inline
Chris@49 23 bool
Chris@49 24 eig_sym
Chris@49 25 (
Chris@49 26 Col<typename T1::pod_type>& eigval,
Chris@49 27 const Base<typename T1::elem_type,T1>& X,
Chris@49 28 const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
Chris@49 29 )
Chris@49 30 {
Chris@49 31 arma_extra_debug_sigprint();
Chris@49 32 arma_ignore(junk);
Chris@49 33
Chris@49 34 // unwrap_check not used as T1::elem_type and T1::pod_type may not be the same.
Chris@49 35 // furthermore, it doesn't matter if X is an alias of eigval, as auxlib::eig_sym() makes a copy of X
Chris@49 36
Chris@49 37 const bool status = auxlib::eig_sym(eigval, X);
Chris@49 38
Chris@49 39 if(status == false)
Chris@49 40 {
Chris@49 41 eigval.reset();
Chris@49 42 arma_bad("eig_sym(): failed to converge", false);
Chris@49 43 }
Chris@49 44
Chris@49 45 return status;
Chris@49 46 }
Chris@49 47
Chris@49 48
Chris@49 49
Chris@49 50 //! Eigenvalues of real/complex symmetric/hermitian matrix X
Chris@49 51 template<typename T1>
Chris@49 52 inline
Chris@49 53 Col<typename T1::pod_type>
Chris@49 54 eig_sym
Chris@49 55 (
Chris@49 56 const Base<typename T1::elem_type,T1>& X,
Chris@49 57 const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
Chris@49 58 )
Chris@49 59 {
Chris@49 60 arma_extra_debug_sigprint();
Chris@49 61 arma_ignore(junk);
Chris@49 62
Chris@49 63 Col<typename T1::pod_type> out;
Chris@49 64 const bool status = auxlib::eig_sym(out, X);
Chris@49 65
Chris@49 66 if(status == false)
Chris@49 67 {
Chris@49 68 out.reset();
Chris@49 69 arma_bad("eig_sym(): failed to converge");
Chris@49 70 }
Chris@49 71
Chris@49 72 return out;
Chris@49 73 }
Chris@49 74
Chris@49 75
Chris@49 76
Chris@49 77 //! Eigenvalues and eigenvectors of real/complex symmetric/hermitian matrix X
Chris@49 78 template<typename T1>
Chris@49 79 inline
Chris@49 80 bool
Chris@49 81 eig_sym
Chris@49 82 (
Chris@49 83 Col<typename T1::pod_type>& eigval,
Chris@49 84 Mat<typename T1::elem_type>& eigvec,
Chris@49 85 const Base<typename T1::elem_type,T1>& X,
Chris@49 86 const char* method = "",
Chris@49 87 const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
Chris@49 88 )
Chris@49 89 {
Chris@49 90 arma_extra_debug_sigprint();
Chris@49 91 arma_ignore(junk);
Chris@49 92
Chris@49 93 arma_debug_check( void_ptr(&eigval) == void_ptr(&eigvec), "eig_sym(): eigval is an alias of eigvec" );
Chris@49 94
Chris@49 95 bool use_divide_and_conquer = false;
Chris@49 96
Chris@49 97 const char sig = method[0];
Chris@49 98
Chris@49 99 switch(sig)
Chris@49 100 {
Chris@49 101 case '\0':
Chris@49 102 case 's':
Chris@49 103 break;
Chris@49 104
Chris@49 105 case 'd':
Chris@49 106 use_divide_and_conquer = true;
Chris@49 107 break;
Chris@49 108
Chris@49 109 default:
Chris@49 110 {
Chris@49 111 arma_stop("eig_sym(): unknown method specified");
Chris@49 112 return false;
Chris@49 113 }
Chris@49 114 }
Chris@49 115
Chris@49 116 const bool status = (use_divide_and_conquer == false) ? auxlib::eig_sym(eigval, eigvec, X) : auxlib::eig_sym_dc(eigval, eigvec, X);
Chris@49 117
Chris@49 118 if(status == false)
Chris@49 119 {
Chris@49 120 eigval.reset();
Chris@49 121 eigvec.reset();
Chris@49 122 arma_bad("eig_sym(): failed to converge", false);
Chris@49 123 }
Chris@49 124
Chris@49 125 return status;
Chris@49 126 }
Chris@49 127
Chris@49 128
Chris@49 129
Chris@49 130 //
Chris@49 131 // general matrices
Chris@49 132 //
Chris@49 133
Chris@49 134
Chris@49 135
Chris@49 136 //! Eigenvalues and eigenvectors (both left and right) of general real/complex square matrix X
Chris@49 137 template<typename T1>
Chris@49 138 inline
Chris@49 139 bool
Chris@49 140 eig_gen
Chris@49 141 (
Chris@49 142 Col< std::complex<typename T1::pod_type> >& eigval,
Chris@49 143 Mat<typename T1::elem_type>& l_eigvec,
Chris@49 144 Mat<typename T1::elem_type>& r_eigvec,
Chris@49 145 const Base<typename T1::elem_type,T1>& X,
Chris@49 146 const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
Chris@49 147 )
Chris@49 148 {
Chris@49 149 arma_extra_debug_sigprint();
Chris@49 150 arma_ignore(junk);
Chris@49 151
Chris@49 152 arma_debug_check
Chris@49 153 (
Chris@49 154 ((&l_eigvec) == (&r_eigvec)),
Chris@49 155 "eig_gen(): l_eigvec is an alias of r_eigvec"
Chris@49 156 );
Chris@49 157
Chris@49 158 arma_debug_check
Chris@49 159 (
Chris@49 160 (
Chris@49 161 (((void*)(&eigval)) == ((void*)(&l_eigvec)))
Chris@49 162 ||
Chris@49 163 (((void*)(&eigval)) == ((void*)(&r_eigvec)))
Chris@49 164 ),
Chris@49 165 "eig_gen(): eigval is an alias of l_eigvec or r_eigvec"
Chris@49 166 );
Chris@49 167
Chris@49 168 const bool status = auxlib::eig_gen(eigval, l_eigvec, r_eigvec, X, 'b');
Chris@49 169
Chris@49 170 if(status == false)
Chris@49 171 {
Chris@49 172 eigval.reset();
Chris@49 173 l_eigvec.reset();
Chris@49 174 r_eigvec.reset();
Chris@49 175 arma_bad("eig_gen(): failed to converge", false);
Chris@49 176 }
Chris@49 177
Chris@49 178 return status;
Chris@49 179 }
Chris@49 180
Chris@49 181
Chris@49 182
Chris@49 183 //! Eigenvalues and eigenvectors of general real square matrix X.
Chris@49 184 //! Optional argument 'side' specifies which eigenvectors should be computed:
Chris@49 185 //! 'r' for right (default) and 'l' for left.
Chris@49 186 template<typename eT, typename T1>
Chris@49 187 inline
Chris@49 188 bool
Chris@49 189 eig_gen
Chris@49 190 (
Chris@49 191 Col< std::complex<eT> >& eigval,
Chris@49 192 Mat< std::complex<eT> >& eigvec,
Chris@49 193 const Base<eT, T1>& X,
Chris@49 194 const char side = 'r',
Chris@49 195 const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
Chris@49 196 )
Chris@49 197 {
Chris@49 198 arma_extra_debug_sigprint();
Chris@49 199 arma_ignore(junk);
Chris@49 200
Chris@49 201 //std::cout << "real" << std::endl;
Chris@49 202
Chris@49 203 arma_debug_check( ( ((void*)(&eigval)) == ((void*)(&eigvec)) ), "eig_gen(): eigval is an alias of eigvec" );
Chris@49 204
Chris@49 205 Mat<eT> dummy_eigvec;
Chris@49 206 Mat<eT> tmp_eigvec;
Chris@49 207
Chris@49 208 bool status;
Chris@49 209
Chris@49 210 switch(side)
Chris@49 211 {
Chris@49 212 case 'r':
Chris@49 213 status = auxlib::eig_gen(eigval, dummy_eigvec, tmp_eigvec, X, side);
Chris@49 214 break;
Chris@49 215
Chris@49 216 case 'l':
Chris@49 217 status = auxlib::eig_gen(eigval, tmp_eigvec, dummy_eigvec, X, side);
Chris@49 218 break;
Chris@49 219
Chris@49 220 default:
Chris@49 221 arma_stop("eig_gen(): parameter 'side' is invalid");
Chris@49 222 status = false;
Chris@49 223 }
Chris@49 224
Chris@49 225 if(status == false)
Chris@49 226 {
Chris@49 227 eigval.reset();
Chris@49 228 eigvec.reset();
Chris@49 229 arma_bad("eig_gen(): failed to converge", false);
Chris@49 230 }
Chris@49 231 else
Chris@49 232 {
Chris@49 233 const uword n = eigval.n_elem;
Chris@49 234
Chris@49 235 if(n > 0)
Chris@49 236 {
Chris@49 237 eigvec.set_size(n,n);
Chris@49 238
Chris@49 239 for(uword j=0; j<n; ++j)
Chris@49 240 {
Chris@49 241 if( (j < n-1) && (eigval[j] == std::conj(eigval[j+1])) )
Chris@49 242 {
Chris@49 243 // eigvec.col(j) = Mat< std::complex<eT> >( tmp_eigvec.col(j), tmp_eigvec.col(j+1) );
Chris@49 244 // eigvec.col(j+1) = Mat< std::complex<eT> >( tmp_eigvec.col(j), -tmp_eigvec.col(j+1) );
Chris@49 245
Chris@49 246 for(uword i=0; i<n; ++i)
Chris@49 247 {
Chris@49 248 eigvec.at(i,j) = std::complex<eT>( tmp_eigvec.at(i,j), tmp_eigvec.at(i,j+1) );
Chris@49 249 eigvec.at(i,j+1) = std::complex<eT>( tmp_eigvec.at(i,j), -tmp_eigvec.at(i,j+1) );
Chris@49 250 }
Chris@49 251
Chris@49 252 ++j;
Chris@49 253 }
Chris@49 254 else
Chris@49 255 {
Chris@49 256 // eigvec.col(i) = tmp_eigvec.col(i);
Chris@49 257
Chris@49 258 for(uword i=0; i<n; ++i)
Chris@49 259 {
Chris@49 260 eigvec.at(i,j) = std::complex<eT>(tmp_eigvec.at(i,j), eT(0));
Chris@49 261 }
Chris@49 262
Chris@49 263 }
Chris@49 264 }
Chris@49 265 }
Chris@49 266 }
Chris@49 267
Chris@49 268 return status;
Chris@49 269 }
Chris@49 270
Chris@49 271
Chris@49 272
Chris@49 273 //! Eigenvalues and eigenvectors of general complex square matrix X
Chris@49 274 //! Optional argument 'side' specifies which eigenvectors should be computed:
Chris@49 275 //! 'r' for right (default) and 'l' for left.
Chris@49 276 template<typename T, typename T1>
Chris@49 277 inline
Chris@49 278 bool
Chris@49 279 eig_gen
Chris@49 280 (
Chris@49 281 Col<std::complex<T> >& eigval,
Chris@49 282 Mat<std::complex<T> >& eigvec,
Chris@49 283 const Base<std::complex<T>, T1>& X,
Chris@49 284 const char side = 'r',
Chris@49 285 const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
Chris@49 286 )
Chris@49 287 {
Chris@49 288 arma_extra_debug_sigprint();
Chris@49 289 arma_ignore(junk);
Chris@49 290
Chris@49 291 //std::cout << "complex" << std::endl;
Chris@49 292
Chris@49 293 arma_debug_check( ( ((void*)(&eigval)) == ((void*)(&eigvec)) ), "eig_gen(): eigval is an alias of eigvec" );
Chris@49 294
Chris@49 295 Mat< std::complex<T> > dummy_eigvec;
Chris@49 296
Chris@49 297 bool status;
Chris@49 298
Chris@49 299 switch(side)
Chris@49 300 {
Chris@49 301 case 'r':
Chris@49 302 status = auxlib::eig_gen(eigval, dummy_eigvec, eigvec, X, side);
Chris@49 303 break;
Chris@49 304
Chris@49 305 case 'l':
Chris@49 306 status = auxlib::eig_gen(eigval, eigvec, dummy_eigvec, X, side);
Chris@49 307 break;
Chris@49 308
Chris@49 309 default:
Chris@49 310 arma_stop("eig_gen(): parameter 'side' is invalid");
Chris@49 311 status = false;
Chris@49 312 }
Chris@49 313
Chris@49 314 if(status == false)
Chris@49 315 {
Chris@49 316 eigval.reset();
Chris@49 317 eigvec.reset();
Chris@49 318 arma_bad("eig_gen(): failed to converge", false);
Chris@49 319 }
Chris@49 320
Chris@49 321 return status;
Chris@49 322 }
Chris@49 323
Chris@49 324
Chris@49 325
Chris@49 326 //! @}
Chris@49 327