use crate::calculus::derivatives::Derivative;
use crate::core::{Expression, Symbol};
use crate::simplify::Simplify;
pub struct ParametricDifferentiation;
impl ParametricDifferentiation {
pub fn first_derivative(
x_param: &Expression,
y_param: &Expression,
parameter: Symbol,
) -> Expression {
let derivatives = Self::compute_first_derivatives(x_param, y_param, parameter);
Self::create_division_inline(&derivatives.dy_dt, &derivatives.dx_dt).simplify()
}
pub fn second_derivative(
x_param: &Expression,
y_param: &Expression,
parameter: Symbol,
) -> Expression {
let first_derivs = Self::compute_first_derivatives(x_param, y_param, parameter.clone());
let dy_dx = Self::create_division_inline(&first_derivs.dy_dt, &first_derivs.dx_dt);
let d_dt_dy_dx = dy_dx.derivative(parameter);
Self::create_division_inline(&d_dt_dy_dx, &first_derivs.dx_dt).simplify()
}
pub fn arc_length_differential(
x_param: &Expression,
y_param: &Expression,
parameter: Symbol,
) -> Expression {
let derivatives = Self::compute_first_derivatives(x_param, y_param, parameter);
let sum_of_squares = Expression::add(vec![
Expression::pow(derivatives.dx_dt, Expression::integer(2)),
Expression::pow(derivatives.dy_dt, Expression::integer(2)),
]);
Expression::function("sqrt", vec![sum_of_squares]).simplify()
}
pub fn curvature(x_param: &Expression, y_param: &Expression, parameter: Symbol) -> Expression {
let derivs = Self::compute_all_derivatives(x_param, y_param, parameter);
let cross_term = Expression::add(vec![
Expression::mul(vec![derivs.dx_dt.clone(), derivs.d2y_dt2]),
Expression::mul(vec![
Expression::integer(-1),
derivs.dy_dt.clone(),
derivs.d2x_dt2,
]),
]);
let numerator = Expression::function("abs", vec![cross_term]);
let sum_of_squares = Expression::add(vec![derivs.dx_dt_sq, derivs.dy_dt_sq]);
let denominator = Expression::pow(
sum_of_squares,
Expression::mul(vec![
Expression::integer(3),
Expression::pow(Expression::integer(2), Expression::integer(-1)),
]),
);
Self::create_division_inline(&numerator, &denominator).simplify()
}
fn compute_first_derivatives(
x_param: &Expression,
y_param: &Expression,
parameter: Symbol,
) -> FirstDerivatives {
FirstDerivatives {
dx_dt: x_param.derivative(parameter.clone()),
dy_dt: y_param.derivative(parameter),
}
}
fn compute_all_derivatives(
x_param: &Expression,
y_param: &Expression,
parameter: Symbol,
) -> AllDerivatives {
let dx_dt = x_param.derivative(parameter.clone());
let dy_dt = y_param.derivative(parameter.clone());
let d2x_dt2 = dx_dt.derivative(parameter.clone());
let d2y_dt2 = dy_dt.derivative(parameter);
let dx_dt_sq = Expression::pow(dx_dt.clone(), Expression::integer(2));
let dy_dt_sq = Expression::pow(dy_dt.clone(), Expression::integer(2));
AllDerivatives {
dx_dt,
dy_dt,
d2x_dt2,
d2y_dt2,
dx_dt_sq,
dy_dt_sq,
}
}
#[inline(always)]
fn create_division_inline(numerator: &Expression, denominator: &Expression) -> Expression {
Expression::mul(vec![
numerator.clone(),
Expression::pow(denominator.clone(), Expression::integer(-1)),
])
}
}
struct FirstDerivatives {
dx_dt: Expression,
dy_dt: Expression,
}
struct AllDerivatives {
dx_dt: Expression,
dy_dt: Expression,
d2x_dt2: Expression,
d2y_dt2: Expression,
dx_dt_sq: Expression,
dy_dt_sq: Expression,
}
pub struct ParametricCurveAnalysis;
impl ParametricCurveAnalysis {
pub fn critical_points(
x_param: &Expression,
y_param: &Expression,
parameter: Symbol,
) -> Vec<Expression> {
let derivatives =
ParametricDifferentiation::compute_first_derivatives(x_param, y_param, parameter);
vec![derivatives.dy_dt, derivatives.dx_dt]
}
pub fn tangent_vector(
x_param: &Expression,
y_param: &Expression,
parameter: Symbol,
) -> (Expression, Expression) {
let derivatives =
ParametricDifferentiation::compute_first_derivatives(x_param, y_param, parameter);
(derivatives.dx_dt, derivatives.dy_dt)
}
}