mathhook_core/calculus/derivatives/advanced_differentiation/
parametric.rs

1//! Parametric differentiation for parametrically defined curves
2//!
3//! Handles differentiation of curves defined parametrically as x = f(t), y = g(t)
4//! using the chain rule: dy/dx = (dy/dt) / (dx/dt)
5
6use crate::calculus::derivatives::Derivative;
7use crate::core::{Expression, Symbol};
8use crate::simplify::Simplify;
9
10/// Parametric differentiation operations
11pub struct ParametricDifferentiation;
12
13impl ParametricDifferentiation {
14    /// Compute dy/dx for parametric curve with cached derivatives
15    ///
16    /// Uses formula: dy/dx = (dy/dt) / (dx/dt)
17    ///
18    /// # Examples
19    ///
20    /// ```rust
21    /// use mathhook_core::simplify::Simplify;
22    /// use mathhook_core::calculus::derivatives::Derivative;
23    /// use mathhook_core::{Expression};
24    /// use mathhook_core::symbol;
25    /// use mathhook_core::calculus::derivatives::ParametricDifferentiation;
26    ///
27    /// let t = symbol!(t);
28    /// let x_param = Expression::function("cos", vec![Expression::symbol(t.clone())]);
29    /// let y_param = Expression::function("sin", vec![Expression::symbol(t.clone())]);
30    /// let dy_dx = ParametricDifferentiation::first_derivative(&x_param, &y_param, t);
31    /// ```
32    pub fn first_derivative(
33        x_param: &Expression,
34        y_param: &Expression,
35        parameter: Symbol,
36    ) -> Expression {
37        let derivatives = Self::compute_first_derivatives(x_param, y_param, parameter);
38        Self::create_division_inline(&derivatives.dy_dt, &derivatives.dx_dt).simplify()
39    }
40
41    /// Compute d²y/dx² for parametric curves
42    ///
43    /// Uses formula: d²y/dx² = (d/dt(dy/dx)) / (dx/dt)
44    ///
45    /// # Examples
46    ///
47    /// ```rust
48    /// use mathhook_core::{Expression};
49    /// use mathhook_core::symbol;
50    /// use mathhook_core::calculus::derivatives::ParametricDifferentiation;
51    ///
52    /// let t = symbol!(t);
53    /// let x_param = Expression::symbol(t.clone());
54    /// let y_param = Expression::pow(Expression::symbol(t.clone()), Expression::integer(2));
55    /// let d2y_dx2 = ParametricDifferentiation::second_derivative(&x_param, &y_param, t);
56    /// ```
57    pub fn second_derivative(
58        x_param: &Expression,
59        y_param: &Expression,
60        parameter: Symbol,
61    ) -> Expression {
62        let first_derivs = Self::compute_first_derivatives(x_param, y_param, parameter.clone());
63
64        let dy_dx = Self::create_division_inline(&first_derivs.dy_dt, &first_derivs.dx_dt);
65
66        let d_dt_dy_dx = dy_dx.derivative(parameter);
67
68        Self::create_division_inline(&d_dt_dy_dx, &first_derivs.dx_dt).simplify()
69    }
70
71    /// Compute arc length differential
72    ///
73    /// Formula: ds = √((dx/dt)² + (dy/dt)²)
74    ///
75    /// # Examples
76    ///
77    /// ```rust
78    /// use mathhook_core::simplify::Simplify;
79    /// use mathhook_core::{Expression};
80    /// use mathhook_core::symbol;
81    /// use mathhook_core::calculus::derivatives::ParametricDifferentiation;
82    ///
83    /// let t = symbol!(t);
84    /// let x_param = Expression::symbol(t.clone());
85    /// let y_param = Expression::pow(Expression::symbol(t.clone()), Expression::integer(2));
86    /// let arc_length_diff = ParametricDifferentiation::arc_length_differential(&x_param, &y_param, t);
87    /// ```
88    pub fn arc_length_differential(
89        x_param: &Expression,
90        y_param: &Expression,
91        parameter: Symbol,
92    ) -> Expression {
93        let derivatives = Self::compute_first_derivatives(x_param, y_param, parameter);
94
95        let sum_of_squares = Expression::add(vec![
96            Expression::pow(derivatives.dx_dt, Expression::integer(2)),
97            Expression::pow(derivatives.dy_dt, Expression::integer(2)),
98        ]);
99
100        Expression::function("sqrt", vec![sum_of_squares]).simplify()
101    }
102
103    /// Compute curvature for parametric curves
104    ///
105    /// Formula: κ = |x'y'' - y'x''| / (x'² + y'²)^(3/2)
106    ///
107    /// # Examples
108    ///
109    /// ```rust
110    /// use mathhook_core::calculus::derivatives::Derivative;
111    /// use mathhook_core::{Expression};
112    /// use mathhook_core::symbol;
113    /// use mathhook_core::calculus::derivatives::ParametricDifferentiation;
114    ///
115    /// let t = symbol!(t);
116    /// let x_param = Expression::function("cos", vec![Expression::symbol(t.clone())]);
117    /// let y_param = Expression::function("sin", vec![Expression::symbol(t.clone())]);
118    /// let curvature = ParametricDifferentiation::curvature(&x_param, &y_param, t);
119    /// ```
120    pub fn curvature(x_param: &Expression, y_param: &Expression, parameter: Symbol) -> Expression {
121        let derivs = Self::compute_all_derivatives(x_param, y_param, parameter);
122
123        let cross_term = Expression::add(vec![
124            Expression::mul(vec![derivs.dx_dt.clone(), derivs.d2y_dt2]),
125            Expression::mul(vec![
126                Expression::integer(-1),
127                derivs.dy_dt.clone(),
128                derivs.d2x_dt2,
129            ]),
130        ]);
131        let numerator = Expression::function("abs", vec![cross_term]);
132
133        let sum_of_squares = Expression::add(vec![derivs.dx_dt_sq, derivs.dy_dt_sq]);
134        let denominator = Expression::pow(
135            sum_of_squares,
136            Expression::mul(vec![
137                Expression::integer(3),
138                Expression::pow(Expression::integer(2), Expression::integer(-1)),
139            ]),
140        );
141
142        Self::create_division_inline(&numerator, &denominator).simplify()
143    }
144
145    /// Compute first derivatives once
146    fn compute_first_derivatives(
147        x_param: &Expression,
148        y_param: &Expression,
149        parameter: Symbol,
150    ) -> FirstDerivatives {
151        FirstDerivatives {
152            dx_dt: x_param.derivative(parameter.clone()),
153            dy_dt: y_param.derivative(parameter),
154        }
155    }
156
157    /// Compute all derivatives needed for curvature
158    fn compute_all_derivatives(
159        x_param: &Expression,
160        y_param: &Expression,
161        parameter: Symbol,
162    ) -> AllDerivatives {
163        let dx_dt = x_param.derivative(parameter.clone());
164        let dy_dt = y_param.derivative(parameter.clone());
165
166        let d2x_dt2 = dx_dt.derivative(parameter.clone());
167        let d2y_dt2 = dy_dt.derivative(parameter);
168
169        let dx_dt_sq = Expression::pow(dx_dt.clone(), Expression::integer(2));
170        let dy_dt_sq = Expression::pow(dy_dt.clone(), Expression::integer(2));
171
172        AllDerivatives {
173            dx_dt,
174            dy_dt,
175            d2x_dt2,
176            d2y_dt2,
177            dx_dt_sq,
178            dy_dt_sq,
179        }
180    }
181
182    /// Inlined division creation
183    #[inline(always)]
184    fn create_division_inline(numerator: &Expression, denominator: &Expression) -> Expression {
185        Expression::mul(vec![
186            numerator.clone(),
187            Expression::pow(denominator.clone(), Expression::integer(-1)),
188        ])
189    }
190}
191
192/// Cached first derivatives
193struct FirstDerivatives {
194    dx_dt: Expression,
195    dy_dt: Expression,
196}
197
198/// Cached all derivatives for curvature computation
199struct AllDerivatives {
200    dx_dt: Expression,
201    dy_dt: Expression,
202    d2x_dt2: Expression,
203    d2y_dt2: Expression,
204    dx_dt_sq: Expression,
205    dy_dt_sq: Expression,
206}
207
208/// Parametric curve analysis
209pub struct ParametricCurveAnalysis;
210
211impl ParametricCurveAnalysis {
212    /// Find critical points where dy/dx = 0 or undefined
213    ///
214    /// # Examples
215    ///
216    /// ```rust
217    /// use mathhook_core::{Expression};
218    /// use mathhook_core::symbol;
219    /// use mathhook_core::calculus::derivatives::ParametricCurveAnalysis;
220    ///
221    /// let t = symbol!(t);
222    /// let x_param = Expression::pow(Expression::symbol(t.clone()), Expression::integer(2));
223    /// let y_param = Expression::pow(Expression::symbol(t.clone()), Expression::integer(3));
224    /// let critical_t = ParametricCurveAnalysis::critical_points(&x_param, &y_param, t);
225    /// ```
226    pub fn critical_points(
227        x_param: &Expression,
228        y_param: &Expression,
229        parameter: Symbol,
230    ) -> Vec<Expression> {
231        let derivatives =
232            ParametricDifferentiation::compute_first_derivatives(x_param, y_param, parameter);
233        vec![derivatives.dy_dt, derivatives.dx_dt]
234    }
235
236    /// Analyze tangent vector at parameter value
237    ///
238    /// # Examples
239    ///
240    /// ```rust
241    /// use mathhook_core::{Expression};
242    /// use mathhook_core::symbol;
243    /// use mathhook_core::calculus::derivatives::ParametricCurveAnalysis;
244    ///
245    /// let t = symbol!(t);
246    /// let x_param = Expression::symbol(t.clone());
247    /// let y_param = Expression::pow(Expression::symbol(t.clone()), Expression::integer(2));
248    /// let tangent = ParametricCurveAnalysis::tangent_vector(&x_param, &y_param, t);
249    /// ```
250    pub fn tangent_vector(
251        x_param: &Expression,
252        y_param: &Expression,
253        parameter: Symbol,
254    ) -> (Expression, Expression) {
255        let derivatives =
256            ParametricDifferentiation::compute_first_derivatives(x_param, y_param, parameter);
257        (derivatives.dx_dt, derivatives.dy_dt)
258    }
259}