#[cfg(test)] mod tests { //https://github.com/scipy/scipy/blob/c1372d8aa90a73d8a52f135529293ff4edb98fc8/scipy/sparse/linalg/tests/test_matfuncs.py #[test] fn exp_static() { use nalgebra::{Matrix1, Matrix2, Matrix3}; { let m = Matrix1::new(1.0); let f = m.exp(); assert!(relative_eq!(f, Matrix1::new(1_f64.exp()), epsilon = 1.0e-7)); } { let m = Matrix2::new(0.0, 1.0, 0.0, 0.0); assert!(relative_eq!( m.exp(), Matrix2::new(1.0, 1.0, 0.0, 1.0), epsilon = 1.0e-7 )); } { let a: f64 = 1.0; let b: f64 = 2.0; let c: f64 = 3.0; let d: f64 = 4.0; let m = Matrix2::new(a, b, c, d); let delta = ((a - d).powf(2.0) + 4.0 * b * c).sqrt(); let delta_2 = delta / 2.0; let ad_2 = (a + d) / 2.0; let m11 = ad_2.exp() * (delta * delta_2.cosh() + (a - d) * delta_2.sinh()); let m12 = 2.0 * b * ad_2.exp() * delta_2.sinh(); let m21 = 2.0 * c * ad_2.exp() * delta_2.sinh(); let m22 = ad_2.exp() * (delta * delta_2.cosh() + (d - a) * delta_2.sinh()); let f = Matrix2::new(m11, m12, m21, m22) / delta; assert!(relative_eq!(f, m.exp(), epsilon = 1.0e-7)); } { // https://mathworld.wolfram.com/MatrixExponential.html use rand::{ distributions::{Distribution, Uniform}, thread_rng, }; let mut rng = thread_rng(); let dist = Uniform::new(-10.0, 10.0); loop { let a: f64 = dist.sample(&mut rng); let b: f64 = dist.sample(&mut rng); let c: f64 = dist.sample(&mut rng); let d: f64 = dist.sample(&mut rng); let m = Matrix2::new(a, b, c, d); let delta_sq = (a - d).powf(2.0) + 4.0 * b * c; if delta_sq < 0.0 { continue; } let delta = delta_sq.sqrt(); let delta_2 = delta / 2.0; let ad_2 = (a + d) / 2.0; let m11 = ad_2.exp() * (delta * delta_2.cosh() + (a - d) * delta_2.sinh()); let m12 = 2.0 * b * ad_2.exp() * delta_2.sinh(); let m21 = 2.0 * c * ad_2.exp() * delta_2.sinh(); let m22 = ad_2.exp() * (delta * delta_2.cosh() + (d - a) * delta_2.sinh()); let f = Matrix2::new(m11, m12, m21, m22) / delta; println!("a: {}", m); assert!(relative_eq!(f, m.exp(), epsilon = 1.0e-7)); break; } } { let m = Matrix3::new(1.0, 3.0, 0.0, 0.0, 1.0, 5.0, 0.0, 0.0, 2.0); let e1 = 1.0_f64.exp(); let e2 = 2.0_f64.exp(); let f = Matrix3::new( e1, 3.0 * e1, 15.0 * (e2 - 2.0 * e1), 0.0, e1, 5.0 * (e2 - e1), 0.0, 0.0, e2, ); assert!(relative_eq!(f, m.exp(), epsilon = 1.0e-7)); } } #[test] fn exp_dynamic() { use nalgebra::DMatrix; let m = DMatrix::from_row_slice(3, 3, &[1.0, 3.0, 0.0, 0.0, 1.0, 5.0, 0.0, 0.0, 2.0]); let e1 = 1.0_f64.exp(); let e2 = 2.0_f64.exp(); let f = DMatrix::from_row_slice( 3, 3, &[ e1, 3.0 * e1, 15.0 * (e2 - 2.0 * e1), 0.0, e1, 5.0 * (e2 - e1), 0.0, 0.0, e2, ], ); assert!(relative_eq!(f, m.exp(), epsilon = 1.0e-7)); } #[test] fn exp_complex() { use nalgebra::{Complex, DMatrix, DVector, Matrix2, RealField}; { let z = Matrix2::>::zeros(); let identity = Matrix2::>::identity(); assert!((z.exp() - identity).norm() < 1e-7); } { let a = Matrix2::>::new( Complex::::new(0.0, 1.0), Complex::::new(0.0, 2.0), Complex::::new(0.0, -1.0), Complex::::new(0.0, 3.0), ); let b = Matrix2::>::new( Complex::::new(0.42645929666726, 1.89217550966333), Complex::::new(-2.13721484276556, -0.97811251808259), Complex::::new(1.06860742138278, 0.48905625904129), Complex::::new(-1.7107555460983, 0.91406299158075), ); assert!((a.exp() - b).norm() < 1.0e-07); } { let d1 = Complex::::new(0.0, ::pi()); let d2 = Complex::::new(0.0, ::frac_pi_2()); let d3 = Complex::::new(0.0, ::frac_pi_4()); let m = DMatrix::>::from_diagonal(&DVector::from_row_slice(&[d1, d2, d3])); let res = DMatrix::>::from_diagonal(&DVector::from_row_slice(&[ d1.exp(), d2.exp(), d3.exp(), ])); assert!((m.exp() - res).norm() < 1e-07); } } }