qfall_math/integer/mat_z/
trace.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 `trace` function.
10
11use flint_sys::fmpz_mat::fmpz_mat_trace;
12
13use super::MatZ;
14use crate::{error::MathError, integer::Z, traits::MatrixDimensions};
15
16impl MatZ {
17    /// Returns the trace of a matrix and an error,
18    /// if the matrix is not square.
19    ///
20    /// # Examples
21    /// ```
22    /// use qfall_math::integer::MatZ;
23    /// use std::str::FromStr;
24    ///
25    /// let matrix = MatZ::from_str("[[1, 2],[3, 4]]").unwrap();
26    /// let trace = matrix.trace().unwrap();
27    /// ```
28    ///
29    /// # Errors and Failures
30    /// - Returns a [`MathError`] of type [`NoSquareMatrix`](MathError::NoSquareMatrix)
31    ///   if the matrix is not a square matrix
32    pub fn trace(&self) -> Result<Z, MathError> {
33        // check if matrix is square
34        if self.get_num_rows() != self.get_num_columns() {
35            return Err(MathError::NoSquareMatrix(self.to_string()));
36        }
37
38        let mut out = Z::default();
39        unsafe {
40            fmpz_mat_trace(&mut out.value, &self.matrix);
41        }
42        Ok(out)
43    }
44}
45
46#[cfg(test)]
47mod test_trace {
48    use crate::integer::{MatZ, Z};
49    use std::str::FromStr;
50
51    /// Test whether `trace` correctly calculates the trace of a matrix
52    #[test]
53    fn trace_works() {
54        let mat_1 = MatZ::from_str("[[5, 2, 0],[2, 1, 0],[0, 0, 1]]").unwrap();
55        let mat_2 = MatZ::from_str("[[-1, 0],[0, 1]]").unwrap();
56
57        let trace_1 = mat_1.trace().unwrap();
58        let trace_2 = mat_2.trace().unwrap();
59
60        assert_eq!(Z::from(7), trace_1);
61        assert_eq!(Z::from(0), trace_2);
62    }
63
64    /// Test whether `trace` works for large values
65    #[test]
66    fn trace_large_values() {
67        let mat_1 = MatZ::from_str(&format!("[[{}, 5],[1, {}]]", i64::MAX, i64::MAX)).unwrap();
68        let mat_2 = MatZ::from_str(&format!("[[{}]]", i64::MIN)).unwrap();
69        let mat_3 = MatZ::from_str(&format!("[[{}, 5],[1, {}]]", i64::MIN, i64::MAX)).unwrap();
70
71        let trace_1 = mat_1.trace().unwrap();
72        let trace_2 = mat_2.trace().unwrap();
73        let trace_3 = mat_3.trace().unwrap();
74
75        assert_eq!(Z::from(2 * i64::MAX as u64), trace_1);
76        assert_eq!(Z::from(i64::MIN), trace_2);
77        assert_eq!(Z::from(-1), trace_3);
78    }
79
80    /// Ensure that a matrix that is not square yields an error.
81    #[test]
82    fn trace_error_not_squared() {
83        let mat_1 = MatZ::from_str("[[1, 0, 1],[0, 1, 1]]").unwrap();
84        let mat_2 = MatZ::from_str("[[1, 0],[0, 1],[1, 0]]").unwrap();
85
86        assert!(mat_1.trace().is_err());
87        assert!(mat_2.trace().is_err());
88    }
89}