argmin_math/nalgebra_m/
inv.rs1use crate::{Allocator, ArgminInv, Error};
9use nalgebra::{
10 base::{dimension::Dim, storage::Storage},
11 ComplexField, DefaultAllocator, OMatrix, SquareMatrix,
12};
13use std::fmt;
14
15#[derive(Debug, thiserror::Error, PartialEq)]
16struct InverseError;
17
18impl fmt::Display for InverseError {
19 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20 write!(f, "Non-invertible matrix")
21 }
22}
23
24impl<N, D, S> ArgminInv<OMatrix<N, D, D>> for SquareMatrix<N, D, S>
25where
26 N: ComplexField,
27 D: Dim,
28 S: Storage<N, D, D>,
29 DefaultAllocator: Allocator<N, D, D>,
30{
31 #[inline]
32 fn inv(&self) -> Result<OMatrix<N, D, D>, Error> {
33 match self.clone_owned().try_inverse() {
34 Some(m) => Ok(m),
35 None => Err(InverseError {}.into()),
36 }
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43 use approx::assert_relative_eq;
44 use nalgebra::Matrix2;
45 use paste::item;
46
47 macro_rules! make_test {
48 ($t:ty) => {
49 item! {
50 #[test]
51 fn [<test_inv_ $t>]() {
52 let a = Matrix2::new(
53 2 as $t, 5 as $t,
54 1 as $t, 3 as $t,
55 );
56 let target = Matrix2::new(
57 3 as $t, -5 as $t,
58 -1 as $t, 2 as $t,
59 );
60 let res = <Matrix2<$t> as ArgminInv<Matrix2<$t>>>::inv(&a).unwrap();
61 for i in 0..2 {
62 for j in 0..2 {
63 assert_relative_eq!(res[(i, j)], target[(i, j)], epsilon = $t::EPSILON);
64 }
65 }
66 }
67 }
68
69 item! {
70 #[test]
71 fn [<test_inv_error $t>]() {
72 let a = Matrix2::new(
73 2 as $t, 5 as $t,
74 4 as $t, 10 as $t,
75 );
76 let err = <Matrix2<$t> as ArgminInv<Matrix2<$t>>>::inv(&a).unwrap_err().downcast::<InverseError>().unwrap();
77 assert_eq!(err, InverseError {});
78 assert_eq!(format!("{}", err), "Non-invertible matrix");
79 assert_eq!(format!("{:?}", err), "InverseError");
80 }
81 }
82 };
83 }
84
85 make_test!(f32);
86 make_test!(f64);
87}