use mathhook_core::calculus::derivatives::Derivative;
use mathhook_core::prelude::*;
#[test]
fn test_derivative_constant() {
let x = symbol!(x);
let expr = expr!(5);
let result = expr.derivative(x);
assert_eq!(result, expr!(0));
}
#[test]
fn test_derivative_variable() {
let x = symbol!(x);
let expr = Expression::symbol(x.clone());
let result = expr.derivative(x);
assert_eq!(result, expr!(1));
}
#[test]
fn test_derivative_different_variable() {
let x = symbol!(x);
let y = symbol!(y);
let expr = Expression::symbol(x);
let result = expr.derivative(y);
assert_eq!(result, expr!(0));
}
#[test]
fn test_derivative_power_rule_simple() {
let x = symbol!(x);
let expr = expr!(x ^ 2);
let result = expr.derivative(x.clone());
let expected = expr!(2 * x);
assert_eq!(result, expected);
}
#[test]
fn test_derivative_power_rule_cubic() {
let x = symbol!(x);
let expr = expr!(x ^ 3);
let result = expr.derivative(x.clone());
let expected = expr!(3 * (x ^ 2));
assert_eq!(result, expected);
}
#[test]
fn test_derivative_power_rule_quartic() {
let x = symbol!(x);
let expr = expr!(x ^ 4);
let result = expr.derivative(x.clone());
let expected = expr!(4 * (x ^ 3));
assert_eq!(result, expected);
}
#[test]
fn test_derivative_linear() {
let x = symbol!(x);
let expr = expr!(2 * x);
let result = expr.derivative(x).simplify();
assert_eq!(result, expr!(2));
}
#[test]
fn test_derivative_sum_rule() {
let x = symbol!(x);
let expr = expr!(x + 5);
let result = expr.derivative(x).simplify();
assert_eq!(result, expr!(1));
}
#[test]
fn test_derivative_polynomial_quadratic() {
let x = symbol!(x);
let expr = expr!((x ^ 2) + (2 * x) + 1);
let result = expr.derivative(x.clone()).simplify();
let expected = expr!((2 * x) + 2);
assert_eq!(result, expected);
}
#[test]
fn test_derivative_polynomial_cubic() {
let x = symbol!(x);
let expr = expr!((x ^ 3) + (3 * (x ^ 2)) + (3 * x) + 1);
let result = expr.derivative(x.clone()).simplify();
let expected = expr!((3 * (x ^ 2)) + (6 * x) + 3);
assert_eq!(result, expected);
}
#[test]
fn test_derivative_product_rule_simple() {
let x = symbol!(x);
let expr = expr!(x * x);
let result = expr.derivative(x.clone()).simplify();
let expected = expr!(2 * x);
assert_eq!(result, expected);
}
#[test]
fn test_derivative_product_rule_polynomial() {
let x = symbol!(x);
let expr = expr!((x ^ 2) * x);
let result = expr.derivative(x.clone()).simplify();
let expected = expr!(3 * (x ^ 2));
assert_eq!(result, expected);
}
#[test]
fn test_derivative_chain_rule_power() {
let x = symbol!(x);
let expr = expr!((x + 1) ^ 2);
let result = expr.derivative(x.clone()).simplify();
let expected = expr!(2 * (x + 1));
assert_eq!(result, expected);
}
#[test]
fn test_derivative_chain_rule_nested() {
let x = symbol!(x);
let expr = expr!(((x ^ 2) + 1) ^ 3);
let result = expr.derivative(x.clone()).simplify();
let expected = Expression::mul(vec![
expr!(6),
Expression::symbol(x.clone()),
expr!(((x ^ 2) + 1) ^ 2),
]);
assert_eq!(result, expected);
}
#[test]
fn test_derivative_sin() {
let x = symbol!(x);
let expr = function!(sin, Expression::symbol(x.clone()));
let result = expr.derivative(x.clone());
let expected = function!(cos, Expression::symbol(x));
assert_eq!(result, expected);
}
#[test]
fn test_derivative_cos() {
let x = symbol!(x);
let expr = function!(cos, Expression::symbol(x.clone()));
let result = expr.derivative(x.clone());
let expected = Expression::mul(vec![
Expression::integer(-1),
function!(sin, Expression::symbol(x)),
]);
assert_eq!(result, expected);
}
#[test]
fn test_derivative_exp() {
let x = symbol!(x);
let expr = function!(exp, Expression::symbol(x.clone()));
let result = expr.derivative(x.clone());
let expected = function!(exp, Expression::symbol(x));
assert_eq!(result, expected);
}
#[test]
#[ignore = "FIXME: Let's find out why"]
fn test_derivative_log() {
let x = symbol!(x);
let expr = function!(log, Expression::symbol(x.clone()));
let result = expr.derivative(x.clone());
let expected = expr!(1 / x);
assert_eq!(result, expected);
}
#[test]
fn test_derivative_sqrt() {
let x = symbol!(x);
let expr = function!(sqrt, Expression::symbol(x.clone()));
let result = expr.derivative(x.clone());
let result_str = format!("{:?}", result);
assert!(result_str.contains("2") || result_str.contains("1/2"));
}
#[test]
fn test_derivative_tan() {
let x = symbol!(x);
let expr = function!(tan, Expression::symbol(x.clone()));
let result = expr.derivative(x.clone());
let result_str = format!("{:?}", result);
assert!(result_str.contains("sec") || result_str.contains("cos"));
}
#[test]
fn test_derivative_higher_order_second() {
let x = symbol!(x);
let expr = expr!(x ^ 3);
let first = expr.derivative(x.clone());
let second = first.derivative(x.clone()).simplify();
let expected = expr!(6 * x);
assert_eq!(second, expected);
}
#[test]
fn test_derivative_higher_order_third() {
let x = symbol!(x);
let expr = expr!(x ^ 3);
let first = expr.derivative(x.clone());
let second = first.derivative(x.clone());
let third = second.derivative(x).simplify();
assert_eq!(third, expr!(6));
}
#[test]
fn test_derivative_constant_multiple() {
let x = symbol!(x);
let expr = expr!(5 * (x ^ 2));
let result = expr.derivative(x.clone()).simplify();
let expected = expr!(10 * x);
assert_eq!(result, expected);
}
#[test]
fn test_derivative_negative_power() {
let x = symbol!(x);
let expr = expr!(x ^ (-1));
let result = expr.derivative(x.clone()).simplify();
let expected = Expression::mul(vec![Expression::integer(-1), expr!(x ^ (-2))]);
assert_eq!(result, expected);
}
#[test]
fn test_derivative_rational_power() {
let x = symbol!(x);
let expr = Expression::pow(Expression::symbol(x.clone()), Expression::rational(1, 2));
let result = expr.derivative(x.clone());
let result_str = format!("{:?}", result);
assert!(result_str.contains("1") && result_str.contains("2"));
}
#[test]
fn test_derivative_multivariate_partial() {
let x = symbol!(x);
let y = symbol!(y);
let expr = expr!(x * y);
let result = expr.derivative(x).simplify();
let expected = Expression::symbol(y);
assert_eq!(result, expected);
}
#[test]
fn test_derivative_quotient_rule() {
let x = symbol!(x);
let expr = expr!(x / (x ^ 2));
let result = expr.derivative(x.clone()).simplify();
let expected = Expression::mul(vec![Expression::integer(-1), expr!(x ^ (-2))]);
assert_eq!(result, expected);
}
#[test]
fn test_derivative_sum_of_functions() {
let x = symbol!(x);
let expr = Expression::add(vec![
function!(sin, Expression::symbol(x.clone())),
function!(cos, Expression::symbol(x.clone())),
]);
let result = expr.derivative(x.clone()).simplify();
let expected = Expression::add(vec![
function!(cos, Expression::symbol(x.clone())),
Expression::mul(vec![
Expression::integer(-1),
function!(sin, Expression::symbol(x)),
]),
])
.simplify();
assert_eq!(result, expected);
}
#[test]
fn test_derivative_product_of_functions() {
let x = symbol!(x);
let expr = expr!(x * (sin(x)));
let result = expr.derivative(x.clone()).simplify();
let result_str = format!("{:?}", result);
assert!(result_str.contains("sin") && result_str.contains("cos"));
}
#[test]
fn test_derivative_zero_result() {
let x = symbol!(x);
let expr = expr!(5);
let result = expr.derivative(x);
assert_eq!(result, expr!(0));
}