mathhook_core/calculus/integrals/
function_integrals.rs

1//! Integration of standard mathematical functions
2//!
3//! Handles integration of trigonometric, exponential, logarithmic,
4//! and other standard functions using the existing Expression::function
5//! infrastructure.
6
7use crate::core::{Expression, Symbol};
8use crate::functions::intelligence::get_universal_registry;
9use crate::functions::properties::{AntiderivativeRule, AntiderivativeRuleType};
10
11/// Function integration handler
12pub struct FunctionIntegrals;
13
14impl FunctionIntegrals {
15    /// Integrate function expressions using known antiderivatives
16    ///
17    /// # Examples
18    ///
19    /// ```rust
20    /// use mathhook_core::{Expression, FunctionIntegrals};
21    /// use mathhook_core::symbol;
22    ///
23    /// let x = symbol!(x);
24    /// let args = vec![Expression::symbol(x.clone())];
25    /// let result = FunctionIntegrals::integrate("sin", &args, x.clone());
26    ///
27    /// let expected = Expression::mul(vec![
28    ///     Expression::integer(-1),
29    ///     Expression::function("cos", vec![Expression::symbol(x)]),
30    /// ]);
31    /// assert_eq!(result, expected);
32    /// ```
33    pub fn integrate(name: &str, args: &[Expression], variable: Symbol) -> Expression {
34        if args.len() == 1 {
35            if let Expression::Symbol(sym) = &args[0] {
36                if *sym == variable {
37                    // Direct integration of f(x) where arg is just x
38                    Self::integrate_simple_function(name, variable)
39                } else {
40                    // f(y) where y ≠ x, treat as constant
41                    Expression::mul(vec![
42                        Expression::function(name, args.to_vec()),
43                        Expression::symbol(variable),
44                    ])
45                }
46            } else {
47                // f(g(x)) - try substitution or chain rule
48                Self::integrate_composite_function(name, &args[0], variable)
49            }
50        } else {
51            // Multi-argument functions - fall back to symbolic
52            Expression::integral(Expression::function(name, args.to_vec()), variable)
53        }
54    }
55
56    /// Integrate simple functions f(x) using standard antiderivatives
57    ///
58    /// # Examples
59    ///
60    /// ```rust
61    /// use mathhook_core::{Expression, FunctionIntegrals};
62    /// use mathhook_core::symbol;
63    ///
64    /// let x = symbol!(x);
65    /// let result = FunctionIntegrals::integrate_simple_function("sin", x.clone());
66    ///
67    /// let expected = Expression::mul(vec![
68    ///     Expression::integer(-1),
69    ///     Expression::function("cos", vec![Expression::symbol(x)]),
70    /// ]);
71    /// assert_eq!(result, expected);
72    /// ```
73    pub fn integrate_simple_function(name: &str, variable: Symbol) -> Expression {
74        let registry = get_universal_registry();
75
76        if let Some(props) = registry.get_properties(name) {
77            if let Some(rule) = props.get_antiderivative_rule() {
78                return Self::apply_antiderivative_rule(rule, name, variable);
79            }
80        }
81
82        Expression::integral(
83            Expression::function(name, vec![Expression::symbol(variable.clone())]),
84            variable,
85        )
86    }
87
88    /// Apply antiderivative rule from registry to compute integral
89    ///
90    /// Takes a rule from the function intelligence registry and constructs
91    /// the corresponding antiderivative expression.
92    ///
93    /// # Arguments
94    ///
95    /// * `rule` - The antiderivative rule from function intelligence registry
96    /// * `function_name` - Original function name (for error messages and fallback)
97    /// * `variable` - Integration variable
98    ///
99    /// # Returns
100    ///
101    /// The antiderivative expression. For unknown rule types, returns symbolic integral.
102    ///
103    /// # Examples
104    ///
105    /// ```rust
106    /// use mathhook_core::{Expression, Symbol};
107    /// use mathhook_core::symbol;
108    /// ```
109    fn apply_antiderivative_rule(
110        rule: &AntiderivativeRule,
111        function_name: &str,
112        variable: Symbol,
113    ) -> Expression {
114        match &rule.rule_type {
115            AntiderivativeRuleType::Simple {
116                antiderivative_fn,
117                coefficient,
118            } => {
119                // ∫f(x)dx = c * F(x)
120                Expression::mul(vec![
121                    coefficient.clone(),
122                    Expression::function(antiderivative_fn, vec![Expression::symbol(variable)]),
123                ])
124            }
125
126            AntiderivativeRuleType::Custom { builder } => {
127                // Builder constructs the expression directly
128                builder(variable)
129            }
130
131            AntiderivativeRuleType::LinearSubstitution { .. } => {
132                // Future implementation
133                Expression::integral(
134                    Expression::function(function_name, vec![Expression::symbol(variable.clone())]),
135                    variable,
136                )
137            }
138
139            AntiderivativeRuleType::TrigSubstitution { .. } => {
140                // Future implementation
141                Expression::integral(
142                    Expression::function(function_name, vec![Expression::symbol(variable.clone())]),
143                    variable,
144                )
145            }
146
147            AntiderivativeRuleType::PartialFractions { .. } => {
148                // Future implementation
149                Expression::integral(
150                    Expression::function(function_name, vec![Expression::symbol(variable.clone())]),
151                    variable,
152                )
153            }
154        }
155    }
156
157    /// Integrate composite functions f(g(x)) using substitution when possible
158    ///
159    /// # Examples
160    ///
161    /// ```rust
162    /// use mathhook_core::{Expression, FunctionIntegrals};
163    /// use mathhook_core::symbol;
164    ///
165    /// let x = symbol!(x);
166    /// let inner = Expression::mul(vec![
167    ///     Expression::integer(2),
168    ///     Expression::symbol(x.clone()),
169    /// ]);
170    /// let result = FunctionIntegrals::integrate_composite_function("sin", &inner, x.clone());
171    ///
172    /// let expected = Expression::mul(vec![
173    ///     Expression::pow(Expression::integer(2), Expression::integer(-1)),
174    ///     Expression::mul(vec![
175    ///         Expression::integer(-1),
176    ///         Expression::function("cos", vec![
177    ///             Expression::mul(vec![
178    ///                 Expression::integer(2),
179    ///                 Expression::symbol(x),
180    ///             ])
181    ///         ]),
182    ///     ]),
183    /// ]);
184    /// assert_eq!(result, expected);
185    /// ```
186    pub fn integrate_composite_function(
187        name: &str,
188        inner: &Expression,
189        variable: Symbol,
190    ) -> Expression {
191        let registry = get_universal_registry();
192
193        if let Some(props) = registry.get_properties(name) {
194            if let Some(_rule) = props.get_antiderivative_rule() {
195                if let Expression::Mul(factors) = inner {
196                    if factors.len() == 2 {
197                        if let (Expression::Number(_), Expression::Symbol(sym)) =
198                            (&factors[0], &factors[1])
199                        {
200                            if *sym == variable {
201                                return Self::integrate_linear_substitution(
202                                    name,
203                                    &factors[0],
204                                    variable,
205                                );
206                            }
207                        }
208                    }
209                }
210            }
211        }
212
213        Expression::integral(Expression::function(name, vec![inner.clone()]), variable)
214    }
215
216    /// Handle integration of f(ax) where a is constant
217    ///
218    /// # Examples
219    ///
220    /// ```rust
221    /// use mathhook_core::{Expression, FunctionIntegrals};
222    /// use mathhook_core::symbol;
223    ///
224    /// let x = symbol!(x);
225    /// let a = Expression::integer(3);
226    /// let result = FunctionIntegrals::integrate_linear_substitution("sin", &a, x.clone());
227    ///
228    /// let expected = Expression::mul(vec![
229    ///     Expression::pow(Expression::integer(3), Expression::integer(-1)),
230    ///     Expression::mul(vec![
231    ///         Expression::integer(-1),
232    ///         Expression::function("cos", vec![
233    ///             Expression::mul(vec![
234    ///                 Expression::integer(3),
235    ///                 Expression::symbol(x),
236    ///             ])
237    ///         ]),
238    ///     ]),
239    /// ]);
240    /// assert_eq!(result, expected);
241    /// ```
242    pub fn integrate_linear_substitution(
243        name: &str,
244        coefficient: &Expression,
245        variable: Symbol,
246    ) -> Expression {
247        let antiderivative = Self::integrate_simple_function(name, variable.clone());
248        let substituted =
249            Self::substitute_variable_with_coefficient(&antiderivative, coefficient, variable);
250
251        // Multiply by 1/a for the substitution
252        Expression::mul(vec![
253            Expression::pow(coefficient.clone(), Expression::integer(-1)),
254            substituted,
255        ])
256    }
257
258    /// Helper to substitute x with ax in an expression
259    fn substitute_variable_with_coefficient(
260        expr: &Expression,
261        coefficient: &Expression,
262        variable: Symbol,
263    ) -> Expression {
264        match expr {
265            Expression::Symbol(sym) if *sym == variable => {
266                Expression::mul(vec![coefficient.clone(), Expression::symbol(variable)])
267            }
268            Expression::Function { name, args } => {
269                let new_args: Vec<Expression> = args
270                    .iter()
271                    .map(|arg| {
272                        Self::substitute_variable_with_coefficient(
273                            arg,
274                            coefficient,
275                            variable.clone(),
276                        )
277                    })
278                    .collect();
279                Expression::function(name, new_args)
280            }
281            Expression::Add(terms) => {
282                let new_terms: Vec<Expression> = terms
283                    .iter()
284                    .map(|term| {
285                        Self::substitute_variable_with_coefficient(
286                            term,
287                            coefficient,
288                            variable.clone(),
289                        )
290                    })
291                    .collect();
292                Expression::add(new_terms)
293            }
294            Expression::Mul(factors) => {
295                let new_factors: Vec<Expression> = factors
296                    .iter()
297                    .map(|factor| {
298                        Self::substitute_variable_with_coefficient(
299                            factor,
300                            coefficient,
301                            variable.clone(),
302                        )
303                    })
304                    .collect();
305                Expression::mul(new_factors)
306            }
307            _ => expr.clone(),
308        }
309    }
310}