qfall_math/rational/mat_q/
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::MatQ;
12use crate::{error::MathError, rational::Q, traits::MatrixDimensions};
13use flint_sys::fmpq_mat::fmpq_mat_det;
14
15impl MatQ {
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::rational::MatQ;
22    /// use std::str::FromStr;
23    ///
24    /// let matrix = MatQ::from_str("[[1/2, 2],[3/7, 4]]").unwrap();
25    /// let matrix_invert = matrix.det().unwrap();
26    /// ```
27    ///
28    /// # Errors and Failures
29    /// - Returns a [`MathError`] of type [`MismatchingMatrixDimension`](MathError::MismatchingMatrixDimension)
30    ///   if the number of rows and columns is not equal.
31    pub fn det(&self) -> Result<Q, MathError> {
32        if self.get_num_rows() != self.get_num_columns() {
33            return Err(MathError::MismatchingMatrixDimension(
34                "The matrix is not square".to_string(),
35            ));
36        }
37
38        let mut det = Q::default();
39        unsafe {
40            fmpq_mat_det(&mut det.value, &self.matrix);
41        }
42        Ok(det)
43    }
44}
45
46#[cfg(test)]
47mod test_determinant {
48    use crate::rational::{MatQ, Q};
49    use std::str::FromStr;
50
51    /// Test whether the determinant is correctly computed
52    #[test]
53    fn determinant_works() {
54        let mat_1 = MatQ::from_str("[[10, 2],[2, 1/2]]").unwrap();
55        let mat_2 = MatQ::from_str(&format!("[[{}, 0],[0, 1]]", i64::MAX)).unwrap();
56        let mat_3 = MatQ::from_str(&format!("[[-1/{}]]", i64::MIN)).unwrap();
57        let mat_4 = MatQ::from_str("[[0, 0],[0, 1]]").unwrap();
58        let mat_5 = MatQ::from_str("[[6, 0, 1],[0, 1, 0],[1, 2, 3]]").unwrap();
59
60        let det_1 = mat_1.det().unwrap();
61        let det_2 = mat_2.det().unwrap();
62        let det_3 = mat_3.det().unwrap();
63        let det_4 = mat_4.det().unwrap();
64        let det_5 = mat_5.det().unwrap();
65
66        let cmp_1 = Q::ONE;
67        let cmp_2 = Q::from(i64::MAX);
68        let cmp_3 = Q::from((-1, i64::MIN));
69        let cmp_4 = Q::ZERO;
70        let cmp_5 = Q::from(17);
71
72        assert_eq!(cmp_1, det_1);
73        assert_eq!(cmp_2, det_2);
74        assert_eq!(cmp_3, det_3);
75        assert_eq!(cmp_4, det_4);
76        assert_eq!(cmp_5, det_5);
77    }
78
79    /// Ensure that an error is returned if the entered matrix is not square
80    #[test]
81    fn not_square_error() {
82        let mat_1 = MatQ::from_str("[[5/7],[2]]").unwrap();
83        let mat_2 = MatQ::from_str("[[2, 0],[0, 1/8],[8/4, -6]]").unwrap();
84
85        assert!(mat_1.det().is_err());
86        assert!(mat_2.det().is_err());
87    }
88}