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