1use crate::matrix::traits::{Identity, Invertible, Matrix};
2
3use super::MatrixF32;
4
5impl Invertible for MatrixF32 {
6 fn inverse_gauss_jordan(&self) -> crate::Result<Self>
7 where
8 Self: Sized,
9 {
10 let mut matrix = self.clone(); let mut inverse = MatrixF32::id(self.rows(), self.tolerance());
12 for i in 0..self.rows() {
13 let mut pivot_row = i;
15 for j in i + 1..self.rows() {
16 if matrix.get(j, i)?.abs() > matrix.get(pivot_row, i)?.abs() {
17 pivot_row = j;
18 }
19 }
20
21 if pivot_row != i {
23 matrix.swap_rows(i, pivot_row)?;
24 inverse.swap_rows(i, pivot_row)?;
25 }
26
27 let pivot = matrix.get(i, i)?.clone();
29 if pivot.abs() < self.tolerance() {
30 return Err(crate::MathError::MatrixError(
31 "Matrix is not invertible".to_string(),
32 ));
33 }
34 for j in 0..self.columns() {
35 matrix.set(i, j, matrix.get(i, j)? / pivot)?;
36 inverse.set(i, j, inverse.get(i, j)? / pivot)?;
37 }
38
39 for j in 0..self.rows() {
41 if j != i {
42 let factor = matrix.get(j, i)?.to_owned();
43 for k in 0..self.columns() {
44 let new_value = matrix.get(j, k)? - factor * matrix.get(i, k)?;
45 matrix.set(j, k, new_value)?;
46 let new_value = inverse.get(j, k)? - factor * inverse.get(i, k)?;
47 inverse.set(j, k, new_value)?;
48 }
49 }
50 }
51 }
52 Ok(inverse)
53 }
54
55 fn inverse_montante(&self) -> crate::Result<Self>
56 where
57 Self: Sized,
58 {
59 todo!()
60 }
61
62 fn inverse_adjoint(&self) -> crate::Result<Self>
63 where
64 Self: Sized,
65 {
66 todo!()
67 }
68}
69
70#[cfg(test)]
71mod test {
72 use crate::matrix::traits::{Invertible, Parseable};
73 use crate::matrix::MatrixF32;
74 use crate::matrix_f32;
75
76 const TOL: f32 = 1e-4;
77
78 #[test]
79 fn inverse_gauss_jordan_2x2_f32() {
80 let mat_a = matrix_f32!("{{1,2},{3,4}}", TOL).unwrap();
81 let mat_a_inv = mat_a.inverse_gauss_jordan().unwrap();
82 let mat_a_inv_expected = matrix_f32!("{{-2,1},{1.5,-0.5}}", TOL).unwrap();
83 pretty_assertions::assert_eq!(mat_a_inv, mat_a_inv_expected);
84 }
85
86 #[test]
87 fn inverse_gauss_jordan_3x3_f32() {
88 let mat_a = matrix_f32!("{{1,2,3},{0,1,4},{5,6,0}}", TOL).unwrap();
89 let mat_a_inv = mat_a.inverse_gauss_jordan().unwrap();
90 let mat_a_inv_expected = matrix_f32!("{{-24,18,5},{20,-15,-4},{-5,4,1}}", TOL).unwrap();
91 pretty_assertions::assert_eq!(mat_a_inv, mat_a_inv_expected);
92 }
93
94 #[test]
95 fn inverse_gauss_jordan_4x4_f32() {
96 let mat_a = matrix_f32!("{{1,2,3,4},{0,1,4,5},{5,6,0,7},{8,9,10,0}}", TOL).unwrap();
97 let mat_a_inv = mat_a.inverse_gauss_jordan().unwrap();
98 let mat_a_inv_expected = matrix_f32!(
99 "{{-5.0736837,3.0421052,0.72631574,0.30526316},{4.9894733,-3.1368423,-0.6105262,-0.24210525},{ -0.43157893,0.38947368,-0.03157895,0.07368421},{-0.6526315,0.51578945,0.1473684,-0.010526315}}",
100 TOL
101 )
102 .unwrap();
103 pretty_assertions::assert_eq!(mat_a_inv, mat_a_inv_expected);
104 }
105
106 #[test]
107 fn inverse_gauss_jordan_5x5_f32() {
108 let mat_a = matrix_f32!(
109 "{{1,2,3,4,5},{0,1,4,5,6},{5,6,0,7,8},{8,9,10,0,11},{12,13,14,15,0}}",
110 TOL
111 )
112 .unwrap();
113 let mat_a_inv = mat_a.inverse_gauss_jordan().unwrap();
114 let mat_a_inv_expected = matrix_f32!(
115 "{{-4.25986, +2.42993, +0.55141, +0.20986, +0.06866} ,{+4.42606, -2.71303, -0.48944, -0.17606, -0.04754} ,{-0.13944, +0.16972, -0.09437, +0.03944, +0.02465} ,{-0.29789, +0.24894, +0.07113, -0.05211, +0.02993} ,{-0.39648, +0.29824, +0.08521, +0.04648, -0.03345}}",
116 TOL
117 )
118 .unwrap();
119 pretty_assertions::assert_eq!(mat_a_inv, mat_a_inv_expected);
120 }
121}