Skip to main content

malachite_base/unsigned_polynomial/arithmetic/
mod_neg.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::num::arithmetic::traits::{ModIsReduced, ModNeg, ModNegAssign};
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::unsigned_polynomial::UnsignedPolynomial;
12
13fn assert_reduced<T: PrimitiveUnsigned>(p: &UnsignedPolynomial<T>, m: T) {
14    assert!(
15        p.mod_is_reduced(&m),
16        "self must be reduced mod m, but {p} has a coefficient >= {m}"
17    );
18}
19
20// Negates every coefficient modulo m. The coefficients are reduced, so a nonzero one stays nonzero
21// and nothing needs trimming.
22fn negate<T: PrimitiveUnsigned>(coefficients: &mut [T], m: T) {
23    for c in coefficients {
24        if *c != T::ZERO {
25            *c = m - *c;
26        }
27    }
28}
29
30impl<T: PrimitiveUnsigned> ModNeg<T> for UnsignedPolynomial<T> {
31    type Output = Self;
32
33    /// Negates an [`UnsignedPolynomial`] modulo `m`, taking the polynomial by value. The
34    /// coefficients must already be reduced modulo `m`.
35    ///
36    /// Each nonzero coefficient $c$ becomes $m - c$, which is also nonzero, so the degree is
37    /// unchanged. The zero polynomial is its own negation.
38    ///
39    /// $$
40    /// f(p, m) = -p \bmod m.
41    /// $$
42    ///
43    /// # Worst-case complexity
44    /// $T(n) = O(n)$
45    ///
46    /// $M(n) = O(1)$
47    ///
48    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.len()`.
49    ///
50    /// # Panics
51    /// Panics if `m` is 0, or if any coefficient of `self` is greater than or equal to `m`.
52    ///
53    /// # Examples
54    /// ```
55    /// use core::str::FromStr;
56    /// use malachite_base::num::arithmetic::traits::ModNeg;
57    /// use malachite_base::num::basic::traits::Zero;
58    /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
59    ///
60    /// let p = UnsignedPolynomial::<u8>::from_str("5*x^2+x+3").unwrap();
61    /// assert_eq!(p.clone().mod_neg(7).to_string(), "2*x^2+6*x+4");
62    /// assert_eq!(
63    ///     UnsignedPolynomial::<u8>::ZERO.mod_neg(7),
64    ///     UnsignedPolynomial::<u8>::ZERO
65    /// );
66    /// ```
67    ///
68    /// This is equivalent to `nmod_poly_neg` from `nmod_poly/neg.c`, FLINT 3.6.0.
69    #[inline]
70    fn mod_neg(mut self, m: T) -> Self {
71        self.mod_neg_assign(m);
72        self
73    }
74}
75
76impl<T: PrimitiveUnsigned> ModNeg<T> for &UnsignedPolynomial<T> {
77    type Output = UnsignedPolynomial<T>;
78
79    /// Negates an [`UnsignedPolynomial`] modulo `m`, taking the polynomial by reference. The
80    /// coefficients must already be reduced modulo `m`.
81    ///
82    /// Each nonzero coefficient $c$ becomes $m - c$, which is also nonzero, so the degree is
83    /// unchanged. The zero polynomial is its own negation.
84    ///
85    /// $$
86    /// f(p, m) = -p \bmod m.
87    /// $$
88    ///
89    /// # Worst-case complexity
90    /// $T(n) = O(n)$
91    ///
92    /// $M(n) = O(n)$
93    ///
94    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.len()`.
95    ///
96    /// # Panics
97    /// Panics if `m` is 0, or if any coefficient of `self` is greater than or equal to `m`.
98    ///
99    /// # Examples
100    /// ```
101    /// use core::str::FromStr;
102    /// use malachite_base::num::arithmetic::traits::ModNeg;
103    /// use malachite_base::num::basic::traits::Zero;
104    /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
105    ///
106    /// let p = UnsignedPolynomial::<u8>::from_str("5*x^2+x+3").unwrap();
107    /// assert_eq!((&p).mod_neg(7).to_string(), "2*x^2+6*x+4");
108    /// assert_eq!(
109    ///     (&UnsignedPolynomial::<u8>::ZERO).mod_neg(7),
110    ///     UnsignedPolynomial::<u8>::ZERO
111    /// );
112    /// ```
113    ///
114    /// This is equivalent to `nmod_poly_neg` from `nmod_poly/neg.c`, FLINT 3.6.0.
115    fn mod_neg(self, m: T) -> UnsignedPolynomial<T> {
116        assert_reduced(self, m);
117        let mut coefficients = self.coefficients.clone();
118        negate(&mut coefficients, m);
119        UnsignedPolynomial { coefficients }
120    }
121}
122
123impl<T: PrimitiveUnsigned> ModNegAssign<T> for UnsignedPolynomial<T> {
124    /// Negates an [`UnsignedPolynomial`] modulo `m`, in place. The coefficients must already be
125    /// reduced modulo `m`.
126    ///
127    /// See [`mod_neg`](ModNeg::mod_neg).
128    ///
129    /// # Worst-case complexity
130    /// $T(n) = O(n)$
131    ///
132    /// $M(n) = O(1)$
133    ///
134    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.len()`.
135    ///
136    /// # Panics
137    /// Panics if `m` is 0, or if any coefficient of `self` is greater than or equal to `m`.
138    ///
139    /// # Examples
140    /// ```
141    /// use core::str::FromStr;
142    /// use malachite_base::num::arithmetic::traits::ModNegAssign;
143    /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
144    ///
145    /// let mut p = UnsignedPolynomial::<u8>::from_str("5*x^2+x+3").unwrap();
146    /// p.mod_neg_assign(7);
147    /// assert_eq!(p.to_string(), "2*x^2+6*x+4");
148    /// ```
149    fn mod_neg_assign(&mut self, m: T) {
150        assert_reduced(self, m);
151        negate(&mut self.coefficients, m);
152    }
153}