use crate::{Matrix, MatrixError, Ratio};
#[macro_export]
macro_rules! determinant_hack {
($a: ident, $b: ident, $c: ident, $d: ident) => (
$a.mul_rat($d).sub_rat(&$b.mul_rat($c))
);
(-, $a: ident, $b: ident, $c: ident, $d: ident) => (
$b.mul_rat($c).sub_rat(&$a.mul_rat($d))
);
($a: ident, $b: ident, $c: ident, $d: ident, $e: ident, $f: ident, $g: ident, $h: ident, $i: ident) => (
$a.mul_rat(&$e.mul_rat($i)).add_rat(
&$b.mul_rat(&$f.mul_rat($g))
).add_rat(
&$c.mul_rat(&$d.mul_rat($h))
).sub_rat(
&$c.mul_rat(&$e.mul_rat($g))
).sub_rat(
&$b.mul_rat(&$d.mul_rat($i))
).sub_rat(
&$a.mul_rat(&$f.mul_rat($h))
)
);
(-, $a: ident, $b: ident, $c: ident, $d: ident, $e: ident, $f: ident, $g: ident, $h: ident, $i: ident) => (
$c.mul_rat(&$e.mul_rat($g)).add_rat(
&$b.mul_rat(&$d.mul_rat($i))
).add_rat(
&$a.mul_rat(&$f.mul_rat($h))
).sub_rat(
&$a.mul_rat(&$e.mul_rat($i))
).sub_rat(
&$b.mul_rat(&$f.mul_rat($g))
).sub_rat(
&$c.mul_rat(&$d.mul_rat($h))
)
);
}
impl Matrix {
pub fn determinant(&self) -> Result<Ratio, MatrixError> {
if !self.is_square() {
return Err(MatrixError::NotSquare(self.cols, self.rows));
}
let n = self.cols;
if n < 5 {
if n < 3 {
if n == 0 {
Err(MatrixError::EmptyMatrix)
} else if n == 1 {
Ok(self.get(0, 0).clone())
} else {
Ok(self.determinant_2_by_2())
}
} else {
if n == 3 {
Ok(self.determinant_3_by_3())
} else {
Ok(self.determinant_4_by_4())
}
}
} else {
let mut result = Ratio::zero();
for j in 0..self.cols {
result.add_rat_mut(&self.get(0, j).mul_rat(&self.cofactor(0, j)));
}
Ok(result)
}
}
pub fn determinant_2_by_2(&self) -> Ratio {
let a = self.get(0, 0);
let b = self.get(0, 1);
let c = self.get(1, 0);
let d = self.get(1, 1);
determinant_hack!(a, b, c, d)
}
pub fn determinant_3_by_3(&self) -> Ratio {
let a = self.get(0, 0);
let b = self.get(0, 1);
let c = self.get(0, 2);
let d = self.get(1, 0);
let e = self.get(1, 1);
let f = self.get(1, 2);
let g = self.get(2, 0);
let h = self.get(2, 1);
let i = self.get(2, 2);
determinant_hack!(a, b, c, d, e, f, g, h, i)
}
pub fn determinant_4_by_4(&self) -> Ratio {
let a00 = self.get(0, 0);
let a01 = self.get(0, 1);
let a02 = self.get(0, 2);
let a03 = self.get(0, 3);
let a10 = self.get(1, 0);
let a11 = self.get(1, 1);
let a12 = self.get(1, 2);
let a13 = self.get(1, 3);
let a20 = self.get(2, 0);
let a21 = self.get(2, 1);
let a22 = self.get(2, 2);
let a23 = self.get(2, 3);
let a30 = self.get(3, 0);
let a31 = self.get(3, 1);
let a32 = self.get(3, 2);
let a33 = self.get(3, 3);
let mut result = determinant_hack!(a11, a12, a13, a21, a22, a23, a31, a32, a33);
result.mul_rat_mut(a00);
let mut d = determinant_hack!(-, a10, a12, a13, a20, a22, a23, a30, a32, a33);
d.mul_rat_mut(a01);
result.add_rat_mut(&d);
let mut d = determinant_hack!(a10, a11, a13, a20, a21, a23, a30, a31, a33);
d.mul_rat_mut(a02);
result.add_rat_mut(&d);
let mut d = determinant_hack!(-, a10, a11, a12, a20, a21, a22, a30, a31, a32);
d.mul_rat_mut(a03);
result.add_rat_mut(&d);
result
}
}