qfall_math/integer/mat_z/
determinant.rs

1// Copyright © 2023 Marcel Luca Schmidt
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! This module contains the implementation of the `determinant` function.
10
11use super::MatZ;
12use crate::{error::MathError, integer::Z, traits::MatrixDimensions};
13use flint_sys::fmpz_mat::fmpz_mat_det;
14
15impl MatZ {
16    /// Returns the determinant of the matrix or an error if
17    /// the number of rows and columns is not equal.
18    ///
19    /// # Examples
20    /// ```
21    /// use qfall_math::integer::MatZ;
22    /// use std::str::FromStr;
23    ///
24    /// let matrix = MatZ::from_str("[[1, 2],[3, 4]]").unwrap();
25    ///
26    /// let determinant = matrix.det().unwrap();
27    /// ```
28    ///
29    /// # Errors and Failures
30    /// - Returns a [`MathError`] of type [`MismatchingMatrixDimension`](MathError::MismatchingMatrixDimension)
31    ///   if the number of rows and columns is not equal.
32    pub fn det(&self) -> Result<Z, MathError> {
33        if self.get_num_rows() != self.get_num_columns() {
34            return Err(MathError::MismatchingMatrixDimension(
35                "The matrix is not square".to_string(),
36            ));
37        }
38
39        let mut det = Z::default();
40        unsafe {
41            fmpz_mat_det(&mut det.value, &self.matrix);
42        }
43        Ok(det)
44    }
45}
46
47#[cfg(test)]
48mod test_determinant {
49    use crate::integer::{MatZ, Z};
50    use std::str::FromStr;
51
52    /// Test whether the determinant is correctly computed
53    #[test]
54    fn determinant_works() {
55        let mat_1 = MatZ::from_str("[[5, 2],[2, 1]]").unwrap();
56        let mat_2 = MatZ::from_str(&format!("[[{}, 0],[0, 1]]", i64::MAX)).unwrap();
57        let mat_3 = MatZ::from_str(&format!("[[{}]]", i64::MIN)).unwrap();
58        let mat_4 = MatZ::from_str("[[0, 0],[0, 1]]").unwrap();
59        let mat_5 = MatZ::from_str("[[6, 0, 1],[0, 1, 0],[1, 2, 3]]").unwrap();
60
61        let det_1 = mat_1.det().unwrap();
62        let det_2 = mat_2.det().unwrap();
63        let det_3 = mat_3.det().unwrap();
64        let det_4 = mat_4.det().unwrap();
65        let det_5 = mat_5.det().unwrap();
66
67        let cmp_1 = Z::ONE;
68        let cmp_2 = Z::from(i64::MAX);
69        let cmp_3 = Z::from(i64::MIN);
70        let cmp_4 = Z::ZERO;
71        let cmp_5 = Z::from(17);
72
73        assert_eq!(cmp_1, det_1);
74        assert_eq!(cmp_2, det_2);
75        assert_eq!(cmp_3, det_3);
76        assert_eq!(cmp_4, det_4);
77        assert_eq!(cmp_5, det_5);
78    }
79
80    /// Ensure that an error is returned if the entered matrix is not square
81    #[test]
82    fn not_square_error() {
83        let mat_1 = MatZ::from_str("[[5],[2]]").unwrap();
84        let mat_2 = MatZ::from_str("[[2, 0],[0, 1],[8, -6]]").unwrap();
85
86        assert!(mat_1.det().is_err());
87        assert!(mat_2.det().is_err());
88    }
89}