mathhook_core/calculus/integrals/
basic.rs1use crate::calculus::integrals::strategy::integrate_with_strategy;
6use crate::core::{Expression, Number, Symbol};
7use crate::simplify::Simplify;
8use num_rational::BigRational;
9use num_traits::Zero;
10pub struct BasicIntegrals;
12impl BasicIntegrals {
13 pub fn handle_calculus(
26 expr: &Expression,
27 data: &crate::core::expression::CalculusData,
28 variable: Symbol,
29 ) -> Expression {
30 match data {
31 crate::core::expression::CalculusData::Integral {
32 variable: var,
33 bounds,
34 ..
35 } => {
36 if *var == variable && bounds.is_none() {
37 expr.clone()
38 } else {
39 Expression::integral(expr.clone(), variable)
40 }
41 }
42 _ => Expression::integral(expr.clone(), variable),
43 }
44 }
45 pub fn handle_constant(expr: &Expression, variable: Symbol) -> Expression {
58 Expression::mul(vec![expr.clone(), Expression::symbol(variable)])
59 }
60 pub fn handle_symbol(sym: &Symbol, variable: &Symbol) -> Expression {
74 if sym == variable {
75 Expression::mul(vec![
76 Expression::mul(vec![
77 Expression::integer(1),
78 Expression::pow(Expression::integer(2), Expression::integer(-1)),
79 ]),
80 Expression::pow(Expression::symbol(variable.clone()), Expression::integer(2)),
81 ])
82 } else {
83 Expression::mul(vec![
84 Expression::symbol(sym.clone()),
85 Expression::symbol(variable.clone()),
86 ])
87 }
88 }
89 pub fn handle_sum(terms: &[Expression], variable: &Symbol, depth: usize) -> Expression {
109 let integrals: Vec<Expression> = terms
110 .iter()
111 .map(|term| integrate_with_strategy(term, variable.clone(), depth + 1))
112 .collect();
113 Expression::add(integrals).simplify()
114 }
115 pub fn handle_product(factors: &[Expression], variable: Symbol, depth: usize) -> Expression {
136 let (constants, variables): (Vec<_>, Vec<_>) = factors
137 .iter()
138 .partition(|f| Self::is_constant_wrt(f, &variable));
139 if variables.is_empty() {
140 return Expression::mul(vec![
141 Expression::mul(factors.to_vec()),
142 Expression::symbol(variable),
143 ]);
144 }
145 if variables.len() == 1 {
146 let constant_part = if constants.is_empty() {
147 Expression::integer(1)
148 } else {
149 Expression::mul(constants.into_iter().cloned().collect())
150 };
151 let integrated_variable =
152 integrate_with_strategy(variables[0], variable.clone(), depth + 1);
153 let result = Expression::mul(vec![constant_part, integrated_variable]);
154 let simplified = result.simplify();
155 return simplified;
156 }
157 Expression::integral(Expression::mul(factors.to_vec()), variable)
158 }
159 pub fn handle_power(base: &Expression, exp: &Expression, variable: Symbol) -> Expression {
186 if let (Expression::Symbol(sym), Expression::Number(Number::Integer(n))) = (base, exp) {
187 if *sym == variable {
188 if *n == -1 {
189 Expression::function(
190 "ln",
191 vec![Expression::function(
192 "abs",
193 vec![Expression::symbol(variable)],
194 )],
195 )
196 } else {
197 let new_exp = Expression::integer(n + 1);
198 let coefficient = Expression::mul(vec![
199 Expression::integer(1),
200 Expression::pow(Expression::integer(n + 1), Expression::integer(-1)),
201 ]);
202 Expression::mul(vec![
203 coefficient,
204 Expression::pow(Expression::symbol(variable), new_exp),
205 ])
206 }
207 } else {
208 Expression::mul(vec![
209 Expression::pow(base.clone(), exp.clone()),
210 Expression::symbol(variable),
211 ])
212 }
213 } else if let (Expression::Symbol(sym), Expression::Number(Number::Rational(r))) =
214 (base, exp)
215 {
216 if *sym == variable {
217 let p = r.numer();
218 let q = r.denom();
219 let p_plus_q = p + q;
220 if p_plus_q.is_zero() {
221 Expression::function(
222 "ln",
223 vec![Expression::function(
224 "abs",
225 vec![Expression::symbol(variable)],
226 )],
227 )
228 } else {
229 let new_exp_num = p_plus_q.clone();
230 let new_exp_denom = q.clone();
231 let new_exp_rational =
232 BigRational::new(new_exp_num.clone(), new_exp_denom.clone());
233 let coefficient_rational = BigRational::new(new_exp_denom, new_exp_num.clone());
234 let coefficient = Expression::Number(Number::rational(coefficient_rational));
235 let new_exp = Expression::Number(Number::rational(new_exp_rational));
236 Expression::mul(vec![
237 coefficient,
238 Expression::pow(Expression::symbol(variable), new_exp),
239 ])
240 }
241 } else {
242 Expression::mul(vec![
243 Expression::pow(base.clone(), exp.clone()),
244 Expression::symbol(variable),
245 ])
246 }
247 } else {
248 Expression::mul(vec![
249 Expression::pow(base.clone(), exp.clone()),
250 Expression::symbol(variable),
251 ])
252 }
253 }
254 fn is_constant_wrt(expr: &Expression, variable: &Symbol) -> bool {
255 !expr.find_variables().contains(variable)
256 }
257}
258#[cfg(test)]
259mod tests {
260 use super::*;
261 use crate::calculus::integrals::Integration;
262 use crate::symbol;
263 #[test]
264 fn test_basic_constant_integration() {
265 let x = symbol!(x);
266 let expr = Expression::integer(5);
267 let result = expr.integrate(x.clone(), 0);
268 println!("Integration result: {}", result);
269 assert!(result.to_string().contains("5"));
270 }
271 #[test]
272 fn test_basic_variable_integration() {
273 let x = symbol!(x);
274 let expr = Expression::symbol(x.clone());
275 let result = expr.integrate(x.clone(), 0);
276 println!("Integration result: {}", result);
277 assert!(result.to_string().contains("x") || result.to_string().contains("2"));
278 }
279 #[test]
280 fn test_power_rule_x_squared() {
281 let x = symbol!(x);
282 let expr = Expression::pow(Expression::symbol(x.clone()), Expression::integer(2));
283 let result = expr.integrate(x.clone(), 0);
284 println!("Integration result for x^2: {}", result);
285 assert!(result.to_string().contains("x") || result.to_string().contains("3"));
286 }
287 #[test]
288 fn test_integral_of_sum() {
289 let x = symbol!(x);
290 let expr = Expression::add(vec![Expression::symbol(x.clone()), Expression::integer(1)]);
291 let result = expr.integrate(x.clone(), 0);
292 println!("Integration result for x + 1: {}", result);
293 assert!(!result.to_string().is_empty());
294 }
295 #[test]
296 fn test_constant_multiple_integration() {
297 let x = symbol!(x);
298 let expr = Expression::mul(vec![Expression::integer(3), Expression::symbol(x.clone())]);
299 let result = expr.integrate(x.clone(), 0);
300 println!("Integration result for 3x: {}", result);
301 assert!(result.to_string().contains("3") || result.to_string().contains("x"));
302 }
303}