mathhook_core/functions/polynomials/
polynomial_eval.rs

1//! Polynomial function evaluations
2
3use crate::core::{Expression, Number, Symbol};
4
5/// Get polynomial degree
6///
7/// # Mathematical Definition
8///
9/// degree(p(x)) = highest power of x in polynomial p
10///
11/// # Arguments
12///
13/// * `poly` - Polynomial expression
14/// * `var` - Variable to check degree for
15///
16/// # Returns
17///
18/// Degree as integer expression or symbolic
19///
20/// # Examples
21///
22/// ```ignore
23/// use mathhook_core::functions::polynomials::polynomial_eval::degree;
24/// use mathhook_core::{expr, symbol};
25///
26/// let x = symbol!(x);
27/// let poly = expr!((x ^ 3) + (2 * (x ^ 2)) + x + 1);
28/// let deg = degree(&poly, &x);
29/// assert_eq!(deg, expr!(3));
30/// ```
31pub fn degree(poly: &Expression, var: &Symbol) -> Expression {
32    match poly {
33        Expression::Pow(base, exp) if matches!(**base, Expression::Symbol(ref s) if s == var) => {
34            if let Expression::Number(Number::Integer(n)) = **exp {
35                Expression::integer(n)
36            } else {
37                exp.as_ref().clone()
38            }
39        }
40        Expression::Add(terms) => {
41            let mut max_degree = 0i64;
42            for term in terms.iter() {
43                if let Expression::Number(Number::Integer(d)) = degree(term, var) {
44                    max_degree = max_degree.max(d);
45                }
46            }
47            Expression::integer(max_degree)
48        }
49        Expression::Mul(factors) => {
50            let mut total_degree = 0i64;
51            for factor in factors.iter() {
52                if let Expression::Number(Number::Integer(d)) = degree(factor, var) {
53                    total_degree += d;
54                }
55            }
56            Expression::integer(total_degree)
57        }
58        Expression::Symbol(s) if s == var => Expression::integer(1),
59        Expression::Number(_) => Expression::integer(0),
60        _ => Expression::function(
61            "degree",
62            vec![poly.clone(), Expression::symbol(var.clone())],
63        ),
64    }
65}
66
67/// Find polynomial roots
68///
69/// # Mathematical Definition
70///
71/// roots(p(x)) = {x : p(x) = 0}
72///
73/// # Arguments
74///
75/// * `poly` - Polynomial expression
76/// * `var` - Variable to solve for
77///
78/// # Returns
79///
80/// Set of roots or symbolic expression
81///
82/// # Examples
83///
84/// ```
85/// use mathhook_core::functions::polynomials::polynomial_eval::roots;
86/// use mathhook_core::{expr, symbol};
87///
88/// let x = symbol!(x);
89/// let poly = expr!((x ^ 2) - 1);
90/// let r = roots(&poly, &x);
91/// ```
92pub fn roots(poly: &Expression, var: &Symbol) -> Expression {
93    Expression::function("roots", vec![poly.clone(), Expression::symbol(var.clone())])
94}
95
96/// Expand polynomial expression
97///
98/// # Mathematical Definition
99///
100/// expand((x+1)²) = x² + 2x + 1
101///
102/// # Arguments
103///
104/// * `expr` - Expression to expand
105///
106/// # Returns
107///
108/// Expanded expression
109///
110/// # Examples
111///
112/// ```
113/// use mathhook_core::functions::polynomials::polynomial_eval::expand;
114/// use mathhook_core::expr;
115///
116/// let result = expand(&expr!(1));
117/// assert_eq!(result, expr!(1));
118/// ```
119pub fn expand(expr: &Expression) -> Expression {
120    expr.clone()
121}
122
123/// Factor polynomial expression
124///
125/// # Mathematical Definition
126///
127/// factor(x² - 1) = (x - 1)(x + 1)
128///
129/// # Arguments
130///
131/// * `expr` - Expression to factor
132///
133/// # Returns
134///
135/// Factored expression
136///
137/// # Examples
138///
139/// ```
140/// use mathhook_core::functions::polynomials::polynomial_eval::factor;
141/// use mathhook_core::expr;
142///
143/// let result = factor(&expr!(1));
144/// assert_eq!(result, expr!(1));
145/// ```
146pub fn factor(expr: &Expression) -> Expression {
147    expr.clone()
148}
149
150#[cfg(test)]
151mod tests {
152    use super::*;
153    use crate::symbol;
154
155    #[test]
156    fn test_degree_constant() {
157        let x = symbol!(x);
158        assert_eq!(degree(&Expression::integer(5), &x), Expression::integer(0));
159    }
160
161    #[test]
162    fn test_degree_linear() {
163        let x = symbol!(x);
164        assert_eq!(
165            degree(&Expression::symbol(x.clone()), &x),
166            Expression::integer(1)
167        );
168    }
169
170    #[test]
171    fn test_degree_quadratic() {
172        let x = symbol!(x);
173        let poly = Expression::pow(Expression::symbol(x.clone()), Expression::integer(2));
174        assert_eq!(degree(&poly, &x), Expression::integer(2));
175    }
176
177    #[test]
178    fn test_expand_constant() {
179        assert_eq!(expand(&Expression::integer(1)), Expression::integer(1));
180    }
181
182    #[test]
183    fn test_factor_constant() {
184        assert_eq!(factor(&Expression::integer(1)), Expression::integer(1));
185    }
186}