Skip to main content

qfall_math/integer_mod_q/mat_polynomial_ring_zq/
get.rs

1// Copyright 2023 Marcel Luca Schmidt
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//! Implementations to get information about a [`MatPolynomialRingZq`] matrix.
10
11use super::MatPolynomialRingZq;
12use crate::{
13    integer::{MatPolyOverZ, PolyOverZ},
14    integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
15    traits::{MatrixDimensions, MatrixGetEntry, MatrixGetSubmatrix, MatrixSetEntry},
16};
17use flint3_sys::{fmpz_poly_mat_entry, fmpz_poly_struct};
18
19impl MatPolynomialRingZq {
20    /// Returns the modulus of the matrix as a [`ModulusPolynomialRingZq`].
21    ///
22    /// # Examples
23    /// ```
24    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
25    /// use qfall_math::integer::MatPolyOverZ;
26    /// use std::str::FromStr;
27    ///
28    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
29    /// let poly_mat = MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42],[0, 2  1 2]]").unwrap();
30    /// let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
31    ///
32    /// let modulus = poly_ring_mat.get_mod();
33    /// ```
34    pub fn get_mod(&self) -> ModulusPolynomialRingZq {
35        self.modulus.clone()
36    }
37}
38
39impl MatPolynomialRingZq {
40    /// Creates a [`MatPolyOverZ`] where each entry is a representative of the
41    /// equivalence class of each entry from a [`MatPolynomialRingZq`] with coefficients centered around `0`.
42    ///
43    /// The representation of the coefficients is in the range `[-modulus/2, modulus/2]` and
44    /// the representation of the polynomials is in the range `[0, modulus_polynomial)`.
45    /// Use [`MatPolynomialRingZq::get_representative_least_nonnegative_residue`] if they should be
46    /// in the range `[0, modulus)`.
47    ///
48    /// # Examples
49    /// ```
50    /// use qfall_math::integer_mod_q::MatPolynomialRingZq;
51    /// use qfall_math::integer::MatPolyOverZ;
52    /// use std::str::FromStr;
53    ///
54    /// let poly_ring_mat = MatPolynomialRingZq::from_str("[[1  10, 1  11]] / 4  1 0 0 1 mod 21").unwrap();
55    ///
56    /// let matrix = poly_ring_mat.get_representative_least_absolute_residue();
57    ///
58    /// let cmp_poly_mat = MatPolyOverZ::from_str("[[1  10, 1  -10]]").unwrap();
59    /// assert_eq!(cmp_poly_mat, matrix);
60    /// ```
61    pub fn get_representative_least_absolute_residue(&self) -> MatPolyOverZ {
62        let mut out = MatPolyOverZ::new(self.get_num_rows(), self.get_num_columns());
63        for row in 0..self.get_num_rows() {
64            for col in 0..self.get_num_columns() {
65                let poly: PolynomialRingZq = unsafe { self.get_entry_unchecked(row, col) };
66                let lar_poly = poly.get_representative_least_absolute_residue();
67                unsafe { out.set_entry_unchecked(row, col, lar_poly) };
68            }
69        }
70        out
71    }
72
73    /// Creates a [`MatPolyOverZ`] where each entry is a representative of the
74    /// equivalence class of each entry from a [`MatPolynomialRingZq`].
75    ///
76    /// The representation of the coefficients is in the range `[0, modulus)` and
77    /// the representation of the polynomials is in the range `[0, modulus_polynomial)`.
78    /// Use [`MatPolynomialRingZq::get_representative_least_absolute_residue`] if they should be
79    /// in the range `[-modulus/2, modulus/2]`.
80    ///
81    /// # Examples
82    /// ```
83    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
84    /// use qfall_math::integer::MatPolyOverZ;
85    /// use std::str::FromStr;
86    ///
87    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
88    /// let poly_mat = MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42],[0, 2  1 2]]").unwrap();
89    /// let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
90    ///
91    /// let matrix = poly_ring_mat.get_representative_least_nonnegative_residue();
92    ///
93    /// let cmp_poly_mat = MatPolyOverZ::from_str("[[3  15 0 1, 1  8],[0, 2  1 2]]").unwrap();
94    /// assert_eq!(cmp_poly_mat, matrix);
95    /// ```
96    pub fn get_representative_least_nonnegative_residue(&self) -> MatPolyOverZ {
97        self.matrix.clone()
98    }
99}
100
101impl MatrixDimensions for MatPolynomialRingZq {
102    /// Returns the number of rows of the matrix as an [`i64`].
103    ///
104    /// # Examples
105    /// ```
106    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
107    /// use qfall_math::integer::MatPolyOverZ;
108    /// use qfall_math::traits::*;
109    /// use std::str::FromStr;
110    ///
111    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
112    /// let poly_mat = MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42],[0, 2  1 2]]").unwrap();
113    /// let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
114    ///
115    /// let rows = poly_ring_mat.get_num_rows();
116    /// ```
117    fn get_num_rows(&self) -> i64 {
118        self.matrix.get_num_rows()
119    }
120
121    /// Returns the number of columns of the matrix as an [`i64`].
122    ///
123    /// # Examples
124    /// ```
125    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
126    /// use qfall_math::integer::MatPolyOverZ;
127    /// use qfall_math::traits::*;
128    /// use std::str::FromStr;
129    ///
130    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
131    /// let poly_mat = MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42],[0, 2  1 2]]").unwrap();
132    /// let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
133    ///
134    /// let rows = poly_ring_mat.get_num_columns();
135    /// ```
136    fn get_num_columns(&self) -> i64 {
137        self.matrix.get_num_columns()
138    }
139}
140
141impl MatrixGetEntry<PolyOverZ> for MatPolynomialRingZq {
142    /// Outputs the [`PolyOverZ`] value of a specific matrix entry
143    /// without checking whether it's part of the matrix.
144    ///
145    /// Parameters:
146    /// - `row`: specifies the row in which the entry is located
147    /// - `column`: specifies the column in which the entry is located
148    ///
149    /// Returns the [`PolyOverZ`] value of the matrix at the position of the given
150    /// row and column.
151    ///
152    /// # Safety
153    /// To use this function safely, make sure that the selected entry is part
154    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
155    /// occur.
156    ///
157    /// # Examples
158    /// ```
159    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
160    /// use qfall_math::integer::{MatPolyOverZ, PolyOverZ};
161    /// use qfall_math::traits::*;
162    /// use std::str::FromStr;
163    ///
164    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 50").unwrap();
165    /// let poly_mat = MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42],[0, 2  1 2]]").unwrap();
166    /// let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
167    ///
168    /// let entry_1: PolyOverZ = unsafe { poly_ring_mat.get_entry_unchecked(1, 0) };
169    /// let entry_2: PolyOverZ = unsafe { poly_ring_mat.get_entry_unchecked(0, 1) };
170    ///
171    ///
172    /// assert_eq!(entry_1, PolyOverZ::from(0));
173    /// assert_eq!(entry_2, PolyOverZ::from(42));
174    /// ```
175    unsafe fn get_entry_unchecked(&self, row: i64, column: i64) -> PolyOverZ {
176        unsafe { self.matrix.get_entry_unchecked(row, column) }
177    }
178}
179
180impl MatrixGetEntry<PolynomialRingZq> for MatPolynomialRingZq {
181    /// Outputs the [`PolynomialRingZq`] value of a specific matrix entry
182    /// without checking whether it's part of the matrix.
183    ///
184    /// Parameters:
185    /// - `row`: specifies the row in which the entry is located
186    /// - `column`: specifies the column in which the entry is located
187    ///
188    /// Returns the [`PolynomialRingZq`] value of the matrix at the position of the given
189    /// row and column.
190    ///
191    /// # Safety
192    /// To use this function safely, make sure that the selected entry is part
193    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
194    /// occur.
195    ///
196    /// # Examples
197    /// ```
198    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq, PolynomialRingZq};
199    /// use qfall_math::integer::{MatPolyOverZ, PolyOverZ};
200    /// use qfall_math::traits::*;
201    /// use std::str::FromStr;
202    ///
203    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 50").unwrap();
204    /// let poly_mat = MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42],[0, 2  1 2]]").unwrap();
205    /// let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
206    ///
207    /// let entry_1: PolynomialRingZq = unsafe { poly_ring_mat.get_entry_unchecked(0, 1) };
208    /// let entry_2: PolynomialRingZq = unsafe { poly_ring_mat.get_entry_unchecked(0, 1) };
209    ///
210    /// let value_cmp = PolynomialRingZq::from((&PolyOverZ::from(42), &modulus));
211    /// assert_eq!(entry_1, value_cmp);
212    /// assert_eq!(entry_1, entry_2);
213    /// ```
214    unsafe fn get_entry_unchecked(&self, row: i64, column: i64) -> PolynomialRingZq {
215        PolynomialRingZq {
216            poly: unsafe { self.matrix.get_entry_unchecked(row, column) },
217            modulus: self.get_mod(),
218        }
219    }
220}
221
222impl MatrixGetSubmatrix for MatPolynomialRingZq {
223    /// Returns a deep copy of the submatrix defined by the given parameters
224    /// and does not check the provided dimensions.
225    /// There is also a safe version of this function that checks the input.
226    ///
227    /// Parameters:
228    /// `row_1`: the starting row of the submatrix
229    /// `row_2`: the ending row of the submatrix
230    /// `col_1`: the starting column of the submatrix
231    /// `col_2`: the ending column of the submatrix
232    ///
233    /// Returns the submatrix from `(row_1, col_1)` to `(row_2, col_2)`(exclusively).
234    ///
235    /// # Examples
236    /// ```
237    /// use qfall_math::{integer::MatPolyOverZ, traits::MatrixGetSubmatrix};
238    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
239    /// use std::str::FromStr;
240    ///
241    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();();
242    /// let mat = MatPolyOverZ::identity(3, 3);
243    /// let poly_ring_mat = MatPolynomialRingZq::from((&mat, &modulus));
244    ///
245    /// let sub_mat_1 = poly_ring_mat.get_submatrix(0, 2, 1, 1).unwrap();
246    /// let sub_mat_2 = poly_ring_mat.get_submatrix(0, -1, 1, -2).unwrap();
247    /// let sub_mat_3 = unsafe{poly_ring_mat.get_submatrix_unchecked(0, 3, 1, 2)};
248    ///
249    /// let e_2 = MatPolyOverZ::from_str("[[0],[1  1],[0]]").unwrap();
250    /// let e_2 = MatPolynomialRingZq::from((&e_2, &modulus));
251    /// assert_eq!(e_2, sub_mat_1);
252    /// assert_eq!(e_2, sub_mat_2);
253    /// assert_eq!(e_2, sub_mat_3);
254    /// ```
255    ///
256    /// # Safety
257    /// To use this function safely, make sure that the selected submatrix is part
258    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
259    /// occur.
260    unsafe fn get_submatrix_unchecked(
261        &self,
262        row_1: i64,
263        row_2: i64,
264        col_1: i64,
265        col_2: i64,
266    ) -> Self {
267        MatPolynomialRingZq {
268            matrix: unsafe {
269                self.matrix
270                    .get_submatrix_unchecked(row_1, row_2, col_1, col_2)
271            },
272            modulus: self.get_mod(),
273        }
274    }
275}
276
277impl MatPolynomialRingZq {
278    /// Efficiently collects all [`fmpz_poly_struct`]s in a [`MatPolynomialRingZq`] without cloning them.
279    ///
280    /// Hence, the values on the returned [`Vec`] are intended for short-term use
281    /// as the access to [`fmpz_poly_struct`] values could lead to memory leaks or modified values
282    /// once the [`MatPolynomialRingZq`] instance was modified or dropped.
283    ///
284    /// # Examples
285    /// ```compile_fail
286    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
287    /// use qfall_math::integer::MatPolyOverZ;
288    /// use std::str::FromStr;
289    ///
290    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
291    /// let poly_mat = MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42],[2  1 2, 3  1 1 1]]").unwrap();
292    /// let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
293    ///
294    /// let fmpz_entries = poly_ring_mat.collect_entries();
295    /// ```
296    #[allow(dead_code)]
297    pub(crate) fn collect_entries<'a>(&self) -> Vec<&'a fmpz_poly_struct> {
298        let mut entries: Vec<&'a fmpz_poly_struct> =
299            Vec::with_capacity((self.get_num_rows() * self.get_num_columns()) as usize);
300
301        for row in 0..self.get_num_rows() {
302            for col in 0..self.get_num_columns() {
303                // efficiently get entry without cloning the entry itself
304                unsafe {
305                    let entry_ptr = fmpz_poly_mat_entry(&self.matrix.matrix, row, col);
306                    let entry_ref: &'a fmpz_poly_struct = &*entry_ptr;
307                    entries.push(entry_ref);
308                }
309                // let entry = fmpz_poly_mat_entry(&self.matrix.matrix, row, col);
310            }
311        }
312
313        entries
314    }
315}
316
317#[cfg(test)]
318mod test_get_entry {
319    use crate::integer::{MatPolyOverZ, PolyOverZ};
320    use crate::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq, PolynomialRingZq};
321    use crate::traits::MatrixGetEntry;
322    use std::str::FromStr;
323
324    const LARGE_PRIME: u64 = u64::MAX - 58;
325
326    /// Ensure that getting entries works on the edge.
327    #[test]
328    fn get_edges() {
329        let modulus = ModulusPolynomialRingZq::from_str("2  42 1 mod 89").unwrap();
330        let matrix = MatPolynomialRingZq::new(5, 10, &modulus);
331
332        let entry_1: PolyOverZ = matrix.get_entry(0, 0).unwrap();
333        let entry_2: PolyOverZ = matrix.get_entry(4, 9).unwrap();
334
335        assert_eq!(PolyOverZ::default(), entry_1);
336        assert_eq!(PolyOverZ::default(), entry_2);
337    }
338
339    /// Ensure that getting entries works with large numbers.
340    #[test]
341    fn large_positive() {
342        let modulus =
343            ModulusPolynomialRingZq::from_str(&format!("5  42 17 1 2 1 mod {LARGE_PRIME}"))
344                .unwrap();
345        let poly_mat =
346            MatPolyOverZ::from_str(&format!("[[4  1 0 {} 1, 1  42],[0, 2  1 2]]", i64::MAX))
347                .unwrap();
348        let matrix = MatPolynomialRingZq::from((&poly_mat, &modulus));
349
350        let entry: PolyOverZ = matrix.get_entry(0, 0).unwrap();
351
352        assert_eq!(
353            PolyOverZ::from_str(&format!("4  1 0 {} 1", i64::MAX)).unwrap(),
354            entry
355        );
356    }
357
358    /// Ensure that a wrong number of rows yields an Error.
359    #[test]
360    fn error_wrong_row() {
361        let modulus =
362            ModulusPolynomialRingZq::from_str(&format!("5  42 17 1 2 1 mod {LARGE_PRIME}"))
363                .unwrap();
364        let matrix = MatPolynomialRingZq::new(5, 10, &modulus);
365
366        assert!(MatrixGetEntry::<PolynomialRingZq>::get_entry(&matrix, 5, 1).is_err());
367        assert!(MatrixGetEntry::<PolynomialRingZq>::get_entry(&matrix, -6, 1).is_err());
368        assert!(MatrixGetEntry::<PolyOverZ>::get_entry(&matrix, 5, 1).is_err());
369        assert!(MatrixGetEntry::<PolyOverZ>::get_entry(&matrix, -6, 1).is_err());
370    }
371
372    /// Ensure that a wrong number of columns yields an Error.
373    #[test]
374    fn error_wrong_column() {
375        let modulus =
376            ModulusPolynomialRingZq::from_str(&format!("5  42 17 1 2 1 mod {LARGE_PRIME}"))
377                .unwrap();
378        let matrix = MatPolynomialRingZq::new(5, 10, &modulus);
379
380        assert!(MatrixGetEntry::<PolynomialRingZq>::get_entry(&matrix, 1, 10).is_err());
381        assert!(MatrixGetEntry::<PolynomialRingZq>::get_entry(&matrix, 1, -11).is_err());
382        assert!(MatrixGetEntry::<PolyOverZ>::get_entry(&matrix, 1, 10).is_err());
383        assert!(MatrixGetEntry::<PolyOverZ>::get_entry(&matrix, 1, -11).is_err());
384    }
385
386    /// Ensure that getting entries works with different types.
387    #[test]
388    fn diff_types() {
389        let modulus =
390            ModulusPolynomialRingZq::from_str(&format!("5  42 17 1 2 1 mod {LARGE_PRIME}"))
391                .unwrap();
392        let matrix = MatPolynomialRingZq::new(5, 10, &modulus);
393
394        let _: PolyOverZ = matrix.get_entry(0, 0).unwrap();
395        let _: PolynomialRingZq = matrix.get_entry(0, 0).unwrap();
396    }
397}
398
399#[cfg(test)]
400mod test_get_num {
401    use crate::{
402        integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
403        traits::MatrixDimensions,
404    };
405    use std::str::FromStr;
406
407    /// Ensure that the getter for number of rows works correctly.
408    #[test]
409    fn num_rows() {
410        let modulus = ModulusPolynomialRingZq::from_str("2  42 1 mod 89").unwrap();
411        let matrix = MatPolynomialRingZq::new(5, 10, &modulus);
412
413        assert_eq!(matrix.get_num_rows(), 5);
414    }
415
416    /// Ensure that the getter for number of columns works correctly.
417    #[test]
418    fn num_columns() {
419        let modulus = ModulusPolynomialRingZq::from_str("2  42 1 mod 89").unwrap();
420        let matrix = MatPolynomialRingZq::new(5, 10, &modulus);
421
422        assert_eq!(matrix.get_num_columns(), 10);
423    }
424}
425
426#[cfg(test)]
427mod test_mod {
428    use crate::{
429        integer::MatPolyOverZ,
430        integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
431    };
432    use std::str::FromStr;
433
434    const LARGE_PRIME: u64 = u64::MAX - 58;
435
436    /// Ensure that the getter for modulus works correctly.
437    #[test]
438    fn get_mod() {
439        let modulus = ModulusPolynomialRingZq::from_str("2  42 1 mod 89").unwrap();
440        let poly_mat = MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42],[0, 2  1 2]]").unwrap();
441        let matrix = MatPolynomialRingZq::from((&poly_mat, &modulus));
442
443        assert_eq!(
444            matrix.get_mod(),
445            ModulusPolynomialRingZq::from_str("2  42 1 mod 89").unwrap()
446        );
447    }
448
449    /// Ensure that the getter for modulus works with large numbers.
450    #[test]
451    fn get_mod_large() {
452        let modulus =
453            ModulusPolynomialRingZq::from_str(&format!("2  42 1 mod {LARGE_PRIME}")).unwrap();
454        let poly_mat = MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42],[0, 2  1 2]]").unwrap();
455        let matrix = MatPolynomialRingZq::from((&poly_mat, &modulus));
456
457        assert_eq!(
458            matrix.get_mod(),
459            ModulusPolynomialRingZq::from_str(&format!("2  42 1 mod {LARGE_PRIME}")).unwrap()
460        );
461    }
462
463    /// Ensure that no memory leak occurs in get_mod.
464    #[test]
465    fn get_mod_memory() {
466        let modulus =
467            ModulusPolynomialRingZq::from_str(&format!("2  42 1 mod {LARGE_PRIME}")).unwrap();
468        let poly_mat = MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42],[0, 2  1 2]]").unwrap();
469        let matrix = MatPolynomialRingZq::from((&poly_mat, &modulus));
470        let _ = matrix.get_mod();
471        let _ = ModulusPolynomialRingZq::from_str(&format!("2  42 1 mod {LARGE_PRIME}")).unwrap();
472
473        let modulus = matrix.get_mod();
474
475        assert_eq!(
476            modulus,
477            ModulusPolynomialRingZq::from_str(&format!("2  42 1 mod {LARGE_PRIME}")).unwrap()
478        );
479    }
480}
481
482#[cfg(test)]
483mod test_get_representative_least_absolute_residue {
484    use crate::{integer::MatPolyOverZ, integer_mod_q::MatPolynomialRingZq};
485    use std::str::FromStr;
486
487    /// Check whether `get_representative_least_absolute_residue` outputs the correct value for large values
488    #[test]
489    fn large_numbers() {
490        let poly_ring = MatPolynomialRingZq::from_str(&format!(
491            "[[2  {} {}]] / 4  1 0 0 1 mod {}",
492            i64::MAX,
493            u64::MAX - 1,
494            u64::MAX
495        ))
496        .unwrap();
497
498        let lar_mat = poly_ring.get_representative_least_absolute_residue();
499
500        let cmp_mat = MatPolyOverZ::from_str(&format!("[[2  {} -1]]", i64::MAX)).unwrap();
501        assert_eq!(cmp_mat, lar_mat);
502    }
503
504    /// Check whether `get_representative_least_absolute_residue` outputs the correct value for special cases
505    #[test]
506    fn special_numbers() {
507        let mat = MatPolynomialRingZq::from_str("[[3  10 0 11]] / 4  1 0 0 1 mod 21").unwrap();
508
509        let lar_mat = mat.get_representative_least_absolute_residue();
510
511        let cmp_mat = MatPolyOverZ::from_str("[[3  10 0 -10]]").unwrap();
512        assert_eq!(cmp_mat, lar_mat);
513    }
514}
515
516#[cfg(test)]
517mod test_get_representative_least_nonnegative_residue {
518    use crate::{
519        integer::MatPolyOverZ,
520        integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
521    };
522    use std::str::FromStr;
523
524    const LARGE_PRIME: u64 = u64::MAX - 58;
525
526    /// Ensure that the getter for a large modulus and large entries works.
527    #[test]
528    fn get_representative_least_nonnegative_residue_large_entry_and_modulus() {
529        let modulus =
530            ModulusPolynomialRingZq::from_str(&format!("5  42 0 0 0 1 mod {LARGE_PRIME}")).unwrap();
531        let poly_mat = MatPolyOverZ::from_str("[[4  1 0 0 1, 1  42],[0, 1  -1]]").unwrap();
532        let matrix = MatPolynomialRingZq::from((&poly_mat, &modulus));
533
534        assert_eq!(
535            MatPolyOverZ::from_str(&format!(
536                "[[4  1 0 0 1, 1  42],[0, 1  {}]]",
537                LARGE_PRIME - 1
538            ))
539            .unwrap(),
540            matrix.get_representative_least_nonnegative_residue()
541        )
542    }
543}
544
545#[cfg(test)]
546mod test_get_vec {
547    use crate::{
548        integer::MatPolyOverZ,
549        integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
550        traits::MatrixGetSubmatrix,
551    };
552    use std::str::FromStr;
553
554    /// Ensure that getting a row works.
555    #[test]
556    fn get_row_works() {
557        let matrix = MatPolyOverZ::from_str(&format!(
558            "[[0, 0, 0],[1  42, 1  {}, 1  {}]]",
559            i64::MAX,
560            i64::MIN
561        ))
562        .unwrap();
563        let modulus =
564            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
565        let matrix = MatPolynomialRingZq::from((&matrix, &modulus));
566
567        let row_1 = matrix.get_row(0).unwrap();
568        let row_2 = matrix.get_row(1).unwrap();
569
570        let cmp_1 = MatPolyOverZ::from_str("[[0, 0, 0]]").unwrap();
571        let cmp_2 = MatPolyOverZ::from_str(&format!("[[1  42, 1  {}, 1  {}]]", i64::MAX, i64::MIN))
572            .unwrap();
573        let cmp_1 = MatPolynomialRingZq::from((&cmp_1, &modulus));
574        let cmp_2 = MatPolynomialRingZq::from((&cmp_2, &modulus));
575        assert_eq!(cmp_1, row_1);
576        assert_eq!(cmp_2, row_2);
577    }
578
579    /// Ensure that getting a row with a negative index works
580    #[test]
581    fn get_row_negative_indexing_works() {
582        let matrix = MatPolyOverZ::from_str(&format!(
583            "[[0, 0, 0],[1  42, 1  {}, 1  {}]]",
584            i64::MAX,
585            u64::MAX - 1
586        ))
587        .unwrap();
588        let modulus =
589            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
590        let matrix = MatPolynomialRingZq::from((&matrix, &modulus));
591        let row_1 = matrix.get_row(-2).unwrap();
592        let row_2 = matrix.get_row(-1).unwrap();
593
594        let cmp_1 = MatPolyOverZ::from_str("[[0, 0, 0]]").unwrap();
595        let cmp_2 =
596            MatPolyOverZ::from_str(&format!("[[1  42, 1  {}, 1  {}]]", i64::MAX, u64::MAX - 1))
597                .unwrap();
598
599        assert_eq!(cmp_1, row_1.matrix);
600        assert_eq!(cmp_2, row_2.matrix);
601    }
602
603    /// Ensure that getting a column works.
604    #[test]
605    fn get_column_works() {
606        let matrix = MatPolyOverZ::from_str(&format!(
607            "[[1  42, 0, 2  17 42],[1  {}, 0, 2  17 42],[1  {}, 0, 2  17 42]]",
608            i64::MAX,
609            i64::MIN
610        ))
611        .unwrap();
612        let modulus =
613            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
614        let matrix = MatPolynomialRingZq::from((&matrix, &modulus));
615
616        let column_1 = matrix.get_column(0).unwrap();
617        let column_2 = matrix.get_column(1).unwrap();
618        let column_3 = matrix.get_column(2).unwrap();
619
620        let cmp_1 =
621            MatPolyOverZ::from_str(&format!("[[1  42],[1  {}],[1  {}]]", i64::MAX, i64::MIN))
622                .unwrap();
623        let cmp_2 = MatPolyOverZ::from_str("[[0],[0],[0]]").unwrap();
624        let cmp_3 = MatPolyOverZ::from_str("[[2  17 42],[2  17 42],[2  17 42]]").unwrap();
625        let cmp_1 = MatPolynomialRingZq::from((&cmp_1, &modulus));
626        let cmp_2 = MatPolynomialRingZq::from((&cmp_2, &modulus));
627        let cmp_3 = MatPolynomialRingZq::from((&cmp_3, &modulus));
628        assert_eq!(cmp_1, column_1);
629        assert_eq!(cmp_2, column_2);
630        assert_eq!(cmp_3, column_3);
631    }
632
633    /// Ensure that getting a column with a negative index works
634    #[test]
635    fn get_column_negative_indexing_works() {
636        let matrix = MatPolyOverZ::from_str(&format!(
637            "[[1  42, 0, 2  17 42],[1  {}, 0, 2  17 42],[1  {}, 0, 2  17 42]]",
638            i64::MAX,
639            u64::MAX - 1
640        ))
641        .unwrap();
642        let modulus =
643            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
644        let matrix = MatPolynomialRingZq::from((&matrix, &modulus));
645        let column_1 = matrix.get_column(-3).unwrap();
646        let column_2 = matrix.get_column(-2).unwrap();
647        let column_3 = matrix.get_column(-1).unwrap();
648
649        let cmp_1 = MatPolyOverZ::from_str(&format!(
650            "[[1  42],[1  {}],[1  {}]]",
651            i64::MAX,
652            u64::MAX - 1
653        ))
654        .unwrap();
655        let cmp_2 = MatPolyOverZ::from_str("[[0],[0],[0]]").unwrap();
656        let cmp_3 = MatPolyOverZ::from_str("[[2  17 42],[2  17 42],[2  17 42]]").unwrap();
657
658        assert_eq!(cmp_1, column_1.matrix);
659        assert_eq!(cmp_2, column_2.matrix);
660        assert_eq!(cmp_3, column_3.matrix);
661    }
662
663    /// Ensure that wrong row and column dimensions yields an error.
664    #[test]
665    fn wrong_dim_error() {
666        let modulus =
667            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
668        let matrix = MatPolyOverZ::from_str(&format!(
669            "[[1  17, 2  17 42, 3  1 1 1],[1  {}, 1  1, 2  2 3],[1  {}, 1  142, 1  1]]",
670            i64::MAX,
671            i64::MIN
672        ))
673        .unwrap();
674        let matrix = MatPolynomialRingZq::from((&matrix, &modulus));
675
676        let row_1 = matrix.get_row(-4);
677        let row_2 = matrix.get_row(4);
678        let column_1 = matrix.get_column(-4);
679        let column_2 = matrix.get_column(4);
680
681        assert!(row_1.is_err());
682        assert!(row_2.is_err());
683        assert!(column_1.is_err());
684        assert!(column_2.is_err());
685    }
686}
687
688#[cfg(test)]
689mod test_get_submatrix {
690    use crate::{
691        integer::{MatPolyOverZ, Z},
692        integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
693        traits::{MatrixDimensions, MatrixGetSubmatrix},
694    };
695    use std::str::FromStr;
696
697    /// Ensures that getting the entire matrix as a submatrix works.
698    #[test]
699    fn entire_matrix() {
700        let modulus =
701            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
702        let mat = MatPolyOverZ::identity(5, 5);
703        let mat = MatPolynomialRingZq::from((&mat, &modulus));
704
705        let sub_mat = mat.get_submatrix(0, 4, 0, 4).unwrap();
706
707        assert_eq!(mat, sub_mat);
708    }
709
710    /// Ensures that a single matrix entry can be retrieved.
711    #[test]
712    fn matrix_single_entry() {
713        let modulus =
714            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
715        let mat = MatPolyOverZ::identity(5, 5);
716        let mat = MatPolynomialRingZq::from((&mat, &modulus));
717
718        let sub_mat = mat.get_submatrix(0, 0, 0, 0).unwrap();
719
720        let cmp_mat = MatPolyOverZ::identity(1, 1);
721        let cmp_mat = MatPolynomialRingZq::from((&cmp_mat, &modulus));
722        assert_eq!(cmp_mat, sub_mat);
723    }
724
725    /// Ensures that the dimensions of the submatrix are correct.
726    #[test]
727    fn correct_dimensions() {
728        let modulus =
729            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
730        let mat = MatPolyOverZ::identity(100, 100);
731        let mat = MatPolynomialRingZq::from((&mat, &modulus));
732
733        let sub_mat = mat.get_submatrix(1, 37, 0, 29).unwrap();
734
735        assert_eq!(37, sub_mat.get_num_rows());
736        assert_eq!(30, sub_mat.get_num_columns());
737    }
738
739    /// Ensures that a submatrix can be correctly retrieved for a matrix with large
740    /// entries.
741    #[test]
742    fn large_entries() {
743        let modulus =
744            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
745        let mat = MatPolyOverZ::from_str(&format!(
746            "[[2  -1 {}, 1  2, 1  3],[1  1, 1  {}, 1  3]]",
747            i64::MAX,
748            i64::MIN
749        ))
750        .unwrap();
751        let mat = MatPolynomialRingZq::from((&mat, &modulus));
752
753        let sub_mat = mat.get_submatrix(0, 1, 0, 1).unwrap();
754
755        let cmp_mat = MatPolyOverZ::from_str(&format!(
756            "[[2  -1 {}, 1  2],[1  1, 1  {}]]",
757            i64::MAX,
758            i64::MIN
759        ))
760        .unwrap();
761        let cmp_mat = MatPolynomialRingZq::from((&cmp_mat, &modulus));
762        assert_eq!(cmp_mat, sub_mat);
763    }
764
765    /// Ensures that an error is returned if coordinates are addressed that are not
766    /// within the matrix.
767    #[test]
768    fn invalid_coordinates() {
769        let modulus =
770            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
771        let mat = MatPolyOverZ::identity(10, 10);
772        let mat = MatPolynomialRingZq::from((&mat, &modulus));
773
774        assert!(mat.get_submatrix(0, 0, 0, 10).is_err());
775        assert!(mat.get_submatrix(0, 10, 0, 0).is_err());
776        assert!(mat.get_submatrix(0, 0, -11, 0).is_err());
777        assert!(mat.get_submatrix(-11, 0, 0, 0).is_err());
778    }
779
780    /// Ensure that negative indices return the correct submatrix.
781    #[test]
782    fn negative_indexing() {
783        let modulus =
784            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
785        let mat = MatPolyOverZ::identity(3, 3);
786        let matrix = MatPolynomialRingZq::from((&mat, &modulus));
787
788        assert_eq!(matrix, matrix.get_submatrix(0, -1, 0, -1).unwrap());
789        assert_eq!(matrix, matrix.get_submatrix(-3, -1, -3, -1).unwrap());
790    }
791
792    /// Ensures that the function panics if no columns of the matrix are addressed.
793    #[test]
794    #[should_panic]
795    fn no_columns() {
796        let modulus =
797            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
798        let mat = MatPolyOverZ::identity(10, 10);
799        let mat = MatPolynomialRingZq::from((&mat, &modulus));
800
801        let _ = mat.get_submatrix(0, 0, 6, 5);
802    }
803
804    /// Ensures that the function panics if no rows of the matrix are addressed.
805    #[test]
806    #[should_panic]
807    fn no_rows() {
808        let modulus =
809            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
810        let mat = MatPolyOverZ::identity(10, 10);
811        let mat = MatPolynomialRingZq::from((&mat, &modulus));
812
813        let _ = mat.get_submatrix(5, 4, 0, 0);
814    }
815
816    /// Ensure that the submatrix function can be called with several types.
817    #[test]
818    fn availability() {
819        let modulus =
820            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
821        let mat = MatPolyOverZ::identity(10, 10);
822        let mat = MatPolynomialRingZq::from((&mat, &modulus));
823
824        let _ = mat.get_submatrix(0_i8, 0_i8, 0_i8, 0_i8);
825        let _ = mat.get_submatrix(0_i16, 0_i16, 0_i16, 0_i16);
826        let _ = mat.get_submatrix(0_i32, 0_i32, 0_i32, 0_i32);
827        let _ = mat.get_submatrix(0_i64, 0_i64, 0_i64, 0_i64);
828        let _ = mat.get_submatrix(0_u8, 0_u8, 0_u8, 0_u8);
829        let _ = mat.get_submatrix(0_u16, 0_i16, 0_u16, 0_u16);
830        let _ = mat.get_submatrix(0_u32, 0_i32, 0_u32, 0_u32);
831        let _ = mat.get_submatrix(0_u64, 0_i64, 0_u64, 0_u64);
832        let _ = mat.get_submatrix(&Z::ZERO, &Z::ZERO, &Z::ZERO, &Z::ZERO);
833    }
834}
835
836#[cfg(test)]
837mod test_collect_entries {
838    use crate::integer::{MatPolyOverZ, PolyOverZ};
839    use crate::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
840    use flint3_sys::fmpz_poly_set;
841    use std::str::FromStr;
842
843    const LARGE_PRIME: u64 = u64::MAX - 58;
844
845    /// Ensures that all entries of the polynomial are actually collected in the vector.
846    #[test]
847    fn all_entries_collected() {
848        let modulus =
849            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {LARGE_PRIME}")).unwrap();
850        let poly_mat_1 = MatPolyOverZ::from_str(&format!(
851            "[[4  -1 0 3 1, 1  {}],[2  1 2, 3  {} 1 1]]",
852            i64::MAX,
853            i64::MIN + 58,
854        ))
855        .unwrap();
856        let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
857        let poly_mat_2 = MatPolyOverZ::from_str("[[1  42, 2  1 17]]").unwrap();
858        let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
859
860        let entries_1 = poly_ring_mat_1.collect_entries();
861        let entries_2 = poly_ring_mat_2.collect_entries();
862
863        let mut entry_1 = PolyOverZ::default();
864        let mut entry_2 = entry_1.clone();
865        let mut entry_3 = entry_1.clone();
866
867        unsafe { fmpz_poly_set(&mut entry_1.poly, entries_1[1]) }
868        unsafe { fmpz_poly_set(&mut entry_2.poly, entries_1[3]) }
869        unsafe { fmpz_poly_set(&mut entry_3.poly, entries_2[0]) }
870
871        assert_eq!(entries_1.len(), 4);
872        assert_eq!(
873            PolyOverZ::from_str(&format!("1  {}", i64::MAX)).unwrap(),
874            entry_1
875        );
876        assert_eq!(
877            PolyOverZ::from_str(&format!("3  {} 1 1", i64::MAX)).unwrap(),
878            entry_2
879        );
880
881        assert_eq!(entries_2.len(), 2);
882        assert_eq!(PolyOverZ::from(42), entry_3);
883    }
884
885    /// Ensure that the doc-test compiles and works correctly.
886    #[test]
887    fn doc_test() {
888        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
889        let poly_mat = MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42],[2  1 2, 3  1 1 1]]").unwrap();
890        let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
891
892        let _ = poly_ring_mat.collect_entries();
893    }
894}