diff --git a/src/lib.rs b/src/lib.rs index 0e0c5cc..b005e4b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -159,7 +159,7 @@ impl Matrix { } pub fn insert_column(&mut self, index: usize, data: Vec) -> Result<(), MatrixError> { - if index >= self.columns { + if index > self.columns { return Err(MatrixError::ColumnOutOfRange); } @@ -177,7 +177,7 @@ impl Matrix { } pub fn insert_rows(&mut self, index: usize, data: Vec) -> Result<(), MatrixError> { - if index >= self.rows { + if index > self.rows { return Err(MatrixError::RowOutOfRange); } @@ -367,7 +367,7 @@ impl Matrix { } let (trig_matrix, sign) = match self.gaussian_elimination() { - Err(MatrixError::FailedGauss) => return Ok(Fraction::new(0, 1).unwrap()), + Err(MatrixError::FailedGauss) => return Ok(Fraction::from(0)), Ok((matrix, sign)) => (matrix, sign), Err(err) => return Err(err), }; @@ -388,28 +388,27 @@ impl Matrix { return Err(MatrixError::NotSquared); } - let mut inverse = Matrix { + let mut augmented = Matrix { rows: self.rows, columns: self.columns, data: self.data.clone(), }; - // Inserts indentity matrix - for i in 0..inverse.rows { - // create full of 0 column - let mut new_column: Vec = vec![Fraction::from(0i64); inverse.rows]; + // construir [A | I] + for i in 0..self.rows { + let mut col = vec![Fraction::from(0); self.rows]; + col[i] = Fraction::from(1); - // at i set to 1 - new_column[i] = Fraction::from(1i64); - - inverse.insert_column(inverse.columns - 1, new_column)?; + augmented.insert_column(augmented.columns, col)?; } - let inverse = inverse.gauss_jordan_elimination()?; + // ahora debe ser 2N + assert_eq!(augmented.columns, self.columns * 2); - // Gets the interesting part that was affected by the gaussian elimination - let inverse = - inverse.sub_matrix((0, self.columns), (self.rows + 1, inverse.columns - 1))?; + let reduced = augmented.gauss_jordan_elimination()?; + + // extraer lado derecho + let inverse = reduced.sub_matrix((0, self.columns), (self.rows, self.columns * 2))?; Ok(inverse) } @@ -1798,7 +1797,7 @@ mod tests { let data = vec![Fraction::from(1), Fraction::from(2)]; - let result = m.insert_column(2, data); + let result = m.insert_column(3, data); assert!(matches!(result, Err(MatrixError::ColumnOutOfRange))); } @@ -1927,7 +1926,7 @@ mod tests { let data = vec![Fraction::from(1), Fraction::from(2)]; - let result = m.insert_rows(2, data); + let result = m.insert_rows(3, data); assert!(matches!(result, Err(MatrixError::RowOutOfRange))); } @@ -2713,4 +2712,142 @@ mod tests { assert_eq!(det_scaled, det_original * Fraction::from(2)); } + + #[test] + fn test_inverse_identity() { + let m = Matrix { + rows: 3, + columns: 3, + data: vec![ + Fraction::from(1), + Fraction::from(0), + Fraction::from(0), + Fraction::from(0), + Fraction::from(1), + Fraction::from(0), + Fraction::from(0), + Fraction::from(0), + Fraction::from(1), + ], + }; + + let inv = m.inverse().unwrap(); + + assert_eq!(inv.data, m.data); + } + + #[test] + fn test_inverse_2x2() { + let m = Matrix { + rows: 2, + columns: 2, + data: vec![ + Fraction::from(4), + Fraction::from(7), + Fraction::from(2), + Fraction::from(6), + ], + }; + + let inv = m.inverse().unwrap(); + + // inversa conocida: + // (1/det) * [ 6 -7 ; -2 4 ] , det = 10 + let expected = vec![ + Fraction::new(6, 10).unwrap(), + Fraction::new(-7, 10).unwrap(), + Fraction::new(-2, 10).unwrap(), + Fraction::new(4, 10).unwrap(), + ]; + + assert_eq!(inv.data, expected); + } + + #[test] + fn test_inverse_multiplication_identity() { + let m = Matrix { + rows: 2, + columns: 2, + data: vec![ + Fraction::from(1), + Fraction::from(2), + Fraction::from(3), + Fraction::from(4), + ], + }; + + let inv = m.inverse().unwrap(); + + let identity = (m.clone() * inv.clone()).unwrap(); + + for i in 0..2 { + for j in 0..2 { + if i == j { + assert_eq!(*identity.get(i, j).unwrap(), Fraction::from(1)); + } else { + assert!(identity.get(i, j).unwrap().is_zero()); + } + } + } + } + + #[test] + fn test_inverse_singular() { + let m = Matrix { + rows: 2, + columns: 2, + data: vec![ + Fraction::from(1), + Fraction::from(2), + Fraction::from(2), + Fraction::from(4), + ], + }; + + let res = m.inverse(); + + assert!(matches!(res, Err(MatrixError::FailedGaussJordan))); + } + + #[test] + fn test_inverse_3x3() { + let m = Matrix { + rows: 3, + columns: 3, + data: vec![ + Fraction::from(1), + Fraction::from(2), + Fraction::from(3), + Fraction::from(0), + Fraction::from(1), + Fraction::from(4), + Fraction::from(5), + Fraction::from(6), + Fraction::from(0), + ], + }; + + let inv = m.inverse().unwrap(); + + let identity = (m * inv).unwrap(); + + for i in 0..3 { + for j in 0..3 { + if i == j { + assert_eq!(*identity.get(i, j).unwrap(), Fraction::from(1)); + } else { + assert!(identity.get(i, j).unwrap().is_zero()); + } + } + } + } + + #[test] + fn test_inverse_not_squared() { + let m = Matrix::new(2, 3, Fraction::from(1)).unwrap(); + + let res = m.inverse(); + + assert!(matches!(res, Err(MatrixError::NotSquared))); + } }