qfall_math/integer/mat_z/
inverse.rs1use super::MatZ;
12use crate::{rational::MatQ, traits::MatrixDimensions};
13use flint_sys::fmpq_mat::fmpq_mat_inv;
14
15impl MatZ {
16 pub fn inverse(&self) -> Option<MatQ> {
29 if self.get_num_rows() != self.get_num_columns() {
31 return None;
32 }
33
34 let mut out = MatQ::new(self.get_num_rows(), self.get_num_columns());
36 match unsafe { fmpq_mat_inv(&mut out.matrix, &MatQ::from(self).matrix) } {
37 0 => None,
38 _ => Some(out),
39 }
40 }
41}
42
43#[cfg(test)]
44mod test_inverse {
45 use crate::{integer::MatZ, rational::MatQ};
46 use std::str::FromStr;
47
48 #[test]
50 fn inverse_works() {
51 let mat_1 = MatZ::from_str("[[5, 2, 0],[2, 1, 0],[0, 0, 1]]").unwrap();
52 let mat_2 = MatZ::from_str(&format!("[[{}]]", i64::MAX)).unwrap();
53 let mat_3 = MatZ::from_str("[[-1, 0],[0, 1]]").unwrap();
54
55 let cmp_inv_1 = MatQ::from_str("[[1, -2, 0],[-2, 5, 0],[0, 0, 1]]").unwrap();
56 let cmp_inv_2 = MatQ::from_str(&format!("[[1/{}]]", i64::MAX)).unwrap();
57 let cmp_inv_3 = MatQ::from_str("[[-1, 0],[0, 1]]").unwrap();
58
59 let inv_1 = mat_1.inverse().unwrap();
60 let inv_2 = mat_2.inverse().unwrap();
61 let inv_3 = mat_3.inverse().unwrap();
62
63 assert_eq!(cmp_inv_1, inv_1);
64 assert_eq!(cmp_inv_2, inv_2);
65 assert_eq!(cmp_inv_3, inv_3);
66 }
67
68 #[test]
70 fn inverse_correct() {
71 let mat = MatZ::from_str("[[5, 2],[2, 1]]").unwrap();
72 let mat_q = MatQ::from(&mat);
73 let cmp = MatQ::identity(2, 2);
74
75 let inv = mat.inverse().unwrap();
76 let diag = &mat_q * &inv;
77
78 assert_eq!(cmp, diag);
79 }
80
81 #[test]
83 fn inv_none_not_squared() {
84 let mat_1 = MatZ::from_str("[[1, 0, 1],[0, 1, 1]]").unwrap();
85 let mat_2 = MatZ::from_str("[[1, 0],[0, 1],[1, 0]]").unwrap();
86
87 assert!(mat_1.inverse().is_none());
88 assert!(mat_2.inverse().is_none());
89 }
90
91 #[test]
93 fn inv_none_det_zero() {
94 let mat = MatZ::from_str("[[2, 0],[0, 0]]").unwrap();
95
96 assert!(mat.inverse().is_none());
97 }
98}