Skip to main content

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