Skip to main content

qfall_math/integer_mod_q/poly_over_zq/
set.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 manipulate a [`PolyOverZq`] polynomial.
10
11use super::PolyOverZq;
12use crate::{
13    integer::Z,
14    integer_mod_q::{Modulus, Zq},
15    macros::for_others::implement_for_owned,
16    traits::SetCoefficient,
17};
18use flint3_sys::{fmpz_mod_poly_set_coeff_fmpz, fmpz_mod_poly_set_fmpz_poly};
19
20impl<Integer: Into<Z>> SetCoefficient<Integer> for PolyOverZq {
21    /// Sets the coefficient of a polynomial [`PolyOverZq`].
22    /// We advise to use small coefficients, since already 2^32 coefficients take space
23    /// of roughly 34 GB. If not careful, be prepared that memory problems can occur, if
24    /// the index is very high.
25    ///
26    /// Parameters:
27    /// - `index`: the index of the coefficient to set (has to be positive)
28    /// - `value`: the new value the coefficient will be set to.
29    ///
30    /// # Examples
31    /// ```
32    /// use qfall_math::integer_mod_q::PolyOverZq;
33    /// use qfall_math::integer::Z;
34    /// use qfall_math::traits::*;
35    /// use std::str::FromStr;
36    ///
37    /// let mut poly = PolyOverZq::from_str("4  0 1 2 3 mod 17").unwrap();
38    ///
39    /// assert!(poly.set_coeff(4, 1000).is_ok());
40    /// unsafe{ poly.set_coeff_unchecked(5, 75) };
41    /// ```
42    ///
43    /// # Safety
44    /// To use this function safely, make sure that the selected index
45    /// is greater or equal than `0` and that the provided value has
46    /// the same base so that they have a matching base.
47    unsafe fn set_coeff_unchecked(&mut self, index: i64, value: Integer) {
48        let value: Z = value.into();
49
50        unsafe {
51            fmpz_mod_poly_set_coeff_fmpz(
52                &mut self.poly,
53                index,
54                &value.value,
55                self.modulus.get_fmpz_mod_ctx_struct(),
56            );
57        }
58    }
59}
60
61impl SetCoefficient<&Zq> for PolyOverZq {
62    /// Sets the coefficient of a polynomial [`PolyOverZq`].
63    /// We advise to use small coefficients, since already 2^32 coefficients take space
64    /// of roughly 34 GB. If not careful, be prepared that memory problems can occur, if
65    /// the index is very high.
66    ///
67    /// This function does not check if the modulus of the polynomial and the value match.
68    ///
69    /// Parameters:
70    /// - `index`: the index of the coefficient to set (has to be positive)
71    /// - `value`: the new value the index should have from a borrowed [`Zq`].
72    ///
73    /// # Examples
74    /// ```
75    /// use qfall_math::integer_mod_q::PolyOverZq;
76    /// use qfall_math::integer_mod_q::Zq;
77    /// use qfall_math::traits::*;
78    /// use std::str::FromStr;
79    ///
80    /// let mut poly = PolyOverZq::from_str("4  0 1 2 3 mod 17").unwrap();
81    /// let value = Zq::from((1000, 17));
82    ///
83    /// assert!(poly.set_coeff(4, &value).is_ok());
84    /// unsafe{ poly.set_coeff_unchecked(5, &value) };
85    /// ```
86    ///
87    /// # Safety
88    /// To use this function safely, make sure that the selected index
89    /// is greater or equal than `0` and that the provided value has
90    /// the same base so that they have a matching base.
91    unsafe fn set_coeff_unchecked(&mut self, index: i64, value: &Zq) {
92        unsafe { self.set_coeff_unchecked(index, &value.value) }
93    }
94}
95
96implement_for_owned!(Zq, PolyOverZq, SetCoefficient);
97
98impl PolyOverZq {
99    /// Changes the modulus of the given polynomial to the new modulus.
100    /// It takes the representation of each coefficient in [0, q) as the new
101    /// coefficients and reduces them by the new [`Modulus`].
102    ///
103    /// Parameters:
104    /// - `modulus`: the new modulus of the polynomial
105    ///
106    /// # Examples
107    /// ```
108    /// use qfall_math::integer_mod_q::PolyOverZq;
109    /// use std::str::FromStr;
110    ///
111    /// let mut poly = PolyOverZq::from_str("4  5 3 7 4 mod 13").unwrap();
112    ///
113    /// poly.change_modulus(5);
114    ///
115    /// assert_eq!(PolyOverZq::from_str("4  0 3 2 4 mod 5").unwrap(), poly);
116    /// ```
117    ///
118    /// # Panics ...
119    /// - if `modulus` is smaller than `2`.
120    pub fn change_modulus(&mut self, modulus: impl Into<Modulus>) {
121        self.modulus = modulus.into();
122        let lnr = self.get_representative_least_nonnegative_residue();
123        unsafe {
124            fmpz_mod_poly_set_fmpz_poly(
125                &mut self.poly,
126                &lnr.poly,
127                self.modulus.get_fmpz_mod_ctx_struct(),
128            );
129        }
130    }
131}
132
133#[cfg(test)]
134mod test_set_coeff_z {
135    use crate::{integer::Z, integer_mod_q::PolyOverZq, traits::SetCoefficient};
136    use std::str::FromStr;
137
138    /// Ensure that the negative indices return an error.
139    #[test]
140    fn set_min_negative_coeff() {
141        let mut poly = PolyOverZq::from_str("2  1 1 mod 11").unwrap();
142
143        assert!(poly.set_coeff(i64::MIN, 2).is_err());
144        assert!(poly.set_coeff(i32::MIN, 2).is_err());
145        assert!(poly.set_coeff(i16::MIN, 2).is_err());
146        assert!(poly.set_coeff(i8::MIN, 2).is_err());
147    }
148
149    /// Ensure that large coefficients work.
150    #[test]
151    fn set_coeff_large() {
152        let mut poly = PolyOverZq::from_str("2  1 1 mod 11").unwrap();
153
154        assert!(poly.set_coeff(2, i32::MAX).is_ok());
155        assert!(poly.set_coeff(2, i64::MAX).is_ok());
156    }
157
158    /// Ensure that the max of [`u8`] and [`u16`] works as an index.
159    #[test]
160    fn set_index_large() {
161        let mut poly = PolyOverZq::from_str("2  1 1 mod 11").unwrap();
162
163        assert!(poly.set_coeff(u8::MAX, 2).is_ok());
164        assert!(poly.set_coeff(u16::MAX, 2).is_ok());
165    }
166
167    /// Ensure that a general case is working.
168    #[test]
169    fn set_coeff_working() {
170        let mut poly = PolyOverZq::from_str("4  0 1 2 3 mod 11").unwrap();
171        let value = 10000;
172
173        poly.set_coeff(0, value).unwrap();
174        poly.set_coeff(5, value).unwrap();
175        assert_eq!(
176            PolyOverZq::from_str("6  1 1 2 3 0 1  mod 11").unwrap(),
177            poly
178        );
179    }
180
181    /// Ensure that the correct coefficient is set and all others are set to `0`.
182    #[test]
183    fn set_coeff_rest_zero() {
184        let mut poly = PolyOverZq::from_str("0 mod 11").unwrap();
185
186        poly.set_coeff(4, -10).unwrap();
187        assert_eq!(PolyOverZq::from_str("5  0 0 0 0 1 mod 11").unwrap(), poly);
188    }
189
190    /// Ensure that setting with a z works.
191    #[test]
192    fn set_coeff_z() {
193        let mut poly = PolyOverZq::from_str("0 mod 11").unwrap();
194
195        poly.set_coeff(4, Z::from(123)).unwrap();
196        assert_eq!(PolyOverZq::from_str("5  0 0 0 0 2 mod 11").unwrap(), poly);
197    }
198}
199
200/// we omit most of the tests for the correct values, since
201/// the values itself are set with set_coeff taking in a [`Z`] value
202#[cfg(test)]
203mod test_set_coeff_zq {
204    use crate::{
205        integer_mod_q::{PolyOverZq, Zq},
206        traits::SetCoefficient,
207    };
208    use std::str::FromStr;
209
210    /// Ensure that an error is returned if the moduli do not match
211    #[test]
212    fn mismatching_moduli() {
213        let mut poly = PolyOverZq::from_str(&format!("4  0 1 2 3 mod {}", u64::MAX - 58)).unwrap();
214        let value = Zq::from((u64::MAX, u64::MAX - 57));
215
216        assert!(poly.set_coeff(4, &value).is_err());
217        assert_eq!(
218            PolyOverZq::from_str(&format!("4  0 1 2 3 mod {}", u64::MAX - 58)).unwrap(),
219            poly
220        )
221    }
222
223    /// Ensure that an ok is returned if the moduli not match
224    #[test]
225    fn matching_moduli() {
226        let mut poly = PolyOverZq::from_str(&format!("4  0 1 2 3 mod {}", u64::MAX - 58)).unwrap();
227        let value = Zq::from((u64::MAX, u64::MAX - 58));
228
229        assert!(poly.set_coeff(4, &value).is_ok());
230        assert_eq!(
231            PolyOverZq::from_str(&format!("5  0 1 2 3 58 mod {}", u64::MAX - 58)).unwrap(),
232            poly
233        )
234    }
235}
236
237#[cfg(test)]
238mod test_change_modulus {
239    use super::PolyOverZq;
240    use crate::integer_mod_q::Modulus;
241    use std::str::FromStr;
242
243    /// Ensures that the modulus is changed correctly.
244    #[test]
245    fn modulus_correct() {
246        let mut poly = PolyOverZq::from_str("6  1 2 3 4 5 6 mod 7").unwrap();
247        let modulus = Modulus::from(8);
248
249        poly.change_modulus(&modulus);
250
251        assert_eq!("6  1 2 3 4 5 6 mod 8", poly.to_string());
252    }
253
254    /// Ensures that the modulus is changed correctly, if the modulus is big.
255    #[test]
256    fn big_modulus_correct() {
257        let mut poly = PolyOverZq::from_str(&format!("6  1 2 3 4 5 6 mod {}", i64::MAX)).unwrap();
258        let modulus = Modulus::from(u64::MAX);
259
260        poly.change_modulus(&modulus);
261
262        assert_eq!(format!("6  1 2 3 4 5 6 mod {}", u64::MAX), poly.to_string());
263    }
264
265    /// Ensures that the poly is reduced correctly.
266    #[test]
267    fn reduced_correct() {
268        let mut poly = PolyOverZq::from_str("6  1 2 3 4 5 6 mod 7").unwrap();
269        let modulus = Modulus::from(2);
270
271        poly.change_modulus(&modulus);
272
273        assert_eq!("5  1 0 1 0 1 mod 2", poly.to_string());
274    }
275}