qfall_math/integer_mod_q/poly_over_zq/arithmetic/
sub.rs1use super::super::PolyOverZq;
12use crate::{
13 error::MathError,
14 integer::PolyOverZ,
15 integer_mod_q::PolynomialRingZq,
16 macros::arithmetics::{
17 arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
18 arithmetic_trait_mixed_borrowed_owned,
19 },
20 traits::CompareBase,
21};
22use flint_sys::{fmpz_mod_poly::fmpz_mod_poly_sub, fq::fq_sub};
23use std::{
24 ops::{Sub, SubAssign},
25 str::FromStr,
26};
27
28impl SubAssign<&PolyOverZq> for PolyOverZq {
29 fn sub_assign(&mut self, other: &Self) {
57 if !self.compare_base(other) {
58 panic!("{}", self.call_compare_base_error(other).unwrap());
59 }
60
61 unsafe {
62 fmpz_mod_poly_sub(
63 &mut self.poly,
64 &self.poly,
65 &other.poly,
66 self.modulus.get_fmpz_mod_ctx_struct(),
67 )
68 };
69 }
70}
71impl SubAssign<&PolyOverZ> for PolyOverZq {
72 fn sub_assign(&mut self, other: &PolyOverZ) {
74 let other = PolyOverZq::from((other, self.get_mod()));
75
76 self.sub_assign(&other);
77 }
78}
79
80arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, PolyOverZq, PolyOverZq);
81arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, PolyOverZq, PolyOverZ);
82
83impl Sub for &PolyOverZq {
84 type Output = PolyOverZq;
85 fn sub(self, other: Self) -> Self::Output {
110 self.sub_safe(other).unwrap()
111 }
112}
113
114arithmetic_trait_borrowed_to_owned!(Sub, sub, PolyOverZq, PolyOverZq, PolyOverZq);
115arithmetic_trait_mixed_borrowed_owned!(Sub, sub, PolyOverZq, PolyOverZq, PolyOverZq);
116
117impl Sub<&PolyOverZ> for &PolyOverZq {
118 type Output = PolyOverZq;
119 fn sub(self, other: &PolyOverZ) -> Self::Output {
139 let mut out = PolyOverZq::from(&self.modulus);
140 unsafe {
141 fmpz_mod_poly_sub(
142 &mut out.poly,
143 &self.poly,
144 &PolyOverZq::from((other, &self.modulus)).poly,
145 self.modulus.get_fmpz_mod_ctx_struct(),
146 );
147 }
148 out
149 }
150}
151
152arithmetic_trait_borrowed_to_owned!(Sub, sub, PolyOverZq, PolyOverZ, PolyOverZq);
153arithmetic_trait_mixed_borrowed_owned!(Sub, sub, PolyOverZq, PolyOverZ, PolyOverZq);
154
155impl Sub<&PolynomialRingZq> for &PolyOverZq {
156 type Output = PolynomialRingZq;
157 fn sub(self, other: &PolynomialRingZq) -> Self::Output {
183 assert_eq!(
184 self.modulus,
185 other.modulus.get_q(),
186 "Tried to subtract polynomials with different moduli."
187 );
188
189 let mut out = PolynomialRingZq::from((&PolyOverZ::default(), &other.modulus));
190 unsafe {
191 fq_sub(
192 &mut out.poly.poly,
193 &self.get_representative_least_nonnegative_residue().poly,
194 &other.poly.poly,
195 other.modulus.get_fq_ctx(),
196 );
197 }
198 out
199 }
200}
201
202arithmetic_trait_borrowed_to_owned!(Sub, sub, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
203arithmetic_trait_mixed_borrowed_owned!(Sub, sub, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
204
205impl PolyOverZq {
206 pub fn sub_safe(&self, other: &Self) -> Result<PolyOverZq, MathError> {
228 if !self.compare_base(other) {
229 return Err(self.call_compare_base_error(other).unwrap());
230 }
231 let mut out = PolyOverZq::from_str(&format!("0 mod {}", self.modulus)).unwrap();
232 unsafe {
233 fmpz_mod_poly_sub(
234 &mut out.poly,
235 &self.poly,
236 &other.poly,
237 self.modulus.get_fmpz_mod_ctx_struct(),
238 );
239 }
240 Ok(out)
241 }
242}
243
244#[cfg(test)]
245mod test_sub_assign {
246 use super::PolyOverZq;
247 use crate::integer::PolyOverZ;
248 use std::str::FromStr;
249
250 #[test]
252 fn correct_small() {
253 let mut a = PolyOverZq::from_str("3 6 2 -3 mod 7").unwrap();
254 let b = PolyOverZq::from_str("5 -1 -2 -5 -1 -2 mod 7").unwrap();
255 let cmp = PolyOverZq::from_str("5 0 4 2 1 2 mod 7").unwrap();
256
257 a -= b;
258
259 assert_eq!(cmp, a);
260 }
261
262 #[test]
264 fn correct_large() {
265 let mut a = PolyOverZq::from_str(&format!(
266 "3 {} {} {} mod {}",
267 u32::MAX,
268 i32::MIN,
269 i32::MAX,
270 u64::MAX
271 ))
272 .unwrap();
273 let b = PolyOverZq::from_str(&format!("2 -{} -{} mod {}", u32::MAX, i32::MAX, u64::MAX))
274 .unwrap();
275 let cmp = PolyOverZq::from_str(&format!(
276 "3 {} -1 {} mod {}",
277 u64::from(u32::MAX) * 2,
278 i32::MAX,
279 u64::MAX
280 ))
281 .unwrap();
282
283 a -= b;
284
285 assert_eq!(cmp, a);
286 }
287
288 #[test]
290 fn availability() {
291 let mut a = PolyOverZq::from_str("3 1 2 -3 mod 5").unwrap();
292 let b = PolyOverZq::from_str("3 -1 -2 3 mod 5").unwrap();
293 let c = PolyOverZ::from_str("2 -2 2").unwrap();
294
295 a -= &b;
296 a -= b;
297 a -= &c;
298 a -= c;
299 }
300
301 #[test]
303 #[should_panic]
304 fn mismatching_moduli() {
305 let mut a: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 7").unwrap();
306 let b: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 8").unwrap();
307
308 a -= b;
309 }
310}
311
312#[cfg(test)]
313mod test_sub {
314 use super::PolyOverZq;
315 use std::str::FromStr;
316
317 #[test]
319 fn sub() {
320 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 6 mod 7").unwrap();
321 let b: PolyOverZq = PolyOverZq::from_str("3 -5 5 1 mod 7").unwrap();
322 let c: PolyOverZq = a - b;
323 assert_eq!(c, PolyOverZq::from_str("3 0 6 5 mod 7").unwrap());
324 }
325
326 #[test]
328 fn sub_borrow() {
329 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 6 mod 7").unwrap();
330 let b: PolyOverZq = PolyOverZq::from_str("3 -5 5 1 mod 7").unwrap();
331 let c: PolyOverZq = &a - &b;
332 assert_eq!(c, PolyOverZq::from_str("3 0 6 5 mod 7").unwrap());
333 }
334
335 #[test]
337 fn sub_first_borrowed() {
338 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 6 mod 7").unwrap();
339 let b: PolyOverZq = PolyOverZq::from_str("3 -5 5 1 mod 7").unwrap();
340 let c: PolyOverZq = a - b;
341 assert_eq!(c, PolyOverZq::from_str("3 0 6 5 mod 7").unwrap());
342 }
343
344 #[test]
346 fn sub_second_borrowed() {
347 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 6 mod 7").unwrap();
348 let b: PolyOverZq = PolyOverZq::from_str("3 -5 5 1 mod 7").unwrap();
349 let c: PolyOverZq = a - b;
350 assert_eq!(c, PolyOverZq::from_str("3 0 6 5 mod 7").unwrap());
351 }
352
353 #[test]
355 fn sub_reduce() {
356 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 1 mod 7").unwrap();
357 let b: PolyOverZq = PolyOverZq::from_str("3 -5 4 -6 mod 7").unwrap();
358 let c: PolyOverZq = a - b;
359 assert_eq!(c, PolyOverZq::from_str("0 mod 7").unwrap());
360 }
361
362 #[test]
364 fn sub_large_numbers() {
365 let a: PolyOverZq = PolyOverZq::from_str(&format!(
366 "3 -{} 4 {} mod {}",
367 u64::MAX,
368 i64::MIN,
369 u64::MAX - 58
370 ))
371 .unwrap();
372 let b: PolyOverZq = PolyOverZq::from_str(&format!(
373 "3 {} 5 {} mod {}",
374 i64::MIN,
375 i64::MIN,
376 u64::MAX - 58
377 ))
378 .unwrap();
379 let c: PolyOverZq = a - b;
380 assert_eq!(
381 c,
382 PolyOverZq::from_str(&format!(
383 "2 {} -1 mod {}",
384 i128::from(i64::MAX) - 57,
385 u64::MAX - 58
386 ))
387 .unwrap()
388 );
389 }
390
391 #[test]
393 #[should_panic]
394 fn sub_mismatching_modulus() {
395 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 6 mod 9").unwrap();
396 let b: PolyOverZq = PolyOverZq::from_str("3 -5 5 1 mod 7").unwrap();
397 let _c: PolyOverZq = a - b;
398 }
399
400 #[test]
402 fn sub_safe_is_err() {
403 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 6 mod 9").unwrap();
404 let b: PolyOverZq = PolyOverZq::from_str("3 -5 5 1 mod 7").unwrap();
405 assert!(&a.sub_safe(&b).is_err());
406 }
407}
408
409#[cfg(test)]
410mod test_mul_poly_over_z {
411 use super::PolyOverZq;
412 use crate::integer::PolyOverZ;
413 use std::str::FromStr;
414
415 #[test]
417 fn borrowed_correctness() {
418 let poly_1 = PolyOverZq::from_str(&format!("1 {} mod {}", i64::MAX, u64::MAX)).unwrap();
419 let poly_2 = PolyOverZ::from_str("2 1 2").unwrap();
420 let poly_cmp =
421 PolyOverZq::from_str(&format!("2 {} -2 mod {}", i64::MAX as u64 - 1, u64::MAX))
422 .unwrap();
423
424 let poly_1 = &poly_1 - &poly_2;
425
426 assert_eq!(poly_cmp, poly_1);
427 }
428
429 #[test]
431 fn availability() {
432 let poly = PolyOverZq::from_str("3 1 2 3 mod 17").unwrap();
433 let z = PolyOverZ::from(2);
434
435 _ = poly.clone() - z.clone();
436 _ = &poly - &z;
437 _ = &poly - z.clone();
438 _ = poly.clone() - &z;
439 }
440}
441
442#[cfg(test)]
443mod test_sub_poly_ring_zq {
444 use super::PolynomialRingZq;
445 use crate::integer_mod_q::PolyOverZq;
446 use std::str::FromStr;
447
448 #[test]
450 fn borrowed_correctness() {
451 let poly_1 =
452 PolynomialRingZq::from_str(&format!("2 2 {} / 4 1 2 3 4 mod {}", i64::MAX, u64::MAX))
453 .unwrap();
454 let poly_2 = PolynomialRingZq::from_str(&format!(
455 "2 -1 -{} / 4 1 2 3 4 mod {}",
456 i64::MAX as u64 - 2,
457 u64::MAX
458 ))
459 .unwrap();
460 let poly = PolyOverZq::from_str(&format!("2 1 2 mod {}", u64::MAX)).unwrap();
461
462 let poly_1 = &poly - &poly_1;
463
464 assert_eq!(poly_2, poly_1);
465 }
466
467 #[test]
469 fn availability() {
470 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 17").unwrap();
471 let zq = PolyOverZq::from((2, 17));
472
473 _ = zq.clone() - poly.clone();
474 _ = &zq - &poly;
475 _ = zq.clone() - &poly;
476 _ = &zq - poly.clone();
477 }
478
479 #[test]
481 #[should_panic]
482 fn different_moduli_panic() {
483 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 17").unwrap();
484 let zq = PolyOverZq::from((2, 16));
485
486 _ = &zq - &poly;
487 }
488}