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}