malachite_base/unsigned_polynomial/comparison/cmp.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::unsigned_polynomial::UnsignedPolynomial;
11use core::cmp::Ordering::{self, *};
12
13impl<T: PrimitiveUnsigned> PartialOrd for UnsignedPolynomial<T> {
14 /// Compares two [`UnsignedPolynomial`]s.
15 ///
16 /// See the documentation for the [`Ord`] implementation.
17 #[inline]
18 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
19 Some(self.cmp(other))
20 }
21}
22
23impl<T: PrimitiveUnsigned> Ord for UnsignedPolynomial<T> {
24 /// Compares two [`UnsignedPolynomial`]s by how they behave for large arguments.
25 ///
26 /// The greater polynomial is the one that is eventually greater: the comparison is the one that
27 /// $p(x)$ and $q(x)$ eventually settle into as $x$ grows. The coefficients are read as the
28 /// numbers they are, so the values being compared are the ones a polynomial over the integers
29 /// would take, not ones reduced by any modulus.
30 ///
31 /// $$
32 /// f(p, q) = \lim_{x \to \infty} \operatorname{cmp}(p(x), q(x)).
33 /// $$
34 ///
35 /// The limit always exists. $p - q$ is a polynomial, so it has finitely many roots, and past
36 /// the largest of them its sign is the sign of its leading coefficient and never changes again.
37 /// That also makes this a total order agreeing with [`Eq`]: the limit is $0$ exactly when $p -
38 /// q$ is the zero polynomial.
39 ///
40 /// Finding it needs no evaluation. A polynomial of higher degree eventually outgrows one of
41 /// lower degree, whatever their coefficients, so the degrees decide first; the zero polynomial,
42 /// having no degree at all, is below every other polynomial. Polynomials of equal degree are
43 /// decided by the highest-degree coefficient at which they differ, since that term eventually
44 /// outgrows the sum of everything below it.
45 ///
46 /// This is the order that makes the polynomials an ordered ring: it is unchanged by adding a
47 /// polynomial to both sides, and by multiplying both sides by a nonzero one. Restricted to the
48 /// constant polynomials it is the order on the `T`s, so the embedding of a number as a
49 /// polynomial preserves comparisons. It is not a well-order, and no order compatible with
50 /// addition can be: $x > x - 1 > x - 2 > \ldots$ descends forever. A well-order on polynomials
51 /// needs to weigh a polynomial's size against its degree, which this order does not do.
52 ///
53 /// # Worst-case complexity
54 /// $T(n) = O(n)$
55 ///
56 /// $M(n) = O(1)$
57 ///
58 /// where $T$ is time, $M$ is additional memory, and $n$ is the smaller of the two polynomials'
59 /// numbers of coefficients. Polynomials of different degrees are compared in constant time.
60 ///
61 /// # Examples
62 /// ```
63 /// use core::str::FromStr;
64 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
65 ///
66 /// // A higher degree wins however small its coefficients: x^2 eventually passes 1000000*x.
67 /// assert!(
68 /// UnsignedPolynomial::<u64>::from_str("x^2").unwrap()
69 /// > UnsignedPolynomial::<u64>::from_str("1000000*x").unwrap()
70 /// );
71 ///
72 /// // At equal degrees the leading coefficient decides.
73 /// assert!(
74 /// UnsignedPolynomial::<u64>::from_str("2*x^2").unwrap()
75 /// > UnsignedPolynomial::<u64>::from_str("x^2+1000000").unwrap()
76 /// );
77 ///
78 /// // When that ties, the next coefficient down does.
79 /// assert!(
80 /// UnsignedPolynomial::<u64>::from_str("x^2+3*x").unwrap()
81 /// > UnsignedPolynomial::<u64>::from_str("x^2+2*x+1000000").unwrap()
82 /// );
83 ///
84 /// // The zero polynomial is below everything else.
85 /// assert!(
86 /// UnsignedPolynomial::<u64>::from_str("0").unwrap()
87 /// < UnsignedPolynomial::<u64>::from_str("1").unwrap()
88 /// );
89 ///
90 /// // Constant polynomials compare as the numbers they are.
91 /// assert!(
92 /// UnsignedPolynomial::<u64>::from_str("123").unwrap()
93 /// > UnsignedPolynomial::<u64>::from_str("122").unwrap()
94 /// );
95 /// ```
96 fn cmp(&self, other: &Self) -> Ordering {
97 if core::ptr::eq(self, other) {
98 return Equal;
99 }
100 // The coefficients are held with no trailing zero, so the length is the degree plus one,
101 // and 0 for the zero polynomial; comparing lengths is comparing degrees. Once the lengths
102 // agree the iterators have the same length, so comparing them from the leading coefficient
103 // down is exactly the comparison at the highest coefficient where the two differ.
104 self.coefficients
105 .len()
106 .cmp(&other.coefficients.len())
107 .then_with(|| {
108 self.coefficients
109 .iter()
110 .rev()
111 .cmp(other.coefficients.iter().rev())
112 })
113 }
114}