1use super::MatPolyOverZ;
12use crate::{
13 integer::PolyOverZ,
14 traits::{MatrixDimensions, MatrixGetEntry, MatrixGetSubmatrix},
15};
16use flint_sys::{
17 fmpz_poly::{fmpz_poly_set, fmpz_poly_struct},
18 fmpz_poly_mat::{
19 fmpz_poly_mat_entry, fmpz_poly_mat_init_set, fmpz_poly_mat_window_clear,
20 fmpz_poly_mat_window_init,
21 },
22};
23use std::mem::MaybeUninit;
24
25impl MatrixDimensions for MatPolyOverZ {
26 fn get_num_rows(&self) -> i64 {
37 self.matrix.r
38 }
39
40 fn get_num_columns(&self) -> i64 {
51 self.matrix.c
52 }
53}
54
55impl MatrixGetEntry<PolyOverZ> for MatPolyOverZ {
56 unsafe fn get_entry_unchecked(&self, row: i64, column: i64) -> PolyOverZ {
83 let mut copy = PolyOverZ::default();
84 let entry = unsafe { fmpz_poly_mat_entry(&self.matrix, row, column) };
85 unsafe { fmpz_poly_set(&mut copy.poly, entry) };
86
87 copy
88 }
89}
90
91impl MatrixGetSubmatrix for MatPolyOverZ {
92 unsafe fn get_submatrix_unchecked(
126 &self,
127 row_1: i64,
128 row_2: i64,
129 col_1: i64,
130 col_2: i64,
131 ) -> Self {
132 let mut window = MaybeUninit::uninit();
133 unsafe {
135 fmpz_poly_mat_window_init(
136 window.as_mut_ptr(),
137 &self.matrix,
138 row_1,
139 col_1,
140 row_2,
141 col_2,
142 )
143 };
144 let mut window_copy = MaybeUninit::uninit();
145 unsafe {
146 fmpz_poly_mat_init_set(window_copy.as_mut_ptr(), window.as_ptr());
148 fmpz_poly_mat_window_clear(window.as_mut_ptr());
151 }
152 MatPolyOverZ {
153 matrix: unsafe { window_copy.assume_init() },
154 }
155 }
156}
157
158impl MatPolyOverZ {
159 pub(crate) fn collect_entries(&self) -> Vec<fmpz_poly_struct> {
175 let mut entries: Vec<fmpz_poly_struct> =
176 Vec::with_capacity((self.get_num_rows() * self.get_num_columns()) as usize);
177
178 for row in 0..self.get_num_rows() {
179 for col in 0..self.get_num_columns() {
180 let entry = unsafe { *fmpz_poly_mat_entry(&self.matrix, row, col) };
182 entries.push(entry);
183 }
184 }
185
186 entries
187 }
188}
189
190#[cfg(test)]
191mod test_get_entry {
192 use crate::{
193 integer::{MatPolyOverZ, PolyOverZ},
194 traits::{MatrixGetEntry, MatrixSetEntry},
195 };
196 use std::str::FromStr;
197
198 #[test]
200 fn max_int_positive() {
201 let mut matrix = MatPolyOverZ::new(5, 10);
202 let value = PolyOverZ::from_str(&format!("2 {} 1", i64::MAX)).unwrap();
203 matrix.set_entry(1, 1, value).unwrap();
204
205 let entry = matrix.get_entry(1, 1).unwrap();
206
207 assert_eq!(format!("2 {} 1", i64::MAX), entry.to_string());
208 }
209
210 #[test]
212 fn large_positive() {
213 let mut matrix = MatPolyOverZ::new(5, 10);
214 let value = PolyOverZ::from_str(&format!("2 {} 1", u64::MAX)).unwrap();
215 matrix.set_entry(1, 1, value).unwrap();
216
217 let entry = matrix.get_entry(1, 1).unwrap();
218
219 assert_eq!(format!("2 {} 1", u64::MAX), entry.to_string());
220 }
221
222 #[test]
224 fn max_int_negative() {
225 let mut matrix = MatPolyOverZ::new(5, 10);
226 let value = PolyOverZ::from_str(&format!("2 {} 1", i64::MIN)).unwrap();
227 matrix.set_entry(1, 1, value).unwrap();
228
229 let entry = matrix.get_entry(1, 1).unwrap();
230
231 assert_eq!(format!("2 {} 1", i64::MIN), entry.to_string());
232 }
233
234 #[test]
236 fn large_negative() {
237 let mut matrix = MatPolyOverZ::new(5, 10);
238 let value = PolyOverZ::from_str(&format!("2 -{} 1", u64::MAX)).unwrap();
239 matrix.set_entry(1, 1, value).unwrap();
240
241 let entry = matrix.get_entry(1, 1).unwrap();
242
243 assert_eq!(format!("2 -{} 1", u64::MAX), entry.to_string());
244 }
245
246 #[test]
248 fn large_poly() {
249 let mut matrix = MatPolyOverZ::new(5, 10);
250 let value =
251 PolyOverZ::from_str(&format!("10000 -{} 1{}", u64::MAX, " 17".repeat(9998))).unwrap();
252 matrix.set_entry(1, 1, value).unwrap();
253
254 let entry = matrix.get_entry(1, 1).unwrap();
255
256 assert_eq!(
257 format!("10000 -{} 1{}", u64::MAX, " 17".repeat(9998)),
258 entry.to_string()
259 );
260 }
261
262 #[test]
264 fn getting_at_zero() {
265 let mut matrix = MatPolyOverZ::new(5, 10);
266 let value = PolyOverZ::from_str(&format!("2 {} 1", i64::MAX)).unwrap();
267 matrix.set_entry(0, 0, value).unwrap();
268
269 let entry = matrix.get_entry(0, 0).unwrap();
270
271 assert_eq!(format!("2 {} 1", i64::MAX), entry.to_string());
272 }
273
274 #[test]
276 fn error_wrong_row() {
277 let matrix = MatPolyOverZ::new(5, 10);
278
279 assert!(matrix.get_entry(5, 1).is_err());
280 assert!(matrix.get_entry(-6, 1).is_err());
281 }
282
283 #[test]
285 fn error_wrong_column() {
286 let matrix = MatPolyOverZ::new(5, 10);
287
288 assert!(matrix.get_entry(1, 100).is_err());
289 assert!(matrix.get_entry(1, -11).is_err());
290 }
291
292 #[test]
294 fn negative_indexing() {
295 let matrix = MatPolyOverZ::from_str("[[1 1, 1 2],[1 3, 1 4],[1 5 , 1 6]]").unwrap();
296
297 assert_eq!(PolyOverZ::from(2), matrix.get_entry(0, -1).unwrap());
298 assert_eq!(PolyOverZ::from(4), matrix.get_entry(-2, 1).unwrap());
299 assert_eq!(PolyOverZ::from(4), matrix.get_entry(-2, -1).unwrap());
300 assert_eq!(PolyOverZ::from(6), matrix.get_entry(-1, -1).unwrap());
301 }
302
303 #[test]
305 fn memory_test() {
306 let mut matrix = MatPolyOverZ::new(5, 10);
307 let value = PolyOverZ::from_str(&format!("2 {} 1", u64::MAX)).unwrap();
308 matrix.set_entry(1, 1, value).unwrap();
309 let entry = matrix.get_entry(1, 1).unwrap();
310 matrix.set_entry(1, 1, PolyOverZ::default()).unwrap();
311
312 assert_eq!(format!("2 {} 1", u64::MAX), entry.to_string());
313 }
314}
315
316#[cfg(test)]
317mod test_get_num {
318 use crate::{integer::MatPolyOverZ, traits::MatrixDimensions};
319
320 #[test]
322 fn num_rows() {
323 let matrix = MatPolyOverZ::new(5, 10);
324
325 assert_eq!(matrix.get_num_rows(), 5);
326 }
327
328 #[test]
330 fn num_columns() {
331 let matrix = MatPolyOverZ::new(5, 10);
332
333 assert_eq!(matrix.get_num_columns(), 10);
334 }
335}
336
337#[cfg(test)]
338mod test_get_vec {
339 use crate::{integer::MatPolyOverZ, traits::MatrixGetSubmatrix};
340 use std::str::FromStr;
341
342 #[test]
344 fn get_row_works() {
345 let matrix = MatPolyOverZ::from_str(&format!(
346 "[[0, 0, 0],[1 42, 1 {}, 1 {}]]",
347 i64::MAX,
348 i64::MIN
349 ))
350 .unwrap();
351 let row_1 = matrix.get_row(0).unwrap();
352 let row_2 = matrix.get_row(1).unwrap();
353
354 let cmp_1 = MatPolyOverZ::from_str("[[0, 0, 0]]").unwrap();
355 let cmp_2 = MatPolyOverZ::from_str(&format!("[[1 42, 1 {}, 1 {}]]", i64::MAX, i64::MIN))
356 .unwrap();
357
358 assert_eq!(cmp_1, row_1);
359 assert_eq!(cmp_2, row_2);
360 }
361
362 #[test]
364 fn get_row_negative_indexing_works() {
365 let matrix = MatPolyOverZ::from_str(&format!(
366 "[[0, 0, 0],[1 42, 1 {}, 1 {}]]",
367 i64::MAX,
368 i64::MIN
369 ))
370 .unwrap();
371 let row_1 = matrix.get_row(-2).unwrap();
372 let row_2 = matrix.get_row(-1).unwrap();
373
374 let cmp_1 = MatPolyOverZ::from_str("[[0, 0, 0]]").unwrap();
375 let cmp_2 = MatPolyOverZ::from_str(&format!("[[1 42, 1 {}, 1 {}]]", i64::MAX, i64::MIN))
376 .unwrap();
377
378 assert_eq!(cmp_1, row_1);
379 assert_eq!(cmp_2, row_2);
380 }
381
382 #[test]
384 fn get_column_works() {
385 let matrix = MatPolyOverZ::from_str(&format!(
386 "[[1 42, 0, 2 17 42],[1 {}, 0, 2 17 42],[1 {}, 0, 2 17 42]]",
387 i64::MAX,
388 i64::MIN
389 ))
390 .unwrap();
391 let column_1 = matrix.get_column(0).unwrap();
392 let column_2 = matrix.get_column(1).unwrap();
393 let column_3 = matrix.get_column(2).unwrap();
394
395 let cmp_1 =
396 MatPolyOverZ::from_str(&format!("[[1 42],[1 {}],[1 {}]]", i64::MAX, i64::MIN))
397 .unwrap();
398 let cmp_2 = MatPolyOverZ::from_str("[[0],[0],[0]]").unwrap();
399 let cmp_3 = MatPolyOverZ::from_str("[[2 17 42],[2 17 42],[2 17 42]]").unwrap();
400
401 assert_eq!(cmp_1, column_1);
402 assert_eq!(cmp_2, column_2);
403 assert_eq!(cmp_3, column_3);
404 }
405
406 #[test]
408 fn get_column_negative_indexing_works() {
409 let matrix = MatPolyOverZ::from_str(&format!(
410 "[[1 42, 0, 2 17 42],[1 {}, 0, 2 17 42],[1 {}, 0, 2 17 42]]",
411 i64::MAX,
412 i64::MIN
413 ))
414 .unwrap();
415 let column_1 = matrix.get_column(-3).unwrap();
416 let column_2 = matrix.get_column(-2).unwrap();
417 let column_3 = matrix.get_column(-1).unwrap();
418
419 let cmp_1 =
420 MatPolyOverZ::from_str(&format!("[[1 42],[1 {}],[1 {}]]", i64::MAX, i64::MIN))
421 .unwrap();
422 let cmp_2 = MatPolyOverZ::from_str("[[0],[0],[0]]").unwrap();
423 let cmp_3 = MatPolyOverZ::from_str("[[2 17 42],[2 17 42],[2 17 42]]").unwrap();
424
425 assert_eq!(cmp_1, column_1);
426 assert_eq!(cmp_2, column_2);
427 assert_eq!(cmp_3, column_3);
428 }
429
430 #[test]
432 fn wrong_dim_error() {
433 let matrix = MatPolyOverZ::from_str(&format!(
434 "[[1 17, 2 17 42, 3 1 1 1],[1 {}, 1 1, 2 2 3],[1 {}, 1 142, 1 1]]",
435 i64::MAX,
436 i64::MIN
437 ))
438 .unwrap();
439 let row_1 = matrix.get_row(-4);
440 let row_2 = matrix.get_row(4);
441 let column_1 = matrix.get_column(-4);
442 let column_2 = matrix.get_column(4);
443
444 assert!(row_1.is_err());
445 assert!(row_2.is_err());
446 assert!(column_1.is_err());
447 assert!(column_2.is_err());
448 }
449}
450
451#[cfg(test)]
452mod test_get_submatrix {
453 use crate::{
454 integer::{MatPolyOverZ, Z},
455 traits::{MatrixDimensions, MatrixGetSubmatrix},
456 };
457 use std::str::FromStr;
458
459 #[test]
461 fn entire_matrix() {
462 let mat = MatPolyOverZ::identity(5, 5);
463
464 let sub_mat = mat.get_submatrix(0, 4, 0, 4).unwrap();
465
466 assert_eq!(mat, sub_mat);
467 }
468
469 #[test]
471 fn matrix_single_entry() {
472 let mat = MatPolyOverZ::identity(5, 5);
473
474 let sub_mat = mat.get_submatrix(0, 0, 0, 0).unwrap();
475
476 let cmp_mat = MatPolyOverZ::identity(1, 1);
477 assert_eq!(cmp_mat, sub_mat);
478 }
479
480 #[test]
482 fn correct_dimensions() {
483 let mat = MatPolyOverZ::identity(100, 100);
484
485 let sub_mat = mat.get_submatrix(1, 37, 0, 29).unwrap();
486
487 assert_eq!(37, sub_mat.get_num_rows());
488 assert_eq!(30, sub_mat.get_num_columns());
489 }
490
491 #[test]
494 fn large_entries() {
495 let mat = MatPolyOverZ::from_str(&format!(
496 "[[2 {} {}, 1 2, 1 3],[1 1, 1 {}, 1 3]]",
497 u64::MAX,
498 i64::MAX,
499 i64::MIN
500 ))
501 .unwrap();
502
503 let sub_mat = mat.get_submatrix(0, 1, 0, 1).unwrap();
504
505 let cmp_mat = MatPolyOverZ::from_str(&format!(
506 "[[2 {} {}, 1 2],[1 1, 1 {}]]",
507 u64::MAX,
508 i64::MAX,
509 i64::MIN
510 ))
511 .unwrap();
512 assert_eq!(cmp_mat, sub_mat);
513 }
514
515 #[test]
518 fn invalid_coordinates() {
519 let mat = MatPolyOverZ::identity(10, 10);
520
521 assert!(mat.get_submatrix(0, 0, 0, 10).is_err());
522 assert!(mat.get_submatrix(0, 10, 0, 0).is_err());
523 assert!(mat.get_submatrix(0, 0, -11, 0).is_err());
524 assert!(mat.get_submatrix(-11, 0, 0, 0).is_err());
525 }
526
527 #[test]
529 fn negative_indexing() {
530 let matrix = MatPolyOverZ::identity(3, 3);
531
532 assert_eq!(matrix, matrix.get_submatrix(0, -1, 0, -1).unwrap());
533 assert_eq!(matrix, matrix.get_submatrix(-3, -1, -3, -1).unwrap());
534 assert_eq!(
535 matrix.get_row(0).unwrap(),
536 matrix.get_submatrix(0, -3, -3, -1).unwrap()
537 );
538 }
539
540 #[test]
542 #[should_panic]
543 fn no_columns() {
544 let mat = MatPolyOverZ::identity(10, 10);
545
546 let _ = mat.get_submatrix(0, 0, 6, 5);
547 }
548
549 #[test]
551 #[should_panic]
552 fn no_rows() {
553 let mat = MatPolyOverZ::identity(10, 10);
554
555 let _ = mat.get_submatrix(5, 4, 0, 0);
556 }
557
558 #[test]
560 fn availability() {
561 let mat = MatPolyOverZ::identity(10, 10);
562
563 let _ = mat.get_submatrix(0_i8, 0_i8, 0_i8, 0_i8);
564 let _ = mat.get_submatrix(0_i16, 0_i16, 0_i16, 0_i16);
565 let _ = mat.get_submatrix(0_i32, 0_i32, 0_i32, 0_i32);
566 let _ = mat.get_submatrix(0_i64, 0_i64, 0_i64, 0_i64);
567 let _ = mat.get_submatrix(0_u8, 0_u8, 0_u8, 0_u8);
568 let _ = mat.get_submatrix(0_u16, 0_i16, 0_u16, 0_u16);
569 let _ = mat.get_submatrix(0_u32, 0_i32, 0_u32, 0_u32);
570 let _ = mat.get_submatrix(0_u64, 0_i64, 0_u64, 0_u64);
571 let _ = mat.get_submatrix(&Z::ZERO, &Z::ZERO, &Z::ZERO, &Z::ZERO);
572 }
573}
574
575#[cfg(test)]
576mod test_collect_entries {
577 use super::MatPolyOverZ;
578 use std::str::FromStr;
579
580 #[test]
582 fn all_entries_collected() {
583 let mat_1 = MatPolyOverZ::from_str(&format!(
584 "[[1 1, 0],[1 {}, 1 {}],[1 -3, 0]]",
585 i64::MAX,
586 i64::MIN
587 ))
588 .unwrap();
589 let mat_2 = MatPolyOverZ::from_str("[[1 -1, 2 1 2]]").unwrap();
590
591 let entries_1 = mat_1.collect_entries();
592 let entries_2 = mat_2.collect_entries();
593
594 assert_eq!(entries_1.len(), 6);
595 assert_eq!(unsafe { *entries_1[0].coeffs }.0, 1);
596 assert!(unsafe { *entries_1[2].coeffs }.0 >= 2_i64.pow(62));
597 assert!(unsafe { *entries_1[3].coeffs }.0 >= 2_i64.pow(62));
598 assert_eq!(unsafe { *entries_1[4].coeffs }.0, -3);
599
600 assert_eq!(entries_2.len(), 2);
601 assert_eq!(unsafe { *entries_2[0].coeffs.offset(0) }.0, -1);
602 assert_eq!(entries_2[0].length, 1);
603 assert_eq!(unsafe { *entries_2[1].coeffs.offset(0) }.0, 1);
604 assert_eq!(unsafe { *entries_2[1].coeffs.offset(1) }.0, 2);
605 assert_eq!(entries_2[1].length, 2);
606 }
607}