grassmann/functions/
eig.rs

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
6//TODO collect eigenvectors
7//TODO for symmetric matrix eigenvectors should be inside Q (verify against LU)
8//TODO exceptional shifts 
9//TODO double shift
10pub 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    //println!("\n eigenvectors start b {}, rank {} \n", b, self.rank());
126
127    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        //println!("\n ({}) - {} \n", i, A.rank());
132        
133        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        //why eigenvalues are not empty ?
306
307        println!("\n K is {} \n result 3 is {:?} \n", K, q);
308
309        //assert!(false);
310    }
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 expected {:?} \n", a.data);
388        println!("\n result {:?} \n", c.data);
389        println!("\n equal {} \n", a == c);
390
391        assert_eq!(a, c, "a == c");
392    }
393}