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
|