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