Skip to main content

qfall_math/integer_mod_q/poly_over_zq/arithmetic/
neg.rs

1// Copyright 2026 Jan Niklas Siemer
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//! Implementation of the [`Neg`] trait for [`PolyOverZq`] values.
10
11use super::super::PolyOverZq;
12use flint3_sys::fmpz_mod_poly_neg;
13use std::ops::Neg;
14
15impl Neg for PolyOverZq {
16    type Output = PolyOverZq;
17
18    /// Implements the [`Neg`] trait for [`PolyOverZq`] values.
19    /// [`Neg`] is implemented for both borrowed and owned [`PolyOverZq`].
20    ///
21    /// When called on owned [`PolyOverZq`] it will reuse the memory of `self`.
22    ///
23    /// Returns the additive inverse of `self` as a [`PolyOverZq`].
24    ///
25    /// # Examples
26    /// ```
27    /// use qfall_math::integer_mod_q::PolyOverZq;
28    /// use std::str::FromStr;
29    ///
30    /// let a: PolyOverZq = PolyOverZq::from_str("3  1 2 42 mod 17").unwrap();
31    ///
32    /// let b: PolyOverZq = -&a;
33    /// let c: PolyOverZq = -a;
34    /// ```
35    fn neg(mut self) -> Self::Output {
36        unsafe {
37            fmpz_mod_poly_neg(
38                &mut self.poly,
39                &self.poly,
40                self.modulus.get_fmpz_mod_ctx_struct(),
41            )
42        };
43        self
44    }
45}
46
47impl Neg for &PolyOverZq {
48    type Output = PolyOverZq;
49
50    /// Documentation at [`PolyOverZq::neg`].
51    fn neg(self) -> Self::Output {
52        let mut out = PolyOverZq::from(&self.modulus);
53        unsafe {
54            fmpz_mod_poly_neg(
55                &mut out.poly,
56                &self.poly,
57                self.modulus.get_fmpz_mod_ctx_struct(),
58            )
59        };
60        out
61    }
62}
63
64#[cfg(test)]
65mod test_neg {
66    use super::PolyOverZq;
67    use crate::integer::PolyOverZ;
68    use std::str::FromStr;
69
70    /// Ensure that `neg` works for small coefficients.
71    #[test]
72    fn correct_small() {
73        let a = PolyOverZq::from_str("4  1 -2 0 3 mod 17").unwrap();
74        let b = PolyOverZq::from_str("4  -1 2 0 -3 mod 17").unwrap();
75        let c = PolyOverZq::from_str("0 mod 17").unwrap();
76
77        assert_eq!(a, -(-&a));
78        assert_eq!(a, -&b);
79        assert_eq!(b, -&a);
80        assert_eq!(a, -b.clone());
81        assert_eq!(b, -a);
82        assert_eq!(c, -&c);
83        assert_eq!(c.clone(), -c);
84    }
85
86    /// Ensure that `neg` works for large coefficients and moduli.
87    #[test]
88    fn correct_large() {
89        let a = PolyOverZq::from_str(&format!("3  {} 0 1 mod {}", i64::MAX, u64::MAX)).unwrap();
90        let b = PolyOverZq::from_str(&format!("3  -{} 0 -1 mod {}", i64::MAX, u64::MAX)).unwrap();
91
92        assert_eq!(a, -(-&a));
93        assert_eq!(b, -&a);
94        assert_eq!(b, -a);
95    }
96
97    /// Ensure that the result is reduced to the least non-negative residues
98    /// and that the modulus is kept.
99    #[test]
100    fn reduced() {
101        let a = PolyOverZq::from_str("4  1 16 0 8 mod 17").unwrap();
102        let cmp = PolyOverZ::from_str("4  16 1 0 9").unwrap();
103
104        let neg_a = -&a;
105
106        assert_eq!(cmp, neg_a.get_representative_least_nonnegative_residue());
107        assert_eq!(cmp, (-a).get_representative_least_nonnegative_residue());
108        assert_eq!(17, neg_a.get_mod());
109    }
110}