malachite_base/unsigned_polynomial/arithmetic/mod_power_of_2_sub.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::{ModPowerOf2IsReduced, ModPowerOf2Sub, ModPowerOf2SubAssign};
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::unsigned_polynomial::UnsignedPolynomial;
12use alloc::vec::Vec;
13use core::cmp::min;
14
15fn assert_reduced<T: PrimitiveUnsigned>(
16 p: &UnsignedPolynomial<T>,
17 q: &UnsignedPolynomial<T>,
18 pow: u64,
19) {
20 assert!(pow <= T::WIDTH);
21 assert!(
22 p.mod_power_of_2_is_reduced(pow),
23 "self must be reduced mod 2^pow, but {p} has a coefficient >= 2^{pow}"
24 );
25 assert!(
26 q.mod_power_of_2_is_reduced(pow),
27 "other must be reduced mod 2^pow, but {q} has a coefficient >= 2^{pow}"
28 );
29}
30
31// Subtracts `ys` from `xs` modulo 2^pow, negating the coefficients of `ys` past the end of `xs`. A
32// nonzero reduced coefficient stays nonzero when negated. The caller trims, since leading
33// coefficients can cancel.
34pub(crate) fn sub_assign_ref<T: PrimitiveUnsigned>(xs: &mut Vec<T>, ys: &[T], pow: u64) {
35 let common = min(xs.len(), ys.len());
36 for (x, &y) in xs.iter_mut().zip(&ys[..common]) {
37 *x = x.wrapping_sub(y).mod_power_of_2(pow);
38 }
39 if ys.len() > common {
40 xs.extend(
41 ys[common..]
42 .iter()
43 .map(|y| y.wrapping_neg().mod_power_of_2(pow)),
44 );
45 }
46}
47
48// Replaces `ys` with `xs - ys` modulo 2^pow, reusing the storage of `ys`. The caller trims.
49pub(crate) fn rsub_assign_ref<T: PrimitiveUnsigned>(ys: &mut Vec<T>, xs: &[T], pow: u64) {
50 let common = min(xs.len(), ys.len());
51 for (y, &x) in ys.iter_mut().zip(&xs[..common]) {
52 *y = x.wrapping_sub(*y).mod_power_of_2(pow);
53 }
54 for y in &mut ys[common..] {
55 *y = y.wrapping_neg().mod_power_of_2(pow);
56 }
57 if xs.len() > common {
58 ys.extend_from_slice(&xs[common..]);
59 }
60}
61
62// Subtracts `ys` from `xs` modulo 2^pow, reusing whichever of the two is longer. The caller trims.
63pub(crate) fn sub_assign_val<T: PrimitiveUnsigned>(xs: &mut Vec<T>, mut ys: Vec<T>, pow: u64) {
64 if ys.len() > xs.len() {
65 rsub_assign_ref(&mut ys, xs, pow);
66 *xs = ys;
67 } else {
68 sub_assign_ref(xs, &ys, pow);
69 }
70}
71
72impl<T: PrimitiveUnsigned> ModPowerOf2Sub<Self> for UnsignedPolynomial<T> {
73 type Output = Self;
74
75 /// Subtracts one [`UnsignedPolynomial`] from another modulo $2^k$, taking both by value. The
76 /// coefficients of both must already be reduced modulo $2^k$.
77 ///
78 /// $$
79 /// f(p, q, k) = p - q \bmod 2^k.
80 /// $$
81 ///
82 /// Coefficients past the end of the shorter polynomial are taken to be zero. Where the second
83 /// polynomial is longer, its coefficients are negated modulo $2^k$. When the two polynomials
84 /// have the same degree, their leading coefficients can cancel modulo $2^k$, and then the
85 /// degree of the difference is lower.
86 ///
87 /// # Worst-case complexity
88 /// $T(n) = O(n)$
89 ///
90 /// $M(n) = O(1)$
91 ///
92 /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
93 /// longer polynomial times `pow`.
94 ///
95 /// # Panics
96 /// Panics if `pow` is greater than `T::WIDTH`, or if any coefficient of `self` or `other` is
97 /// greater than or equal to $2^k$.
98 ///
99 /// # Examples
100 /// ```
101 /// use core::str::FromStr;
102 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Sub;
103 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
104 ///
105 /// assert_eq!(
106 /// UnsignedPolynomial::<u8>::from_str("5*x^2+x+3")
107 /// .unwrap()
108 /// .mod_power_of_2_sub(
109 /// UnsignedPolynomial::<u8>::from_str("3*x^2+7*x+1").unwrap(),
110 /// 3
111 /// )
112 /// .to_string(),
113 /// "2*x^2+2*x+2"
114 /// );
115 /// // The leading coefficients cancel.
116 /// assert_eq!(
117 /// UnsignedPolynomial::<u8>::from_str("5*x^2+x")
118 /// .unwrap()
119 /// .mod_power_of_2_sub(UnsignedPolynomial::<u8>::from_str("5*x^2+3").unwrap(), 3)
120 /// .to_string(),
121 /// "x+5"
122 /// );
123 /// ```
124 ///
125 /// This is equivalent to `nmod_poly_sub` from `nmod_poly/sub.c`, FLINT 3.6.0, with the modulus
126 /// $2^k$.
127 fn mod_power_of_2_sub(mut self, other: Self, pow: u64) -> Self {
128 assert_reduced(&self, &other, pow);
129 sub_assign_val(&mut self.coefficients, other.coefficients, pow);
130 self.trim();
131 self
132 }
133}
134
135impl<T: PrimitiveUnsigned> ModPowerOf2Sub<&Self> for UnsignedPolynomial<T> {
136 type Output = Self;
137
138 /// Subtracts one [`UnsignedPolynomial`] from another modulo $2^k$, taking the first by value
139 /// and the second by reference. The coefficients of both must already be reduced modulo $2^k$.
140 ///
141 /// $$
142 /// f(p, q, k) = p - q \bmod 2^k.
143 /// $$
144 ///
145 /// Coefficients past the end of the shorter polynomial are taken to be zero. Where the second
146 /// polynomial is longer, its coefficients are negated modulo $2^k$. When the two polynomials
147 /// have the same degree, their leading coefficients can cancel modulo $2^k$, and then the
148 /// degree of the difference is lower.
149 ///
150 /// # Worst-case complexity
151 /// $T(n) = O(n)$
152 ///
153 /// $M(n) = O(n)$
154 ///
155 /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
156 /// longer polynomial times `pow`.
157 ///
158 /// # Panics
159 /// Panics if `pow` is greater than `T::WIDTH`, or if any coefficient of `self` or `other` is
160 /// greater than or equal to $2^k$.
161 ///
162 /// # Examples
163 /// ```
164 /// use core::str::FromStr;
165 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Sub;
166 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
167 ///
168 /// assert_eq!(
169 /// UnsignedPolynomial::<u8>::from_str("5*x^2+x+3")
170 /// .unwrap()
171 /// .mod_power_of_2_sub(
172 /// &UnsignedPolynomial::<u8>::from_str("3*x^2+7*x+1").unwrap(),
173 /// 3
174 /// )
175 /// .to_string(),
176 /// "2*x^2+2*x+2"
177 /// );
178 /// // The leading coefficients cancel.
179 /// assert_eq!(
180 /// UnsignedPolynomial::<u8>::from_str("5*x^2+x")
181 /// .unwrap()
182 /// .mod_power_of_2_sub(&UnsignedPolynomial::<u8>::from_str("5*x^2+3").unwrap(), 3)
183 /// .to_string(),
184 /// "x+5"
185 /// );
186 /// ```
187 ///
188 /// This is equivalent to `nmod_poly_sub` from `nmod_poly/sub.c`, FLINT 3.6.0, with the modulus
189 /// $2^k$.
190 fn mod_power_of_2_sub(mut self, other: &Self, pow: u64) -> Self {
191 assert_reduced(&self, other, pow);
192 sub_assign_ref(&mut self.coefficients, &other.coefficients, pow);
193 self.trim();
194 self
195 }
196}
197
198impl<T: PrimitiveUnsigned> ModPowerOf2Sub<UnsignedPolynomial<T>> for &UnsignedPolynomial<T> {
199 type Output = UnsignedPolynomial<T>;
200
201 /// Subtracts one [`UnsignedPolynomial`] from another modulo $2^k$, taking the first by
202 /// reference and the second by value. The coefficients of both must already be reduced modulo
203 /// $2^k$.
204 ///
205 /// $$
206 /// f(p, q, k) = p - q \bmod 2^k.
207 /// $$
208 ///
209 /// Coefficients past the end of the shorter polynomial are taken to be zero. Where the second
210 /// polynomial is longer, its coefficients are negated modulo $2^k$. When the two polynomials
211 /// have the same degree, their leading coefficients can cancel modulo $2^k$, and then the
212 /// degree of the difference is lower.
213 ///
214 /// # Worst-case complexity
215 /// $T(n) = O(n)$
216 ///
217 /// $M(n) = O(n)$
218 ///
219 /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
220 /// longer polynomial times `pow`.
221 ///
222 /// # Panics
223 /// Panics if `pow` is greater than `T::WIDTH`, or if any coefficient of `self` or `other` is
224 /// greater than or equal to $2^k$.
225 ///
226 /// # Examples
227 /// ```
228 /// use core::str::FromStr;
229 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Sub;
230 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
231 ///
232 /// assert_eq!(
233 /// (&UnsignedPolynomial::<u8>::from_str("5*x^2+x+3").unwrap())
234 /// .mod_power_of_2_sub(
235 /// UnsignedPolynomial::<u8>::from_str("3*x^2+7*x+1").unwrap(),
236 /// 3
237 /// )
238 /// .to_string(),
239 /// "2*x^2+2*x+2"
240 /// );
241 /// // The leading coefficients cancel.
242 /// assert_eq!(
243 /// (&UnsignedPolynomial::<u8>::from_str("5*x^2+x").unwrap())
244 /// .mod_power_of_2_sub(UnsignedPolynomial::<u8>::from_str("5*x^2+3").unwrap(), 3)
245 /// .to_string(),
246 /// "x+5"
247 /// );
248 /// ```
249 ///
250 /// This is equivalent to `nmod_poly_sub` from `nmod_poly/sub.c`, FLINT 3.6.0, with the modulus
251 /// $2^k$.
252 fn mod_power_of_2_sub(
253 self,
254 mut other: UnsignedPolynomial<T>,
255 pow: u64,
256 ) -> UnsignedPolynomial<T> {
257 assert_reduced(self, &other, pow);
258 rsub_assign_ref(&mut other.coefficients, &self.coefficients, pow);
259 other.trim();
260 other
261 }
262}
263
264impl<T: PrimitiveUnsigned> ModPowerOf2Sub<&UnsignedPolynomial<T>> for &UnsignedPolynomial<T> {
265 type Output = UnsignedPolynomial<T>;
266
267 /// Subtracts one [`UnsignedPolynomial`] from another modulo $2^k$, taking both by reference.
268 /// The coefficients of both must already be reduced modulo $2^k$.
269 ///
270 /// $$
271 /// f(p, q, k) = p - q \bmod 2^k.
272 /// $$
273 ///
274 /// Coefficients past the end of the shorter polynomial are taken to be zero. Where the second
275 /// polynomial is longer, its coefficients are negated modulo $2^k$. When the two polynomials
276 /// have the same degree, their leading coefficients can cancel modulo $2^k$, and then the
277 /// degree of the difference is lower.
278 ///
279 /// # Worst-case complexity
280 /// $T(n) = O(n)$
281 ///
282 /// $M(n) = O(n)$
283 ///
284 /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
285 /// longer polynomial times `pow`.
286 ///
287 /// # Panics
288 /// Panics if `pow` is greater than `T::WIDTH`, or if any coefficient of `self` or `other` is
289 /// greater than or equal to $2^k$.
290 ///
291 /// # Examples
292 /// ```
293 /// use core::str::FromStr;
294 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Sub;
295 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
296 ///
297 /// assert_eq!(
298 /// (&UnsignedPolynomial::<u8>::from_str("5*x^2+x+3").unwrap())
299 /// .mod_power_of_2_sub(
300 /// &UnsignedPolynomial::<u8>::from_str("3*x^2+7*x+1").unwrap(),
301 /// 3
302 /// )
303 /// .to_string(),
304 /// "2*x^2+2*x+2"
305 /// );
306 /// // The leading coefficients cancel.
307 /// assert_eq!(
308 /// (&UnsignedPolynomial::<u8>::from_str("5*x^2+x").unwrap())
309 /// .mod_power_of_2_sub(&UnsignedPolynomial::<u8>::from_str("5*x^2+3").unwrap(), 3)
310 /// .to_string(),
311 /// "x+5"
312 /// );
313 /// ```
314 ///
315 /// This is equivalent to `nmod_poly_sub` from `nmod_poly/sub.c`, FLINT 3.6.0, with the modulus
316 /// $2^k$.
317 fn mod_power_of_2_sub(self, other: &UnsignedPolynomial<T>, pow: u64) -> UnsignedPolynomial<T> {
318 assert_reduced(self, other, pow);
319 let mut coefficients = self.coefficients.clone();
320 sub_assign_ref(&mut coefficients, &other.coefficients, pow);
321 let mut result = UnsignedPolynomial { coefficients };
322 result.trim();
323 result
324 }
325}
326
327impl<T: PrimitiveUnsigned> ModPowerOf2SubAssign<Self> for UnsignedPolynomial<T> {
328 /// Subtracts a [`UnsignedPolynomial`] from a [`UnsignedPolynomial`] modulo $2^k$, in place,
329 /// taking the second by value. The coefficients of both must already be reduced modulo $2^k$.
330 ///
331 /// $$
332 /// p \gets p - q \bmod 2^k.
333 /// $$
334 ///
335 /// Coefficients past the end of the shorter polynomial are taken to be zero. Where the second
336 /// polynomial is longer, its coefficients are negated modulo $2^k$. When the two polynomials
337 /// have the same degree, their leading coefficients can cancel modulo $2^k$, and then the
338 /// degree of the difference is lower.
339 ///
340 /// # Worst-case complexity
341 /// $T(n) = O(n)$
342 ///
343 /// $M(n) = O(1)$
344 ///
345 /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
346 /// longer polynomial times `pow`.
347 ///
348 /// # Panics
349 /// Panics if `pow` is greater than `T::WIDTH`, or if any coefficient of `self` or `other` is
350 /// greater than or equal to $2^k$.
351 ///
352 /// # Examples
353 /// ```
354 /// use core::str::FromStr;
355 /// use malachite_base::num::arithmetic::traits::ModPowerOf2SubAssign;
356 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
357 ///
358 /// let mut p = UnsignedPolynomial::<u8>::from_str("5*x^2+x+3").unwrap();
359 /// p.mod_power_of_2_sub_assign(
360 /// UnsignedPolynomial::<u8>::from_str("3*x^2+7*x+1").unwrap(),
361 /// 3,
362 /// );
363 /// assert_eq!(p.to_string(), "2*x^2+2*x+2");
364 ///
365 /// // The leading coefficients cancel.
366 /// let mut p = UnsignedPolynomial::<u8>::from_str("5*x^2+x").unwrap();
367 /// p.mod_power_of_2_sub_assign(UnsignedPolynomial::<u8>::from_str("5*x^2+3").unwrap(), 3);
368 /// assert_eq!(p.to_string(), "x+5");
369 /// ```
370 ///
371 /// This is equivalent to `nmod_poly_sub` from `nmod_poly/sub.c`, FLINT 3.6.0, with the modulus
372 /// $2^k$.
373 fn mod_power_of_2_sub_assign(&mut self, other: Self, pow: u64) {
374 assert_reduced(self, &other, pow);
375 sub_assign_val(&mut self.coefficients, other.coefficients, pow);
376 self.trim();
377 }
378}
379
380impl<T: PrimitiveUnsigned> ModPowerOf2SubAssign<&Self> for UnsignedPolynomial<T> {
381 /// Subtracts a [`UnsignedPolynomial`] from a [`UnsignedPolynomial`] modulo $2^k$, in place,
382 /// taking the second by reference. The coefficients of both must already be reduced modulo
383 /// $2^k$.
384 ///
385 /// $$
386 /// p \gets p - q \bmod 2^k.
387 /// $$
388 ///
389 /// Coefficients past the end of the shorter polynomial are taken to be zero. Where the second
390 /// polynomial is longer, its coefficients are negated modulo $2^k$. When the two polynomials
391 /// have the same degree, their leading coefficients can cancel modulo $2^k$, and then the
392 /// degree of the difference is lower.
393 ///
394 /// # Worst-case complexity
395 /// $T(n) = O(n)$
396 ///
397 /// $M(n) = O(n)$
398 ///
399 /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
400 /// longer polynomial times `pow`.
401 ///
402 /// # Panics
403 /// Panics if `pow` is greater than `T::WIDTH`, or if any coefficient of `self` or `other` is
404 /// greater than or equal to $2^k$.
405 ///
406 /// # Examples
407 /// ```
408 /// use core::str::FromStr;
409 /// use malachite_base::num::arithmetic::traits::ModPowerOf2SubAssign;
410 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
411 ///
412 /// let mut p = UnsignedPolynomial::<u8>::from_str("5*x^2+x+3").unwrap();
413 /// p.mod_power_of_2_sub_assign(
414 /// &UnsignedPolynomial::<u8>::from_str("3*x^2+7*x+1").unwrap(),
415 /// 3,
416 /// );
417 /// assert_eq!(p.to_string(), "2*x^2+2*x+2");
418 ///
419 /// // The leading coefficients cancel.
420 /// let mut p = UnsignedPolynomial::<u8>::from_str("5*x^2+x").unwrap();
421 /// p.mod_power_of_2_sub_assign(&UnsignedPolynomial::<u8>::from_str("5*x^2+3").unwrap(), 3);
422 /// assert_eq!(p.to_string(), "x+5");
423 /// ```
424 ///
425 /// This is equivalent to `nmod_poly_sub` from `nmod_poly/sub.c`, FLINT 3.6.0, with the modulus
426 /// $2^k$.
427 fn mod_power_of_2_sub_assign(&mut self, other: &Self, pow: u64) {
428 assert_reduced(self, other, pow);
429 sub_assign_ref(&mut self.coefficients, &other.coefficients, pow);
430 self.trim();
431 }
432}