qfall_math/integer_mod_q/polynomial_ring_zq/
set.rs

1// Copyright © 2023 Marcel Luca Schmidt
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 [`PolynomialRingZq`] element.
10
11use super::PolynomialRingZq;
12use crate::{
13    integer::Z, integer_mod_q::Zq, macros::for_others::implement_for_owned, traits::SetCoefficient,
14};
15use flint_sys::fmpz_poly::fmpz_poly_set_coeff_fmpz;
16
17impl<Integer: Into<Z>> SetCoefficient<Integer> for PolynomialRingZq {
18    /// Sets the coefficient of a [`PolynomialRingZq`] element.
19    /// We advise to use small coefficients, since already 2^32 coefficients take space
20    /// of roughly 34 GB. If not careful, be prepared that memory problems can occur, if
21    /// the index is very high.
22    ///
23    /// Parameters:
24    /// - `index`: the index of the coefficient to set (has to be positive)
25    /// - `value`: the new value the index should have
26    ///
27    /// # Examples
28    /// ```
29    /// use crate::qfall_math::traits::SetCoefficient;
30    /// use qfall_math::integer::PolyOverZ;
31    /// use qfall_math::integer_mod_q::{PolynomialRingZq, ModulusPolynomialRingZq};
32    /// use std::str::FromStr;
33    ///
34    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
35    /// let poly = PolyOverZ::from_str("3  0 1 1").unwrap();
36    /// let mut poly_ring = PolynomialRingZq::from((&poly, &modulus));
37    ///
38    /// poly_ring.set_coeff(2, 16).unwrap();
39    /// unsafe{ poly_ring.set_coeff_unchecked(5, 5) };
40    /// ```
41    ///
42    /// # Safety
43    /// To use this function safely, make sure that the selected index
44    /// is greater or equal than `0` and that the provided value has
45    /// the same base so that they have a matching base.
46    unsafe fn set_coeff_unchecked(&mut self, index: i64, value: Integer) {
47        let value = value.into();
48
49        unsafe {
50            fmpz_poly_set_coeff_fmpz(&mut self.poly.poly, index, &value.value);
51        };
52        self.reduce();
53    }
54}
55
56impl SetCoefficient<&Zq> for PolynomialRingZq {
57    /// Sets the coefficient of a [`PolynomialRingZq`] element.
58    /// We advise to use small coefficients, since already 2^32 coefficients take space
59    /// of roughly 34 GB. If not careful, be prepared that memory problems can occur, if
60    /// the index is very high.
61    ///
62    /// This function does not check if the modulus of the polynomial and the value match.
63    ///
64    /// Parameters:
65    /// - `index`: the index of the coefficient to set (has to be positive)
66    /// - `value`: the new value the index should have
67    ///
68    /// # Examples
69    /// ```
70    /// use crate::qfall_math::traits::SetCoefficient;
71    /// use qfall_math::integer::PolyOverZ;
72    /// use qfall_math::integer_mod_q::{PolynomialRingZq, ModulusPolynomialRingZq};
73    /// use qfall_math::integer_mod_q::Zq;
74    /// use std::str::FromStr;    
75    ///
76    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
77    /// let poly = PolyOverZ::from_str("3  0 1 1").unwrap();
78    /// let mut poly_ring = PolynomialRingZq::from((&poly, &modulus));
79    /// let value = Zq::from((1000, 17));
80    ///
81    /// poly_ring.set_coeff(2, &value).unwrap();
82    /// unsafe{ poly_ring.set_coeff_unchecked(5, &value) };
83    /// ```
84    ///
85    /// # Safety
86    /// To use this function safely, make sure that the selected index
87    /// is greater or equal than `0` and that the provided value has
88    /// the same base so that they have a matching base.
89    unsafe fn set_coeff_unchecked(&mut self, index: i64, value: &Zq) {
90        unsafe { self.set_coeff_unchecked(index, &value.value) };
91    }
92}
93
94implement_for_owned!(Zq, PolynomialRingZq, SetCoefficient);
95
96#[cfg(test)]
97mod test_set_coeff {
98    use crate::{
99        integer::{PolyOverZ, Z},
100        integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq, Zq},
101        traits::SetCoefficient,
102    };
103    use std::str::FromStr;
104
105    /// Ensure that setting is available for other types.
106    #[test]
107    fn availability() {
108        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
109        let poly = PolyOverZ::from_str("3  0 1 1").unwrap();
110        let mut poly_ring = PolynomialRingZq::from((&poly, &modulus));
111
112        poly_ring.set_coeff(1, 3u64).unwrap();
113        poly_ring.set_coeff(1, 3u32).unwrap();
114        poly_ring.set_coeff(1, 3u16).unwrap();
115        poly_ring.set_coeff(1, 3u8).unwrap();
116        poly_ring.set_coeff(1, 3i64).unwrap();
117        poly_ring.set_coeff(1, 3i32).unwrap();
118        poly_ring.set_coeff(1, 3i16).unwrap();
119        poly_ring.set_coeff(1, 3i8).unwrap();
120        poly_ring.set_coeff(1, Z::from(3)).unwrap();
121        poly_ring.set_coeff(1, &Z::from(3)).unwrap();
122        poly_ring.set_coeff(1, &Zq::from((3, 17))).unwrap();
123    }
124
125    /// Ensure that large coefficients work.
126    #[test]
127    fn set_coeff_large() {
128        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
129        let poly = PolyOverZ::from_str("3  0 1 1").unwrap();
130        let mut poly_ring = PolynomialRingZq::from((&poly, &modulus));
131
132        assert!(poly_ring.set_coeff(2, i32::MAX).is_ok());
133        assert!(poly_ring.set_coeff(2, i64::MAX).is_ok());
134    }
135
136    /// Ensure that the max of [`u8`] and [`u16`] works as an index.
137    #[test]
138    fn set_index_large() {
139        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
140        let poly = PolyOverZ::from_str("3  0 1 1").unwrap();
141        let mut poly_ring = PolynomialRingZq::from((&poly, &modulus));
142
143        assert!(poly_ring.set_coeff(u8::MAX, 2).is_ok());
144        assert!(poly_ring.set_coeff(u16::MAX, 2).is_ok());
145    }
146
147    /// Ensure that a general case is working.
148    #[test]
149    fn set_coeff_working() {
150        let modulus = ModulusPolynomialRingZq::from_str("5  1 0 0 1 5 mod 17").unwrap();
151        let poly = PolyOverZ::from_str("3  0 2 1").unwrap();
152        let mut poly_ring = PolynomialRingZq::from((&poly, &modulus));
153        let value = 10000;
154
155        poly_ring.set_coeff(0, value).unwrap();
156        poly_ring.set_coeff(2, value).unwrap();
157
158        let cmp_poly = PolyOverZ::from_str("3  10000 2 10000").unwrap();
159        let cmp_poly_ring = PolynomialRingZq::from((&cmp_poly, &modulus));
160        assert_eq!(cmp_poly_ring, poly_ring);
161    }
162
163    /// Ensure that the set polynomial is reduced correctly.
164    #[test]
165    fn set_reduce() {
166        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
167        let poly = PolyOverZ::from(1);
168        let mut poly_ring = PolynomialRingZq::from((&poly, &modulus));
169
170        poly_ring.set_coeff(3, 1).unwrap();
171
172        let cmp_poly = PolyOverZ::from(0);
173        let cmp_poly_ring = PolynomialRingZq::from((&cmp_poly, &modulus));
174        assert_eq!(cmp_poly_ring, poly_ring);
175    }
176
177    /// Ensure that the correct coefficient is set and all others are set to `0`.
178    #[test]
179    fn set_coeff_rest_zero() {
180        let modulus = ModulusPolynomialRingZq::from_str("7  1 8 0 0 1 0 12 mod 17").unwrap();
181        let poly = PolyOverZ::from_str("2  0 2").unwrap();
182        let mut poly_ring = PolynomialRingZq::from((&poly, &modulus));
183
184        poly_ring.set_coeff(5, 10).unwrap();
185
186        let cmp_poly = PolyOverZ::from_str("6  0 2 0 0 0 10").unwrap();
187        let cmp_poly_ring = PolynomialRingZq::from((&cmp_poly, &modulus));
188        assert_eq!(cmp_poly_ring, poly_ring);
189    }
190
191    /// Ensure that the negative indices return an error.
192    #[test]
193    fn set_negative_index() {
194        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
195        let poly = PolyOverZ::from_str("3  0 1 1").unwrap();
196        let mut poly_ring = PolynomialRingZq::from((&poly, &modulus));
197
198        assert!(poly_ring.set_coeff(-1, 2).is_err());
199        assert!(poly_ring.set_coeff(i64::MIN, 2).is_err());
200        assert!(poly_ring.set_coeff(i32::MIN, 2).is_err());
201        assert!(poly_ring.set_coeff(i16::MIN, 2).is_err());
202        assert!(poly_ring.set_coeff(i8::MIN, 2).is_err());
203    }
204
205    /// Ensure that a different base returns an error.
206    #[test]
207    fn different_base() {
208        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
209        let poly = PolyOverZ::from_str("3  0 1 1").unwrap();
210        let mut poly_ring = PolynomialRingZq::from((&poly, &modulus));
211        let value = Zq::from((13, 18));
212
213        assert!(poly_ring.set_coeff(1, &value).is_err());
214    }
215}