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}