qfall_math/integer_mod_q/poly_over_zq/arithmetic/
add.rs1use super::super::PolyOverZq;
12use crate::{
13 error::MathError,
14 integer::PolyOverZ,
15 macros::arithmetics::{
16 arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
17 arithmetic_trait_mixed_borrowed_owned, arithmetic_trait_reverse,
18 },
19 traits::CompareBase,
20};
21use flint_sys::fmpz_mod_poly::fmpz_mod_poly_add;
22use std::{
23 ops::{Add, AddAssign},
24 str::FromStr,
25};
26
27impl AddAssign<&PolyOverZq> for PolyOverZq {
28 fn add_assign(&mut self, other: &Self) {
56 if !self.compare_base(other) {
57 panic!("{}", self.call_compare_base_error(other).unwrap());
58 }
59
60 unsafe {
61 fmpz_mod_poly_add(
62 &mut self.poly,
63 &self.poly,
64 &other.poly,
65 self.modulus.get_fmpz_mod_ctx_struct(),
66 )
67 };
68 }
69}
70impl AddAssign<&PolyOverZ> for PolyOverZq {
71 fn add_assign(&mut self, other: &PolyOverZ) {
73 let other = PolyOverZq::from((other, self.get_mod()));
74
75 self.add_assign(&other);
76 }
77}
78
79arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, PolyOverZq, PolyOverZq);
80arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, PolyOverZq, PolyOverZ);
81
82impl Add for &PolyOverZq {
83 type Output = PolyOverZq;
84 fn add(self, other: Self) -> Self::Output {
109 self.add_safe(other).unwrap()
110 }
111}
112
113arithmetic_trait_borrowed_to_owned!(Add, add, PolyOverZq, PolyOverZq, PolyOverZq);
114arithmetic_trait_mixed_borrowed_owned!(Add, add, PolyOverZq, PolyOverZq, PolyOverZq);
115
116impl Add<&PolyOverZ> for &PolyOverZq {
117 type Output = PolyOverZq;
118 fn add(self, other: &PolyOverZ) -> Self::Output {
138 let mut out = PolyOverZq::from(&self.modulus);
139 unsafe {
140 fmpz_mod_poly_add(
141 &mut out.poly,
142 &self.poly,
143 &PolyOverZq::from((other, &self.modulus)).poly,
144 self.modulus.get_fmpz_mod_ctx_struct(),
145 );
146 }
147 out
148 }
149}
150
151arithmetic_trait_reverse!(Add, add, PolyOverZ, PolyOverZq, PolyOverZq);
152
153arithmetic_trait_borrowed_to_owned!(Add, add, PolyOverZq, PolyOverZ, PolyOverZq);
154arithmetic_trait_borrowed_to_owned!(Add, add, PolyOverZ, PolyOverZq, PolyOverZq);
155arithmetic_trait_mixed_borrowed_owned!(Add, add, PolyOverZq, PolyOverZ, PolyOverZq);
156arithmetic_trait_mixed_borrowed_owned!(Add, add, PolyOverZ, PolyOverZq, PolyOverZq);
157
158impl PolyOverZq {
159 pub fn add_safe(&self, other: &Self) -> Result<PolyOverZq, MathError> {
181 if !self.compare_base(other) {
182 return Err(self.call_compare_base_error(other).unwrap());
183 }
184 let mut out = PolyOverZq::from_str(&format!("0 mod {}", self.modulus)).unwrap();
185 unsafe {
186 fmpz_mod_poly_add(
187 &mut out.poly,
188 &self.poly,
189 &other.poly,
190 self.modulus.get_fmpz_mod_ctx_struct(),
191 );
192 }
193 Ok(out)
194 }
195}
196
197#[cfg(test)]
198mod test_add_assign {
199 use super::PolyOverZq;
200 use crate::integer::PolyOverZ;
201 use std::str::FromStr;
202
203 #[test]
205 fn correct_small() {
206 let mut a = PolyOverZq::from_str("3 6 2 -3 mod 7").unwrap();
207 let b = PolyOverZq::from_str("5 1 2 5 1 2 mod 7").unwrap();
208 let cmp = PolyOverZq::from_str("5 0 4 2 1 2 mod 7").unwrap();
209
210 a += b;
211
212 assert_eq!(cmp, a);
213 }
214
215 #[test]
217 fn correct_large() {
218 let mut a = PolyOverZq::from_str(&format!(
219 "3 {} {} {} mod {}",
220 u32::MAX,
221 i32::MIN,
222 i32::MAX,
223 u64::MAX
224 ))
225 .unwrap();
226 let b = PolyOverZq::from_str(&format!("2 {} {} mod {}", u32::MAX, i32::MAX, u64::MAX))
227 .unwrap();
228 let cmp = PolyOverZq::from_str(&format!(
229 "3 {} -1 {} mod {}",
230 u64::from(u32::MAX) * 2,
231 i32::MAX,
232 u64::MAX
233 ))
234 .unwrap();
235
236 a += b;
237
238 assert_eq!(cmp, a);
239 }
240
241 #[test]
243 fn availability() {
244 let mut a = PolyOverZq::from_str("3 1 2 -3 mod 5").unwrap();
245 let b = PolyOverZq::from_str("3 -1 -2 3 mod 5").unwrap();
246 let c = PolyOverZ::from_str("2 -2 2").unwrap();
247
248 a += &b;
249 a += b;
250 a += &c;
251 a += c;
252 }
253
254 #[test]
256 #[should_panic]
257 fn mismatching_moduli() {
258 let mut a: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 7").unwrap();
259 let b: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 8").unwrap();
260
261 a += b;
262 }
263}
264
265#[cfg(test)]
266mod test_add {
267 use super::PolyOverZq;
268 use std::str::FromStr;
269
270 #[test]
272 fn add() {
273 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 1 mod 7").unwrap();
274 let b: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 7").unwrap();
275 let c: PolyOverZq = a + b;
276 assert_eq!(c, PolyOverZq::from_str("3 4 1 2 mod 7").unwrap());
277 }
278
279 #[test]
281 fn add_borrow() {
282 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 1 mod 7").unwrap();
283 let b: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 7").unwrap();
284 let c: PolyOverZq = &a + &b;
285 assert_eq!(c, PolyOverZq::from_str("3 4 1 2 mod 7").unwrap());
286 }
287
288 #[test]
290 fn add_first_borrowed() {
291 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 1 mod 7").unwrap();
292 let b: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 7").unwrap();
293 let c: PolyOverZq = &a + b;
294 assert_eq!(c, PolyOverZq::from_str("3 4 1 2 mod 7").unwrap());
295 }
296
297 #[test]
299 fn add_second_borrowed() {
300 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 1 mod 7").unwrap();
301 let b: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 7").unwrap();
302 let c: PolyOverZq = a + &b;
303 assert_eq!(c, PolyOverZq::from_str("3 4 1 2 mod 7").unwrap());
304 }
305
306 #[test]
308 fn add_reduce() {
309 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 1 mod 7").unwrap();
310 let b: PolyOverZq = PolyOverZq::from_str("3 -5 4 6 mod 7").unwrap();
311 let c: PolyOverZq = a + b;
312 assert_eq!(c, PolyOverZq::from_str("2 4 1 mod 7").unwrap());
313 }
314
315 #[test]
317 fn add_large_numbers() {
318 let a: PolyOverZq = PolyOverZq::from_str(&format!(
319 "3 -{} 4 {} mod {}",
320 u64::MAX,
321 i64::MIN,
322 u64::MAX - 58
323 ))
324 .unwrap();
325 let b: PolyOverZq = PolyOverZq::from_str(&format!(
326 "3 {} 4 {} mod {}",
327 i64::MIN,
328 i64::MIN,
329 u64::MAX - 58
330 ))
331 .unwrap();
332 let c: PolyOverZq = a + b;
333 assert!(
334 c == PolyOverZq::from_str(&format!(
335 "3 -{} 8 {} mod {}",
336 i128::from(i64::MAX) + 59,
337 -59,
338 u64::MAX - 58
339 ))
340 .unwrap()
341 );
342 }
343
344 #[test]
346 #[should_panic]
347 fn add_mismatching_modulus() {
348 let a: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 7").unwrap();
349 let b: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 8").unwrap();
350 let _c: PolyOverZq = a + b;
351 }
352
353 #[test]
355 fn add_safe_is_err() {
356 let a: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 7").unwrap();
357 let b: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 11").unwrap();
358 assert!(&a.add_safe(&b).is_err());
359 }
360}
361
362#[cfg(test)]
363mod test_mul_poly_over_z {
364 use super::PolyOverZq;
365 use crate::integer::PolyOverZ;
366 use std::str::FromStr;
367
368 #[test]
370 fn borrowed_correctness() {
371 let poly_1 = PolyOverZq::from_str(&format!("1 {} mod {}", i64::MAX, u64::MAX)).unwrap();
372 let poly_2 = PolyOverZ::from_str("2 1 2").unwrap();
373 let poly_cmp =
374 PolyOverZq::from_str(&format!("2 {} 2 mod {}", i64::MAX as u64 + 1, u64::MAX))
375 .unwrap();
376
377 let poly_1 = &poly_1 + &poly_2;
378
379 assert_eq!(poly_cmp, poly_1);
380 }
381
382 #[test]
384 fn availability() {
385 let poly = PolyOverZq::from_str("3 1 2 3 mod 17").unwrap();
386 let z = PolyOverZ::from(2);
387
388 _ = poly.clone() + z.clone();
389 _ = z.clone() + poly.clone();
390 _ = &poly + &z;
391 _ = &z + &poly;
392 _ = &poly + z.clone();
393 _ = z.clone() + &poly;
394 _ = &z + poly.clone();
395 _ = poly.clone() + &z;
396 }
397}