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}