mathhook_core/calculus/integrals.rs
1//! Integration operations and methods
2//!
3//! Implements symbolic integration including basic antiderivatives,
4//! integration by parts, substitution, trigonometric integrals,
5//! and definite integrals. Utilizes the existing Expression::Calculus
6//! infrastructure and Expression::function support.
7
8mod basic;
9pub mod by_parts;
10// mod definite;
11pub mod educational;
12mod function_integrals;
13pub mod numerical;
14pub mod rational;
15pub mod risch;
16pub mod strategy;
17pub mod substitution;
18pub mod table;
19pub mod trigonometric;
20
21pub use basic::BasicIntegrals;
22pub use by_parts::IntegrationByParts;
23// pub use definite::DefiniteIntegrals;
24pub use educational::{
25 explain_constant_rule, explain_definite_integral, explain_integration_by_parts,
26 explain_power_rule, explain_sum_rule, explain_u_substitution,
27};
28pub use function_integrals::FunctionIntegrals;
29pub use numerical::{
30 AdaptiveSimpson, GaussianQuadrature, IntegrationConfig, IntegrationResult, NumericalIntegrator,
31 RombergIntegration,
32};
33pub use rational::{integrate_rational, is_rational_function};
34pub use substitution::try_substitution;
35pub use trigonometric::try_trigonometric_integration;
36
37use crate::core::{Expression, Symbol};
38use crate::error::MathError;
39use std::collections::HashMap;
40use strategy::integrate_with_strategy;
41
42/// Trait for integration operations
43/// Added `depth` parameter to prevent infinite recursion in integration by parts.
44/// The `depth` parameter tracks recursion depth and enables maximum depth limiting.
45///
46/// Default depth is 0 (top-level call). Internal implementations increment this
47/// to prevent stack overflow in cases where simplification fails.
48pub trait Integration {
49 /// Compute indefinite integral with recursion depth tracking
50 ///
51 /// Returns an unevaluated integral if no closed form exists.
52 ///
53 /// # Arguments
54 ///
55 /// * `variable` - The variable to integrate with respect to
56 /// * `depth` - Current recursion depth (default: 0)
57 ///
58 /// # Examples
59 ///
60 /// ```rust
61 /// use mathhook_core::calculus::integrals::IntegrationMethods;
62 /// use mathhook_core::Expression;
63 /// use mathhook_core::calculus::integrals::Integration;
64 /// use mathhook_core::symbol;
65 ///
66 /// let x = symbol!(x);
67 /// let expr = Expression::pow(Expression::symbol(x.clone()), Expression::integer(2));
68 /// let result = expr.integrate(x, 0);
69 /// # Ok::<(), Box<dyn std::error::Error>>(())
70 /// ```
71 fn integrate(&self, variable: Symbol, depth: usize) -> Expression;
72
73 /// Compute definite integral
74 ///
75 /// # Errors
76 ///
77 /// Returns `MathError::DomainError` when evaluation at bounds fails.
78 ///
79 /// # Examples
80 ///
81 /// ```rust
82 /// use mathhook_core::Expression;
83 /// use mathhook_core::symbol;
84 /// use mathhook_core::calculus::integrals::Integration;
85 ///
86 /// let x = symbol!(x);
87 /// let expr = Expression::symbol(x.clone());
88 /// let lower = Expression::integer(0);
89 /// let upper = Expression::integer(1);
90 /// let result = expr.definite_integrate(x, lower, upper);
91 /// # Ok::<(), Box<dyn std::error::Error>>(())
92 /// ```
93 fn definite_integrate(
94 &self,
95 variable: Symbol,
96 lower: Expression,
97 upper: Expression,
98 ) -> Result<Expression, MathError>;
99}
100
101impl Integration for Expression {
102 fn integrate(&self, variable: Symbol, depth: usize) -> Expression {
103 integrate_with_strategy(self, variable, depth)
104 }
105
106 fn definite_integrate(
107 &self,
108 variable: Symbol,
109 lower: Expression,
110 upper: Expression,
111 ) -> Result<Expression, MathError> {
112 let antiderivative = self.integrate(variable.clone(), 0);
113
114 let mut substitutions = HashMap::new();
115 substitutions.insert(variable.name().to_string(), upper.clone());
116 let upper_val = antiderivative.clone().substitute(&substitutions);
117
118 substitutions.insert(variable.name().to_string(), lower.clone());
119 let lower_val = antiderivative.substitute(&substitutions);
120
121 Ok(Expression::add(vec![
122 upper_val,
123 Expression::mul(vec![Expression::integer(-1), lower_val]),
124 ]))
125 }
126}
127
128/// Integration methods collection
129pub struct IntegrationMethods;
130
131impl IntegrationMethods {
132 /// Attempt integration by parts
133 ///
134 /// Uses the IntegrationByParts module to attempt integration by parts.
135 ///
136 /// # Errors
137 ///
138 /// Returns `MathError::NotImplemented` if integration by parts cannot be applied
139 /// or if no antiderivative can be found.
140 ///
141 /// # Examples
142 ///
143 /// ```rust
144 /// use mathhook_core::Expression;
145 /// use mathhook_core::symbol;
146 /// use mathhook_core::calculus::integrals::IntegrationMethods;
147 ///
148 /// let x = symbol!(x);
149 /// let expr = Expression::mul(vec![
150 /// Expression::symbol(x.clone()),
151 /// Expression::function("exp", vec![Expression::symbol(x.clone())])
152 /// ]);
153 /// let result = IntegrationMethods::by_parts(&expr, x);
154 /// # Ok::<(), Box<dyn std::error::Error>>(())
155 /// ```
156 pub fn by_parts(expr: &Expression, variable: Symbol) -> Result<Expression, MathError> {
157 IntegrationByParts::integrate(expr, variable.clone(), 0).ok_or_else(|| {
158 MathError::NotImplemented {
159 feature: format!("integration by parts for {}", expr),
160 }
161 })
162 }
163
164 /// Attempt integration by substitution
165 ///
166 /// Uses u-substitution to integrate composite functions f(g(x)) where
167 /// the derivative g'(x) appears in the integrand.
168 ///
169 /// # Errors
170 ///
171 /// Returns `MathError::NotImplemented` if no suitable substitution can be found.
172 ///
173 /// # Examples
174 ///
175 /// ```rust
176 /// use mathhook_core::{Expression, Symbol};
177 /// use mathhook_core::symbol;
178 /// use mathhook_core::calculus::integrals::IntegrationMethods;
179 ///
180 /// let x = symbol!(x);
181 /// let expr = Expression::function("sin", vec![
182 /// Expression::pow(Expression::symbol(x.clone()), Expression::integer(2))
183 /// ]);
184 /// let result = IntegrationMethods::substitution(&expr, x);
185 /// # Ok::<(), Box<dyn std::error::Error>>(())
186 /// ```
187 pub fn substitution(expr: &Expression, variable: Symbol) -> Result<Expression, MathError> {
188 try_substitution(expr, &variable, 0).ok_or_else(|| MathError::NotImplemented {
189 feature: format!("u-substitution for {}", expr),
190 })
191 }
192}