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}