Skip to content

Commit 91e2c2e

Browse files
committed
Fix Derivative[n][f] simplification and add tests
Add double negation (--x → x) simplification and Exp[x] → E^x conversion in the simplifier so Derivative[4][Sin] and Derivative[1][Exp] produce correct output matching wolframscript. Add 13 unit tests covering Derivative[n][f] pure function return.
1 parent 0619156 commit 91e2c2e

2 files changed

Lines changed: 86 additions & 0 deletions

File tree

src/functions/calculus_ast.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5416,6 +5416,14 @@ pub fn simplify(mut expr: Expr) -> Expr {
54165416
if let Expr::Integer(n) = operand {
54175417
return Expr::Integer(-n);
54185418
}
5419+
// --x → x (double negation)
5420+
if let Expr::UnaryOp {
5421+
op: UnaryOperator::Minus,
5422+
operand: ref inner,
5423+
} = operand
5424+
{
5425+
return *inner.clone();
5426+
}
54195427
}
54205428
Expr::UnaryOp {
54215429
op,
@@ -5439,6 +5447,16 @@ pub fn simplify(mut expr: Expr) -> Expr {
54395447
return result;
54405448
}
54415449
}
5450+
// Convert Exp[x] → E^x
5451+
if name == "Exp"
5452+
&& args.len() == 1
5453+
&& let Ok(result) = crate::functions::math_ast::power_two(
5454+
&Expr::Constant("E".to_string()),
5455+
&args[0],
5456+
)
5457+
{
5458+
return result;
5459+
}
54425460
// Delegate Sqrt to handle Sqrt[0] → 0, Sqrt[1] → 1, etc.
54435461
if name == "Sqrt" && args.len() == 1 {
54445462
let canonical = make_sqrt(args[0].clone());

tests/interpreter_tests/calculus.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,74 @@ mod derivative_prime_notation {
555555
"E^x*Cos[x] + E^x*Sin[x]"
556556
);
557557
}
558+
559+
// Derivative[n][f] returning pure functions
560+
#[test]
561+
fn derivative_n_sin() {
562+
assert_eq!(interpret("Derivative[1][Sin]").unwrap(), "Cos[#1] & ");
563+
}
564+
565+
#[test]
566+
fn derivative_n_cos() {
567+
assert_eq!(interpret("Derivative[1][Cos]").unwrap(), "-Sin[#1] & ");
568+
}
569+
570+
#[test]
571+
fn derivative_n_exp() {
572+
assert_eq!(interpret("Derivative[1][Exp]").unwrap(), "E^#1 & ");
573+
}
574+
575+
#[test]
576+
fn derivative_n_log() {
577+
assert_eq!(interpret("Derivative[1][Log]").unwrap(), "#1^(-1) & ");
578+
}
579+
580+
#[test]
581+
fn derivative_n_sin_second() {
582+
assert_eq!(interpret("Derivative[2][Sin]").unwrap(), "-Sin[#1] & ");
583+
}
584+
585+
#[test]
586+
fn derivative_n_sin_third() {
587+
assert_eq!(interpret("Derivative[3][Sin]").unwrap(), "-Cos[#1] & ");
588+
}
589+
590+
#[test]
591+
fn derivative_n_sin_fourth() {
592+
assert_eq!(interpret("Derivative[4][Sin]").unwrap(), "Sin[#1] & ");
593+
}
594+
595+
#[test]
596+
fn derivative_n_pure_function_cubic() {
597+
assert_eq!(interpret("Derivative[1][#^3&]").unwrap(), "3*#1^2 & ");
598+
}
599+
600+
#[test]
601+
fn derivative_n_pure_function_cubic_second() {
602+
assert_eq!(interpret("Derivative[2][#^3&]").unwrap(), "6*#1 & ");
603+
}
604+
605+
#[test]
606+
fn derivative_n_pure_function_cubic_third() {
607+
assert_eq!(interpret("Derivative[3][#^3&]").unwrap(), "6 & ");
608+
}
609+
610+
#[test]
611+
fn derivative_n_applied() {
612+
// Derivative[1][Sin][x] should evaluate like Sin'[x]
613+
assert_eq!(interpret("Derivative[1][Sin][x]").unwrap(), "Cos[x]");
614+
}
615+
616+
#[test]
617+
fn derivative_n_applied_numeric() {
618+
assert_eq!(interpret("Derivative[1][Sin][0]").unwrap(), "1");
619+
}
620+
621+
#[test]
622+
fn derivative_n_undefined_function() {
623+
// Derivative of undefined function stays symbolic
624+
assert_eq!(interpret("Derivative[1][g]").unwrap(), "Derivative[1][g]");
625+
}
558626
}
559627

560628
mod series {

0 commit comments

Comments
 (0)