1use crate::{Number, core::{matrix::Matrix, matrix2::Matrix2, matrix4::Matrix4, vector::Vector}, matrix, matrix2};
2use super::{qr::{ apply_Qt_givens_hess, givens_qr_upper_hessenberg }, utils::{eq_bound, eq_bound_eps_v}};
3
4
5
6pub fn eig<T: Number>(A: &Matrix<T>, precision: f64, steps: i32) -> Vec<f64> {
11
12 assert!(A.rows == A.columns, "eig: A should be square");
13
14 let s = 2;
15
16 let w = true;
17
18 let zero = T::from_f64(0.).unwrap();
19
20 let mut A = A.upper_hessenberg();
21
22 let mut q = Vec::new();
23
24 let mut x = zero;
25
26 let mut rows = A.rows;
27
28 let mut cols = A.columns;
29
30
31
32 for i in 0..steps {
33
34 if rows <= 1 && cols <= 1 {
35 let d = T::to_f64(&A[[0, 0]]).unwrap();
36 q.push(d);
37 break;
38 }
39
40 if i > 0 && (i % s) == 0 {
41 let k = rows - 2;
42
43 let a = T::to_f64(&A[[k, k]]).unwrap();
44 let b = T::to_f64(&A[[k, k + 1]]).unwrap();
45 let c = T::to_f64(&A[[k + 1, k]]).unwrap();
46 let d = T::to_f64(&A[[k + 1, k + 1]]).unwrap();
47
48 let u = c.abs();
49
50 if u < precision {
51
52 q.push(d);
53
54 rows -= 1;
55
56 cols -= 1;
57
58 } else {
59
60 if w {
61
62 let l = matrix2![
63 a, b,
64 c, d
65 ];
66
67 let r = l.eig();
68
69 if r.is_none() {
70
71 x = T::from_f64(d).unwrap();
72
73 } else {
74
75 let (e1, e2) = r.unwrap();
76
77 let d1 = e1 - d;
78
79 let d2 = e2 - d;
80
81 if d1.abs() < d2.abs() {
82 x = T::from_f64(e1).unwrap();
83 } else {
84 x = T::from_f64(e2).unwrap();
85 }
86 }
87 } else {
88 x = T::from_f64(d).unwrap();
89 }
90 }
91 }
92
93 if x != zero {
94 for j in 0..rows {
95 A[[j, j]] -= x;
96 }
97 }
98
99 let (mut R, q) = givens_qr_upper_hessenberg(A, cols);
100
101 apply_Qt_givens_hess(&mut R, &q, cols);
102
103 A = R;
104
105 if x != zero {
106 for j in 0..rows {
107 A[[j, j]] += x;
108 }
109 }
110
111 x = zero;
112 }
113
114 q
115}
116
117
118
119pub fn eigenvectors<T: Number>(A: &Matrix<T>, q: &Vec<f64>) -> Vec<(f64, Vector<T>)> {
120
121 let mut result: Vec<(f64, Vector<T>)> = Vec::new();
122
123 let b: Vector<T> = Vector::zeros(A.columns);
124
125 for i in 0..q.len() {
128
129 let A: Matrix<T> = A - &(Matrix::id(A.rows) * T::from_f64(q[i]).unwrap());
130
131 let lu = A.lu();
134
135 let x = A.solve(&b, &lu);
136
137 if x.is_some() {
138 let t = (q[i], x.unwrap());
139 result.push(t);
140 }
141 }
142
143 result
144}
145
146
147
148pub fn eig_decompose<T: Number>(A: &Matrix<T>) -> Option<(Matrix<T>, Matrix<T>, Matrix<T>)> {
149
150 let precision = f32::EPSILON as f64;
151 let steps = 1000;
152 let mut q = A.eig(precision, steps);
153 let v = A.eigenvectors(&q);
154
155 let ps: Vec<T> = v.iter().map(|t| { T::from_f64(t.0).unwrap() }).collect();
156 let ps: Vector<T> = Vector::new(ps);
157 let vs: Vec<Vector<T>> = v.iter().map(|t| { t.1.clone() }).collect();
158
159 let mut L: Matrix<T> = Matrix::new(A.rows, A.columns);
160
161 L.set_diag(ps);
162
163 let Y = Matrix::from_basis(vs);
164 let lu = Y.lu();
165 let Y_inv = Y.inv(&lu);
166
167 if Y_inv.is_none() {
168 return None;
169 }
170
171 let Y_inv = Y_inv.unwrap();
172
173 Some((Y, L, Y_inv))
174}
175
176
177
178mod tests {
179 use rand::Rng;
180 use std::{ f32::EPSILON as EP, f64::EPSILON, f64::consts::PI };
181 use crate::{ matrix, core::{matrix::Matrix, vector::Vector}};
182 use super::{ Matrix4, eq_bound, eq_bound_eps_v };
183
184
185
186 #[test]
187 fn eigenvectors_test3() {
188
189 let test = 20;
190
191 for i in 2..test {
192 let size = i;
193 let max = 5.;
194 let zero: Vector<f64> = Vector::zeros(size);
195 let mut A: Matrix<f64> = Matrix::rand_diag(size, max);
196 let mut a: Vector<f64> = A.extract_diag();
197 let S: Matrix<f64> = Matrix::rand(size, size, max);
198 let K: Matrix<f64> = A.conjugate(&S).unwrap();
199
200 let R = K.eig_decompose();
201
202 if R.is_some() {
203 let (S, Y, S_inv) = R.unwrap();
204 println!("\n K is {} \n", K);
205 println!("\n S is {} \n", S);
206 println!("\n Y is {} \n", Y);
207 println!("\n S_inv is {} \n", S_inv);
208
209 let P: Matrix<f64> = &(&S * &Y) * &S_inv;
210
211 let diff = &P - &K;
212
213 let bound = f32::EPSILON * 10.;
214
215 println!("\n ({})diff {} \n", bound, diff);
216
217 assert!(eq_bound(&K, &P, bound as f64), "\n eigenvectors_test3 K equal to P \n");
218 }
219 }
220 }
221
222
223
224 #[test]
225 fn eigenvectors_test2() {
226
227 fn round(n:&f64) -> f64 {
228 let c = (2. as f64).powf(8.);
229 (n * c).round() / c
230 }
231
232 let test = 20;
233
234 for i in 2..test {
235 let size = i;
236 let max = 5.;
237 let zero: Vector<f64> = Vector::zeros(size);
238 let mut A: Matrix<f64> = Matrix::rand_diag(size, max);
239 let mut a = A.extract_diag();
240 let S: Matrix<f64> = Matrix::rand(size, size, max);
241 let K: Matrix<f64> = A.conjugate(&S).unwrap();
242 let precision = f32::EPSILON as f64;
243 let steps = 1000;
244 let mut q = K.eig(precision, steps);
245 let v = K.eigenvectors(&q);
246
247 for i in 0..v.len() {
248 let (e, k) = &v[i];
249 let id: Matrix<f64> = Matrix::id(size);
250 let M: Matrix<f64> = id * *e;
251 let mut y: Vector<f64> = &(&K - &M) * k;
252 y.apply(round);
253 println!("\n y {} \n", y);
254 assert!(eq_bound_eps_v(&zero, &y));
255 }
256 }
257 }
258
259
260
261 #[test]
262 fn eigenvectors_test1() {
263
264 let test = 20;
265
266 for i in 2..test {
267
268 let size = i;
269
270 let max = 5.0;
271
272 let mut K: Matrix<f64> = Matrix::rand_diag(size, max);
273
274 let precision = f32::EPSILON as f64;
275
276 let steps = 1000;
277
278 let q = K.eig(precision, steps);
279
280 let v = K.eigenvectors(&q);
281
282 let vs: Vec<Vector<f64>> = v.iter().rev().map(|t| { t.1.clone() }).collect();
283
284 let y = Matrix::from_basis(vs);
285
286 let id: Matrix<f64> = Matrix::id(size);
287
288 assert_eq!(y, id, "y == id");
289 }
290 }
291
292
293
294 #[test]
295 fn eig4() {
296
297 let m = Matrix4::rotation(0.4, 0.3, 0.2);
298 let K: Matrix<f64> = m.into();
299 let K: Matrix<f64> = K.lps(3);
300
301 let precision = f32::EPSILON as f64;
302 let steps = 10000;
303 let mut q = K.eig(precision, steps);
304
305 println!("\n K is {} \n result 3 is {:?} \n", K, q);
308
309 }
311
312
313
314 #[test]
315 fn eig3() {
316
317 let K = matrix![f64,
318 0., 0., 0., 1.;
319 1., 0., 0., 0.;
320 0., 1., 0., 0.;
321 0., 0., 1., 0.;
322 ];
323 let precision = f32::EPSILON as f64;
324 let steps = 1000;
325 let mut q = K.eig(precision, steps);
326
327 println!("\n result 2 is {:?} \n", q);
328 }
329
330
331
332 #[test]
333 fn eig2() {
334
335 let K = matrix![f64,
336 0., 1.;
337 1., 0.;
338 ];
339 let precision = f32::EPSILON as f64;
340 let steps = 1000;
341 let mut q = K.eig(precision, steps);
342
343 println!("\n result is {:?} \n", q);
344 }
345
346
347
348 #[test]
349 fn eig1() {
350
351 let test = 20;
352
353 for i in 2..test {
354 eig_test(i);
355 }
356 }
357
358
359
360 fn eig_test(i: usize) {
361
362 println!("\n eig test {} \n", i);
363
364 let f = move |x: &mut f64| -> f64 {
365 let c = (2. as f64).powf(12.);
366 (*x * c).round() / c
367 };
368
369 let size = i;
370 let max = 5.;
371 let mut A: Matrix<f64> = Matrix::rand_diag(size, max);
372 let mut a = A.extract_diag();
373 let S: Matrix<f64> = Matrix::rand(size, size, max);
374 let K: Matrix<f64> = A.conjugate(&S).unwrap();
375
376 let precision = f32::EPSILON as f64;
377 let steps = 1000;
378 let mut q = K.eig(precision, steps);
379 let mut c = Vector::new(q);
380
381 c.data = c.data.iter_mut().map(&f).collect();
382 a.data = a.data.iter_mut().map(&f).collect();
383
384 c.data.sort_by(|a, b| b.partial_cmp(a).unwrap());
385 a.data.sort_by(|a, b| b.partial_cmp(a).unwrap());
386
387 println!("\n result {:?} \n", c.data);
389 println!("\n equal {} \n", a == c);
390
391 assert_eq!(a, c, "a == c");
392 }
393}