1use ndarray::Array2;
4use polynomials::{poly, Polynomial};
5
6pub fn determinant(poly_array: &Array2<Polynomial<i32>>) -> Polynomial<i32> {
12 if poly_array.shape() == &[1, 1] {
13 poly_array[[0, 0]].clone()
14 } else {
15 (0..poly_array.shape()[1])
16 .map(|j| {
17 if (j % 2) == 0 {
18 poly_array[[0, j]].clone() * determinant(&reduce_coordinate(poly_array, 0, j))
19 } else {
20 poly_array[[0, j]].clone()
21 * (-1)
22 * determinant(&reduce_coordinate(poly_array, 0, j))
23 }
24 })
25 .fold(poly![0], |acc, p| acc + p)
26 }
27}
28
29pub fn cofactor(
33 poly_array: &Array2<Polynomial<i32>>,
34 row: usize,
35 column: usize,
36) -> Polynomial<i32> {
37 if (row + column) % 2 == 0 {
38 determinant(&reduce_coordinate(poly_array, row, column))
39 } else {
40 determinant(&reduce_coordinate(poly_array, row, column)) * (-1)
41 }
42}
43
44fn reduce_coordinate(
46 poly_array: &Array2<Polynomial<i32>>,
47 row: usize,
48 column: usize,
49) -> Array2<Polynomial<i32>> {
50 let original_shape = [poly_array.shape()[0], poly_array.shape()[1]];
51 let mut sub_poly_array = Vec::new();
52 for i in 0..original_shape[0] {
53 for j in 0..original_shape[1] {
54 if !((i == row) || (j == column)) {
55 sub_poly_array.push(poly_array[[i, j]].clone())
56 }
57 }
58 }
59 Array2::from_shape_vec(
60 (original_shape[0] - 1, original_shape[1] - 1),
61 sub_poly_array,
62 )
63 .unwrap()
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69 use ndarray::array;
70 use polynomials::poly;
71 use test_case::test_case;
72
73 #[test_case(array![[poly![1, 0], poly![0, 2]], [poly![1, 0], poly![1, 1]]], poly![1, -1] ; "linear")]
74 #[test_case(array![[poly![1, 1], poly![0, 1]], [poly![1, 0], poly![0, 1]]], poly![0, 0, 1] ; "quadratic")]
75 fn computing_determinant(poly_array: Array2<Polynomial<i32>>, expected: Polynomial<i32>) {
76 assert_eq!(determinant(&poly_array), expected);
77 }
78
79 #[test_case(array![[poly![1, 0], poly![0, 2]], [poly![1, 0], poly![1, 1]]], 0, 0, poly![1, 1] ; "Two by two linear polynomials [0, 0]")]
80 #[test_case(array![[poly![1, 0], poly![0, 2]], [poly![1, 0], poly![1, 1]]], 0, 1, poly![-1, 0] ; "Two by two linear polynomials [0, 1]")]
81 #[test_case(array![[poly![1, 0], poly![0, 2]], [poly![1, 0], poly![1, 1]]], 1, 0, poly![0, -2] ; "Two by two linear polynomials [1, 0]")]
82 #[test_case(array![[poly![1, 0], poly![0, 2]], [poly![1, 0], poly![1, 1]]], 1, 1, poly![1, 0] ; "Two by two linear polynomials [1, 1]")]
83 fn computing_cofactor(
84 poly_array: Array2<Polynomial<i32>>,
85 row: usize,
86 column: usize,
87 expected: Polynomial<i32>,
88 ) {
89 assert_eq!(cofactor(&poly_array, row, column), expected);
90 }
91
92 #[test_case(array![[poly![1, 0], poly![0, 2]], [poly![1, 0], poly![1, 1]]], 0, 0, array![[poly![1, 1]]] ; "Two by two linear polynomials [0, 0]")]
93 #[test_case(array![[poly![1, 0], poly![0, 2]], [poly![1, 0], poly![1, 1]]], 0, 1, array![[poly![1, 0]]] ; "Two by two linear polynomials [0, 1]")]
94 #[test_case(array![[poly![1, 0], poly![0, 2]], [poly![1, 0], poly![1, 1]]], 1, 0, array![[poly![0, 2]]] ; "Two by two linear polynomials [1, 0]")]
95 #[test_case(array![[poly![1, 0], poly![0, 2]], [poly![1, 0], poly![1, 1]]], 1, 1, array![[poly![1, 0]]] ; "Two by two linear polynomials [1, 1]")]
96 fn reducing_coordinate(
97 poly_array: Array2<Polynomial<i32>>,
98 row: usize,
99 column: usize,
100 expected: Array2<Polynomial<i32>>,
101 ) {
102 assert_eq!(reduce_coordinate(&poly_array, row, column), expected);
103 }
104}