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}