#![cfg(all(feature = "matrix", feature = "rational"))]
use puremp::{Int, Matrix, Rational};
fn mi(rows: usize, cols: usize, d: &[i64]) -> Matrix<Int> {
Matrix::new(rows, cols, d.iter().map(|&x| Int::from(x)).collect())
}
fn mr(rows: usize, cols: usize, d: &[i64]) -> Matrix<Rational> {
Matrix::new(rows, cols, d.iter().map(|&x| Rational::from(x)).collect())
}
#[test]
fn ring_operations() {
let a = mi(2, 2, &[1, 2, 3, 4]);
let b = mi(2, 2, &[5, 6, 7, 8]);
assert_eq!(&a * &b, mi(2, 2, &[19, 22, 43, 50]));
assert_eq!(&a + &b, mi(2, 2, &[6, 8, 10, 12]));
assert_eq!(a.transpose(), mi(2, 2, &[1, 3, 2, 4]));
assert_eq!(&a * &Matrix::<Int>::identity(2), a);
}
#[test]
fn integer_determinant_bareiss() {
assert_eq!(mi(2, 2, &[1, 2, 3, 4]).determinant().to_string(), "-2");
assert_eq!(
mi(3, 3, &[6, 1, 1, 4, -2, 5, 2, 8, 7])
.determinant()
.to_string(),
"-306"
);
assert_eq!(
mi(3, 3, &[1, 2, 3, 4, 5, 6, 7, 8, 9])
.determinant()
.to_string(),
"0"
);
assert_eq!(Matrix::<Int>::identity(5).determinant().to_string(), "1");
}
#[test]
fn rational_inverse_solve_rank() {
let a = mr(2, 2, &[4, 7, 2, 6]);
let inv = a.inverse().unwrap();
assert_eq!(&a * &inv, Matrix::<Rational>::identity(2));
assert_eq!(a.determinant().to_string(), "10");
let m = mr(2, 2, &[2, 1, 1, 3]);
let x = m.solve(&[Rational::from(1), Rational::from(2)]).unwrap();
assert_eq!(x[0].to_string(), "1/5");
assert_eq!(x[1].to_string(), "3/5");
let s = mr(2, 2, &[1, 2, 2, 4]);
assert!(s.inverse().is_none());
assert_eq!(s.rank(), 1);
assert_eq!(mr(3, 3, &[1, 0, 0, 0, 1, 0, 0, 0, 1]).rank(), 3);
}
#[test]
fn fraction_free_inverse_solve_with_pivots() {
let m = mr(3, 3, &[0, 1, 2, 1, 0, 3, 4, 5, 0]);
let inv = m.inverse().expect("nonsingular");
assert_eq!(&m * &inv, Matrix::<Rational>::identity(3));
let x = m
.solve(&[Rational::from(1), Rational::from(2), Rational::from(3)])
.unwrap();
for i in 0..3 {
let mut acc = Rational::ZERO;
for (j, xj) in x.iter().enumerate() {
acc = acc.add(&m.get(i, j).mul(xj));
}
assert_eq!(acc, Rational::from((i + 1) as i64));
}
let mf = mr(2, 2, &[0, 3, 2, 5]).scalar_mul(&Rational::new(1.into(), 3.into()));
assert_eq!(
&mf * &mf.inverse().unwrap(),
Matrix::<Rational>::identity(2)
);
assert!(mr(2, 2, &[1, 2, 2, 4]).inverse().is_none());
assert!(mr(2, 2, &[0, 0, 1, 2]).inverse().is_none());
}