malachite_nz/integer_polynomial/mod.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::integer::Integer;
10use crate::integer_polynomial::conversion::string::from_string::from_string_with;
11use crate::integer_polynomial::conversion::string::to_string::Language;
12use alloc::string::String;
13use alloc::vec;
14use alloc::vec::Vec;
15use core::ops::Deref;
16use malachite_base::named::Named;
17use malachite_base::num::basic::traits::{NegativeOne, One, Two, Zero};
18use malachite_base::num::conversion::traits::ExactFrom;
19use malachite_base::polynomial::Polynomial;
20use malachite_base::vars::{Var, VarScheme};
21
22/// Traits for arithmetic on [`IntegerPolynomial`]s.
23pub mod arithmetic;
24/// Implementations of [`Ord`] and [`PartialOrd`] for [`IntegerPolynomial`], comparing two
25/// polynomials by their behavior for large arguments.
26pub mod comparison;
27/// Functions for converting an [`IntegerPolynomial`] to and from other types.
28pub mod conversion;
29/// Iterators that generate [`IntegerPolynomial`]s without repetition.
30pub mod exhaustive;
31#[cfg(feature = "random")]
32/// Iterators that generate [`IntegerPolynomial`]s randomly.
33pub mod random;
34
35// The zero `Integer`, as something a reference can be handed out to.
36//
37// A `Integer` owns a `Vec` when it is large, so it has a destructor, and a `&Integer::ZERO` written
38// where a reference is returned would point at a temporary that does not outlive the call. A
39// `static` is the same zero with a lifetime long enough to hand out.
40pub(crate) static ZERO: Integer = Integer::ZERO;
41
42/// A polynomial in one variable whose coefficients are [`Integer`]s.
43///
44/// The coefficients are held in ascending order, so that the coefficient of $x^i$ is the one at
45/// index $i$, and the last is the leading one. Trailing zero coefficients are not held at all: the
46/// zero polynomial has no coefficients, and every other polynomial's last coefficient is nonzero.
47/// That is what makes a polynomial's representation unique, and so what lets [`Eq`] be derived.
48///
49/// The field is private, since not every [`Vec`] of [`Integer`]s is one:
50/// [`from_coefficients_asc`](IntegerPolynomial::from_coefficients_asc) is how a [`Vec`] becomes
51/// one.
52#[derive(Clone, Default, Eq, Hash, PartialEq)]
53#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
54#[cfg_attr(
55 feature = "serde",
56 serde(try_from = "SerdeIntegerPolynomial", into = "SerdeIntegerPolynomial")
57)]
58pub struct IntegerPolynomial {
59 coefficients: Vec<Integer>,
60}
61
62// As for a `NaturalPolynomial`: the coefficients are the polynomial, so the encoding is the list of
63// them and nothing around it, and a list whose last coefficient is zero is rejected.
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65#[cfg_attr(feature = "serde", serde(transparent))]
66pub(crate) struct SerdeIntegerPolynomial(pub(crate) Vec<Integer>);
67
68/// The constant 0.
69impl Zero for IntegerPolynomial {
70 const ZERO: Self = Self {
71 coefficients: Vec::new(),
72 };
73}
74
75impl IntegerPolynomial {
76 // Returns true iff `self` is valid.
77 //
78 // To be valid, its last coefficient, if it has one at all, must be nonzero. All
79 // `IntegerPolynomial`s must be valid.
80 #[cfg(feature = "test_build")]
81 pub fn is_valid(&self) -> bool {
82 self.coefficients.last() != Some(&Integer::ZERO)
83 }
84
85 // Drops the trailing zero coefficients, which is what makes a `Vec` of coefficients the one
86 // representation of its polynomial.
87 fn trim(&mut self) {
88 while self.coefficients.last() == Some(&Integer::ZERO) {
89 self.coefficients.pop();
90 }
91 }
92
93 /// The constant polynomial -1.
94 ///
95 /// This is a function rather than an associated constant, for the reason given by
96 /// [`one`](Self::one).
97 ///
98 /// # Worst-case complexity
99 /// Constant time and additional memory.
100 ///
101 /// # Examples
102 /// ```
103 /// use malachite_base::polynomial::Polynomial;
104 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
105 ///
106 /// assert_eq!(IntegerPolynomial::negative_one().to_string(), "-1");
107 /// assert_eq!(IntegerPolynomial::negative_one().degree(), Some(0));
108 /// ```
109 pub fn negative_one() -> Self {
110 Self {
111 coefficients: vec![Integer::NEGATIVE_ONE],
112 }
113 }
114
115 /// Returns a reference to an [`IntegerPolynomial`]'s coefficients, in ascending order.
116 ///
117 /// The first is the constant term and the last is the leading coefficient, so the slice is what
118 /// [`from_coefficients_asc`](Self::from_coefficients_asc) would take back. It holds no trailing
119 /// zeros, and for the zero polynomial it is empty.
120 ///
121 /// # Worst-case complexity
122 /// Constant time and additional memory.
123 ///
124 /// # Examples
125 /// ```
126 /// use core::str::FromStr;
127 /// use malachite_base::num::basic::traits::Zero;
128 /// use malachite_base::strings::ToDebugString;
129 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
130 ///
131 /// let p = IntegerPolynomial::from_str("x^2+3*x+2").unwrap();
132 /// assert_eq!(p.coefficients_asc().to_debug_string(), "[2, 3, 1]");
133 /// assert_eq!(
134 /// IntegerPolynomial::ZERO.coefficients_asc().to_debug_string(),
135 /// "[]"
136 /// );
137 /// ```
138 #[inline]
139 pub fn coefficients_asc(&self) -> &[Integer] {
140 &self.coefficients
141 }
142}
143
144impl Polynomial for IntegerPolynomial {
145 type Coefficient = Integer;
146 type CoefficientOutput<'a>
147 = &'a Integer
148 where
149 Self: 'a;
150
151 /// The constant polynomial 1.
152 ///
153 /// This is a function rather than an associated constant, and [`One`] is not implemented,
154 /// because a polynomial holds its coefficients in a [`Vec`] and a [`Vec`] with anything in it
155 /// cannot be built at compile time. The zero polynomial has no coefficients, so
156 /// [`ZERO`](malachite_base::num::basic::traits::Zero::ZERO) is a constant after all.
157 ///
158 /// # Worst-case complexity
159 /// Constant time and additional memory.
160 ///
161 /// # Examples
162 /// ```
163 /// use malachite_base::polynomial::Polynomial;
164 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
165 ///
166 /// assert_eq!(IntegerPolynomial::one().to_string(), "1");
167 /// assert_eq!(IntegerPolynomial::one().degree(), Some(0));
168 /// ```
169 fn one() -> Self {
170 Self {
171 coefficients: vec![Integer::ONE],
172 }
173 }
174
175 /// The constant polynomial 2.
176 ///
177 /// This is a function rather than an associated constant, for the reason given by
178 /// [`one`](Self::one).
179 ///
180 /// # Worst-case complexity
181 /// Constant time and additional memory.
182 ///
183 /// # Examples
184 /// ```
185 /// use malachite_base::polynomial::Polynomial;
186 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
187 ///
188 /// assert_eq!(IntegerPolynomial::two().to_string(), "2");
189 /// assert_eq!(IntegerPolynomial::two().degree(), Some(0));
190 /// ```
191 fn two() -> Self {
192 Self {
193 coefficients: vec![Integer::TWO],
194 }
195 }
196
197 /// The polynomial $x$, of degree 1 with leading coefficient 1 and constant term 0.
198 ///
199 /// This is a function rather than an associated constant, for the reason given by
200 /// [`one`](Self::one).
201 ///
202 /// # Worst-case complexity
203 /// Constant time and additional memory.
204 ///
205 /// # Examples
206 /// ```
207 /// use malachite_base::polynomial::Polynomial;
208 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
209 ///
210 /// assert_eq!(IntegerPolynomial::x().to_string(), "x");
211 /// assert_eq!(IntegerPolynomial::x().degree(), Some(1));
212 /// ```
213 fn x() -> Self {
214 Self {
215 coefficients: vec![Integer::ZERO, Integer::ONE],
216 }
217 }
218
219 /// Converts a [`Vec`] of [`Integer`]s to an [`IntegerPolynomial`].
220 ///
221 /// The coefficients are in ascending order, so that the first is the constant term. Trailing
222 /// zeros are dropped, since a polynomial does not hold them; the [`Vec`] may therefore end with
223 /// as many as it likes, and the empty [`Vec`] is the zero polynomial.
224 ///
225 /// # Worst-case complexity
226 /// $T(n) = O(n)$
227 ///
228 /// $M(n) = O(1)$
229 ///
230 /// where $T$ is time, $M$ is additional memory, and $n$ is `coefficients.len()`.
231 ///
232 /// # Examples
233 /// ```
234 /// use malachite_base::num::basic::traits::{One, Two, Zero};
235 /// use malachite_base::polynomial::Polynomial;
236 /// use malachite_nz::integer::Integer;
237 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
238 ///
239 /// let p = IntegerPolynomial::from_coefficients_asc(vec![
240 /// Integer::TWO,
241 /// Integer::from(3u32),
242 /// Integer::ONE,
243 /// ]);
244 /// assert_eq!(p.to_string(), "x^2+3*x+2");
245 ///
246 /// // The trailing zeros are not part of the polynomial.
247 /// let q = IntegerPolynomial::from_coefficients_asc(vec![
248 /// Integer::TWO,
249 /// Integer::from(3u32),
250 /// Integer::ONE,
251 /// Integer::ZERO,
252 /// Integer::ZERO,
253 /// ]);
254 /// assert_eq!(q.to_string(), "x^2+3*x+2");
255 ///
256 /// assert_eq!(
257 /// IntegerPolynomial::from_coefficients_asc(vec![]).to_string(),
258 /// "0"
259 /// );
260 /// ```
261 fn from_coefficients_asc(coefficients: Vec<Integer>) -> Self {
262 let mut p = Self { coefficients };
263 p.trim();
264 p
265 }
266
267 /// Converts an [`IntegerPolynomial`] to a [`Vec`] of [`Integer`]s, in ascending order.
268 ///
269 /// The first is the constant term and the last is the leading coefficient, so the [`Vec`] is
270 /// what [`from_coefficients_asc`](Self::from_coefficients_asc) would take back. It holds no
271 /// trailing zeros, and for the zero polynomial it is empty.
272 ///
273 /// # Worst-case complexity
274 /// Constant time and additional memory.
275 ///
276 /// # Examples
277 /// ```
278 /// use core::str::FromStr;
279 /// use malachite_base::num::basic::traits::Zero;
280 /// use malachite_base::polynomial::Polynomial;
281 /// use malachite_base::strings::ToDebugString;
282 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
283 ///
284 /// let p = IntegerPolynomial::from_str("x^2+3*x+2").unwrap();
285 /// assert_eq!(p.into_coefficients_asc().to_debug_string(), "[2, 3, 1]");
286 /// assert_eq!(
287 /// IntegerPolynomial::ZERO
288 /// .into_coefficients_asc()
289 /// .to_debug_string(),
290 /// "[]"
291 /// );
292 /// ```
293 #[inline]
294 fn into_coefficients_asc(self) -> Vec<Integer> {
295 self.coefficients
296 }
297
298 /// Returns the degree of an [`IntegerPolynomial`].
299 ///
300 /// The zero polynomial has no degree, and gives `None`. Every other polynomial's degree is the
301 /// index of its leading coefficient, so that a nonzero constant has degree 0.
302 ///
303 /// # Worst-case complexity
304 /// Constant time and additional memory.
305 ///
306 /// # Examples
307 /// ```
308 /// use core::str::FromStr;
309 /// use malachite_base::num::basic::traits::Zero;
310 /// use malachite_base::polynomial::Polynomial;
311 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
312 ///
313 /// assert_eq!(IntegerPolynomial::ZERO.degree(), None);
314 /// assert_eq!(IntegerPolynomial::from_str("5").unwrap().degree(), Some(0));
315 /// assert_eq!(IntegerPolynomial::from_str("x").unwrap().degree(), Some(1));
316 /// assert_eq!(
317 /// IntegerPolynomial::from_str("x^2+3*x+2").unwrap().degree(),
318 /// Some(2)
319 /// );
320 /// ```
321 #[inline]
322 fn degree(&self) -> Option<u64> {
323 self.coefficients.len().checked_sub(1).map(u64::exact_from)
324 }
325
326 /// Returns the length of a [`IntegerPolynomial`]: the number of coefficients it holds.
327 ///
328 /// A polynomial holds no trailing zeros, so its length is one more than its
329 /// [`degree`](Self::degree), and the zero polynomial, which has no degree, has length 0.
330 ///
331 /// # Worst-case complexity
332 /// Constant time and additional memory.
333 ///
334 /// # Examples
335 /// ```
336 /// use core::str::FromStr;
337 /// use malachite_base::num::basic::traits::Zero;
338 /// use malachite_base::polynomial::Polynomial;
339 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
340 ///
341 /// assert_eq!(IntegerPolynomial::ZERO.len(), 0);
342 /// assert_eq!(IntegerPolynomial::from_str("-5").unwrap().len(), 1);
343 /// assert_eq!(IntegerPolynomial::from_str("x").unwrap().len(), 2);
344 /// assert_eq!(IntegerPolynomial::from_str("x^2-3*x+2").unwrap().len(), 3);
345 /// ```
346 ///
347 /// This is equivalent to `fmpz_poly_length` from `fmpz_poly.h`, FLINT 3.6.0.
348 #[inline]
349 fn len(&self) -> u64 {
350 u64::exact_from(self.coefficients.len())
351 }
352
353 /// Returns a reference to one of an [`IntegerPolynomial`]'s coefficients.
354 ///
355 /// The index is the power of the variable the coefficient belongs to, so that index 0 gives the
356 /// constant term. An index past the degree gives zero, which is the coefficient a polynomial
357 /// has there.
358 ///
359 /// # Worst-case complexity
360 /// Constant time and additional memory.
361 ///
362 /// # Examples
363 /// ```
364 /// use core::str::FromStr;
365 /// use malachite_base::polynomial::Polynomial;
366 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
367 ///
368 /// let p = IntegerPolynomial::from_str("x^2+3*x+2").unwrap();
369 /// assert_eq!(*p.coefficient(0), 2);
370 /// assert_eq!(*p.coefficient(1), 3);
371 /// assert_eq!(*p.coefficient(2), 1);
372 /// assert_eq!(*p.coefficient(100), 0);
373 /// ```
374 #[inline]
375 fn coefficient(&self, index: u64) -> &Integer {
376 usize::try_from(index)
377 .ok()
378 .and_then(|i| self.coefficients.get(i))
379 .unwrap_or(&ZERO)
380 }
381
382 /// Returns a reference to an [`IntegerPolynomial`]'s leading coefficient.
383 ///
384 /// This is the coefficient of the highest power of the variable that the polynomial has one
385 /// for. The zero polynomial has no such power, and gives zero, which is what every one of its
386 /// coefficients is.
387 ///
388 /// # Worst-case complexity
389 /// Constant time and additional memory.
390 ///
391 /// # Examples
392 /// ```
393 /// use core::str::FromStr;
394 /// use malachite_base::num::basic::traits::Zero;
395 /// use malachite_base::polynomial::Polynomial;
396 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
397 ///
398 /// let p = IntegerPolynomial::from_str("7*x^2+3*x+2").unwrap();
399 /// assert_eq!(*p.leading_coefficient(), 7);
400 /// assert_eq!(*IntegerPolynomial::ZERO.leading_coefficient(), 0);
401 /// ```
402 #[inline]
403 fn leading_coefficient(&self) -> &Integer {
404 self.coefficients.last().unwrap_or(&ZERO)
405 }
406
407 /// Determines whether an [`IntegerPolynomial`] is monic: nonzero, with leading coefficient 1.
408 ///
409 /// The zero polynomial is not monic.
410 ///
411 /// # Worst-case complexity
412 /// Constant time and additional memory.
413 ///
414 /// # Examples
415 /// ```
416 /// use core::str::FromStr;
417 /// use malachite_base::num::basic::traits::Zero;
418 /// use malachite_base::polynomial::Polynomial;
419 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
420 ///
421 /// assert!(IntegerPolynomial::from_str("x^2-3*x+2").unwrap().is_monic());
422 /// assert!(!IntegerPolynomial::from_str("-x^2+3").unwrap().is_monic());
423 /// assert!(!IntegerPolynomial::ZERO.is_monic());
424 /// ```
425 #[inline]
426 fn is_monic(&self) -> bool {
427 self.coefficients.last().is_some_and(|c| *c == 1u32)
428 }
429
430 /// Mutates one of an [`IntegerPolynomial`]'s coefficients using a provided closure, and then
431 /// returns whatever the closure returns.
432 ///
433 /// The index is the power of the variable the coefficient belongs to. An index past the degree
434 /// is not an error: the polynomial grows to reach it, and the closure is handed the zero that
435 /// was there all along.
436 ///
437 /// After the closure executes, this function drops whatever trailing zero coefficients the
438 /// polynomial has acquired, so that a coefficient set to zero, or a growth that came to
439 /// nothing, leaves no trace.
440 ///
441 /// # Worst-case complexity
442 /// $T(n, m) = O(n + m)$
443 ///
444 /// $M(n, m) = O(n + m)$
445 ///
446 /// where $T$ is time, $M$ is additional memory, $n$ is `index`, and $m$ is the cost of the
447 /// closure.
448 ///
449 /// # Panics
450 /// Panics if `index` does not fit in a [`usize`], which cannot happen on a target with 64-bit
451 /// pointers, or if growing to reach `index` would exceed the maximum length of a [`Vec`].
452 ///
453 /// # Examples
454 /// ```
455 /// use core::str::FromStr;
456 /// use malachite_base::num::basic::traits::{One, Zero};
457 /// use malachite_base::polynomial::Polynomial;
458 /// use malachite_nz::integer::Integer;
459 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
460 ///
461 /// let mut p = IntegerPolynomial::from_str("x^2+3*x+2").unwrap();
462 ///
463 /// let ret = p.mutate_coefficient(1, |c| {
464 /// *c += Integer::ONE;
465 /// true
466 /// });
467 /// assert_eq!(p.to_string(), "x^2+4*x+2");
468 /// assert_eq!(ret, true);
469 ///
470 /// // The polynomial grows to reach a coefficient it did not have.
471 /// p.mutate_coefficient(5, |c| *c += Integer::ONE);
472 /// assert_eq!(p.to_string(), "x^5+x^2+4*x+2");
473 ///
474 /// // Clearing the leading coefficient lowers the degree.
475 /// p.mutate_coefficient(5, |c| *c = Integer::ZERO);
476 /// assert_eq!(p.to_string(), "x^2+4*x+2");
477 /// ```
478 fn mutate_coefficient<F: FnOnce(&mut Integer) -> T, T>(&mut self, index: u64, f: F) -> T {
479 let index = usize::exact_from(index);
480 if index >= self.coefficients.len() {
481 self.coefficients.resize(index + 1, Integer::ZERO);
482 }
483 let out = f(&mut self.coefficients[index]);
484 self.trim();
485 out
486 }
487
488 /// Sets the coefficients of a [`IntegerPolynomial`] of $x^i$ for $i$ in `start..end` to zero.
489 ///
490 /// Indices past the degree are allowed; the coefficients there are zero already. Zeroing the
491 /// leading coefficient lowers the degree, to that of the highest nonzero coefficient that
492 /// remains.
493 ///
494 /// # Worst-case complexity
495 /// $T(n) = O(n)$
496 ///
497 /// $M(n) = O(1)$
498 ///
499 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.len()`.
500 ///
501 /// # Panics
502 /// Panics if `start > end`.
503 ///
504 /// # Examples
505 /// ```
506 /// use core::str::FromStr;
507 /// use malachite_base::polynomial::Polynomial;
508 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
509 ///
510 /// let mut p;
511 /// p = IntegerPolynomial::from_str("5*x^4-4*x^3+3*x^2-2*x+1").unwrap();
512 /// p.zero_coefficients(1, 3);
513 /// assert_eq!(p.to_string(), "5*x^4-4*x^3+1");
514 /// p = IntegerPolynomial::from_str("5*x^4-4*x^3+3*x^2-2*x+1").unwrap();
515 /// p.zero_coefficients(2, 10);
516 /// assert_eq!(p.to_string(), "-2*x+1");
517 /// p = IntegerPolynomial::from_str("5*x^4-4*x^3+3*x^2-2*x+1").unwrap();
518 /// p.zero_coefficients(5, 10);
519 /// assert_eq!(p.to_string(), "5*x^4-4*x^3+3*x^2-2*x+1");
520 /// ```
521 ///
522 /// This is equivalent to `fmpz_poly_zero_coeffs` from `fmpz_poly/zero_coeffs.c`, FLINT 3.6.0.
523 fn zero_coefficients(&mut self, start: u64, end: u64) {
524 assert!(start <= end);
525 let len = self.coefficients.len();
526 let Ok(start) = usize::try_from(start) else {
527 return;
528 };
529 if start >= len {
530 return;
531 }
532 let end = usize::try_from(end).map_or(len, |end| end.min(len));
533 if end == len {
534 // The range reaches the leading coefficient, so the zeros it leaves are trailing.
535 self.coefficients.truncate(start);
536 self.trim();
537 } else {
538 self.coefficients[start..end].fill(Integer::ZERO);
539 }
540 }
541
542 /// Truncates a [`IntegerPolynomial`] to its first `len` coefficients, taking the polynomial by
543 /// reference and returning the result.
544 ///
545 /// The result is the polynomial reduced modulo $x^{\mathrm{len}}$: every term of degree `len`
546 /// or more is dropped, and then any zeros left at the top go too, so the result may have fewer
547 /// than `len` coefficients. A polynomial with at most `len` coefficients is returned unchanged.
548 ///
549 /// $$
550 /// f(p, n) = p \bmod x^n.
551 /// $$
552 ///
553 /// # Worst-case complexity
554 /// $T(n) = O(n)$
555 ///
556 /// $M(n) = O(n)$
557 ///
558 /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
559 /// coefficients that are kept.
560 ///
561 /// # Examples
562 /// ```
563 /// use core::str::FromStr;
564 /// use malachite_base::polynomial::Polynomial;
565 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
566 ///
567 /// assert_eq!(
568 /// IntegerPolynomial::from_str("x^3-2*x^2+3*x-4")
569 /// .unwrap()
570 /// .truncate(2)
571 /// .to_string(),
572 /// "3*x-4"
573 /// );
574 /// // A polynomial with no more than len coefficients is unchanged.
575 /// assert_eq!(
576 /// IntegerPolynomial::from_str("x^3-2*x^2+3*x-4")
577 /// .unwrap()
578 /// .truncate(10)
579 /// .to_string(),
580 /// "x^3-2*x^2+3*x-4"
581 /// );
582 /// // Truncating can uncover zeros, which are dropped too.
583 /// assert_eq!(
584 /// IntegerPolynomial::from_str("x^3+3*x-4")
585 /// .unwrap()
586 /// .truncate(3)
587 /// .to_string(),
588 /// "3*x-4"
589 /// );
590 /// assert_eq!(
591 /// IntegerPolynomial::from_str("x^3-2*x^2+3*x-4")
592 /// .unwrap()
593 /// .truncate(0)
594 /// .to_string(),
595 /// "0"
596 /// );
597 /// ```
598 ///
599 /// This is equivalent to `fmpz_poly_set_trunc` from `fmpz_poly/set_trunc.c`, FLINT 3.6.0.
600 fn truncate(&self, len: u64) -> Self {
601 let kept = usize::try_from(len).map_or(self.coefficients.len(), |len| {
602 len.min(self.coefficients.len())
603 });
604 // Skip the zeros that truncating leaves at the top rather than copying them and trimming.
605 let kept = self.coefficients[..kept]
606 .iter()
607 .rposition(|c| *c != 0u32)
608 .map_or(0, |i| i + 1);
609 Self {
610 coefficients: self.coefficients[..kept].to_vec(),
611 }
612 }
613
614 /// Truncates a [`IntegerPolynomial`] to its first `len` coefficients, in place.
615 ///
616 /// See [`truncate`](Self::truncate) for what the result is.
617 ///
618 /// # Worst-case complexity
619 /// $T(n) = O(n)$
620 ///
621 /// $M(n) = O(1)$
622 ///
623 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.len()`.
624 ///
625 /// # Examples
626 /// ```
627 /// use core::str::FromStr;
628 /// use malachite_base::polynomial::Polynomial;
629 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
630 ///
631 /// let mut p;
632 /// p = IntegerPolynomial::from_str("x^3-2*x^2+3*x-4").unwrap();
633 /// p.truncate_assign(2);
634 /// assert_eq!(p.to_string(), "3*x-4");
635 /// // A polynomial with no more than len coefficients is unchanged.
636 /// p = IntegerPolynomial::from_str("x^3-2*x^2+3*x-4").unwrap();
637 /// p.truncate_assign(10);
638 /// assert_eq!(p.to_string(), "x^3-2*x^2+3*x-4");
639 /// // Truncating can uncover zeros, which are dropped too.
640 /// p = IntegerPolynomial::from_str("x^3+3*x-4").unwrap();
641 /// p.truncate_assign(3);
642 /// assert_eq!(p.to_string(), "3*x-4");
643 /// p = IntegerPolynomial::from_str("x^3-2*x^2+3*x-4").unwrap();
644 /// p.truncate_assign(0);
645 /// assert_eq!(p.to_string(), "0");
646 /// ```
647 ///
648 /// This is equivalent to `fmpz_poly_truncate` from `fmpz_poly/truncate.c`, FLINT 3.6.0.
649 fn truncate_assign(&mut self, len: u64) {
650 if let Ok(len) = usize::try_from(len)
651 && len < self.coefficients.len()
652 {
653 self.coefficients.truncate(len);
654 self.trim();
655 }
656 }
657
658 /// Reverses the coefficients of a [`IntegerPolynomial`], considered as having length `len`,
659 /// taking the polynomial by reference.
660 ///
661 /// The polynomial is first truncated, or padded with zeros, to exactly `len` coefficients, and
662 /// those are then reversed, so that the result's coefficient of $x^i$ is the polynomial's
663 /// coefficient of $x^{\mathrm{len} - 1 - i}$:
664 ///
665 /// $$
666 /// f(p, n) = x^{n-1} \left( p \bmod x^n \right)\!\left(\frac{1}{x}\right).
667 /// $$
668 ///
669 /// A polynomial holds no trailing zeros, so the result may have fewer than `len` coefficients:
670 /// it does whenever the polynomial's constant term is zero.
671 ///
672 /// # Worst-case complexity
673 /// $T(n, m) = O(n + m)$
674 ///
675 /// $M(n, m) = O(n + m)$
676 ///
677 /// where $T$ is time, $M$ is additional memory, $n$ is `len`, and $m$ is the total number of
678 /// bits of the coefficients.
679 ///
680 /// # Panics
681 /// Panics if `len` exceeds `self.len()` and does not fit in a [`usize`], which cannot happen on
682 /// a target with 64-bit pointers.
683 ///
684 /// # Examples
685 /// ```
686 /// use core::str::FromStr;
687 /// use malachite_base::polynomial::Polynomial;
688 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
689 ///
690 /// assert_eq!(
691 /// IntegerPolynomial::from_str("x^2-2*x+3")
692 /// .unwrap()
693 /// .reverse(3)
694 /// .to_string(),
695 /// "3*x^2-2*x+1"
696 /// );
697 /// // Padding to length 5 adds low zeros.
698 /// assert_eq!(
699 /// IntegerPolynomial::from_str("x^2-2*x+3")
700 /// .unwrap()
701 /// .reverse(5)
702 /// .to_string(),
703 /// "3*x^4-2*x^3+x^2"
704 /// );
705 /// // Truncating to length 2 drops x^2 first.
706 /// assert_eq!(
707 /// IntegerPolynomial::from_str("x^2-2*x+3")
708 /// .unwrap()
709 /// .reverse(2)
710 /// .to_string(),
711 /// "3*x-2"
712 /// );
713 /// // A zero constant term becomes a trailing zero, and is dropped.
714 /// assert_eq!(
715 /// IntegerPolynomial::from_str("x^2-2*x")
716 /// .unwrap()
717 /// .reverse(3)
718 /// .to_string(),
719 /// "-2*x+1"
720 /// );
721 /// ```
722 ///
723 /// This is equivalent to `fmpz_poly_reverse` from `fmpz_poly/reverse.c`, FLINT 3.6.0.
724 fn reverse(&self, len: u64) -> Self {
725 let kept = usize::try_from(len).map_or(self.coefficients.len(), |len| {
726 len.min(self.coefficients.len())
727 });
728 if kept == 0 {
729 return Self::ZERO;
730 }
731 // The coefficients past the kept ones become the result's low zeros.
732 let mut coefficients = vec![Integer::ZERO; usize::exact_from(len) - kept];
733 coefficients.extend(self.coefficients[..kept].iter().rev().cloned());
734 Self::from_coefficients_asc(coefficients)
735 }
736
737 /// Reverses the coefficients of a [`IntegerPolynomial`], considered as having length `len`, in
738 /// place.
739 ///
740 /// See [`reverse`](Self::reverse) for what the result is.
741 ///
742 /// # Worst-case complexity
743 /// $T(n) = O(n)$
744 ///
745 /// $M(n) = O(n)$
746 ///
747 /// where $T$ is time, $M$ is additional memory, and $n$ is the larger of `len` and
748 /// `self.len()`.
749 ///
750 /// # Panics
751 /// Panics if `len` exceeds `self.len()` and does not fit in a [`usize`], which cannot happen on
752 /// a target with 64-bit pointers.
753 ///
754 /// # Examples
755 /// ```
756 /// use core::str::FromStr;
757 /// use malachite_base::polynomial::Polynomial;
758 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
759 ///
760 /// let mut p;
761 /// p = IntegerPolynomial::from_str("x^2-2*x+3").unwrap();
762 /// p.reverse_assign(3);
763 /// assert_eq!(p.to_string(), "3*x^2-2*x+1");
764 /// // Padding to length 5 adds low zeros.
765 /// p = IntegerPolynomial::from_str("x^2-2*x+3").unwrap();
766 /// p.reverse_assign(5);
767 /// assert_eq!(p.to_string(), "3*x^4-2*x^3+x^2");
768 /// // Truncating to length 2 drops x^2 first.
769 /// p = IntegerPolynomial::from_str("x^2-2*x+3").unwrap();
770 /// p.reverse_assign(2);
771 /// assert_eq!(p.to_string(), "3*x-2");
772 /// // A zero constant term becomes a trailing zero, and is dropped.
773 /// p = IntegerPolynomial::from_str("x^2-2*x").unwrap();
774 /// p.reverse_assign(3);
775 /// assert_eq!(p.to_string(), "-2*x+1");
776 /// ```
777 ///
778 /// This is equivalent to `fmpz_poly_reverse` from `fmpz_poly/reverse.c`, FLINT 3.6.0.
779 fn reverse_assign(&mut self, len: u64) {
780 let kept = usize::try_from(len).map_or(self.coefficients.len(), |len| {
781 len.min(self.coefficients.len())
782 });
783 if kept == 0 {
784 *self = Self::ZERO;
785 return;
786 }
787 self.coefficients.truncate(kept);
788 self.coefficients.reverse();
789 // Pad at the high end and rotate the padding down, so that it becomes the low zeros.
790 let len = usize::exact_from(len);
791 self.coefficients.resize(len, Integer::ZERO);
792 self.coefficients.rotate_right(len - kept);
793 // The polynomial's low zeros, if any, are now at the top.
794 self.trim();
795 }
796
797 /// Converts an [`IntegerPolynomial`] to a [`String`], naming its variable with any
798 /// [`VarScheme`].
799 ///
800 /// The syntax is the one [`Display`](core::fmt::Display) writes, which that implementation
801 /// describes; the only difference is that the variable is whichever one is handed in rather
802 /// than `x`.
803 ///
804 /// # Worst-case complexity
805 /// $T(n) = O(n \log n \log\log n)$
806 ///
807 /// $M(n) = O(n \log n)$
808 ///
809 /// where $T$ is time, $M$ is additional memory, and $n$ is the sum of the bits of the
810 /// coefficients.
811 ///
812 /// # Panics
813 /// Panics if `var`'s index is not less than its scheme's [`capacity`](VarScheme::capacity).
814 ///
815 /// # Examples
816 /// ```
817 /// use core::str::FromStr;
818 /// use malachite_base::polynomial::Polynomial;
819 /// use malachite_base::vars::VarScheme;
820 /// use malachite_base::vars::greek::GreekVars;
821 /// use malachite_base::vars::indexed::IndexedVars;
822 /// use malachite_base::vars::list::ListVars;
823 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
824 ///
825 /// let p = IntegerPolynomial::from_str("x^2+3*x+2").unwrap();
826 /// assert_eq!(p.to_string_with(GreekVars.var(0)), "α^2+3*α+2");
827 /// assert_eq!(p.to_string_with(IndexedVars.var(7)), "x₇^2+3*x₇+2");
828 ///
829 /// let vars = ListVars::new(["t"]);
830 /// assert_eq!(p.to_string_with(vars.var(0)), "t^2+3*t+2");
831 /// ```
832 fn to_string_with<S: VarScheme + ?Sized>(&self, var: Var<'_, S>) -> String {
833 let mut s = String::new();
834 // Writing to a `String` cannot fail, so the result is the string itself.
835 self.write_with_var(var, Language::Plain, &mut s).unwrap();
836 s
837 }
838
839 /// Converts an [`IntegerPolynomial`] to a LaTeX math-mode fragment, naming its variable with
840 /// any [`VarScheme`].
841 ///
842 /// The fragment is the one [`ToLatex`](malachite_base::strings::latex::ToLatex) writes, which
843 /// that implementation describes; the only difference is that the variable is whichever one is
844 /// handed in rather than `x`.
845 ///
846 /// # Worst-case complexity
847 /// $T(n) = O(n \log n \log\log n)$
848 ///
849 /// $M(n) = O(n \log n)$
850 ///
851 /// where $T$ is time, $M$ is additional memory, and $n$ is the sum of the bits of the
852 /// coefficients.
853 ///
854 /// # Panics
855 /// Panics if `var`'s index is not less than its scheme's [`capacity`](VarScheme::capacity).
856 ///
857 /// # Examples
858 /// ```
859 /// use core::str::FromStr;
860 /// use malachite_base::polynomial::Polynomial;
861 /// use malachite_base::vars::VarScheme;
862 /// use malachite_base::vars::greek::GreekVars;
863 /// use malachite_base::vars::indexed::IndexedVars;
864 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
865 ///
866 /// let p = IntegerPolynomial::from_str("x^2+3*x+2").unwrap();
867 /// assert_eq!(
868 /// p.to_latex_string_with(GreekVars.var(0)),
869 /// r"\alpha^2+3\alpha+2"
870 /// );
871 /// assert_eq!(p.to_latex_string_with(IndexedVars.var(7)), "x_7^2+3x_7+2");
872 /// ```
873 ///
874 /// The polynomial is `x^2+3*x+2` in each row; only its variable differs.
875 ///
876 /// | variable | fragment | renders as |
877 /// |----------|----------------------|----------------------|
878 /// | `α` | `\alpha^2+3\alpha+2` | $\alpha^2+3\alpha+2$ |
879 /// | `x₇` | `x_7^2+3x_7+2` | $x_7^2+3x_7+2$ |
880 fn to_latex_string_with<S: VarScheme + ?Sized>(&self, var: Var<'_, S>) -> String {
881 let mut s = String::new();
882 // Writing to a `String` cannot fail, so the result is the string itself.
883 self.write_with_var(var, Language::Latex, &mut s).unwrap();
884 s
885 }
886
887 /// Converts an [`IntegerPolynomial`] to a Typst math-mode fragment, naming its variable with
888 /// any [`VarScheme`].
889 ///
890 /// The fragment is the one [`ToTypst`](malachite_base::strings::typst::ToTypst) writes, which
891 /// that implementation describes; the only difference is that the variable is whichever one is
892 /// handed in rather than `x`.
893 ///
894 /// # Worst-case complexity
895 /// $T(n) = O(n \log n \log\log n)$
896 ///
897 /// $M(n) = O(n \log n)$
898 ///
899 /// where $T$ is time, $M$ is additional memory, and $n$ is the sum of the bits of the
900 /// coefficients.
901 ///
902 /// # Panics
903 /// Panics if `var`'s index is not less than its scheme's [`capacity`](VarScheme::capacity).
904 ///
905 /// # Examples
906 /// ```
907 /// use core::str::FromStr;
908 /// use malachite_base::polynomial::Polynomial;
909 /// use malachite_base::vars::VarScheme;
910 /// use malachite_base::vars::greek::GreekVars;
911 /// use malachite_base::vars::indexed::IndexedVars;
912 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
913 ///
914 /// let p = IntegerPolynomial::from_str("x^2+3*x+2").unwrap();
915 /// assert_eq!(p.to_typst_string_with(GreekVars.var(0)), "α^2+3α+2");
916 /// assert_eq!(p.to_typst_string_with(IndexedVars.var(7)), "x_7^2+3x_7+2");
917 /// ```
918 ///
919 /// The polynomial is `x^2+3*x+2` in each row; only its variable differs.
920 ///
921 /// | variable | fragment |
922 /// |----------|----------------|
923 /// | `α` | `α^2+3α+2` |
924 /// | `x₇` | `x_7^2+3x_7+2` |
925 fn to_typst_string_with<S: VarScheme + ?Sized>(&self, var: Var<'_, S>) -> String {
926 let mut s = String::new();
927 // Writing to a `String` cannot fail, so the result is the string itself.
928 self.write_with_var(var, Language::Typst, &mut s).unwrap();
929 s
930 }
931
932 /// Converts a string to an [`IntegerPolynomial`], with its variable named by any [`VarScheme`].
933 ///
934 /// The syntax is the one [`FromStr`](core::str::FromStr) reads, which that implementation
935 /// describes; the only difference is that the variable is whichever one is handed in rather
936 /// than `x`.
937 ///
938 /// # Worst-case complexity
939 /// $T(n) = O(n (\log n)^2 \log\log n)$
940 ///
941 /// $M(n) = O(n \log n)$
942 ///
943 /// where $T$ is time, $M$ is additional memory, and $n$ is `s.len()`.
944 ///
945 /// # Examples
946 /// ```
947 /// use malachite_base::polynomial::Polynomial;
948 /// use malachite_base::vars::VarScheme;
949 /// use malachite_base::vars::greek::GreekVars;
950 /// use malachite_base::vars::list::ListVars;
951 /// use malachite_nz::integer_polynomial::IntegerPolynomial;
952 ///
953 /// let p = IntegerPolynomial::from_string_with(GreekVars.var(0), "α^2+3*α+2").unwrap();
954 /// assert_eq!(p.to_string(), "x^2+3*x+2");
955 ///
956 /// let vars = ListVars::new(["t"]);
957 /// assert_eq!(
958 /// IntegerPolynomial::from_string_with(vars.var(0), "t^2+1")
959 /// .unwrap()
960 /// .to_string(),
961 /// "x^2+1"
962 /// );
963 ///
964 /// // The variable must be the one that was asked for.
965 /// assert!(IntegerPolynomial::from_string_with(GreekVars.var(0), "β^2").is_none());
966 /// ```
967 #[inline]
968 fn from_string_with<S: VarScheme + ?Sized>(var: Var<'_, S>, s: &str) -> Option<Self> {
969 from_string_with(var, s)
970 }
971}
972
973impl_named!(IntegerPolynomial);
974
975/// `ShortlexIntegerPolynomial` is a wrapper around an [`IntegerPolynomial`], taking the
976/// [`IntegerPolynomial`] by value.
977///
978/// [`IntegerPolynomial`] is ordered by how its polynomials behave for large arguments, which is the
979/// order that respects their arithmetic. Sometimes a different order is wanted: one that puts the
980/// smaller polynomials first, whatever their signs, so that a list of them is enumerated from the
981/// simplest upward. Wrapping an [`IntegerPolynomial`] in a `ShortlexIntegerPolynomial` provides
982/// one: polynomials are compared first by degree and then, in case of a tie, by their coefficients
983/// from highest to lowest. This is a total order whose equality agrees with [`IntegerPolynomial`]
984/// equality; it is FLINT's order for polynomials, the one `fmpq_poly_cmp` implements.
985///
986/// The difference from the [`Ord`] implementation on [`IntegerPolynomial`] is what happens when the
987/// degrees differ. There, a polynomial of higher degree dominates, so it is the greater one only if
988/// its leading coefficient is positive, and $-x^3 < x^2$. Here, degree decides outright, so $-x^3 >
989/// x^2$.
990///
991/// Neither order is a well-order. Ordering by degree first does not make one: $x > x - 1 > x - 2 >
992/// \ldots$ all have degree 1, so the chain descends forever under either order. No order that
993/// restricts to the usual order on the constant polynomials can be a well-order, since the
994/// [`Integer`]s are not well-ordered.
995///
996/// `ShortlexIntegerPolynomial` owns its value. This is useful in many cases, for example if you
997/// want to use [`IntegerPolynomial`]s as keys in a map. In other situations, it is better to use
998/// [`ShortlexIntegerPolynomialRef`], which only has a reference to its value.
999// Serialized as its inner `IntegerPolynomial`, since the wrapper adds no data of its own.
1000#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
1001#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
1002#[cfg_attr(feature = "serde", serde(transparent))]
1003pub struct ShortlexIntegerPolynomial(pub IntegerPolynomial);
1004
1005/// `ShortlexIntegerPolynomialRef` is a wrapper around an [`IntegerPolynomial`], taking the
1006/// [`IntegerPolynomial`] by reference.
1007///
1008/// See the [`ShortlexIntegerPolynomial`] documentation for details.
1009#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1010pub struct ShortlexIntegerPolynomialRef<'a>(pub &'a IntegerPolynomial);
1011
1012impl ShortlexIntegerPolynomial {
1013 /// Borrows a [`ShortlexIntegerPolynomial`] as a [`ShortlexIntegerPolynomialRef`].
1014 ///
1015 /// # Worst-case complexity
1016 /// Constant time and additional memory.
1017 ///
1018 /// # Examples
1019 /// ```
1020 /// use core::str::FromStr;
1021 /// use malachite_nz::integer_polynomial::{
1022 /// IntegerPolynomial, ShortlexIntegerPolynomial, ShortlexIntegerPolynomialRef,
1023 /// };
1024 ///
1025 /// let p = IntegerPolynomial::from_str("x^2-3*x+2").unwrap();
1026 /// let x = ShortlexIntegerPolynomial(p.clone());
1027 /// assert_eq!(x.as_ref(), ShortlexIntegerPolynomialRef(&p));
1028 /// ```
1029 pub const fn as_ref(&self) -> ShortlexIntegerPolynomialRef<'_> {
1030 ShortlexIntegerPolynomialRef(&self.0)
1031 }
1032}
1033
1034impl Deref for ShortlexIntegerPolynomial {
1035 type Target = IntegerPolynomial;
1036
1037 /// Allows a [`ShortlexIntegerPolynomial`] to dereference to an [`IntegerPolynomial`].
1038 ///
1039 /// ```
1040 /// use core::str::FromStr;
1041 /// use malachite_nz::integer_polynomial::{IntegerPolynomial, ShortlexIntegerPolynomial};
1042 ///
1043 /// let p = IntegerPolynomial::from_str("x^2-3*x+2").unwrap();
1044 /// let x = ShortlexIntegerPolynomial(p.clone());
1045 /// assert_eq!(*x, p);
1046 /// ```
1047 fn deref(&self) -> &IntegerPolynomial {
1048 &self.0
1049 }
1050}
1051
1052impl Deref for ShortlexIntegerPolynomialRef<'_> {
1053 type Target = IntegerPolynomial;
1054
1055 /// Allows a [`ShortlexIntegerPolynomialRef`] to dereference to an [`IntegerPolynomial`].
1056 ///
1057 /// ```
1058 /// use core::str::FromStr;
1059 /// use malachite_nz::integer_polynomial::{IntegerPolynomial, ShortlexIntegerPolynomialRef};
1060 ///
1061 /// let p = IntegerPolynomial::from_str("x^2-3*x+2").unwrap();
1062 /// let x = ShortlexIntegerPolynomialRef(&p);
1063 /// assert_eq!(*x, p);
1064 /// ```
1065 fn deref(&self) -> &IntegerPolynomial {
1066 self.0
1067 }
1068}