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}