qfall_math/integer/mat_poly_over_z/
properties.rs1use super::MatPolyOverZ;
13use crate::{
14 integer::Z,
15 traits::{MatrixDimensions, MatrixGetEntry},
16};
17use flint_sys::fmpz_poly_mat::{fmpz_poly_mat_is_one, fmpz_poly_mat_is_zero, fmpz_poly_mat_rank};
18
19impl MatPolyOverZ {
20 pub fn is_identity(&self) -> bool {
35 1 == unsafe { fmpz_poly_mat_is_one(&self.matrix) }
36 }
37
38 pub fn is_square(&self) -> bool {
53 self.get_num_columns() == self.get_num_rows()
54 }
55
56 pub fn is_zero(&self) -> bool {
71 unsafe { 0 != fmpz_poly_mat_is_zero(&self.matrix) }
74 }
75
76 pub fn is_symmetric(&self) -> bool {
88 if !self.is_square() {
89 return false;
90 }
91 for row in 0..self.get_num_rows() {
92 for column in 0..row {
93 if unsafe {
94 self.get_entry_unchecked(row, column) != self.get_entry_unchecked(column, row)
95 } {
96 return false;
97 }
98 }
99 }
100 true
101 }
102
103 pub fn rank(&self) -> Z {
115 Z::from(unsafe { fmpz_poly_mat_rank(&self.matrix) })
116 }
117}
118
119#[cfg(test)]
120mod test_is_identity {
121 use crate::integer::MatPolyOverZ;
122 use std::str::FromStr;
123
124 #[test]
126 fn identity_true() {
127 let matrix_1x1 = MatPolyOverZ::from_str("[[1 1]]").unwrap();
128 let matrix_2x2 = MatPolyOverZ::from_str("[[1 1, 0],[0, 1 1]]").unwrap();
129 let matrix_3x3 =
130 MatPolyOverZ::from_str("[[1 1, 0, 0],[0, 1 1, 0],[0, 0, 1 1]]").unwrap();
131 let matrix_2x3 = MatPolyOverZ::from_str("[[1 1, 0, 0],[0, 1 1, 0]]").unwrap();
132 let matrix_3x2 = MatPolyOverZ::from_str("[[1 1, 0],[0, 1 1],[0, 0]]").unwrap();
133
134 assert!(matrix_1x1.is_identity());
135 assert!(matrix_2x2.is_identity());
136 assert!(matrix_3x3.is_identity());
137 assert!(matrix_2x3.is_identity());
138 assert!(matrix_3x2.is_identity());
139 }
140
141 #[test]
143 fn not_identity() {
144 let matrix_side_entry = MatPolyOverZ::from_str("[[1 1, 1 1],[0, 1 1]]").unwrap();
145 let matrix_negative_1 = MatPolyOverZ::from_str("[[1 -1, 0],[0, 1 1]]").unwrap();
146 let matrix_negative_2 = MatPolyOverZ::from_str("[[1 -17, 0],[0, 1 1]]").unwrap();
147 let matrix_higher_degree = MatPolyOverZ::from_str("[[1 1, 0],[0, 2 1 42]]").unwrap();
148 let matrix_matrix_positive = MatPolyOverZ::from_str("[[1 17, 0],[0, 1 1]]").unwrap();
149 let matrix_large_negative =
150 MatPolyOverZ::from_str(&format!("[[1 -{}, 0],[0, 1 1]]", u64::MAX)).unwrap();
151 let matrix_large_positive =
152 MatPolyOverZ::from_str(&format!("[[1 {}, 0],[0, 1 1]]", u64::MAX)).unwrap();
153
154 assert!(!matrix_side_entry.is_identity());
155 assert!(!matrix_negative_1.is_identity());
156 assert!(!matrix_negative_2.is_identity());
157 assert!(!matrix_higher_degree.is_identity());
158 assert!(!matrix_matrix_positive.is_identity());
159 assert!(!matrix_large_negative.is_identity());
160 assert!(!matrix_large_positive.is_identity());
161 }
162}
163
164#[cfg(test)]
165mod test_is_square {
166 use crate::integer::MatPolyOverZ;
167 use std::str::FromStr;
168
169 #[test]
171 fn square_matrix() {
172 let matrix_negative =
173 MatPolyOverZ::from_str("[[1 -17, 0, 0],[0, 1 1, 0],[0, 0, 0]]").unwrap();
174 let matrix_higher_degree = MatPolyOverZ::from_str("[[1 1, 0],[0, 2 1 42]]").unwrap();
175 let matrix_matrix_positive = MatPolyOverZ::from_str("[[1 17]]").unwrap();
176 let matrix_large_negative =
177 MatPolyOverZ::from_str(&format!("[[1 -{}, 0],[0, 1 1]]", u64::MAX)).unwrap();
178 let matrix_large_positive = MatPolyOverZ::from_str(&format!(
179 "[[1 {}, 0, 0, 0],[0, 1 1, 0, 0],[0, 1 1, 0, 0],[0, 1 1, 0, 0]]",
180 u64::MAX
181 ))
182 .unwrap();
183
184 assert!(matrix_negative.is_square());
185 assert!(matrix_matrix_positive.is_square());
186 assert!(matrix_higher_degree.is_square());
187 assert!(matrix_large_negative.is_square());
188 assert!(matrix_large_positive.is_square());
189 }
190
191 #[test]
193 fn not_square_matrix() {
194 let matrix_1x2 = MatPolyOverZ::from_str("[[1 1, 0]]").unwrap();
195 let matrix_2x1 = MatPolyOverZ::from_str("[[1 1],[0]]").unwrap();
196 let matrix_2x3 = MatPolyOverZ::from_str("[[1 1, 0, 0],[0, 1 1, 0]]").unwrap();
197 let matrix_3x2 = MatPolyOverZ::from_str("[[1 1, 0],[0, 1 1],[0, 0]]").unwrap();
198
199 assert!(!matrix_1x2.is_square());
200 assert!(!matrix_2x1.is_square());
201 assert!(!matrix_2x3.is_square());
202 assert!(!matrix_3x2.is_square());
203 }
204}
205
206#[cfg(test)]
207mod test_is_zero {
208 use super::MatPolyOverZ;
209 use std::str::FromStr;
210
211 #[test]
213 fn zero_detection() {
214 let zero = MatPolyOverZ::from_str("[[0, 0],[0, 0]]").unwrap();
215 let zero_2 = MatPolyOverZ::from_str("[[0, 0],[0, 0],[0, 3 0 0 0]]").unwrap();
216
217 assert!(zero.is_zero());
218 assert!(zero_2.is_zero());
219 }
220
221 #[test]
223 fn zero_rejection() {
224 let small = MatPolyOverZ::from_str("[[0, 0],[4 0 0 0 2, 0]]").unwrap();
225 let large =
226 MatPolyOverZ::from_str(&format!("[[0, 0],[1 {}, 0]]", (u128::MAX - 1) / 2 + 1))
227 .unwrap();
228
229 assert!(!small.is_zero());
230 assert!(!large.is_zero());
231 }
232}
233
234#[cfg(test)]
235mod test_is_symmetric {
236 use super::MatPolyOverZ;
237 use std::str::FromStr;
238
239 #[test]
241 fn symmetric_rejection() {
242 let mat_2x3 = MatPolyOverZ::from_str("[[0, 1 6, 2 1 4],[1 2, 0, 2 1 1]]").unwrap();
243 let mat_2x2 = MatPolyOverZ::from_str("[[1 9, 0],[2 1 71, 0]]").unwrap();
244
245 assert!(!mat_2x3.is_symmetric());
246 assert!(!mat_2x2.is_symmetric());
247 }
248
249 #[test]
251 fn symmetric_detection() {
252 let mat_2x2 = MatPolyOverZ::from_str(&format!(
253 "[[2 1 {}, 2 3 {}],[2 3 {}, 3 1 {} 8]]",
254 u64::MIN,
255 u64::MAX,
256 u64::MAX,
257 i64::MAX
258 ))
259 .unwrap();
260
261 assert!(mat_2x2.is_symmetric());
262 }
263}
264
265#[cfg(test)]
266mod test_rank {
267 use crate::integer::{MatPolyOverZ, Z};
268 use std::str::FromStr;
269
270 #[test]
272 fn rank_works() {
273 let mat_1 = MatPolyOverZ::from_str("[[1 5, 1 2],[1 2, 1 1]]").unwrap();
274 let mat_2 = MatPolyOverZ::from_str(&format!(
275 "[[2 {} 3, 0, 0, 0],[0, 0, 1 5, 1 7]]",
276 i64::MIN
277 ))
278 .unwrap();
279 let mat_3 = MatPolyOverZ::from_str("[[0],[0]]").unwrap();
280 let mat_4 = MatPolyOverZ::from_str("[[0, 0],[0, 1 1]]").unwrap();
281 let mat_5 = MatPolyOverZ::from_str("[[0, 1 1],[0, 1 5]]").unwrap();
282 let mat_6 =
283 MatPolyOverZ::from_str("[[1 6, 0, 1 1],[0, 1 1, 0],[2 1 5, 1 2, 0]]").unwrap();
284
285 let rank_1 = mat_1.rank();
286 let rank_2 = mat_2.rank();
287 let rank_3 = mat_3.rank();
288 let rank_4 = mat_4.rank();
289 let rank_5 = mat_5.rank();
290 let rank_6 = mat_6.rank();
291
292 assert_eq!(Z::from(2), rank_1);
293 assert_eq!(Z::from(2), rank_2);
294 assert_eq!(Z::ZERO, rank_3);
295 assert_eq!(Z::ONE, rank_4);
296 assert_eq!(Z::ONE, rank_5);
297 assert_eq!(Z::from(3), rank_6);
298 }
299}