comparison armadillo-3.900.4/include/armadillo_bits/fn_eig.hpp @ 49:1ec0e2823891

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