Skip to main content

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, SetCoefficient},
16};
17use flint3_sys::{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 with coefficients centered around `0`.
120    ///
121    /// The output [`PolyOverZ`] has coefficients in the range of `[-modulus/2, modulus/2]`.
122    /// For even moduli, the positive representative is chosen for the element `modulus / 2`.
123    /// Use [`PolynomialRingZq::get_representative_least_nonnegative_residue`] if they should be
124    /// in the range `[0, modulus)`.
125    ///
126    /// # Examples
127    /// ```
128    /// use qfall_math::integer_mod_q::PolynomialRingZq;
129    /// use qfall_math::integer::PolyOverZ;
130    /// use std::str::FromStr;
131    ///
132    /// let value = PolynomialRingZq::from_str("2  10 11 / 4  1 0 0 1 mod 21").unwrap();
133    ///
134    /// let least_abs_residue = value.get_representative_least_absolute_residue();
135    ///
136    /// assert_eq!(PolyOverZ::from_str("2  10 -10").unwrap(), least_abs_residue);
137    /// ```
138    pub fn get_representative_least_absolute_residue(&self) -> PolyOverZ {
139        let mut out = PolyOverZ::default();
140        for i in 0..=self.get_degree() {
141            let coeff: Zq = unsafe { self.get_coeff_unchecked(i) };
142            let lar_coeff = coeff.get_representative_least_absolute_residue();
143            unsafe { out.set_coeff_unchecked(i, lar_coeff) };
144        }
145        out
146    }
147
148    /// Returns a representative polynomial of the [`PolynomialRingZq`] element.
149    ///
150    /// The representation of the coefficients is in the range `[0, modulus)` and
151    /// the representation of the polynomial is in the range `[0, modulus_polynomial)`.
152    /// Use [`PolynomialRingZq::get_representative_least_absolute_residue`] if they should be
153    /// in the range `[-modulus/2, modulus/2]`.
154    ///
155    /// # Examples
156    /// ```
157    /// use qfall_math::integer::PolyOverZ;
158    /// use qfall_math::integer_mod_q::{PolynomialRingZq, ModulusPolynomialRingZq};
159    /// use std::str::FromStr;
160    ///
161    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
162    /// let poly = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
163    /// let poly_ring = PolynomialRingZq::from((&poly, &modulus));
164    ///
165    /// let poly_z = poly_ring.get_representative_least_nonnegative_residue();
166    ///
167    /// let cmp_poly = PolyOverZ::from_str("3  15 0 1").unwrap();
168    /// assert_eq!(cmp_poly, poly_z);
169    /// ```
170    pub fn get_representative_least_nonnegative_residue(&self) -> PolyOverZ {
171        self.poly.clone()
172    }
173
174    /// Returns the degree of a [`PolynomialRingZq`] as a [`i64`].
175    /// The zero polynomial has degree `-1`.
176    ///
177    /// # Examples
178    /// ```
179    /// use qfall_math::integer::PolyOverZ;
180    /// use qfall_math::integer_mod_q::{PolynomialRingZq, ModulusPolynomialRingZq};
181    /// use std::str::FromStr;
182    ///
183    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
184    /// let poly = PolyOverZ::from_str("3  0 1 1").unwrap();
185    /// let poly_ring = PolynomialRingZq::from((&poly, &modulus));
186    ///
187    /// let degree = poly_ring.get_degree();
188    ///
189    /// assert_eq!(2, degree);
190    /// ```
191    pub fn get_degree(&self) -> i64 {
192        unsafe { fmpz_poly_degree(&self.poly.poly) }
193    }
194}
195
196#[cfg(test)]
197mod test_get_coeff {
198    use crate::{
199        integer::{PolyOverZ, Z},
200        integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq, Zq},
201        traits::GetCoefficient,
202    };
203    use std::str::FromStr;
204
205    /// Ensure that 0 is returned if the provided index is not yet set.
206    #[test]
207    fn index_out_of_range() {
208        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
209        let poly = PolyOverZ::from_str("3  1 1 1").unwrap();
210        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
211
212        let zero_coeff_z: Z = poly_ring.get_coeff(3).unwrap();
213        let zero_coeff_zq = poly_ring.get_coeff(3).unwrap();
214
215        assert_eq!(0, zero_coeff_z);
216        assert_eq!(Zq::from((0, 17)), zero_coeff_zq);
217    }
218
219    /// Tests if coefficients are returned correctly.
220    #[test]
221    fn coeff_correct() {
222        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
223        let poly = PolyOverZ::from_str("3  1 0 3").unwrap();
224        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
225
226        let coeff_z: Z = poly_ring.get_coeff(2).unwrap();
227        let coeff_zq = poly_ring.get_coeff(2).unwrap();
228
229        assert_eq!(3, coeff_z);
230        assert_eq!(Zq::from((3, 17)), coeff_zq);
231    }
232
233    /// Tests if large coefficients are returned correctly.
234    #[test]
235    fn large_coeff() {
236        let modulus =
237            ModulusPolynomialRingZq::from_str(&format!("5  1 0 4 1 1 mod {}", u64::MAX)).unwrap();
238        let poly = PolyOverZ::from_str(&format!("3  0 {} 1", i64::MAX)).unwrap();
239        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
240
241        let coefficient_1: Z = poly_ring.get_coeff(1).unwrap();
242        let coefficient_2: Zq = poly_ring.get_coeff(1).unwrap();
243
244        assert_eq!(i64::MAX, coefficient_1);
245        assert_eq!(Zq::from((i64::MAX, u64::MAX)), coefficient_2);
246    }
247
248    /// Tests if negative index yields an error in get_coeff with [`Z`].
249    #[test]
250    #[should_panic]
251    fn negative_index_error_z() {
252        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
253        let poly = PolyOverZ::from_str("3  1 0 3").unwrap();
254        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
255
256        let _: Z = poly_ring.get_coeff(-1).unwrap();
257    }
258
259    /// Tests if negative index yields an error in get_coeff with [`Zq`].
260    #[test]
261    #[should_panic]
262    fn negative_index_error_zq() {
263        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
264        let poly = PolyOverZ::from_str("3  1 0 3").unwrap();
265        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
266
267        let _: Zq = poly_ring.get_coeff(-1).unwrap();
268    }
269}
270
271#[cfg(test)]
272mod test_get_mod {
273    use crate::{
274        integer::PolyOverZ,
275        integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
276    };
277    use std::str::FromStr;
278
279    /// Ensure that the large modulus polynomial is returned correctly.
280    #[test]
281    fn large_positive() {
282        let modulus =
283            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX - 58))
284                .unwrap();
285        let poly = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
286        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
287
288        assert_eq!(modulus, poly_ring.get_mod());
289    }
290}
291
292#[cfg(test)]
293mod test_get_representative_least_absolute_residue {
294    use crate::{integer::PolyOverZ, integer_mod_q::PolynomialRingZq};
295    use std::str::FromStr;
296
297    /// Check whether `get_representative_least_absolute_residue` outputs the correct value for large values
298    #[test]
299    fn large_numbers() {
300        let poly_ring = PolynomialRingZq::from_str(&format!(
301            "2  {} {} / 4  1 0 0 1 mod {}",
302            i64::MAX,
303            u64::MAX - 1,
304            u64::MAX
305        ))
306        .unwrap();
307
308        let poly_z = poly_ring.get_representative_least_absolute_residue();
309
310        let cmp_poly = PolyOverZ::from_str(&format!("2  {} -1", i64::MAX)).unwrap();
311        assert_eq!(cmp_poly, poly_z);
312    }
313
314    /// Check whether `get_representative_least_absolute_residue` outputs the correct value for special cases
315    #[test]
316    fn special_numbers() {
317        let poly_ring = PolynomialRingZq::from_str("3  10 0 11 / 4  1 0 0 1 mod 21").unwrap();
318
319        let poly_z = poly_ring.get_representative_least_absolute_residue();
320
321        let cmp_poly = PolyOverZ::from_str("3  10 0 -10").unwrap();
322        assert_eq!(cmp_poly, poly_z);
323    }
324}
325
326#[cfg(test)]
327mod test_get_representative_least_nonnegative_residue {
328    use crate::{
329        integer::PolyOverZ,
330        integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
331    };
332    use std::str::FromStr;
333
334    /// Ensure that the getter works for large entries.
335    #[test]
336    fn large_positive() {
337        let large_prime = u64::MAX - 58;
338        let modulus =
339            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {large_prime}")).unwrap();
340        let poly = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
341        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
342
343        let poly_z = poly_ring.get_representative_least_nonnegative_residue();
344
345        let cmp_poly = PolyOverZ::from_str(&format!("3  {} 0 1", u64::MAX - 60)).unwrap();
346        assert_eq!(cmp_poly, poly_z);
347    }
348}
349
350#[cfg(test)]
351mod test_get_degree {
352    use crate::{
353        integer::PolyOverZ,
354        integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
355    };
356    use std::str::FromStr;
357
358    /// Ensure that degree is working.
359    #[test]
360    fn degree() {
361        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
362        let poly = PolyOverZ::from_str("3  0 1 1").unwrap();
363        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
364
365        let deg = poly_ring.get_degree();
366
367        assert_eq!(2, deg);
368    }
369
370    /// Ensure that degree is working for constant polynomials.
371    #[test]
372    fn degree_constant() {
373        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
374        let poly = PolyOverZ::from(1);
375        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
376
377        let deg = poly_ring.get_degree();
378
379        assert_eq!(0, deg);
380    }
381
382    /// Ensure that degree is working for polynomials with leading 0 coefficients.
383    #[test]
384    fn degree_leading_zeros() {
385        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
386        let poly = PolyOverZ::from_str("3  1 0 0").unwrap();
387        let poly_ring = PolynomialRingZq::from((&poly, &modulus));
388
389        let deg = poly_ring.get_degree();
390
391        assert_eq!(0, deg);
392    }
393}