1use crate::calculus::derivatives::Derivative;
3use crate::core::{Expression, Symbol};
4use crate::simplify::Simplify;
5use crate::symbol;
6pub struct HigherOrderDerivatives;
8impl HigherOrderDerivatives {
9 pub fn compute(expr: &Expression, variable: Symbol, order: u32) -> Expression {
25 match order {
26 0 => expr.clone(),
27 1 => expr.derivative(variable).simplify(),
28 n => {
29 let mut result = expr.clone();
30 for _ in 0..n {
31 result = result.derivative(variable.clone()).simplify();
32 }
33 result
34 }
35 }
36 }
37 pub fn mixed_partial(expr: &Expression, derivatives: Vec<(Symbol, u32)>) -> Expression {
54 let mut result = expr.clone();
55 for (variable, order) in derivatives {
56 if order > 0 {
57 result = Self::compute(&result, variable, order);
58 }
59 }
60 result.simplify()
61 }
62 pub fn exists(expr: &Expression, variable: Symbol, order: u32) -> bool {
77 if order == 0 {
78 return true;
79 }
80 if !expr.is_differentiable(variable.clone()) {
81 return false;
82 }
83 if order == 1 {
84 return true;
85 }
86 let first_derivative = expr.derivative(variable.clone());
87 Self::exists(&first_derivative, variable, order - 1)
88 }
89 pub fn derivative_table(
102 expr: &Expression,
103 variable: &Symbol,
104 max_order: u32,
105 ) -> Vec<Expression> {
106 let mut table = Vec::with_capacity((max_order + 1) as usize);
107 let mut current = expr.clone();
108 table.push(current.clone());
109 for _ in 1..=max_order {
110 current = current.derivative(variable.clone()).simplify();
111 table.push(current.clone());
112 }
113 table
114 }
115 pub fn find_pattern(expr: &Expression, variable: Symbol, check_orders: u32) -> Option<u32> {
128 let derivatives = Self::derivative_table(expr, &variable, check_orders);
129 (1..=(check_orders / 2)).find(|&period| Self::has_period(&derivatives, period as usize))
130 }
131 fn has_period(derivatives: &[Expression], period: usize) -> bool {
133 if derivatives.len() < 2 * period {
134 return false;
135 }
136 for i in 0..period {
137 if derivatives[i] != derivatives[i + period] {
138 return false;
139 }
140 }
141 true
142 }
143 pub fn leibniz_rule(u: &Expression, v: &Expression, variable: &Symbol, n: u32) -> Expression {
158 let mut terms = Vec::with_capacity((n + 1) as usize);
159 for k in 0..=n {
160 let binomial_coeff = Self::binomial_coefficient(n, k);
161 let u_derivative = Self::compute(u, variable.clone(), k);
162 let v_derivative = Self::compute(v, variable.clone(), n - k);
163 let term = Expression::mul(vec![
164 Expression::integer(binomial_coeff),
165 u_derivative,
166 v_derivative,
167 ]);
168 terms.push(term);
169 }
170 Expression::add(terms).simplify()
171 }
172 fn binomial_coefficient(n: u32, k: u32) -> i64 {
174 if k > n {
175 return 0;
176 }
177 if k == 0 || k == n {
178 return 1;
179 }
180 let k = k.min(n - k);
181 let mut result = 1i64;
182 for i in 0..k {
183 result = result * (n - i) as i64 / (i + 1) as i64;
184 }
185 result
186 }
187 pub fn faa_di_bruno(
201 outer_function: &str,
202 inner_function: &Expression,
203 variable: Symbol,
204 n: u32,
205 ) -> Expression {
206 if n == 0 {
207 return Expression::function(outer_function, vec![inner_function.clone()]);
208 }
209 if n == 1 {
210 let outer_derivative = Self::get_function_derivative(outer_function, inner_function);
211 let inner_derivative = inner_function.derivative(variable);
212 return Expression::mul(vec![outer_derivative, inner_derivative]).simplify();
213 }
214 Expression::derivative(
215 Expression::function(outer_function, vec![inner_function.clone()]),
216 variable,
217 n,
218 )
219 }
220 fn get_function_derivative(function_name: &str, arg: &Expression) -> Expression {
225 use crate::functions::intelligence::get_universal_registry;
226 let registry = get_universal_registry();
227 if let Some(props) = registry.get_properties(function_name) {
228 if let Some(derivative) = props.get_derivative_expression(arg) {
229 return derivative;
230 }
231 }
232 Expression::derivative(
233 Expression::function(function_name, vec![arg.clone()]),
234 symbol!(x),
235 1,
236 )
237 }
238}
239#[cfg(test)]
240mod tests {
241 use super::*;
242 use crate::symbol;
243 #[test]
244 fn test_polynomial_higher_derivatives() {
245 let x = symbol!(x);
246 let x4 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(4));
247 let first = HigherOrderDerivatives::compute(&x4, x.clone(), 1);
248 assert!(!first.is_zero());
249 let second = HigherOrderDerivatives::compute(&x4, x.clone(), 2);
250 assert!(!second.is_zero());
251 let third = HigherOrderDerivatives::compute(&x4, x.clone(), 3);
252 assert!(!third.is_zero());
253 let fourth = HigherOrderDerivatives::compute(&x4, x.clone(), 4);
254 assert!(!fourth.is_zero());
255 let fifth = HigherOrderDerivatives::compute(&x4, x.clone(), 5);
256 assert_eq!(fifth.simplify(), Expression::integer(0));
257 }
258 #[test]
259 fn test_exponential_derivatives() {
260 let x = symbol!(x);
261 let exp_x = Expression::function("exp", vec![Expression::symbol(x.clone())]);
262 for order in 1..=5 {
263 let derivative = HigherOrderDerivatives::compute(&exp_x, x.clone(), order);
264 assert!(!derivative.is_zero());
265 }
266 }
267 #[test]
268 fn test_trigonometric_patterns() {
269 let x = symbol!(x);
270 let sin_x = Expression::function("sin", vec![Expression::symbol(x.clone())]);
271 let cos_x = Expression::function("cos", vec![Expression::symbol(x.clone())]);
272 let sin_table = HigherOrderDerivatives::derivative_table(&sin_x, &x, 8);
273 assert_eq!(sin_table.len(), 9);
274 let cos_table = HigherOrderDerivatives::derivative_table(&cos_x, &x, 8);
275 assert_eq!(cos_table.len(), 9);
276 let sin_pattern = HigherOrderDerivatives::find_pattern(&sin_x, x.clone(), 8);
277 assert!(sin_pattern.is_some());
278 let cos_pattern = HigherOrderDerivatives::find_pattern(&cos_x, x.clone(), 8);
279 assert!(cos_pattern.is_some());
280 }
281 #[test]
282 fn test_mixed_partial_derivatives() {
283 let x = symbol!(x);
284 let y = symbol!(y);
285 let xy = Expression::mul(vec![
286 Expression::symbol(x.clone()),
287 Expression::symbol(y.clone()),
288 ]);
289 let mixed_xy =
290 HigherOrderDerivatives::mixed_partial(&xy, vec![(x.clone(), 1), (y.clone(), 1)]);
291 assert!(!mixed_xy.is_zero());
292 let x2y = Expression::mul(vec![
293 Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
294 Expression::symbol(y.clone()),
295 ]);
296 let mixed_x2y =
297 HigherOrderDerivatives::mixed_partial(&x2y, vec![(x.clone(), 2), (y.clone(), 1)]);
298 assert!(!mixed_x2y.is_zero());
299 }
300 #[test]
301 fn test_derivative_existence() {
302 let x = symbol!(x);
303 let smooth_expr = Expression::function("sin", vec![Expression::symbol(x.clone())]);
304 assert!(HigherOrderDerivatives::exists(&smooth_expr, x.clone(), 0));
305 assert!(HigherOrderDerivatives::exists(&smooth_expr, x.clone(), 1));
306 assert!(HigherOrderDerivatives::exists(&smooth_expr, x.clone(), 10));
307 let polynomial = Expression::pow(Expression::symbol(x.clone()), Expression::integer(3));
308 assert!(HigherOrderDerivatives::exists(&polynomial, x.clone(), 3));
309 assert!(HigherOrderDerivatives::exists(&polynomial, x.clone(), 4));
310 }
311 #[test]
312 fn test_leibniz_rule() {
313 let x = symbol!(x);
314 let u = Expression::symbol(x.clone());
315 let v = Expression::function("sin", vec![Expression::symbol(x.clone())]);
316 let leibniz_2 = HigherOrderDerivatives::leibniz_rule(&u, &v, &x, 2);
317 assert!(!leibniz_2.is_zero());
318 let leibniz_3 = HigherOrderDerivatives::leibniz_rule(&u, &v, &x, 3);
319 assert!(!leibniz_3.is_zero());
320 let u_poly = Expression::pow(Expression::symbol(x.clone()), Expression::integer(2));
321 let v_exp = Expression::function("exp", vec![Expression::symbol(x.clone())]);
322 let leibniz_poly = HigherOrderDerivatives::leibniz_rule(&u_poly, &v_exp, &x, 2);
323 assert!(!leibniz_poly.is_zero());
324 }
325 #[test]
326 fn test_binomial_coefficients() {
327 assert_eq!(HigherOrderDerivatives::binomial_coefficient(0, 0), 1);
328 assert_eq!(HigherOrderDerivatives::binomial_coefficient(1, 0), 1);
329 assert_eq!(HigherOrderDerivatives::binomial_coefficient(1, 1), 1);
330 assert_eq!(HigherOrderDerivatives::binomial_coefficient(2, 1), 2);
331 assert_eq!(HigherOrderDerivatives::binomial_coefficient(3, 2), 3);
332 assert_eq!(HigherOrderDerivatives::binomial_coefficient(4, 2), 6);
333 assert_eq!(HigherOrderDerivatives::binomial_coefficient(5, 3), 10);
334 assert_eq!(HigherOrderDerivatives::binomial_coefficient(10, 5), 252);
335 assert_eq!(HigherOrderDerivatives::binomial_coefficient(5, 6), 0);
336 }
337 #[test]
338 fn test_faa_di_bruno_formula() {
339 let x = symbol!(x);
340 let inner = Expression::pow(Expression::symbol(x.clone()), Expression::integer(2));
341 let chain_1 = HigherOrderDerivatives::faa_di_bruno("sin", &inner, x.clone(), 1);
342 assert!(!chain_1.is_zero());
343 let chain_2 = HigherOrderDerivatives::faa_di_bruno("sin", &inner, x.clone(), 2);
344 assert!(!chain_2.is_zero());
345 let exp_inner = Expression::function("exp", vec![Expression::symbol(x.clone())]);
346 let exp_chain = HigherOrderDerivatives::faa_di_bruno("ln", &exp_inner, x.clone(), 1);
347 assert!(!exp_chain.is_zero());
348 }
349 #[test]
350 fn test_zero_order_derivative() {
351 let x = symbol!(x);
352 let expr = Expression::add(vec![
353 Expression::pow(Expression::symbol(x.clone()), Expression::integer(3)),
354 Expression::function("sin", vec![Expression::symbol(x.clone())]),
355 Expression::integer(5),
356 ]);
357 let zero_order = HigherOrderDerivatives::compute(&expr, x.clone(), 0);
358 assert_eq!(zero_order, expr);
359 }
360 #[test]
361 fn test_multivariate_higher_derivatives() {
362 let x = symbol!(x);
363 let y = symbol!(y);
364 let multivar = Expression::add(vec![
365 Expression::mul(vec![
366 Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
367 Expression::pow(Expression::symbol(y.clone()), Expression::integer(3)),
368 ]),
369 Expression::function(
370 "sin",
371 vec![Expression::mul(vec![
372 Expression::symbol(x.clone()),
373 Expression::symbol(y.clone()),
374 ])],
375 ),
376 ]);
377 let dx2 = HigherOrderDerivatives::compute(&multivar, x.clone(), 2);
378 assert!(!dx2.is_zero());
379 let dy3 = HigherOrderDerivatives::compute(&multivar, y.clone(), 3);
380 assert!(!dy3.is_zero());
381 let mixed =
382 HigherOrderDerivatives::mixed_partial(&multivar, vec![(x.clone(), 1), (y.clone(), 2)]);
383 assert!(!mixed.is_zero());
384 }
385 #[test]
386 fn test_edge_cases() {
387 let x = symbol!(x);
388 let constant = Expression::integer(42);
389 let const_deriv = HigherOrderDerivatives::compute(&constant, x.clone(), 5);
390 assert_eq!(const_deriv.simplify(), Expression::integer(0));
391 let linear = Expression::symbol(x.clone());
392 let linear_second = HigherOrderDerivatives::compute(&linear, x.clone(), 2);
393 assert_eq!(linear_second.simplify(), Expression::integer(0));
394 let empty_mixed = HigherOrderDerivatives::mixed_partial(&linear, vec![]);
395 assert_eq!(empty_mixed, linear);
396 }
397}