qfall_math/integer_mod_q/polynomial_ring_zq/
get.rs

1// Copyright © 2023 Marcel Luca Schmidt, 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 content of a [`PolynomialRingZq].
10
11use super::PolynomialRingZq;
12use crate::{
13    integer::{PolyOverZ, Z},
14    integer_mod_q::{ModulusPolynomialRingZq, Zq},
15    traits::GetCoefficient,
16};
17use flint_sys::fmpz_poly::{fmpz_poly_degree, fmpz_poly_get_coeff_fmpz};
18
19impl GetCoefficient<Zq> for PolynomialRingZq {
20    /// Returns the coefficient of a [`PolynomialRingZq`] as a [`Zq`].
21    ///
22    /// If an index is provided which exceeds the highest set coefficient, `0` is returned.
23    ///
24    /// Parameters:
25    /// - `index`: the index of the coefficient to get (has to be positive)
26    ///
27    /// Returns the coefficient as a [`Zq`], or a [`MathError`](crate::error::MathError) if the provided index
28    /// is negative and therefore invalid, or it does not fit into an [`i64`].
29    ///
30    /// # Examples
31    /// ```
32    /// use qfall_math::traits::*;
33    /// use qfall_math::integer_mod_q::{PolynomialRingZq, Zq};
34    /// use std::str::FromStr;
35    ///
36    /// let poly_ring = PolynomialRingZq::from_str("3  0 1 1 / 4  1 0 0 1 mod 17").unwrap();
37    ///
38    /// let coeff_0: Zq = poly_ring.get_coeff(0).unwrap();
39    /// let coeff_1: Zq = unsafe{ poly_ring.get_coeff_unchecked(1) };
40    /// let coeff_3: Zq = poly_ring.get_coeff(3).unwrap();
41    ///
42    /// assert_eq!(Zq::from((0, 17)), coeff_0);
43    /// assert_eq!(Zq::from((1, 17)), coeff_1);
44    /// assert_eq!(Zq::from((0, 17)), coeff_3);
45    /// ```
46    ///
47    /// # Safety
48    /// To use this function safely, make sure that the selected index
49    /// is greater or equal than `0`.
50    unsafe fn get_coeff_unchecked(&self, index: i64) -> Zq {
51        let mut out_z = Z::default();
52        unsafe { fmpz_poly_get_coeff_fmpz(&mut out_z.value, &self.poly.poly, index) }
53        Zq::from((out_z, &self.modulus.get_q()))
54    }
55}
56
57impl GetCoefficient<Z> for PolynomialRingZq {
58    /// Returns the coefficient of a [`PolynomialRingZq`] as a [`Z`].
59    ///
60    /// If an index is provided which exceeds the highest set coefficient, `0` is returned.
61    ///
62    /// Parameters:
63    /// - `index`: the index of the coefficient to get (has to be positive)
64    ///
65    /// Returns the coefficient as a [`Z`], or a [`MathError`](crate::error::MathError) if the provided index
66    /// is negative and therefore invalid, or it does not fit into an [`i64`].
67    ///
68    /// # Examples
69    /// ```
70    /// use qfall_math::traits::*;
71    /// use qfall_math::integer::{PolyOverZ, Z};
72    /// use qfall_math::integer_mod_q::{PolynomialRingZq, ModulusPolynomialRingZq};
73    /// use std::str::FromStr;
74    ///
75    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
76    /// let poly = PolyOverZ::from_str("3  0 1 1").unwrap();
77    /// let poly_ring = PolynomialRingZq::from((&poly, &modulus));
78    ///
79    /// let coeff_0: Z = poly_ring.get_coeff(0).unwrap();
80    /// let coeff_1: Z = unsafe{ poly_ring.get_coeff_unchecked(1) };
81    /// let coeff_3: Z = poly_ring.get_coeff(3).unwrap();
82    ///
83    /// assert_eq!(Z::ZERO, coeff_0);
84    /// assert_eq!(Z::ONE, coeff_1);
85    /// assert_eq!(Z::ZERO, coeff_3);
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 { fmpz_poly_get_coeff_fmpz(&mut out.value, &self.poly.poly, index) }
94        out
95    }
96}
97
98impl PolynomialRingZq {
99    /// Returns the modulus object of the [`PolynomialRingZq`] element.
100    ///
101    /// # Examples
102    /// ```
103    /// use qfall_math::integer::PolyOverZ;
104    /// use qfall_math::integer_mod_q::{PolynomialRingZq, ModulusPolynomialRingZq};
105    /// use std::str::FromStr;
106    ///
107    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
108    /// let poly = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
109    /// let poly_ring = PolynomialRingZq::from((&poly, &modulus));
110    ///
111    /// let poly_ring_mod = poly_ring.get_mod();
112    ///
113    /// assert_eq!(modulus, poly_ring_mod);
114    /// ```
115    pub fn get_mod(&self) -> ModulusPolynomialRingZq {
116        self.modulus.clone()
117    }
118
119    /// Returns a representative polynomial of the [`PolynomialRingZq`] element.
120    ///
121    /// The representation of the coefficients is in the range `[0, modulus)` and
122    /// the representation of the polynomial is in the range `[0, modulus_polynomial)`.
123    ///
124    /// # Examples
125    /// ```
126    /// use qfall_math::integer::PolyOverZ;
127    /// use qfall_math::integer_mod_q::{PolynomialRingZq, ModulusPolynomialRingZq};
128    /// use std::str::FromStr;
129    ///
130    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
131    /// let poly = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
132    /// let poly_ring = PolynomialRingZq::from((&poly, &modulus));
133    ///
134    /// let poly_z = poly_ring.get_representative_least_nonnegative_residue();
135    ///
136    /// let cmp_poly = PolyOverZ::from_str("3  15 0 1").unwrap();
137    /// assert_eq!(cmp_poly, poly_z);
138    /// ```
139    pub fn get_representative_least_nonnegative_residue(&self) -> PolyOverZ {
140        self.poly.clone()
141    }
142
143    /// Returns the degree of a [`PolynomialRingZq`] as a [`i64`].
144    /// The zero polynomial has degree `-1`.
145    ///
146    /// # Examples
147    /// ```
148    /// use qfall_math::integer::PolyOverZ;
149    /// use qfall_math::integer_mod_q::{PolynomialRingZq, ModulusPolynomialRingZq};
150    /// use std::str::FromStr;
151    ///
152    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
153    /// let poly = PolyOverZ::from_str("3  0 1 1").unwrap();
154    /// let poly_ring = PolynomialRingZq::from((&poly, &modulus));
155    ///
156    /// let degree = poly_ring.get_degree();
157    ///
158    /// assert_eq!(2, degree);
159    /// ```
160    pub fn get_degree(&self) -> i64 {
161        unsafe { fmpz_poly_degree(&self.poly.poly) }
162    }
163}
164
165#[cfg(test)]
166mod test_get_coeff {
167    use crate::{
168        integer::{PolyOverZ, Z},
169        integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq, Zq},
170        traits::GetCoefficient,
171    };
172    use std::str::FromStr;
173
174    /// Ensure that 0 is returned if the provided index is not yet set.
175    #[test]
176    fn index_out_of_range() {
177        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
178        let poly = PolyOverZ::from_str("3  1 1 1").unwrap();
179        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
180
181        let zero_coeff_z: Z = poly_ring.get_coeff(3).unwrap();
182        let zero_coeff_zq = poly_ring.get_coeff(3).unwrap();
183
184        assert_eq!(0, zero_coeff_z);
185        assert_eq!(Zq::from((0, 17)), zero_coeff_zq);
186    }
187
188    /// Tests if coefficients are returned correctly.
189    #[test]
190    fn coeff_correct() {
191        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
192        let poly = PolyOverZ::from_str("3  1 0 3").unwrap();
193        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
194
195        let coeff_z: Z = poly_ring.get_coeff(2).unwrap();
196        let coeff_zq = poly_ring.get_coeff(2).unwrap();
197
198        assert_eq!(3, coeff_z);
199        assert_eq!(Zq::from((3, 17)), coeff_zq);
200    }
201
202    /// Tests if large coefficients are returned correctly.
203    #[test]
204    fn large_coeff() {
205        let modulus =
206            ModulusPolynomialRingZq::from_str(&format!("5  1 0 4 1 9 mod {}", u64::MAX)).unwrap();
207        let poly = PolyOverZ::from_str(&format!("3  0 {} 1", i64::MAX)).unwrap();
208        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
209
210        let coefficient_1: Z = poly_ring.get_coeff(1).unwrap();
211        let coefficient_2: Zq = poly_ring.get_coeff(1).unwrap();
212
213        assert_eq!(i64::MAX, coefficient_1);
214        assert_eq!(Zq::from((i64::MAX, u64::MAX)), coefficient_2);
215    }
216
217    /// Tests if negative index yields an error in get_coeff with [`Z`].
218    #[test]
219    #[should_panic]
220    fn negative_index_error_z() {
221        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
222        let poly = PolyOverZ::from_str("3  1 0 3").unwrap();
223        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
224
225        let _: Z = poly_ring.get_coeff(-1).unwrap();
226    }
227
228    /// Tests if negative index yields an error in get_coeff with [`Zq`].
229    #[test]
230    #[should_panic]
231    fn negative_index_error_zq() {
232        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
233        let poly = PolyOverZ::from_str("3  1 0 3").unwrap();
234        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
235
236        let _: Zq = poly_ring.get_coeff(-1).unwrap();
237    }
238}
239
240#[cfg(test)]
241mod test_get_mod {
242    use crate::{
243        integer::PolyOverZ,
244        integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
245    };
246    use std::str::FromStr;
247
248    /// Ensure that the large modulus polynomial is returned correctly.
249    #[test]
250    fn large_positive() {
251        let modulus =
252            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX - 58))
253                .unwrap();
254        let poly = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
255        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
256
257        assert_eq!(modulus, poly_ring.get_mod());
258    }
259}
260
261#[cfg(test)]
262mod test_get_representative_least_nonnegative_residue {
263    use crate::{
264        integer::PolyOverZ,
265        integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
266    };
267    use std::str::FromStr;
268
269    /// Ensure that the getter works for large entries.
270    #[test]
271    fn large_positive() {
272        let large_prime = u64::MAX - 58;
273        let modulus =
274            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {large_prime}")).unwrap();
275        let poly = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
276        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
277
278        let poly_z = poly_ring.get_representative_least_nonnegative_residue();
279
280        let cmp_poly = PolyOverZ::from_str(&format!("3  {} 0 1", u64::MAX - 60)).unwrap();
281        assert_eq!(cmp_poly, poly_z);
282    }
283}
284
285#[cfg(test)]
286mod test_get_degree {
287    use crate::{
288        integer::PolyOverZ,
289        integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
290    };
291    use std::str::FromStr;
292
293    /// Ensure that degree is working.
294    #[test]
295    fn degree() {
296        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
297        let poly = PolyOverZ::from_str("3  0 1 1").unwrap();
298        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
299
300        let deg = poly_ring.get_degree();
301
302        assert_eq!(2, deg);
303    }
304
305    /// Ensure that degree is working for constant polynomials.
306    #[test]
307    fn degree_constant() {
308        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
309        let poly = PolyOverZ::from(1);
310        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
311
312        let deg = poly_ring.get_degree();
313
314        assert_eq!(0, deg);
315    }
316
317    /// Ensure that degree is working for polynomials with leading 0 coefficients.
318    #[test]
319    fn degree_leading_zeros() {
320        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
321        let poly = PolyOverZ::from_str("3  1 0 0").unwrap();
322        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
323
324        let deg = poly_ring.get_degree();
325
326        assert_eq!(0, deg);
327    }
328}