1use crate::maps::faer_bridge;
2
3pub trait HasExpMap: Sized {
4 type Algebra: Clone + PartialEq;
5 fn exp(x: &Self::Algebra) -> Self;
6 fn log(&self) -> Option<Self::Algebra>;
7}
8
9pub trait MatrixExpMap: HasExpMap {
10 fn matrix_data(x: &Self::Algebra) -> (alloc::vec::Vec<f64>, usize);
11 fn from_matrix_data(data: alloc::vec::Vec<f64>, n: usize) -> Self;
12 fn algebra_from_matrix_data(data: alloc::vec::Vec<f64>, n: usize) -> Self::Algebra;
13 fn to_matrix_data(&self) -> (alloc::vec::Vec<f64>, usize);
14}
15
16impl<T: MatrixExpMap> HasExpMap for T {
17 type Algebra = T::Algebra;
18 fn exp(x: &Self::Algebra) -> Self {
19 let (data, n) = T::matrix_data(x);
20 let result = faer_bridge::matrix_exp(&data, n);
21 T::from_matrix_data(result, n)
22 }
23 fn log(&self) -> Option<Self::Algebra> {
24 let (data, n) = self.to_matrix_data();
25 let result = faer_bridge::matrix_log(&data, n)?;
26 Some(T::algebra_from_matrix_data(result, n))
27 }
28}
29
30pub fn exp_log_roundtrip_error(
31 data: &[f64],
32 n: usize,
33) -> Option<f64> {
34 let exp_data = faer_bridge::matrix_exp(data, n);
35 let log_data = faer_bridge::matrix_log(&exp_data, n)?;
36 let max_err = data.iter()
37 .zip(log_data.iter())
38 .map(|(a, b)| libm::fabs(a - b))
39 .fold(0.0f64, f64::max);
40 Some(max_err)
41}
42
43pub fn log_exp_roundtrip_error(
44 data: &[f64],
45 n: usize,
46) -> Option<f64> {
47 let log_data = faer_bridge::matrix_log(data, n)?;
48 let exp_data = faer_bridge::matrix_exp(&log_data, n);
49 let max_err = data.iter()
50 .zip(exp_data.iter())
51 .map(|(a, b)| libm::fabs(a - b))
52 .fold(0.0f64, f64::max);
53 Some(max_err)
54}