use permutohedron::heap_recursive;
use savage_macros::function;
use crate::{expression::Expression, functions::SquareMatrix, helpers::*};
#[function(
name = "det",
description = "determinant of a square matrix",
examples = r#"[
("det([[1, 2], [3, 4]])", "-2"),
("det([[a, b], [c, d]])", "a * d - b * c"),
("det([])", "1"),
]"#,
categories = r#"[
"linear algebra",
]"#
)]
fn determinant(matrix: SquareMatrix) -> Expression {
if matrix.is_empty() {
return int(1);
}
let mut indices = (0..matrix.nrows()).collect::<Vec<usize>>();
let mut products = Vec::new();
heap_recursive(indices.as_mut_slice(), |permutation| {
products.push(
(0..matrix.nrows())
.map(|i| matrix[(i, permutation[i])].clone())
.reduce(|a, b| a * b)
.unwrap(),
);
});
let mut positive = true;
products
.into_iter()
.reduce(|a, b| {
positive = !positive;
if positive {
a + b
} else {
a - b
}
})
.unwrap()
}