1use crate::calculus::derivatives::{Derivative, FunctionDerivatives};
4use crate::core::{Expression, Symbol};
5use crate::educational::message_registry::{MessageBuilder, MessageCategory, MessageType};
6use crate::educational::step_by_step::{Step, StepByStepExplanation};
7use crate::formatter::latex::LaTeXFormatter;
8use crate::simplify::Simplify;
9
10use super::format_expr;
11
12pub fn explain_chain_rule(
14 func_name: &str,
15 arg: &Expression,
16 variable: &Symbol,
17) -> StepByStepExplanation {
18 let mut steps = Vec::new();
19 let expr = Expression::function(func_name, vec![arg.clone()]);
20
21 steps.push(Step {
22 title: "Identify Composite Function".to_owned(),
23 description: format!(
24 "Outer function: {}(u)\nInner function: u = {}",
25 func_name,
26 format_expr(arg)
27 ),
28 expression: expr.clone(),
29 rule_applied: "Identification".to_owned(),
30 latex: Some(expr.to_latex(None).unwrap_or_else(|_| "f(g(x))".to_owned())),
31 });
32
33 if let Some(step) = MessageBuilder::new(
34 MessageCategory::Calculus,
35 MessageType::DerivativeChainRule,
36 0,
37 )
38 .with_substitution("outer_function", func_name)
39 .with_substitution("inner_function", format_expr(arg))
40 .build()
41 {
42 steps.push(step);
43 }
44
45 steps.push(Step {
46 title: "State Chain Rule".to_owned(),
47 description: "d/dx[f(g(x))] = f'(g(x)) * g'(x)".to_owned(),
48 expression: expr.clone(),
49 rule_applied: "Chain Rule".to_owned(),
50 latex: Some("f'(g(x)) \\cdot g'(x)".to_owned()),
51 });
52
53 let outer_derivative = FunctionDerivatives::get(func_name, arg, variable.clone());
54
55 steps.push(Step {
56 title: "Differentiate Outer Function".to_owned(),
57 description: format!(
58 "d/du[{}(u)] = {}\nEvaluated at u = {}: {}",
59 func_name,
60 func_name,
61 format_expr(arg),
62 format_expr(&outer_derivative)
63 ),
64 expression: outer_derivative.clone(),
65 rule_applied: "Outer Derivative".to_owned(),
66 latex: Some(
67 outer_derivative
68 .to_latex(None)
69 .unwrap_or_else(|_| "f'(u)".to_owned()),
70 ),
71 });
72
73 let inner_derivative = arg.derivative(variable.clone());
74 steps.push(Step {
75 title: "Differentiate Inner Function".to_owned(),
76 description: format!(
77 "d/d{}[{}] = {}",
78 variable.name(),
79 format_expr(arg),
80 format_expr(&inner_derivative)
81 ),
82 expression: inner_derivative.clone(),
83 rule_applied: "Inner Derivative".to_owned(),
84 latex: Some(
85 inner_derivative
86 .to_latex(None)
87 .unwrap_or_else(|_| "g'(x)".to_owned()),
88 ),
89 });
90
91 let result = Expression::mul(vec![outer_derivative, inner_derivative]).simplify();
92 steps.push(Step {
93 title: "Multiply Results".to_owned(),
94 description: format!("Result: {}", format_expr(&result)),
95 expression: result.clone(),
96 rule_applied: "Chain Rule Application".to_owned(),
97 latex: Some(
98 result
99 .to_latex(None)
100 .unwrap_or_else(|_| "result".to_owned()),
101 ),
102 });
103
104 let step_count = steps.len();
105 StepByStepExplanation {
106 initial_expression: expr,
107 final_expression: result,
108 steps,
109 total_steps: step_count,
110 rules_used: vec!["Chain Rule".to_owned()],
111 }
112}
113
114pub fn explain_product_rule(
116 first: &Expression,
117 second: &Expression,
118 variable: &Symbol,
119) -> StepByStepExplanation {
120 let mut steps = Vec::new();
121 let expr = Expression::mul(vec![first.clone(), second.clone()]);
122
123 steps.push(Step {
124 title: "Identify Product".to_owned(),
125 description: format!(
126 "Two functions multiplied:\nf(x) = {}\ng(x) = {}",
127 format_expr(first),
128 format_expr(second)
129 ),
130 expression: expr.clone(),
131 rule_applied: "Identification".to_owned(),
132 latex: Some(expr.to_latex(None).unwrap_or_else(|_| "f*g".to_owned())),
133 });
134
135 if let Some(step) = MessageBuilder::new(
136 MessageCategory::Calculus,
137 MessageType::DerivativeProductRule,
138 0,
139 )
140 .with_substitution("first_function", format_expr(first))
141 .with_substitution("second_function", format_expr(second))
142 .build()
143 {
144 steps.push(step);
145 }
146
147 steps.push(Step {
148 title: "State Product Rule".to_owned(),
149 description: "d/dx[f*g] = f'*g + f*g'".to_owned(),
150 expression: expr.clone(),
151 rule_applied: "Product Rule".to_owned(),
152 latex: Some("f' \\cdot g + f \\cdot g'".to_owned()),
153 });
154
155 let first_derivative = first.derivative(variable.clone());
156 steps.push(Step {
157 title: "Differentiate First Function".to_owned(),
158 description: format!("f'(x) = {}", format_expr(&first_derivative)),
159 expression: first_derivative.clone(),
160 rule_applied: "First Derivative".to_owned(),
161 latex: Some(
162 first_derivative
163 .to_latex(None)
164 .unwrap_or_else(|_| "f'".to_owned()),
165 ),
166 });
167
168 let second_derivative = second.derivative(variable.clone());
169 steps.push(Step {
170 title: "Differentiate Second Function".to_owned(),
171 description: format!("g'(x) = {}", format_expr(&second_derivative)),
172 expression: second_derivative.clone(),
173 rule_applied: "Second Derivative".to_owned(),
174 latex: Some(
175 second_derivative
176 .to_latex(None)
177 .unwrap_or_else(|_| "g'".to_owned()),
178 ),
179 });
180
181 let result = Expression::add(vec![
182 Expression::mul(vec![first_derivative, second.clone()]),
183 Expression::mul(vec![first.clone(), second_derivative]),
184 ])
185 .simplify();
186
187 steps.push(Step {
188 title: "Apply Product Rule Formula".to_owned(),
189 description: format!("f'*g + f*g' = {}", format_expr(&result)),
190 expression: result.clone(),
191 rule_applied: "Product Rule Application".to_owned(),
192 latex: Some(
193 result
194 .to_latex(None)
195 .unwrap_or_else(|_| "result".to_owned()),
196 ),
197 });
198
199 let step_count = steps.len();
200 StepByStepExplanation {
201 initial_expression: expr,
202 final_expression: result,
203 steps,
204 total_steps: step_count,
205 rules_used: vec!["Product Rule".to_owned()],
206 }
207}
208
209pub fn explain_quotient_rule(
211 numerator: &Expression,
212 denominator: &Expression,
213 variable: &Symbol,
214) -> StepByStepExplanation {
215 let mut steps = Vec::new();
216
217 let expr = Expression::mul(vec![
218 numerator.clone(),
219 Expression::pow(denominator.clone(), Expression::integer(-1)),
220 ]);
221
222 steps.push(Step {
223 title: "Identify Quotient".to_owned(),
224 description: format!(
225 "Numerator: {}\nDenominator: {}",
226 format_expr(numerator),
227 format_expr(denominator)
228 ),
229 expression: expr.clone(),
230 rule_applied: "Identification".to_owned(),
231 latex: Some(format!(
232 "\\frac{{{}}}{{{}}}",
233 numerator.to_latex(None).unwrap_or_else(|_| "f".to_owned()),
234 denominator
235 .to_latex(None)
236 .unwrap_or_else(|_| "g".to_owned())
237 )),
238 });
239
240 if let Some(step) = MessageBuilder::new(
241 MessageCategory::Calculus,
242 MessageType::DerivativeQuotientRule,
243 0,
244 )
245 .with_substitution("numerator", format_expr(numerator))
246 .with_substitution("denominator", format_expr(denominator))
247 .build()
248 {
249 steps.push(step);
250 }
251
252 steps.push(Step {
253 title: "State Quotient Rule".to_owned(),
254 description: "d/dx[f/g] = (f'*g - f*g') / g^2".to_owned(),
255 expression: expr.clone(),
256 rule_applied: "Quotient Rule".to_owned(),
257 latex: Some("\\frac{f' \\cdot g - f \\cdot g'}{g^2}".to_owned()),
258 });
259
260 let numerator_derivative = numerator.derivative(variable.clone());
261 steps.push(Step {
262 title: "Differentiate Numerator".to_owned(),
263 description: format!("f'(x) = {}", format_expr(&numerator_derivative)),
264 expression: numerator_derivative.clone(),
265 rule_applied: "Numerator Derivative".to_owned(),
266 latex: Some(
267 numerator_derivative
268 .to_latex(None)
269 .unwrap_or_else(|_| "f'".to_owned()),
270 ),
271 });
272
273 let denominator_derivative = denominator.derivative(variable.clone());
274 steps.push(Step {
275 title: "Differentiate Denominator".to_owned(),
276 description: format!("g'(x) = {}", format_expr(&denominator_derivative)),
277 expression: denominator_derivative.clone(),
278 rule_applied: "Denominator Derivative".to_owned(),
279 latex: Some(
280 denominator_derivative
281 .to_latex(None)
282 .unwrap_or_else(|_| "g'".to_owned()),
283 ),
284 });
285
286 let result_numerator = Expression::add(vec![
287 Expression::mul(vec![numerator_derivative, denominator.clone()]),
288 Expression::mul(vec![
289 Expression::integer(-1),
290 numerator.clone(),
291 denominator_derivative,
292 ]),
293 ])
294 .simplify();
295
296 steps.push(Step {
297 title: "Apply Quotient Rule Formula".to_owned(),
298 description: format!("(f'*g - f*g') = {}", format_expr(&result_numerator)),
299 expression: result_numerator.clone(),
300 rule_applied: "Numerator Calculation".to_owned(),
301 latex: Some(
302 result_numerator
303 .to_latex(None)
304 .unwrap_or_else(|_| "result_num".to_owned()),
305 ),
306 });
307
308 let result = Expression::mul(vec![
309 result_numerator,
310 Expression::pow(denominator.clone(), Expression::integer(-2)),
311 ])
312 .simplify();
313
314 steps.push(Step {
315 title: "Simplify".to_owned(),
316 description: format!("Result: {}", format_expr(&result)),
317 expression: result.clone(),
318 rule_applied: "Quotient Rule Application".to_owned(),
319 latex: Some(
320 result
321 .to_latex(None)
322 .unwrap_or_else(|_| "result".to_owned()),
323 ),
324 });
325
326 let step_count = steps.len();
327 StepByStepExplanation {
328 initial_expression: expr,
329 final_expression: result,
330 steps,
331 total_steps: step_count,
332 rules_used: vec!["Quotient Rule".to_owned()],
333 }
334}