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}