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}