1use super::MatPolyOverZ;
12use crate::{
13 integer::PolyOverZ,
14 traits::{MatrixDimensions, MatrixGetEntry, MatrixGetSubmatrix},
15};
16use flint3_sys::{
17 fmpz_poly_set, fmpz_poly_struct,
18 {
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<'a>(&self) -> Vec<&'a fmpz_poly_struct> {
175 let mut entries: Vec<&'a 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 unsafe {
182 let entry_ptr = fmpz_poly_mat_entry(&self.matrix, row, col);
183 let entry_ref: &'a fmpz_poly_struct = &*entry_ptr;
184 entries.push(entry_ref);
185 }
186 }
187 }
188
189 entries
190 }
191}
192
193#[cfg(test)]
194mod test_get_entry {
195 use crate::{
196 integer::{MatPolyOverZ, PolyOverZ},
197 traits::{MatrixGetEntry, MatrixSetEntry},
198 };
199 use std::str::FromStr;
200
201 #[test]
203 fn max_int_positive() {
204 let mut matrix = MatPolyOverZ::new(5, 10);
205 let value = PolyOverZ::from_str(&format!("2 {} 1", i64::MAX)).unwrap();
206 matrix.set_entry(1, 1, value).unwrap();
207
208 let entry = matrix.get_entry(1, 1).unwrap();
209
210 assert_eq!(format!("2 {} 1", i64::MAX), entry.to_string());
211 }
212
213 #[test]
215 fn large_positive() {
216 let mut matrix = MatPolyOverZ::new(5, 10);
217 let value = PolyOverZ::from_str(&format!("2 {} 1", u64::MAX)).unwrap();
218 matrix.set_entry(1, 1, value).unwrap();
219
220 let entry = matrix.get_entry(1, 1).unwrap();
221
222 assert_eq!(format!("2 {} 1", u64::MAX), entry.to_string());
223 }
224
225 #[test]
227 fn max_int_negative() {
228 let mut matrix = MatPolyOverZ::new(5, 10);
229 let value = PolyOverZ::from_str(&format!("2 {} 1", i64::MIN)).unwrap();
230 matrix.set_entry(1, 1, value).unwrap();
231
232 let entry = matrix.get_entry(1, 1).unwrap();
233
234 assert_eq!(format!("2 {} 1", i64::MIN), entry.to_string());
235 }
236
237 #[test]
239 fn large_negative() {
240 let mut matrix = MatPolyOverZ::new(5, 10);
241 let value = PolyOverZ::from_str(&format!("2 -{} 1", u64::MAX)).unwrap();
242 matrix.set_entry(1, 1, value).unwrap();
243
244 let entry = matrix.get_entry(1, 1).unwrap();
245
246 assert_eq!(format!("2 -{} 1", u64::MAX), entry.to_string());
247 }
248
249 #[test]
251 fn large_poly() {
252 let mut matrix = MatPolyOverZ::new(5, 10);
253 let value =
254 PolyOverZ::from_str(&format!("10000 -{} 1{}", u64::MAX, " 17".repeat(9998))).unwrap();
255 matrix.set_entry(1, 1, value).unwrap();
256
257 let entry = matrix.get_entry(1, 1).unwrap();
258
259 assert_eq!(
260 format!("10000 -{} 1{}", u64::MAX, " 17".repeat(9998)),
261 entry.to_string()
262 );
263 }
264
265 #[test]
267 fn getting_at_zero() {
268 let mut matrix = MatPolyOverZ::new(5, 10);
269 let value = PolyOverZ::from_str(&format!("2 {} 1", i64::MAX)).unwrap();
270 matrix.set_entry(0, 0, value).unwrap();
271
272 let entry = matrix.get_entry(0, 0).unwrap();
273
274 assert_eq!(format!("2 {} 1", i64::MAX), entry.to_string());
275 }
276
277 #[test]
279 fn error_wrong_row() {
280 let matrix = MatPolyOverZ::new(5, 10);
281
282 assert!(matrix.get_entry(5, 1).is_err());
283 assert!(matrix.get_entry(-6, 1).is_err());
284 }
285
286 #[test]
288 fn error_wrong_column() {
289 let matrix = MatPolyOverZ::new(5, 10);
290
291 assert!(matrix.get_entry(1, 100).is_err());
292 assert!(matrix.get_entry(1, -11).is_err());
293 }
294
295 #[test]
297 fn negative_indexing() {
298 let matrix = MatPolyOverZ::from_str("[[1 1, 1 2],[1 3, 1 4],[1 5 , 1 6]]").unwrap();
299
300 assert_eq!(PolyOverZ::from(2), matrix.get_entry(0, -1).unwrap());
301 assert_eq!(PolyOverZ::from(4), matrix.get_entry(-2, 1).unwrap());
302 assert_eq!(PolyOverZ::from(4), matrix.get_entry(-2, -1).unwrap());
303 assert_eq!(PolyOverZ::from(6), matrix.get_entry(-1, -1).unwrap());
304 }
305
306 #[test]
308 fn memory_test() {
309 let mut matrix = MatPolyOverZ::new(5, 10);
310 let value = PolyOverZ::from_str(&format!("2 {} 1", u64::MAX)).unwrap();
311 matrix.set_entry(1, 1, value).unwrap();
312 let entry = matrix.get_entry(1, 1).unwrap();
313 matrix.set_entry(1, 1, PolyOverZ::default()).unwrap();
314
315 assert_eq!(format!("2 {} 1", u64::MAX), entry.to_string());
316 }
317}
318
319#[cfg(test)]
320mod test_get_num {
321 use crate::{integer::MatPolyOverZ, traits::MatrixDimensions};
322
323 #[test]
325 fn num_rows() {
326 let matrix = MatPolyOverZ::new(5, 10);
327
328 assert_eq!(matrix.get_num_rows(), 5);
329 }
330
331 #[test]
333 fn num_columns() {
334 let matrix = MatPolyOverZ::new(5, 10);
335
336 assert_eq!(matrix.get_num_columns(), 10);
337 }
338}
339
340#[cfg(test)]
341mod test_get_vec {
342 use crate::{integer::MatPolyOverZ, traits::MatrixGetSubmatrix};
343 use std::str::FromStr;
344
345 #[test]
347 fn get_row_works() {
348 let matrix = MatPolyOverZ::from_str(&format!(
349 "[[0, 0, 0],[1 42, 1 {}, 1 {}]]",
350 i64::MAX,
351 i64::MIN
352 ))
353 .unwrap();
354 let row_1 = matrix.get_row(0).unwrap();
355 let row_2 = matrix.get_row(1).unwrap();
356
357 let cmp_1 = MatPolyOverZ::from_str("[[0, 0, 0]]").unwrap();
358 let cmp_2 = MatPolyOverZ::from_str(&format!("[[1 42, 1 {}, 1 {}]]", i64::MAX, i64::MIN))
359 .unwrap();
360
361 assert_eq!(cmp_1, row_1);
362 assert_eq!(cmp_2, row_2);
363 }
364
365 #[test]
367 fn get_row_negative_indexing_works() {
368 let matrix = MatPolyOverZ::from_str(&format!(
369 "[[0, 0, 0],[1 42, 1 {}, 1 {}]]",
370 i64::MAX,
371 i64::MIN
372 ))
373 .unwrap();
374 let row_1 = matrix.get_row(-2).unwrap();
375 let row_2 = matrix.get_row(-1).unwrap();
376
377 let cmp_1 = MatPolyOverZ::from_str("[[0, 0, 0]]").unwrap();
378 let cmp_2 = MatPolyOverZ::from_str(&format!("[[1 42, 1 {}, 1 {}]]", i64::MAX, i64::MIN))
379 .unwrap();
380
381 assert_eq!(cmp_1, row_1);
382 assert_eq!(cmp_2, row_2);
383 }
384
385 #[test]
387 fn get_column_works() {
388 let matrix = MatPolyOverZ::from_str(&format!(
389 "[[1 42, 0, 2 17 42],[1 {}, 0, 2 17 42],[1 {}, 0, 2 17 42]]",
390 i64::MAX,
391 i64::MIN
392 ))
393 .unwrap();
394 let column_1 = matrix.get_column(0).unwrap();
395 let column_2 = matrix.get_column(1).unwrap();
396 let column_3 = matrix.get_column(2).unwrap();
397
398 let cmp_1 =
399 MatPolyOverZ::from_str(&format!("[[1 42],[1 {}],[1 {}]]", i64::MAX, i64::MIN))
400 .unwrap();
401 let cmp_2 = MatPolyOverZ::from_str("[[0],[0],[0]]").unwrap();
402 let cmp_3 = MatPolyOverZ::from_str("[[2 17 42],[2 17 42],[2 17 42]]").unwrap();
403
404 assert_eq!(cmp_1, column_1);
405 assert_eq!(cmp_2, column_2);
406 assert_eq!(cmp_3, column_3);
407 }
408
409 #[test]
411 fn get_column_negative_indexing_works() {
412 let matrix = MatPolyOverZ::from_str(&format!(
413 "[[1 42, 0, 2 17 42],[1 {}, 0, 2 17 42],[1 {}, 0, 2 17 42]]",
414 i64::MAX,
415 i64::MIN
416 ))
417 .unwrap();
418 let column_1 = matrix.get_column(-3).unwrap();
419 let column_2 = matrix.get_column(-2).unwrap();
420 let column_3 = matrix.get_column(-1).unwrap();
421
422 let cmp_1 =
423 MatPolyOverZ::from_str(&format!("[[1 42],[1 {}],[1 {}]]", i64::MAX, i64::MIN))
424 .unwrap();
425 let cmp_2 = MatPolyOverZ::from_str("[[0],[0],[0]]").unwrap();
426 let cmp_3 = MatPolyOverZ::from_str("[[2 17 42],[2 17 42],[2 17 42]]").unwrap();
427
428 assert_eq!(cmp_1, column_1);
429 assert_eq!(cmp_2, column_2);
430 assert_eq!(cmp_3, column_3);
431 }
432
433 #[test]
435 fn wrong_dim_error() {
436 let matrix = MatPolyOverZ::from_str(&format!(
437 "[[1 17, 2 17 42, 3 1 1 1],[1 {}, 1 1, 2 2 3],[1 {}, 1 142, 1 1]]",
438 i64::MAX,
439 i64::MIN
440 ))
441 .unwrap();
442 let row_1 = matrix.get_row(-4);
443 let row_2 = matrix.get_row(4);
444 let column_1 = matrix.get_column(-4);
445 let column_2 = matrix.get_column(4);
446
447 assert!(row_1.is_err());
448 assert!(row_2.is_err());
449 assert!(column_1.is_err());
450 assert!(column_2.is_err());
451 }
452}
453
454#[cfg(test)]
455mod test_get_submatrix {
456 use crate::{
457 integer::{MatPolyOverZ, Z},
458 traits::{MatrixDimensions, MatrixGetSubmatrix},
459 };
460 use std::str::FromStr;
461
462 #[test]
464 fn entire_matrix() {
465 let mat = MatPolyOverZ::identity(5, 5);
466
467 let sub_mat = mat.get_submatrix(0, 4, 0, 4).unwrap();
468
469 assert_eq!(mat, sub_mat);
470 }
471
472 #[test]
474 fn matrix_single_entry() {
475 let mat = MatPolyOverZ::identity(5, 5);
476
477 let sub_mat = mat.get_submatrix(0, 0, 0, 0).unwrap();
478
479 let cmp_mat = MatPolyOverZ::identity(1, 1);
480 assert_eq!(cmp_mat, sub_mat);
481 }
482
483 #[test]
485 fn correct_dimensions() {
486 let mat = MatPolyOverZ::identity(100, 100);
487
488 let sub_mat = mat.get_submatrix(1, 37, 0, 29).unwrap();
489
490 assert_eq!(37, sub_mat.get_num_rows());
491 assert_eq!(30, sub_mat.get_num_columns());
492 }
493
494 #[test]
497 fn large_entries() {
498 let mat = MatPolyOverZ::from_str(&format!(
499 "[[2 {} {}, 1 2, 1 3],[1 1, 1 {}, 1 3]]",
500 u64::MAX,
501 i64::MAX,
502 i64::MIN
503 ))
504 .unwrap();
505
506 let sub_mat = mat.get_submatrix(0, 1, 0, 1).unwrap();
507
508 let cmp_mat = MatPolyOverZ::from_str(&format!(
509 "[[2 {} {}, 1 2],[1 1, 1 {}]]",
510 u64::MAX,
511 i64::MAX,
512 i64::MIN
513 ))
514 .unwrap();
515 assert_eq!(cmp_mat, sub_mat);
516 }
517
518 #[test]
521 fn invalid_coordinates() {
522 let mat = MatPolyOverZ::identity(10, 10);
523
524 assert!(mat.get_submatrix(0, 0, 0, 10).is_err());
525 assert!(mat.get_submatrix(0, 10, 0, 0).is_err());
526 assert!(mat.get_submatrix(0, 0, -11, 0).is_err());
527 assert!(mat.get_submatrix(-11, 0, 0, 0).is_err());
528 }
529
530 #[test]
532 fn negative_indexing() {
533 let matrix = MatPolyOverZ::identity(3, 3);
534
535 assert_eq!(matrix, matrix.get_submatrix(0, -1, 0, -1).unwrap());
536 assert_eq!(matrix, matrix.get_submatrix(-3, -1, -3, -1).unwrap());
537 assert_eq!(
538 matrix.get_row(0).unwrap(),
539 matrix.get_submatrix(0, -3, -3, -1).unwrap()
540 );
541 }
542
543 #[test]
545 #[should_panic]
546 fn no_columns() {
547 let mat = MatPolyOverZ::identity(10, 10);
548
549 let _ = mat.get_submatrix(0, 0, 6, 5);
550 }
551
552 #[test]
554 #[should_panic]
555 fn no_rows() {
556 let mat = MatPolyOverZ::identity(10, 10);
557
558 let _ = mat.get_submatrix(5, 4, 0, 0);
559 }
560
561 #[test]
563 fn availability() {
564 let mat = MatPolyOverZ::identity(10, 10);
565
566 let _ = mat.get_submatrix(0_i8, 0_i8, 0_i8, 0_i8);
567 let _ = mat.get_submatrix(0_i16, 0_i16, 0_i16, 0_i16);
568 let _ = mat.get_submatrix(0_i32, 0_i32, 0_i32, 0_i32);
569 let _ = mat.get_submatrix(0_i64, 0_i64, 0_i64, 0_i64);
570 let _ = mat.get_submatrix(0_u8, 0_u8, 0_u8, 0_u8);
571 let _ = mat.get_submatrix(0_u16, 0_i16, 0_u16, 0_u16);
572 let _ = mat.get_submatrix(0_u32, 0_i32, 0_u32, 0_u32);
573 let _ = mat.get_submatrix(0_u64, 0_i64, 0_u64, 0_u64);
574 let _ = mat.get_submatrix(&Z::ZERO, &Z::ZERO, &Z::ZERO, &Z::ZERO);
575 }
576}
577
578#[cfg(test)]
579mod test_collect_entries {
580 use super::MatPolyOverZ;
581 use std::str::FromStr;
582
583 #[test]
585 fn all_entries_collected() {
586 let mat_1 = MatPolyOverZ::from_str(&format!(
587 "[[1 1, 0],[1 {}, 1 {}],[1 -3, 0]]",
588 i64::MAX,
589 i64::MIN
590 ))
591 .unwrap();
592 let mat_2 = MatPolyOverZ::from_str("[[1 -1, 2 1 2]]").unwrap();
593
594 let entries_1 = mat_1.collect_entries();
595 let entries_2 = mat_2.collect_entries();
596
597 assert_eq!(entries_1.len(), 6);
598 assert_eq!(unsafe { *entries_1[0].coeffs }, 1);
599 assert!(unsafe { *entries_1[2].coeffs } >= 2_i64.pow(62));
600 assert!(unsafe { *entries_1[3].coeffs } >= 2_i64.pow(62));
601 assert_eq!(unsafe { *entries_1[4].coeffs }, -3);
602
603 assert_eq!(entries_2.len(), 2);
604 assert_eq!(unsafe { *entries_2[0].coeffs.offset(0) }, -1);
605 assert_eq!(entries_2[0].length, 1);
606 assert_eq!(unsafe { *entries_2[1].coeffs.offset(0) }, 1);
607 assert_eq!(unsafe { *entries_2[1].coeffs.offset(1) }, 2);
608 assert_eq!(entries_2[1].length, 2);
609 }
610}