qfall_math/integer_mod_q/poly_over_zq/
get.rs

1// Copyright © 2023 Marvin Beckmann
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 [`PolyOverZq`] polynomial.
10
11use super::PolyOverZq;
12use crate::{
13    integer::{PolyOverZ, Z},
14    integer_mod_q::{Modulus, Zq},
15    traits::GetCoefficient,
16};
17use flint_sys::fmpz_mod_poly::{
18    fmpz_mod_poly_degree, fmpz_mod_poly_get_coeff_fmpz, fmpz_mod_poly_get_fmpz_poly,
19};
20
21impl GetCoefficient<Zq> for PolyOverZq {
22    /// Returns the coefficient of a polynomial [`PolyOverZq`] as a [`Zq`].
23    ///
24    /// If an index is provided which exceeds the highest set coefficient, `0` is returned.
25    ///
26    /// Parameters:
27    /// - `index`: the index of the coefficient to get (has to be positive)
28    ///
29    /// Returns the coefficient as a [`Zq`], or a [`MathError`](crate::error::MathError) if the provided index
30    /// is negative and therefore invalid, or it does not fit into an [`i64`].
31    ///
32    /// # Examples
33    /// ```
34    /// use qfall_math::traits::*;
35    /// use qfall_math::integer_mod_q::PolyOverZq;
36    /// use qfall_math::integer_mod_q::Zq;
37    /// use std::str::FromStr;
38    ///
39    /// let poly = PolyOverZq::from_str("4  0 1 2 3 mod 17").unwrap();
40    ///
41    /// let coeff_0: Zq = poly.get_coeff(0).unwrap();
42    /// let coeff_1: Zq = unsafe{ poly.get_coeff_unchecked(1) };
43    /// let coeff_4: Zq = poly.get_coeff(4).unwrap();
44    ///
45    /// assert_eq!(Zq::from((0, 17)), coeff_0);
46    /// assert_eq!(Zq::from((1, 17)), coeff_1);
47    /// assert_eq!(Zq::from((0, 17)), coeff_4);
48    /// ```
49    ///
50    /// # Safety
51    /// To use this function safely, make sure that the selected index
52    /// is greater or equal than `0`.
53    unsafe fn get_coeff_unchecked(&self, index: i64) -> Zq {
54        let out_z: Z = unsafe { self.get_coeff_unchecked(index) };
55        Zq::from((out_z, &self.modulus))
56    }
57}
58
59impl GetCoefficient<Z> for PolyOverZq {
60    /// Returns the coefficient of a polynomial [`PolyOverZq`] as a [`Z`].
61    ///
62    /// If an index is provided which exceeds the highest set coefficient, `0` is returned.
63    ///
64    /// Parameters:
65    /// - `index`: the index of the coefficient to get (has to be positive)
66    ///
67    /// Returns the coefficient as a [`Z`], or a [`MathError`](crate::error::MathError) if the provided index
68    /// is negative and therefore invalid, or it does not fit into an [`i64`].
69    ///
70    /// # Examples
71    /// ```
72    /// use qfall_math::traits::*;
73    /// use qfall_math::integer_mod_q::PolyOverZq;
74    /// use qfall_math::integer::Z;
75    /// use std::str::FromStr;
76    ///
77    /// let poly = PolyOverZq::from_str("4  0 1 2 3 mod 17").unwrap();
78    ///
79    /// let coeff_0: Z = poly.get_coeff(0).unwrap();
80    /// let coeff_1: Z = unsafe{ poly.get_coeff_unchecked(1) };
81    /// let coeff_4: Z = poly.get_coeff(4).unwrap();
82    ///
83    /// assert_eq!(Z::ZERO, coeff_0);
84    /// assert_eq!(Z::ONE, coeff_1);
85    /// assert_eq!(Z::ZERO, coeff_4);
86    /// ```
87    ///
88    /// # Safety
89    /// To use this function safely, make sure that the selected index
90    /// is greater or equal than `0`.
91    unsafe fn get_coeff_unchecked(&self, index: i64) -> Z {
92        let mut out = Z::default();
93        unsafe {
94            fmpz_mod_poly_get_coeff_fmpz(
95                &mut out.value,
96                &self.poly,
97                index,
98                self.modulus.get_fmpz_mod_ctx_struct(),
99            )
100        }
101        out
102    }
103}
104
105impl PolyOverZq {
106    /// Returns the degree of a polynomial [`PolyOverZq`] as a [`i64`].
107    /// The zero polynomial has degree `-1`.
108    ///
109    /// # Examples
110    /// ```
111    /// use qfall_math::integer_mod_q::PolyOverZq;
112    /// use std::str::FromStr;
113    ///
114    /// let poly = PolyOverZq::from_str("4  0 1 2 3 mod 7").unwrap();
115    ///
116    /// let degree = poly.get_degree(); // This would only return 3
117    /// ```
118    pub fn get_degree(&self) -> i64 {
119        unsafe { fmpz_mod_poly_degree(&self.poly, self.modulus.get_fmpz_mod_ctx_struct()) }
120    }
121
122    /// Returns the modulus of the polynomial as a [`Modulus`].
123    ///
124    /// # Examples
125    /// ```
126    /// use qfall_math::integer_mod_q::PolyOverZq;
127    /// use std::str::FromStr;
128    ///
129    /// let matrix = PolyOverZq::from_str("2  1 3 mod 7").unwrap();
130    /// let modulus = matrix.get_mod();
131    /// ```
132    pub fn get_mod(&self) -> Modulus {
133        self.modulus.clone()
134    }
135
136    /// Returns a representative polynomial of the [`PolyOverZq`] element.
137    ///
138    /// The representation of the coefficients is in the range `[0, modulus)`.
139    ///
140    /// # Examples
141    /// ```
142    /// use qfall_math::integer::PolyOverZ;
143    /// use qfall_math::integer_mod_q::PolyOverZq;
144    /// use std::str::FromStr;
145    ///
146    /// let poly_zq = PolyOverZq::from_str("4  -3 0 31 1 mod 17").unwrap();
147    ///
148    /// let poly_z = poly_zq.get_representative_least_nonnegative_residue();
149    ///
150    /// let cmp_poly = PolyOverZ::from_str("4  14 0 14 1").unwrap();
151    /// assert_eq!(cmp_poly, poly_z);
152    /// ```
153    pub fn get_representative_least_nonnegative_residue(&self) -> PolyOverZ {
154        let mut out = PolyOverZ::default();
155        unsafe {
156            fmpz_mod_poly_get_fmpz_poly(
157                &mut out.poly,
158                &self.poly,
159                self.modulus.get_fmpz_mod_ctx_struct(),
160            )
161        };
162        out
163    }
164}
165
166// We omit the tests for the value of the [`Zq`], and focus on the [`Modulus`] being set correctly
167// since get_coefficient for [`Z`] is called, where we will check the value itself.
168#[cfg(test)]
169mod test_get_coeff_zq_modulus {
170    use crate::{
171        integer_mod_q::{Modulus, PolyOverZq, Zq},
172        traits::GetCoefficient,
173    };
174    use std::str::FromStr;
175
176    /// Ensure that the [`Modulus`] is transferred correctly when accessing an index out of bounds.
177    #[test]
178    fn index_out_of_range_modulus() {
179        let modulus_str = format!("17{}", u64::MAX);
180        let modulus = Modulus::from_str(&modulus_str).unwrap();
181
182        let poly = PolyOverZq::from_str(&format!("4  0 1 2 3 mod {modulus_str}")).unwrap();
183
184        let zero_coeff: Zq = poly.get_coeff(4).unwrap();
185
186        assert_eq!(modulus, zero_coeff.modulus);
187    }
188
189    /// Ensure that the [`Modulus`] is transferred correctly when accessing an index in bounds.
190    #[test]
191    fn index_in_range_modulus() {
192        let modulus_str = format!("17{}", u64::MAX);
193        let modulus = Modulus::from_str(&modulus_str).unwrap();
194
195        let poly = PolyOverZq::from_str(&format!("4  0 1 2 3 mod {modulus_str}")).unwrap();
196
197        let third_coeff: Zq = poly.get_coeff(3).unwrap();
198
199        assert_eq!(modulus, third_coeff.modulus);
200    }
201}
202
203#[cfg(test)]
204mod test_get_coeff_z {
205    use crate::{integer::Z, integer_mod_q::PolyOverZq, traits::GetCoefficient};
206    use std::str::FromStr;
207
208    /// Ensure that `0` is returned if the provided index is not yet set.
209    #[test]
210    fn index_out_of_range() {
211        let modulus_str = format!("17{}", u64::MAX);
212
213        let poly = PolyOverZq::from_str(&format!("4  0 1 2 3 mod {modulus_str}")).unwrap();
214
215        let zero_coeff: Z = poly.get_coeff(4).unwrap();
216
217        assert_eq!(0, zero_coeff);
218    }
219
220    /// Tests if positive coefficients are returned correctly.
221    #[test]
222    fn positive_coeff() {
223        let modulus_str = format!("17{}", u64::MAX);
224
225        let poly = PolyOverZq::from_str(&format!("4  0 1 2 3 mod {modulus_str}")).unwrap();
226
227        let coeff: Z = poly.get_coeff(2).unwrap();
228
229        assert_eq!(2, coeff);
230    }
231
232    /// Tests if large coefficients are returned correctly.
233    #[test]
234    fn large_coeff() {
235        let modulus_str = format!("17{}", u64::MAX);
236        let large_string = format!("2  {} {} mod {modulus_str}", u64::MAX, i64::MAX);
237        let poly = PolyOverZq::from_str(&large_string).unwrap();
238
239        let coefficint_1: Z = poly.get_coeff(0).unwrap();
240        let coefficint_2: Z = poly.get_coeff(1).unwrap();
241
242        assert_eq!(u64::MAX, coefficint_1);
243        assert_eq!(i64::MAX, coefficint_2);
244    }
245
246    /// Tests if large negative coefficients are returned correctly.
247    #[test]
248    fn large_modulus_applied_negative_large_coefficient() {
249        let modulus_str = format!("{}", u64::MAX);
250        let large_string = format!("2  -{} {} mod {modulus_str}", u64::MAX, i64::MAX);
251        let poly = PolyOverZq::from_str(&large_string).unwrap();
252
253        let coefficint_1: Z = poly.get_coeff(0).unwrap();
254        let coefficint_2: Z = poly.get_coeff(1).unwrap();
255
256        assert_eq!(0, coefficint_1);
257        assert_eq!(i64::MAX, coefficint_2);
258    }
259}
260
261#[cfg(test)]
262mod test_get_degree {
263    use crate::integer_mod_q::PolyOverZq;
264    use std::str::FromStr;
265
266    /// Ensure that degree is working.
267    #[test]
268    fn degree() {
269        let poly = PolyOverZq::from_str("4  0 1 2 3 mod 7").unwrap();
270
271        let deg = poly.get_degree();
272
273        assert_eq!(3, deg);
274    }
275
276    /// Ensure that degree is working for constant polynomials.
277    #[test]
278    fn degree_constant() {
279        let poly_1 = PolyOverZq::from_str("1  1 mod 19").unwrap();
280        let poly_2 = PolyOverZq::from_str("0 mod 19").unwrap();
281
282        let deg_1 = poly_1.get_degree();
283        let deg_2 = poly_2.get_degree();
284
285        assert_eq!(0, deg_1);
286        assert_eq!(-1, deg_2);
287    }
288
289    /// Ensure that degree is working for polynomials with leading 0 coefficients.
290    #[test]
291    fn degree_leading_zeros() {
292        let poly = PolyOverZq::from_str("4  1 0 0 0 mod 199").unwrap();
293
294        let deg = poly.get_degree();
295
296        assert_eq!(0, deg);
297    }
298
299    /// Ensure that degree is working for polynomials with many coefficients
300    /// flint does not reduce the exponent due to computational cost.
301    #[test]
302    fn degree_many_coefficients() {
303        let poly_1 = PolyOverZq::from_str("7  1 2 3 4 8 1 3 mod 2").unwrap();
304        let poly_2 = PolyOverZq::from_str(&format!(
305            "7  1 2 3 4 8 {} {} mod {}",
306            u64::MAX,
307            i64::MAX,
308            u128::MAX
309        ))
310        .unwrap();
311
312        let deg_1 = poly_1.get_degree();
313        let deg_2 = poly_2.get_degree();
314
315        assert_eq!(6, deg_1);
316        assert_eq!(6, deg_2);
317    }
318}
319
320#[cfg(test)]
321mod test_mod {
322    use crate::integer_mod_q::{Modulus, PolyOverZq};
323    use std::str::FromStr;
324
325    /// Ensure that the getter for modulus works correctly.
326    #[test]
327    fn get_mod() {
328        let poly = PolyOverZq::from_str("2  1 2 mod 7").unwrap();
329
330        assert_eq!(poly.get_mod(), Modulus::from(7));
331    }
332
333    /// Ensure that the getter for modulus works with large numbers.
334    #[test]
335    fn get_mod_large() {
336        let poly = PolyOverZq::from_str(&format!("2  1 2 mod {}", u64::MAX)).unwrap();
337
338        assert_eq!(poly.get_mod(), Modulus::from(u64::MAX));
339    }
340}
341
342#[cfg(test)]
343mod test_get_representative_least_nonnegative_residue {
344    use crate::{integer::PolyOverZ, integer_mod_q::PolyOverZq};
345    use std::str::FromStr;
346
347    /// Ensure that the getter works for large entries.
348    #[test]
349    fn large_positive() {
350        let large_prime = u64::MAX - 58;
351        let poly_zq = PolyOverZq::from_str(&format!("4  -1 0 0 1 mod {large_prime}")).unwrap();
352
353        let poly_z = poly_zq.get_representative_least_nonnegative_residue();
354
355        let cmp_poly = PolyOverZ::from_str(&format!("4  {} 0 0 1", u64::MAX - 59)).unwrap();
356        assert_eq!(cmp_poly, poly_z);
357    }
358}