use crate::calculus::derivatives::Derivative;
use crate::core::{Expression, Number, Symbol};
use crate::simplify::Simplify;
pub struct PowerRule;
impl PowerRule {
pub fn apply(base: &Expression, exponent: &Expression, variable: Symbol) -> Expression {
match (base, exponent) {
(Expression::Symbol(sym), Expression::Number(Number::Integer(n)))
if *sym == variable =>
{
Self::simple_power_rule(*n, variable) }
_ => Self::logarithmic_differentiation(base, exponent, variable),
}
}
pub fn simple_power_rule(n: i64, variable: Symbol) -> Expression {
match n {
0 => Expression::integer(0), 1 => Expression::integer(1), _ => Expression::mul(vec![
Expression::integer(n),
Expression::pow(Expression::symbol(variable), Expression::integer(n - 1)),
]), }
}
pub fn logarithmic_differentiation(
base: &Expression,
exponent: &Expression,
variable: Symbol,
) -> Expression {
let ln_base = Expression::function("ln", vec![base.clone()]);
let exp_derivative = exponent.derivative(variable.clone());
let base_derivative = base.derivative(variable);
let original_expr = Expression::pow(base.clone(), exponent.clone());
Expression::mul(vec![
original_expr,
Expression::add(vec![
Expression::mul(vec![exp_derivative, ln_base]),
Expression::mul(vec![
exponent.clone(),
Self::div(base_derivative, base.clone()),
]),
]),
])
.simplify()
}
pub fn div(numerator: Expression, denominator: Expression) -> Expression {
Expression::div(numerator, denominator)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::symbol;
#[test]
fn test_integer_powers() {
let x = symbol!(x);
let x0 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(0));
assert_eq!(x0.derivative(x.clone()).simplify(), Expression::integer(0));
let x1 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(1));
assert_eq!(x1.derivative(x.clone()).simplify(), Expression::integer(1));
let x2 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(2));
let expected_x2 =
Expression::mul(vec![Expression::integer(2), Expression::symbol(x.clone())]);
assert_eq!(x2.derivative(x.clone()).simplify(), expected_x2.simplify());
let x3 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(3));
let expected_x3 = Expression::mul(vec![
Expression::integer(3),
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
]);
assert_eq!(x3.derivative(x.clone()).simplify(), expected_x3.simplify());
let x5 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(5));
let expected_x5 = Expression::mul(vec![
Expression::integer(5),
Expression::pow(Expression::symbol(x.clone()), Expression::integer(4)),
]);
assert_eq!(x5.derivative(x.clone()).simplify(), expected_x5.simplify());
}
#[test]
fn test_negative_powers() {
let x = symbol!(x);
let x_neg1 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(-1));
let expected_neg1 = Expression::mul(vec![
Expression::integer(-1),
Expression::pow(Expression::symbol(x.clone()), Expression::integer(-2)),
]);
assert_eq!(
x_neg1.derivative(x.clone()).simplify(),
expected_neg1.simplify()
);
let x_neg2 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(-2));
let expected_neg2 = Expression::mul(vec![
Expression::integer(-2),
Expression::pow(Expression::symbol(x.clone()), Expression::integer(-3)),
]);
assert_eq!(
x_neg2.derivative(x.clone()).simplify(),
expected_neg2.simplify()
);
let x_neg3 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(-3));
let expected_neg3 = Expression::mul(vec![
Expression::integer(-3),
Expression::pow(Expression::symbol(x.clone()), Expression::integer(-4)),
]);
assert_eq!(
x_neg3.derivative(x.clone()).simplify(),
expected_neg3.simplify()
);
}
#[test]
fn test_fractional_powers() {
let x = symbol!(x);
let sqrt_x = Expression::pow(
Expression::symbol(x.clone()),
Expression::mul(vec![
Expression::integer(1),
Expression::pow(Expression::integer(2), Expression::integer(-1)),
]),
);
let result = sqrt_x.derivative(x.clone());
assert!(!result.is_zero());
let cbrt_x = Expression::pow(
Expression::symbol(x.clone()),
Expression::mul(vec![
Expression::integer(1),
Expression::pow(Expression::integer(3), Expression::integer(-1)),
]),
);
let result_cbrt = cbrt_x.derivative(x.clone());
assert!(!result_cbrt.is_zero());
}
#[test]
fn test_variable_exponents() {
let x = symbol!(x);
let y = symbol!(y);
let x_to_y = Expression::pow(Expression::symbol(x.clone()), Expression::symbol(y.clone()));
let dx_result = x_to_y.derivative(x.clone());
let dy_result = x_to_y.derivative(y.clone());
assert!(!dx_result.is_zero());
assert!(!dy_result.is_zero());
let y_to_x = Expression::pow(Expression::symbol(y.clone()), Expression::symbol(x.clone()));
let dx_y_to_x = y_to_x.derivative(x.clone());
let dy_y_to_x = y_to_x.derivative(y.clone());
assert!(!dx_y_to_x.is_zero());
assert!(!dy_y_to_x.is_zero());
}
#[test]
fn test_special_cases() {
let x = symbol!(x);
let x_to_x = Expression::pow(Expression::symbol(x.clone()), Expression::symbol(x.clone()));
let result = x_to_x.derivative(x.clone());
assert!(!result.is_zero());
let two_to_x = Expression::pow(Expression::integer(2), Expression::symbol(x.clone()));
let result_2x = two_to_x.derivative(x.clone());
assert!(!result_2x.is_zero());
let x_to_pi = Expression::pow(
Expression::symbol(x.clone()),
Expression::constant(crate::MathConstant::Pi),
);
let result_x_pi = x_to_pi.derivative(x.clone());
assert!(!result_x_pi.is_zero());
}
}