1#[path = "trig_diff.rs"]
2mod trig_diff;
3
4use crate::expr::{const_, pow, Expr, ExprKind};
5use crate::rational::Rational;
6use crate::symbol::Symbol;
7
8pub fn diff(expr: Expr, var: Symbol) -> Expr {
9 let raw = diff_without_simplify(expr, var);
10 #[cfg(feature = "simplify")]
11 {
12 raw.simplify()
13 }
14 #[cfg(not(feature = "simplify"))]
15 {
16 raw
17 }
18}
19
20pub fn diff_without_simplify(expr: Expr, var: Symbol) -> Expr {
25 diff_expr(&expr, var)
26}
27
28pub(crate) fn diff_expr(e: &Expr, var: Symbol) -> Expr {
30 diff_kind(e.kind(), var)
31}
32
33fn diff_kind(kind: &ExprKind, var: Symbol) -> Expr {
34 match kind {
35 ExprKind::Const(_) => const_(Rational::zero()),
36 ExprKind::Var(s) => {
37 if *s == var {
38 const_(Rational::one())
39 } else {
40 const_(Rational::zero())
41 }
42 }
43 ExprKind::Add(a, b) => diff_expr(a, var) + diff_expr(b, var),
44 ExprKind::Sub(a, b) => diff_expr(a, var) - diff_expr(b, var),
45 ExprKind::Neg(e) => -diff_expr(e, var),
46 ExprKind::Mul(f, g) => {
47 let fp = diff_expr(f, var);
48 let gp = diff_expr(g, var);
49 fp * g.clone() + f.clone() * gp
50 }
51 ExprKind::Div(f, g) => {
52 let fp = diff_expr(f, var);
53 let gp = diff_expr(g, var);
54 let g_c = g.clone();
55 (fp * g_c.clone() - f.clone() * gp) / pow(g_c, const_(Rational::from(2)))
56 }
57 ExprKind::Pow(base, exp) => diff_pow(base, exp, var),
58 ExprKind::Sin(e) => diff_expr(e, var) * crate::expr::cos(e.clone()),
59 ExprKind::Cos(e) => -diff_expr(e, var) * crate::expr::sin(e.clone()),
60 ExprKind::Tan(e) => {
61 diff_expr(e, var) / pow(crate::expr::cos(e.clone()), const_(Rational::from(2)))
62 }
63 ExprKind::Exp(e) => diff_expr(e, var) * crate::expr::exp(e.clone()),
64 ExprKind::Ln(e) => diff_expr(e, var) / e.clone(),
65 ExprKind::Atan(e) => {
66 diff_expr(e, var) / (const_(Rational::one()) + pow(e.clone(), const_(Rational::from(2))))
67 }
68 k => trig_diff::diff_trig_kind(k, var)
69 .expect("extended trigonometric kinds are handled in trig_diff"),
70 }
71}
72
73fn diff_pow(base: &Expr, exp: &Expr, var: Symbol) -> Expr {
74 if let ExprKind::Var(s) = base.kind() {
75 if s.name() == "e" {
76 if is_var_expr(exp, var) {
77 return diff_expr(&crate::expr::exp(exp.clone()), var);
78 }
79 }
80 }
81 if let ExprKind::Const(n) = exp.kind() {
82 if let Some(n) = n.try_as_rational() {
83 if let Some(k) = n.as_integer() {
84 if k == 0 {
85 return const_(Rational::zero());
86 }
87 if k == 1 {
88 return diff_expr(base, var);
89 }
90 return const_(Rational::from(k))
91 * pow(base.clone(), const_(Rational::from(k - 1)))
92 * diff_expr(base, var);
93 }
94 }
95 }
96 let up = diff_expr(base, var);
97 let vp = diff_expr(exp, var);
98 let term1 = exp.clone() * pow(base.clone(), exp.clone() - const_(Rational::one())) * up;
99 let u_ln = base.clone();
100 let term2 = pow(base.clone(), exp.clone()) * crate::expr::ln(u_ln) * vp;
101 term1 + term2
102}
103
104fn is_var_expr(e: &Expr, var: Symbol) -> bool {
105 matches!(e.kind(), ExprKind::Var(s) if *s == var)
106}