use lager::{isclose::IsClose, Matrix}; #[test] fn index_matrices() { let mtx = Matrix::new([[1., 2., 3.], [4., 5., 6.], [7., 8., 9.]]); assert_eq!(mtx[[0, 0]], 1.); assert_eq!(mtx[[0, 2]], 3.); assert_eq!(mtx[[2, 0]], 7.); assert_eq!(mtx[[2, 2]], 9.); } #[test] fn check_matrices_are_close() { let mtx1 = Matrix::new([[4.4, 7.3, 2.5], [2.4, 6.4, 2.2], [9.5, 3.5, 4.6]]); let mtx2 = Matrix::new([ [4.40004, 7.299998, 2.50002], [2.39998, 6.400001, 2.19998], [9.50006, 3.499997, 4.60004], ]); assert!(mtx1.isclose(&mtx2)); } #[test] fn multiply_3x3_identity_matrices() { let i3 = Matrix::new([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]); let res = i3.mul(&i3); assert!(res.isclose(&i3)); } #[test] fn multiply_2x2_matrices_elementwise() { let mtx1 = Matrix::new([[1., 2.], [3., 4.]]); let mtx2 = Matrix::new([[4., 6.], [7., 5.]]); let res = mtx1 * mtx2; assert!(res.isclose(&Matrix::new([[4., 12.], [21., 20.]]))); } #[test] fn multiply_3x3_matrices() { let mtx1 = Matrix::new([[1., 2., 3.], [4., 5., 6.], [7., 8., 9.]]); let mtx2 = Matrix::new([[1., 2., 1.], [2., 4., 6.], [7., 2., 5.]]); let res = mtx1.mul(&mtx2); let expected = Matrix::new([[26., 16., 28.], [56., 40., 64.], [86., 64., 100.]]); assert!(res.isclose(&expected)); } #[test] fn multiply_matrices_different_shapes() { let mtx1 = Matrix::new([[1., 2., 3.], [4., 5., 6.]]); let mtx2 = Matrix::new([[10., 11.], [20., 21.], [30., 31.]]); let res = mtx1.mul(&mtx2); let expected = Matrix::new([[140., 146.], [320., 335.]]); assert!(res.isclose(&expected)); } #[test] fn get_view_from_matrix() { let mtx = Matrix::new([[1., 2., 3.], [4., 5., 6.]]); let slice = mtx.view([0..2, 1..3]); let slice_mtx: Matrix = slice.into(); let expected = Matrix::new([[2., 3.], [5., 6.]]); assert!(slice_mtx.isclose(&expected)); } #[test] fn view_iterator_column() { let mtx = Matrix::new([[1., 2., 3.], [4., 5., 6.], [7., 8., 9.]]); let slice = mtx.view::<3, 1>([0..3, 1..2]); let mut iter = slice.iter(); assert_eq!(Some(&2.), iter.next()); assert_eq!(Some(&5.), iter.next()); assert_eq!(Some(&8.), iter.next()); assert_eq!(None, iter.next()); } #[test] fn view_iterator_matrix() { let mtx = Matrix::new([[1., 2., 3.], [4., 5., 6.], [7., 8., 9.]]); let slice = mtx.view::<2, 2>([1..3, 0..2]); let mut iter = slice.iter(); assert_eq!(Some(&4.), iter.next()); assert_eq!(Some(&5.), iter.next()); assert_eq!(Some(&7.), iter.next()); assert_eq!(Some(&8.), iter.next()); assert_eq!(None, iter.next()); } #[test] fn row_echelon() { let mut mtx = Matrix::new([ [2., 4., 1., 1., 0., 0.], [-1., 1., -1., 0., 1., 0.], [1., 4., 0., 0., 0., 1.], ]); mtx.into_row_echelon(); let expected = Matrix::new([ [2., 4., 1., 1., 0., 0.], [0., 3., -0.5, 0.5, 1., 0.], [0., 0., -1. / 6., -5. / 6., -2. / 3., 1.], ]); assert!(mtx.isclose(&expected)); } #[test] fn reduced_row_echelon() { let mut mtx = Matrix::new([ [2., 4., 1., 1., 0., 0.], [-1., 1., -1., 0., 1., 0.], [1., 4., 0., 0., 0., 1.], ]); mtx.into_reduced_row_echelon(); let expected = Matrix::new([ [1., 0., 0., -4., -4., 5.], [0., 1., 0., 1., 1., -1.], [0., 0., 1., 5., 4., -6.], ]); assert!(mtx.isclose(&expected)); } #[test] fn matrix_inverse() { let mtx = Matrix::new([[2., 4., 1.], [-1., 1., -1.], [1., 4., 0.]]); let result = mtx.inv(); let expected = Matrix::new([[-4., -4., 5.], [1., 1., -1.], [5., 4., -6.]]); assert!(result.isclose(&expected)); } #[test] fn hstack() { let mtx1: Matrix = Matrix::new([[2., 4., 1., 7.], [-1., 1., -1., 2.], [1., 4., 0., 9.]]); let mtx2: Matrix = Matrix::new([[-4., -4., 5.], [1., 1., -1.], [5., 4., -6.]]); let result: Matrix = mtx1.hstack(mtx2); let expected = Matrix::new([ [2., 4., 1., 7., -4., -4., 5.], [-1., 1., -1., 2., 1., 1., -1.], [1., 4., 0., 9., 5., 4., -6.], ]); assert!(result.isclose(&expected)); } #[test] fn vstack() { let mtx1: Matrix = Matrix::new([[2., 4., 1.], [-1., 1., -1.], [1., 4., 0.]]); let mtx2: Matrix = Matrix::new([[-4., -4., 5.], [1., 1., -1.], [5., 4., -6.], [7., 2., 9.]]); let result: Matrix = mtx1.vstack(mtx2); let expected = Matrix::new([ [2., 4., 1.], [-1., 1., -1.], [1., 4., 0.], [-4., -4., 5.], [1., 1., -1.], [5., 4., -6.], [7., 2., 9.], ]); assert!(result.isclose(&expected)); } #[test] fn zeros() { let result = Matrix::zeros(); let expected = Matrix::new([[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]]); assert!(result.isclose(&expected)); } #[test] fn ones() { let result = Matrix::ones(); let expected = Matrix::new([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]); assert!(result.isclose(&expected)); } #[test] fn identity_3x3() { let result = Matrix::identity(); let expected = Matrix::new([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]); assert!(result.isclose(&expected)); } #[test] fn lu_decomposition() { let mtx = Matrix::new([[2., -1., -2.], [-4., 6., 3.], [-4., -2., 8.]]); let result = mtx.lu(); assert!(result.l.is_lower_triangular()); assert!(result.u.is_upper_triangular()); assert_eq!(result.p.count(), 3); assert!(3.0_f64.isclose(result.p.sum())); assert!(mtx.isclose(&result.p.inv().mul(&result.l.mul(&result.u)))); } #[test] fn lu_decomposition_unknown_result() { // This test gives a result that doesn't match other implementations, // but still seems to give a valid result. Probably something to do with // the choice of pivots. let mtx = Matrix::new([[10., -7., 0.], [-3., 2., 6.], [5., -1., 5.]]); // What other tools give as the output, not used here // let expected = LUDecomposition { // l: Matrix::new([[1., 0., 0.], [0.5, 1., 0.], [-0.3, -0.04, 1.]]), // u: Matrix::new([[10., -7., 0.], [0., 2.5, 5.], [0., 0., 6.2]]), // p: Matrix::new([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]), // }; let result = mtx.lu(); assert!(result.l.is_lower_triangular()); assert!(result.u.is_upper_triangular()); assert_eq!(result.p.count(), 3); assert!(3.0_f64.isclose(result.p.sum())); assert!(mtx.isclose(&result.p.inv().mul(&result.l.mul(&result.u)))); } #[test] fn lu_decomposition_with_permuations() { // This test requires permutations otherwise NaNs result in the // decomposition let mtx = Matrix::new([ [0., 2., 8., 6.], [0., 0., 1., 2.], [0., 1., 0., 1.], [3., 7., 1., 0.], ]); let result = mtx.lu(); assert!(result.l.is_lower_triangular()); assert!(result.u.is_upper_triangular()); assert_eq!(result.p.count(), 4); assert!(4.0_f64.isclose(result.p.sum())); assert!(mtx.isclose(&result.p.inv().mul(&result.l.mul(&result.u)))); } #[test] fn count_3x3() { let mtx = Matrix::new([[2., 4., 1.], [0., 1., -1.], [1., 4., 0.]]); assert_eq!(mtx.count(), 7); } #[test] fn diag_3x3() { let mtx = Matrix::new([[2., 4., 1.], [0., 1., -1.], [1., 4., 0.]]); let result = mtx.diag(); let expected = Matrix::new([[2.], [1.], [0.]]); assert!(expected.isclose(&result)) } #[test] fn determinant_3x3() { let mtx: Matrix = Matrix::new([[2., 4., 1.], [-1., 1., -1.], [1., 4., 0.]]); assert!((-1.0_f64).isclose(mtx.det())); } #[test] fn determinant_4x4() { let mtx: Matrix = Matrix::new([ [4., 3., 2., 1.], [1., 10., 3., 4.], [5., 3., 2., -4.], [4., 8., 7., 9.], ]); assert!(602.0_f64.isclose(mtx.det())); } #[test] fn transpose() { let mtx = Matrix::new([[1., 2., 3.], [4., 5., 6.], [7., 8., 9.], [10., 11., 12.]]); let res = mtx.t(); let expected = Matrix::new([[1., 4., 7., 10.], [2., 5., 8., 11.], [3., 6., 9., 12.]]); assert!(res.isclose(&expected)); }