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