qfall_math/integer/mat_z/
properties.rs1use super::MatZ;
12use crate::{
13 integer::Z,
14 traits::{MatrixDimensions, MatrixGetEntry},
15};
16use flint_sys::fmpz_mat::{fmpz_mat_is_one, fmpz_mat_is_square, fmpz_mat_is_zero, fmpz_mat_rank};
17
18impl MatZ {
19 pub fn is_identity(&self) -> bool {
32 1 == unsafe { fmpz_mat_is_one(&self.matrix) }
33 }
34
35 pub fn is_square(&self) -> bool {
48 1 == unsafe { fmpz_mat_is_square(&self.matrix) }
49 }
50
51 pub fn is_zero(&self) -> bool {
64 1 == unsafe { fmpz_mat_is_zero(&self.matrix) }
65 }
66
67 pub fn is_symmetric(&self) -> bool {
79 if !self.is_square() {
80 return false;
81 }
82 for row in 0..self.get_num_rows() {
83 for column in 0..row {
84 if unsafe {
85 self.get_entry_unchecked(row, column) != self.get_entry_unchecked(column, row)
86 } {
87 return false;
88 }
89 }
90 }
91 true
92 }
93
94 pub fn rank(&self) -> Z {
106 Z::from(unsafe { fmpz_mat_rank(&self.matrix) })
107 }
108}
109
110#[cfg(test)]
111mod test_is_identity {
112 use super::MatZ;
113 use std::str::FromStr;
114
115 #[test]
117 fn identity_detection() {
118 let ident = MatZ::identity(2, 2);
119 let nosquare = MatZ::from_str("[[1, 0],[0, 1],[0, 0]]").unwrap();
120
121 assert!(ident.is_identity());
122 assert!(nosquare.is_identity());
123 assert!(MatZ::identity(1, 1).is_identity());
124 assert!(MatZ::identity(2, 4).is_identity());
125 assert!(MatZ::identity(4, 4).is_identity());
126 }
127
128 #[test]
130 fn identity_rejection() {
131 let small = MatZ::from_str("[[0, 0],[2, 0]]").unwrap();
132 let large = MatZ::from_str(&format!("[[1, 0],[0, {}]]", (u128::MAX - 1) / 2 + 2)).unwrap();
133
134 assert!(!(small.is_identity()));
135 assert!(!(large.is_identity()));
136 }
137}
138
139#[cfg(test)]
140mod test_is_zero {
141 use super::MatZ;
142 use std::str::FromStr;
143
144 #[test]
146 fn zero_detection() {
147 let zero_1 = MatZ::from_str("[[0, 0],[0, 0],[0, 0]]").unwrap();
148 let zero_2 = MatZ::from_str("[[0, 0, 0, 0],[0, 0, 0, 0]]").unwrap();
149 let zero_3 = MatZ::from_str("[[0, 0],[0, 0]]").unwrap();
150
151 assert!(zero_1.is_zero());
152 assert!(zero_2.is_zero());
153 assert!(zero_3.is_zero());
154 }
155
156 #[test]
158 fn zero_rejection() {
159 let small = MatZ::from_str("[[0, 0],[2, 0]]").unwrap();
160 let large = MatZ::from_str(&format!("[[0, 0],[{}, 0]]", (u128::MAX - 1) / 2 + 1)).unwrap();
161
162 assert!(!small.is_zero());
163 assert!(!large.is_zero());
164 }
165}
166
167#[cfg(test)]
168mod test_is_square {
169 use super::MatZ;
170 use std::str::FromStr;
171
172 #[test]
174 fn square_detection() {
175 let square_1 = MatZ::from_str("[[0, 4],[0, 0]]").unwrap();
176 let square_2 = MatZ::from_str("[[0, 6, 4],[0, 0, 1],[4, 6, 1]]").unwrap();
177
178 assert!(square_1.is_square());
179 assert!(square_2.is_square());
180 }
181
182 #[test]
184 fn square_rejection() {
185 let small = MatZ::from_str("[[0, 0, 4],[2, 0, 1]]").unwrap();
186 let large =
187 MatZ::from_str(&format!("[[9, 0],[{}, 0],[1, 4]]", (u128::MAX - 1) / 2 + 1)).unwrap();
188
189 assert!(!small.is_square());
190 assert!(!large.is_square());
191 }
192}
193
194#[cfg(test)]
195mod test_is_symmetric {
196 use super::MatZ;
197 use std::str::FromStr;
198
199 #[test]
201 fn symmetric_rejection() {
202 let mat_2x3 = MatZ::from_str("[[0, 5, 4],[2, 0, 1]]").unwrap();
203 let mat_2x2 = MatZ::from_str("[[9, 0],[71, 0]]").unwrap();
204
205 assert!(!mat_2x3.is_symmetric());
206 assert!(!mat_2x2.is_symmetric());
207 }
208
209 #[test]
211 fn symmetric_detection() {
212 let mat_2x2 = MatZ::from_str(&format!(
213 "[[{}, {}],[{}, {}]]",
214 u64::MIN,
215 u64::MAX,
216 u64::MAX,
217 i64::MAX
218 ))
219 .unwrap();
220
221 assert!(mat_2x2.is_symmetric());
222 }
223}
224
225#[cfg(test)]
226mod test_rank {
227 use crate::integer::{MatZ, Z};
228 use std::str::FromStr;
229
230 #[test]
232 fn rank_works() {
233 let mat_1 = MatZ::from_str("[[5, 2],[2, 1]]").unwrap();
234 let mat_2 = MatZ::from_str(&format!("[[{}, 0, 2, 8],[0, 1, 5, 7]]", i64::MIN)).unwrap();
235 let mat_3 = MatZ::from_str("[[0],[0]]").unwrap();
236 let mat_4 = MatZ::from_str("[[0, 0],[0, 1]]").unwrap();
237 let mat_5 = MatZ::from_str("[[0, 1],[0, 5]]").unwrap();
238 let mat_6 = MatZ::from_str("[[6, 0, 1],[0, 1, 0],[1, 2, 3]]").unwrap();
239
240 let rank_1 = mat_1.rank();
241 let rank_2 = mat_2.rank();
242 let rank_3 = mat_3.rank();
243 let rank_4 = mat_4.rank();
244 let rank_5 = mat_5.rank();
245 let rank_6 = mat_6.rank();
246
247 assert_eq!(Z::from(2), rank_1);
248 assert_eq!(Z::from(2), rank_2);
249 assert_eq!(Z::ZERO, rank_3);
250 assert_eq!(Z::ONE, rank_4);
251 assert_eq!(Z::ONE, rank_5);
252 assert_eq!(Z::from(3), rank_6);
253 }
254}