mathhook_core/core/polynomial/
properties.rs

1//! Polynomial Properties
2//!
3//! Core polynomial properties: degree, leading coefficient, content, primitive part.
4//! These methods are cached using thread-local LRU caching for performance.
5
6use super::classification::PolynomialClassification;
7use crate::core::{Expression, Symbol};
8
9mod content;
10mod degree;
11#[cfg(test)]
12mod tests;
13
14// Re-export for internal use within polynomial module
15pub(crate) use content::{compute_content_impl, divide_by_integer};
16pub(crate) use degree::{
17    compute_leading_coefficient_impl, compute_total_degree_impl, degree_cached,
18};
19
20/// Trait for polynomial properties
21///
22/// Provides methods for computing polynomial properties such as degree,
23/// leading coefficient, content, and primitive part. Results are cached
24/// using thread-local LRU caching for performance.
25///
26/// # Examples
27///
28/// ```rust
29/// use mathhook_core::core::polynomial::{PolynomialClassification, PolynomialProperties};
30/// use mathhook_core::{expr, symbol};
31///
32/// let x = symbol!(x);
33/// let poly = expr!(x ^ 3);
34///
35/// assert_eq!(poly.degree(&x), Some(3));
36/// ```
37pub trait PolynomialProperties: PolynomialClassification {
38    /// Compute degree with respect to a variable
39    ///
40    /// Returns the highest power of the variable in the polynomial.
41    ///
42    /// # Arguments
43    ///
44    /// * `var` - The variable to compute degree for
45    ///
46    /// # Returns
47    ///
48    /// `Some(degree)` if the expression is a polynomial in the variable,
49    /// `None` if not a polynomial.
50    ///
51    /// # Examples
52    ///
53    /// ```rust
54    /// use mathhook_core::core::polynomial::PolynomialProperties;
55    /// use mathhook_core::{expr, symbol};
56    ///
57    /// let x = symbol!(x);
58    ///
59    /// assert_eq!(expr!(x ^ 3).degree(&x), Some(3));
60    /// assert_eq!(expr!(5).degree(&x), Some(0));
61    /// ```
62    fn degree(&self, var: &Symbol) -> Option<i64>;
63
64    /// Compute total degree (sum of degrees in all variables)
65    ///
66    /// For multivariate polynomials, returns the maximum sum of exponents
67    /// across all terms.
68    ///
69    /// # Examples
70    ///
71    /// ```rust
72    /// use mathhook_core::core::polynomial::PolynomialProperties;
73    /// use mathhook_core::{expr, symbol};
74    ///
75    /// let x = symbol!(x);
76    /// let y = symbol!(y);
77    /// let poly = expr!(x * y);  // x*y has total degree 2
78    ///
79    /// assert_eq!(poly.total_degree(), Some(2));
80    /// ```
81    fn total_degree(&self) -> Option<i64>;
82
83    /// Get leading coefficient with respect to a variable
84    ///
85    /// Returns the coefficient of the highest degree term.
86    ///
87    /// # Arguments
88    ///
89    /// * `var` - The variable to find leading coefficient for
90    ///
91    /// # Examples
92    ///
93    /// ```rust
94    /// use mathhook_core::core::polynomial::PolynomialProperties;
95    /// use mathhook_core::{expr, symbol};
96    ///
97    /// let x = symbol!(x);
98    /// let poly = expr!((5 * (x ^ 2)) + (3 * x) + 1);
99    ///
100    /// // Leading coefficient of 5x^2 + 3x + 1 is 5
101    /// let lc = poly.leading_coefficient(&x);
102    /// ```
103    fn leading_coefficient(&self, var: &Symbol) -> Expression;
104
105    /// Extract content (GCD of all coefficients)
106    ///
107    /// The content is the GCD of all numeric coefficients in the polynomial.
108    ///
109    /// # Examples
110    ///
111    /// ```rust
112    /// use mathhook_core::core::polynomial::PolynomialProperties;
113    /// use mathhook_core::{expr, symbol};
114    ///
115    /// let x = symbol!(x);
116    /// let poly = expr!((6 * (x ^ 2)) + (9 * x) + 3);
117    ///
118    /// // Content of 6x^2 + 9x + 3 is 3
119    /// let content = poly.content();
120    /// ```
121    fn content(&self) -> Expression;
122
123    /// Extract primitive part (polynomial divided by content)
124    ///
125    /// The primitive part is the polynomial with content factored out.
126    ///
127    /// # Examples
128    ///
129    /// ```rust
130    /// use mathhook_core::core::polynomial::PolynomialProperties;
131    /// use mathhook_core::{expr, symbol};
132    ///
133    /// let x = symbol!(x);
134    /// let poly = expr!((6 * (x ^ 2)) + (9 * x) + 3);
135    ///
136    /// // Primitive part of 6x^2 + 9x + 3 is 2x^2 + 3x + 1
137    /// let pp = poly.primitive_part();
138    /// ```
139    fn primitive_part(&self) -> Expression;
140}
141
142impl PolynomialProperties for Expression {
143    fn degree(&self, var: &Symbol) -> Option<i64> {
144        degree_cached(self, var)
145    }
146
147    fn total_degree(&self) -> Option<i64> {
148        let vars = self.polynomial_variables();
149        if vars.is_empty() {
150            return Some(0);
151        }
152
153        // For total degree, we need to find the maximum sum of degrees in any term
154        compute_total_degree_impl(self, &vars)
155    }
156
157    fn leading_coefficient(&self, var: &Symbol) -> Expression {
158        compute_leading_coefficient_impl(self, var)
159    }
160
161    fn content(&self) -> Expression {
162        compute_content_impl(self)
163    }
164
165    fn primitive_part(&self) -> Expression {
166        let content = self.content();
167        if content.is_zero() || content == Expression::integer(1) {
168            self.clone()
169        } else {
170            // Divide polynomial by content
171            divide_by_integer(self, &content)
172        }
173    }
174}