mathhook_core/calculus/derivatives/
power_rule.rs

1//! Power rule implementation for derivatives
2
3use crate::calculus::derivatives::Derivative;
4use crate::core::{Expression, Number, Symbol};
5use crate::simplify::Simplify;
6
7/// Power rule implementation
8pub struct PowerRule;
9
10impl PowerRule {
11    /// Apply power rule and chain rule for power expressions
12    ///
13    /// # Examples
14    ///
15    /// ```rust
16    /// use mathhook_core::simplify::Simplify;
17    /// use mathhook_core::calculus::derivatives::Derivative;
18    /// use mathhook_core::{Expression, PowerRule};
19    /// use mathhook_core::symbol;
20    ///
21    /// let x = symbol!(x);
22    /// let base = Expression::symbol(x.clone());
23    /// let exponent = Expression::integer(2);
24    /// let result = PowerRule::apply(&base, &exponent, x);
25    /// ```
26    pub fn apply(base: &Expression, exponent: &Expression, variable: Symbol) -> Expression {
27        match (base, exponent) {
28            (Expression::Symbol(sym), Expression::Number(Number::Integer(n)))
29                if *sym == variable =>
30            {
31                Self::simple_power_rule(*n, variable) // d/dx[x^n] = nx^(n-1)
32            }
33            _ => Self::logarithmic_differentiation(base, exponent, variable),
34        }
35    }
36
37    /// Handle simple power rule for symbol raised to integer power
38    ///
39    /// # Examples
40    ///
41    /// ```rust
42    /// use mathhook_core::{Expression, PowerRule};
43    /// use mathhook_core::symbol;
44    ///
45    /// let x = symbol!(x);
46    /// let result = PowerRule::simple_power_rule(3, x);
47    /// ```
48    pub fn simple_power_rule(n: i64, variable: Symbol) -> Expression {
49        match n {
50            0 => Expression::integer(0), // d/dx[x^0] = d/dx[1] = 0
51            1 => Expression::integer(1), // d/dx[x^1] = d/dx[x] = 1
52            _ => Expression::mul(vec![
53                Expression::integer(n),
54                Expression::pow(Expression::symbol(variable), Expression::integer(n - 1)),
55            ]), // d/dx[x^n] = nx^(n-1)
56        }
57    }
58
59    /// Handle general power using logarithmic differentiation
60    ///
61    /// # Examples
62    ///
63    /// ```rust
64    /// use mathhook_core::{Expression, symbol};
65    /// use mathhook_core::calculus::derivatives::PowerRule;
66    ///
67    /// let x = symbol!(x);
68    /// let base = Expression::function("sin", vec![Expression::symbol(x.clone())]);
69    /// let exponent = Expression::symbol(x.clone());
70    /// let result = PowerRule::logarithmic_differentiation(&base, &exponent, x.clone());
71    /// ```
72    pub fn logarithmic_differentiation(
73        base: &Expression,
74        exponent: &Expression,
75        variable: Symbol,
76    ) -> Expression {
77        let ln_base = Expression::function("ln", vec![base.clone()]);
78        let exp_derivative = exponent.derivative(variable.clone());
79        let base_derivative = base.derivative(variable);
80
81        let original_expr = Expression::pow(base.clone(), exponent.clone());
82
83        // d/dx[f^g] = f^g * (g'ln(f) + g*f'/f)
84        Expression::mul(vec![
85            original_expr,
86            Expression::add(vec![
87                Expression::mul(vec![exp_derivative, ln_base]),
88                Expression::mul(vec![
89                    exponent.clone(),
90                    Self::div(base_derivative, base.clone()),
91                ]),
92            ]),
93        ])
94        .simplify()
95    }
96
97    /// Create division expression helper for derivatives
98    ///
99    /// Uses the symbolic division constructor since derivatives are symbolic operations.
100    ///
101    /// # Examples
102    ///
103    /// ```rust
104    /// use mathhook_core::{Expression, symbol};
105    /// use mathhook_core::calculus::derivatives::PowerRule;
106    ///
107    /// let x = symbol!(x);
108    /// let numerator = Expression::integer(1);
109    /// let denominator = Expression::symbol(x);
110    /// let division = PowerRule::div(numerator, denominator);
111    /// ```
112    pub fn div(numerator: Expression, denominator: Expression) -> Expression {
113        Expression::div(numerator, denominator)
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120    use crate::symbol;
121
122    #[test]
123    fn test_integer_powers() {
124        let x = symbol!(x);
125
126        // d/dx[x^0] = 0
127        let x0 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(0));
128        assert_eq!(x0.derivative(x.clone()).simplify(), Expression::integer(0));
129
130        // d/dx[x^1] = 1
131        let x1 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(1));
132        assert_eq!(x1.derivative(x.clone()).simplify(), Expression::integer(1));
133
134        // d/dx[x^2] = 2x
135        let x2 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(2));
136        let expected_x2 =
137            Expression::mul(vec![Expression::integer(2), Expression::symbol(x.clone())]);
138        assert_eq!(x2.derivative(x.clone()).simplify(), expected_x2.simplify());
139
140        // d/dx[x^3] = 3x^2
141        let x3 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(3));
142        let expected_x3 = Expression::mul(vec![
143            Expression::integer(3),
144            Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
145        ]);
146        assert_eq!(x3.derivative(x.clone()).simplify(), expected_x3.simplify());
147
148        // d/dx[x^5] = 5x^4
149        let x5 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(5));
150        let expected_x5 = Expression::mul(vec![
151            Expression::integer(5),
152            Expression::pow(Expression::symbol(x.clone()), Expression::integer(4)),
153        ]);
154        assert_eq!(x5.derivative(x.clone()).simplify(), expected_x5.simplify());
155    }
156
157    #[test]
158    fn test_negative_powers() {
159        let x = symbol!(x);
160
161        // d/dx[x^(-1)] = -x^(-2)
162        let x_neg1 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(-1));
163        let expected_neg1 = Expression::mul(vec![
164            Expression::integer(-1),
165            Expression::pow(Expression::symbol(x.clone()), Expression::integer(-2)),
166        ]);
167        assert_eq!(
168            x_neg1.derivative(x.clone()).simplify(),
169            expected_neg1.simplify()
170        );
171
172        // d/dx[x^(-2)] = -2x^(-3)
173        let x_neg2 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(-2));
174        let expected_neg2 = Expression::mul(vec![
175            Expression::integer(-2),
176            Expression::pow(Expression::symbol(x.clone()), Expression::integer(-3)),
177        ]);
178        assert_eq!(
179            x_neg2.derivative(x.clone()).simplify(),
180            expected_neg2.simplify()
181        );
182
183        // d/dx[x^(-3)] = -3x^(-4)
184        let x_neg3 = Expression::pow(Expression::symbol(x.clone()), Expression::integer(-3));
185        let expected_neg3 = Expression::mul(vec![
186            Expression::integer(-3),
187            Expression::pow(Expression::symbol(x.clone()), Expression::integer(-4)),
188        ]);
189        assert_eq!(
190            x_neg3.derivative(x.clone()).simplify(),
191            expected_neg3.simplify()
192        );
193    }
194
195    #[test]
196    fn test_fractional_powers() {
197        let x = symbol!(x);
198
199        // d/dx[x^(1/2)] = (1/2)x^(-1/2)
200        let sqrt_x = Expression::pow(
201            Expression::symbol(x.clone()),
202            Expression::mul(vec![
203                Expression::integer(1),
204                Expression::pow(Expression::integer(2), Expression::integer(-1)),
205            ]),
206        );
207        let result = sqrt_x.derivative(x.clone());
208        assert!(!result.is_zero());
209
210        // d/dx[x^(1/3)] = (1/3)x^(-2/3)
211        let cbrt_x = Expression::pow(
212            Expression::symbol(x.clone()),
213            Expression::mul(vec![
214                Expression::integer(1),
215                Expression::pow(Expression::integer(3), Expression::integer(-1)),
216            ]),
217        );
218        let result_cbrt = cbrt_x.derivative(x.clone());
219        assert!(!result_cbrt.is_zero());
220    }
221
222    #[test]
223    fn test_variable_exponents() {
224        let x = symbol!(x);
225        let y = symbol!(y);
226
227        // d/dx[x^y] and d/dy[x^y]
228        let x_to_y = Expression::pow(Expression::symbol(x.clone()), Expression::symbol(y.clone()));
229        let dx_result = x_to_y.derivative(x.clone());
230        let dy_result = x_to_y.derivative(y.clone());
231
232        assert!(!dx_result.is_zero());
233        assert!(!dy_result.is_zero());
234
235        // d/dx[y^x] and d/dy[y^x]
236        let y_to_x = Expression::pow(Expression::symbol(y.clone()), Expression::symbol(x.clone()));
237        let dx_y_to_x = y_to_x.derivative(x.clone());
238        let dy_y_to_x = y_to_x.derivative(y.clone());
239
240        assert!(!dx_y_to_x.is_zero());
241        assert!(!dy_y_to_x.is_zero());
242    }
243
244    #[test]
245    fn test_special_cases() {
246        let x = symbol!(x);
247
248        // d/dx[x^x]
249        let x_to_x = Expression::pow(Expression::symbol(x.clone()), Expression::symbol(x.clone()));
250        let result = x_to_x.derivative(x.clone());
251        assert!(!result.is_zero());
252
253        // d/dx[2^x]
254        let two_to_x = Expression::pow(Expression::integer(2), Expression::symbol(x.clone()));
255        let result_2x = two_to_x.derivative(x.clone());
256        assert!(!result_2x.is_zero());
257
258        // d/dx[x^π]
259        let x_to_pi = Expression::pow(
260            Expression::symbol(x.clone()),
261            Expression::constant(crate::MathConstant::Pi),
262        );
263        let result_x_pi = x_to_pi.derivative(x.clone());
264        assert!(!result_x_pi.is_zero());
265    }
266}