qfall_math/rational/mat_q/
properties.rs

1// Copyright © 2023 Phil Milewski, Marvin Beckmann
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 includes functionality about properties of [`MatQ`] instances.
10
11use super::MatQ;
12use crate::traits::{MatrixDimensions, MatrixGetEntry};
13use flint_sys::fmpq_mat::{fmpq_mat_is_one, fmpq_mat_is_square, fmpq_mat_is_zero};
14
15impl MatQ {
16    /// Checks if a [`MatQ`] is the identity matrix.
17    ///
18    /// Returns `true` if every diagonal entry of the upper square matrix is `1`
19    /// and all other entries are `0`.
20    ///
21    /// # Examples
22    /// ```
23    /// use qfall_math::rational::MatQ;
24    ///
25    /// let value = MatQ::identity(2, 2);
26    /// assert!(value.is_identity());
27    /// ```
28    ///
29    /// ```
30    /// use qfall_math::rational::MatQ;
31    /// use std::str::FromStr;
32    ///
33    /// let value = MatQ::from_str("[[1, 0],[0, 1],[0, 0]]").unwrap();
34    /// assert!(value.is_identity());
35    /// ```
36    pub fn is_identity(&self) -> bool {
37        1 == unsafe { fmpq_mat_is_one(&self.matrix) }
38    }
39
40    /// Checks if a [`MatQ`] is a square matrix.
41    ///
42    /// Returns `true` if the number of rows and columns is identical.
43    ///
44    /// # Examples
45    /// ```
46    /// use qfall_math::rational::MatQ;
47    /// use std::str::FromStr;
48    ///
49    /// let value = MatQ::from_str("[[4/7, 0],[5/8, 1/9]]").unwrap();
50    /// assert!(value.is_square());
51    /// ```
52    pub fn is_square(&self) -> bool {
53        1 == unsafe { fmpq_mat_is_square(&self.matrix) }
54    }
55
56    /// Checks if every entry of a [`MatQ`] is `0`.
57    ///
58    /// Returns `true` if every entry is `0`.
59    ///
60    /// # Examples
61    /// ```
62    /// use qfall_math::rational::MatQ;
63    /// use std::str::FromStr;
64    ///
65    /// let value = MatQ::from_str("[[0, 0],[0, 0]]").unwrap();
66    /// assert!(value.is_zero());
67    /// ```
68    pub fn is_zero(&self) -> bool {
69        1 == unsafe { fmpq_mat_is_zero(&self.matrix) }
70    }
71
72    /// Checks if a [`MatQ`] is symmetric.
73    ///
74    /// Returns `true` if we have `a_ij == a_ji` for all i,j.
75    ///
76    /// # Examples
77    /// ```
78    /// use qfall_math::rational::MatQ;
79    ///
80    /// let value = MatQ::identity(2,2);
81    /// assert!(value.is_symmetric());
82    /// ```
83    pub fn is_symmetric(&self) -> bool {
84        if !self.is_square() {
85            return false;
86        }
87        for row in 0..self.get_num_rows() {
88            for column in 0..row {
89                if unsafe {
90                    self.get_entry_unchecked(row, column) != self.get_entry_unchecked(column, row)
91                } {
92                    return false;
93                }
94            }
95        }
96        true
97    }
98}
99
100#[cfg(test)]
101mod test_is_identity {
102    use super::MatQ;
103    use std::str::FromStr;
104
105    /// Ensure that is_identity returns `true` for identity matrices.
106    #[test]
107    fn identity_detection() {
108        let ident = MatQ::identity(2, 2);
109
110        assert!(ident.is_identity());
111    }
112
113    /// Ensure that is_identity returns `false` for non-identity matrices.
114    #[test]
115    fn identity_rejection() {
116        let small = MatQ::from_str("[[0, 0],[2/81, 0]]").unwrap();
117        let large = MatQ::from_str(&format!("[[1, 0],[0, {}]]", (u128::MAX - 1) / 2 + 2)).unwrap();
118
119        assert!(!small.is_identity());
120        assert!(!large.is_identity());
121    }
122}
123
124#[cfg(test)]
125mod test_is_zero {
126    use super::MatQ;
127    use std::str::FromStr;
128
129    /// Ensure that is_zero returns `true` for all zero matrices.
130    #[test]
131    fn zero_detection() {
132        let zero = MatQ::from_str("[[0, 0],[0, 0]]").unwrap();
133
134        assert!(zero.is_zero());
135    }
136
137    /// Ensure that is_zero returns `false` for non-zero matrices.
138    #[test]
139    fn zero_rejection() {
140        let small = MatQ::from_str("[[0, 7/8],[2, 0]]").unwrap();
141        let large = MatQ::from_str(&format!("[[0, 0],[{}, 0]]", (u128::MAX - 1) / 2 + 1)).unwrap();
142
143        assert!(!small.is_zero());
144        assert!(!large.is_zero());
145    }
146}
147
148#[cfg(test)]
149mod test_is_square {
150    use super::MatQ;
151    use std::str::FromStr;
152
153    /// Ensure that is_square returns `true` for square matrices.
154    #[test]
155    fn square_detection() {
156        let mat_2x2 = MatQ::from_str("[[0, 4/9],[0, 0]]").unwrap();
157        let mat_3x3 = MatQ::from_str("[[0, 6/123, 4/7],[0, 0, 1/213],[4/341, 6/83, 1]]").unwrap();
158
159        assert!(mat_2x2.is_square());
160        assert!(mat_3x3.is_square());
161    }
162
163    /// Ensure that is_square returns `false` for non-square matrices.
164    #[test]
165    fn sqaure_rejection() {
166        let mat_2x3 = MatQ::from_str("[[0, 5/6, 4],[2/7, 0, 1]]").unwrap();
167        let mat_3x2 = MatQ::from_str("[[9, 0],[127/71, 0],[0, 0]]").unwrap();
168
169        assert!(!mat_2x3.is_square());
170        assert!(!mat_3x2.is_square());
171    }
172}
173
174#[cfg(test)]
175mod test_is_symmetric {
176    use super::MatQ;
177    use std::str::FromStr;
178
179    /// Ensure that is_symmetric returns `false` for non-symmetric matrices.
180    #[test]
181    fn symmetric_rejection() {
182        let mat_2x3 = MatQ::from_str("[[0, 5/6, 4],[2/7, 0, 1]]").unwrap();
183        let mat_2x2 = MatQ::from_str("[[9, 0],[127/71, 0]]").unwrap();
184
185        assert!(!mat_2x3.is_symmetric());
186        assert!(!mat_2x2.is_symmetric());
187    }
188
189    /// Ensure that is_symmetric returns `true` for symmetric matrices.
190    #[test]
191    fn symmetric_detection() {
192        let mat_2x2 = MatQ::from_str(&format!(
193            "[[{}, 1/{}],[1/{}, {}]]",
194            u64::MIN,
195            u64::MAX,
196            u64::MAX,
197            i64::MAX
198        ))
199        .unwrap();
200
201        assert!(mat_2x2.is_symmetric());
202    }
203}